From 08097b6c7ebb70a7a549187ed90fe97775b11d6f Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 10 Apr 2026 20:31:50 +0200 Subject: [PATCH] feat(app): wire IGameState+IEvents into Program and SmokePlugin Pass WorldGameState and WorldEvents into GameWindow so OnLoad fires FireEntitySpawned and Add for each hydrated entity. SmokePlugin now subscribes to EntitySpawned in Enable(), unsubscribes in Disable(), and logs the replay count at subscribe time and total seen at disable. Co-Authored-By: Claude Sonnet 4.6 --- src/AcDream.App/Program.cs | 2 +- src/AcDream.App/Rendering/GameWindow.cs | 23 ++++++++++++++++++++--- src/AcDream.Plugins.Smoke/SmokePlugin.cs | 21 +++++++++++++++++++-- 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/src/AcDream.App/Program.cs b/src/AcDream.App/Program.cs index da0f748..e989b6e 100644 --- a/src/AcDream.App/Program.cs +++ b/src/AcDream.App/Program.cs @@ -50,7 +50,7 @@ try catch (Exception ex) { Log.Error(ex, "plugin enable failed: {Id}", plugin.Manifest.Id); } } - using var window = new GameWindow(datDir); + using var window = new GameWindow(datDir, worldGameState, worldEvents); window.Run(); } finally diff --git a/src/AcDream.App/Rendering/GameWindow.cs b/src/AcDream.App/Rendering/GameWindow.cs index 126eccb..868c42e 100644 --- a/src/AcDream.App/Rendering/GameWindow.cs +++ b/src/AcDream.App/Rendering/GameWindow.cs @@ -1,3 +1,4 @@ +using AcDream.Core.Plugins; using DatReaderWriter; using DatReaderWriter.Options; using Silk.NET.Input; @@ -10,6 +11,8 @@ namespace AcDream.App.Rendering; public sealed class GameWindow : IDisposable { private readonly string _datDir; + private readonly WorldGameState _worldGameState; + private readonly WorldEvents _worldEvents; private IWindow? _window; private GL? _gl; private IInputContext? _input; @@ -25,7 +28,12 @@ public sealed class GameWindow : IDisposable private TextureCache? _textureCache; private IReadOnlyList _entities = Array.Empty(); - public GameWindow(string datDir) => _datDir = datDir; + public GameWindow(string datDir, WorldGameState worldGameState, WorldEvents worldEvents) + { + _datDir = datDir; + _worldGameState = worldGameState; + _worldEvents = worldEvents; + } public void Run() { @@ -209,14 +217,23 @@ public sealed class GameWindow : IDisposable (lbY - centerY) * 192f, 0f); - hydratedEntities.Add(new AcDream.Core.World.WorldEntity + var hydrated = new AcDream.Core.World.WorldEntity { Id = e.Id, SourceGfxObjOrSetupId = e.SourceGfxObjOrSetupId, Position = e.Position + worldOffset, Rotation = e.Rotation, MeshRefs = meshRefs, - }); + }; + hydratedEntities.Add(hydrated); + + var snapshot = new AcDream.Plugin.Abstractions.WorldEntitySnapshot( + Id: hydrated.Id, + SourceId: hydrated.SourceGfxObjOrSetupId, + Position: hydrated.Position, + Rotation: hydrated.Rotation); + _worldGameState.Add(snapshot); + _worldEvents.FireEntitySpawned(snapshot); } } diff --git a/src/AcDream.Plugins.Smoke/SmokePlugin.cs b/src/AcDream.Plugins.Smoke/SmokePlugin.cs index 310b1a3..d824825 100644 --- a/src/AcDream.Plugins.Smoke/SmokePlugin.cs +++ b/src/AcDream.Plugins.Smoke/SmokePlugin.cs @@ -5,6 +5,7 @@ namespace AcDream.Plugins.Smoke; public sealed class SmokePlugin : IAcDreamPlugin { private IPluginHost? _host; + private int _entitiesSeen; public void Initialize(IPluginHost host) { @@ -12,6 +13,22 @@ public sealed class SmokePlugin : IAcDreamPlugin _host.Log.Info("smoke plugin initialized"); } - public void Enable() => _host?.Log.Info("smoke plugin enabled"); - public void Disable() => _host?.Log.Info("smoke plugin disabled"); + public void Enable() + { + _host?.Log.Info("smoke plugin enabled"); + if (_host is not null) + { + _host.Events.EntitySpawned += OnEntitySpawned; + _host.Log.Info($"smoke plugin sees {_entitiesSeen} entities (replay count at subscribe)"); + } + } + + public void Disable() + { + if (_host is not null) + _host.Events.EntitySpawned -= OnEntitySpawned; + _host?.Log.Info($"smoke plugin disabled (saw {_entitiesSeen} entities total)"); + } + + private void OnEntitySpawned(WorldEntitySnapshot snapshot) => _entitiesSeen++; }