mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-09-15 23:02:34 +02:00
170 lines
6.5 KiB
C#
170 lines
6.5 KiB
C#
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using NUnit.Framework;
|
|
using Robust.Shared;
|
|
using Robust.Shared.Configuration;
|
|
using Robust.Shared.GameObjects;
|
|
using Robust.Shared.Map;
|
|
using Robust.Shared.Network;
|
|
using Robust.Shared.Player;
|
|
|
|
namespace Robust.UnitTesting.Server.GameStates;
|
|
|
|
public sealed class MissingParentTest : RobustIntegrationTest
|
|
{
|
|
/// <summary>
|
|
/// Check that PVS & clients can handle entities being sent before their parents are.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task TestMissingParent()
|
|
{
|
|
var server = StartServer();
|
|
var client = StartClient();
|
|
|
|
await Task.WhenAll(client.WaitIdleAsync(), server.WaitIdleAsync());
|
|
|
|
var mapMan = server.ResolveDependency<IMapManager>();
|
|
var sEntMan = server.ResolveDependency<IEntityManager>();
|
|
var confMan = server.ResolveDependency<IConfigurationManager>();
|
|
var sPlayerMan = server.ResolveDependency<ISharedPlayerManager>();
|
|
|
|
var cEntMan = client.ResolveDependency<IEntityManager>();
|
|
var netMan = client.ResolveDependency<IClientNetManager>();
|
|
var cPlayerMan = client.ResolveDependency<ISharedPlayerManager>();
|
|
var cConfMan = client.ResolveDependency<IConfigurationManager>();
|
|
|
|
Assert.DoesNotThrow(() => client.SetConnectTarget(server));
|
|
client.Post(() => netMan.ClientConnect(null!, 0, null!));
|
|
server.Post(() => confMan.SetCVar(CVars.NetPVS, true));
|
|
|
|
for (int i = 0; i < 10; i++)
|
|
{
|
|
await server.WaitRunTicks(1);
|
|
await client.WaitRunTicks(1);
|
|
}
|
|
|
|
// Limit client to receiving at most 1 entity per tick.
|
|
cConfMan.SetCVar(CVars.NetPVSEntityBudget, 1);
|
|
|
|
for (int i = 0; i < 10; i++)
|
|
{
|
|
await server.WaitRunTicks(1);
|
|
await client.WaitRunTicks(1);
|
|
}
|
|
|
|
// Ensure client & server ticks are synced.
|
|
// Client runs 1 tick ahead
|
|
{
|
|
var sTick = (int)server.Timing.CurTick.Value;
|
|
var cTick = (int)client.Timing.CurTick.Value;
|
|
var delta = cTick - sTick;
|
|
|
|
if (delta > 1)
|
|
await server.WaitRunTicks(delta - 1);
|
|
else if (delta < 1)
|
|
await client.WaitRunTicks(1 - delta);
|
|
|
|
sTick = (int)server.Timing.CurTick.Value;
|
|
cTick = (int)client.Timing.CurTick.Value;
|
|
delta = cTick - sTick;
|
|
Assert.That(delta, Is.EqualTo(1));
|
|
}
|
|
|
|
// Set up map and spawn player
|
|
NetEntity player = default;
|
|
NetEntity entity = default;
|
|
EntityCoordinates coords = default;
|
|
NetCoordinates nCoords = default;
|
|
await server.WaitPost(() =>
|
|
{
|
|
var map = server.System<SharedMapSystem>().CreateMap();
|
|
coords = new(map, default);
|
|
|
|
var playerUid = sEntMan.SpawnEntity(null, coords);
|
|
var entUid = sEntMan.SpawnEntity(null, coords);
|
|
entity = sEntMan.GetNetEntity(entUid);
|
|
player = sEntMan.GetNetEntity(playerUid);
|
|
nCoords = sEntMan.GetNetCoordinates(coords);
|
|
|
|
// Attach player.
|
|
var session = sPlayerMan.Sessions.First();
|
|
server.PlayerMan.SetAttachedEntity(session, playerUid);
|
|
sPlayerMan.JoinGame(session);
|
|
});
|
|
|
|
for (int i = 0; i < 10; i++)
|
|
{
|
|
await server.WaitRunTicks(1);
|
|
await client.WaitRunTicks(1);
|
|
}
|
|
|
|
Assert.That(player, Is.Not.EqualTo(NetEntity.Invalid));
|
|
Assert.That(entity, Is.Not.EqualTo(NetEntity.Invalid));
|
|
|
|
// Check player got properly attached, and has received the other entity.
|
|
Assert.That(cEntMan.TryGetEntityData(entity, out _, out var meta));
|
|
Assert.That(cEntMan.TryGetEntity(player, out var cPlayerUid));
|
|
Assert.That(cPlayerMan.LocalEntity, Is.EqualTo(cPlayerUid));
|
|
Assert.That(server.Transform(player).Coordinates, Is.EqualTo(coords));
|
|
Assert.That(client.Transform(player).Coordinates, Is.EqualTo(client.EntMan.GetCoordinates(nCoords)));
|
|
Assert.That(client.Transform(entity).ParentUid.IsValid(), Is.True);
|
|
Assert.That(client.MetaData(entity).Flags & MetaDataFlags.Detached, Is.EqualTo(MetaDataFlags.None));
|
|
|
|
// Spawn 20 new entities
|
|
NetEntity first = default;
|
|
NetEntity last = default;
|
|
await server.WaitPost(() =>
|
|
{
|
|
first = sEntMan.GetNetEntity(sEntMan.SpawnEntity(null, coords));
|
|
for (var i = 0; i < 18; i++)
|
|
{
|
|
sEntMan.SpawnEntity(null, coords);
|
|
}
|
|
last = sEntMan.GetNetEntity(sEntMan.SpawnEntity(null, coords));
|
|
});
|
|
|
|
// Wait for the client to receive some, but not all, of the entities
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
await server.WaitRunTicks(1);
|
|
await client.WaitRunTicks(1);
|
|
}
|
|
Assert.That(cEntMan.TryGetEntity(first, out _), Is.True);
|
|
Assert.That(cEntMan.TryGetEntity(last, out _), Is.False);
|
|
|
|
// Re-parent the known entity to an entity that the client has not received yet.
|
|
await server.WaitPost(() =>
|
|
{
|
|
var newCoords = new EntityCoordinates(sEntMan.GetEntity(last), default);
|
|
server.System<SharedTransformSystem>().SetCoordinates(sEntMan.GetEntity(entity), newCoords);
|
|
});
|
|
|
|
// Wait a few more ticks
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
await server.WaitRunTicks(1);
|
|
await client.WaitRunTicks(1);
|
|
}
|
|
|
|
// Client should still not have received the new parent, however this shouldn't cause any issues.
|
|
// The already known entity should just have been moved to nullspace.
|
|
Assert.That(cEntMan.TryGetEntity(last, out _), Is.False);
|
|
Assert.That(client.Transform(entity).ParentUid.IsValid(), Is.False);
|
|
Assert.That(client.MetaData(entity).Flags & MetaDataFlags.Detached, Is.EqualTo(MetaDataFlags.None));
|
|
|
|
// Wait untill the client receives the parent entity
|
|
for (int i = 0; i < 10; i++)
|
|
{
|
|
await server.WaitRunTicks(1);
|
|
await client.WaitRunTicks(1);
|
|
}
|
|
|
|
// now that the parent was received the entity should no longer be in nullspace.
|
|
Assert.That(cEntMan.TryGetEntity(last, out var newParent), Is.True);
|
|
Assert.That(client.Transform(entity).ParentUid.IsValid(), Is.True);
|
|
Assert.That(client.Transform(entity).ParentUid, Is.EqualTo(newParent));
|
|
Assert.That(client.MetaData(entity).Flags & MetaDataFlags.Detached, Is.EqualTo(MetaDataFlags.None));
|
|
}
|
|
}
|
|
|