summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnthony Zhang <azhang9@gmail.com>2013-07-21 16:54:25 -0400
committerAnthony Zhang <azhang9@gmail.com>2013-07-21 16:54:25 -0400
commit8ebf9d3c2ae63374c5501be0660b0d57204bd335 (patch)
tree6c943fc82110d45a9e330f8e7f6a0a5452e8110c
parentac5e801834245bcf93f720d290a36b09a2527576 (diff)
Super duper VoxelManipulator speedups to nearly every API function, and plus support for unloaded areas. Still in progress. Also, fix //allocate for very large schematics.
-rw-r--r--WorldEdit API.md2
-rw-r--r--worldedit/code.lua4
-rw-r--r--worldedit/init.lua2
-rw-r--r--worldedit/manipulations.lua164
-rw-r--r--worldedit/primitives.lua188
-rw-r--r--worldedit/queue.lua27
-rw-r--r--worldedit/serialization.lua25
-rw-r--r--worldedit/visualization.lua18
8 files changed, 285 insertions, 145 deletions
diff --git a/WorldEdit API.md b/WorldEdit API.md
index 12320f6..1006932 100644
--- a/WorldEdit API.md
+++ b/WorldEdit API.md
@@ -208,6 +208,6 @@ Returns an error if the code fails or nil otherwise.
### error = worldedit.luatransform(pos1, pos2, code)
-Executes `code` as a Lua chunk in the global namespace with the variable pos available, for each node in a region defined by positions `pos1` and `pos2`.
+Executes `code` as a Lua chunk in the global namespace with the variable `pos` available, for each node in a region defined by positions `pos1` and `pos2`.
Returns an error if the code fails or nil otherwise. \ No newline at end of file
diff --git a/worldedit/code.lua b/worldedit/code.lua
index 366688e..8e2d362 100644
--- a/worldedit/code.lua
+++ b/worldedit/code.lua
@@ -24,6 +24,10 @@ worldedit.luatransform = function(pos1, pos2, code)
end
local operation = factory()
+ --make area stay loaded
+ local manip = minetest.get_voxel_manip()
+ manip:read_from_map(pos1, pos2)
+
local pos = {x=pos1.x, y=0, z=0}
while pos.x <= pos2.x do
pos.y = pos1.y
diff --git a/worldedit/init.lua b/worldedit/init.lua
index 11b90e9..f41d740 100644
--- a/worldedit/init.lua
+++ b/worldedit/init.lua
@@ -2,7 +2,7 @@ local path = minetest.get_modpath(minetest.get_current_modname())
local loadmodule = function(path)
return pcall(function()
- dofile(path)
+ return dofile(path)
end)
end
diff --git a/worldedit/manipulations.lua b/worldedit/manipulations.lua
index b92296a..2180cb6 100644
--- a/worldedit/manipulations.lua
+++ b/worldedit/manipulations.lua
@@ -3,6 +3,7 @@ local minetest = minetest --local copy of global
--wip: test the entire API again to make sure it works
--wip: remove env parameter where no longer needed in chat commands module
+--wip: fix the queue
--modifies positions `pos1` and `pos2` so that each component of `pos1` is less than or equal to its corresponding conent of `pos2`, returning two new positions
worldedit.sort_pos = function(pos1, pos2)
@@ -32,12 +33,19 @@ worldedit.set = function(pos1, pos2, nodename)
--set up voxel manipulator
local manip = minetest.get_voxel_manip()
- manip:read_from_map(pos1, pos2)
+ local emerged_pos1, emerged_pos2 = manip:read_from_map(pos1, pos2)
+ local area = VoxelArea:new({MinEdge=emerged_pos1, MaxEdge=emerged_pos2})
- --fill nodes table with node to be set
+ --fill emerged area with ignore
local nodes = {}
+ local ignore = minetest.get_content_id("ignore")
+ for i = 1, worldedit.volume(emerged_pos1, emerged_pos2) do
+ nodes[i] = ignore
+ end
+
+ --fill selected area with node
local node_id = minetest.get_content_id(nodename)
- for i = 1, (pos2.x - pos1.x) * (pos2.y - pos1.y) * (pos2.z - pos1.z) do
+ for i in area:iterp(pos1, pos2) do
nodes[i] = node_id
end
@@ -53,39 +61,55 @@ end
worldedit.replace = function(pos1, pos2, searchnode, replacenode)
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
- local node = {name=replacenode}
- local add_node = minetest.add_node
- local nodes = minetest.find_nodes_in_area(pos1, pos2, searchnode)
- for _, pos in ipairs(nodes) do
- add_node(pos, node)
+ --set up voxel manipulator
+ local manip = minetest.get_voxel_manip()
+ local emerged_pos1, emerged_pos2 = manip:read_from_map(pos1, pos2)
+ local area = VoxelArea:new({MinEdge=emerged_pos1, MaxEdge=emerged_pos2})
+
+ local nodes = manip:get_data()
+ local searchnode_id = minetest.get_content_id(searchnode)
+ local replacenode_id = minetest.get_content_id(replacenode)
+ local count = 0
+ for i in area:iterp(pos1, pos2) do --replace searchnode with replacenode
+ if nodes[i] == searchnode_id then
+ nodes[i] = replacenode_id
+ count = count + 1
+ end
end
- return #nodes
+
+ --update map nodes
+ manip:set_data(nodes)
+ manip:write_to_map()
+ manip:update_map()
+
+ return count
end
--replaces all nodes other than `searchnode` with `replacenode` in a region defined by positions `pos1` and `pos2`, returning the number of nodes replaced
-worldedit.replaceinverse = function(pos1, pos2, searchnode, replacenode) --wip: use voxelmanip get_data for this
+worldedit.replaceinverse = function(pos1, pos2, searchnode, replacenode)
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
- local pos = {x=pos1.x, y=0, z=0}
- local node = {name=replacenode}
- local get_node, add_node = minetest.get_node, minetest.add_node
+ --set up voxel manipulator
+ local manip = minetest.get_voxel_manip()
+ local emerged_pos1, emerged_pos2 = manip:read_from_map(pos1, pos2)
+ local area = VoxelArea:new({MinEdge=emerged_pos1, MaxEdge=emerged_pos2})
+
+ local nodes = manip:get_data()
+ local searchnode_id = minetest.get_content_id(searchnode)
+ local replacenode_id = minetest.get_content_id(replacenode)
local count = 0
- while pos.x <= pos2.x do
- pos.y = pos1.y
- while pos.y <= pos2.y do
- pos.z = pos1.z
- while pos.z <= pos2.z do
- local name = get_node(pos).name
- if name ~= "ignore" and name ~= searchnode then
- add_node(pos, node)
- count = count + 1
- end
- pos.z = pos.z + 1
- end
- pos.y = pos.y + 1
+ for i in area:iterp(pos1, pos2) do --replace anything that is not searchnode with replacenode
+ if nodes[i] ~= searchnode_id then
+ nodes[i] = replacenode_id
+ count = count + 1
end
- pos.x = pos.x + 1
end
+
+ --update map nodes
+ manip:set_data(nodes)
+ manip:write_to_map()
+ manip:update_map()
+
return count
end
@@ -94,7 +118,7 @@ worldedit.copy = function(pos1, pos2, axis, amount, env)
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
if env == nil then env = minetest.env end
- --wip: copy slice by slice using schematic method in the copy axis and transfer metadata in separate loop (and if the amount is greater than the length in the axis, copy whole thing at a time)
+ --wip: copy slice by slice using schematic method in the copy axis and transfer metadata in separate loop (and if the amount is greater than the length in the axis, copy whole thing at a time), use voxelmanip to keep area loaded
if amount < 0 then
local pos = {x=pos1.x, y=0, z=0}
while pos.x <= pos2.x do
@@ -144,7 +168,7 @@ worldedit.move = function(pos1, pos2, axis, amount, env)
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
if env == nil then env = minetest.env end
- --wip: move slice by slice using schematic method in the move axis and transfer metadata in separate loop (and if the amount is greater than the length in the axis, copy whole thing at a time and erase original after, using schematic method)
+ --wip: move slice by slice using schematic method in the move axis and transfer metadata in separate loop (and if the amount is greater than the length in the axis, copy whole thing at a time and erase original after, using schematic method), use voxelmanip to keep area loaded
if amount < 0 then
local pos = {x=pos1.x, y=0, z=0}
while pos.x <= pos2.x do
@@ -205,7 +229,7 @@ worldedit.stack = function(pos1, pos2, axis, count, env)
amount = amount + length
copy(pos1, pos2, axis, amount, env)
end
- return worldedit.volume(pos1, pos2)
+ return worldedit.volume(pos1, pos2) * count
end
--scales the region defined by positions `pos1` and `pos2` by an factor of positive integer `factor` with `pos1` as the origin, returning the number of nodes scaled, the new scaled position 1, and the new scaled position 2
@@ -216,14 +240,20 @@ worldedit.scale = function(pos1, pos2, factor)
local get_node, get_meta, place_schematic = minetest.get_node, minetest.get_meta, minetest.place_schematic
local placeholder_node = {name="", param1=0, param2=0}
local nodes = {}
- for i = 1, size ^ 3 do
+ for i = 1, factor ^ 3 do
nodes[i] = placeholder_node
end
- local schematic = {size={x=size, y=size, z=size}, data=nodes}
+ local schematic = {size={x=factor, y=factor, z=factor}, data=nodes}
+
+ local size = factor - 1
+
+ --make area stay loaded
+ local manip = minetest.get_voxel_manip()
+ local new_pos2 = {x=pos1.x + (pos2.x - pos1.x) * factor + size, y=pos1.y + (pos2.y - pos1.y) * factor + size, z=pos1.z + (pos2.z - pos1.z) * factor + size}
+ local emerged_pos1, emerged_pos2 = manip:read_from_map(pos1, new_pos2)
local pos = {x=pos2.x, y=0, z=0}
local bigpos = {x=0, y=0, z=0}
- size = factor - 1
while pos.x >= pos1.x do
pos.y = pos2.y
while pos.y >= pos1.y do
@@ -236,14 +266,19 @@ worldedit.scale = function(pos1, pos2, factor)
local posx, posy, posz = pos1.x + (pos.x - pos1.x) * factor, pos1.y + (pos.y - pos1.y) * factor, pos1.z + (pos.z - pos1.z) * factor
--create large node
- placeholder_node[1], placeholder_node[3] = node.name, node.param2
+ placeholder_node.name = node.name
+ placeholder_node.param1, placeholder_node.param2 = node.param1, node.param2
bigpos.x, bigpos.y, bigpos.z = posx, posy, posz
place_schematic(bigpos, schematic)
- for x = 0, size do --fill in large node meta
- for y = 0, size do
- for z = 0, size do
- bigpos.x, bigpos.y, bigpos.z = posx + x, posy + y, posz + z
- get_meta(bigpos):from_table(meta) --set metadata of new node
+
+ --fill in large node meta
+ if next(meta.fields) ~= nil and next(meta.inventory) ~= nil then --node has meta fields
+ for x = 0, size do
+ for y = 0, size do
+ for z = 0, size do
+ bigpos.x, bigpos.y, bigpos.z = posx + x, posy + y, posz + z
+ get_meta(bigpos):from_table(meta) --set metadata of new node
+ end
end
end
end
@@ -253,8 +288,7 @@ worldedit.scale = function(pos1, pos2, factor)
end
pos.x = pos.x - 1
end
- local newpos2 = {x=pos1.x + (pos2.x - pos1.x) * factor + size, y=pos1.y + (pos2.y - pos1.y) * factor + size, z=pos1.z + (pos2.z - pos1.z) * factor + size}
- return worldedit.volume(pos1, pos2), pos1, newpos2
+ return worldedit.volume(pos1, pos2) * (factor ^ 3), pos1, new_pos2
end
--transposes a region defined by the positions `pos1` and `pos2` between the `axis1` and `axis2` axes, returning the number of nodes transposed, the new transposed position 1, and the new transposed position 2
@@ -275,9 +309,16 @@ worldedit.transpose = function(pos1, pos2, axis1, axis2, env)
end
--calculate the new position 2 after transposition
- local newpos2 = {x=pos2.x, y=pos2.y, z=pos2.z}
- newpos2[axis1] = pos1[axis1] + extent2
- newpos2[axis2] = pos1[axis2] + extent1
+ local new_pos2 = {x=pos2.x, y=pos2.y, z=pos2.z}
+ new_pos2[axis1] = pos1[axis1] + extent2
+ new_pos2[axis2] = pos1[axis2] + extent1
+
+ --make area stay loaded
+ local manip = minetest.get_voxel_manip()
+ local upperbound = {x=pos2.x, y=pos2.y, z=pos2.z}
+ if upperbound[axis1] < new_pos2[axis1] then upperbound[axis1] = new_pos2[axis1] end
+ if upperbound[axis2] < new_pos2[axis2] then upperbound[axis2] = new_pos2[axis2] end
+ manip:read_from_map(pos1, upperbound)
local pos = {x=pos1.x, y=0, z=0}
local get_node, get_meta, add_node = minetest.get_node, minetest.get_meta, minetest.add_node
@@ -306,34 +347,38 @@ worldedit.transpose = function(pos1, pos2, axis1, axis2, env)
end
pos.x = pos.x + 1
end
- return worldedit.volume(pos1, pos2), pos1, newpos2
+ return worldedit.volume(pos1, pos2), pos1, new_pos2
end
--flips a region defined by the positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z"), returning the number of nodes flipped
worldedit.flip = function(pos1, pos2, axis, env)
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
+ --make area stay loaded
+ local manip = minetest.get_voxel_manip()
+ manip:read_from_map(pos1, pos2)
+
--wip: flip the region slice by slice along the flip axis using schematic method
local pos = {x=pos1.x, y=0, z=0}
local start = pos1[axis] + pos2[axis]
pos2[axis] = pos1[axis] + math.floor((pos2[axis] - pos1[axis]) / 2)
- if env == nil then env = minetest.env end
+ local get_node, get_meta, add_node = minetest.get_node, minetest.get_meta, minetest.add_node
while pos.x <= pos2.x do
pos.y = pos1.y
while pos.y <= pos2.y do
pos.z = pos1.z
while pos.z <= pos2.z do
- local node1 = env:get_node(pos)
- local meta1 = env:get_meta(pos):to_table()
+ local node1 = get_node(pos)
+ local meta1 = get_meta(pos):to_table()
local value = pos[axis]
pos[axis] = start - value
- local node2 = env:get_node(pos)
- local meta2 = env:get_meta(pos):to_table()
- env:add_node(pos, node1)
- env:get_meta(pos):from_table(meta1)
+ local node2 = get_node(pos)
+ local meta2 = get_meta(pos):to_table()
+ add_node(pos, node1)
+ get_meta(pos):from_table(meta1)
pos[axis] = value
- env:add_node(pos, node2)
- env:get_meta(pos):from_table(meta2)
+ add_node(pos, node2)
+ get_meta(pos):from_table(meta2)
pos.z = pos.z + 1
end
pos.y = pos.y + 1
@@ -372,7 +417,7 @@ worldedit.rotate = function(pos1, pos2, axis, angle, env)
end
--rotates all oriented nodes in a region defined by the positions `pos1` and `pos2` by `angle` degrees clockwise (90 degree increment) around the Y axis, returning the number of nodes oriented
-worldedit.orient = function(pos1, pos2, angle, env)
+worldedit.orient = function(pos1, pos2, angle, env) --wip: support 6D facedir rotation along arbitrary axis
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
local registered_nodes = minetest.registered_nodes
@@ -394,6 +439,10 @@ worldedit.orient = function(pos1, pos2, angle, env)
local wallmounted_substitution = wallmounted[angle]
local facedir_substitution = facedir[angle]
+ --make area stay loaded
+ local manip = minetest.get_voxel_manip()
+ manip:read_from_map(pos1, pos2)
+
local count = 0
local get_node, get_meta, add_node = minetest.get_node, minetest.get_meta, minetest.add_node
local pos = {x=pos1.x, y=0, z=0}
@@ -431,6 +480,11 @@ end
--fixes the lighting in a region defined by positions `pos1` and `pos2`, returning the number of nodes updated
worldedit.fixlight = function(pos1, pos2, env)
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
+
+ --make area stay loaded
+ local manip = minetest.get_voxel_manip()
+ manip:read_from_map(pos1, pos2)
+
local nodes = minetest.find_nodes_in_area(pos1, pos2, "air")
local dig_node = minetest.dig_node
for _, pos in ipairs(nodes) do
diff --git a/worldedit/primitives.lua b/worldedit/primitives.lua
index fecb6d8..85bc3b3 100644
--- a/worldedit/primitives.lua
+++ b/worldedit/primitives.lua
@@ -5,27 +5,39 @@ local minetest = minetest --local copy of global
worldedit.hollow_sphere = function(pos, radius, nodename)
--set up voxel manipulator
local manip = minetest.get_voxel_manip()
- manip:read_from_map(
- {x=pos.x - radius, y=pos.y - radius, z=pos.z - radius},
- {x=pos.x + radius, y=pos.y + radius, z=pos.z + radius},
- )
+ local pos1 = {x=pos.x - radius, y=pos.y - radius, z=pos.z - radius}
+ local pos2 = {x=pos.x + radius, y=pos.y + radius, z=pos.z + radius}
+ local emerged_pos1, emerged_pos2 = manip:read_from_map(pos1, pos2)
+ local area = VoxelArea:new({MinEdge=emerged_pos1, MaxEdge=emerged_pos2})
- local insert = table.insert
+ --fill emerged area with ignore
+ local nodes = {}
+ local ignore = minetest.get_content_id("ignore")
+ for i = 1, worldedit.volume(emerged_pos1, emerged_pos2) do
+ nodes[i] = ignore
+ end
+
+ --fill selected area with node
local node_id = minetest.get_content_id(nodename)
- local ignore_id = minetest.get_content_id("ignore")
local min_radius, max_radius = radius * (radius - 1), radius * (radius + 1)
- local nodes = {}
+ local ystride, zstride = area.ystride, area.zstride
+ local x, y, z = -radius, -radius, -radius
local count = 0
- for x = -radius, radius do
- for y = -radius, radius do
- for z = -radius, radius do
- local squared = x * x + y * y + z * z
- if squared >= min_radius and squared <= max_radius then --surface of sphere
- insert(nodes, node_id)
- count = count + 1
- else
- insert(nodes, ignore_id)
- end
+ for i in area:iterp(pos1, pos2) do
+ local squared = x * x + y * y + z * z
+ if squared >= min_radius and squared <= max_radius then --position is on surface of sphere
+ nodes[i] = node_id
+ count = count + 1
+ end
+
+ --move to the next position
+ x = x + 1
+ if x > radius then
+ x = -radius
+ y = y + 1
+ if y > radius then
+ y = -radius
+ z = z + 1
end
end
end
@@ -42,26 +54,38 @@ end
worldedit.sphere = function(pos, radius, nodename)
--set up voxel manipulator
local manip = minetest.get_voxel_manip()
- manip:read_from_map(
- {x=pos.x - radius, y=pos.y - radius, z=pos.z - radius},
- {x=pos.x + radius, y=pos.y + radius, z=pos.z + radius},
- )
+ local pos1 = {x=pos.x - radius, y=pos.y - radius, z=pos.z - radius}
+ local pos2 = {x=pos.x + radius, y=pos.y + radius, z=pos.z + radius}
+ local emerged_pos1, emerged_pos2 = manip:read_from_map(pos1, pos2)
+ local area = VoxelArea:new({MinEdge=emerged_pos1, MaxEdge=emerged_pos2})
- local insert = table.insert
+ --fill emerged area with ignore
+ local nodes = {}
+ local ignore = minetest.get_content_id("ignore")
+ for i = 1, worldedit.volume(emerged_pos1, emerged_pos2) do
+ nodes[i] = ignore
+ end
+
+ --fill selected area with node
local node_id = minetest.get_content_id(nodename)
- local ignore_id = minetest.get_content_id("ignore")
local max_radius = radius * (radius + 1)
- local nodes = {}
+ local ystride, zstride = area.ystride, area.zstride
+ local x, y, z = -radius, -radius, -radius
local count = 0
- for x = -radius, radius do
- for y = -radius, radius do
- for z = -radius, radius do
- if x * x + y * y + z * z <= max_radius then --inside sphere
- insert(nodes, node_id)
- count = count + 1
- else
- insert(nodes, ignore_id)
- end
+ for i in area:iterp(pos1, pos2) do
+ if x * x + y * y + z * z <= max_radius then --position is inside sphere
+ nodes[i] = node_id
+ count = count + 1
+ end
+
+ --move to the next position
+ x = x + 1
+ if x > radius then
+ x = -radius
+ y = y + 1
+ if y > radius then
+ y = -radius
+ z = z + 1
end
end
end
@@ -75,30 +99,42 @@ worldedit.sphere = function(pos, radius, nodename)
end
--adds a hollow dome centered at `pos` with radius `radius`, composed of `nodename`, returning the number of nodes added
-worldedit.hollow_dome = function(pos, radius, nodename) --wip: use bresenham sphere for maximum speed
+worldedit.hollow_dome = function(pos, radius, nodename)
--set up voxel manipulator
local manip = minetest.get_voxel_manip()
- manip:read_from_map(
- {x=pos.x - radius, y=pos.y, z=pos.z - radius},
- {x=pos.x + radius, y=pos.y + radius, z=pos.z + radius},
- )
+ local pos1 = {x=pos.x - radius, y=pos.y, z=pos.z - radius}
+ local pos2 = {x=pos.x + radius, y=pos.y + radius, z=pos.z + radius}
+ local emerged_pos1, emerged_pos2 = manip:read_from_map(pos1, pos2)
+ local area = VoxelArea:new({MinEdge=emerged_pos1, MaxEdge=emerged_pos2})
- local insert = table.insert
+ --fill emerged area with ignore
+ local nodes = {}
+ local ignore = minetest.get_content_id("ignore")
+ for i = 1, worldedit.volume(emerged_pos1, emerged_pos2) do
+ nodes[i] = ignore
+ end
+
+ --fill selected area with node
local node_id = minetest.get_content_id(nodename)
- local ignore_id = minetest.get_content_id("ignore")
local min_radius, max_radius = radius * (radius - 1), radius * (radius + 1)
- local nodes = {}
+ local ystride, zstride = area.ystride, area.zstride
+ local x, y, z = -radius, 0, -radius
local count = 0
- for x = -radius, radius do
- for y = 0, radius do
- for z = -radius, radius do
- local squared = x * x + y * y + z * z
- if squared >= min_radius and squared <= max_radius then --surface of dome
- insert(nodes, node_id)
- count = count + 1
- else
- insert(nodes, ignore_id)
- end
+ for i in area:iterp(pos1, pos2) do
+ local squared = x * x + y * y + z * z
+ if squared >= min_radius and squared <= max_radius then --position is on surface of sphere
+ nodes[i] = node_id
+ count = count + 1
+ end
+
+ --move to the next position
+ x = x + 1
+ if x > radius then
+ x = -radius
+ y = y + 1
+ if y > radius then
+ y = 0
+ z = z + 1
end
end
end
@@ -115,26 +151,38 @@ end
worldedit.dome = function(pos, radius, nodename) --wip: use bresenham sphere for maximum speed
--set up voxel manipulator
local manip = minetest.get_voxel_manip()
- manip:read_from_map(
- {x=pos.x - radius, y=pos.y, z=pos.z - radius},
- {x=pos.x + radius, y=pos.y + radius, z=pos.z + radius},
- )
+ local pos1 = {x=pos.x - radius, y=pos.y, z=pos.z - radius}
+ local pos2 = {x=pos.x + radius, y=pos.y + radius, z=pos.z + radius}
+ local emerged_pos1, emerged_pos2 = manip:read_from_map(pos1, pos2)
+ local area = VoxelArea:new({MinEdge=emerged_pos1, MaxEdge=emerged_pos2})
- local insert = table.insert
+ --fill emerged area with ignore
+ local nodes = {}
+ local ignore = minetest.get_content_id("ignore")
+ for i = 1, worldedit.volume(emerged_pos1, emerged_pos2) do
+ nodes[i] = ignore
+ end
+
+ --fill selected area with node
local node_id = minetest.get_content_id(nodename)
- local ignore_id = minetest.get_content_id("ignore")
local max_radius = radius * (radius + 1)
- local nodes = {}
+ local ystride, zstride = area.ystride, area.zstride
+ local x, y, z = -radius, 0, -radius
local count = 0
- for x = -radius, radius do
- for y = 0, radius do
- for z = -radius, radius do
- if x * x + y * y + z * z <= max_radius then --inside dome
- insert(nodes, node_id)
- count = count + 1
- else
- insert(nodes, ignore_id)
- end
+ for i in area:iterp(pos1, pos2) do
+ if x * x + y * y + z * z <= max_radius then --position is inside sphere
+ nodes[i] = node_id
+ count = count + 1
+ end
+
+ --move to the next position
+ x = x + 1
+ if x > radius then
+ x = -radius
+ y = y + 1
+ if y > radius then
+ y = 0
+ z = z + 1
end
end
end
@@ -148,7 +196,7 @@ worldedit.dome = function(pos, radius, nodename) --wip: use bresenham sphere for
end
--adds a hollow cylinder at `pos` along the `axis` axis ("x" or "y" or "z") with length `length` and radius `radius`, composed of `nodename`, returning the number of nodes added
-worldedit.hollow_cylinder = function(pos, axis, length, radius, nodename)
+worldedit.hollow_cylinder = function(pos, axis, length, radius, nodename) --wip: rewrite this using voxelmanip
local other1, other2
if axis == "x" then
other1, other2 = "y", "z"
@@ -216,7 +264,7 @@ worldedit.hollow_cylinder = function(pos, axis, length, radius, nodename)
end
--adds a cylinder at `pos` along the `axis` axis ("x" or "y" or "z") with length `length` and radius `radius`, composed of `nodename`, returning the number of nodes added
-worldedit.cylinder = function(pos, axis, length, radius, nodename, env)
+worldedit.cylinder = function(pos, axis, length, radius, nodename, env) --wip: rewrite this using voxelmanip
local other1, other2
if axis == "x" then
other1, other2 = "y", "z"
@@ -281,7 +329,7 @@ worldedit.cylinder = function(pos, axis, length, radius, nodename, env)
end
--adds a pyramid centered at `pos` with height `height`, composed of `nodename`, returning the number of nodes added
-worldedit.pyramid = function(pos, height, nodename, env)
+worldedit.pyramid = function(pos, height, nodename, env) --wip: rewrite this using voxelmanip
local pos1x, pos1y, pos1z = pos.x - height, pos.y, pos.z - height
local pos2x, pos2y, pos2z = pos.x + height, pos.y + height, pos.z + height
local pos = {x=0, y=pos1y, z=0}
diff --git a/worldedit/queue.lua b/worldedit/queue.lua
index 9246b9d..e9f3ac3 100644
--- a/worldedit/queue.lua
+++ b/worldedit/queue.lua
@@ -12,41 +12,39 @@ minetest.register_globalstep(function(dtime)
local elapsed = 0
local env = minetest.env
while worldedit.lower <= worldedit.higher and elapsed <= worldedit.MAXIMUM_TIME do
- local entry = worldedit.queue[worldedit.lower]
+ local entry = worldedit.queue[worldedit.lower]
if entry.t == "set_node" then
env:set_node(entry.pos, entry.node)
- elapsed = elapsed + 0.0002
+ elapsed = elapsed + 0.0002
elseif entry.t == "remove_node" then
env:remove_node(entry.pos)
- elapsed = elapsed + 0.0002
+ elapsed = elapsed + 0.0002
elseif entry.t == "place_node" then
env:place_node(entry.pos, entry.node)
- elapsed = elapsed + 0.001
+ elapsed = elapsed + 0.001
elseif entry.t == "dig_node" then
env:dig_node(entry.pos)
- elapsed = elapsed + 0.001
+ elapsed = elapsed + 0.001
elseif entry.t == "add_entity" then
env:add_entity(entry.pos, entry.name)
- elapsed = elapsed + 0.005
+ elapsed = elapsed + 0.005
elseif entry.t == "add_item" then
env:add_item(entry.pos, entry.item)
- elapsed = elapsed + 0.005
+ elapsed = elapsed + 0.005
elseif entry.t == "meta_from_table" then
env:get_meta(entry.pos):from_table(entry.table)
- elapsed = elapsed + 0.0002
+ elapsed = elapsed + 0.0002
else
print("Unknown queue event type: " .. entry.t)
end
worldedit.queue[worldedit.lower] = nil
- worldedit.lower = worldedit.lower + 1
+ worldedit.lower = worldedit.lower + 1
end
end)
-do
- worldedit.enqueue = function(value)
- worldedit.higher = worldedit.higher + 1
- worldedit.queue[worldedit.higher] = value
- end
+worldedit.enqueue = function(value)
+ worldedit.higher = worldedit.higher + 1
+ worldedit.queue[worldedit.higher] = value
end
function table.copy(t, seen)
@@ -123,4 +121,3 @@ worldedit.queue_aliasenv = {
add_entity = queue_addentity,
add_item = queue_additem,
}
-
diff --git a/worldedit/serialization.lua b/worldedit/serialization.lua
index 74cb218..e0d960d 100644
--- a/worldedit/serialization.lua
+++ b/worldedit/serialization.lua
@@ -34,6 +34,10 @@ end
--converts the region defined by positions `pos1` and `pos2` into a single string, returning the serialized data and the number of nodes serialized
worldedit.serialize = function(pos1, pos2) --wip: check for ItemStacks and whether they can be serialized
+ --make area stay loaded
+ local manip = minetest.get_voxel_manip()
+ manip:read_from_map(pos1, pos2)
+
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
local pos = {x=pos1.x, y=0, z=0}
local count = 0
@@ -141,7 +145,24 @@ worldedit.allocate = function(originpos, value)
count = count + 1
end
elseif version == 4 then --current nested table format
- local nodes = minetest.deserialize(value)
+ --wip: this is a filthy hack that works surprisingly well
+ value = value:gsub("return%s*{", "", 1):gsub("}%s*$", "", 1)
+ local escaped = value:gsub("\\\\", "@@"):gsub("\\\"", "@@"):gsub("(\"[^\"]*\")", function(s) return string.rep("@", #s) end)
+ local startpos, startpos1, endpos = 1, 1
+ local nodes = {}
+ while true do
+ startpos, endpos = escaped:find("},%s*{", startpos)
+ if not startpos then
+ break
+ end
+ local current = value:sub(startpos1, startpos)
+ table.insert(nodes, minetest.deserialize("return " .. current))
+ startpos, startpos1 = endpos, endpos
+ end
+ table.insert(nodes, minetest.deserialize("return " .. value:sub(startpos1)))
+
+ --local nodes = minetest.deserialize(value) --wip: this is broken for larger tables in the current version of LuaJIT
+
count = #nodes
for index = 1, count do
local entry = nodes[index]
@@ -161,7 +182,7 @@ end
--loads the nodes represented by string `value` at position `originpos`, returning the number of nodes deserialized
--contains code based on [table.save/table.load](http://lua-users.org/wiki/SaveTableToFile) by ChillCode, available under the MIT license (GPL compatible)
-worldedit.deserialize = function(originpos, value)
+worldedit.deserialize = function(originpos, value) --wip: use voxelmanip to make sure the blocks are loaded
local originx, originy, originz = originpos.x, originpos.y, originpos.z
local count = 0
local add_node, get_meta = minetest.add_node, minetest.get_meta
diff --git a/worldedit/visualization.lua b/worldedit/visualization.lua
index c07a139..d654146 100644
--- a/worldedit/visualization.lua
+++ b/worldedit/visualization.lua
@@ -33,6 +33,10 @@ minetest.register_node("worldedit:placeholder", {
--hides all nodes in a region defined by positions `pos1` and `pos2` by non-destructively replacing them with invisible nodes, returning the number of nodes hidden
worldedit.hide = function(pos1, pos2)
+ --make area stay loaded
+ local manip = minetest.get_voxel_manip()
+ manip:read_from_map(pos1, pos2)
+
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
local pos = {x=pos1.x, y=0, z=0}
local placeholder = {name="worldedit:placeholder", param1=0, param2=0}
@@ -60,6 +64,10 @@ end
--suppresses all instances of `nodename` in a region defined by positions `pos1` and `pos2` by non-destructively replacing them with invisible nodes, returning the number of nodes suppressed
worldedit.suppress = function(pos1, pos2, nodename)
+ --make area stay loaded
+ local manip = minetest.get_voxel_manip()
+ manip:read_from_map(pos1, pos2)
+
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
local placeholder = {name="worldedit:placeholder", param1=0, param2=0}
local nodes = minetest.find_nodes_in_area(pos1, pos2, nodename)
@@ -77,7 +85,11 @@ worldedit.suppress = function(pos1, pos2, nodename)
end
--highlights all instances of `nodename` in a region defined by positions `pos1` and `pos2` by non-destructively hiding all other nodes, returning the number of nodes found
-worldedit.highlight = function(pos1, pos2, nodename) --wip: speed this up with voxmanip get_data
+worldedit.highlight = function(pos1, pos2, nodename) --wip: speed this up with voxmanip get_data to speed up searching
+ --make area stay loaded
+ local manip = minetest.get_voxel_manip()
+ manip:read_from_map(pos1, pos2)
+
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
local pos = {x=pos1.x, y=0, z=0}
local placeholder = {name="worldedit:placeholder", param1=0, param2=0}
@@ -110,6 +122,10 @@ end
--restores all nodes hidden with WorldEdit functions in a region defined by positions `pos1` and `pos2`, returning the number of nodes restored
worldedit.restore = function(pos1, pos2)
+ --make area stay loaded
+ local manip = minetest.get_voxel_manip()
+ manip:read_from_map(pos1, pos2)
+
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
local node = {name="", param1=0, param2=0}
local nodes = minetest.find_nodes_in_area(pos1, pos2, "worldedit:placeholder")