Godot bridge
The bridge is the controlled boundary between ECS simulation and Godot. ECS systems produce data or requests; bridge nodes consume them at main-thread sync points.
Sync-point rule
Never access Godot objects from ECS jobs or hot per-entity loops. Audio, navigation, signals and other engine-facing operations happen through the bridge on the main thread.
Per-frame budgets are explicit: AudioBridge.MaxVoices is 32 and its pending queue is capped at MaxPending = 1024; NavBridge.PathsPerFrame defaults to 64. Overflow is deliberately bounded rather than allowing unbounded backlog.
Signals
EcsSignals batches EntityDied(index, version) and HitPlayer(damage).
signals.EnqueueDeath(deadEntity);
signals.EnqueueHit(25);
int emitted = signals.EmitPending();The two internal queues are thread-safe and each is capped at MaxPendingPerQueue = 4096. If a queue is full, the oldest entry is dropped. Entity.Null deaths are ignored. EmitPending() drains deaths before hits; _Process() drains automatically.
Audio
audio.RegisterBank(0, stream);
audio.PushBank(0, muzzlePos, 0.8f);
int played = audio.Flush();MaxVoices = 32 limits each flush. The pending queue is capped at 1024. When the queue is full, a new event replaces the quietest pending event only if it is louder; otherwise the new event is dropped. This preserves strong events during bursts.
Flush() reuses its scratch list and skips sorting when there are at most 32 pending events. Above 32 it keeps the loudest 32. If Sink is non-null, it is the only playback destination; otherwise the real AudioStreamPlayer3D pool is used. This makes injected test sinks exclusive rather than double-playing with real players.
Navigation
NavBridge resolves pending NavRequest components into NavPath buffers, up to Budget requests per physics frame. Failed queries leave requests pending without consuming budget.
The bridge caches an EntityQuery per World in a ConditionalWeakTable. It therefore scans only chunks containing NavRequest, rather than copying and testing every live entity each physics frame. The cache is weakly keyed so it does not retain disposed worlds.
int done = NavBridge.ProcessBudget(World.Default, query, 64);The default StraightLineQuery requires no navigation server. Production integrations can inject an INavQuery implementation.
GDScript facade
GdScriptApi exposes World.Default to GDScript. SpawnScene returns a Vector2I(Index, Version) key; KillEntity(index, version) defers destruction through an ECB and flushes automatically. Always keep the index/version pair together to avoid ABA errors after index reuse.
var key = ecs.SpawnScene(enemy_scene, Vector3(10, 0, 5))
var pos = ecs.GetEntityPos(key.x, key.y)
ecs.KillEntity(key.x, key.y)GetPhysicsHz() and GetLodBias() expose the core QualityConfig singleton. GetEntityPos returns Vector3.ZERO for a dead/stale entity or one without LocalTransform.
Full API
See Bridge API for exact signatures.