Files
tbd-station-14/Content.Server/Mind/MindSystem.cs
Vera Aguilera Puerto bcef118489 Extra checks in MindSystem entity deletion ghost spawning.
I have a feeling this might be the cause of the round restart bugs, so make sure the round hasn't ended in the spawned timer code and log every ghost spawned by this.
2022-03-07 12:56:19 +01:00

150 lines
5.4 KiB
C#

using System;
using Content.Server.GameTicking;
using Content.Server.Ghost;
using Content.Server.Ghost.Components;
using Content.Server.Mind.Components;
using Content.Shared.Examine;
using Content.Shared.Ghost;
using Content.Shared.MobState.Components;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Map;
using Robust.Shared.Timing;
namespace Content.Server.Mind;
public sealed class MindSystem : EntitySystem
{
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly GameTicker _gameTicker = default!;
[Dependency] private readonly GhostSystem _ghostSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<MindComponent, ComponentShutdown>(OnShutdown);
SubscribeLocalEvent<MindComponent, ExaminedEvent>(OnExamined);
}
public void SetGhostOnShutdown(EntityUid uid, bool value, MindComponent? mind = null)
{
if (!Resolve(uid, ref mind))
return;
mind.GhostOnShutdown = value;
}
/// <summary>
/// Don't call this unless you know what the hell you're doing.
/// Use <see cref="Mind.TransferTo(System.Nullable{Robust.Shared.GameObjects.EntityUid},bool)"/> instead.
/// If that doesn't cover it, make something to cover it.
/// </summary>
public void InternalAssignMind(EntityUid uid, Mind value, MindComponent? mind = null)
{
if (!Resolve(uid, ref mind))
return;
mind.Mind = value;
RaiseLocalEvent(uid, new MindAddedMessage());
}
/// <summary>
/// Don't call this unless you know what the hell you're doing.
/// Use <see cref="Mind.TransferTo(System.Nullable{Robust.Shared.GameObjects.EntityUid},bool)"/> instead.
/// If that doesn't cover it, make something to cover it.
/// </summary>
public void InternalEjectMind(EntityUid uid, MindComponent? mind = null)
{
if (!Resolve(uid, ref mind))
return;
if (!Deleted(uid))
RaiseLocalEvent(uid, new MindRemovedMessage());
mind.Mind = null;
}
private void OnShutdown(EntityUid uid, MindComponent mind, ComponentShutdown args)
{
// Let's not create ghosts if not in the middle of the round.
if (_gameTicker.RunLevel != GameRunLevel.InRound)
return;
if (mind.HasMind)
{
if (mind.Mind?.VisitingEntity is {Valid: true} visiting)
{
if (TryComp(visiting, out GhostComponent? ghost))
{
_ghostSystem.SetCanReturnToBody(ghost, false);
}
mind.Mind!.TransferTo(visiting);
}
else if (mind.GhostOnShutdown)
{
var spawnPosition = Transform(uid).Coordinates;
// Use a regular timer here because the entity has probably been deleted.
Timer.Spawn(0, () =>
{
// Make extra sure the round didn't end between spawning the timer and it being executed.
if (_gameTicker.RunLevel != GameRunLevel.InRound)
return;
// Async this so that we don't throw if the grid we're on is being deleted.
var gridId = spawnPosition.GetGridId(EntityManager);
if (!spawnPosition.IsValid(EntityManager) || gridId == GridId.Invalid || !_mapManager.GridExists(gridId))
{
spawnPosition = _gameTicker.GetObserverSpawnPoint();
}
var ghost = Spawn("MobObserver", spawnPosition);
var ghostComponent = Comp<GhostComponent>(ghost);
_ghostSystem.SetCanReturnToBody(ghostComponent, false);
// Log these to make sure they're not causing the GameTicker round restart bugs...
Logger.DebugS("mind", $"Entity \"{ToPrettyString(uid)}\" for {mind.Mind?.CharacterName} was deleted, spawned \"{ToPrettyString(ghost)}\".");
if (mind.Mind == null)
return;
var val = mind.Mind.CharacterName ?? string.Empty;
MetaData(ghost).EntityName = val;
mind.Mind.TransferTo(ghost);
});
}
}
}
private void OnExamined(EntityUid uid, MindComponent mind, ExaminedEvent args)
{
if (!mind.ShowExamineInfo || !args.IsInDetailsRange)
{
return;
}
var dead = TryComp<MobStateComponent?>(uid, out var state) && state.IsDead();
if (dead)
{
if (mind.Mind?.Session == null) {
// Player has no session attached and dead
args.PushMarkup($"[color=yellow]{Loc.GetString("mind-component-no-mind-and-dead-text", ("ent", uid))}[/color]");
} else {
// Player is dead with session
args.PushMarkup($"[color=red]{Loc.GetString("comp-mind-examined-dead", ("ent", uid))}[/color]");
}
}
else if (!mind.HasMind)
{
args.PushMarkup($"[color=mediumpurple]{Loc.GetString("comp-mind-examined-catatonic", ("ent", uid))}[/color]");
}
else if (mind.Mind?.Session == null)
{
args.PushMarkup($"[color=yellow]{Loc.GetString("comp-mind-examined-ssd", ("ent", uid))}[/color]");
}
}
}