Skip to content

Bridge API

Namespace GodotECS.Bridge. Components for talking to Godot, plus the main-thread bridge nodes that drain them at sync points. See Godot bridge for the usage model.

Components

AudioEvent

csharp
public struct AudioEvent : IBufferElementData
{
    public int BankId;
    public Godot.Vector3 Pos;
    public float Volume;
}

One positional sound request. Lives in a buffer on the emitting entity; drained by AudioBridge.Flush(). BankId selects a stream registered via RegisterBank, Pos is the world-space emission point, Volume is linear gain (0–1).

NetworkId

csharp
public struct NetworkId : IComponentData
{
    public int Id;
}

Network identity for replication / remote spawning. Plain tag-along id; no system in the bridge reads it — your netcode does.

csharp
public struct NavPath : IBufferElementData
{
    public Godot.Vector3 Point;
}

One waypoint of a resolved path. The buffer is cleared and rewritten by NavBridge.ProcessBudget on success.

csharp
public struct NavRequest : IComponentData
{
    public Godot.Vector3 Target;
    public int RequestId;
    public bool Pending;
}

Path request. Set Pending = true to enqueue; NavBridge sets it to false once the NavPath buffer holds the result. Failed queries (query returns false) leave it Pending for a later frame.

BridgeClock

csharp
public struct BridgeClock : ISingleton
{
    public uint Tick;
}

World-tick mirror for Godot-side readers. Singleton; Tick mirrors World.Tick.

Audio

IAudioSink

csharp
public interface IAudioSink
{
    void Play(int bankId, Godot.Vector3 pos, float volume);
    int Played { get; }
}

Mockable playback target. The engine implementation drives real players; tests inject a counting mock. Played is the total number of Play calls received.

NullAudioSink

csharp
public sealed class NullAudioSink : IAudioSink
{
    public int Played { get; private set; }
    public void Play(int bankId, Godot.Vector3 pos, float volume);
}

Counts plays, plays nothing. Play ignores its arguments except incrementing Played. Default test double for AudioBridge.Sink.

AudioBridge

csharp
public partial class AudioBridge : Godot.Node
{
    public const int MaxVoices = 32;
    public IAudioSink Sink { get; set; }
    public int PendingCount { get; }
    public void RegisterBank(int bankId, Godot.AudioStream stream);
    public void PushBank(int bankId, Godot.Vector3 pos, float volume);
    public static List<AudioEvent> ClusterCap(List<AudioEvent> src, int cap);
    public int Flush();
    public override void _Ready();
    public override void _Process(double delta);
}
  • MaxVoices — voice pool size and per-flush cap.
  • Sink — when null, Flush only drives the real player pool; set a mock in tests.
  • PendingCount — queued events not yet flushed.
  • RegisterBank — maps a bank id to a stream (overwrites existing).
  • PushBank — appends one AudioEvent to the pending queue.
  • ClusterCap — returns a copy of src sorted by descending Volume, truncated to cap. Does not modify src.
  • Flush() — plays at most MaxVoices pending events (loudest first), clears the queue, returns the number played. Each event goes to Sink?.Play(...) and to a round-robin AudioStreamPlayer3D from the pool — but only if its bank is registered and non-null. Volume is clamped to [0.0001, 1] and converted with LinearToDb. Returns 0 when the queue is empty.
  • _Ready() — creates the 32 AudioStreamPlayer3D children (Voice0…Voice31).
  • _Process(double delta) — flushes automatically when the queue is non-empty.

Signals

EcsSignals

csharp
public partial class EcsSignals : Godot.Node
{
    [Godot.Signal]
    public delegate void EntityDiedEventHandler(int index, int version);
    [Godot.Signal]
    public delegate void HitPlayerEventHandler(int damage);

    public readonly List<Entity> EmittedDeaths;
    public readonly List<int> EmittedHits;
    public int PendingDeaths { get; }
    public int PendingHits { get; }
    public void EnqueueDeath(Entity e);
    public void EnqueueHit(int damage);
    public int EmitPending();
    public override void _Process(double delta);
}
  • Signals: EntityDied(index, version) per dead entity, HitPlayer(damage) per hit.
  • EnqueueDeath — queues unless e.IsNull. EnqueueHit — always queues.
  • EmitPending() — drains deaths first, then hits; appends to EmittedDeaths / EmittedHits, emits the Godot signals, returns the total emitted.
  • _Process(double delta) — calls EmitPending() when either queue is non-empty.

INavQuery

csharp
public interface INavQuery
{
    bool TryGetPath(Godot.Vector3 from, Godot.Vector3 to, List<Godot.Vector3> outPoints);
}

Mockable path query. Fills outPoints; returns false when no path exists (the request stays Pending).

StraightLineQuery

csharp
public sealed class StraightLineQuery : INavQuery
{
    public bool TryGetPath(Godot.Vector3 from, Godot.Vector3 to, List<Godot.Vector3> outPoints);
}

Server-free default: appends from then to, always returns true.

csharp
public partial class NavBridge : Godot.Node
{
    public const int PathsPerFrame = 64;
    public INavQuery Query { get; set; }
    public int Budget { get; set; }
    public static int ProcessBudget(World world, INavQuery query, int budget);
    public override void _PhysicsProcess(double delta);
}
  • PathsPerFrame — default per-frame budget (64).
  • Budget — current budget, initialized to PathsPerFrame; set to 0/negative to pause resolution (ProcessBudget returns 0).
  • ProcessBudget(World world, INavQuery query, int budget) — resolves up to budget Pending NavRequests: start is LocalTransform.Pos (or Vector3.Zero), on success the NavPath buffer is cleared and refilled and Pending set to false. Returns the resolved count. Returns 0 for null world/query, non-positive budget, or empty world. Entities whose query call returns false are skipped without consuming budget.
  • _PhysicsProcess(double delta)ProcessBudget(World.Default, Query ?? StraightLineQuery, Budget).

GDScript facade

GdScriptApi

csharp
public partial class GdScriptApi : Godot.Node
{
    public int GetEntityCount();
    public uint GetTick();
    public int SpawnScene(EntityScene scene, Godot.Vector3 pos);
    public bool KillEntity(int index, int version);
    public Godot.Vector3 GetEntityPos(int index, int version);
}

All methods operate on World.Default:

  • GetEntityCount()Entities.LiveCount.
  • GetTick()World.Tick.
  • SpawnScene(EntityScene scene, Vector3 pos) — appends the scene at pos; returns the root entity's Index, or -1 for a null/empty scene.
  • KillEntity(int index, int version) — destroys the entity; false if not alive.
  • GetEntityPos(int index, int version)LocalTransform.Pos, or Vector3.Zero when dead or lacking the component.

GodotECS docs — version 0.1.0. All rights reserved until a license is added.