-
-
Notifications
You must be signed in to change notification settings - Fork 0
GlobalGridManager
GlobalGridManager is the root coordinator of GridForge. If you strip the library down to its top-level control point, this is it.
Its job is to answer three big questions:
- Is the global grid system active?
- Which grids are currently registered?
- Given a world-space position or global voxel identity, which runtime objects does that resolve to?
| Member | Purpose |
|---|---|
VoxelSize |
Global voxel size used for snapping and per-grid dimension math |
SpatialGridCellSize |
Coarse spatial hash cell size used for grid lookup |
ActiveGrids |
Bucket of currently allocated grids indexed by global grid id |
BoundsTracker |
Exact-bounds duplicate protection |
SpatialGridHash |
Spatial hash from coarse cell key to registered grid indices |
Version |
Global system version for significant changes |
OnActiveGridAdded / Removed / Change / OnReset
|
Top-level change notifications |
The important architectural point is that GlobalGridManager owns grid discovery and lifetime, not per-grid storage details.
Setup() activates the global manager and initializes its shared structures.
Architecturally, this means:
- global voxel size is fixed for the active session
- the spatial hash cell size is fixed for the active session
- all later grid registration and snapping behavior depends on those values
Reset() clears active grids, clears spatial hash state, and raises the reset event. With deactivate: true, it also marks the manager inactive again.
This is why tests and tools should treat Reset() as the authoritative cleanup boundary.
TryAddGrid(...) is the manager's most important write path.
At a high level it does this:
- validate manager activity and capacity
- validate incoming configuration
- derive an exact
BoundsKey - reject duplicate bounds if already registered
- rent a pooled
VoxelGrid - initialize that grid
- register it into every overlapping spatial hash cell
- discover and link neighboring grids that truly overlap
- increment manager version and publish an add event
That means registration is doing both identity work and topology work.
It is easy to confuse these two:
- exact identity map
- prevents duplicate grids with the same snapped bounds
- used for correctness
- coarse spatial lookup map
- maps coarse world regions to candidate grid ids
- used for speed
They solve different problems and the architecture needs both.
GlobalGridManager exposes the top-level lookup surface for the whole library.
| Lookup | Purpose |
|---|---|
TryGetGrid(int index, ...) |
Resolve a grid by global id |
TryGetGrid(Vector3d position, ...) |
Resolve the grid containing a world position |
TryGetGrid(GlobalVoxelIndex, ...) |
Resolve a grid by persisted cross-system voxel identity |
TryGetGridAndVoxel(...) |
Resolve both grid and voxel in one call |
TryGetVoxel(...) |
Resolve only the voxel when the grid instance is not needed |
The important detail is that world-space resolution is always a two-step process:
- coarse candidate filtering through the spatial hash
- exact in-bounds confirmation against candidate grids
The spatial hash exists to avoid scanning every grid for every query.
The manager:
- snaps a world position into a coarse spatial hash key
- looks up candidate grid ids for that key
- checks which candidate grid actually contains the position
The hash cell size is intentionally coarser than voxel size. It is about locating candidate grids, not individual cells inside those grids.
The manager also owns grid-to-grid relationship discovery.
During registration it:
- checks other grids already present in the same spatial hash cells
- verifies actual overlap with
VoxelGrid.IsGridOverlapValid(...) - links valid neighbors in both directions
During removal it:
- unlinks the removed grid from the spatial hash
- removes valid neighbor relationships from affected grids
This is why GlobalGridManager is also the entry point for dynamic load/unload behavior, not just for lookup.
The manager's change model has two layers:
Use manager events when something needs to react right away to:
- a grid being added
- a grid being removed
- a grid meaningfully changing
- a global reset occurring
Use versions when something needs to observe change passively:
-
Versionon the manager for significant global changes - per-grid version increments for grid-local mutations
The manager only increments its own version for certain changes. Not every voxel-level mutation is a global version event.
Two configuration values at setup time shape almost everything downstream:
Affects:
- snapped bounds
- voxel world positions
- grid dimensions
- tracer resolution
- world-to-voxel conversion
Affects:
- coarse candidate grid lookup
- registration into the spatial hash
- overlap discovery scan scope
Changing either one changes how the whole runtime behaves.
Use GlobalGridManager when the question is:
- which grid owns this space?
- is the world active?
- how do I register or remove a grid?
- how do I reset the shared state?
Do not use it when the question is primarily:
- how do I mutate obstacle state on a voxel?
- how do I register occupants?
- how do I scan for nearby occupants?
- how do I trace coverage over a region?
Those belong to the dedicated managers and utilities built on top of the manager's registry and lookup surface.
- Forgetting
Setup()before registration or lookup - Assuming grid state is instance-local instead of globally coordinated
- Treating
SpatialGridCellSizeas if it were scan-cell size - Forgetting that duplicate grid detection is based on snapped bounds
- Holding stale grid ids or voxel identities across resets without revalidation
- Architecture Overview for the full system map
- VoxelGrid and Voxel Model for what happens after a grid is resolved
- GridTracer and Coverage for how world-space regions find candidate grids and cells