]> git.lizzy.rs Git - worldedit.git/commitdiff
Use modpack for easier installation (idea is taken from cornernote's mod format)...
authorAnthony Zhang <azhang9@gmail.com>
Mon, 1 Oct 2012 20:19:09 +0000 (16:19 -0400)
committerAnthony Zhang <azhang9@gmail.com>
Mon, 1 Oct 2012 20:20:20 +0000 (16:20 -0400)
16 files changed:
Chat Commands.md [new file with mode: 0644]
README.md
WorldEdit API.md [new file with mode: 0644]
functions.lua [deleted file]
init.lua [deleted file]
mark.lua [deleted file]
modpack.txt [new file with mode: 0644]
table_save.lua [deleted file]
textures/worldedit_pos1.png [deleted file]
textures/worldedit_pos2.png [deleted file]
worldedit/functions.lua [new file with mode: 0644]
worldedit/init.lua [new file with mode: 0644]
worldedit/mark.lua [new file with mode: 0644]
worldedit/table_save.lua [new file with mode: 0644]
worldedit/textures/worldedit_pos1.png [new file with mode: 0644]
worldedit/textures/worldedit_pos2.png [new file with mode: 0644]

diff --git a/Chat Commands.md b/Chat Commands.md
new file mode 100644 (file)
index 0000000..f4febf7
--- /dev/null
@@ -0,0 +1,195 @@
+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
index f6dbf8776db5ec5a11de74286fbc56f5eaaa69c8..5313137b9bf8f45bdf156e161f97b4dba9cc2f57 100644 (file)
--- a/README.md
+++ b/README.md
@@ -34,336 +34,21 @@ Entities are used to mark the location of the WorldEdit regions. They appear as
 
 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).
 
diff --git a/WorldEdit API.md b/WorldEdit API.md
new file mode 100644 (file)
index 0000000..41fab69
--- /dev/null
@@ -0,0 +1,131 @@
+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
diff --git a/functions.lua b/functions.lua
deleted file mode 100644 (file)
index 2d949c6..0000000
+++ /dev/null
@@ -1,707 +0,0 @@
---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
diff --git a/init.lua b/init.lua
deleted file mode 100644 (file)
index 84cf4fe..0000000
--- a/init.lua
+++ /dev/null
@@ -1,655 +0,0 @@
-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
diff --git a/mark.lua b/mark.lua
deleted file mode 100644 (file)
index 0f011d2..0000000
--- a/mark.lua
+++ /dev/null
@@ -1,70 +0,0 @@
-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
diff --git a/modpack.txt b/modpack.txt
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/table_save.lua b/table_save.lua
deleted file mode 100644 (file)
index cbc18ae..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
---[[
-   Save Table to File
-   Load Table from File
-   v 1.0
-   
-   Lua 5.2 compatible
-   
-   Only Saves Tables, Numbers and Strings
-   Insides Table References are saved
-   Does not save Userdata, Metatables, Functions and indices of these
-   ----------------------------------------------------
-   table.save( table , filename )
-   
-   on failure: returns an error msg
-   
-   ----------------------------------------------------
-   table.load( filename or stringtable )
-   
-   Loads a table that has been saved via the table.save function
-   
-   on success: returns a previously saved table
-   on failure: returns as second argument an error msg
-   ----------------------------------------------------
-   
-   Licensed under the same terms as Lua itself.
-]]--
-do
-   -- declare local variables
-   --// exportstring( string )
-   --// returns a "Lua" portable version of the string
-   local function exportstring( s )
-      return string.format("%q", s)
-   end
-
-   --// The Save Function
-   function table.save(  tbl,filename )
-      local charS,charE = "   ","\n"
-      local file,err = io.open( filename, "wb" )
-      if err then return err end
-
-      -- initiate variables for save procedure
-      local tables,lookup = { tbl },{ [tbl] = 1 }
-      file:write( "return {"..charE )
-
-      for idx,t in ipairs( tables ) do
-         file:write( "-- Table: {"..idx.."}"..charE )
-         file:write( "{"..charE )
-         local thandled = {}
-
-         for i,v in ipairs( t ) do
-            thandled[i] = true
-            local stype = type( v )
-            -- only handle value
-            if stype == "table" then
-               if not lookup[v] then
-                  table.insert( tables, v )
-                  lookup[v] = #tables
-               end
-               file:write( charS.."{"..lookup[v].."},"..charE )
-            elseif stype == "string" then
-               file:write(  charS..exportstring( v )..","..charE )
-            elseif stype == "number" then
-               file:write(  charS..tostring( v )..","..charE )
-            end
-         end
-
-         for i,v in pairs( t ) do
-            -- escape handled values
-            if (not thandled[i]) then
-            
-               local str = ""
-               local stype = type( i )
-               -- handle index
-               if stype == "table" then
-                  if not lookup[i] then
-                     table.insert( tables,i )
-                     lookup[i] = #tables
-                  end
-                  str = charS.."[{"..lookup[i].."}]="
-               elseif stype == "string" then
-                  str = charS.."["..exportstring( i ).."]="
-               elseif stype == "number" then
-                  str = charS.."["..tostring( i ).."]="
-               end
-            
-               if str ~= "" then
-                  stype = type( v )
-                  -- handle value
-                  if stype == "table" then
-                     if not lookup[v] then
-                        table.insert( tables,v )
-                        lookup[v] = #tables
-                     end
-                     file:write( str.."{"..lookup[v].."},"..charE )
-                  elseif stype == "string" then
-                     file:write( str..exportstring( v )..","..charE )
-                  elseif stype == "number" then
-                     file:write( str..tostring( v )..","..charE )
-                  end
-               end
-            end
-         end
-         file:write( "},"..charE )
-      end
-      file:write( "}" )
-      file:close()
-   end
-   
-   --// The Load Function
-   function table.load( sfile )
-      local ftables,err = loadfile( sfile )
-      if err then return _,err end
-      local tables = ftables()
-      for idx = 1,#tables do
-         local tolinki = {}
-         for i,v in pairs( tables[idx] ) do
-            if type( v ) == "table" then
-               tables[idx][i] = tables[v[1]]
-            end
-            if type( i ) == "table" and tables[i[1]] then
-               table.insert( tolinki,{ i,tables[i[1]] } )
-            end
-         end
-         -- link indices
-         for _,v in ipairs( tolinki ) do
-            tables[idx][v[2]],tables[idx][v[1]] =  tables[idx][v[1]],nil
-         end
-      end
-      return tables[1]
-   end
--- close do
-end
--- ChillCode
\ No newline at end of file
diff --git a/textures/worldedit_pos1.png b/textures/worldedit_pos1.png
deleted file mode 100644 (file)
index 4c304aa..0000000
Binary files a/textures/worldedit_pos1.png and /dev/null differ
diff --git a/textures/worldedit_pos2.png b/textures/worldedit_pos2.png
deleted file mode 100644 (file)
index 1502f16..0000000
Binary files a/textures/worldedit_pos2.png and /dev/null differ
diff --git a/worldedit/functions.lua b/worldedit/functions.lua
new file mode 100644 (file)
index 0000000..2d949c6
--- /dev/null
@@ -0,0 +1,707 @@
+--modifies positions `pos1` and `pos2` so that each component of `pos1` is less than or equal to its corresponding conent of `pos2`, returning two new positions\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
diff --git a/worldedit/init.lua b/worldedit/init.lua
new file mode 100644 (file)
index 0000000..84cf4fe
--- /dev/null
@@ -0,0 +1,655 @@
+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
diff --git a/worldedit/mark.lua b/worldedit/mark.lua
new file mode 100644 (file)
index 0000000..0f011d2
--- /dev/null
@@ -0,0 +1,70 @@
+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
diff --git a/worldedit/table_save.lua b/worldedit/table_save.lua
new file mode 100644 (file)
index 0000000..cbc18ae
--- /dev/null
@@ -0,0 +1,133 @@
+--[[
+   Save Table to File
+   Load Table from File
+   v 1.0
+   
+   Lua 5.2 compatible
+   
+   Only Saves Tables, Numbers and Strings
+   Insides Table References are saved
+   Does not save Userdata, Metatables, Functions and indices of these
+   ----------------------------------------------------
+   table.save( table , filename )
+   
+   on failure: returns an error msg
+   
+   ----------------------------------------------------
+   table.load( filename or stringtable )
+   
+   Loads a table that has been saved via the table.save function
+   
+   on success: returns a previously saved table
+   on failure: returns as second argument an error msg
+   ----------------------------------------------------
+   
+   Licensed under the same terms as Lua itself.
+]]--
+do
+   -- declare local variables
+   --// exportstring( string )
+   --// returns a "Lua" portable version of the string
+   local function exportstring( s )
+      return string.format("%q", s)
+   end
+
+   --// The Save Function
+   function table.save(  tbl,filename )
+      local charS,charE = "   ","\n"
+      local file,err = io.open( filename, "wb" )
+      if err then return err end
+
+      -- initiate variables for save procedure
+      local tables,lookup = { tbl },{ [tbl] = 1 }
+      file:write( "return {"..charE )
+
+      for idx,t in ipairs( tables ) do
+         file:write( "-- Table: {"..idx.."}"..charE )
+         file:write( "{"..charE )
+         local thandled = {}
+
+         for i,v in ipairs( t ) do
+            thandled[i] = true
+            local stype = type( v )
+            -- only handle value
+            if stype == "table" then
+               if not lookup[v] then
+                  table.insert( tables, v )
+                  lookup[v] = #tables
+               end
+               file:write( charS.."{"..lookup[v].."},"..charE )
+            elseif stype == "string" then
+               file:write(  charS..exportstring( v )..","..charE )
+            elseif stype == "number" then
+               file:write(  charS..tostring( v )..","..charE )
+            end
+         end
+
+         for i,v in pairs( t ) do
+            -- escape handled values
+            if (not thandled[i]) then
+            
+               local str = ""
+               local stype = type( i )
+               -- handle index
+               if stype == "table" then
+                  if not lookup[i] then
+                     table.insert( tables,i )
+                     lookup[i] = #tables
+                  end
+                  str = charS.."[{"..lookup[i].."}]="
+               elseif stype == "string" then
+                  str = charS.."["..exportstring( i ).."]="
+               elseif stype == "number" then
+                  str = charS.."["..tostring( i ).."]="
+               end
+            
+               if str ~= "" then
+                  stype = type( v )
+                  -- handle value
+                  if stype == "table" then
+                     if not lookup[v] then
+                        table.insert( tables,v )
+                        lookup[v] = #tables
+                     end
+                     file:write( str.."{"..lookup[v].."},"..charE )
+                  elseif stype == "string" then
+                     file:write( str..exportstring( v )..","..charE )
+                  elseif stype == "number" then
+                     file:write( str..tostring( v )..","..charE )
+                  end
+               end
+            end
+         end
+         file:write( "},"..charE )
+      end
+      file:write( "}" )
+      file:close()
+   end
+   
+   --// The Load Function
+   function table.load( sfile )
+      local ftables,err = loadfile( sfile )
+      if err then return _,err end
+      local tables = ftables()
+      for idx = 1,#tables do
+         local tolinki = {}
+         for i,v in pairs( tables[idx] ) do
+            if type( v ) == "table" then
+               tables[idx][i] = tables[v[1]]
+            end
+            if type( i ) == "table" and tables[i[1]] then
+               table.insert( tolinki,{ i,tables[i[1]] } )
+            end
+         end
+         -- link indices
+         for _,v in ipairs( tolinki ) do
+            tables[idx][v[2]],tables[idx][v[1]] =  tables[idx][v[1]],nil
+         end
+      end
+      return tables[1]
+   end
+-- close do
+end
+-- ChillCode
\ No newline at end of file
diff --git a/worldedit/textures/worldedit_pos1.png b/worldedit/textures/worldedit_pos1.png
new file mode 100644 (file)
index 0000000..4c304aa
Binary files /dev/null and b/worldedit/textures/worldedit_pos1.png differ
diff --git a/worldedit/textures/worldedit_pos2.png b/worldedit/textures/worldedit_pos2.png
new file mode 100644 (file)
index 0000000..1502f16
Binary files /dev/null and b/worldedit/textures/worldedit_pos2.png differ