diff --git a/CHANGELOG.md b/CHANGELOG.md index cced82b..91e0999 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,13 @@ # WorldEditAdditions Changelog It's about time I started a changelog! This will serve from now on as the main changelog for WorldEditAdditions. +Note to self: See the bottom of this file for the release template text. ## v1.12 (unreleased) - Add `//srect` (_select rectangle_) - thanks, @VorTechnix! + - Add `//spush`, `//spop`, and `//sstack` + - `//overlay`: Don't place nodes above water + ## v1.11: The big data update (25th January 2021) - Add `//scale` (currently **experimental**) diff --git a/Chat-Command-Reference.md b/Chat-Command-Reference.md index 14623c6..28d765e 100644 --- a/Chat-Command-Reference.md +++ b/Chat-Command-Reference.md @@ -491,6 +491,30 @@ Short for _select rectangle_. Sets the pos2 at a set distance along 2 axes from //srect -z y 25 ``` +## `//sstack` +Displays the contents of your per-user selection stack. This stack can be pushed to and popped from rather like a stack of plates. See also `//spush` (for pushing to the selection stack) and `//spop` (for popping from the selection stack). + +``` +//sstack +``` + +## `//spush` +Pushes the currently defined region onto your per-user selection stack. Does not otherwise alter the defined region. + +If the stack is full (currently the limit is set to 100 regions in the stack), then it will complain at you but otherwise will have no effect. + +Note that pos2 does _not_ need to be defined in order to use this. if it isn't defined, then a pos2 of `nil` will be pushed onto the stack instead. + +``` +//spush +``` + +## `//spop` +Pops a selection off your per-user selection stack and applies it to the currently defined region. If pos2 from the item popped from the stack is nil, then pos2 is explicitly unset. If the stack is empty, this has no effect. + +``` +//spop +``` ## `//y` Confirms the execution of a command if it could potentially affect a large number of nodes and take a while. This is a regular WorldEdit command. diff --git a/README.md b/README.md index 105dcb7..b3de001 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,6 @@ The detailed explanations have moved! Check them out [here](https://github.com/s - [`//replacemix [] [] [ []] [ []] ....`](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/master/Chat-Command-Reference.md#replacemix-target_node-chance-replace_node_a-chance_a-replace_node_b-chance_b-replace_node_n-chance_n-) - [`//floodfill [ []]`](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/master/Chat-Command-Reference.md#floodfill-replace_node-radius-floodfill) - [`//scale | [ [ ]]`](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/master/Chat-Command-Reference.md#scale-axis-scale_factor--factor_x-factor_y-factor_z-anchor_x-anchor_y-anchor_z) **experimental** - - [`//srect [ []] `](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/master/Chat-Command-Reference.md#srect-axis1-axis2-length) ### Terrain - [`//overlay [] [] [ []] ...`](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/master/Chat-Command-Reference.md#overlay-node_name_a-chance_a-node_name_b-chance_b-node_name_n-chance_n-) @@ -57,6 +56,12 @@ The detailed explanations have moved! Check them out [here](https://github.com/s ### Statistics - [`//count`](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/master/Chat-Command-Reference.md#count) +### Selection +- [`//srect [ []] `](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/master/Chat-Command-Reference.md#srect-axis1-axis2-length) +- [`//sstack`](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/master/Chat-Command-Reference.md#sstack) +- [`//spush`](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/master/Chat-Command-Reference.md#spush) +- [`//spop`](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/master/Chat-Command-Reference.md#spop) + ### Meta - [`//multi ....`](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/master/Chat-Command-Reference.md#multi-command_a-command_b-command_c-) - [`//many `](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/master/Chat-Command-Reference.md#many-times-command) _(new in v1.9)_ diff --git a/worldeditadditions/init.lua b/worldeditadditions/init.lua index 49acea4..9ed6be0 100644 --- a/worldeditadditions/init.lua +++ b/worldeditadditions/init.lua @@ -45,3 +45,4 @@ dofile(worldeditadditions.modpath.."/lib/forest.lua") dofile(worldeditadditions.modpath.."/lib/ellipsoidapply.lua") dofile(worldeditadditions.modpath.."/lib/subdivide.lua") +dofile(worldeditadditions.modpath.."/lib/selection/stack.lua") diff --git a/worldeditadditions/lib/overlay.lua b/worldeditadditions/lib/overlay.lua index 12a35f5..cc21b8d 100644 --- a/worldeditadditions/lib/overlay.lua +++ b/worldeditadditions/lib/overlay.lua @@ -23,32 +23,38 @@ function worldeditadditions.overlay(pos1, pos2, node_weights) for x = pos2.x, pos1.x, -1 do local found_air = false local placed_node = false - + -- print("\n\n[overlay] ****** column start ******") for y = pos2.y, pos1.y, -1 do local i = area:index(x, y, z) + -- print("[overlay] pos", x, y, z, "id", data[i], "name", minetest.get_name_from_content_id(data[i]), "is_liquid", worldeditadditions.is_liquidlike(data[i])) local is_air = worldeditadditions.is_airlike(data[i]) + local is_liquid = worldeditadditions.is_liquidlike(data[i]) -- wielded_light is now handled by worldeditadditions.is_airlike local is_ignore = data[i] == node_id_ignore if not is_air and not is_ignore then - if found_air then + local i_above = area:index(x, y + 1, z) + if found_air and not is_liquid then local new_id = node_ids[math.random(node_ids_count)] -- We've found an air block previously, so it must be above us -- Replace the node above us with the target block - data[area:index(x, y + 1, z)] = new_id + data[i_above] = new_id changes.updated = changes.updated + 1 placed_node = true if not changes.placed[new_id] then changes.placed[new_id] = 0 end changes.placed[new_id] = changes.placed[new_id] + 1 + -- print("[overlay] placed above ", x, y, z) break -- Move on to the next column end - elseif not is_ignore then + elseif not is_ignore and not is_liquid then + -- print("[overlay] found air at", x, y, z) found_air = true end + if is_liquid then found_air = false end end if not placed_node then diff --git a/worldeditadditions/lib/selection/stack.lua b/worldeditadditions/lib/selection/stack.lua new file mode 100644 index 0000000..7ef7a0d --- /dev/null +++ b/worldeditadditions/lib/selection/stack.lua @@ -0,0 +1,47 @@ +--- Holds the per-user selection stacks. +worldeditadditions.sstack = {} + +local sstack_max = 100 + +--- Calculates the height of the selection stack for the defined user. +-- If the defined user doesn't yet have a stack, a value of 0 is returned. +-- @param user string The name of the user to count the size of the selection stack for. +-- @return number The number of items on the stack for the given user. +function worldeditadditions.scount(name) + if not worldeditadditions.sstack[name] then + return 0 + end + return #worldeditadditions.sstack[name] +end + +--- Inserts a selection region onto the stack for the user with the given name. +-- Stacks are per-user. +-- @param name string The name of the user to insert onto. +-- @param pos1 Vector Position 1 +-- @param pos2 Vector Position 2 +function worldeditadditions.spush(name, pos1, pos2) + if not worldeditadditions.sstack[name] then + worldeditadditions.sstack[name] = {} + end + -- Checck the stack height + if #worldeditadditions.sstack[name] > sstack_max then + return false, "Error: Selection stack height of "..sstack_max.." would be exceeded by pushing a new selection onto the stack now." + end + + table.insert(worldeditadditions.sstack[name], { pos1, pos2 }) + + return true +end + +--- Pops a selection region off the stack for the given user. +-- Stacks are per-user. +-- @param name string The name of the user to remove a selection region off the stack for. +-- @return bool,Vector|string, Vector A bool true/false indicating success, followed by either a error message as a string if false or a pair of Vectors for the pos1 and pos2 from the item popped from the stack respectively. +function worldeditadditions.spop(name) + if not worldeditadditions.sstack[name] or #worldeditadditions.sstack[name] == 0 then + return false, "Error: The stack for user "..name.." is empty, so can't remove anything from it." + end + + local item = table.remove(worldeditadditions.sstack[name]) + return true, item[1], item[2] +end diff --git a/worldeditadditions/utils/node_identification.lua b/worldeditadditions/utils/node_identification.lua index 207cd4b..5375cb6 100644 --- a/worldeditadditions/utils/node_identification.lua +++ b/worldeditadditions/utils/node_identification.lua @@ -44,7 +44,7 @@ function worldeditadditions.is_liquidlike(id) if node_name == nil or not minetest.registered_nodes[node_name] then return false end local liquidtype = minetest.registered_nodes[node_name].liquidtype - -- print("[is_liquidlike]", "id", id, "liquidtype", liquidtype) + -- print("[is_liquidlike]", "id", id, "name", node_name, "liquidtype", liquidtype) if liquidtype == nil or liquidtype == "none" then return false end -- If it's not none, then it has to be a liquid as the only other values are source and flowing diff --git a/worldeditadditions/utils/vector.lua b/worldeditadditions/utils/vector.lua index 75f2b75..3df6611 100644 --- a/worldeditadditions/utils/vector.lua +++ b/worldeditadditions/utils/vector.lua @@ -1,6 +1,7 @@ worldeditadditions.vector = {} function worldeditadditions.vector.tostring(v) + if not v then return "(nil)" end return "(" .. v.x ..", " .. v.y ..", " .. v.z ..")" end diff --git a/worldeditadditions_commands/commands/selectors/spop.lua b/worldeditadditions_commands/commands/selectors/spop.lua new file mode 100644 index 0000000..0e3ea9c --- /dev/null +++ b/worldeditadditions_commands/commands/selectors/spop.lua @@ -0,0 +1,33 @@ +-- ███████ ██████ ██████ ██████ +-- ██ ██ ██ ██ ██ ██ ██ +-- ███████ ██████ ██ ██ ██████ +-- ██ ██ ██ ██ ██ +-- ███████ ██ ██████ ██ +worldedit.register_command("spop", { + params = "", + description = "Pops a region off your (per-user) selection stack.", + privs = { worldedit = true }, + parse = function(params_text) + return true + end, + nodes_needed = function(name) + return 0 + end, + func = function(name) + local success, pos1, pos2 = worldeditadditions.spop(name) + if not success then return success, pos1 end + + worldedit.pos1[name] = pos1 + worldedit.pos2[name] = pos2 + worldedit.marker_update(name) + + local new_count = worldeditadditions.scount(name) + local plural = "s are" + if new_count == 1 then plural = " is" end + + local region_text = worldeditadditions.vector.tostring(worldedit.pos1[name]).." - "..worldeditadditions.vector.tostring(worldedit.pos2[name]) + + minetest.log("action", name .. " used //spush at "..region_text..". Stack height is now " .. new_count.." regions") + return true, "Region "..region_text.." pushed onto selection stack; "..new_count.." region"..plural.." now in the stack" + end +}) diff --git a/worldeditadditions_commands/commands/selectors/spush.lua b/worldeditadditions_commands/commands/selectors/spush.lua new file mode 100644 index 0000000..8c85fe0 --- /dev/null +++ b/worldeditadditions_commands/commands/selectors/spush.lua @@ -0,0 +1,32 @@ +-- ███████ ██████ ██ ██ ███████ ██ ██ +-- ██ ██ ██ ██ ██ ██ ██ ██ +-- ███████ ██████ ██ ██ ███████ ███████ +-- ██ ██ ██ ██ ██ ██ ██ +-- ███████ ██ ██████ ███████ ██ ██ +worldedit.register_command("spush", { + params = "", + description = "Pushes the currently defined region onto your (per-user) selection stack.", + privs = { worldedit = true }, + require_pos = 1, + parse = function(params_text) + return true + end, + nodes_needed = function(name) + return 0 + end, + func = function(name) + local success, msg = worldeditadditions.spush(name, worldedit.pos1[name], worldedit.pos2[name]) + if not success then + return success, msg + end + + local new_count = worldeditadditions.scount(name) + local plural = "s are" + if new_count == 1 then plural = " is" end + + local region_text = worldeditadditions.vector.tostring(worldedit.pos1[name]).." - "..worldeditadditions.vector.tostring(worldedit.pos2[name]) + + minetest.log("action", name .. " used //spush at "..region_text..". Stack height is now " .. new_count.." regions") + return true, "Region "..region_text.." pushed onto selection stack; "..new_count.." region"..plural.." now in the stack" + end +}) diff --git a/worldeditadditions_commands/commands/selectors/sstack.lua b/worldeditadditions_commands/commands/selectors/sstack.lua new file mode 100644 index 0000000..6ff4cac --- /dev/null +++ b/worldeditadditions_commands/commands/selectors/sstack.lua @@ -0,0 +1,36 @@ +-- ███████ ███████ ████████ █████ ██████ ██ ██ +-- ██ ██ ██ ██ ██ ██ ██ ██ +-- ███████ ███████ ██ ███████ ██ █████ +-- ██ ██ ██ ██ ██ ██ ██ ██ +-- ███████ ███████ ██ ██ ██ ██████ ██ ██ +worldedit.register_command("sstack", { + params = "", + description = "Displays the contents of your (per-user) selection stack.", + privs = { worldedit = true }, + parse = function(params_text) + return true + end, + nodes_needed = function(name) + return 0 + end, + func = function(name) + + local result = {"Stack contents for user ", name, ":\n"} + if not worldeditadditions.sstack[name] then + table.insert(result, "(empty)") + else + for i,item in ipairs(worldeditadditions.sstack[name]) do + table.insert(result, i) + table.insert(result, ": ") + table.insert(result, worldeditadditions.vector.tostring(item[1])) + table.insert(result, " - ") + table.insert(result, worldeditadditions.vector.tostring(item[2])) + table.insert(result, "\n") + end + table.insert(result, "========================\nTotal ") + table.insert(result, #worldeditadditions.sstack[name]) + table.insert(result, " items") + end + return true, table.concat(result, "") + end +}) diff --git a/worldeditadditions_commands/init.lua b/worldeditadditions_commands/init.lua index 425413c..75b85cf 100644 --- a/worldeditadditions_commands/init.lua +++ b/worldeditadditions_commands/init.lua @@ -44,6 +44,9 @@ dofile(we_c.modpath.."/commands/meta/ellipsoidapply.lua") -- dofile(we_c.modpath.."/commands/selectors/scol.lua") dofile(we_c.modpath.."/commands/selectors/srect.lua") -- dofile(we_c.modpath.."/commands/selectors/scube.lua") +dofile(we_c.modpath.."/commands/selectors/sstack.lua") +dofile(we_c.modpath.."/commands/selectors/spush.lua") +dofile(we_c.modpath.."/commands/selectors/spop.lua") dofile(we_c.modpath.."/commands/extra/saplingaliases.lua") dofile(we_c.modpath.."/commands/extra/basename.lua")