diff options
author | Anthony Zhang <azhang9@gmail.com> | 2012-10-01 16:19:09 -0400 |
---|---|---|
committer | Anthony Zhang <azhang9@gmail.com> | 2012-10-01 16:20:20 -0400 |
commit | 12dfbd198d117b9d76e86a056f79b7276e8db0a6 (patch) | |
tree | 246020297cc9040c6365c8cec56544d503ff5b5c /worldedit | |
parent | a82ab9176f831b4f1beb9d2f3c3a7d582abf8b44 (diff) |
Use modpack for easier installation (idea is taken from cornernote's mod format), fix some grammar in API reference, move chat command reference and API reference to separate files.
Diffstat (limited to 'worldedit')
-rw-r--r-- | worldedit/functions.lua | 707 | ||||
-rw-r--r-- | worldedit/init.lua | 655 | ||||
-rw-r--r-- | worldedit/mark.lua | 70 | ||||
-rw-r--r-- | worldedit/table_save.lua | 133 | ||||
-rw-r--r-- | worldedit/textures/worldedit_pos1.png | bin | 0 -> 142 bytes | |||
-rw-r--r-- | worldedit/textures/worldedit_pos2.png | bin | 0 -> 157 bytes |
6 files changed, 1565 insertions, 0 deletions
diff --git a/worldedit/functions.lua b/worldedit/functions.lua new file mode 100644 index 0000000..2d949c6 --- /dev/null +++ b/worldedit/functions.lua @@ -0,0 +1,707 @@ +--modifies positions `pos1` and `pos2` so that each component of `pos1` is less than or equal to its corresponding conent of `pos2`, returning two new positions
+worldedit.sort_pos = function(pos1, pos2)
+ pos1 = {x=pos1.x, y=pos1.y, z=pos1.z}
+ pos2 = {x=pos2.x, y=pos2.y, z=pos2.z}
+ if pos1.x > pos2.x then
+ pos2.x, pos1.x = pos1.x, pos2.x
+ end
+ if pos1.y > pos2.y then
+ pos2.y, pos1.y = pos1.y, pos2.y
+ end
+ if pos1.z > pos2.z then
+ pos2.z, pos1.z = pos1.z, pos2.z
+ end
+ return pos1, pos2
+end
+
+--determines the volume of the region defined by positions `pos1` and `pos2`, returning the volume
+worldedit.volume = function(pos1, pos2)
+ local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
+ return (pos2.x - pos1.x + 1) * (pos2.y - pos1.y + 1) * (pos2.z - pos1.z + 1)
+end
+
+--sets a region defined by positions `pos1` and `pos2` to `nodename`, returning the number of nodes filled
+worldedit.set = function(pos1, pos2, nodename)
+ local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
+ local env = minetest.env
+
+ local node = {name=nodename}
+ local pos = {x=pos1.x, y=0, z=0}
+ while pos.x <= pos2.x do
+ pos.y = pos1.y
+ while pos.y <= pos2.y do
+ pos.z = pos1.z
+ while pos.z <= pos2.z do
+ env:add_node(pos, node)
+ pos.z = pos.z + 1
+ end
+ pos.y = pos.y + 1
+ end
+ pos.x = pos.x + 1
+ end
+ return worldedit.volume(pos1, pos2)
+end
+
+--replaces all instances of `searchnode` with `replacenode` in a region defined by positions `pos1` and `pos2`, returning the number of nodes replaced
+worldedit.replace = function(pos1, pos2, searchnode, replacenode)
+ local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
+ local env = minetest.env
+
+ if minetest.registered_nodes[searchnode] == nil then
+ searchnode = "default:" .. searchnode
+ end
+ if minetest.registered_nodes[replacenode] == nil then
+ replacenode = "default:" .. replacenode
+ end
+
+ local pos = {x=pos1.x, y=0, z=0}
+ local node = {name=replacenode}
+ local count = 0
+ while pos.x <= pos2.x do
+ pos.y = pos1.y
+ while pos.y <= pos2.y do
+ pos.z = pos1.z
+ while pos.z <= pos2.z do
+ if env:get_node(pos).name == searchnode then
+ env:add_node(pos, node)
+ count = count + 1
+ end
+ pos.z = pos.z + 1
+ end
+ pos.y = pos.y + 1
+ end
+ pos.x = pos.x + 1
+ end
+ return count
+end
+
+--adds a hollow sphere at `pos` with radius `radius`, composed of `nodename`, returning the number of nodes added
+worldedit.hollow_sphere = function(pos, radius, nodename) --wip: use bresenham sphere for maximum speed
+ local node = {name=nodename}
+ local pos1 = {x=0, y=0, z=0}
+ local full_radius = radius * radius + radius
+ local env = minetest.env
+ for x = -radius, radius do
+ pos1.x = pos.x + x
+ for y = -radius, radius do
+ pos1.y = pos.y + y
+ for z = -radius, radius do
+ if x*x+y*y+z*z >= (radius-1) * (radius-1) + (radius-1) and x*x+y*y+z*z <= full_radius then
+ pos1.z = pos.z + z
+ env:add_node({x=pos.x+x,y=pos.y+y,z=pos.z+z}, node)
+ end
+ end
+ end
+ end
+end
+
+--adds a sphere at `pos` with radius `radius`, composed of `nodename`, returning the number of nodes added
+worldedit.sphere = function(pos, radius, nodename) --wip: use bresenham sphere for maximum speed
+ local node = {name=nodename}
+ local pos1 = {x=0, y=0, z=0}
+ local full_radius = radius * radius + radius
+ local count = 0
+ local env = minetest.env
+ for x = -radius, radius do
+ pos1.x = pos.x + x
+ for y = -radius, radius do
+ pos1.y = pos.y + y
+ for z = -radius, radius do
+ if x*x+y*y+z*z <= full_radius then
+ pos1.z = pos.z + z
+ env:add_node(pos1, node)
+ count = count + 1
+ end
+ end
+ end
+ end
+ return count
+end
+
+--adds a hollow cylinder at `pos` along the `axis` axis ("x" or "y" or "z") with length `length` and radius `radius`, composed of `nodename`, returning the number of nodes added
+worldedit.hollow_cylinder = function(pos, axis, length, radius, nodename)
+ local other1, other2
+ if axis == "x" then
+ other1, other2 = "y", "z"
+ elseif axis == "y" then
+ other1, other2 = "x", "z"
+ else --axis == "z"
+ other1, other2 = "x", "y"
+ end
+
+ local env = minetest.env
+ local currentpos = {x=pos.x, y=pos.y, z=pos.z}
+ local node = {name=nodename}
+ local count = 0
+ local step = 1
+ if length < 0 then
+ length = -length
+ step = -1
+ end
+ for i = 1, length do
+ local offset1, offset2 = 0, radius
+ local delta = -radius
+ while offset1 <= offset2 do
+ --add node at each octant
+ local first1, first2 = pos[other1] + offset1, pos[other1] - offset1
+ local second1, second2 = pos[other2] + offset2, pos[other2] - offset2
+ currentpos[other1], currentpos[other2] = first1, second1
+ env:add_node(currentpos, node) --octant 1
+ currentpos[other1] = first2
+ env:add_node(currentpos, node) --octant 4
+ currentpos[other2] = second2
+ env:add_node(currentpos, node) --octant 5
+ currentpos[other1] = first1
+ env:add_node(currentpos, node) --octant 8
+ local first1, first2 = pos[other1] + offset2, pos[other1] - offset2
+ local second1, second2 = pos[other2] + offset1, pos[other2] - offset1
+ currentpos[other1], currentpos[other2] = first1, second1
+ env:add_node(currentpos, node) --octant 2
+ currentpos[other1] = first2
+ env:add_node(currentpos, node) --octant 3
+ currentpos[other2] = second2
+ env:add_node(currentpos, node) --octant 6
+ currentpos[other1] = first1
+ env:add_node(currentpos, node) --octant 7
+
+ count = count + 8 --wip: broken
+
+ --move to next location
+ delta = delta + (offset1 * 2) + 1
+ if delta >= 0 then
+ offset2 = offset2 - 1
+ delta = delta - (offset2 * 2)
+ end
+ offset1 = offset1 + 1
+ end
+ currentpos[axis] = currentpos[axis] + step
+ end
+ return count
+end
+
+--adds a cylinder at `pos` along the `axis` axis ("x" or "y" or "z") with length `length` and radius `radius`, composed of `nodename`, returning the number of nodes added
+worldedit.cylinder = function(pos, axis, length, radius, nodename)
+ local other1, other2
+ if axis == "x" then
+ other1, other2 = "y", "z"
+ elseif axis == "y" then
+ other1, other2 = "x", "z"
+ else --axis == "z"
+ other1, other2 = "x", "y"
+ end
+
+ local env = minetest.env
+ local currentpos = {x=pos.x, y=pos.y, z=pos.z}
+ local node = {name=nodename}
+ local count = 0
+ local step = 1
+ if length < 0 then
+ length = -length
+ step = -1
+ end
+ for i = 1, length do
+ local offset1, offset2 = 0, radius
+ local delta = -radius
+ while offset1 <= offset2 do
+ --connect each pair of octants
+ currentpos[other1] = pos[other1] - offset1
+ local second1, second2 = pos[other2] + offset2, pos[other2] - offset2
+ for i = 0, offset1 * 2 do
+ currentpos[other2] = second1
+ env:add_node(currentpos, node) --octant 1 to 4
+ currentpos[other2] = second2
+ env:add_node(currentpos, node) --octant 5 to 8
+ currentpos[other1] = currentpos[other1] + 1
+ end
+ currentpos[other1] = pos[other1] - offset2
+ local second1, second2 = pos[other2] + offset1, pos[other2] - offset1
+ for i = 0, offset2 * 2 do
+ currentpos[other2] = second1
+ env:add_node(currentpos, node) --octant 2 to 3
+ currentpos[other2] = second2
+ env:add_node(currentpos, node) --octant 6 to 7
+ currentpos[other1] = currentpos[other1] + 1
+ end
+
+ count = count + (offset1 * 4) + (offset2 * 4) + 4 --wip: broken
+
+ --move to next location
+ delta = delta + (offset1 * 2) + 1
+ offset1 = offset1 + 1
+ if delta >= 0 then
+ offset2 = offset2 - 1
+ delta = delta - (offset2 * 2)
+ end
+ end
+ currentpos[axis] = currentpos[axis] + step
+ end
+ return count
+end
+
+--adds a pyramid at `pos` with height `height`, composed of `nodename`, returning the number of nodes added
+worldedit.pyramid = function(pos, height, nodename)
+ local pos1x, pos1y, pos1z = pos.x - height, pos.y, pos.z - height
+ local pos2x, pos2y, pos2z = pos.x + height, pos.y + height, pos.z + height
+ local pos = {x=0, y=pos1y, z=0}
+
+ local count = 0
+ local node = {name=nodename}
+ local env = minetest.env
+ while pos.y <= pos2y do --each vertical level of the pyramid
+ pos.x = pos1x
+ while pos.x <= pos2x do
+ pos.z = pos1z
+ while pos.z <= pos2z do
+ env:add_node(pos, node)
+ pos.z = pos.z + 1
+ end
+ pos.x = pos.x + 1
+ end
+ count = count + ((pos2y - pos.y) * 2 + 1) ^ 2
+ pos.y = pos.y + 1
+
+ pos1x, pos2x = pos1x + 1, pos2x - 1
+ pos1z, pos2z = pos1z + 1, pos2z - 1
+
+ end
+ return count
+end
+
+--adds a spiral at `pos` with width `width`, height `height`, space between walls `spacer`, composed of `nodename`, returning the number of nodes added
+worldedit.spiral = function(pos, width, height, spacer, nodename) --wip: clean this up
+ -- spiral matrix - http://rosettacode.org/wiki/Spiral_matrix#Lua
+ av, sn = math.abs, function(s) return s~=0 and s/av(s) or 0 end
+ local function sindex(z, x) -- returns the value at (x, z) in a spiral that starts at 1 and goes outwards
+ if z == -x and z >= x then return (2*z+1)^2 end
+ local l = math.max(av(z), av(x))
+ 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
+ end
+ local function spiralt(side)
+ local ret, id, start, stop = {}, 0, math.floor((-side+1)/2), math.floor((side-1)/2)
+ for i = 1, side do
+ for j = 1, side do
+ local id = side^2 - sindex(stop - i + 1,start + j - 1)
+ ret[id] = {x=i,z=j}
+ end
+ end
+ return ret
+ end
+ -- connect the joined parts
+ local spiral = spiralt(width)
+ height = tonumber(height)
+ if height < 1 then height = 1 end
+ spacer = tonumber(spacer)-1
+ if spacer < 1 then spacer = 1 end
+ local count = 0
+ local node = {name=nodename}
+ local np,lp
+ for y=0,height do
+ lp = nil
+ for _,v in ipairs(spiral) do
+ np = {x=pos.x+v.x*spacer, y=pos.y+y, z=pos.z+v.z*spacer}
+ if lp~=nil then
+ if lp.x~=np.x then
+ if lp.x<np.x then
+ for i=lp.x+1,np.x do
+ minetest.env:add_node({x=i, y=np.y, z=np.z}, node)
+ count = count + 1
+ end
+ else
+ for i=np.x,lp.x-1 do
+ minetest.env:add_node({x=i, y=np.y, z=np.z}, node)
+ count = count + 1
+ end
+ end
+ end
+ if lp.z~=np.z then
+ if lp.z<np.z then
+ for i=lp.z+1,np.z do
+ minetest.env:add_node({x=np.x, y=np.y, z=i}, node)
+ count = count + 1
+ end
+ else
+ for i=np.z,lp.z-1 do
+ minetest.env:add_node({x=np.x, y=np.y, z=i}, node)
+ count = count + 1
+ end
+ end
+ end
+ end
+ lp = np
+ end
+ end
+ return count
+end
+
+--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
+worldedit.copy = function(pos1, pos2, axis, amount)
+ local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
+ local env = minetest.env
+
+ if amount < 0 then
+ local pos = {x=pos1.x, y=0, z=0}
+ while pos.x <= pos2.x do
+ pos.y = pos1.y
+ while pos.y <= pos2.y do
+ pos.z = pos1.z
+ while pos.z <= pos2.z do
+ local node = env:get_node(pos) --obtain current node
+ local meta = env:get_meta(pos):to_table() --get meta of current node
+ local value = pos[axis] --store current position
+ pos[axis] = value + amount --move along axis
+ env:add_node(pos, node) --copy node to new position
+ env:get_meta(pos):from_table(meta) --set metadata of new node
+ pos[axis] = value --restore old position
+ pos.z = pos.z + 1
+ end
+ pos.y = pos.y + 1
+ end
+ pos.x = pos.x + 1
+ end
+ else
+ local pos = {x=pos2.x, y=0, z=0}
+ while pos.x >= pos1.x do
+ pos.y = pos2.y
+ while pos.y >= pos1.y do
+ pos.z = pos2.z
+ while pos.z >= pos1.z do
+ local node = minetest.env:get_node(pos) --obtain current node
+ local meta = env:get_meta(pos):to_table() --get meta of current node
+ local value = pos[axis] --store current position
+ pos[axis] = value + amount --move along axis
+ minetest.env:add_node(pos, node) --copy node to new position
+ env:get_meta(pos):from_table(meta) --set metadata of new node
+ pos[axis] = value --restore old position
+ pos.z = pos.z - 1
+ end
+ pos.y = pos.y - 1
+ end
+ pos.x = pos.x - 1
+ end
+ end
+ return worldedit.volume(pos1, pos2)
+end
+
+--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
+worldedit.move = function(pos1, pos2, axis, amount)
+ local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
+ local env = minetest.env
+
+ if amount < 0 then
+ local pos = {x=pos1.x, y=0, z=0}
+ while pos.x <= pos2.x do
+ pos.y = pos1.y
+ while pos.y <= pos2.y do
+ pos.z = pos1.z
+ while pos.z <= pos2.z do
+ local node = env:get_node(pos) --obtain current node
+ local meta = env:get_meta(pos):to_table() --get metadata of current node
+ env:remove_node(pos)
+ local value = pos[axis] --store current position
+ pos[axis] = value + amount --move along axis
+ env:add_node(pos, node) --move node to new position
+ env:get_meta(pos):from_table(meta) --set metadata of new node
+ pos[axis] = value --restore old position
+ pos.z = pos.z + 1
+ end
+ pos.y = pos.y + 1
+ end
+ pos.x = pos.x + 1
+ end
+ else
+ local pos = {x=pos2.x, y=0, z=0}
+ while pos.x >= pos1.x do
+ pos.y = pos2.y
+ while pos.y >= pos1.y do
+ pos.z = pos2.z
+ while pos.z >= pos1.z do
+ local node = env:get_node(pos) --obtain current node
+ local meta = env:get_meta(pos):to_table() --get metadata of current node
+ env:remove_node(pos)
+ local value = pos[axis] --store current position
+ pos[axis] = value + amount --move along axis
+ env:add_node(pos, node) --move node to new position
+ env:get_meta(pos):from_table(meta) --set metadata of new node
+ pos[axis] = value --restore old position
+ pos.z = pos.z - 1
+ end
+ pos.y = pos.y - 1
+ end
+ pos.x = pos.x - 1
+ end
+ end
+ return worldedit.volume(pos1, pos2)
+end
+
+--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
+worldedit.stack = function(pos1, pos2, axis, count)
+ local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
+ local length = pos2[axis] - pos1[axis] + 1
+ if count < 0 then
+ count = -count
+ length = -length
+ end
+ local amount = 0
+ local copy = worldedit.copy
+ for i = 1, count do
+ amount = amount + length
+ copy(pos1, pos2, axis, amount)
+ end
+ return worldedit.volume(pos1, pos2)
+end
+
+--transposes a region defined by the positions `pos1` and `pos2` between the `axis1` and `axis2` axes, returning the number of nodes transposed
+worldedit.transpose = function(pos1, pos2, axis1, axis2)
+ local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
+
+ local pos = {x=pos1.x, y=0, z=0}
+ local env = minetest.env
+ while pos.x <= pos2.x do
+ pos.y = pos1.y
+ while pos.y <= pos2.y do
+ pos.z = pos1.z
+ while pos.z <= pos2.z do
+ local extent1, extent2 = pos[axis1] - pos1[axis1], pos[axis2] - pos1[axis2]
+ if extent1 < extent2 then
+ local node1 = env:get_node(pos)
+ local meta1 = env:get_meta(pos):to_table()
+ local value1, value2 = pos[axis1], pos[axis2]
+ pos[axis1], pos[axis2] = value1 + extent2, value2 + extent1
+ local node2 = env:get_node(pos)
+ local meta2 = env:get_meta(pos):to_table()
+ env:add_node(pos, node1)
+ env:get_meta(pos):from_table(meta1)
+ pos[axis1], pos[axis2] = value1, value2
+ env:add_node(pos, node2)
+ env:get_meta(pos):from_table(meta2)
+ end
+ pos.z = pos.z + 1
+ end
+ pos.y = pos.y + 1
+ end
+ pos.x = pos.x + 1
+ end
+ return worldedit.volume(pos1, pos2)
+end
+
+--flips a region defined by the positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z"), returning the number of nodes flipped
+worldedit.flip = function(pos1, pos2, axis)
+ local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
+
+ local pos = {x=pos1.x, y=0, z=0}
+ local start = pos1[axis] + pos2[axis]
+ pos2[axis] = pos1[axis] + math.floor((pos2[axis] - pos1[axis]) / 2)
+ local env = minetest.env
+ while pos.x <= pos2.x do
+ pos.y = pos1.y
+ while pos.y <= pos2.y do
+ pos.z = pos1.z
+ while pos.z <= pos2.z do
+ local node1 = env:get_node(pos)
+ local meta1 = env:get_meta(pos):to_table()
+ local value = pos[axis]
+ pos[axis] = start - value
+ local node2 = env:get_node(pos)
+ local meta2 = env:get_meta(pos):to_table()
+ env:add_node(pos, node1)
+ env:get_meta(pos):from_table(meta1)
+ pos[axis] = value
+ env:add_node(pos, node2)
+ env:get_meta(pos):from_table(meta2)
+ pos.z = pos.z + 1
+ end
+ pos.y = pos.y + 1
+ end
+ pos.x = pos.x + 1
+ end
+ return worldedit.volume(pos1, pos2)
+end
+
+--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
+worldedit.rotate = function(pos1, pos2, axis, angle)
+ local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
+
+ local axis1, axis2
+ if axis == "x" then
+ axis1, axis2 = "z", "y"
+ elseif axis == "y" then
+ axis1, axis2 = "x", "z"
+ else --axis == "z"
+ axis1, axis2 = "y", "x"
+ end
+ angle = angle % 360
+
+ if angle == 90 then
+ worldedit.transpose(pos1, pos2, axis1, axis2)
+ worldedit.flip(pos1, pos2, axis2)
+ elseif angle == 180 then
+ worldedit.flip(pos1, pos2, axis1)
+ worldedit.flip(pos1, pos2, axis2)
+ elseif angle == 270 then
+ worldedit.transpose(pos1, pos2, axis1, axis2)
+ worldedit.flip(pos1, pos2, axis1)
+ end
+ return worldedit.volume(pos1, pos2)
+end
+
+--digs a region defined by positions `pos1` and `pos2`, returning the number of nodes dug
+worldedit.dig = function(pos1, pos2)
+ local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
+ local env = minetest.env
+
+ local pos = {x=pos1.x, y=0, z=0}
+ while pos.x <= pos2.x do
+ pos.y = pos1.y
+ while pos.y <= pos2.y do
+ pos.z = pos1.z
+ while pos.z <= pos2.z do
+ env:dig_node(pos)
+ pos.z = pos.z + 1
+ end
+ pos.y = pos.y + 1
+ end
+ pos.x = pos.x + 1
+ end
+ return worldedit.volume(pos1, pos2)
+end
+
+--converts the region defined by positions `pos1` and `pos2` into a single string, returning the serialized data and the number of nodes serialized
+worldedit.serialize = function(pos1, pos2)
+ local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
+ local pos = {x=pos1.x, y=0, z=0}
+ local count = 0
+ local result = {}
+ local env = minetest.env
+ while pos.x <= pos2.x do
+ pos.y = pos1.y
+ while pos.y <= pos2.y do
+ pos.z = pos1.z
+ while pos.z <= pos2.z do
+ local node = env:get_node(pos)
+ if node.name ~= "air" and node.name ~= "ignore" then
+ count = count + 1
+ result[count] = pos.x - pos1.x .. " " .. pos.y - pos1.y .. " " .. pos.z - pos1.z .. " " .. node.name .. " " .. node.param1 .. " " .. node.param2
+ end
+ pos.z = pos.z + 1
+ end
+ pos.y = pos.y + 1
+ end
+ pos.x = pos.x + 1
+ end
+ result = table.concat(result, "\n")
+ return result, count
+end
+
+--loads the nodes represented by string `value` at position `originpos`, returning the number of nodes deserialized
+worldedit.deserialize = function(originpos, value)
+ local pos = {x=0, y=0, z=0}
+ local node = {name="", param1=0, param2=0}
+ local count = 0
+ local env = minetest.env
+ 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
+ pos.x = originpos.x + tonumber(x)
+ pos.y = originpos.y + tonumber(y)
+ pos.z = originpos.z + tonumber(z)
+ node.name = name
+ node.param1 = param1
+ node.param2 = param2
+ env:add_node(pos, node)
+ count = count + 1
+ end
+ return count
+end
+
+--loads the nodes represented by string `value` at position `originpos`, returning the number of nodes deserialized
+--based on [table.save/table.load](http://lua-users.org/wiki/SaveTableToFile) by ChillCode, available under the MIT license (GPL compatible)
+worldedit.deserialize_old = function(originpos, value)
+ --obtain the node table
+ local count = 0
+ local get_tables = loadstring(value)
+ if get_tables == nil then --error loading value
+ return count
+ end
+ local tables = get_tables()
+
+ --transform the node table into an array of nodes
+ for i = 1, #tables do
+ for j, v in pairs(tables[i]) do
+ if type(v) == "table" then
+ tables[i][j] = tables[v[1]]
+ end
+ end
+ end
+
+ --load the node array
+ local env = minetest.env
+ for i, v in ipairs(tables[1]) do
+ local pos = v[1]
+ pos.x, pos.y, pos.z = originpos.x + pos.x, originpos.y + pos.y, originpos.z + pos.z
+ env:add_node(pos, v[2])
+ count = count + 1
+ end
+ return count
+end
+
+--saves the nodes and meta defined by positions `pos1` and `pos2` into a file, returning the number of nodes saved
+worldedit.metasave = function(pos1, pos2, file) --wip: simply work with strings instead of doing IO
+ local path = minetest.get_worldpath() .. "/schems"
+ local filename = path .. "/" .. file .. ".wem"
+ os.execute("mkdir \"" .. path .. "\"") --create directory if it does not already exist
+ local rows = {}
+ local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
+ local pos = {x=pos1.x, y=0, z=0}
+ local count = 0
+ local result = {}
+ local env = minetest.env
+ while pos.x <= pos2.x do
+ pos.y = pos1.y
+ while pos.y <= pos2.y do
+ pos.z = pos1.z
+ while pos.z <= pos2.z do
+ local node = env:get_node(pos)
+ if node.name ~= "air" and node.name ~= "ignore" then
+ count = count + 1
+ local row = {
+ x = pos.x-pos1.x,
+ y = pos.y-pos1.y,
+ z = pos.z-pos1.z,
+ name = node.name,
+ param1 = node.param1,
+ param2 = node.param2,
+ meta = env:get_meta(pos):to_table(),
+ }
+ table.insert(rows, row)
+ end
+ pos.z = pos.z + 1
+ end
+ pos.y = pos.y + 1
+ end
+ pos.x = pos.x + 1
+ end
+ local err = table.save(rows,filename)
+ if err then return _,err end
+ return count
+end
+
+--loads the nodes and meta from `file` to position `pos1`, returning the number of nodes loaded
+worldedit.metaload = function(pos1, file) --wip: simply work with strings instead of doing IO
+ local filename = minetest.get_worldpath() .. "/schems/" .. file .. ".wem"
+ local rows, err = table.load(filename)
+ if err then return _,err end
+ local pos = {x=0, y=0, z=0}
+ local node = {name="", param1=0, param2=0}
+ local count = 0
+ local env = minetest.env
+ for i,row in pairs(rows) do
+ pos.x = pos1.x + tonumber(row.x)
+ pos.y = pos1.y + tonumber(row.y)
+ pos.z = pos1.z + tonumber(row.z)
+ node.name = row.name
+ node.param1 = row.param1
+ node.param2 = row.param2
+ env:add_node(pos, node)
+ env:get_meta(pos):from_table(row.meta)
+ count = count + 1
+ end
+ return count
+end
\ No newline at end of file diff --git a/worldedit/init.lua b/worldedit/init.lua new file mode 100644 index 0000000..84cf4fe --- /dev/null +++ b/worldedit/init.lua @@ -0,0 +1,655 @@ +minetest.register_privilege("worldedit", "Can use WorldEdit commands")
+
+worldedit = {}
+
+worldedit.set_pos = {}
+
+worldedit.pos1 = {}
+worldedit.pos2 = {}
+
+dofile(minetest.get_modpath("worldedit") .. "/functions.lua")
+dofile(minetest.get_modpath("worldedit") .. "/mark.lua")
+
+--determines whether `nodename` is a valid node name, returning a boolean
+worldedit.node_is_valid = function(temp_pos, nodename)
+ return minetest.registered_nodes[nodename] ~= nil
+ or minetest.registered_nodes["default:" .. nodename] ~= nil
+end
+
+--determines the axis in which a player is facing, returning an axis ("x", "y", or "z") and the sign (1 or -1)
+worldedit.player_axis = function(name)
+ local dir = minetest.env:get_player_by_name(name):get_look_dir()
+ local x, y, z = math.abs(dir.x), math.abs(dir.y), math.abs(dir.z)
+ if x > y then
+ if x > z then
+ return "x", dir.x > 0 and 1 or -1
+ end
+ elseif y > z then
+ return "y", dir.y > 0 and 1 or -1
+ end
+ return "z", dir.z > 0 and 1 or -1
+end
+
+minetest.register_chatcommand("/reset", {
+ params = "",
+ description = "Reset the region so that it is empty",
+ privs = {worldedit=true},
+ func = function(name, param)
+ worldedit.pos1[name] = nil
+ worldedit.pos2[name] = nil
+ worldedit.mark_pos1(name)
+ worldedit.mark_pos2(name)
+ minetest.chat_send_player(name, "WorldEdit region reset")
+ end,
+})
+
+minetest.register_chatcommand("/mark", {
+ params = "",
+ description = "Show markers at the region positions",
+ privs = {worldedit=true},
+ func = function(name, param)
+ worldedit.mark_pos1(name)
+ worldedit.mark_pos2(name)
+ minetest.chat_send_player(name, "WorldEdit region marked")
+ end,
+})
+
+minetest.register_chatcommand("/pos1", {
+ params = "",
+ description = "Set WorldEdit region position 1 to the player's location",
+ privs = {worldedit=true},
+ func = function(name, param)
+ local pos = minetest.env:get_player_by_name(name):getpos()
+ pos.x, pos.y, pos.z = math.floor(pos.x), math.floor(pos.y), math.floor(pos.z)
+ worldedit.pos1[name] = pos
+ worldedit.mark_pos1(name)
+ minetest.chat_send_player(name, "WorldEdit position 1 set to " .. minetest.pos_to_string(pos))
+ end,
+})
+
+minetest.register_chatcommand("/pos2", {
+ params = "",
+ description = "Set WorldEdit region position 2 to the player's location",
+ privs = {worldedit=true},
+ func = function(name, param)
+ local pos = minetest.env:get_player_by_name(name):getpos()
+ pos.x, pos.y, pos.z = math.floor(pos.x), math.floor(pos.y), math.floor(pos.z)
+ worldedit.pos2[name] = pos
+ worldedit.mark_pos2(name)
+ minetest.chat_send_player(name, "WorldEdit position 2 set to " .. minetest.pos_to_string(pos))
+ end,
+})
+
+minetest.register_chatcommand("/p", {
+ params = "set/get",
+ description = "Set WorldEdit region by punching two nodes, or display the current WorldEdit region",
+ privs = {worldedit=true},
+ func = function(name, param)
+ if param == "set" then --set both WorldEdit positions
+ worldedit.set_pos[name] = 1
+ minetest.chat_send_player(name, "Select positions by punching two nodes")
+ elseif param == "get" then --display current WorldEdit positions
+ if worldedit.pos1[name] ~= nil then
+ minetest.chat_send_player(name, "WorldEdit position 1: " .. minetest.pos_to_string(worldedit.pos1[name]))
+ else
+ minetest.chat_send_player(name, "WorldEdit position 1 not set")
+ end
+ if worldedit.pos2[name] ~= nil then
+ minetest.chat_send_player(name, "WorldEdit position 2: " .. minetest.pos_to_string(worldedit.pos2[name]))
+ else
+ minetest.chat_send_player(name, "WorldEdit position 2 not set")
+ end
+ else
+ minetest.chat_send_player(name, "Unknown subcommand: " .. param)
+ end
+ end,
+})
+
+minetest.register_on_punchnode(function(pos, node, puncher)
+ local name = puncher:get_player_name()
+ if name ~= "" and worldedit.set_pos[name] ~= nil then --currently setting position
+ if worldedit.set_pos[name] == 1 then --setting position 1
+ worldedit.set_pos[name] = 2 --set position 2 on the next invocation
+ worldedit.pos1[name] = pos
+ worldedit.mark_pos1(name)
+ minetest.chat_send_player(name, "WorldEdit region position 1 set to " .. minetest.pos_to_string(pos))
+ else --setting position 2
+ worldedit.set_pos[name] = nil --finished setting positions
+ worldedit.pos2[name] = pos
+ worldedit.mark_pos2(name)
+ minetest.chat_send_player(name, "WorldEdit region position 2 set to " .. minetest.pos_to_string(pos))
+ end
+ end
+end)
+
+minetest.register_chatcommand("/volume", {
+ params = "",
+ description = "Display the volume of the current WorldEdit region",
+ privs = {worldedit=true},
+ func = function(name, param)
+ local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
+ if pos1 == nil or pos2 == nil then
+ minetest.chat_send_player(name, "No WorldEdit region selected")
+ return
+ end
+
+ local volume = worldedit.volume(pos1, pos2)
+ 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 .. ")")
+ end,
+})
+
+minetest.register_chatcommand("/set", {
+ params = "<node>",
+ description = "Set the current WorldEdit region to <node>",
+ privs = {worldedit=true},
+ func = function(name, param)
+ local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
+ if pos1 == nil or pos2 == nil then
+ minetest.chat_send_player(name, "No WorldEdit region selected")
+ return
+ end
+
+ if param == "" or not worldedit.node_is_valid(pos1, param) then
+ minetest.chat_send_player(name, "Invalid node name: " .. param)
+ return
+ end
+
+ local count = worldedit.set(pos1, pos2, param)
+ minetest.chat_send_player(name, count .. " nodes set")
+ end,
+})
+
+minetest.register_chatcommand("/replace", {
+ params = "<search node> <replace node>",
+ description = "Replace all instances of <search node> with <place node> in the current WorldEdit region",
+ privs = {worldedit=true},
+ func = function(name, param)
+ local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
+ if pos1 == nil or pos2 == nil then
+ minetest.chat_send_player(name, "No WorldEdit region selected")
+ return
+ end
+
+ local found, _, searchnode, replacenode = param:find("^([^%s]+)%s+([^%s]+)$")
+ if found == nil then
+ minetest.chat_send_player(name, "Invalid usage: " .. param)
+ return
+ end
+ if not worldedit.node_is_valid(pos1, searchnode) then
+ minetest.chat_send_player(name, "Invalid search node name: " .. searchnode)
+ return
+ end
+ if not worldedit.node_is_valid(pos1, replacenode) then
+ minetest.chat_send_player(name, "Invalid replace node name: " .. replacenode)
+ return
+ end
+
+ local count = worldedit.replace(pos1, pos2, searchnode, replacenode)
+ minetest.chat_send_player(name, count .. " nodes replaced")
+ end,
+})
+
+minetest.register_chatcommand("/hollowsphere", {
+ params = "<radius> <node>",
+ description = "Add hollow sphere at WorldEdit position 1 with radius <radius>, composed of <node>",
+ privs = {worldedit=true},
+ func = function(name, param)
+ local pos = worldedit.pos1[name]
+ if pos == nil then
+ minetest.chat_send_player(name, "No WorldEdit region selected")
+ return
+ end
+
+ local found, _, radius, nodename = param:find("^(%d+)%s+([^%s]+)$")
+ if found == nil then
+ minetest.chat_send_player(name, "Invalid usage: " .. param)
+ return
+ end
+ if not worldedit.node_is_valid(pos, nodename) then
+ minetest.chat_send_player(name, "Invalid node name: " .. param)
+ return
+ end
+
+ local count = worldedit.hollow_sphere(pos, tonumber(radius), nodename)
+ minetest.chat_send_player(name, count .. " nodes added")
+ end,
+})
+
+minetest.register_chatcommand("/sphere", {
+ params = "<radius> <node>",
+ description = "Add sphere at WorldEdit position 1 with radius <radius>, composed of <node>",
+ privs = {worldedit=true},
+ func = function(name, param)
+ local pos = worldedit.pos1[name]
+ if pos == nil then
+ minetest.chat_send_player(name, "No WorldEdit region selected")
+ return
+ end
+
+ local found, _, radius, nodename = param:find("^(%d+)%s+([^%s]+)$")
+ if found == nil then
+ minetest.chat_send_player(name, "Invalid usage: " .. param)
+ return
+ end
+ if not worldedit.node_is_valid(pos, nodename) then
+ minetest.chat_send_player(name, "Invalid node name: " .. param)
+ return
+ end
+
+ local count = worldedit.sphere(pos, tonumber(radius), nodename)
+ minetest.chat_send_player(name, count .. " nodes added")
+ end,
+})
+
+minetest.register_chatcommand("/hollowcylinder", {
+ params = "x/y/z/? <length> <radius> <node>",
+ description = "Add hollow cylinder at WorldEdit position 1 along the x/y/z/? axis with length <length> and radius <radius>, composed of <node>",
+ privs = {worldedit=true},
+ func = function(name, param)
+ local pos = worldedit.pos1[name]
+ if pos == nil then
+ minetest.chat_send_player(name, "No WorldEdit region selected")
+ return
+ end
+
+ local found, _, axis, length, radius, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+([^%s]+)$")
+ if found == nil then
+ minetest.chat_send_player(name, "Invalid usage: " .. param)
+ return
+ end
+ if axis == "?" then
+ axis, sign = worldedit.player_axis(name)
+ length = length * sign
+ end
+ if not worldedit.node_is_valid(pos, nodename) then
+ minetest.chat_send_player(name, "Invalid node name: " .. param)
+ return
+ end
+
+ local count = worldedit.hollow_cylinder(pos, axis, tonumber(length), tonumber(radius), nodename)
+ minetest.chat_send_player(name, count .. " nodes added")
+ end,
+})
+
+minetest.register_chatcommand("/cylinder", {
+ params = "x/y/z/? <length> <radius> <node>",
+ description = "Add cylinder at WorldEdit position 1 along the x/y/z/? axis with length <length> and radius <radius>, composed of <node>",
+ privs = {worldedit=true},
+ func = function(name, param)
+ local pos = worldedit.pos1[name]
+ if pos == nil then
+ minetest.chat_send_player(name, "No WorldEdit region selected")
+ return
+ end
+
+ local found, _, axis, length, radius, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+([^%s]+)$")
+ if found == nil then
+ minetest.chat_send_player(name, "Invalid usage: " .. param)
+ return
+ end
+ if axis == "?" then
+ axis, sign = worldedit.player_axis(name)
+ length = length * sign
+ end
+ if not worldedit.node_is_valid(pos, nodename) then
+ minetest.chat_send_player(name, "Invalid node name: " .. param)
+ return
+ end
+
+ local count = worldedit.cylinder(pos, axis, tonumber(length), tonumber(radius), nodename)
+ minetest.chat_send_player(name, count .. " nodes added")
+ end,
+})
+
+minetest.register_chatcommand("/pyramid", {
+ params = "<height> <node>",
+ description = "Add pyramid at WorldEdit position 1 with height <height>, composed of <node>",
+ privs = {worldedit=true},
+ func = function(name, param)
+ local pos = worldedit.pos1[name]
+ if pos == nil then
+ minetest.chat_send_player(name, "No WorldEdit region selected")
+ return
+ end
+
+ local found, _, size, nodename = param:find("(%d+)%s+([^%s]+)$")
+ if found == nil then
+ minetest.chat_send_player(name, "Invalid usage: " .. param)
+ return
+ end
+ if not worldedit.node_is_valid(pos, nodename) then
+ minetest.chat_send_player(name, "Invalid node name: " .. param)
+ return
+ end
+
+ local count = worldedit.pyramid(pos, tonumber(size), nodename)
+ minetest.chat_send_player(name, count .. " nodes added")
+ end,
+})
+
+minetest.register_chatcommand("/spiral", {
+ params = "<width> <height> <space> <node>",
+ description = "Add spiral at WorldEdit position 1 with width <width>, height <height>, space between walls <space>, composed of <node>",
+ privs = {worldedit=true},
+ func = function(name, param)
+ local pos = worldedit.pos1[name]
+ if pos == nil then
+ minetest.chat_send_player(name, "No WorldEdit region selected")
+ return
+ end
+
+ local found, _, width, height, space, nodename = param:find("(%d+)%s+(%d+)%s+(%d+)%s+([^%s]+)$")
+ if found == nil then
+ minetest.chat_send_player(name, "Invalid usage: " .. param)
+ return
+ end
+ if not worldedit.node_is_valid(pos, nodename) then
+ minetest.chat_send_player(name, "Invalid node name: " .. param)
+ return
+ end
+
+ local count = worldedit.spiral(pos, tonumber(width), tonumber(height), tonumber(space), nodename)
+ minetest.chat_send_player(name, count .. " nodes changed")
+ end,
+})
+
+minetest.register_chatcommand("/copy", {
+ params = "x/y/z/? <amount>",
+ description = "Copy the current WorldEdit region along the x/y/z/? axis by <amount> nodes",
+ privs = {worldedit=true},
+ func = function(name, param)
+ local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
+ if pos1 == nil or pos2 == nil then
+ minetest.chat_send_player(name, "No WorldEdit region selected")
+ return
+ end
+
+ local found, _, axis, amount = param:find("^([xyz%?])%s+([+-]?%d+)$")
+ if found == nil then
+ minetest.chat_send_player(name, "Invalid usage: " .. param)
+ return
+ end
+ if axis == "?" then
+ axis, sign = worldedit.player_axis(name)
+ amount = amount * sign
+ end
+
+ local count = worldedit.copy(pos1, pos2, axis, tonumber(amount))
+ minetest.chat_send_player(name, count .. " nodes copied")
+ end,
+})
+
+minetest.register_chatcommand("/move", {
+ params = "x/y/z/? <amount>",
+ description = "Move the current WorldEdit region along the x/y/z/? axis by <amount> nodes",
+ privs = {worldedit=true},
+ func = function(name, param)
+ local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
+ if pos1 == nil or pos2 == nil then
+ minetest.chat_send_player(name, "No WorldEdit region selected")
+ return
+ end
+
+ local found, _, axis, amount = param:find("^([xyz%?])%s+([+-]?%d+)$")
+ if found == nil then
+ minetest.chat_send_player(name, "Invalid usage: " .. param)
+ return
+ end
+ if axis == "?" then
+ axis, sign = worldedit.player_axis(name)
+ amount = amount * sign
+ end
+
+ local count = worldedit.move(pos1, pos2, axis, tonumber(amount))
+
+ pos1[axis] = pos1[axis] + amount
+ pos2[axis] = pos2[axis] + amount
+ worldedit.mark_pos1(name)
+ worldedit.mark_pos2(name)
+
+ minetest.chat_send_player(name, count .. " nodes moved")
+ end,
+})
+
+minetest.register_chatcommand("/stack", {
+ params = "x/y/z/? <count>",
+ description = "Stack the current WorldEdit region along the x/y/z/? axis <count> times",
+ privs = {worldedit=true},
+ func = function(name, param)
+ local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
+ if pos1 == nil or pos2 == nil then
+ minetest.chat_send_player(name, "No WorldEdit region selected")
+ return
+ end
+
+ local found, _, axis, count = param:find("^([xyz%?])%s+([+-]?%d+)$")
+ if found == nil then
+ minetest.chat_send_player(name, "Invalid usage: " .. param)
+ return
+ end
+ if axis == "?" then
+ axis, sign = worldedit.player_axis(name)
+ count = count * sign
+ end
+
+ local count = worldedit.stack(pos1, pos2, axis, tonumber(count))
+ minetest.chat_send_player(name, count .. " nodes stacked")
+ end,
+})
+
+minetest.register_chatcommand("/transpose", {
+ params = "x/y/z/? x/y/z/?",
+ description = "Transpose the current WorldEdit region along the x/y/z/? and x/y/z/? axes",
+ privs = {worldedit=true},
+ func = function(name, param)
+ local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
+ if pos1 == nil or pos2 == nil then
+ minetest.chat_send_player(name, "No WorldEdit region selected")
+ return
+ end
+
+ local found, _, axis1, axis2 = param:find("^([xyz%?])%s+([xyz%?])$")
+ if found == nil then
+ minetest.chat_send_player(name, "Invalid usage: " .. param)
+ return
+ end
+ if axis1 == "?" then
+ axis1 = worldedit.player_axis(name)
+ end
+ if axis2 == "?" then
+ axis2 = worldedit.player_axis(name)
+ end
+ if axis1 == axis2 then
+ minetest.chat_send_player(name, "Invalid usage: axes are the same")
+ return
+ end
+
+ local count = worldedit.transpose(pos1, pos2, axis1, axis2)
+ minetest.chat_send_player(name, count .. " nodes transposed")
+ end,
+})
+
+minetest.register_chatcommand("/flip", {
+ params = "x/y/z/?",
+ description = "Flip the current WorldEdit region along the x/y/z/? axis",
+ privs = {worldedit=true},
+ func = function(name, param)
+ local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
+ if pos1 == nil or pos2 == nil then
+ minetest.chat_send_player(name, "No WorldEdit region selected")
+ return
+ end
+
+ if param == "?" then
+ param = worldedit.player_axis(name)
+ end
+ if param ~= "x" and param ~= "y" and param ~= "z" then
+ minetest.chat_send_player(name, "Invalid usage: " .. param)
+ return
+ end
+
+ local count = worldedit.flip(pos1, pos2, param)
+ minetest.chat_send_player(name, count .. " nodes flipped")
+ end,
+})
+
+minetest.register_chatcommand("/rotate", {
+ params = "<axis> <angle>",
+ description = "Rotate the current WorldEdit region around the axis <axis> by angle <angle> (90 degree increment)",
+ privs = {worldedit=true},
+ func = function(name, param)
+ local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
+ if pos1 == nil or pos2 == nil then
+ minetest.chat_send_player(name, "No WorldEdit region selected")
+ return
+ end
+
+ local found, _, axis, angle = param:find("^([xyz%?])%s+([+-]?%d+)$")
+ if found == nil then
+ minetest.chat_send_player(name, "Invalid usage: " .. param)
+ return
+ end
+ if axis == "?" then
+ axis = worldedit.player_axis(name)
+ end
+ if angle % 90 ~= 0 then
+ minetest.chat_send_player(name, "Invalid usage: angle must be multiple of 90")
+ return
+ end
+
+ local count = worldedit.rotate(pos1, pos2, axis, angle)
+ minetest.chat_send_player(name, count .. " nodes rotated")
+ end,
+})
+
+minetest.register_chatcommand("/dig", {
+ params = "",
+ description = "Dig the current WorldEdit region",
+ privs = {worldedit=true},
+ func = function(name, param)
+ local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
+ if pos1 == nil or pos2 == nil then
+ minetest.chat_send_player(name, "No WorldEdit region selected")
+ return
+ end
+
+ local count = worldedit.dig(pos1, pos2)
+ minetest.chat_send_player(name, count .. " nodes dug")
+ end,
+})
+
+minetest.register_chatcommand("/save", {
+ params = "<file>",
+ description = "Save the current WorldEdit region to \"(world folder)/schems/<file>.we\"",
+ privs = {worldedit=true},
+ func = function(name, param)
+ local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
+ if pos1 == nil or pos2 == nil then
+ minetest.chat_send_player(name, "No WorldEdit region selected")
+ return
+ end
+
+ if param == "" then
+ minetest.chat_send_player(name, "Invalid usage: " .. param)
+ return
+ end
+
+ local result, count = worldedit.serialize(pos1, pos2)
+
+ local path = minetest.get_worldpath() .. "/schems"
+ local filename = path .. "/" .. param .. ".we"
+ os.execute("mkdir \"" .. path .. "\"") --create directory if it does not already exist
+ local file, err = io.open(filename, "wb")
+ if err ~= nil then
+ minetest.chat_send_player(name, "Could not save file to \"" .. filename .. "\"")
+ return
+ end
+ file:write(result)
+ file:flush()
+ file:close()
+
+ minetest.chat_send_player(name, count .. " nodes saved")
+ end,
+})
+
+minetest.register_chatcommand("/load", {
+ params = "<file>",
+ description = "Load nodes from \"(world folder)/schems/<file>.we\" with position 1 of the current WorldEdit region as the origin",
+ privs = {worldedit=true},
+ func = function(name, param)
+ local pos1 = worldedit.pos1[name]
+ if pos1 == nil then
+ minetest.chat_send_player(name, "No WorldEdit region selected")
+ return
+ end
+
+ if param == "" then
+ minetest.chat_send_player(name, "Invalid usage: " .. param)
+ return
+ end
+
+ local filename = minetest.get_worldpath() .. "/schems/" .. param .. ".we"
+ local file, err = io.open(filename, "rb")
+ if err ~= nil then
+ minetest.chat_send_player(name, "Could not open file \"" .. filename .. "\"")
+ return
+ end
+ local value = file:read("*a")
+ file:close()
+
+ local count
+ if value:find("{") then --old WorldEdit format
+ count = worldedit.deserialize_old(pos1, value)
+ else --new WorldEdit format
+ count = worldedit.deserialize(pos1, value)
+ end
+
+ minetest.chat_send_player(name, count .. " nodes loaded")
+ end,
+})
+
+minetest.register_chatcommand("/metasave", {
+ params = "<file>",
+ description = "Save the current WorldEdit region to \"(world folder)/schems/<file>.wem\"",
+ privs = {worldedit=true},
+ func = function(name, param)
+ local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
+ if pos1 == nil or pos2 == nil then
+ minetest.chat_send_player(name, "No WorldEdit region selected")
+ return
+ end
+ if param == "" then
+ minetest.chat_send_player(name, "Invalid usage: " .. param)
+ return
+ end
+ local count, err = worldedit.metasave(pos1, pos2, param)
+ if err then
+ minetest.chat_send_player(name, "error loading file: " .. err)
+ else
+ minetest.chat_send_player(name, count .. " nodes saved")
+ end
+ end,
+})
+
+minetest.register_chatcommand("/metaload", {
+ params = "<file>",
+ description = "Load nodes from \"(world folder)/schems/<file>.wem\" with position 1 of the current WorldEdit region as the origin",
+ privs = {worldedit=true},
+ func = function(name, param)
+ local pos1 = worldedit.pos1[name]
+ if pos1 == nil then
+ minetest.chat_send_player(name, "No WorldEdit region selected")
+ return
+ end
+ if param == "" then
+ minetest.chat_send_player(name, "Invalid usage: " .. param)
+ return
+ end
+ local count, err = worldedit.metaload(pos1, param)
+ if err then
+ minetest.chat_send_player(name, "error loading file: " .. err)
+ else
+ minetest.chat_send_player(name, count .. " nodes loaded")
+ end
+ end,
+})
diff --git a/worldedit/mark.lua b/worldedit/mark.lua new file mode 100644 index 0000000..0f011d2 --- /dev/null +++ b/worldedit/mark.lua @@ -0,0 +1,70 @@ +worldedit.marker1 = {}
+worldedit.marker2 = {}
+
+--marks worldedit region position 1
+worldedit.mark_pos1 = function(name)
+ local pos = worldedit.pos1[name]
+ if worldedit.marker1[name] ~= nil then --marker already exists
+ worldedit.marker1[name]:remove() --remove marker
+ worldedit.marker1[name] = nil
+ end
+ if pos ~= nil then --add marker
+ worldedit.marker1[name] = minetest.env:add_entity(pos, "worldedit:pos1")
+ worldedit.marker1[name]:get_luaentity().active = true
+ end
+end
+
+--marks worldedit region position 2
+worldedit.mark_pos2 = function(name)
+ local pos = worldedit.pos2[name]
+ if worldedit.marker2[name] ~= nil then --marker already exists
+ worldedit.marker2[name]:remove() --remove marker
+ worldedit.marker2[name] = nil
+ end
+ if pos ~= nil then --add marker
+ worldedit.marker2[name] = minetest.env:add_entity(pos, "worldedit:pos2")
+ worldedit.marker2[name]:get_luaentity().active = true
+ end
+end
+
+minetest.register_entity("worldedit:pos1", {
+ initial_properties = {
+ visual = "cube",
+ visual_size = {x=1.1, y=1.1},
+ textures = {"worldedit_pos1.png", "worldedit_pos1.png",
+ "worldedit_pos1.png", "worldedit_pos1.png",
+ "worldedit_pos1.png", "worldedit_pos1.png"},
+ collisionbox = {-0.55, -0.55, -0.55, 0.55, 0.55, 0.55},
+ },
+ on_step = function(self, dtime)
+ if self.active == nil then
+ self.object:remove()
+ end
+ end,
+ on_punch = function(self, hitter)
+ self.object:remove()
+ local name = hitter:get_player_name()
+ worldedit.marker1[name] = nil
+ end,
+})
+
+minetest.register_entity("worldedit:pos2", {
+ initial_properties = {
+ visual = "cube",
+ visual_size = {x=1.1, y=1.1},
+ textures = {"worldedit_pos2.png", "worldedit_pos2.png",
+ "worldedit_pos2.png", "worldedit_pos2.png",
+ "worldedit_pos2.png", "worldedit_pos2.png"},
+ collisionbox = {-0.55, -0.55, -0.55, 0.55, 0.55, 0.55},
+ },
+ on_step = function(self, dtime)
+ if self.active == nil then
+ self.object:remove()
+ end
+ end,
+ on_punch = function(self, hitter)
+ self.object:remove()
+ local name = hitter:get_player_name()
+ worldedit.marker2[name] = nil
+ end,
+})
\ No newline at end of file diff --git a/worldedit/table_save.lua b/worldedit/table_save.lua new file mode 100644 index 0000000..cbc18ae --- /dev/null +++ b/worldedit/table_save.lua @@ -0,0 +1,133 @@ +--[[ + Save Table to File + Load Table from File + v 1.0 + + Lua 5.2 compatible + + Only Saves Tables, Numbers and Strings + Insides Table References are saved + Does not save Userdata, Metatables, Functions and indices of these + ---------------------------------------------------- + table.save( table , filename ) + + on failure: returns an error msg + + ---------------------------------------------------- + table.load( filename or stringtable ) + + Loads a table that has been saved via the table.save function + + on success: returns a previously saved table + on failure: returns as second argument an error msg + ---------------------------------------------------- + + Licensed under the same terms as Lua itself. +]]-- +do + -- declare local variables + --// exportstring( string ) + --// returns a "Lua" portable version of the string + local function exportstring( s ) + return string.format("%q", s) + end + + --// The Save Function + function table.save( tbl,filename ) + local charS,charE = " ","\n" + local file,err = io.open( filename, "wb" ) + if err then return err end + + -- initiate variables for save procedure + local tables,lookup = { tbl },{ [tbl] = 1 } + file:write( "return {"..charE ) + + for idx,t in ipairs( tables ) do + file:write( "-- Table: {"..idx.."}"..charE ) + file:write( "{"..charE ) + local thandled = {} + + for i,v in ipairs( t ) do + thandled[i] = true + local stype = type( v ) + -- only handle value + if stype == "table" then + if not lookup[v] then + table.insert( tables, v ) + lookup[v] = #tables + end + file:write( charS.."{"..lookup[v].."},"..charE ) + elseif stype == "string" then + file:write( charS..exportstring( v )..","..charE ) + elseif stype == "number" then + file:write( charS..tostring( v )..","..charE ) + end + end + + for i,v in pairs( t ) do + -- escape handled values + if (not thandled[i]) then + + local str = "" + local stype = type( i ) + -- handle index + if stype == "table" then + if not lookup[i] then + table.insert( tables,i ) + lookup[i] = #tables + end + str = charS.."[{"..lookup[i].."}]=" + elseif stype == "string" then + str = charS.."["..exportstring( i ).."]=" + elseif stype == "number" then + str = charS.."["..tostring( i ).."]=" + end + + if str ~= "" then + stype = type( v ) + -- handle value + if stype == "table" then + if not lookup[v] then + table.insert( tables,v ) + lookup[v] = #tables + end + file:write( str.."{"..lookup[v].."},"..charE ) + elseif stype == "string" then + file:write( str..exportstring( v )..","..charE ) + elseif stype == "number" then + file:write( str..tostring( v )..","..charE ) + end + end + end + end + file:write( "},"..charE ) + end + file:write( "}" ) + file:close() + end + + --// The Load Function + function table.load( sfile ) + local ftables,err = loadfile( sfile ) + if err then return _,err end + local tables = ftables() + for idx = 1,#tables do + local tolinki = {} + for i,v in pairs( tables[idx] ) do + if type( v ) == "table" then + tables[idx][i] = tables[v[1]] + end + if type( i ) == "table" and tables[i[1]] then + table.insert( tolinki,{ i,tables[i[1]] } ) + end + end + -- link indices + for _,v in ipairs( tolinki ) do + tables[idx][v[2]],tables[idx][v[1]] = tables[idx][v[1]],nil + end + end + return tables[1] + end +-- close do +end +-- ChillCode
\ No newline at end of file diff --git a/worldedit/textures/worldedit_pos1.png b/worldedit/textures/worldedit_pos1.png Binary files differnew file mode 100644 index 0000000..4c304aa --- /dev/null +++ b/worldedit/textures/worldedit_pos1.png diff --git a/worldedit/textures/worldedit_pos2.png b/worldedit/textures/worldedit_pos2.png Binary files differnew file mode 100644 index 0000000..1502f16 --- /dev/null +++ b/worldedit/textures/worldedit_pos2.png |