mirror of
https://github.com/Uberi/Minetest-WorldEdit.git
synced 2025-06-29 22:50:46 +02:00
Compare commits
104 Commits
Author | SHA1 | Date | |
---|---|---|---|
03327a767d | |||
8bd5db51b2 | |||
416ffb3709 | |||
040282bbe6 | |||
b0bf52e9b6 | |||
3c51ec8c4a | |||
49b683f27f | |||
c1f3cfc1e4 | |||
b252df2166 | |||
7e1be63344 | |||
faa4a7b065 | |||
8b9054a1cc | |||
dfcf02bbc2 | |||
0fddd17f23 | |||
e550604747 | |||
8ebf9d3c2a | |||
ac5e801834 | |||
b6bc841c39 | |||
48009b6c62 | |||
9db6192eba | |||
1e5f623cbb | |||
58970e7fab | |||
7070f81c59 | |||
a192d51a58 | |||
d4187866db | |||
74018dab99 | |||
f1cfc47189 | |||
0664cde287 | |||
f952ee4740 | |||
a1dcc43210 | |||
d7ae19b7b8 | |||
52c1379bce | |||
d52f3d649e | |||
cedecac3f8 | |||
18bc4e6815 | |||
9e1c2614d3 | |||
98c5bc5c5f | |||
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 |
332
Chat Commands.md
Normal file
332
Chat Commands.md
Normal file
@ -0,0 +1,332 @@
|
|||||||
|
Chat Commands
|
||||||
|
-------------
|
||||||
|
For more information, see the [README](README.md).
|
||||||
|
|
||||||
|
### //inspect
|
||||||
|
|
||||||
|
Enable or disable node inspection.
|
||||||
|
|
||||||
|
//inspect on
|
||||||
|
//inspect off
|
||||||
|
//inspect 1
|
||||||
|
//inspect 0
|
||||||
|
//inspect true
|
||||||
|
//inspect false
|
||||||
|
//inspect yes
|
||||||
|
//inspect no
|
||||||
|
//inspect enable
|
||||||
|
//inspect disable
|
||||||
|
|
||||||
|
### //reset
|
||||||
|
|
||||||
|
Reset the region so that it is empty.
|
||||||
|
|
||||||
|
//reset
|
||||||
|
|
||||||
|
### //mark
|
||||||
|
|
||||||
|
Show markers at the region positions.
|
||||||
|
|
||||||
|
//mark
|
||||||
|
|
||||||
|
### //unmark
|
||||||
|
|
||||||
|
Hide markers if currently shown.
|
||||||
|
|
||||||
|
//unmark
|
||||||
|
|
||||||
|
### //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
|
||||||
|
|
||||||
|
### //fixedpos set1 x y z
|
||||||
|
|
||||||
|
Set a WorldEdit region position to the position at (<x>, <y>, <z>).
|
||||||
|
|
||||||
|
//fixedpos set1 0, 0, 0
|
||||||
|
//fixedpos set1 -30, 5, 28
|
||||||
|
//fixedpos set2 1004, -200, 432
|
||||||
|
|
||||||
|
### //volume
|
||||||
|
|
||||||
|
Display the volume of the current WorldEdit region.
|
||||||
|
|
||||||
|
//volume
|
||||||
|
|
||||||
|
### //set <node>
|
||||||
|
|
||||||
|
Set the current WorldEdit region to <node>.
|
||||||
|
|
||||||
|
//set air
|
||||||
|
//set cactus
|
||||||
|
//set Bronze Block
|
||||||
|
//set mesecons:wire_00000000_off
|
||||||
|
|
||||||
|
### //replace <search node> <replace node>
|
||||||
|
|
||||||
|
Replace all instances of <search node> with <replace node> in the current WorldEdit region.
|
||||||
|
|
||||||
|
//replace Cobblestone air
|
||||||
|
//replace lightstone_blue glass
|
||||||
|
//replace dirt Bronze Block
|
||||||
|
//replace mesecons:wire_00000000_off flowers:flower_tulip
|
||||||
|
|
||||||
|
### //replaceinverse <search node> <replace node>
|
||||||
|
|
||||||
|
Replace all nodes other than <search node> with <replace node> in the current WorldEdit region.
|
||||||
|
|
||||||
|
//replaceinverse Cobblestone air
|
||||||
|
//replaceinverse flowers:flower_waterlily glass
|
||||||
|
//replaceinverse dirt Bronze Block
|
||||||
|
//replaceinverse mesecons:wire_00000000_off flowers:flower_tulip
|
||||||
|
|
||||||
|
### //hollowsphere <radius> <node>
|
||||||
|
|
||||||
|
Add hollow sphere centered at WorldEdit position 1 with radius <radius>, composed of <node>.
|
||||||
|
|
||||||
|
//hollowsphere 5 Diamond Block
|
||||||
|
//hollowsphere 12 glass
|
||||||
|
//hollowsphere 17 mesecons:wire_00000000_off
|
||||||
|
|
||||||
|
### //sphere <radius> <node>
|
||||||
|
|
||||||
|
Add sphere centered at WorldEdit position 1 with radius <radius>, composed of <node>.
|
||||||
|
|
||||||
|
//sphere 5 Diamond Block
|
||||||
|
//sphere 12 glass
|
||||||
|
//sphere 17 mesecons:wire_00000000_off
|
||||||
|
|
||||||
|
### //hollowdome <radius> <node>
|
||||||
|
|
||||||
|
Add hollow dome centered at WorldEdit position 1 with radius <radius>, composed of <node>.
|
||||||
|
|
||||||
|
//hollowdome 5 Diamond Block
|
||||||
|
//hollowdome -12 glass
|
||||||
|
//hollowdome 17 mesecons:wire_00000000_off
|
||||||
|
|
||||||
|
### //dome <radius> <node>
|
||||||
|
|
||||||
|
Add dome centered at WorldEdit position 1 with radius <radius>, composed of <node>.
|
||||||
|
|
||||||
|
//dome 5 Diamond Block
|
||||||
|
//dome -12 glass
|
||||||
|
//dome 17 mesecons:wire_00000000_off
|
||||||
|
|
||||||
|
### //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 Bronze Block
|
||||||
|
//hollowcylinder y 28 10 glass
|
||||||
|
//hollowcylinder z -12 3 mesecons:wire_00000000_off
|
||||||
|
//hollowcylinder ? 2 4 default: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 Bronze Block
|
||||||
|
//cylinder y 28 10 glass
|
||||||
|
//cylinder z -12 3 mesecons:wire_00000000_off
|
||||||
|
//cylinder ? 2 4 default:stone
|
||||||
|
|
||||||
|
### //pyramid x/y/z? <height> <node>
|
||||||
|
|
||||||
|
Add pyramid centered at WorldEdit position 1 along the x/y/z/? axis with height <height>, composed of <node>.
|
||||||
|
|
||||||
|
//pyramid x 8 Diamond Block
|
||||||
|
//pyramid y -5 glass
|
||||||
|
//pyramid z 2 mesecons:wire_00000000_off
|
||||||
|
//pyramid ? 12 mesecons:wire_00000000_off
|
||||||
|
|
||||||
|
### //spiral <length> <height> <spacer> <node>
|
||||||
|
|
||||||
|
Add spiral centered at WorldEdit position 1 with side length <length>, height <height>, space between walls <spacer>, composed of <node>.
|
||||||
|
|
||||||
|
//spiral 20 5 3 Diamond Block
|
||||||
|
//spiral 5 2 1 glass
|
||||||
|
//spiral 7 1 5 mesecons:wire_00000000_off
|
||||||
|
|
||||||
|
### //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
|
||||||
|
|
||||||
|
### //scale <factor>
|
||||||
|
|
||||||
|
Scale the current WorldEdit positions and region by a factor of positive integer <factor> with position 1 as the origin.
|
||||||
|
|
||||||
|
//scale 2
|
||||||
|
//scale 1
|
||||||
|
//scale 10
|
||||||
|
|
||||||
|
### //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 Diamond Block
|
||||||
|
//suppress glass
|
||||||
|
//suppress mesecons:wire_00000000_off
|
||||||
|
|
||||||
|
### //highlight <node>
|
||||||
|
|
||||||
|
Highlight <node> in the current WorldEdit region by hiding everything else non-destructively.
|
||||||
|
|
||||||
|
//highlight Diamond Block
|
||||||
|
//highlight glass
|
||||||
|
//highlight mesecons:wire_00000000_off
|
||||||
|
|
||||||
|
### //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.add_node(pos, {name="default:stone"})
|
||||||
|
//luatransform if minetest.get_node(pos).name == "air" then minetest.add_node(pos, {name="default:water_source"})
|
||||||
|
|
||||||
|
### //mtschemcreate <file>
|
||||||
|
|
||||||
|
Save the current WorldEdit region using the Minetest Schematic format to "(world folder)/schems/<file>.mts".
|
||||||
|
|
||||||
|
//mtschemcreate some random filename
|
||||||
|
//mtschemcreate huge_base
|
||||||
|
|
||||||
|
### //mtschemplace <file>
|
||||||
|
|
||||||
|
Load nodes from "(world folder)/schems/<file>.mts" with position 1 of the current WorldEdit region as the origin.
|
||||||
|
|
||||||
|
//mtschemplace some random filename
|
||||||
|
//mtschemplace huge_base
|
||||||
|
|
||||||
|
### //mtschemprob start/finish/get
|
||||||
|
|
||||||
|
After using //mtschemprob start all nodes punched will bring up a text field where a probablity can be entered.
|
||||||
|
This mode can be left with //mtschemprob finish. //mtschemprob get will display the probabilities saved for the nodes.
|
||||||
|
|
||||||
|
//mtschemprob get
|
||||||
|
|
||||||
|
### //clearobjects
|
||||||
|
|
||||||
|
Clears all objects within the WorldEdit region.
|
||||||
|
|
||||||
|
//clearobjects
|
232
README.md
232
README.md
@ -1,8 +1,10 @@
|
|||||||
WorldEdit v0.5 for MineTest 0.4
|
WorldEdit v1.0 for MineTest 0.4.8+
|
||||||
===============================
|
==================================
|
||||||
In-game world editing for [MineTest](http://minetest.net/)! Tons of chat commands to help with building, fixing, and more.
|
The ultimate in-game world editing tool for [Minetest](http://minetest.net/)! Tons of functionality to help with building, fixing, and more.
|
||||||
|
|
||||||
For more information, see the [forum topic](http://minetest.net/forum/viewtopic.php?id=572) at the MineTest forums.
|
For more information, see the [forum topic](https://forum.minetest.net/viewtopic.php?id=572) at the Minetest forums.
|
||||||
|
|
||||||
|
# New users should see the [tutorial](Tutorial.md).
|
||||||
|
|
||||||
Usage
|
Usage
|
||||||
-----
|
-----
|
||||||
@ -12,9 +14,53 @@ 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.
|
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.
|
||||||
|
|
||||||
|
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).
|
||||||
|
|
||||||
|
If visual manipulation of nodes is desired, the [WorldEdit GUI](https://forum.minetest.net/viewtopic.php?id=3112) mod provides a simple interface with buttons and text entry fields for this purpose.
|
||||||
|
|
||||||
|
Compatibility
|
||||||
|
-------------
|
||||||
|
This mod supports Minetest versions 0.4.8 and newer. Older versions of WorldEdit may work with older versions of Minetest, but are not recommended.
|
||||||
|
|
||||||
|
WorldEdit works quite well with other mods, and does not have any known mod conflicts.
|
||||||
|
|
||||||
|
WorldEdit API
|
||||||
|
-------------
|
||||||
|
WorldEdit exposes all significant functionality in a simple Lua 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.
|
||||||
|
|
||||||
|
If you don't add WorldEdit to your "depends.txt" file, each file in the WorldEdit mod is also independent. For example, one may import the WorldEdit primitives API using the following code:
|
||||||
|
|
||||||
|
dofile(minetest.get_modpath("worldedit").."/primitives.lua")
|
||||||
|
|
||||||
|
AGPLv3 compatible mods may further include WorldEdit files in their own mods. This may be useful if a modder wishes to completely avoid any dependencies on WorldEdit. Note that it is required to give credit to the authors.
|
||||||
|
|
||||||
|
This API is documented in the [WorldEdit API Reference](WorldEdit API.md).
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
Nodes
|
||||||
|
-----
|
||||||
|
Node names are required for many types of commands that identify or modify specific types of nodes. They can be specified in a number of ways.
|
||||||
|
|
||||||
|
First, by description - the tooltip that appears when hovering over the item in an inventory. This is case insensitive and includes values such as "Cobblestone" and "bronze block". Note that certain commands (namely, `//replace` and `//replaceinverse`) do not support descriptions that contain spaces in the `<searchnode>` field.
|
||||||
|
|
||||||
|
Second, by name - the node name that is defined by code, but without the mod name prefix. This is case sensitive and includes values such as "piston_normal_off" and "cactus". Nodes defined in the `default` mod always take precedence over other nodes when searching for the correct one, and if there are multiple possible nodes (such as "a:celery" and "b:celery"), one is chosen in no particular order.
|
||||||
|
|
||||||
|
Finally, by full name - the unambiguous identifier of the node, prefixes and all. This is case sensitive and includes values such as "default:stone" and "mesecons:wire_00000000_off".
|
||||||
|
|
||||||
|
The node name "air" can be used anywhere a normal node name can, and acts as a blank node. This is useful for clearing or removing nodes. For example, `//set air` would remove all the nodes in the current WorldEdit region. Similarly, `//sphere 10 air`, when WorldEdit position 1 underground, would dig a large sphere out of the ground.
|
||||||
|
|
||||||
Regions
|
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.
|
Most WorldEdit commands operate on regions. Regions are a set of two positions that define a 3D cuboid. They are local to each player and chat commands affect only the region for the player giving the commands.
|
||||||
|
|
||||||
Each positions together define two opposing corners of the cube. With two opposing corners it is possible to determine both the location and dimensions of the region.
|
Each positions together define two opposing corners of the cube. With two opposing corners it is possible to determine both the location and dimensions of the region.
|
||||||
|
|
||||||
@ -26,170 +72,36 @@ 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.
|
To remove the entities, simply punch them. This does not reset the positions themselves.
|
||||||
|
|
||||||
Commands
|
Schematics
|
||||||
--------
|
----------
|
||||||
|
WorldEdit supports two different types of schematics.
|
||||||
|
|
||||||
### //reset
|
The first is the WorldEdit Schematic format, with the file extension ".we", and in some older versions, ".wem". There have been several previous versions of the WorldEdit Schematic format, but WorldEdit is capable of loading any past versions, and will always support them - there is no need to worry about schematics becoming obselete.
|
||||||
|
|
||||||
Reset the region so that it is empty.
|
The current version of the WorldEdit Schematic format, internally known as version 4, is essentially an array of node data tables in Lua 5.2 table syntax. Specifically:
|
||||||
|
|
||||||
//reset
|
return {
|
||||||
|
{
|
||||||
|
["y"] = <y-axis coordinate>,
|
||||||
|
["x"] = <x-axis coordinate>,
|
||||||
|
["name"] = <node name>,
|
||||||
|
["z"] = <z-axis coordinate>,
|
||||||
|
["meta"] = <metadata table>,
|
||||||
|
["param2"] = <param2 value>,
|
||||||
|
["param1"] = <y-axis coordinate>,
|
||||||
|
},
|
||||||
|
<...>
|
||||||
|
}
|
||||||
|
|
||||||
### //pos1
|
Value ordering and minor aspects of the syntax, such as trailing commas or newlines, are not guaranteed.
|
||||||
|
|
||||||
Set WorldEdit region position 1 to the player's location.
|
The WorldEdit Schematic format is accessed via the WorldEdit API, or WorldEdit serialization chat commands such as `//serialize` and `//deserialize`.
|
||||||
|
|
||||||
//pos1
|
The second is the Minetest Schematic format (MTS). The details of this format may be found in the Minetest documentation and are out of the scope of this document. Access to this format is done via specialized MTS commands such as `//mtschemcreate` and `//mtschemplace`.
|
||||||
|
|
||||||
### //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
|
|
||||||
|
|
||||||
WorldEdit API
|
|
||||||
-------------
|
|
||||||
WorldEdit exposes all significant functionality in a simple interface. Adding WorldEdit to the file "depends.txt" in your mod gives you access to all of the `worldedit` functions. These are useful if you're looking for high-performance node manipulation without all the hassle of writing tons of code.
|
|
||||||
|
|
||||||
### worldedit.volume(pos1, pos2)
|
|
||||||
|
|
||||||
Determines the volume of the region defined by positions `pos1` and `pos2`.
|
|
||||||
|
|
||||||
Returns the volume.
|
|
||||||
|
|
||||||
### worldedit.set(pos1, pos2, nodename)
|
|
||||||
|
|
||||||
Sets a region defined by positions `pos1` and `pos2` to `nodename`. To clear to region, use "air" as the value of `nodename`.
|
|
||||||
|
|
||||||
Returns the number of nodes set.
|
|
||||||
|
|
||||||
### worldedit.replace(pos1, pos2, searchnode, replacenode)
|
|
||||||
|
|
||||||
Replaces all instances of `searchnode` with `replacenode` in a region defined by positions `pos1` and `pos2`.
|
|
||||||
|
|
||||||
Returns the number of nodes replaced.
|
|
||||||
|
|
||||||
### worldedit.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.
|
|
||||||
|
|
||||||
License
|
License
|
||||||
-------
|
-------
|
||||||
Copyright 2012 sfan5 and Anthony Zhang (Temperest)
|
Copyright 2013 sfan5, Anthony Zhang (Uberi/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).
|
This mod is licensed under the [GNU Affero General Public License](http://www.gnu.org/licenses/agpl-3.0.html).
|
||||||
|
|
||||||
|
55
Tutorial.md
Normal file
55
Tutorial.md
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
WorldEdit Tutorial
|
||||||
|
==================
|
||||||
|
This is a step-by-step tutorial outlining the basic usage of WorldEdit. For more information, see the [README](README.md).
|
||||||
|
|
||||||
|
Let's start with a few assumptions:
|
||||||
|
|
||||||
|
* You have a compatible version of Minetest working.
|
||||||
|
* See the [README](README.md) for compatibility information.
|
||||||
|
* You have WorldEdit installed as a mod.
|
||||||
|
* If using Windows, [MODSTER](https://forum.minetest.net/viewtopic.php?pid=101463) makes installing mods totally painless.
|
||||||
|
* Simply download the file, extract the archive, and move it to the correct mod folder for Minetest.
|
||||||
|
* You are familiar with the basics of the game.
|
||||||
|
* How to walk, jump, and climb.
|
||||||
|
* How to dig, place, and punch blocks.
|
||||||
|
* How to type into the chat and read text from it.
|
||||||
|
|
||||||
|
Overview
|
||||||
|
--------
|
||||||
|
WorldEdit has a "region", which is simply a cuboid area defined by two markers, both of which the player can move around. Every player can have their own region with their own two markers.
|
||||||
|
|
||||||
|
WorldEdit chat commands can work inside the region selected, or around the first marker.
|
||||||
|
|
||||||
|
Step 1: Selecting a region
|
||||||
|
--------------------------
|
||||||
|
In the chat prompt, enter `//p set`. In the chat, you are prompted to punch two nodes to set the positions of the two markers.
|
||||||
|
|
||||||
|
Punch a nearby node. Be careful of breakable ones such as torches. A black cube reading "1" will appear around the node. This is the marker for WorldEdit position 1.
|
||||||
|
|
||||||
|
Walk away from the node you just punched. Now, punch another node. A black cube reading "2" will appear around the node. This is the marker for WorldEdit position 2.
|
||||||
|
|
||||||
|
Step 2: Region commands
|
||||||
|
-----------------------
|
||||||
|
In the chat prompt, enter `//set mese`. In the chat, you will see a message showing the number of nodes set after a small delay.
|
||||||
|
|
||||||
|
Look at the place between the two markers: it is now filled with MESE blocks!
|
||||||
|
|
||||||
|
The `//set <node>` command fills the region with whatever node you want. It is a region-oriented command, which means it works inside the WorldEdit region only.
|
||||||
|
|
||||||
|
Now, try a few different variations, such as `//set torch`, `//set cobble`, and `//set water`.
|
||||||
|
|
||||||
|
Step 3: Position commands
|
||||||
|
-------------------------
|
||||||
|
In the chat prompt, enter `//hollowdome 30 glass`. In the chat, you will see a message showing the number of nodes set after a small delay.
|
||||||
|
|
||||||
|
Look around marker 1: it is now surrounded by a hollow glass dome!
|
||||||
|
|
||||||
|
The `//hollowdome <radius> <node>` command creates a hollow dome centered around marker 1, made of any node you want. It is a position-oriented command, which means it works around marker 1 and can go outside the WorldEdit region.
|
||||||
|
|
||||||
|
Step 4: Other commands
|
||||||
|
----------------------
|
||||||
|
There are many more commands than what is shown here. See the [Chat Commands Reference](Chat Commands.md) for a detailed list of them, along with descriptions and examples for every single one.
|
||||||
|
|
||||||
|
If you're in-game and forgot how a command works, just use the `/help <command name>` command, without the first forward slash. For example, to see some information about the `//set <node>` command mentioned earlier, simply use `/help /set`.
|
||||||
|
|
||||||
|
A very useful command to check out is the `//save <schematic>` command, which can save everything inside the WorldEdit region to a file, stored on the computer hosting the server (the player's computer, in single player mode). You can then later use `//load <schematic>` to load the data in a file into a world, even another world on another computer.
|
219
WorldEdit API.md
Normal file
219
WorldEdit API.md
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
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.scale(pos1, pos2, factor)
|
||||||
|
|
||||||
|
Scales the region defined by positions `pos1` and `pos2` by an factor of positive integer `factor` with `pos1` as the origin.
|
||||||
|
|
||||||
|
Returns the number of nodes scaled, the new scaled position 1, and the new scaled position 2.
|
||||||
|
|
||||||
|
### 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 transposed position 1, and the new transposed 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.
|
||||||
|
|
||||||
|
### count = worldedit.clearobjects(pos1, pos2)
|
||||||
|
|
||||||
|
Clears all objects in a region defined by the positions `pos1` and `pos2`.
|
||||||
|
|
||||||
|
Returns the number of objects cleared.
|
||||||
|
|
||||||
|
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 centered at `pos` with radius `radius`, composed of `nodename`.
|
||||||
|
|
||||||
|
Returns the number of nodes added.
|
||||||
|
|
||||||
|
### count = worldedit.sphere(pos, radius, nodename)
|
||||||
|
|
||||||
|
Adds a sphere centered 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 centered at `pos` with radius `radius`, composed of `nodename`.
|
||||||
|
|
||||||
|
Returns the number of nodes added.
|
||||||
|
|
||||||
|
### count = worldedit.dome(pos, radius, nodename)
|
||||||
|
|
||||||
|
Adds a dome centered 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, axis, height, nodename)
|
||||||
|
|
||||||
|
Adds a pyramid centered at `pos` along the `axis` axis ("x" or "y" or "z") with height `height`.
|
||||||
|
|
||||||
|
Returns the number of nodes added.
|
||||||
|
|
||||||
|
### count = worldedit.spiral(pos, length, height, spacer, nodename)
|
||||||
|
|
||||||
|
Adds a spiral centered at `pos` with side length `length`, 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,
|
|
||||||
})
|
|
58
mark.lua
58
mark.lua
@ -1,58 +0,0 @@
|
|||||||
worldedit.marker1 = {}
|
|
||||||
worldedit.marker2 = {}
|
|
||||||
|
|
||||||
--marks worldedit region position 1
|
|
||||||
worldedit.mark_pos1 = function(name)
|
|
||||||
local pos = worldedit.pos1[name]
|
|
||||||
if worldedit.marker1[name] ~= nil then --marker already exists
|
|
||||||
worldedit.marker1[name]:remove() --remove marker
|
|
||||||
worldedit.marker1[name] = nil
|
|
||||||
end
|
|
||||||
if pos ~= nil then --add marker
|
|
||||||
worldedit.marker1[name] = minetest.env:add_entity(pos, "worldedit:pos1")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--marks worldedit region position 2
|
|
||||||
worldedit.mark_pos2 = function(name)
|
|
||||||
local pos = worldedit.pos2[name]
|
|
||||||
if worldedit.marker2[name] ~= nil then --marker already exists
|
|
||||||
worldedit.marker2[name]:remove() --remove marker
|
|
||||||
worldedit.marker2[name] = nil
|
|
||||||
end
|
|
||||||
if pos ~= nil then --add marker
|
|
||||||
worldedit.marker2[name] = minetest.env:add_entity(pos, "worldedit:pos2")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
minetest.register_entity("worldedit:pos1", {
|
|
||||||
initial_properties = {
|
|
||||||
visual = "cube",
|
|
||||||
visual_size = {x=1.1, y=1.1},
|
|
||||||
textures = {"worldedit_pos1.png", "worldedit_pos1.png",
|
|
||||||
"worldedit_pos1.png", "worldedit_pos1.png",
|
|
||||||
"worldedit_pos1.png", "worldedit_pos1.png"},
|
|
||||||
collisionbox = {-0.55, -0.55, -0.55, 0.55, 0.55, 0.55},
|
|
||||||
},
|
|
||||||
on_punch = function(self, hitter)
|
|
||||||
self.object:remove()
|
|
||||||
local name = hitter:get_player_name()
|
|
||||||
worldedit.marker1[name] = nil
|
|
||||||
end,
|
|
||||||
})
|
|
||||||
|
|
||||||
minetest.register_entity("worldedit:pos2", {
|
|
||||||
initial_properties = {
|
|
||||||
visual = "cube",
|
|
||||||
visual_size = {x=1.1, y=1.1},
|
|
||||||
textures = {"worldedit_pos2.png", "worldedit_pos2.png",
|
|
||||||
"worldedit_pos2.png", "worldedit_pos2.png",
|
|
||||||
"worldedit_pos2.png", "worldedit_pos2.png"},
|
|
||||||
collisionbox = {-0.55, -0.55, -0.55, 0.55, 0.55, 0.55},
|
|
||||||
},
|
|
||||||
on_punch = function(self, hitter)
|
|
||||||
self.object:remove()
|
|
||||||
local name = hitter:get_player_name()
|
|
||||||
worldedit.marker2[name] = nil
|
|
||||||
end,
|
|
||||||
})
|
|
0
modpack.txt
Normal file
0
modpack.txt
Normal file
48
worldedit/code.lua
Normal file
48
worldedit/code.lua
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
worldedit = worldedit or {}
|
||||||
|
local minetest = minetest --local copy of global
|
||||||
|
|
||||||
|
--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()
|
||||||
|
|
||||||
|
--make area stay loaded
|
||||||
|
local manip = minetest.get_voxel_manip()
|
||||||
|
manip:read_from_map(pos1, pos2)
|
||||||
|
|
||||||
|
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
|
20
worldedit/compatibility.lua
Normal file
20
worldedit/compatibility.lua
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
worldedit = worldedit or {}
|
||||||
|
local minetest = minetest --local copy of global
|
||||||
|
|
||||||
|
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
|
19
worldedit/init.lua
Normal file
19
worldedit/init.lua
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
assert(minetest.get_voxel_manip, string.rep(">", 300) .. "HEY YOU! YES, YOU OVER THERE. THIS VERSION OF WORLDEDIT REQUIRES MINETEST 0.4.8 OR LATER! YOU HAVE AN OLD VERSION." .. string.rep("<", 300))
|
||||||
|
|
||||||
|
local path = minetest.get_modpath(minetest.get_current_modname())
|
||||||
|
|
||||||
|
local loadmodule = function(path)
|
||||||
|
local file = io.open(path)
|
||||||
|
if not file then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
file:close()
|
||||||
|
return dofile(path)
|
||||||
|
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")
|
579
worldedit/manipulations.lua
Normal file
579
worldedit/manipulations.lua
Normal file
@ -0,0 +1,579 @@
|
|||||||
|
worldedit = worldedit or {}
|
||||||
|
local minetest = minetest --local copy of global
|
||||||
|
|
||||||
|
--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)
|
||||||
|
|
||||||
|
--set up voxel manipulator
|
||||||
|
local manip = minetest.get_voxel_manip()
|
||||||
|
local emerged_pos1, emerged_pos2 = manip:read_from_map(pos1, pos2)
|
||||||
|
local area = VoxelArea:new({MinEdge=emerged_pos1, MaxEdge=emerged_pos2})
|
||||||
|
|
||||||
|
--fill emerged area with ignore
|
||||||
|
local nodes = {}
|
||||||
|
local ignore = minetest.get_content_id("ignore")
|
||||||
|
for i = 1, worldedit.volume(emerged_pos1, emerged_pos2) do
|
||||||
|
nodes[i] = ignore
|
||||||
|
end
|
||||||
|
|
||||||
|
--fill selected area with node
|
||||||
|
local node_id = minetest.get_content_id(nodename)
|
||||||
|
for i in area:iterp(pos1, pos2) do
|
||||||
|
nodes[i] = node_id
|
||||||
|
end
|
||||||
|
|
||||||
|
--update map nodes
|
||||||
|
manip:set_data(nodes)
|
||||||
|
manip:write_to_map()
|
||||||
|
manip:update_map()
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
--set up voxel manipulator
|
||||||
|
local manip = minetest.get_voxel_manip()
|
||||||
|
local emerged_pos1, emerged_pos2 = manip:read_from_map(pos1, pos2)
|
||||||
|
local area = VoxelArea:new({MinEdge=emerged_pos1, MaxEdge=emerged_pos2})
|
||||||
|
|
||||||
|
local nodes = manip:get_data()
|
||||||
|
local searchnode_id = minetest.get_content_id(searchnode)
|
||||||
|
local replacenode_id = minetest.get_content_id(replacenode)
|
||||||
|
local count = 0
|
||||||
|
for i in area:iterp(pos1, pos2) do --replace searchnode with replacenode
|
||||||
|
if nodes[i] == searchnode_id then
|
||||||
|
nodes[i] = replacenode_id
|
||||||
|
count = count + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--update map nodes
|
||||||
|
manip:set_data(nodes)
|
||||||
|
manip:write_to_map()
|
||||||
|
manip:update_map()
|
||||||
|
|
||||||
|
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)
|
||||||
|
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||||
|
|
||||||
|
--set up voxel manipulator
|
||||||
|
local manip = minetest.get_voxel_manip()
|
||||||
|
local emerged_pos1, emerged_pos2 = manip:read_from_map(pos1, pos2)
|
||||||
|
local area = VoxelArea:new({MinEdge=emerged_pos1, MaxEdge=emerged_pos2})
|
||||||
|
|
||||||
|
local nodes = manip:get_data()
|
||||||
|
local searchnode_id = minetest.get_content_id(searchnode)
|
||||||
|
local replacenode_id = minetest.get_content_id(replacenode)
|
||||||
|
local count = 0
|
||||||
|
for i in area:iterp(pos1, pos2) do --replace anything that is not searchnode with replacenode
|
||||||
|
if nodes[i] ~= searchnode_id then
|
||||||
|
nodes[i] = replacenode_id
|
||||||
|
count = count + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--update map nodes
|
||||||
|
manip:set_data(nodes)
|
||||||
|
manip:write_to_map()
|
||||||
|
manip:update_map()
|
||||||
|
|
||||||
|
return count
|
||||||
|
end
|
||||||
|
|
||||||
|
worldedit.copy = function(pos1, pos2, axis, amount)
|
||||||
|
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||||
|
|
||||||
|
if amount == 0 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
--make area stay loaded
|
||||||
|
local manip = minetest.get_voxel_manip()
|
||||||
|
manip:read_from_map(pos1, pos2)
|
||||||
|
|
||||||
|
--prepare slice along axis
|
||||||
|
local extent = {
|
||||||
|
[axis] = 1,
|
||||||
|
[other1]=pos2[other1] - pos1[other1] + 1,
|
||||||
|
[other2]=pos2[other2] - pos1[other2] + 1,
|
||||||
|
}
|
||||||
|
local nodes = {}
|
||||||
|
local schematic = {size=extent, data=nodes}
|
||||||
|
|
||||||
|
local currentpos = {x=pos1.x, y=pos1.y, z=pos1.z}
|
||||||
|
local stride = {x=1, y=extent.x, z=extent.x * extent.y}
|
||||||
|
local get_node = minetest.get_node
|
||||||
|
for index1 = 1, extent[axis] do --go through each slice
|
||||||
|
--copy slice into schematic
|
||||||
|
local newindex1 = (index1 + offset[axis]) * stride[axis] + 1 --offset contributed by axis plus 1 to make it 1-indexed
|
||||||
|
for index2 = 1, extent[other1] do
|
||||||
|
local newindex2 = newindex1 + (index2 + offset[other1]) * stride[other1]
|
||||||
|
for index3 = 1, extent[other2] do
|
||||||
|
local i = newindex2 + (index3 + offset[other2]) * stride[other2]
|
||||||
|
nodes[i] = get_node(pos)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--copy schematic to target
|
||||||
|
currentpos[axis] = currentpos[axis] + amount
|
||||||
|
place_schematic(currentpos, schematic)
|
||||||
|
|
||||||
|
--wip: copy meta
|
||||||
|
|
||||||
|
currentpos[axis] = currentpos[axis] + 1
|
||||||
|
end
|
||||||
|
return worldedit.volume(pos1, pos2)
|
||||||
|
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)
|
||||||
|
|
||||||
|
--make area stay loaded
|
||||||
|
local manip = minetest.get_voxel_manip()
|
||||||
|
manip:read_from_map(pos1, pos2)
|
||||||
|
|
||||||
|
local get_node, get_meta, add_node = minetest.get_node, minetest.get_meta, minetest.add_node
|
||||||
|
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 = get_node(pos) --obtain current node
|
||||||
|
local meta = get_meta(pos):to_table() --get meta of current node
|
||||||
|
local value = pos[axis] --store current position
|
||||||
|
pos[axis] = value + amount --move along axis
|
||||||
|
add_node(pos, node) --copy node to new position
|
||||||
|
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 = get_node(pos) --obtain current node
|
||||||
|
local meta = get_meta(pos):to_table() --get meta of current node
|
||||||
|
local value = pos[axis] --store current position
|
||||||
|
pos[axis] = value + amount --move along axis
|
||||||
|
add_node(pos, node) --copy node to new position
|
||||||
|
get_meta(pos):from_table(meta) --set metadata of new node
|
||||||
|
pos[axis] = value --restore old position
|
||||||
|
pos.z = pos.z - 1
|
||||||
|
end
|
||||||
|
pos.y = pos.y - 1
|
||||||
|
end
|
||||||
|
pos.x = pos.x - 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return worldedit.volume(pos1, pos2)
|
||||||
|
end
|
||||||
|
|
||||||
|
--moves the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") by `amount` nodes, returning the number of nodes moved
|
||||||
|
worldedit.move = function(pos1, pos2, axis, amount)
|
||||||
|
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||||
|
|
||||||
|
--make area stay loaded
|
||||||
|
local manip = minetest.get_voxel_manip()
|
||||||
|
manip:read_from_map(pos1, pos2)
|
||||||
|
|
||||||
|
--wip: move slice by slice using schematic method in the move axis and transfer metadata in separate loop (and if the amount is greater than the length in the axis, copy whole thing at a time and erase original after, using schematic method)
|
||||||
|
local get_node, get_meta, add_node, remove_node = minetest.get_node, minetest.get_meta, minetest.add_node, minetest.remove_node
|
||||||
|
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 = get_node(pos) --obtain current node
|
||||||
|
local meta = get_meta(pos):to_table() --get metadata of current node
|
||||||
|
remove_node(pos)
|
||||||
|
local value = pos[axis] --store current position
|
||||||
|
pos[axis] = value + amount --move along axis
|
||||||
|
add_node(pos, node) --move node to new position
|
||||||
|
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 = get_node(pos) --obtain current node
|
||||||
|
local meta = get_meta(pos):to_table() --get metadata of current node
|
||||||
|
remove_node(pos)
|
||||||
|
local value = pos[axis] --store current position
|
||||||
|
pos[axis] = value + amount --move along axis
|
||||||
|
add_node(pos, node) --move node to new position
|
||||||
|
get_meta(pos):from_table(meta) --set metadata of new node
|
||||||
|
pos[axis] = value --restore old position
|
||||||
|
pos.z = pos.z - 1
|
||||||
|
end
|
||||||
|
pos.y = pos.y - 1
|
||||||
|
end
|
||||||
|
pos.x = pos.x - 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return worldedit.volume(pos1, pos2)
|
||||||
|
end
|
||||||
|
|
||||||
|
--duplicates the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") `count` times, returning the number of nodes stacked
|
||||||
|
worldedit.stack = function(pos1, pos2, axis, count)
|
||||||
|
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||||
|
local length = pos2[axis] - pos1[axis] + 1
|
||||||
|
if count < 0 then
|
||||||
|
count = -count
|
||||||
|
length = -length
|
||||||
|
end
|
||||||
|
local amount = 0
|
||||||
|
local copy = worldedit.copy
|
||||||
|
for i = 1, count do
|
||||||
|
amount = amount + length
|
||||||
|
copy(pos1, pos2, axis, amount)
|
||||||
|
end
|
||||||
|
return worldedit.volume(pos1, pos2) * count
|
||||||
|
end
|
||||||
|
|
||||||
|
--scales the region defined by positions `pos1` and `pos2` by an factor of positive integer `factor` with `pos1` as the origin, returning the number of nodes scaled, the new scaled position 1, and the new scaled position 2
|
||||||
|
worldedit.scale = function(pos1, pos2, factor)
|
||||||
|
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||||
|
|
||||||
|
--prepare schematic of large node
|
||||||
|
local get_node, get_meta, place_schematic = minetest.get_node, minetest.get_meta, minetest.place_schematic
|
||||||
|
local placeholder_node = {name="", param1=0, param2=0}
|
||||||
|
local nodes = {}
|
||||||
|
for i = 1, factor ^ 3 do
|
||||||
|
nodes[i] = placeholder_node
|
||||||
|
end
|
||||||
|
local schematic = {size={x=factor, y=factor, z=factor}, data=nodes}
|
||||||
|
|
||||||
|
local size = factor - 1
|
||||||
|
|
||||||
|
--make area stay loaded
|
||||||
|
local manip = minetest.get_voxel_manip()
|
||||||
|
local new_pos2 = {x=pos1.x + (pos2.x - pos1.x) * factor + size, y=pos1.y + (pos2.y - pos1.y) * factor + size, z=pos1.z + (pos2.z - pos1.z) * factor + size}
|
||||||
|
manip:read_from_map(pos1, new_pos2)
|
||||||
|
|
||||||
|
local pos = {x=pos2.x, y=0, z=0}
|
||||||
|
local bigpos = {x=0, 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 = get_node(pos) --obtain current node
|
||||||
|
local meta = get_meta(pos):to_table() --get meta of current node
|
||||||
|
|
||||||
|
local value = pos[axis] --store current position
|
||||||
|
local posx, posy, posz = pos1.x + (pos.x - pos1.x) * factor, pos1.y + (pos.y - pos1.y) * factor, pos1.z + (pos.z - pos1.z) * factor
|
||||||
|
|
||||||
|
--create large node
|
||||||
|
placeholder_node.name = node.name
|
||||||
|
placeholder_node.param1, placeholder_node.param2 = node.param1, node.param2
|
||||||
|
bigpos.x, bigpos.y, bigpos.z = posx, posy, posz
|
||||||
|
place_schematic(bigpos, schematic)
|
||||||
|
|
||||||
|
--fill in large node meta
|
||||||
|
if next(meta.fields) ~= nil and next(meta.inventory) ~= nil then --node has meta fields
|
||||||
|
for x = 0, size do
|
||||||
|
for y = 0, size do
|
||||||
|
for z = 0, size do
|
||||||
|
bigpos.x, bigpos.y, bigpos.z = posx + x, posy + y, posz + z
|
||||||
|
get_meta(bigpos):from_table(meta) --set metadata of new node
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
pos.z = pos.z - 1
|
||||||
|
end
|
||||||
|
pos.y = pos.y - 1
|
||||||
|
end
|
||||||
|
pos.x = pos.x - 1
|
||||||
|
end
|
||||||
|
return worldedit.volume(pos1, pos2) * (factor ^ 3), pos1, new_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 transposed position 1, and the new transposed position 2
|
||||||
|
worldedit.transpose = function(pos1, pos2, axis1, axis2)
|
||||||
|
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 new_pos2 = {x=pos2.x, y=pos2.y, z=pos2.z}
|
||||||
|
new_pos2[axis1] = pos1[axis1] + extent2
|
||||||
|
new_pos2[axis2] = pos1[axis2] + extent1
|
||||||
|
|
||||||
|
--make area stay loaded
|
||||||
|
local manip = minetest.get_voxel_manip()
|
||||||
|
local upperbound = {x=pos2.x, y=pos2.y, z=pos2.z}
|
||||||
|
if upperbound[axis1] < new_pos2[axis1] then upperbound[axis1] = new_pos2[axis1] end
|
||||||
|
if upperbound[axis2] < new_pos2[axis2] then upperbound[axis2] = new_pos2[axis2] end
|
||||||
|
manip:read_from_map(pos1, upperbound)
|
||||||
|
|
||||||
|
local pos = {x=pos1.x, y=0, z=0}
|
||||||
|
local get_node, get_meta, add_node = minetest.get_node, minetest.get_meta, minetest.add_node
|
||||||
|
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 = get_node(pos)
|
||||||
|
local meta1 = 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 = get_node(pos)
|
||||||
|
local meta2 = get_meta(pos):to_table()
|
||||||
|
add_node(pos, node1)
|
||||||
|
get_meta(pos):from_table(meta1)
|
||||||
|
pos[axis1], pos[axis2] = value1, value2 --restore position values
|
||||||
|
add_node(pos, node2)
|
||||||
|
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, new_pos2
|
||||||
|
end
|
||||||
|
|
||||||
|
--flips a region defined by the positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z"), returning the number of nodes flipped
|
||||||
|
worldedit.flip = function(pos1, pos2, axis)
|
||||||
|
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||||
|
|
||||||
|
--make area stay loaded
|
||||||
|
local manip = minetest.get_voxel_manip()
|
||||||
|
manip:read_from_map(pos1, pos2)
|
||||||
|
|
||||||
|
--wip: flip the region slice by slice along the flip axis using schematic method
|
||||||
|
local pos = {x=pos1.x, y=0, z=0}
|
||||||
|
local start = pos1[axis] + pos2[axis]
|
||||||
|
pos2[axis] = pos1[axis] + math.floor((pos2[axis] - pos1[axis]) / 2)
|
||||||
|
local get_node, get_meta, add_node = minetest.get_node, minetest.get_meta, minetest.add_node
|
||||||
|
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 = get_node(pos)
|
||||||
|
local meta1 = get_meta(pos):to_table()
|
||||||
|
local value = pos[axis]
|
||||||
|
pos[axis] = start - value
|
||||||
|
local node2 = get_node(pos)
|
||||||
|
local meta2 = get_meta(pos):to_table()
|
||||||
|
add_node(pos, node1)
|
||||||
|
get_meta(pos):from_table(meta1)
|
||||||
|
pos[axis] = value
|
||||||
|
add_node(pos, node2)
|
||||||
|
get_meta(pos):from_table(meta2)
|
||||||
|
pos.z = pos.z + 1
|
||||||
|
end
|
||||||
|
pos.y = pos.y + 1
|
||||||
|
end
|
||||||
|
pos.x = pos.x + 1
|
||||||
|
end
|
||||||
|
return worldedit.volume(pos1, pos2)
|
||||||
|
end
|
||||||
|
|
||||||
|
--rotates a region defined by the positions `pos1` and `pos2` by `angle` degrees clockwise around axis `axis` (90 degree increment), returning the number of nodes rotated
|
||||||
|
worldedit.rotate = function(pos1, pos2, axis, angle)
|
||||||
|
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||||
|
|
||||||
|
local axis1, axis2
|
||||||
|
if axis == "x" then
|
||||||
|
axis1, axis2 = "z", "y"
|
||||||
|
elseif axis == "y" then
|
||||||
|
axis1, axis2 = "x", "z"
|
||||||
|
else --axis == "z"
|
||||||
|
axis1, axis2 = "y", "x"
|
||||||
|
end
|
||||||
|
angle = angle % 360
|
||||||
|
|
||||||
|
local count
|
||||||
|
if angle == 90 then
|
||||||
|
worldedit.flip(pos1, pos2, axis1)
|
||||||
|
count, pos1, pos2 = worldedit.transpose(pos1, pos2, axis1, axis2)
|
||||||
|
elseif angle == 180 then
|
||||||
|
worldedit.flip(pos1, pos2, axis1)
|
||||||
|
count = worldedit.flip(pos1, pos2, axis2)
|
||||||
|
elseif angle == 270 then
|
||||||
|
worldedit.flip(pos1, pos2, axis2)
|
||||||
|
count, pos1, pos2 = worldedit.transpose(pos1, pos2, axis1, axis2)
|
||||||
|
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) --wip: support 6D facedir rotation along arbitrary axis
|
||||||
|
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||||
|
local registered_nodes = minetest.registered_nodes
|
||||||
|
|
||||||
|
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]
|
||||||
|
|
||||||
|
--make area stay loaded
|
||||||
|
local manip = minetest.get_voxel_manip()
|
||||||
|
manip:read_from_map(pos1, pos2)
|
||||||
|
|
||||||
|
local count = 0
|
||||||
|
local get_node, get_meta, add_node = minetest.get_node, minetest.get_meta, minetest.add_node
|
||||||
|
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 = get_node(pos)
|
||||||
|
local def = registered_nodes[node.name]
|
||||||
|
if def then
|
||||||
|
if def.paramtype2 == "wallmounted" then
|
||||||
|
node.param2 = wallmounted_substitution[node.param2]
|
||||||
|
local meta = get_meta(pos):to_table()
|
||||||
|
add_node(pos, node)
|
||||||
|
get_meta(pos):from_table(meta)
|
||||||
|
count = count + 1
|
||||||
|
elseif def.paramtype2 == "facedir" then
|
||||||
|
node.param2 = facedir_substitution[node.param2]
|
||||||
|
local meta = get_meta(pos):to_table()
|
||||||
|
add_node(pos, node)
|
||||||
|
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)
|
||||||
|
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||||
|
|
||||||
|
--make area stay loaded
|
||||||
|
local manip = minetest.get_voxel_manip()
|
||||||
|
manip:read_from_map(pos1, pos2)
|
||||||
|
|
||||||
|
local nodes = minetest.find_nodes_in_area(pos1, pos2, "air")
|
||||||
|
local dig_node = minetest.dig_node
|
||||||
|
for _, pos in ipairs(nodes) do
|
||||||
|
dig_node(pos)
|
||||||
|
end
|
||||||
|
return #nodes
|
||||||
|
end
|
||||||
|
|
||||||
|
--clears all objects in a region defined by the positions `pos1` and `pos2`, returning the number of objects cleared
|
||||||
|
worldedit.clearobjects = function(pos1, pos2)
|
||||||
|
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||||
|
|
||||||
|
--make area stay loaded
|
||||||
|
local manip = minetest.get_voxel_manip()
|
||||||
|
manip:read_from_map(pos1, pos2)
|
||||||
|
|
||||||
|
local pos1x, pos1y, pos1z = pos1.x, pos1.y, pos1.z
|
||||||
|
local pos2x, pos2y, pos2z = pos2.x + 1, pos2.y + 1, pos2.z + 1
|
||||||
|
local center = {x=(pos1x + pos2x) / 2, y=(pos1y + pos2y) / 2, z=(pos1z + pos2z) / 2} --center of region
|
||||||
|
local radius = ((center.x - pos1x + 0.5) + (center.y - pos1y + 0.5) + (center.z - pos1z + 0.5)) ^ 0.5 --bounding sphere radius
|
||||||
|
local count = 0
|
||||||
|
for _, obj in pairs(minetest.get_objects_inside_radius(center, radius)) do --all objects in bounding sphere
|
||||||
|
local entity = obj:get_luaentity()
|
||||||
|
if not (entity and entity.name:find("^worldedit:")) then --avoid WorldEdit entities
|
||||||
|
local pos = obj:getpos()
|
||||||
|
if pos.x >= pos1x and pos.x <= pos2x
|
||||||
|
and pos.y >= pos1y and pos.y <= pos2y
|
||||||
|
and pos.z >= pos1z and pos.z <= pos2z then --inside region
|
||||||
|
obj:remove()
|
||||||
|
count = count + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return count
|
||||||
|
end
|
478
worldedit/primitives.lua
Normal file
478
worldedit/primitives.lua
Normal file
@ -0,0 +1,478 @@
|
|||||||
|
worldedit = worldedit or {}
|
||||||
|
local minetest = minetest --local copy of global
|
||||||
|
|
||||||
|
--adds a hollow sphere centered at `pos` with radius `radius`, composed of `nodename`, returning the number of nodes added
|
||||||
|
worldedit.hollow_sphere = function(pos, radius, nodename)
|
||||||
|
--set up voxel manipulator
|
||||||
|
local manip = minetest.get_voxel_manip()
|
||||||
|
local pos1 = {x=pos.x - radius, y=pos.y - radius, z=pos.z - radius}
|
||||||
|
local pos2 = {x=pos.x + radius, y=pos.y + radius, z=pos.z + radius}
|
||||||
|
local emerged_pos1, emerged_pos2 = manip:read_from_map(pos1, pos2)
|
||||||
|
local area = VoxelArea:new({MinEdge=emerged_pos1, MaxEdge=emerged_pos2})
|
||||||
|
|
||||||
|
--fill emerged area with ignore
|
||||||
|
local nodes = {}
|
||||||
|
local ignore = minetest.get_content_id("ignore")
|
||||||
|
for i = 1, worldedit.volume(emerged_pos1, emerged_pos2) do
|
||||||
|
nodes[i] = ignore
|
||||||
|
end
|
||||||
|
|
||||||
|
--fill selected area with node
|
||||||
|
local node_id = minetest.get_content_id(nodename)
|
||||||
|
local min_radius, max_radius = radius * (radius - 1), radius * (radius + 1)
|
||||||
|
local offsetx, offsety, offsetz = pos.x - emerged_pos1.x, pos.y - emerged_pos1.y, pos.z - emerged_pos1.z
|
||||||
|
local zstride, ystride = area.zstride, area.ystride
|
||||||
|
local count = 0
|
||||||
|
for z = -radius, radius do
|
||||||
|
local newz = (z + offsetz) * zstride + 1 --offset contributed by z plus 1 to make it 1-indexed
|
||||||
|
for y = -radius, radius do
|
||||||
|
local newy = newz + (y + offsety) * ystride
|
||||||
|
for x = -radius, radius do
|
||||||
|
local squared = x * x + y * y + z * z
|
||||||
|
if squared >= min_radius and squared <= max_radius then --position is on surface of sphere
|
||||||
|
local i = newy + (x + offsetx)
|
||||||
|
nodes[i] = node_id
|
||||||
|
count = count + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--update map nodes
|
||||||
|
manip:set_data(nodes)
|
||||||
|
manip:write_to_map()
|
||||||
|
manip:update_map()
|
||||||
|
|
||||||
|
return count
|
||||||
|
end
|
||||||
|
|
||||||
|
--adds a sphere centered at `pos` with radius `radius`, composed of `nodename`, returning the number of nodes added
|
||||||
|
worldedit.sphere = function(pos, radius, nodename)
|
||||||
|
--set up voxel manipulator
|
||||||
|
local manip = minetest.get_voxel_manip()
|
||||||
|
local pos1 = {x=pos.x - radius, y=pos.y - radius, z=pos.z - radius}
|
||||||
|
local pos2 = {x=pos.x + radius, y=pos.y + radius, z=pos.z + radius}
|
||||||
|
local emerged_pos1, emerged_pos2 = manip:read_from_map(pos1, pos2)
|
||||||
|
local area = VoxelArea:new({MinEdge=emerged_pos1, MaxEdge=emerged_pos2})
|
||||||
|
|
||||||
|
--fill emerged area with ignore
|
||||||
|
local nodes = {}
|
||||||
|
local ignore = minetest.get_content_id("ignore")
|
||||||
|
for i = 1, worldedit.volume(emerged_pos1, emerged_pos2) do
|
||||||
|
nodes[i] = ignore
|
||||||
|
end
|
||||||
|
|
||||||
|
--fill selected area with node
|
||||||
|
local node_id = minetest.get_content_id(nodename)
|
||||||
|
local max_radius = radius * (radius + 1)
|
||||||
|
local offsetx, offsety, offsetz = pos.x - emerged_pos1.x, pos.y - emerged_pos1.y, pos.z - emerged_pos1.z
|
||||||
|
local zstride, ystride = area.zstride, area.ystride
|
||||||
|
local count = 0
|
||||||
|
for z = -radius, radius do
|
||||||
|
local newz = (z + offsetz) * zstride + 1 --offset contributed by z plus 1 to make it 1-indexed
|
||||||
|
for y = -radius, radius do
|
||||||
|
local newy = newz + (y + offsety) * ystride
|
||||||
|
for x = -radius, radius do
|
||||||
|
if x * x + y * y + z * z <= max_radius then --position is inside sphere
|
||||||
|
local i = newy + (x + offsetx)
|
||||||
|
nodes[i] = node_id
|
||||||
|
count = count + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--update map nodes
|
||||||
|
manip:set_data(nodes)
|
||||||
|
manip:write_to_map()
|
||||||
|
manip:update_map()
|
||||||
|
|
||||||
|
return count
|
||||||
|
end
|
||||||
|
|
||||||
|
--adds a hollow dome centered at `pos` with radius `radius`, composed of `nodename`, returning the number of nodes added
|
||||||
|
worldedit.hollow_dome = function(pos, radius, nodename)
|
||||||
|
--set up voxel manipulator
|
||||||
|
local manip = minetest.get_voxel_manip()
|
||||||
|
local pos1 = {x=pos.x - radius, y=pos.y, z=pos.z - radius}
|
||||||
|
local pos2 = {x=pos.x + radius, y=pos.y + radius, z=pos.z + radius}
|
||||||
|
local emerged_pos1, emerged_pos2 = manip:read_from_map(pos1, pos2)
|
||||||
|
local area = VoxelArea:new({MinEdge=emerged_pos1, MaxEdge=emerged_pos2})
|
||||||
|
|
||||||
|
--fill emerged area with ignore
|
||||||
|
local nodes = {}
|
||||||
|
local ignore = minetest.get_content_id("ignore")
|
||||||
|
for i = 1, worldedit.volume(emerged_pos1, emerged_pos2) do
|
||||||
|
nodes[i] = ignore
|
||||||
|
end
|
||||||
|
|
||||||
|
local miny, maxy = 0, radius
|
||||||
|
if radius < 0 then
|
||||||
|
radius = -radius
|
||||||
|
miny, maxy = -radius, 0
|
||||||
|
end
|
||||||
|
|
||||||
|
--fill selected area with node
|
||||||
|
local node_id = minetest.get_content_id(nodename)
|
||||||
|
local min_radius, max_radius = radius * (radius - 1), radius * (radius + 1)
|
||||||
|
local offsetx, offsety, offsetz = pos.x - emerged_pos1.x, pos.y - emerged_pos1.y, pos.z - emerged_pos1.z
|
||||||
|
local zstride, ystride = area.zstride, area.ystride
|
||||||
|
local count = 0
|
||||||
|
for z = -radius, radius do
|
||||||
|
local newz = (z + offsetz) * zstride + 1 --offset contributed by z plus 1 to make it 1-indexed
|
||||||
|
for y = miny, maxy do
|
||||||
|
local newy = newz + (y + offsety) * ystride
|
||||||
|
for x = -radius, radius do
|
||||||
|
local squared = x * x + y * y + z * z
|
||||||
|
if squared >= min_radius and squared <= max_radius then --position is on surface of sphere
|
||||||
|
local i = newy + (x + offsetx)
|
||||||
|
nodes[i] = node_id
|
||||||
|
count = count + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--update map nodes
|
||||||
|
manip:set_data(nodes)
|
||||||
|
manip:write_to_map()
|
||||||
|
manip:update_map()
|
||||||
|
|
||||||
|
return count
|
||||||
|
end
|
||||||
|
|
||||||
|
--adds a dome centered at `pos` with radius `radius`, composed of `nodename`, returning the number of nodes added
|
||||||
|
worldedit.dome = function(pos, radius, nodename)
|
||||||
|
--set up voxel manipulator
|
||||||
|
local manip = minetest.get_voxel_manip()
|
||||||
|
local pos1 = {x=pos.x - radius, y=pos.y, z=pos.z - radius}
|
||||||
|
local pos2 = {x=pos.x + radius, y=pos.y + radius, z=pos.z + radius}
|
||||||
|
local emerged_pos1, emerged_pos2 = manip:read_from_map(pos1, pos2)
|
||||||
|
local area = VoxelArea:new({MinEdge=emerged_pos1, MaxEdge=emerged_pos2})
|
||||||
|
|
||||||
|
--fill emerged area with ignore
|
||||||
|
local nodes = {}
|
||||||
|
local ignore = minetest.get_content_id("ignore")
|
||||||
|
for i = 1, worldedit.volume(emerged_pos1, emerged_pos2) do
|
||||||
|
nodes[i] = ignore
|
||||||
|
end
|
||||||
|
|
||||||
|
local miny, maxy = 0, radius
|
||||||
|
if radius < 0 then
|
||||||
|
radius = -radius
|
||||||
|
miny, maxy = -radius, 0
|
||||||
|
end
|
||||||
|
|
||||||
|
--fill selected area with node
|
||||||
|
local node_id = minetest.get_content_id(nodename)
|
||||||
|
local max_radius = radius * (radius + 1)
|
||||||
|
local offsetx, offsety, offsetz = pos.x - emerged_pos1.x, pos.y - emerged_pos1.y, pos.z - emerged_pos1.z
|
||||||
|
local zstride, ystride = area.zstride, area.ystride
|
||||||
|
local count = 0
|
||||||
|
for z = -radius, radius do
|
||||||
|
local newz = (z + offsetz) * zstride + 1 --offset contributed by z plus 1 to make it 1-indexed
|
||||||
|
for y = miny, maxy do
|
||||||
|
local newy = newz + (y + offsety) * ystride
|
||||||
|
for x = -radius, radius do
|
||||||
|
if x * x + y * y + z * z <= max_radius then --position is inside sphere
|
||||||
|
local i = newy + (x + offsetx)
|
||||||
|
nodes[i] = node_id
|
||||||
|
count = count + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--update map nodes
|
||||||
|
manip:set_data(nodes)
|
||||||
|
manip:write_to_map()
|
||||||
|
manip:update_map()
|
||||||
|
|
||||||
|
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) --wip: rewrite this using voxelmanip
|
||||||
|
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
|
||||||
|
|
||||||
|
--handle negative lengths
|
||||||
|
local currentpos = {x=pos.x, y=pos.y, z=pos.z}
|
||||||
|
if length < 0 then
|
||||||
|
length = -length
|
||||||
|
currentpos[axis] = currentpos[axis] - length
|
||||||
|
end
|
||||||
|
|
||||||
|
--make area stay loaded
|
||||||
|
local manip = minetest.get_voxel_manip()
|
||||||
|
local pos1 = {
|
||||||
|
[axis]=currentpos[axis],
|
||||||
|
[other1]=currentpos[other1] - radius,
|
||||||
|
[other2]=currentpos[other2] - radius
|
||||||
|
}
|
||||||
|
local pos2 = {
|
||||||
|
[axis]=currentpos[axis] + length - 1,
|
||||||
|
[other1]=currentpos[other1] + radius,
|
||||||
|
[other2]=currentpos[other2] + radius
|
||||||
|
}
|
||||||
|
manip:read_from_map(pos1, pos2)
|
||||||
|
|
||||||
|
--create schematic for single node column along the axis
|
||||||
|
local node = {name=nodename, param1=0, param2=0}
|
||||||
|
local nodes = {}
|
||||||
|
for i = 1, length do
|
||||||
|
nodes[i] = node
|
||||||
|
end
|
||||||
|
local schematic = {size={[axis]=length, [other1]=1, [other2]=1}, data=nodes}
|
||||||
|
|
||||||
|
--add columns in a circle around axis to form cylinder
|
||||||
|
local place_schematic = minetest.place_schematic
|
||||||
|
local count = 0
|
||||||
|
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
|
||||||
|
place_schematic(currentpos, schematic) --octant 1
|
||||||
|
currentpos[other1] = first2
|
||||||
|
place_schematic(currentpos, schematic) --octant 4
|
||||||
|
currentpos[other2] = second2
|
||||||
|
place_schematic(currentpos, schematic) --octant 5
|
||||||
|
currentpos[other1] = first1
|
||||||
|
place_schematic(currentpos, schematic) --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
|
||||||
|
place_schematic(currentpos, schematic) --octant 2
|
||||||
|
currentpos[other1] = first2
|
||||||
|
place_schematic(currentpos, schematic) --octant 3
|
||||||
|
currentpos[other2] = second2
|
||||||
|
place_schematic(currentpos, schematic) --octant 6
|
||||||
|
currentpos[other1] = first1
|
||||||
|
place_schematic(currentpos, schematic) --octant 7
|
||||||
|
|
||||||
|
count = count + 8 --wip: broken because sometimes currentpos is repeated
|
||||||
|
|
||||||
|
--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
|
||||||
|
count = count * length --apply the length to the number of nodes
|
||||||
|
return count
|
||||||
|
end
|
||||||
|
|
||||||
|
--adds a cylinder at `pos` along the `axis` axis ("x" or "y" or "z") with length `length` and radius `radius`, composed of `nodename`, returning the number of nodes added
|
||||||
|
worldedit.cylinder = function(pos, axis, length, radius, nodename)
|
||||||
|
local other1, other2
|
||||||
|
if axis == "x" then
|
||||||
|
other1, other2 = "y", "z"
|
||||||
|
elseif axis == "y" then
|
||||||
|
other1, other2 = "x", "z"
|
||||||
|
else --axis == "z"
|
||||||
|
other1, other2 = "x", "y"
|
||||||
|
end
|
||||||
|
|
||||||
|
--handle negative lengths
|
||||||
|
local currentpos = {x=pos.x, y=pos.y, z=pos.z}
|
||||||
|
if length < 0 then
|
||||||
|
length = -length
|
||||||
|
currentpos[axis] = currentpos[axis] - length
|
||||||
|
end
|
||||||
|
|
||||||
|
--set up voxel manipulator
|
||||||
|
local manip = minetest.get_voxel_manip()
|
||||||
|
local pos1 = {
|
||||||
|
[axis]=currentpos[axis],
|
||||||
|
[other1]=currentpos[other1] - radius,
|
||||||
|
[other2]=currentpos[other2] - radius
|
||||||
|
}
|
||||||
|
local pos2 = {
|
||||||
|
[axis]=currentpos[axis] + length - 1,
|
||||||
|
[other1]=currentpos[other1] + radius,
|
||||||
|
[other2]=currentpos[other2] + radius
|
||||||
|
}
|
||||||
|
local emerged_pos1, emerged_pos2 = manip:read_from_map(pos1, pos2)
|
||||||
|
local area = VoxelArea:new({MinEdge=emerged_pos1, MaxEdge=emerged_pos2})
|
||||||
|
|
||||||
|
--fill emerged area with ignore
|
||||||
|
local nodes = {}
|
||||||
|
local ignore = minetest.get_content_id("ignore")
|
||||||
|
for i = 1, worldedit.volume(emerged_pos1, emerged_pos2) do
|
||||||
|
nodes[i] = ignore
|
||||||
|
end
|
||||||
|
|
||||||
|
--fill selected area with node
|
||||||
|
local node_id = minetest.get_content_id(nodename)
|
||||||
|
local max_radius = radius * (radius + 1)
|
||||||
|
local stride = {x=1, y=area.ystride, z=area.zstride}
|
||||||
|
local offset = {x=currentpos.x - emerged_pos1.x, y=currentpos.y - emerged_pos1.y, z=currentpos.z - emerged_pos1.z}
|
||||||
|
local min_slice, max_slice = offset[axis], offset[axis] + length - 1
|
||||||
|
local count = 0
|
||||||
|
for index2 = -radius, radius do
|
||||||
|
local newindex2 = (index2 + offset[other1]) * stride[other1] + 1 --offset contributed by other axis 1 plus 1 to make it 1-indexed
|
||||||
|
for index3 = -radius, radius do
|
||||||
|
local newindex3 = newindex2 + (index3 + offset[other2]) * stride[other2]
|
||||||
|
if index2 * index2 + index3 * index3 <= max_radius then
|
||||||
|
for index1 = min_slice, max_slice do --add column along axis
|
||||||
|
local i = newindex3 + index1 * stride[axis]
|
||||||
|
nodes[i] = node_id
|
||||||
|
end
|
||||||
|
count = count + length
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--update map nodes
|
||||||
|
manip:set_data(nodes)
|
||||||
|
manip:write_to_map()
|
||||||
|
manip:update_map()
|
||||||
|
|
||||||
|
return count
|
||||||
|
end
|
||||||
|
|
||||||
|
--adds a pyramid centered at `pos` with height `height`, composed of `nodename`, returning the number of nodes added
|
||||||
|
worldedit.pyramid = function(pos, axis, height, nodename)
|
||||||
|
local other1, other2
|
||||||
|
if axis == "x" then
|
||||||
|
other1, other2 = "y", "z"
|
||||||
|
elseif axis == "y" then
|
||||||
|
other1, other2 = "x", "z"
|
||||||
|
else --axis == "z"
|
||||||
|
other1, other2 = "x", "y"
|
||||||
|
end
|
||||||
|
|
||||||
|
local pos1 = {x=pos.x - height, y=pos.y - height, z=pos.z - height}
|
||||||
|
local pos2 = {x=pos.x + height, y=pos.y + height, z=pos.z + height}
|
||||||
|
|
||||||
|
--handle inverted pyramids
|
||||||
|
local startaxis, endaxis, step
|
||||||
|
if height > 0 then
|
||||||
|
height = height - 1
|
||||||
|
step = 1
|
||||||
|
pos1[axis] = pos[axis] --upper half of box
|
||||||
|
else
|
||||||
|
height = height + 1
|
||||||
|
step = -1
|
||||||
|
pos2[axis] = pos[axis] --lower half of box
|
||||||
|
end
|
||||||
|
|
||||||
|
--set up voxel manipulator
|
||||||
|
local manip = minetest.get_voxel_manip()
|
||||||
|
local emerged_pos1, emerged_pos2 = manip:read_from_map(pos1, pos2)
|
||||||
|
local area = VoxelArea:new({MinEdge=emerged_pos1, MaxEdge=emerged_pos2})
|
||||||
|
|
||||||
|
--fill emerged area with ignore
|
||||||
|
local nodes = {}
|
||||||
|
local ignore = minetest.get_content_id("ignore")
|
||||||
|
for i = 1, worldedit.volume(emerged_pos1, emerged_pos2) do
|
||||||
|
nodes[i] = ignore
|
||||||
|
end
|
||||||
|
|
||||||
|
--fill selected area with node
|
||||||
|
local node_id = minetest.get_content_id(nodename)
|
||||||
|
local stride = {x=1, y=area.ystride, z=area.zstride}
|
||||||
|
local offset = {x=pos.x - emerged_pos1.x, y=pos.y - emerged_pos1.y, z=pos.z - emerged_pos1.z}
|
||||||
|
local size = height * step
|
||||||
|
local count = 0
|
||||||
|
for index1 = 0, height, step do --go through each level of the pyramid
|
||||||
|
local newindex1 = (index1 + offset[axis]) * stride[axis] + 1 --offset contributed by axis plus 1 to make it 1-indexed
|
||||||
|
for index2 = -size, size do
|
||||||
|
local newindex2 = newindex1 + (index2 + offset[other1]) * stride[other1]
|
||||||
|
for index3 = -size, size do
|
||||||
|
local i = newindex2 + (index3 + offset[other2]) * stride[other2]
|
||||||
|
nodes[i] = node_id
|
||||||
|
end
|
||||||
|
end
|
||||||
|
count = count + (size * 2 + 1) ^ 2
|
||||||
|
size = size - 1
|
||||||
|
end
|
||||||
|
|
||||||
|
--update map nodes
|
||||||
|
manip:set_data(nodes)
|
||||||
|
manip:write_to_map()
|
||||||
|
manip:update_map()
|
||||||
|
|
||||||
|
return count
|
||||||
|
end
|
||||||
|
|
||||||
|
--adds a spiral centered at `pos` with side length `length`, height `height`, space between walls `spacer`, composed of `nodename`, returning the number of nodes added
|
||||||
|
worldedit.spiral = function(pos, length, height, spacer, nodename)
|
||||||
|
local extent = math.ceil(length / 2)
|
||||||
|
local pos1 = {x=pos.x - extent, y=pos.y, z=pos.z - extent}
|
||||||
|
local pos2 = {x=pos.x + extent, y=pos.y + height, z=pos.z + extent}
|
||||||
|
|
||||||
|
--set up voxel manipulator
|
||||||
|
local manip = minetest.get_voxel_manip()
|
||||||
|
local emerged_pos1, emerged_pos2 = manip:read_from_map(pos1, pos2)
|
||||||
|
local area = VoxelArea:new({MinEdge=emerged_pos1, MaxEdge=emerged_pos2})
|
||||||
|
|
||||||
|
--fill emerged area with ignore
|
||||||
|
local nodes = {}
|
||||||
|
local ignore = minetest.get_content_id("ignore")
|
||||||
|
for i = 1, worldedit.volume(emerged_pos1, emerged_pos2) do
|
||||||
|
nodes[i] = ignore
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
local node_id = minetest.get_content_id(nodename)
|
||||||
|
local stride = {x=1, y=area.ystride, z=area.zstride}
|
||||||
|
local offsetx, offsety, offsetz = pos.x - emerged_pos1.x, pos.y - emerged_pos1.y, pos.z - emerged_pos1.z
|
||||||
|
local i = offsetz * stride.z + offsety * stride.y + offsetx + 1
|
||||||
|
|
||||||
|
--add first column
|
||||||
|
local column = i
|
||||||
|
for y = 1, height do
|
||||||
|
nodes[column] = node_id
|
||||||
|
column = column + stride.y
|
||||||
|
end
|
||||||
|
|
||||||
|
--add spiral segments
|
||||||
|
local axis, other = "x", "z"
|
||||||
|
local sign = 1
|
||||||
|
local count = height
|
||||||
|
for segment = 1, length / spacer - 1 do --go through each segment except the last
|
||||||
|
for index = 1, segment * spacer do --fill segment
|
||||||
|
i = i + stride[axis] * sign
|
||||||
|
local column = i
|
||||||
|
for y = 1, height do --add column
|
||||||
|
nodes[column] = node_id
|
||||||
|
column = column + stride.y
|
||||||
|
end
|
||||||
|
count = count + height
|
||||||
|
end
|
||||||
|
axis, other = other, axis --swap axes
|
||||||
|
if segment % 2 == 1 then --change sign every other turn
|
||||||
|
sign = -sign
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--add shorter final segment
|
||||||
|
for index = 1, (math.floor(length / spacer) - 2) * spacer do
|
||||||
|
i = i + stride[axis] * sign
|
||||||
|
local column = i
|
||||||
|
for y = 1, height do --add column
|
||||||
|
nodes[column] = node_id
|
||||||
|
column = column + stride.y
|
||||||
|
end
|
||||||
|
count = count + height
|
||||||
|
end
|
||||||
|
print(minetest.serialize(nodes))
|
||||||
|
--update map nodes
|
||||||
|
manip:set_data(nodes)
|
||||||
|
manip:write_to_map()
|
||||||
|
manip:update_map()
|
||||||
|
|
||||||
|
return count
|
||||||
|
end
|
273
worldedit/serialization.lua
Normal file
273
worldedit/serialization.lua
Normal file
@ -0,0 +1,273 @@
|
|||||||
|
worldedit = worldedit or {}
|
||||||
|
local minetest = minetest --local copy of global
|
||||||
|
|
||||||
|
--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)
|
||||||
|
--make area stay loaded
|
||||||
|
local manip = minetest.get_voxel_manip()
|
||||||
|
manip:read_from_map(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 get_node, get_meta = minetest.get_node, minetest.get_meta
|
||||||
|
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 = get_node(pos)
|
||||||
|
if node.name ~= "air" and node.name ~= "ignore" then
|
||||||
|
count = count + 1
|
||||||
|
local meta = 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 and stack:to_string() or stack
|
||||||
|
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
|
||||||
|
--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
|
||||||
|
table.insert(nodes, minetest.deserialize("return " .. value:sub(startpos1)))
|
||||||
|
|
||||||
|
--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]
|
||||||
|
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)
|
||||||
|
--make area stay loaded --wip: not very performant
|
||||||
|
local pos1, pos2 = worldedit.allocate(originpos, value)
|
||||||
|
local manip = minetest.get_voxel_manip()
|
||||||
|
manip:read_from_map(pos1, pos2)
|
||||||
|
|
||||||
|
local originx, originy, originz = originpos.x, originpos.y, originpos.z
|
||||||
|
local count = 0
|
||||||
|
local add_node, get_meta = minetest.add_node, minetest.get_meta
|
||||||
|
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
|
||||||
|
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
|
||||||
|
add_node(entry, entry) --entry acts both as position and as node
|
||||||
|
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, pos.y, pos.z = originx + tonumber(x), originy + tonumber(y), originz + tonumber(z)
|
||||||
|
node.name, node.param1, node.param2 = name, param1, param2
|
||||||
|
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
|
||||||
|
table.insert(nodes, minetest.deserialize("return " .. value:sub(startpos1)))
|
||||||
|
|
||||||
|
--local nodes = minetest.deserialize(value) --wip: this is broken for larger tables in the current version of LuaJIT
|
||||||
|
|
||||||
|
--load the nodes
|
||||||
|
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
|
||||||
|
add_node(entry, entry) --entry acts both as position and as node
|
||||||
|
end
|
||||||
|
|
||||||
|
--load the metadata
|
||||||
|
for index = 1, count do
|
||||||
|
local entry = nodes[index]
|
||||||
|
get_meta(entry):from_table(entry.meta)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return count
|
||||||
|
end
|
142
worldedit/visualization.lua
Normal file
142
worldedit/visualization.lua
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
worldedit = worldedit or {}
|
||||||
|
local minetest = minetest --local copy of global
|
||||||
|
|
||||||
|
--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)
|
||||||
|
--make area stay loaded
|
||||||
|
local manip = minetest.get_voxel_manip()
|
||||||
|
manip:read_from_map(pos1, pos2)
|
||||||
|
|
||||||
|
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||||
|
local pos = {x=pos1.x, y=0, z=0}
|
||||||
|
local get_node, get_meta, add_node = minetest.get_node, minetest.get_meta, minetest.add_node
|
||||||
|
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 = get_node(pos)
|
||||||
|
if node.name ~= "worldedit:placeholder" then
|
||||||
|
local data = get_meta(pos):to_table() --obtain metadata of original node
|
||||||
|
data.fields.worldedit_placeholder = node.name --add the node's name
|
||||||
|
node.name = "worldedit:placeholder" --set node name
|
||||||
|
add_node(pos, node) --add placeholder node
|
||||||
|
get_meta(pos):from_table(data) --set placeholder metadata to the original node's metadata
|
||||||
|
end
|
||||||
|
pos.z = pos.z + 1
|
||||||
|
end
|
||||||
|
pos.y = pos.y + 1
|
||||||
|
end
|
||||||
|
pos.x = pos.x + 1
|
||||||
|
end
|
||||||
|
return worldedit.volume(pos1, pos2)
|
||||||
|
end
|
||||||
|
|
||||||
|
--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)
|
||||||
|
--ignore placeholder supression
|
||||||
|
if nodename == "worldedit:placeholder" then
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
--make area stay loaded
|
||||||
|
local manip = minetest.get_voxel_manip()
|
||||||
|
manip:read_from_map(pos1, pos2)
|
||||||
|
|
||||||
|
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||||
|
local nodes = minetest.find_nodes_in_area(pos1, pos2, nodename)
|
||||||
|
local get_node, get_meta, add_node = minetest.get_node, minetest.get_meta, minetest.add_node
|
||||||
|
for _, pos in ipairs(nodes) do
|
||||||
|
local node = get_node(pos)
|
||||||
|
local data = get_meta(pos):to_table() --obtain metadata of original node
|
||||||
|
data.fields.worldedit_placeholder = node.name --add the node's name
|
||||||
|
node.name = "worldedit:placeholder" --set node name
|
||||||
|
add_node(pos, node) --add placeholder node
|
||||||
|
get_meta(pos):from_table(data) --set placeholder metadata to the original node's metadata
|
||||||
|
end
|
||||||
|
return #nodes
|
||||||
|
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)
|
||||||
|
--make area stay loaded
|
||||||
|
local manip = minetest.get_voxel_manip()
|
||||||
|
manip:read_from_map(pos1, pos2)
|
||||||
|
|
||||||
|
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||||
|
local pos = {x=pos1.x, y=0, z=0}
|
||||||
|
local get_node, get_meta, add_node = minetest.get_node, minetest.get_meta, minetest.add_node
|
||||||
|
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 = get_node(pos)
|
||||||
|
if node.name == nodename then --node found
|
||||||
|
count = count + 1
|
||||||
|
elseif node.name ~= "worldedit:placeholder" then --hide other nodes
|
||||||
|
local data = get_meta(pos):to_table() --obtain metadata of original node
|
||||||
|
data.fields.worldedit_placeholder = node.name --add the node's name
|
||||||
|
node.name = "worldedit:placeholder" --set node name
|
||||||
|
add_node(pos, node) --add placeholder node
|
||||||
|
get_meta(pos):from_table(data) --set placeholder metadata to the original node's metadata
|
||||||
|
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)
|
||||||
|
--make area stay loaded
|
||||||
|
local manip = minetest.get_voxel_manip()
|
||||||
|
manip:read_from_map(pos1, pos2)
|
||||||
|
|
||||||
|
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||||
|
local nodes = minetest.find_nodes_in_area(pos1, pos2, "worldedit:placeholder")
|
||||||
|
local get_node, get_meta, add_node = minetest.get_node, minetest.get_meta, minetest.add_node
|
||||||
|
for _, pos in ipairs(nodes) do
|
||||||
|
local node = get_node(pos)
|
||||||
|
local data = 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
|
||||||
|
add_node(pos, node) --add original node
|
||||||
|
get_meta(pos):from_table(data) --set original node metadata
|
||||||
|
end
|
||||||
|
return #nodes
|
||||||
|
end
|
1
worldedit_commands/depends.txt
Normal file
1
worldedit_commands/depends.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
worldedit
|
1163
worldedit_commands/init.lua
Normal file
1163
worldedit_commands/init.lua
Normal file
File diff suppressed because it is too large
Load Diff
125
worldedit_commands/mark.lua
Normal file
125
worldedit_commands/mark.lua
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
worldedit.marker1 = {}
|
||||||
|
worldedit.marker2 = {}
|
||||||
|
worldedit.marker = {}
|
||||||
|
|
||||||
|
--wip: use this as a huge entity to make a full worldedit region box
|
||||||
|
minetest.register_entity(":worldedit:region_cube", {
|
||||||
|
initial_properties = {
|
||||||
|
visual = "upright_sprite",
|
||||||
|
visual_size = {x=1.1, y=1.1},
|
||||||
|
textures = {"worldedit_pos1.png"},
|
||||||
|
visual_size = {x=10, y=10},
|
||||||
|
physical = false,
|
||||||
|
},
|
||||||
|
on_step = function(self, dtime)
|
||||||
|
if self.active == nil then
|
||||||
|
self.object:remove()
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
on_punch = function(self, hitter)
|
||||||
|
--wip: remove the entire region marker
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
--marks worldedit region position 1
|
||||||
|
worldedit.mark_pos1 = function(name)
|
||||||
|
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||||
|
|
||||||
|
if pos1 ~= nil then
|
||||||
|
--make area stay loaded
|
||||||
|
local manip = minetest.get_voxel_manip()
|
||||||
|
manip:read_from_map(pos1, pos1)
|
||||||
|
end
|
||||||
|
if worldedit.marker1[name] ~= nil then --marker already exists
|
||||||
|
worldedit.marker1[name]:remove() --remove marker
|
||||||
|
worldedit.marker1[name] = nil
|
||||||
|
end
|
||||||
|
if pos1 ~= nil then
|
||||||
|
--add marker
|
||||||
|
worldedit.marker1[name] = minetest.add_entity(pos1, "worldedit:pos1")
|
||||||
|
worldedit.marker1[name]:get_luaentity().active = true
|
||||||
|
if pos2 ~= nil then --region defined
|
||||||
|
worldedit.mark_region(pos1, pos2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--marks worldedit region position 2
|
||||||
|
worldedit.mark_pos2 = function(name)
|
||||||
|
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
|
||||||
|
|
||||||
|
if pos2 ~= nil then
|
||||||
|
--make area stay loaded
|
||||||
|
local manip = minetest.get_voxel_manip()
|
||||||
|
manip:read_from_map(pos2, pos2)
|
||||||
|
end
|
||||||
|
if worldedit.marker2[name] ~= nil then --marker already exists
|
||||||
|
worldedit.marker2[name]:remove() --remove marker
|
||||||
|
worldedit.marker2[name] = nil
|
||||||
|
end
|
||||||
|
if pos2 ~= nil then
|
||||||
|
--add marker
|
||||||
|
worldedit.marker2[name] = minetest.add_entity(pos2, "worldedit:pos2")
|
||||||
|
worldedit.marker2[name]:get_luaentity().active = true
|
||||||
|
if pos1 ~= nil then --region defined
|
||||||
|
worldedit.mark_region(pos1, pos2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
worldedit.mark_region = function(pos1, pos2)
|
||||||
|
--make area stay loaded
|
||||||
|
local manip = minetest.get_voxel_manip()
|
||||||
|
manip:read_from_map(pos1, pos2)
|
||||||
|
|
||||||
|
if worldedit.marker[name] ~= nil then --marker already exists
|
||||||
|
--wip: remove markers
|
||||||
|
end
|
||||||
|
if pos1 ~= nil and pos2 ~= nil then
|
||||||
|
--wip: place markers
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_entity(":worldedit:pos1", {
|
||||||
|
initial_properties = {
|
||||||
|
visual = "cube",
|
||||||
|
visual_size = {x=1.1, y=1.1},
|
||||||
|
textures = {"worldedit_pos1.png", "worldedit_pos1.png",
|
||||||
|
"worldedit_pos1.png", "worldedit_pos1.png",
|
||||||
|
"worldedit_pos1.png", "worldedit_pos1.png"},
|
||||||
|
collisionbox = {-0.55, -0.55, -0.55, 0.55, 0.55, 0.55},
|
||||||
|
physical = false,
|
||||||
|
},
|
||||||
|
on_step = function(self, dtime)
|
||||||
|
if self.active == nil then
|
||||||
|
self.object:remove()
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
on_punch = function(self, hitter)
|
||||||
|
self.object:remove()
|
||||||
|
local name = hitter:get_player_name()
|
||||||
|
worldedit.marker1[name] = nil
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_entity(":worldedit:pos2", {
|
||||||
|
initial_properties = {
|
||||||
|
visual = "cube",
|
||||||
|
visual_size = {x=1.1, y=1.1},
|
||||||
|
textures = {"worldedit_pos2.png", "worldedit_pos2.png",
|
||||||
|
"worldedit_pos2.png", "worldedit_pos2.png",
|
||||||
|
"worldedit_pos2.png", "worldedit_pos2.png"},
|
||||||
|
collisionbox = {-0.55, -0.55, -0.55, 0.55, 0.55, 0.55},
|
||||||
|
physical = false,
|
||||||
|
},
|
||||||
|
on_step = function(self, dtime)
|
||||||
|
if self.active == nil then
|
||||||
|
self.object:remove()
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
on_punch = function(self, hitter)
|
||||||
|
self.object:remove()
|
||||||
|
local name = hitter:get_player_name()
|
||||||
|
worldedit.marker2[name] = nil
|
||||||
|
end,
|
||||||
|
})
|
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