core library

The engine core: chunk grid, meshing with light and ambient occlusion, chunk streaming on isolates, voxel physics and rays. Renderer-agnostic. Every other subject of this package is written on it.

Classes

ChunkGenerator
Fills one chunk volume (ChunkSize.volume bytes of block ids) for chunk (cx, cz) of dimension. Runs on a worker isolate: it must be pure in (seed, position) and touch nothing outside itself.
ChunkJobs
Where generation and meshing jobs run. ChunkWorkerPool is the isolate implementation; a test can answer synchronously.
ChunkMesher
Face-culling, greedy mesher with baked ambient occlusion, sky + block light, liquids (lowered surface, own transparent surface), cross plants, torches, and the sub-block solids (slab, fence, stairs) built from axis-aligned boxes lit like cube faces. Works on a volume padded on every horizontal side, filled from the eight neighbour chunks, so a border face and its AO corners never guess.
ChunkMeshResult
Everything a mesh job produces for one chunk: four surfaces, one per way they draw, and the chunk's light volumes.
ChunkMeshSink
What the streamer hands finished meshes to: a renderer, or a test.
ChunkSize
The one chunk geometry: 16 × 16 columns, 128 cells tall. A chunk volume is a byte per cell, indexed x-first within z within y.
ChunkStreamer
Chunk streaming around a centre, without a renderer: the load window, the generation and mesh jobs, edits and their remesh rule, per-dimension edit deltas and the light volumes each mesh job returns. Finished meshes go to sink within a per-frame budget.
ChunkWorkerConfig
Everything a worker isolate needs to build its own generator and mesher.
ChunkWorkerPool
A fixed pool of isolates running chunk generation and meshing. Requests are answered by futures; each goes to the least busy worker.
CollisionBox
An axis-aligned box as min / max corners: a test reads a face without adding a size to a position.
EditDeltaCodec
The binary form of a world's edits: what a generated world needs on top of its seed to be the world the player left. Little-endian throughout:
FenceJoin
The sides of a fence that reach toward a neighbour, as bits of a mask.
IVec3
An integer cell position. Value-equal, so it keys maps and sets.
LiquidFlow
Cellular liquid flow over a VoxelEditor, driven by edits alone so an idle world costs nothing: a generated lake is sources resting on solid and never enters the queue until something next to it changes.
LiquidRule
How one liquid kind flows.
MeshSurface
One vertex-coloured, indexed triangle list, in chunk-local coordinates (x and z 0..16, y 0..128). Every face is a quad of four vertices and six indices. Triangles wind clockwise seen from the side the normal points to, so a renderer whose front faces are counter-clockwise must mirror the handedness at its camera or cull the other side.
PathCosts
What a path may cross and what each cell costs, the game's say in Pathfinder. The engine knows solids, liquids and fences from the block table; which liquid burns and which floor is slow is the game's.
Pathfinder
A* on the block grid for walking creatures. A node is a feet cell (air, air above, something to stand on below, never a fence top); the moves are the four horizontal steps, a step up of one (with head room) and a drop of up to maxDrop onto a landing. The heuristic is the Manhattan distance. At most maxNodes expansions per call; when the goal is not reached the best partial path toward it is returned (the node closest by heuristic, ties on the lower cost). Below y 0 counts as solid.
RayHit
A voxel raycast hit: the cell, the face normal it was entered through, and the distance travelled to that face.
Reach
Reach: the one rule every swing, every use and every bite obeys.
VoxelBlockDef
What the engine needs to know about one block id: how it is drawn, whether it stops a body or light, the light it gives, and whether it is a liquid. Names, drops, tools and every other gameplay fact stay with the game.
VoxelBlockTable
The block ids of one game, indexed by the byte a chunk stores. Id 0 is air. Built once from the game's definitions; the typed arrays are what a mesher on a worker isolate is handed.
VoxelBody
An AABB anchored at the feet, swept against the block volume one axis at a time. Knows nothing of rendering: a game moves its visuals from position.
VoxelEditor
A world the flow can change as well as read.
VoxelModel
A small voxel model: a map from voxel to linear rgb colour, the way creatures, held items and drops are drawn (coloured cubes, no textures). These are the tools that paint one; a renderer turns it into a mesh through VoxelModel.arrays.
VoxelModelArrays
A voxel model's faces as flat arrays, four vertices and six indices a face.
VoxelQuery
What a body or a ray needs to read from a world: the block at a cell and what that block is.
VoxelRaycast
Grid traversal (Amanatides & Woo) through a VoxelQuery.

Enums

BlockShape
How a block is drawn and what it collides with. The declaration order is a contract: the mesher reads a shape as its index from a byte table.

Constants

fenceBarrierHeight → const double
How tall a fence stands to a body with VoxelBody.fenceBarrier: above any jump an animal makes (8 m/s rises 1.23 m), so a pen holds it while the player, who meets the drawn block, jumps onto the rail.
ladderDepth → const double
How far a ladder's rungs stand off its wall, and where its rails run across it.
ladderRail0 → const double
How far a ladder's rungs stand off its wall, and where its rails run across it.
ladderRail1 → const double
How far a ladder's rungs stand off its wall, and where its rails run across it.

Functions

collisionBoxesAt(VoxelQuery q, int x, int y, int z, {bool fenceBarrier = false}) → List<CollisionBox>
The boxes a body collides with at the world cell (x, y, z), in the block's own 0..1 space. Most blocks answer from their shape alone (VoxelBlockTable.collisionBoxes); a fence and a ladder also read their neighbours. fenceBarrier raises a fence to fenceBarrierHeight.
collisionBoxesOf(BlockShape shape, {required bool solid}) → List<CollisionBox>
The boxes a body collides with, in the block's own 0..1 space. Empty for a block that stops no body. Stairs: the bottom slab plus the high step at the back, the same halves the mesher draws (N = high step at z 0..0.5, E = at x 0.5..1). A fence is its lone post here and a ladder nothing: the arms and the ladder's wall depend on the neighbours, which collisionBoxesAt reads. The lists are constants: never mutate one.
eulerYXZ(double x, double y, double z) → Quaternion
The rotation of Euler angles applied Y, then X, then Z (yaw, pitch, roll): the order an animated part is posed in.
eulerYXZInto(Quaternion out, double x, double y, double z) → Quaternion
eulerYXZ written into out, which it returns: the product of the three axis rotations worked out by hand, so posing a part every step allocates nothing.
fenceBoxesOf(int joins, {bool barrier = false}) → List<CollisionBox>
The boxes a fence with joins stops a body with, in the block's own 0..1 space: the post, stretched along each axis to the sides it joins. Every piece is as tall as the post, one block, or fenceBarrierHeight when barrier is set. Shared: never mutate.
fenceJoinsAt(VoxelQuery q, int x, int y, int z) → int
The sides of the fence at (x, y, z) that join a neighbour: a fence or an opaque block beside it. The mesher draws its rails by the same rule, and the outline and the collider read it here, so the three cannot disagree.
ladderBoxAt(VoxelQuery q, int x, int y, int z) → CollisionBox
The box a ladder at (x, y, z) fills, in the block's own 0..1 space: its rails and rungs, lying on the wall it hangs from. The wall is the first opaque neighbour of -x, +x, +z, else -z — the mesher's order. A body in the ladder's cell still stands in it (0.12 deep), so it keeps climbing.
lerpAngle(double from, double to, double t) → double
from moved toward to by t along the shorter way round the circle, in radians.
lerpd(double a, double b, double t) → double
a moved toward b by t.
selectionBoxAt(VoxelQuery q, int x, int y, int z) → CollisionBox
The box an aimed block's outline is drawn around, in world space: the bounds of what the chunk mesher actually draws in the cell, not the cell. A torch gets a thin post, a slab half a cube, a door a panel, a plant the sheet it grows. Shapes that lean on a neighbour (a wall torch, a ladder) or join one (a fence) read the same neighbours, in the same order, as the mesher does, so the box and the mesh cannot disagree.

Typedefs

CellLight = ({int block, int sky})
(sky, block) light of a cell, 0..15 each.
ChunkGeneratorFactory = ChunkGenerator Function()
Builds a ChunkGenerator inside a worker isolate. It is sent to the isolate, so it must capture only sendable values: make it in a static or top-level function, never in an instance method whose this holds scene objects.
ChunkPos = ({int x, int z})
A chunk column position, in chunks.
EditsByDimension = Map<int, Map<ChunkPos, Map<int, int>>>
Every dimension's edit delta: dimension -> chunk -> (cell index -> id).
LiquidContact = int? Function(int kind, bool source, int touching)
What a liquid cell of kind (a source when source) becomes when it touches a liquid of touching kind, or null when the two ignore each other. Lava meeting water hardens this way.

Exceptions / Errors

ChunkJobCancelled
What a ChunkJobs fails a job with when it drops the job on purpose (a disposed pool). The streamer ignores it; any other job error is a bug and ChunkStreamer.update rethrows it.