Quick Start

Get GridPlacement 6.0 up and running with the correct C# API and architecture.

sort Weight: 5

1. Project Configuration

Ensure your project structure includes the Core DLL and the Godot Adapter layer.

1
2
3
4
5
6
your_project/
├── /
│   ├── .csproj
│   └── bin/
│       └── .Core.dll  # The Pure Logic Core
│   └── .Godot.dll     # The Godot Adapter Layer

2. Scene Setup

2.1 Composition Root

Add a GPUserScopeRoot node to your main scene. This node handles service registration and input routing.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// In your main scene or autoload
public partial class MainScene : Node
{
    [Export] public GPUserScopeRoot UserScopeRoot { get; set; }
    
    public override void _Ready()
    {
        // The GPUserScopeRoot automatically configures services
        // Access the registry for dependency injection
        var registry = UserScopeRoot.Registry;
    }
}

2.2 Input Configuration

Create a CoreInputActionSettingsResource and assign it to the GPUserScopeRoot.

1
2
3
4
5
6
7
// Configure input actions
var inputSettings = new CoreInputActionSettingsResource();
inputSettings.PlaceAction = "ui_accept";
inputSettings.CancelAction = "ui_cancel";
inputSettings.RotateAction = "ui_rotate";

UserScopeRoot.ActionSettings = inputSettings;

2.3 Service Registration

The GPUserScopeRoot automatically registers core services:

  • IPlacementService - Placement business logic
  • ITargetingService - Grid targeting and validation
  • IIndicatorService - Visual feedback and previews
  • IEventBus - Domain event publishing

3. Basic Gameplay Integration (C#)

3.1 Placement Workflow

Use the PlacementWorkflow for placement operations:

 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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
using GridPlacement.Core.Workflows;
using GridPlacement.Core.Types;
using GridPlacement.Core.Sessions;

public partial class PlayerController : Node
{
    private ServiceRegistry _registry;
    private PlacementWorkflow _placementWorkflow;
    private TargetingWorkflow _targetingWorkflow;

    public override void _Ready()
    {
        // Get the service registry from the composition root
        var userScopeRoot = GetNode<GPUserScopeRoot>("/root/GPUserScopeRoot");
        _registry = userScopeRoot.Registry;
        
        // Resolve workflows from the registry
        _placementWorkflow = _registry.GetService<PlacementWorkflow>();
        _targetingWorkflow = _registry.GetService<TargetingWorkflow>();
    }

    public void StartPlacement(string placeableId)
    {
        // Create a placeable (normally loaded from configuration)
        var placeable = new Placeable
        {
            Id = placeableId,
            Name = "Building Block",
            Description = "A basic building block",
            Position = new CoreVector2I(0, 0)
        };

        // Start the placement session
        var result = _placementWorkflow.StartSession(placeableId, placeable);
        
        // Handle the orchestrator output (visual effects, UI updates, etc.)
        ProcessOrchestratorOutput(result);
    }

    public void UpdatePlacement(Vector2 mousePosition)
    {
        if (!_placementWorkflow.Session.IsActive)
            return;

        // Convert mouse position to grid coordinates
        var gridPos = ConvertToGridCoordinates(mousePosition);
        var targetingSnapshot = new TargetingSnapshot2D
        {
            GridPosition = gridPos,
            IsValid = true
        };

        // Update the placement workflow
        var result = _placementWorkflow.Update(targetingSnapshot);
        ProcessOrchestratorOutput(result);
    }

    public void RotatePlacement()
    {
        if (_placementWorkflow.Session.IsActive)
        {
            var result = _placementWorkflow.Rotate();
            ProcessOrchestratorOutput(result);
        }
    }

    public void ConfirmPlacement()
    {
        if (_placementWorkflow.Session.IsActive)
        {
            var result = _placementWorkflow.Confirm();
            ProcessOrchestratorOutput(result);
        }
    }

    private void ProcessOrchestratorOutput(OrchestratorOutput output)
    {
        // Apply visual effects, update UI, handle events
        // This is where you would:
        // - Update preview meshes
        // - Show/hide placement indicators
        // - Play sounds or animations
        // - Update UI state
    }
}

3.2 Input Handling

Connect to the input service for reactive input handling:

 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
30
31
32
33
34
35
36
37
38
39
40
41
42
using GridPlacement.Core.Systems.Input;

public partial class InputController : Node
{
    private CoreInputService _inputService;
    private PlayerController _playerController;

    public override void _Ready()
    {
        var userScopeRoot = GetNode<GPUserScopeRoot>("/root/GPUserScopeRoot");
        var registry = userScopeRoot.Registry;
        _inputService = registry.GetService<CoreInputService>();
        _playerController = GetNode<PlayerController>("../PlayerController");

        // Subscribe to input events
        _inputService.PlaceActionTriggered += OnPlaceAction;
        _inputService.CancelActionTriggered += OnCancelAction;
        _inputService.RotateActionTriggered += OnRotateAction;
    }

    private void OnPlaceAction()
    {
        if (_playerController.IsPlacementActive)
        {
            _playerController.ConfirmPlacement();
        }
        else
        {
            _playerController.StartPlacement("basic_building");
        }
    }

    private void OnCancelAction()
    {
        _playerController.CancelPlacement();
    }

    private void OnRotateAction()
    {
        _playerController.RotatePlacement();
    }
}

4. Reactive UI (GDScript)

Connect to the adapter events for live UI updates:

 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
30
31
32
33
34
35
36
extends Control

# Reference to the placement adapter
var placement_adapter: PlacementAdapter

func _ready():
    # Get the placement adapter from the service registry
    var user_scope_root = get_node("/root/GPUserScopeRoot")
    var registry = user_scope_root.get_registry()
    placement_adapter = registry.get_service("PlacementAdapter")
    
    # Connect to adapter events for live updates
    placement_adapter.output_ready.connect(_on_placement_updated)

func _on_placement_updated(output: OrchestratorOutput):
    # Update UI based on placement state
    var session = placement_adapter.orchestrator.session
    
    if session.is_active:
        $PlacementPanel.show()
        $CoordinateLabel.text = "Position: " + str(session.last_snapshot.grid_position)
        $ValidityLabel.text = "Valid: " + str(session.last_snapshot.is_valid)
    else:
        $PlacementPanel.hide()

func _on_build_button_pressed():
    # Start placement with a specific placeable
    placement_adapter.start_session("basic_building", load("res://resources/basic_building.tres"))

func _on_rotate_button_pressed():
    # Rotate the current placement
    placement_adapter.rotate()

func _on_cancel_button_pressed():
    # Cancel the current placement
    placement_adapter.cancel_session()

5. Configuration and Data

5.1 Placeable Configuration

Create placeable resources for your game objects:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// Example: Create a placeable from a configuration
public Placeable CreatePlaceableFromConfig(string configPath)
{
    var config = ResourceLoader.Load<PlaceableConfig>(configPath);
    
    return new Placeable
    {
        Id = config.Id,
        Name = config.Name,
        Description = config.Description,
        Size = config.Size,
        Properties = config.Properties
    };
}

5.2 Grid Configuration

Configure grid properties for your game:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
using GridPlacement.Core.State.Grid;

public void ConfigureGrid()
{
    var gridState = _registry.GetService<IGridState>();
    
    // Set grid dimensions
    gridState.SetGridSize(new CoreVector2I(50, 50));
    
    // Configure cell size (in world units)
    gridState.SetCellSize(new CoreVector2(1.0f, 1.0f));
    
    // Set grid origin
    gridState.SetOrigin(new CoreVector2(0, 0));
}

6. Common Patterns

6.1 Session Management

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
public class PlacementManager : Node
{
    private PlacementWorkflow _workflow;
    
    public bool IsPlacementActive => _workflow.Session.IsActive;
    public Placeable CurrentPlaceable => _workflow.Session.Placeable;
    public CoreVector2I CurrentPosition => _workflow.Session.LastSnapshot.GridPosition;
    
    public void CancelPlacement()
    {
        if (IsPlacementActive)
        {
            _workflow.Cancel();
        }
    }
}

6.2 Event-Driven Updates

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
public class UIController : Node
{
    public override void _Ready()
    {
        var eventBus = _registry.GetService<IEventBus>();
        eventBus.Subscribe<PlaceableSelectedEvent>(OnPlaceableSelected);
        eventBus.Subscribe<PlacementCompletedEvent>(OnPlacementCompleted);
    }
    
    private void OnPlaceableSelected(PlaceableSelectedEvent evt)
    {
        UpdateUIForPlacement(evt.Placeable);
    }
    
    private void OnPlacementCompleted(PlacementCompletedEvent evt)
    {
        ShowPlacementSuccess(evt.Position);
    }
}

Next Steps

Troubleshooting

Q: Services not found in registry

  • Ensure GPUserScopeRoot is properly initialized before accessing services
  • Check that the Core DLL is loaded and Godot adapter is properly configured

Q: Placement workflow not responding

  • Verify that a placement session is active before calling Update() or Confirm()
  • Check that the targeting snapshot contains valid grid coordinates

Q: UI not updating

  • Connect to adapter events instead of polling for state changes
  • Use the OrchestratorOutput to drive visual updates and UI state changes