From 653864be994734783be2dd76d37237d49cfb09db Mon Sep 17 00:00:00 2001 From: Starbeamrainbowlabs Date: Mon, 11 Oct 2021 02:41:45 +0100 Subject: [PATCH] Start working on //copy, but it's not finished yet. We need to merge @VorTechnix's branch in first to gain access to advanced axis parsing functions before we can complete it. For this reason, the command registration for //copy is currently commented out. --- worldeditadditions/init.lua | 2 + worldeditadditions/lib/copy.lua | 47 ++++++++++++++++ worldeditadditions/utils/parse/axes.lua | 55 +++++++++++++++++++ worldeditadditions/utils/parse/init.lua | 4 +- worldeditadditions_commands/commands/copy.lua | 50 +++++++++++++++++ 5 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 worldeditadditions/lib/copy.lua create mode 100644 worldeditadditions/utils/parse/axes.lua create mode 100644 worldeditadditions_commands/commands/copy.lua diff --git a/worldeditadditions/init.lua b/worldeditadditions/init.lua index 2b50a0e..8dfe215 100644 --- a/worldeditadditions/init.lua +++ b/worldeditadditions/init.lua @@ -53,6 +53,8 @@ dofile(wea.modpath.."/lib/conv/conv.lua") dofile(wea.modpath.."/lib/erode/erode.lua") dofile(wea.modpath.."/lib/noise/init.lua") +dofile(wea.modpath.."/lib/copy.lua") + dofile(wea.modpath.."/lib/count.lua") dofile(wea.modpath.."/lib/bonemeal.lua") diff --git a/worldeditadditions/lib/copy.lua b/worldeditadditions/lib/copy.lua new file mode 100644 index 0000000..5bac439 --- /dev/null +++ b/worldeditadditions/lib/copy.lua @@ -0,0 +1,47 @@ +--- Copies a region to another location, potentially overwriting the exiting region. +-- @module worldeditadditions.copy + +local wea = worldeditadditions +local Vector3 = wea.Vector3 + +-- ██████ ██████ ██████ ██ ██ +-- ██ ██ ██ ██ ██ ██ ██ +-- ██ ██ ██ ██████ ████ +-- ██ ██ ██ ██ ██ +-- ██████ ██████ ██ ██ + +function worldeditadditions.count(source_pos1, source_pos2, target_pos1, target_pos2) + source_pos1, source_pos2 = Vector3.sort(source_pos1, source_pos2) + target_pos1, target_pos2 = Vector3.sort(target_pos1, target_pos2) + + local offset = source_pos1:subtract(target_pos1) + -- {source,target}_pos2 will always have the highest co-ordinates now + + -- Fetch the nodes in the source area + local manip_source, area_source = worldedit.manip_helpers.init(source_pos1, source_pos2) + local data_source = manip_source:get_data() + + -- Fetch a manip for the target area + local manip_target, area_target = worldedit.manip_helpers.init(target_pos1, target_pos2) + local data_target = manip_target:get_data() + + -- z y x is the preferred loop order (because CPU cache I'd guess, since then we're iterating linearly through the data array) + + for z = source_pos2.z, source_pos1.z, -1 do + for y = source_pos2.y, source_pos1.y, -1 do + for x = source_pos2.x, source_pos1.x, -1 do + local source = Vector3.new(x, y, z) + local source_i = area_source:index(x, y, z) + local target = source:subtract(offset) + local target_i = area_target:index(target.x, target.y, target.z) + + data_target[target_i] = data_source[source_i] + end + end + end + + -- Save the modified nodes back to disk & return + worldedit.manip_helpers.finish(manip_target, data_target) + + return true, worldedit.volume(target_pos1, target_pos2) +end diff --git a/worldeditadditions/utils/parse/axes.lua b/worldeditadditions/utils/parse/axes.lua new file mode 100644 index 0000000..9cb29ed --- /dev/null +++ b/worldeditadditions/utils/parse/axes.lua @@ -0,0 +1,55 @@ +local wea = worldeditadditions +local Vector3 = dofile(wea.modpath.."/utils/vector3.lua") +-- BUG: This does not exist yet - need to merge @VorTechnix's branch first to get it +-- TODO: Uncomment then once it's implemented +-- local parse_axis = dofile(wea.modpath.."/utils/axis.lua") + +--- Parses a token list of axes and counts into a Vector3. +-- For example, "x 4" would become { x = 4, y = 0, z = 0 }, and "? 4 -z 10" +-- might become { x = 4, y = 0, z = -10 }. +-- Note that the input here needs to be *pre split*. wea.split_shell is +-- recommended for this purpose. +-- Uses wea.parse.axis for parsing axis names. +-- @param token_list string[] A list of tokens to parse +-- @returns Vector3 A Vector3 generated from parsing out the input token list. +local function parse_axes(token_list) + local vector_result = wea.Vector3.new() + + if #token_list < 2 then + return false, "Error: Not enough arguments (at least 2 are required)" + end + + local state = "AXIS" + local current_axis = nil + local success + + for i,token in ipairs(token_list) do + if state == "AXIS" then + success, current_axis = parse_axis(token) + if not success then return success, current_axis end + state = "VALUE" + elseif state == "VALUE" then + + local offset_this = tonumber(token) + if not offset_this then + return false, "Error: Invalid count value for axis '"..current_axis.."'. Values may only be positive or negative integers." + end + + -- Handle negative axes + if current_axis:sub(1, 1) == "-" then + offset_this = -offset_this + current_axis = current_axis:sub(2, 2) + end + + vector_result[current_axis] = vector_result[current_axis] + offset_this + + state = "AXIS" + else + return false, "Error: Failed to parse input due to unknown state '"..tostring(state).."' (this is probably a bug - please report it!)" + end + end + + return vector_result +end + +return parse_axes diff --git a/worldeditadditions/utils/parse/init.lua b/worldeditadditions/utils/parse/init.lua index ae8d8b4..dc01104 100644 --- a/worldeditadditions/utils/parse/init.lua +++ b/worldeditadditions/utils/parse/init.lua @@ -4,7 +4,9 @@ -- ██ ██ ██ ██ ██ ██ ██ -- ██ ██ ██ ██ ██ ███████ ███████ -worldeditadditions.parse = {} +worldeditadditions.parse = { + axes = dofile(worldeditadditions.modpath.."/utils/parse/axes.lua") +} dofile(worldeditadditions.modpath.."/utils/parse/chance.lua") dofile(worldeditadditions.modpath.."/utils/parse/map.lua") diff --git a/worldeditadditions_commands/commands/copy.lua b/worldeditadditions_commands/commands/copy.lua new file mode 100644 index 0000000..4a0e1e3 --- /dev/null +++ b/worldeditadditions_commands/commands/copy.lua @@ -0,0 +1,50 @@ +local wea = worldeditadditions +-- ██████ ██████ ██████ ██ ██ +-- ██ ██ ██ ██ ██ ██ ██ +-- ██ ██ ██ ██████ ████ +-- ██ ██ ██ ██ ██ +-- ██████ ██████ ██ ██ +worldedit.register_command("copy", { -- TODO: Make this an override + params = " [ [...]]", + description = "Copies the defined region to another location - potentially on multiple axes at once.", + privs = { worldedit = true }, + require_pos = 2, + parse = function(params_text) + if not params_text then params_text = "" end + + local parts = wea.split_shell(params_text) + + local copy_offset = wea.parse.axes(parts) + + if copy_offset == wea.Vector3.new() then + return false, "Refusing to copy region a distance of 0 nodes" + end + + return true, copy_offset:floor() + end, + nodes_needed = function(name) + -- We don't actually modify anything, but without returning a + -- number here safe_region doesn't work + return worldedit.volume(worldedit.pos1[name], worldedit.pos2[name]) + end, + func = function(name, copy_offset) + local start_time = wea.get_ms_time() + + local source_pos1 = wea.Vector3.clone(worldedit.pos1[name]) + local source_pos2 = wea.Vector3.clone(worldedit.pos2[name]) + + local target_pos1 = source_pos1:add(copy_offset) + local target_pos2 = source_pos2:add(copy_offset) + + local success, nodes_modified = wea.copy( + source_pos1, source_pos2, + target_pos1, target_pos2 + ) + + local time_taken = wea.get_ms_time() - start_time + + + minetest.log("action", name.." used //copy from "..source_pos1.." - "..source_pos2.." to "..target_pos1.." - "..target_pos2..", modifying "..nodes_modified.." nodes in "..wea.format.human_time(time_taken)) + return true, nodes_modified.." nodes copied using offset "..copy_offset.." in "..wea.format.human_time(time_taken) + end +})