Decal state handling (#12624)

This commit is contained in:
Leon Friedrich
2022-12-19 08:28:46 +13:00
committed by GitHub
parent 2759ef009e
commit 8f352f87c2
8 changed files with 312 additions and 99 deletions

View File

@@ -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() {}

View File

@@ -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<EntityUid, Dictionary<Vector2i, Dictionary<uint, Decal>>> Data = new();
public Dictionary<EntityUid, Dictionary<Vector2i, DecalChunk>> Data = new();
public Dictionary<EntityUid, HashSet<Vector2i>> RemovedChunks = new();
}
}

View File

@@ -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<DecalGridComponent.DecalGridChunkCollection>? _ = default)
{
var dictionary = serializationManager.Read<Dictionary<Vector2i, Dictionary<uint, Decal>>>(node, context, skipHook, notNullableOverride: true);
var dictionary = serializationManager.Read<Dictionary<Vector2i, DecalChunk>>(node, context, skipHook: skipHook, notNullableOverride: true);
var uids = new SortedSet<uint>();
var uidChunkMap = new Dictionary<uint, Vector2i>();
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<Vector2i, Dictionary<uint, Decal>>();
var newDict = new Dictionary<Vector2i, DecalChunk>();
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};

View File

@@ -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<Vector2i, Dictionary<uint, Decal>> ChunkCollection)
/// <summary>
/// Tick at which PVS was last toggled. Ensures that all players receive a full update when toggling PVS.
/// </summary>
public GameTick ForceTick { get; set; }
[DataDefinition]
[Serializable, NetSerializable]
public sealed class DecalChunk
{
[DataField("decals")]
public Dictionary<uint, Decal> Decals;
[NonSerialized]
public GameTick LastModified;
public DecalChunk()
{
Decals = new();
}
public DecalChunk(Dictionary<uint, Decal> 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<Vector2i, DecalChunk> ChunkCollection)
{
public uint NextUid;
}
}
[Serializable, NetSerializable]
public sealed class DecalGridState : ComponentState, IComponentDeltaState
{
public Dictionary<Vector2i, DecalChunk> Chunks;
public bool FullState => AllChunks == null;
// required to infer deleted/missing chunks for delta states
public HashSet<Vector2i>? AllChunks;
public DecalGridState(Dictionary<Vector2i, DecalChunk> 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<Vector2i, DecalChunk>(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);
}
}
}

View File

@@ -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<Vector2i, Dictionary<uint, Decal>>? ChunkCollection(EntityUid gridEuid, DecalGridComponent? comp = null)
protected Dictionary<Vector2i, DecalChunk>? 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;
}