]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Optimise DecalOverlay (#25266)
authormetalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
Fri, 23 Feb 2024 07:12:23 +0000 (18:12 +1100)
committerGitHub <noreply@github.com>
Fri, 23 Feb 2024 07:12:23 +0000 (18:12 +1100)
ChunkSize is still 32 so doesn't cut down on heaps of decals atm though we avoid passing many decals to drawing with the coordinates bounds check now.

Content.Client/Decals/DecalSystem.cs
Content.Client/Decals/Overlays/DecalOverlay.cs
Content.Server/Chunking/ChunkingSystem.cs
Content.Server/Decals/DecalSystem.cs
Content.Server/Parallax/BiomeSystem.cs
Content.Shared/Decals/Decal.cs
Content.Shared/Decals/DecalGridComponent.cs
Content.Shared/Decals/SharedDecalSystem.cs

index be442ab8a0a2eac21571eb6b285097c657249812..901ab270fb590841124a7c08ccb410f4aea88b1e 100644 (file)
@@ -50,16 +50,8 @@ namespace Content.Client.Decals
         protected override void OnDecalRemoved(EntityUid gridId, uint decalId, DecalGridComponent component, Vector2i indices, DecalChunk chunk)
         {
             base.OnDecalRemoved(gridId, decalId, component, indices, chunk);
-
-            if (!component.DecalZIndexIndex.Remove(decalId, out var zIndex))
-                return;
-
-            if (!component.DecalRenderIndex.TryGetValue(zIndex, out var renderIndex))
-                return;
-
-            renderIndex.Remove(decalId);
-            if (renderIndex.Count == 0)
-                component.DecalRenderIndex.Remove(zIndex);
+            DebugTools.Assert(chunk.Decals.ContainsKey(decalId));
+            chunk.Decals.Remove(decalId);
         }
 
         private void OnHandleState(EntityUid gridUid, DecalGridComponent gridComp, ref ComponentHandleState args)
@@ -133,8 +125,6 @@ namespace Content.Client.Decals
         private void UpdateChunks(EntityUid gridId, DecalGridComponent gridComp, Dictionary<Vector2i, DecalChunk> updatedGridChunks)
         {
             var chunkCollection = gridComp.ChunkCollection.ChunkCollection;
-            var renderIndex = gridComp.DecalRenderIndex;
-            var zIndexIndex = gridComp.DecalZIndexIndex;
 
             // Update any existing data / remove decals we didn't receive data for.
             foreach (var (indices, newChunkData) in updatedGridChunks)
@@ -155,11 +145,6 @@ namespace Content.Client.Decals
 
                 foreach (var (uid, decal) in newChunkData.Decals)
                 {
-                    if (zIndexIndex.TryGetValue(uid, out var zIndex))
-                        renderIndex[zIndex].Remove(uid);
-
-                    renderIndex.GetOrNew(decal.ZIndex)[uid] = decal;
-                    zIndexIndex[uid] = decal.ZIndex;
                     gridComp.DecalIndex[uid] = indices;
                 }
             }
index 8eb1a256645e128ed3cde7c1bc95f19d6255ede9..d9904ae80b5e31c6f35a5b7b7ceeb363fd7d332e 100644 (file)
@@ -3,6 +3,7 @@ using Robust.Client.GameObjects;
 using Robust.Client.Graphics;
 using Robust.Shared.Enums;
 using Robust.Shared.Map;
+using Robust.Shared.Map.Enumerators;
 using Robust.Shared.Prototypes;
 
 namespace Content.Client.Decals.Overlays
@@ -15,6 +16,8 @@ namespace Content.Client.Decals.Overlays
 
         private readonly Dictionary<string, (Texture Texture, bool SnapCardinals)> _cachedTextures = new(64);
 
+        private readonly List<(uint Id, Decal Decal)> _decals = new();
+
         public DecalOverlay(
             SpriteSystem sprites,
             IEntityManager entManager,
@@ -30,10 +33,10 @@ namespace Content.Client.Decals.Overlays
             if (args.MapId == MapId.Nullspace)
                 return;
 
-            var grid = Grid;
+            var owner = Grid.Owner;
 
-            if (!_entManager.TryGetComponent(grid, out DecalGridComponent? decalGrid) ||
-                !_entManager.TryGetComponent(grid, out TransformComponent? xform))
+            if (!_entManager.TryGetComponent(owner, out DecalGridComponent? decalGrid) ||
+                !_entManager.TryGetComponent(owner, out TransformComponent? xform))
             {
                 return;
             }
@@ -46,46 +49,68 @@ namespace Content.Client.Decals.Overlays
             var xformSystem = _entManager.System<TransformSystem>();
             var eyeAngle = args.Viewport.Eye?.Rotation ?? Angle.Zero;
 
-            var zIndexDictionary = decalGrid.DecalRenderIndex;
+            var gridAABB = xformSystem.GetInvWorldMatrix(xform).TransformBox(args.WorldBounds.Enlarged(1f));
+            var chunkEnumerator = new ChunkIndicesEnumerator(gridAABB, SharedDecalSystem.ChunkSize);
+            _decals.Clear();
+
+            while (chunkEnumerator.MoveNext(out var index))
+            {
+                if (!decalGrid.ChunkCollection.ChunkCollection.TryGetValue(index.Value, out var chunk))
+                    continue;
+
+                foreach (var (id, decal) in chunk.Decals)
+                {
+                    if (!gridAABB.Contains(decal.Coordinates))
+                        continue;
+
+                    _decals.Add((id, decal));
+                }
+            }
 
-            if (zIndexDictionary.Count == 0)
+            if (_decals.Count == 0)
                 return;
 
-            var (_, worldRot, worldMatrix) = xformSystem.GetWorldPositionRotationMatrix(xform);
+            _decals.Sort((x, y) =>
+            {
+                var zComp = x.Decal.ZIndex.CompareTo(y.Decal.ZIndex);
 
+                if (zComp != 0)
+                    return zComp;
+
+                return x.Id.CompareTo(y.Id);
+            });
+
+            var (_, worldRot, worldMatrix) = xformSystem.GetWorldPositionRotationMatrix(xform);
             handle.SetTransform(worldMatrix);
 
-            foreach (var decals in zIndexDictionary.Values)
+            foreach (var (_, decal) in _decals)
             {
-                foreach (var decal in decals.Values)
+                if (!_cachedTextures.TryGetValue(decal.Id, out var cache))
                 {
-                    if (!_cachedTextures.TryGetValue(decal.Id, out var cache))
+                    // Nothing to cache someone messed up
+                    if (!_prototypeManager.TryIndex<DecalPrototype>(decal.Id, out var decalProto))
                     {
-                        // Nothing to cache someone messed up
-                        if (!_prototypeManager.TryIndex<DecalPrototype>(decal.Id, out var decalProto))
-                        {
-                            continue;
-                        }
-
-                        cache = (_sprites.Frame0(decalProto.Sprite), decalProto.SnapCardinals);
-                        _cachedTextures[decal.Id] = cache;
+                        continue;
                     }
 
-                    var cardinal = Angle.Zero;
-
-                    if (cache.SnapCardinals)
-                    {
-                        var worldAngle = eyeAngle + worldRot;
-                        cardinal = worldAngle.GetCardinalDir().ToAngle();
-                    }
+                    cache = (_sprites.Frame0(decalProto.Sprite), decalProto.SnapCardinals);
+                    _cachedTextures[decal.Id] = cache;
+                }
 
-                    var angle = decal.Angle - cardinal;
+                var cardinal = Angle.Zero;
 
-                    if (angle.Equals(Angle.Zero))
-                        handle.DrawTexture(cache.Texture, decal.Coordinates, decal.Color);
-                    else
-                        handle.DrawTexture(cache.Texture, decal.Coordinates, angle, decal.Color);
+                if (cache.SnapCardinals)
+                {
+                    var worldAngle = eyeAngle + worldRot;
+                    cardinal = worldAngle.GetCardinalDir().ToAngle();
                 }
+
+                var angle = decal.Angle - cardinal;
+
+                if (angle.Equals(Angle.Zero))
+                    handle.DrawTexture(cache.Texture, decal.Coordinates, decal.Color);
+                else
+                    handle.DrawTexture(cache.Texture, decal.Coordinates, angle, decal.Color);
             }
 
             handle.SetTransform(Matrix3.Identity);
index e4775439cb614481d4a4e6c7a2c26b7774133075..9bc1ab0a3b969533e52abd8709561b291265906a 100644 (file)
@@ -8,6 +8,7 @@ using Robust.Shared.Map;
 using Robust.Shared.Map.Components;
 using Robust.Shared.Player;
 using Robust.Shared.Utility;
+using ChunkIndicesEnumerator = Robust.Shared.Map.Enumerators.ChunkIndicesEnumerator;
 
 namespace Content.Shared.Chunking;
 
index 5bfd91486caee074d557fd71c17989b3837a6b40..ad225afe2247d8f303989e509ac0169d1d8dae97 100644 (file)
@@ -21,6 +21,7 @@ using Robust.Shared.Threading;
 using Robust.Shared.Timing;
 using Robust.Shared.Utility;
 using static Content.Shared.Decals.DecalGridComponent;
+using ChunkIndicesEnumerator = Robust.Shared.Map.Enumerators.ChunkIndicesEnumerator;
 
 namespace Content.Server.Decals
 {
index 0b8c7a4d82d9bf708ee9d153934b801648b3c4d0..c4c2300870d71678d635fe720b3f3ed12bcf0879 100644 (file)
@@ -29,6 +29,7 @@ using Robust.Shared.Prototypes;
 using Robust.Shared.Random;
 using Robust.Shared.Threading;
 using Robust.Shared.Utility;
+using ChunkIndicesEnumerator = Robust.Shared.Map.Enumerators.ChunkIndicesEnumerator;
 
 namespace Content.Server.Parallax;
 
index 56ecc829e7c677ab11768e4bd50a715f9ed9a786..cb6f944c650e400678b90b4f93683edc2f83872b 100644 (file)
@@ -8,7 +8,7 @@ namespace Content.Shared.Decals
     public sealed partial class Decal
     {
         // if these are made not-readonly, then decal grid state handling needs to be updated to clone decals.
-        [DataField("coordinates")] public  Vector2 Coordinates = Vector2.Zero;
+        [DataField("coordinates")] public Vector2 Coordinates = Vector2.Zero;
         [DataField("id")] public  string Id = string.Empty;
         [DataField("color")] public  Color? Color;
         [DataField("angle")] public  Angle Angle = Angle.Zero;
index 140eb5bafcd5af7d2311b34786cf0c393da18fb0..8ac05cb280fa387871e9c1a3788d9556a61f798e 100644 (file)
@@ -12,7 +12,8 @@ namespace Content.Shared.Decals
     [NetworkedComponent]
     public sealed partial class DecalGridComponent : Component
     {
-        [DataField("chunkCollection", serverOnly: true)]
+        [Access(Other = AccessPermissions.ReadExecute)]
+        [DataField(serverOnly: true)]
         public DecalGridChunkCollection ChunkCollection = new(new ());
 
         /// <summary>
@@ -25,10 +26,6 @@ namespace Content.Shared.Decals
         /// </summary>
         public GameTick ForceTick { get; set; }
 
-        // client-side data. I CBF creating a separate client-side comp for this. The server can survive with some empty dictionaries.
-        public readonly Dictionary<uint, int> DecalZIndexIndex = new();
-        public readonly SortedDictionary<int, SortedDictionary<uint, Decal>> DecalRenderIndex = new();
-
         [DataDefinition]
         [Serializable, NetSerializable]
         public sealed partial class DecalChunk
index 02f73bdacb38520c797f0371d2dc9adf70f1975d..76fa9d64dba6daec17f798f46019a0b4ad5c7cc4 100644 (file)
@@ -122,39 +122,6 @@ namespace Content.Shared.Decals
         }
     }
 
-    // TODO: Pretty sure paul was moving this somewhere but just so people know
-    public struct ChunkIndicesEnumerator
-    {
-        private Vector2i _chunkLB;
-        private Vector2i _chunkRT;
-
-        private int _xIndex;
-        private int _yIndex;
-
-        public ChunkIndicesEnumerator(Box2 localAABB, int chunkSize)
-        {
-            _chunkLB = new Vector2i((int)Math.Floor(localAABB.Left / chunkSize), (int)Math.Floor(localAABB.Bottom / chunkSize));
-            _chunkRT = new Vector2i((int)Math.Floor(localAABB.Right / chunkSize), (int)Math.Floor(localAABB.Top / chunkSize));
-
-            _xIndex = _chunkLB.X;
-            _yIndex = _chunkLB.Y;
-        }
-
-        public bool MoveNext([NotNullWhen(true)] out Vector2i? indices)
-        {
-            if (_yIndex > _chunkRT.Y)
-            {
-                _yIndex = _chunkLB.Y;
-                _xIndex += 1;
-            }
-
-            indices = new Vector2i(_xIndex, _yIndex);
-            _yIndex += 1;
-
-            return _xIndex <= _chunkRT.X;
-        }
-    }
-
     /// <summary>
     ///     Sent by clients to request that a decal is placed on the server.
     /// </summary>