diff --git a/Content.Client/Decals/DecalSystem.cs b/Content.Client/Decals/DecalSystem.cs index fa6066c17b..159efced01 100644 --- a/Content.Client/Decals/DecalSystem.cs +++ b/Content.Client/Decals/DecalSystem.cs @@ -15,15 +15,11 @@ namespace Content.Client.Decals private DecalOverlay _overlay = default!; - // TODO move this data to the component - public readonly Dictionary>> DecalRenderIndex = new(); - private readonly Dictionary> _decalZIndexIndex = new(); - public override void Initialize() { base.Initialize(); - _overlay = new DecalOverlay(this, _sprites, EntityManager, PrototypeManager); + _overlay = new DecalOverlay(_sprites, EntityManager, PrototypeManager); _overlayManager.AddOverlay(_overlay); SubscribeLocalEvent(OnHandleState); @@ -42,41 +38,25 @@ namespace Content.Client.Decals } } - protected override void OnCompRemove(EntityUid uid, DecalGridComponent component, ComponentRemove args) - { - DecalRenderIndex.Remove(uid); - _decalZIndexIndex.Remove(uid); - base.OnCompRemove(uid, component, args); - } - - protected override void OnCompAdd(EntityUid uid, DecalGridComponent component, ComponentAdd args) - { - DecalRenderIndex[uid] = new(); - _decalZIndexIndex[uid] = new(); - base.OnCompAdd(uid, component, args); - } - public override void Shutdown() { base.Shutdown(); _overlayManager.RemoveOverlay(_overlay); } - protected override bool RemoveDecalHook(EntityUid gridId, uint uid) + protected override void OnDecalRemoved(EntityUid gridId, uint decalId, DecalGridComponent component, Vector2i indices, DecalChunk chunk) { - RemoveDecalFromRenderIndex(gridId, uid); - return base.RemoveDecalHook(gridId, uid); - } + base.OnDecalRemoved(gridId, decalId, component, indices, chunk); - private void RemoveDecalFromRenderIndex(EntityUid gridId, uint uid) - { - var zIndex = _decalZIndexIndex[gridId][uid]; + if (!component.DecalZIndexIndex.Remove(decalId, out var zIndex)) + return; - DecalRenderIndex[gridId][zIndex].Remove(uid); - if (DecalRenderIndex[gridId][zIndex].Count == 0) - DecalRenderIndex[gridId].Remove(zIndex); + if (!component.DecalRenderIndex.TryGetValue(zIndex, out var renderIndex)) + return; - _decalZIndexIndex[gridId].Remove(uid); + renderIndex.Remove(decalId); + if (renderIndex.Count == 0) + component.DecalRenderIndex.Remove(zIndex); } private void OnHandleState(EntityUid gridUid, DecalGridComponent gridComp, ref ComponentHandleState args) @@ -143,14 +123,8 @@ namespace Content.Client.Decals private void UpdateChunks(EntityUid gridId, DecalGridComponent gridComp, Dictionary updatedGridChunks) { var chunkCollection = gridComp.ChunkCollection.ChunkCollection; - - if (!ChunkIndex.TryGetValue(gridId, out var chunkIndex) || - !DecalRenderIndex.TryGetValue(gridId, out var renderIndex) || - !_decalZIndexIndex.TryGetValue(gridId, out var zIndexIndex)) - { - Logger.Error($"Grid missing from dictionaries while updating decal chunks for grid {ToPrettyString(gridId)}"); - return; - } + 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) @@ -161,8 +135,8 @@ namespace Content.Client.Decals removedUids.ExceptWith(newChunkData.Decals.Keys); foreach (var removedUid in removedUids) { - RemoveDecalHook(gridId, removedUid); - chunkIndex.Remove(removedUid); + OnDecalRemoved(gridId, removedUid, gridComp, indices, chunk); + gridComp.DecalIndex.Remove(removedUid); } } @@ -175,7 +149,7 @@ namespace Content.Client.Decals renderIndex.GetOrNew(decal.ZIndex)[uid] = decal; zIndexIndex[uid] = decal.ZIndex; - chunkIndex[uid] = indices; + gridComp.DecalIndex[uid] = indices; } } } @@ -184,20 +158,14 @@ namespace Content.Client.Decals { var chunkCollection = gridComp.ChunkCollection.ChunkCollection; - if (!ChunkIndex.TryGetValue(gridId, out var chunkIndex)) - { - Logger.Error($"Missing grid in ChunkIndex dictionary while removing chunks from grid {ToPrettyString(gridId)}"); - return; - } - foreach (var index in chunks) { if (!chunkCollection.TryGetValue(index, out var chunk)) continue; - foreach (var uid in chunk.Decals.Keys) + foreach (var decalId in chunk.Decals.Keys) { - RemoveDecalHook(gridId, uid); - chunkIndex.Remove(uid); + OnDecalRemoved(gridId, decalId, gridComp, index, chunk); + gridComp.DecalIndex.Remove(decalId); } chunkCollection.Remove(index); diff --git a/Content.Client/Decals/Overlays/DecalOverlay.cs b/Content.Client/Decals/Overlays/DecalOverlay.cs index 5c6a4570de..c37a0e3aea 100644 --- a/Content.Client/Decals/Overlays/DecalOverlay.cs +++ b/Content.Client/Decals/Overlays/DecalOverlay.cs @@ -3,13 +3,11 @@ using Robust.Client.GameObjects; using Robust.Client.Graphics; using Robust.Shared.Enums; using Robust.Shared.Prototypes; -using Robust.Shared.Utility; namespace Content.Client.Decals.Overlays { public sealed class DecalOverlay : Overlay { - private readonly DecalSystem _decals; private readonly SpriteSystem _sprites; private readonly IEntityManager _entManager; private readonly IPrototypeManager _prototypeManager; @@ -19,12 +17,10 @@ namespace Content.Client.Decals.Overlays private readonly Dictionary _cachedTextures = new(64); public DecalOverlay( - DecalSystem decals, SpriteSystem sprites, IEntityManager entManager, IPrototypeManager prototypeManager) { - _decals = decals; _sprites = sprites; _entManager = entManager; _prototypeManager = prototypeManager; @@ -37,17 +33,14 @@ namespace Content.Client.Decals.Overlays var xformQuery = _entManager.GetEntityQuery(); var eyeAngle = args.Viewport.Eye?.Rotation ?? Angle.Zero; - foreach (var (gridId, zIndexDictionary) in _decals.DecalRenderIndex) + foreach (var (decalGrid, xform) in _entManager.EntityQuery(true)) { + var gridId = decalGrid.Owner; + var zIndexDictionary = decalGrid.DecalRenderIndex; + if (zIndexDictionary.Count == 0) continue; - if (!xformQuery.TryGetComponent(gridId, out var xform)) - { - Logger.Error($"Tried to draw decals on a non-existent grid. GridUid: {gridId}"); - continue; - } - if (xform.MapID != args.MapId) continue; @@ -61,8 +54,7 @@ namespace Content.Client.Decals.Overlays { if (!_cachedTextures.TryGetValue(decal.Id, out var cache) && _prototypeManager.TryIndex(decal.Id, out var decalProto)) { - var sprite = GetDecalSprite(decal.Id); - cache = (_sprites.Frame0(sprite), decalProto.SnapCardinals); + cache = (_sprites.Frame0(decalProto.Sprite), decalProto.SnapCardinals); _cachedTextures[decal.Id] = cache; } @@ -86,14 +78,5 @@ namespace Content.Client.Decals.Overlays handle.SetTransform(Matrix3.Identity); } - - public SpriteSpecifier GetDecalSprite(string id) - { - if (_prototypeManager.TryIndex(id, out var proto)) - return proto.Sprite; - - Logger.Error($"Unknown decal prototype: {id}"); - return new SpriteSpecifier.Texture(new ResourcePath("/Textures/noSprite.png")); - } } } diff --git a/Content.Server/Decals/Commands/EditDecalCommand.cs b/Content.Server/Decals/Commands/EditDecalCommand.cs index 934443672b..cc1be6d2a2 100644 --- a/Content.Server/Decals/Commands/EditDecalCommand.cs +++ b/Content.Server/Decals/Commands/EditDecalCommand.cs @@ -61,7 +61,7 @@ Possible modes are:\n return; } - if (!decalSystem.SetDecalPosition(gridId, uid, gridId, new Vector2(x, y))) + if (!decalSystem.SetDecalPosition(gridId, uid, new(gridId, (x, y)))) { shell.WriteError("Failed changing decalposition."); } diff --git a/Content.Server/Decals/DecalSystem.cs b/Content.Server/Decals/DecalSystem.cs index 0b082c6353..1160d0fac8 100644 --- a/Content.Server/Decals/DecalSystem.cs +++ b/Content.Server/Decals/DecalSystem.cs @@ -104,46 +104,51 @@ namespace Content.Server.Decals private void OnGridSplit(ref PostGridSplitEvent ev) { + if (!TryComp(ev.OldGrid, out DecalGridComponent? oldComp)) + return; + + if (!TryComp(ev.Grid, out DecalGridComponent? newComp)) + return; + // Transfer decals over to the new grid. var enumerator = MapManager.GetGrid(ev.Grid).GetAllTilesEnumerator(); - var oldChunkCollection = DecalGridChunkCollection(ev.OldGrid); - var chunkCollection = DecalGridChunkCollection(ev.Grid); - if (chunkCollection == null || oldChunkCollection == null) - return; + var oldChunkCollection = oldComp.ChunkCollection.ChunkCollection; + var chunkCollection = newComp.ChunkCollection.ChunkCollection; 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; + if (!oldChunkCollection.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.Decals) + foreach (var (oldDecalId, decal) in oldChunk.Decals) { - if (!bounds.Contains(decal.Coordinates)) continue; + if (!bounds.Contains(decal.Coordinates)) + continue; - var uid = chunkCollection.NextUid++; - var chunk = chunkCollection.ChunkCollection.GetOrNew(chunkIndices); - - chunk.Decals[uid] = decal; - ChunkIndex[ev.Grid][uid] = chunkIndices; - DirtyChunk(ev.Grid, chunkIndices, chunk); - - toRemove.Add(oldUid); - ChunkIndex[ev.OldGrid].Remove(oldUid); + var newDecalId = newComp.ChunkCollection.NextDecalId++; + var newChunk = chunkCollection.GetOrNew(chunkIndices); + newChunk.Decals[newDecalId] = decal; + newComp.DecalIndex[newDecalId] = chunkIndices; + toRemove.Add(oldDecalId); } - foreach (var uid in toRemove) + foreach (var oldDecalId in toRemove) { - oldChunk.Decals.Remove(uid); + oldChunk.Decals.Remove(oldDecalId); + oldComp.DecalIndex.Remove(oldDecalId); } + DirtyChunk(ev.Grid, chunkIndices, chunkCollection.GetOrNew(chunkIndices)); + if (oldChunk.Decals.Count == 0) - oldChunkCollection.ChunkCollection.Remove(chunkIndices); + oldChunkCollection.Remove(chunkIndices); if (toRemove.List?.Count > 0) DirtyChunk(ev.OldGrid, chunkIndices, oldChunk); @@ -163,32 +168,35 @@ namespace Content.Server.Decals if (!args.NewTile.IsSpace(_tileDefMan)) return; - var chunkCollection = ChunkCollection(args.Entity); - if (chunkCollection == null) + if (!TryComp(args.Entity, out DecalGridComponent? grid)) return; var indices = GetChunkIndices(args.NewTile.GridIndices); var toDelete = new HashSet(); - if (chunkCollection.TryGetValue(indices, out var chunk)) + if (!grid.ChunkCollection.ChunkCollection.TryGetValue(indices, out var chunk)) + return; + + foreach (var (uid, decal) in chunk.Decals) { - 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) { - if (new Vector2((int) Math.Floor(decal.Coordinates.X), (int) Math.Floor(decal.Coordinates.Y)) == - args.NewTile.GridIndices) - { - toDelete.Add(uid); - } + toDelete.Add(uid); } } - if (toDelete.Count == 0) return; + if (toDelete.Count == 0) + return; - foreach (var uid in toDelete) + foreach (var decalId in toDelete) { - RemoveDecalInternal( args.NewTile.GridUid, uid); + grid.DecalIndex.Remove(decalId); + chunk.Decals.Remove(decalId); } - DirtyChunk(args.NewTile.GridUid, indices, chunk!); + DirtyChunk(args.Entity, indices, chunk); + if (chunk.Decals.Count == 0) + grid.ChunkCollection.ChunkCollection.Remove(indices); } private void OnPlayerStatusChanged(object? sender, SessionStatusEventArgs e) @@ -237,10 +245,9 @@ namespace Content.Server.Decals return; // remove all decals on the same tile - foreach (var (uid, decal) in GetDecalsInRange(gridId.Value, ev.Coordinates.Position)) + foreach (var (decalId, _) in GetDecalsInRange(gridId.Value, ev.Coordinates.Position)) { - var chunkIndices = GetChunkIndices(decal.Coordinates); - RemoveDecal(gridId.Value, uid); + RemoveDecal(gridId.Value, decalId); } } @@ -252,19 +259,17 @@ namespace Content.Server.Decals _dirtyChunks[id].Add(chunkIndices); } - public bool TryAddDecal(string id, EntityCoordinates coordinates, [NotNullWhen(true)] out uint? uid, Color? color = null, Angle? rotation = null, int zIndex = 0, bool cleanable = false) + public bool TryAddDecal(string id, EntityCoordinates coordinates, out uint decalId, Color? color = null, Angle? rotation = null, int zIndex = 0, bool cleanable = false) { - uid = 0; - rotation ??= Angle.Zero; var decal = new Decal(coordinates.Position, id, color, rotation.Value, zIndex, cleanable); - return TryAddDecal(decal, coordinates, out uid); + return TryAddDecal(decal, coordinates, out decalId); } - public bool TryAddDecal(Decal decal, EntityCoordinates coordinates, [NotNull] out uint? uid) + public bool TryAddDecal(Decal decal, EntityCoordinates coordinates, out uint decalId) { - uid = 0; + decalId = 0; if (!PrototypeManager.HasIndex(decal.Id)) return false; @@ -276,29 +281,29 @@ namespace Content.Server.Decals if (grid.GetTileRef(coordinates).IsSpace(_tileDefMan)) return false; - var chunkCollection = DecalGridChunkCollection(gridId.Value); - if (chunkCollection == null) + if (!TryComp(gridId, out DecalGridComponent? comp)) return false; - uid = chunkCollection.NextUid++; + decalId = comp.ChunkCollection.NextDecalId++; var chunkIndices = GetChunkIndices(decal.Coordinates); - var chunk = chunkCollection.ChunkCollection.GetOrNew(chunkIndices); - chunk.Decals[uid.Value] = decal; - ChunkIndex[gridId.Value][uid.Value] = chunkIndices; + var chunk = comp.ChunkCollection.ChunkCollection.GetOrNew(chunkIndices); + chunk.Decals[decalId] = decal; + comp.DecalIndex[decalId] = chunkIndices; DirtyChunk(gridId.Value, chunkIndices, chunk); return true; } - public bool RemoveDecal(EntityUid gridId, uint uid) => RemoveDecalInternal(gridId, uid); + public bool RemoveDecal(EntityUid gridId, uint decalId, DecalGridComponent? component = null) + => RemoveDecalInternal(gridId, decalId, out _, component); public HashSet<(uint Index, Decal Decal)> GetDecalsInRange(EntityUid gridId, Vector2 position, float distance = 0.75f, Func? validDelegate = null) { - var uids = new HashSet<(uint, Decal)>(); + var decalIds = new HashSet<(uint, Decal)>(); var chunkCollection = ChunkCollection(gridId); var chunkIndices = GetChunkIndices(position); if (chunkCollection == null || !chunkCollection.TryGetValue(chunkIndices, out var chunk)) - return uids; + return decalIds; foreach (var (uid, decal) in chunk.Decals) { @@ -307,150 +312,63 @@ namespace Content.Server.Decals if (validDelegate == null || validDelegate(decal)) { - uids.Add((uid, decal)); + decalIds.Add((uid, decal)); } } - return uids; + return decalIds; } - public bool SetDecalPosition(EntityUid gridId, uint uid, EntityCoordinates coordinates) + /// + /// Changes a decals position. Note this will actually result in a new decal being created, possibly on a new grid or chunk. + /// + /// + /// If the new position is invalid, this will result in the decal getting deleted. + /// + public bool SetDecalPosition(EntityUid gridId, uint decalId, EntityCoordinates coordinates, DecalGridComponent? comp = null) { - var newGridId = coordinates.GetGridUid(EntityManager); - if (newGridId == null) + if (!Resolve(gridId, ref comp)) return false; - return SetDecalPosition(gridId, uid, newGridId.Value, coordinates.Position); + if (!RemoveDecalInternal(gridId, decalId, out var removed, comp)) + return false; + + return TryAddDecal(removed.WithCoordinates(coordinates.Position), coordinates, out _); } - public bool SetDecalPosition(EntityUid gridId, uint uid, EntityUid newGridId, Vector2 position) + private bool ModifyDecal(EntityUid gridId, uint decalId, Func modifyDecal, DecalGridComponent? comp = null) { - if (!ChunkIndex.TryGetValue(gridId, out var values) || !values.TryGetValue(uid, out var indices)) - { - return false; - } - - var chunkCollection = ChunkCollection(gridId); - if (chunkCollection == null) + if (!Resolve(gridId, ref comp)) return false; - var decal = chunkCollection[indices].Decals[uid]; - if (newGridId == gridId) - { - var existingChunk = chunkCollection[indices]; - existingChunk.Decals[uid] = decal.WithCoordinates(position); - DirtyChunk(gridId, indices, existingChunk); - return true; - } - - RemoveDecalInternal(gridId, uid); - - var newChunkCollection = ChunkCollection(newGridId); - if (newChunkCollection == null) + if (!comp.DecalIndex.TryGetValue(decalId, out var indices)) return false; - var chunkIndices = GetChunkIndices(position); - if(!newChunkCollection.ContainsKey(chunkIndices)) - newChunkCollection[chunkIndices] = new(); - - var chunk = newChunkCollection[chunkIndices]; - chunk.Decals[uid] = decal.WithCoordinates(position); - ChunkIndex[newGridId][uid] = chunkIndices; - DirtyChunk(newGridId, chunkIndices, chunk); - return true; - } - - public bool SetDecalColor(EntityUid gridId, uint uid, Color? color) - { - if (!ChunkIndex.TryGetValue(gridId, out var values) || !values.TryGetValue(uid, out var indices)) - { - return false; - } - - var chunkCollection = ChunkCollection(gridId); - if (chunkCollection == null) - return false; - - var chunk = chunkCollection[indices]; - var decal = chunk.Decals[uid]; - chunk.Decals[uid] = decal.WithColor(color); + var chunk = comp.ChunkCollection.ChunkCollection[indices]; + var decal = chunk.Decals[decalId]; + chunk.Decals[decalId] = modifyDecal(decal); DirtyChunk(gridId, indices, chunk); return true; } - public bool SetDecalId(EntityUid gridId, uint uid, string id) - { - if (!ChunkIndex.TryGetValue(gridId, out var values) || !values.TryGetValue(uid, out var indices)) - { - return false; - } + public bool SetDecalColor(EntityUid gridId, uint decalId, Color? value, DecalGridComponent? comp = null) + => ModifyDecal(gridId, decalId, x => x.WithColor(value), comp); + public bool SetDecalRotation(EntityUid gridId, uint decalId, Angle value, DecalGridComponent? comp = null) + => ModifyDecal(gridId, decalId, x => x.WithRotation(value), comp); + + public bool SetDecalZIndex(EntityUid gridId, uint decalId, int value, DecalGridComponent? comp = null) + => ModifyDecal(gridId, decalId, x => x.WithZIndex(value), comp); + + public bool SetDecalCleanable(EntityUid gridId, uint decalId, bool value, DecalGridComponent? comp = null) + => ModifyDecal(gridId, decalId, x => x.WithCleanable(value), comp); + + public bool SetDecalId(EntityUid gridId, uint decalId, string id, DecalGridComponent? comp = null) + { if (!PrototypeManager.HasIndex(id)) throw new ArgumentOutOfRangeException($"Tried to set decal id to invalid prototypeid: {id}"); - var chunkCollection = ChunkCollection(gridId); - if (chunkCollection == null) - return false; - - var chunk = chunkCollection[indices]; - var decal = chunk.Decals[uid]; - chunk.Decals[uid] = decal.WithId(id); - DirtyChunk(gridId, indices , chunk); - return true; - } - - public bool SetDecalRotation(EntityUid gridId, uint uid, Angle angle) - { - if (!ChunkIndex.TryGetValue(gridId, out var values) || !values.TryGetValue(uid, out var indices)) - { - return false; - } - - var chunkCollection = ChunkCollection(gridId); - if (chunkCollection == null) - return false; - - var chunk = chunkCollection[indices]; - var decal = chunk.Decals[uid]; - chunk.Decals[uid] = decal.WithRotation(angle); - DirtyChunk(gridId, indices, chunk); - return true; - } - - public bool SetDecalZIndex(EntityUid gridId, uint uid, int zIndex) - { - if (!ChunkIndex.TryGetValue(gridId, out var values) || !values.TryGetValue(uid, out var indices)) - { - return false; - } - - var chunkCollection = ChunkCollection(gridId); - if (chunkCollection == null) - return false; - - var chunk = chunkCollection[indices]; - var decal = chunk.Decals[uid]; - chunk.Decals[uid] = decal.WithZIndex(zIndex); - DirtyChunk(gridId, indices, chunk); - return true; - } - - public bool SetDecalCleanable(EntityUid gridId, uint uid, bool cleanable) - { - if (!ChunkIndex.TryGetValue(gridId, out var values) || !values.TryGetValue(uid, out var indices)) - { - return false; - } - - var chunkCollection = ChunkCollection(gridId); - if (chunkCollection == null) - return false; - - var chunk = chunkCollection[indices]; - var decal = chunk.Decals[uid]; - chunk.Decals[uid] = decal.WithCleanable(cleanable); - DirtyChunk(gridId, indices, chunk); - return true; + return ModifyDecal(gridId, decalId, x => x.WithId(id), comp); } public override void Update(float frameTime) diff --git a/Content.Shared/Decals/DecalGridChunkCollectionTypeSerializer.cs b/Content.Shared/Decals/DecalGridChunkCollectionTypeSerializer.cs index 3c72be4298..af5bf3adc8 100644 --- a/Content.Shared/Decals/DecalGridChunkCollectionTypeSerializer.cs +++ b/Content.Shared/Decals/DecalGridChunkCollectionTypeSerializer.cs @@ -51,7 +51,7 @@ namespace Content.Shared.Decals newDict[indices].Decals[newUid] = dictionary[indices].Decals[oldUid]; } - return new DecalGridComponent.DecalGridChunkCollection(newDict){NextUid = nextIndex}; + return new DecalGridComponent.DecalGridChunkCollection(newDict){NextDecalId = nextIndex}; } public DataNode Write(ISerializationManager serializationManager, diff --git a/Content.Shared/Decals/DecalGridComponent.cs b/Content.Shared/Decals/DecalGridComponent.cs index c4ea6cdc1d..32273e76f8 100644 --- a/Content.Shared/Decals/DecalGridComponent.cs +++ b/Content.Shared/Decals/DecalGridComponent.cs @@ -15,11 +15,20 @@ namespace Content.Shared.Decals [DataField("chunkCollection", serverOnly: true)] public DecalGridChunkCollection ChunkCollection = new(new ()); + /// + /// Dictionary mapping decals to their corresponding grid chunks. + /// + public readonly Dictionary DecalIndex = new(); + /// /// Tick at which PVS was last toggled. Ensures that all players receive a full update when toggling PVS. /// 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 class DecalChunk @@ -51,7 +60,7 @@ namespace Content.Shared.Decals [DataRecord, Serializable, NetSerializable] public record DecalGridChunkCollection(Dictionary ChunkCollection) { - public uint NextUid; + public uint NextDecalId; } } diff --git a/Content.Shared/Decals/SharedDecalSystem.cs b/Content.Shared/Decals/SharedDecalSystem.cs index 5c1c86a43e..7043a7b396 100644 --- a/Content.Shared/Decals/SharedDecalSystem.cs +++ b/Content.Shared/Decals/SharedDecalSystem.cs @@ -11,9 +11,6 @@ namespace Content.Shared.Decals [Dependency] protected readonly IPrototypeManager PrototypeManager = default!; [Dependency] protected readonly IMapManager MapManager = default!; - // TODO move this data to the component - protected readonly Dictionary> ChunkIndex = new(); - // Note that this constant is effectively baked into all map files, because of how they save the grid decal component. // So if this ever needs changing, the maps need converting. public const int ChunkSize = 32; @@ -24,78 +21,61 @@ namespace Content.Shared.Decals base.Initialize(); SubscribeLocalEvent(OnGridInitialize); - SubscribeLocalEvent(OnCompAdd); SubscribeLocalEvent(OnCompStartup); - SubscribeLocalEvent(OnCompRemove); } private void OnGridInitialize(GridInitializeEvent msg) { EnsureComp(msg.EntityUid); } - - protected virtual void OnCompRemove(EntityUid uid, DecalGridComponent component, ComponentRemove args) - { - ChunkIndex.Remove(uid); - } - - protected virtual void OnCompAdd(EntityUid uid, DecalGridComponent component, ComponentAdd args) - { - ChunkIndex[uid] = new(); - } - + private void OnCompStartup(EntityUid uid, DecalGridComponent component, ComponentStartup args) { - var index = ChunkIndex[uid]; foreach (var (indices, decals) in component.ChunkCollection.ChunkCollection) { foreach (var decalUid in decals.Decals.Keys) { - index[decalUid] = indices; + component.DecalIndex[decalUid] = indices; } } } - protected DecalGridChunkCollection? DecalGridChunkCollection(EntityUid gridEuid, DecalGridComponent? comp = null) + protected Dictionary? ChunkCollection(EntityUid gridEuid, DecalGridComponent? comp = null) { if (!Resolve(gridEuid, ref comp)) return null; - return comp.ChunkCollection; - } - - protected Dictionary? ChunkCollection(EntityUid gridEuid, DecalGridComponent? comp = null) - { - var collection = DecalGridChunkCollection(gridEuid, comp); - return collection?.ChunkCollection; + return comp.ChunkCollection.ChunkCollection; } protected virtual void DirtyChunk(EntityUid id, Vector2i chunkIndices, DecalChunk chunk) {} - protected bool RemoveDecalInternal(EntityUid gridId, uint uid) + // internal, so that client/predicted code doesn't accidentally remove decals. There is a public server-side function. + protected bool RemoveDecalInternal(EntityUid gridId, uint decalId, [NotNullWhen(true)] out Decal? removed, DecalGridComponent? component = null) { - if (!RemoveDecalHook(gridId, uid)) return false; - - if (!ChunkIndex.TryGetValue(gridId, out var values) || !values.TryGetValue(uid, out var indices)) - { + removed = null; + if (!Resolve(gridId, ref component)) return false; - } - var chunkCollection = ChunkCollection(gridId); - if (chunkCollection == null || !chunkCollection.TryGetValue(indices, out var chunk) || !chunk.Decals.Remove(uid)) + if (!component.DecalIndex.Remove(decalId, out var indices) + || !component.ChunkCollection.ChunkCollection.TryGetValue(indices, out var chunk) + || !chunk.Decals.Remove(decalId, out removed)) { return false; } if (chunk.Decals.Count == 0) - chunkCollection.Remove(indices); + component.ChunkCollection.ChunkCollection.Remove(indices); - ChunkIndex[gridId].Remove(uid); DirtyChunk(gridId, indices, chunk); + OnDecalRemoved(gridId, decalId, component, indices, chunk); return true; } - protected virtual bool RemoveDecalHook(EntityUid gridId, uint uid) => true; + protected virtual void OnDecalRemoved(EntityUid gridId, uint decalId, DecalGridComponent component, Vector2i indices, DecalChunk chunk) + { + // used by client-side overlay code + } } // TODO: Pretty sure paul was moving this somewhere but just so people know