From 4b2f2b00017cf47354be164fe95fdad8557c37bf Mon Sep 17 00:00:00 2001 From: Starbeamrainbowlabs Date: Sat, 16 Jan 2021 18:36:17 +0000 Subject: [PATCH] Add //line Fixes #25. --- CHANGELOG.md | 1 + Chat-Command-Reference.md | 14 +++++ README.md | 1 + worldeditadditions/init.lua | 1 + worldeditadditions/lib/line.lua | 52 +++++++++++++++++++ worldeditadditions_commands/commands/line.lua | 52 +++++++++++++++++++ worldeditadditions_commands/init.lua | 1 + 7 files changed, 122 insertions(+) create mode 100644 worldeditadditions/lib/line.lua create mode 100644 worldeditadditions_commands/commands/line.lua diff --git a/CHANGELOG.md b/CHANGELOG.md index 4deb423..ddf28e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ It's about time I started a changelog! This will serve from now on as the main c - `//many`: Improve format of progress messages, add ETA - `//subdivide`: Make asynchronous, and use `minetest.emerge_area()` to ensure areas are loaded before executing on a subdivision chunk - This will ensure that `//subdivide`ing enormous regions should now function as expected. Want to level an entire rainforest with `//subdivide` and `//clearcut`? Now you can! :D + - Add `//line` for drawing simple lines ## v1.9: The Nature Update (20th September 2020) diff --git a/Chat-Command-Reference.md b/Chat-Command-Reference.md index 9052b0c..47d7e90 100644 --- a/Chat-Command-Reference.md +++ b/Chat-Command-Reference.md @@ -137,6 +137,20 @@ Creates a hollow torus at position 1 with the radius major and minor radii. Work //hollowtorus 21 11 stone ``` +### `//line [ []]` +Draw a line from position 1 to position 2, optionally with a given thickness. + +The radius can be tought fo as the thickness of the line, and is defined as the distance from a given node to an imaginary line from pos1 to pos2. Defaults to drawing with dirt and a radius of 1. + +Floating-point values are fully supported for the radius. + +``` +//line +//line stone +//line sandstone 3 +//line glass 0.5 +``` + ### `//maze [ [ []]]` Generates a maze using replace_node as the walls and air as the paths. Uses [an algorithm of my own devising](https://starbeamrainbowlabs.com/blog/article.php?article=posts/070-Language-Review-Lua.html). It is guaranteed that you can get from every point to every other point in generated mazes, and there are no loops. diff --git a/README.md b/README.md index 501d355..75cc952 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ The detailed explanations have moved! Check them out [here](https://github.com/s - [`//torus `](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/master/Chat-Command-Reference.md#torus-major_radius-minor_radius-node_name) - [`//hollowtorus `](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/master/Chat-Command-Reference.md#hollowtorus-major_radius-minor_radius-node_name) - [`//walls `](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/master/Chat-Command-Reference.md#walls-replace_node) + - [`//line [ []]`](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/master/Chat-Command-Reference.md#line-replace_node-radius) - [`//maze [ [ []]]`](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/master/Chat-Command-Reference.md#maze-replace_node-seed) - [`//maze3d [ [ [ []]]]`](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/master/Chat-Command-Reference.md#maze3d-replace_node-seed) diff --git a/worldeditadditions/init.lua b/worldeditadditions/init.lua index 577316d..ed9b3a5 100644 --- a/worldeditadditions/init.lua +++ b/worldeditadditions/init.lua @@ -24,6 +24,7 @@ dofile(worldeditadditions.modpath.."/lib/layers.lua") dofile(worldeditadditions.modpath.."/lib/fillcaves.lua") dofile(worldeditadditions.modpath.."/lib/ellipsoid.lua") dofile(worldeditadditions.modpath.."/lib/torus.lua") +dofile(worldeditadditions.modpath.."/lib/line.lua") dofile(worldeditadditions.modpath.."/lib/walls.lua") dofile(worldeditadditions.modpath.."/lib/replacemix.lua") dofile(worldeditadditions.modpath.."/lib/maze2d.lua") diff --git a/worldeditadditions/lib/line.lua b/worldeditadditions/lib/line.lua new file mode 100644 index 0000000..67e17c9 --- /dev/null +++ b/worldeditadditions/lib/line.lua @@ -0,0 +1,52 @@ +--- Counts the nodes in a given area. +-- @module worldeditadditions.count + +-- ██ ██ ███ ██ ███████ +-- ██ ██ ████ ██ ██ +-- ██ ██ ██ ██ ██ █████ +-- ██ ██ ██ ██ ██ ██ +-- ███████ ██ ██ ████ ███████ +function worldeditadditions.line(pos1, pos2, thickness, node_name) + local pos1_sorted, pos2_sorted = worldedit.sort_pos(pos1, pos2) + -- pos2 will always have the highest co-ordinates now + + pos1 = vector.new(pos1) + pos2 = vector.new(pos2) + + local node_id_replace = minetest.get_content_id(node_name) + print("thickness", thickness, "node_name", node_name, "node_id_replace", node_id_replace) + + -- Fetch the nodes in the specified area + local manip, area = worldedit.manip_helpers.init(pos1, pos2) + local data = manip:get_data() + + -- z y x is the preferred loop order (because CPU cache I'd guess, since then we're iterating linearly through the data array) + local counts = { replaced = 0 } + for z = pos2_sorted.z, pos1_sorted.z, -1 do + for x = pos2_sorted.x, pos1_sorted.x, -1 do + for y = pos2_sorted.y, pos1_sorted.y, -1 do + local here = vector.new(x, y, z) + local D = vector.normalize( + vector.subtract(pos2, pos1) + ) + local d = vector.dot(vector.subtract(here, pos1), D) + local closest_on_line = vector.add( + pos1, + vector.multiply(D, d) + ) + local distance = vector.length(vector.subtract(here, closest_on_line)) + + if distance < thickness then + print("[line] vector", closest_on_line.x, closest_on_line.y, closest_on_line.z, "length", distance) + data[area:index(x, y, z)] = node_id_replace + counts.replaced = counts.replaced + 1 + end + end + end + end + + -- Save the modified nodes back to disk & return + worldedit.manip_helpers.finish(manip, data) + + return true, counts +end diff --git a/worldeditadditions_commands/commands/line.lua b/worldeditadditions_commands/commands/line.lua new file mode 100644 index 0000000..c911d45 --- /dev/null +++ b/worldeditadditions_commands/commands/line.lua @@ -0,0 +1,52 @@ +-- ██ ██ ███ ██ ███████ +-- ██ ██ ████ ██ ██ +-- ██ ██ ██ ██ ██ █████ +-- ██ ██ ██ ██ ██ ██ +-- ███████ ██ ██ ████ ███████ +worldedit.register_command("line", { + params = "[ []]", + description = "Draws a line of a given radius (default: 1) from pos1 to pos2 in the given node (default: dirt).", + privs = { worldedit = true }, + require_pos = 1, + parse = function(params_text) + if not params_text then params_text = "" end + local found, _, replace_node, radius = params_text:find("([a-z:_\\-]+)%s+([0-9.]+)") + + if found == nil then + found, _, replace_node = params_text:find("([a-z:_\\-]+)") + radius = 1 + end + if found == nil then + replace_node = "default:dirt" + end + radius = tonumber(radius) + + replace_node = worldedit.normalize_nodename(replace_node) + + if not replace_node then + worldedit.player_notify(name, "Error: Invalid node name.") + return false + end + + return true, replace_node, radius + end, + nodes_needed = function(name, replace_node, radius) + -- Volume of a hemisphere + return math.ceil(math.pi + * radius * radius + * vector.distance( + vector.new(worldedit.pos1[name]), + vector.new(worldedit.pos2[name]) + )) -- Volume of a cylinder + end, + func = function(name, replace_node, radius) + local start_time = worldeditadditions.get_ms_time() + local success, stats = worldeditadditions.line(worldedit.pos1[name], worldedit.pos2[name], radius, replace_node) + local time_taken = worldeditadditions.get_ms_time() - start_time + + if success == false then return false, stats end + + minetest.log("action", name .. " used //line at " .. worldeditadditions.vector.tostring(worldedit.pos1[name]) .. ", replacing " .. stats.replaced .. " nodes in " .. time_taken .. "s") + return true, stats.replaced .. " nodes replaced in " .. worldeditadditions.human_time(time_taken) + end +}) diff --git a/worldeditadditions_commands/init.lua b/worldeditadditions_commands/init.lua index e91c3c5..e669580 100644 --- a/worldeditadditions_commands/init.lua +++ b/worldeditadditions_commands/init.lua @@ -25,6 +25,7 @@ dofile(we_c.modpath.."/commands/layers.lua") dofile(we_c.modpath.."/commands/fillcaves.lua") dofile(we_c.modpath.."/commands/ellipsoid.lua") dofile(we_c.modpath.."/commands/torus.lua") +dofile(we_c.modpath.."/commands/line.lua") dofile(we_c.modpath.."/commands/walls.lua") dofile(we_c.modpath.."/commands/maze.lua") dofile(we_c.modpath.."/commands/replacemix.lua")