From 77bd892bbd0d3429eea1f7917f297827cd1510cd Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Thu, 28 Apr 2022 20:23:43 +1000 Subject: [PATCH] Fix decals (finally) (#7771) --- Content.Client/Decals/DecalOverlay.cs | 2 + Content.Client/Decals/DecalSystem.cs | 36 ++++--- .../TileReactions/CleanTileReaction.cs | 2 +- Content.Server/Decals/DecalSystem.cs | 102 +++++++++++++++--- .../Decals/DecalChunkUpdateEvent.cs | 5 +- Content.Shared/Decals/SharedDecalSystem.cs | 2 +- 6 files changed, 114 insertions(+), 35 deletions(-) diff --git a/Content.Client/Decals/DecalOverlay.cs b/Content.Client/Decals/DecalOverlay.cs index a5e5a2d831..03b7f87cc0 100644 --- a/Content.Client/Decals/DecalOverlay.cs +++ b/Content.Client/Decals/DecalOverlay.cs @@ -45,6 +45,8 @@ namespace Content.Client.Decals foreach (var (gridId, zIndexDictionary) in _decals.DecalRenderIndex) { + if (zIndexDictionary.Count == 0) continue; + var gridUid = _mapManager.GetGridEuid(gridId); var xform = xformQuery.GetComponent(gridUid); diff --git a/Content.Client/Decals/DecalSystem.cs b/Content.Client/Decals/DecalSystem.cs index bdcc0bf1e8..de8be03a23 100644 --- a/Content.Client/Decals/DecalSystem.cs +++ b/Content.Client/Decals/DecalSystem.cs @@ -61,7 +61,6 @@ namespace Content.Client.Decals protected override bool RemoveDecalHook(GridId gridId, uint uid) { RemoveDecalFromRenderIndex(gridId, uid); - return base.RemoveDecalHook(gridId, uid); } @@ -80,8 +79,11 @@ namespace Content.Client.Decals { foreach (var (gridId, gridChunks) in ev.Data) { + if (gridChunks.Count == 0) continue; + var chunkCollection = ChunkCollection(gridId); + // Update any existing data / remove decals we didn't receive data for. foreach (var (indices, newChunkData) in gridChunks) { if (chunkCollection.TryGetValue(indices, out var chunk)) @@ -90,8 +92,14 @@ namespace Content.Client.Decals removedUids.ExceptWith(newChunkData.Keys); foreach (var removedUid in removedUids) { - RemoveDecalFromRenderIndex(gridId, removedUid); + RemoveDecalInternal(gridId, removedUid); } + + chunkCollection[indices] = newChunkData; + } + else + { + chunkCollection.Add(indices, newChunkData); } foreach (var (uid, decal) in newChunkData) @@ -107,25 +115,27 @@ namespace Content.Client.Decals DecalRenderIndex[gridId][decal.ZIndex][uid] = decal; DecalZIndexIndex[gridId][uid] = decal.ZIndex; - ChunkIndex[gridId][uid] = indices; } - - chunkCollection[indices] = newChunkData; } + } - // Now we'll cull old chunks out of range as the server will send them to us anyway. - var toRemove = new RemQueue(); + // Now we'll cull old chunks out of range as the server will send them to us anyway. + foreach (var (gridId, chunks) in ev.RemovedChunks) + { + if (chunks.Count == 0) continue; - foreach (var (index, _) in chunkCollection) + var chunkCollection = ChunkCollection(gridId); + + foreach (var index in chunks) { - if (gridChunks.ContainsKey(index)) continue; + if (!chunkCollection.TryGetValue(index, out var chunk)) continue; - toRemove.Add(index); - } + foreach (var (uid, _) in chunk) + { + RemoveDecalInternal(gridId, uid); + } - foreach (var index in toRemove) - { chunkCollection.Remove(index); } } diff --git a/Content.Server/Chemistry/TileReactions/CleanTileReaction.cs b/Content.Server/Chemistry/TileReactions/CleanTileReaction.cs index ddeceec2d9..ade768c856 100644 --- a/Content.Server/Chemistry/TileReactions/CleanTileReaction.cs +++ b/Content.Server/Chemistry/TileReactions/CleanTileReaction.cs @@ -44,7 +44,7 @@ namespace Content.Server.Chemistry.TileReactions } var decalSystem = EntitySystem.Get(); - foreach (var uid in decalSystem.GetDecalsInRange(tile.GridIndex, tile.GridIndices+new Vector2(0.5f, 0.5f), validDelegate: x => x.Cleanable)) + foreach (var (uid, _) in decalSystem.GetDecalsInRange(tile.GridIndex, tile.GridIndices+new Vector2(0.5f, 0.5f), validDelegate: x => x.Cleanable)) { decalSystem.RemoveDecal(tile.GridIndex, uid); } diff --git a/Content.Server/Decals/DecalSystem.cs b/Content.Server/Decals/DecalSystem.cs index 087f16ce69..f95dc68408 100644 --- a/Content.Server/Decals/DecalSystem.cs +++ b/Content.Server/Decals/DecalSystem.cs @@ -8,6 +8,7 @@ using Robust.Server.Player; using Robust.Shared.Enums; using Robust.Shared.Map; using Robust.Shared.Player; +using Robust.Shared.Utility; namespace Content.Server.Decals { @@ -42,6 +43,52 @@ namespace Content.Server.Decals SubscribeNetworkEvent(OnDecalPlacementRequest); SubscribeNetworkEvent(OnDecalRemovalRequest); + SubscribeLocalEvent(OnGridSplit); + } + + private void OnGridSplit(ref PostGridSplitEvent ev) + { + // Transfer decals over to the new grid. + var enumerator = MapManager.GetGrid(ev.Grid).GetAllTilesEnumerator(); + var oldChunkCollection = DecalGridChunkCollection(ev.OldGrid); + var chunkCollection = DecalGridChunkCollection(ev.Grid); + + while (enumerator.MoveNext(out var tile)) + { + var tilePos = (Vector2) tile.Value.GridIndices; + var chunkIndices = GetChunkIndices(tilePos); + + if (!oldChunkCollection.ChunkCollection.TryGetValue(chunkIndices, out var oldChunk)) continue; + + var bounds = new Box2(tilePos - 0.01f, tilePos + 1.01f); + var toRemove = new RemQueue(); + + foreach (var (oldUid, decal) in oldChunk) + { + if (!bounds.Contains(decal.Coordinates)) continue; + + var uid = chunkCollection.NextUid++; + var chunk = chunkCollection.ChunkCollection.GetOrNew(chunkIndices); + + chunk[uid] = decal; + ChunkIndex[ev.Grid][uid] = chunkIndices; + DirtyChunk(ev.Grid, chunkIndices); + + toRemove.Add(oldUid); + ChunkIndex[ev.OldGrid].Remove(oldUid); + } + + foreach (var uid in toRemove) + { + oldChunk.Remove(uid); + } + + if (oldChunk.Count == 0) + oldChunkCollection.ChunkCollection.Remove(chunkIndices); + + if (toRemove.List?.Count > 0) + DirtyChunk(ev.OldGrid, chunkIndices); + } } public override void Shutdown() @@ -127,9 +174,10 @@ namespace Content.Server.Decals return; // remove all decals on the same tile - foreach (var decal in GetDecalsInRange(gridId, ev.Coordinates.Position)) + foreach (var (uid, decal) in GetDecalsInRange(gridId, ev.Coordinates.Position)) { - RemoveDecal(gridId, decal); + var chunkIndices = GetChunkIndices(decal.Coordinates); + RemoveDecal(gridId, uid); } } @@ -158,10 +206,10 @@ namespace Content.Server.Decals return false; var gridId = coordinates.GetGridId(EntityManager); - if (!gridId.IsValid()) + if (!MapManager.TryGetGrid(gridId, out var grid)) return false; - if (MapManager.GetGrid(gridId).GetTileRef(coordinates).IsSpace()) + if (grid.GetTileRef(coordinates).IsSpace(_tileDefMan)) return false; var chunkCollection = DecalGridChunkCollection(gridId); @@ -178,9 +226,9 @@ namespace Content.Server.Decals public bool RemoveDecal(GridId gridId, uint uid) => RemoveDecalInternal(gridId, uid); - public HashSet GetDecalsInRange(GridId gridId, Vector2 position, float distance = 0.75f, Func? validDelegate = null) + public HashSet<(uint Index, Decal Decal)> GetDecalsInRange(GridId gridId, Vector2 position, float distance = 0.75f, Func? validDelegate = null) { - var uids = new HashSet(); + var uids = new HashSet<(uint, Decal)>(); var chunkCollection = ChunkCollection(gridId); var chunkIndices = GetChunkIndices(position); if (!chunkCollection.TryGetValue(chunkIndices, out var chunk)) @@ -193,7 +241,7 @@ namespace Content.Server.Decals if (validDelegate == null || validDelegate(decal)) { - uids.Add(uid); + uids.Add((uid, decal)); } } @@ -310,15 +358,33 @@ namespace Content.Server.Decals { base.Update(frameTime); - foreach (var session in Filter.GetAllPlayers(_playerManager)) { if (session is not IPlayerSession { Status: SessionStatus.InGame } playerSession) continue; - var chunks = GetChunksForSession(playerSession); + var chunksInRange = GetChunksForSession(playerSession); + var staleChunks = new Dictionary>(); + + // Get any chunks not in range anymore + foreach (var (gridId, oldIndices) in _previousSentChunks[playerSession]) + { + if (!chunksInRange.TryGetValue(gridId, out var chunks)) + { + staleChunks[gridId] = oldIndices; + continue; + } + + foreach (var chunk in oldIndices) + { + if (chunks.Contains(chunk)) continue; + var elmo = staleChunks.GetOrNew(gridId); + elmo.Add(chunk); + } + } + var updatedChunks = _chunkViewerPool.Get(); - foreach (var (gridId, gridChunks) in chunks) + foreach (var (gridId, gridChunks) in chunksInRange) { var newChunks = _chunkIndexPool.Get(); newChunks.UnionWith(gridChunks); @@ -344,17 +410,18 @@ namespace Content.Server.Decals if (updatedChunks.Count == 0) { - ReturnToPool(chunks); + ReturnToPool(chunksInRange); // Even if updatedChunks is empty we'll still return it to the pool as it may have been allocated higher. ReturnToPool(updatedChunks); - continue; } + if (updatedChunks.Count == 0 && staleChunks.Count == 0) continue; + ReturnToPool(_previousSentChunks[playerSession]); - _previousSentChunks[playerSession] = chunks; + _previousSentChunks[playerSession] = chunksInRange; //send all gridChunks to client - SendChunkUpdates(playerSession, updatedChunks); + SendChunkUpdates(playerSession, updatedChunks, staleChunks); } _dirtyChunks.Clear(); @@ -372,7 +439,10 @@ namespace Content.Server.Decals _chunkViewerPool.Return(chunks); } - private void SendChunkUpdates(IPlayerSession session, Dictionary> updatedChunks) + private void SendChunkUpdates( + IPlayerSession session, + Dictionary> updatedChunks, + Dictionary> staleChunks) { var updatedDecals = new Dictionary>>(); foreach (var (gridId, chunks) in updatedChunks) @@ -388,7 +458,7 @@ namespace Content.Server.Decals updatedDecals[gridId] = gridChunks; } - RaiseNetworkEvent(new DecalChunkUpdateEvent{Data = updatedDecals}, Filter.SinglePlayer(session)); + RaiseNetworkEvent(new DecalChunkUpdateEvent{Data = updatedDecals, RemovedChunks = staleChunks}, Filter.SinglePlayer(session)); } private HashSet GetSessionViewers(IPlayerSession session) diff --git a/Content.Shared/Decals/DecalChunkUpdateEvent.cs b/Content.Shared/Decals/DecalChunkUpdateEvent.cs index 05a8f8e3d6..53877192a6 100644 --- a/Content.Shared/Decals/DecalChunkUpdateEvent.cs +++ b/Content.Shared/Decals/DecalChunkUpdateEvent.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using Robust.Shared.GameObjects; using Robust.Shared.Map; -using Robust.Shared.Maths; using Robust.Shared.Serialization; namespace Content.Shared.Decals @@ -11,5 +7,6 @@ namespace Content.Shared.Decals public sealed class DecalChunkUpdateEvent : EntityEventArgs { public Dictionary>> Data = new(); + public Dictionary> RemovedChunks = new(); } } diff --git a/Content.Shared/Decals/SharedDecalSystem.cs b/Content.Shared/Decals/SharedDecalSystem.cs index b693abf325..b67767758a 100644 --- a/Content.Shared/Decals/SharedDecalSystem.cs +++ b/Content.Shared/Decals/SharedDecalSystem.cs @@ -79,7 +79,7 @@ namespace Content.Shared.Decals if (chunkCollection[indices].Count == 0) chunkCollection.Remove(indices); - ChunkIndex[gridId]?.Remove(uid); + ChunkIndex[gridId].Remove(uid); DirtyChunk(gridId, indices); return true; }