Merge pull request #2 from sbrl/master

Selection Saving Beta
This commit is contained in:
VorTechnix 2021-03-01 20:44:25 -08:00 committed by GitHub
commit 7f6c8e146e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 198 additions and 6 deletions

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

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

@ -40,7 +40,6 @@ The detailed explanations have moved! Check them out [here](https://github.com/s
- [`//replacemix <target_node> [<chance>] <replace_node_a> [<chance_a>] [<replace_node_b> [<chance_b>]] [<replace_node_N> [<chance_N>]] ....`](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 [<replace_node> [<radius>]]`](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/master/Chat-Command-Reference.md#floodfill-replace_node-radius-floodfill)
- [`//scale <axis> <scale_factor> | <factor_x> [<factor_y> <factor_z> [<anchor_x> <anchor_y> <anchor_z>]]`](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 [<axis1> [<axis2>]] <length>`](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/master/Chat-Command-Reference.md#srect-axis1-axis2-length)
### Terrain
- [`//overlay <node_name_a> [<chance_a>] <node_name_b> [<chance_b>] [<node_name_N> [<chance_N>]] ...`](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 [<axis1> [<axis2>]] <length>`](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 <command_a> <command_b> ....`](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/master/Chat-Command-Reference.md#multi-command_a-command_b-command_c-)
- [`//many <times> <command>`](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/master/Chat-Command-Reference.md#many-times-command) _(new in v1.9)_

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

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

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

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

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

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

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

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

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