Parallelize gas and decal systems. (#12349)
This commit is contained in:
@@ -1,4 +1,3 @@
|
|||||||
using System.Runtime.CompilerServices;
|
|
||||||
using Content.Server.Atmos.Components;
|
using Content.Server.Atmos.Components;
|
||||||
using Content.Shared.Atmos;
|
using Content.Shared.Atmos;
|
||||||
using Content.Shared.Atmos.EntitySystems;
|
using Content.Shared.Atmos.EntitySystems;
|
||||||
@@ -12,9 +11,12 @@ using Robust.Server.Player;
|
|||||||
using Robust.Shared.Configuration;
|
using Robust.Shared.Configuration;
|
||||||
using Robust.Shared.Enums;
|
using Robust.Shared.Enums;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Threading;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using DependencyAttribute = Robust.Shared.IoC.DependencyAttribute;
|
using DependencyAttribute = Robust.Shared.IoC.DependencyAttribute;
|
||||||
|
|
||||||
// ReSharper disable once RedundantUsingDirective
|
// ReSharper disable once RedundantUsingDirective
|
||||||
@@ -28,6 +30,7 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||||
[Dependency] private readonly IConfigurationManager _confMan = default!;
|
[Dependency] private readonly IConfigurationManager _confMan = default!;
|
||||||
|
[Dependency] private readonly IParallelManager _parMan = default!;
|
||||||
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
|
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
|
||||||
[Dependency] private readonly ChunkingSystem _chunkingSys = default!;
|
[Dependency] private readonly ChunkingSystem _chunkingSys = default!;
|
||||||
|
|
||||||
@@ -96,30 +99,22 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
{
|
{
|
||||||
if (e.NewStatus != SessionStatus.InGame)
|
if (e.NewStatus != SessionStatus.InGame)
|
||||||
{
|
{
|
||||||
if (_lastSentChunks.Remove(e.Session, out var set))
|
if (_lastSentChunks.Remove(e.Session, out var sets))
|
||||||
ReturnToPool(set);
|
{
|
||||||
return;
|
foreach (var set in sets.Values)
|
||||||
|
{
|
||||||
|
set.Clear();
|
||||||
|
_chunkIndexPool.Return(set);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_lastSentChunks.ContainsKey(e.Session))
|
if (!_lastSentChunks.ContainsKey(e.Session))
|
||||||
{
|
{
|
||||||
_lastSentChunks[e.Session] = _chunkViewerPool.Get();
|
_lastSentChunks[e.Session] = new();
|
||||||
DebugTools.Assert(_lastSentChunks[e.Session].Count == 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ReturnToPool(Dictionary<EntityUid, HashSet<Vector2i>> chunks)
|
|
||||||
{
|
|
||||||
foreach (var (_, previous) in chunks)
|
|
||||||
{
|
|
||||||
previous.Clear();
|
|
||||||
_chunkIndexPool.Return(previous);
|
|
||||||
}
|
|
||||||
|
|
||||||
chunks.Clear();
|
|
||||||
_chunkViewerPool.Return(chunks);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates the visuals for a tile on some grid chunk.
|
/// Updates the visuals for a tile on some grid chunk.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -164,6 +159,7 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
|
|
||||||
private void UpdateOverlayData(GameTick curTick)
|
private void UpdateOverlayData(GameTick curTick)
|
||||||
{
|
{
|
||||||
|
// TODO parallelize?
|
||||||
foreach (var (gridId, invalidIndices) in _invalidTiles)
|
foreach (var (gridId, invalidIndices) in _invalidTiles)
|
||||||
{
|
{
|
||||||
if (!TryComp(gridId, out GridAtmosphereComponent? gam))
|
if (!TryComp(gridId, out GridAtmosphereComponent? gam))
|
||||||
@@ -203,24 +199,16 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
// Now we'll go through each player, then through each chunk in range of that player checking if the player is still in range
|
// Now we'll go through each player, then through each chunk in range of that player checking if the player is still in range
|
||||||
// If they are, check if they need the new data to send (i.e. if there's an overlay for the gas).
|
// If they are, check if they need the new data to send (i.e. if there's an overlay for the gas).
|
||||||
// Afterwards we reset all the chunk data for the next time we tick.
|
// Afterwards we reset all the chunk data for the next time we tick.
|
||||||
|
var players = _playerManager.ServerSessions.Where(x => x.Status == SessionStatus.InGame).ToArray();
|
||||||
|
var opts = new ParallelOptions { MaxDegreeOfParallelism = _parMan.ParallelProcessCount };
|
||||||
|
Parallel.ForEach(players, opts, p => UpdatePlayer(p, curTick));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdatePlayer(IPlayerSession playerSession, GameTick curTick)
|
||||||
|
{
|
||||||
var xformQuery = GetEntityQuery<TransformComponent>();
|
var xformQuery = GetEntityQuery<TransformComponent>();
|
||||||
|
|
||||||
foreach (var session in Filter.GetAllPlayers(_playerManager))
|
|
||||||
{
|
|
||||||
if (session is IPlayerSession { Status: SessionStatus.InGame } playerSession)
|
|
||||||
UpdatePlayer(playerSession, xformQuery, curTick);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdatePlayer(IPlayerSession playerSession, EntityQuery<TransformComponent> xformQuery, GameTick curTick)
|
|
||||||
{
|
|
||||||
var chunksInRange = _chunkingSys.GetChunksForSession(playerSession, ChunkSize, xformQuery, _chunkIndexPool, _chunkViewerPool);
|
var chunksInRange = _chunkingSys.GetChunksForSession(playerSession, ChunkSize, xformQuery, _chunkIndexPool, _chunkViewerPool);
|
||||||
|
var previouslySent = _lastSentChunks[playerSession];
|
||||||
if (!_lastSentChunks.TryGetValue(playerSession, out var previouslySent))
|
|
||||||
{
|
|
||||||
_lastSentChunks[playerSession] = previouslySent = _chunkViewerPool.Get();
|
|
||||||
DebugTools.Assert(previouslySent.Count == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
var ev = new GasOverlayUpdateEvent();
|
var ev = new GasOverlayUpdateEvent();
|
||||||
|
|
||||||
@@ -289,8 +277,8 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ev.UpdatedChunks.Count != 0 || ev.RemovedChunks.Count != 0)
|
||||||
RaiseNetworkEvent(ev, playerSession.ConnectedClient);
|
RaiseNetworkEvent(ev, playerSession.ConnectedClient);
|
||||||
ReturnToPool(ev.RemovedChunks);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Reset(RoundRestartCleanupEvent ev)
|
public override void Reset(RoundRestartCleanupEvent ev)
|
||||||
@@ -300,10 +288,14 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
|
|
||||||
foreach (var data in _lastSentChunks.Values)
|
foreach (var data in _lastSentChunks.Values)
|
||||||
{
|
{
|
||||||
ReturnToPool(data);
|
foreach (var previous in data.Values)
|
||||||
|
{
|
||||||
|
previous.Clear();
|
||||||
|
_chunkIndexPool.Return(previous);
|
||||||
}
|
}
|
||||||
|
|
||||||
_lastSentChunks.Clear();
|
data.Clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Content.Server.Administration.Managers;
|
using Content.Server.Administration.Managers;
|
||||||
using Content.Shared.Administration;
|
using Content.Shared.Administration;
|
||||||
using Content.Shared.Chunking;
|
using Content.Shared.Chunking;
|
||||||
@@ -9,6 +11,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.Threading;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
namespace Content.Server.Decals
|
namespace Content.Server.Decals
|
||||||
@@ -18,6 +21,7 @@ namespace Content.Server.Decals
|
|||||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
[Dependency] private readonly IAdminManager _adminManager = default!;
|
[Dependency] private readonly IAdminManager _adminManager = default!;
|
||||||
[Dependency] private readonly ITileDefinitionManager _tileDefMan = default!;
|
[Dependency] private readonly ITileDefinitionManager _tileDefMan = default!;
|
||||||
|
[Dependency] private readonly IParallelManager _parMan = default!;
|
||||||
[Dependency] private readonly ChunkingSystem _chunking = default!;
|
[Dependency] private readonly ChunkingSystem _chunking = default!;
|
||||||
|
|
||||||
private readonly Dictionary<EntityUid, HashSet<Vector2i>> _dirtyChunks = new();
|
private readonly Dictionary<EntityUid, HashSet<Vector2i>> _dirtyChunks = new();
|
||||||
@@ -395,16 +399,18 @@ namespace Content.Server.Decals
|
|||||||
{
|
{
|
||||||
base.Update(frameTime);
|
base.Update(frameTime);
|
||||||
|
|
||||||
var xformQuery = GetEntityQuery<TransformComponent>();
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var session in Filter.GetAllPlayers(_playerManager))
|
public void UpdatePlayer(IPlayerSession player)
|
||||||
{
|
{
|
||||||
if (session is not IPlayerSession { Status: SessionStatus.InGame } playerSession)
|
var xformQuery = GetEntityQuery<TransformComponent>();
|
||||||
continue;
|
var chunksInRange = _chunking.GetChunksForSession(player, ChunkSize, xformQuery, _chunkIndexPool, _chunkViewerPool);
|
||||||
|
|
||||||
var chunksInRange = _chunking.GetChunksForSession(playerSession, ChunkSize, xformQuery, _chunkIndexPool, _chunkViewerPool);
|
|
||||||
var staleChunks = _chunkViewerPool.Get();
|
var staleChunks = _chunkViewerPool.Get();
|
||||||
var previouslySent = _previousSentChunks.GetOrNew(playerSession);
|
var previouslySent = _previousSentChunks[player];
|
||||||
|
|
||||||
// Get any chunks not in range anymore
|
// Get any chunks not in range anymore
|
||||||
// Then, remove them from previousSentChunks (for stuff like grids out of range)
|
// Then, remove them from previousSentChunks (for stuff like grids out of range)
|
||||||
@@ -477,10 +483,7 @@ namespace Content.Server.Decals
|
|||||||
}
|
}
|
||||||
|
|
||||||
//send all gridChunks to client
|
//send all gridChunks to client
|
||||||
SendChunkUpdates(playerSession, updatedChunks, staleChunks);
|
SendChunkUpdates(player, updatedChunks, staleChunks);
|
||||||
}
|
|
||||||
|
|
||||||
_dirtyChunks.Clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ReturnToPool(Dictionary<EntityUid, HashSet<Vector2i>> chunks)
|
private void ReturnToPool(Dictionary<EntityUid, HashSet<Vector2i>> chunks)
|
||||||
@@ -518,6 +521,7 @@ namespace Content.Server.Decals
|
|||||||
updatedDecals[gridId] = gridChunks;
|
updatedDecals[gridId] = gridChunks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (updatedDecals.Count != 0 || staleChunks.Count != 0)
|
||||||
RaiseNetworkEvent(new DecalChunkUpdateEvent{Data = updatedDecals, RemovedChunks = staleChunks}, Filter.SinglePlayer(session));
|
RaiseNetworkEvent(new DecalChunkUpdateEvent{Data = updatedDecals, RemovedChunks = staleChunks}, Filter.SinglePlayer(session));
|
||||||
|
|
||||||
ReturnToPool(updatedChunks);
|
ReturnToPool(updatedChunks);
|
||||||
|
|||||||
Reference in New Issue
Block a user