1
0
mirror of https://github.com/Uberi/Minetest-WorldEdit.git synced 2025-06-29 22:50:46 +02:00

37 Commits
0.6 ... 1.0

Author SHA1 Message Date
03327a767d Add version checker since so many people are confused about which version to use. 2013-08-06 16:28:05 -04:00
8bd5db51b2 Final changes and version number bump. 2013-08-01 23:53:38 -04:00
416ffb3709 Fix //pyramid examples. 2013-07-31 22:29:01 -04:00
040282bbe6 New module loader properly halts when load-time error occurs in module. 2013-07-31 22:15:52 -04:00
b0bf52e9b6 Rewrite spirals from scratch and fix upside-down pyramids. Use voxelmanip for markers to ensure area is emerged. 2013-07-31 22:15:08 -04:00
3c51ec8c4a //pyramid works along any axis and backwards. Working //clearobjects and //cylinder command, begin implementing super marker. Remove EnvRef usages and the block queue (the block queue does not work with VoxelManips). More block emergers. 2013-07-31 00:02:37 -04:00
49b683f27f Support negative values to make upside-down domes and pyramids (slight changes to worldedit.pyramid interface for coming changes). Add experimental //clearobjects, make node inspector work per-player. 2013-07-29 12:43:24 -04:00
c1f3cfc1e4 Fix bugs in visualization API and make it ore robust. Fix bugs in //fixedpos, //suppress, and //highlight. 2013-07-28 18:15:46 -04:00
b252df2166 Slight optimizations, and make //pyramid work properly again. 2013-07-28 17:08:12 -04:00
7e1be63344 Add //fixedpos command and document it. 2013-07-28 17:07:47 -04:00
faa4a7b065 More speedups for //hollowsphere, //sphere, //hollowdome, //dome, //cylinder, better module loader, fix message in //volume. 2013-07-27 21:34:42 -04:00
8b9054a1cc Add tutorial for new users, and a note about compatibility. 2013-07-25 16:09:00 -04:00
dfcf02bbc2 Add a few notes on air. 2013-07-22 11:04:03 -04:00
0fddd17f23 Add the node inspector, a tool for finding information about nodes. Configurable via the //inspect command. 2013-07-21 17:16:29 -04:00
e550604747 Add a section about the different types of schematics. 2013-07-21 17:15:04 -04:00
8ebf9d3c2a Super duper VoxelManipulator speedups to nearly every API function, and plus support for unloaded areas. Still in progress. Also, fix //allocate for very large schematics. 2013-07-21 16:54:25 -04:00
ac5e801834 Even bigger speed gains by using LuaVoxelManipulator in a few choice places! Faster //set, //cylinder, etc., but plenty of room for improvements still. 2013-07-12 14:22:30 -04:00
b6bc841c39 Fix volume of spheres, domes, and their hollow variants. 2013-06-24 18:22:01 -04:00
48009b6c62 Support aliases in node name resolution. For example, //set mapgen_dirt. Technique outlined by kharl in IRC. 2013-06-24 17:13:10 -04:00
9db6192eba Avoid using slower and deprecated EnvRef, fix schematic data MapNodes, huge speed boost to worldedit.hollow_cylinder, fix some bugs. 2013-06-23 12:46:59 -04:00
1e5f623cbb Super-speed a few primitives and visualization functions, including hollowsphere, sphere, hollowdome, dome, and suppress. 2013-06-22 23:08:51 -04:00
58970e7fab Clarify the documentation regarding the the positioning of WorldEdit primitives relative to position 1. 2013-06-22 23:05:34 -04:00
7070f81c59 Significant but highly experimental speed-ups for worldedit.set, replace, and scale, plus preparation for more. 2013-06-22 20:59:23 -04:00
a192d51a58 Add initial support for Minetest schematic API
Thanks to kwolekr for the code
2013-06-22 08:25:59 +02:00
d4187866db Add //scale <factor> command (suggested by Jordach), fix transposition description in docs. 2013-06-18 15:05:49 -04:00
74018dab99 Support descriptions and partial node names in chat commands (e.g., //set blue lightstone, //replace piston_normal_off bronze block). 2013-06-12 19:59:13 -04:00
f1cfc47189 Fix //rotate for real this time. 2013-06-02 17:50:14 -04:00
0664cde287 Fix //rotate, improve queue (order now preserved), typos fixed (quene -> queue). 2013-05-30 20:38:56 -04:00
f952ee4740 Block queue doesn't lag anymore on slow operations like digging and placing nodes, better and more efficient //fixlight. 2013-05-30 19:13:21 -04:00
a1dcc43210 Fix //move again 2013-05-20 20:48:12 +02:00
d7ae19b7b8 Fix the //move command (WorldEdit API is unaffected). 2013-05-18 19:00:12 -04:00
52c1379bce Make chat messages consistent. 2013-05-15 17:52:12 -04:00
d52f3d649e Add //unmark chat command, fix position setting not being reset by //reset. 2013-05-15 17:03:26 -04:00
cedecac3f8 Merge remote-tracking branch 'refs/remotes/origin/master' 2013-05-02 18:20:59 -04:00
18bc4e6815 Fix deserialization for real this time. 2013-04-29 19:52:00 -04:00
9e1c2614d3 Update Copyright Year 2013-04-29 14:34:55 +03:00
98c5bc5c5f Fix loading of schematics containing chests that had empty slots. 2013-04-28 19:01:24 -04:00
14 changed files with 1587 additions and 939 deletions

View File

@ -2,6 +2,21 @@ 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.
@ -14,6 +29,12 @@ 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.
@ -35,6 +56,14 @@ Set WorldEdit region, WorldEdit position 1, or WorldEdit position 2 by punching
//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.
@ -45,93 +74,95 @@ Display the volume of the current WorldEdit region.
Set the current WorldEdit region to <node>.
//set dirt
//set default:glass
//set mesecons:mesecon
//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 cobble stone
//replace default:steelblock glass
//replace dirt flowers:flower_waterlily
//replace flowers:flower_rose flowers:flower_tulip
//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 air stone
//replaceinverse water_source default:dirt
//replaceinverse mesecons:mesecon air
//replaceinverse default:steelblock default:glass
//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 at WorldEdit position 1 with radius <radius>, composed of <node>.
Add hollow sphere centered at WorldEdit position 1 with radius <radius>, composed of <node>.
//hollowsphere 5 dirt
//hollowsphere 12 default:glass
//hollowsphere 17 mesecons:mesecon
//hollowsphere 5 Diamond Block
//hollowsphere 12 glass
//hollowsphere 17 mesecons:wire_00000000_off
### //sphere <radius> <node>
Add sphere at WorldEdit position 1 with radius <radius>, composed of <node>.
Add sphere centered at WorldEdit position 1 with radius <radius>, composed of <node>.
//sphere 5 dirt
//sphere 12 default:glass
//sphere 17 mesecons:mesecon
//sphere 5 Diamond Block
//sphere 12 glass
//sphere 17 mesecons:wire_00000000_off
### //hollowdome <radius> <node>
Add hollow dome at WorldEdit position 1 with radius <radius>, composed of <node>.
Add hollow dome centered at WorldEdit position 1 with radius <radius>, composed of <node>.
//hollowdome 5 dirt
//hollowdome 12 default:glass
//hollowdome 17 mesecons:mesecon
//hollowdome 5 Diamond Block
//hollowdome -12 glass
//hollowdome 17 mesecons:wire_00000000_off
### //dome <radius> <node>
Add dome at WorldEdit position 1 with radius <radius>, composed of <node>.
Add dome centered at WorldEdit position 1 with radius <radius>, composed of <node>.
//dome 5 dirt
//dome 12 default:glass
//dome 17 mesecons:mesecon
//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 dirt
//hollowcylinder y 28 10 default:glass
//hollowcylinder z -12 3 mesecons:mesecon
//hollowcylinder ? 2 4 stone
//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 dirt
//cylinder y 28 10 default:glass
//cylinder z -12 3 mesecons:mesecon
//cylinder ? 2 4 stone
//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 <height> <node>
### //pyramid x/y/z? <height> <node>
Add pyramid at WorldEdit position 1 with height <height>, composed of <node>.
Add pyramid centered at WorldEdit position 1 along the x/y/z/? axis with height <height>, composed of <node>.
//pyramid 8 dirt
//pyramid 5 default:glass
//pyramid 2 stone
//pyramid x 8 Diamond Block
//pyramid y -5 glass
//pyramid z 2 mesecons:wire_00000000_off
//pyramid ? 12 mesecons:wire_00000000_off
### //spiral <width> <height> <spacer> <node>
### //spiral <length> <height> <spacer> <node>
Add spiral at WorldEdit position 1 with width <width>, height <height>, space between walls <spacer>, composed of <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 dirt
//spiral 5 2 1 default:glass
//spiral 7 1 5 stone
//spiral 20 5 3 Diamond Block
//spiral 5 2 1 glass
//spiral 7 1 5 mesecons:wire_00000000_off
### //copy x/y/z/? <amount>
@ -160,6 +191,14 @@ Stack the current WorldEdit region along the x/y/z/? axis <count> times.
//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.
@ -212,17 +251,17 @@ Hide all nodes in the current WorldEdit region non-destructively.
Suppress all <node> in the current WorldEdit region non-destructively.
//suppress dirt
//suppress default:glass
//suppress mesecons:mesecon
//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 dirt
//highlight default:glass
//highlight mesecons:mesecon
//highlight Diamond Block
//highlight glass
//highlight mesecons:wire_00000000_off
### //restore
@ -262,5 +301,32 @@ Executes <code> as a Lua chunk in the global namespace.
Executes <code> as a Lua chunk in the global namespace with the variable pos available, for each node in the current WorldEdit region.
//luatransform minetest.env:add_node(pos, {name="default:stone"})
//luatransform if minetest.env:get_node(pos).name == "air" then minetest.env:add_node(pos, {name="default:water_source"})
//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

View File

@ -1,8 +1,10 @@
WorldEdit v0.6 for MineTest 0.4
===============================
In-game world editing for [MineTest](http://minetest.net/)! Tons of chat commands to help with building, fixing, and more.
WorldEdit v1.0 for MineTest 0.4.8+
==================================
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
-----
@ -12,6 +14,30 @@ 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.
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.
@ -20,9 +46,21 @@ When an axis is specified in a WorldEdit command, it is specified as one of the
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
-------
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.
@ -34,21 +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.
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).
Schematics
----------
WorldEdit supports two different types of schematics.
If visual manipulation of nodes is desired, the [WorldEdit GUI](http://minetest.net/forum/viewtopic.php?id=3112) mod provides a simple interface with buttons and text entry fields for this purpose.
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.
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. The API is useful for tasks such as high-performance node manipulation, alternative interfaces, and map creation.
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:
This API is documented in the [WorldEdit API Reference](WorldEdit API.md).
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>,
},
<...>
}
Value ordering and minor aspects of the syntax, such as trailing commas or newlines, are not guaranteed.
The WorldEdit Schematic format is accessed via the WorldEdit API, or WorldEdit serialization chat commands such as `//serialize` and `//deserialize`.
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`.
License
-------
Copyright 2012 sfan5, Anthony Zhang (Temperest), and Brett O'Donnell (cornernote).
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).

55
Tutorial.md Normal file
View 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.

View File

@ -46,11 +46,17 @@ Duplicates the region defined by positions `pos1` and `pos2` along the `axis` ax
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 position 1, and the new position 2.
Returns the number of nodes transposed, the new transposed position 1, and the new transposed position 2.
### count = worldedit.flip(pos1, pos2, axis)
@ -76,31 +82,37 @@ 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 at `pos` with radius `radius`, composed of `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 at `pos` with radius `radius`, composed of `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 at `pos` with radius `radius`, composed of `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 at `pos` with radius `radius`, composed of `nodename`.
Adds a dome centered at `pos` with radius `radius`, composed of `nodename`.
Returns the number of nodes added.
@ -116,15 +128,15 @@ Adds a cylinder at `pos` along the `axis` axis ("x" or "y" or "z") with length `
Returns the number of nodes added.
### count = worldedit.pyramid(pos, height, nodename)
### count = worldedit.pyramid(pos, axis, height, nodename)
Adds a pyramid at `pos` with height `height`.
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, width, height, spacer, nodename)
### count = worldedit.spiral(pos, length, height, spacer, nodename)
Adds a spiral at `pos` with width `width`, height `height`, space between walls `spacer`, composed of `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.
@ -202,6 +214,6 @@ 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`.
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.

View File

@ -1,4 +1,5 @@
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)
@ -23,6 +24,10 @@ worldedit.luatransform = function(pos1, pos2, code)
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

View File

@ -1,4 +1,5 @@
worldedit = worldedit or {}
local minetest = minetest --local copy of global
worldedit.allocate_old = worldedit.allocate
worldedit.deserialize_old = worldedit.deserialize
@ -16,4 +17,4 @@ worldedit.metaload = function(originpos, filename)
if err then return 0 end
local data = file:read("*a")
return worldedit.deserialize(originpos, data)
end
end

View File

@ -1,9 +1,14 @@
local path = minetest.get_modpath("worldedit")
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)
return pcall(function()
dofile(path)
end)
local file = io.open(path)
if not file then
return
end
file:close()
return dofile(path)
end
loadmodule(path .. "/manipulations.lua")
@ -12,4 +17,3 @@ loadmodule(path .. "/visualization.lua")
loadmodule(path .. "/serialization.lua")
loadmodule(path .. "/code.lua")
loadmodule(path .. "/compatibility.lua")
loadmodule(path .. "/queue.lua")

View File

@ -1,4 +1,5 @@
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)
@ -23,93 +24,154 @@ worldedit.volume = function(pos1, pos2)
end
--sets a region defined by positions `pos1` and `pos2` to `nodename`, returning the number of nodes filled
worldedit.set = function(pos1, pos2, nodename, env)
worldedit.set = function(pos1, pos2, nodename)
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
if env == nil then env = minetest.env end
local node = {name=nodename}
local pos = {x=pos1.x, y=0, z=0}
while pos.x <= pos2.x do
pos.y = pos1.y
while pos.y <= pos2.y do
pos.z = pos1.z
while pos.z <= pos2.z do
env:add_node(pos, node)
pos.z = pos.z + 1
end
pos.y = pos.y + 1
end
pos.x = pos.x + 1
--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, env)
worldedit.replace = function(pos1, pos2, searchnode, replacenode)
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
if env == nil then env = minetest.env end
if minetest.registered_nodes[searchnode] == nil then
searchnode = "default:" .. searchnode
end
--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 pos = {x=pos1.x, y=0, z=0}
local node = {name=replacenode}
local nodes = manip:get_data()
local searchnode_id = minetest.get_content_id(searchnode)
local replacenode_id = minetest.get_content_id(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
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
pos.x = pos.x + 1
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, env)
worldedit.replaceinverse = function(pos1, pos2, searchnode, replacenode)
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
if env == nil then env = minetest.env end
if minetest.registered_nodes[searchnode] == nil then
searchnode = "default:" .. searchnode
end
--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 pos = {x=pos1.x, y=0, z=0}
local node = {name=replacenode}
local nodes = manip:get_data()
local searchnode_id = minetest.get_content_id(searchnode)
local replacenode_id = minetest.get_content_id(replacenode)
local count = 0
while pos.x <= pos2.x do
pos.y = pos1.y
while pos.y <= pos2.y do
pos.z = pos1.z
while pos.z <= pos2.z do
local name = env:get_node(pos).name
if name ~= "ignore" and name ~= searchnode then
env:add_node(pos, node)
count = count + 1
end
pos.z = pos.z + 1
end
pos.y = pos.y + 1
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
pos.x = pos.x + 1
end
--update map nodes
manip:set_data(nodes)
manip:write_to_map()
manip:update_map()
return count
end
--copies the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") by `amount` nodes, returning the number of nodes copied
worldedit.copy = function(pos1, pos2, axis, amount, env)
worldedit.copy = function(pos1, pos2, axis, amount)
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
if env == nil then env = minetest.env end
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
@ -117,12 +179,12 @@ worldedit.copy = function(pos1, pos2, axis, amount, env)
while pos.y <= pos2.y do
pos.z = pos1.z
while pos.z <= pos2.z do
local node = env:get_node(pos) --obtain current node
local meta = env:get_meta(pos):to_table() --get meta of current node
local 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
env:add_node(pos, node) --copy node to new position
env:get_meta(pos):from_table(meta) --set metadata of new node
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
@ -137,12 +199,12 @@ worldedit.copy = function(pos1, pos2, axis, amount, env)
while pos.y >= pos1.y do
pos.z = pos2.z
while pos.z >= pos1.z do
local node = minetest.env:get_node(pos) --obtain current node
local meta = env:get_meta(pos):to_table() --get meta of current node
local 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
minetest.env:add_node(pos, node) --copy node to new position
env:get_meta(pos):from_table(meta) --set metadata of new node
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
@ -155,10 +217,15 @@ worldedit.copy = function(pos1, pos2, axis, amount, env)
end
--moves the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") by `amount` nodes, returning the number of nodes moved
worldedit.move = function(pos1, pos2, axis, amount, env)
worldedit.move = function(pos1, pos2, axis, amount)
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
if env == nil then env = minetest.env end
--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
@ -166,13 +233,13 @@ worldedit.move = function(pos1, pos2, axis, amount, env)
while pos.y <= pos2.y do
pos.z = pos1.z
while pos.z <= pos2.z do
local node = env:get_node(pos) --obtain current node
local meta = env:get_meta(pos):to_table() --get metadata of current node
env:remove_node(pos)
local 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
env:add_node(pos, node) --move node to new position
env:get_meta(pos):from_table(meta) --set metadata of new node
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
@ -187,13 +254,13 @@ worldedit.move = function(pos1, pos2, axis, amount, env)
while pos.y >= pos1.y do
pos.z = pos2.z
while pos.z >= pos1.z do
local node = env:get_node(pos) --obtain current node
local meta = env:get_meta(pos):to_table() --get metadata of current node
env:remove_node(pos)
local 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
env:add_node(pos, node) --move node to new position
env:get_meta(pos):from_table(meta) --set metadata of new node
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
@ -206,7 +273,7 @@ worldedit.move = function(pos1, pos2, axis, amount, env)
end
--duplicates the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") `count` times, returning the number of nodes stacked
worldedit.stack = function(pos1, pos2, axis, count, env)
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
@ -217,13 +284,72 @@ worldedit.stack = function(pos1, pos2, axis, count, env)
local copy = worldedit.copy
for i = 1, count do
amount = amount + length
copy(pos1, pos2, axis, amount, env)
copy(pos1, pos2, axis, amount)
end
return worldedit.volume(pos1, pos2)
return worldedit.volume(pos1, pos2) * count
end
--transposes a region defined by the positions `pos1` and `pos2` between the `axis1` and `axis2` axes, returning the number of nodes transposed, the new position 1, and the new position 2
worldedit.transpose = function(pos1, pos2, axis1, axis2, env)
--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
@ -240,12 +366,19 @@ worldedit.transpose = function(pos1, pos2, axis1, axis2, env)
end
--calculate the new position 2 after transposition
local newpos2 = {x=pos2.x, y=pos2.y, z=pos2.z}
newpos2[axis1] = pos1[axis1] + extent2
newpos2[axis2] = pos1[axis2] + extent1
local 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}
if env == nil then env = minetest.env end
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
@ -253,17 +386,17 @@ worldedit.transpose = function(pos1, pos2, axis1, axis2, env)
while pos.z <= pos2.z do
local extent1, extent2 = pos[axis1] - pos1[axis1], pos[axis2] - pos1[axis2]
if compare(extent1, extent2) then --transpose only if below the diagonal
local node1 = env:get_node(pos)
local meta1 = env:get_meta(pos):to_table()
local 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 = env:get_node(pos)
local meta2 = env:get_meta(pos):to_table()
env:add_node(pos, node1)
env:get_meta(pos):from_table(meta1)
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
env:add_node(pos, node2)
env:get_meta(pos):from_table(meta2)
add_node(pos, node2)
get_meta(pos):from_table(meta2)
end
pos.z = pos.z + 1
end
@ -271,33 +404,38 @@ worldedit.transpose = function(pos1, pos2, axis1, axis2, env)
end
pos.x = pos.x + 1
end
return worldedit.volume(pos1, pos2), pos1, newpos2
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, env)
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)
if env == nil then env = minetest.env end
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 = env:get_node(pos)
local meta1 = env:get_meta(pos):to_table()
local node1 = get_node(pos)
local meta1 = get_meta(pos):to_table()
local value = pos[axis]
pos[axis] = start - value
local node2 = env:get_node(pos)
local meta2 = env:get_meta(pos):to_table()
env:add_node(pos, node1)
env:get_meta(pos):from_table(meta1)
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
env:add_node(pos, node2)
env:get_meta(pos):from_table(meta2)
add_node(pos, node2)
get_meta(pos):from_table(meta2)
pos.z = pos.z + 1
end
pos.y = pos.y + 1
@ -308,7 +446,7 @@ worldedit.flip = function(pos1, pos2, axis, env)
end
--rotates a region defined by the positions `pos1` and `pos2` by `angle` degrees clockwise around axis `axis` (90 degree increment), returning the number of nodes rotated
worldedit.rotate = function(pos1, pos2, axis, angle, env)
worldedit.rotate = function(pos1, pos2, axis, angle)
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
local axis1, axis2
@ -323,23 +461,23 @@ worldedit.rotate = function(pos1, pos2, axis, angle, env)
local count
if angle == 90 then
worldedit.flip(pos1, pos2, axis1, env)
count, pos1, pos2 = worldedit.transpose(pos1, pos2, axis1, axis2, env)
worldedit.flip(pos1, pos2, axis1)
count, pos1, pos2 = worldedit.transpose(pos1, pos2, axis1, axis2)
elseif angle == 180 then
worldedit.flip(pos1, pos2, axis1, env)
count = worldedit.flip(pos1, pos2, axis2, env)
worldedit.flip(pos1, pos2, axis1)
count = worldedit.flip(pos1, pos2, axis2)
elseif angle == 270 then
worldedit.flip(pos1, pos2, axis2, env)
count, pos1, pos2 = worldedit.transpose(pos1, pos2, axis1, axis2, env)
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, env)
worldedit.orient = function(pos1, pos2, angle) --wip: support 6D facedir rotation along arbitrary axis
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
local nodes = minetest.registered_nodes
if env == nil then env = minetest.env end
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},
@ -358,27 +496,32 @@ worldedit.orient = function(pos1, pos2, angle, env)
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 = env:get_node(pos)
local def = nodes[node.name]
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 = env:get_meta(pos):to_table()
env:add_node(pos, node)
env:get_meta(pos):from_table(meta)
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 = env:get_meta(pos):to_table()
env:add_node(pos, node)
env:get_meta(pos):from_table(meta)
local meta = get_meta(pos):to_table()
add_node(pos, node)
get_meta(pos):from_table(meta)
count = count + 1
end
end
@ -392,26 +535,45 @@ worldedit.orient = function(pos1, pos2, angle, env)
end
--fixes the lighting in a region defined by positions `pos1` and `pos2`, returning the number of nodes updated
worldedit.fixlight = function(pos1, pos2, env)
worldedit.fixlight = function(pos1, pos2)
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
if env == nil then env = minetest.env end
local count = 0
local pos = {x=pos1.x, y=0, z=0}
while pos.x <= pos2.x do
pos.y = pos1.y
while pos.y <= pos2.y do
pos.z = pos1.z
while pos.z <= pos2.z do
if env:get_node(pos).name == "air" then
env:dig_node(pos)
count = count + 1
end
pos.z = pos.z + 1
--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
pos.y = pos.y + 1
end
pos.x = pos.x + 1
end
return count
end

View File

@ -1,101 +1,198 @@
worldedit = worldedit or {}
local minetest = minetest --local copy of global
--adds a hollow sphere at `pos` with radius `radius`, composed of `nodename`, returning the number of nodes added
worldedit.hollow_sphere = function(pos, radius, nodename, env)
local node = {name=nodename}
local pos1 = {x=0, y=0, z=0}
local min_radius = radius * (radius - 1)
local max_radius = radius * (radius + 1)
--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
if env == nil then env = minetest.env end
for x = -radius, radius do
pos1.x = pos.x + x
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
pos1.y = pos.y + y
for z = -radius, radius do
if x*x+y*y+z*z >= min_radius and x*x+y*y+z*z <= max_radius then
pos1.z = pos.z + z
env:add_node(pos1, node)
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 at `pos` with radius `radius`, composed of `nodename`, returning the number of nodes added
worldedit.sphere = function(pos, radius, nodename, env)
local node = {name=nodename}
local pos1 = {x=0, y=0, z=0}
--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
if env == nil then env = minetest.env end
for x = -radius, radius do
pos1.x = pos.x + x
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
pos1.y = pos.y + y
for z = -radius, radius do
if x*x+y*y+z*z <= max_radius then
pos1.z = pos.z + z
env:add_node(pos1, node)
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 at `pos` with radius `radius`, composed of `nodename`, returning the number of nodes added
worldedit.hollow_dome = function(pos, radius, nodename, env) --wip: use bresenham sphere for maximum speed
local node = {name=nodename}
local pos1 = {x=0, y=0, z=0}
local min_radius = radius * (radius - 1)
local max_radius = radius * (radius + 1)
--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
if env == nil then env = minetest.env end
for x = -radius, radius do
pos1.x = pos.x + x
for y = 0, radius do
pos1.y = pos.y + y
for z = -radius, radius do
if x*x+y*y+z*z >= min_radius and x*x+y*y+z*z <= max_radius then
pos1.z = pos.z + z
env:add_node(pos1, node)
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 at `pos` with radius `radius`, composed of `nodename`, returning the number of nodes added
worldedit.dome = function(pos, radius, nodename, env) --wip: use bresenham sphere for maximum speed
local node = {name=nodename}
local pos1 = {x=0, y=0, z=0}
--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
if env == nil then env = minetest.env end
for x = -radius, radius do
pos1.x = pos.x + x
for y = 0, radius do
pos1.y = pos.y + y
for z = -radius, radius do
if x*x+y*y+z*z <= max_radius then
pos1.z = pos.z + z
env:add_node(pos1, node)
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, env)
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"
@ -105,58 +202,79 @@ worldedit.hollow_cylinder = function(pos, axis, length, radius, nodename, env)
other1, other2 = "x", "y"
end
if env == nil then env = minetest.env end
--handle negative lengths
local currentpos = {x=pos.x, y=pos.y, z=pos.z}
local node = {name=nodename}
local count = 0
local step = 1
if length < 0 then
length = -length
step = -1
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
local offset1, offset2 = 0, radius
local delta = -radius
while offset1 <= offset2 do
--add node at each octant
local first1, first2 = pos[other1] + offset1, pos[other1] - offset1
local second1, second2 = pos[other2] + offset2, pos[other2] - offset2
currentpos[other1], currentpos[other2] = first1, second1
env:add_node(currentpos, node) --octant 1
currentpos[other1] = first2
env:add_node(currentpos, node) --octant 4
currentpos[other2] = second2
env:add_node(currentpos, node) --octant 5
currentpos[other1] = first1
env:add_node(currentpos, node) --octant 8
local first1, first2 = pos[other1] + offset2, pos[other1] - offset2
local second1, second2 = pos[other2] + offset1, pos[other2] - offset1
currentpos[other1], currentpos[other2] = first1, second1
env:add_node(currentpos, node) --octant 2
currentpos[other1] = first2
env:add_node(currentpos, node) --octant 3
currentpos[other2] = second2
env:add_node(currentpos, node) --octant 6
currentpos[other1] = first1
env:add_node(currentpos, node) --octant 7
count = count + 8 --wip: broken
--move to next location
delta = delta + (offset1 * 2) + 1
if delta >= 0 then
offset2 = offset2 - 1
delta = delta - (offset2 * 2)
end
offset1 = offset1 + 1
end
currentpos[axis] = currentpos[axis] + step
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, env)
worldedit.cylinder = function(pos, axis, length, radius, nodename)
local other1, other2
if axis == "x" then
other1, other2 = "y", "z"
@ -166,146 +284,195 @@ worldedit.cylinder = function(pos, axis, length, radius, nodename, env)
other1, other2 = "x", "y"
end
if env == nil then env = minetest.env end
--handle negative lengths
local currentpos = {x=pos.x, y=pos.y, z=pos.z}
local node = {name=nodename}
local count = 0
local step = 1
if length < 0 then
length = -length
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
for i = 1, length do
local offset1, offset2 = 0, radius
local delta = -radius
while offset1 <= offset2 do
--connect each pair of octants
currentpos[other1] = pos[other1] - offset1
local second1, second2 = pos[other2] + offset2, pos[other2] - offset2
for i = 0, offset1 * 2 do
currentpos[other2] = second1
env:add_node(currentpos, node) --octant 1 to 4
currentpos[other2] = second2
env:add_node(currentpos, node) --octant 5 to 8
currentpos[other1] = currentpos[other1] + 1
end
currentpos[other1] = pos[other1] - offset2
local second1, second2 = pos[other2] + offset1, pos[other2] - offset1
for i = 0, offset2 * 2 do
currentpos[other2] = second1
env:add_node(currentpos, node) --octant 2 to 3
currentpos[other2] = second2
env:add_node(currentpos, node) --octant 6 to 7
currentpos[other1] = currentpos[other1] + 1
end
count = count + (offset1 * 4) + (offset2 * 4) + 4 --wip: broken
--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})
--move to next location
delta = delta + (offset1 * 2) + 1
offset1 = offset1 + 1
if delta >= 0 then
offset2 = offset2 - 1
delta = delta - (offset2 * 2)
end
end
currentpos[axis] = currentpos[axis] + step
--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
return count
end
--adds a pyramid at `pos` with height `height`, composed of `nodename`, returning the number of nodes added
worldedit.pyramid = function(pos, height, nodename, env)
local pos1x, pos1y, pos1z = pos.x - height, pos.y, pos.z - height
local pos2x, pos2y, pos2z = pos.x + height, pos.y + height, pos.z + height
local pos = {x=0, y=pos1y, z=0}
--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
local node = {name=nodename}
if env == nil then env = minetest.env end
while pos.y <= pos2y do --each vertical level of the pyramid
pos.x = pos1x
while pos.x <= pos2x do
pos.z = pos1z
while pos.z <= pos2z do
env:add_node(pos, node)
pos.z = pos.z + 1
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
pos.x = pos.x + 1
end
count = count + ((pos2y - pos.y) * 2 + 1) ^ 2
pos.y = pos.y + 1
pos1x, pos2x = pos1x + 1, pos2x - 1
pos1z, pos2z = pos1z + 1, pos2z - 1
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 at `pos` with width `width`, height `height`, space between walls `spacer`, composed of `nodename`, returning the number of nodes added
worldedit.spiral = function(pos, width, height, spacer, nodename, env) --wip: clean this up
-- spiral matrix - http://rosettacode.org/wiki/Spiral_matrix#Lua
av, sn = math.abs, function(s) return s~=0 and s/av(s) or 0 end
local function sindex(z, x) -- returns the value at (x, z) in a spiral that starts at 1 and goes outwards
if z == -x and z >= x then return (2*z+1)^2 end
local l = math.max(av(z), av(x))
return (2*l-1)^2+4*l+2*l*sn(x+z)+sn(z^2-x^2)*(l-(av(z)==l and sn(z)*x or sn(x)*z)) -- OH GOD WHAT
--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 function spiralt(side)
local ret, id, start, stop = {}, 0, math.floor((-side+1)/2), math.floor((side-1)/2)
for i = 1, side do
for j = 1, side do
local id = side^2 - sindex(stop - i + 1,start + j - 1)
ret[id] = {x=i,z=j}
--
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
return ret
end
if env == nil then env = minetest.env end
-- connect the joined parts
local spiral = spiralt(width)
height = tonumber(height)
if height < 1 then height = 1 end
spacer = tonumber(spacer)-1
if spacer < 1 then spacer = 1 end
local count = 0
local node = {name=nodename}
local np,lp
for y=0,height do
lp = nil
for _,v in ipairs(spiral) do
np = {x=pos.x+v.x*spacer, y=pos.y+y, z=pos.z+v.z*spacer}
if lp~=nil then
if lp.x~=np.x then
if lp.x<np.x then
for i=lp.x+1,np.x do
env:add_node({x=i, y=np.y, z=np.z}, node)
count = count + 1
end
else
for i=np.x,lp.x-1 do
env:add_node({x=i, y=np.y, z=np.z}, node)
count = count + 1
end
end
end
if lp.z~=np.z then
if lp.z<np.z then
for i=lp.z+1,np.z do
env:add_node({x=np.x, y=np.y, z=i}, node)
count = count + 1
end
else
for i=np.z,lp.z-1 do
env:add_node({x=np.x, y=np.y, z=i}, node)
count = count + 1
end
end
end
end
lp = np
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
end

View File

@ -1,108 +0,0 @@
worldedit = worldedit or {}
worldedit.queue = {}
worldedit.ENABLE_QUEUE = true
worldedit.BLOCKS_PER_GLOBALSTEP = 512
minetest.register_globalstep(function(dtime)
i = 1
while i <= #worldedit.queue and i <= worldedit.BLOCKS_PER_GLOBALSTEP do
idx = (#worldedit.queue + 1) - i -- we use the last entry, so we don't spend days moving stuff in the table because we removed the first entry
if worldedit.queue[idx].t == "set_node" then
minetest.env:set_node(worldedit.queue[idx].pos, worldedit.queue[idx].node)
elseif worldedit.queue[idx].t == "remove_node" then
minetest.env:remove_node(worldedit.queue[idx].pos)
elseif worldedit.queue[idx].t == "place_node" then
minetest.env:place_node(worldedit.queue[idx].pos, worldedit.queue[idx].node)
elseif worldedit.queue[idx].t == "dig_node" then
minetest.env:dig_node(worldedit.queue[idx].pos)
elseif worldedit.queue[idx].t == "add_entity" then
minetest.env:add_entity(worldedit.queue[idx].pos, worldedit.queue[idx].name)
elseif worldedit.queue[idx].t == "add_item" then
minetest.env:add_item(worldedit.queue[idx].pos, worldedit.queue[idx].item)
elseif worldedit.queue[idx].t == "meta_from_table" then
minetest.env:get_meta(worldedit.queue[idx].pos):from_table(worldedit.queue[idx].table)
else
print("Unknown queue event type: " .. worldedit.queue[idx].t)
end
table.remove(worldedit.queue, idx)
i = i + 1
end
end)
function table.copy(t, seen)
seen = seen or {}
if t == nil then return nil end
if seen[t] then return seen[t] end
local nt = {}
for k, v in pairs(t) do
if type(v) == 'table' then
nt[k] = table.copy(v, seen)
else
nt[k] = v
end
end
seen[t] = nt
return nt
end
local quene_setnode = function(self, pos_, node_)
table.insert(worldedit.queue, {pos=table.copy(pos_), node=table.copy(node_), t="set_node"})
end
local quene_removenode = function(self, pos_)
table.insert(worldedit.queue, {pos=table.copy(pos_), t="remove_node"})
end
local quene_placenode = function(self, pos_, node_)
table.insert(worldedit.queue, {pos=table.copy(pos_), node=table.copy(node_), t="place_node"})
end
local quene_dignode = function(self, pos_)
table.insert(worldedit.queue, {pos=table.copy(pos_), t="dig_node"})
end
local quene_addentity = function(self, pos_, name_)
table.insert(worldedit.queue, {pos=table.copy(pos_), name=name_.."", t="add_entity"})
end
local quene_additem = function(self, pos_, item_)
table.insert(worldedit.queue, {pos=table.copy(pos_), item=item_.."", t="add_item"})
end
local quene_setmeta = function(self, pos_, table_)
table.insert(worldedit.queue, {pos=table.copy(pos_), table=table.copy(table_), t="meta_from_table"})
end
local aliasmeta = {
-- the other functions are left out because they are not used in worldedit
to_table = function(self) return minetest.env:get_meta(self._pos):to_table() end,
set_string = function(self, name_, value_) minetest.env:get_meta(self._pos):set_string(name_, value_) end,
from_table = function(self, tbl) quene_setmeta(nil, self._pos, tbl) end,
}
local get_meta_alias = function(self, pos)
local am = table.copy(aliasmeta)
am._pos = pos
return am
end
worldedit.quene_aliasenv = {
-- ALL functions that are not just piped to the real minetest.env function must copy the arguments, not just reference them
set_node = quene_setnode,
add_node = quene_setnode,
remove_node = quene_removenode,
get_node = function(self, pos) return minetest.env:get_node(pos) end,
get_node_or_nil = function(self, pos) return minetest.env:get_node_or_nil(pos) end,
get_node_light = function(self, pos, timeofday) return minetest.env:get_node_light(pos, timeofday) end,
place_node = quene_placenode,
dig_node = quene_dignode,
punch_node = function(self, pos) return minetest.env:punch_node(pos) end,
get_meta = get_meta_alias,
get_node_timer = function(self, pos) return minetest.env:get_node_timer(pos) end,
add_entity = quene_addentity,
add_item = quene_additem,
}

View File

@ -1,4 +1,5 @@
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)
@ -32,26 +33,30 @@ worldedit.valueversion = function(value)
end
--converts the region defined by positions `pos1` and `pos2` into a single string, returning the serialized data and the number of nodes serialized
worldedit.serialize = function(pos1, pos2) --wip: check for ItemStacks and whether they can be serialized
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 env = minetest.env
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 = env:get_node(pos)
local node = get_node(pos)
if node.name ~= "air" and node.name ~= "ignore" then
count = count + 1
local meta = env:get_meta(pos):to_table()
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()
inventory[index] = stack.to_string and stack:to_string() or stack
end
end
@ -140,7 +145,24 @@ worldedit.allocate = function(originpos, value)
count = count + 1
end
elseif version == 4 then --current nested table format
local nodes = minetest.deserialize(value)
--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]
@ -160,10 +182,15 @@ end
--loads the nodes represented by string `value` at position `originpos`, returning the number of nodes deserialized
--contains code based on [table.save/table.load](http://lua-users.org/wiki/SaveTableToFile) by ChillCode, available under the MIT license (GPL compatible)
worldedit.deserialize = function(originpos, value, env)
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
if env == nil then env = minetest.env end
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
@ -190,33 +217,29 @@ worldedit.deserialize = function(originpos, value, env)
local entry = nodes[index]
local pos = entry[1]
pos.x, pos.y, pos.z = originx - pos.x, originy - pos.y, originz - pos.z
env:add_node(pos, entry[2])
add_node(pos, entry[2])
end
else --previous meta flat table format
for index = 1, #nodes do
local entry = nodes[index]
entry.x, entry.y, entry.z = originx + entry.x, originy + entry.y, originz + entry.z
env:add_node(entry, entry) --entry acts both as position and as node
env:get_meta(entry):from_table(entry.meta)
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 = originx + tonumber(x)
pos.y = originy + tonumber(y)
pos.z = originz + tonumber(z)
node.name = name
node.param1 = param1
node.param2 = param2
env:add_node(pos, node)
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 escaped = value:gsub("\\\\", "@@"):gsub("\\\"", "@@"):gsub("(\"[^\"]*\")", function(s) return string.rep("@", #s) end)
local startpos, startpos1, endpos = 1, 1
local nodes = {}
while true do
@ -228,14 +251,22 @@ worldedit.deserialize = function(originpos, value, env)
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
env:add_node(entry, entry) --entry acts both as position and as node
env:get_meta(entry):from_table(entry.meta)
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

View File

@ -1,4 +1,5 @@
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)
@ -31,24 +32,27 @@ minetest.register_node("worldedit:placeholder", {
})
--hides all nodes in a region defined by positions `pos1` and `pos2` by non-destructively replacing them with invisible nodes, returning the number of nodes hidden
worldedit.hide = function(pos1, pos2, tenv)
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
if env == nil then env = minetest.env end
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 placeholder = {name="worldedit:placeholder", param1=0, param2=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 = env:get_node(pos)
placeholder.param1, placeholder.param2 = node.param1, node.param2 --copy node's param1 and param2
local data = env:get_meta(pos):to_table() --obtain metadata of original node
env:add_node(pos, placeholder) --add placeholder node
local meta = env:get_meta(pos) --obtain placeholder meta
meta:from_table(data) --set placeholder metadata to the original node's metadata
meta:set_string("worldedit_placeholder", node.name) --add the node's name
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
@ -59,68 +63,54 @@ worldedit.hide = function(pos1, pos2, tenv)
end
--suppresses all instances of `nodename` in a region defined by positions `pos1` and `pos2` by non-destructively replacing them with invisible nodes, returning the number of nodes suppressed
worldedit.suppress = function(pos1, pos2, nodename, tenv)
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)
if env == nil then env = minetest.env end
if minetest.registered_nodes[nodename] == nil then
nodename = "default:" .. nodename
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
local pos = {x=pos1.x, y=0, z=0}
local placeholder = {name="worldedit:placeholder", param1=0, param2=0}
local count = 0
while pos.x <= pos2.x do
pos.y = pos1.y
while pos.y <= pos2.y do
pos.z = pos1.z
while pos.z <= pos2.z do
local node = env:get_node(pos)
if node.name == nodename then
placeholder.param1, placeholder.param2 = node.param1, node.param2 --copy node's param1 and param2
local data = env:get_meta(pos):to_table() --obtain metadata of original node
env:add_node(pos, placeholder) --add placeholder node
local meta = env:get_meta(pos) --obtain placeholder meta
meta:from_table(data) --set placeholder metadata to the original node's metadata
meta:set_string("worldedit_placeholder", nodename) --add the node's name
count = count + 1
end
pos.z = pos.z + 1
end
pos.y = pos.y + 1
end
pos.x = pos.x + 1
end
return count
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, tenv)
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)
if env == nil then env = minetest.env end
if minetest.registered_nodes[nodename] == nil then
nodename = "default:" .. nodename
end
local pos = {x=pos1.x, y=0, z=0}
local placeholder = {name="worldedit:placeholder", param1=0, param2=0}
local 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 = env:get_node(pos)
local node = get_node(pos)
if node.name == nodename then --node found
count = count + 1
else --hide other nodes
placeholder.param1, placeholder.param2 = node.param1, node.param2 --copy node's param1 and param2
local data = env:get_meta(pos):to_table() --obtain metadata of original node
env:add_node(pos, placeholder) --add placeholder node
local meta = env:get_meta(pos) --obtain placeholder meta
meta:from_table(data) --set placeholder metadata to the original node's metadata
meta:set_string("worldedit_placeholder", node.name) --add the node's name
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
@ -132,33 +122,21 @@ worldedit.highlight = function(pos1, pos2, nodename, tenv)
end
--restores all nodes hidden with WorldEdit functions in a region defined by positions `pos1` and `pos2`, returning the number of nodes restored
worldedit.restore = function(pos1, pos2, tenv)
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
if env == nil then env = minetest.env end
worldedit.restore = function(pos1, pos2)
--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}
local node = {name="", param1=0, param2=0}
local count = 0
while pos.x <= pos2.x do
pos.y = pos1.y
while pos.y <= pos2.y do
pos.z = pos1.z
while pos.z <= pos2.z do
local currentnode = env:get_node(pos)
if currentnode.name == "worldedit:placeholder" then
node.param1, node.param2 = currentnode.param1, currentnode.param2 --copy node's param1 and param2
local data = env:get_meta(pos):to_table() --obtain node metadata
node.name = data.fields.worldedit_placeholder --set node name
data.fields.worldedit_placeholder = nil --delete old nodename
env:add_node(pos, node) --add original node
env:get_meta(pos):from_table(data) --set original node metadata
count = count + 1
end
pos.z = pos.z + 1
end
pos.y = pos.y + 1
end
pos.x = pos.x + 1
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 count
return #nodes
end

File diff suppressed because it is too large Load Diff

View File

@ -1,29 +1,82 @@
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 pos = worldedit.pos1[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 pos ~= nil then --add marker
worldedit.marker1[name] = minetest.env:add_entity(pos, "worldedit:pos1")
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 pos = worldedit.pos2[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 pos ~= nil then --add marker
worldedit.marker2[name] = minetest.env:add_entity(pos, "worldedit:pos2")
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
@ -35,6 +88,7 @@ minetest.register_entity(":worldedit:pos1", {
"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
@ -56,6 +110,7 @@ minetest.register_entity(":worldedit:pos2", {
"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