diff --git a/src/AcDream.App/Rendering/GameWindow.cs b/src/AcDream.App/Rendering/GameWindow.cs
index b81d484..14463e8 100644
--- a/src/AcDream.App/Rendering/GameWindow.cs
+++ b/src/AcDream.App/Rendering/GameWindow.cs
@@ -33,6 +33,7 @@ public sealed class GameWindow : IDisposable
/// after OnLoad completes (modern path is mandatory as of N.5).
private AcDream.App.Rendering.Wb.WbMeshAdapter? _wbMeshAdapter;
private AcDream.App.Rendering.Wb.EntitySpawnAdapter? _wbEntitySpawnAdapter;
+ private AcDream.App.Rendering.Vfx.EntityScriptActivator? _entityScriptActivator;
private AcDream.App.Rendering.Wb.WbDrawDispatcher? _wbDrawDispatcher;
/// Phase N.5: ARB_bindless_texture + ARB_shader_draw_parameters
/// support. Required at startup — missing bindless throws
@@ -1612,6 +1613,30 @@ public sealed class GameWindow : IDisposable
var wbEntitySpawnAdapter = new AcDream.App.Rendering.Wb.EntitySpawnAdapter(
_textureCache!, SequencerFactory, _wbMeshAdapter!);
_wbEntitySpawnAdapter = wbEntitySpawnAdapter;
+
+ // Phase C.1.5a: construct EntityScriptActivator so server-spawned static
+ // entities (portals first) fire Setup.DefaultScript through the
+ // PhysicsScriptRunner on enter-world. _scriptRunner and _particleSink
+ // are initialised earlier in OnLoad (line ~1083); both are non-null
+ // here. The resolver lambda captures _dats and swallows dat-lookup
+ // throws — see C.1.5a spec §6 (error handling) for rationale.
+ var capturedDatsForActivator = _dats;
+ uint ResolveDefaultScript(AcDream.Core.World.WorldEntity e)
+ {
+ try
+ {
+ var setup = capturedDatsForActivator?.Get(e.SourceGfxObjOrSetupId);
+ return setup?.DefaultScript.DataId ?? 0u;
+ }
+ catch
+ {
+ return 0u;
+ }
+ }
+ var entityScriptActivator = new AcDream.App.Rendering.Vfx.EntityScriptActivator(
+ _scriptRunner!, _particleSink!, ResolveDefaultScript);
+ _entityScriptActivator = entityScriptActivator;
+
// Phase Post-A.5 #53 (Task 12): wire EntityClassificationCache.InvalidateLandblock
// so Tier 1 cache entries get swept on LB demote (Near to Far) and unload.
// Per spec §5.3 W3b. The callback receives the canonical landblock id
@@ -1619,7 +1644,8 @@ public sealed class GameWindow : IDisposable
_worldState = new AcDream.App.Streaming.GpuWorldState(
wbSpawnAdapter,
wbEntitySpawnAdapter,
- onLandblockUnloaded: _classificationCache.InvalidateLandblock);
+ onLandblockUnloaded: _classificationCache.InvalidateLandblock,
+ entityScriptActivator: entityScriptActivator);
_wbDrawDispatcher = new AcDream.App.Rendering.Wb.WbDrawDispatcher(
_gl, _meshShader!, _textureCache!, _wbMeshAdapter!, _wbEntitySpawnAdapter, _bindlessSupport!,