Fix decals (finally) (#7771)

This commit is contained in:
metalgearsloth
2022-04-28 20:23:43 +10:00
committed by GitHub
parent c2b4a4acef
commit 77bd892bbd
6 changed files with 114 additions and 35 deletions

View File

@@ -45,6 +45,8 @@ namespace Content.Client.Decals
foreach (var (gridId, zIndexDictionary) in _decals.DecalRenderIndex) foreach (var (gridId, zIndexDictionary) in _decals.DecalRenderIndex)
{ {
if (zIndexDictionary.Count == 0) continue;
var gridUid = _mapManager.GetGridEuid(gridId); var gridUid = _mapManager.GetGridEuid(gridId);
var xform = xformQuery.GetComponent(gridUid); var xform = xformQuery.GetComponent(gridUid);

View File

@@ -61,7 +61,6 @@ namespace Content.Client.Decals
protected override bool RemoveDecalHook(GridId gridId, uint uid) protected override bool RemoveDecalHook(GridId gridId, uint uid)
{ {
RemoveDecalFromRenderIndex(gridId, uid); RemoveDecalFromRenderIndex(gridId, uid);
return base.RemoveDecalHook(gridId, uid); return base.RemoveDecalHook(gridId, uid);
} }
@@ -80,8 +79,11 @@ namespace Content.Client.Decals
{ {
foreach (var (gridId, gridChunks) in ev.Data) foreach (var (gridId, gridChunks) in ev.Data)
{ {
if (gridChunks.Count == 0) continue;
var chunkCollection = ChunkCollection(gridId); var chunkCollection = ChunkCollection(gridId);
// Update any existing data / remove decals we didn't receive data for.
foreach (var (indices, newChunkData) in gridChunks) foreach (var (indices, newChunkData) in gridChunks)
{ {
if (chunkCollection.TryGetValue(indices, out var chunk)) if (chunkCollection.TryGetValue(indices, out var chunk))
@@ -90,8 +92,14 @@ namespace Content.Client.Decals
removedUids.ExceptWith(newChunkData.Keys); removedUids.ExceptWith(newChunkData.Keys);
foreach (var removedUid in removedUids) 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) foreach (var (uid, decal) in newChunkData)
@@ -107,25 +115,27 @@ namespace Content.Client.Decals
DecalRenderIndex[gridId][decal.ZIndex][uid] = decal; DecalRenderIndex[gridId][decal.ZIndex][uid] = decal;
DecalZIndexIndex[gridId][uid] = decal.ZIndex; DecalZIndexIndex[gridId][uid] = decal.ZIndex;
ChunkIndex[gridId][uid] = indices; 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. // Now we'll cull old chunks out of range as the server will send them to us anyway.
var toRemove = new RemQueue<Vector2i>(); foreach (var (gridId, chunks) in ev.RemovedChunks)
foreach (var (index, _) in chunkCollection)
{ {
if (gridChunks.ContainsKey(index)) continue; if (chunks.Count == 0) continue;
toRemove.Add(index); var chunkCollection = ChunkCollection(gridId);
foreach (var index in chunks)
{
if (!chunkCollection.TryGetValue(index, out var chunk)) continue;
foreach (var (uid, _) in chunk)
{
RemoveDecalInternal(gridId, uid);
} }
foreach (var index in toRemove)
{
chunkCollection.Remove(index); chunkCollection.Remove(index);
} }
} }

View File

@@ -44,7 +44,7 @@ namespace Content.Server.Chemistry.TileReactions
} }
var decalSystem = EntitySystem.Get<DecalSystem>(); var decalSystem = EntitySystem.Get<DecalSystem>();
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); decalSystem.RemoveDecal(tile.GridIndex, uid);
} }

View File

@@ -8,6 +8,7 @@ using Robust.Server.Player;
using Robust.Shared.Enums; using Robust.Shared.Enums;
using Robust.Shared.Map; using Robust.Shared.Map;
using Robust.Shared.Player; using Robust.Shared.Player;
using Robust.Shared.Utility;
namespace Content.Server.Decals namespace Content.Server.Decals
{ {
@@ -42,6 +43,52 @@ namespace Content.Server.Decals
SubscribeNetworkEvent<RequestDecalPlacementEvent>(OnDecalPlacementRequest); SubscribeNetworkEvent<RequestDecalPlacementEvent>(OnDecalPlacementRequest);
SubscribeNetworkEvent<RequestDecalRemovalEvent>(OnDecalRemovalRequest); SubscribeNetworkEvent<RequestDecalRemovalEvent>(OnDecalRemovalRequest);
SubscribeLocalEvent<PostGridSplitEvent>(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<uint>();
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() public override void Shutdown()
@@ -127,9 +174,10 @@ namespace Content.Server.Decals
return; return;
// remove all decals on the same tile // 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; return false;
var gridId = coordinates.GetGridId(EntityManager); var gridId = coordinates.GetGridId(EntityManager);
if (!gridId.IsValid()) if (!MapManager.TryGetGrid(gridId, out var grid))
return false; return false;
if (MapManager.GetGrid(gridId).GetTileRef(coordinates).IsSpace()) if (grid.GetTileRef(coordinates).IsSpace(_tileDefMan))
return false; return false;
var chunkCollection = DecalGridChunkCollection(gridId); var chunkCollection = DecalGridChunkCollection(gridId);
@@ -178,9 +226,9 @@ namespace Content.Server.Decals
public bool RemoveDecal(GridId gridId, uint uid) => RemoveDecalInternal(gridId, uid); public bool RemoveDecal(GridId gridId, uint uid) => RemoveDecalInternal(gridId, uid);
public HashSet<uint> GetDecalsInRange(GridId gridId, Vector2 position, float distance = 0.75f, Func<Decal, bool>? validDelegate = null) public HashSet<(uint Index, Decal Decal)> GetDecalsInRange(GridId gridId, Vector2 position, float distance = 0.75f, Func<Decal, bool>? validDelegate = null)
{ {
var uids = new HashSet<uint>(); var uids = new HashSet<(uint, Decal)>();
var chunkCollection = ChunkCollection(gridId); var chunkCollection = ChunkCollection(gridId);
var chunkIndices = GetChunkIndices(position); var chunkIndices = GetChunkIndices(position);
if (!chunkCollection.TryGetValue(chunkIndices, out var chunk)) if (!chunkCollection.TryGetValue(chunkIndices, out var chunk))
@@ -193,7 +241,7 @@ namespace Content.Server.Decals
if (validDelegate == null || validDelegate(decal)) if (validDelegate == null || validDelegate(decal))
{ {
uids.Add(uid); uids.Add((uid, decal));
} }
} }
@@ -310,15 +358,33 @@ namespace Content.Server.Decals
{ {
base.Update(frameTime); base.Update(frameTime);
foreach (var session in Filter.GetAllPlayers(_playerManager)) foreach (var session in Filter.GetAllPlayers(_playerManager))
{ {
if (session is not IPlayerSession { Status: SessionStatus.InGame } playerSession) if (session is not IPlayerSession { Status: SessionStatus.InGame } playerSession)
continue; continue;
var chunks = GetChunksForSession(playerSession); var chunksInRange = GetChunksForSession(playerSession);
var staleChunks = new Dictionary<GridId, HashSet<Vector2i>>();
// 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(); var updatedChunks = _chunkViewerPool.Get();
foreach (var (gridId, gridChunks) in chunks) foreach (var (gridId, gridChunks) in chunksInRange)
{ {
var newChunks = _chunkIndexPool.Get(); var newChunks = _chunkIndexPool.Get();
newChunks.UnionWith(gridChunks); newChunks.UnionWith(gridChunks);
@@ -344,17 +410,18 @@ namespace Content.Server.Decals
if (updatedChunks.Count == 0) 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. // Even if updatedChunks is empty we'll still return it to the pool as it may have been allocated higher.
ReturnToPool(updatedChunks); ReturnToPool(updatedChunks);
continue;
} }
if (updatedChunks.Count == 0 && staleChunks.Count == 0) continue;
ReturnToPool(_previousSentChunks[playerSession]); ReturnToPool(_previousSentChunks[playerSession]);
_previousSentChunks[playerSession] = chunks; _previousSentChunks[playerSession] = chunksInRange;
//send all gridChunks to client //send all gridChunks to client
SendChunkUpdates(playerSession, updatedChunks); SendChunkUpdates(playerSession, updatedChunks, staleChunks);
} }
_dirtyChunks.Clear(); _dirtyChunks.Clear();
@@ -372,7 +439,10 @@ namespace Content.Server.Decals
_chunkViewerPool.Return(chunks); _chunkViewerPool.Return(chunks);
} }
private void SendChunkUpdates(IPlayerSession session, Dictionary<GridId, HashSet<Vector2i>> updatedChunks) private void SendChunkUpdates(
IPlayerSession session,
Dictionary<GridId, HashSet<Vector2i>> updatedChunks,
Dictionary<GridId, HashSet<Vector2i>> staleChunks)
{ {
var updatedDecals = new Dictionary<GridId, Dictionary<Vector2i, Dictionary<uint, Decal>>>(); var updatedDecals = new Dictionary<GridId, Dictionary<Vector2i, Dictionary<uint, Decal>>>();
foreach (var (gridId, chunks) in updatedChunks) foreach (var (gridId, chunks) in updatedChunks)
@@ -388,7 +458,7 @@ namespace Content.Server.Decals
updatedDecals[gridId] = gridChunks; updatedDecals[gridId] = gridChunks;
} }
RaiseNetworkEvent(new DecalChunkUpdateEvent{Data = updatedDecals}, Filter.SinglePlayer(session)); RaiseNetworkEvent(new DecalChunkUpdateEvent{Data = updatedDecals, RemovedChunks = staleChunks}, Filter.SinglePlayer(session));
} }
private HashSet<EntityUid> GetSessionViewers(IPlayerSession session) private HashSet<EntityUid> GetSessionViewers(IPlayerSession session)

View File

@@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using Robust.Shared.GameObjects;
using Robust.Shared.Map; using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
namespace Content.Shared.Decals namespace Content.Shared.Decals
@@ -11,5 +7,6 @@ namespace Content.Shared.Decals
public sealed class DecalChunkUpdateEvent : EntityEventArgs public sealed class DecalChunkUpdateEvent : EntityEventArgs
{ {
public Dictionary<GridId, Dictionary<Vector2i, Dictionary<uint, Decal>>> Data = new(); public Dictionary<GridId, Dictionary<Vector2i, Dictionary<uint, Decal>>> Data = new();
public Dictionary<GridId, HashSet<Vector2i>> RemovedChunks = new();
} }
} }

View File

@@ -79,7 +79,7 @@ namespace Content.Shared.Decals
if (chunkCollection[indices].Count == 0) if (chunkCollection[indices].Count == 0)
chunkCollection.Remove(indices); chunkCollection.Remove(indices);
ChunkIndex[gridId]?.Remove(uid); ChunkIndex[gridId].Remove(uid);
DirtyChunk(gridId, indices); DirtyChunk(gridId, indices);
return true; return true;
} }