\r
local count = 0\r
\r
- --- TODO: This could be shortened by checking `inverse` in the loop,\r
- -- but that would have a speed penalty. Is the penalty big enough\r
- -- to matter?\r
if not inverse then\r
for i in area:iterp(pos1, pos2) do\r
if data[i] == search_id then\r
function worldedit.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 when negative to avoid corruption.\r
- -- FIXME: Lots of code duplication here.\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 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
- 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 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
+ 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
- return worldedit.volume(pos1, pos2)\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
---- Copies a region by offset vector `off`.\r
--- @param pos1\r
--- @param pos2\r
--- @param off\r
--- @return The number of nodes copied.\r
-function worldedit.copy2(pos1, pos2, off)\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
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 newpos = vector.add(pos, off) -- Calculate new position\r
- set_node(newpos, node) -- Copy node to new position\r
- get_meta(newpos):from_table(meta) -- Set metadata of new 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
return worldedit.volume(pos1, pos2)\r
end\r
\r
+--- Copies a region by offset vector `off`.\r
+-- @param pos1\r
+-- @param pos2\r
+-- @param off\r
+-- @return The number of nodes copied.\r
+function worldedit.copy2(pos1, pos2, off)\r
+ local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
+\r
+ local src_manip, src_area = mh.init(pos1, pos2)\r
+ local src_stride = {x=1, y=src_area.ystride, z=src_area.zstride}\r
+ local src_offset = vector.subtract(pos1, src_area.MinEdge)\r
+\r
+ local dpos1 = vector.add(pos1, off)\r
+ local dpos2 = vector.add(pos2, off)\r
+ local dim = vector.add(vector.subtract(pos2, pos1), 1)\r
+\r
+ local dst_manip, dst_area = mh.init(dpos1, dpos2)\r
+ local dst_stride = {x=1, y=dst_area.ystride, z=dst_area.zstride}\r
+ local dst_offset = vector.subtract(dpos1, dst_area.MinEdge)\r
+\r
+ local function do_copy(src_data, dst_data)\r
+ for z = 0, dim.z-1 do\r
+ local src_index_z = (src_offset.z + z) * src_stride.z + 1 -- +1 for 1-based indexing\r
+ local dst_index_z = (dst_offset.z + z) * dst_stride.z + 1\r
+ for y = 0, dim.y-1 do\r
+ local src_index_y = src_index_z + (src_offset.y + y) * src_stride.y\r
+ local dst_index_y = dst_index_z + (dst_offset.y + y) * dst_stride.y\r
+ -- Copy entire row at once\r
+ local src_index_x = src_index_y + src_offset.x\r
+ local dst_index_x = dst_index_y + dst_offset.x\r
+ for x = 0, dim.x-1 do\r
+ dst_data[dst_index_x + x] = src_data[src_index_x + x]\r
+ end\r
+ end\r
+ end\r
+ end\r
+\r
+ -- Copy node data\r
+ local src_data = src_manip:get_data()\r
+ local dst_data = dst_manip:get_data()\r
+ do_copy(src_data, dst_data)\r
+ dst_manip:set_data(dst_data)\r
+\r
+ -- Copy param1\r
+ src_manip:get_light_data(src_data)\r
+ dst_manip:get_light_data(dst_data)\r
+ do_copy(src_data, dst_data)\r
+ dst_manip:set_light_data(dst_data)\r
+\r
+ -- Copy param2\r
+ src_manip:get_param2_data(src_data)\r
+ dst_manip:get_param2_data(dst_data)\r
+ do_copy(src_data, dst_data)\r
+ dst_manip:set_param2_data(dst_data)\r
+\r
+ mh.finish(dst_manip)\r
+ src_data = nil\r
+ dst_data = nil\r
+\r
+ -- Copy metadata\r
+ local get_meta = minetest.get_meta\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
+ 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
+\r
+ return worldedit.volume(pos1, pos2)\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