diff --git a/Content.Client/Decals/DecalSystem.cs b/Content.Client/Decals/DecalSystem.cs index 72ffd12179..8142146640 100644 --- a/Content.Client/Decals/DecalSystem.cs +++ b/Content.Client/Decals/DecalSystem.cs @@ -1,7 +1,9 @@ using Content.Shared.Decals; using Robust.Client.GameObjects; using Robust.Client.Graphics; +using Robust.Shared.GameStates; using Robust.Shared.Utility; +using static Content.Shared.Decals.DecalGridComponent; namespace Content.Client.Decals { @@ -21,6 +23,7 @@ namespace Content.Client.Decals _overlay = new DecalOverlay(this, _sprites, EntityManager, PrototypeManager); _overlayManager.AddOverlay(_overlay); + SubscribeLocalEvent(OnHandleState); SubscribeNetworkEvent(OnChunkUpdate); SubscribeLocalEvent(OnGridInitialize); SubscribeLocalEvent(OnGridRemoval); @@ -73,6 +76,35 @@ namespace Content.Client.Decals _decalZIndexIndex[gridId].Remove(uid); } + private void OnHandleState(EntityUid gridUid, DecalGridComponent gridComp, ref ComponentHandleState args) + { + if (args.Current is not DecalGridState state) + return; + + // is this a delta or full state? + var removedChunks = new List(); + if (!state.FullState) + { + foreach (var key in gridComp.ChunkCollection.ChunkCollection.Keys) + { + if (!state.AllChunks!.Contains(key)) + removedChunks.Add(key); + } + } + else + { + foreach (var key in gridComp.ChunkCollection.ChunkCollection.Keys) + { + if (!state.Chunks.ContainsKey(key)) + removedChunks.Add(key); + } + } + + RemoveChunks(gridUid, gridComp, removedChunks); + UpdateChunks(gridUid, gridComp, state.Chunks); + return; + } + private void OnChunkUpdate(DecalChunkUpdateEvent ev) { foreach (var (gridId, updatedGridChunks) in ev.Data) @@ -85,37 +117,7 @@ namespace Content.Client.Decals continue; } - var chunkCollection = gridComp.ChunkCollection.ChunkCollection; - var chunkIndex = ChunkIndex[gridId]; - var renderIndex = DecalRenderIndex[gridId]; - var zIndexIndex = _decalZIndexIndex[gridId]; - - // Update any existing data / remove decals we didn't receive data for. - foreach (var (indices, newChunkData) in updatedGridChunks) - { - if (chunkCollection.TryGetValue(indices, out var chunk)) - { - var removedUids = new HashSet(chunk.Keys); - removedUids.ExceptWith(newChunkData.Keys); - foreach (var removedUid in removedUids) - { - RemoveDecalHook(gridId, removedUid); - chunkIndex.Remove(removedUid); - } - } - - chunkCollection[indices] = newChunkData; - - foreach (var (uid, decal) in newChunkData) - { - if (zIndexIndex.TryGetValue(uid, out var zIndex)) - renderIndex[zIndex].Remove(uid); - - renderIndex.GetOrNew(decal.ZIndex)[uid] = decal; - zIndexIndex[uid] = decal.ZIndex; - chunkIndex[uid] = indices; - } - } + UpdateChunks(gridId, gridComp, updatedGridChunks); } // Now we'll cull old chunks out of range as the server will send them to us anyway. @@ -129,21 +131,61 @@ namespace Content.Client.Decals continue; } - var chunkCollection = gridComp.ChunkCollection.ChunkCollection; - var chunkIndex = ChunkIndex[gridId]; + RemoveChunks(gridId, gridComp, chunks); + } + } - foreach (var index in chunks) + private void UpdateChunks(EntityUid gridId, DecalGridComponent gridComp, Dictionary updatedGridChunks) + { + var chunkCollection = gridComp.ChunkCollection.ChunkCollection; + var chunkIndex = ChunkIndex[gridId]; + var renderIndex = DecalRenderIndex[gridId]; + var zIndexIndex = _decalZIndexIndex[gridId]; + + // Update any existing data / remove decals we didn't receive data for. + foreach (var (indices, newChunkData) in updatedGridChunks) + { + if (chunkCollection.TryGetValue(indices, out var chunk)) { - if (!chunkCollection.TryGetValue(index, out var chunk)) continue; - - foreach (var (uid, _) in chunk) + var removedUids = new HashSet(chunk.Decals.Keys); + removedUids.ExceptWith(newChunkData.Decals.Keys); + foreach (var removedUid in removedUids) { - RemoveDecalHook(gridId, uid); - chunkIndex.Remove(uid); + RemoveDecalHook(gridId, removedUid); + chunkIndex.Remove(removedUid); } - - chunkCollection.Remove(index); } + + chunkCollection[indices] = newChunkData; + + 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; + chunkIndex[uid] = indices; + } + } + } + + private void RemoveChunks(EntityUid gridId, DecalGridComponent gridComp, IEnumerable chunks) + { + var chunkCollection = gridComp.ChunkCollection.ChunkCollection; + var chunkIndex = ChunkIndex[gridId]; + + foreach (var index in chunks) + { + if (!chunkCollection.TryGetValue(index, out var chunk)) continue; + + foreach (var uid in chunk.Decals.Keys) + { + RemoveDecalHook(gridId, uid); + chunkIndex.Remove(uid); + } + + chunkCollection.Remove(index); } } } diff --git a/Content.MapRenderer/Painters/GridPainter.cs b/Content.MapRenderer/Painters/GridPainter.cs index fffe3c160c..c6175a722d 100644 --- a/Content.MapRenderer/Painters/GridPainter.cs +++ b/Content.MapRenderer/Painters/GridPainter.cs @@ -122,9 +122,9 @@ namespace Content.MapRenderer.Painters // for some reason decal moment i guess. if (_sEntityManager.TryGetComponent(grid.Owner, out var comp)) { - foreach (var (_, list) in comp.ChunkCollection.ChunkCollection) + foreach (var chunk in comp.ChunkCollection.ChunkCollection.Values) { - foreach (var (_, decal) in list) + foreach (var decal in chunk.Decals.Values) { var (x, y) = TransformLocalPosition(decal.Coordinates, grid); decals.GetOrNew(grid.Owner).Add(new DecalData(decal, x, y)); diff --git a/Content.Server/Decals/DecalSystem.cs b/Content.Server/Decals/DecalSystem.cs index 2bc91bad06..7b1dd93aef 100644 --- a/Content.Server/Decals/DecalSystem.cs +++ b/Content.Server/Decals/DecalSystem.cs @@ -8,11 +8,15 @@ using Content.Shared.Decals; using Content.Shared.Maps; using Microsoft.Extensions.ObjectPool; using Robust.Server.Player; +using Robust.Shared; +using Robust.Shared.Configuration; using Robust.Shared.Enums; +using Robust.Shared.GameStates; using Robust.Shared.Map; -using Robust.Shared.Player; using Robust.Shared.Threading; +using Robust.Shared.Timing; using Robust.Shared.Utility; +using static Content.Shared.Decals.DecalGridComponent; namespace Content.Server.Decals { @@ -23,6 +27,8 @@ namespace Content.Server.Decals [Dependency] private readonly ITileDefinitionManager _tileDefMan = default!; [Dependency] private readonly IParallelManager _parMan = default!; [Dependency] private readonly ChunkingSystem _chunking = default!; + [Dependency] private readonly IConfigurationManager _conf = default!; + [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly IDependencyCollection _dependencies = default!; private readonly Dictionary> _dirtyChunks = new(); @@ -36,6 +42,7 @@ namespace Content.Server.Decals private ObjectPool>> _chunkViewerPool = new DefaultObjectPool>>( new DefaultPooledObjectPolicy>>(), 64); + private bool _pvsEnabled; public override void Initialize() { @@ -43,10 +50,57 @@ namespace Content.Server.Decals _playerManager.PlayerStatusChanged += OnPlayerStatusChanged; SubscribeLocalEvent(OnTileChanged); + SubscribeLocalEvent(OnGetState); SubscribeNetworkEvent(OnDecalPlacementRequest); SubscribeNetworkEvent(OnDecalRemovalRequest); SubscribeLocalEvent(OnGridSplit); + + _conf.OnValueChanged(CVars.NetPVS, OnPvsToggle, true); + } + + private void OnPvsToggle(bool value) + { + if (value == _pvsEnabled) + return; + + _pvsEnabled = value; + + if (value) + return; + + foreach (var playerData in _previousSentChunks.Values) + { + playerData.Clear(); + } + + foreach (var (grid, meta) in EntityQuery(true)) + { + grid.ForceTick = _timing.CurTick; + Dirty(grid, meta); + } + } + + private void OnGetState(EntityUid uid, DecalGridComponent component, ref ComponentGetState args) + { + if (_pvsEnabled && !args.ReplayState) + return; + + // Should this be a full component state or a delta-state? + if (args.FromTick <= component.CreationTick && args.FromTick <= component.ForceTick) + { + args.State = new DecalGridState(component.ChunkCollection.ChunkCollection); + return; + } + + var data = new Dictionary(); + foreach (var (index, chunk) in component.ChunkCollection.ChunkCollection) + { + if (chunk.LastModified >= args.FromTick) + data[index] = chunk; + } + + args.State = new DecalGridState(data) { AllChunks = new(component.ChunkCollection.ChunkCollection.Keys) }; } private void OnGridSplit(ref PostGridSplitEvent ev) @@ -69,16 +123,16 @@ namespace Content.Server.Decals var bounds = new Box2(tilePos - 0.01f, tilePos + 1.01f); var toRemove = new RemQueue(); - foreach (var (oldUid, decal) in oldChunk) + foreach (var (oldUid, decal) in oldChunk.Decals) { if (!bounds.Contains(decal.Coordinates)) continue; var uid = chunkCollection.NextUid++; var chunk = chunkCollection.ChunkCollection.GetOrNew(chunkIndices); - chunk[uid] = decal; + chunk.Decals[uid] = decal; ChunkIndex[ev.Grid][uid] = chunkIndices; - DirtyChunk(ev.Grid, chunkIndices); + DirtyChunk(ev.Grid, chunkIndices, chunk); toRemove.Add(oldUid); ChunkIndex[ev.OldGrid].Remove(oldUid); @@ -86,14 +140,14 @@ namespace Content.Server.Decals foreach (var uid in toRemove) { - oldChunk.Remove(uid); + oldChunk.Decals.Remove(uid); } - if (oldChunk.Count == 0) + if (oldChunk.Decals.Count == 0) oldChunkCollection.ChunkCollection.Remove(chunkIndices); if (toRemove.List?.Count > 0) - DirtyChunk(ev.OldGrid, chunkIndices); + DirtyChunk(ev.OldGrid, chunkIndices, oldChunk); } } @@ -102,6 +156,7 @@ namespace Content.Server.Decals base.Shutdown(); _playerManager.PlayerStatusChanged -= OnPlayerStatusChanged; + _conf.UnsubValueChanged(CVars.NetPVS, OnPvsToggle); } private void OnTileChanged(TileChangedEvent args) @@ -117,7 +172,7 @@ namespace Content.Server.Decals var toDelete = new HashSet(); if (chunkCollection.TryGetValue(indices, out var chunk)) { - foreach (var (uid, decal) in chunk) + foreach (var (uid, decal) in chunk.Decals) { if (new Vector2((int) Math.Floor(decal.Coordinates.X), (int) Math.Floor(decal.Coordinates.Y)) == args.NewTile.GridIndices) @@ -134,7 +189,7 @@ namespace Content.Server.Decals RemoveDecalInternal( args.NewTile.GridUid, uid); } - DirtyChunk(args.NewTile.GridUid, indices); + DirtyChunk(args.NewTile.GridUid, indices, chunk!); } private void OnPlayerStatusChanged(object? sender, SessionStatusEventArgs e) @@ -190,8 +245,9 @@ namespace Content.Server.Decals } } - protected override void DirtyChunk(EntityUid id, Vector2i chunkIndices) + protected override void DirtyChunk(EntityUid id, Vector2i chunkIndices, DecalChunk chunk) { + chunk.LastModified = _timing.CurTick; if(!_dirtyChunks.ContainsKey(id)) _dirtyChunks[id] = new HashSet(); _dirtyChunks[id].Add(chunkIndices); @@ -227,11 +283,10 @@ namespace Content.Server.Decals uid = chunkCollection.NextUid++; var chunkIndices = GetChunkIndices(decal.Coordinates); - if(!chunkCollection.ChunkCollection.ContainsKey(chunkIndices)) - chunkCollection.ChunkCollection[chunkIndices] = new(); - chunkCollection.ChunkCollection[chunkIndices][uid.Value] = decal; + var chunk = chunkCollection.ChunkCollection.GetOrNew(chunkIndices); + chunk.Decals[uid.Value] = decal; ChunkIndex[gridId.Value][uid.Value] = chunkIndices; - DirtyChunk(gridId.Value, chunkIndices); + DirtyChunk(gridId.Value, chunkIndices, chunk); return true; } @@ -246,7 +301,7 @@ namespace Content.Server.Decals if (chunkCollection == null || !chunkCollection.TryGetValue(chunkIndices, out var chunk)) return uids; - foreach (var (uid, decal) in chunk) + foreach (var (uid, decal) in chunk.Decals) { if ((position - decal.Coordinates-new Vector2(0.5f, 0.5f)).Length > distance) continue; @@ -276,15 +331,16 @@ namespace Content.Server.Decals return false; } - DirtyChunk(gridId, indices); var chunkCollection = ChunkCollection(gridId); if (chunkCollection == null) return false; - var decal = chunkCollection[indices][uid]; + var decal = chunkCollection[indices].Decals[uid]; if (newGridId == gridId) { - chunkCollection[indices][uid] = decal.WithCoordinates(position); + var existingChunk = chunkCollection[indices]; + existingChunk.Decals[uid] = decal.WithCoordinates(position); + DirtyChunk(gridId, indices, existingChunk); return true; } @@ -297,9 +353,11 @@ namespace Content.Server.Decals var chunkIndices = GetChunkIndices(position); if(!newChunkCollection.ContainsKey(chunkIndices)) newChunkCollection[chunkIndices] = new(); - newChunkCollection[chunkIndices][uid] = decal.WithCoordinates(position); + + var chunk = newChunkCollection[chunkIndices]; + chunk.Decals[uid] = decal.WithCoordinates(position); ChunkIndex[newGridId][uid] = chunkIndices; - DirtyChunk(newGridId, chunkIndices); + DirtyChunk(newGridId, chunkIndices, chunk); return true; } @@ -315,9 +373,9 @@ namespace Content.Server.Decals return false; var chunk = chunkCollection[indices]; - var decal = chunk[uid]; - chunk[uid] = decal.WithColor(color); - DirtyChunk(gridId, indices); + var decal = chunk.Decals[uid]; + chunk.Decals[uid] = decal.WithColor(color); + DirtyChunk(gridId, indices, chunk); return true; } @@ -336,9 +394,9 @@ namespace Content.Server.Decals return false; var chunk = chunkCollection[indices]; - var decal = chunk[uid]; - chunk[uid] = decal.WithId(id); - DirtyChunk(gridId, indices); + var decal = chunk.Decals[uid]; + chunk.Decals[uid] = decal.WithId(id); + DirtyChunk(gridId, indices , chunk); return true; } @@ -354,9 +412,9 @@ namespace Content.Server.Decals return false; var chunk = chunkCollection[indices]; - var decal = chunk[uid]; - chunk[uid] = decal.WithRotation(angle); - DirtyChunk(gridId, indices); + var decal = chunk.Decals[uid]; + chunk.Decals[uid] = decal.WithRotation(angle); + DirtyChunk(gridId, indices, chunk); return true; } @@ -372,9 +430,9 @@ namespace Content.Server.Decals return false; var chunk = chunkCollection[indices]; - var decal = chunk[uid]; - chunk[uid] = decal.WithZIndex(zIndex); - DirtyChunk(gridId, indices); + var decal = chunk.Decals[uid]; + chunk.Decals[uid] = decal.WithZIndex(zIndex); + DirtyChunk(gridId, indices, chunk); return true; } @@ -390,9 +448,9 @@ namespace Content.Server.Decals return false; var chunk = chunkCollection[indices]; - var decal = chunk[uid]; - chunk[uid] = decal.WithCleanable(cleanable); - DirtyChunk(gridId, indices); + var decal = chunk.Decals[uid]; + chunk.Decals[uid] = decal.WithCleanable(cleanable); + DirtyChunk(gridId, indices, chunk); return true; } @@ -400,9 +458,25 @@ namespace Content.Server.Decals { base.Update(frameTime); - var players = _playerManager.ServerSessions.Where(x => x.Status == SessionStatus.InGame).ToArray(); - var opts = new ParallelOptions { MaxDegreeOfParallelism = _parMan.ParallelProcessCount }; - Parallel.ForEach(players, opts, UpdatePlayer); + foreach (var ent in _dirtyChunks.Keys) + { + if (TryComp(ent, out DecalGridComponent? decals)) + Dirty(decals); + } + + if (!_pvsEnabled) + { + _dirtyChunks.Clear(); + return; + } + + if (_pvsEnabled) + { + var players = _playerManager.ServerSessions.Where(x => x.Status == SessionStatus.InGame).ToArray(); + var opts = new ParallelOptions { MaxDegreeOfParallelism = _parMan.ParallelProcessCount }; + Parallel.ForEach(players, opts, UpdatePlayer); + } + _dirtyChunks.Clear(); } @@ -506,20 +580,20 @@ namespace Content.Server.Decals Dictionary> updatedChunks, Dictionary> staleChunks) { - var updatedDecals = new Dictionary>>(); + var updatedDecals = new Dictionary>(); foreach (var (gridId, chunks) in updatedChunks) { var collection = ChunkCollection(gridId); if (collection == null) continue; - var gridChunks = new Dictionary>(); + var gridChunks = new Dictionary(); foreach (var indices in chunks) { gridChunks.Add(indices, collection.TryGetValue(indices, out var chunk) ? chunk - : new Dictionary(0)); + : new()); } updatedDecals[gridId] = gridChunks; } diff --git a/Content.Shared/Decals/Decal.cs b/Content.Shared/Decals/Decal.cs index 29c9bd78f6..e576bfdd50 100644 --- a/Content.Shared/Decals/Decal.cs +++ b/Content.Shared/Decals/Decal.cs @@ -6,12 +6,13 @@ namespace Content.Shared.Decals [DataDefinition] public sealed class Decal { + // if these are made not-readonly, then decal grid state handling needs to be updated to clone decals. [DataField("coordinates")] public readonly Vector2 Coordinates = Vector2.Zero; [DataField("id")] public readonly string Id = string.Empty; [DataField("color")] public readonly Color? Color; [DataField("angle")] public readonly Angle Angle = Angle.Zero; [DataField("zIndex")] public readonly int ZIndex; - [DataField("cleanable")] public bool Cleanable; + [DataField("cleanable")] public readonly bool Cleanable; public Decal() {} diff --git a/Content.Shared/Decals/DecalChunkUpdateEvent.cs b/Content.Shared/Decals/DecalChunkUpdateEvent.cs index ada0a3cb43..74bea5333c 100644 --- a/Content.Shared/Decals/DecalChunkUpdateEvent.cs +++ b/Content.Shared/Decals/DecalChunkUpdateEvent.cs @@ -1,12 +1,12 @@ -using Robust.Shared.Map; using Robust.Shared.Serialization; +using static Content.Shared.Decals.DecalGridComponent; namespace Content.Shared.Decals { [Serializable, NetSerializable] public sealed class DecalChunkUpdateEvent : EntityEventArgs { - public Dictionary>> Data = new(); + public Dictionary> Data = new(); public Dictionary> RemovedChunks = new(); } } diff --git a/Content.Shared/Decals/DecalGridChunkCollectionTypeSerializer.cs b/Content.Shared/Decals/DecalGridChunkCollectionTypeSerializer.cs index 6dacb001df..861477b00d 100644 --- a/Content.Shared/Decals/DecalGridChunkCollectionTypeSerializer.cs +++ b/Content.Shared/Decals/DecalGridChunkCollectionTypeSerializer.cs @@ -3,6 +3,7 @@ using Robust.Shared.Serialization.Markdown; using Robust.Shared.Serialization.Markdown.Mapping; using Robust.Shared.Serialization.Markdown.Validation; using Robust.Shared.Serialization.TypeSerializers.Interfaces; +using static Content.Shared.Decals.DecalGridComponent; namespace Content.Shared.Decals { @@ -20,13 +21,13 @@ namespace Content.Shared.Decals IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null, ISerializationManager.InstantiationDelegate? _ = default) { - var dictionary = serializationManager.Read>>(node, context, skipHook, notNullableOverride: true); + var dictionary = serializationManager.Read>(node, context, skipHook: skipHook, notNullableOverride: true); var uids = new SortedSet(); var uidChunkMap = new Dictionary(); foreach (var (indices, decals) in dictionary) { - foreach (var (uid, _) in decals) + foreach (var uid in decals.Decals.Keys) { uids.Add(uid); uidChunkMap[uid] = indices; @@ -40,13 +41,13 @@ namespace Content.Shared.Decals uidMap[uid] = nextIndex++; } - var newDict = new Dictionary>(); + var newDict = new Dictionary(); foreach (var (oldUid, newUid) in uidMap) { var indices = uidChunkMap[oldUid]; if(!newDict.ContainsKey(indices)) newDict[indices] = new(); - newDict[indices][newUid] = dictionary[indices][oldUid]; + newDict[indices].Decals[newUid] = dictionary[indices].Decals[oldUid]; } return new DecalGridComponent.DecalGridChunkCollection(newDict){NextUid = nextIndex}; diff --git a/Content.Shared/Decals/DecalGridComponent.cs b/Content.Shared/Decals/DecalGridComponent.cs index 5bb0a51109..1c64699b25 100644 --- a/Content.Shared/Decals/DecalGridComponent.cs +++ b/Content.Shared/Decals/DecalGridComponent.cs @@ -1,16 +1,110 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Serialization; +using Robust.Shared.Timing; +using Robust.Shared.Utility; +using static Content.Shared.Decals.DecalGridComponent; + namespace Content.Shared.Decals { [RegisterComponent] [Access(typeof(SharedDecalSystem))] + [NetworkedComponent] public sealed class DecalGridComponent : Component { [DataField("chunkCollection", serverOnly: true)] public DecalGridChunkCollection ChunkCollection = new(new ()); - [DataRecord] - public record DecalGridChunkCollection(Dictionary> ChunkCollection) + /// + /// Tick at which PVS was last toggled. Ensures that all players receive a full update when toggling PVS. + /// + public GameTick ForceTick { get; set; } + + [DataDefinition] + [Serializable, NetSerializable] + public sealed class DecalChunk + { + [DataField("decals")] + public Dictionary Decals; + + [NonSerialized] + public GameTick LastModified; + + public DecalChunk() + { + Decals = new(); + } + + public DecalChunk(Dictionary decals) + { + Decals = decals; + } + + public DecalChunk(DecalChunk chunk) + { + // decals are readonly, so this should be fine. + Decals = chunk.Decals.ShallowClone(); + LastModified = chunk.LastModified; + } + } + + [DataRecord, Serializable, NetSerializable] + public record DecalGridChunkCollection(Dictionary ChunkCollection) { public uint NextUid; } } + + [Serializable, NetSerializable] + public sealed class DecalGridState : ComponentState, IComponentDeltaState + { + public Dictionary Chunks; + public bool FullState => AllChunks == null; + + // required to infer deleted/missing chunks for delta states + public HashSet? AllChunks; + + public DecalGridState(Dictionary chunks) + { + Chunks = chunks; + } + + public void ApplyToFullState(ComponentState fullState) + { + DebugTools.Assert(!FullState); + var state = (DecalGridState) fullState; + DebugTools.Assert(state.FullState); + + foreach (var key in state.Chunks.Keys) + { + if (!AllChunks!.Contains(key)) + state.Chunks.Remove(key); + } + + foreach (var (chunk, data) in Chunks) + { + state.Chunks[chunk] = new(data); + } + } + + public ComponentState CreateNewFullState(ComponentState fullState) + { + DebugTools.Assert(!FullState); + var state = (DecalGridState) fullState; + DebugTools.Assert(state.FullState); + + var chunks = new Dictionary(state.Chunks.Count); + + foreach (var (chunk, data) in Chunks) + { + chunks[chunk] = new(data); + } + + foreach (var (chunk, data) in state.Chunks) + { + if (AllChunks!.Contains(chunk)) + chunks.TryAdd(chunk, new(data)); + } + return new DecalGridState(chunks); + } + } } diff --git a/Content.Shared/Decals/SharedDecalSystem.cs b/Content.Shared/Decals/SharedDecalSystem.cs index c7e7299926..e7e21ad379 100644 --- a/Content.Shared/Decals/SharedDecalSystem.cs +++ b/Content.Shared/Decals/SharedDecalSystem.cs @@ -4,6 +4,7 @@ using Robust.Shared.Configuration; using Robust.Shared.Map; using Robust.Shared.Prototypes; using Robust.Shared.Serialization; +using static Content.Shared.Decals.DecalGridComponent; namespace Content.Shared.Decals { @@ -32,7 +33,7 @@ namespace Content.Shared.Decals ChunkIndex[msg.EntityUid] = new(); foreach (var (indices, decals) in comp.ChunkCollection.ChunkCollection) { - foreach (var uid in decals.Keys) + foreach (var uid in decals.Decals.Keys) { ChunkIndex[msg.EntityUid][uid] = indices; } @@ -47,13 +48,13 @@ namespace Content.Shared.Decals return comp.ChunkCollection; } - protected Dictionary>? ChunkCollection(EntityUid gridEuid, DecalGridComponent? comp = null) + protected Dictionary? ChunkCollection(EntityUid gridEuid, DecalGridComponent? comp = null) { var collection = DecalGridChunkCollection(gridEuid, comp); return collection?.ChunkCollection; } - protected virtual void DirtyChunk(EntityUid id, Vector2i chunkIndices) {} + protected virtual void DirtyChunk(EntityUid id, Vector2i chunkIndices, DecalChunk chunk) {} protected bool RemoveDecalInternal(EntityUid gridId, uint uid) { @@ -65,16 +66,16 @@ namespace Content.Shared.Decals } var chunkCollection = ChunkCollection(gridId); - if (chunkCollection == null || !chunkCollection.TryGetValue(indices, out var chunk) || !chunk.Remove(uid)) + if (chunkCollection == null || !chunkCollection.TryGetValue(indices, out var chunk) || !chunk.Decals.Remove(uid)) { return false; } - if (chunk.Count == 0) + if (chunk.Decals.Count == 0) chunkCollection.Remove(indices); ChunkIndex[gridId].Remove(uid); - DirtyChunk(gridId, indices); + DirtyChunk(gridId, indices, chunk); return true; }