From ffdd1b65b37c9083272c3d1bd841144bee196c91 Mon Sep 17 00:00:00 2001 From: Starbeamrainbowlabs Date: Sat, 25 May 2024 14:45:56 +0100 Subject: [PATCH] Implement //set+ This is on the road to //orient and later stair/etc support in //rotate :D --- CHANGELOG.md | 5 ++ worldeditadditions/init.lua | 1 + worldeditadditions/lib/orient.lua | 51 ++++++++++++ worldeditadditions/lib/set.lua | 79 +++++++++++++++++++ worldeditadditions_commands/commands/set.lua | 83 ++++++++++++++++++++ worldeditadditions_commands/init.lua | 1 + worldeditadditions_core/core/pos.lua | 14 ++++ worldeditadditions_core/utils/param2.lua | 32 ++++++++ 8 files changed, 266 insertions(+) create mode 100644 worldeditadditions/lib/orient.lua create mode 100644 worldeditadditions/lib/set.lua create mode 100644 worldeditadditions_commands/commands/set.lua create mode 100644 worldeditadditions_core/utils/param2.lua diff --git a/CHANGELOG.md b/CHANGELOG.md index ca7867d..0bef8ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,11 +13,16 @@ Note to self: See the bottom of this file for the release template text. - Added [`//rotate+`](https://worldeditadditions.mooncarrot.space/Reference/#rotate) to rotate regions through arbitrary series of potentially non-axis-aligned rotations. **Does not support slabs/stairs yet,** but this is on the todo list! - Added [`//speed`](https://worldeditadditions.mooncarrot.space/Reference/#rotate) to adjust your own movement speed - Also added an associated [movement speed adjustment tool](https://worldeditadditions.mooncarrot.space/Reference/#movement), which looks like this: ![A picture of the move speed adjustment tool. It looks like a monarch butterfly.](https://raw.githubusercontent.com/sbrl/Minetest-WorldEditAdditions/dev/worldeditadditions_farwand/textures/worldeditadditions_movement.png) +- Added [`//set+`](https://worldeditadditions.mooncarrot.space/Reference/#set) for setting nodes and param2/light levels quickly. + - NOTE TO SELF: Setting light values doesn't appear to be working very well for some reason ### 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 - Improve documentation of [`//noise2d`](https://worldeditadditions.mooncarrot.space/Reference/#noise2d). If it still doesn't make sense, please let me know. It's a complicated command that needs reworking a bit to be easier to use. +### Lua API changes +- Add `core.pos.get12(player_name, sort=false)` + ## 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 diff --git a/worldeditadditions/init.lua b/worldeditadditions/init.lua index 09afb3c..06b3088 100644 --- a/worldeditadditions/init.lua +++ b/worldeditadditions/init.lua @@ -41,6 +41,7 @@ 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/set.lua") dofile(wea.modpath.."/lib/conv/conv.lua") dofile(wea.modpath.."/lib/erode/erode.lua") dofile(wea.modpath.."/lib/noise/init.lua") diff --git a/worldeditadditions/lib/orient.lua b/worldeditadditions/lib/orient.lua new file mode 100644 index 0000000..6a80517 --- /dev/null +++ b/worldeditadditions/lib/orient.lua @@ -0,0 +1,51 @@ +local weac = worldeditadditions_core +local Vector3 = weac.Vector3 + +--- +-- @module worldeditadditions + + + +-- ██████ ██████ ██ ███████ ███ ██ ████████ +-- ██ ██ ██ ██ ██ ██ ████ ██ ██ +-- ██ ██ ██████ ██ █████ ██ ██ ██ ██ +-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +-- ██████ ██ ██ ██ ███████ ██ ████ ██ + + + +--- Re-orients the nodes in the given region around a given origin point using a set of rotations. +-- TODO Learn quaternions and make this more effiient. +-- @param pos1 Vector3 Position 1 of the region to orient nodes in. +-- @param pos2 Vector3 Position 2 of the region to orient nodes in. +-- @param rotlist table<{axis: string, rad: number}> The list of rotations. Rotations will be processed in order. Each rotation is a table with a SINGLE axis as a string (x, y, z, -x, -y, or -z; the axis parameter), and an amount in radians to rotate by (the rad parameter). +-- @returns bool,string|table<{changed: number}> A success boolean (true == success; false == failure), followed by either an error message as a string if success == false or a table of statistics if success == true. +-- +-- Currently the only parameter in the statistics table is changed, which is a number representing the number of nodes that were rotated. +-- +-- This is NOT NECESSARILY the number of nodes in the target region..... since rotations and roundings mean the target area the source region was rotated into could have slightly more or less nodes than the source region. +function worldeditadditions.orient(pos1, pos2, rotlist) + pos1, pos2 = Vector3.sort(pos1, pos2) + + --- 1: Compile the rotation list + local rotlist_c = weac.rotation.rotlist_compile(rotlist) + + --- 2: Fetch the nodes in the specified area + local manip, area = worldedit.manip_helpers.init(pos1, pos2) + local data = manip:get_data() + + local stats = { + count = 0 + } + + local param2_cache = {} + + for i in area:iterp(pos1, pos2) do + -- data[i] + + stats.count = stats.count + 1 + end + + --- 8: Return + return true, stats +end diff --git a/worldeditadditions/lib/set.lua b/worldeditadditions/lib/set.lua new file mode 100644 index 0000000..1b5f8d3 --- /dev/null +++ b/worldeditadditions/lib/set.lua @@ -0,0 +1,79 @@ +local wea_c = worldeditadditions_core +local Vector3 = wea_c.Vector3 + +--- +-- @module worldeditadditions + + + +-- ███████ ███████ ████████ +-- ██ ██ ██ +-- ███████ █████ ██ +-- ██ ██ ██ +-- ███████ ███████ ██ + +--- Sets the given parameter to the given value. +-- This function would pair well with worldeditadditions.nodeapply. +-- @param pos1 Vector3 Position 1 of the define region to operate on. +-- @param pos2 Vector3 Position 2 of the define region to operate on. +-- @param param string="param|param2" The name of the parameter to set. Currently possible values: +-- - **`param`:** Param1, aka the node id. +-- - **`param2`:** The supplementary parameter that each node has. See also . The node type is set by the mod or game that provides each node in question. +-- - **`light`:** Sets the light value of all nodes in the defined region. +-- @param value string|number The value to set the given parameter to. If `param` is set to "param" and `value` is a `string`, then `value` is converted into a number by calling `minetest.get_content_id()`. +-- @returns bool,table|string true,statistics_table OR false,error_message. +function worldeditadditions.set(pos1, pos2, mode, value) + if mode ~= "param" and mode ~= "param2" and mode ~= "light" then + return false, "Error: Unknown parameter type "..tostring(mode)..". Supported values: param, param2." + end + + pos1, pos2 = Vector3.sort(pos1, pos2) + -- pos2 will always have the highest co-ordinates now + + print("SET mode", mode, "value", value) + + local setvalue = value + if mode == "param" and type(setvalue) == "string" then + setvalue = minetest.get_content_id(setvalue) + print("SET TRANSFORM setvalue TO", setvalue) + end + + print("SET setvalue", setvalue) + + -- Initialise statistics + local stats = { changed = 0 } + + -- Fetch the nodes in the specified area + local manip, area = worldedit.manip_helpers.init(pos1, pos2) + local data = nil + if mode == "param" then + data = manip:get_data() + elseif mode == "param2" then + data = manip:get_param2_data() + elseif mode == "light" then + -- Shortcut! + manip:set_lighting({ day = setvalue, night = setvalue }, pos1, pos2) + manip:write_to_map(false) + manip:update_map() + return true, stats + end + + for i in area:iterp(pos1, pos2) do + data[i] = setvalue + stats.changed = stats.changed + 1 + end + + if mode == "param" then + manip:set_data(data) + else + manip:set_param2_data(data) + end + + + -- Save the modified nodes back to disk & return + -- Can't use worldedit.manip_helpers.finish 'cause of dynamic param/light setting + manip:write_to_map() + manip:update_map() + + return true, stats +end diff --git a/worldeditadditions_commands/commands/set.lua b/worldeditadditions_commands/commands/set.lua new file mode 100644 index 0000000..70e9986 --- /dev/null +++ b/worldeditadditions_commands/commands/set.lua @@ -0,0 +1,83 @@ +local wea = worldeditadditions +local core = worldeditadditions_core +local Vector3 = core.Vector3 + +-- ███████ ███████ ████████ █ +-- ██ ██ ██ █ +-- ███████ █████ ██ ████████ +-- ██ ██ ██ █ +-- ███████ ███████ ██ █ +core.register_command("set+", { + params = + "[param|param2|p2|light|l] ", + description = + "Sets the node, param2, or light level to a fixed value in the defined region. Defaults to setting the node. If param2/p2 is specified, the param2 value associated with nodes is set instead. If light/l is specified, the light level is set.", + privs = { worldedit = true }, + require_pos = 2, + parse = function(params_text) + if not params_text or params_text == "" then + return false, "Error: No arguments specified" + end + + local parts = core.split_shell(params_text) + print("parts", core.inspect(parts)) + + local mode = "param" + local value = nil + + local possible_modes = { "param", "p", "param2", "p2", "light", "l" } + + if core.table.contains(possible_modes, parts[1]) then + mode = parts[1] + table.remove(parts, 1) + end + value = table.concat(parts, " ") + + print("mode", core.inspect(mode)) + print("value", core.inspect(value)) + + -- Normalise mode + if mode == "p" then mode = "param" + elseif mode == "p2" then mode = "param2" + elseif mode == "l" then mode = "light" end + + if mode == "param" then + local val_raw = value + value = worldedit.normalize_nodename(value) + if not value then return false, tostring(val_raw).." could not be normalised into a valid node name, and the mode was set to 'param'." end + else + local val_raw = value + value = tonumber(value) + if not value then return false, tostring(val_raw).." does not appear to be a valid number." end + value = math.floor(value) + end + + print("AFTER mode", core.inspect(mode)) + print("AFTER value", core.inspect(value)) + + return true, mode, value + end, + nodes_needed = function(name) -- target_node, target_node_chance, replace_nodes + return worldedit.volume(worldedit.pos1[name], worldedit.pos2[name]) + end, + func = function(name, mode, value) + local start_time = core.get_ms_time() + local pos1, pos2 = core.pos.get12(name) + + local success, stats = wea.set( + worldedit.pos1[name], worldedit.pos2[name], + mode, + value + ) + if not success then return success, stats end + + local time_taken = core.get_ms_time() - start_time + + + minetest.log("action", + name .. + " used //set+ at "..pos1.." - "..pos2..", affecting "..stats.changed.." nodes in "..time_taken.."s") + + return true, stats.changed.." nodes updated in "..core.format.human_time(time_taken) + end +}) diff --git a/worldeditadditions_commands/init.lua b/worldeditadditions_commands/init.lua index fa57a68..2927b06 100644 --- a/worldeditadditions_commands/init.lua +++ b/worldeditadditions_commands/init.lua @@ -39,6 +39,7 @@ 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") +dofile(wea_cmd.modpath.."/commands/set.lua") -- Meta Commands dofile(wea_cmd.modpath .. "/commands/meta/init.lua") diff --git a/worldeditadditions_core/core/pos.lua b/worldeditadditions_core/core/pos.lua index 40d6354..442fc57 100644 --- a/worldeditadditions_core/core/pos.lua +++ b/worldeditadditions_core/core/pos.lua @@ -133,6 +133,19 @@ local function get1(player_name) return get(player_name, 1) end -- @returns Vector3? The position requested, or nil if it doesn't exist. local function get2(player_name) return get(player_name, 2) end +--- Convenience function that returns pos1 and pos2 with the coordinates sorted for the given player. +-- @param player_name string The name of the player to fetch the position for. +-- @param sort=false bool If true, the pos1 and pos2 are run through Vector3.sort() automatically. +-- @returns Vector3?,Vector3 The positions requested, or nil if either of them don't exist. +local function get12(player_name, sort) + if sort == nil then sort = false end + local pos1 = get(player_name, 1) + local pos2 = get(player_name, 2) + if pos1 == nil or pos2 == nil then return nil, nil end + if sort then pos1, pos2 = Vector3.sort(pos1, pos2) end + return pos1, pos2 +end + --- Gets a list of all the positions for the given player. -- @param player_name string The name of the player to fetch the position for. -- @returns Vector3[] A list of positions for the given player. @@ -296,6 +309,7 @@ anchor = wea_c.EventEmitter.new({ get = get, get1 = get1, get2 = get2, + get12 = get12, get_all = get_all, get_bounds = get_bounds, count = count, diff --git a/worldeditadditions_core/utils/param2.lua b/worldeditadditions_core/utils/param2.lua new file mode 100644 index 0000000..de0ca70 --- /dev/null +++ b/worldeditadditions_core/utils/param2.lua @@ -0,0 +1,32 @@ + +--- +-- @module worldeditadditions_core.param2 + +-- //set +-- //set param2|p2 + + +local function param2_to_dir(param2_type, param2) + if param2_type == "" then + return { + + } + else + return nil + end +end + +local function dir_to_param2(dir) + +end + +local function orient(param2, rotlist) + +end + + + + +return { + orient = orient +} \ No newline at end of file