Grid Placement

Composition + injection (5.0.2)

How the 5.0.2 container/injector era wires systems together at initialization time.

5.0.2 projects typically wire GridBuilding through a composition container and an injector pattern.

Initialization vs Runtime

This guide covers initialization-time dependency injection — wiring settings, services, and state when the scene loads.

For runtime placement validation (rules that run when placing objects), see Placement Rules.

The intent (5.0.2)

  • Centralize dependency wiring (settings, state, references) so scene nodes do not hand-wire everything.
  • Allow test environments to stand up “the whole stack” by instantiating a known scene.

Common 5.0.2 wiring pattern

1
2
3
4
5
6
7
Scene root
GBInjectorSystem / composition container
Systems (BuildingSystem, ManipulationSystem, GridTargetingSystem, IndicatorManager)
Shared state objects (mode/targeting/building/manipulation)

Testing implication (5.0.2)

Some features require a full environment scene to exist (not a minimal unit harness).

Example from the 5.0.2-era manipulation architecture notes:

  • Minimal collision test scenes are good for geometry/collision math.
  • But manipulation workflow tests require an “all systems” environment so that:
    • ManipulationSystem exists
    • ManipulationParent exists
    • targeting/building/indicator systems are present

This is one of the reasons the later 6.0 architecture tries to push more logic into testable services and shrink the engine glue surface.

Example: Basic Injector Setup

Here’s a concrete example of setting up the injector system in 5.0.2:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# Main scene script that sets up the composition container
# See: res://addons/grid_building/test/e2e/all_systems_integration_tests.gd
class_name GameLevel
extends Node2D

@onready var injector: GBInjectorSystem = $GBInjectorSystem

func _ready() -> void:
    # 1. Create the container (the root of all configuration)
    # See: res://addons/grid_building/test/resources/composition_containers/test_composition_container.tres
    var container := GBCompositionContainer.new()
    
    # 2. Configure the GBConfig sub-resource
    # This holds your settings, templates, and actions
    # See: res://addons/grid_building/resources/gb_config.gd
    container.config = GBConfig.new()
    container.config.settings.building.add_placeable_instance = true
    
    # 3. Assign the container to the injector
    # The injector will automatically find nodes in the scene tree
    # and call resolve_gb_dependencies(container) on them.
    # See: res://addons/grid_building/systems/injection/gb_injector_system.gd (_ready -> _initialize -> _inject_existing)
    injector.composition_container = container
    
    # 4. (Optional) Manual validation
    # The injector runs validation automatically on ready, but you can 
    # trigger it manually if you update configuration at runtime.
    # See: res://addons/grid_building/systems/injection/gb_injector_system.gd (run_validation method)
    injector.run_validation()

Dependency Resolution

In 5.0.2, nodes implement resolve_gb_dependencies(container: GBCompositionContainer) to receive their dependencies. Note that there is no implements keyword in GDScript; the injector simply checks for the method’s existence.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# Example: A custom node receiving dependencies
# See: res://addons/grid_building/test/building/workflows/building_and_placement_tests.gd
class_name MyCustomBuildingNode
extends Node2D

var _building_settings: BuildingSettings
var _logger: GBLogger

func resolve_gb_dependencies(container: GBCompositionContainer) -> void:
    # Access services and settings through the container
    # See: res://addons/grid_building/resources/gb_composition_container.gd
    _building_settings = container.get_settings().building
    _logger = container.get_logger()
    
    _logger.log_info("Custom node injected successfully!")

Scene Hierarchy

The standard 5.0.2 hierarchy places the injector and core systems near the scene root:

1
2
3
4
5
6
7
8
9
GameLevel (Node2D)
├── GBInjectorSystem        # Dependency injection
├── BuildingSystem          # Placement management
├── GridPositioner2D        # Snapping cursor
│   └── ManipulationParent  # Rotation/Flipping
├── TileMapLayer            # Grid source
├── Camera2D                # Viewport
└── UI
    └── PlaceableSelectionUI

Custom Injection Target

Since 5.0.2 uses method-based injection, you can easily extend the pattern for your own game services:

1
2
3
4
5
6
7
8
# In your custom BuildingSystem or other node
func resolve_gb_dependencies(container: GBCompositionContainer) -> void:
    # Standard dependencies
    _logger = container.get_logger()
    
    # Custom dependencies can be retrieved via meta or global services
    # if they aren't part of the standard GBCompositionContainer
    var economy = get_node("/root/Economy")

Testing with Full Environment

In 5.0.2, integration tests often use a specialized environment node to stand up the stack. See GBTestEnvironment for the implementation details.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Test helper example (similar to AllSystemsTestEnvironment)
# See: res://addons/grid_building/test/e2e/all_systems_integration_tests.gd
func test_placement_integration() -> void:
    # stand up the environment
    # See: res://addons/grid_building/test/scenes/env/gb_test_environment.gd
    var runner := scene_runner("**res://addons/grid_building/test/scenes/env/all_systems_test_environment.tscn**")
    var env := runner.scene() as AllSystemsTestEnvironment
    
    # Access injected systems
    var building_sys = env.building_system
    assert_not_null(building_sys)

Cross Test Validation

  • Injection Logic: res://addons/grid_building/systems/injection/gb_injector_system.gd — Core implementation of the recursive injection pattern:
    • _ready() and _initialize(): Trigger automatic injection when composition_container is assigned
    • inject_recursive(): Performs initial scene tree injection
    • _on_child_entered_tree(): Handles runtime node injection via signal callback
    • _validate_after_injection(): Runs automatic validation after injection completes
  • Integration Tests: res://addons/grid_building/test/e2e/all_systems_integration_tests.gd — Validates that all systems in a standard scene receive their dependencies.
  • Environment Setup: res://addons/grid_building/test/scenes/env/gb_test_environment.gd — Demonstrates the “canonical” way to stand up a wired 5.0.2 environment for testing.
  • Configuration Validation: res://addons/grid_building/test/utilities/gb_configuration_validator_test.gd — Confirms that the injector correctly triggers validation after wiring.