#1 Normalize line endings

開啟中
pgimeno 請求將 1 次代碼提交從 pgimeno/normalize-line-ends 合併至 pgimeno/master
共有 10 個文件被更改,包括 2044 次插入1925 次删除
  1. 6 0
      .gitattributes
  2. 508 508
      ChatCommands.md
  3. 119 119
      Tutorial.md
  4. 240 240
      WorldEdit API.md
  5. 52 47
      worldedit/code.lua
  6. 74 73
      worldedit/compatibility.lua
  7. 40 32
      worldedit/init.lua
  8. 676 617
      worldedit/manipulations.lua
  9. 329 289
      worldedit/primitives.lua
  10. 0 0
      worldedit/serialization.lua

+ 6 - 0
.gitattributes

@@ -0,0 +1,6 @@
+*.txt   text
+*.md    text
+*.lua   text
+*.conf  text
+*.ld    text
+*.png   binary

File diff suppressed because it is too large
+ 508 - 508
ChatCommands.md


+ 119 - 119
Tutorial.md

@@ -1,120 +1,120 @@
-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.
-  * See the installation instructions in [README](README.md) if you need more details.
-* You are familiar with the basics of the game.
-  * How to walk, jump, and climb.
-  * How to dig, place, and punch blocks.
-  * One of the following:
-    * How to type into the chat and read text from it.
-    * How to open the inventory screen and press buttons on 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 GUI buttons and chat commands generally work inside the region selected, or around the first marker.
-
-If you are using the chat commands, follow the steps under **Chat Commands**. If you are using the WorldEdit GUI, follow the steps under **WorldEdit GUI**.
-
-Step 1: Selecting a region
---------------------------
-### Chat Commands
-
-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.
-
-### WorldEdit GUI
-
-Open the main WorldEdit GUI from your inventory screen. The icon looks like a globe with a red dot in the center.
-
-Press the "Get/Set Positions" button. On the new screen, press the "Set Position 1" button. The inventory screen should close.
-
-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. Open your inventory again. It should be on the same page as it was before.
-
-Press the "Set Position 2" button. The inventory screen should close.
-
-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
------------------------
-### Chat 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`.
-
-### WorldEdit GUI
-
-Open the main WorldEdit GUI from your inventory screen.
-
-Press the "Set Nodes" button. You should see a new screen with various options for setting nodes.
-
-Enter "mese" in the "Name" field. Press Search if you would like to see what the node you just entered looks like.
-
-Press the "Set Nodes" button on this screen. 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 Nodes" function 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 on the node name, such as "torch", "cobble", and "water".
-
-Step 3: Position commands
--------------------------
-### Chat 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.
-
-### WorldEdit GUI
-
-Open the main WorldEdit GUI from your inventory screen.
-
-Press the "Sphere/Dome" button. You should see a new screen with various options for making spheres or domes.
-
-Enter "glass" in the "Name" field. Press Search if you would like to see what the node you just entered looks like.
-
-Enter "30" in the "Radius" field.
-
-Press the "Hollow Dome" button on this screen. In the chat, you will see a message showing the number of nodes added after a small delay.
-
-Look around marker 1: it is now surrounded by a hollow glass dome!
-
-The "Hollow Dome" function 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
-----------------------
-### Chat Commands
-
-There are many more commands than what is shown here. See the [Chat Commands Reference](ChatCommands.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.
-
-### WorldEdit GUI
-
-This only scratches the surface of what WorldEdit is capable of. Most of the functions in the WorldEdit GUI correspond to chat commands, and so the [Chat Commands Reference](ChatCommands.md) may be useful if you get stuck.
-
+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.
+  * See the installation instructions in [README](README.md) if you need more details.
+* You are familiar with the basics of the game.
+  * How to walk, jump, and climb.
+  * How to dig, place, and punch blocks.
+  * One of the following:
+    * How to type into the chat and read text from it.
+    * How to open the inventory screen and press buttons on 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 GUI buttons and chat commands generally work inside the region selected, or around the first marker.
+
+If you are using the chat commands, follow the steps under **Chat Commands**. If you are using the WorldEdit GUI, follow the steps under **WorldEdit GUI**.
+
+Step 1: Selecting a region
+--------------------------
+### Chat Commands
+
+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.
+
+### WorldEdit GUI
+
+Open the main WorldEdit GUI from your inventory screen. The icon looks like a globe with a red dot in the center.
+
+Press the "Get/Set Positions" button. On the new screen, press the "Set Position 1" button. The inventory screen should close.
+
+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. Open your inventory again. It should be on the same page as it was before.
+
+Press the "Set Position 2" button. The inventory screen should close.
+
+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
+-----------------------
+### Chat 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`.
+
+### WorldEdit GUI
+
+Open the main WorldEdit GUI from your inventory screen.
+
+Press the "Set Nodes" button. You should see a new screen with various options for setting nodes.
+
+Enter "mese" in the "Name" field. Press Search if you would like to see what the node you just entered looks like.
+
+Press the "Set Nodes" button on this screen. 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 Nodes" function 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 on the node name, such as "torch", "cobble", and "water".
+
+Step 3: Position commands
+-------------------------
+### Chat 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.
+
+### WorldEdit GUI
+
+Open the main WorldEdit GUI from your inventory screen.
+
+Press the "Sphere/Dome" button. You should see a new screen with various options for making spheres or domes.
+
+Enter "glass" in the "Name" field. Press Search if you would like to see what the node you just entered looks like.
+
+Enter "30" in the "Radius" field.
+
+Press the "Hollow Dome" button on this screen. In the chat, you will see a message showing the number of nodes added after a small delay.
+
+Look around marker 1: it is now surrounded by a hollow glass dome!
+
+The "Hollow Dome" function 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
+----------------------
+### Chat Commands
+
+There are many more commands than what is shown here. See the [Chat Commands Reference](ChatCommands.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.
+
+### WorldEdit GUI
+
+This only scratches the surface of what WorldEdit is capable of. Most of the functions in the WorldEdit GUI correspond to chat commands, and so the [Chat Commands Reference](ChatCommands.md) may be useful if you get stuck.
+
 It is helpful to explore the various buttons in the interface and check out what they do. Learning the chat command interface is also useful if you use WorldEdit intensively - an experienced chat command user can usually work faster than an experienced WorldEdit GUI user.

+ 240 - 240
WorldEdit API.md

@@ -1,240 +1,240 @@
-WorldEdit API
-=============
-The WorldEdit API is composed of multiple modules, each of which is independent and can be used without the other. Each module is contained within a single file.
-
-If needed, individual modules such as visualization.lua can be removed without affecting the rest of the program. The only file that cannot be removed is init.lua, which is necessary for the mod to run.
-
-For more information, see the [README](README.md).
-
-General
--------
-
-### value = worldedit.version
-
-Contains the current version of WorldEdit in a table of the form `{major=MAJOR_INTEGER, minor=MINOR_INTEGER}`, where `MAJOR_INTEGER` is the major version (the number before the period) as an integer, and `MINOR_INTEGER` is the minor version (the number after the period) as an integer. This is intended for version checking purposes.
-
-### value = worldedit.version_string
-
-Contains the current version of WorldEdit in the form of a string `"MAJOR_INTEGER.MINOR_INTEGER"`, where `MAJOR_INTEGER` is the major version (the number before the period) as an integer, and `MINOR_INTEGER` is the minor version (the number after the period) as an integer. This is intended for display purposes.
-
-Manipulations
--------------
-Contained in manipulations.lua, this module allows several node operations to be applied over a region.
-
-### count = worldedit.set(pos1, pos2, node_name)
-
-Sets a region defined by positions `pos1` and `pos2` to `node_name`. To clear a region, use "air" as the value of `node_name`.
-If `node_name` is a list of nodes, each set node is randomly picked from it.
-
-Returns the number of nodes set.
-
-### `count = worldedit.set_param2(pos1, pos2, param2)`
-
-Sets the param2 values of all nodes in a region defined by positions `pos1` and `pos2` to `param2`.
-
-Returns the number of nodes set.
-
-### count = worldedit.replace(pos1, pos2, searchnode, replacenode)
-
-Replaces all instances of `searchnode` with `replacenode` in a region defined by positions `pos1` and `pos2`.
-
-Returns the number of nodes replaced.
-
-### count = worldedit.replaceinverse(pos1, pos2, searchnode, replacenode)
-
-Replaces all nodes other than `searchnode` with `replacenode` in a region defined by positions `pos1` and `pos2`.
-
-Returns the number of nodes replaced.
-
-### count = worldedit.copy(pos1, pos2, axis, amount)
-
-Copies the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") by `amount` nodes.
-
-Returns the number of nodes copied.
-
-### count = worldedit.copy2(pos1, pos2, off)
-
-Copies the region defined by positions `pos1` and `pos2` by the offset vector `off`.
-Note that the offset needs to be big enough that there is no overlap.
-
-Returns the number of nodes copied.
-
-### count = worldedit.move(pos1, pos2, axis, amount)
-
-Moves the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") by `amount` nodes.
-
-Returns the number of nodes moved.
-
-### count = worldedit.stack(pos1, pos2, axis, count)
-
-Duplicates the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") `count` times.
-
-Returns the number of nodes stacked.
-
-### count = worldedit.stack2(pos1, pos2, direction, amount)
-
-Duplicates the region defined by positions `pos1` and `pos2` `amount` times with offset vector `direction`.
-Note that the offset vector needs to be big enough that there is no overlap.
-
-Returns the number of nodes stacked.
-
-### count, newpos1, newpos2 = worldedit.stretch(pos1, pos2, stretchx, stretchy, stretchz)
-
-Stretches the region defined by positions `pos1` and `pos2` by an factor of positive integers `stretchx`, `stretchy`. and `stretchz` along the X, Y, and Z axes, respectively, with `pos1` as the origin.
-
-Returns the number of nodes stretched, the new scaled position 1, and the new scaled position 2.
-
-### count, newpos1, newpos2 = worldedit.transpose(pos1, pos2, axis1, axis2)
-
-Transposes a region defined by the positions `pos1` and `pos2` between the `axis1` and `axis2` axes ("x" or "y" or "z").
-
-Returns the number of nodes transposed, the new transposed position 1, and the new transposed position 2.
-
-### count = worldedit.flip(pos1, pos2, axis)
-
-Flips a region defined by the positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z").
-
-Returns the number of nodes flipped.
-
-### count, newpos2, newpos2 = worldedit.rotate(pos1, pos2, angle)
-
-Rotates a region defined by the positions `pos1` and `pos2` by `angle` degrees clockwise around the y axis (supporting 90 degree increments only).
-
-Returns the number of nodes rotated, the new position 1, and the new position 2.
-
-### count = worldedit.orient(pos1, pos2, angle)
-
-Rotates all oriented nodes in a region defined by the positions `pos1` and `pos2` by `angle` degrees clockwise (90 degree increment) around the Y axis.
-
-Returns the number of nodes oriented.
-
-### count = worldedit.fixlight(pos1, pos2)
-
-Fixes the lighting in a region defined by positions `pos1` and `pos2`.
-
-Returns the number of nodes updated.
-
-### count = worldedit.clearobjects(pos1, pos2)
-
-Clears all objects in a region defined by the positions `pos1` and `pos2`.
-
-Returns the number of objects cleared.
-
-Primitives
-----------
-Contained in primitives.lua, this module allows the creation of several geometric primitives.
-
-### count = worldedit.cube(pos, width, height, length, node_name, hollow)
-
-Adds a cube with its ground level centered at `pos`, the dimensions `width` x `height` x `length`, composed of `node_name`.
-
-Returns the number of nodes added.
-
-### count = worldedit.sphere(pos, radius, node_name, hollow)
-
-Adds a sphere centered at `pos` with radius `radius`, composed of `node_name`.
-
-Returns the number of nodes added.
-
-### count = worldedit.dome(pos, radius, node_name, hollow)
-
-Adds a dome centered at `pos` with radius `radius`, composed of `node_name`.
-
-Returns the number of nodes added.
-
-### count = worldedit.cylinder(pos, axis, length, radius1, radius2, node_name, hollow)
-
-Adds a cylinder-like at `pos` along the `axis` axis ("x" or "y" or "z") with length `length`, base radius `radius1` and top radius `radius2`, composed of `node_name`.
-
-Returns the number of nodes added.
-
-### count = worldedit.pyramid(pos, axis, height, node_name, hollow)
-
-Adds a pyramid centered at `pos` along the `axis` axis ("x" or "y" or "z") with height `height`, composed of `node_name`.
-
-Returns the number of nodes added.
-
-### count = worldedit.spiral(pos, length, height, spacer, node_name)
-
-Adds a spiral centered at `pos` with side length `length`, height `height`, space between walls `spacer`, composed of `node_name`.
-
-Returns the number of nodes added.
-
-Visualization
--------------
-Contained in visualization.lua, this module allows nodes to be visualized in different ways.
-
-### volume = worldedit.volume(pos1, pos2)
-
-Determines the volume of the region defined by positions `pos1` and `pos2`.
-
-Returns the volume.
-
-### count = worldedit.hide(pos1, pos2)
-
-Hides all nodes in a region defined by positions `pos1` and `pos2` by non-destructively replacing them with invisible nodes.
-
-Returns the number of nodes hidden.
-
-### count = worldedit.suppress(pos1, pos2, node_name)
-
-Suppresses all instances of `node_name` in a region defined by positions `pos1` and `pos2` by non-destructively replacing them with invisible nodes.
-
-Returns the number of nodes suppressed.
-
-### count = worldedit.highlight(pos1, pos2, node_name)
-
-Highlights all instances of `node_name` in a region defined by positions `pos1` and `pos2` by non-destructively hiding all other nodes.
-
-Returns the number of nodes found.
-
-### count = worldedit.restore(pos1, pos2)
-
-Restores all nodes hidden with WorldEdit functions in a region defined by positions `pos1` and `pos2`.
-
-Returns the number of nodes restored.
-
-Serialization
--------------
-Contained in serialization.lua, this module allows regions of nodes to be serialized and deserialized to formats suitable for use outside Minetest.
-
-### version, extra_fields, content = worldedit.read_header(value)
-
-Reads the header from serialized data `value`.
-
-Returns the version as a positive integer (nil for unknown versions),
-extra header fields (nil if not supported), and the content after the header.
-
-### data, count = worldedit.serialize(pos1, pos2)
-
-Converts the region defined by positions `pos1` and `pos2` into a single string.
-
-Returns the serialized data and the number of nodes serialized, or nil.
-
-### pos1, pos2, count = worldedit.allocate(origin_pos, value)
-
-Determines the volume the nodes represented by string `value` would occupy if deserialized at `origin_pos`.
-
-Returns the two corner positions and the number of nodes, or nil.
-
-### count = worldedit.deserialize(origin_pos, value)
-
-Loads the nodes represented by string `value` at position `origin_pos`.
-
-Returns the number of nodes deserialized or nil.
-
-Code
-----
-Contained in code.lua, this module allows arbitrary Lua code to be used with WorldEdit.
-
-### error = worldedit.lua(code)
-
-Executes `code` as a Lua chunk in the global namespace.
-
-Returns an error if the code fails or nil otherwise.
-
-### error = worldedit.luatransform(pos1, pos2, code)
-
-Executes `code` as a Lua chunk in the global namespace with the variable `pos` available, for each node in a region defined by positions `pos1` and `pos2`.
-
-Returns an error if the code fails or nil otherwise.
+WorldEdit API
+=============
+The WorldEdit API is composed of multiple modules, each of which is independent and can be used without the other. Each module is contained within a single file.
+
+If needed, individual modules such as visualization.lua can be removed without affecting the rest of the program. The only file that cannot be removed is init.lua, which is necessary for the mod to run.
+
+For more information, see the [README](README.md).
+
+General
+-------
+
+### value = worldedit.version
+
+Contains the current version of WorldEdit in a table of the form `{major=MAJOR_INTEGER, minor=MINOR_INTEGER}`, where `MAJOR_INTEGER` is the major version (the number before the period) as an integer, and `MINOR_INTEGER` is the minor version (the number after the period) as an integer. This is intended for version checking purposes.
+
+### value = worldedit.version_string
+
+Contains the current version of WorldEdit in the form of a string `"MAJOR_INTEGER.MINOR_INTEGER"`, where `MAJOR_INTEGER` is the major version (the number before the period) as an integer, and `MINOR_INTEGER` is the minor version (the number after the period) as an integer. This is intended for display purposes.
+
+Manipulations
+-------------
+Contained in manipulations.lua, this module allows several node operations to be applied over a region.
+
+### count = worldedit.set(pos1, pos2, node_name)
+
+Sets a region defined by positions `pos1` and `pos2` to `node_name`. To clear a region, use "air" as the value of `node_name`.
+If `node_name` is a list of nodes, each set node is randomly picked from it.
+
+Returns the number of nodes set.
+
+### `count = worldedit.set_param2(pos1, pos2, param2)`
+
+Sets the param2 values of all nodes in a region defined by positions `pos1` and `pos2` to `param2`.
+
+Returns the number of nodes set.
+
+### count = worldedit.replace(pos1, pos2, searchnode, replacenode)
+
+Replaces all instances of `searchnode` with `replacenode` in a region defined by positions `pos1` and `pos2`.
+
+Returns the number of nodes replaced.
+
+### count = worldedit.replaceinverse(pos1, pos2, searchnode, replacenode)
+
+Replaces all nodes other than `searchnode` with `replacenode` in a region defined by positions `pos1` and `pos2`.
+
+Returns the number of nodes replaced.
+
+### count = worldedit.copy(pos1, pos2, axis, amount)
+
+Copies the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") by `amount` nodes.
+
+Returns the number of nodes copied.
+
+### count = worldedit.copy2(pos1, pos2, off)
+
+Copies the region defined by positions `pos1` and `pos2` by the offset vector `off`.
+Note that the offset needs to be big enough that there is no overlap.
+
+Returns the number of nodes copied.
+
+### count = worldedit.move(pos1, pos2, axis, amount)
+
+Moves the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") by `amount` nodes.
+
+Returns the number of nodes moved.
+
+### count = worldedit.stack(pos1, pos2, axis, count)
+
+Duplicates the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") `count` times.
+
+Returns the number of nodes stacked.
+
+### count = worldedit.stack2(pos1, pos2, direction, amount)
+
+Duplicates the region defined by positions `pos1` and `pos2` `amount` times with offset vector `direction`.
+Note that the offset vector needs to be big enough that there is no overlap.
+
+Returns the number of nodes stacked.
+
+### count, newpos1, newpos2 = worldedit.stretch(pos1, pos2, stretchx, stretchy, stretchz)
+
+Stretches the region defined by positions `pos1` and `pos2` by an factor of positive integers `stretchx`, `stretchy`. and `stretchz` along the X, Y, and Z axes, respectively, with `pos1` as the origin.
+
+Returns the number of nodes stretched, the new scaled position 1, and the new scaled position 2.
+
+### count, newpos1, newpos2 = worldedit.transpose(pos1, pos2, axis1, axis2)
+
+Transposes a region defined by the positions `pos1` and `pos2` between the `axis1` and `axis2` axes ("x" or "y" or "z").
+
+Returns the number of nodes transposed, the new transposed position 1, and the new transposed position 2.
+
+### count = worldedit.flip(pos1, pos2, axis)
+
+Flips a region defined by the positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z").
+
+Returns the number of nodes flipped.
+
+### count, newpos2, newpos2 = worldedit.rotate(pos1, pos2, angle)
+
+Rotates a region defined by the positions `pos1` and `pos2` by `angle` degrees clockwise around the y axis (supporting 90 degree increments only).
+
+Returns the number of nodes rotated, the new position 1, and the new position 2.
+
+### count = worldedit.orient(pos1, pos2, angle)
+
+Rotates all oriented nodes in a region defined by the positions `pos1` and `pos2` by `angle` degrees clockwise (90 degree increment) around the Y axis.
+
+Returns the number of nodes oriented.
+
+### count = worldedit.fixlight(pos1, pos2)
+
+Fixes the lighting in a region defined by positions `pos1` and `pos2`.
+
+Returns the number of nodes updated.
+
+### count = worldedit.clearobjects(pos1, pos2)
+
+Clears all objects in a region defined by the positions `pos1` and `pos2`.
+
+Returns the number of objects cleared.
+
+Primitives
+----------
+Contained in primitives.lua, this module allows the creation of several geometric primitives.
+
+### count = worldedit.cube(pos, width, height, length, node_name, hollow)
+
+Adds a cube with its ground level centered at `pos`, the dimensions `width` x `height` x `length`, composed of `node_name`.
+
+Returns the number of nodes added.
+
+### count = worldedit.sphere(pos, radius, node_name, hollow)
+
+Adds a sphere centered at `pos` with radius `radius`, composed of `node_name`.
+
+Returns the number of nodes added.
+
+### count = worldedit.dome(pos, radius, node_name, hollow)
+
+Adds a dome centered at `pos` with radius `radius`, composed of `node_name`.
+
+Returns the number of nodes added.
+
+### count = worldedit.cylinder(pos, axis, length, radius1, radius2, node_name, hollow)
+
+Adds a cylinder-like at `pos` along the `axis` axis ("x" or "y" or "z") with length `length`, base radius `radius1` and top radius `radius2`, composed of `node_name`.
+
+Returns the number of nodes added.
+
+### count = worldedit.pyramid(pos, axis, height, node_name, hollow)
+
+Adds a pyramid centered at `pos` along the `axis` axis ("x" or "y" or "z") with height `height`, composed of `node_name`.
+
+Returns the number of nodes added.
+
+### count = worldedit.spiral(pos, length, height, spacer, node_name)
+
+Adds a spiral centered at `pos` with side length `length`, height `height`, space between walls `spacer`, composed of `node_name`.
+
+Returns the number of nodes added.
+
+Visualization
+-------------
+Contained in visualization.lua, this module allows nodes to be visualized in different ways.
+
+### volume = worldedit.volume(pos1, pos2)
+
+Determines the volume of the region defined by positions `pos1` and `pos2`.
+
+Returns the volume.
+
+### count = worldedit.hide(pos1, pos2)
+
+Hides all nodes in a region defined by positions `pos1` and `pos2` by non-destructively replacing them with invisible nodes.
+
+Returns the number of nodes hidden.
+
+### count = worldedit.suppress(pos1, pos2, node_name)
+
+Suppresses all instances of `node_name` in a region defined by positions `pos1` and `pos2` by non-destructively replacing them with invisible nodes.
+
+Returns the number of nodes suppressed.
+
+### count = worldedit.highlight(pos1, pos2, node_name)
+
+Highlights all instances of `node_name` in a region defined by positions `pos1` and `pos2` by non-destructively hiding all other nodes.
+
+Returns the number of nodes found.
+
+### count = worldedit.restore(pos1, pos2)
+
+Restores all nodes hidden with WorldEdit functions in a region defined by positions `pos1` and `pos2`.
+
+Returns the number of nodes restored.
+
+Serialization
+-------------
+Contained in serialization.lua, this module allows regions of nodes to be serialized and deserialized to formats suitable for use outside Minetest.
+
+### version, extra_fields, content = worldedit.read_header(value)
+
+Reads the header from serialized data `value`.
+
+Returns the version as a positive integer (nil for unknown versions),
+extra header fields (nil if not supported), and the content after the header.
+
+### data, count = worldedit.serialize(pos1, pos2)
+
+Converts the region defined by positions `pos1` and `pos2` into a single string.
+
+Returns the serialized data and the number of nodes serialized, or nil.
+
+### pos1, pos2, count = worldedit.allocate(origin_pos, value)
+
+Determines the volume the nodes represented by string `value` would occupy if deserialized at `origin_pos`.
+
+Returns the two corner positions and the number of nodes, or nil.
+
+### count = worldedit.deserialize(origin_pos, value)
+
+Loads the nodes represented by string `value` at position `origin_pos`.
+
+Returns the number of nodes deserialized or nil.
+
+Code
+----
+Contained in code.lua, this module allows arbitrary Lua code to be used with WorldEdit.
+
+### error = worldedit.lua(code)
+
+Executes `code` as a Lua chunk in the global namespace.
+
+Returns an error if the code fails or nil otherwise.
+
+### error = worldedit.luatransform(pos1, pos2, code)
+
+Executes `code` as a Lua chunk in the global namespace with the variable `pos` available, for each node in a region defined by positions `pos1` and `pos2`.
+
+Returns an error if the code fails or nil otherwise.

+ 52 - 47
worldedit/code.lua

@@ -1,52 +1,52 @@
---- Lua code execution functions.
-
---- Executes `code` as a Lua chunk in the global namespace.
-function worldedit.lua(code)
-	local func, err = loadstring(code)
-	if not func then  -- Syntax error
-		return err
-	end
-	local good, err = pcall(func)
-	if not good then  -- Runtime error
-		return err
-	end
-	return nil
-end
-
-
---- Executes `code` as a Lua chunk in the global namespace with the variable
-function worldedit.luatransform(pos1, pos2, code)
-	pos1, pos2 = worldedit.sort_pos(pos1, pos2)
-
-	local factory, err = loadstring("return function(pos) " .. code .. " end")
-	if not factory then  -- Syntax error
-		return err
-	end
-	local func = factory()
-
-	worldedit.keep_loaded(pos1, pos2)
-
-	local pos = {x=pos1.x, y=0, z=0}
-	while pos.x <= pos2.x do
-		pos.y = pos1.y
-		while pos.y <= pos2.y do
-			pos.z = pos1.z
-			while pos.z <= pos2.z do
-				local good, err = pcall(func, pos)
-				if not good then -- Runtime error
-					return err
-				end
-				pos.z = pos.z + 1
-			end
-			pos.y = pos.y + 1
-		end
-		pos.x = pos.x + 1
-	end
-	return nil
-end
-
+--- Lua code execution functions.
+-- @module worldedit.code
+
+--- Executes `code` as a Lua chunk in the global namespace.
+-- @return An error message if the code fails, or nil on success.
+function worldedit.lua(code)
+	local func, err = loadstring(code)
+	if not func then  -- Syntax error
+		return err
+	end
+	local good, err = pcall(func)
+	if not good then  -- Runtime error
+		return err
+	end
+	return nil
+end
+
+
+--- Executes `code` as a Lua chunk in the global namespace with the variable
+-- pos available, for each node in a region defined by positions `pos1` and
+-- `pos2`.
+-- @return An error message if the code fails, or nil on success.
+function worldedit.luatransform(pos1, pos2, code)
+	pos1, pos2 = worldedit.sort_pos(pos1, pos2)
+
+	local factory, err = loadstring("return function(pos) " .. code .. " end")
+	if not factory then  -- Syntax error
+		return err
+	end
+	local func = factory()
+
+	worldedit.keep_loaded(pos1, pos2)
+
+	local pos = {x=pos1.x, y=0, z=0}
+	while pos.x <= pos2.x do
+		pos.y = pos1.y
+		while pos.y <= pos2.y do
+			pos.z = pos1.z
+			while pos.z <= pos2.z do
+				local good, err = pcall(func, pos)
+				if not good then -- Runtime error
+					return err
+				end
+				pos.z = pos.z + 1
+			end
+			pos.y = pos.y + 1
+		end
+		pos.x = pos.x + 1
+	end
+	return nil
+end
+

+ 74 - 73
worldedit/compatibility.lua

@@ -1,74 +1,74 @@
---- Compatibility functions.
-
-local function deprecated(new_func)
-	local info = debug.getinfo(1, "n")
-	local msg = "worldedit." .. info.name .. "() is deprecated."
-	if new_func then
-		msg = msg .. "  Use worldedit." .. new_func .. "() instead."
-	end
-	minetest.log("deprecated", msg)
-end
-
-worldedit.allocate_old = worldedit.allocate
-
-worldedit.deserialize_old = worldedit.deserialize
-
-function worldedit.metasave(pos1, pos2, filename)
-	deprecated("save")
-	local file, err = io.open(filename, "wb")
-	if err then return 0 end
-	local data, count = worldedit.serialize(pos1, pos2)
-	file:write(data)
-	file:close()
-	return count
-end
-
-function worldedit.metaload(originpos, filename)
-	deprecated("load")
-	filename = minetest.get_worldpath() .. "/schems/" .. file .. ".wem"
-	local file, err = io.open(filename, "wb")
-	if err then return 0 end
-	local data = file:read("*a")
-	return worldedit.deserialize(originpos, data)
-end
-
-function worldedit.scale(pos1, pos2, factor)
-	deprecated("stretch")
-	return worldedit.stretch(pos1, pos2, factor, factor, factor)
-end
-
-function worldedit.valueversion(value)
-	deprecated("read_header")
-	local version = worldedit.read_header(value)
-	if not version or version > worldedit.LATEST_SERIALIZATION_VERSION then
-		return 0
-	end
-	return version
-end
-
-function worldedit.replaceinverse(pos1, pos2, search_node, replace_node)
-	deprecated("replace")
-	return worldedit.replace(pos1, pos2, search_node, replace_node, true)
-end
-
-function worldedit.clearobjects(...)
-	deprecated("clear_objects")
-	return worldedit.clear_objects(...)
-end
-
-function worldedit.hollow_sphere(pos, radius, node_name)
-	deprecated("sphere")
-	return worldedit.sphere(pos, radius, node_name, true)
-end
-
-function worldedit.hollow_dome(pos, radius, node_name)
-	deprecated("dome")
-	return worldedit.dome(pos, radius, node_name, true)
-end
-
-function worldedit.hollow_cylinder(pos, axis, length, radius, node_name)
-	deprecated("cylinder")
-	return worldedit.cylinder(pos, axis, length, radius, node_name, true)
-end
-
+--- Compatibility functions.
+-- @module worldedit.compatibility
+
+local function deprecated(new_func)
+	local info = debug.getinfo(1, "n")
+	local msg = "worldedit." .. info.name .. "() is deprecated."
+	if new_func then
+		msg = msg .. "  Use worldedit." .. new_func .. "() instead."
+	end
+	minetest.log("deprecated", msg)
+end
+
+worldedit.allocate_old = worldedit.allocate
+
+worldedit.deserialize_old = worldedit.deserialize
+
+function worldedit.metasave(pos1, pos2, filename)
+	deprecated("save")
+	local file, err = io.open(filename, "wb")
+	if err then return 0 end
+	local data, count = worldedit.serialize(pos1, pos2)
+	file:write(data)
+	file:close()
+	return count
+end
+
+function worldedit.metaload(originpos, filename)
+	deprecated("load")
+	filename = minetest.get_worldpath() .. "/schems/" .. file .. ".wem"
+	local file, err = io.open(filename, "wb")
+	if err then return 0 end
+	local data = file:read("*a")
+	return worldedit.deserialize(originpos, data)
+end
+
+function worldedit.scale(pos1, pos2, factor)
+	deprecated("stretch")
+	return worldedit.stretch(pos1, pos2, factor, factor, factor)
+end
+
+function worldedit.valueversion(value)
+	deprecated("read_header")
+	local version = worldedit.read_header(value)
+	if not version or version > worldedit.LATEST_SERIALIZATION_VERSION then
+		return 0
+	end
+	return version
+end
+
+function worldedit.replaceinverse(pos1, pos2, search_node, replace_node)
+	deprecated("replace")
+	return worldedit.replace(pos1, pos2, search_node, replace_node, true)
+end
+
+function worldedit.clearobjects(...)
+	deprecated("clear_objects")
+	return worldedit.clear_objects(...)
+end
+
+function worldedit.hollow_sphere(pos, radius, node_name)
+	deprecated("sphere")
+	return worldedit.sphere(pos, radius, node_name, true)
+end
+
+function worldedit.hollow_dome(pos, radius, node_name)
+	deprecated("dome")
+	return worldedit.dome(pos, radius, node_name, true)
+end
+
+function worldedit.hollow_cylinder(pos, axis, length, radius, node_name)
+	deprecated("cylinder")
+	return worldedit.cylinder(pos, axis, length, radius, node_name, true)
+end
+

+ 40 - 32
worldedit/init.lua

@@ -1,40 +1,40 @@
---- Worldedit.
-
-
-worldedit = {}
-
-local ver = {major=1, minor=2}
-worldedit.version = ver
-worldedit.version_string = string.format("%d.%d", ver.major, ver.minor)
-
-local path = minetest.get_modpath(minetest.get_current_modname())
-
-local function load_module(path)
-	local file = io.open(path, "r")
-	if not file then return end
-	file:close()
-	return dofile(path)
-end
-
-dofile(path .. "/common.lua")
-load_module(path .. "/manipulations.lua")
-load_module(path .. "/primitives.lua")
-load_module(path .. "/visualization.lua")
-load_module(path .. "/serialization.lua")
-load_module(path .. "/code.lua")
-load_module(path .. "/compatibility.lua")
-load_module(path .. "/cuboid.lua")
-
-
-if minetest.settings:get_bool("log_mods") then
-	print("[WorldEdit] Loaded!")
-end
-
+--- Worldedit.
+-- @module worldedit
+-- @release 1.2
+-- @copyright 2013 sfan5, Anthony Zhang (Uberi/Temperest), and Brett O'Donnell (cornernote).
+-- @license GNU Affero General Public License version 3 (AGPLv3)
+-- @author sfan5
+-- @author Anthony Zang (Uberi/Temperest)
+-- @author Bret O'Donnel (cornernote)
+-- @author ShadowNinja
+
+
+worldedit = {}
+
+local ver = {major=1, minor=2}
+worldedit.version = ver
+worldedit.version_string = string.format("%d.%d", ver.major, ver.minor)
+
+local path = minetest.get_modpath(minetest.get_current_modname())
+
+local function load_module(path)
+	local file = io.open(path, "r")
+	if not file then return end
+	file:close()
+	return dofile(path)
+end
+
+dofile(path .. "/common.lua")
+load_module(path .. "/manipulations.lua")
+load_module(path .. "/primitives.lua")
+load_module(path .. "/visualization.lua")
+load_module(path .. "/serialization.lua")
+load_module(path .. "/code.lua")
+load_module(path .. "/compatibility.lua")
+load_module(path .. "/cuboid.lua")
+
+
+if minetest.settings:get_bool("log_mods") then
+	print("[WorldEdit] Loaded!")
+end
+

File diff suppressed because it is too large
+ 676 - 617
worldedit/manipulations.lua


+ 329 - 289
worldedit/primitives.lua

@@ -1,329 +1,329 @@
---- Functions for creating primitive shapes.
-
-local mh = worldedit.manip_helpers
-
-
---- Adds a cube
-function worldedit.cube(pos, width, height, length, node_name, hollow)
-	-- Set up voxel manipulator
-	local basepos = vector.subtract(pos, {x=math.floor(width/2), y=0, z=math.floor(length/2)})
-	local manip, area = mh.init(basepos, vector.add(basepos, {x=width, y=height, z=length}))
-	local data = mh.get_empty_data(area)
-
-	-- Add cube
-	local node_id = minetest.get_content_id(node_name)
-	local stride = {x=1, y=area.ystride, z=area.zstride}
-	local offset = vector.subtract(basepos, area.MinEdge)
-	local count = 0
-
-	for z = 0, length-1 do
-		local index_z = (offset.z + z) * stride.z + 1 -- +1 for 1-based indexing
-		for y = 0, height-1 do
-			local index_y = index_z + (offset.y + y) * stride.y
-			for x = 0, width-1 do
-				local is_wall = z == 0 or z == length-1
-					or y == 0 or y == height-1
-					or x == 0 or x == width-1
-				if not hollow or is_wall then
-					local i = index_y + (offset.x + x)
-					data[i] = node_id
-					count = count + 1
-				end
-			end
-		end
-	end
-
-	mh.finish(manip, data)
-	return count
-end
-
---- Adds a sphere of `node_name` centered at `pos`.
-function worldedit.sphere(pos, radius, node_name, hollow)
-	local manip, area = mh.init_radius(pos, radius)
-
-	local data = mh.get_empty_data(area)
-
-	-- Fill selected area with node
-	local node_id = minetest.get_content_id(node_name)
-	local min_radius, max_radius = radius * (radius - 1), radius * (radius + 1)
-	local offset_x, offset_y, offset_z = pos.x - area.MinEdge.x, pos.y - area.MinEdge.y, pos.z - area.MinEdge.z
-	local stride_z, stride_y = area.zstride, area.ystride
-	local count = 0
-	for z = -radius, radius do
-		-- Offset contributed by z plus 1 to make it 1-indexed
-		local new_z = (z + offset_z) * stride_z + 1
-		for y = -radius, radius do
-			local new_y = new_z + (y + offset_y) * stride_y
-			for x = -radius, radius do
-				local squared = x * x + y * y + z * z
-				if squared <= max_radius and (not hollow or squared >= min_radius) then
-					-- Position is on surface of sphere
-					local i = new_y + (x + offset_x)
-					data[i] = node_id
-					count = count + 1
-				end
-			end
-		end
-	end
-
-	mh.finish(manip, data)
-
-	return count
-end
-
-
---- Adds a dome.
-function worldedit.dome(pos, radius, node_name, hollow)
-	local min_y, max_y = 0, radius
-	if radius < 0 then
-		radius = -radius
-		min_y, max_y = -radius, 0
-	end
-
-	local manip, area = mh.init_axis_radius(pos, "y", radius)
-	local data = mh.get_empty_data(area)
-
-	-- Add dome
-	local node_id = minetest.get_content_id(node_name)
-	local min_radius, max_radius = radius * (radius - 1), radius * (radius + 1)
-	local offset_x, offset_y, offset_z = pos.x - area.MinEdge.x, pos.y - area.MinEdge.y, pos.z - area.MinEdge.z
-	local stride_z, stride_y = area.zstride, area.ystride
-	local count = 0
-	for z = -radius, radius do
-		local new_z = (z + offset_z) * stride_z + 1 --offset contributed by z plus 1 to make it 1-indexed
-		for y = min_y, max_y do
-			local new_y = new_z + (y + offset_y) * stride_y
-			for x = -radius, radius do
-				local squared = x * x + y * y + z * z
-				if squared <= max_radius and (not hollow or squared >= min_radius) then
-					-- Position is in dome
-					local i = new_y + (x + offset_x)
-					data[i] = node_id
-					count = count + 1
-				end
-			end
-		end
-	end
-
-	mh.finish(manip, data)
-
-	return count
-end
-
---- Adds a cylinder.
-function worldedit.cylinder(pos, axis, length, radius1, radius2, node_name, hollow)
-	local other1, other2 = worldedit.get_axis_others(axis)
-
-	-- Backwards compatibility
-	if type(radius2) == "string" then
-		hollow = node_name
-		node_name = radius2
-		radius2 = radius1 -- straight cylinder
-	end
-
-	-- Handle negative lengths
-	local current_pos = {x=pos.x, y=pos.y, z=pos.z}
-	if length < 0 then
-		length = -length
-		current_pos[axis] = current_pos[axis] - length
-		radius1, radius2 = radius2, radius1
-	end
-
-	-- Set up voxel manipulator
-	local manip, area = mh.init_axis_radius_length(current_pos, axis, math.max(radius1, radius2), length)
-	local data = mh.get_empty_data(area)
-
-	-- Add desired shape (anything inbetween cylinder & cone)
-	local node_id = minetest.get_content_id(node_name)
-	local stride = {x=1, y=area.ystride, z=area.zstride}
-	local offset = {
-		x = current_pos.x - area.MinEdge.x,
-		y = current_pos.y - area.MinEdge.y,
-		z = current_pos.z - area.MinEdge.z,
-	}
-	local count = 0
-	for i = 0, length - 1 do
-		-- Calulate radius for this "height" in the cylinder
-		local radius = radius1 + (radius2 - radius1) * (i + 1) / length
-		radius = math.floor(radius + 0.5) -- round
-		local min_radius, max_radius = radius * (radius - 1), radius * (radius + 1)
-
-		for index2 = -radius, radius do
-			-- Offset contributed by other axis 1 plus 1 to make it 1-indexed
-			local new_index2 = (index2 + offset[other1]) * stride[other1] + 1
-			for index3 = -radius, radius do
-				local new_index3 = new_index2 + (index3 + offset[other2]) * stride[other2]
-				local squared = index2 * index2 + index3 * index3
-				if squared <= max_radius and (not hollow or squared >= min_radius) then
-					-- Position is in cylinder, add node here
-					local vi = new_index3 + (offset[axis] + i) * stride[axis]
-					data[vi] = node_id
-					count = count + 1
-				end
-			end
-		end
-	end
-
-	mh.finish(manip, data)
-
-	return count
-end
-
-
---- Adds a pyramid.
-function worldedit.pyramid(pos, axis, height, node_name, hollow)
-	local other1, other2 = worldedit.get_axis_others(axis)
-
-	-- Set up voxel manipulator
-	-- FIXME: passing negative <radius> causes mis-sorted pos to be passed
-	-- into mh.init() which is technically not allowed but works
-	local manip, area = mh.init_axis_radius(pos, axis, height)
-	local data = mh.get_empty_data(area)
-
-	-- Handle inverted pyramids
-	local step
-	if height > 0 then
-		height = height - 1
-		step = 1
-	else
-		height = height + 1
-		step = -1
-	end
-
-	-- Add pyramid
-	local node_id = minetest.get_content_id(node_name)
-	local stride = {x=1, y=area.ystride, z=area.zstride}
-	local offset = {
-		x = pos.x - area.MinEdge.x,
-		y = pos.y - area.MinEdge.y,
-		z = pos.z - area.MinEdge.z,
-	}
-	local size = math.abs(height * step)
-	local count = 0
-	-- For each level of the pyramid
-	for index1 = 0, height, step do
-		-- Offset contributed by axis plus 1 to make it 1-indexed
-		local new_index1 = (index1 + offset[axis]) * stride[axis] + 1
-		for index2 = -size, size do
-			local new_index2 = new_index1 + (index2 + offset[other1]) * stride[other1]
-			for index3 = -size, size do
-				local i = new_index2 + (index3 + offset[other2]) * stride[other2]
-				if (not hollow or size - math.abs(index2) < 2 or size - math.abs(index3) < 2) then
-				       data[i] = node_id
-				       count = count + 1
-				end
-			end
-		end
-		size = size - 1
-	end
-
-	mh.finish(manip, data)
-
-	return count
-end
-
---- Adds a spiral.
-function worldedit.spiral(pos, length, height, spacer, node_name)
-	local extent = math.ceil(length / 2)
-
-	local manip, area = mh.init_axis_radius_length(pos, "y", extent, height)
-	local data = mh.get_empty_data(area)
-
-	-- Set up variables
-	local node_id = minetest.get_content_id(node_name)
-	local stride = {x=1, y=area.ystride, z=area.zstride}
-	local offset_x, offset_y, offset_z = pos.x - area.MinEdge.x, pos.y - area.MinEdge.y, pos.z - area.MinEdge.z
-	local i = offset_z * stride.z + offset_y * stride.y + offset_x + 1
-
-	-- Add first column
-	local count = height
-	local column = i
-	for y = 1, height do
-		data[column] = node_id
-		column = column + stride.y
-	end
-
-	-- Add spiral segments
-	local stride_axis, stride_other = stride.x, stride.z
-	local sign = -1
-	local segment_length = 0
-	spacer = spacer + 1
-	-- Go through each segment except the last
-	for segment = 1, math.floor(length / spacer) * 2 do
-		-- Change sign and length every other turn starting with the first
-		if segment % 2 == 1 then
-			sign = -sign
-			segment_length = segment_length + spacer
-		end
-		-- Fill segment
-		for index = 1, segment_length do
-			-- Move along the direction of the segment
-			i = i + stride_axis * sign
-			local column = i
-			-- Add column
-			for y = 1, height do
-				data[column] = node_id
-				column = column + stride.y
-			end
-		end
-		count = count + segment_length * height
-		stride_axis, stride_other = stride_other, stride_axis -- Swap axes
-	end
-
-	-- Add shorter final segment
-	sign = -sign
-	for index = 1, segment_length do
-		i = i + stride_axis * sign
-		local column = i
-		-- Add column
-		for y = 1, height do
-			data[column] = node_id
-			column = column + stride.y
-		end
-	end
-	count = count + segment_length * height
-
-	mh.finish(manip, data)
-
-	return count
-end
+--- Functions for creating primitive shapes.
+-- @module worldedit.primitives
+
+local mh = worldedit.manip_helpers
+
+
+--- Adds a cube
+-- @param pos Position of ground level center of cube
+-- @param width Cube width. (x)
+-- @param height Cube height. (y)
+-- @param length Cube length. (z)
+-- @param node_name Name of node to make cube of.
+-- @param hollow Whether the cube should be hollow.
+-- @return The number of nodes added.
+function worldedit.cube(pos, width, height, length, node_name, hollow)
+	-- Set up voxel manipulator
+	local basepos = vector.subtract(pos, {x=math.floor(width/2), y=0, z=math.floor(length/2)})
+	local manip, area = mh.init(basepos, vector.add(basepos, {x=width, y=height, z=length}))
+	local data = mh.get_empty_data(area)
+
+	-- Add cube
+	local node_id = minetest.get_content_id(node_name)
+	local stride = {x=1, y=area.ystride, z=area.zstride}
+	local offset = vector.subtract(basepos, area.MinEdge)
+	local count = 0
+
+	for z = 0, length-1 do
+		local index_z = (offset.z + z) * stride.z + 1 -- +1 for 1-based indexing
+		for y = 0, height-1 do
+			local index_y = index_z + (offset.y + y) * stride.y
+			for x = 0, width-1 do
+				local is_wall = z == 0 or z == length-1
+					or y == 0 or y == height-1
+					or x == 0 or x == width-1
+				if not hollow or is_wall then
+					local i = index_y + (offset.x + x)
+					data[i] = node_id
+					count = count + 1
+				end
+			end
+		end
+	end
+
+	mh.finish(manip, data)
+	return count
+end
+
+--- Adds a sphere of `node_name` centered at `pos`.
+-- @param pos Position to center sphere at.
+-- @param radius Sphere radius.
+-- @param node_name Name of node to make shere of.
+-- @param hollow Whether the sphere should be hollow.
+-- @return The number of nodes added.
+function worldedit.sphere(pos, radius, node_name, hollow)
+	local manip, area = mh.init_radius(pos, radius)
+
+	local data = mh.get_empty_data(area)
+
+	-- Fill selected area with node
+	local node_id = minetest.get_content_id(node_name)
+	local min_radius, max_radius = radius * (radius - 1), radius * (radius + 1)
+	local offset_x, offset_y, offset_z = pos.x - area.MinEdge.x, pos.y - area.MinEdge.y, pos.z - area.MinEdge.z
+	local stride_z, stride_y = area.zstride, area.ystride
+	local count = 0
+	for z = -radius, radius do
+		-- Offset contributed by z plus 1 to make it 1-indexed
+		local new_z = (z + offset_z) * stride_z + 1
+		for y = -radius, radius do
+			local new_y = new_z + (y + offset_y) * stride_y
+			for x = -radius, radius do
+				local squared = x * x + y * y + z * z
+				if squared <= max_radius and (not hollow or squared >= min_radius) then
+					-- Position is on surface of sphere
+					local i = new_y + (x + offset_x)
+					data[i] = node_id
+					count = count + 1
+				end
+			end
+		end
+	end
+
+	mh.finish(manip, data)
+
+	return count
+end
+
+
+--- Adds a dome.
+-- @param pos Position to center dome at.
+-- @param radius Dome radius.  Negative for concave domes.
+-- @param node_name Name of node to make dome of.
+-- @param hollow Whether the dome should be hollow.
+-- @return The number of nodes added.
+-- TODO: Add axis option.
+function worldedit.dome(pos, radius, node_name, hollow)
+	local min_y, max_y = 0, radius
+	if radius < 0 then
+		radius = -radius
+		min_y, max_y = -radius, 0
+	end
+
+	local manip, area = mh.init_axis_radius(pos, "y", radius)
+	local data = mh.get_empty_data(area)
+
+	-- Add dome
+	local node_id = minetest.get_content_id(node_name)
+	local min_radius, max_radius = radius * (radius - 1), radius * (radius + 1)
+	local offset_x, offset_y, offset_z = pos.x - area.MinEdge.x, pos.y - area.MinEdge.y, pos.z - area.MinEdge.z
+	local stride_z, stride_y = area.zstride, area.ystride
+	local count = 0
+	for z = -radius, radius do
+		local new_z = (z + offset_z) * stride_z + 1 --offset contributed by z plus 1 to make it 1-indexed
+		for y = min_y, max_y do
+			local new_y = new_z + (y + offset_y) * stride_y
+			for x = -radius, radius do
+				local squared = x * x + y * y + z * z
+				if squared <= max_radius and (not hollow or squared >= min_radius) then
+					-- Position is in dome
+					local i = new_y + (x + offset_x)
+					data[i] = node_id
+					count = count + 1
+				end
+			end
+		end
+	end
+
+	mh.finish(manip, data)
+
+	return count
+end
+
+--- Adds a cylinder.
+-- @param pos Position to center base of cylinder at.
+-- @param axis Axis ("x", "y", or "z")
+-- @param length Cylinder length.
+-- @param radius1 Cylinder base radius.
+-- @param radius2 Cylinder top radius.
+-- @param node_name Name of node to make cylinder of.
+-- @param hollow Whether the cylinder should be hollow.
+-- @return The number of nodes added.
+function worldedit.cylinder(pos, axis, length, radius1, radius2, node_name, hollow)
+	local other1, other2 = worldedit.get_axis_others(axis)
+
+	-- Backwards compatibility
+	if type(radius2) == "string" then
+		hollow = node_name
+		node_name = radius2
+		radius2 = radius1 -- straight cylinder
+	end
+
+	-- Handle negative lengths
+	local current_pos = {x=pos.x, y=pos.y, z=pos.z}
+	if length < 0 then
+		length = -length
+		current_pos[axis] = current_pos[axis] - length
+		radius1, radius2 = radius2, radius1
+	end
+
+	-- Set up voxel manipulator
+	local manip, area = mh.init_axis_radius_length(current_pos, axis, math.max(radius1, radius2), length)
+	local data = mh.get_empty_data(area)
+
+	-- Add desired shape (anything inbetween cylinder & cone)
+	local node_id = minetest.get_content_id(node_name)
+	local stride = {x=1, y=area.ystride, z=area.zstride}
+	local offset = {
+		x = current_pos.x - area.MinEdge.x,
+		y = current_pos.y - area.MinEdge.y,
+		z = current_pos.z - area.MinEdge.z,
+	}
+	local count = 0
+	for i = 0, length - 1 do
+		-- Calulate radius for this "height" in the cylinder
+		local radius = radius1 + (radius2 - radius1) * (i + 1) / length
+		radius = math.floor(radius + 0.5) -- round
+		local min_radius, max_radius = radius * (radius - 1), radius * (radius + 1)
+
+		for index2 = -radius, radius do
+			-- Offset contributed by other axis 1 plus 1 to make it 1-indexed
+			local new_index2 = (index2 + offset[other1]) * stride[other1] + 1
+			for index3 = -radius, radius do
+				local new_index3 = new_index2 + (index3 + offset[other2]) * stride[other2]
+				local squared = index2 * index2 + index3 * index3
+				if squared <= max_radius and (not hollow or squared >= min_radius) then
+					-- Position is in cylinder, add node here
+					local vi = new_index3 + (offset[axis] + i) * stride[axis]
+					data[vi] = node_id
+					count = count + 1
+				end
+			end
+		end
+	end
+
+	mh.finish(manip, data)
+
+	return count
+end
+
+
+--- Adds a pyramid.
+-- @param pos Position to center base of pyramid at.
+-- @param axis Axis ("x", "y", or "z")
+-- @param height Pyramid height.
+-- @param node_name Name of node to make pyramid of.
+-- @param hollow Whether the pyramid should be hollow.
+-- @return The number of nodes added.
+function worldedit.pyramid(pos, axis, height, node_name, hollow)
+	local other1, other2 = worldedit.get_axis_others(axis)
+
+	-- Set up voxel manipulator
+	-- FIXME: passing negative <radius> causes mis-sorted pos to be passed
+	-- into mh.init() which is technically not allowed but works
+	local manip, area = mh.init_axis_radius(pos, axis, height)
+	local data = mh.get_empty_data(area)
+
+	-- Handle inverted pyramids
+	local step
+	if height > 0 then
+		height = height - 1
+		step = 1
+	else
+		height = height + 1
+		step = -1
+	end
+
+	-- Add pyramid
+	local node_id = minetest.get_content_id(node_name)
+	local stride = {x=1, y=area.ystride, z=area.zstride}
+	local offset = {
+		x = pos.x - area.MinEdge.x,
+		y = pos.y - area.MinEdge.y,
+		z = pos.z - area.MinEdge.z,
+	}
+	local size = math.abs(height * step)
+	local count = 0
+	-- For each level of the pyramid
+	for index1 = 0, height, step do
+		-- Offset contributed by axis plus 1 to make it 1-indexed
+		local new_index1 = (index1 + offset[axis]) * stride[axis] + 1
+		for index2 = -size, size do
+			local new_index2 = new_index1 + (index2 + offset[other1]) * stride[other1]
+			for index3 = -size, size do
+				local i = new_index2 + (index3 + offset[other2]) * stride[other2]
+				if (not hollow or size - math.abs(index2) < 2 or size - math.abs(index3) < 2) then
+				       data[i] = node_id
+				       count = count + 1
+				end
+			end
+		end
+		size = size - 1
+	end
+
+	mh.finish(manip, data)
+
+	return count
+end
+
+--- Adds a spiral.
+-- @param pos Position to center spiral at.
+-- @param length Spral length.
+-- @param height Spiral height.
+-- @param spacer Space between walls.
+-- @param node_name Name of node to make spiral of.
+-- @return Number of nodes added.
+-- TODO: Add axis option.
+function worldedit.spiral(pos, length, height, spacer, node_name)
+	local extent = math.ceil(length / 2)
+
+	local manip, area = mh.init_axis_radius_length(pos, "y", extent, height)
+	local data = mh.get_empty_data(area)
+
+	-- Set up variables
+	local node_id = minetest.get_content_id(node_name)
+	local stride = {x=1, y=area.ystride, z=area.zstride}
+	local offset_x, offset_y, offset_z = pos.x - area.MinEdge.x, pos.y - area.MinEdge.y, pos.z - area.MinEdge.z
+	local i = offset_z * stride.z + offset_y * stride.y + offset_x + 1
+
+	-- Add first column
+	local count = height
+	local column = i
+	for y = 1, height do
+		data[column] = node_id
+		column = column + stride.y
+	end
+
+	-- Add spiral segments
+	local stride_axis, stride_other = stride.x, stride.z
+	local sign = -1
+	local segment_length = 0
+	spacer = spacer + 1
+	-- Go through each segment except the last
+	for segment = 1, math.floor(length / spacer) * 2 do
+		-- Change sign and length every other turn starting with the first
+		if segment % 2 == 1 then
+			sign = -sign
+			segment_length = segment_length + spacer
+		end
+		-- Fill segment
+		for index = 1, segment_length do
+			-- Move along the direction of the segment
+			i = i + stride_axis * sign
+			local column = i
+			-- Add column
+			for y = 1, height do
+				data[column] = node_id
+				column = column + stride.y
+			end
+		end
+		count = count + segment_length * height
+		stride_axis, stride_other = stride_other, stride_axis -- Swap axes
+	end
+
+	-- Add shorter final segment
+	sign = -sign
+	for index = 1, segment_length do
+		i = i + stride_axis * sign
+		local column = i
+		-- Add column
+		for y = 1, height do
+			data[column] = node_id
+			column = column + stride.y
+		end
+	end
+	count = count + segment_length * height
+
+	mh.finish(manip, data)
+
+	return count
+end

+ 0 - 0
worldedit/serialization.lua


Some files were not shown because too many files changed in this diff