Skip to content

Commit

Permalink
Minor PVS stuff (#4573)
Browse files Browse the repository at this point in the history
Co-authored-by: ElectroJr <[email protected]>
  • Loading branch information
metalgearsloth and ElectroJr authored Nov 22, 2023
1 parent b459d2c commit f69440b
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 26 deletions.
68 changes: 45 additions & 23 deletions Robust.Server/GameStates/PvsSystem.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Numerics;
using System.Runtime.InteropServices;
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -433,10 +435,15 @@ private void OnMapCreated(MapChangedEvent e)

#endregion

public (List<(int, IChunkIndexLocation)> , HashSet<int>[], EntityUid[][] viewers) GetChunks(ICommonSession[] sessions)
public List<(int, IChunkIndexLocation)> GetChunks(
ICommonSession[] sessions,
ref HashSet<int>[] playerChunks,
ref EntityUid[][] viewerEntities)
{
var playerChunks = new HashSet<int>[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.
Expand All @@ -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++)
{
Expand Down Expand Up @@ -552,7 +559,7 @@ private void OnMapCreated(MapChangedEvent e)
}
}

return (_chunkList, playerChunks, viewerEntities);
return _chunkList;
}

public void RegisterNewPreviousChunkTrees(
Expand All @@ -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);
Expand Down Expand Up @@ -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<EntityUid>();
{
viewers = Array.Empty<EntityUid>();
return;
}

// Fast path
if (session.ViewSubscriptions.Count == 0)
{
if (session.AttachedEntity == null)
return Array.Empty<EntityUid>();
{
viewers = Array.Empty<EntityUid>();
return;
}

return new[] { session.AttachedEntity.Value };
Array.Resize(ref viewers, 1);
viewers[0] = session.AttachedEntity.Value;
return;
}

var viewers = new HashSet<EntityUid>();
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
Expand Down
9 changes: 6 additions & 3 deletions Robust.Server/GameStates/ServerGameStateManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<int>[] _playerChunks = Array.Empty<HashSet<int>>();
private EntityUid[][] _viewerEntities = Array.Empty<EntityUid[]>();

private PvsSystem _pvs = default!;

[Dependency] private readonly EntityManager _entityManager = default!;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -310,8 +313,8 @@ private struct PvsData
ArrayPool<bool>.Shared.Return(reuse);
return new PvsData()
{
PlayerChunks = playerChunks,
ViewerEntities = viewerEntities,
PlayerChunks = _playerChunks,
ViewerEntities = _viewerEntities,
ChunkCache = chunkCache,
};
}
Expand Down

0 comments on commit f69440b

Please sign in to comment.