diff --git a/Content.Client/Decals/DecalSystem.cs b/Content.Client/Decals/DecalSystem.cs index be442ab8a0..901ab270fb 100644 --- a/Content.Client/Decals/DecalSystem.cs +++ b/Content.Client/Decals/DecalSystem.cs @@ -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 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; } } diff --git a/Content.Client/Decals/Overlays/DecalOverlay.cs b/Content.Client/Decals/Overlays/DecalOverlay.cs index 8eb1a25664..d9904ae80b 100644 --- a/Content.Client/Decals/Overlays/DecalOverlay.cs +++ b/Content.Client/Decals/Overlays/DecalOverlay.cs @@ -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 _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(); 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(); - if (zIndexDictionary.Count == 0) + 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 (_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(decal.Id, out var decalProto)) { - // Nothing to cache someone messed up - if (!_prototypeManager.TryIndex(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(); - } - - 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); + cache = (_sprites.Frame0(decalProto.Sprite), decalProto.SnapCardinals); + _cachedTextures[decal.Id] = cache; } + + var cardinal = Angle.Zero; + + 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); diff --git a/Content.Server/Chunking/ChunkingSystem.cs b/Content.Server/Chunking/ChunkingSystem.cs index e4775439cb..9bc1ab0a3b 100644 --- a/Content.Server/Chunking/ChunkingSystem.cs +++ b/Content.Server/Chunking/ChunkingSystem.cs @@ -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; diff --git a/Content.Server/Decals/DecalSystem.cs b/Content.Server/Decals/DecalSystem.cs index 5bfd91486c..ad225afe22 100644 --- a/Content.Server/Decals/DecalSystem.cs +++ b/Content.Server/Decals/DecalSystem.cs @@ -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 { diff --git a/Content.Server/Parallax/BiomeSystem.cs b/Content.Server/Parallax/BiomeSystem.cs index 0b8c7a4d82..c4c2300870 100644 --- a/Content.Server/Parallax/BiomeSystem.cs +++ b/Content.Server/Parallax/BiomeSystem.cs @@ -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; diff --git a/Content.Shared/Decals/Decal.cs b/Content.Shared/Decals/Decal.cs index 56ecc829e7..cb6f944c65 100644 --- a/Content.Shared/Decals/Decal.cs +++ b/Content.Shared/Decals/Decal.cs @@ -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; diff --git a/Content.Shared/Decals/DecalGridComponent.cs b/Content.Shared/Decals/DecalGridComponent.cs index 140eb5bafc..8ac05cb280 100644 --- a/Content.Shared/Decals/DecalGridComponent.cs +++ b/Content.Shared/Decals/DecalGridComponent.cs @@ -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 ()); /// @@ -25,10 +26,6 @@ namespace Content.Shared.Decals /// 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 DecalZIndexIndex = new(); - public readonly SortedDictionary> DecalRenderIndex = new(); - [DataDefinition] [Serializable, NetSerializable] public sealed partial class DecalChunk diff --git a/Content.Shared/Decals/SharedDecalSystem.cs b/Content.Shared/Decals/SharedDecalSystem.cs index 02f73bdacb..76fa9d64db 100644 --- a/Content.Shared/Decals/SharedDecalSystem.cs +++ b/Content.Shared/Decals/SharedDecalSystem.cs @@ -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; - } - } - /// /// Sent by clients to request that a decal is placed on the server. ///