Decal state handling (#12624)
This commit is contained in:
@@ -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<DecalGridComponent, ComponentHandleState>(OnHandleState);
|
||||
SubscribeNetworkEvent<DecalChunkUpdateEvent>(OnChunkUpdate);
|
||||
SubscribeLocalEvent<GridInitializeEvent>(OnGridInitialize);
|
||||
SubscribeLocalEvent<GridRemovalEvent>(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<Vector2i>();
|
||||
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<uint>(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<Vector2i, DecalChunk> 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<uint>(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<Vector2i> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,9 +122,9 @@ namespace Content.MapRenderer.Painters
|
||||
// for some reason decal moment i guess.
|
||||
if (_sEntityManager.TryGetComponent<DecalGridComponent>(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));
|
||||
|
||||
@@ -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<EntityUid, HashSet<Vector2i>> _dirtyChunks = new();
|
||||
@@ -36,6 +42,7 @@ namespace Content.Server.Decals
|
||||
private ObjectPool<Dictionary<EntityUid, HashSet<Vector2i>>> _chunkViewerPool =
|
||||
new DefaultObjectPool<Dictionary<EntityUid, HashSet<Vector2i>>>(
|
||||
new DefaultPooledObjectPolicy<Dictionary<EntityUid, HashSet<Vector2i>>>(), 64);
|
||||
private bool _pvsEnabled;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -43,10 +50,57 @@ namespace Content.Server.Decals
|
||||
|
||||
_playerManager.PlayerStatusChanged += OnPlayerStatusChanged;
|
||||
SubscribeLocalEvent<TileChangedEvent>(OnTileChanged);
|
||||
SubscribeLocalEvent<DecalGridComponent, ComponentGetState>(OnGetState);
|
||||
|
||||
SubscribeNetworkEvent<RequestDecalPlacementEvent>(OnDecalPlacementRequest);
|
||||
SubscribeNetworkEvent<RequestDecalRemovalEvent>(OnDecalRemovalRequest);
|
||||
SubscribeLocalEvent<PostGridSplitEvent>(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<DecalGridComponent, MetaDataComponent>(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<Vector2i, DecalChunk>();
|
||||
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<uint>();
|
||||
|
||||
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<uint>();
|
||||
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<Vector2i>();
|
||||
_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<EntityUid, HashSet<Vector2i>> updatedChunks,
|
||||
Dictionary<EntityUid, HashSet<Vector2i>> staleChunks)
|
||||
{
|
||||
var updatedDecals = new Dictionary<EntityUid, Dictionary<Vector2i, Dictionary<uint, Decal>>>();
|
||||
var updatedDecals = new Dictionary<EntityUid, Dictionary<Vector2i, DecalChunk>>();
|
||||
foreach (var (gridId, chunks) in updatedChunks)
|
||||
{
|
||||
var collection = ChunkCollection(gridId);
|
||||
if (collection == null)
|
||||
continue;
|
||||
|
||||
var gridChunks = new Dictionary<Vector2i, Dictionary<uint, Decal>>();
|
||||
var gridChunks = new Dictionary<Vector2i, DecalChunk>();
|
||||
foreach (var indices in chunks)
|
||||
{
|
||||
gridChunks.Add(indices,
|
||||
collection.TryGetValue(indices, out var chunk)
|
||||
? chunk
|
||||
: new Dictionary<uint, Decal>(0));
|
||||
: new());
|
||||
}
|
||||
updatedDecals[gridId] = gridChunks;
|
||||
}
|
||||
|
||||
@@ -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() {}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user