Context & State
This page clarifies the context objects and state containers that flow through the Grid Building systems.
Why Distinguish Context vs State?
- Context = relatively stable service/registry style objects (DI container, manager singletons, configuration blocks) passed around for lookups.
- State = ephemeral, frame or interaction scoped data (current selection, targeting position, last rule results) that mutates frequently.
Separating them helps keep rule evaluation & indicators pure (depend on inputs, not global singletons) and simplifies testing (inject mock contexts, build explicit state).
Core Context Objects
| Object | Purpose | Notes |
|---|---|---|
| GBCompositionContainer | Dependency Injection root; registers systems & provides lookup. | Construction‑phase only mutations. |
| GBSystemsContext | Aggregates references to active systems (Building, GridTargeting, Manipulation). Emits system change signals. | Signals: building_system_changed, grid_targeting_system_changed, manipulation_system_changed. |
| GBLevelContext | World/scene level references and wiring for runtime. | Exports: target_map, maps, objects_parent. Applies to states: sets GridTargetingState.target_map, GridTargetingState.maps, and BuildingState.placed_parent. Stable across a gameplay session. |
| GBOwnerContext | Owner/Player centric info (player id, permissions, team). | Enables multiplayer separation later. Used by BuildingState, ManipulationState, and GridTargetingState. |
| GBConfig | Root configuration resource; groups settings classes. | Read‑mostly at runtime. |
| GBMessages | Messaging / event bus (if enabled) for decoupled notifications. | Optional injection. |
Major Enhancements in v5.0.0
🏗️ Architectural Improvements
- Unified Dependency Injection: Complete rewrite using GBCompositionContainer and GBInjectorSystem
- Enhanced Context Separation: Better separation between stable contexts and ephemeral state {/* Supports 4.5 as well. Minimum 4.4+. */}
- Improved State Management: More robust lifecycle handling for state containers
🔧 Context Enhancements
- GBCompositionContainer: New dependency injection root with better system registration
- Enhanced GBSystemsContext: Improved aggregation of active systems with better coordination
- Unified GBConfig: All configuration consolidated in single root resource
- Better Context Assembly: More efficient placement context construction and reuse
📊 State Container Improvements
- Enhanced ManipulationState: Better handling of preview states and validation results
- Improved GridTargetingState: More responsive cursor tracking and tile snapping
- Better ModeState: Enhanced mode transitions and state persistence
- Optimized State Lifecycle: Reduced allocations and faster state mutations
🐛 Debugging & Testing
- Context Debugging: Better support for inspecting context objects during development
- State Tracing: Enhanced logging for state changes and mutations {/* Removed internal testing class reference */}
State Containers
| State | Fields (Representative) | Lifecycle |
|---|---|---|
| BuildingState | placed_parent: Node, preview: Node; owner from GBOwnerContext. Signals: success, failed, preview_changed, placed_parent_changed, system_changed. | Build mode session |
| ManipulationState | data: ManipulationData, active_manipulatable: Manipulatable, active_target_node: Node, parent: Node2D. Signals: started, confirmed, finished, canceled, failed, plus change signals. | Active while previewing/manipulating |
| ModeState | current: GBEnums.Mode (OFF/BUILD/DEMOLISH/INSPECT). Signal: mode_changed. | Changes via input/mode toggles |
| GridTargetingState | ready: bool, target: Node2D, positioner: Node2D, target_map: TileMapLayer, maps: Array[TileMapLayer]. Signals: ready_changed, target_changed, positioner_changed, target_map_changed, maps_changed. | Revalidated on movement/changes |
Rule evaluation inputs (what actually gets passed)
For placement rules, the only runtime input passed into rules is the GridTargetingState:
- The validator calls
PlacementRule.setup(p_gts: GridTargetingState)for each rule before evaluation. - Rules read from GridTargetingState (e.g.,
target,target_map,maps) and derive their validation results.
What rules do NOT receive directly:
- BuildingState: used after validation for commit and signal emission; not part of rule inputs.
- ManipulationState, ModeState: not required for rule checks.
- GBLevelContext: used earlier to configure states (sets
target_map,maps,placed_parent). Not passed to rules. - GBSystemsContext: available to systems, not to rules.
Implicit dependencies managed by systems (not passed to rules):
- Logger/messages/templates and indicator services are injected into managers via GBCompositionContainer and used by surrounding systems like IndicatorManager and the validator. Example: IndicatorManager initializes with GridTargetingState, the rule set, messages, logger, and indicator template; rules themselves still only get the GridTargetingState in
setup().
Summary:
- Keep rules pure over GridTargetingState. Configure the state via GBLevelContext and DI once, then let rules evaluate.
- Use BuildingState for post-validation signals and instantiation via
placed_parent. - For rules that need owner context (e.g., inventory spending), read the placer from GridTargetingState:
GridTargetingState.get_owner()orget_owner_root()provide access to the owner entity/root.- Example: SpendMaterialsRuleGeneric pulls its spender via the targeting state and locates the material container from there.
Identity vs Owner vs Engine Owner IDs
- User identity (who is acting):
- Represented conceptually as a
UserId(and optionally aGameSessionId) at the game/backend level. - The host game is responsible for resolving the current user/session and passing that identity into GridBuilding-facing APIs (for example, placement or demolition commands).
- GridBuilding does not reference PlayerSessions directly; it treats user/session identifiers as opaque values supplied by the host.
- Represented conceptually as a
- Owner / owner root (engine entity):
get_owner()/get_owner_root()and relatedOwner/OwnerContextconcepts represent the engine entity (player character, NPC, controller node) that owns or drives a grid-building context.- Use this when rules or systems need access to the scene entity (for parenting, material containers, etc.), not when they just need a user ID.
- Engine-specific owner IDs (Godot APIs):
- Some Godot APIs expose their own “owner IDs” (for example,
CollisionObject2Dshape owner IDs used in collision utilities). - These IDs are engine-internal identifiers, not user or session IDs.
- When you see fields like
shapeOwnerIdorcollisionOwnerIdin GridBuilding’s Godot utilities, treat them strictly as wrappers over Godot’s engine API, not as gameplay identity.
- Some Godot APIs expose their own “owner IDs” (for example,
Summary:
- Use user/session identity (supplied by the host game) for attribution, persistence, and cross-plugin coordination.
- Use owner/owner root when you need the actual engine entity/node that is performing an action within GridBuilding.
- Treat engine owner IDs from Godot as low-level technical details that should never be repurposed as user IDs.
Immutability Guidelines
- Context objects: treat as effectively immutable once gameplay starts. If dynamic reconfiguration is required (e.g. hot‑reloading settings), expose a narrow API that emits change events—avoid direct field mutation relied on by many subsystems.
- State objects: may be mutated, but prefer wrapping mutations in clearly named system methods (
set_rotation_deg(),select_variant()) to centralize side effects (cache invalidation, events).
{/* Testing Strategy moved to internal/testing_strategy.md */}
Cross‑References
Support / Purchase Hub: Linktree – All Grid Builder Links
Glossary
Placement Context
Packaged snapshot object containing the minimal inputs required for placement rule evaluation at a given frame: targeting state, manipulation state, config, systems, level, and owner contexts. Built fresh (or partially reused) whenever cursor position, rotation, variant, or selection changes. Its purpose is to present rules with an immutable view for pure evaluation—rules should not mutate it. See assembly details above.