VoxelManip
![]() |
This page contains unofficial Lua API documentation and is likely to be outdated or wrong. For the official and up-to-date documentation, refer to lua_api.txt found in your Minetest installation directory under doc . |
![]() |
This page has been proposed for deletion for the following reason: "Contains unofficial and potentially outdated, redundant and inconsistent Lua API information" If you don't think that this page should be deleted, please explain why on the talk page. |
- Available in versions 0.4.8+
The Voxel Manipulator can be used to set many nodes in a specified area at once, which is useful to avoid unnecessary calculations. The metas of nodes, if they have one, do not become removed and the on_constructs and on_destructs are ignored.
Contents |
VoxelManip
It's an interface to the MapVoxelManipulator for Lua, it can be created via VoxelManip() or minetest.get_voxel_manip().
The usage varies between mapgen and no mapgen, see #Examples.
Methods:
Name | Usability in on_generated or somewhere else | Description | Comments |
---|---|---|---|
read_from_map(p1, p2) | no mapgen | Reads a chunk of map from the map containing the region formed by p1 and p2. | returns actual emerged pmin, actual emerged pmax, where "emerged" means that VoxelManip will "round up" to the nearest 16x16x16 map block boundary when actually creating the volume and will return the pmin and pmax of that envelope. |
write_to_map([fix_light]) | both | This writes the data loaded from the VoxelManip back to the map. If fix_light is explicitly set to false, no light calculation transpires. | The data should be set using VoxelManip:set_data before calling this. See also minetest.fix_light. |
get_data([buffer]) | both | Gets the data read into the VoxelManip object, if buffer is a table, this table is used to store the values instead of returning a new one. | This method returns or sets raw node data in the form of an array of node content ids. The buffer can be used to increase performance (less garbage collection etc.). |
set_data(data) | both | Sets the data contents of the VoxelManip object | if you build the "data" array manually it must have the correct starting index and be contiguous and complete (an entry for every block in the volume) |
set_lighting(light[, p1, p2]) | only mapgen | Set the lighting within the VoxelManip to an uniform value | light is a table, {day=<0...15>, night=<0...15>}, (p1, p2) is the area in which lighting is set; defaults to the whole area if left out. |
get_light_data() | both | Gets the param1 (light data) read into the VoxelManip object | Returns an array (indices 1 to volume) of integers ranging from 0 to 255, param1 = (artificial * 0x10) + sun; Each value is the bitwise combination of artificial and sun light values (0..15 each) |
set_light_data(light_data) | both (sunlight maybe mapgen only) | Sets the param1 (light) contents of each node in the VoxelManip | It expects lighting data in the same format that get_light_data() returns. Set the fix_light argument of write_to_map to false, else this method doesn't work. |
get_param2_data([buffer]) | both | Gets the param2 data read into the VoxelManip object | Available since 0.4.10 |
set_param2_data(param2_data) | both | Sets the param2 contents of each node in the VoxelManip | Available since 0.4.10 |
calc_lighting([p1, p2][, propagate_shadow]) | mapgen only | Calculate lighting within the VoxelManip | (p1, p2) is the area in which lighting is set; defaults to the whole area if omitted. If propagate_shadow is explicitly set to false, shadows are not spread down to other mapchunks. |
update_liquids() | both | Update liquid flow | |
update_map() | deprecated | Does nothing, kept for compatibility. | See [1] |
VoxelArea
VoxelArea is a helper class for voxel areas, it can be created via VoxelArea:new{MinEdge=pmin, MaxEdge=pmax}.
The coordinates are *inclusive*, like most other things in Minetest
methods:
name | description | comments |
---|---|---|
getExtent() | returns a 3d vector containing the size of the area formed by MinEdge and MaxEdge | |
getVolume() | returns the volume of the area formed by MinEdge and MaxEdge | |
index(x, y, z) | returns the index of an absolute position in a flat array starting at 1 + mapblock index. | useful for things like VoxelManip, raw Schematic specifiers, PerlinNoiseMap:get2d/3dMap, and so on. Indexes are only valid for a specific extent at a specific location in the map! |
indexp(p) | same as index(p.x, p.y, p.z) | |
position(i) | returns the absolute position vector corresponding to index i | |
contains(x, y, z) | check if (x,y,z) is inside area formed by MinEdge and MaxEdge | |
containsp(p) | same as contains(p.x, p.y, p.z) | |
containsi(i) | same as above, except takes an index (mostly useless) | |
iter(minx, miny, minz, maxx, maxy, maxz) | returns an iterator that returns indices | from (minx,miny,minz) to (maxx,maxy,maxz) in the order of [z [y [x]]]. Use this when you want to set a cuboid of nodes. |
iterp(minp, maxp) | same as above, except takes two vectors |
For more information, have a look at the implementation.
Tips for handling indices
Using offsets
Instead of recalculating the index using area:index or using the area:iter function, to move in specific directions you only need to add a specific number.
This is the area:index function:
function VoxelArea:index(x, y, z) local MinEdge = self.MinEdge local i = (z - MinEdge.z) * self.zstride + (y - MinEdge.y) * self.ystride + (x - MinEdge.x) + 1 return math.floor(i) end
If you have one index given and want to have the index for the position 1m above you don't need to recalculate the whole thing:
self = area MinEdge = area.MinEdge i = area:index(x, y, z) = (z - MinEdge.z) * self.zstride + (y - MinEdge.y) * self.ystride + (x - MinEdge.x) + 1 i2 = area:index(x, y+1, z) = (z - MinEdge.z) * self.zstride + ((y+1) - MinEdge.y) * self.ystride + (x - MinEdge.x) + 1 = (z - MinEdge.z) * self.zstride + (y - MinEdge.y) * self.ystride + self.ystride + (x - MinEdge.x) + 1 = i + self.ystride ↓ area:index(x, y+1, z) = area:index(x, y, z) + area.ystride
So if you want to move n meters in x direction:
newindex = index + n
respectively in y direction:
newindex = index + n * area.ystride
and in z direction:
newindex = index + n * area.zstride
n can be negative, of course, but it can't be float, and take care to not leave the area
Examples
-- This sets every air node below y = 31 to cobble when generating map local c_cobble = minetest.get_content_id("default:cobble") local c_air = minetest.get_content_id("air") minetest.register_on_generated(function(minp, maxp) -- Do nothing if the area is above 30 if minp.y > 30 then return end -- Get the vmanip mapgen object and the nodes and VoxelArea local vm, emin, emax = minetest.get_mapgen_object("voxelmanip") local data = vm:get_data() local area = VoxelArea:new{MinEdge=emin, MaxEdge=emax} -- Replace air with cobble for i in area:iter( minp.x, minp.y, minp.z, maxp.x, math.min(maxp.y, 30), maxp.z ) do if data[i] == c_air then data[i] = c_cobble end end -- Return the changed nodes data, fix light and change map vm:set_data(data) vm:set_lighting{day=0, night=0} vm:calc_lighting() vm:write_to_map() end)
-- This sets a sheet of cobble and wood when placing mese local floor_size = 9 local c_cobble = minetest.get_content_id"default:cobble" local c_wood = minetest.get_content_id"default:wood" local sidelen = floor_size * 2 + 1 -- e.g. floor_size = 1 → 3x3 nodes local function set_my_floor(pos) local x,y,z = pos.x,pos.y,pos.z local pos1 = {x = x - floor_size, y = y, z = z - floor_size} local pos2 = {x = x + floor_size, y = y + 1, z = z + floor_size} -- Get the vmanip object and the area and nodes local manip = minetest.get_voxel_manip() local e1, e2 = manip:read_from_map(pos1, pos2) local area = VoxelArea:new{MinEdge=e1, MaxEdge=e2} local data = manip:get_data() -- Set cobble and wood, I chose randomly some line pattern local i = area:index(x - floor_size, y, z - floor_size) for _ = 1, sidelen do for _ = 1, sidelen do local k = i % 5 if k == 1 or k == 4 then data[i] = c_wood else data[i] = c_cobble end i = i + 1 end i = i - sidelen + area.zstride end -- Add a wood node above the middle data[area:index(x, y + 1, z)] = c_wood -- Return the changed nodes, change map and show it to the players manip:set_data(data) manip:write_to_map() manip:update_map() -- update_map is deprecated soon end minetest.override_item("default:mese", { on_place = function(_,_, pt) if not pt then return end set_my_floor(pt.above) end })