Skip to content

Instantly share code, notes, and snippets.

@GreenXenith
Last active January 3, 2022 08:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save GreenXenith/3a269c5511fee3afd4fbe23517a1c94c to your computer and use it in GitHub Desktop.
Save GreenXenith/3a269c5511fee3afd4fbe23517a1c94c to your computer and use it in GitHub Desktop.
voxelarea documentation problems

VoxelArea

The VoxelArea metatable1 provides an OOP-like2 utility3 for dealing with LuaVoxelManip4 (specifically, for doing the index math5).


1 Beginners are not likely to know what a metatable even is. The information is superfluous anyway.

2 Beginners may not know what "OOP" means.

3 "Utility" is a bit technical, "helper" may be easier to understand.

4 "LuaVoxelManip" should probably be "the VoxelManip object" or similar.

5 "index math" is vague and unhelpful.

VoxelArea.new(self, o)1

Sets self.__index to self and self as the metatable of o2, which can have3 the following fields:

  • MinEdge: Minimum position of the area, inclusive. Defaults to vector.new(1, 1, 1) if nil4.

  • MaxEdge: Maximum position of the area, inclusive. Defaults to vector.new(0, 0, 0) if nil4.

Both positions should be vector`s of integer numbers; each component of `MinEdge should be smaller than the respective component of MaxEdge if the VoxelArea is to be non-empty. You can use minp, maxp = vector.sort(minp, maxp) to achieve this.

Calculates ystride and zstride5 and stores both in o%6.

Common usage:7

local voxelmanip = minetest.get_voxel_manip(pos_min, pos_max)
local emin, emax = voxelmanip:read_from_map(pos_min, pos_max)
local voxelarea = VoxelArea:new{ MinEdge = emin, MaxEdge = emax }
Warning
Always pass the actual emerged8 min9 &10 max9 positions. Do not pass the desired min &10 max positions11.
Warning
Never pass fractional values as min-12 or max edge.
Tip
You can use vector.floor, vector.round or vector.apply(vec, math.ceil) to guarantee integer values.

The following methods can both be called in an imperative manner13 (VoxelArea.<method>(self, …​)) or an OOP manner (recommended): self:<method>(…​). The below examples are documented using the latter style, where area is a valid table with VoxelArea as the metatable.14


1 Documenting the internal representation of VoxelArea() is confusing and unnecesary, especially for beginners.

2 We are documenting VoxelArea, not classes. It returns a new VoxelArea object, it’s as simple as that.

3 It will always have these fields.

4 Possibly superfluous.

5 What are ystride and zstride?

6 Again, referencing "o" is confusing and unnecessary.

7 Common syntax for those variables is usually vmanip and varea. Do we need to decide a policy on example variable naming? Also, literal-syntax should probably be avoided; It is only used because someone thought it was cute and no one bothered to change it.

8 Why would a beginner know what "emerged" means, especially without any context about VManip?

9 Use full "minimum" and "maximum".

10 Use "and".

11 This is confusing.

12 Inconsistent trailing dash.

13 Again, beginners may not know what imperative or OOP is. The only version we need to document is the supported syntax, which is OOP. Advanced users can extrapolate imperative usage if they wish.

14 If it’s recommended, just don’t bother with the imperative notes at all.

area:getExtent()

Returns the dimensions of area as integer vector1.


1 "Integer vector" is strange wording. Not sure how to improve. Also missing "an".

area:getVolume()

Returns the volume of area as integer1.


1 Missing "an".

area:index(x, y, z)

x, y, z are absolute coordinates of a node within the area. Returns an integer index to be used for data tables returned by VoxelManip objects.

Warning
This will silently floor the returned index instead of throwing an error. Make sure that the coordinates you pass are (1) not fractional and (2) within the area.

area:indexp(p)

Shorthand for area:index(p.x, p.y, p.z).

area:position(index)

Inverse to area:indexp. Returns the absolute node position corresponding to the index as a table with x, y and z fields.

Tip
The returned table is missing the vector metatable. If it is not performance-critical, use p = vector.new(area:position(index)) to create a copied vector with metatable.

area:contains(x, y, z)

Returns true if all x, y, z coordinates are between the respective MinEdge and MaxEdge coordinates, both inclusive.

area:containsp(p)

Shorthand for area:contains(p.x, p.y, p.z)

area:containsi(i)

Returns true if i is between 1 and the area volume, both inclusive.

Warning
area:containsi(area:indexp(p)) is not equivalent to area:containsp(p), as area:indexp will happily produce valid indices for some out-of-area positions.

area:iter(minx, miny, minz, maxx, maxy, maxz)

Returns an iterator (a function that returns the index of the current position and advances to the next one) that iterates in XYZ order (first incrementing X until the line has been finished, then Y until the plane has been finished, then Z until the cuboid has been finished).

area:iterp(minp, maxp)

Shorthand for area:iter(minp.x, minp.y, minp.z, maxp.x, maxp.y, maxp.z).

Example:1

for index in area:iterp(pos_min, pos_max) do
	content_id_data[index] = ...
end

which is equivalent to (but shorter &2 faster than):

for z = pos_min.z, pos_max.z do
	for y = pos_min.y, pos_max.y do
		for x = pos_min.x, pos_max.x do
			local index = area:index(x, y, z)
			content_id_data[index] = ...
		end
	end
end

1 Do examples need to be runable? …​ is not likely valid out of context.

2 Use "and".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment