-
-
Notifications
You must be signed in to change notification settings - Fork 0
Determinism Snapping and Pooling
This page covers the three invariants that shape most of GridForge's implementation choices:
- deterministic math and ordering
- snapped spatial boundaries
- aggressive object and collection reuse
GridForge is built around fixed-point math and explicit ordering.
In practice that means:
- core spatial math uses
Fixed64,Vector2d, andVector3d - grid creation and tracing logic work from snapped fixed-point bounds
- behavior must stay stable across both
netstandard2.1andnet8.0
Vector2d APIs use the same fixed-point math as the 3D APIs. They project XZ
coordinates onto a chosen layerY and then flow through the same world, grid,
voxel, tracer, scan, obstacle, and blocker systems.
GridConfiguration orders incoming bounds on construction, and GridWorld
snaps them during registration.
That snapped result affects:
- grid dimensions
- duplicate grid detection
- world-space containment tests
- tracer coverage
- blocker coverage
- local voxel index resolution
GridConfiguration.TopologyMetrics establishes deterministic cell geometry for
the grid being registered.
That means:
- grid configuration snapping depends on the normalized topology metrics
- voxel index math for that grid depends on those metrics
- changing cell geometry is a grid-configuration choice, not a hidden world-wide scalar
When tests or tools need different cell geometry, create the grid with explicit topology metrics and keep expectations local to that grid.
Pooling makes storage slots reusable, so GridIndex and OccupantTicket.Slot
are never sufficient identities by themselves. An active world receives a
process-unique token, each grid registration receives a nonrepeating generation
local to that world, and each occupant registration receives a process-unique
generation. WorldVoxelIndex and OccupantTicket carry those values so stale
references fail instead of aliasing replacement state.
These generations are transient validation metadata. They are not serialized,
durable across processes, or authoritative ordering inputs. Persist host-owned
content identity such as IVoxelOccupant.GlobalId, then resolve fresh runtime
handles when rebuilding a world.
Pooling in GridForge is not an optimization sprinkled on top. It shapes the object lifecycle.
The internal pools cover types such as:
VoxelGridVoxelScanCell- scan-cell maps
- neighbor arrays
- temporary query lists and hash sets
Every new mutable field introduced into a pooled type needs a matching reset story.
- Was the grid created with the topology metrics you think it was?
- What are the snapped bounds after normalization?
- Is the queried world-space position exactly on a boundary?
- Are you looking at a pooled object or temporary collection after its intended lifetime?
- Did a previous test, tool run, or benchmark leave world state active longer than intended?