Mode Events and Hooks

This guide documents the events and hooks available for connecting your game’s UI to GridPlacement mode changes.

Event Architecture

GridPlacement uses a dual-event pattern:

  • Core events — C# EventHandler<T> events on IModeService
  • Godot signalsPlacementSignalBus for Godot-native UI wiring

Both are fired simultaneously so you can use either pattern.

Mode Events (IModeService)

ModeChanged Event

Fired when the primary grid mode changes.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
modeService.ModeChanged += (sender, args) =>
{
    switch (args.NewMode)
    {
        case GridMode.Place:   ShowPlacePalette(); break;
        case GridMode.Move:   ShowMoveCursor(); break;
        case GridMode.Remove: ShowDemolishCursor(); break;
        case GridMode.Edit:   // Edit mode entered - waiting for entity selection
        case GridMode.Inspect: ShowInspectPanel(); break;
    }
};

EntitySelectedForEdit Event

Fired when an editable entity is selected in Edit mode.

1
2
3
4
5
modeService.EntitySelectedForEdit += (sender, args) =>
{
    // Load entity data and show edit UI
    ShowEditPanel(args.EntityId, args.EntityType);
};

Event Properties:

PropertyTypeDescription
EntityIdEntityIdECS entity ID of selected object
EntityTypestringType name for loading appropriate edit UI

Godot Signal Bus

The PlacementSignalBus provides Godot-native signals:

1
2
3
4
5
6
7
8
// In PlacementBootstrap
public PlacementSignalBus PlacementSignals { get; } = new();

// Signals available:
// PlacementSignals.PlaceConfirmed
// PlacementSignals.PlacementInvalid
// PlacementSignals.ManipulationStarted
// etc.

Wiring in GDScript

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
func _ready():
    bootstrap.PlacementSignals.ModeChanged.connect(_on_mode_changed)
    bootstrap.PlacementSignals.EntitySelectedForEdit.connect(_on_entity_selected_for_edit)

func _on_mode_changed(mode: GridMode):
    match mode:
        MODE_PLACE: show_palette()
        MODE_MOVE: show_move_cursor()
        MODE_EDIT: show_edit_hint()

func _on_entity_selected_for_edit(entity_id: int, entity_type: String):
    show_edit_panel(entity_id, entity_type)

Edit Mode Workflow

Edit mode follows a two-event pattern:

  1. ModeChanged → Game shows “select entity to edit” hint
  2. EntitySelectedForEdit → Game shows edit panel with entity properties
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
private void OnModeChanged(object? sender, ModeChangedEvent args)
{
    if (args.NewMode == GridMode.Edit)
    {
        _ui.ShowEditModeHint("Click an editable building to edit its properties");
    }
}

private void OnEntitySelectedForEdit(object? sender, EntitySelectedForEditEvent args)
{
    // Load entity data from ECS
    var entity = _store.GetEntityById(args.EntityId);

    // Show edit panel
    _ui.ShowEditPanel(args.EntityType, entity);
}

Complete Signal List

SignalEvent ClassWhen Fired
ModeChangedModeChangedEventAny mode transition
EntitySelectedForEditEntitySelectedForEditEventEditable entity selected in Edit mode
PlacementConfirmedPlacementConfirmedEventPlacement committed
PlacementInvalidPlacementInvalidEventPlacement rejected by rules

Example: Full UI Wiring

 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
public class PlacementUiController : Node
{
    [Export] private PlacementBootstrap _bootstrap = null!;
    [Export] private Control _editPanel = null!;
    [Export] private Control _palettePanel = null!;

    public override void _Ready()
    {
        var modeService = _bootstrap.Coordinator?.ModeService;
        modeService.ModeChanged += OnModeChanged;
        modeService.EntitySelectedForEdit += OnEntitySelectedForEdit;
    }

    private void OnModeChanged(object? sender, ModeChangedEvent args)
    {
        _palettePanel.Visible = args.NewMode == GridMode.Place;
        _editPanel.Visible = false;

        if (args.NewMode == GridMode.Edit)
        {
            _ui.ShowMessage("Select a building to edit");
        }
    }

    private void OnEntitySelectedForEdit(object? sender, EntitySelectedForEditEvent args)
    {
        _editPanel.Visible = true;
        _ui.LoadEntityForEditing(args.EntityId, args.EntityType);
    }
}