Remove ghost role component references (#15262)
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
using Content.Server.Mind.Commands;
|
||||
using Robust.Server.Player;
|
||||
|
||||
namespace Content.Server.Ghost.Roles.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
[Access(typeof(GhostRoleSystem))]
|
||||
public abstract class GhostRoleComponent : Component
|
||||
public sealed class GhostRoleComponent : Component
|
||||
{
|
||||
[DataField("name")] public string _roleName = "Unknown";
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace Content.Server.Ghost.Roles.Components
|
||||
/// Whether the <see cref="MakeSentientCommand"/> should run on the mob.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)] [DataField("makeSentient")]
|
||||
protected bool MakeSentient = true;
|
||||
public bool MakeSentient = true;
|
||||
|
||||
/// <summary>
|
||||
/// The probability that this ghost role will be available after init.
|
||||
@@ -83,7 +83,5 @@ namespace Content.Server.Ghost.Roles.Components
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("reregister")]
|
||||
public bool ReregisterOnGhost { get; set; } = true;
|
||||
|
||||
public abstract bool Take(IPlayerSession session);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,67 +1,26 @@
|
||||
using Content.Server.Mind.Commands;
|
||||
using Content.Server.Mind.Components;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
using Content.Server.Ghost.Roles.Events;
|
||||
|
||||
namespace Content.Server.Ghost.Roles.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Allows a ghost to take this role, spawning a new entity.
|
||||
/// </summary>
|
||||
[RegisterComponent, ComponentReference(typeof(GhostRoleComponent))]
|
||||
public sealed class GhostRoleMobSpawnerComponent : GhostRoleComponent
|
||||
[RegisterComponent]
|
||||
[Access(typeof(GhostRoleSystem))]
|
||||
public sealed class GhostRoleMobSpawnerComponent : Component
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entMan = default!;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)] [DataField("deleteOnSpawn")]
|
||||
private bool _deleteOnSpawn = true;
|
||||
public bool DeleteOnSpawn = true;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)] [DataField("availableTakeovers")]
|
||||
private int _availableTakeovers = 1;
|
||||
public int AvailableTakeovers = 1;
|
||||
|
||||
[ViewVariables]
|
||||
private int _currentTakeovers = 0;
|
||||
public int CurrentTakeovers = 0;
|
||||
|
||||
[CanBeNull]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("prototype", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
|
||||
public string? Prototype { get; private set; }
|
||||
|
||||
public override bool Take(IPlayerSession session)
|
||||
{
|
||||
if (Taken)
|
||||
return false;
|
||||
|
||||
if (string.IsNullOrEmpty(Prototype))
|
||||
throw new NullReferenceException("Prototype string cannot be null or empty!");
|
||||
|
||||
var mob = _entMan.SpawnEntity(Prototype, _entMan.GetComponent<TransformComponent>(Owner).Coordinates);
|
||||
var xform = _entMan.GetComponent<TransformComponent>(mob);
|
||||
xform.AttachToGridOrMap();
|
||||
|
||||
var spawnedEvent = new GhostRoleSpawnerUsedEvent(Owner, mob);
|
||||
_entMan.EventBus.RaiseLocalEvent(mob, spawnedEvent, false);
|
||||
|
||||
if (MakeSentient)
|
||||
MakeSentientCommand.MakeSentient(mob, _entMan, AllowMovement, AllowSpeech);
|
||||
|
||||
mob.EnsureComponent<MindComponent>();
|
||||
|
||||
var ghostRoleSystem = EntitySystem.Get<GhostRoleSystem>();
|
||||
ghostRoleSystem.GhostRoleInternalCreateMindAndTransfer(session, Owner, mob, this);
|
||||
|
||||
if (++_currentTakeovers < _availableTakeovers)
|
||||
return true;
|
||||
|
||||
Taken = true;
|
||||
|
||||
if (_deleteOnSpawn)
|
||||
_entMan.QueueDeleteEntity(Owner);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,36 +1,11 @@
|
||||
using Content.Server.Mind.Commands;
|
||||
using Content.Server.Mind.Components;
|
||||
using Robust.Server.Player;
|
||||
|
||||
namespace Content.Server.Ghost.Roles.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Allows a ghost to take over the Owner entity.
|
||||
/// </summary>
|
||||
[RegisterComponent, ComponentReference(typeof(GhostRoleComponent))]
|
||||
public sealed class GhostTakeoverAvailableComponent : GhostRoleComponent
|
||||
[RegisterComponent]
|
||||
[Access(typeof(GhostRoleSystem))]
|
||||
public sealed class GhostTakeoverAvailableComponent : Component
|
||||
{
|
||||
public override bool Take(IPlayerSession session)
|
||||
{
|
||||
if (Taken)
|
||||
return false;
|
||||
|
||||
Taken = true;
|
||||
|
||||
var mind = Owner.EnsureComponent<MindComponent>();
|
||||
|
||||
if (mind.HasMind)
|
||||
return false;
|
||||
|
||||
if (MakeSentient)
|
||||
MakeSentientCommand.MakeSentient(Owner, IoCManager.Resolve<IEntityManager>(), AllowMovement, AllowSpeech);
|
||||
|
||||
var ghostRoleSystem = EntitySystem.Get<GhostRoleSystem>();
|
||||
ghostRoleSystem.GhostRoleInternalCreateMindAndTransfer(session, Owner, Owner, this);
|
||||
|
||||
ghostRoleSystem.UnregisterGhostRole(this);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
using Robust.Server.Player;
|
||||
|
||||
namespace Content.Server.Ghost.Roles.Components;
|
||||
|
||||
[ByRefEvent]
|
||||
public record struct TakeGhostRoleEvent(IPlayerSession Player)
|
||||
{
|
||||
public bool TookRole { get; set; }
|
||||
}
|
||||
@@ -2,7 +2,9 @@ using Content.Server.Administration.Logs;
|
||||
using Content.Server.EUI;
|
||||
using Content.Server.Ghost.Components;
|
||||
using Content.Server.Ghost.Roles.Components;
|
||||
using Content.Server.Ghost.Roles.Events;
|
||||
using Content.Server.Ghost.Roles.UI;
|
||||
using Content.Server.Mind.Commands;
|
||||
using Content.Server.Mind.Components;
|
||||
using Content.Server.Players;
|
||||
using Content.Shared.Administration;
|
||||
@@ -30,6 +32,7 @@ namespace Content.Server.Ghost.Roles
|
||||
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly FollowerSystem _followerSystem = default!;
|
||||
[Dependency] private readonly TransformSystem _transform = default!;
|
||||
|
||||
private uint _nextRoleIdentifier;
|
||||
private bool _needsUpdateGhostRoleCount = true;
|
||||
@@ -51,22 +54,27 @@ namespace Content.Server.Ghost.Roles
|
||||
SubscribeLocalEvent<GhostTakeoverAvailableComponent, MobStateChangedEvent>(OnMobStateChanged);
|
||||
SubscribeLocalEvent<GhostRoleComponent, ComponentInit>(OnInit);
|
||||
SubscribeLocalEvent<GhostRoleComponent, ComponentShutdown>(OnShutdown);
|
||||
SubscribeLocalEvent<GhostRoleMobSpawnerComponent, TakeGhostRoleEvent>(OnSpawnerTakeRole);
|
||||
SubscribeLocalEvent<GhostTakeoverAvailableComponent, TakeGhostRoleEvent>(OnTakeoverTakeRole);
|
||||
_playerManager.PlayerStatusChanged += PlayerStatusChanged;
|
||||
}
|
||||
|
||||
private void OnMobStateChanged(EntityUid uid, GhostRoleComponent component, MobStateChangedEvent args)
|
||||
private void OnMobStateChanged(EntityUid uid, GhostTakeoverAvailableComponent component, MobStateChangedEvent args)
|
||||
{
|
||||
if (!TryComp(uid, out GhostRoleComponent? ghostRole))
|
||||
return;
|
||||
|
||||
switch (args.NewMobState)
|
||||
{
|
||||
case MobState.Alive:
|
||||
{
|
||||
if (!component.Taken)
|
||||
RegisterGhostRole(component);
|
||||
if (!ghostRole.Taken)
|
||||
RegisterGhostRole(ghostRole);
|
||||
break;
|
||||
}
|
||||
case MobState.Critical:
|
||||
case MobState.Dead:
|
||||
UnregisterGhostRole(component);
|
||||
UnregisterGhostRole(ghostRole);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -180,7 +188,11 @@ namespace Content.Server.Ghost.Roles
|
||||
public void Takeover(IPlayerSession player, uint identifier)
|
||||
{
|
||||
if (!_ghostRoles.TryGetValue(identifier, out var role)) return;
|
||||
if (!role.Take(player)) return;
|
||||
|
||||
var ev = new TakeGhostRoleEvent(player);
|
||||
RaiseLocalEvent(role.Owner, ref ev);
|
||||
|
||||
if (!ev.TookRole) return;
|
||||
|
||||
if (player.AttachedEntity != null)
|
||||
_adminLogger.Add(LogType.GhostRoleTaken, LogImpact.Low, $"{player:player} took the {role.RoleName:roleName} ghost role {ToPrettyString(player.AttachedEntity.Value):entity}");
|
||||
@@ -239,18 +251,24 @@ namespace Content.Server.Ghost.Roles
|
||||
|
||||
private void OnMindAdded(EntityUid uid, GhostTakeoverAvailableComponent component, MindAddedMessage args)
|
||||
{
|
||||
component.Taken = true;
|
||||
UnregisterGhostRole(component);
|
||||
}
|
||||
|
||||
private void OnMindRemoved(EntityUid uid, GhostRoleComponent component, MindRemovedMessage args)
|
||||
{
|
||||
// Avoid re-registering it for duplicate entries and potential exceptions.
|
||||
if (!component.ReregisterOnGhost || component.LifeStage > ComponentLifeStage.Running)
|
||||
if (!TryComp(uid, out GhostRoleComponent? ghostRole))
|
||||
return;
|
||||
|
||||
component.Taken = false;
|
||||
RegisterGhostRole(component);
|
||||
ghostRole.Taken = true;
|
||||
UnregisterGhostRole(ghostRole);
|
||||
}
|
||||
|
||||
private void OnMindRemoved(EntityUid uid, GhostTakeoverAvailableComponent component, MindRemovedMessage args)
|
||||
{
|
||||
if (!TryComp(uid, out GhostRoleComponent? ghostRole))
|
||||
return;
|
||||
|
||||
// Avoid re-registering it for duplicate entries and potential exceptions.
|
||||
if (!ghostRole.ReregisterOnGhost || component.LifeStage > ComponentLifeStage.Running)
|
||||
return;
|
||||
|
||||
ghostRole.Taken = false;
|
||||
RegisterGhostRole(ghostRole);
|
||||
}
|
||||
|
||||
public void Reset(RoundRestartCleanupEvent ev)
|
||||
@@ -282,6 +300,73 @@ namespace Content.Server.Ghost.Roles
|
||||
{
|
||||
UnregisterGhostRole(role);
|
||||
}
|
||||
|
||||
private void OnSpawnerTakeRole(EntityUid uid, GhostRoleMobSpawnerComponent component, ref TakeGhostRoleEvent args)
|
||||
{
|
||||
if (!TryComp(uid, out GhostRoleComponent? ghostRole) ||
|
||||
ghostRole.Taken)
|
||||
{
|
||||
args.TookRole = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(component.Prototype))
|
||||
throw new NullReferenceException("Prototype string cannot be null or empty!");
|
||||
|
||||
var mob = Spawn(component.Prototype, Transform(uid).Coordinates);
|
||||
_transform.AttachToGridOrMap(mob);
|
||||
|
||||
var spawnedEvent = new GhostRoleSpawnerUsedEvent(uid, mob);
|
||||
RaiseLocalEvent(mob, spawnedEvent);
|
||||
|
||||
if (ghostRole.MakeSentient)
|
||||
MakeSentientCommand.MakeSentient(mob, EntityManager, ghostRole.AllowMovement, ghostRole.AllowSpeech);
|
||||
|
||||
mob.EnsureComponent<MindComponent>();
|
||||
|
||||
GhostRoleInternalCreateMindAndTransfer(args.Player, uid, mob, ghostRole);
|
||||
|
||||
if (++component.CurrentTakeovers < component.AvailableTakeovers)
|
||||
{
|
||||
args.TookRole = true;
|
||||
return;
|
||||
}
|
||||
|
||||
ghostRole.Taken = true;
|
||||
|
||||
if (component.DeleteOnSpawn)
|
||||
QueueDel(uid);
|
||||
|
||||
args.TookRole = true;
|
||||
}
|
||||
|
||||
private void OnTakeoverTakeRole(EntityUid uid, GhostTakeoverAvailableComponent component, ref TakeGhostRoleEvent args)
|
||||
{
|
||||
if (!TryComp(uid, out GhostRoleComponent? ghostRole) ||
|
||||
ghostRole.Taken)
|
||||
{
|
||||
args.TookRole = false;
|
||||
return;
|
||||
}
|
||||
|
||||
ghostRole.Taken = true;
|
||||
|
||||
var mind = EnsureComp<MindComponent>(uid);
|
||||
|
||||
if (mind.HasMind)
|
||||
{
|
||||
args.TookRole = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (ghostRole.MakeSentient)
|
||||
MakeSentientCommand.MakeSentient(uid, EntityManager, ghostRole.AllowMovement, ghostRole.AllowSpeech);
|
||||
|
||||
GhostRoleInternalCreateMindAndTransfer(args.Player, uid, uid, ghostRole);
|
||||
UnregisterGhostRole(ghostRole);
|
||||
|
||||
args.TookRole = true;
|
||||
}
|
||||
}
|
||||
|
||||
[AnyCommand]
|
||||
|
||||
@@ -46,16 +46,23 @@ namespace Content.Server.Ghost.Roles
|
||||
var description = args[2];
|
||||
var rules = args.Length >= 4 ? args[3] : Loc.GetString("ghost-role-component-default-rules");
|
||||
|
||||
if (entityManager.TryGetComponent(uid, out GhostRoleComponent? ghostRole))
|
||||
{
|
||||
shell.WriteLine($"Entity {metaData.EntityName} with id {uid} already has a {nameof(GhostRoleComponent)}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (entityManager.TryGetComponent(uid, out GhostTakeoverAvailableComponent? takeOver))
|
||||
{
|
||||
shell.WriteLine($"Entity {metaData.EntityName} with id {uid} already has a {nameof(GhostTakeoverAvailableComponent)}");
|
||||
return;
|
||||
}
|
||||
|
||||
takeOver = entityManager.AddComponent<GhostTakeoverAvailableComponent>(uid);
|
||||
takeOver.RoleName = name;
|
||||
takeOver.RoleDescription = description;
|
||||
takeOver.RoleRules = rules;
|
||||
ghostRole = entityManager.AddComponent<GhostRoleComponent>(uid);
|
||||
entityManager.AddComponent<GhostTakeoverAvailableComponent>(uid);
|
||||
ghostRole.RoleName = name;
|
||||
ghostRole.RoleDescription = description;
|
||||
ghostRole.RoleRules = rules;
|
||||
|
||||
shell.WriteLine($"Made entity {metaData.EntityName} a ghost role.");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user