using System.Collections.Generic; using JetBrains.Annotations; using Robust.Client.Graphics; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Map; namespace Robust.Client.GameObjects { /// /// Updates the layer animation for every visible sprite. /// [UsedImplicitly] public class SpriteSystem : EntitySystem { [Dependency] private readonly IEyeManager _eyeManager = default!; [Dependency] private readonly RenderingTreeSystem _treeSystem = default!; private readonly Queue _inertUpdateQueue = new(); private HashSet _manualUpdate = new(); public override void Initialize() { base.Initialize(); SubscribeLocalEvent(QueueUpdateInert); } private void QueueUpdateInert(SpriteUpdateInertEvent ev) { _inertUpdateQueue.Enqueue(ev.Sprite); } /// public override void FrameUpdate(float frameTime) { while (_inertUpdateQueue.TryDequeue(out var sprite)) { sprite.DoUpdateIsInert(); } foreach (var sprite in _manualUpdate) { if (!sprite.Deleted && !sprite.IsInert) sprite.FrameUpdate(frameTime); } var pvsBounds = _eyeManager.GetWorldViewbounds(); var currentMap = _eyeManager.CurrentMap; if (currentMap == MapId.Nullspace) { return; } foreach (var comp in _treeSystem.GetRenderTrees(currentMap, pvsBounds)) { var bounds = comp.Owner.Transform.InvWorldMatrix.TransformBox(pvsBounds); comp.SpriteTree.QueryAabb(ref frameTime, (ref float state, in SpriteComponent value) => { if (value.IsInert) { return true; } if (!_manualUpdate.Contains(value)) value.FrameUpdate(state); return true; }, bounds, true); } _manualUpdate.Clear(); } /// /// Force update of the sprite component next frame /// public void ForceUpdate(ISpriteComponent sprite) { _manualUpdate.Add(sprite); } } }