Core/Godot DLL Integration Guide

This guide covers the new 6.0.0 architecture where GridPlacement’s core logic is separated into an engine-agnostic C# DLL with a dedicated Godot integration layer.

Naming Note โ€“ GridBuilding โ†’ GridPlacement 6.0
In 5.x, the Godot plugin shipped as GridBuilding. For the C#โ€‘based 6.0 line, GridPlacement (GP) is canonical across the board (plugin name, docs, assemblies, and C# namespaces). When this guide talks about the “core DLL” and “Godot integration layer”, it is describing the GridPlacement 6.0 C# plugin.

Runtime chains

When debugging, prefer tracing the runtime chain before diving into implementation details:

๐Ÿ—๏ธ Architecture Overview

Two-Layer Architecture

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚           Godot Layer               โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
โ”‚  โ”‚  Godot Systems & UI Nodes       โ”‚ โ”‚ โ† Call services + listen to events
โ”‚  โ”‚  Adapter Nodes (optional)       โ”‚ โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                    โ†“
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚            Core DLL                 โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
โ”‚  โ”‚   Services & Domain Events      โ”‚ โ”‚ โ† Engine-agnostic logic
โ”‚  โ”‚   BuildingState & other state   โ”‚ โ”‚
โ”‚  โ”‚   Validation & Error Handling   โ”‚ โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Core DLL (GridPlacement.Core.dll)

  • Engine Agnostic: No Godot dependencies
  • Business Logic: Building placement, validation, state management
  • Event System: C# events for all building operations
  • Thread Safe: ReaderWriterLockSlim for concurrent access
  • Testable: Can be unit tested independently

Godot Integration Layer

  • Adapter / system nodes: Thin Godot nodes that resolve Core services via DI and forward domain events to Godot signals or local state.
  • Godot Systems: Engine-specific implementations that call into services.
  • UI Integration: GDScript-friendly wrappers around service APIs and events.
  • Resource Management: Godot-specific asset handling.

First-class wiring (GameComposition + GameUserSessions)

GridPlacement 6.0 is designed so identity and lifetime are explicit integration concerns.

The shipped Godot addon stays self-contained: GPUserScopeRoot provides a minimal default session model and input routing without requiring GameComposition/GameUserSessions.

If your host game uses GameComposition/GameUserSessions, implement identity/session wiring in an integration layer and validate it with the GridPlacement.Integrations.* test projects.

๐Ÿš€ Quick Start

1. Project Setup

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# Your project structure
your_project/
โ”œโ”€โ”€ addons/
โ”‚   โ””โ”€โ”€ grid_building/
โ”‚       โ”œโ”€โ”€ plugin.cfg
โ”‚       โ”œโ”€โ”€ GridBuilding.csproj
โ”‚       โ”œโ”€โ”€ Systems/
โ”‚       โ”‚   โ””โ”€โ”€ [Godot systems]
โ”‚       โ””โ”€โ”€ addons/
โ”‚           โ””โ”€โ”€ grid_building/
โ”‚               โ””โ”€โ”€ bin/
โ”‚                   โ””โ”€โ”€ GridPlacement.Core.dll  โ† Compiled Core DLL

2. Basic Usage

 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
// In your Godot C# script (6.0 service-based integration)
using Godot;
using GridPlacement.Godot.Bootstrap;
using GridPlacement.Godot.Bootstrap.Modules;

public partial class PlacementController : Node
{
    private GridPlacementGodotWorkflowModule.PlacementWorkflowBridge? _workflow;

    public override void _Ready()
    {
        // Recommended for real games: resolve services via a game-owned composition route.
        // GPUserScopeRoot is a convenience wrapper when you choose to include it in your scene.
        var scopeRoot = GetNodeOrNull<GPUserScopeRoot>("../GPUserScopeRoot");
        if (scopeRoot is null)
        {
            GD.PrintErr("Composition root not found; cannot resolve GridPlacement workflows.");
            return;
        }

        _workflow = scopeRoot.Registry.GetService<GridPlacementGodotWorkflowModule.PlacementWorkflowBridge>();

        // Optional: subscribe to workflow events
        _workflow.PlacementValidated += report => GD.Print($"Validated: {report}");
        _workflow.PlacementExecuted += report => GD.Print($"Executed: {report}");
    }

    public void SelectPlaceable(Placeable placeable)
    {
        _workflow?.SelectPlaceable(placeable);
    }
}

3. GDScript Integration

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# In your GDScript (via a thin C# adapter node)
extends Node

@onready var building_system = $BuildingSystemNode

func _ready():
    # Connect to signals raised by your C# system node
    building_system.building_placed.connect(_on_building_placed)
    building_system.building_removed.connect(_on_building_removed)

func _on_building_placed(building_type, position, instance_id):
    print("Building placed: ", building_type, " at ", position)

func place_tower():
    # Adapter node forwards to the underlying IBuildingService
    building_system.place_building("tower", Vector2i(5, 5))

๐Ÿ”„ Event System Integration

C# Events โ†’ Godot Signals

The Godot integration layer converts Core C# domain events to Godot signals via thin adapter/system nodes. In a typical setup, a dedicated C# node subscribes to Core events and emits Godot signals that your UI or GDScript code can listen to.

C# Event (Core DLL)Godot Signal (adapter node)Parameters
BuildingPlacedEventbuilding_placedbuilding_type: String, position: Vector2i, instance_id: String
BuildingRemovedEventbuilding_removedbuilding_type: String, position: Vector2i, instance_id: String
BuildingDamagedEventbuilding_damagedinstance_id: String, damage: float, current_health: float
BuildingDestroyedEventbuilding_destroyedinstance_id: String
BuildingRepairedEventbuilding_repairedinstance_id: String, repair_amount: float, new_health: float
BuildingHealthChangedEventbuilding_health_changedinstance_id: String, previous_health: float, current_health: float

Event Flow Example

User Action โ†’ Godot gameplay code calls a placement method (C# or GDScript)
         โ†“
Core DLL IBuildingService.PlaceBuilding() handles the request
         โ†“
Core DLL publishes BuildingPlacedEvent
         โ†“
Adapter/system node receives the domain event
         โ†“
Adapter/system node emits a building_placed Godot signal
         โ†“
Godot signal system notifies connected GDScript/C# handlers

๐Ÿ› ๏ธ Core DLL API Reference

BuildingService

Place Building

1
public BuildingState PlaceBuilding(string buildingType, Vector2I gridPosition, string ownerId = "")

Validation Rules:

  • Position coordinates must be non-negative
  • Position must not be occupied
  • Building type must be valid
  • Special rules (towers: Y โ‰ฅ 5, walls: even coordinates)

Returns: BuildingState with generated InstanceId

Remove Building

1
public bool RemoveBuilding(string buildingId)

Returns: true if building was found and removed

Apply Damage

1
public bool ApplyDamage(string buildingId, float damageAmount)

Effects:

  • Reduces building health
  • Changes status to Damaged if health < max
  • Triggers BuildingDamagedEvent
  • Triggers BuildingDestroyedEvent if health โ‰ค 0

Repair Building

1
public bool RepairBuilding(string buildingId, float repairAmount)

Effects:

  • Increases building health (up to max)
  • Changes status from Damaged to Operational
  • Triggers BuildingRepairedEvent

BuildingState Properties

PropertyTypeDescription
BuildingTypestringType of building (basic, tower, wall, etc.)
GridPositionVector2IPosition on the grid
InstanceIdstringUnique identifier (GUID)
OwnerIdstringOwner of the building
StatusBuildingStatusCurrent state (Placed, Damaged, Destroyed, etc.)
HealthfloatCurrent health points
MaxHealthfloatMaximum health points

BuildingStatus Enum

1
2
3
4
5
6
7
8
9
public enum BuildingStatus
{
    Placed,
    UnderConstruction,
    Operational,
    Damaged,
    Destroyed,
    Repairing
}

๐Ÿงช Testing Integration

Unit Testing Core DLL

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
[Test]
public void BuildingService_CanPlaceAndRemoveBuilding()
{
    var service = new BuildingService();
    var building = service.PlaceBuilding("basic", new Vector2I(5, 10));
    
    Assert.NotNull(building);
    Assert.Equal("basic", building.BuildingType);
    Assert.Equal(1, service.GetAllBuildings().Count());
    
    var removed = service.RemoveBuilding(building.InstanceId);
    Assert.True(removed);
    Assert.Equal(0, service.GetAllBuildings().Count());
}

Integration Testing with Godot

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// Pseudo-code: adapter node converts Core events to Godot signals
// (replace `BuildingEventsAdapter` with your own adapter implementation)
var adapter = new BuildingEventsAdapter(service);
var signalReceived = false;

// Adapter exposes a Godot-style signal/event
adapter.BuildingPlaced += () => signalReceived = true;

// Trigger Core DLL event
var building = service.PlaceBuilding("tower", new Vector2I(3, 7));

Assert.True(signalReceived);

Integration testing (reuse-first, no engine)

When validating wiring for session support, identity propagation, or adapter readiness, prefer extending the existing Core integration tests before adding new engine tests:

  • plugins/gameplay/GridPlacement/cs/Core/Tests/Core/GridBuilding.Core.Tests/PlacementWorkflowOrchestratorIntegrationTests.cs

This keeps the tests deterministic and avoids depending on Godot runtime behavior.

๐Ÿ”ง Advanced Configuration

Custom Validation Rules

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// Extend BuildingService validation
public class CustomBuildingService : BuildingService
{
    protected override List<string> ValidateBuildingPlacement(Vector2I position, string buildingType)
    {
        var errors = base.ValidateBuildingPlacement(position, buildingType);
        
        // Add custom rules
        if (buildingType == "special" && position.X < 10)
        {
            errors.Add("Special buildings must be placed at X โ‰ฅ 10");
        }
        
        return errors;
    }
}

Custom Event Handlers

1
2
3
4
5
// In your adapter/system node
protected void OnBuildingPlaced(object? sender, BuildingPlacedEvent e)
{
    // Forward to Godot-facing signals, UI hooks, etc.
}

Thread Safety Considerations

The Core DLL uses ReaderWriterLockSlim for thread safety:

1
2
3
4
5
// Thread-safe operations are automatic
Parallel.ForEach(positions, pos => {
    var building = service.PlaceBuilding("basic", pos);
    // No additional synchronization needed
});

๐Ÿšจ Error Handling

Exception Types

ExceptionWhen ThrownHow to Handle
BuildingPlacementExceptionValidation failsShow error message to user
ArgumentExceptionInvalid parametersValidate user input
InvalidOperationExceptionDuplicate placementCheck position first

Error Handling Pattern

1
2
3
4
5
6
7
8
9
// Example: your adapter node delegates to a core service and reports errors.
try
{
    _buildingService.PlaceBuilding(buildingType, position);
}
catch (Exception ex)
{
    GD.PrintErr(ex);
}

๐Ÿ“Š Performance Considerations

Memory Management

  • Core DLL uses efficient Dictionary-based lookup
  • Event subscriptions are automatically cleaned up
  • Building states are lightweight structs

Thread Performance

  • Read operations use read locks (concurrent access)
  • Write operations use write locks (exclusive access)
  • Event publishing creates handler copies to avoid deadlocks

Optimization Tips

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// Good: Batch operations
var buildings = new List<BuildingState>();
foreach (var pos in positions)
{
    buildings.Add(service.PlaceBuilding("basic", pos));
}

// Avoid: Excessive individual calls
// foreach (var pos in positions)
// {
//     service.PlaceBuilding("basic", pos); // Creates many events
// }

๐Ÿ” Debugging

Core DLL Debugging

1
2
3
4
5
6
// Enable console logging
Console.WriteLine($"[BuildingService] Placed {buildingType} at {position}");

// Check event subscriptions
var subscriberCount = EventDispatcher.Instance.GetSubscriberCount<BuildingPlacedEvent>();
GD.Print($"BuildingPlacedEvent subscribers: {subscriberCount}");

Godot Integration Debugging

1
2
3
4
5
// Check signal connections
if (!IsConnected("building_placed", Callable.From<string, Vector2I, string>(OnBuildingPlaced)))
{
    GD.PrintErr("building_placed signal not connected!");
}

โœ… Integration Checklist

Setup

  • Core DLL copied to addons/grid_building/bin/
  • Godot project references Core DLL
  • Adapter/system nodes that subscribe to Core services are added to the scene tree
  • Plugin configuration updated

Testing

  • Core DLL builds successfully
  • Building placement works
  • Events convert to signals
  • Error handling works
  • Thread safety verified

Performance

  • No memory leaks in event system
  • Acceptable placement performance
  • UI remains responsive during operations

Documentation

  • API documentation updated
  • Integration examples provided
  • Troubleshooting guide created

๐ŸŽ‰ Success!

Your GridBuilding plugin is now using the new Core/Godot DLL architecture! You have:

  • โœ… Engine-agnostic core logic that can be tested independently
  • โœ… Robust event system with automatic signal conversion
  • โœ… Thread-safe operations for concurrent access
  • โœ… Comprehensive error handling with detailed validation
  • โœ… Better performance with optimized C# implementation

Next Steps

  1. Explore the Core DLL - Try unit testing your building logic
  2. Custom validation - Add game-specific building rules
  3. Performance optimization - Profile and optimize for your use case
  4. Contribute back - Share improvements with the community

Need help? Check the troubleshooting section or create an issue on GitHub.