Fix some Mind ECS bugs (#17480)
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
using Content.Server.Mind;
|
||||
using Content.Server.Players;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Console;
|
||||
@@ -21,7 +22,9 @@ namespace Content.Server.GameTicking.Commands
|
||||
}
|
||||
|
||||
var playerMgr = IoCManager.Resolve<IPlayerManager>();
|
||||
var ticker = EntitySystem.Get<GameTicker>();
|
||||
var sysMan = IoCManager.Resolve<EntitySystemManager>();
|
||||
var ticker = sysMan.GetEntitySystem<GameTicker>();
|
||||
var mind = sysMan.GetEntitySystem<MindSystem>();
|
||||
|
||||
NetUserId userId;
|
||||
if (args.Length == 0)
|
||||
@@ -48,7 +51,7 @@ namespace Content.Server.GameTicking.Commands
|
||||
return;
|
||||
}
|
||||
|
||||
data.ContentData()?.WipeMind();
|
||||
mind.WipeMind(data.ContentData()?.Mind);
|
||||
shell.WriteLine("Player is not currently online, but they will respawn if they come back online");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -27,15 +27,28 @@ namespace Content.Server.GameTicking
|
||||
{
|
||||
var session = args.Session;
|
||||
|
||||
if (_mindSystem.TryGetMind(session.UserId, out var mind))
|
||||
{
|
||||
if (args.OldStatus == SessionStatus.Connecting && args.NewStatus == SessionStatus.Connected)
|
||||
mind.Session = session;
|
||||
|
||||
DebugTools.Assert(mind.Session == session);
|
||||
DebugTools.Assert(session.Data.ContentData()?.Mind is not {} dataMind || dataMind == mind);
|
||||
}
|
||||
|
||||
switch (args.NewStatus)
|
||||
{
|
||||
case SessionStatus.Connected:
|
||||
{
|
||||
AddPlayerToDb(args.Session.UserId.UserId);
|
||||
|
||||
// Always make sure the client has player data. Mind gets assigned on spawn.
|
||||
// Always make sure the client has player data.
|
||||
if (session.Data.ContentDataUncast == null)
|
||||
session.Data.ContentDataUncast = new PlayerData(session.UserId, args.Session.Name);
|
||||
{
|
||||
var data = new PlayerData(session.UserId, args.Session.Name);
|
||||
data.Mind = mind;
|
||||
session.Data.ContentDataUncast = data;
|
||||
}
|
||||
|
||||
// Make the player actually join the game.
|
||||
// timer time must be > tick length
|
||||
@@ -74,28 +87,28 @@ namespace Content.Server.GameTicking
|
||||
return;
|
||||
}
|
||||
|
||||
SpawnWaitDb();
|
||||
break;
|
||||
}
|
||||
|
||||
if (data.Mind.CurrentEntity == null || Deleted(data.Mind.CurrentEntity))
|
||||
{
|
||||
DebugTools.Assert(data.Mind.CurrentEntity == null, "a mind's current entity has been deleted");
|
||||
SpawnWaitDb();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (data.Mind.CurrentEntity == null)
|
||||
{
|
||||
SpawnWaitDb();
|
||||
}
|
||||
else
|
||||
{
|
||||
session.AttachToEntity(data.Mind.CurrentEntity);
|
||||
PlayerJoinGame(session);
|
||||
}
|
||||
session.AttachToEntity(data.Mind.CurrentEntity);
|
||||
PlayerJoinGame(session);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SessionStatus.Disconnected:
|
||||
{
|
||||
_chatManager.SendAdminAnnouncement(Loc.GetString("player-leave-message", ("name", args.Session.Name)));
|
||||
if (mind != null)
|
||||
mind.Session = null;
|
||||
|
||||
_userDb.ClientDisconnected(session);
|
||||
break;
|
||||
|
||||
@@ -414,13 +414,6 @@ namespace Content.Server.GameTicking
|
||||
PlayerJoinLobby(player);
|
||||
}
|
||||
|
||||
// Delete the minds of everybody.
|
||||
// TODO: Maybe move this into a separate manager?
|
||||
foreach (var unCastData in _playerManager.GetAllPlayerData())
|
||||
{
|
||||
unCastData.ContentData()?.WipeMind();
|
||||
}
|
||||
|
||||
// Delete all entities.
|
||||
foreach (var entity in EntityManager.GetEntities().ToArray())
|
||||
{
|
||||
|
||||
@@ -175,9 +175,8 @@ namespace Content.Server.GameTicking
|
||||
|
||||
DebugTools.AssertNotNull(data);
|
||||
|
||||
data!.WipeMind();
|
||||
var newMind = _mindSystem.CreateMind(data.UserId, character.Name);
|
||||
_mindSystem.ChangeOwningPlayer(newMind, data.UserId);
|
||||
var newMind = _mindSystem.CreateMind(data!.UserId, character.Name);
|
||||
_mindSystem.SetUserId(newMind, data.UserId);
|
||||
|
||||
var jobPrototype = _prototypeManager.Index<JobPrototype>(jobId);
|
||||
var job = new Job(newMind, jobPrototype);
|
||||
@@ -244,7 +243,7 @@ namespace Content.Server.GameTicking
|
||||
|
||||
public void Respawn(IPlayerSession player)
|
||||
{
|
||||
player.ContentData()?.WipeMind();
|
||||
_mindSystem.WipeMind(player);
|
||||
_adminLogger.Add(LogType.Respawn, LogImpact.Medium, $"Player {player} was respawned.");
|
||||
|
||||
if (LobbyEnabled)
|
||||
@@ -278,9 +277,8 @@ namespace Content.Server.GameTicking
|
||||
|
||||
DebugTools.AssertNotNull(data);
|
||||
|
||||
data!.WipeMind();
|
||||
var newMind = _mindSystem.CreateMind(data.UserId);
|
||||
_mindSystem.ChangeOwningPlayer(newMind, data.UserId);
|
||||
var newMind = _mindSystem.CreateMind(data!.UserId);
|
||||
_mindSystem.SetUserId(newMind, data.UserId);
|
||||
_mindSystem.AddRole(newMind, new ObserverRole(newMind));
|
||||
|
||||
var mob = SpawnObserverMob();
|
||||
|
||||
@@ -759,7 +759,7 @@ public sealed class NukeopsRuleSystem : GameRuleSystem<NukeopsRuleComponent>
|
||||
var mob = EntityManager.SpawnEntity(species.Prototype, _random.Pick(spawns));
|
||||
SetupOperativeEntity(mob, spawnDetails.Name, spawnDetails.Gear, profile, component);
|
||||
var newMind = _mindSystem.CreateMind(session.UserId, spawnDetails.Name);
|
||||
_mindSystem.ChangeOwningPlayer(newMind, session.UserId);
|
||||
_mindSystem.SetUserId(newMind, session.UserId);
|
||||
_mindSystem.AddRole(newMind, new NukeopsRole(newMind, nukeOpsAntag));
|
||||
|
||||
_mindSystem.TransferTo(newMind, mob);
|
||||
|
||||
@@ -208,7 +208,7 @@ public sealed class PiratesRuleSystem : GameRuleSystem<PiratesRuleComponent>
|
||||
|
||||
var session = ops[i];
|
||||
var newMind = _mindSystem.CreateMind(session.UserId, name);
|
||||
_mindSystem.ChangeOwningPlayer(newMind, session.UserId);
|
||||
_mindSystem.SetUserId(newMind, session.UserId);
|
||||
|
||||
var mob = Spawn("MobHuman", _random.Pick(spawns));
|
||||
MetaData(mob).EntityName = name;
|
||||
|
||||
@@ -236,8 +236,6 @@ namespace Content.Server.Ghost
|
||||
if (Deleted(uid) || Terminating(uid))
|
||||
return;
|
||||
|
||||
if (EntityManager.TryGetComponent<MindContainerComponent?>(uid, out var mind))
|
||||
_mindSystem.SetGhostOnShutdown(uid, false, mind);
|
||||
QueueDel(uid);
|
||||
}
|
||||
|
||||
|
||||
@@ -222,7 +222,7 @@ namespace Content.Server.Ghost.Roles
|
||||
EntityManager.GetComponent<MetaDataComponent>(mob).EntityName);
|
||||
_mindSystem.AddRole(newMind, new GhostRoleMarkerRole(newMind, role.RoleName));
|
||||
|
||||
_mindSystem.ChangeOwningPlayer(newMind, player.UserId);
|
||||
_mindSystem.SetUserId(newMind, player.UserId);
|
||||
_mindSystem.TransferTo(newMind, mob);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using YamlDotNet.Core.Tokens;
|
||||
|
||||
namespace Content.Server.Mind.Components
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Linq;
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Server.Mind.Components;
|
||||
using Content.Server.Objectives;
|
||||
using Content.Server.Roles;
|
||||
@@ -30,16 +31,14 @@ namespace Content.Server.Mind
|
||||
/// Note: the Mind is NOT initially attached!
|
||||
/// The provided UserId is solely for tracking of intended owner.
|
||||
/// </summary>
|
||||
/// <param name="userId">The session ID of the original owner (may get credited).</param>
|
||||
public Mind(NetUserId? userId)
|
||||
public Mind()
|
||||
{
|
||||
OriginalOwnerUserId = userId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The session ID of the player owning this mind.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
[ViewVariables, Access(typeof(MindSystem))]
|
||||
public NetUserId? UserId { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -112,7 +111,7 @@ namespace Content.Server.Mind
|
||||
/// The session of the player owning this mind.
|
||||
/// Can be null, in which case the player is currently not logged in.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
[ViewVariables, Access(typeof(MindSystem), typeof(GameTicker))]
|
||||
public IPlayerSession? Session { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -10,6 +10,7 @@ using Content.Server.Players;
|
||||
using Content.Server.Roles;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.GameTicking;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Mobs.Components;
|
||||
@@ -30,29 +31,25 @@ public sealed class MindSystem : EntitySystem
|
||||
[Dependency] private readonly GhostSystem _ghostSystem = default!;
|
||||
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly ActorSystem _actor = default!;
|
||||
|
||||
// This is dictionary is required to track the minds of disconnected players that may have had their entity deleted.
|
||||
private readonly Dictionary<NetUserId, Mind> _userMinds = new();
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<MindContainerComponent, ComponentShutdown>(OnShutdown);
|
||||
SubscribeLocalEvent<MindContainerComponent, ExaminedEvent>(OnExamined);
|
||||
SubscribeLocalEvent<MindContainerComponent, SuicideEvent>(OnSuicide);
|
||||
SubscribeLocalEvent<VisitingMindComponent, EntityTerminatingEvent>(OnTerminating);
|
||||
SubscribeLocalEvent<VisitingMindComponent, PlayerDetachedEvent>(OnDetached);
|
||||
SubscribeLocalEvent<MindContainerComponent, EntityTerminatingEvent>(OnMindContainerTerminating);
|
||||
SubscribeLocalEvent<VisitingMindComponent, EntityTerminatingEvent>(OnVisitingTerminating);
|
||||
SubscribeLocalEvent<RoundRestartCleanupEvent>(OnReset);
|
||||
}
|
||||
|
||||
private void OnDetached(EntityUid uid, VisitingMindComponent component, PlayerDetachedEvent args)
|
||||
public override void Shutdown()
|
||||
{
|
||||
component.Mind = null;
|
||||
RemCompDeferred(uid, component);
|
||||
}
|
||||
|
||||
private void OnTerminating(EntityUid uid, VisitingMindComponent component, ref EntityTerminatingEvent args)
|
||||
{
|
||||
if (component.Mind?.Session?.AttachedEntity == uid)
|
||||
UnVisit(component.Mind);
|
||||
base.Shutdown();
|
||||
WipeAllMinds();
|
||||
}
|
||||
|
||||
public void SetGhostOnShutdown(EntityUid uid, bool value, MindContainerComponent? mind = null)
|
||||
@@ -63,6 +60,49 @@ public sealed class MindSystem : EntitySystem
|
||||
mind.GhostOnShutdown = value;
|
||||
}
|
||||
|
||||
private void OnReset(RoundRestartCleanupEvent ev)
|
||||
{
|
||||
WipeAllMinds();
|
||||
}
|
||||
|
||||
public void WipeAllMinds()
|
||||
{
|
||||
foreach (var mind in _userMinds.Values)
|
||||
{
|
||||
WipeMind(mind);
|
||||
}
|
||||
DebugTools.Assert(_userMinds.Count == 0);
|
||||
|
||||
foreach (var unCastData in _playerManager.GetAllPlayerData())
|
||||
{
|
||||
if (unCastData.ContentData()?.Mind is not { } mind)
|
||||
continue;
|
||||
|
||||
Log.Error("Player mind was missing from MindSystem dictionary.");
|
||||
WipeMind(mind);
|
||||
}
|
||||
}
|
||||
|
||||
public Mind? GetMind(NetUserId user)
|
||||
{
|
||||
TryGetMind(user, out var mind);
|
||||
return mind;
|
||||
}
|
||||
|
||||
public bool TryGetMind(NetUserId user, [NotNullWhen(true)] out Mind? mind)
|
||||
{
|
||||
if (_userMinds.TryGetValue(user, out mind))
|
||||
{
|
||||
DebugTools.Assert(mind.UserId == user);
|
||||
DebugTools.Assert(_playerManager.GetPlayerData(user).ContentData() is not {} data
|
||||
|| data.Mind == mind);
|
||||
return true;
|
||||
}
|
||||
|
||||
DebugTools.Assert(_playerManager.GetPlayerData(user).ContentData()?.Mind == null);
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Don't call this unless you know what the hell you're doing.
|
||||
/// Use <see cref="MindSystem.TransferTo(Mind,System.Nullable{Robust.Shared.GameObjects.EntityUid},bool)"/> instead.
|
||||
@@ -91,29 +131,39 @@ public sealed class MindSystem : EntitySystem
|
||||
mind.Mind = null;
|
||||
}
|
||||
|
||||
private void OnShutdown(EntityUid uid, MindContainerComponent mindContainerComp, ComponentShutdown args)
|
||||
private void OnVisitingTerminating(EntityUid uid, VisitingMindComponent component, ref EntityTerminatingEvent args)
|
||||
{
|
||||
if (component.Mind != null)
|
||||
UnVisit(component.Mind);
|
||||
}
|
||||
|
||||
private void OnMindContainerTerminating(EntityUid uid, MindContainerComponent component, ref EntityTerminatingEvent args)
|
||||
{
|
||||
// Let's not create ghosts if not in the middle of the round.
|
||||
if (_gameTicker.RunLevel != GameRunLevel.InRound)
|
||||
return;
|
||||
|
||||
if (!TryGetMind(uid, out var mind, mindContainerComp))
|
||||
if (component.Mind is not { } mind)
|
||||
return;
|
||||
|
||||
if (mind.VisitingEntity is {Valid: true} visiting)
|
||||
// If the player is currently visiting some other entity, simply attach to that entity.
|
||||
if (mind.VisitingEntity is {Valid: true} visiting
|
||||
&& visiting != uid
|
||||
&& !Deleted(visiting)
|
||||
&& !Terminating(visiting))
|
||||
{
|
||||
if (TryComp(visiting, out GhostComponent? ghost))
|
||||
{
|
||||
_ghostSystem.SetCanReturnToBody(ghost, false);
|
||||
}
|
||||
|
||||
TransferTo(mind, visiting);
|
||||
if (TryComp(visiting, out GhostComponent? ghost))
|
||||
_ghostSystem.SetCanReturnToBody(ghost, false);
|
||||
return;
|
||||
}
|
||||
else if (mindContainerComp.GhostOnShutdown)
|
||||
|
||||
TransferTo(mind, null);
|
||||
|
||||
if (component.GhostOnShutdown && mind.Session != null)
|
||||
{
|
||||
// Changing an entities parents while deleting is VERY sus. This WILL throw exceptions.
|
||||
// TODO: just find the applicable spawn position directly without actually updating the transform's parent.
|
||||
Transform(uid).AttachToGridOrMap();
|
||||
var xform = Transform(uid);
|
||||
var gridId = xform.GridUid;
|
||||
var spawnPosition = Transform(uid).Coordinates;
|
||||
|
||||
// Use a regular timer here because the entity has probably been deleted.
|
||||
@@ -124,11 +174,8 @@ public sealed class MindSystem : EntitySystem
|
||||
return;
|
||||
|
||||
// Async this so that we don't throw if the grid we're on is being deleted.
|
||||
var gridId = spawnPosition.GetGridUid(EntityManager);
|
||||
if (!spawnPosition.IsValid(EntityManager) || gridId == EntityUid.Invalid || !_mapManager.GridExists(gridId))
|
||||
{
|
||||
if (!_mapManager.GridExists(gridId))
|
||||
spawnPosition = _gameTicker.GetObserverSpawnPoint();
|
||||
}
|
||||
|
||||
// TODO refactor observer spawning.
|
||||
// please.
|
||||
@@ -195,9 +242,10 @@ public sealed class MindSystem : EntitySystem
|
||||
|
||||
public Mind CreateMind(NetUserId? userId, string? name = null)
|
||||
{
|
||||
var mind = new Mind(userId);
|
||||
var mind = new Mind();
|
||||
mind.CharacterName = name;
|
||||
ChangeOwningPlayer(mind, userId);
|
||||
SetUserId(mind, userId);
|
||||
|
||||
return mind;
|
||||
}
|
||||
|
||||
@@ -262,7 +310,6 @@ public sealed class MindSystem : EntitySystem
|
||||
if (mind == null || mind.VisitingEntity == null)
|
||||
return;
|
||||
|
||||
DebugTools.Assert(mind.VisitingEntity != mind.OwnedEntity);
|
||||
RemoveVisitingEntity(mind);
|
||||
|
||||
if (mind.Session == null || mind.Session.AttachedEntity == mind.VisitingEntity)
|
||||
@@ -300,6 +347,25 @@ public sealed class MindSystem : EntitySystem
|
||||
RaiseLocalEvent(oldVisitingEnt, new MindUnvisitedMessage(), true);
|
||||
}
|
||||
|
||||
public void WipeMind(IPlayerSession player)
|
||||
{
|
||||
var mind = player.ContentData()?.Mind;
|
||||
DebugTools.Assert(GetMind(player.UserId) == mind);
|
||||
WipeMind(mind);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Detaches a mind from all entities and clears the user ID.
|
||||
/// </summary>
|
||||
public void WipeMind(Mind? mind)
|
||||
{
|
||||
if (mind == null)
|
||||
return;
|
||||
|
||||
TransferTo(mind, null);
|
||||
SetUserId(mind, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transfer this mind's control over to a new entity.
|
||||
/// </summary>
|
||||
@@ -316,12 +382,8 @@ public sealed class MindSystem : EntitySystem
|
||||
/// </exception>
|
||||
public void TransferTo(Mind mind, EntityUid? entity, bool ghostCheckOverride = false)
|
||||
{
|
||||
// Looks like caller just wants us to go back to normal.
|
||||
if (entity == mind.OwnedEntity)
|
||||
{
|
||||
UnVisit(mind);
|
||||
return;
|
||||
}
|
||||
|
||||
MindContainerComponent? component = null;
|
||||
var alreadyAttached = false;
|
||||
@@ -382,51 +444,6 @@ public sealed class MindSystem : EntitySystem
|
||||
}
|
||||
}
|
||||
|
||||
public void ChangeOwningPlayer(Mind mind, NetUserId? newOwner)
|
||||
{
|
||||
// Make sure to remove control from our old owner if they're logged in.
|
||||
var oldSession = mind.Session;
|
||||
oldSession?.AttachToEntity(null);
|
||||
|
||||
if (mind.UserId.HasValue)
|
||||
{
|
||||
if (_playerManager.TryGetPlayerData(mind.UserId.Value, out var oldUncast))
|
||||
{
|
||||
var data = oldUncast.ContentData();
|
||||
DebugTools.AssertNotNull(data);
|
||||
data!.UpdateMindFromMindChangeOwningPlayer(null);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Warning($"Mind UserId {newOwner} is does not exist in PlayerManager");
|
||||
}
|
||||
}
|
||||
|
||||
SetUserId(mind, newOwner);
|
||||
if (!newOwner.HasValue)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_playerManager.TryGetPlayerData(newOwner.Value, out var uncast))
|
||||
{
|
||||
// This restriction is because I'm too lazy to initialize the player data
|
||||
// for a client that hasn't logged in yet.
|
||||
// Go ahead and remove it if you need.
|
||||
throw new ArgumentException("New owner must have previously logged into the server.", nameof(newOwner));
|
||||
}
|
||||
|
||||
// PlayerData? newOwnerData = null;
|
||||
var newOwnerData = uncast.ContentData();
|
||||
|
||||
// Yank new owner out of their old mind too.
|
||||
// Can I mention how much I love the word yank?
|
||||
DebugTools.AssertNotNull(newOwnerData);
|
||||
if (newOwnerData!.Mind != null)
|
||||
ChangeOwningPlayer(newOwnerData.Mind, null);
|
||||
newOwnerData.UpdateMindFromMindChangeOwningPlayer(mind);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an objective to this mind.
|
||||
/// </summary>
|
||||
@@ -569,19 +586,56 @@ public sealed class MindSystem : EntitySystem
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the Mind's UserId and Session
|
||||
/// Sets the Mind's UserId, Session, and updates the player's PlayerData.
|
||||
/// This should have no direct effect on the entity that any mind is connected to, but it may change a player's attached entity.
|
||||
/// </summary>
|
||||
/// <param name="mind"></param>
|
||||
/// <param name="userId"></param>
|
||||
private void SetUserId(Mind mind, NetUserId? userId)
|
||||
public void SetUserId(Mind mind, NetUserId? userId)
|
||||
{
|
||||
mind.UserId = userId;
|
||||
|
||||
if (!userId.HasValue)
|
||||
if (mind.UserId == userId)
|
||||
return;
|
||||
|
||||
if (userId != null && !_playerManager.TryGetPlayerData(userId.Value, out _))
|
||||
{
|
||||
Log.Error($"Attempted to set mind user to invalid value {userId}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mind.Session != null)
|
||||
{
|
||||
mind.Session.AttachToEntity(null);
|
||||
mind.Session = null;
|
||||
}
|
||||
|
||||
if (mind.UserId != null)
|
||||
{
|
||||
_userMinds.Remove(mind.UserId.Value);
|
||||
if (_playerManager.GetPlayerData(mind.UserId.Value).ContentData() is { } oldData)
|
||||
oldData.Mind = null;
|
||||
mind.UserId = null;
|
||||
}
|
||||
|
||||
if (userId == null)
|
||||
{
|
||||
DebugTools.AssertNull(mind.Session);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_userMinds.TryGetValue(userId.Value, out var oldMind))
|
||||
SetUserId(oldMind, null);
|
||||
|
||||
DebugTools.AssertNull(_playerManager.GetPlayerData(userId.Value).ContentData()?.Mind);
|
||||
|
||||
_userMinds[userId.Value] = mind;
|
||||
mind.UserId = userId;
|
||||
|
||||
_playerManager.TryGetSessionById(userId.Value, out var ret);
|
||||
mind.Session = ret;
|
||||
|
||||
// session may be null, but user data may still exist for disconnected players.
|
||||
if (_playerManager.GetPlayerData(userId.Value).ContentData() is { } data)
|
||||
data.Mind = mind;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Server.Mind;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Network;
|
||||
@@ -27,8 +28,8 @@ namespace Content.Server.Players
|
||||
/// The currently occupied mind of the player owning this data.
|
||||
/// DO NOT DIRECTLY SET THIS UNLESS YOU KNOW WHAT YOU'RE DOING.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public Mind.Mind? Mind { get; private set; }
|
||||
[ViewVariables, Access(typeof(MindSystem), typeof(GameTicker))]
|
||||
public Mind.Mind? Mind { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If true, the player is an admin and they explicitly de-adminned mid-game,
|
||||
@@ -36,27 +37,6 @@ namespace Content.Server.Players
|
||||
/// </summary>
|
||||
public bool ExplicitlyDeadminned { get; set; }
|
||||
|
||||
public void WipeMind()
|
||||
{
|
||||
var entityManager = IoCManager.Resolve<IEntityManager>();
|
||||
var mindSystem = entityManager.System<MindSystem>();
|
||||
|
||||
// This will ensure Mind == null
|
||||
if (Mind == null)
|
||||
return;
|
||||
|
||||
mindSystem.TransferTo(Mind, null);
|
||||
mindSystem.ChangeOwningPlayer(Mind, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called from Mind.ChangeOwningPlayer *and nowhere else.*
|
||||
/// </summary>
|
||||
public void UpdateMindFromMindChangeOwningPlayer(Mind.Mind? mind)
|
||||
{
|
||||
Mind = mind;
|
||||
}
|
||||
|
||||
public PlayerData(NetUserId userId, string name)
|
||||
{
|
||||
UserId = userId;
|
||||
|
||||
Reference in New Issue
Block a user