Add //line

Fixes #25.
This commit is contained in:
Starbeamrainbowlabs 2021-01-16 18:36:17 +00:00
parent 0cfd651510
commit 4b2f2b0001
No known key found for this signature in database
GPG Key ID: 1BE5172E637709C2
7 changed files with 122 additions and 0 deletions

@ -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)

@ -137,6 +137,20 @@ Creates a hollow torus at position 1 with the radius major and minor radii. Work
//hollowtorus 21 11 stone
```
### `//line [<replace_node> [<radius>]]`
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 <replace_node> [<path_length> [<path_width> [<seed>]]]`
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.

@ -30,6 +30,7 @@ The detailed explanations have moved! Check them out [here](https://github.com/s
- [`//torus <major_radius> <minor_radius> <node_name>`](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/master/Chat-Command-Reference.md#torus-major_radius-minor_radius-node_name)
- [`//hollowtorus <major_radius> <minor_radius> <node_name>`](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/master/Chat-Command-Reference.md#hollowtorus-major_radius-minor_radius-node_name)
- [`//walls <replace_node>`](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/master/Chat-Command-Reference.md#walls-replace_node)
- [`//line [<replace_node> [<radius>]]`](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/master/Chat-Command-Reference.md#line-replace_node-radius)
- [`//maze <replace_node> [<path_length> [<path_width> [<seed>]]]`](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/master/Chat-Command-Reference.md#maze-replace_node-seed)
- [`//maze3d <replace_node> [<path_length> [<path_width> [<path_depth> [<seed>]]]]`](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/master/Chat-Command-Reference.md#maze3d-replace_node-seed)

@ -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")

@ -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

@ -0,0 +1,52 @@
-- ██ ██ ███ ██ ███████
-- ██ ██ ████ ██ ██
-- ██ ██ ██ ██ ██ █████
-- ██ ██ ██ ██ ██ ██
-- ███████ ██ ██ ████ ███████
worldedit.register_command("line", {
params = "[<replace_node> [<radius>]]",
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
})

@ -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")