Files
RobustToolbox/Robust.UnitTesting/Server/GameStates/PvsPauseTest.cs
T
b15d960c69 Try improve RaiseEvent performance (#5925)
* IEventBus -> EventBus

* Fix CompIdx.RefArray

* IEntityManager -> EntityManager

* Remove double delegate

* Add GetNetCompEventHandlers()

* release notes & cleanup

* Make PVS use GetNetCompEventHandlers

* I love event bus tests

* also fix pvs pause test

* dont trimm

---------

Co-authored-by: PJB3005 <pieterjan.briers+git@gmail.com>
Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
2025-11-13 21:32:40 +11:00

174 lines
6.5 KiB
C#

using System;
using System.Linq;
using System.Numerics;
using System.Threading.Tasks;
using NUnit.Framework;
using Robust.Client.GameStates;
using Robust.Shared;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Network;
namespace Robust.UnitTesting.Server.GameStates;
public sealed class PvsPauseTest : RobustIntegrationTest
{
/// <summary>
/// Check that the client "pauses" entities that have left their PVS range.
/// </summary>
[Test]
public async Task PauseTest()
{
var server = StartServer();
var client = StartClient();
await Task.WhenAll(client.WaitIdleAsync(), server.WaitIdleAsync());
var sEntMan = server.EntMan;
var confMan = server.CfgMan;
var sPlayerMan = server.PlayerMan;
var xforms = sEntMan.System<SharedTransformSystem>();
var metaSys = sEntMan.System<MetaDataSystem>();
var stateMan = (ClientGameStateManager) client.ResolveDependency<IClientGameStateManager>();
var cEntMan = client.EntMan;
var cPlayerMan = client.PlayerMan;
var netMan = client.ResolveDependency<IClientNetManager>();
Assert.DoesNotThrow(() => client.SetConnectTarget(server));
client.Post(() => netMan.ClientConnect(null!, 0, null!));
server.Post(() => confMan.SetCVar(CVars.NetPVS, true));
async Task RunTicks()
{
for (int i = 0; i < 10; i++)
{
await server.WaitRunTicks(1);
await client.WaitRunTicks(1);
}
}
await RunTicks();
// Set up map and spawn player
EntityUid map = default;
EntityUid playerUid = default;
EntityUid sEnt = default;
EntityCoordinates coords = default;
await server.WaitPost(() =>
{
map = server.System<SharedMapSystem>().CreateMap();
coords = new(map, default);
playerUid = sEntMan.SpawnEntity(null, coords);
sEnt = sEntMan.SpawnEntity(null, coords);
// Attach player.
var session = sPlayerMan.Sessions.First();
server.PlayerMan.SetAttachedEntity(session, playerUid);
sPlayerMan.JoinGame(session);
});
await RunTicks();
var farAway = new EntityCoordinates(map, new Vector2(100, 100));
var netEnt = sEntMan.GetNetEntity(sEnt);
var player = sEntMan.GetNetEntity(playerUid);
Assert.That(player, Is.Not.EqualTo(NetEntity.Invalid));
Assert.That(netEnt, Is.Not.EqualTo(NetEntity.Invalid));
// Check player got properly attached, and has received the other entity.
Assert.That(cEntMan.TryGetEntity(netEnt, out var uid));
Assert.That(cEntMan.TryGetEntity(player, out var cPlayerUid));
var cEnt = uid!.Value;
Assert.That(cPlayerMan.LocalEntity, Is.EqualTo(cPlayerUid));
void AssertEnt(bool paused, bool detached, bool clientPaused)
{
var cMeta = client.MetaData(cEnt);
var sMeta = server.MetaData(sEnt);
Assert.That(cMeta.Flags.HasFlag(MetaDataFlags.Detached), Is.EqualTo(detached));
Assert.That(sMeta.Flags.HasFlag(MetaDataFlags.Detached), Is.False);
Assert.That(stateMan.IsQueuedForDetach(netEnt), Is.False);
Assert.That(sMeta.EntityPaused, Is.EqualTo(paused));
Assert.That(cMeta.EntityPaused, Is.EqualTo(clientPaused));
if (detached)
Assert.That(cMeta.PauseTime, Is.EqualTo(TimeSpan.Zero));
if (clientPaused)
Assert.That(cMeta.PauseTime, Is.GreaterThanOrEqualTo(TimeSpan.Zero));
else
Assert.That(cMeta.PauseTime, Is.Null);
if (paused)
Assert.That(sMeta.PauseTime, Is.GreaterThan(TimeSpan.Zero));
else
Assert.That(sMeta.PauseTime, Is.Null);
}
// Entity is initially in view and not paused.
AssertEnt(paused: false, detached: false, clientPaused: false);
// Move the player out of the entity's PVS range
await server.WaitPost(() => xforms.SetCoordinates(sEntMan.GetEntity(player), farAway));
await RunTicks();
// Client should now have detached & locally paused the entity.
AssertEnt(paused: false, detached: true, clientPaused: true);
// Move the player back into range
await server.WaitPost( () => xforms.SetCoordinates(sEntMan.GetEntity(player), coords));
await RunTicks();
AssertEnt(paused: false, detached: false, clientPaused: false);
// Actually pause the entity.
await server.WaitPost(() => metaSys.SetEntityPaused(sEnt, true));
await RunTicks();
AssertEnt(paused: true, detached: false, clientPaused: true);
// Out of range
await server.WaitPost(() => xforms.SetCoordinates(sEntMan.GetEntity(player), farAway));
await RunTicks();
AssertEnt(paused: true, detached: true, clientPaused: true);
// Back in range
await server.WaitPost(() => xforms.SetCoordinates(sEntMan.GetEntity(player), coords));
await RunTicks();
AssertEnt(paused: true, detached: false, clientPaused: true);
// Unpause the entity while out of range
{
await server.WaitPost(() => xforms.SetCoordinates(sEntMan.GetEntity(player), farAway));
await RunTicks();
AssertEnt(paused: true, detached: true, clientPaused: true);
await server.WaitPost(() => metaSys.SetEntityPaused(sEnt, false));
await RunTicks();
AssertEnt(paused: false, detached: true, clientPaused: true);
await server.WaitPost(() => xforms.SetCoordinates(sEntMan.GetEntity(player), coords));
await RunTicks();
AssertEnt(paused: false, detached: false, clientPaused: false);
}
// Pause the entity while out of range
{
await server.WaitPost(() => xforms.SetCoordinates(sEntMan.GetEntity(player), farAway));
await RunTicks();
AssertEnt(paused: false, detached: true, clientPaused: true);
await server.WaitPost(() => metaSys.SetEntityPaused(sEnt, true));
await RunTicks();
AssertEnt(paused: true, detached: true, clientPaused: true);
await server.WaitPost(() => xforms.SetCoordinates(sEntMan.GetEntity(player), coords));
await RunTicks();
AssertEnt(paused: true, detached: false, clientPaused: true);
}
client.Post(() => netMan.ClientDisconnect(""));
await RunTicks();
}
}