]> git.lizzy.rs Git - worldedit.git/blobdiff - worldedit/manipulations.lua
Make object right-click work with wand
[worldedit.git] / worldedit / manipulations.lua
index 25aa14110f0cbb63fad4edf64cf0ac93fcbc1401..01fb99a3ac195dbf383ae97aa8db8ee1c1c14b67 100644 (file)
@@ -152,57 +152,21 @@ end
 function worldedit.copy(pos1, pos2, axis, amount)\r
        local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
 \r
-       local dim = vector.add(vector.subtract(pos2, pos1), 1)\r
-       if amount > 0 and amount < dim[axis] then\r
-               -- Source and destination region are overlapping and moving needs to\r
-               -- happen in reverse.\r
-               -- FIXME: I can't be bothered, so just defer to the legacy code for now.\r
-               return worldedit.legacy_copy(pos1, pos2, axis, amount)\r
-       end\r
+       -- Decide if we need to copy stuff backwards (only applies to metadata)\r
+       local backwards = amount > 0 and amount < (pos2[axis] - pos1[axis] + 1)\r
 \r
        local off = {x=0, y=0, z=0}\r
        off[axis] = amount\r
-       return worldedit.copy2(pos1, pos2, off)\r
-end\r
-\r
--- This function is not offical part of the API and may be removed at any time.\r
-function worldedit.legacy_copy(pos1, pos2, axis, amount)\r
-       local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
-\r
-       worldedit.keep_loaded(pos1, pos2)\r
-\r
-       local get_node, get_meta, set_node = minetest.get_node,\r
-                       minetest.get_meta, minetest.set_node\r
-       -- Copy things backwards\r
-       local pos = {}\r
-       pos.x = pos2.x\r
-       while pos.x >= pos1.x do\r
-               pos.y = pos2.y\r
-               while pos.y >= pos1.y do\r
-                       pos.z = pos2.z\r
-                       while pos.z >= pos1.z do\r
-                               local node = get_node(pos) -- Obtain current node\r
-                               local meta = get_meta(pos):to_table() -- Get meta of current node\r
-                               local value = pos[axis] -- Store current position\r
-                               pos[axis] = value + amount -- Move along axis\r
-                               set_node(pos, node) -- Copy node to new position\r
-                               get_meta(pos):from_table(meta) -- Set metadata of new node\r
-                               pos[axis] = value -- Restore old position\r
-                               pos.z = pos.z - 1\r
-                       end\r
-                       pos.y = pos.y - 1\r
-               end\r
-               pos.x = pos.x - 1\r
-       end\r
-       return worldedit.volume(pos1, pos2)\r
+       return worldedit.copy2(pos1, pos2, off, backwards)\r
 end\r
 \r
 --- Copies a region by offset vector `off`.\r
 -- @param pos1\r
 -- @param pos2\r
 -- @param off\r
+-- @param meta_backwards (not officially part of API)\r
 -- @return The number of nodes copied.\r
-function worldedit.copy2(pos1, pos2, off)\r
+function worldedit.copy2(pos1, pos2, off, meta_backwards)\r
        local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
 \r
        local src_manip, src_area = mh.init(pos1, pos2)\r
@@ -258,6 +222,18 @@ function worldedit.copy2(pos1, pos2, off)
 \r
        -- Copy metadata\r
        local get_meta = minetest.get_meta\r
+       if meta_backwards then\r
+       for z = dim.z-1, 0, -1 do\r
+               for y = dim.y-1, 0, -1 do\r
+                       for x = dim.x-1, 0, -1 do\r
+                               local pos = {x=pos1.x+x, y=pos1.y+y, z=pos1.z+z}\r
+                               local meta = get_meta(pos):to_table()\r
+                               pos = vector.add(pos, off)\r
+                               get_meta(pos):from_table(meta)\r
+                       end\r
+               end\r
+       end\r
+       else\r
        for z = 0, dim.z-1 do\r
                for y = 0, dim.y-1 do\r
                        for x = 0, dim.x-1 do\r
@@ -268,90 +244,71 @@ function worldedit.copy2(pos1, pos2, off)
                        end\r
                end\r
        end\r
+       end\r
 \r
        return worldedit.volume(pos1, pos2)\r
 end\r
 \r
+--- Deletes all node metadata in the region\r
+-- @param pos1\r
+-- @param pos2\r
+-- @return The number of nodes that had their meta deleted.\r
+function worldedit.delete_meta(pos1, pos2)\r
+       local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
+\r
+       local meta_positions = minetest.find_nodes_with_meta(pos1, pos2)\r
+       local get_meta = minetest.get_meta\r
+       for _, pos in ipairs(meta_positions) do\r
+               get_meta(pos):from_table(nil)\r
+       end\r
+\r
+       return #meta_positions\r
+end\r
+\r
 --- Moves a region along `axis` by `amount` nodes.\r
 -- @return The number of nodes moved.\r
 function worldedit.move(pos1, pos2, axis, amount)\r
        local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
 \r
        local dim = vector.add(vector.subtract(pos2, pos1), 1)\r
-       if math.abs(amount) < dim[axis] then\r
-               -- Source and destination region are overlapping\r
-               -- FIXME: I can't be bothered, so just defer to the legacy code for now.\r
-               return worldedit.legacy_move(pos1, pos2, axis, amount)\r
+       local overlap = math.abs(amount) < dim[axis]\r
+       -- Decide if we need to copy metadata backwards\r
+       local backwards = overlap and amount > 0\r
+\r
+       local function nuke_area(my_off, my_dim)\r
+               if my_dim.x == 0 or my_dim.y == 0 or my_dim.z == 0 then\r
+                       return\r
+               end\r
+               local my_pos1 = vector.add(pos1, my_off)\r
+               local my_pos2 = vector.subtract(vector.add(my_pos1, my_dim), 1)\r
+               worldedit.set(my_pos1, my_pos2, "air")\r
+               worldedit.delete_meta(my_pos1, my_pos2)\r
        end\r
 \r
        -- Copy stuff to new location\r
        local off = {x=0, y=0, z=0}\r
        off[axis] = amount\r
-       worldedit.copy2(pos1, pos2, off)\r
+       worldedit.copy2(pos1, pos2, off, backwards)\r
        -- Nuke old area\r
-       worldedit.set(pos1, pos2, "air")\r
-\r
-       return worldedit.volume(pos1, pos2)\r
-end\r
-\r
--- This function is not offical part of the API and may be removed at any time.\r
-function worldedit.legacy_move(pos1, pos2, axis, amount)\r
-       local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
-\r
-       worldedit.keep_loaded(pos1, pos2)\r
-\r
-       local get_node, get_meta, set_node, remove_node = minetest.get_node,\r
-                       minetest.get_meta, minetest.set_node, minetest.remove_node\r
-       -- Copy things backwards when negative to avoid corruption.\r
-       if amount < 0 then\r
-               local pos = {}\r
-               pos.x = pos1.x\r
-               while pos.x <= pos2.x do\r
-                       pos.y = pos1.y\r
-                       while pos.y <= pos2.y do\r
-                               pos.z = pos1.z\r
-                               while pos.z <= pos2.z do\r
-                                       local node = get_node(pos) -- Obtain current node\r
-                                       local meta = get_meta(pos):to_table() -- Get metadata of current node\r
-                                       remove_node(pos) -- Remove current node\r
-                                       local value = pos[axis] -- Store current position\r
-                                       pos[axis] = value + amount -- Move along axis\r
-                                       set_node(pos, node) -- Move node to new position\r
-                                       get_meta(pos):from_table(meta) -- Set metadata of new node\r
-                                       pos[axis] = value -- Restore old position\r
-                                       pos.z = pos.z + 1\r
-                               end\r
-                               pos.y = pos.y + 1\r
-                       end\r
-                       pos.x = pos.x + 1\r
-               end\r
+       if not overlap then\r
+               nuke_area({x=0, y=0, z=0}, dim)\r
        else\r
-               local pos = {}\r
-               pos.x = pos2.x\r
-               while pos.x >= pos1.x do\r
-                       pos.y = pos2.y\r
-                       while pos.y >= pos1.y do\r
-                               pos.z = pos2.z\r
-                               while pos.z >= pos1.z do\r
-                                       local node = get_node(pos) -- Obtain current node\r
-                                       local meta = get_meta(pos):to_table() -- Get metadata of current node\r
-                                       remove_node(pos) -- Remove current node\r
-                                       local value = pos[axis] -- Store current position\r
-                                       pos[axis] = value + amount -- Move along axis\r
-                                       set_node(pos, node) -- Move node to new position\r
-                                       get_meta(pos):from_table(meta) -- Set metadata of new node\r
-                                       pos[axis] = value -- Restore old position\r
-                                       pos.z = pos.z - 1\r
-                               end\r
-                               pos.y = pos.y - 1\r
-                       end\r
-                       pos.x = pos.x - 1\r
+               -- Source and destination region are overlapping, which means we can't\r
+               -- blindly delete the [pos1, pos2] area\r
+               local leftover = vector.new(dim) -- size of the leftover slice\r
+               leftover[axis] = math.abs(amount)\r
+               if amount > 0 then\r
+                       nuke_area({x=0, y=0, z=0}, leftover)\r
+               else\r
+                       local top = {x=0, y=0, z=0} -- offset of the leftover slice from pos1\r
+                       top[axis] = dim[axis] - 1\r
+                       nuke_area(top, leftover)\r
                end\r
        end\r
+\r
        return worldedit.volume(pos1, pos2)\r
 end\r
 \r
-\r
 --- Duplicates a region along `axis` `amount` times.\r
 -- Stacking is spread across server steps.\r
 -- @param pos1\r