diff --git a/worldeditadditions/ellipsoid.lua b/worldeditadditions/ellipsoid.lua new file mode 100644 index 0000000..a604006 --- /dev/null +++ b/worldeditadditions/ellipsoid.lua @@ -0,0 +1,50 @@ +--- Overlap command. Places a specified node on top of +-- @module worldeditadditions.overlay + +function worldedit.ellipsoid(position, radius, target_node) + -- position = { x, y, z } + + + -- Fetch the nodes in the specified area + -- OPTIMIZE: We should be able to calculate a more efficient box-area here + local manip, area = worldedit.manip_helpers.init_radius(pos1, math.max(radius.x, radius.y, radius.z)) + local data = manip:get_data() + + local node_id = minetest.get_content_id(target_node) + local node_id_air = minetest.get_content_id("air") + + local offset_x, offset_y, offset_z = pos.x - area.MinEdge.x, pos.y - area.MinEdge.y + local stride_z, stride_y = area.zstride, area.ystride + + local idx_z_base = pos.z - area.MinEdge.z -- initial z offset + for z = -radius.z, radius.z do + + local idx_y_base = idx_z_base + for y = -radius.y + offset_y, radius.y + offset_y do + + local i = idx_y_base + for x = -radius.x + offset_x, radius.x + offset_x do + + -- If we're inside the ellipse, then fill it in + if math.abs(z - position.z) < radius.z and + math.abs(y - position.y) < radius.y and + math.ans(z - position.x) < radius.x then + data[i] = node_id + end + + + i = i + 1 + end + idx_y_base = idx_y_base + y_stride + + end + idx_z_base = idx_z_base + z_stride + + end + + + -- Save the modified nodes back to disk & return + worldedit.manip_helpers.finish(manip, data) + + return changes +end diff --git a/worldeditadditions_commands/init.lua b/worldeditadditions_commands/init.lua index 91cfee4..fadc914 100644 --- a/worldeditadditions_commands/init.lua +++ b/worldeditadditions_commands/init.lua @@ -7,12 +7,19 @@ local safe_region, check_region, reset_pending = dofile(minetest.get_modpath("worldedit_commands") .. "/safe.lua") + +-- ███████ ██ ██████ ██████ ██████ ███████ ██ ██ ██ +-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +-- █████ ██ ██ ██ ██ ██ ██ ██ █████ ██ ██ ██ +-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +-- ██ ███████ ██████ ██████ ██████ ██ ██ ███████ ███████ + local function parse_params_floodfill(params_text) 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 = 25 + radius = 20 end if found == nil then replace_node = "default:water_source" @@ -26,7 +33,7 @@ end minetest.register_chatcommand("/floodfill", { params = "[ []]", - description = "Floods all connected nodes of the same type starting at pos1 with (which defaults to `water_source`), in a sphere with a radius of (which defaults to 50).", + description = "Floods all connected nodes of the same type starting at pos1 with (which defaults to `water_source`), in a sphere with a radius of (which defaults to 20).", privs = { worldedit = true }, func = safe_region(function(name, params_text) local replace_node, radius = parse_params_floodfill(params_text) @@ -41,7 +48,7 @@ minetest.register_chatcommand("/floodfill", { local time_taken = os.clock() - start_time worldedit.player_notify(name, nodes_replaced .. " nodes replaced in " .. time_taken .. "s") - minetest.log("action", name .. " used floodfill at " .. worldeditadditions.vector.tostring(worldedit.pos1[name]) .. ", replacing " .. nodes_replaced .. " nodes in " .. time_taken .. "s") + minetest.log("action", name .. " used //floodfill at " .. worldeditadditions.vector.tostring(worldedit.pos1[name]) .. ", replacing " .. nodes_replaced .. " nodes in " .. time_taken .. "s") end, function(name, params_text) local replace_node, radius = parse_params_floodfill(params_text) -- Volume of a hemisphere @@ -50,6 +57,12 @@ minetest.register_chatcommand("/floodfill", { }) +-- ██████ ██ ██ ███████ ██████ ██ █████ ██ ██ +-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +-- ██ ██ ██ ██ █████ ██████ ██ ███████ ████ +-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +-- ██████ ████ ███████ ██ ██ ███████ ██ ██ ██ + minetest.register_chatcommand("/overlay", { params = "", description = "Places in the last contiguous air space encountered above the first non-air node. In other words, overlays all top-most nodes in the specified area with .", @@ -67,7 +80,7 @@ minetest.register_chatcommand("/overlay", { local time_taken = os.clock() - start_time worldedit.player_notify(name, changes.updated .. " nodes replaced and " .. changes.skipped_columns .. " columns skipped in " .. time_taken .. "s") - minetest.log("action", name .. " used overlay at " .. worldeditadditions.vector.tostring(worldedit.pos1[name]) .. ", replacing " .. changes.updated .. " nodes and skipping " .. changes.skipped_columns .. " columns in " .. time_taken .. "s") + minetest.log("action", name .. " used //overlay at " .. worldeditadditions.vector.tostring(worldedit.pos1[name]) .. ", replacing " .. changes.updated .. " nodes and skipping " .. changes.skipped_columns .. " columns in " .. time_taken .. "s") end, function(name, params_text) if not worldedit.normalize_nodename(params_text) then worldedit.player_notify(name, "Error: Invalid node name '" .. params_text .. "'.") @@ -82,3 +95,60 @@ minetest.register_chatcommand("/overlay", { return vol.x*vol.z end) }) + + +-- ███████ ██ ██ ██ ██████ ███████ ██████ ██ ██████ +-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +-- █████ ██ ██ ██ ██████ ███████ ██ ██ ██ ██ ██ +-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +-- ███████ ███████ ███████ ██ ██ ███████ ██████ ██ ██████ + +local function parse_params_ellipsoid(params_text) + local found, _, radius_x, radius_y, radius_z, replace_node = params_text:find("([0-9]+)%s+([0-9]+)%s+([0-9]+)%s+([a-z:_\\-]+)") + + if found == nil then + return nil, nil + end + + local radius = { + x = tonumber(radius_x), + y = tonumber(radius_y), + z = tonumber(radius_z) + } + + replace_node = worldedit.normalize_nodename(replace_node) + + return replace_node, radius +end + +minetest.register_chatcommand("/ellipsoid", { + params = " ", + description = "Creates a 3D ellipsoid with a radius of (rx, ry, rz) at pos1, filled with .", + privs = { worldedit = true }, + func = safe_region(function(name, params_text) + local target_node, radius = parse_params_ellipsoid(params_text) + + if not target_node then + worldedit.player_notify(name, "Error: Invalid node name.") + return false + end + if not radius then + worldedit.player_notify(name, "Error: Invalid radius(es).") + return false + end + + local start_time = os.clock() + local replaced = worldedit.ellipsoid(worldedit.pos1[name], radius, target_node) + local time_taken = os.clock() - start_time + + worldedit.player_notify(name, replaced .. " nodes replaced in " .. time_taken .. "s") + minetest.log("action", name .. " used //ellipsoid at " .. worldeditadditions.vector.tostring(worldedit.pos1[name]) .. ", replacing " .. replaced .. " nodes in " .. time_taken .. "s") + end, function(name, params_text) + local target_node, radius = parse_params_ellipsoid(params_text) + if target_node == nil or radius == nil then + worldedit.player_notify(name, "Error: Invalid input '" .. params_text .. "'. Try '/help /ellipsoid' to learn how to use this command.") + end + + return math.ceil(4/3 * math.pi * radius.x * radius.y * radius.z) + end) +})