namespace OECS; /// /// Manages a group of systems, running them in registration order /// against a specific . /// public class SystemGroup { private readonly World _world; private readonly List _systems = new(); /// /// Creates a system group bound to the given world. /// public SystemGroup(World world) { _world = world ?? throw new ArgumentNullException(nameof(world)); } /// /// The number of systems in this group. /// public int Count => _systems.Count; /// /// Adds a system to the group. Systems execute in the order they are added. /// public void Add(ISystem system) { _systems.Add(system); } /// /// Removes a system from the group. /// public void Remove(ISystem system) { _systems.Remove(system); } /// /// Runs all systems with a timed tick. /// Systems that implement receive the tick data; /// plain implementations receive only the world. /// public void RunTimed(float deltaTime) { RunAll(Tick.Timed(deltaTime)); } /// /// Runs all systems with a logical tick. /// public void RunLogical() { RunAll(Tick.Logical()); } private void RunAll(Tick tick) { // Drain commands enqueued before the tick so the first system // sees their effects. _world.ExecuteCommands(); _world.BeginBatching(); foreach (var system in _systems) { if (system is ITickedSystem ticked) { ticked.Run(_world, tick); } else { system.Run(_world); } // Drain commands after each system so subsequent systems // see the effects of commands enqueued by prior systems. _world.ExecuteCommands(); // Flush pending mutations so subsequent systems see // entity/component changes from commands and previous systems. _world.FlushPendingMutations(); // Post changes after each system so subscribers see // incremental updates. _world.PostChanges(); } _world.EndBatching(); // Drain any remaining commands (e.g., those enqueued outside systems). _world.ExecuteCommands(); // Post any remaining changes (e.g., from command execution). _world.PostChanges(); } }