From 65d833de1e1e8be4fc29e22c3243d93d6a4f4365 Mon Sep 17 00:00:00 2001 From: Erik Date: Mon, 11 May 2026 14:30:53 +0200 Subject: [PATCH] feat(vfx #C.1.5a): construct EntityScriptActivator in GameWindow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wires the activator into the production lifecycle: - Construct alongside _wbEntitySpawnAdapter using _scriptRunner + _particleSink (both built earlier in OnLoad). - Production resolver lambda hits _dats.Get(...) wrapped in try/catch returning 0 on miss/throw — matches ParticleRenderer's defensive read pattern. - Pass into GpuWorldState's new optional ctor parameter. Closes the wiring half of C.1.5a. Visual verification at the Holtburg Town network portal is the acceptance gate. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/AcDream.App/Rendering/GameWindow.cs | 28 ++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) 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!,