Improve LuaVoxelManip documentation
This commit is contained in:
parent
2a12579fab
commit
f9e394a466
|
@ -4,6 +4,11 @@
|
||||||
-- Constants values for use with the Lua API
|
-- Constants values for use with the Lua API
|
||||||
--
|
--
|
||||||
|
|
||||||
|
-- Built-in Content IDs (for use with VoxelManip API)
|
||||||
|
core.CONTENT_UNKNOWN = 125
|
||||||
|
core.CONTENT_AIR = 126
|
||||||
|
core.CONTENT_IGNORE = 127
|
||||||
|
|
||||||
-- Block emerge status constants (for use with core.emerge_area)
|
-- Block emerge status constants (for use with core.emerge_area)
|
||||||
core.EMERGE_CANCELLED = 0
|
core.EMERGE_CANCELLED = 0
|
||||||
core.EMERGE_ERRORED = 1
|
core.EMERGE_ERRORED = 1
|
||||||
|
|
167
doc/lua_api.txt
167
doc/lua_api.txt
|
@ -2812,22 +2812,171 @@ nil, this table will be used to store the result instead of creating a new table
|
||||||
`noisevals = noise:getMapSlice({x=24, z=1}, {x=1, z=1})`
|
`noisevals = noise:getMapSlice({x=24, z=1}, {x=1, z=1})`
|
||||||
|
|
||||||
### `VoxelManip`
|
### `VoxelManip`
|
||||||
An interface to the `MapVoxelManipulator` for Lua.
|
|
||||||
|
|
||||||
It can be created via `VoxelManip()` or `minetest.get_voxel_manip()`.
|
#### About VoxelManip
|
||||||
The map will be pre-loaded if two positions are passed to either.
|
VoxelManip is a scripting interface to the internal 'Map Voxel Manipulator' facility. The purpose of
|
||||||
|
this object is for fast, low-level, bulk access to reading and writing Map content. As such, setting
|
||||||
|
map nodes through VoxelManip will lack many of the higher level features and concepts you may be used
|
||||||
|
to with other methods of setting nodes. For example, nodes will not have their construction and
|
||||||
|
destruction callbacks run, and no rollback information is logged.
|
||||||
|
|
||||||
|
It is important to note that VoxelManip is designed for speed, and *not* ease of use or flexibility.
|
||||||
|
If your mod requires a map manipulation facility that will handle 100% of all edge cases, or the use
|
||||||
|
of high level node placement features, perhaps minetest.set_node() is better suited for the job.
|
||||||
|
|
||||||
|
In addition, VoxelManip might not be faster, or could even be slower, for your specific use case.
|
||||||
|
VoxelManip is most effective when setting very large areas of map at once - for example, if only
|
||||||
|
setting a 5x5x5 node area, a minetest.set_node() loop may be more optimal. Always profile code
|
||||||
|
using both methods of map manipulation to determine which is most appropriate for your usage.
|
||||||
|
|
||||||
|
#### Using VoxelManip
|
||||||
|
A VoxelManip object can be created any time using either:
|
||||||
|
`VoxelManip([p1, p2])`, or `minetest.get_voxel_manip([p1, p2])`.
|
||||||
|
|
||||||
|
If the optional position parameters are present for either of these routines, the specified region
|
||||||
|
will be pre-loaded into the VoxelManip object on creation. Otherwise, the area of map you wish to
|
||||||
|
manipulate must first be loaded into the VoxelManip object using `VoxelManip:read_from_map()`.
|
||||||
|
|
||||||
|
Note that `VoxelManip:read_from_map()` returns two position vectors. The region formed by these
|
||||||
|
positions indicate the minimum and maximum (respectively) positions of the area actually loaded in
|
||||||
|
the VoxelManip, which may be larger than the area requested. For convenience, the loaded area
|
||||||
|
coordinates can also be queried any time after loading map data with `VoxelManip:get_emerged_area()`.
|
||||||
|
|
||||||
|
Now that the VoxelManip object is populated with map data, your mod can fetch a copy of this data
|
||||||
|
using either of two methods. `VoxelManip:get_node_at()`, which retrieves an individual node in a
|
||||||
|
MapNode formatted table at the position requested is the simplest method to use, but also the slowest.
|
||||||
|
|
||||||
|
Nodes in a VoxelManip object may also be read in bulk to a flat array table using:
|
||||||
|
`VoxelManip:get_data()` for node content (in Content ID form, see section 'Content IDs'),
|
||||||
|
`VoxelManip:get_light_data()` for node light levels, and
|
||||||
|
`VoxelManip:get_param2_data()` for the node type-dependent "param2" values.
|
||||||
|
|
||||||
|
See section 'Flat array format' for more details.
|
||||||
|
|
||||||
|
It is very important to understand that the tables returned by any of the above three functions
|
||||||
|
represent a snapshot of the VoxelManip's internal state at the time of the call. This copy of the
|
||||||
|
data will *not* magically update itself if another function modifies the internal VoxelManip state.
|
||||||
|
Any functions that modify a VoxelManip's contents work on the VoxelManip's internal state unless
|
||||||
|
otherwise explicitly stated.
|
||||||
|
|
||||||
|
Once the bulk data has been edited to your liking, the internal VoxelManip state can be set using:
|
||||||
|
`VoxelManip:set_data()` for node content (in Content ID form, see section 'Content IDs'),
|
||||||
|
`VoxelManip:set_light_data()` for node light levels, and
|
||||||
|
`VoxelManip:set_param2_data()` for the node type-dependent "param2" values.
|
||||||
|
|
||||||
|
The parameter to each of the above three functions can use any table at all in the same flat array
|
||||||
|
format as produced by get_data() et al. and is *not required* to be a table retrieved from get_data().
|
||||||
|
|
||||||
|
Once the internal VoxelManip state has been modified to your liking, the changes can be committed back
|
||||||
|
to the map by calling `VoxelManip:write_to_map()`.
|
||||||
|
|
||||||
|
Finally, a call to `VoxelManip:update_map()` is required to re-calculate lighting and set the blocks
|
||||||
|
as being modified so that connected clients are sent the updated parts of map.
|
||||||
|
|
||||||
|
|
||||||
|
##### Flat array format
|
||||||
|
Let
|
||||||
|
`Nx = p2.X - p1.X + 1`,
|
||||||
|
`Ny = p2.Y - p1.Y + 1`, and
|
||||||
|
`Nz = p2.Z - p1.Z + 1`.
|
||||||
|
|
||||||
|
Then, for a loaded region of p1..p2, this array ranges from `1` up to and including the value of
|
||||||
|
the expression `Nx * Ny * Nz`.
|
||||||
|
|
||||||
|
Positions offset from p1 are present in the array with the format of:
|
||||||
|
```
|
||||||
|
[
|
||||||
|
(0, 0, 0), (1, 0, 0), (2, 0, 0), ... (Nx, 0, 0),
|
||||||
|
(0, 1, 0), (1, 1, 0), (2, 1, 0), ... (Nx, 1, 0),
|
||||||
|
...
|
||||||
|
(0, Ny, 0), (1, Ny, 0), (2, Ny, 0), ... (Nx, Ny, 0),
|
||||||
|
(0, 0, 1), (1, 0, 1), (2, 0, 1), ... (Nx, 0, 1),
|
||||||
|
...
|
||||||
|
(0, Ny, 2), (1, Ny, 2), (2, Ny, 2), ... (Nx, Ny, 2),
|
||||||
|
...
|
||||||
|
(0, Ny, Nz), (1, Ny, Nz), (2, Ny, Nz), ... (Nx, Ny, Nz)
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
and the array index for a position p contained completely in p1..p2 is:
|
||||||
|
|
||||||
|
`(p.Z - p1.Z) * Ny * Nx + (p.Y - p1.Y) * Nx + (p.X - p1.X) + 1`
|
||||||
|
|
||||||
|
Note that this is the same "flat 3D array" format as `PerlinNoiseMap:get3dMap_flat()`.
|
||||||
|
VoxelArea objects (see section 'VoxelArea') can be used to simplify calculation of the index
|
||||||
|
for a single point in a flat VoxelManip array.
|
||||||
|
|
||||||
|
##### Content IDs
|
||||||
|
A Content ID is a unique integer identifier for a specific node type. These IDs are used by VoxelManip
|
||||||
|
in place of the node name string for `VoxelManip:get_data()` and `VoxelManip:set_data()`. You can use
|
||||||
|
`minetest.get_content_id()` to look up the Content ID for the specified node name, and
|
||||||
|
`minetest.get_name_from_content_id()` to look up the node name string for a given Content ID.
|
||||||
|
After registration of a node, its Content ID will remain the same throughout execution of the mod.
|
||||||
|
Note that the node being queried needs to have already been been registered.
|
||||||
|
|
||||||
|
The following builtin node types have their Content IDs defined as constants:
|
||||||
|
```
|
||||||
|
core.CONTENT_UNKNOWN (ID for "unknown" nodes)
|
||||||
|
core.CONTENT_AIR (ID for "air" nodes)
|
||||||
|
core.CONTENT_IGNORE (ID for "ignore" nodes)
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Mapgen VoxelManip objects
|
||||||
|
Inside of `on_generated()` callbacks, it is possible to retrieve the same VoxelManip object used by the
|
||||||
|
core's Map Generator (commonly abbreviated Mapgen). Most of the rules previously described still apply
|
||||||
|
but with a few differences:
|
||||||
|
* The Mapgen VoxelManip object is retrieved using: `minetest.get_mapgen_object("voxelmanip")`
|
||||||
|
* This VoxelManip object already has the region of map just generated loaded into it; it's not necessary
|
||||||
|
to call `VoxelManip:read_from_map()` before using a Mapgen VoxelManip.
|
||||||
|
* The `on_generated()` callbacks of some mods may place individual nodes in the generated area using
|
||||||
|
non-VoxelManip map modification methods. Because the same Mapgen VoxelManip object is passed through
|
||||||
|
each `on_generated()` callback, it becomes necessary for the Mapgen VoxelManip object to maintain
|
||||||
|
consistency with the current map state. For this reason, calling any of the following functions:
|
||||||
|
`minetest.add_node()`, `minetest.set_node()`, or `minetest.swap_node()`
|
||||||
|
will also update the Mapgen VoxelManip object's internal state active on the current thread.
|
||||||
|
* After modifying the Mapgen VoxelManip object's internal buffer, it may be necessary to update lighting
|
||||||
|
information using either: `VoxelManip:calc_lighting()` or `VoxelManip:set_lighting()`.
|
||||||
|
* `VoxelManip:update_map()` does not need to be called after `write_to_map()`. The map update is performed
|
||||||
|
automatically after all on_generated callbacks have been run for that generated block.
|
||||||
|
|
||||||
|
##### Other API functions operating on a VoxelManip
|
||||||
|
If any VoxelManip contents were set to a liquid node, `VoxelManip:update_liquids()` must be called
|
||||||
|
for these liquid nodes to begin flowing. It is recommended to call this function only after having
|
||||||
|
written all buffered data back to the VoxelManip object, save for special situations where the modder
|
||||||
|
desires to only have certain liquid nodes begin flowing.
|
||||||
|
|
||||||
|
The functions `minetest.generate_ores()` and `minetest.generate_decorations()` will generate all
|
||||||
|
registered decorations and ores throughout the full area inside of the specified VoxelManip object.
|
||||||
|
|
||||||
|
`minetest.place_schematic_on_vmanip()` is otherwise identical to `minetest.place_schematic()`,
|
||||||
|
except instead of placing the specified schematic directly on the map at the specified position, it
|
||||||
|
will place the schematic inside of the VoxelManip.
|
||||||
|
|
||||||
|
##### Notes
|
||||||
|
* Attempting to read data from a VoxelManip object before map is read will result in a zero-length
|
||||||
|
array table for `VoxelManip:get_data()`, and an "ignore" node at any position for
|
||||||
|
`VoxelManip:get_node_at()`.
|
||||||
|
* If either a region of map has not yet been generated or is out-of-bounds of the map, that region is
|
||||||
|
filled with "ignore" nodes.
|
||||||
|
* Other mods, or the core itself, could possibly modify the area of map currently loaded into a VoxelManip
|
||||||
|
object. With the exception of Mapgen VoxelManips (see above section), the internal buffers are not
|
||||||
|
updated. For this reason, it is strongly encouraged to complete the usage of a particular VoxelManip
|
||||||
|
object in the same callback it had been created.
|
||||||
|
* If a VoxelManip object will be used often, such as in an `on_generated()` callback, consider passing
|
||||||
|
a file-scoped table as the optional parameter to `VoxelManip:get_data()`, which serves as a static
|
||||||
|
buffer the function can use to write map data to instead of returning a new table each call. This
|
||||||
|
greatly enhances performance by avoiding unnecessary memory allocations.
|
||||||
|
|
||||||
#### Methods
|
#### Methods
|
||||||
* `read_from_map(p1, p2)`: Reads a chunk of map from the map containing the
|
* `read_from_map(p1, p2)`: Loads a chunk of map into the VoxelManip object containing
|
||||||
region formed by `p1` and `p2`.
|
the region formed by `p1` and `p2`.
|
||||||
* returns actual emerged `pmin`, actual emerged `pmax`
|
* returns actual emerged `pmin`, actual emerged `pmax`
|
||||||
* `write_to_map()`: Writes the data loaded from the `VoxelManip` back to the map.
|
* `write_to_map()`: Writes the data loaded from the `VoxelManip` back to the map.
|
||||||
* **important**: data must be set using `VoxelManip:set_data` before calling this
|
* **important**: data must be set using `VoxelManip:set_data()` before calling this
|
||||||
* `get_node_at(pos)`: Returns a `MapNode` table of the node currently loaded in
|
* `get_node_at(pos)`: Returns a `MapNode` table of the node currently loaded in
|
||||||
the `VoxelManip` at that position
|
the `VoxelManip` at that position
|
||||||
* `set_node_at(pos, node)`: Sets a specific `MapNode` in the `VoxelManip` at
|
* `set_node_at(pos, node)`: Sets a specific `MapNode` in the `VoxelManip` at that position
|
||||||
that position
|
* `get_data([buffer])`: Retrieves the node content data loaded into the `VoxelManip` object
|
||||||
* `get_data(buffer)`: Gets the data read into the `VoxelManip` object
|
|
||||||
* returns raw node data in the form of an array of node content IDs
|
* returns raw node data in the form of an array of node content IDs
|
||||||
* if the param `buffer` is present, this table will be used to store the result instead
|
* if the param `buffer` is present, this table will be used to store the result instead
|
||||||
* `set_data(data)`: Sets the data contents of the `VoxelManip` object
|
* `set_data(data)`: Sets the data contents of the `VoxelManip` object
|
||||||
|
|
Loading…
Reference in New Issue