using System.Linq; using Content.IntegrationTests.Pair; using Content.Server.Players; using Content.Shared.Ghost; using Content.Shared.Mind; using Robust.Server.GameObjects; using Robust.Server.Player; using Robust.Shared.Enums; using Robust.Shared.GameObjects; using Robust.Shared.Map; using Robust.Shared.Network; namespace Content.IntegrationTests.Tests.Minds; // This partial class contains misc helper functions for other tests. public sealed partial class MindTests { /// /// Gets a server-client pair and ensures that the client is attached to a simple mind test entity. /// /// /// Without this, it may be possible that a tests starts with the client attached to an entity that does not match /// the player's mind's current entity, likely because some previous test directly changed the players attached /// entity. /// private static async Task SetupPair(bool dirty = false) { var pair = await PoolManager.GetServerClient(new PoolSettings { DummyTicker = false, Connected = true, Dirty = dirty }); var entMan = pair.Server.ResolveDependency(); var playerMan = pair.Server.ResolveDependency(); var mindSys = entMan.System(); var player = playerMan.ServerSessions.Single(); EntityUid entity = default; EntityUid mindId = default!; MindComponent mind = default!; await pair.Server.WaitPost(() => { entity = entMan.SpawnEntity(null, MapCoordinates.Nullspace); mindId = mindSys.CreateMind(player.UserId); mind = entMan.GetComponent(mindId); mindSys.TransferTo(mindId, entity); }); await pair.RunTicksSync(5); Assert.Multiple(() => { Assert.That(player.ContentData()?.Mind, Is.EqualTo(mindId)); Assert.That(player.AttachedEntity, Is.EqualTo(entity)); Assert.That(player.AttachedEntity, Is.EqualTo(mind.CurrentEntity), "Player is not attached to the mind's current entity."); Assert.That(entMan.EntityExists(mind.OwnedEntity), "The mind's current entity does not exist"); Assert.That(mind.VisitingEntity == null || entMan.EntityExists(mind.VisitingEntity), "The minds visited entity does not exist."); }); return pair; } private static async Task BecomeGhost(TestPair pair, bool visit = false) { var entMan = pair.Server.ResolveDependency(); var playerMan = pair.Server.ResolveDependency(); var mindSys = entMan.System(); EntityUid ghostUid = default; EntityUid mindId = default!; MindComponent mind = default!; var player = playerMan.ServerSessions.Single(); await pair.Server.WaitAssertion(() => { var oldUid = player.AttachedEntity; ghostUid = entMan.SpawnEntity("MobObserver", MapCoordinates.Nullspace); mindId = mindSys.GetMind(player.UserId)!.Value; Assert.That(mindId, Is.Not.EqualTo(default(EntityUid))); mind = entMan.GetComponent(mindId); if (visit) { mindSys.Visit(mindId, ghostUid); return; } mindSys.TransferTo(mindId, ghostUid); if (oldUid != null) entMan.DeleteEntity(oldUid.Value); }); await pair.RunTicksSync(5); Assert.Multiple(() => { Assert.That(entMan.HasComponent(ghostUid)); Assert.That(player.AttachedEntity, Is.EqualTo(ghostUid)); Assert.That(mind.CurrentEntity, Is.EqualTo(ghostUid)); }); if (!visit) Assert.That(mind.VisitingEntity, Is.Null); return ghostUid; } private static async Task VisitGhost(Pair.TestPair pair, bool _ = false) { return await BecomeGhost(pair, visit: true); } /// /// Get the player's current mind and check that the entities exists. /// private static (EntityUid Id, MindComponent Comp) GetMind(Pair.TestPair pair) { var playerMan = pair.Server.ResolveDependency(); var entMan = pair.Server.ResolveDependency(); var player = playerMan.ServerSessions.SingleOrDefault(); Assert.That(player, Is.Not.Null); var mindId = player.ContentData()!.Mind!.Value; Assert.That(mindId, Is.Not.EqualTo(default(EntityUid))); var mind = entMan.GetComponent(mindId); Assert.Multiple(() => { Assert.That(player.AttachedEntity, Is.EqualTo(mind.CurrentEntity), "Player is not attached to the mind's current entity."); Assert.That(entMan.EntityExists(mind.OwnedEntity), "The mind's current entity does not exist"); Assert.That(mind.VisitingEntity == null || entMan.EntityExists(mind.VisitingEntity), "The minds visited entity does not exist."); }); return (mindId, mind); } private static async Task Disconnect(Pair.TestPair pair) { var netManager = pair.Client.ResolveDependency(); var playerMan = pair.Server.ResolveDependency(); var entMan = pair.Server.ResolveDependency(); var player = playerMan.ServerSessions.Single(); var mindId = player.ContentData()!.Mind!.Value; var mind = entMan.GetComponent(mindId); await pair.Client.WaitAssertion(() => { netManager.ClientDisconnect("Disconnect command used."); }); await pair.RunTicksSync(5); Assert.Multiple(() => { Assert.That(player.Status, Is.EqualTo(SessionStatus.Disconnected)); Assert.That(mind.UserId, Is.Not.Null); Assert.That(mind.Session, Is.Null); }); } private static async Task Connect(Pair.TestPair pair, string username) { var netManager = pair.Client.ResolveDependency(); var playerMan = pair.Server.ResolveDependency(); Assert.That(!playerMan.ServerSessions.Any()); await Task.WhenAll(pair.Client.WaitIdleAsync(), pair.Client.WaitIdleAsync()); pair.Client.SetConnectTarget(pair.Server); await pair.Client.WaitPost(() => netManager.ClientConnect(null!, 0, username)); await pair.RunTicksSync(5); var player = playerMan.ServerSessions.Single(); Assert.That(player.Status, Is.EqualTo(SessionStatus.InGame)); } private static async Task DisconnectReconnect(Pair.TestPair pair) { var playerMan = pair.Server.ResolveDependency(); var player = playerMan.ServerSessions.Single(); var name = player.Name; var id = player.UserId; await Disconnect(pair); await Connect(pair, name); // Session has changed var newSession = playerMan.ServerSessions.Single(); Assert.Multiple(() => { Assert.That(newSession, Is.Not.EqualTo(player)); Assert.That(newSession.UserId, Is.EqualTo(id)); }); return newSession; } }