--- /dev/null
+Chat Commands\r
+-------------\r
+For more information, see the [README](README.md).\r
+\r
+### //reset\r
+\r
+Reset the region so that it is empty.\r
+\r
+ //reset\r
+\r
+### //mark\r
+\r
+Show markers at the region positions.\r
+\r
+ //mark\r
+\r
+### //pos1\r
+\r
+Set WorldEdit region position 1 to the player's location.\r
+\r
+ //pos1\r
+\r
+### //pos2\r
+\r
+Set WorldEdit region position 2 to the player's location.\r
+\r
+ //pos2\r
+\r
+### //p set/get\r
+\r
+Set WorldEdit region by punching two nodes, or display the current WorldEdit region.\r
+\r
+ //p set\r
+ //p get\r
+\r
+### //volume\r
+\r
+Display the volume of the current WorldEdit region.\r
+\r
+ //volume\r
+\r
+### //set <node>\r
+\r
+Set the current WorldEdit region to <node>.\r
+\r
+ //set dirt\r
+ //set default:glass\r
+ //set mesecons:mesecon\r
+\r
+### //replace <search node> <replace node>\r
+\r
+Replace all instances of <search node> with <place node> in the current WorldEdit region.\r
+\r
+ //replace cobble stone\r
+ //replace default:steelblock glass\r
+ //replace dirt flowers:flower_waterlily\r
+ //replace flowers:flower_rose flowers:flower_tulip\r
+\r
+### //hollowsphere <radius> <node>\r
+\r
+Add hollow sphere at WorldEdit position 1 with radius <radius>, composed of <node>.\r
+\r
+ //hollowsphere 5 dirt\r
+ //hollowsphere 12 default:glass\r
+ //hollowsphere 17 mesecons:mesecon\r
+\r
+### //sphere <radius> <node>\r
+\r
+Add sphere at WorldEdit position 1 with radius <radius>, composed of <node>.\r
+\r
+ //sphere 5 dirt\r
+ //sphere 12 default:glass\r
+ //sphere 17 mesecons:mesecon\r
+\r
+### //hollowcylinder x/y/z/? <length> <radius> <node>\r
+\r
+Add hollow cylinder at WorldEdit position 1 along the x/y/z/? axis with length <length> and radius <radius>, composed of <node>.\r
+\r
+ //hollowcylinder x +5 8 dirt\r
+ //hollowcylinder y 28 10 default:glass\r
+ //hollowcylinder z -12 3 mesecons:mesecon\r
+ //hollowcylinder ? 2 4 stone\r
+\r
+### //cylinder x/y/z/? <length> <radius> <node>\r
+\r
+Add cylinder at WorldEdit position 1 along the x/y/z/? axis with length <length> and radius <radius>, composed of <node>.\r
+\r
+ //cylinder x +5 8 dirt\r
+ //cylinder y 28 10 default:glass\r
+ //cylinder z -12 3 mesecons:mesecon\r
+ //cylinder ? 2 4 stone\r
+ \r
+### //pyramid <height> <node>\r
+\r
+Add pyramid at WorldEdit position 1 with height <height>, composed of <node>.\r
+\r
+ //pyramid 8 dirt\r
+ //pyramid 5 default:glass\r
+ //pyramid 2 stone\r
+\r
+### //spiral <width> <height> <spacer> <node>\r
+\r
+Add spiral at WorldEdit position 1 with width <width>, height <height>, space between walls <spacer>, composed of <node>.\r
+\r
+ //spiral 20 5 3 dirt\r
+ //spiral 5 2 1 default:glass\r
+ //spiral 7 1 5 stone\r
+\r
+### //copy x/y/z/? <amount>\r
+\r
+Copy the current WorldEdit region along the x/y/z/? axis by <amount> nodes.\r
+\r
+ //copy x 15\r
+ //copy y -7\r
+ //copy z +4\r
+ //copy ? 8\r
+\r
+### //move x/y/z/? <amount>\r
+\r
+Move the current WorldEdit positions and region along the x/y/z/? axis by <amount> nodes.\r
+\r
+ //move x 15\r
+ //move y -7\r
+ //move z +4\r
+ //move ? -1\r
+\r
+### //stack x/y/z/? <count>\r
+\r
+Stack the current WorldEdit region along the x/y/z/? axis <count> times.\r
+\r
+ //stack x 3\r
+ //stack y -1\r
+ //stack z +5\r
+ //stack ? 12\r
+\r
+### //transpose x/y/z/? x/y/z/?\r
+\r
+Transpose the current WorldEdit region along the x/y/z/? and x/y/z/? axes.\r
+\r
+ //transpose x y\r
+ //transpose x z\r
+ //transpose y z\r
+ //transpose ? y\r
+\r
+### //flip x/y/z/?\r
+\r
+Flip the current WorldEdit region along the x/y/z/? axis.\r
+\r
+ //flip x\r
+ //flip y\r
+ //flip z\r
+ //flip ?\r
+\r
+### //rotate x/y/z/? <angle>\r
+\r
+Rotate the current WorldEdit region along the x/y/z/? axis by angle <angle> (90 degree increment).\r
+\r
+ //rotate x 90\r
+ //rotate y 180\r
+ //rotate z 270\r
+ //rotate ? -90\r
+\r
+### //dig\r
+\r
+Dig the current WorldEdit region.\r
+\r
+ //dig\r
+\r
+### //save <file>\r
+\r
+Save the current WorldEdit region to "(world folder)/schems/<file>.we".\r
+\r
+ //save some random filename\r
+ //save huge_base\r
+\r
+### //load <file>\r
+\r
+Load nodes from "(world folder)/schems/<file>.we" with position 1 of the current WorldEdit region as the origin.\r
+\r
+ //load some random filename\r
+ //load huge_base\r
+\r
+### //metasave <file>\r
+\r
+Save the current WorldEdit region including metadata to "(world folder)/schems/<file>.wem".\r
+\r
+ //metasave some random filename\r
+ //metasave huge_base\r
+\r
+### //metaload <file>\r
+\r
+Load nodes and metadata from "(world folder)/schems/<file>.wem" with position 1 of the current WorldEdit region as the origin.\r
+\r
+ //metaload some random filename\r
+ //metaload huge_base
\ No newline at end of file
To remove the entities, simply punch them. This does not reset the positions themselves.
-Commands
---------
-
-### //reset
-
-Reset the region so that it is empty.
-
- //reset
-
-### //mark
-
-Show markers at the region positions.
-
- //mark
-
-### //pos1
-
-Set WorldEdit region position 1 to the player's location.
-
- //pos1
-
-### //pos2
-
-Set WorldEdit region position 2 to the player's location.
-
- //pos2
-
-### //p set/get
-
-Set WorldEdit region by punching two nodes, or display the current WorldEdit region.
-
- //p set
- //p get
-
-### //volume
-
-Display the volume of the current WorldEdit region.
-
- //volume
-
-### //set <node>
-
-Set the current WorldEdit region to <node>.
-
- //set dirt
- //set default:glass
- //set mesecons:mesecon
-
-### //replace <search node> <replace node>
-
-Replace all instances of <search node> with <place node> in the current WorldEdit region.
-
- //replace cobble stone
- //replace default:steelblock glass
- //replace dirt flowers:flower_waterlily
- //replace flowers:flower_rose flowers:flower_tulip
-
-### //hollowsphere <radius> <node>
-
-Add hollow sphere at WorldEdit position 1 with radius <radius>, composed of <node>.
-
- //hollowsphere 5 dirt
- //hollowsphere 12 default:glass
- //hollowsphere 17 mesecons:mesecon
-
-### //sphere <radius> <node>
-
-Add sphere at WorldEdit position 1 with radius <radius>, composed of <node>.
-
- //sphere 5 dirt
- //sphere 12 default:glass
- //sphere 17 mesecons:mesecon
-
-### //hollowcylinder x/y/z/? <length> <radius> <node>
-
-Add hollow cylinder at WorldEdit position 1 along the x/y/z/? axis with length <length> and radius <radius>, composed of <node>.
-
- //hollowcylinder x +5 8 dirt
- //hollowcylinder y 28 10 default:glass
- //hollowcylinder z -12 3 mesecons:mesecon
- //hollowcylinder ? 2 4 stone
-
-### //cylinder x/y/z/? <length> <radius> <node>
-
-Add cylinder at WorldEdit position 1 along the x/y/z/? axis with length <length> and radius <radius>, composed of <node>.
-
- //cylinder x +5 8 dirt
- //cylinder y 28 10 default:glass
- //cylinder z -12 3 mesecons:mesecon
- //cylinder ? 2 4 stone
-
-### //pyramid <height> <node>
-
-Add pyramid at WorldEdit position 1 with height <height>, composed of <node>.
-
- //pyramid 8 dirt
- //pyramid 5 default:glass
- //pyramid 2 stone
-
-### //spiral <width> <height> <spacer> <node>
-
-Add spiral at WorldEdit position 1 with width <width>, height <height>, space between walls <spacer>, composed of <node>.
-
- //spiral 20 5 3 dirt
- //spiral 5 2 1 default:glass
- //spiral 7 1 5 stone
-
-### //copy x/y/z/? <amount>
-
-Copy the current WorldEdit region along the x/y/z/? axis by <amount> nodes.
-
- //copy x 15
- //copy y -7
- //copy z +4
- //copy ? 8
-
-### //move x/y/z/? <amount>
-
-Move the current WorldEdit positions and region along the x/y/z/? axis by <amount> nodes.
-
- //move x 15
- //move y -7
- //move z +4
- //move ? -1
-
-### //stack x/y/z/? <count>
-
-Stack the current WorldEdit region along the x/y/z/? axis <count> times.
-
- //stack x 3
- //stack y -1
- //stack z +5
- //stack ? 12
-
-### //transpose x/y/z/? x/y/z/?
-
-Transpose the current WorldEdit region along the x/y/z/? and x/y/z/? axes.
-
- //transpose x y
- //transpose x z
- //transpose y z
- //transpose ? y
-
-### //flip x/y/z/?
-
-Flip the current WorldEdit region along the x/y/z/? axis.
-
- //flip x
- //flip y
- //flip z
- //flip ?
-
-### //rotate x/y/z/? <angle>
-
-Rotate the current WorldEdit region along the x/y/z/? axis by angle <angle> (90 degree increment).
-
- //rotate x 90
- //rotate y 180
- //rotate z 270
- //rotate ? -90
-
-### //dig
-
-Dig the current WorldEdit region.
-
- //dig
-
-### //save <file>
-
-Save the current WorldEdit region to "(world folder)/schems/<file>.we".
-
- //save some random filename
- //save huge_base
-
-### //load <file>
-
-Load nodes from "(world folder)/schems/<file>.we" with position 1 of the current WorldEdit region as the origin.
-
- //load some random filename
- //load huge_base
-
-### //metasave <file>
-
-Save the current WorldEdit region including metadata to "(world folder)/schems/<file>.wem".
-
- //metasave some random filename
- //metasave huge_base
-
-### //metaload <file>
-
-Load nodes and metadata from "(world folder)/schems/<file>.wem" with position 1 of the current WorldEdit region as the origin.
+Chat Commands
+-------------
+WorldEdit is accessed in-game through an interface. By default, the mod distribution includes a chat interface for this purpose. It is documented in the [Chat Commands Reference](Chat Commands.md).
- //metaload some random filename
- //metaload huge_base
+If visual manipulation of nodes is desired, the [WorldEdit GUI](http://minetest.net/forum/viewtopic.php?id=3112) mod provides a simple interface with buttons and text entry fields for this purpose.
WorldEdit API
-------------
-WorldEdit exposes all significant functionality in a simple interface. Adding WorldEdit to the file "depends.txt" in your mod gives you access to all of the `worldedit` functions. These are useful if you're looking for high-performance node manipulation without all the hassle of writing tons of code.
-
-### worldedit.volume(pos1, pos2)
-
-Determines the volume of the region defined by positions `pos1` and `pos2`.
-
-Returns the volume.
-
-### worldedit.set(pos1, pos2, nodename)
-
-Sets a region defined by positions `pos1` and `pos2` to `nodename`. To clear to region, use "air" as the value of `nodename`.
-
-Returns the number of nodes set.
-
-### worldedit.replace(pos1, pos2, searchnode, replacenode)
-
-Replaces all instances of `searchnode` with `replacenode` in a region defined by positions `pos1` and `pos2`.
-
-Returns the number of nodes replaced.
-
-### worldedit.hollow_sphere = function(pos, radius, nodename)
-
-Adds a hollow sphere at `pos` with radius `radius`, composed of `nodename`.
-
-Returns the number of nodes added.
-
-### worldedit.sphere = function(pos, radius, nodename)
-
-Adds a sphere at `pos` with radius `radius`, composed of `nodename`.
-
-Returns the number of nodes added.
-
-### worldedit.hollow_cylinder(pos, axis, length, radius, nodename)
-
-Adds a hollow cylinder at `pos` along the `axis` axis ("x" or "y" or "z") with length `length` and radius `radius`, composed of `nodename`.
-
-Returns the number of nodes added.
-
-### worldedit.cylinder(pos, axis, length, radius, nodename)
-
-Adds a cylinder at `pos` along the `axis` axis ("x" or "y" or "z") with length `length` and radius `radius`, composed of `nodename`.
-
-Returns the number of nodes added.
-
-### worldedit.pyramid(pos, height, nodename)
-
-Adds a pyramid at `pos` with height `height`.
-
-Returns the number of nodes added.
-
-### worldedit.spiral(pos, width, height, spacer, nodename)
-
-Adds a spiral at `pos` with width `width`, height `height`, space between walls `spacer`, composed of `nodename`.
-
-Returns the number of nodes added.
-
-### worldedit.copy(pos1, pos2, axis, amount)
-
-Copies the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") by `amount` nodes.
-
-Returns the number of nodes copied.
-
-### worldedit.move(pos1, pos2, axis, amount)
-
-Moves the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") by `amount` nodes.
-
-Returns the number of nodes moved.
-
-### worldedit.stack(pos1, pos2, axis, count)
-
-Duplicates the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") `count` times.
-
-Returns the number of nodes stacked.
-
-### worldedit.transpose(pos1, pos2, axis1, axis2)
-
-Transposes a region defined by the positions `pos1` and `pos2` between the `axis1` and `axis2` axes ("x" or "y" or "z").
-
-Returns the number of nodes transposed.
-
-### worldedit.flip(pos1, pos2, axis)
-
-Flips a region defined by the positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z").
-
-Returns the number of nodes flipped.
-
-### worldedit.rotate(pos1, pos2, angle)
-
-Rotates a region defined by the positions `pos1` and `pos2` by `angle` degrees clockwise around the y axis (supporting 90 degree increments only).
-
-Returns the number of nodes rotated.
-
-### worldedit.dig(pos1, pos2)
-
-Digs a region defined by positions `pos1` and `pos2`.
-
-Returns the number of nodes dug.
-
-### worldedit.serialize(pos1, pos2)
-
-Converts the region defined by positions `pos1` and `pos2` into a single string.
-
-Returns the serialized data and the number of nodes serialized.
-
-### worldedit.deserialize(originpos, value)
-
-Loads the nodes represented by string `value` at position `originpos`.
-
-Returns the number of nodes deserialized.
-
-### worldedit.deserialize_old(originpos, value)
-
-Loads the nodes represented by string `value` at position `originpos`, using the older table-based WorldEdit format.
-
-This function is deprecated, and should not be used unless there is a need to support legacy WorldEdit save files.
-
-Returns the number of nodes deserialized.
-
-### worldedit.metasave(pos1, pos2, file)
-
-Saves the nodes and meta defined by positions `pos1` and `pos2` into a file
-
-Returns the number of nodes saved
-
-### worldedit.metaload(pos1, file)
-
-Loads the nodes and meta from `file` to position `pos1`
+WorldEdit exposes all significant functionality in a simple interface. Adding WorldEdit to the file "depends.txt" in your mod gives you access to all of the `worldedit` functions. The API is useful for tasks such as high-performance node manipulation, alternative interfaces, and map creation.
-Returns the number of nodes loaded
+This API is documented in the [WorldEdit API Reference](WorldEdit API.md).
License
-------
-Copyright 2012 sfan5 and Anthony Zhang (Temperest)
+Copyright 2012 sfan5, Anthony Zhang (Temperest), and Brett O'Donnell (cornernote).
This mod is licensed under the [GNU Affero General Public License](http://www.gnu.org/licenses/agpl-3.0.html).
--- /dev/null
+WorldEdit API\r
+-------------\r
+For more information, see the [README](README.md).\r
+\r
+### worldedit.volume(pos1, pos2)\r
+\r
+Determines the volume of the region defined by positions `pos1` and `pos2`.\r
+\r
+Returns the volume.\r
+\r
+### worldedit.set(pos1, pos2, nodename)\r
+\r
+Sets a region defined by positions `pos1` and `pos2` to `nodename`. To clear to region, use "air" as the value of `nodename`.\r
+\r
+Returns the number of nodes set.\r
+\r
+### worldedit.replace(pos1, pos2, searchnode, replacenode)\r
+\r
+Replaces all instances of `searchnode` with `replacenode` in a region defined by positions `pos1` and `pos2`.\r
+\r
+Returns the number of nodes replaced.\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
+Returns the number of nodes added.\r
+\r
+### worldedit.sphere = function(pos, radius, nodename)\r
+\r
+Adds a sphere at `pos` with radius `radius`, composed of `nodename`.\r
+\r
+Returns the number of nodes added.\r
+\r
+### worldedit.hollow_cylinder(pos, axis, length, radius, nodename)\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`.\r
+\r
+Returns the number of nodes added.\r
+\r
+### worldedit.cylinder(pos, axis, length, radius, nodename)\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`.\r
+\r
+Returns the number of nodes added.\r
+\r
+### worldedit.pyramid(pos, height, nodename)\r
+\r
+Adds a pyramid at `pos` with height `height`.\r
+\r
+Returns the number of nodes added.\r
+\r
+### worldedit.spiral(pos, width, height, spacer, 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
+\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
+### worldedit.serialize(pos1, pos2)\r
+\r
+Converts the region defined by positions `pos1` and `pos2` into a single string.\r
+\r
+Returns the serialized data and the number of nodes serialized.\r
+\r
+### worldedit.deserialize(originpos, value)\r
+\r
+Loads the nodes represented by string `value` at position `originpos`.\r
+\r
+Returns the number of nodes deserialized.\r
+\r
+### worldedit.deserialize_old(originpos, value)\r
+\r
+Loads the nodes represented by string `value` at position `originpos`, using the older table-based WorldEdit format.\r
+\r
+This function is deprecated, and should not be used unless there is a need to support legacy WorldEdit save files.\r
+\r
+Returns the number of nodes deserialized.\r
+\r
+### worldedit.metasave(pos1, pos2, file)\r
+\r
+Saves the nodes and meta defined by positions `pos1` and `pos2` into a file.\r
+\r
+Returns the number of nodes saved.\r
+\r
+### worldedit.metaload(pos1, file)\r
+\r
+Loads the nodes and meta from `file` to position `pos1`.\r
+\r
+Returns the number of nodes loaded.
\ No newline at end of file
+++ /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
+++ /dev/null
-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
+++ /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
---[[
- 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
--- /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
--- /dev/null
+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
--- /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
+--[[
+ 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