Skip to content

GlobalGridManager

DESKTOP-5KM6RA3\david edited this page Apr 7, 2026 · 3 revisions

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:

  1. Is the global grid system active?
  2. Which grids are currently registered?
  3. Given a world-space position or global voxel identity, which runtime objects does that resolve to?

What It Owns

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.

Lifecycle

Setup(...)

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(...)

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.

Registration Flow

TryAddGrid(...) is the manager's most important write path.

At a high level it does this:

  1. validate manager activity and capacity
  2. validate incoming configuration
  3. derive an exact BoundsKey
  4. reject duplicate bounds if already registered
  5. rent a pooled VoxelGrid
  6. initialize that grid
  7. register it into every overlapping spatial hash cell
  8. discover and link neighboring grids that truly overlap
  9. increment manager version and publish an add event

That means registration is doing both identity work and topology work.

Why There Are Two Hashing Concepts

It is easy to confuse these two:

BoundsTracker

  • exact identity map
  • prevents duplicate grids with the same snapped bounds
  • used for correctness

SpatialGridHash

  • coarse spatial lookup map
  • maps coarse world regions to candidate grid ids
  • used for speed

They solve different problems and the architecture needs both.

Lookup Responsibilities

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:

  1. coarse candidate filtering through the spatial hash
  2. exact in-bounds confirmation against candidate grids

Spatial Hashing Model

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.

Neighbor Linking

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.

Events And Versioning

The manager's change model has two layers:

Events

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

Versions

Use versions when something needs to observe change passively:

  • Version on 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.

Setup Values That Affect The Whole System

Two configuration values at setup time shape almost everything downstream:

VoxelSize

Affects:

  • snapped bounds
  • voxel world positions
  • grid dimensions
  • tracer resolution
  • world-to-voxel conversion

SpatialGridCellSize

Affects:

  • coarse candidate grid lookup
  • registration into the spatial hash
  • overlap discovery scan scope

Changing either one changes how the whole runtime behaves.

What Belongs Here Vs Elsewhere

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.

Common Architectural Pitfalls

  • Forgetting Setup() before registration or lookup
  • Assuming grid state is instance-local instead of globally coordinated
  • Treating SpatialGridCellSize as 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

Read This Next

Clone this wiki locally