Compare commits

...

5 Commits

Author SHA1 Message Date
Starbeamrainbowlabs 9f8cb4d5da
//rotate: add comments on what needs doing to wrangle it into shape 2023-12-14 00:31:12 +00:00
Starbeamrainbowlabs 27aa3a9c8f
It works!! ....but the output seems off when non 90° increments
...probably due to the wiping and rotation overlapping
2023-12-13 23:20:32 +00:00
Starbeamrainbowlabs 7d29453699
plug in new //rotate+ logic
...but it doesn't work yet
currently it crashes with a variety of interesting and colourful error messages
working on debugging it now, but it's gonna take a moment
2023-12-13 23:05:00 +00:00
Starbeamrainbowlabs b92cc434db
core/run_command: be more robust in case of programming errors 2023-12-13 23:04:09 +00:00
Starbeamrainbowlabs 873ff4bef8
Bugfix: don't error out on //flora → //bonemeal alias if bonemeal mod isn't installed
Also add worldeditadditions_core.command_exists to check both WEA and WEW for whether a command exists or not
2023-12-13 22:15:27 +00:00
11 changed files with 102 additions and 27 deletions

View File

@ -11,6 +11,9 @@ Note to self: See the bottom of this file for the release template text.
- Added [`//nodeapply`](https://worldeditadditions.mooncarrot.space/Reference/#nodeapply), a generalisation of [`//airapply`](https://worldeditadditions.mooncarrot.space/Reference/#airapply) that works with a defined list of nodes. Check out [the reference](https://worldeditadditions.mooncarrot.space/Reference/#nodeapply) - it has some cool tricks to it! (thanks for suggesting, @kliv91 from the Discord server!)
- Added [`//ngroups`](https://worldeditadditions.mooncarrot.space/Reference/#ngroups), which lists the groups that a given node is a member of. Useful when paired with [`//nodeapply`](https://worldeditadditions.mooncarrot.space/Reference/#nodeapply)!
### Bugfixes and changes
- Don't warn on failed registration of `//flora` → [`//bonemeal`](https://worldeditadditions.mooncarrot.space/Reference/#bonemeal) if the `bonemeal` mod isn't installed (e.g. in MineClone2) - thanks @VorTechnix in #106
## v1.14.5: The multipoint update, hotfix 5 (1st August 2023)
- Fix a bug where creative players in survival couldn't punch out position markers

View File

@ -32,6 +32,7 @@ dofile(wea.modpath.."/lib/spiral_circle.lua")
dofile(wea.modpath.."/lib/dome.lua")
dofile(wea.modpath.."/lib/spline.lua")
dofile(wea.modpath.."/lib/revolve.lua")
dofile(wea.modpath.."/lib/rotate.lua")
dofile(wea.modpath.."/lib/conv/conv.lua")
dofile(wea.modpath.."/lib/erode/erode.lua")
dofile(wea.modpath.."/lib/noise/init.lua")

View File

@ -16,15 +16,20 @@ local function __compile_rotlist(rotlist)
--- 1: Construct a Vector3 to represent which axis we want to rotate on
local rotval = Vector3.new(0, 0, 0)
-- Assume that if it's a table, it's a Vector3 instance
if type(rot) == "table" then rotval = rot:clone() end
if rot.axis:find("x", 1, true) then rotval.x = 1
elseif rot.axis:find("y", 1, true) then rotval.y = 1
elseif rot.axis:find("z", 1, true) then rotval.z = 1 end
if rot.axis:sub(1, 1) == "-" then
rotval = rotval * -1
if type(rot) == "table" then
print("DEBUG:__compile_rotlist rot is talble, ROT", weac.inspect(rot))
rotval = rot.axis:clone()
else
-- Otherwise, treat it as a string
if rot.axis:find("x", 1, true) then rotval.x = 1
elseif rot.axis:find("y", 1, true) then rotval.y = 1
elseif rot.axis:find("z", 1, true) then rotval.z = 1 end
if rot.axis:sub(1, 1) == "-" then
rotval = rotval * -1
end
end
--- 2: Rotate & apply amount of rotation to apply in radians
return rotval * rot.rad
end)
@ -53,6 +58,7 @@ function worldeditadditions.rotate(pos1, pos2, origin, rotlist)
-- First, rotate the defined region to find the target region
local pos1_rot, pos2_rot = pos1:clone(), pos2:clone()
for i, rot in ipairs(rotlist_c) do
print("DEBUG origin", weac.inspect(origin), "pos1_rot", weac.inspect(pos1_rot), "pos2_rot", weac.inspect(pos2_rot), "rot", weac.inspect(rot))
pos1_rot = Vector3.rotate3d(origin, pos1_rot, rot)
pos2_rot = Vector3.rotate3d(origin, pos2_rot, rot)
end
@ -67,6 +73,9 @@ function worldeditadditions.rotate(pos1, pos2, origin, rotlist)
local manip_src, area_src = worldedit.manip_helpers.init(pos1, pos2)
local data_src = manip_src:get_data()
-- TODO: grab only an area at this point for dest and a blank target table. Then copy over to the real dest later to ensure consistency. This is important because we are dealing in (potentially) non-cardinal rectangles here
-- local area = VoxelArea:new({MinEdge=emerged_pos1, MaxEdge=emerged_pos2})
local manip_dest, area_dest = worldedit.manip_helpers.init(pos1_dstvm, pos2_dstvm)
local data_dest = manip_dest:get_data()
-- TODO: Also carry param2 along for the ride
@ -81,7 +90,7 @@ function worldeditadditions.rotate(pos1, pos2, origin, rotlist)
local cpos_dest = cpos_src:clone()
-- TODO: This is very inefficient. If we could use quaternions here to stack up the rotations, it would be much more efficient.
for i, rot in ipairs(rotlist) do
for i, rot in ipairs(rotlist_c) do
cpos_dest = Vector3.rotate3d(origin, cpos_dest, rot)
end

View File

@ -7,7 +7,10 @@ wea_c.register_alias("conv", "convolve")
wea_c.register_alias("naturalise", "layers")
wea_c.register_alias("naturalize", "layers")
wea_c.register_alias("flora", "bonemeal")
if wea_c.command_exists("/bonemeal") then
-- No need to log here, since we notify the server admin in the server logs in the dofile() for the main //bonemeal command
wea_c.register_alias("flora", "bonemeal")
end
-- Measure Tools
wea_c.register_alias("mcount", "count")

View File

@ -8,7 +8,7 @@ local Vector3 = wea_c.Vector3
-- ██ ██ ██ ██ ██ ██ ██ ██ ██
-- ██ ██ ██████ ██ ██ ██ ██ ███████
worldeditadditions_core.register_command("rotate", {
worldeditadditions_core.register_command("rotate+", {
params = "<axis> <degrees> [<axis> <degrees> ...] [origin|o [<pos_number>]]",
description = "Rotates the defined region arounnd the given axis by the given number of degrees. Angles are NOT limited to 90-degree increments. When multiple axes and angles are specified, these transformations are applied in order. If o [<pos_number>] is specified, then the specific position number (default: 3) is considered a custom rotation origin instead of the centre of the region. CAUTION: Rotating large areas of memory by 45° can be memory intensive!",
privs = { worldedit = true },
@ -17,6 +17,8 @@ worldeditadditions_core.register_command("rotate", {
if not params_text then params_text = "" end
local parts = wea_c.split_shell(params_text)
print("DEBUG:rotate/parse parts", wea_c.inspect(parts))
local mode_store
local mode = "AXIS"
local success, axis_next, angle
@ -27,7 +29,14 @@ worldeditadditions_core.register_command("rotate", {
for i,part in ipairs(parts) do
if part == "origin" or part == "o" then
mode_store = mode
mode = "ORIGIN"
-- If the NEXT item is a number, then parse it.
if i < #parts and tonumber(parts[i+1]) ~= nil then
mode = "ORIGIN"
else
-- If not, then default to pos3 and continue in the original mode
origin = 3
end
elseif mode == "ORIGIN" then
origin = tonumber(part)
if not origin or origin < 1 then
@ -38,7 +47,7 @@ worldeditadditions_core.register_command("rotate", {
mode = mode_store
mode_store = nil
elseif mode == "AXIS" then
axis_next = wea_c.parse.axis_rotation.axis_name(part)
success, axis_next = wea_c.parse.axes_rotation.axis_name(part)
if not success then return success, axis_next end
mode = "ANGLE"
elseif mode == "ANGLE" then
@ -75,21 +84,46 @@ worldeditadditions_core.register_command("rotate", {
end
end
print("DEBUG:rotate/parse ORIGIN", origin, "rotlist", wea_c.inspect(rotlist))
return true, origin, rotlist
end,
nodes_needed = function(name, times)
-- TODO: .......this is a good question, actually.
nodes_needed = function(name, origin, rotlist)
-- BUG: .......this is a good question, actually. This naïve is flawed, since if we rotate by e.g. 45° we could end up replacing more nodes than if we rotate by 90° increments. This is further complicated by the allowance of a custom point of origin.
return Vector3.volume(wea_c.pos.get1(name), wea_c.pos.get2(name)) * 2
end,
func = function(name, origin, rotlist)
local start_time = wea_c.get_ms_time()
-- TODO: Do rotation operation here.
-------------------------------------------------
local pos1, pos2 = wea_c.pos.get1(name), wea_c.pos.get2(name)
local pos_origin = nil
if type(origin) == "number" then
pos_origin = wea_c.pos.get(name, origin)
elseif type(origin) == "string" and origin == "__AUTO__" then
pos_origin = Vector3.mean(pos1, pos2)
end
if pos_origin == nil then
-- There's a very small chance that this could be a bug here if origin is (NOT type("number") and NOT type("string") and ~= "__AUTO__"), but this shouldn't happen because we constrain the output of the above parser. This means we can safely make this assumption here
return false, "Error: Failed to get origin point from position "..tostring(origin).." because it doesn't exist."
end
local success, stats = worldeditadditions.rotate(
pos1, pos2,
pos_origin,
rotlist
)
if not success then return success, stats end
-- TODO: Adjust the defined area to match the target here? Maybe make this optional somehow given the target may or may nor be axis-aligned
-------------------------------------------------
local time_taken = wea_c.get_ms_time() - start_time
-- TODO: Update logging below. This will obviously crash due to unknown variables right now.
minetest.log("action", name .. " used //rotate at "..pos1.." - "..pos2.." with origin "..origin..", replacing "..changed.." nodes in "..time_taken.."s")
return true, changed.." nodes replaced in "..wea_c.format.human_time(time_taken)
minetest.log("action", name .. " used //rotate at "..pos1.." - "..pos2.." with origin "..pos_origin..", rotating "..stats.count_rotated.." nodes in "..time_taken.."s")
return true, stats.count_rotated.." nodes rotated through "..tostring(#rotlist).." rotations in "..wea_c.format.human_time(time_taken)
end
})

View File

@ -38,6 +38,7 @@ dofile(wea_cmd.modpath.."/commands/count.lua")
dofile(wea_cmd.modpath.."/commands/sculpt.lua")
dofile(wea_cmd.modpath.."/commands/spline.lua")
dofile(wea_cmd.modpath.."/commands/revolve.lua")
dofile(wea_cmd.modpath.."/commands/rotate.lua")
-- Meta Commands
dofile(wea_cmd.modpath .. "/commands/meta/init.lua")

View File

@ -0,0 +1,23 @@
--- WorldEditAdditions chat command registration
-- @namespace worldeditadditions_core
local wea_c = worldeditadditions_core
--- Returns whether a WorldEditAdditions (or WorldEdit) command exists with the given name.
-- Note that this does NOT check for general Minetest chat commands - only commands registered through WorldEditAdditions or WorldEdit, if WorldEdit is currently loaded - the eventual plan is to make it an optional dependency.
-- @param cmdname string The name of the command to check for. Remember to remove the first forward slash! In other words if you would normally type `//layers` in-game, then you'd call `worldeditadditions.command_exists("/layers")`.
-- @param only_wea bool If true, then only check for WorldEditAdditions commands and not commands from related compatible mods such as WorldEdit.
-- @returns bool Whether a WorldEdit/WorldEditAdditions command exists with the given name.
local function command_exists(cmdname, only_wea)
if only_wea == nil then only_wea = false end
if wea_c.registered_commands[cmdname] ~= nil then
return true
end
if only_wea == true then return false end
if worldedit.registered_commands[cmdname] ~= nil then
return true
end
return false
end
return command_exists

View File

@ -5,7 +5,7 @@
-- ██ ██ ███████ ██████ ██ ███████ ██ ███████ ██ ██
--- WorldEditAdditions chat command registration
-- @module worldeditadditions_core
-- @namespace worldeditadditions_core
local wea_c = worldeditadditions_core
local run_command = dofile(wea_c.modpath.."/core/run_command.lua")

View File

@ -39,7 +39,7 @@ local function run_command(cmdname, options, player_name, paramtext)
local parse_result = { options.parse(paramtext) }
local success = table.remove(parse_result, 1)
if not success then
worldedit.player_notify(player_name, parse_result[1] or "Invalid usage (no further error message was provided by the command. This is probably a bug.)")
worldedit.player_notify(player_name, tostring(parse_result[1]) or "Invalid usage (no further error message was provided by the command. This is probably a bug.)")
return false
end

View File

@ -61,6 +61,7 @@ wea_c.setting_handler = dofile(wea_c.modpath.."/utils/setting_handler.lua") -- A
wea_c.pos = dofile(modpath.."/core/pos.lua") -- AFTER EventEmitter
wea_c.register_command = dofile(modpath.."/core/register_command.lua")
wea_c.command_exists = dofile(modpath.."/core/command_exists.lua")
wea_c.fetch_command_def = dofile(modpath.."/core/fetch_command_def.lua")
wea_c.register_alias = dofile(modpath.."/core/register_alias.lua")
wea_c.entities = dofile(modpath.."/core/entities/init.lua") -- AFTER pos

View File

@ -21,7 +21,7 @@ function rot_axis_left(axis)
elseif axis.z == 1 or axis.z == -1 then
axis.x, axis.z = -axis.z, 0
end
return axis -- CAUDION, this function mutates!
return axis -- CAUTION, this function mutates!
end
--- Parses an axis name into a string.
@ -40,12 +40,12 @@ local function parse_rotation_axis_name(str, player)
-- At most ONE of these cases is true at a time.
-- Even if it were possible to handle more than one (which it isn't without quaternions which aren't used in the backend), we would have an undefined ordering problem with the application of such rotations. Rotations ≠ translations in this case!
if str:find("x", 1, true) then rotval.x = 1
elseif str:find("y", 1, true) then rotval.y = 1
elseif str:find("z", 1, true) then rotval.z = 1
elseif str:find("left", 1, true) then rotval.z = -1
if str:find("x", 1, true) then vector.x = 1
elseif str:find("y", 1, true) then vector.y = 1
elseif str:find("z", 1, true) then vector.z = 1
elseif str:find("left", 1, true) then vector.z = -1
elseif str:find("right", 1, true)
or str:find("yaw") then rotval.z = 1
or str:find("yaw") then vector.z = 1
elseif type(player) ~= "nil" then
local player_rotation_h = calc_rotation_text(player:get_look_horizontal())