\r
//dig\r
\r
+## //hide\r
+\r
+Hide all nodes in the current WorldEdit region non-destructively.\r
+\r
+ //hide\r
+\r
+### //suppress <node>\r
+\r
+Suppress all <node> in the current WorldEdit region non-destructively.\r
+\r
+ //suppress dirt\r
+ //suppress default:glass\r
+ //suppress mesecons:mesecon\r
+\r
+### //find <node>\r
+\r
+Find <node> in the current WorldEdit region by hiding everything else non-destructively.\r
+\r
+ //find dirt\r
+ //find default:glass\r
+ //find mesecons:mesecon\r
+\r
+### //restore\r
+\r
+Restores nodes hidden with WorldEdit in the current WorldEdit region.\r
+\r
+ //restore\r
+\r
### //save <file>\r
\r
Save the current WorldEdit region to "(world folder)/schems/<file>.we".\r
WorldEdit API\r
--------------\r
+=============\r
+The WorldEdit API is composed of multiple modules, each of which is independent and can be used without the other. Each module is contained within a single file.\r
+\r
For more information, see the [README](README.md).\r
\r
+Manipulations\r
+-------------\r
+Contained in manipulations.lua, this module allows several node operations to be applied over a region.\r
+\r
### worldedit.volume(pos1, pos2)\r
\r
Determines the volume of the region defined by positions `pos1` and `pos2`.\r
\r
Returns the number of nodes replaced.\r
\r
+Returns the number of nodes added.\r
+\r
+### worldedit.copy(pos1, pos2, axis, amount)\r
+\r
+Copies the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") by `amount` nodes.\r
+\r
+Returns the number of nodes copied.\r
+\r
+### worldedit.move(pos1, pos2, axis, amount)\r
+\r
+Moves the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") by `amount` nodes.\r
+\r
+Returns the number of nodes moved.\r
+\r
+### worldedit.stack(pos1, pos2, axis, count)\r
+\r
+Duplicates the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") `count` times.\r
+\r
+Returns the number of nodes stacked.\r
+\r
+### worldedit.transpose(pos1, pos2, axis1, axis2)\r
+\r
+Transposes a region defined by the positions `pos1` and `pos2` between the `axis1` and `axis2` axes ("x" or "y" or "z").\r
+\r
+Returns the number of nodes transposed.\r
+\r
+### worldedit.flip(pos1, pos2, axis)\r
+\r
+Flips a region defined by the positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z").\r
+\r
+Returns the number of nodes flipped.\r
+\r
+### worldedit.rotate(pos1, pos2, angle)\r
+\r
+Rotates a region defined by the positions `pos1` and `pos2` by `angle` degrees clockwise around the y axis (supporting 90 degree increments only).\r
+\r
+Returns the number of nodes rotated.\r
+\r
+### worldedit.dig(pos1, pos2)\r
+\r
+Digs a region defined by positions `pos1` and `pos2`.\r
+\r
+Returns the number of nodes dug.\r
+\r
+Primitives\r
+----------\r
+Contained in primitives.lua, this module allows the creation of several geometric primitives.\r
+\r
### worldedit.hollow_sphere = function(pos, radius, nodename)\r
\r
Adds a hollow sphere at `pos` with radius `radius`, composed of `nodename`.\r
\r
Adds a spiral at `pos` with width `width`, height `height`, space between walls `spacer`, composed of `nodename`.\r
\r
-Returns the number of nodes added.\r
-\r
-### worldedit.copy(pos1, pos2, axis, amount)\r
-\r
-Copies the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") by `amount` nodes.\r
-\r
-Returns the number of nodes copied.\r
-\r
-### worldedit.move(pos1, pos2, axis, amount)\r
-\r
-Moves the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") by `amount` nodes.\r
-\r
-Returns the number of nodes moved.\r
-\r
-### worldedit.stack(pos1, pos2, axis, count)\r
-\r
-Duplicates the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") `count` times.\r
+Visualization\r
+-------------\r
+Contained in visualization.lua, this module allows nodes to be visualized in different ways.\r
\r
-Returns the number of nodes stacked.\r
+### worldedit.hide(pos1, pos2)\r
\r
-### worldedit.transpose(pos1, pos2, axis1, axis2)\r
+Hides all nodes in a region defined by positions `pos1` and `pos2` by non-destructively replacing them with invisible nodes.\r
\r
-Transposes a region defined by the positions `pos1` and `pos2` between the `axis1` and `axis2` axes ("x" or "y" or "z").\r
+Returns the number of nodes hidden.\r
\r
-Returns the number of nodes transposed.\r
+### worldedit.suppress(pos1, pos2, nodename)\r
\r
-### worldedit.flip(pos1, pos2, axis)\r
+Suppresses all instances of `nodename` in a region defined by positions `pos1` and `pos2` by non-destructively replacing them with invisible nodes.\r
\r
-Flips a region defined by the positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z").\r
+Returns the number of nodes suppressed.\r
\r
-Returns the number of nodes flipped.\r
+### worldedit.find(pos1, pos2, nodename)\r
\r
-### worldedit.rotate(pos1, pos2, angle)\r
+Finds all instances of `nodename` in a region defined by positions `pos1` and `pos2` by non-destructively hiding all other nodes.\r
\r
-Rotates a region defined by the positions `pos1` and `pos2` by `angle` degrees clockwise around the y axis (supporting 90 degree increments only).\r
+Returns the number of nodes found.\r
\r
-Returns the number of nodes rotated.\r
+### worldedit.restore(pos1, pos2)\r
\r
-### worldedit.dig(pos1, pos2)\r
+Restores all nodes hidden with WorldEdit functions in a region defined by positions `pos1` and `pos2`.\r
\r
-Digs a region defined by positions `pos1` and `pos2`.\r
+Returns the number of nodes restored.\r
\r
-Returns the number of nodes dug.\r
+Serialization\r
+-------------\r
+Contained in serialization.lua, this module allows regions of nodes to be serialized and deserialized to formats suitable for use outside MineTest.\r
\r
### worldedit.serialize(pos1, pos2)\r
\r
+++ /dev/null
---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\r
-worldedit.sort_pos = function(pos1, pos2)\r
- pos1 = {x=pos1.x, y=pos1.y, z=pos1.z}\r
- pos2 = {x=pos2.x, y=pos2.y, z=pos2.z}\r
- if pos1.x > pos2.x then\r
- pos2.x, pos1.x = pos1.x, pos2.x\r
- end\r
- if pos1.y > pos2.y then\r
- pos2.y, pos1.y = pos1.y, pos2.y\r
- end\r
- if pos1.z > pos2.z then\r
- pos2.z, pos1.z = pos1.z, pos2.z\r
- end\r
- return pos1, pos2\r
-end\r
-\r
---determines the volume of the region defined by positions `pos1` and `pos2`, returning the volume\r
-worldedit.volume = function(pos1, pos2)\r
- local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
- return (pos2.x - pos1.x + 1) * (pos2.y - pos1.y + 1) * (pos2.z - pos1.z + 1)\r
-end\r
-\r
---sets a region defined by positions `pos1` and `pos2` to `nodename`, returning the number of nodes filled\r
-worldedit.set = function(pos1, pos2, nodename)\r
- local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
- local env = minetest.env\r
-\r
- local node = {name=nodename}\r
- local pos = {x=pos1.x, y=0, z=0}\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
- env:add_node(pos, node)\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
-end\r
-\r
---replaces all instances of `searchnode` with `replacenode` in a region defined by positions `pos1` and `pos2`, returning the number of nodes replaced\r
-worldedit.replace = function(pos1, pos2, searchnode, replacenode)\r
- local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
- local env = minetest.env\r
-\r
- if minetest.registered_nodes[searchnode] == nil then\r
- searchnode = "default:" .. searchnode\r
- end\r
- if minetest.registered_nodes[replacenode] == nil then\r
- replacenode = "default:" .. replacenode\r
- end\r
-\r
- local pos = {x=pos1.x, y=0, z=0}\r
- local node = {name=replacenode}\r
- local count = 0\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
- if env:get_node(pos).name == searchnode then\r
- env:add_node(pos, node)\r
- count = count + 1\r
- end\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 count\r
-end\r
-\r
---adds a hollow sphere at `pos` with radius `radius`, composed of `nodename`, returning the number of nodes added\r
-worldedit.hollow_sphere = function(pos, radius, nodename) --wip: use bresenham sphere for maximum speed\r
- local node = {name=nodename}\r
- local pos1 = {x=0, y=0, z=0}\r
- local full_radius = radius * radius + radius\r
- local env = minetest.env\r
- for x = -radius, radius do\r
- pos1.x = pos.x + x\r
- for y = -radius, radius do\r
- pos1.y = pos.y + y\r
- for z = -radius, radius do\r
- if x*x+y*y+z*z >= (radius-1) * (radius-1) + (radius-1) and x*x+y*y+z*z <= full_radius then\r
- pos1.z = pos.z + z\r
- env:add_node({x=pos.x+x,y=pos.y+y,z=pos.z+z}, node)\r
- end\r
- end\r
- end\r
- end\r
-end\r
-\r
---adds a sphere at `pos` with radius `radius`, composed of `nodename`, returning the number of nodes added\r
-worldedit.sphere = function(pos, radius, nodename) --wip: use bresenham sphere for maximum speed\r
- local node = {name=nodename}\r
- local pos1 = {x=0, y=0, z=0}\r
- local full_radius = radius * radius + radius\r
- local count = 0\r
- local env = minetest.env\r
- for x = -radius, radius do\r
- pos1.x = pos.x + x\r
- for y = -radius, radius do\r
- pos1.y = pos.y + y\r
- for z = -radius, radius do\r
- if x*x+y*y+z*z <= full_radius then\r
- pos1.z = pos.z + z\r
- env:add_node(pos1, node)\r
- count = count + 1\r
- end\r
- end\r
- end\r
- end\r
- return count\r
-end\r
-\r
---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\r
-worldedit.hollow_cylinder = function(pos, axis, length, radius, nodename)\r
- local other1, other2\r
- if axis == "x" then\r
- other1, other2 = "y", "z"\r
- elseif axis == "y" then\r
- other1, other2 = "x", "z"\r
- else --axis == "z"\r
- other1, other2 = "x", "y"\r
- end\r
-\r
- local env = minetest.env\r
- local currentpos = {x=pos.x, y=pos.y, z=pos.z}\r
- local node = {name=nodename}\r
- local count = 0\r
- local step = 1\r
- if length < 0 then\r
- length = -length\r
- step = -1\r
- end\r
- for i = 1, length do\r
- local offset1, offset2 = 0, radius\r
- local delta = -radius\r
- while offset1 <= offset2 do\r
- --add node at each octant\r
- local first1, first2 = pos[other1] + offset1, pos[other1] - offset1\r
- local second1, second2 = pos[other2] + offset2, pos[other2] - offset2\r
- currentpos[other1], currentpos[other2] = first1, second1\r
- env:add_node(currentpos, node) --octant 1\r
- currentpos[other1] = first2\r
- env:add_node(currentpos, node) --octant 4\r
- currentpos[other2] = second2\r
- env:add_node(currentpos, node) --octant 5\r
- currentpos[other1] = first1\r
- env:add_node(currentpos, node) --octant 8\r
- local first1, first2 = pos[other1] + offset2, pos[other1] - offset2\r
- local second1, second2 = pos[other2] + offset1, pos[other2] - offset1\r
- currentpos[other1], currentpos[other2] = first1, second1\r
- env:add_node(currentpos, node) --octant 2\r
- currentpos[other1] = first2\r
- env:add_node(currentpos, node) --octant 3\r
- currentpos[other2] = second2\r
- env:add_node(currentpos, node) --octant 6\r
- currentpos[other1] = first1\r
- env:add_node(currentpos, node) --octant 7\r
-\r
- count = count + 8 --wip: broken\r
-\r
- --move to next location\r
- delta = delta + (offset1 * 2) + 1\r
- if delta >= 0 then\r
- offset2 = offset2 - 1\r
- delta = delta - (offset2 * 2)\r
- end\r
- offset1 = offset1 + 1\r
- end\r
- currentpos[axis] = currentpos[axis] + step\r
- end\r
- return count\r
-end\r
-\r
---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\r
-worldedit.cylinder = function(pos, axis, length, radius, nodename)\r
- local other1, other2\r
- if axis == "x" then\r
- other1, other2 = "y", "z"\r
- elseif axis == "y" then\r
- other1, other2 = "x", "z"\r
- else --axis == "z"\r
- other1, other2 = "x", "y"\r
- end\r
-\r
- local env = minetest.env\r
- local currentpos = {x=pos.x, y=pos.y, z=pos.z}\r
- local node = {name=nodename}\r
- local count = 0\r
- local step = 1\r
- if length < 0 then\r
- length = -length\r
- step = -1\r
- end\r
- for i = 1, length do\r
- local offset1, offset2 = 0, radius\r
- local delta = -radius\r
- while offset1 <= offset2 do\r
- --connect each pair of octants\r
- currentpos[other1] = pos[other1] - offset1\r
- local second1, second2 = pos[other2] + offset2, pos[other2] - offset2\r
- for i = 0, offset1 * 2 do\r
- currentpos[other2] = second1\r
- env:add_node(currentpos, node) --octant 1 to 4\r
- currentpos[other2] = second2\r
- env:add_node(currentpos, node) --octant 5 to 8\r
- currentpos[other1] = currentpos[other1] + 1\r
- end\r
- currentpos[other1] = pos[other1] - offset2\r
- local second1, second2 = pos[other2] + offset1, pos[other2] - offset1\r
- for i = 0, offset2 * 2 do\r
- currentpos[other2] = second1\r
- env:add_node(currentpos, node) --octant 2 to 3\r
- currentpos[other2] = second2\r
- env:add_node(currentpos, node) --octant 6 to 7\r
- currentpos[other1] = currentpos[other1] + 1\r
- end\r
-\r
- count = count + (offset1 * 4) + (offset2 * 4) + 4 --wip: broken\r
-\r
- --move to next location\r
- delta = delta + (offset1 * 2) + 1\r
- offset1 = offset1 + 1\r
- if delta >= 0 then\r
- offset2 = offset2 - 1\r
- delta = delta - (offset2 * 2)\r
- end\r
- end\r
- currentpos[axis] = currentpos[axis] + step\r
- end\r
- return count\r
-end\r
-\r
---adds a pyramid at `pos` with height `height`, composed of `nodename`, returning the number of nodes added\r
-worldedit.pyramid = function(pos, height, nodename)\r
- local pos1x, pos1y, pos1z = pos.x - height, pos.y, pos.z - height\r
- local pos2x, pos2y, pos2z = pos.x + height, pos.y + height, pos.z + height\r
- local pos = {x=0, y=pos1y, z=0}\r
-\r
- local count = 0\r
- local node = {name=nodename}\r
- local env = minetest.env\r
- while pos.y <= pos2y do --each vertical level of the pyramid\r
- pos.x = pos1x\r
- while pos.x <= pos2x do\r
- pos.z = pos1z\r
- while pos.z <= pos2z do\r
- env:add_node(pos, node)\r
- pos.z = pos.z + 1\r
- end\r
- pos.x = pos.x + 1\r
- end\r
- count = count + ((pos2y - pos.y) * 2 + 1) ^ 2\r
- pos.y = pos.y + 1\r
-\r
- pos1x, pos2x = pos1x + 1, pos2x - 1\r
- pos1z, pos2z = pos1z + 1, pos2z - 1\r
-\r
- end\r
- return count\r
-end\r
-\r
---adds a spiral at `pos` with width `width`, height `height`, space between walls `spacer`, composed of `nodename`, returning the number of nodes added\r
-worldedit.spiral = function(pos, width, height, spacer, nodename) --wip: clean this up\r
- -- spiral matrix - http://rosettacode.org/wiki/Spiral_matrix#Lua\r
- av, sn = math.abs, function(s) return s~=0 and s/av(s) or 0 end\r
- local function sindex(z, x) -- returns the value at (x, z) in a spiral that starts at 1 and goes outwards\r
- if z == -x and z >= x then return (2*z+1)^2 end\r
- local l = math.max(av(z), av(x))\r
- return (2*l-1)^2+4*l+2*l*sn(x+z)+sn(z^2-x^2)*(l-(av(z)==l and sn(z)*x or sn(x)*z)) -- OH GOD WHAT\r
- end\r
- local function spiralt(side)\r
- local ret, id, start, stop = {}, 0, math.floor((-side+1)/2), math.floor((side-1)/2)\r
- for i = 1, side do\r
- for j = 1, side do\r
- local id = side^2 - sindex(stop - i + 1,start + j - 1)\r
- ret[id] = {x=i,z=j}\r
- end\r
- end\r
- return ret\r
- end\r
- -- connect the joined parts\r
- local spiral = spiralt(width)\r
- height = tonumber(height)\r
- if height < 1 then height = 1 end\r
- spacer = tonumber(spacer)-1\r
- if spacer < 1 then spacer = 1 end\r
- local count = 0\r
- local node = {name=nodename}\r
- local np,lp\r
- for y=0,height do\r
- lp = nil\r
- for _,v in ipairs(spiral) do\r
- np = {x=pos.x+v.x*spacer, y=pos.y+y, z=pos.z+v.z*spacer}\r
- if lp~=nil then\r
- if lp.x~=np.x then \r
- if lp.x<np.x then \r
- for i=lp.x+1,np.x do\r
- minetest.env:add_node({x=i, y=np.y, z=np.z}, node)\r
- count = count + 1\r
- end\r
- else\r
- for i=np.x,lp.x-1 do\r
- minetest.env:add_node({x=i, y=np.y, z=np.z}, node)\r
- count = count + 1\r
- end\r
- end\r
- end\r
- if lp.z~=np.z then \r
- if lp.z<np.z then \r
- for i=lp.z+1,np.z do\r
- minetest.env:add_node({x=np.x, y=np.y, z=i}, node)\r
- count = count + 1\r
- end\r
- else\r
- for i=np.z,lp.z-1 do\r
- minetest.env:add_node({x=np.x, y=np.y, z=i}, node)\r
- count = count + 1\r
- end\r
- end\r
- end\r
- end\r
- lp = np\r
- end\r
- end\r
- return count\r
-end\r
-\r
---copies the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") by `amount` nodes, returning the number of nodes copied\r
-worldedit.copy = function(pos1, pos2, axis, amount)\r
- local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
- local env = minetest.env\r
-\r
- if amount < 0 then\r
- local pos = {x=pos1.x, y=0, z=0}\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 = env:get_node(pos) --obtain current node\r
- local meta = env: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
- env:add_node(pos, node) --copy node to new position\r
- env: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 = {x=pos2.x, y=0, z=0}\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 = minetest.env:get_node(pos) --obtain current node\r
- local meta = env: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
- minetest.env:add_node(pos, node) --copy node to new position\r
- env: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
- end\r
- return worldedit.volume(pos1, pos2)\r
-end\r
-\r
---moves the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") by `amount` nodes, returning the number of nodes moved\r
-worldedit.move = function(pos1, pos2, axis, amount)\r
- local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
- local env = minetest.env\r
-\r
- if amount < 0 then\r
- local pos = {x=pos1.x, y=0, z=0}\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 = env:get_node(pos) --obtain current node\r
- local meta = env:get_meta(pos):to_table() --get metadata of current node\r
- env:remove_node(pos)\r
- local value = pos[axis] --store current position\r
- pos[axis] = value + amount --move along axis\r
- env:add_node(pos, node) --move node to new position\r
- env: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 = {x=pos2.x, y=0, z=0}\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 = env:get_node(pos) --obtain current node\r
- local meta = env:get_meta(pos):to_table() --get metadata of current node\r
- env:remove_node(pos)\r
- local value = pos[axis] --store current position\r
- pos[axis] = value + amount --move along axis\r
- env:add_node(pos, node) --move node to new position\r
- env: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
- end\r
- return worldedit.volume(pos1, pos2)\r
-end\r
-\r
---duplicates the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") `count` times, returning the number of nodes stacked\r
-worldedit.stack = function(pos1, pos2, axis, count)\r
- local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
- local length = pos2[axis] - pos1[axis] + 1\r
- if count < 0 then\r
- count = -count\r
- length = -length\r
- end\r
- local amount = 0\r
- local copy = worldedit.copy\r
- for i = 1, count do\r
- amount = amount + length\r
- copy(pos1, pos2, axis, amount)\r
- end\r
- return worldedit.volume(pos1, pos2)\r
-end\r
-\r
---transposes a region defined by the positions `pos1` and `pos2` between the `axis1` and `axis2` axes, returning the number of nodes transposed\r
-worldedit.transpose = function(pos1, pos2, axis1, axis2)\r
- local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
-\r
- local pos = {x=pos1.x, y=0, z=0}\r
- local env = minetest.env\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 extent1, extent2 = pos[axis1] - pos1[axis1], pos[axis2] - pos1[axis2]\r
- if extent1 < extent2 then\r
- local node1 = env:get_node(pos)\r
- local meta1 = env:get_meta(pos):to_table()\r
- local value1, value2 = pos[axis1], pos[axis2]\r
- pos[axis1], pos[axis2] = value1 + extent2, value2 + extent1\r
- local node2 = env:get_node(pos)\r
- local meta2 = env:get_meta(pos):to_table()\r
- env:add_node(pos, node1)\r
- env:get_meta(pos):from_table(meta1)\r
- pos[axis1], pos[axis2] = value1, value2\r
- env:add_node(pos, node2)\r
- env:get_meta(pos):from_table(meta2)\r
- end\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
-end\r
-\r
---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\r
-worldedit.flip = function(pos1, pos2, axis)\r
- local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
-\r
- local pos = {x=pos1.x, y=0, z=0}\r
- local start = pos1[axis] + pos2[axis]\r
- pos2[axis] = pos1[axis] + math.floor((pos2[axis] - pos1[axis]) / 2)\r
- local env = minetest.env\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 node1 = env:get_node(pos)\r
- local meta1 = env:get_meta(pos):to_table()\r
- local value = pos[axis]\r
- pos[axis] = start - value\r
- local node2 = env:get_node(pos)\r
- local meta2 = env:get_meta(pos):to_table()\r
- env:add_node(pos, node1)\r
- env:get_meta(pos):from_table(meta1)\r
- pos[axis] = value\r
- env:add_node(pos, node2)\r
- env:get_meta(pos):from_table(meta2)\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
-end\r
-\r
---rotates a region defined by the positions `pos1` and `pos2` by `angle` degrees clockwise around axis `axis` (90 degree increment), returning the number of nodes rotated\r
-worldedit.rotate = function(pos1, pos2, axis, angle)\r
- local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
-\r
- local axis1, axis2\r
- if axis == "x" then\r
- axis1, axis2 = "z", "y"\r
- elseif axis == "y" then\r
- axis1, axis2 = "x", "z"\r
- else --axis == "z"\r
- axis1, axis2 = "y", "x"\r
- end\r
- angle = angle % 360\r
-\r
- if angle == 90 then\r
- worldedit.transpose(pos1, pos2, axis1, axis2)\r
- worldedit.flip(pos1, pos2, axis2)\r
- elseif angle == 180 then\r
- worldedit.flip(pos1, pos2, axis1)\r
- worldedit.flip(pos1, pos2, axis2)\r
- elseif angle == 270 then\r
- worldedit.transpose(pos1, pos2, axis1, axis2)\r
- worldedit.flip(pos1, pos2, axis1)\r
- end\r
- return worldedit.volume(pos1, pos2)\r
-end\r
-\r
---digs a region defined by positions `pos1` and `pos2`, returning the number of nodes dug\r
-worldedit.dig = function(pos1, pos2)\r
- local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
- local env = minetest.env\r
-\r
- local pos = {x=pos1.x, y=0, z=0}\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
- env:dig_node(pos)\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
-end\r
-\r
---converts the region defined by positions `pos1` and `pos2` into a single string, returning the serialized data and the number of nodes serialized\r
-worldedit.serialize = function(pos1, pos2)\r
- local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
- local pos = {x=pos1.x, y=0, z=0}\r
- local count = 0\r
- local result = {}\r
- local env = minetest.env\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 = env:get_node(pos)\r
- if node.name ~= "air" and node.name ~= "ignore" then\r
- count = count + 1\r
- result[count] = pos.x - pos1.x .. " " .. pos.y - pos1.y .. " " .. pos.z - pos1.z .. " " .. node.name .. " " .. node.param1 .. " " .. node.param2\r
- end\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
- result = table.concat(result, "\n")\r
- return result, count\r
-end\r
-\r
---loads the nodes represented by string `value` at position `originpos`, returning the number of nodes deserialized\r
-worldedit.deserialize = function(originpos, value)\r
- local pos = {x=0, y=0, z=0}\r
- local node = {name="", param1=0, param2=0}\r
- local count = 0\r
- local env = minetest.env\r
- for x, y, z, name, param1, param2 in value:gmatch("([+-]?%d+)%s+([+-]?%d+)%s+([+-]?%d+)%s+([^%s]+)%s+(%d+)%s+(%d+)[^\r\n]*[\r\n]*") do\r
- pos.x = originpos.x + tonumber(x)\r
- pos.y = originpos.y + tonumber(y)\r
- pos.z = originpos.z + tonumber(z)\r
- node.name = name\r
- node.param1 = param1\r
- node.param2 = param2\r
- env:add_node(pos, node)\r
- count = count + 1\r
- end\r
- return count\r
-end\r
-\r
---loads the nodes represented by string `value` at position `originpos`, returning the number of nodes deserialized\r
---based on [table.save/table.load](http://lua-users.org/wiki/SaveTableToFile) by ChillCode, available under the MIT license (GPL compatible)\r
-worldedit.deserialize_old = function(originpos, value)\r
- --obtain the node table\r
- local count = 0\r
- local get_tables = loadstring(value)\r
- if get_tables == nil then --error loading value\r
- return count\r
- end\r
- local tables = get_tables()\r
-\r
- --transform the node table into an array of nodes\r
- for i = 1, #tables do\r
- for j, v in pairs(tables[i]) do\r
- if type(v) == "table" then\r
- tables[i][j] = tables[v[1]]\r
- end\r
- end\r
- end\r
-\r
- --load the node array\r
- local env = minetest.env\r
- for i, v in ipairs(tables[1]) do\r
- local pos = v[1]\r
- pos.x, pos.y, pos.z = originpos.x + pos.x, originpos.y + pos.y, originpos.z + pos.z\r
- env:add_node(pos, v[2])\r
- count = count + 1\r
- end\r
- return count\r
-end\r
-\r
---saves the nodes and meta defined by positions `pos1` and `pos2` into a file, returning the number of nodes saved\r
-worldedit.metasave = function(pos1, pos2, file) --wip: simply work with strings instead of doing IO\r
- local path = minetest.get_worldpath() .. "/schems"\r
- local filename = path .. "/" .. file .. ".wem"\r
- os.execute("mkdir \"" .. path .. "\"") --create directory if it does not already exist\r
- local rows = {}\r
- local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
- local pos = {x=pos1.x, y=0, z=0}\r
- local count = 0\r
- local result = {}\r
- local env = minetest.env\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 = env:get_node(pos)\r
- if node.name ~= "air" and node.name ~= "ignore" then\r
- count = count + 1\r
- local row = {\r
- x = pos.x-pos1.x,\r
- y = pos.y-pos1.y,\r
- z = pos.z-pos1.z,\r
- name = node.name,\r
- param1 = node.param1,\r
- param2 = node.param2,\r
- meta = env:get_meta(pos):to_table(),\r
- }\r
- table.insert(rows, row)\r
- end\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 err = table.save(rows,filename)\r
- if err then return _,err end\r
- return count\r
-end\r
-\r
---loads the nodes and meta from `file` to position `pos1`, returning the number of nodes loaded\r
-worldedit.metaload = function(pos1, file) --wip: simply work with strings instead of doing IO\r
- local filename = minetest.get_worldpath() .. "/schems/" .. file .. ".wem"\r
- local rows, err = table.load(filename)\r
- if err then return _,err end\r
- local pos = {x=0, y=0, z=0}\r
- local node = {name="", param1=0, param2=0}\r
- local count = 0\r
- local env = minetest.env\r
- for i,row in pairs(rows) do\r
- pos.x = pos1.x + tonumber(row.x)\r
- pos.y = pos1.y + tonumber(row.y)\r
- pos.z = pos1.z + tonumber(row.z)\r
- node.name = row.name\r
- node.param1 = row.param1\r
- node.param2 = row.param2\r
- env:add_node(pos, node)\r
- env:get_meta(pos):from_table(row.meta)\r
- count = count + 1\r
- end\r
- return count\r
-end
\ No newline at end of file
-minetest.register_privilege("worldedit", "Can use WorldEdit commands")\r
-\r
-worldedit = {}\r
-\r
-worldedit.set_pos = {}\r
-\r
-worldedit.pos1 = {}\r
-worldedit.pos2 = {}\r
-\r
-dofile(minetest.get_modpath("worldedit") .. "/functions.lua")\r
-dofile(minetest.get_modpath("worldedit") .. "/mark.lua")\r
-\r
---determines whether `nodename` is a valid node name, returning a boolean\r
-worldedit.node_is_valid = function(temp_pos, nodename)\r
- return minetest.registered_nodes[nodename] ~= nil\r
- or minetest.registered_nodes["default:" .. nodename] ~= nil\r
-end\r
-\r
---determines the axis in which a player is facing, returning an axis ("x", "y", or "z") and the sign (1 or -1)\r
-worldedit.player_axis = function(name)\r
- local dir = minetest.env:get_player_by_name(name):get_look_dir()\r
- local x, y, z = math.abs(dir.x), math.abs(dir.y), math.abs(dir.z)\r
- if x > y then\r
- if x > z then\r
- return "x", dir.x > 0 and 1 or -1\r
- end\r
- elseif y > z then\r
- return "y", dir.y > 0 and 1 or -1\r
- end\r
- return "z", dir.z > 0 and 1 or -1\r
-end\r
-\r
-minetest.register_chatcommand("/reset", {\r
- params = "",\r
- description = "Reset the region so that it is empty",\r
- privs = {worldedit=true},\r
- func = function(name, param)\r
- worldedit.pos1[name] = nil\r
- worldedit.pos2[name] = nil\r
- worldedit.mark_pos1(name)\r
- worldedit.mark_pos2(name)\r
- minetest.chat_send_player(name, "WorldEdit region reset")\r
- end,\r
-})\r
-\r
-minetest.register_chatcommand("/mark", {\r
- params = "",\r
- description = "Show markers at the region positions",\r
- privs = {worldedit=true},\r
- func = function(name, param)\r
- worldedit.mark_pos1(name)\r
- worldedit.mark_pos2(name)\r
- minetest.chat_send_player(name, "WorldEdit region marked")\r
- end,\r
-})\r
-\r
-minetest.register_chatcommand("/pos1", {\r
- params = "",\r
- description = "Set WorldEdit region position 1 to the player's location",\r
- privs = {worldedit=true},\r
- func = function(name, param)\r
- local pos = minetest.env:get_player_by_name(name):getpos()\r
- pos.x, pos.y, pos.z = math.floor(pos.x), math.floor(pos.y), math.floor(pos.z)\r
- worldedit.pos1[name] = pos\r
- worldedit.mark_pos1(name)\r
- minetest.chat_send_player(name, "WorldEdit position 1 set to " .. minetest.pos_to_string(pos))\r
- end,\r
-})\r
-\r
-minetest.register_chatcommand("/pos2", {\r
- params = "",\r
- description = "Set WorldEdit region position 2 to the player's location",\r
- privs = {worldedit=true},\r
- func = function(name, param)\r
- local pos = minetest.env:get_player_by_name(name):getpos()\r
- pos.x, pos.y, pos.z = math.floor(pos.x), math.floor(pos.y), math.floor(pos.z)\r
- worldedit.pos2[name] = pos\r
- worldedit.mark_pos2(name)\r
- minetest.chat_send_player(name, "WorldEdit position 2 set to " .. minetest.pos_to_string(pos))\r
- end,\r
-})\r
-\r
-minetest.register_chatcommand("/p", {\r
- params = "set/get",\r
- description = "Set WorldEdit region by punching two nodes, or display the current WorldEdit region",\r
- privs = {worldedit=true},\r
- func = function(name, param)\r
- if param == "set" then --set both WorldEdit positions\r
- worldedit.set_pos[name] = 1\r
- minetest.chat_send_player(name, "Select positions by punching two nodes")\r
- elseif param == "get" then --display current WorldEdit positions\r
- if worldedit.pos1[name] ~= nil then\r
- minetest.chat_send_player(name, "WorldEdit position 1: " .. minetest.pos_to_string(worldedit.pos1[name]))\r
- else\r
- minetest.chat_send_player(name, "WorldEdit position 1 not set")\r
- end\r
- if worldedit.pos2[name] ~= nil then\r
- minetest.chat_send_player(name, "WorldEdit position 2: " .. minetest.pos_to_string(worldedit.pos2[name]))\r
- else\r
- minetest.chat_send_player(name, "WorldEdit position 2 not set")\r
- end\r
- else\r
- minetest.chat_send_player(name, "Unknown subcommand: " .. param)\r
- end\r
- end,\r
-})\r
-\r
-minetest.register_on_punchnode(function(pos, node, puncher)\r
- local name = puncher:get_player_name()\r
- if name ~= "" and worldedit.set_pos[name] ~= nil then --currently setting position\r
- if worldedit.set_pos[name] == 1 then --setting position 1\r
- worldedit.set_pos[name] = 2 --set position 2 on the next invocation\r
- worldedit.pos1[name] = pos\r
- worldedit.mark_pos1(name)\r
- minetest.chat_send_player(name, "WorldEdit region position 1 set to " .. minetest.pos_to_string(pos))\r
- else --setting position 2\r
- worldedit.set_pos[name] = nil --finished setting positions\r
- worldedit.pos2[name] = pos\r
- worldedit.mark_pos2(name)\r
- minetest.chat_send_player(name, "WorldEdit region position 2 set to " .. minetest.pos_to_string(pos))\r
- end\r
- end\r
-end)\r
-\r
-minetest.register_chatcommand("/volume", {\r
- params = "",\r
- description = "Display the volume of the current WorldEdit region",\r
- privs = {worldedit=true},\r
- func = function(name, param)\r
- local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
- if pos1 == nil or pos2 == nil then\r
- minetest.chat_send_player(name, "No WorldEdit region selected")\r
- return\r
- end\r
-\r
- local volume = worldedit.volume(pos1, pos2)\r
- minetest.chat_send_player(name, "Current WorldEdit region has a volume of " .. volume .. " nodes (" .. pos2.x - pos1.x .. "*" .. pos2.y - pos1.y .. "*" .. pos2.z - pos1.z .. ")")\r
- end,\r
-})\r
-\r
-minetest.register_chatcommand("/set", {\r
- params = "<node>",\r
- description = "Set the current WorldEdit region to <node>",\r
- privs = {worldedit=true},\r
- func = function(name, param)\r
- local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
- if pos1 == nil or pos2 == nil then\r
- minetest.chat_send_player(name, "No WorldEdit region selected")\r
- return\r
- end\r
-\r
- if param == "" or not worldedit.node_is_valid(pos1, param) then\r
- minetest.chat_send_player(name, "Invalid node name: " .. param)\r
- return\r
- end\r
-\r
- local count = worldedit.set(pos1, pos2, param)\r
- minetest.chat_send_player(name, count .. " nodes set")\r
- end,\r
-})\r
-\r
-minetest.register_chatcommand("/replace", {\r
- params = "<search node> <replace node>",\r
- description = "Replace all instances of <search node> with <place node> in the current WorldEdit region",\r
- privs = {worldedit=true},\r
- func = function(name, param)\r
- local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
- if pos1 == nil or pos2 == nil then\r
- minetest.chat_send_player(name, "No WorldEdit region selected")\r
- return\r
- end\r
-\r
- local found, _, searchnode, replacenode = param:find("^([^%s]+)%s+([^%s]+)$")\r
- if found == nil then\r
- minetest.chat_send_player(name, "Invalid usage: " .. param)\r
- return\r
- end\r
- if not worldedit.node_is_valid(pos1, searchnode) then\r
- minetest.chat_send_player(name, "Invalid search node name: " .. searchnode)\r
- return\r
- end\r
- if not worldedit.node_is_valid(pos1, replacenode) then\r
- minetest.chat_send_player(name, "Invalid replace node name: " .. replacenode)\r
- return\r
- end\r
-\r
- local count = worldedit.replace(pos1, pos2, searchnode, replacenode)\r
- minetest.chat_send_player(name, count .. " nodes replaced")\r
- end,\r
-})\r
-\r
-minetest.register_chatcommand("/hollowsphere", {\r
- params = "<radius> <node>",\r
- description = "Add hollow sphere at WorldEdit position 1 with radius <radius>, composed of <node>",\r
- privs = {worldedit=true},\r
- func = function(name, param)\r
- local pos = worldedit.pos1[name]\r
- if pos == nil then\r
- minetest.chat_send_player(name, "No WorldEdit region selected")\r
- return\r
- end\r
-\r
- local found, _, radius, nodename = param:find("^(%d+)%s+([^%s]+)$")\r
- if found == nil then\r
- minetest.chat_send_player(name, "Invalid usage: " .. param)\r
- return\r
- end\r
- if not worldedit.node_is_valid(pos, nodename) then\r
- minetest.chat_send_player(name, "Invalid node name: " .. param)\r
- return\r
- end\r
-\r
- local count = worldedit.hollow_sphere(pos, tonumber(radius), nodename)\r
- minetest.chat_send_player(name, count .. " nodes added")\r
- end,\r
-})\r
-\r
-minetest.register_chatcommand("/sphere", {\r
- params = "<radius> <node>",\r
- description = "Add sphere at WorldEdit position 1 with radius <radius>, composed of <node>",\r
- privs = {worldedit=true},\r
- func = function(name, param)\r
- local pos = worldedit.pos1[name]\r
- if pos == nil then\r
- minetest.chat_send_player(name, "No WorldEdit region selected")\r
- return\r
- end\r
-\r
- local found, _, radius, nodename = param:find("^(%d+)%s+([^%s]+)$")\r
- if found == nil then\r
- minetest.chat_send_player(name, "Invalid usage: " .. param)\r
- return\r
- end\r
- if not worldedit.node_is_valid(pos, nodename) then\r
- minetest.chat_send_player(name, "Invalid node name: " .. param)\r
- return\r
- end\r
-\r
- local count = worldedit.sphere(pos, tonumber(radius), nodename)\r
- minetest.chat_send_player(name, count .. " nodes added")\r
- end,\r
-})\r
-\r
-minetest.register_chatcommand("/hollowcylinder", {\r
- params = "x/y/z/? <length> <radius> <node>",\r
- description = "Add hollow cylinder at WorldEdit position 1 along the x/y/z/? axis with length <length> and radius <radius>, composed of <node>",\r
- privs = {worldedit=true},\r
- func = function(name, param)\r
- local pos = worldedit.pos1[name]\r
- if pos == nil then\r
- minetest.chat_send_player(name, "No WorldEdit region selected")\r
- return\r
- end\r
-\r
- local found, _, axis, length, radius, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+([^%s]+)$")\r
- if found == nil then\r
- minetest.chat_send_player(name, "Invalid usage: " .. param)\r
- return\r
- end\r
- if axis == "?" then\r
- axis, sign = worldedit.player_axis(name)\r
- length = length * sign\r
- end\r
- if not worldedit.node_is_valid(pos, nodename) then\r
- minetest.chat_send_player(name, "Invalid node name: " .. param)\r
- return\r
- end\r
-\r
- local count = worldedit.hollow_cylinder(pos, axis, tonumber(length), tonumber(radius), nodename)\r
- minetest.chat_send_player(name, count .. " nodes added")\r
- end,\r
-})\r
-\r
-minetest.register_chatcommand("/cylinder", {\r
- params = "x/y/z/? <length> <radius> <node>",\r
- description = "Add cylinder at WorldEdit position 1 along the x/y/z/? axis with length <length> and radius <radius>, composed of <node>",\r
- privs = {worldedit=true},\r
- func = function(name, param)\r
- local pos = worldedit.pos1[name]\r
- if pos == nil then\r
- minetest.chat_send_player(name, "No WorldEdit region selected")\r
- return\r
- end\r
-\r
- local found, _, axis, length, radius, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+([^%s]+)$")\r
- if found == nil then\r
- minetest.chat_send_player(name, "Invalid usage: " .. param)\r
- return\r
- end\r
- if axis == "?" then\r
- axis, sign = worldedit.player_axis(name)\r
- length = length * sign\r
- end\r
- if not worldedit.node_is_valid(pos, nodename) then\r
- minetest.chat_send_player(name, "Invalid node name: " .. param)\r
- return\r
- end\r
-\r
- local count = worldedit.cylinder(pos, axis, tonumber(length), tonumber(radius), nodename)\r
- minetest.chat_send_player(name, count .. " nodes added")\r
- end,\r
-})\r
-\r
-minetest.register_chatcommand("/pyramid", {\r
- params = "<height> <node>",\r
- description = "Add pyramid at WorldEdit position 1 with height <height>, composed of <node>",\r
- privs = {worldedit=true},\r
- func = function(name, param)\r
- local pos = worldedit.pos1[name]\r
- if pos == nil then\r
- minetest.chat_send_player(name, "No WorldEdit region selected")\r
- return\r
- end\r
-\r
- local found, _, size, nodename = param:find("(%d+)%s+([^%s]+)$")\r
- if found == nil then\r
- minetest.chat_send_player(name, "Invalid usage: " .. param)\r
- return\r
- end\r
- if not worldedit.node_is_valid(pos, nodename) then\r
- minetest.chat_send_player(name, "Invalid node name: " .. param)\r
- return\r
- end\r
-\r
- local count = worldedit.pyramid(pos, tonumber(size), nodename)\r
- minetest.chat_send_player(name, count .. " nodes added")\r
- end,\r
-})\r
-\r
-minetest.register_chatcommand("/spiral", {\r
- params = "<width> <height> <space> <node>",\r
- description = "Add spiral at WorldEdit position 1 with width <width>, height <height>, space between walls <space>, composed of <node>",\r
- privs = {worldedit=true},\r
- func = function(name, param)\r
- local pos = worldedit.pos1[name]\r
- if pos == nil then\r
- minetest.chat_send_player(name, "No WorldEdit region selected")\r
- return\r
- end\r
-\r
- local found, _, width, height, space, nodename = param:find("(%d+)%s+(%d+)%s+(%d+)%s+([^%s]+)$")\r
- if found == nil then\r
- minetest.chat_send_player(name, "Invalid usage: " .. param)\r
- return\r
- end\r
- if not worldedit.node_is_valid(pos, nodename) then\r
- minetest.chat_send_player(name, "Invalid node name: " .. param)\r
- return\r
- end\r
-\r
- local count = worldedit.spiral(pos, tonumber(width), tonumber(height), tonumber(space), nodename)\r
- minetest.chat_send_player(name, count .. " nodes changed")\r
- end,\r
-})\r
-\r
-minetest.register_chatcommand("/copy", {\r
- params = "x/y/z/? <amount>",\r
- description = "Copy the current WorldEdit region along the x/y/z/? axis by <amount> nodes",\r
- privs = {worldedit=true},\r
- func = function(name, param)\r
- local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
- if pos1 == nil or pos2 == nil then\r
- minetest.chat_send_player(name, "No WorldEdit region selected")\r
- return\r
- end\r
-\r
- local found, _, axis, amount = param:find("^([xyz%?])%s+([+-]?%d+)$")\r
- if found == nil then\r
- minetest.chat_send_player(name, "Invalid usage: " .. param)\r
- return\r
- end\r
- if axis == "?" then\r
- axis, sign = worldedit.player_axis(name)\r
- amount = amount * sign\r
- end\r
-\r
- local count = worldedit.copy(pos1, pos2, axis, tonumber(amount))\r
- minetest.chat_send_player(name, count .. " nodes copied")\r
- end,\r
-})\r
-\r
-minetest.register_chatcommand("/move", {\r
- params = "x/y/z/? <amount>",\r
- description = "Move the current WorldEdit region along the x/y/z/? axis by <amount> nodes",\r
- privs = {worldedit=true},\r
- func = function(name, param)\r
- local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
- if pos1 == nil or pos2 == nil then\r
- minetest.chat_send_player(name, "No WorldEdit region selected")\r
- return\r
- end\r
-\r
- local found, _, axis, amount = param:find("^([xyz%?])%s+([+-]?%d+)$")\r
- if found == nil then\r
- minetest.chat_send_player(name, "Invalid usage: " .. param)\r
- return\r
- end\r
- if axis == "?" then\r
- axis, sign = worldedit.player_axis(name)\r
- amount = amount * sign\r
- end\r
-\r
- local count = worldedit.move(pos1, pos2, axis, tonumber(amount))\r
-\r
- pos1[axis] = pos1[axis] + amount\r
- pos2[axis] = pos2[axis] + amount\r
- worldedit.mark_pos1(name)\r
- worldedit.mark_pos2(name)\r
-\r
- minetest.chat_send_player(name, count .. " nodes moved")\r
- end,\r
-})\r
-\r
-minetest.register_chatcommand("/stack", {\r
- params = "x/y/z/? <count>",\r
- description = "Stack the current WorldEdit region along the x/y/z/? axis <count> times",\r
- privs = {worldedit=true},\r
- func = function(name, param)\r
- local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
- if pos1 == nil or pos2 == nil then\r
- minetest.chat_send_player(name, "No WorldEdit region selected")\r
- return\r
- end\r
-\r
- local found, _, axis, count = param:find("^([xyz%?])%s+([+-]?%d+)$")\r
- if found == nil then\r
- minetest.chat_send_player(name, "Invalid usage: " .. param)\r
- return\r
- end\r
- if axis == "?" then\r
- axis, sign = worldedit.player_axis(name)\r
- count = count * sign\r
- end\r
-\r
- local count = worldedit.stack(pos1, pos2, axis, tonumber(count))\r
- minetest.chat_send_player(name, count .. " nodes stacked")\r
- end,\r
-})\r
-\r
-minetest.register_chatcommand("/transpose", {\r
- params = "x/y/z/? x/y/z/?",\r
- description = "Transpose the current WorldEdit region along the x/y/z/? and x/y/z/? axes",\r
- privs = {worldedit=true},\r
- func = function(name, param)\r
- local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
- if pos1 == nil or pos2 == nil then\r
- minetest.chat_send_player(name, "No WorldEdit region selected")\r
- return\r
- end\r
-\r
- local found, _, axis1, axis2 = param:find("^([xyz%?])%s+([xyz%?])$")\r
- if found == nil then\r
- minetest.chat_send_player(name, "Invalid usage: " .. param)\r
- return\r
- end\r
- if axis1 == "?" then\r
- axis1 = worldedit.player_axis(name)\r
- end\r
- if axis2 == "?" then\r
- axis2 = worldedit.player_axis(name)\r
- end\r
- if axis1 == axis2 then\r
- minetest.chat_send_player(name, "Invalid usage: axes are the same")\r
- return\r
- end\r
-\r
- local count = worldedit.transpose(pos1, pos2, axis1, axis2)\r
- minetest.chat_send_player(name, count .. " nodes transposed")\r
- end,\r
-})\r
-\r
-minetest.register_chatcommand("/flip", {\r
- params = "x/y/z/?",\r
- description = "Flip the current WorldEdit region along the x/y/z/? axis",\r
- privs = {worldedit=true},\r
- func = function(name, param)\r
- local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
- if pos1 == nil or pos2 == nil then\r
- minetest.chat_send_player(name, "No WorldEdit region selected")\r
- return\r
- end\r
-\r
- if param == "?" then\r
- param = worldedit.player_axis(name)\r
- end\r
- if param ~= "x" and param ~= "y" and param ~= "z" then\r
- minetest.chat_send_player(name, "Invalid usage: " .. param)\r
- return\r
- end\r
-\r
- local count = worldedit.flip(pos1, pos2, param)\r
- minetest.chat_send_player(name, count .. " nodes flipped")\r
- end,\r
-})\r
-\r
-minetest.register_chatcommand("/rotate", {\r
- params = "<axis> <angle>",\r
- description = "Rotate the current WorldEdit region around the axis <axis> by angle <angle> (90 degree increment)",\r
- privs = {worldedit=true},\r
- func = function(name, param)\r
- local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
- if pos1 == nil or pos2 == nil then\r
- minetest.chat_send_player(name, "No WorldEdit region selected")\r
- return\r
- end\r
-\r
- local found, _, axis, angle = param:find("^([xyz%?])%s+([+-]?%d+)$")\r
- if found == nil then\r
- minetest.chat_send_player(name, "Invalid usage: " .. param)\r
- return\r
- end\r
- if axis == "?" then\r
- axis = worldedit.player_axis(name)\r
- end\r
- if angle % 90 ~= 0 then\r
- minetest.chat_send_player(name, "Invalid usage: angle must be multiple of 90")\r
- return\r
- end\r
-\r
- local count = worldedit.rotate(pos1, pos2, axis, angle)\r
- minetest.chat_send_player(name, count .. " nodes rotated")\r
- end,\r
-})\r
-\r
-minetest.register_chatcommand("/dig", {\r
- params = "",\r
- description = "Dig the current WorldEdit region",\r
- privs = {worldedit=true},\r
- func = function(name, param)\r
- local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
- if pos1 == nil or pos2 == nil then\r
- minetest.chat_send_player(name, "No WorldEdit region selected")\r
- return\r
- end\r
-\r
- local count = worldedit.dig(pos1, pos2)\r
- minetest.chat_send_player(name, count .. " nodes dug")\r
- end,\r
-})\r
-\r
-minetest.register_chatcommand("/save", {\r
- params = "<file>",\r
- description = "Save the current WorldEdit region to \"(world folder)/schems/<file>.we\"",\r
- privs = {worldedit=true},\r
- func = function(name, param)\r
- local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
- if pos1 == nil or pos2 == nil then\r
- minetest.chat_send_player(name, "No WorldEdit region selected")\r
- return\r
- end\r
-\r
- if param == "" then\r
- minetest.chat_send_player(name, "Invalid usage: " .. param)\r
- return\r
- end\r
-\r
- local result, count = worldedit.serialize(pos1, pos2)\r
-\r
- local path = minetest.get_worldpath() .. "/schems"\r
- local filename = path .. "/" .. param .. ".we"\r
- os.execute("mkdir \"" .. path .. "\"") --create directory if it does not already exist\r
- local file, err = io.open(filename, "wb")\r
- if err ~= nil then\r
- minetest.chat_send_player(name, "Could not save file to \"" .. filename .. "\"")\r
- return\r
- end\r
- file:write(result)\r
- file:flush()\r
- file:close()\r
-\r
- minetest.chat_send_player(name, count .. " nodes saved")\r
- end,\r
-})\r
-\r
-minetest.register_chatcommand("/load", {\r
- params = "<file>",\r
- description = "Load nodes from \"(world folder)/schems/<file>.we\" with position 1 of the current WorldEdit region as the origin",\r
- privs = {worldedit=true},\r
- func = function(name, param)\r
- local pos1 = worldedit.pos1[name]\r
- if pos1 == nil then\r
- minetest.chat_send_player(name, "No WorldEdit region selected")\r
- return\r
- end\r
-\r
- if param == "" then\r
- minetest.chat_send_player(name, "Invalid usage: " .. param)\r
- return\r
- end\r
-\r
- local filename = minetest.get_worldpath() .. "/schems/" .. param .. ".we"\r
- local file, err = io.open(filename, "rb")\r
- if err ~= nil then\r
- minetest.chat_send_player(name, "Could not open file \"" .. filename .. "\"")\r
- return\r
- end\r
- local value = file:read("*a")\r
- file:close()\r
-\r
- local count\r
- if value:find("{") then --old WorldEdit format\r
- count = worldedit.deserialize_old(pos1, value)\r
- else --new WorldEdit format\r
- count = worldedit.deserialize(pos1, value)\r
- end\r
-\r
- minetest.chat_send_player(name, count .. " nodes loaded")\r
- end,\r
-})\r
-\r
-minetest.register_chatcommand("/metasave", {\r
- params = "<file>",\r
- description = "Save the current WorldEdit region to \"(world folder)/schems/<file>.wem\"",\r
- privs = {worldedit=true},\r
- func = function(name, param)\r
- local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
- if pos1 == nil or pos2 == nil then\r
- minetest.chat_send_player(name, "No WorldEdit region selected")\r
- return\r
- end\r
- if param == "" then\r
- minetest.chat_send_player(name, "Invalid usage: " .. param)\r
- return\r
- end\r
- local count, err = worldedit.metasave(pos1, pos2, param)\r
- if err then\r
- minetest.chat_send_player(name, "error loading file: " .. err)\r
- else\r
- minetest.chat_send_player(name, count .. " nodes saved")\r
- end\r
- end,\r
-})\r
-\r
-minetest.register_chatcommand("/metaload", {\r
- params = "<file>",\r
- description = "Load nodes from \"(world folder)/schems/<file>.wem\" with position 1 of the current WorldEdit region as the origin",\r
- privs = {worldedit=true},\r
- func = function(name, param)\r
- local pos1 = worldedit.pos1[name]\r
- if pos1 == nil then\r
- minetest.chat_send_player(name, "No WorldEdit region selected")\r
- return\r
- end\r
- if param == "" then\r
- minetest.chat_send_player(name, "Invalid usage: " .. param)\r
- return\r
- end\r
- local count, err = worldedit.metaload(pos1, param)\r
- if err then\r
- minetest.chat_send_player(name, "error loading file: " .. err)\r
- else\r
- minetest.chat_send_player(name, count .. " nodes loaded")\r
- end\r
- end,\r
-})\r
+dofile(minetest.get_modpath("worldedit") .. "/manipulations.lua")\r
+dofile(minetest.get_modpath("worldedit") .. "/primitives.lua")\r
+dofile(minetest.get_modpath("worldedit") .. "/visualization.lua")\r
+dofile(minetest.get_modpath("worldedit") .. "/serialization.lua")
\ No newline at end of file
--- /dev/null
+worldedit = worldedit or {}\r
+\r
+--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\r
+worldedit.sort_pos = function(pos1, pos2)\r
+ pos1 = {x=pos1.x, y=pos1.y, z=pos1.z}\r
+ pos2 = {x=pos2.x, y=pos2.y, z=pos2.z}\r
+ if pos1.x > pos2.x then\r
+ pos2.x, pos1.x = pos1.x, pos2.x\r
+ end\r
+ if pos1.y > pos2.y then\r
+ pos2.y, pos1.y = pos1.y, pos2.y\r
+ end\r
+ if pos1.z > pos2.z then\r
+ pos2.z, pos1.z = pos1.z, pos2.z\r
+ end\r
+ return pos1, pos2\r
+end\r
+\r
+--determines the volume of the region defined by positions `pos1` and `pos2`, returning the volume\r
+worldedit.volume = function(pos1, pos2)\r
+ local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
+ return (pos2.x - pos1.x + 1) * (pos2.y - pos1.y + 1) * (pos2.z - pos1.z + 1)\r
+end\r
+\r
+--sets a region defined by positions `pos1` and `pos2` to `nodename`, returning the number of nodes filled\r
+worldedit.set = function(pos1, pos2, nodename)\r
+ local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
+ local env = minetest.env\r
+\r
+ local node = {name=nodename}\r
+ local pos = {x=pos1.x, y=0, z=0}\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
+ env:add_node(pos, node)\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
+end\r
+\r
+--replaces all instances of `searchnode` with `replacenode` in a region defined by positions `pos1` and `pos2`, returning the number of nodes replaced\r
+worldedit.replace = function(pos1, pos2, searchnode, replacenode)\r
+ local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
+ local env = minetest.env\r
+\r
+ if minetest.registered_nodes[searchnode] == nil then\r
+ searchnode = "default:" .. searchnode\r
+ end\r
+\r
+ local pos = {x=pos1.x, y=0, z=0}\r
+ local node = {name=replacenode}\r
+ local count = 0\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
+ if env:get_node(pos).name == searchnode then\r
+ env:add_node(pos, node)\r
+ count = count + 1\r
+ end\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 count\r
+end\r
+\r
+--copies the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") by `amount` nodes, returning the number of nodes copied\r
+worldedit.copy = function(pos1, pos2, axis, amount)\r
+ local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
+ local env = minetest.env\r
+\r
+ if amount < 0 then\r
+ local pos = {x=pos1.x, y=0, z=0}\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 = env:get_node(pos) --obtain current node\r
+ local meta = env: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
+ env:add_node(pos, node) --copy node to new position\r
+ env: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 = {x=pos2.x, y=0, z=0}\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 = minetest.env:get_node(pos) --obtain current node\r
+ local meta = env: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
+ minetest.env:add_node(pos, node) --copy node to new position\r
+ env: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
+ end\r
+ return worldedit.volume(pos1, pos2)\r
+end\r
+\r
+--moves the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") by `amount` nodes, returning the number of nodes moved\r
+worldedit.move = function(pos1, pos2, axis, amount)\r
+ local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
+ local env = minetest.env\r
+\r
+ if amount < 0 then\r
+ local pos = {x=pos1.x, y=0, z=0}\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 = env:get_node(pos) --obtain current node\r
+ local meta = env:get_meta(pos):to_table() --get metadata of current node\r
+ env:remove_node(pos)\r
+ local value = pos[axis] --store current position\r
+ pos[axis] = value + amount --move along axis\r
+ env:add_node(pos, node) --move node to new position\r
+ env: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 = {x=pos2.x, y=0, z=0}\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 = env:get_node(pos) --obtain current node\r
+ local meta = env:get_meta(pos):to_table() --get metadata of current node\r
+ env:remove_node(pos)\r
+ local value = pos[axis] --store current position\r
+ pos[axis] = value + amount --move along axis\r
+ env:add_node(pos, node) --move node to new position\r
+ env: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
+ end\r
+ return worldedit.volume(pos1, pos2)\r
+end\r
+\r
+--duplicates the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") `count` times, returning the number of nodes stacked\r
+worldedit.stack = function(pos1, pos2, axis, count)\r
+ local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
+ local length = pos2[axis] - pos1[axis] + 1\r
+ if count < 0 then\r
+ count = -count\r
+ length = -length\r
+ end\r
+ local amount = 0\r
+ local copy = worldedit.copy\r
+ for i = 1, count do\r
+ amount = amount + length\r
+ copy(pos1, pos2, axis, amount)\r
+ end\r
+ return worldedit.volume(pos1, pos2)\r
+end\r
+\r
+--transposes a region defined by the positions `pos1` and `pos2` between the `axis1` and `axis2` axes, returning the number of nodes transposed\r
+worldedit.transpose = function(pos1, pos2, axis1, axis2)\r
+ local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
+\r
+ local pos = {x=pos1.x, y=0, z=0}\r
+ local env = minetest.env\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 extent1, extent2 = pos[axis1] - pos1[axis1], pos[axis2] - pos1[axis2]\r
+ if extent1 < extent2 then\r
+ local node1 = env:get_node(pos)\r
+ local meta1 = env:get_meta(pos):to_table()\r
+ local value1, value2 = pos[axis1], pos[axis2]\r
+ pos[axis1], pos[axis2] = value1 + extent2, value2 + extent1\r
+ local node2 = env:get_node(pos)\r
+ local meta2 = env:get_meta(pos):to_table()\r
+ env:add_node(pos, node1)\r
+ env:get_meta(pos):from_table(meta1)\r
+ pos[axis1], pos[axis2] = value1, value2\r
+ env:add_node(pos, node2)\r
+ env:get_meta(pos):from_table(meta2)\r
+ end\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
+end\r
+\r
+--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\r
+worldedit.flip = function(pos1, pos2, axis)\r
+ local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
+\r
+ local pos = {x=pos1.x, y=0, z=0}\r
+ local start = pos1[axis] + pos2[axis]\r
+ pos2[axis] = pos1[axis] + math.floor((pos2[axis] - pos1[axis]) / 2)\r
+ local env = minetest.env\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 node1 = env:get_node(pos)\r
+ local meta1 = env:get_meta(pos):to_table()\r
+ local value = pos[axis]\r
+ pos[axis] = start - value\r
+ local node2 = env:get_node(pos)\r
+ local meta2 = env:get_meta(pos):to_table()\r
+ env:add_node(pos, node1)\r
+ env:get_meta(pos):from_table(meta1)\r
+ pos[axis] = value\r
+ env:add_node(pos, node2)\r
+ env:get_meta(pos):from_table(meta2)\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
+end\r
+\r
+--rotates a region defined by the positions `pos1` and `pos2` by `angle` degrees clockwise around axis `axis` (90 degree increment), returning the number of nodes rotated\r
+worldedit.rotate = function(pos1, pos2, axis, angle)\r
+ local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
+\r
+ local axis1, axis2\r
+ if axis == "x" then\r
+ axis1, axis2 = "z", "y"\r
+ elseif axis == "y" then\r
+ axis1, axis2 = "x", "z"\r
+ else --axis == "z"\r
+ axis1, axis2 = "y", "x"\r
+ end\r
+ angle = angle % 360\r
+\r
+ if angle == 90 then\r
+ worldedit.transpose(pos1, pos2, axis1, axis2)\r
+ worldedit.flip(pos1, pos2, axis2)\r
+ elseif angle == 180 then\r
+ worldedit.flip(pos1, pos2, axis1)\r
+ worldedit.flip(pos1, pos2, axis2)\r
+ elseif angle == 270 then\r
+ worldedit.transpose(pos1, pos2, axis1, axis2)\r
+ worldedit.flip(pos1, pos2, axis1)\r
+ end\r
+ return worldedit.volume(pos1, pos2)\r
+end\r
+\r
+--digs a region defined by positions `pos1` and `pos2`, returning the number of nodes dug\r
+worldedit.dig = function(pos1, pos2)\r
+ local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
+ local env = minetest.env\r
+\r
+ local pos = {x=pos1.x, y=0, z=0}\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
+ env:dig_node(pos)\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
+end
\ No newline at end of file
+++ /dev/null
-worldedit.marker1 = {}\r
-worldedit.marker2 = {}\r
-\r
---marks worldedit region position 1\r
-worldedit.mark_pos1 = function(name)\r
- local pos = worldedit.pos1[name]\r
- if worldedit.marker1[name] ~= nil then --marker already exists\r
- worldedit.marker1[name]:remove() --remove marker\r
- worldedit.marker1[name] = nil\r
- end\r
- if pos ~= nil then --add marker\r
- worldedit.marker1[name] = minetest.env:add_entity(pos, "worldedit:pos1")\r
- worldedit.marker1[name]:get_luaentity().active = true\r
- end\r
-end\r
-\r
---marks worldedit region position 2\r
-worldedit.mark_pos2 = function(name)\r
- local pos = worldedit.pos2[name]\r
- if worldedit.marker2[name] ~= nil then --marker already exists\r
- worldedit.marker2[name]:remove() --remove marker\r
- worldedit.marker2[name] = nil\r
- end\r
- if pos ~= nil then --add marker\r
- worldedit.marker2[name] = minetest.env:add_entity(pos, "worldedit:pos2")\r
- worldedit.marker2[name]:get_luaentity().active = true\r
- end\r
-end\r
-\r
-minetest.register_entity("worldedit:pos1", {\r
- initial_properties = {\r
- visual = "cube",\r
- visual_size = {x=1.1, y=1.1},\r
- textures = {"worldedit_pos1.png", "worldedit_pos1.png",\r
- "worldedit_pos1.png", "worldedit_pos1.png",\r
- "worldedit_pos1.png", "worldedit_pos1.png"},\r
- collisionbox = {-0.55, -0.55, -0.55, 0.55, 0.55, 0.55},\r
- },\r
- on_step = function(self, dtime)\r
- if self.active == nil then\r
- self.object:remove()\r
- end\r
- end,\r
- on_punch = function(self, hitter)\r
- self.object:remove()\r
- local name = hitter:get_player_name()\r
- worldedit.marker1[name] = nil\r
- end,\r
-})\r
-\r
-minetest.register_entity("worldedit:pos2", {\r
- initial_properties = {\r
- visual = "cube",\r
- visual_size = {x=1.1, y=1.1},\r
- textures = {"worldedit_pos2.png", "worldedit_pos2.png",\r
- "worldedit_pos2.png", "worldedit_pos2.png",\r
- "worldedit_pos2.png", "worldedit_pos2.png"},\r
- collisionbox = {-0.55, -0.55, -0.55, 0.55, 0.55, 0.55},\r
- },\r
- on_step = function(self, dtime)\r
- if self.active == nil then\r
- self.object:remove()\r
- end\r
- end,\r
- on_punch = function(self, hitter)\r
- self.object:remove()\r
- local name = hitter:get_player_name()\r
- worldedit.marker2[name] = nil\r
- end,\r
-})
\ No newline at end of file
--- /dev/null
+worldedit = worldedit or {}\r
+\r
+--adds a hollow sphere at `pos` with radius `radius`, composed of `nodename`, returning the number of nodes added\r
+worldedit.hollow_sphere = function(pos, radius, nodename) --wip: use bresenham sphere for maximum speed\r
+ local node = {name=nodename}\r
+ local pos1 = {x=0, y=0, z=0}\r
+ local full_radius = radius * radius + radius\r
+ local env = minetest.env\r
+ for x = -radius, radius do\r
+ pos1.x = pos.x + x\r
+ for y = -radius, radius do\r
+ pos1.y = pos.y + y\r
+ for z = -radius, radius do\r
+ if x*x+y*y+z*z >= (radius-1) * (radius-1) + (radius-1) and x*x+y*y+z*z <= full_radius then\r
+ pos1.z = pos.z + z\r
+ env:add_node({x=pos.x+x,y=pos.y+y,z=pos.z+z}, node)\r
+ end\r
+ end\r
+ end\r
+ end\r
+end\r
+\r
+--adds a sphere at `pos` with radius `radius`, composed of `nodename`, returning the number of nodes added\r
+worldedit.sphere = function(pos, radius, nodename) --wip: use bresenham sphere for maximum speed\r
+ local node = {name=nodename}\r
+ local pos1 = {x=0, y=0, z=0}\r
+ local full_radius = radius * radius + radius\r
+ local count = 0\r
+ local env = minetest.env\r
+ for x = -radius, radius do\r
+ pos1.x = pos.x + x\r
+ for y = -radius, radius do\r
+ pos1.y = pos.y + y\r
+ for z = -radius, radius do\r
+ if x*x+y*y+z*z <= full_radius then\r
+ pos1.z = pos.z + z\r
+ env:add_node(pos1, node)\r
+ count = count + 1\r
+ end\r
+ end\r
+ end\r
+ end\r
+ return count\r
+end\r
+\r
+--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\r
+worldedit.hollow_cylinder = function(pos, axis, length, radius, nodename)\r
+ local other1, other2\r
+ if axis == "x" then\r
+ other1, other2 = "y", "z"\r
+ elseif axis == "y" then\r
+ other1, other2 = "x", "z"\r
+ else --axis == "z"\r
+ other1, other2 = "x", "y"\r
+ end\r
+\r
+ local env = minetest.env\r
+ local currentpos = {x=pos.x, y=pos.y, z=pos.z}\r
+ local node = {name=nodename}\r
+ local count = 0\r
+ local step = 1\r
+ if length < 0 then\r
+ length = -length\r
+ step = -1\r
+ end\r
+ for i = 1, length do\r
+ local offset1, offset2 = 0, radius\r
+ local delta = -radius\r
+ while offset1 <= offset2 do\r
+ --add node at each octant\r
+ local first1, first2 = pos[other1] + offset1, pos[other1] - offset1\r
+ local second1, second2 = pos[other2] + offset2, pos[other2] - offset2\r
+ currentpos[other1], currentpos[other2] = first1, second1\r
+ env:add_node(currentpos, node) --octant 1\r
+ currentpos[other1] = first2\r
+ env:add_node(currentpos, node) --octant 4\r
+ currentpos[other2] = second2\r
+ env:add_node(currentpos, node) --octant 5\r
+ currentpos[other1] = first1\r
+ env:add_node(currentpos, node) --octant 8\r
+ local first1, first2 = pos[other1] + offset2, pos[other1] - offset2\r
+ local second1, second2 = pos[other2] + offset1, pos[other2] - offset1\r
+ currentpos[other1], currentpos[other2] = first1, second1\r
+ env:add_node(currentpos, node) --octant 2\r
+ currentpos[other1] = first2\r
+ env:add_node(currentpos, node) --octant 3\r
+ currentpos[other2] = second2\r
+ env:add_node(currentpos, node) --octant 6\r
+ currentpos[other1] = first1\r
+ env:add_node(currentpos, node) --octant 7\r
+\r
+ count = count + 8 --wip: broken\r
+\r
+ --move to next location\r
+ delta = delta + (offset1 * 2) + 1\r
+ if delta >= 0 then\r
+ offset2 = offset2 - 1\r
+ delta = delta - (offset2 * 2)\r
+ end\r
+ offset1 = offset1 + 1\r
+ end\r
+ currentpos[axis] = currentpos[axis] + step\r
+ end\r
+ return count\r
+end\r
+\r
+--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\r
+worldedit.cylinder = function(pos, axis, length, radius, nodename)\r
+ local other1, other2\r
+ if axis == "x" then\r
+ other1, other2 = "y", "z"\r
+ elseif axis == "y" then\r
+ other1, other2 = "x", "z"\r
+ else --axis == "z"\r
+ other1, other2 = "x", "y"\r
+ end\r
+\r
+ local env = minetest.env\r
+ local currentpos = {x=pos.x, y=pos.y, z=pos.z}\r
+ local node = {name=nodename}\r
+ local count = 0\r
+ local step = 1\r
+ if length < 0 then\r
+ length = -length\r
+ step = -1\r
+ end\r
+ for i = 1, length do\r
+ local offset1, offset2 = 0, radius\r
+ local delta = -radius\r
+ while offset1 <= offset2 do\r
+ --connect each pair of octants\r
+ currentpos[other1] = pos[other1] - offset1\r
+ local second1, second2 = pos[other2] + offset2, pos[other2] - offset2\r
+ for i = 0, offset1 * 2 do\r
+ currentpos[other2] = second1\r
+ env:add_node(currentpos, node) --octant 1 to 4\r
+ currentpos[other2] = second2\r
+ env:add_node(currentpos, node) --octant 5 to 8\r
+ currentpos[other1] = currentpos[other1] + 1\r
+ end\r
+ currentpos[other1] = pos[other1] - offset2\r
+ local second1, second2 = pos[other2] + offset1, pos[other2] - offset1\r
+ for i = 0, offset2 * 2 do\r
+ currentpos[other2] = second1\r
+ env:add_node(currentpos, node) --octant 2 to 3\r
+ currentpos[other2] = second2\r
+ env:add_node(currentpos, node) --octant 6 to 7\r
+ currentpos[other1] = currentpos[other1] + 1\r
+ end\r
+\r
+ count = count + (offset1 * 4) + (offset2 * 4) + 4 --wip: broken\r
+\r
+ --move to next location\r
+ delta = delta + (offset1 * 2) + 1\r
+ offset1 = offset1 + 1\r
+ if delta >= 0 then\r
+ offset2 = offset2 - 1\r
+ delta = delta - (offset2 * 2)\r
+ end\r
+ end\r
+ currentpos[axis] = currentpos[axis] + step\r
+ end\r
+ return count\r
+end\r
+\r
+--adds a pyramid at `pos` with height `height`, composed of `nodename`, returning the number of nodes added\r
+worldedit.pyramid = function(pos, height, nodename)\r
+ local pos1x, pos1y, pos1z = pos.x - height, pos.y, pos.z - height\r
+ local pos2x, pos2y, pos2z = pos.x + height, pos.y + height, pos.z + height\r
+ local pos = {x=0, y=pos1y, z=0}\r
+\r
+ local count = 0\r
+ local node = {name=nodename}\r
+ local env = minetest.env\r
+ while pos.y <= pos2y do --each vertical level of the pyramid\r
+ pos.x = pos1x\r
+ while pos.x <= pos2x do\r
+ pos.z = pos1z\r
+ while pos.z <= pos2z do\r
+ env:add_node(pos, node)\r
+ pos.z = pos.z + 1\r
+ end\r
+ pos.x = pos.x + 1\r
+ end\r
+ count = count + ((pos2y - pos.y) * 2 + 1) ^ 2\r
+ pos.y = pos.y + 1\r
+\r
+ pos1x, pos2x = pos1x + 1, pos2x - 1\r
+ pos1z, pos2z = pos1z + 1, pos2z - 1\r
+\r
+ end\r
+ return count\r
+end\r
+\r
+--adds a spiral at `pos` with width `width`, height `height`, space between walls `spacer`, composed of `nodename`, returning the number of nodes added\r
+worldedit.spiral = function(pos, width, height, spacer, nodename) --wip: clean this up\r
+ -- spiral matrix - http://rosettacode.org/wiki/Spiral_matrix#Lua\r
+ av, sn = math.abs, function(s) return s~=0 and s/av(s) or 0 end\r
+ local function sindex(z, x) -- returns the value at (x, z) in a spiral that starts at 1 and goes outwards\r
+ if z == -x and z >= x then return (2*z+1)^2 end\r
+ local l = math.max(av(z), av(x))\r
+ return (2*l-1)^2+4*l+2*l*sn(x+z)+sn(z^2-x^2)*(l-(av(z)==l and sn(z)*x or sn(x)*z)) -- OH GOD WHAT\r
+ end\r
+ local function spiralt(side)\r
+ local ret, id, start, stop = {}, 0, math.floor((-side+1)/2), math.floor((side-1)/2)\r
+ for i = 1, side do\r
+ for j = 1, side do\r
+ local id = side^2 - sindex(stop - i + 1,start + j - 1)\r
+ ret[id] = {x=i,z=j}\r
+ end\r
+ end\r
+ return ret\r
+ end\r
+ -- connect the joined parts\r
+ local spiral = spiralt(width)\r
+ height = tonumber(height)\r
+ if height < 1 then height = 1 end\r
+ spacer = tonumber(spacer)-1\r
+ if spacer < 1 then spacer = 1 end\r
+ local count = 0\r
+ local node = {name=nodename}\r
+ local np,lp\r
+ for y=0,height do\r
+ lp = nil\r
+ for _,v in ipairs(spiral) do\r
+ np = {x=pos.x+v.x*spacer, y=pos.y+y, z=pos.z+v.z*spacer}\r
+ if lp~=nil then\r
+ if lp.x~=np.x then \r
+ if lp.x<np.x then \r
+ for i=lp.x+1,np.x do\r
+ minetest.env:add_node({x=i, y=np.y, z=np.z}, node)\r
+ count = count + 1\r
+ end\r
+ else\r
+ for i=np.x,lp.x-1 do\r
+ minetest.env:add_node({x=i, y=np.y, z=np.z}, node)\r
+ count = count + 1\r
+ end\r
+ end\r
+ end\r
+ if lp.z~=np.z then \r
+ if lp.z<np.z then \r
+ for i=lp.z+1,np.z do\r
+ minetest.env:add_node({x=np.x, y=np.y, z=i}, node)\r
+ count = count + 1\r
+ end\r
+ else\r
+ for i=np.z,lp.z-1 do\r
+ minetest.env:add_node({x=np.x, y=np.y, z=i}, node)\r
+ count = count + 1\r
+ end\r
+ end\r
+ end\r
+ end\r
+ lp = np\r
+ end\r
+ end\r
+ return count\r
+end
\ No newline at end of file
--- /dev/null
+worldedit = worldedit or {}\r
+\r
+dofile(minetest.get_modpath("worldedit") .. "/table_save.lua") --wip: remove dependency\r
+\r
+--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\r
+worldedit.sort_pos = function(pos1, pos2)\r
+ pos1 = {x=pos1.x, y=pos1.y, z=pos1.z}\r
+ pos2 = {x=pos2.x, y=pos2.y, z=pos2.z}\r
+ if pos1.x > pos2.x then\r
+ pos2.x, pos1.x = pos1.x, pos2.x\r
+ end\r
+ if pos1.y > pos2.y then\r
+ pos2.y, pos1.y = pos1.y, pos2.y\r
+ end\r
+ if pos1.z > pos2.z then\r
+ pos2.z, pos1.z = pos1.z, pos2.z\r
+ end\r
+ return pos1, pos2\r
+end\r
+\r
+--converts the region defined by positions `pos1` and `pos2` into a single string, returning the serialized data and the number of nodes serialized\r
+worldedit.serialize = function(pos1, pos2)\r
+ local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
+ local pos = {x=pos1.x, y=0, z=0}\r
+ local count = 0\r
+ local result = {}\r
+ local env = minetest.env\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 = env:get_node(pos)\r
+ if node.name ~= "air" and node.name ~= "ignore" then\r
+ count = count + 1\r
+ result[count] = pos.x - pos1.x .. " " .. pos.y - pos1.y .. " " .. pos.z - pos1.z .. " " .. node.name .. " " .. node.param1 .. " " .. node.param2\r
+ end\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
+ result = table.concat(result, "\n") --join all node entries into single string\r
+ return result, count\r
+end\r
+\r
+--loads the nodes represented by string `value` at position `originpos`, returning the number of nodes deserialized\r
+worldedit.deserialize = function(originpos, value)\r
+ local pos = {x=0, y=0, z=0}\r
+ local node = {name="", param1=0, param2=0}\r
+ local count = 0\r
+ local env = minetest.env\r
+ for x, y, z, name, param1, param2 in value:gmatch("([+-]?%d+)%s+([+-]?%d+)%s+([+-]?%d+)%s+([^%s]+)%s+(%d+)%s+(%d+)[^\r\n]*[\r\n]*") do --match node entries\r
+ pos.x = originpos.x + tonumber(x)\r
+ pos.y = originpos.y + tonumber(y)\r
+ pos.z = originpos.z + tonumber(z)\r
+ node.name = name\r
+ node.param1 = param1\r
+ node.param2 = param2\r
+ env:add_node(pos, node)\r
+ count = count + 1\r
+ end\r
+ return count\r
+end\r
+\r
+--loads the nodes represented by string `value` at position `originpos`, returning the number of nodes deserialized\r
+--based on [table.save/table.load](http://lua-users.org/wiki/SaveTableToFile) by ChillCode, available under the MIT license (GPL compatible)\r
+worldedit.deserialize_old = function(originpos, value)\r
+ --obtain the node table\r
+ local count = 0\r
+ local get_tables = loadstring(value)\r
+ if get_tables == nil then --error loading value\r
+ return count\r
+ end\r
+ local tables = get_tables()\r
+\r
+ --transform the node table into an array of nodes\r
+ for i = 1, #tables do\r
+ for j, v in pairs(tables[i]) do\r
+ if type(v) == "table" then\r
+ tables[i][j] = tables[v[1]]\r
+ end\r
+ end\r
+ end\r
+\r
+ --load the node array\r
+ local env = minetest.env\r
+ for i, v in ipairs(tables[1]) do\r
+ local pos = v[1]\r
+ pos.x, pos.y, pos.z = originpos.x + pos.x, originpos.y + pos.y, originpos.z + pos.z\r
+ env:add_node(pos, v[2])\r
+ count = count + 1\r
+ end\r
+ return count\r
+end\r
+\r
+--saves the nodes and meta defined by positions `pos1` and `pos2` into a file, returning the number of nodes saved\r
+worldedit.metasave = function(pos1, pos2, file) --wip: simply work with strings instead of doing IO\r
+ local path = minetest.get_worldpath() .. "/schems"\r
+ local filename = path .. "/" .. file .. ".wem"\r
+ os.execute("mkdir \"" .. path .. "\"") --create directory if it does not already exist\r
+ local rows = {}\r
+ local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
+ local pos = {x=pos1.x, y=0, z=0}\r
+ local count = 0\r
+ local result = {}\r
+ local env = minetest.env\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 = env:get_node(pos)\r
+ if node.name ~= "air" and node.name ~= "ignore" then\r
+ count = count + 1\r
+ local row = {\r
+ x = pos.x-pos1.x,\r
+ y = pos.y-pos1.y,\r
+ z = pos.z-pos1.z,\r
+ name = node.name,\r
+ param1 = node.param1,\r
+ param2 = node.param2,\r
+ meta = env:get_meta(pos):to_table(),\r
+ }\r
+ table.insert(rows, row)\r
+ end\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 err = table.save(rows,filename)\r
+ if err then return _,err end\r
+ return count\r
+end\r
+\r
+--loads the nodes and meta from `file` to position `pos1`, returning the number of nodes loaded\r
+worldedit.metaload = function(pos1, file) --wip: simply work with strings instead of doing IO\r
+ local filename = minetest.get_worldpath() .. "/schems/" .. file .. ".wem"\r
+ local rows, err = table.load(filename)\r
+ if err then return _,err end\r
+ local pos = {x=0, y=0, z=0}\r
+ local node = {name="", param1=0, param2=0}\r
+ local count = 0\r
+ local env = minetest.env\r
+ for i,row in pairs(rows) do\r
+ pos.x = pos1.x + tonumber(row.x)\r
+ pos.y = pos1.y + tonumber(row.y)\r
+ pos.z = pos1.z + tonumber(row.z)\r
+ node.name = row.name\r
+ node.param1 = row.param1\r
+ node.param2 = row.param2\r
+ env:add_node(pos, node)\r
+ env:get_meta(pos):from_table(row.meta)\r
+ count = count + 1\r
+ end\r
+ return count\r
+end
\ No newline at end of file
--- /dev/null
+worldedit = worldedit or {}\r
+\r
+--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\r
+worldedit.sort_pos = function(pos1, pos2)\r
+ pos1 = {x=pos1.x, y=pos1.y, z=pos1.z}\r
+ pos2 = {x=pos2.x, y=pos2.y, z=pos2.z}\r
+ if pos1.x > pos2.x then\r
+ pos2.x, pos1.x = pos1.x, pos2.x\r
+ end\r
+ if pos1.y > pos2.y then\r
+ pos2.y, pos1.y = pos1.y, pos2.y\r
+ end\r
+ if pos1.z > pos2.z then\r
+ pos2.z, pos1.z = pos1.z, pos2.z\r
+ end\r
+ return pos1, pos2\r
+end\r
+\r
+--determines the volume of the region defined by positions `pos1` and `pos2`, returning the volume\r
+worldedit.volume = function(pos1, pos2)\r
+ local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
+ return (pos2.x - pos1.x + 1) * (pos2.y - pos1.y + 1) * (pos2.z - pos1.z + 1)\r
+end\r
+\r
+minetest.register_node("worldedit:placeholder", {\r
+ drawtype = "airlike",\r
+ paramtype = "light",\r
+ sunlight_propagates = true,\r
+ diggable = false,\r
+ groups = {not_in_creative_inventory=1},\r
+})\r
+\r
+--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\r
+worldedit.hide = function(pos1, pos2)\r
+ local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
+ local env = minetest.env\r
+\r
+ local pos = {x=pos1.x, y=0, z=0}\r
+ local placeholder = {name="worldedit:placeholder", param1=0, param2=0}\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 = env:get_node(pos)\r
+ placeholder.param1, placeholder.param2 = node.param1, node.param2 --copy node's param1 and param2\r
+ local data = env:get_meta(pos):to_table() --obtain metadata of original node\r
+ env:add_node(pos, placeholder) --add placeholder node\r
+ local meta = env:get_meta(pos) --obtain placeholder meta\r
+ meta:from_table(data) --set placeholder metadata to the original node's metadata\r
+ meta:set_string("worldedit_placeholder", node.name) --add the node's name\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
+end\r
+\r
+--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\r
+worldedit.suppress = function(pos1, pos2, nodename)\r
+ local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
+ local env = minetest.env\r
+\r
+ if minetest.registered_nodes[nodename] == nil then\r
+ nodename = "default:" .. nodename\r
+ end\r
+\r
+ local pos = {x=pos1.x, y=0, z=0}\r
+ local placeholder = {name="worldedit:placeholder", param1=0, param2=0}\r
+ local count = 0\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 = env:get_node(pos)\r
+ if node.name == nodename then\r
+ placeholder.param1, placeholder.param2 = node.param1, node.param2 --copy node's param1 and param2\r
+ local data = env:get_meta(pos):to_table() --obtain metadata of original node\r
+ env:add_node(pos, placeholder) --add placeholder node\r
+ local meta = env:get_meta(pos) --obtain placeholder meta\r
+ meta:from_table(data) --set placeholder metadata to the original node's metadata\r
+ meta:set_string("worldedit_placeholder", nodename) --add the node's name\r
+ count = count + 1\r
+ end\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 count\r
+end\r
+\r
+--finds 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\r
+worldedit.find = function(pos1, pos2, nodename)\r
+ local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
+ local env = minetest.env\r
+\r
+ if minetest.registered_nodes[nodename] == nil then\r
+ nodename = "default:" .. nodename\r
+ end\r
+\r
+ local pos = {x=pos1.x, y=0, z=0}\r
+ local placeholder = {name="worldedit:placeholder", param1=0, param2=0}\r
+ local count = 0\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 = env:get_node(pos)\r
+ if node.name == nodename then --node found\r
+ count = count + 1\r
+ else --hide other nodes\r
+ placeholder.param1, placeholder.param2 = node.param1, node.param2 --copy node's param1 and param2\r
+ local data = env:get_meta(pos):to_table() --obtain metadata of original node\r
+ env:add_node(pos, placeholder) --add placeholder node\r
+ local meta = env:get_meta(pos) --obtain placeholder meta\r
+ meta:from_table(data) --set placeholder metadata to the original node's metadata\r
+ meta:set_string("worldedit_placeholder", node.name) --add the node's name\r
+ end\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 count\r
+end\r
+\r
+--restores all nodes hidden with WorldEdit functions in a region defined by positions `pos1` and `pos2`, returning the number of nodes restored\r
+worldedit.restore = function(pos1, pos2)\r
+ local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
+ local env = minetest.env\r
+\r
+ local pos = {x=pos1.x, y=0, z=0}\r
+ local node = {name="", param1=0, param2=0}\r
+ local count = 0\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 currentnode = env:get_node(pos)\r
+ if currentnode.name == "worldedit:placeholder" then\r
+ node.param1, node.param2 = currentnode.param1, currentnode.param2 --copy node's param1 and param2\r
+ local data = env:get_meta(pos):to_table() --obtain node metadata\r
+ node.name = data.fields.worldedit_placeholder --set node name\r
+ data.fields.worldedit_placeholder = nil --delete old nodename\r
+ env:add_node(pos, node) --add original node\r
+ env:get_meta(pos):from_table(data) --set original node metadata\r
+ count = count + 1\r
+ end\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 count\r
+end
\ No newline at end of file
--- /dev/null
+worldedit
\ No newline at end of file
--- /dev/null
+minetest.register_privilege("worldedit", "Can use WorldEdit commands")\r
+\r
+worldedit.set_pos = {}\r
+\r
+worldedit.pos1 = {}\r
+worldedit.pos2 = {}\r
+\r
+dofile(minetest.get_modpath("worldedit_commands") .. "/mark.lua")\r
+\r
+--determines whether `nodename` is a valid node name, returning a boolean\r
+worldedit.node_is_valid = function(nodename)\r
+ return minetest.registered_nodes[nodename] ~= nil\r
+ or minetest.registered_nodes["default:" .. nodename] ~= nil\r
+end\r
+\r
+--determines the axis in which a player is facing, returning an axis ("x", "y", or "z") and the sign (1 or -1)\r
+worldedit.player_axis = function(name)\r
+ local dir = minetest.env:get_player_by_name(name):get_look_dir()\r
+ local x, y, z = math.abs(dir.x), math.abs(dir.y), math.abs(dir.z)\r
+ if x > y then\r
+ if x > z then\r
+ return "x", dir.x > 0 and 1 or -1\r
+ end\r
+ elseif y > z then\r
+ return "y", dir.y > 0 and 1 or -1\r
+ end\r
+ return "z", dir.z > 0 and 1 or -1\r
+end\r
+\r
+minetest.register_chatcommand("/reset", {\r
+ params = "",\r
+ description = "Reset the region so that it is empty",\r
+ privs = {worldedit=true},\r
+ func = function(name, param)\r
+ worldedit.pos1[name] = nil\r
+ worldedit.pos2[name] = nil\r
+ worldedit.mark_pos1(name)\r
+ worldedit.mark_pos2(name)\r
+ minetest.chat_send_player(name, "WorldEdit region reset")\r
+ end,\r
+})\r
+\r
+minetest.register_chatcommand("/mark", {\r
+ params = "",\r
+ description = "Show markers at the region positions",\r
+ privs = {worldedit=true},\r
+ func = function(name, param)\r
+ worldedit.mark_pos1(name)\r
+ worldedit.mark_pos2(name)\r
+ minetest.chat_send_player(name, "WorldEdit region marked")\r
+ end,\r
+})\r
+\r
+minetest.register_chatcommand("/pos1", {\r
+ params = "",\r
+ description = "Set WorldEdit region position 1 to the player's location",\r
+ privs = {worldedit=true},\r
+ func = function(name, param)\r
+ local pos = minetest.env:get_player_by_name(name):getpos()\r
+ pos.x, pos.y, pos.z = math.floor(pos.x), math.floor(pos.y), math.floor(pos.z)\r
+ worldedit.pos1[name] = pos\r
+ worldedit.mark_pos1(name)\r
+ minetest.chat_send_player(name, "WorldEdit position 1 set to " .. minetest.pos_to_string(pos))\r
+ end,\r
+})\r
+\r
+minetest.register_chatcommand("/pos2", {\r
+ params = "",\r
+ description = "Set WorldEdit region position 2 to the player's location",\r
+ privs = {worldedit=true},\r
+ func = function(name, param)\r
+ local pos = minetest.env:get_player_by_name(name):getpos()\r
+ pos.x, pos.y, pos.z = math.floor(pos.x), math.floor(pos.y), math.floor(pos.z)\r
+ worldedit.pos2[name] = pos\r
+ worldedit.mark_pos2(name)\r
+ minetest.chat_send_player(name, "WorldEdit position 2 set to " .. minetest.pos_to_string(pos))\r
+ end,\r
+})\r
+\r
+minetest.register_chatcommand("/p", {\r
+ params = "set/get",\r
+ description = "Set WorldEdit region by punching two nodes, or display the current WorldEdit region",\r
+ privs = {worldedit=true},\r
+ func = function(name, param)\r
+ if param == "set" then --set both WorldEdit positions\r
+ worldedit.set_pos[name] = 1\r
+ minetest.chat_send_player(name, "Select positions by punching two nodes")\r
+ elseif param == "get" then --display current WorldEdit positions\r
+ if worldedit.pos1[name] ~= nil then\r
+ minetest.chat_send_player(name, "WorldEdit position 1: " .. minetest.pos_to_string(worldedit.pos1[name]))\r
+ else\r
+ minetest.chat_send_player(name, "WorldEdit position 1 not set")\r
+ end\r
+ if worldedit.pos2[name] ~= nil then\r
+ minetest.chat_send_player(name, "WorldEdit position 2: " .. minetest.pos_to_string(worldedit.pos2[name]))\r
+ else\r
+ minetest.chat_send_player(name, "WorldEdit position 2 not set")\r
+ end\r
+ else\r
+ minetest.chat_send_player(name, "Unknown subcommand: " .. param)\r
+ end\r
+ end,\r
+})\r
+\r
+minetest.register_on_punchnode(function(pos, node, puncher)\r
+ local name = puncher:get_player_name()\r
+ if name ~= "" and worldedit.set_pos[name] ~= nil then --currently setting position\r
+ if worldedit.set_pos[name] == 1 then --setting position 1\r
+ worldedit.set_pos[name] = 2 --set position 2 on the next invocation\r
+ worldedit.pos1[name] = pos\r
+ worldedit.mark_pos1(name)\r
+ minetest.chat_send_player(name, "WorldEdit region position 1 set to " .. minetest.pos_to_string(pos))\r
+ else --setting position 2\r
+ worldedit.set_pos[name] = nil --finished setting positions\r
+ worldedit.pos2[name] = pos\r
+ worldedit.mark_pos2(name)\r
+ minetest.chat_send_player(name, "WorldEdit region position 2 set to " .. minetest.pos_to_string(pos))\r
+ end\r
+ end\r
+end)\r
+\r
+minetest.register_chatcommand("/volume", {\r
+ params = "",\r
+ description = "Display the volume of the current WorldEdit region",\r
+ privs = {worldedit=true},\r
+ func = function(name, param)\r
+ local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
+ if pos1 == nil or pos2 == nil then\r
+ minetest.chat_send_player(name, "No WorldEdit region selected")\r
+ return\r
+ end\r
+\r
+ local volume = worldedit.volume(pos1, pos2)\r
+ minetest.chat_send_player(name, "Current WorldEdit region has a volume of " .. volume .. " nodes (" .. pos2.x - pos1.x .. "*" .. pos2.y - pos1.y .. "*" .. pos2.z - pos1.z .. ")")\r
+ end,\r
+})\r
+\r
+minetest.register_chatcommand("/set", {\r
+ params = "<node>",\r
+ description = "Set the current WorldEdit region to <node>",\r
+ privs = {worldedit=true},\r
+ func = function(name, param)\r
+ local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
+ if pos1 == nil or pos2 == nil then\r
+ minetest.chat_send_player(name, "No WorldEdit region selected")\r
+ return\r
+ end\r
+\r
+ if param == "" or not worldedit.node_is_valid(param) then\r
+ minetest.chat_send_player(name, "Invalid node name: " .. param)\r
+ return\r
+ end\r
+\r
+ local count = worldedit.set(pos1, pos2, param)\r
+ minetest.chat_send_player(name, count .. " nodes set")\r
+ end,\r
+})\r
+\r
+minetest.register_chatcommand("/replace", {\r
+ params = "<search node> <replace node>",\r
+ description = "Replace all instances of <search node> with <place node> in the current WorldEdit region",\r
+ privs = {worldedit=true},\r
+ func = function(name, param)\r
+ local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
+ if pos1 == nil or pos2 == nil then\r
+ minetest.chat_send_player(name, "No WorldEdit region selected")\r
+ return\r
+ end\r
+\r
+ local found, _, searchnode, replacenode = param:find("^([^%s]+)%s+([^%s]+)$")\r
+ if found == nil then\r
+ minetest.chat_send_player(name, "Invalid usage: " .. param)\r
+ return\r
+ end\r
+ if not worldedit.node_is_valid(searchnode) then\r
+ minetest.chat_send_player(name, "Invalid search node name: " .. searchnode)\r
+ return\r
+ end\r
+ if not worldedit.node_is_valid(replacenode) then\r
+ minetest.chat_send_player(name, "Invalid replace node name: " .. replacenode)\r
+ return\r
+ end\r
+\r
+ local count = worldedit.replace(pos1, pos2, searchnode, replacenode)\r
+ minetest.chat_send_player(name, count .. " nodes replaced")\r
+ end,\r
+})\r
+\r
+minetest.register_chatcommand("/hollowsphere", {\r
+ params = "<radius> <node>",\r
+ description = "Add hollow sphere at WorldEdit position 1 with radius <radius>, composed of <node>",\r
+ privs = {worldedit=true},\r
+ func = function(name, param)\r
+ local pos = worldedit.pos1[name]\r
+ if pos == nil then\r
+ minetest.chat_send_player(name, "No WorldEdit region selected")\r
+ return\r
+ end\r
+\r
+ local found, _, radius, nodename = param:find("^(%d+)%s+([^%s]+)$")\r
+ if found == nil then\r
+ minetest.chat_send_player(name, "Invalid usage: " .. param)\r
+ return\r
+ end\r
+ if not worldedit.node_is_valid(nodename) then\r
+ minetest.chat_send_player(name, "Invalid node name: " .. param)\r
+ return\r
+ end\r
+\r
+ local count = worldedit.hollow_sphere(pos, tonumber(radius), nodename)\r
+ minetest.chat_send_player(name, count .. " nodes added")\r
+ end,\r
+})\r
+\r
+minetest.register_chatcommand("/sphere", {\r
+ params = "<radius> <node>",\r
+ description = "Add sphere at WorldEdit position 1 with radius <radius>, composed of <node>",\r
+ privs = {worldedit=true},\r
+ func = function(name, param)\r
+ local pos = worldedit.pos1[name]\r
+ if pos == nil then\r
+ minetest.chat_send_player(name, "No WorldEdit region selected")\r
+ return\r
+ end\r
+\r
+ local found, _, radius, nodename = param:find("^(%d+)%s+([^%s]+)$")\r
+ if found == nil then\r
+ minetest.chat_send_player(name, "Invalid usage: " .. param)\r
+ return\r
+ end\r
+ if not worldedit.node_is_valid(nodename) then\r
+ minetest.chat_send_player(name, "Invalid node name: " .. param)\r
+ return\r
+ end\r
+\r
+ local count = worldedit.sphere(pos, tonumber(radius), nodename)\r
+ minetest.chat_send_player(name, count .. " nodes added")\r
+ end,\r
+})\r
+\r
+minetest.register_chatcommand("/hollowcylinder", {\r
+ params = "x/y/z/? <length> <radius> <node>",\r
+ description = "Add hollow cylinder at WorldEdit position 1 along the x/y/z/? axis with length <length> and radius <radius>, composed of <node>",\r
+ privs = {worldedit=true},\r
+ func = function(name, param)\r
+ local pos = worldedit.pos1[name]\r
+ if pos == nil then\r
+ minetest.chat_send_player(name, "No WorldEdit region selected")\r
+ return\r
+ end\r
+\r
+ local found, _, axis, length, radius, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+([^%s]+)$")\r
+ if found == nil then\r
+ minetest.chat_send_player(name, "Invalid usage: " .. param)\r
+ return\r
+ end\r
+ if axis == "?" then\r
+ axis, sign = worldedit.player_axis(name)\r
+ length = length * sign\r
+ end\r
+ if not worldedit.node_is_valid(nodename) then\r
+ minetest.chat_send_player(name, "Invalid node name: " .. param)\r
+ return\r
+ end\r
+\r
+ local count = worldedit.hollow_cylinder(pos, axis, tonumber(length), tonumber(radius), nodename)\r
+ minetest.chat_send_player(name, count .. " nodes added")\r
+ end,\r
+})\r
+\r
+minetest.register_chatcommand("/cylinder", {\r
+ params = "x/y/z/? <length> <radius> <node>",\r
+ description = "Add cylinder at WorldEdit position 1 along the x/y/z/? axis with length <length> and radius <radius>, composed of <node>",\r
+ privs = {worldedit=true},\r
+ func = function(name, param)\r
+ local pos = worldedit.pos1[name]\r
+ if pos == nil then\r
+ minetest.chat_send_player(name, "No WorldEdit region selected")\r
+ return\r
+ end\r
+\r
+ local found, _, axis, length, radius, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+([^%s]+)$")\r
+ if found == nil then\r
+ minetest.chat_send_player(name, "Invalid usage: " .. param)\r
+ return\r
+ end\r
+ if axis == "?" then\r
+ axis, sign = worldedit.player_axis(name)\r
+ length = length * sign\r
+ end\r
+ if not worldedit.node_is_valid(nodename) then\r
+ minetest.chat_send_player(name, "Invalid node name: " .. param)\r
+ return\r
+ end\r
+\r
+ local count = worldedit.cylinder(pos, axis, tonumber(length), tonumber(radius), nodename)\r
+ minetest.chat_send_player(name, count .. " nodes added")\r
+ end,\r
+})\r
+\r
+minetest.register_chatcommand("/pyramid", {\r
+ params = "<height> <node>",\r
+ description = "Add pyramid at WorldEdit position 1 with height <height>, composed of <node>",\r
+ privs = {worldedit=true},\r
+ func = function(name, param)\r
+ local pos = worldedit.pos1[name]\r
+ if pos == nil then\r
+ minetest.chat_send_player(name, "No WorldEdit region selected")\r
+ return\r
+ end\r
+\r
+ local found, _, size, nodename = param:find("(%d+)%s+([^%s]+)$")\r
+ if found == nil then\r
+ minetest.chat_send_player(name, "Invalid usage: " .. param)\r
+ return\r
+ end\r
+ if not worldedit.node_is_valid(nodename) then\r
+ minetest.chat_send_player(name, "Invalid node name: " .. param)\r
+ return\r
+ end\r
+\r
+ local count = worldedit.pyramid(pos, tonumber(size), nodename)\r
+ minetest.chat_send_player(name, count .. " nodes added")\r
+ end,\r
+})\r
+\r
+minetest.register_chatcommand("/spiral", {\r
+ params = "<width> <height> <space> <node>",\r
+ description = "Add spiral at WorldEdit position 1 with width <width>, height <height>, space between walls <space>, composed of <node>",\r
+ privs = {worldedit=true},\r
+ func = function(name, param)\r
+ local pos = worldedit.pos1[name]\r
+ if pos == nil then\r
+ minetest.chat_send_player(name, "No WorldEdit region selected")\r
+ return\r
+ end\r
+\r
+ local found, _, width, height, space, nodename = param:find("(%d+)%s+(%d+)%s+(%d+)%s+([^%s]+)$")\r
+ if found == nil then\r
+ minetest.chat_send_player(name, "Invalid usage: " .. param)\r
+ return\r
+ end\r
+ if not worldedit.node_is_valid(nodename) then\r
+ minetest.chat_send_player(name, "Invalid node name: " .. param)\r
+ return\r
+ end\r
+\r
+ local count = worldedit.spiral(pos, tonumber(width), tonumber(height), tonumber(space), nodename)\r
+ minetest.chat_send_player(name, count .. " nodes changed")\r
+ end,\r
+})\r
+\r
+minetest.register_chatcommand("/copy", {\r
+ params = "x/y/z/? <amount>",\r
+ description = "Copy the current WorldEdit region along the x/y/z/? axis by <amount> nodes",\r
+ privs = {worldedit=true},\r
+ func = function(name, param)\r
+ local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
+ if pos1 == nil or pos2 == nil then\r
+ minetest.chat_send_player(name, "No WorldEdit region selected")\r
+ return\r
+ end\r
+\r
+ local found, _, axis, amount = param:find("^([xyz%?])%s+([+-]?%d+)$")\r
+ if found == nil then\r
+ minetest.chat_send_player(name, "Invalid usage: " .. param)\r
+ return\r
+ end\r
+ if axis == "?" then\r
+ axis, sign = worldedit.player_axis(name)\r
+ amount = amount * sign\r
+ end\r
+\r
+ local count = worldedit.copy(pos1, pos2, axis, tonumber(amount))\r
+ minetest.chat_send_player(name, count .. " nodes copied")\r
+ end,\r
+})\r
+\r
+minetest.register_chatcommand("/move", {\r
+ params = "x/y/z/? <amount>",\r
+ description = "Move the current WorldEdit region along the x/y/z/? axis by <amount> nodes",\r
+ privs = {worldedit=true},\r
+ func = function(name, param)\r
+ local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
+ if pos1 == nil or pos2 == nil then\r
+ minetest.chat_send_player(name, "No WorldEdit region selected")\r
+ return\r
+ end\r
+\r
+ local found, _, axis, amount = param:find("^([xyz%?])%s+([+-]?%d+)$")\r
+ if found == nil then\r
+ minetest.chat_send_player(name, "Invalid usage: " .. param)\r
+ return\r
+ end\r
+ if axis == "?" then\r
+ axis, sign = worldedit.player_axis(name)\r
+ amount = amount * sign\r
+ end\r
+\r
+ local count = worldedit.move(pos1, pos2, axis, tonumber(amount))\r
+\r
+ pos1[axis] = pos1[axis] + amount\r
+ pos2[axis] = pos2[axis] + amount\r
+ worldedit.mark_pos1(name)\r
+ worldedit.mark_pos2(name)\r
+\r
+ minetest.chat_send_player(name, count .. " nodes moved")\r
+ end,\r
+})\r
+\r
+minetest.register_chatcommand("/stack", {\r
+ params = "x/y/z/? <count>",\r
+ description = "Stack the current WorldEdit region along the x/y/z/? axis <count> times",\r
+ privs = {worldedit=true},\r
+ func = function(name, param)\r
+ local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
+ if pos1 == nil or pos2 == nil then\r
+ minetest.chat_send_player(name, "No WorldEdit region selected")\r
+ return\r
+ end\r
+\r
+ local found, _, axis, count = param:find("^([xyz%?])%s+([+-]?%d+)$")\r
+ if found == nil then\r
+ minetest.chat_send_player(name, "Invalid usage: " .. param)\r
+ return\r
+ end\r
+ if axis == "?" then\r
+ axis, sign = worldedit.player_axis(name)\r
+ count = count * sign\r
+ end\r
+\r
+ local count = worldedit.stack(pos1, pos2, axis, tonumber(count))\r
+ minetest.chat_send_player(name, count .. " nodes stacked")\r
+ end,\r
+})\r
+\r
+minetest.register_chatcommand("/transpose", {\r
+ params = "x/y/z/? x/y/z/?",\r
+ description = "Transpose the current WorldEdit region along the x/y/z/? and x/y/z/? axes",\r
+ privs = {worldedit=true},\r
+ func = function(name, param)\r
+ local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
+ if pos1 == nil or pos2 == nil then\r
+ minetest.chat_send_player(name, "No WorldEdit region selected")\r
+ return\r
+ end\r
+\r
+ local found, _, axis1, axis2 = param:find("^([xyz%?])%s+([xyz%?])$")\r
+ if found == nil then\r
+ minetest.chat_send_player(name, "Invalid usage: " .. param)\r
+ return\r
+ end\r
+ if axis1 == "?" then\r
+ axis1 = worldedit.player_axis(name)\r
+ end\r
+ if axis2 == "?" then\r
+ axis2 = worldedit.player_axis(name)\r
+ end\r
+ if axis1 == axis2 then\r
+ minetest.chat_send_player(name, "Invalid usage: axes are the same")\r
+ return\r
+ end\r
+\r
+ local count = worldedit.transpose(pos1, pos2, axis1, axis2)\r
+ minetest.chat_send_player(name, count .. " nodes transposed")\r
+ end,\r
+})\r
+\r
+minetest.register_chatcommand("/flip", {\r
+ params = "x/y/z/?",\r
+ description = "Flip the current WorldEdit region along the x/y/z/? axis",\r
+ privs = {worldedit=true},\r
+ func = function(name, param)\r
+ local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
+ if pos1 == nil or pos2 == nil then\r
+ minetest.chat_send_player(name, "No WorldEdit region selected")\r
+ return\r
+ end\r
+\r
+ if param == "?" then\r
+ param = worldedit.player_axis(name)\r
+ end\r
+ if param ~= "x" and param ~= "y" and param ~= "z" then\r
+ minetest.chat_send_player(name, "Invalid usage: " .. param)\r
+ return\r
+ end\r
+\r
+ local count = worldedit.flip(pos1, pos2, param)\r
+ minetest.chat_send_player(name, count .. " nodes flipped")\r
+ end,\r
+})\r
+\r
+minetest.register_chatcommand("/rotate", {\r
+ params = "<axis> <angle>",\r
+ description = "Rotate the current WorldEdit region around the axis <axis> by angle <angle> (90 degree increment)",\r
+ privs = {worldedit=true},\r
+ func = function(name, param)\r
+ local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
+ if pos1 == nil or pos2 == nil then\r
+ minetest.chat_send_player(name, "No WorldEdit region selected")\r
+ return\r
+ end\r
+\r
+ local found, _, axis, angle = param:find("^([xyz%?])%s+([+-]?%d+)$")\r
+ if found == nil then\r
+ minetest.chat_send_player(name, "Invalid usage: " .. param)\r
+ return\r
+ end\r
+ if axis == "?" then\r
+ axis = worldedit.player_axis(name)\r
+ end\r
+ if angle % 90 ~= 0 then\r
+ minetest.chat_send_player(name, "Invalid usage: angle must be multiple of 90")\r
+ return\r
+ end\r
+\r
+ local count = worldedit.rotate(pos1, pos2, axis, angle)\r
+ minetest.chat_send_player(name, count .. " nodes rotated")\r
+ end,\r
+})\r
+\r
+minetest.register_chatcommand("/dig", {\r
+ params = "",\r
+ description = "Dig the current WorldEdit region",\r
+ privs = {worldedit=true},\r
+ func = function(name, param)\r
+ local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
+ if pos1 == nil or pos2 == nil then\r
+ minetest.chat_send_player(name, "No WorldEdit region selected")\r
+ return\r
+ end\r
+\r
+ local count = worldedit.dig(pos1, pos2)\r
+ minetest.chat_send_player(name, count .. " nodes dug")\r
+ end,\r
+})\r
+\r
+minetest.register_chatcommand("/hide", {\r
+ params = "<node>",\r
+ description = "Hide all nodes in the current WorldEdit region non-destructively",\r
+ privs = {worldedit=true},\r
+ func = function(name, param)\r
+ local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
+ if pos1 == nil or pos2 == nil then\r
+ minetest.chat_send_player(name, "No WorldEdit region selected")\r
+ return\r
+ end\r
+\r
+ local count = worldedit.hide(pos1, pos2)\r
+ minetest.chat_send_player(name, count .. " nodes hidden")\r
+ end,\r
+})\r
+\r
+minetest.register_chatcommand("/suppress", {\r
+ params = "<node>",\r
+ description = "Suppress all <node> in the current WorldEdit region non-destructively",\r
+ privs = {worldedit=true},\r
+ func = function(name, param)\r
+ local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
+ if pos1 == nil or pos2 == nil then\r
+ minetest.chat_send_player(name, "No WorldEdit region selected")\r
+ return\r
+ end\r
+\r
+ if param == "" or not worldedit.node_is_valid(param) then\r
+ minetest.chat_send_player(name, "Invalid node name: " .. param)\r
+ return\r
+ end\r
+\r
+ local count = worldedit.suppress(pos1, pos2, param)\r
+ minetest.chat_send_player(name, count .. " nodes suppressed")\r
+ end,\r
+})\r
+\r
+minetest.register_chatcommand("/find", {\r
+ params = "<node>",\r
+ description = "Find <node> in the current WorldEdit region by hiding everything else non-destructively",\r
+ privs = {worldedit=true},\r
+ func = function(name, param)\r
+ local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
+ if pos1 == nil or pos2 == nil then\r
+ minetest.chat_send_player(name, "No WorldEdit region selected")\r
+ return\r
+ end\r
+\r
+ if param == "" or not worldedit.node_is_valid(param) then\r
+ minetest.chat_send_player(name, "Invalid node name: " .. param)\r
+ return\r
+ end\r
+\r
+ local count = worldedit.find(pos1, pos2, param)\r
+ minetest.chat_send_player(name, count .. " nodes found")\r
+ end,\r
+})\r
+\r
+minetest.register_chatcommand("/restore", {\r
+ params = "",\r
+ description = "Restores nodes hidden with WorldEdit in the current WorldEdit region",\r
+ privs = {worldedit=true},\r
+ func = function(name, param)\r
+ local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
+ if pos1 == nil or pos2 == nil then\r
+ minetest.chat_send_player(name, "No WorldEdit region selected")\r
+ return\r
+ end\r
+\r
+ local count = worldedit.restore(pos1, pos2)\r
+ minetest.chat_send_player(name, count .. " nodes restored")\r
+ end,\r
+})\r
+\r
+minetest.register_chatcommand("/save", {\r
+ params = "<file>",\r
+ description = "Save the current WorldEdit region to \"(world folder)/schems/<file>.we\"",\r
+ privs = {worldedit=true},\r
+ func = function(name, param)\r
+ local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
+ if pos1 == nil or pos2 == nil then\r
+ minetest.chat_send_player(name, "No WorldEdit region selected")\r
+ return\r
+ end\r
+\r
+ if param == "" then\r
+ minetest.chat_send_player(name, "Invalid usage: " .. param)\r
+ return\r
+ end\r
+\r
+ local result, count = worldedit.serialize(pos1, pos2)\r
+\r
+ local path = minetest.get_worldpath() .. "/schems"\r
+ local filename = path .. "/" .. param .. ".we"\r
+ os.execute("mkdir \"" .. path .. "\"") --create directory if it does not already exist\r
+ local file, err = io.open(filename, "wb")\r
+ if err ~= nil then\r
+ minetest.chat_send_player(name, "Could not save file to \"" .. filename .. "\"")\r
+ return\r
+ end\r
+ file:write(result)\r
+ file:flush()\r
+ file:close()\r
+\r
+ minetest.chat_send_player(name, count .. " nodes saved")\r
+ end,\r
+})\r
+\r
+minetest.register_chatcommand("/load", {\r
+ params = "<file>",\r
+ description = "Load nodes from \"(world folder)/schems/<file>.we\" with position 1 of the current WorldEdit region as the origin",\r
+ privs = {worldedit=true},\r
+ func = function(name, param)\r
+ local pos1 = worldedit.pos1[name]\r
+ if pos1 == nil then\r
+ minetest.chat_send_player(name, "No WorldEdit region selected")\r
+ return\r
+ end\r
+\r
+ if param == "" then\r
+ minetest.chat_send_player(name, "Invalid usage: " .. param)\r
+ return\r
+ end\r
+\r
+ local filename = minetest.get_worldpath() .. "/schems/" .. param .. ".we"\r
+ local file, err = io.open(filename, "rb")\r
+ if err ~= nil then\r
+ minetest.chat_send_player(name, "Could not open file \"" .. filename .. "\"")\r
+ return\r
+ end\r
+ local value = file:read("*a")\r
+ file:close()\r
+\r
+ local count\r
+ if value:find("{") then --old WorldEdit format\r
+ count = worldedit.deserialize_old(pos1, value)\r
+ else --new WorldEdit format\r
+ count = worldedit.deserialize(pos1, value)\r
+ end\r
+\r
+ minetest.chat_send_player(name, count .. " nodes loaded")\r
+ end,\r
+})\r
+\r
+minetest.register_chatcommand("/metasave", {\r
+ params = "<file>",\r
+ description = "Save the current WorldEdit region to \"(world folder)/schems/<file>.wem\"",\r
+ privs = {worldedit=true},\r
+ func = function(name, param)\r
+ local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]\r
+ if pos1 == nil or pos2 == nil then\r
+ minetest.chat_send_player(name, "No WorldEdit region selected")\r
+ return\r
+ end\r
+ if param == "" then\r
+ minetest.chat_send_player(name, "Invalid usage: " .. param)\r
+ return\r
+ end\r
+ local count, err = worldedit.metasave(pos1, pos2, param)\r
+ if err then\r
+ minetest.chat_send_player(name, "error loading file: " .. err)\r
+ else\r
+ minetest.chat_send_player(name, count .. " nodes saved")\r
+ end\r
+ end,\r
+})\r
+\r
+minetest.register_chatcommand("/metaload", {\r
+ params = "<file>",\r
+ description = "Load nodes from \"(world folder)/schems/<file>.wem\" with position 1 of the current WorldEdit region as the origin",\r
+ privs = {worldedit=true},\r
+ func = function(name, param)\r
+ local pos1 = worldedit.pos1[name]\r
+ if pos1 == nil then\r
+ minetest.chat_send_player(name, "No WorldEdit region selected")\r
+ return\r
+ end\r
+ if param == "" then\r
+ minetest.chat_send_player(name, "Invalid usage: " .. param)\r
+ return\r
+ end\r
+ local count, err = worldedit.metaload(pos1, param)\r
+ if err then\r
+ minetest.chat_send_player(name, "error loading file: " .. err)\r
+ else\r
+ minetest.chat_send_player(name, count .. " nodes loaded")\r
+ end\r
+ end,\r
+})\r
--- /dev/null
+worldedit.marker1 = {}\r
+worldedit.marker2 = {}\r
+\r
+--marks worldedit region position 1\r
+worldedit.mark_pos1 = function(name)\r
+ local pos = worldedit.pos1[name]\r
+ if worldedit.marker1[name] ~= nil then --marker already exists\r
+ worldedit.marker1[name]:remove() --remove marker\r
+ worldedit.marker1[name] = nil\r
+ end\r
+ if pos ~= nil then --add marker\r
+ worldedit.marker1[name] = minetest.env:add_entity(pos, "worldedit:pos1")\r
+ worldedit.marker1[name]:get_luaentity().active = true\r
+ end\r
+end\r
+\r
+--marks worldedit region position 2\r
+worldedit.mark_pos2 = function(name)\r
+ local pos = worldedit.pos2[name]\r
+ if worldedit.marker2[name] ~= nil then --marker already exists\r
+ worldedit.marker2[name]:remove() --remove marker\r
+ worldedit.marker2[name] = nil\r
+ end\r
+ if pos ~= nil then --add marker\r
+ worldedit.marker2[name] = minetest.env:add_entity(pos, "worldedit:pos2")\r
+ worldedit.marker2[name]:get_luaentity().active = true\r
+ end\r
+end\r
+\r
+minetest.register_entity(":worldedit:pos1", {\r
+ initial_properties = {\r
+ visual = "cube",\r
+ visual_size = {x=1.1, y=1.1},\r
+ textures = {"worldedit_pos1.png", "worldedit_pos1.png",\r
+ "worldedit_pos1.png", "worldedit_pos1.png",\r
+ "worldedit_pos1.png", "worldedit_pos1.png"},\r
+ collisionbox = {-0.55, -0.55, -0.55, 0.55, 0.55, 0.55},\r
+ },\r
+ on_step = function(self, dtime)\r
+ if self.active == nil then\r
+ self.object:remove()\r
+ end\r
+ end,\r
+ on_punch = function(self, hitter)\r
+ self.object:remove()\r
+ local name = hitter:get_player_name()\r
+ worldedit.marker1[name] = nil\r
+ end,\r
+})\r
+\r
+minetest.register_entity(":worldedit:pos2", {\r
+ initial_properties = {\r
+ visual = "cube",\r
+ visual_size = {x=1.1, y=1.1},\r
+ textures = {"worldedit_pos2.png", "worldedit_pos2.png",\r
+ "worldedit_pos2.png", "worldedit_pos2.png",\r
+ "worldedit_pos2.png", "worldedit_pos2.png"},\r
+ collisionbox = {-0.55, -0.55, -0.55, 0.55, 0.55, 0.55},\r
+ },\r
+ on_step = function(self, dtime)\r
+ if self.active == nil then\r
+ self.object:remove()\r
+ end\r
+ end,\r
+ on_punch = function(self, hitter)\r
+ self.object:remove()\r
+ local name = hitter:get_player_name()\r
+ worldedit.marker2[name] = nil\r
+ end,\r
+})
\ No newline at end of file