Misc mind tweaks and fixes (#20614)
This commit is contained in:
@@ -1,7 +1,12 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using Content.Server.GameTicking;
|
using Content.Server.GameTicking;
|
||||||
|
using Content.Server.Players;
|
||||||
|
using Content.Shared.Mind;
|
||||||
|
using Content.Shared.Players;
|
||||||
|
using Robust.Server.Player;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Network;
|
using Robust.Shared.Network;
|
||||||
@@ -25,6 +30,9 @@ public sealed partial class TestPair
|
|||||||
public RobustIntegrationTest.ServerIntegrationInstance Server { get; private set; } = default!;
|
public RobustIntegrationTest.ServerIntegrationInstance Server { get; private set; } = default!;
|
||||||
public RobustIntegrationTest.ClientIntegrationInstance Client { get; private set; } = default!;
|
public RobustIntegrationTest.ClientIntegrationInstance Client { get; private set; } = default!;
|
||||||
|
|
||||||
|
public IPlayerSession? Player => (IPlayerSession?) Server.PlayerMan.Sessions.FirstOrDefault();
|
||||||
|
public PlayerData? PlayerData => Player?.Data.ContentData();
|
||||||
|
|
||||||
public PoolTestLogHandler ServerLogHandler { get; private set; } = default!;
|
public PoolTestLogHandler ServerLogHandler { get; private set; } = default!;
|
||||||
public PoolTestLogHandler ClientLogHandler { get; private set; } = default!;
|
public PoolTestLogHandler ClientLogHandler { get; private set; } = default!;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
#nullable enable
|
||||||
|
using Robust.Shared.Console;
|
||||||
|
using Robust.Shared.Map;
|
||||||
|
|
||||||
|
namespace Content.IntegrationTests.Tests.Minds;
|
||||||
|
|
||||||
|
[TestFixture]
|
||||||
|
public sealed partial class MindTests
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public async Task DeleteAllThenGhost()
|
||||||
|
{
|
||||||
|
var settings = new PoolSettings
|
||||||
|
{
|
||||||
|
Dirty = true,
|
||||||
|
DummyTicker = false,
|
||||||
|
Connected = true
|
||||||
|
};
|
||||||
|
await using var pair = await PoolManager.GetServerClient(settings);
|
||||||
|
|
||||||
|
// Client is connected with a valid entity & mind
|
||||||
|
Assert.That(pair.Client.EntMan.EntityExists(pair.Client.Player?.ControlledEntity));
|
||||||
|
Assert.That(pair.Server.EntMan.EntityExists(pair.PlayerData?.Mind));
|
||||||
|
|
||||||
|
// Delete **everything**
|
||||||
|
var conHost = pair.Server.ResolveDependency<IConsoleHost>();
|
||||||
|
await pair.Server.WaitPost(() => conHost.ExecuteCommand("entities delete"));
|
||||||
|
await pair.RunTicksSync(5);
|
||||||
|
|
||||||
|
Assert.That(pair.Server.EntMan.EntityCount, Is.EqualTo(0));
|
||||||
|
Assert.That(pair.Client.EntMan.EntityCount, Is.EqualTo(0));
|
||||||
|
|
||||||
|
// Create a new map.
|
||||||
|
int mapId = 1;
|
||||||
|
await pair.Server.WaitPost(() => conHost.ExecuteCommand($"addmap {mapId}"));
|
||||||
|
await pair.RunTicksSync(5);
|
||||||
|
|
||||||
|
// Client is not attached to anything
|
||||||
|
Assert.Null(pair.Client.Player?.ControlledEntity);
|
||||||
|
Assert.Null(pair.PlayerData?.Mind);
|
||||||
|
|
||||||
|
// Attempt to ghost
|
||||||
|
var cConHost = pair.Client.ResolveDependency<IConsoleHost>();
|
||||||
|
await pair.Client.WaitPost(() => cConHost.ExecuteCommand("ghost"));
|
||||||
|
await pair.RunTicksSync(10);
|
||||||
|
|
||||||
|
// Client should be attached to a ghost placed on the new map.
|
||||||
|
Assert.That(pair.Client.EntMan.EntityExists(pair.Client.Player?.ControlledEntity));
|
||||||
|
Assert.That(pair.Server.EntMan.EntityExists(pair.PlayerData?.Mind));
|
||||||
|
var xform = pair.Client.Transform(pair.Client.Player!.ControlledEntity!.Value);
|
||||||
|
Assert.That(xform.MapID, Is.EqualTo(new MapId(mapId)));
|
||||||
|
|
||||||
|
await pair.CleanReturnAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,8 +27,8 @@ namespace Content.Server.Ghost
|
|||||||
var minds = _entities.System<SharedMindSystem>();
|
var minds = _entities.System<SharedMindSystem>();
|
||||||
if (!minds.TryGetMind(player, out var mindId, out var mind))
|
if (!minds.TryGetMind(player, out var mindId, out var mind))
|
||||||
{
|
{
|
||||||
shell.WriteLine("You have no Mind, you can't ghost.");
|
mindId = minds.CreateMind(player.UserId);
|
||||||
return;
|
mind = _entities.GetComponent<MindComponent>(mindId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!EntitySystem.Get<GameTicker>().OnGhostAttempt(mindId, true, true, mind))
|
if (!EntitySystem.Get<GameTicker>().OnGhostAttempt(mindId, true, true, mind))
|
||||||
|
|||||||
@@ -31,6 +31,25 @@ public sealed class MindSystem : SharedMindSystem
|
|||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
SubscribeLocalEvent<MindContainerComponent, EntityTerminatingEvent>(OnMindContainerTerminating);
|
SubscribeLocalEvent<MindContainerComponent, EntityTerminatingEvent>(OnMindContainerTerminating);
|
||||||
|
SubscribeLocalEvent<MindComponent, ComponentShutdown>(OnMindShutdown);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnMindShutdown(EntityUid uid, MindComponent mind, ComponentShutdown args)
|
||||||
|
{
|
||||||
|
if (mind.UserId is {} user)
|
||||||
|
{
|
||||||
|
UserMinds.Remove(user);
|
||||||
|
if (_players.GetPlayerData(user).ContentData() is { } oldData)
|
||||||
|
oldData.Mind = null;
|
||||||
|
mind.UserId = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TryComp(mind.OwnedEntity, out MetaDataComponent? meta) || meta.EntityLifeStage >= EntityLifeStage.Terminating)
|
||||||
|
return;
|
||||||
|
|
||||||
|
RaiseLocalEvent(mind.OwnedEntity.Value, new MindRemovedMessage(uid, mind), true);
|
||||||
|
mind.OwnedEntity = null;
|
||||||
|
mind.OwnedComponent = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnMindContainerTerminating(EntityUid uid, MindContainerComponent component, ref EntityTerminatingEvent args)
|
private void OnMindContainerTerminating(EntityUid uid, MindContainerComponent component, ref EntityTerminatingEvent args)
|
||||||
@@ -195,11 +214,11 @@ public sealed class MindSystem : SharedMindSystem
|
|||||||
public override void TransferTo(EntityUid mindId, EntityUid? entity, bool ghostCheckOverride = false, bool createGhost = true,
|
public override void TransferTo(EntityUid mindId, EntityUid? entity, bool ghostCheckOverride = false, bool createGhost = true,
|
||||||
MindComponent? mind = null)
|
MindComponent? mind = null)
|
||||||
{
|
{
|
||||||
base.TransferTo(mindId, entity, ghostCheckOverride, createGhost, mind);
|
if (mind == null && !Resolve(mindId, ref mind))
|
||||||
|
|
||||||
if (!Resolve(mindId, ref mind))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
base.TransferTo(mindId, entity, ghostCheckOverride, createGhost, mind);
|
||||||
|
|
||||||
if (entity == mind.OwnedEntity)
|
if (entity == mind.OwnedEntity)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
@@ -65,8 +65,7 @@ namespace Content.Shared.Mind
|
|||||||
/// The component currently owned by this mind.
|
/// The component currently owned by this mind.
|
||||||
/// Can be null.
|
/// Can be null.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ViewVariables]
|
[ViewVariables] public MindContainerComponent? OwnedComponent;
|
||||||
public MindContainerComponent? OwnedComponent { get; internal set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The entity currently owned by this mind.
|
/// The entity currently owned by this mind.
|
||||||
|
|||||||
@@ -8,13 +8,11 @@ using Content.Shared.Interaction.Events;
|
|||||||
using Content.Shared.Mind.Components;
|
using Content.Shared.Mind.Components;
|
||||||
using Content.Shared.Mobs.Components;
|
using Content.Shared.Mobs.Components;
|
||||||
using Content.Shared.Mobs.Systems;
|
using Content.Shared.Mobs.Systems;
|
||||||
using Content.Shared.Objectives;
|
|
||||||
using Content.Shared.Objectives.Systems;
|
using Content.Shared.Objectives.Systems;
|
||||||
using Content.Shared.Players;
|
using Content.Shared.Players;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Network;
|
using Robust.Shared.Network;
|
||||||
using Robust.Shared.Players;
|
using Robust.Shared.Players;
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
namespace Content.Shared.Mind;
|
namespace Content.Shared.Mind;
|
||||||
@@ -25,6 +23,7 @@ public abstract class SharedMindSystem : EntitySystem
|
|||||||
[Dependency] private readonly MobStateSystem _mobState = default!;
|
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||||
[Dependency] private readonly SharedObjectivesSystem _objectives = default!;
|
[Dependency] private readonly SharedObjectivesSystem _objectives = default!;
|
||||||
[Dependency] private readonly SharedPlayerSystem _player = default!;
|
[Dependency] private readonly SharedPlayerSystem _player = default!;
|
||||||
|
[Dependency] private readonly MetaDataSystem _metadata = default!;
|
||||||
|
|
||||||
// This is dictionary is required to track the minds of disconnected players that may have had their entity deleted.
|
// This is dictionary is required to track the minds of disconnected players that may have had their entity deleted.
|
||||||
protected readonly Dictionary<NetUserId, EntityUid> UserMinds = new();
|
protected readonly Dictionary<NetUserId, EntityUid> UserMinds = new();
|
||||||
@@ -132,12 +131,11 @@ public abstract class SharedMindSystem : EntitySystem
|
|||||||
public EntityUid CreateMind(NetUserId? userId, string? name = null)
|
public EntityUid CreateMind(NetUserId? userId, string? name = null)
|
||||||
{
|
{
|
||||||
var mindId = Spawn(null, MapCoordinates.Nullspace);
|
var mindId = Spawn(null, MapCoordinates.Nullspace);
|
||||||
|
_metadata.SetEntityName(mindId, name == null ? "mind" : $"mind ({name})");
|
||||||
var mind = EnsureComp<MindComponent>(mindId);
|
var mind = EnsureComp<MindComponent>(mindId);
|
||||||
mind.CharacterName = name;
|
mind.CharacterName = name;
|
||||||
SetUserId(mindId, userId, mind);
|
SetUserId(mindId, userId, mind);
|
||||||
|
|
||||||
Dirty(mindId, MetaData(mindId));
|
|
||||||
|
|
||||||
return mindId;
|
return mindId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -343,7 +341,14 @@ public abstract class SharedMindSystem : EntitySystem
|
|||||||
{
|
{
|
||||||
mindId = default;
|
mindId = default;
|
||||||
mind = null;
|
mind = null;
|
||||||
return _player.ContentData(player) is { } data && TryGetMind(data, out mindId, out mind);
|
if (_player.ContentData(player) is not { } data)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (TryGetMind(data, out mindId, out mind))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
DebugTools.AssertNull(data.Mind);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
Reference in New Issue
Block a user