Ghost roles create new minds, better tracking of roles at round end screen (#5175)
* Ghost roles now get new Minds
* Some round start/end button stuff
* Mind tracking for better round end reports
* Make traitor kill objectives use mind CharacterName rather than actual occupied entity ("kill brain" prevention)
* Transition over to EntityUid for mind stuff because that's the only way to do it
* BrainSystem fix for PR rebase
This commit is contained in:
@@ -92,7 +92,7 @@ namespace Content.Server.Mind.Components
|
||||
EntitySystem.Get<SharedGhostSystem>().SetCanReturnToBody(ghost, false);
|
||||
}
|
||||
|
||||
Mind!.TransferTo(visiting);
|
||||
Mind!.TransferTo(visiting.Uid);
|
||||
}
|
||||
else if (GhostOnShutdown)
|
||||
{
|
||||
@@ -116,7 +116,7 @@ namespace Content.Server.Mind.Components
|
||||
if (Mind != null)
|
||||
{
|
||||
ghost.Name = Mind.CharacterName ?? string.Empty;
|
||||
Mind.TransferTo(ghost);
|
||||
Mind.TransferTo(ghost.Uid);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -37,12 +37,14 @@ namespace Content.Server.Mind
|
||||
private readonly List<Objective> _objectives = new();
|
||||
|
||||
/// <summary>
|
||||
/// Creates the new mind attached to a specific player session.
|
||||
/// Creates the new 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 owning player.</param>
|
||||
/// <param name="userId">The session ID of the original owner (may get credited).</param>
|
||||
public Mind(NetUserId userId)
|
||||
{
|
||||
UserId = userId;
|
||||
OriginalOwnerUserId = userId;
|
||||
}
|
||||
|
||||
// TODO: This session should be able to be changed, probably.
|
||||
@@ -52,6 +54,13 @@ namespace Content.Server.Mind
|
||||
[ViewVariables]
|
||||
public NetUserId? UserId { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The session ID of the original owner, if any.
|
||||
/// May end up used for round-end information (as the owner may have abandoned Mind since)
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public NetUserId OriginalOwnerUserId { get; }
|
||||
|
||||
[ViewVariables]
|
||||
public bool IsVisitingEntity => VisitingEntity != null;
|
||||
|
||||
@@ -234,12 +243,10 @@ namespace Content.Server.Mind
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Transfer this mind's control over to a new entity.
|
||||
/// </summary>
|
||||
/// <param name="entity">
|
||||
/// <param name="entityUid">
|
||||
/// The entity to control.
|
||||
/// Can be null, in which case it will simply detach the mind from any entity.
|
||||
/// </param>
|
||||
@@ -249,28 +256,31 @@ namespace Content.Server.Mind
|
||||
/// <exception cref="ArgumentException">
|
||||
/// Thrown if <paramref name="entity"/> is already owned by another mind.
|
||||
/// </exception>
|
||||
public void TransferTo(IEntity? entity, bool ghostCheckOverride = false)
|
||||
public void TransferTo(EntityUid? entityUid, bool ghostCheckOverride = false)
|
||||
{
|
||||
var entMan = IoCManager.Resolve<IEntityManager>();
|
||||
IEntity? entity = (entityUid != null) ? entMan.GetEntity(entityUid.Value) : null;
|
||||
|
||||
MindComponent? component = null;
|
||||
var alreadyAttached = false;
|
||||
|
||||
if (entity != null)
|
||||
if (entityUid != null)
|
||||
{
|
||||
if (!entity.TryGetComponent(out component))
|
||||
if (!entMan.TryGetComponent<MindComponent>(entityUid.Value, out component))
|
||||
{
|
||||
component = entity.AddComponent<MindComponent>();
|
||||
component = entMan.AddComponent<MindComponent>(entityUid.Value);
|
||||
}
|
||||
else if (component.HasMind)
|
||||
else if (component!.HasMind)
|
||||
{
|
||||
EntitySystem.Get<GameTicker>().OnGhostAttempt(component.Mind!, false);
|
||||
}
|
||||
|
||||
if (entity.TryGetComponent(out ActorComponent? actor))
|
||||
if (entMan.TryGetComponent<ActorComponent>(entityUid.Value, out var actor))
|
||||
{
|
||||
// Happens when transferring to your currently visited entity.
|
||||
if (actor.PlayerSession != Session)
|
||||
{
|
||||
throw new ArgumentException("Visit target already has a session.", nameof(entity));
|
||||
throw new ArgumentException("Visit target already has a session.", nameof(entityUid));
|
||||
}
|
||||
|
||||
alreadyAttached = true;
|
||||
@@ -298,11 +308,6 @@ namespace Content.Server.Mind
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveOwningPlayer()
|
||||
{
|
||||
UserId = null;
|
||||
}
|
||||
|
||||
public void ChangeOwningPlayer(NetUserId? newOwner)
|
||||
{
|
||||
var playerMgr = IoCManager.Resolve<IPlayerManager>();
|
||||
@@ -329,7 +334,7 @@ namespace Content.Server.Mind
|
||||
{
|
||||
var data = playerMgr.GetPlayerData(UserId.Value).ContentData();
|
||||
DebugTools.AssertNotNull(data);
|
||||
data!.Mind = null;
|
||||
data!.UpdateMindFromMindChangeOwningPlayer(null);
|
||||
}
|
||||
|
||||
UserId = newOwner;
|
||||
@@ -342,7 +347,7 @@ namespace Content.Server.Mind
|
||||
// Can I mention how much I love the word yank?
|
||||
DebugTools.AssertNotNull(newOwnerData);
|
||||
newOwnerData!.Mind?.ChangeOwningPlayer(null);
|
||||
newOwnerData.Mind = this;
|
||||
newOwnerData.UpdateMindFromMindChangeOwningPlayer(this);
|
||||
}
|
||||
|
||||
public void Visit(IEntity entity)
|
||||
|
||||
46
Content.Server/Mind/MindTrackerSystem.cs
Normal file
46
Content.Server/Mind/MindTrackerSystem.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Server.Mind.Components;
|
||||
using Content.Shared.GameTicking;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Server.Mind
|
||||
{
|
||||
/// <summary>
|
||||
/// This is absolutely evil.
|
||||
/// It tracks all mind changes and logs all the Mind objects.
|
||||
/// This is so that when round end comes around, there's a coherent list of all Minds that were in play during the round.
|
||||
/// The Minds themselves contain metadata about their owners.
|
||||
/// Anyway, this is because disconnected people and ghost roles have been breaking round end statistics for way too long.
|
||||
/// </summary>
|
||||
public class MindTrackerSystem : EntitySystem
|
||||
{
|
||||
[ViewVariables]
|
||||
public readonly HashSet<Mind> AllMinds = new();
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<RoundRestartCleanupEvent>(Reset);
|
||||
SubscribeLocalEvent<MindComponent, MindAddedMessage>(OnMindAdded);
|
||||
}
|
||||
|
||||
void Reset(RoundRestartCleanupEvent ev)
|
||||
{
|
||||
AllMinds.Clear();
|
||||
}
|
||||
|
||||
void OnMindAdded(EntityUid uid, MindComponent mc, MindAddedMessage args)
|
||||
{
|
||||
var mind = mc.Mind;
|
||||
if (mind != null)
|
||||
AllMinds.Add(mind);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user