From f69440b3f25873bc50813d17a467c78ab7706b9e Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Wed, 22 Nov 2023 21:54:07 +1100 Subject: [PATCH] Minor PVS stuff (#4573) Co-authored-by: ElectroJr --- Robust.Server/GameStates/PvsSystem.cs | 68 ++++++++++++------- .../GameStates/ServerGameStateManager.cs | 9 ++- 2 files changed, 51 insertions(+), 26 deletions(-) diff --git a/Robust.Server/GameStates/PvsSystem.cs b/Robust.Server/GameStates/PvsSystem.cs index a70d164588f..36597913ac9 100644 --- a/Robust.Server/GameStates/PvsSystem.cs +++ b/Robust.Server/GameStates/PvsSystem.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Numerics; using System.Runtime.InteropServices; @@ -271,6 +272,7 @@ private void OnEntityDeleted(EntityUid e, MetaDataComponent metadata) { sessionData.LastSeenAt.Remove(metadata.NetEntity); sessionData.LastLeftView.Remove(metadata.NetEntity); + if (sessionData.SentEntities.TryGetValue(previousTick, out var ents)) ents.Remove(metadata.NetEntity); } @@ -433,10 +435,15 @@ private void OnMapCreated(MapChangedEvent e) #endregion - public (List<(int, IChunkIndexLocation)> , HashSet[], EntityUid[][] viewers) GetChunks(ICommonSession[] sessions) + public List<(int, IChunkIndexLocation)> GetChunks( + ICommonSession[] sessions, + ref HashSet[] playerChunks, + ref EntityUid[][] viewerEntities) { - var playerChunks = new HashSet[sessions.Length]; - var viewerEntities = new EntityUid[sessions.Length][]; + // Pass these in to avoid allocating new ones every tick, 99% of the time sessions length is going to be the same size. + // These values will get overridden here and the old values have already been returned to the pool by this point. + Array.Resize(ref playerChunks, sessions.Length); + Array.Resize(ref viewerEntities, sessions.Length); _chunkList.Clear(); // Keep track of the index of each chunk we use for a faster index lookup. @@ -459,8 +466,8 @@ private void OnMapCreated(MapChangedEvent e) var session = sessions[i]; playerChunks[i] = _playerChunkPool.Get(); - var viewers = GetSessionViewers(session); - viewerEntities[i] = viewers; + ref var viewers = ref viewerEntities[i]; + GetSessionViewers(session, ref viewers); for (var j = 0; j < viewers.Length; j++) { @@ -552,7 +559,7 @@ private void OnMapCreated(MapChangedEvent e) } } - return (_chunkList, playerChunks, viewerEntities); + return _chunkList; } public void RegisterNewPreviousChunkTrees( @@ -569,23 +576,20 @@ public void RegisterNewPreviousChunkTrees( _reusedTrees.Add(chunks[i]); } - var previousIndices = _previousTrees.Keys.ToArray(); - for (var i = 0; i < previousIndices.Length; i++) + foreach (var (index, chunk) in _previousTrees) { - var index = previousIndices[i]; // ReSharper disable once InconsistentlySynchronizedField - if (_reusedTrees.Contains(index)) continue; - var chunk = _previousTrees[index]; - if (chunk.HasValue) + if (_reusedTrees.Contains(index)) + continue; + + if (chunk != null) { _chunkCachePool.Return(chunk.Value.metadata); _treePool.Return(chunk.Value.tree); } if (!chunks.Contains(index)) - { _previousTrees.Remove(index); - } } _previousTrees.EnsureCapacity(chunks.Count); @@ -1313,26 +1317,44 @@ private EntityState GetFullEntityState(ICommonSession player, EntityUid entityUi return entState; } - private EntityUid[] GetSessionViewers(ICommonSession session) + private void GetSessionViewers(ICommonSession session, [NotNull] ref EntityUid[]? viewers) { if (session.Status != SessionStatus.InGame) - return Array.Empty(); + { + viewers = Array.Empty(); + return; + } // Fast path if (session.ViewSubscriptions.Count == 0) { if (session.AttachedEntity == null) - return Array.Empty(); + { + viewers = Array.Empty(); + return; + } - return new[] { session.AttachedEntity.Value }; + Array.Resize(ref viewers, 1); + viewers[0] = session.AttachedEntity.Value; + return; } - var viewers = new HashSet(); - if (session.AttachedEntity != null) - viewers.Add(session.AttachedEntity.Value); + int i = 0; + if (session.AttachedEntity is { } local) + { + DebugTools.Assert(!session.ViewSubscriptions.Contains(local)); + Array.Resize(ref viewers, session.ViewSubscriptions.Count + 1); + viewers[i++] = local; + } + else + { + Array.Resize(ref viewers, session.ViewSubscriptions.Count); + } - viewers.UnionWith(session.ViewSubscriptions); - return viewers.ToArray(); + foreach (var ent in session.ViewSubscriptions) + { + viewers[i++] = ent; + } } // Read Safe diff --git a/Robust.Server/GameStates/ServerGameStateManager.cs b/Robust.Server/GameStates/ServerGameStateManager.cs index 1f1db6a3ce3..2e04bdb675e 100644 --- a/Robust.Server/GameStates/ServerGameStateManager.cs +++ b/Robust.Server/GameStates/ServerGameStateManager.cs @@ -37,6 +37,9 @@ public sealed class ServerGameStateManager : IServerGameStateManager, IPostInjec // Mapping of net UID of clients -> last known acked state. private GameTick _lastOldestAck = GameTick.Zero; + private HashSet[] _playerChunks = Array.Empty>(); + private EntityUid[][] _viewerEntities = Array.Empty(); + private PvsSystem _pvs = default!; [Dependency] private readonly EntityManager _entityManager = default!; @@ -267,7 +270,7 @@ private struct PvsData private PvsData? GetPVSData(ICommonSession[] players) { - var (chunks, playerChunks, viewerEntities) = _pvs.GetChunks(players); + var chunks= _pvs.GetChunks(players, ref _playerChunks, ref _viewerEntities); const int ChunkBatchSize = 2; var chunksCount = chunks.Count; var chunkBatches = (int)MathF.Ceiling((float)chunksCount / ChunkBatchSize); @@ -310,8 +313,8 @@ private struct PvsData ArrayPool.Shared.Return(reuse); return new PvsData() { - PlayerChunks = playerChunks, - ViewerEntities = viewerEntities, + PlayerChunks = _playerChunks, + ViewerEntities = _viewerEntities, ChunkCache = chunkCache, }; }