mirror of
https://github.com/Uberi/Minetest-WorldEdit.git
synced 2025-06-29 14:40:54 +02:00
Compare commits
67 Commits
Author | SHA1 | Date | |
---|---|---|---|
522edf1cd4 | |||
5e5c1dc6c3 | |||
71b6004b92 | |||
20722389bd | |||
f5145d6ba1 | |||
0317deb101 | |||
65c218c3e2 | |||
d1828affff | |||
9209d81d20 | |||
34c4475d06 | |||
7eb102181b | |||
4a98773025 | |||
cfaed1781a | |||
7cf84045d4 | |||
e2f1c4ef17 | |||
c27ab877f1 | |||
7cb2df24b8 | |||
6fb039fb9d | |||
0003770ffb | |||
9f35891996 | |||
6f3127f32e | |||
5f1fb56b8b | |||
89e18d6108 | |||
e5331d39ae | |||
f087c3ef71 | |||
426dfb0bc3 | |||
fdca506505 | |||
aa4a70d237 | |||
5f598db3e6 | |||
4f0ffe731f | |||
e9cdf616ec | |||
5585b7d242 | |||
a76ee00391 | |||
1c31bd7f0d | |||
1b13538353 | |||
12dfbd198d | |||
a82ab9176f | |||
382c57d008 | |||
def676cd2d | |||
d89fded397 | |||
724cd6ccb6 | |||
f42d2358fd | |||
474130d188 | |||
a95164b63b | |||
0f9f247cc1 | |||
7ce20dbfce | |||
c8cfd524dd | |||
6f96131382 | |||
8102eb982e | |||
93100a20be | |||
17c1e3887c | |||
a429e104a2 | |||
ce9ce35a20 | |||
a25a2a1fb0 | |||
340416c789 | |||
6eb08edd30 | |||
91c24d3a60 | |||
1a9ce8b9c1 | |||
21192ceb57 | |||
e39493e789 | |||
5b66b5ec25 | |||
66c7f1fb96 | |||
87f23b8647 | |||
8cd32bcc59 | |||
a4a3613170 | |||
9067f73349 | |||
5ce4517e66 |
266
Chat Commands.md
Normal file
266
Chat Commands.md
Normal file
@ -0,0 +1,266 @@
|
||||
Chat Commands
|
||||
-------------
|
||||
For more information, see the [README](README.md).
|
||||
|
||||
### //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/set1/set2/get
|
||||
|
||||
Set WorldEdit region, WorldEdit position 1, or WorldEdit position 2 by punching nodes, or display the current WorldEdit region.
|
||||
|
||||
//p set
|
||||
//p set1
|
||||
//p set2
|
||||
//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 <replace 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
|
||||
|
||||
### //replaceinverse <search node> <replace node>
|
||||
|
||||
Replace all nodes other than <search node> with <replace node> in the current WorldEdit region.
|
||||
|
||||
//replaceinverse air stone
|
||||
//replaceinverse water_source default:dirt
|
||||
//replaceinverse mesecons:mesecon air
|
||||
//replaceinverse default:steelblock default:glass
|
||||
|
||||
### //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
|
||||
|
||||
### //hollowdome <radius> <node>
|
||||
|
||||
Add hollow dome at WorldEdit position 1 with radius <radius>, composed of <node>.
|
||||
|
||||
//hollowdome 5 dirt
|
||||
//hollowdome 12 default:glass
|
||||
//hollowdome 17 mesecons:mesecon
|
||||
|
||||
### //dome <radius> <node>
|
||||
|
||||
Add dome at WorldEdit position 1 with radius <radius>, composed of <node>.
|
||||
|
||||
//dome 5 dirt
|
||||
//dome 12 default:glass
|
||||
//dome 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 positions and 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 positions and region along the x/y/z/? axis by angle <angle> (90 degree increment).
|
||||
|
||||
//rotate x 90
|
||||
//rotate y 180
|
||||
//rotate z 270
|
||||
//rotate ? -90
|
||||
|
||||
### //orient <angle>
|
||||
|
||||
Rotate oriented nodes in the current WorldEdit region around the Y axis by angle <angle> (90 degree increment)
|
||||
|
||||
//orient 90
|
||||
//orient 180
|
||||
//orient 270
|
||||
//orient -90
|
||||
|
||||
### //fixlight
|
||||
|
||||
Fixes the lighting in the current WorldEdit region.
|
||||
|
||||
//fixlight
|
||||
|
||||
### //hide
|
||||
|
||||
Hide all nodes in the current WorldEdit region non-destructively.
|
||||
|
||||
//hide
|
||||
|
||||
### //suppress <node>
|
||||
|
||||
Suppress all <node> in the current WorldEdit region non-destructively.
|
||||
|
||||
//suppress dirt
|
||||
//suppress default:glass
|
||||
//suppress mesecons:mesecon
|
||||
|
||||
### //highlight <node>
|
||||
|
||||
Highlight <node> in the current WorldEdit region by hiding everything else non-destructively.
|
||||
|
||||
//highlight dirt
|
||||
//highlight default:glass
|
||||
//highlight mesecons:mesecon
|
||||
|
||||
### //restore
|
||||
|
||||
Restores nodes hidden with WorldEdit in the current WorldEdit region.
|
||||
|
||||
//restore
|
||||
|
||||
### //save <file>
|
||||
|
||||
Save the current WorldEdit region to "(world folder)/schems/<file>.we".
|
||||
|
||||
//save some random filename
|
||||
//save huge_base
|
||||
|
||||
### //allocate <file>
|
||||
|
||||
Set the region defined by nodes from "(world folder)/schems/<file>.we" as the current WorldEdit region.
|
||||
|
||||
//allocate some random filename
|
||||
//allocate 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
|
||||
|
||||
### //lua <code>
|
||||
|
||||
Executes <code> as a Lua chunk in the global namespace.
|
||||
|
||||
//lua worldedit.pos1["singleplayer"] = {x=0, y=0, z=0}
|
||||
//lua worldedit.rotate(worldedit.pos1["singleplayer"], worldedit.pos2["singleplayer"], "y", 90)
|
||||
|
||||
### //luatransform <code>
|
||||
|
||||
Executes <code> as a Lua chunk in the global namespace with the variable pos available, for each node in the current WorldEdit region.
|
||||
|
||||
//luatransform minetest.env:add_node(pos, {name="default:stone"})
|
||||
//luatransform if minetest.env:get_node(pos).name == "air" then minetest.env:add_node(pos, {name="default:water_source"})
|
175
README.md
175
README.md
@ -1,4 +1,4 @@
|
||||
WorldEdit v0.5 for MineTest 0.4
|
||||
WorldEdit v0.6 for MineTest 0.4
|
||||
===============================
|
||||
In-game world editing for [MineTest](http://minetest.net/)! Tons of chat commands to help with building, fixing, and more.
|
||||
|
||||
@ -12,6 +12,14 @@ WorldEdit has a huge potential for abuse by untrusted players. Therefore, users
|
||||
|
||||
For in-game information about these commands, type `/help <command name>` in the chat. For example, to learn more about the `//copy` command, simply type `/help /copy` to display information relevant to copying a region.
|
||||
|
||||
Axes
|
||||
----
|
||||
The coordinate system is the same as that used by MineTest; Y is upwards, X is perpendicular, and Z is parallel.
|
||||
|
||||
When an axis is specified in a WorldEdit command, it is specified as one of the following values: x, y, z, or ?.
|
||||
|
||||
The value ? represents the axis the player is currently facing. If the player is facing more than one axis, the axis the player face direction is closest to will be used.
|
||||
|
||||
Regions
|
||||
-------
|
||||
Most WorldEdit commands operate on regions. Regions are a set of two positions that define a 3D cube. They are local to each player and chat commands affect only the region for the player giving the commands.
|
||||
@ -26,173 +34,24 @@ 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
|
||||
--------
|
||||
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).
|
||||
|
||||
### //reset
|
||||
|
||||
Reset the region so that it is empty.
|
||||
|
||||
//reset
|
||||
|
||||
### //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
|
||||
|
||||
### //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
|
||||
|
||||
### //move x/y/z <amount>
|
||||
|
||||
Move the current WorldEdit region along the x/y/z axis by <amount> nodes.
|
||||
|
||||
//move x 15
|
||||
//move y -7
|
||||
//move z +4
|
||||
|
||||
### //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
|
||||
|
||||
### //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
|
||||
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 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.
|
||||
|
||||
### 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.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.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.
|
||||
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).
|
||||
|
||||
Basically, this means everyone is free to use, modify, and distribute the files, as long as these modifications are also licensed the same way.
|
||||
|
||||
Most importantly, the Affero variant of the GPL requires you to publish your modifications in source form, even if the mod is run only on the server, and not distributed.
|
||||
Most importantly, the Affero variant of the GPL requires you to publish your modifications in source form, even if the mod is run only on the server, and not distributed.
|
||||
|
207
WorldEdit API.md
Normal file
207
WorldEdit API.md
Normal file
@ -0,0 +1,207 @@
|
||||
WorldEdit API
|
||||
=============
|
||||
The WorldEdit API is composed of multiple modules, each of which is independent and can be used without the other. Each module is contained within a single file.
|
||||
|
||||
If needed, individual modules such as visualization.lua can be removed without affecting the rest of the program. The only file that cannot be removed is init.lua, which is necessary for the mod to run.
|
||||
|
||||
For more information, see the [README](README.md).
|
||||
|
||||
Manipulations
|
||||
-------------
|
||||
Contained in manipulations.lua, this module allows several node operations to be applied over a region.
|
||||
|
||||
### count = 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.
|
||||
|
||||
### count = 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.
|
||||
|
||||
### count = worldedit.replaceinverse(pos1, pos2, searchnode, replacenode)
|
||||
|
||||
Replaces all nodes other than `searchnode` with `replacenode` in a region defined by positions `pos1` and `pos2`.
|
||||
|
||||
Returns the number of nodes replaced.
|
||||
|
||||
### count = 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.
|
||||
|
||||
### count = 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.
|
||||
|
||||
### count = 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.
|
||||
|
||||
### count, newpos1, newpos2 = 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, the new position 1, and the new position 2.
|
||||
|
||||
### count = 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.
|
||||
|
||||
### count, newpos2, newpos2 = 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, the new position 1, and the new position 2.
|
||||
|
||||
### count = worldedit.orient(pos1, pos2, angle)
|
||||
|
||||
Rotates all oriented nodes in a region defined by the positions `pos1` and `pos2` by `angle` degrees clockwise (90 degree increment) around the Y axis.
|
||||
|
||||
Returns the number of nodes oriented.
|
||||
|
||||
### count = worldedit.fixlight(pos1, pos2)
|
||||
|
||||
Fixes the lighting in a region defined by positions `pos1` and `pos2`.
|
||||
|
||||
Returns the number of nodes updated.
|
||||
|
||||
Primitives
|
||||
----------
|
||||
Contained in primitives.lua, this module allows the creation of several geometric primitives.
|
||||
|
||||
### count = worldedit.hollow_sphere(pos, radius, nodename)
|
||||
|
||||
Adds a hollow sphere at `pos` with radius `radius`, composed of `nodename`.
|
||||
|
||||
Returns the number of nodes added.
|
||||
|
||||
### count = worldedit.sphere(pos, radius, nodename)
|
||||
|
||||
Adds a sphere at `pos` with radius `radius`, composed of `nodename`.
|
||||
|
||||
Returns the number of nodes added.
|
||||
|
||||
### count = worldedit.hollow_dome(pos, radius, nodename)
|
||||
|
||||
Adds a hollow dome at `pos` with radius `radius`, composed of `nodename`.
|
||||
|
||||
Returns the number of nodes added.
|
||||
|
||||
### count = worldedit.dome(pos, radius, nodename)
|
||||
|
||||
Adds a dome at `pos` with radius `radius`, composed of `nodename`.
|
||||
|
||||
Returns the number of nodes added.
|
||||
|
||||
### count = 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.
|
||||
|
||||
### count = 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.
|
||||
|
||||
### count = worldedit.pyramid(pos, height, nodename)
|
||||
|
||||
Adds a pyramid at `pos` with height `height`.
|
||||
|
||||
Returns the number of nodes added.
|
||||
|
||||
### count = 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.
|
||||
|
||||
Visualization
|
||||
-------------
|
||||
Contained in visualization.lua, this module allows nodes to be visualized in different ways.
|
||||
|
||||
### volume = worldedit.volume(pos1, pos2)
|
||||
|
||||
Determines the volume of the region defined by positions `pos1` and `pos2`.
|
||||
|
||||
Returns the volume.
|
||||
|
||||
### count = worldedit.hide(pos1, pos2)
|
||||
|
||||
Hides all nodes in a region defined by positions `pos1` and `pos2` by non-destructively replacing them with invisible nodes.
|
||||
|
||||
Returns the number of nodes hidden.
|
||||
|
||||
### count = worldedit.suppress(pos1, pos2, nodename)
|
||||
|
||||
Suppresses all instances of `nodename` in a region defined by positions `pos1` and `pos2` by non-destructively replacing them with invisible nodes.
|
||||
|
||||
Returns the number of nodes suppressed.
|
||||
|
||||
### count = worldedit.highlight(pos1, pos2, nodename)
|
||||
|
||||
Highlights all instances of `nodename` in a region defined by positions `pos1` and `pos2` by non-destructively hiding all other nodes.
|
||||
|
||||
Returns the number of nodes found.
|
||||
|
||||
### count = worldedit.restore(pos1, pos2)
|
||||
|
||||
Restores all nodes hidden with WorldEdit functions in a region defined by positions `pos1` and `pos2`.
|
||||
|
||||
Returns the number of nodes restored.
|
||||
|
||||
Serialization
|
||||
-------------
|
||||
Contained in serialization.lua, this module allows regions of nodes to be serialized and deserialized to formats suitable for use outside MineTest.
|
||||
|
||||
### version = worldedit.valueversion(value)
|
||||
|
||||
Determines the version of serialized data `value`.
|
||||
|
||||
Returns the version as a positive integer or 0 for unknown versions.
|
||||
|
||||
### data, count = 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.
|
||||
|
||||
### pos1, pos2, count = worldedit.allocate(originpos, value)
|
||||
|
||||
Determines the volume the nodes represented by string `value` would occupy if deserialized at `originpos`.
|
||||
|
||||
Returns the two corner positions and the number of nodes.
|
||||
|
||||
### count = worldedit.deserialize(originpos, value)
|
||||
|
||||
Loads the nodes represented by string `value` at position `originpos`.
|
||||
|
||||
Returns the number of nodes deserialized.
|
||||
|
||||
Code
|
||||
----
|
||||
Contained in code.lua, this module allows arbitrary Lua code to be used with WorldEdit.
|
||||
|
||||
### error = worldedit.lua(code)
|
||||
|
||||
Executes `code` as a Lua chunk in the global namespace.
|
||||
|
||||
Returns an error if the code fails or nil otherwise.
|
||||
|
||||
### error = worldedit.luatransform(pos1, pos2, code)
|
||||
|
||||
Executes `code` as a Lua chunk in the global namespace with the variable pos available, for each node in a region defined by positions `pos1` and `pos2`.
|
||||
|
||||
Returns an error if the code fails or nil otherwise.
|
280
functions.lua
280
functions.lua
@ -1,280 +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
|
||||
worldedit.sort_pos = function(pos1, pos2)
|
||||
pos1 = {x=pos1.x, y=pos1.y, z=pos1.z}
|
||||
pos2 = {x=pos2.x, y=pos2.y, z=pos2.z}
|
||||
if pos1.x > pos2.x then
|
||||
pos2.x, pos1.x = pos1.x, pos2.x
|
||||
end
|
||||
if pos1.y > pos2.y then
|
||||
pos2.y, pos1.y = pos1.y, pos2.y
|
||||
end
|
||||
if pos1.z > pos2.z then
|
||||
pos2.z, pos1.z = pos1.z, pos2.z
|
||||
end
|
||||
return pos1, pos2
|
||||
end
|
||||
|
||||
--determines the volume of the region defined by positions `pos1` and `pos2`, returning the volume
|
||||
worldedit.volume = function(pos1, pos2)
|
||||
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||
return (pos2.x - pos1.x + 1) * (pos2.y - pos1.y + 1) * (pos2.z - pos1.z + 1)
|
||||
end
|
||||
|
||||
--sets a region defined by positions `pos1` and `pos2` to `nodename`, returning the number of nodes filled
|
||||
worldedit.set = function(pos1, pos2, nodename)
|
||||
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||
local env = minetest.env
|
||||
|
||||
local node = {name=nodename}
|
||||
local pos = {x=pos1.x, y=0, z=0}
|
||||
while pos.x <= pos2.x do
|
||||
pos.y = pos1.y
|
||||
while pos.y <= pos2.y do
|
||||
pos.z = pos1.z
|
||||
while pos.z <= pos2.z do
|
||||
env:add_node(pos, node)
|
||||
pos.z = pos.z + 1
|
||||
end
|
||||
pos.y = pos.y + 1
|
||||
end
|
||||
pos.x = pos.x + 1
|
||||
end
|
||||
return worldedit.volume(pos1, pos2)
|
||||
end
|
||||
|
||||
--replaces all instances of `searchnode` with `replacenode` in a region defined by positions `pos1` and `pos2`, returning the number of nodes replaced
|
||||
worldedit.replace = function(pos1, pos2, searchnode, replacenode)
|
||||
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||
local env = minetest.env
|
||||
|
||||
if searchnode:find(":") == nil then
|
||||
searchnode = "default:" .. searchnode
|
||||
end
|
||||
|
||||
local pos = {x=pos1.x, y=0, z=0}
|
||||
local node = {name=replacenode}
|
||||
local count = 0
|
||||
while pos.x <= pos2.x do
|
||||
pos.y = pos1.y
|
||||
while pos.y <= pos2.y do
|
||||
pos.z = pos1.z
|
||||
while pos.z <= pos2.z do
|
||||
if env:get_node(pos).name == searchnode then
|
||||
env:add_node(pos, node)
|
||||
count = count + 1
|
||||
end
|
||||
pos.z = pos.z + 1
|
||||
end
|
||||
pos.y = pos.y + 1
|
||||
end
|
||||
pos.x = pos.x + 1
|
||||
end
|
||||
return count
|
||||
end
|
||||
|
||||
--copies the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") by `amount` nodes, returning the number of nodes copied
|
||||
worldedit.copy = function(pos1, pos2, axis, amount)
|
||||
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||
local env = minetest.env
|
||||
|
||||
if amount < 0 then
|
||||
local pos = {x=pos1.x, y=0, z=0}
|
||||
while pos.x <= pos2.x do
|
||||
pos.y = pos1.y
|
||||
while pos.y <= pos2.y do
|
||||
pos.z = pos1.z
|
||||
while pos.z <= pos2.z do
|
||||
local node = env:get_node(pos, node)
|
||||
local value = pos[axis]
|
||||
pos[axis] = value - amount
|
||||
env:add_node(pos, node)
|
||||
pos[axis] = value
|
||||
pos.z = pos.z + 1
|
||||
end
|
||||
pos.y = pos.y + 1
|
||||
end
|
||||
pos.x = pos.x + 1
|
||||
end
|
||||
else
|
||||
local pos = {x=pos2.x, y=0, z=0}
|
||||
while pos.x >= pos1.x do
|
||||
pos.y = pos2.y
|
||||
while pos.y >= pos1.y do
|
||||
pos.z = pos2.z
|
||||
while pos.z >= pos1.z do
|
||||
local node = minetest.env:get_node(pos, node)
|
||||
local value = pos[axis]
|
||||
pos[axis] = value + amount
|
||||
minetest.env:add_node(pos, node)
|
||||
pos[axis] = value
|
||||
pos.z = pos.z - 1
|
||||
end
|
||||
pos.y = pos.y - 1
|
||||
end
|
||||
pos.x = pos.x - 1
|
||||
end
|
||||
end
|
||||
return worldedit.volume(pos1, pos2)
|
||||
end
|
||||
|
||||
--moves the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") by `amount` nodes, returning the number of nodes moved
|
||||
worldedit.move = function(pos1, pos2, axis, amount)
|
||||
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||
local env = minetest.env
|
||||
|
||||
if amount < 0 then
|
||||
local pos = {x=pos1.x, y=0, z=0}
|
||||
while pos.x <= pos2.x do
|
||||
pos.y = pos1.y
|
||||
while pos.y <= pos2.y do
|
||||
pos.z = pos1.z
|
||||
while pos.z <= pos2.z do
|
||||
local node = env:get_node(pos, node)
|
||||
env:remove_node(pos)
|
||||
local value = pos[axis]
|
||||
pos[axis] = value - amount
|
||||
env:add_node(pos, node)
|
||||
pos[axis] = value
|
||||
pos.z = pos.z + 1
|
||||
end
|
||||
pos.y = pos.y + 1
|
||||
end
|
||||
pos.x = pos.x + 1
|
||||
end
|
||||
else
|
||||
local pos = {x=pos2.x, y=0, z=0}
|
||||
while pos.x >= pos1.x do
|
||||
pos.y = pos2.y
|
||||
while pos.y >= pos1.y do
|
||||
pos.z = pos2.z
|
||||
while pos.z >= pos1.z do
|
||||
local node = minetest.env:get_node(pos, node)
|
||||
env:remove_node(pos)
|
||||
local value = pos[axis]
|
||||
pos[axis] = value + amount
|
||||
minetest.env:add_node(pos, node)
|
||||
pos[axis] = value
|
||||
pos.z = pos.z - 1
|
||||
end
|
||||
pos.y = pos.y - 1
|
||||
end
|
||||
pos.x = pos.x - 1
|
||||
end
|
||||
end
|
||||
return worldedit.volume(pos1, pos2)
|
||||
end
|
||||
|
||||
--duplicates the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") `count` times, returning the number of nodes stacked
|
||||
worldedit.stack = function(pos1, pos2, axis, count)
|
||||
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||
local length = pos2[axis] - pos1[axis] + 1
|
||||
local amount = 0
|
||||
local copy = worldedit.copy
|
||||
if count < 0 then
|
||||
count = -count
|
||||
length = -length
|
||||
end
|
||||
for i = 1, count do
|
||||
amount = amount + length
|
||||
copy(pos1, pos2, axis, amount)
|
||||
end
|
||||
return worldedit.volume(pos1, pos2)
|
||||
end
|
||||
|
||||
--digs a region defined by positions `pos1` and `pos2`, returning the number of nodes dug
|
||||
worldedit.dig = function(pos1, pos2)
|
||||
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||
local env = minetest.env
|
||||
|
||||
local pos = {x=pos1.x, y=0, z=0}
|
||||
while pos.x <= pos2.x do
|
||||
pos.y = pos1.y
|
||||
while pos.y <= pos2.y do
|
||||
pos.z = pos1.z
|
||||
while pos.z <= pos2.z do
|
||||
env:dig_node(pos)
|
||||
pos.z = pos.z + 1
|
||||
end
|
||||
pos.y = pos.y + 1
|
||||
end
|
||||
pos.x = pos.x + 1
|
||||
end
|
||||
return worldedit.volume(pos1, pos2)
|
||||
end
|
||||
|
||||
--converts the region defined by positions `pos1` and `pos2` into a single string, returning the serialized data and the number of nodes serialized
|
||||
worldedit.serialize = function(pos1, pos2)
|
||||
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||
local pos = {x=pos1.x, y=0, z=0}
|
||||
local count = 0
|
||||
local result = {}
|
||||
local env = minetest.env
|
||||
while pos.x <= pos2.x do
|
||||
pos.y = pos1.y
|
||||
while pos.y <= pos2.y do
|
||||
pos.z = pos1.z
|
||||
while pos.z <= pos2.z do
|
||||
local node = env:get_node(pos)
|
||||
if node.name ~= "air" and node.name ~= "ignore" then
|
||||
count = count + 1
|
||||
result[count] = pos.x - pos1.x .. " " .. pos.y - pos1.y .. " " .. pos.z - pos1.z .. " " .. node.name .. " " .. node.param1 .. " " .. node.param2
|
||||
end
|
||||
pos.z = pos.z + 1
|
||||
end
|
||||
pos.y = pos.y + 1
|
||||
end
|
||||
pos.x = pos.x + 1
|
||||
end
|
||||
result = table.concat(result, "\n")
|
||||
return result, count
|
||||
end
|
||||
|
||||
--loads the nodes represented by string `value` at position `originpos`, returning the number of nodes deserialized
|
||||
worldedit.deserialize = function(originpos, value)
|
||||
local pos = {x=0, y=0, z=0}
|
||||
local node = {name="", param1=0, param2=0}
|
||||
local count = 0
|
||||
local env = minetest.env
|
||||
for x, y, z, name, param1, param2 in value:gmatch("([+-]?%d+)%s+([+-]?%d+)%s+([+-]?%d+)%s+([^%s]+)%s+(%d+)%s+(%d+)[^\r\n]*[\r\n]*") do
|
||||
pos.x = originpos.x + tonumber(x)
|
||||
pos.y = originpos.y + tonumber(y)
|
||||
pos.z = originpos.z + tonumber(z)
|
||||
node.name = name
|
||||
node.param1 = param1
|
||||
node.param2 = param2
|
||||
env:add_node(pos, node)
|
||||
count = count + 1
|
||||
end
|
||||
return count
|
||||
end
|
||||
|
||||
--loads the nodes represented by string `value` at position `originpos`, returning the number of nodes deserialized
|
||||
--based on [table.save/table.load](http://lua-users.org/wiki/SaveTableToFile) by ChillCode, available under the MIT license (GPL compatible)
|
||||
worldedit.deserialize_old = function(originpos, value)
|
||||
--obtain the node table
|
||||
local count = 0
|
||||
local get_tables = loadstring(value)
|
||||
if get_tables == nil then --error loading value
|
||||
return count
|
||||
end
|
||||
local tables = get_tables()
|
||||
|
||||
--transform the node table into an array of nodes
|
||||
for i = 1, #tables do
|
||||
for j, v in pairs(tables[i]) do
|
||||
if type(v) == "table" then
|
||||
tables[i][j] = tables[v[1]]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--load the node array
|
||||
local env = minetest.env
|
||||
for i, v in ipairs(tables[1]) do
|
||||
local pos = v[1]
|
||||
pos.x, pos.y, pos.z = originpos.x + pos.x, originpos.y + pos.y, originpos.z + pos.z
|
||||
env:add_node(pos, v[2])
|
||||
count = count + 1
|
||||
end
|
||||
return count
|
||||
end
|
321
init.lua
321
init.lua
@ -1,321 +0,0 @@
|
||||
minetest.register_privilege("worldedit", "Can use WorldEdit commands")
|
||||
|
||||
worldedit = {}
|
||||
|
||||
worldedit.set_pos = {}
|
||||
|
||||
worldedit.pos1 = {}
|
||||
worldedit.pos2 = {}
|
||||
|
||||
dofile(minetest.get_modpath("worldedit") .. "/functions.lua")
|
||||
dofile(minetest.get_modpath("worldedit") .. "/mark.lua")
|
||||
|
||||
--determines whether `nodename` is a valid node name, returning a boolean
|
||||
worldedit.node_is_valid = function(temp_pos, nodename)
|
||||
local originalnode = minetest.env:get_node(temp_pos) --save the original node to restore later
|
||||
minetest.env:add_node(temp_pos, {name=nodename}) --attempt to add the node
|
||||
local value = minetest.env:get_node(temp_pos).name --obtain the name of the newly added node
|
||||
if value == nodename or value == "default:" .. nodename then --successfully added node
|
||||
minetest.env:add_node(temp_pos, originalnode) --restore the original node
|
||||
return true --node is valid
|
||||
end
|
||||
return false --node is not valid
|
||||
end
|
||||
|
||||
minetest.register_chatcommand("/reset", {
|
||||
params = "",
|
||||
description = "Reset the region so that it is empty",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
worldedit.pos1[name] = nil
|
||||
worldedit.pos2[name] = nil
|
||||
worldedit.mark_pos1(name)
|
||||
worldedit.mark_pos2(name)
|
||||
minetest.chat_send_player(name, "WorldEdit region reset")
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/pos1", {
|
||||
params = "",
|
||||
description = "Set WorldEdit region position 1 to the player's location",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local pos = minetest.env:get_player_by_name(name):getpos()
|
||||
pos.x = math.floor(pos.x)
|
||||
pos.y = math.floor(pos.y)
|
||||
pos.z = math.floor(pos.z)
|
||||
worldedit.pos1[name] = pos
|
||||
worldedit.mark_pos1(name)
|
||||
minetest.chat_send_player(name, "WorldEdit position 1 set to (" .. pos.x .. "," .. pos.y .. "," .. pos.z .. ")")
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/pos2", {
|
||||
params = "",
|
||||
description = "Set WorldEdit region position 2 to the player's location",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local pos = minetest.env:get_player_by_name(name):getpos()
|
||||
pos.x = math.floor(pos.x)
|
||||
pos.y = math.floor(pos.y)
|
||||
pos.z = math.floor(pos.z)
|
||||
worldedit.pos2[name] = pos
|
||||
worldedit.mark_pos2(name)
|
||||
minetest.chat_send_player(name, "WorldEdit position 2 set to (" .. pos.x .. "," .. pos.y .. "," .. pos.z .. ")")
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/p", {
|
||||
params = "set/get",
|
||||
description = "Set WorldEdit region by punching two nodes, or display the current WorldEdit region",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
if param == "set" then --set both WorldEdit positions
|
||||
worldedit.set_pos[name] = 1
|
||||
minetest.chat_send_player(name, "Select positions by punching two nodes")
|
||||
elseif param == "get" then --display current WorldEdit positions
|
||||
local pos = worldedit.pos1[name]
|
||||
minetest.chat_send_player(name, "WorldEdit position 1: (" .. pos.x .. "," .. pos.y .. "," .. pos.z .. ")")
|
||||
local pos = worldedit.pos2[name]
|
||||
minetest.chat_send_player(name, "WorldEdit position 2: (" .. pos.x .. "," .. pos.y .. "," .. pos.z .. ")")
|
||||
else
|
||||
minetest.chat_send_player(name, "Unknown subcommand: " .. param)
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_on_punchnode(function(pos, node, puncher)
|
||||
local name = puncher:get_player_name()
|
||||
if name ~= "" and worldedit.set_pos[name] ~= nil then --currently setting position
|
||||
if worldedit.set_pos[name] == 1 then --setting position 1
|
||||
worldedit.set_pos[name] = 2 --set position 2 on the next invocation
|
||||
worldedit.pos1[name] = pos
|
||||
worldedit.mark_pos1(name)
|
||||
minetest.chat_send_player(name, "WorldEdit region position 1 set to (" .. pos.x .. "," .. pos.y .. "," .. pos.z .. ")")
|
||||
else --setting position 2
|
||||
worldedit.set_pos[name] = nil --finished setting positions
|
||||
worldedit.pos2[name] = pos
|
||||
worldedit.mark_pos2(name)
|
||||
minetest.chat_send_player(name, "WorldEdit region position 2 set to (" .. pos.x .. "," .. pos.y .. "," .. pos.z .. ")")
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_chatcommand("/volume", {
|
||||
params = "",
|
||||
description = "Display the volume of the current WorldEdit region",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||
if pos1 == nil or pos2 == nil then
|
||||
minetest.chat_send_player(name, "No WorldEdit region selected")
|
||||
return
|
||||
end
|
||||
|
||||
local volume = worldedit.volume(pos1, pos2)
|
||||
minetest.chat_send_player(name, "Current WorldEdit region has a volume of " .. volume .. " nodes (" .. pos2.x - pos1.x .. "*" .. pos2.y - pos1.y .. "*" .. pos2.z - pos1.z .. ")")
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/set", {
|
||||
params = "<node>",
|
||||
description = "Set the current WorldEdit region to <node>",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||
if pos1 == nil or pos2 == nil then
|
||||
minetest.chat_send_player(name, "No WorldEdit region selected")
|
||||
return
|
||||
end
|
||||
|
||||
if param == "" or not worldedit.node_is_valid(pos1, param) then
|
||||
minetest.chat_send_player(name, "Invalid node name: " .. param)
|
||||
return
|
||||
end
|
||||
|
||||
local count = worldedit.set(pos1, pos2, param)
|
||||
minetest.chat_send_player(name, count .. " nodes set")
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/replace", {
|
||||
params = "<search node> <replace node>",
|
||||
description = "Replace all instances of <search node> with <place node> in the current WorldEdit region",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||
if pos1 == nil or pos2 == nil then
|
||||
minetest.chat_send_player(name, "No WorldEdit region selected")
|
||||
return
|
||||
end
|
||||
|
||||
local found, _, searchnode, replacenode = param:find("([^%s]+)%s+([^%s]+)")
|
||||
if found == nil then
|
||||
minetest.chat_send_player(name, "Invalid usage: " .. param)
|
||||
return
|
||||
end
|
||||
if not worldedit.node_is_valid(pos1, searchnode) then
|
||||
minetest.chat_send_player(name, "Invalid search node name: " .. searchnode)
|
||||
return
|
||||
end
|
||||
if not worldedit.node_is_valid(pos1, replacenode) then
|
||||
minetest.chat_send_player(name, "Invalid replace node name: " .. replacenode)
|
||||
return
|
||||
end
|
||||
|
||||
local count = worldedit.replace(pos1, pos2, searchnode, replacenode)
|
||||
minetest.chat_send_player(name, count .. " nodes replaced")
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/copy", {
|
||||
params = "x/y/z <amount>",
|
||||
description = "Copy the current WorldEdit region along the x/y/z axis by <amount> nodes",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||
if pos1 == nil or pos2 == nil then
|
||||
minetest.chat_send_player(name, "No WorldEdit region selected")
|
||||
return
|
||||
end
|
||||
|
||||
local found, _, axis, amount = param:find("([xyz])%s+([+-]?%d+)")
|
||||
if found == nil then
|
||||
minetest.chat_send_player(name, "Invalid usage: " .. param)
|
||||
return
|
||||
end
|
||||
|
||||
local count = worldedit.copy(pos1, pos2, axis, tonumber(amount))
|
||||
minetest.chat_send_player(name, count .. " nodes copied")
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/move", {
|
||||
params = "x/y/z <amount>",
|
||||
description = "Move the current WorldEdit region along the x/y/z axis by <amount> nodes",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||
if pos1 == nil or pos2 == nil then
|
||||
minetest.chat_send_player(name, "No WorldEdit region selected")
|
||||
return
|
||||
end
|
||||
|
||||
local found, _, axis, amount = param:find("([xyz])%s+([+-]?%d+)")
|
||||
if found == nil then
|
||||
minetest.chat_send_player(name, "Invalid usage: " .. param)
|
||||
return
|
||||
end
|
||||
|
||||
local count = worldedit.move(pos1, pos2, axis, tonumber(amount))
|
||||
minetest.chat_send_player(name, count .. " nodes moved")
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/stack", {
|
||||
params = "x/y/z <count>",
|
||||
description = "Stack the current WorldEdit region along the x/y/z axis <count> times",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||
if pos1 == nil or pos2 == nil then
|
||||
minetest.chat_send_player(name, "No WorldEdit region selected")
|
||||
return
|
||||
end
|
||||
|
||||
local found, _, axis, count = param:find("([xyz])%s+([+-]?%d+)")
|
||||
if found == nil then
|
||||
minetest.chat_send_player(name, "Invalid usage: " .. param)
|
||||
return
|
||||
end
|
||||
|
||||
local count = worldedit.stack(pos1, pos2, axis, tonumber(count))
|
||||
minetest.chat_send_player(name, count .. " nodes stacked")
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/dig", {
|
||||
params = "",
|
||||
description = "Dig the current WorldEdit region",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||
if pos1 == nil or pos2 == nil then
|
||||
minetest.chat_send_player(name, "No WorldEdit region selected")
|
||||
return
|
||||
end
|
||||
|
||||
local count = worldedit.dig(pos1, pos2)
|
||||
minetest.chat_send_player(name, count .. " nodes dug")
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/save", {
|
||||
params = "<file>",
|
||||
description = "Save the current WorldEdit region to \"(world folder)/schems/<file>.we\"",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||
if pos1 == nil or pos2 == nil then
|
||||
minetest.chat_send_player(name, "No WorldEdit region selected")
|
||||
return
|
||||
end
|
||||
|
||||
if param == "" then
|
||||
minetest.chat_send_player(name, "Invalid usage: " .. param)
|
||||
return
|
||||
end
|
||||
|
||||
local result, count = worldedit.serialize(pos1, pos2)
|
||||
|
||||
local path = minetest.get_worldpath() .. "/schems"
|
||||
local filename = path .. "/" .. param .. ".we"
|
||||
os.execute("mkdir \"" .. path .. "\"") --create directory if it does not already exist
|
||||
local file, err = io.open(filename, "wb")
|
||||
if err ~= nil then
|
||||
minetest.chat_send_player(name, "Could not save file to \"" .. filename .. "\"")
|
||||
return
|
||||
end
|
||||
file:write(result)
|
||||
file:flush()
|
||||
file:close()
|
||||
|
||||
minetest.chat_send_player(name, count .. " nodes saved")
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/load", {
|
||||
params = "<file>",
|
||||
description = "Load nodes from \"(world folder)/schems/<file>.we\" with position 1 of the current WorldEdit region as the origin",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local pos1 = worldedit.pos1[name]
|
||||
if pos1 == nil then
|
||||
minetest.chat_send_player(name, "No WorldEdit region selected")
|
||||
return
|
||||
end
|
||||
|
||||
if param == "" then
|
||||
minetest.chat_send_player(name, "Invalid usage: " .. param)
|
||||
return
|
||||
end
|
||||
|
||||
local filename = minetest.get_worldpath() .. "/schems/" .. param .. ".we"
|
||||
local file, err = io.open(filename, "rb")
|
||||
if err ~= nil then
|
||||
minetest.chat_send_player(name, "Could not open file \"" .. filename .. "\"")
|
||||
return
|
||||
end
|
||||
local value = file:read("*a")
|
||||
file:close()
|
||||
|
||||
local count
|
||||
if value:find("{") then --old WorldEdit format
|
||||
count = worldedit.deserialize_old(pos1, value)
|
||||
else --new WorldEdit format
|
||||
count = worldedit.deserialize(pos1, value)
|
||||
end
|
||||
|
||||
minetest.chat_send_player(name, count .. " nodes loaded")
|
||||
end,
|
||||
})
|
0
modpack.txt
Normal file
0
modpack.txt
Normal file
43
worldedit/code.lua
Normal file
43
worldedit/code.lua
Normal file
@ -0,0 +1,43 @@
|
||||
worldedit = worldedit or {}
|
||||
|
||||
--executes `code` as a Lua chunk in the global namespace, returning an error if the code fails or nil otherwise
|
||||
worldedit.lua = function(code)
|
||||
local operation, message = loadstring(code)
|
||||
if operation == nil then --code parsing failed
|
||||
return message
|
||||
end
|
||||
local status, message = pcall(operation)
|
||||
if status == nil then --operation failed
|
||||
return message
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
--executes `code` as a Lua chunk in the global namespace with the variable pos available, for each node in a region defined by positions `pos1` and `pos2`, returning an error if the code fails or nil otherwise
|
||||
worldedit.luatransform = function(pos1, pos2, code)
|
||||
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||
|
||||
local factory, message = loadstring("return function(pos) " .. code .. " end")
|
||||
if factory == nil then --code parsing failed
|
||||
return message
|
||||
end
|
||||
local operation = factory()
|
||||
|
||||
local pos = {x=pos1.x, y=0, z=0}
|
||||
while pos.x <= pos2.x do
|
||||
pos.y = pos1.y
|
||||
while pos.y <= pos2.y do
|
||||
pos.z = pos1.z
|
||||
while pos.z <= pos2.z do
|
||||
local status, message = pcall(operation, pos)
|
||||
if status == nil then --operation failed
|
||||
return message
|
||||
end
|
||||
pos.z = pos.z + 1
|
||||
end
|
||||
pos.y = pos.y + 1
|
||||
end
|
||||
pos.x = pos.x + 1
|
||||
end
|
||||
return nil
|
||||
end
|
19
worldedit/compatibility.lua
Normal file
19
worldedit/compatibility.lua
Normal file
@ -0,0 +1,19 @@
|
||||
worldedit = worldedit or {}
|
||||
|
||||
worldedit.allocate_old = worldedit.allocate
|
||||
worldedit.deserialize_old = worldedit.deserialize
|
||||
worldedit.metasave = function(pos1, pos2, filename)
|
||||
local file, err = io.open(filename, "wb")
|
||||
if err then return 0 end
|
||||
local data, count = worldedit.serialize(pos1, pos2)
|
||||
file:write(data)
|
||||
file:close()
|
||||
return count
|
||||
end
|
||||
worldedit.metaload = function(originpos, filename)
|
||||
filename = minetest.get_worldpath() .. "/schems/" .. file .. ".wem"
|
||||
local file, err = io.open(filename, "wb")
|
||||
if err then return 0 end
|
||||
local data = file:read("*a")
|
||||
return worldedit.deserialize(originpos, data)
|
||||
end
|
15
worldedit/init.lua
Normal file
15
worldedit/init.lua
Normal file
@ -0,0 +1,15 @@
|
||||
local path = minetest.get_modpath("worldedit")
|
||||
|
||||
local loadmodule = function(path)
|
||||
return pcall(function()
|
||||
dofile(path)
|
||||
end)
|
||||
end
|
||||
|
||||
loadmodule(path .. "/manipulations.lua")
|
||||
loadmodule(path .. "/primitives.lua")
|
||||
loadmodule(path .. "/visualization.lua")
|
||||
loadmodule(path .. "/serialization.lua")
|
||||
loadmodule(path .. "/code.lua")
|
||||
loadmodule(path .. "/compatibility.lua")
|
||||
loadmodule(path .. "/queue.lua")
|
417
worldedit/manipulations.lua
Normal file
417
worldedit/manipulations.lua
Normal file
@ -0,0 +1,417 @@
|
||||
worldedit = worldedit or {}
|
||||
|
||||
--modifies positions `pos1` and `pos2` so that each component of `pos1` is less than or equal to its corresponding conent of `pos2`, returning two new positions
|
||||
worldedit.sort_pos = function(pos1, pos2)
|
||||
pos1 = {x=pos1.x, y=pos1.y, z=pos1.z}
|
||||
pos2 = {x=pos2.x, y=pos2.y, z=pos2.z}
|
||||
if pos1.x > pos2.x then
|
||||
pos2.x, pos1.x = pos1.x, pos2.x
|
||||
end
|
||||
if pos1.y > pos2.y then
|
||||
pos2.y, pos1.y = pos1.y, pos2.y
|
||||
end
|
||||
if pos1.z > pos2.z then
|
||||
pos2.z, pos1.z = pos1.z, pos2.z
|
||||
end
|
||||
return pos1, pos2
|
||||
end
|
||||
|
||||
--determines the volume of the region defined by positions `pos1` and `pos2`, returning the volume
|
||||
worldedit.volume = function(pos1, pos2)
|
||||
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||
return (pos2.x - pos1.x + 1) * (pos2.y - pos1.y + 1) * (pos2.z - pos1.z + 1)
|
||||
end
|
||||
|
||||
--sets a region defined by positions `pos1` and `pos2` to `nodename`, returning the number of nodes filled
|
||||
worldedit.set = function(pos1, pos2, nodename, env)
|
||||
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||
if env == nil then env = minetest.env end
|
||||
|
||||
local node = {name=nodename}
|
||||
local pos = {x=pos1.x, y=0, z=0}
|
||||
while pos.x <= pos2.x do
|
||||
pos.y = pos1.y
|
||||
while pos.y <= pos2.y do
|
||||
pos.z = pos1.z
|
||||
while pos.z <= pos2.z do
|
||||
env:add_node(pos, node)
|
||||
pos.z = pos.z + 1
|
||||
end
|
||||
pos.y = pos.y + 1
|
||||
end
|
||||
pos.x = pos.x + 1
|
||||
end
|
||||
return worldedit.volume(pos1, pos2)
|
||||
end
|
||||
|
||||
--replaces all instances of `searchnode` with `replacenode` in a region defined by positions `pos1` and `pos2`, returning the number of nodes replaced
|
||||
worldedit.replace = function(pos1, pos2, searchnode, replacenode, env)
|
||||
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||
if env == nil then env = minetest.env end
|
||||
|
||||
if minetest.registered_nodes[searchnode] == nil then
|
||||
searchnode = "default:" .. searchnode
|
||||
end
|
||||
|
||||
local pos = {x=pos1.x, y=0, z=0}
|
||||
local node = {name=replacenode}
|
||||
local count = 0
|
||||
while pos.x <= pos2.x do
|
||||
pos.y = pos1.y
|
||||
while pos.y <= pos2.y do
|
||||
pos.z = pos1.z
|
||||
while pos.z <= pos2.z do
|
||||
if env:get_node(pos).name == searchnode then
|
||||
env:add_node(pos, node)
|
||||
count = count + 1
|
||||
end
|
||||
pos.z = pos.z + 1
|
||||
end
|
||||
pos.y = pos.y + 1
|
||||
end
|
||||
pos.x = pos.x + 1
|
||||
end
|
||||
return count
|
||||
end
|
||||
|
||||
--replaces all nodes other than `searchnode` with `replacenode` in a region defined by positions `pos1` and `pos2`, returning the number of nodes replaced
|
||||
worldedit.replaceinverse = function(pos1, pos2, searchnode, replacenode, env)
|
||||
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||
if env == nil then env = minetest.env end
|
||||
|
||||
if minetest.registered_nodes[searchnode] == nil then
|
||||
searchnode = "default:" .. searchnode
|
||||
end
|
||||
|
||||
local pos = {x=pos1.x, y=0, z=0}
|
||||
local node = {name=replacenode}
|
||||
local count = 0
|
||||
while pos.x <= pos2.x do
|
||||
pos.y = pos1.y
|
||||
while pos.y <= pos2.y do
|
||||
pos.z = pos1.z
|
||||
while pos.z <= pos2.z do
|
||||
local name = env:get_node(pos).name
|
||||
if name ~= "ignore" and name ~= searchnode then
|
||||
env:add_node(pos, node)
|
||||
count = count + 1
|
||||
end
|
||||
pos.z = pos.z + 1
|
||||
end
|
||||
pos.y = pos.y + 1
|
||||
end
|
||||
pos.x = pos.x + 1
|
||||
end
|
||||
return count
|
||||
end
|
||||
|
||||
--copies the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") by `amount` nodes, returning the number of nodes copied
|
||||
worldedit.copy = function(pos1, pos2, axis, amount, env)
|
||||
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||
if env == nil then env = minetest.env end
|
||||
|
||||
if amount < 0 then
|
||||
local pos = {x=pos1.x, y=0, z=0}
|
||||
while pos.x <= pos2.x do
|
||||
pos.y = pos1.y
|
||||
while pos.y <= pos2.y do
|
||||
pos.z = pos1.z
|
||||
while pos.z <= pos2.z do
|
||||
local node = env:get_node(pos) --obtain current node
|
||||
local meta = env:get_meta(pos):to_table() --get meta of current node
|
||||
local value = pos[axis] --store current position
|
||||
pos[axis] = value + amount --move along axis
|
||||
env:add_node(pos, node) --copy node to new position
|
||||
env:get_meta(pos):from_table(meta) --set metadata of new node
|
||||
pos[axis] = value --restore old position
|
||||
pos.z = pos.z + 1
|
||||
end
|
||||
pos.y = pos.y + 1
|
||||
end
|
||||
pos.x = pos.x + 1
|
||||
end
|
||||
else
|
||||
local pos = {x=pos2.x, y=0, z=0}
|
||||
while pos.x >= pos1.x do
|
||||
pos.y = pos2.y
|
||||
while pos.y >= pos1.y do
|
||||
pos.z = pos2.z
|
||||
while pos.z >= pos1.z do
|
||||
local node = minetest.env:get_node(pos) --obtain current node
|
||||
local meta = env:get_meta(pos):to_table() --get meta of current node
|
||||
local value = pos[axis] --store current position
|
||||
pos[axis] = value + amount --move along axis
|
||||
minetest.env:add_node(pos, node) --copy node to new position
|
||||
env:get_meta(pos):from_table(meta) --set metadata of new node
|
||||
pos[axis] = value --restore old position
|
||||
pos.z = pos.z - 1
|
||||
end
|
||||
pos.y = pos.y - 1
|
||||
end
|
||||
pos.x = pos.x - 1
|
||||
end
|
||||
end
|
||||
return worldedit.volume(pos1, pos2)
|
||||
end
|
||||
|
||||
--moves the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") by `amount` nodes, returning the number of nodes moved
|
||||
worldedit.move = function(pos1, pos2, axis, amount, env)
|
||||
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||
if env == nil then env = minetest.env end
|
||||
|
||||
if amount < 0 then
|
||||
local pos = {x=pos1.x, y=0, z=0}
|
||||
while pos.x <= pos2.x do
|
||||
pos.y = pos1.y
|
||||
while pos.y <= pos2.y do
|
||||
pos.z = pos1.z
|
||||
while pos.z <= pos2.z do
|
||||
local node = env:get_node(pos) --obtain current node
|
||||
local meta = env:get_meta(pos):to_table() --get metadata of current node
|
||||
env:remove_node(pos)
|
||||
local value = pos[axis] --store current position
|
||||
pos[axis] = value + amount --move along axis
|
||||
env:add_node(pos, node) --move node to new position
|
||||
env:get_meta(pos):from_table(meta) --set metadata of new node
|
||||
pos[axis] = value --restore old position
|
||||
pos.z = pos.z + 1
|
||||
end
|
||||
pos.y = pos.y + 1
|
||||
end
|
||||
pos.x = pos.x + 1
|
||||
end
|
||||
else
|
||||
local pos = {x=pos2.x, y=0, z=0}
|
||||
while pos.x >= pos1.x do
|
||||
pos.y = pos2.y
|
||||
while pos.y >= pos1.y do
|
||||
pos.z = pos2.z
|
||||
while pos.z >= pos1.z do
|
||||
local node = env:get_node(pos) --obtain current node
|
||||
local meta = env:get_meta(pos):to_table() --get metadata of current node
|
||||
env:remove_node(pos)
|
||||
local value = pos[axis] --store current position
|
||||
pos[axis] = value + amount --move along axis
|
||||
env:add_node(pos, node) --move node to new position
|
||||
env:get_meta(pos):from_table(meta) --set metadata of new node
|
||||
pos[axis] = value --restore old position
|
||||
pos.z = pos.z - 1
|
||||
end
|
||||
pos.y = pos.y - 1
|
||||
end
|
||||
pos.x = pos.x - 1
|
||||
end
|
||||
end
|
||||
return worldedit.volume(pos1, pos2)
|
||||
end
|
||||
|
||||
--duplicates the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") `count` times, returning the number of nodes stacked
|
||||
worldedit.stack = function(pos1, pos2, axis, count, env)
|
||||
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||
local length = pos2[axis] - pos1[axis] + 1
|
||||
if count < 0 then
|
||||
count = -count
|
||||
length = -length
|
||||
end
|
||||
local amount = 0
|
||||
local copy = worldedit.copy
|
||||
for i = 1, count do
|
||||
amount = amount + length
|
||||
copy(pos1, pos2, axis, amount, env)
|
||||
end
|
||||
return worldedit.volume(pos1, pos2)
|
||||
end
|
||||
|
||||
--transposes a region defined by the positions `pos1` and `pos2` between the `axis1` and `axis2` axes, returning the number of nodes transposed, the new position 1, and the new position 2
|
||||
worldedit.transpose = function(pos1, pos2, axis1, axis2, env)
|
||||
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||
|
||||
local compare
|
||||
local extent1, extent2 = pos2[axis1] - pos1[axis1], pos2[axis2] - pos1[axis2]
|
||||
|
||||
if extent1 > extent2 then
|
||||
compare = function(extent1, extent2)
|
||||
return extent1 > extent2
|
||||
end
|
||||
else
|
||||
compare = function(extent1, extent2)
|
||||
return extent1 < extent2
|
||||
end
|
||||
end
|
||||
|
||||
--calculate the new position 2 after transposition
|
||||
local newpos2 = {x=pos2.x, y=pos2.y, z=pos2.z}
|
||||
newpos2[axis1] = pos1[axis1] + extent2
|
||||
newpos2[axis2] = pos1[axis2] + extent1
|
||||
|
||||
local pos = {x=pos1.x, y=0, z=0}
|
||||
if env == nil then env = minetest.env end
|
||||
while pos.x <= pos2.x do
|
||||
pos.y = pos1.y
|
||||
while pos.y <= pos2.y do
|
||||
pos.z = pos1.z
|
||||
while pos.z <= pos2.z do
|
||||
local extent1, extent2 = pos[axis1] - pos1[axis1], pos[axis2] - pos1[axis2]
|
||||
if compare(extent1, extent2) then --transpose only if below the diagonal
|
||||
local node1 = env:get_node(pos)
|
||||
local meta1 = env:get_meta(pos):to_table()
|
||||
local value1, value2 = pos[axis1], pos[axis2] --save position values
|
||||
pos[axis1], pos[axis2] = pos1[axis1] + extent2, pos1[axis2] + extent1 --swap axis extents
|
||||
local node2 = env:get_node(pos)
|
||||
local meta2 = env:get_meta(pos):to_table()
|
||||
env:add_node(pos, node1)
|
||||
env:get_meta(pos):from_table(meta1)
|
||||
pos[axis1], pos[axis2] = value1, value2 --restore position values
|
||||
env:add_node(pos, node2)
|
||||
env:get_meta(pos):from_table(meta2)
|
||||
end
|
||||
pos.z = pos.z + 1
|
||||
end
|
||||
pos.y = pos.y + 1
|
||||
end
|
||||
pos.x = pos.x + 1
|
||||
end
|
||||
return worldedit.volume(pos1, pos2), pos1, newpos2
|
||||
end
|
||||
|
||||
--flips a region defined by the positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z"), returning the number of nodes flipped
|
||||
worldedit.flip = function(pos1, pos2, axis, env)
|
||||
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||
|
||||
local pos = {x=pos1.x, y=0, z=0}
|
||||
local start = pos1[axis] + pos2[axis]
|
||||
pos2[axis] = pos1[axis] + math.floor((pos2[axis] - pos1[axis]) / 2)
|
||||
if env == nil then env = minetest.env end
|
||||
while pos.x <= pos2.x do
|
||||
pos.y = pos1.y
|
||||
while pos.y <= pos2.y do
|
||||
pos.z = pos1.z
|
||||
while pos.z <= pos2.z do
|
||||
local node1 = env:get_node(pos)
|
||||
local meta1 = env:get_meta(pos):to_table()
|
||||
local value = pos[axis]
|
||||
pos[axis] = start - value
|
||||
local node2 = env:get_node(pos)
|
||||
local meta2 = env:get_meta(pos):to_table()
|
||||
env:add_node(pos, node1)
|
||||
env:get_meta(pos):from_table(meta1)
|
||||
pos[axis] = value
|
||||
env:add_node(pos, node2)
|
||||
env:get_meta(pos):from_table(meta2)
|
||||
pos.z = pos.z + 1
|
||||
end
|
||||
pos.y = pos.y + 1
|
||||
end
|
||||
pos.x = pos.x + 1
|
||||
end
|
||||
return worldedit.volume(pos1, pos2)
|
||||
end
|
||||
|
||||
--rotates a region defined by the positions `pos1` and `pos2` by `angle` degrees clockwise around axis `axis` (90 degree increment), returning the number of nodes rotated
|
||||
worldedit.rotate = function(pos1, pos2, axis, angle, env)
|
||||
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||
|
||||
local axis1, axis2
|
||||
if axis == "x" then
|
||||
axis1, axis2 = "z", "y"
|
||||
elseif axis == "y" then
|
||||
axis1, axis2 = "x", "z"
|
||||
else --axis == "z"
|
||||
axis1, axis2 = "y", "x"
|
||||
end
|
||||
angle = angle % 360
|
||||
|
||||
local count
|
||||
if angle == 90 then
|
||||
worldedit.flip(pos1, pos2, axis1, env)
|
||||
count, pos1, pos2 = worldedit.transpose(pos1, pos2, axis1, axis2, env)
|
||||
elseif angle == 180 then
|
||||
worldedit.flip(pos1, pos2, axis1, env)
|
||||
count = worldedit.flip(pos1, pos2, axis2, env)
|
||||
elseif angle == 270 then
|
||||
worldedit.flip(pos1, pos2, axis2, env)
|
||||
count, pos1, pos2 = worldedit.transpose(pos1, pos2, axis1, axis2, env)
|
||||
end
|
||||
return count, pos1, pos2
|
||||
end
|
||||
|
||||
--rotates all oriented nodes in a region defined by the positions `pos1` and `pos2` by `angle` degrees clockwise (90 degree increment) around the Y axis, returning the number of nodes oriented
|
||||
worldedit.orient = function(pos1, pos2, angle, env)
|
||||
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||
local nodes = minetest.registered_nodes
|
||||
if env == nil then env = minetest.env end
|
||||
local wallmounted = {
|
||||
[90]={[0]=0, [1]=1, [2]=5, [3]=4, [4]=2, [5]=3},
|
||||
[180]={[0]=0, [1]=1, [2]=3, [3]=2, [4]=5, [5]=4},
|
||||
[270]={[0]=0, [1]=1, [2]=4, [3]=5, [4]=3, [5]=2}
|
||||
}
|
||||
local facedir = {
|
||||
[90]={[0]=1, [1]=2, [2]=3, [3]=0},
|
||||
[180]={[0]=2, [1]=3, [2]=0, [3]=1},
|
||||
[270]={[0]=3, [1]=0, [2]=1, [3]=2}
|
||||
}
|
||||
|
||||
angle = angle % 360
|
||||
if angle == 0 then
|
||||
return 0
|
||||
end
|
||||
local wallmounted_substitution = wallmounted[angle]
|
||||
local facedir_substitution = facedir[angle]
|
||||
|
||||
local count = 0
|
||||
local pos = {x=pos1.x, y=0, z=0}
|
||||
while pos.x <= pos2.x do
|
||||
pos.y = pos1.y
|
||||
while pos.y <= pos2.y do
|
||||
pos.z = pos1.z
|
||||
while pos.z <= pos2.z do
|
||||
local node = env:get_node(pos)
|
||||
local def = nodes[node.name]
|
||||
if def then
|
||||
if def.paramtype2 == "wallmounted" then
|
||||
node.param2 = wallmounted_substitution[node.param2]
|
||||
local meta = env:get_meta(pos):to_table()
|
||||
env:add_node(pos, node)
|
||||
env:get_meta(pos):from_table(meta)
|
||||
count = count + 1
|
||||
elseif def.paramtype2 == "facedir" then
|
||||
node.param2 = facedir_substitution[node.param2]
|
||||
local meta = env:get_meta(pos):to_table()
|
||||
env:add_node(pos, node)
|
||||
env:get_meta(pos):from_table(meta)
|
||||
count = count + 1
|
||||
end
|
||||
end
|
||||
pos.z = pos.z + 1
|
||||
end
|
||||
pos.y = pos.y + 1
|
||||
end
|
||||
pos.x = pos.x + 1
|
||||
end
|
||||
return count
|
||||
end
|
||||
|
||||
--fixes the lighting in a region defined by positions `pos1` and `pos2`, returning the number of nodes updated
|
||||
worldedit.fixlight = function(pos1, pos2, env)
|
||||
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||
if env == nil then env = minetest.env end
|
||||
local count = 0
|
||||
|
||||
local pos = {x=pos1.x, y=0, z=0}
|
||||
while pos.x <= pos2.x do
|
||||
pos.y = pos1.y
|
||||
while pos.y <= pos2.y do
|
||||
pos.z = pos1.z
|
||||
while pos.z <= pos2.z do
|
||||
if env:get_node(pos).name == "air" then
|
||||
env:dig_node(pos)
|
||||
count = count + 1
|
||||
end
|
||||
pos.z = pos.z + 1
|
||||
end
|
||||
pos.y = pos.y + 1
|
||||
end
|
||||
pos.x = pos.x + 1
|
||||
end
|
||||
return count
|
||||
end
|
311
worldedit/primitives.lua
Normal file
311
worldedit/primitives.lua
Normal file
@ -0,0 +1,311 @@
|
||||
worldedit = worldedit or {}
|
||||
|
||||
--adds a hollow sphere at `pos` with radius `radius`, composed of `nodename`, returning the number of nodes added
|
||||
worldedit.hollow_sphere = function(pos, radius, nodename, env)
|
||||
local node = {name=nodename}
|
||||
local pos1 = {x=0, y=0, z=0}
|
||||
local min_radius = radius * (radius - 1)
|
||||
local max_radius = radius * (radius + 1)
|
||||
local count = 0
|
||||
if env == nil then env = minetest.env end
|
||||
for x = -radius, radius do
|
||||
pos1.x = pos.x + x
|
||||
for y = -radius, radius do
|
||||
pos1.y = pos.y + y
|
||||
for z = -radius, radius do
|
||||
if x*x+y*y+z*z >= min_radius and x*x+y*y+z*z <= max_radius then
|
||||
pos1.z = pos.z + z
|
||||
env:add_node(pos1, node)
|
||||
count = count + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return count
|
||||
end
|
||||
|
||||
--adds a sphere at `pos` with radius `radius`, composed of `nodename`, returning the number of nodes added
|
||||
worldedit.sphere = function(pos, radius, nodename, env)
|
||||
local node = {name=nodename}
|
||||
local pos1 = {x=0, y=0, z=0}
|
||||
local max_radius = radius * (radius + 1)
|
||||
local count = 0
|
||||
if env == nil then env = minetest.env end
|
||||
for x = -radius, radius do
|
||||
pos1.x = pos.x + x
|
||||
for y = -radius, radius do
|
||||
pos1.y = pos.y + y
|
||||
for z = -radius, radius do
|
||||
if x*x+y*y+z*z <= max_radius then
|
||||
pos1.z = pos.z + z
|
||||
env:add_node(pos1, node)
|
||||
count = count + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return count
|
||||
end
|
||||
|
||||
--adds a hollow dome at `pos` with radius `radius`, composed of `nodename`, returning the number of nodes added
|
||||
worldedit.hollow_dome = function(pos, radius, nodename, env) --wip: use bresenham sphere for maximum speed
|
||||
local node = {name=nodename}
|
||||
local pos1 = {x=0, y=0, z=0}
|
||||
local min_radius = radius * (radius - 1)
|
||||
local max_radius = radius * (radius + 1)
|
||||
local count = 0
|
||||
if env == nil then env = minetest.env end
|
||||
for x = -radius, radius do
|
||||
pos1.x = pos.x + x
|
||||
for y = 0, radius do
|
||||
pos1.y = pos.y + y
|
||||
for z = -radius, radius do
|
||||
if x*x+y*y+z*z >= min_radius and x*x+y*y+z*z <= max_radius then
|
||||
pos1.z = pos.z + z
|
||||
env:add_node(pos1, node)
|
||||
count = count + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return count
|
||||
end
|
||||
|
||||
--adds a dome at `pos` with radius `radius`, composed of `nodename`, returning the number of nodes added
|
||||
worldedit.dome = function(pos, radius, nodename, env) --wip: use bresenham sphere for maximum speed
|
||||
local node = {name=nodename}
|
||||
local pos1 = {x=0, y=0, z=0}
|
||||
local max_radius = radius * (radius + 1)
|
||||
local count = 0
|
||||
if env == nil then env = minetest.env end
|
||||
for x = -radius, radius do
|
||||
pos1.x = pos.x + x
|
||||
for y = 0, radius do
|
||||
pos1.y = pos.y + y
|
||||
for z = -radius, radius do
|
||||
if x*x+y*y+z*z <= max_radius then
|
||||
pos1.z = pos.z + z
|
||||
env:add_node(pos1, node)
|
||||
count = count + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return count
|
||||
end
|
||||
|
||||
--adds a hollow cylinder at `pos` along the `axis` axis ("x" or "y" or "z") with length `length` and radius `radius`, composed of `nodename`, returning the number of nodes added
|
||||
worldedit.hollow_cylinder = function(pos, axis, length, radius, nodename, env)
|
||||
local other1, other2
|
||||
if axis == "x" then
|
||||
other1, other2 = "y", "z"
|
||||
elseif axis == "y" then
|
||||
other1, other2 = "x", "z"
|
||||
else --axis == "z"
|
||||
other1, other2 = "x", "y"
|
||||
end
|
||||
|
||||
if env == nil then env = minetest.env end
|
||||
local currentpos = {x=pos.x, y=pos.y, z=pos.z}
|
||||
local node = {name=nodename}
|
||||
local count = 0
|
||||
local step = 1
|
||||
if length < 0 then
|
||||
length = -length
|
||||
step = -1
|
||||
end
|
||||
for i = 1, length do
|
||||
local offset1, offset2 = 0, radius
|
||||
local delta = -radius
|
||||
while offset1 <= offset2 do
|
||||
--add node at each octant
|
||||
local first1, first2 = pos[other1] + offset1, pos[other1] - offset1
|
||||
local second1, second2 = pos[other2] + offset2, pos[other2] - offset2
|
||||
currentpos[other1], currentpos[other2] = first1, second1
|
||||
env:add_node(currentpos, node) --octant 1
|
||||
currentpos[other1] = first2
|
||||
env:add_node(currentpos, node) --octant 4
|
||||
currentpos[other2] = second2
|
||||
env:add_node(currentpos, node) --octant 5
|
||||
currentpos[other1] = first1
|
||||
env:add_node(currentpos, node) --octant 8
|
||||
local first1, first2 = pos[other1] + offset2, pos[other1] - offset2
|
||||
local second1, second2 = pos[other2] + offset1, pos[other2] - offset1
|
||||
currentpos[other1], currentpos[other2] = first1, second1
|
||||
env:add_node(currentpos, node) --octant 2
|
||||
currentpos[other1] = first2
|
||||
env:add_node(currentpos, node) --octant 3
|
||||
currentpos[other2] = second2
|
||||
env:add_node(currentpos, node) --octant 6
|
||||
currentpos[other1] = first1
|
||||
env:add_node(currentpos, node) --octant 7
|
||||
|
||||
count = count + 8 --wip: broken
|
||||
|
||||
--move to next location
|
||||
delta = delta + (offset1 * 2) + 1
|
||||
if delta >= 0 then
|
||||
offset2 = offset2 - 1
|
||||
delta = delta - (offset2 * 2)
|
||||
end
|
||||
offset1 = offset1 + 1
|
||||
end
|
||||
currentpos[axis] = currentpos[axis] + step
|
||||
end
|
||||
return count
|
||||
end
|
||||
|
||||
--adds a cylinder at `pos` along the `axis` axis ("x" or "y" or "z") with length `length` and radius `radius`, composed of `nodename`, returning the number of nodes added
|
||||
worldedit.cylinder = function(pos, axis, length, radius, nodename, env)
|
||||
local other1, other2
|
||||
if axis == "x" then
|
||||
other1, other2 = "y", "z"
|
||||
elseif axis == "y" then
|
||||
other1, other2 = "x", "z"
|
||||
else --axis == "z"
|
||||
other1, other2 = "x", "y"
|
||||
end
|
||||
|
||||
if env == nil then env = minetest.env end
|
||||
local currentpos = {x=pos.x, y=pos.y, z=pos.z}
|
||||
local node = {name=nodename}
|
||||
local count = 0
|
||||
local step = 1
|
||||
if length < 0 then
|
||||
length = -length
|
||||
step = -1
|
||||
end
|
||||
for i = 1, length do
|
||||
local offset1, offset2 = 0, radius
|
||||
local delta = -radius
|
||||
while offset1 <= offset2 do
|
||||
--connect each pair of octants
|
||||
currentpos[other1] = pos[other1] - offset1
|
||||
local second1, second2 = pos[other2] + offset2, pos[other2] - offset2
|
||||
for i = 0, offset1 * 2 do
|
||||
currentpos[other2] = second1
|
||||
env:add_node(currentpos, node) --octant 1 to 4
|
||||
currentpos[other2] = second2
|
||||
env:add_node(currentpos, node) --octant 5 to 8
|
||||
currentpos[other1] = currentpos[other1] + 1
|
||||
end
|
||||
currentpos[other1] = pos[other1] - offset2
|
||||
local second1, second2 = pos[other2] + offset1, pos[other2] - offset1
|
||||
for i = 0, offset2 * 2 do
|
||||
currentpos[other2] = second1
|
||||
env:add_node(currentpos, node) --octant 2 to 3
|
||||
currentpos[other2] = second2
|
||||
env:add_node(currentpos, node) --octant 6 to 7
|
||||
currentpos[other1] = currentpos[other1] + 1
|
||||
end
|
||||
|
||||
count = count + (offset1 * 4) + (offset2 * 4) + 4 --wip: broken
|
||||
|
||||
--move to next location
|
||||
delta = delta + (offset1 * 2) + 1
|
||||
offset1 = offset1 + 1
|
||||
if delta >= 0 then
|
||||
offset2 = offset2 - 1
|
||||
delta = delta - (offset2 * 2)
|
||||
end
|
||||
end
|
||||
currentpos[axis] = currentpos[axis] + step
|
||||
end
|
||||
return count
|
||||
end
|
||||
|
||||
--adds a pyramid at `pos` with height `height`, composed of `nodename`, returning the number of nodes added
|
||||
worldedit.pyramid = function(pos, height, nodename, env)
|
||||
local pos1x, pos1y, pos1z = pos.x - height, pos.y, pos.z - height
|
||||
local pos2x, pos2y, pos2z = pos.x + height, pos.y + height, pos.z + height
|
||||
local pos = {x=0, y=pos1y, z=0}
|
||||
|
||||
local count = 0
|
||||
local node = {name=nodename}
|
||||
if env == nil then env = minetest.env end
|
||||
while pos.y <= pos2y do --each vertical level of the pyramid
|
||||
pos.x = pos1x
|
||||
while pos.x <= pos2x do
|
||||
pos.z = pos1z
|
||||
while pos.z <= pos2z do
|
||||
env:add_node(pos, node)
|
||||
pos.z = pos.z + 1
|
||||
end
|
||||
pos.x = pos.x + 1
|
||||
end
|
||||
count = count + ((pos2y - pos.y) * 2 + 1) ^ 2
|
||||
pos.y = pos.y + 1
|
||||
|
||||
pos1x, pos2x = pos1x + 1, pos2x - 1
|
||||
pos1z, pos2z = pos1z + 1, pos2z - 1
|
||||
|
||||
end
|
||||
return count
|
||||
end
|
||||
|
||||
--adds a spiral at `pos` with width `width`, height `height`, space between walls `spacer`, composed of `nodename`, returning the number of nodes added
|
||||
worldedit.spiral = function(pos, width, height, spacer, nodename, env) --wip: clean this up
|
||||
-- spiral matrix - http://rosettacode.org/wiki/Spiral_matrix#Lua
|
||||
av, sn = math.abs, function(s) return s~=0 and s/av(s) or 0 end
|
||||
local function sindex(z, x) -- returns the value at (x, z) in a spiral that starts at 1 and goes outwards
|
||||
if z == -x and z >= x then return (2*z+1)^2 end
|
||||
local l = math.max(av(z), av(x))
|
||||
return (2*l-1)^2+4*l+2*l*sn(x+z)+sn(z^2-x^2)*(l-(av(z)==l and sn(z)*x or sn(x)*z)) -- OH GOD WHAT
|
||||
end
|
||||
local function spiralt(side)
|
||||
local ret, id, start, stop = {}, 0, math.floor((-side+1)/2), math.floor((side-1)/2)
|
||||
for i = 1, side do
|
||||
for j = 1, side do
|
||||
local id = side^2 - sindex(stop - i + 1,start + j - 1)
|
||||
ret[id] = {x=i,z=j}
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
if env == nil then env = minetest.env end
|
||||
-- connect the joined parts
|
||||
local spiral = spiralt(width)
|
||||
height = tonumber(height)
|
||||
if height < 1 then height = 1 end
|
||||
spacer = tonumber(spacer)-1
|
||||
if spacer < 1 then spacer = 1 end
|
||||
local count = 0
|
||||
local node = {name=nodename}
|
||||
local np,lp
|
||||
for y=0,height do
|
||||
lp = nil
|
||||
for _,v in ipairs(spiral) do
|
||||
np = {x=pos.x+v.x*spacer, y=pos.y+y, z=pos.z+v.z*spacer}
|
||||
if lp~=nil then
|
||||
if lp.x~=np.x then
|
||||
if lp.x<np.x then
|
||||
for i=lp.x+1,np.x do
|
||||
env:add_node({x=i, y=np.y, z=np.z}, node)
|
||||
count = count + 1
|
||||
end
|
||||
else
|
||||
for i=np.x,lp.x-1 do
|
||||
env:add_node({x=i, y=np.y, z=np.z}, node)
|
||||
count = count + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
if lp.z~=np.z then
|
||||
if lp.z<np.z then
|
||||
for i=lp.z+1,np.z do
|
||||
env:add_node({x=np.x, y=np.y, z=i}, node)
|
||||
count = count + 1
|
||||
end
|
||||
else
|
||||
for i=np.z,lp.z-1 do
|
||||
env:add_node({x=np.x, y=np.y, z=i}, node)
|
||||
count = count + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
lp = np
|
||||
end
|
||||
end
|
||||
return count
|
||||
end
|
108
worldedit/queue.lua
Normal file
108
worldedit/queue.lua
Normal file
@ -0,0 +1,108 @@
|
||||
worldedit = worldedit or {}
|
||||
|
||||
worldedit.queue = {}
|
||||
|
||||
worldedit.ENABLE_QUEUE = true
|
||||
worldedit.BLOCKS_PER_GLOBALSTEP = 512
|
||||
|
||||
minetest.register_globalstep(function(dtime)
|
||||
i = 1
|
||||
while i <= #worldedit.queue and i <= worldedit.BLOCKS_PER_GLOBALSTEP do
|
||||
idx = (#worldedit.queue + 1) - i -- we use the last entry, so we don't spend days moving stuff in the table because we removed the first entry
|
||||
if worldedit.queue[idx].t == "set_node" then
|
||||
minetest.env:set_node(worldedit.queue[idx].pos, worldedit.queue[idx].node)
|
||||
elseif worldedit.queue[idx].t == "remove_node" then
|
||||
minetest.env:remove_node(worldedit.queue[idx].pos)
|
||||
elseif worldedit.queue[idx].t == "place_node" then
|
||||
minetest.env:place_node(worldedit.queue[idx].pos, worldedit.queue[idx].node)
|
||||
elseif worldedit.queue[idx].t == "dig_node" then
|
||||
minetest.env:dig_node(worldedit.queue[idx].pos)
|
||||
elseif worldedit.queue[idx].t == "add_entity" then
|
||||
minetest.env:add_entity(worldedit.queue[idx].pos, worldedit.queue[idx].name)
|
||||
elseif worldedit.queue[idx].t == "add_item" then
|
||||
minetest.env:add_item(worldedit.queue[idx].pos, worldedit.queue[idx].item)
|
||||
elseif worldedit.queue[idx].t == "meta_from_table" then
|
||||
minetest.env:get_meta(worldedit.queue[idx].pos):from_table(worldedit.queue[idx].table)
|
||||
else
|
||||
print("Unknown queue event type: " .. worldedit.queue[idx].t)
|
||||
end
|
||||
table.remove(worldedit.queue, idx)
|
||||
i = i + 1
|
||||
end
|
||||
end)
|
||||
|
||||
function table.copy(t, seen)
|
||||
seen = seen or {}
|
||||
if t == nil then return nil end
|
||||
if seen[t] then return seen[t] end
|
||||
|
||||
local nt = {}
|
||||
for k, v in pairs(t) do
|
||||
if type(v) == 'table' then
|
||||
nt[k] = table.copy(v, seen)
|
||||
else
|
||||
nt[k] = v
|
||||
end
|
||||
end
|
||||
seen[t] = nt
|
||||
return nt
|
||||
end
|
||||
|
||||
local quene_setnode = function(self, pos_, node_)
|
||||
table.insert(worldedit.queue, {pos=table.copy(pos_), node=table.copy(node_), t="set_node"})
|
||||
end
|
||||
|
||||
local quene_removenode = function(self, pos_)
|
||||
table.insert(worldedit.queue, {pos=table.copy(pos_), t="remove_node"})
|
||||
end
|
||||
|
||||
local quene_placenode = function(self, pos_, node_)
|
||||
table.insert(worldedit.queue, {pos=table.copy(pos_), node=table.copy(node_), t="place_node"})
|
||||
end
|
||||
|
||||
local quene_dignode = function(self, pos_)
|
||||
table.insert(worldedit.queue, {pos=table.copy(pos_), t="dig_node"})
|
||||
end
|
||||
|
||||
local quene_addentity = function(self, pos_, name_)
|
||||
table.insert(worldedit.queue, {pos=table.copy(pos_), name=name_.."", t="add_entity"})
|
||||
end
|
||||
|
||||
local quene_additem = function(self, pos_, item_)
|
||||
table.insert(worldedit.queue, {pos=table.copy(pos_), item=item_.."", t="add_item"})
|
||||
end
|
||||
|
||||
local quene_setmeta = function(self, pos_, table_)
|
||||
table.insert(worldedit.queue, {pos=table.copy(pos_), table=table.copy(table_), t="meta_from_table"})
|
||||
end
|
||||
|
||||
local aliasmeta = {
|
||||
-- the other functions are left out because they are not used in worldedit
|
||||
to_table = function(self) return minetest.env:get_meta(self._pos):to_table() end,
|
||||
set_string = function(self, name_, value_) minetest.env:get_meta(self._pos):set_string(name_, value_) end,
|
||||
from_table = function(self, tbl) quene_setmeta(nil, self._pos, tbl) end,
|
||||
}
|
||||
|
||||
local get_meta_alias = function(self, pos)
|
||||
local am = table.copy(aliasmeta)
|
||||
am._pos = pos
|
||||
return am
|
||||
end
|
||||
|
||||
worldedit.quene_aliasenv = {
|
||||
-- ALL functions that are not just piped to the real minetest.env function must copy the arguments, not just reference them
|
||||
set_node = quene_setnode,
|
||||
add_node = quene_setnode,
|
||||
remove_node = quene_removenode,
|
||||
get_node = function(self, pos) return minetest.env:get_node(pos) end,
|
||||
get_node_or_nil = function(self, pos) return minetest.env:get_node_or_nil(pos) end,
|
||||
get_node_light = function(self, pos, timeofday) return minetest.env:get_node_light(pos, timeofday) end,
|
||||
place_node = quene_placenode,
|
||||
dig_node = quene_dignode,
|
||||
punch_node = function(self, pos) return minetest.env:punch_node(pos) end,
|
||||
get_meta = get_meta_alias,
|
||||
get_node_timer = function(self, pos) return minetest.env:get_node_timer(pos) end,
|
||||
add_entity = quene_addentity,
|
||||
add_item = quene_additem,
|
||||
}
|
||||
|
242
worldedit/serialization.lua
Normal file
242
worldedit/serialization.lua
Normal file
@ -0,0 +1,242 @@
|
||||
worldedit = worldedit or {}
|
||||
|
||||
--modifies positions `pos1` and `pos2` so that each component of `pos1` is less than or equal to its corresponding conent of `pos2`, returning two new positions
|
||||
worldedit.sort_pos = function(pos1, pos2)
|
||||
pos1 = {x=pos1.x, y=pos1.y, z=pos1.z}
|
||||
pos2 = {x=pos2.x, y=pos2.y, z=pos2.z}
|
||||
if pos1.x > pos2.x then
|
||||
pos2.x, pos1.x = pos1.x, pos2.x
|
||||
end
|
||||
if pos1.y > pos2.y then
|
||||
pos2.y, pos1.y = pos1.y, pos2.y
|
||||
end
|
||||
if pos1.z > pos2.z then
|
||||
pos2.z, pos1.z = pos1.z, pos2.z
|
||||
end
|
||||
return pos1, pos2
|
||||
end
|
||||
|
||||
--determines the version of serialized data `value`, returning the version as a positive integer or 0 for unknown versions
|
||||
worldedit.valueversion = function(value)
|
||||
if value:find("([+-]?%d+)%s+([+-]?%d+)%s+([+-]?%d+)") and not value:find("%{") then --previous list format
|
||||
return 3
|
||||
elseif value:find("^[^\"']+%{%d+%}") then
|
||||
if value:find("%[\"meta\"%]") then --previous meta flat table format
|
||||
return 2
|
||||
end
|
||||
return 1 --original flat table format
|
||||
elseif value:find("%{") then --current nested table format
|
||||
return 4
|
||||
end
|
||||
return 0 --unknown format
|
||||
end
|
||||
|
||||
--converts the region defined by positions `pos1` and `pos2` into a single string, returning the serialized data and the number of nodes serialized
|
||||
worldedit.serialize = function(pos1, pos2) --wip: check for ItemStacks and whether they can be serialized
|
||||
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||
local pos = {x=pos1.x, y=0, z=0}
|
||||
local count = 0
|
||||
local result = {}
|
||||
local env = minetest.env
|
||||
while pos.x <= pos2.x do
|
||||
pos.y = pos1.y
|
||||
while pos.y <= pos2.y do
|
||||
pos.z = pos1.z
|
||||
while pos.z <= pos2.z do
|
||||
local node = env:get_node(pos)
|
||||
if node.name ~= "air" and node.name ~= "ignore" then
|
||||
count = count + 1
|
||||
local meta = env:get_meta(pos):to_table()
|
||||
|
||||
--convert metadata itemstacks to itemstrings
|
||||
for name, inventory in pairs(meta.inventory) do
|
||||
for index, stack in ipairs(inventory) do
|
||||
inventory[index] = stack:to_string()
|
||||
end
|
||||
end
|
||||
|
||||
result[count] = {
|
||||
x = pos.x - pos1.x,
|
||||
y = pos.y - pos1.y,
|
||||
z = pos.z - pos1.z,
|
||||
name = node.name,
|
||||
param1 = node.param1,
|
||||
param2 = node.param2,
|
||||
meta = meta,
|
||||
}
|
||||
end
|
||||
pos.z = pos.z + 1
|
||||
end
|
||||
pos.y = pos.y + 1
|
||||
end
|
||||
pos.x = pos.x + 1
|
||||
end
|
||||
result = minetest.serialize(result) --convert entries to a string
|
||||
return result, count
|
||||
end
|
||||
|
||||
--determines the volume the nodes represented by string `value` would occupy if deserialized at `originpos`, returning the two corner positions and the number of nodes
|
||||
--contains code based on [table.save/table.load](http://lua-users.org/wiki/SaveTableToFile) by ChillCode, available under the MIT license (GPL compatible)
|
||||
worldedit.allocate = function(originpos, value)
|
||||
local huge = math.huge
|
||||
local pos1x, pos1y, pos1z = huge, huge, huge
|
||||
local pos2x, pos2y, pos2z = -huge, -huge, -huge
|
||||
local originx, originy, originz = originpos.x, originpos.y, originpos.z
|
||||
local count = 0
|
||||
local version = worldedit.valueversion(value)
|
||||
if version == 1 or version == 2 then --flat table format
|
||||
--obtain the node table
|
||||
local get_tables = loadstring(value)
|
||||
if get_tables then --error loading value
|
||||
return originpos, originpos, count
|
||||
end
|
||||
local tables = get_tables()
|
||||
|
||||
--transform the node table into an array of nodes
|
||||
for i = 1, #tables do
|
||||
for j, v in pairs(tables[i]) do
|
||||
if type(v) == "table" then
|
||||
tables[i][j] = tables[v[1]]
|
||||
end
|
||||
end
|
||||
end
|
||||
local nodes = tables[1]
|
||||
|
||||
--check the node array
|
||||
count = #nodes
|
||||
if version == 1 then --original flat table format
|
||||
for index = 1, count do
|
||||
local entry = nodes[index]
|
||||
local pos = entry[1]
|
||||
local x, y, z = originx - pos.x, originy - pos.y, originz - pos.z
|
||||
if x < pos1x then pos1x = x end
|
||||
if y < pos1y then pos1y = y end
|
||||
if z < pos1z then pos1z = z end
|
||||
if x > pos2x then pos2x = x end
|
||||
if y > pos2y then pos2y = y end
|
||||
if z > pos2z then pos2z = z end
|
||||
end
|
||||
else --previous meta flat table format
|
||||
for index = 1, count do
|
||||
local entry = nodes[index]
|
||||
local x, y, z = originx - entry.x, originy - entry.y, originz - entry.z
|
||||
if x < pos1x then pos1x = x end
|
||||
if y < pos1y then pos1y = y end
|
||||
if z < pos1z then pos1z = z end
|
||||
if x > pos2x then pos2x = x end
|
||||
if y > pos2y then pos2y = y end
|
||||
if z > pos2z then pos2z = z end
|
||||
end
|
||||
end
|
||||
elseif version == 3 then --previous list format
|
||||
for x, y, z, name, param1, param2 in value:gmatch("([+-]?%d+)%s+([+-]?%d+)%s+([+-]?%d+)%s+([^%s]+)%s+(%d+)%s+(%d+)[^\r\n]*[\r\n]*") do --match node entries
|
||||
x, y, z = originx + tonumber(x), originy + tonumber(y), originz + tonumber(z)
|
||||
if x < pos1x then pos1x = x end
|
||||
if y < pos1y then pos1y = y end
|
||||
if z < pos1z then pos1z = z end
|
||||
if x > pos2x then pos2x = x end
|
||||
if y > pos2y then pos2y = y end
|
||||
if z > pos2z then pos2z = z end
|
||||
count = count + 1
|
||||
end
|
||||
elseif version == 4 then --current nested table format
|
||||
local nodes = minetest.deserialize(value)
|
||||
count = #nodes
|
||||
for index = 1, count do
|
||||
local entry = nodes[index]
|
||||
x, y, z = originx + entry.x, originy + entry.y, originz + entry.z
|
||||
if x < pos1x then pos1x = x end
|
||||
if y < pos1y then pos1y = y end
|
||||
if z < pos1z then pos1z = z end
|
||||
if x > pos2x then pos2x = x end
|
||||
if y > pos2y then pos2y = y end
|
||||
if z > pos2z then pos2z = z end
|
||||
end
|
||||
end
|
||||
local pos1 = {x=pos1x, y=pos1y, z=pos1z}
|
||||
local pos2 = {x=pos2x, y=pos2y, z=pos2z}
|
||||
return pos1, pos2, count
|
||||
end
|
||||
|
||||
--loads the nodes represented by string `value` at position `originpos`, returning the number of nodes deserialized
|
||||
--contains code based on [table.save/table.load](http://lua-users.org/wiki/SaveTableToFile) by ChillCode, available under the MIT license (GPL compatible)
|
||||
worldedit.deserialize = function(originpos, value, env)
|
||||
local originx, originy, originz = originpos.x, originpos.y, originpos.z
|
||||
local count = 0
|
||||
if env == nil then env = minetest.env end
|
||||
local version = worldedit.valueversion(value)
|
||||
if version == 1 or version == 2 then --original flat table format
|
||||
--obtain the node table
|
||||
local get_tables = loadstring(value)
|
||||
if not get_tables then --error loading value
|
||||
return count
|
||||
end
|
||||
local tables = get_tables()
|
||||
|
||||
--transform the node table into an array of nodes
|
||||
for i = 1, #tables do
|
||||
for j, v in pairs(tables[i]) do
|
||||
if type(v) == "table" then
|
||||
tables[i][j] = tables[v[1]]
|
||||
end
|
||||
end
|
||||
end
|
||||
local nodes = tables[1]
|
||||
|
||||
--load the node array
|
||||
count = #nodes
|
||||
if version == 1 then --original flat table format
|
||||
for index = 1, count do
|
||||
local entry = nodes[index]
|
||||
local pos = entry[1]
|
||||
pos.x, pos.y, pos.z = originx - pos.x, originy - pos.y, originz - pos.z
|
||||
env:add_node(pos, entry[2])
|
||||
end
|
||||
else --previous meta flat table format
|
||||
for index = 1, #nodes do
|
||||
local entry = nodes[index]
|
||||
entry.x, entry.y, entry.z = originx + entry.x, originy + entry.y, originz + entry.z
|
||||
env:add_node(entry, entry) --entry acts both as position and as node
|
||||
env:get_meta(entry):from_table(entry.meta)
|
||||
end
|
||||
end
|
||||
elseif version == 3 then --previous list format
|
||||
local pos = {x=0, y=0, z=0}
|
||||
local node = {name="", param1=0, param2=0}
|
||||
for x, y, z, name, param1, param2 in value:gmatch("([+-]?%d+)%s+([+-]?%d+)%s+([+-]?%d+)%s+([^%s]+)%s+(%d+)%s+(%d+)[^\r\n]*[\r\n]*") do --match node entries
|
||||
pos.x = originx + tonumber(x)
|
||||
pos.y = originy + tonumber(y)
|
||||
pos.z = originz + tonumber(z)
|
||||
node.name = name
|
||||
node.param1 = param1
|
||||
node.param2 = param2
|
||||
env:add_node(pos, node)
|
||||
count = count + 1
|
||||
end
|
||||
elseif version == 4 then --current nested table format
|
||||
--wip: this is a filthy hack that works surprisingly well
|
||||
value = value:gsub("return%s*{", "", 1):gsub("}%s*$", "", 1)
|
||||
local escaped = value:gsub("\\\\", "@@"):gsub("\\\"", "@@"):gsub("(\"[^\"]+\")", function(s) return string.rep("@", #s) end)
|
||||
local startpos, startpos1, endpos = 1, 1
|
||||
local nodes = {}
|
||||
while true do
|
||||
startpos, endpos = escaped:find("},%s*{", startpos)
|
||||
if not startpos then
|
||||
break
|
||||
end
|
||||
local current = value:sub(startpos1, startpos)
|
||||
table.insert(nodes, minetest.deserialize("return " .. current))
|
||||
startpos, startpos1 = endpos, endpos
|
||||
end
|
||||
|
||||
--local nodes = minetest.deserialize(value) --wip: this is broken for larger tables in the current version of LuaJIT
|
||||
count = #nodes
|
||||
for index = 1, count do
|
||||
local entry = nodes[index]
|
||||
entry.x, entry.y, entry.z = originx + entry.x, originy + entry.y, originz + entry.z
|
||||
env:add_node(entry, entry) --entry acts both as position and as node
|
||||
env:get_meta(entry):from_table(entry.meta)
|
||||
end
|
||||
end
|
||||
return count
|
||||
end
|
164
worldedit/visualization.lua
Normal file
164
worldedit/visualization.lua
Normal file
@ -0,0 +1,164 @@
|
||||
worldedit = worldedit or {}
|
||||
|
||||
--modifies positions `pos1` and `pos2` so that each component of `pos1` is less than or equal to its corresponding conent of `pos2`, returning two new positions
|
||||
worldedit.sort_pos = function(pos1, pos2)
|
||||
pos1 = {x=pos1.x, y=pos1.y, z=pos1.z}
|
||||
pos2 = {x=pos2.x, y=pos2.y, z=pos2.z}
|
||||
if pos1.x > pos2.x then
|
||||
pos2.x, pos1.x = pos1.x, pos2.x
|
||||
end
|
||||
if pos1.y > pos2.y then
|
||||
pos2.y, pos1.y = pos1.y, pos2.y
|
||||
end
|
||||
if pos1.z > pos2.z then
|
||||
pos2.z, pos1.z = pos1.z, pos2.z
|
||||
end
|
||||
return pos1, pos2
|
||||
end
|
||||
|
||||
--determines the volume of the region defined by positions `pos1` and `pos2`, returning the volume
|
||||
worldedit.volume = function(pos1, pos2)
|
||||
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||
return (pos2.x - pos1.x + 1) * (pos2.y - pos1.y + 1) * (pos2.z - pos1.z + 1)
|
||||
end
|
||||
|
||||
minetest.register_node("worldedit:placeholder", {
|
||||
drawtype = "airlike",
|
||||
paramtype = "light",
|
||||
sunlight_propagates = true,
|
||||
diggable = false,
|
||||
groups = {not_in_creative_inventory=1},
|
||||
})
|
||||
|
||||
--hides all nodes in a region defined by positions `pos1` and `pos2` by non-destructively replacing them with invisible nodes, returning the number of nodes hidden
|
||||
worldedit.hide = function(pos1, pos2, tenv)
|
||||
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||
if env == nil then env = minetest.env end
|
||||
|
||||
local pos = {x=pos1.x, y=0, z=0}
|
||||
local placeholder = {name="worldedit:placeholder", param1=0, param2=0}
|
||||
while pos.x <= pos2.x do
|
||||
pos.y = pos1.y
|
||||
while pos.y <= pos2.y do
|
||||
pos.z = pos1.z
|
||||
while pos.z <= pos2.z do
|
||||
local node = env:get_node(pos)
|
||||
placeholder.param1, placeholder.param2 = node.param1, node.param2 --copy node's param1 and param2
|
||||
local data = env:get_meta(pos):to_table() --obtain metadata of original node
|
||||
env:add_node(pos, placeholder) --add placeholder node
|
||||
local meta = env:get_meta(pos) --obtain placeholder meta
|
||||
meta:from_table(data) --set placeholder metadata to the original node's metadata
|
||||
meta:set_string("worldedit_placeholder", node.name) --add the node's name
|
||||
pos.z = pos.z + 1
|
||||
end
|
||||
pos.y = pos.y + 1
|
||||
end
|
||||
pos.x = pos.x + 1
|
||||
end
|
||||
return worldedit.volume(pos1, pos2)
|
||||
end
|
||||
|
||||
--suppresses all instances of `nodename` in a region defined by positions `pos1` and `pos2` by non-destructively replacing them with invisible nodes, returning the number of nodes suppressed
|
||||
worldedit.suppress = function(pos1, pos2, nodename, tenv)
|
||||
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||
if env == nil then env = minetest.env end
|
||||
|
||||
if minetest.registered_nodes[nodename] == nil then
|
||||
nodename = "default:" .. nodename
|
||||
end
|
||||
|
||||
local pos = {x=pos1.x, y=0, z=0}
|
||||
local placeholder = {name="worldedit:placeholder", param1=0, param2=0}
|
||||
local count = 0
|
||||
while pos.x <= pos2.x do
|
||||
pos.y = pos1.y
|
||||
while pos.y <= pos2.y do
|
||||
pos.z = pos1.z
|
||||
while pos.z <= pos2.z do
|
||||
local node = env:get_node(pos)
|
||||
if node.name == nodename then
|
||||
placeholder.param1, placeholder.param2 = node.param1, node.param2 --copy node's param1 and param2
|
||||
local data = env:get_meta(pos):to_table() --obtain metadata of original node
|
||||
env:add_node(pos, placeholder) --add placeholder node
|
||||
local meta = env:get_meta(pos) --obtain placeholder meta
|
||||
meta:from_table(data) --set placeholder metadata to the original node's metadata
|
||||
meta:set_string("worldedit_placeholder", nodename) --add the node's name
|
||||
count = count + 1
|
||||
end
|
||||
pos.z = pos.z + 1
|
||||
end
|
||||
pos.y = pos.y + 1
|
||||
end
|
||||
pos.x = pos.x + 1
|
||||
end
|
||||
return count
|
||||
end
|
||||
|
||||
--highlights all instances of `nodename` in a region defined by positions `pos1` and `pos2` by non-destructively hiding all other nodes, returning the number of nodes found
|
||||
worldedit.highlight = function(pos1, pos2, nodename, tenv)
|
||||
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||
if env == nil then env = minetest.env end
|
||||
|
||||
if minetest.registered_nodes[nodename] == nil then
|
||||
nodename = "default:" .. nodename
|
||||
end
|
||||
|
||||
local pos = {x=pos1.x, y=0, z=0}
|
||||
local placeholder = {name="worldedit:placeholder", param1=0, param2=0}
|
||||
local count = 0
|
||||
while pos.x <= pos2.x do
|
||||
pos.y = pos1.y
|
||||
while pos.y <= pos2.y do
|
||||
pos.z = pos1.z
|
||||
while pos.z <= pos2.z do
|
||||
local node = env:get_node(pos)
|
||||
if node.name == nodename then --node found
|
||||
count = count + 1
|
||||
else --hide other nodes
|
||||
placeholder.param1, placeholder.param2 = node.param1, node.param2 --copy node's param1 and param2
|
||||
local data = env:get_meta(pos):to_table() --obtain metadata of original node
|
||||
env:add_node(pos, placeholder) --add placeholder node
|
||||
local meta = env:get_meta(pos) --obtain placeholder meta
|
||||
meta:from_table(data) --set placeholder metadata to the original node's metadata
|
||||
meta:set_string("worldedit_placeholder", node.name) --add the node's name
|
||||
end
|
||||
pos.z = pos.z + 1
|
||||
end
|
||||
pos.y = pos.y + 1
|
||||
end
|
||||
pos.x = pos.x + 1
|
||||
end
|
||||
return count
|
||||
end
|
||||
|
||||
--restores all nodes hidden with WorldEdit functions in a region defined by positions `pos1` and `pos2`, returning the number of nodes restored
|
||||
worldedit.restore = function(pos1, pos2, tenv)
|
||||
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||
if env == nil then env = minetest.env end
|
||||
|
||||
local pos = {x=pos1.x, y=0, z=0}
|
||||
local node = {name="", param1=0, param2=0}
|
||||
local count = 0
|
||||
while pos.x <= pos2.x do
|
||||
pos.y = pos1.y
|
||||
while pos.y <= pos2.y do
|
||||
pos.z = pos1.z
|
||||
while pos.z <= pos2.z do
|
||||
local currentnode = env:get_node(pos)
|
||||
if currentnode.name == "worldedit:placeholder" then
|
||||
node.param1, node.param2 = currentnode.param1, currentnode.param2 --copy node's param1 and param2
|
||||
local data = env:get_meta(pos):to_table() --obtain node metadata
|
||||
node.name = data.fields.worldedit_placeholder --set node name
|
||||
data.fields.worldedit_placeholder = nil --delete old nodename
|
||||
env:add_node(pos, node) --add original node
|
||||
env:get_meta(pos):from_table(data) --set original node metadata
|
||||
count = count + 1
|
||||
end
|
||||
pos.z = pos.z + 1
|
||||
end
|
||||
pos.y = pos.y + 1
|
||||
end
|
||||
pos.x = pos.x + 1
|
||||
end
|
||||
return count
|
||||
end
|
1
worldedit_commands/depends.txt
Normal file
1
worldedit_commands/depends.txt
Normal file
@ -0,0 +1 @@
|
||||
worldedit
|
996
worldedit_commands/init.lua
Normal file
996
worldedit_commands/init.lua
Normal file
@ -0,0 +1,996 @@
|
||||
minetest.register_privilege("worldedit", "Can use WorldEdit commands")
|
||||
|
||||
worldedit.set_pos = {}
|
||||
|
||||
worldedit.pos1 = {}
|
||||
worldedit.pos2 = {}
|
||||
|
||||
dofile(minetest.get_modpath("worldedit_commands") .. "/mark.lua")
|
||||
|
||||
--determines whether `nodename` is a valid node name, returning a boolean
|
||||
worldedit.node_is_valid = function(nodename)
|
||||
return minetest.registered_nodes[nodename] ~= nil
|
||||
or minetest.registered_nodes["default:" .. nodename] ~= nil
|
||||
end
|
||||
|
||||
--determines the axis in which a player is facing, returning an axis ("x", "y", or "z") and the sign (1 or -1)
|
||||
worldedit.player_axis = function(name)
|
||||
local dir = minetest.env:get_player_by_name(name):get_look_dir()
|
||||
local x, y, z = math.abs(dir.x), math.abs(dir.y), math.abs(dir.z)
|
||||
if x > y then
|
||||
if x > z then
|
||||
return "x", dir.x > 0 and 1 or -1
|
||||
end
|
||||
elseif y > z then
|
||||
return "y", dir.y > 0 and 1 or -1
|
||||
end
|
||||
return "z", dir.z > 0 and 1 or -1
|
||||
end
|
||||
|
||||
minetest.register_chatcommand("/reset", {
|
||||
params = "",
|
||||
description = "Reset the region so that it is empty",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
worldedit.pos1[name] = nil
|
||||
worldedit.pos2[name] = nil
|
||||
worldedit.mark_pos1(name)
|
||||
worldedit.mark_pos2(name)
|
||||
minetest.chat_send_player(name, "WorldEdit region reset", false)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/mark", {
|
||||
params = "",
|
||||
description = "Show markers at the region positions",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
worldedit.mark_pos1(name)
|
||||
worldedit.mark_pos2(name)
|
||||
minetest.chat_send_player(name, "WorldEdit region marked", false)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/pos1", {
|
||||
params = "",
|
||||
description = "Set WorldEdit region position 1 to the player's location",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local pos = minetest.env:get_player_by_name(name):getpos()
|
||||
pos.x, pos.y, pos.z = math.floor(pos.x + 0.5), math.floor(pos.y + 0.5), math.floor(pos.z + 0.5)
|
||||
worldedit.pos1[name] = pos
|
||||
worldedit.mark_pos1(name)
|
||||
minetest.chat_send_player(name, "WorldEdit position 1 set to " .. minetest.pos_to_string(pos), false)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/pos2", {
|
||||
params = "",
|
||||
description = "Set WorldEdit region position 2 to the player's location",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local pos = minetest.env:get_player_by_name(name):getpos()
|
||||
pos.x, pos.y, pos.z = math.floor(pos.x + 0.5), math.floor(pos.y + 0.5), math.floor(pos.z + 0.5)
|
||||
worldedit.pos2[name] = pos
|
||||
worldedit.mark_pos2(name)
|
||||
minetest.chat_send_player(name, "WorldEdit position 2 set to " .. minetest.pos_to_string(pos), false)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/p", {
|
||||
params = "set/set1/set2/get",
|
||||
description = "Set WorldEdit region, WorldEdit position 1, or WorldEdit position 2 by punching nodes, or display the current WorldEdit region",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
if param == "set" then --set both WorldEdit positions
|
||||
worldedit.set_pos[name] = "pos1"
|
||||
minetest.chat_send_player(name, "Select positions by punching two nodes", false)
|
||||
elseif param == "set1" then --set WorldEdit position 1
|
||||
worldedit.set_pos[name] = "pos1only"
|
||||
minetest.chat_send_player(name, "Select position 1 by punching a node", false)
|
||||
elseif param == "set2" then --set WorldEdit position 2
|
||||
worldedit.set_pos[name] = "pos2"
|
||||
minetest.chat_send_player(name, "Select position 2 by punching a node", false)
|
||||
elseif param == "get" then --display current WorldEdit positions
|
||||
if worldedit.pos1[name] ~= nil then
|
||||
minetest.chat_send_player(name, "WorldEdit position 1: " .. minetest.pos_to_string(worldedit.pos1[name]), false)
|
||||
else
|
||||
minetest.chat_send_player(name, "WorldEdit position 1 not set", false)
|
||||
end
|
||||
if worldedit.pos2[name] ~= nil then
|
||||
minetest.chat_send_player(name, "WorldEdit position 2: " .. minetest.pos_to_string(worldedit.pos2[name]), false)
|
||||
else
|
||||
minetest.chat_send_player(name, "WorldEdit position 2 not set", false)
|
||||
end
|
||||
else
|
||||
minetest.chat_send_player(name, "Unknown subcommand: " .. param, false)
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_on_punchnode(function(pos, node, puncher)
|
||||
local name = puncher:get_player_name()
|
||||
if name ~= "" and worldedit.set_pos[name] ~= nil then --currently setting position
|
||||
if worldedit.set_pos[name] == "pos1" then --setting position 1
|
||||
worldedit.pos1[name] = pos
|
||||
worldedit.mark_pos1(name)
|
||||
worldedit.set_pos[name] = "pos2" --set position 2 on the next invocation
|
||||
minetest.chat_send_player(name, "WorldEdit position 1 set to " .. minetest.pos_to_string(pos), false)
|
||||
elseif worldedit.set_pos[name] == "pos1only" then --setting position 1 only
|
||||
worldedit.pos1[name] = pos
|
||||
worldedit.mark_pos1(name)
|
||||
worldedit.set_pos[name] = nil --finished setting positions
|
||||
minetest.chat_send_player(name, "WorldEdit position 1 set to " .. minetest.pos_to_string(pos), false)
|
||||
elseif worldedit.set_pos[name] == "pos2" then --setting position 2
|
||||
worldedit.pos2[name] = pos
|
||||
worldedit.mark_pos2(name)
|
||||
worldedit.set_pos[name] = nil --finished setting positions
|
||||
minetest.chat_send_player(name, "WorldEdit position 2 set to " .. minetest.pos_to_string(pos), false)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_chatcommand("/volume", {
|
||||
params = "",
|
||||
description = "Display the volume of the current WorldEdit region",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||
if pos1 == nil or pos2 == nil then
|
||||
minetest.chat_send_player(name, "No WorldEdit region selected", false)
|
||||
return
|
||||
end
|
||||
|
||||
local volume = worldedit.volume(pos1, pos2)
|
||||
minetest.chat_send_player(name, "Current WorldEdit region has a volume of " .. volume .. " nodes (" .. pos2.x - pos1.x .. "*" .. pos2.y - pos1.y .. "*" .. pos2.z - pos1.z .. ")", false)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/set", {
|
||||
params = "<node>",
|
||||
description = "Set the current WorldEdit region to <node>",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||
if pos1 == nil or pos2 == nil then
|
||||
minetest.chat_send_player(name, "No WorldEdit region selected", false)
|
||||
return
|
||||
end
|
||||
|
||||
if param == "" or not worldedit.node_is_valid(param) then
|
||||
minetest.chat_send_player(name, "Invalid node name: " .. param, false)
|
||||
return
|
||||
end
|
||||
|
||||
local tenv = minetest.env
|
||||
if worldedit.ENABLE_QUEUE then
|
||||
tenv = worldedit.quene_aliasenv
|
||||
end
|
||||
local count = worldedit.set(pos1, pos2, param, tenv)
|
||||
minetest.chat_send_player(name, count .. " nodes set", false)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/replace", {
|
||||
params = "<search node> <replace node>",
|
||||
description = "Replace all instances of <search node> with <replace node> in the current WorldEdit region",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||
if pos1 == nil or pos2 == nil then
|
||||
minetest.chat_send_player(name, "No WorldEdit region selected", false)
|
||||
return
|
||||
end
|
||||
|
||||
local found, _, searchnode, replacenode = param:find("^([^%s]+)%s+([^%s]+)$")
|
||||
if found == nil then
|
||||
minetest.chat_send_player(name, "Invalid usage: " .. param, false)
|
||||
return
|
||||
end
|
||||
if not worldedit.node_is_valid(searchnode) then
|
||||
minetest.chat_send_player(name, "Invalid search node name: " .. searchnode, false)
|
||||
return
|
||||
end
|
||||
if not worldedit.node_is_valid(replacenode) then
|
||||
minetest.chat_send_player(name, "Invalid replace node name: " .. replacenode, false)
|
||||
return
|
||||
end
|
||||
|
||||
local tenv = minetest.env
|
||||
if worldedit.ENABLE_QUEUE then
|
||||
tenv = worldedit.quene_aliasenv
|
||||
end
|
||||
local count = worldedit.replace(pos1, pos2, searchnode, replacenode, tenv)
|
||||
minetest.chat_send_player(name, count .. " nodes replaced", false)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/replaceinverse", {
|
||||
params = "<search node> <replace node>",
|
||||
description = "Replace all nodes other than <search node> with <replace node> in the current WorldEdit region",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||
if pos1 == nil or pos2 == nil then
|
||||
minetest.chat_send_player(name, "No WorldEdit region selected", false)
|
||||
return
|
||||
end
|
||||
|
||||
local found, _, searchnode, replacenode = param:find("^([^%s]+)%s+([^%s]+)$")
|
||||
if found == nil then
|
||||
minetest.chat_send_player(name, "Invalid usage: " .. param, false)
|
||||
return
|
||||
end
|
||||
if not worldedit.node_is_valid(searchnode) then
|
||||
minetest.chat_send_player(name, "Invalid search node name: " .. searchnode, false)
|
||||
return
|
||||
end
|
||||
if not worldedit.node_is_valid(replacenode) then
|
||||
minetest.chat_send_player(name, "Invalid replace node name: " .. replacenode, false)
|
||||
return
|
||||
end
|
||||
|
||||
local tenv = minetest.env
|
||||
if worldedit.ENABLE_QUEUE then
|
||||
tenv = worldedit.quene_aliasenv
|
||||
end
|
||||
local count = worldedit.replaceinverse(pos1, pos2, searchnode, replacenode, tenv)
|
||||
minetest.chat_send_player(name, count .. " nodes replaced", false)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/hollowsphere", {
|
||||
params = "<radius> <node>",
|
||||
description = "Add hollow sphere at WorldEdit position 1 with radius <radius>, composed of <node>",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local pos = worldedit.pos1[name]
|
||||
if pos == nil then
|
||||
minetest.chat_send_player(name, "No WorldEdit region selected", false)
|
||||
return
|
||||
end
|
||||
|
||||
local found, _, radius, nodename = param:find("^(%d+)%s+([^%s]+)$")
|
||||
if found == nil then
|
||||
minetest.chat_send_player(name, "Invalid usage: " .. param, false)
|
||||
return
|
||||
end
|
||||
if not worldedit.node_is_valid(nodename) then
|
||||
minetest.chat_send_player(name, "Invalid node name: " .. param, false)
|
||||
return
|
||||
end
|
||||
|
||||
local tenv = minetest.env
|
||||
if worldedit.ENABLE_QUEUE then
|
||||
tenv = worldedit.quene_aliasenv
|
||||
end
|
||||
local count = worldedit.hollow_sphere(pos, tonumber(radius), nodename, tenv)
|
||||
minetest.chat_send_player(name, count .. " nodes added", false)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/sphere", {
|
||||
params = "<radius> <node>",
|
||||
description = "Add sphere at WorldEdit position 1 with radius <radius>, composed of <node>",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local pos = worldedit.pos1[name]
|
||||
if pos == nil then
|
||||
minetest.chat_send_player(name, "No WorldEdit region selected", false)
|
||||
return
|
||||
end
|
||||
|
||||
local found, _, radius, nodename = param:find("^(%d+)%s+([^%s]+)$")
|
||||
if found == nil then
|
||||
minetest.chat_send_player(name, "Invalid usage: " .. param, false)
|
||||
return
|
||||
end
|
||||
if not worldedit.node_is_valid(nodename) then
|
||||
minetest.chat_send_player(name, "Invalid node name: " .. param, false)
|
||||
return
|
||||
end
|
||||
|
||||
local tenv = minetest.env
|
||||
if worldedit.ENABLE_QUEUE then
|
||||
tenv = worldedit.quene_aliasenv
|
||||
end
|
||||
local count = worldedit.sphere(pos, tonumber(radius), nodename, tenv)
|
||||
minetest.chat_send_player(name, count .. " nodes added", false)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/hollowdome", {
|
||||
params = "<radius> <node>",
|
||||
description = "Add hollow dome at WorldEdit position 1 with radius <radius>, composed of <node>",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local pos = worldedit.pos1[name]
|
||||
if pos == nil then
|
||||
minetest.chat_send_player(name, "No WorldEdit region selected", false)
|
||||
return
|
||||
end
|
||||
|
||||
local found, _, radius, nodename = param:find("^(%d+)%s+([^%s]+)$")
|
||||
if found == nil then
|
||||
minetest.chat_send_player(name, "Invalid usage: " .. param, false)
|
||||
return
|
||||
end
|
||||
if not worldedit.node_is_valid(nodename) then
|
||||
minetest.chat_send_player(name, "Invalid node name: " .. param, false)
|
||||
return
|
||||
end
|
||||
|
||||
local tenv = minetest.env
|
||||
if worldedit.ENABLE_QUEUE then
|
||||
tenv = worldedit.quene_aliasenv
|
||||
end
|
||||
local count = worldedit.hollow_dome(pos, tonumber(radius), nodename, tenv)
|
||||
minetest.chat_send_player(name, count .. " nodes added", false)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/dome", {
|
||||
params = "<radius> <node>",
|
||||
description = "Add dome at WorldEdit position 1 with radius <radius>, composed of <node>",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local pos = worldedit.pos1[name]
|
||||
if pos == nil then
|
||||
minetest.chat_send_player(name, "No WorldEdit region selected", false)
|
||||
return
|
||||
end
|
||||
|
||||
local found, _, radius, nodename = param:find("^(%d+)%s+([^%s]+)$")
|
||||
if found == nil then
|
||||
minetest.chat_send_player(name, "Invalid usage: " .. param, false)
|
||||
return
|
||||
end
|
||||
if not worldedit.node_is_valid(nodename) then
|
||||
minetest.chat_send_player(name, "Invalid node name: " .. param, false)
|
||||
return
|
||||
end
|
||||
|
||||
local tenv = minetest.env
|
||||
if worldedit.ENABLE_QUEUE then
|
||||
tenv = worldedit.quene_aliasenv
|
||||
end
|
||||
local count = worldedit.dome(pos, tonumber(radius), nodename, tenv)
|
||||
minetest.chat_send_player(name, count .. " nodes added", false)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/hollowcylinder", {
|
||||
params = "x/y/z/? <length> <radius> <node>",
|
||||
description = "Add hollow cylinder at WorldEdit position 1 along the x/y/z/? axis with length <length> and radius <radius>, composed of <node>",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local pos = worldedit.pos1[name]
|
||||
if pos == nil then
|
||||
minetest.chat_send_player(name, "No WorldEdit region selected", false)
|
||||
return
|
||||
end
|
||||
|
||||
local found, _, axis, length, radius, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+([^%s]+)$")
|
||||
if found == nil then
|
||||
minetest.chat_send_player(name, "Invalid usage: " .. param, false)
|
||||
return
|
||||
end
|
||||
if axis == "?" then
|
||||
axis, sign = worldedit.player_axis(name)
|
||||
length = length * sign
|
||||
end
|
||||
if not worldedit.node_is_valid(nodename) then
|
||||
minetest.chat_send_player(name, "Invalid node name: " .. param, false)
|
||||
return
|
||||
end
|
||||
|
||||
local tenv = minetest.env
|
||||
if worldedit.ENABLE_QUEUE then
|
||||
tenv = worldedit.quene_aliasenv
|
||||
end
|
||||
local count = worldedit.hollow_cylinder(pos, axis, tonumber(length), tonumber(radius), nodename, tenv)
|
||||
minetest.chat_send_player(name, count .. " nodes added", false)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/cylinder", {
|
||||
params = "x/y/z/? <length> <radius> <node>",
|
||||
description = "Add cylinder at WorldEdit position 1 along the x/y/z/? axis with length <length> and radius <radius>, composed of <node>",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local pos = worldedit.pos1[name]
|
||||
if pos == nil then
|
||||
minetest.chat_send_player(name, "No WorldEdit region selected", false)
|
||||
return
|
||||
end
|
||||
|
||||
local found, _, axis, length, radius, nodename = param:find("^([xyz%?])%s+([+-]?%d+)%s+(%d+)%s+([^%s]+)$")
|
||||
if found == nil then
|
||||
minetest.chat_send_player(name, "Invalid usage: " .. param, false)
|
||||
return
|
||||
end
|
||||
if axis == "?" then
|
||||
axis, sign = worldedit.player_axis(name)
|
||||
length = length * sign
|
||||
end
|
||||
if not worldedit.node_is_valid(nodename) then
|
||||
minetest.chat_send_player(name, "Invalid node name: " .. param, false)
|
||||
return
|
||||
end
|
||||
|
||||
local tenv = minetest.env
|
||||
if worldedit.ENABLE_QUEUE then
|
||||
tenv = worldedit.quene_aliasenv
|
||||
end
|
||||
local count = worldedit.cylinder(pos, axis, tonumber(length), tonumber(radius), nodename, tenv)
|
||||
minetest.chat_send_player(name, count .. " nodes added", false)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/pyramid", {
|
||||
params = "<height> <node>",
|
||||
description = "Add pyramid at WorldEdit position 1 with height <height>, composed of <node>",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local pos = worldedit.pos1[name]
|
||||
if pos == nil then
|
||||
minetest.chat_send_player(name, "No WorldEdit region selected", false)
|
||||
return
|
||||
end
|
||||
|
||||
local found, _, size, nodename = param:find("(%d+)%s+([^%s]+)$")
|
||||
if found == nil then
|
||||
minetest.chat_send_player(name, "Invalid usage: " .. param, false)
|
||||
return
|
||||
end
|
||||
if not worldedit.node_is_valid(nodename) then
|
||||
minetest.chat_send_player(name, "Invalid node name: " .. param, false)
|
||||
return
|
||||
end
|
||||
|
||||
local tenv = minetest.env
|
||||
if worldedit.ENABLE_QUEUE then
|
||||
tenv = worldedit.quene_aliasenv
|
||||
end
|
||||
local count = worldedit.pyramid(pos, tonumber(size), nodename, tenv)
|
||||
minetest.chat_send_player(name, count .. " nodes added", false)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/spiral", {
|
||||
params = "<width> <height> <space> <node>",
|
||||
description = "Add spiral at WorldEdit position 1 with width <width>, height <height>, space between walls <space>, composed of <node>",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local pos = worldedit.pos1[name]
|
||||
if pos == nil then
|
||||
minetest.chat_send_player(name, "No WorldEdit region selected", false)
|
||||
return
|
||||
end
|
||||
|
||||
local found, _, width, height, space, nodename = param:find("(%d+)%s+(%d+)%s+(%d+)%s+([^%s]+)$")
|
||||
if found == nil then
|
||||
minetest.chat_send_player(name, "Invalid usage: " .. param, false)
|
||||
return
|
||||
end
|
||||
if not worldedit.node_is_valid(nodename) then
|
||||
minetest.chat_send_player(name, "Invalid node name: " .. param, false)
|
||||
return
|
||||
end
|
||||
|
||||
local tenv = minetest.env
|
||||
if worldedit.ENABLE_QUEUE then
|
||||
tenv = worldedit.quene_aliasenv
|
||||
end
|
||||
local count = worldedit.spiral(pos, tonumber(width), tonumber(height), tonumber(space), nodename, tenv)
|
||||
minetest.chat_send_player(name, count .. " nodes changed", false)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/copy", {
|
||||
params = "x/y/z/? <amount>",
|
||||
description = "Copy the current WorldEdit region along the x/y/z/? axis by <amount> nodes",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||
if pos1 == nil or pos2 == nil then
|
||||
minetest.chat_send_player(name, "No WorldEdit region selected", false)
|
||||
return
|
||||
end
|
||||
|
||||
local found, _, axis, amount = param:find("^([xyz%?])%s+([+-]?%d+)$")
|
||||
if found == nil then
|
||||
minetest.chat_send_player(name, "Invalid usage: " .. param, false)
|
||||
return
|
||||
end
|
||||
if axis == "?" then
|
||||
axis, sign = worldedit.player_axis(name)
|
||||
amount = amount * sign
|
||||
end
|
||||
|
||||
local tenv = minetest.env
|
||||
if worldedit.ENABLE_QUEUE then
|
||||
tenv = worldedit.quene_aliasenv
|
||||
end
|
||||
local count = worldedit.copy(pos1, pos2, axis, tonumber(amount), tenv)
|
||||
minetest.chat_send_player(name, count .. " nodes copied", false)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/move", {
|
||||
params = "x/y/z/? <amount>",
|
||||
description = "Move the current WorldEdit region along the x/y/z/? axis by <amount> nodes",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||
if pos1 == nil or pos2 == nil then
|
||||
minetest.chat_send_player(name, "No WorldEdit region selected", false)
|
||||
return
|
||||
end
|
||||
|
||||
local found, _, axis, amount = param:find("^([xyz%?])%s+([+-]?%d+)$")
|
||||
if found == nil then
|
||||
minetest.chat_send_player(name, "Invalid usage: " .. param, false)
|
||||
return
|
||||
end
|
||||
if axis == "?" then
|
||||
axis, sign = worldedit.player_axis(name)
|
||||
amount = amount * sign
|
||||
end
|
||||
|
||||
local count = worldedit.move(pos1, pos2, axis, tonumber(amount))
|
||||
|
||||
pos1[axis] = pos1[axis] + amount
|
||||
pos2[axis] = pos2[axis] + amount
|
||||
worldedit.mark_pos1(name)
|
||||
worldedit.mark_pos2(name)
|
||||
|
||||
local tenv = minetest.env
|
||||
if worldedit.ENABLE_QUEUE then
|
||||
tenv = worldedit.quene_aliasenv
|
||||
end
|
||||
local count = worldedit.copy(pos1, pos2, axis, tonumber(amount), tenv)
|
||||
minetest.chat_send_player(name, count .. " nodes moved", false)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/stack", {
|
||||
params = "x/y/z/? <count>",
|
||||
description = "Stack the current WorldEdit region along the x/y/z/? axis <count> times",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||
if pos1 == nil or pos2 == nil then
|
||||
minetest.chat_send_player(name, "No WorldEdit region selected", false)
|
||||
return
|
||||
end
|
||||
|
||||
local found, _, axis, count = param:find("^([xyz%?])%s+([+-]?%d+)$")
|
||||
if found == nil then
|
||||
minetest.chat_send_player(name, "Invalid usage: " .. param, false)
|
||||
return
|
||||
end
|
||||
if axis == "?" then
|
||||
axis, sign = worldedit.player_axis(name)
|
||||
count = count * sign
|
||||
end
|
||||
|
||||
local tenv = minetest.env
|
||||
if worldedit.ENABLE_QUEUE then
|
||||
tenv = worldedit.quene_aliasenv
|
||||
end
|
||||
local count = worldedit.stack(pos1, pos2, axis, tonumber(count), tenv)
|
||||
minetest.chat_send_player(name, count .. " nodes stacked", false)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/transpose", {
|
||||
params = "x/y/z/? x/y/z/?",
|
||||
description = "Transpose the current WorldEdit region along the x/y/z/? and x/y/z/? axes",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||
if pos1 == nil or pos2 == nil then
|
||||
minetest.chat_send_player(name, "No WorldEdit region selected", false)
|
||||
return
|
||||
end
|
||||
|
||||
local found, _, axis1, axis2 = param:find("^([xyz%?])%s+([xyz%?])$")
|
||||
if found == nil then
|
||||
minetest.chat_send_player(name, "Invalid usage: " .. param, false)
|
||||
return
|
||||
end
|
||||
if axis1 == "?" then
|
||||
axis1 = worldedit.player_axis(name)
|
||||
end
|
||||
if axis2 == "?" then
|
||||
axis2 = worldedit.player_axis(name)
|
||||
end
|
||||
if axis1 == axis2 then
|
||||
minetest.chat_send_player(name, "Invalid usage: axes are the same", false)
|
||||
return
|
||||
end
|
||||
|
||||
local tenv = minetest.env
|
||||
if worldedit.ENABLE_QUEUE then
|
||||
tenv = worldedit.quene_aliasenv
|
||||
end
|
||||
local count, pos1, pos2 = worldedit.transpose(pos1, pos2, axis1, axis2, tenv)
|
||||
|
||||
--reset markers to transposed positions
|
||||
worldedit.pos1[name] = pos1
|
||||
worldedit.pos2[name] = pos2
|
||||
worldedit.mark_pos1(name)
|
||||
worldedit.mark_pos2(name)
|
||||
|
||||
minetest.chat_send_player(name, count .. " nodes transposed", false)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/flip", {
|
||||
params = "x/y/z/?",
|
||||
description = "Flip the current WorldEdit region along the x/y/z/? axis",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||
if pos1 == nil or pos2 == nil then
|
||||
minetest.chat_send_player(name, "No WorldEdit region selected", false)
|
||||
return
|
||||
end
|
||||
|
||||
if param == "?" then
|
||||
param = worldedit.player_axis(name)
|
||||
end
|
||||
if param ~= "x" and param ~= "y" and param ~= "z" then
|
||||
minetest.chat_send_player(name, "Invalid usage: " .. param, false)
|
||||
return
|
||||
end
|
||||
|
||||
local tenv = minetest.env
|
||||
if worldedit.ENABLE_QUEUE then
|
||||
tenv = worldedit.quene_aliasenv
|
||||
end
|
||||
local count = worldedit.flip(pos1, pos2, param, tenv)
|
||||
minetest.chat_send_player(name, count .. " nodes flipped", false)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/rotate", {
|
||||
params = "<axis> <angle>",
|
||||
description = "Rotate the current WorldEdit region around the axis <axis> by angle <angle> (90 degree increment)",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||
if pos1 == nil or pos2 == nil then
|
||||
minetest.chat_send_player(name, "No WorldEdit region selected", false)
|
||||
return
|
||||
end
|
||||
|
||||
local found, _, axis, angle = param:find("^([xyz%?])%s+([+-]?%d+)$")
|
||||
if found == nil then
|
||||
minetest.chat_send_player(name, "Invalid usage: " .. param, false)
|
||||
return
|
||||
end
|
||||
if axis == "?" then
|
||||
axis = worldedit.player_axis(name)
|
||||
end
|
||||
if angle % 90 ~= 0 then
|
||||
minetest.chat_send_player(name, "Invalid usage: angle must be multiple of 90", false)
|
||||
return
|
||||
end
|
||||
|
||||
local tenv = minetest.env
|
||||
if worldedit.ENABLE_QUEUE then
|
||||
tenv = worldedit.quene_aliasenv
|
||||
end
|
||||
local count, pos1, pos2 = worldedit.rotate(pos1, pos2, axis, angle, tenv)
|
||||
|
||||
--reset markers to rotated positions
|
||||
worldedit.pos1[name] = pos1
|
||||
worldedit.pos2[name] = pos2
|
||||
worldedit.mark_pos1(name)
|
||||
worldedit.mark_pos2(name)
|
||||
|
||||
minetest.chat_send_player(name, count .. " nodes rotated", false)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/orient", {
|
||||
params = "<angle>",
|
||||
description = "Rotate oriented nodes in the current WorldEdit region around the Y axis by angle <angle> (90 degree increment)",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||
if pos1 == nil or pos2 == nil then
|
||||
minetest.chat_send_player(name, "No WorldEdit region selected", false)
|
||||
return
|
||||
end
|
||||
|
||||
local found, _, angle = param:find("^([+-]?%d+)$")
|
||||
if found == nil then
|
||||
minetest.chat_send_player(name, "Invalid usage: " .. param, false)
|
||||
return
|
||||
end
|
||||
if angle % 90 ~= 0 then
|
||||
minetest.chat_send_player(name, "Invalid usage: angle must be multiple of 90", false)
|
||||
return
|
||||
end
|
||||
|
||||
local tenv = minetest.env
|
||||
if worldedit.ENABLE_QUEUE then
|
||||
tenv = worldedit.quene_aliasenv
|
||||
end
|
||||
local count = worldedit.orient(pos1, pos2, angle, tenv)
|
||||
|
||||
minetest.chat_send_player(name, count .. " nodes oriented", false)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/fixlight", {
|
||||
params = "",
|
||||
description = "Fix the lighting in the current WorldEdit region",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||
if pos1 == nil or pos2 == nil then
|
||||
minetest.chat_send_player(name, "No WorldEdit region selected", false)
|
||||
return
|
||||
end
|
||||
|
||||
local tenv = minetest.env
|
||||
if worldedit.ENABLE_QUEUE then
|
||||
tenv = worldedit.quene_aliasenv
|
||||
end
|
||||
local count = worldedit.fixlight(pos1, pos2, tenv)
|
||||
minetest.chat_send_player(name, count .. " nodes updated", false)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/hide", {
|
||||
params = "",
|
||||
description = "Hide all nodes in the current WorldEdit region non-destructively",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||
if pos1 == nil or pos2 == nil then
|
||||
minetest.chat_send_player(name, "No WorldEdit region selected", false)
|
||||
return
|
||||
end
|
||||
|
||||
local tenv = minetest.env
|
||||
if worldedit.ENABLE_QUEUE then
|
||||
tenv = worldedit.quene_aliasenv
|
||||
end
|
||||
local count = worldedit.hide(pos1, pos2, tenv)
|
||||
minetest.chat_send_player(name, count .. " nodes hidden", false)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/suppress", {
|
||||
params = "<node>",
|
||||
description = "Suppress all <node> in the current WorldEdit region non-destructively",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||
if pos1 == nil or pos2 == nil then
|
||||
minetest.chat_send_player(name, "No WorldEdit region selected", false)
|
||||
return
|
||||
end
|
||||
|
||||
if param == "" or not worldedit.node_is_valid(param) then
|
||||
minetest.chat_send_player(name, "Invalid node name: " .. param, false)
|
||||
return
|
||||
end
|
||||
|
||||
local tenv = minetest.env
|
||||
if worldedit.ENABLE_QUEUE then
|
||||
tenv = worldedit.quene_aliasenv
|
||||
end
|
||||
local count = worldedit.suppress(pos1, pos2, param, tenv)
|
||||
minetest.chat_send_player(name, count .. " nodes suppressed", false)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/highlight", {
|
||||
params = "<node>",
|
||||
description = "Highlight <node> in the current WorldEdit region by hiding everything else non-destructively",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||
if pos1 == nil or pos2 == nil then
|
||||
minetest.chat_send_player(name, "No WorldEdit region selected", false)
|
||||
return
|
||||
end
|
||||
|
||||
if param == "" or not worldedit.node_is_valid(param) then
|
||||
minetest.chat_send_player(name, "Invalid node name: " .. param, false)
|
||||
return
|
||||
end
|
||||
|
||||
local tenv = minetest.env
|
||||
if worldedit.ENABLE_QUEUE then
|
||||
tenv = worldedit.quene_aliasenv
|
||||
end
|
||||
local count = worldedit.highlight(pos1, pos2, param, tenv)
|
||||
minetest.chat_send_player(name, count .. " nodes highlighted", false)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/restore", {
|
||||
params = "",
|
||||
description = "Restores nodes hidden with WorldEdit in the current WorldEdit region",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||
if pos1 == nil or pos2 == nil then
|
||||
minetest.chat_send_player(name, "No WorldEdit region selected", false)
|
||||
return
|
||||
end
|
||||
|
||||
local tenv = minetest.env
|
||||
if worldedit.ENABLE_QUEUE then
|
||||
tenv = worldedit.quene_aliasenv
|
||||
end
|
||||
local count = worldedit.restore(pos1, pos2, tenv)
|
||||
minetest.chat_send_player(name, count .. " nodes restored", false)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/save", {
|
||||
params = "<file>",
|
||||
description = "Save the current WorldEdit region to \"(world folder)/schems/<file>.we\"",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||
if pos1 == nil or pos2 == nil then
|
||||
minetest.chat_send_player(name, "No WorldEdit region selected", false)
|
||||
return
|
||||
end
|
||||
|
||||
if param == "" then
|
||||
minetest.chat_send_player(name, "Invalid usage: " .. param, false)
|
||||
return
|
||||
end
|
||||
|
||||
local result, count = worldedit.serialize(pos1, pos2)
|
||||
|
||||
local path = minetest.get_worldpath() .. "/schems"
|
||||
local filename = path .. "/" .. param .. ".we"
|
||||
os.execute("mkdir \"" .. path .. "\"") --create directory if it does not already exist
|
||||
local file, err = io.open(filename, "wb")
|
||||
if err ~= nil then
|
||||
minetest.chat_send_player(name, "Could not save file to \"" .. filename .. "\"", false)
|
||||
return
|
||||
end
|
||||
file:write(result)
|
||||
file:flush()
|
||||
file:close()
|
||||
|
||||
minetest.chat_send_player(name, count .. " nodes saved", false)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/allocate", {
|
||||
params = "<file>",
|
||||
description = "Set the region defined by nodes from \"(world folder)/schems/<file>.we\" as the current WorldEdit region",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local pos1 = worldedit.pos1[name]
|
||||
if pos1 == nil then
|
||||
minetest.chat_send_player(name, "No WorldEdit region selected", false)
|
||||
return
|
||||
end
|
||||
|
||||
if param == "" then
|
||||
minetest.chat_send_player(name, "Invalid usage: " .. param, false)
|
||||
return
|
||||
end
|
||||
|
||||
local filename = minetest.get_worldpath() .. "/schems/" .. param .. ".we"
|
||||
local file, err = io.open(filename, "rb")
|
||||
if err ~= nil then
|
||||
minetest.chat_send_player(name, "Could not open file \"" .. filename .. "\"", false)
|
||||
return
|
||||
end
|
||||
local value = file:read("*a")
|
||||
file:close()
|
||||
|
||||
if worldedit.valueversion(value) == 0 then --unknown version
|
||||
minetest.chat_send_player(name, "Invalid file: file is invalid or created with newer version of WorldEdit", false)
|
||||
return
|
||||
end
|
||||
local nodepos1, nodepos2, count = worldedit.allocate(pos1, value)
|
||||
|
||||
worldedit.pos1[name] = nodepos1
|
||||
worldedit.mark_pos1(name)
|
||||
worldedit.pos2[name] = nodepos2
|
||||
worldedit.mark_pos2(name)
|
||||
|
||||
minetest.chat_send_player(name, count .. " nodes allocated", false)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/load", {
|
||||
params = "<file>",
|
||||
description = "Load nodes from \"(world folder)/schems/<file>[.we[m]]\" with position 1 of the current WorldEdit region as the origin",
|
||||
privs = {worldedit=true},
|
||||
func = function(name, param)
|
||||
local pos1 = worldedit.pos1[name]
|
||||
if pos1 == nil then
|
||||
minetest.chat_send_player(name, "No WorldEdit region selected", false)
|
||||
return
|
||||
end
|
||||
|
||||
if param == "" then
|
||||
minetest.chat_send_player(name, "Invalid usage: " .. param, false)
|
||||
return
|
||||
end
|
||||
|
||||
--find the file in the world path
|
||||
local testpaths = {
|
||||
minetest.get_worldpath() .. "/schems/" .. param,
|
||||
minetest.get_worldpath() .. "/schems/" .. param .. ".we",
|
||||
minetest.get_worldpath() .. "/schems/" .. param .. ".wem",
|
||||
}
|
||||
local file, err
|
||||
for index, path in ipairs(testpaths) do
|
||||
file, err = io.open(path, "rb")
|
||||
if not err then
|
||||
break
|
||||
end
|
||||
end
|
||||
if err then
|
||||
minetest.chat_send_player(name, "Could not open file \"" .. param .. "\"", false)
|
||||
return
|
||||
end
|
||||
local value = file:read("*a")
|
||||
file:close()
|
||||
|
||||
if worldedit.valueversion(value) == 0 then --unknown version
|
||||
minetest.chat_send_player(name, "Invalid file: file is invalid or created with newer version of WorldEdit", false)
|
||||
return
|
||||
end
|
||||
|
||||
local tenv = minetest.env
|
||||
if worldedit.ENABLE_QUEUE then
|
||||
tenv = worldedit.quene_aliasenv
|
||||
end
|
||||
local count = worldedit.deserialize(pos1, value, tenv)
|
||||
|
||||
minetest.chat_send_player(name, count .. " nodes loaded", false)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/lua", {
|
||||
params = "<code>",
|
||||
description = "Executes <code> as a Lua chunk in the global namespace",
|
||||
privs = {worldedit=true, server=true},
|
||||
func = function(name, param)
|
||||
local err = worldedit.lua(param)
|
||||
if err then
|
||||
minetest.chat_send_player(name, "Code error: " .. err, false)
|
||||
else
|
||||
minetest.chat_send_player(name, "Code successfully executed", false)
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("/luatransform", {
|
||||
params = "<code>",
|
||||
description = "Executes <code> as a Lua chunk in the global namespace with the variable pos available, for each node in the current WorldEdit region",
|
||||
privs = {worldedit=true, server=true},
|
||||
func = function(name, param)
|
||||
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||
if pos1 == nil or pos2 == nil then
|
||||
minetest.chat_send_player(name, "No WorldEdit region selected", false)
|
||||
return
|
||||
end
|
||||
|
||||
local err = worldedit.luatransform(pos1, pos2, param)
|
||||
if err then
|
||||
minetest.chat_send_player(name, "Code error: " .. err, false)
|
||||
else
|
||||
minetest.chat_send_player(name, "Code successfully executed", false)
|
||||
end
|
||||
end,
|
||||
})
|
@ -10,6 +10,7 @@ worldedit.mark_pos1 = function(name)
|
||||
end
|
||||
if pos ~= nil then --add marker
|
||||
worldedit.marker1[name] = minetest.env:add_entity(pos, "worldedit:pos1")
|
||||
worldedit.marker1[name]:get_luaentity().active = true
|
||||
end
|
||||
end
|
||||
|
||||
@ -22,10 +23,11 @@ worldedit.mark_pos2 = function(name)
|
||||
end
|
||||
if pos ~= nil then --add marker
|
||||
worldedit.marker2[name] = minetest.env:add_entity(pos, "worldedit:pos2")
|
||||
worldedit.marker2[name]:get_luaentity().active = true
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_entity("worldedit:pos1", {
|
||||
minetest.register_entity(":worldedit:pos1", {
|
||||
initial_properties = {
|
||||
visual = "cube",
|
||||
visual_size = {x=1.1, y=1.1},
|
||||
@ -34,6 +36,11 @@ minetest.register_entity("worldedit:pos1", {
|
||||
"worldedit_pos1.png", "worldedit_pos1.png"},
|
||||
collisionbox = {-0.55, -0.55, -0.55, 0.55, 0.55, 0.55},
|
||||
},
|
||||
on_step = function(self, dtime)
|
||||
if self.active == nil then
|
||||
self.object:remove()
|
||||
end
|
||||
end,
|
||||
on_punch = function(self, hitter)
|
||||
self.object:remove()
|
||||
local name = hitter:get_player_name()
|
||||
@ -41,7 +48,7 @@ minetest.register_entity("worldedit:pos1", {
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_entity("worldedit:pos2", {
|
||||
minetest.register_entity(":worldedit:pos2", {
|
||||
initial_properties = {
|
||||
visual = "cube",
|
||||
visual_size = {x=1.1, y=1.1},
|
||||
@ -50,6 +57,11 @@ minetest.register_entity("worldedit:pos2", {
|
||||
"worldedit_pos2.png", "worldedit_pos2.png"},
|
||||
collisionbox = {-0.55, -0.55, -0.55, 0.55, 0.55, 0.55},
|
||||
},
|
||||
on_step = function(self, dtime)
|
||||
if self.active == nil then
|
||||
self.object:remove()
|
||||
end
|
||||
end,
|
||||
on_punch = function(self, hitter)
|
||||
self.object:remove()
|
||||
local name = hitter:get_player_name()
|
Before Width: | Height: | Size: 142 B After Width: | Height: | Size: 142 B |
Before Width: | Height: | Size: 157 B After Width: | Height: | Size: 157 B |
Reference in New Issue
Block a user