From fb60a5695092b05e713476ff4f6b3960b17b1cff Mon Sep 17 00:00:00 2001
From: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com>
Date: Tue, 7 Nov 2023 14:16:32 +1100
Subject: [PATCH] Guardian bugfixes (#21467)
---
Content.Server/Guardian/GuardianComponent.cs | 10 ++-
.../Guardian/GuardianHostComponent.cs | 8 +-
Content.Server/Guardian/GuardianSystem.cs | 75 +++++++++++++------
3 files changed, 61 insertions(+), 32 deletions(-)
diff --git a/Content.Server/Guardian/GuardianComponent.cs b/Content.Server/Guardian/GuardianComponent.cs
index dcb9a8c05400ec..a54d03375679ef 100644
--- a/Content.Server/Guardian/GuardianComponent.cs
+++ b/Content.Server/Guardian/GuardianComponent.cs
@@ -9,24 +9,26 @@ public sealed partial class GuardianComponent : Component
///
/// The guardian host entity
///
- public EntityUid Host;
+ [DataField]
+ public EntityUid? Host;
///
/// Percentage of damage reflected from the guardian to the host
///
- [DataField("damageShare")]
+ [DataField]
public float DamageShare { get; set; } = 0.65f;
///
/// Maximum distance the guardian can travel before it's forced to recall, use YAML to set
///
- [DataField("distanceAllowed")]
+ [DataField]
public float DistanceAllowed { get; set; } = 5f;
///
/// If the guardian is currently manifested
///
- public bool GuardianLoose = false;
+ [DataField]
+ public bool GuardianLoose;
}
}
diff --git a/Content.Server/Guardian/GuardianHostComponent.cs b/Content.Server/Guardian/GuardianHostComponent.cs
index 6a747ae86a4cf2..e9d0e4affd21c0 100644
--- a/Content.Server/Guardian/GuardianHostComponent.cs
+++ b/Content.Server/Guardian/GuardianHostComponent.cs
@@ -1,6 +1,5 @@
using Robust.Shared.Containers;
using Robust.Shared.Prototypes;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
namespace Content.Server.Guardian
{
@@ -16,6 +15,7 @@ public sealed partial class GuardianHostComponent : Component
///
/// Can be null if the component is added at any time.
///
+ [DataField]
public EntityUid? HostedGuardian;
///
@@ -23,9 +23,9 @@ public sealed partial class GuardianHostComponent : Component
///
[ViewVariables] public ContainerSlot GuardianContainer = default!;
- [DataField("action", customTypeSerializer: typeof(PrototypeIdSerializer))]
- public string Action = "ActionToggleGuardian";
+ [DataField]
+ public EntProtoId Action = "ActionToggleGuardian";
- [DataField("actionEntity")] public EntityUid? ActionEntity;
+ [DataField] public EntityUid? ActionEntity;
}
}
diff --git a/Content.Server/Guardian/GuardianSystem.cs b/Content.Server/Guardian/GuardianSystem.cs
index b6121a7fbda42c..2847b45ba17bd8 100644
--- a/Content.Server/Guardian/GuardianSystem.cs
+++ b/Content.Server/Guardian/GuardianSystem.cs
@@ -41,10 +41,11 @@ public override void Initialize()
SubscribeLocalEvent(OnCreatorExamine);
SubscribeLocalEvent(OnDoAfter);
+ SubscribeLocalEvent(OnGuardianShutdown);
SubscribeLocalEvent(OnGuardianMove);
SubscribeLocalEvent(OnGuardianDamaged);
- SubscribeLocalEvent(OnGuardianPlayer);
- SubscribeLocalEvent(OnGuardianUnplayer);
+ SubscribeLocalEvent(OnGuardianPlayerAttached);
+ SubscribeLocalEvent(OnGuardianPlayerDetached);
SubscribeLocalEvent(OnHostInit);
SubscribeLocalEvent(OnHostMove);
@@ -56,6 +57,21 @@ public override void Initialize()
SubscribeLocalEvent(OnGuardianAttackAttempt);
}
+ private void OnGuardianShutdown(EntityUid uid, GuardianComponent component, ComponentShutdown args)
+ {
+ var host = component.Host;
+ component.Host = null;
+
+ if (!TryComp(host, out GuardianHostComponent? hostComponent))
+ return;
+
+ hostComponent.GuardianContainer.Remove(uid);
+ hostComponent.HostedGuardian = null;
+ Dirty(host.Value, hostComponent);
+ QueueDel(hostComponent.ActionEntity);
+ hostComponent.ActionEntity = null;
+ }
+
private void OnPerformAction(EntityUid uid, GuardianHostComponent component, GuardianToggleActionEvent args)
{
if (args.Handled)
@@ -67,24 +83,29 @@ private void OnPerformAction(EntityUid uid, GuardianHostComponent component, Gua
args.Handled = true;
}
- private void OnGuardianUnplayer(EntityUid uid, GuardianComponent component, PlayerDetachedEvent args)
+ private void OnGuardianPlayerDetached(EntityUid uid, GuardianComponent component, PlayerDetachedEvent args)
{
var host = component.Host;
-
- if (!TryComp(host, out var hostComponent) || LifeStage(host) >= EntityLifeStage.MapInitialized)
+ if (!TryComp(host, out var hostComponent) || TerminatingOrDeleted(host.Value))
+ {
+ QueueDel(uid);
return;
+ }
- RetractGuardian(host, hostComponent, uid, component);
+ RetractGuardian(host.Value, hostComponent, uid, component);
}
- private void OnGuardianPlayer(EntityUid uid, GuardianComponent component, PlayerAttachedEvent args)
+ private void OnGuardianPlayerAttached(EntityUid uid, GuardianComponent component, PlayerAttachedEvent args)
{
var host = component.Host;
if (!HasComp(host))
+ {
+ QueueDel(uid);
return;
+ }
- _popupSystem.PopupEntity(Loc.GetString("guardian-available"), host, host);
+ _popupSystem.PopupEntity(Loc.GetString("guardian-available"), host.Value, host.Value);
}
private void OnHostInit(EntityUid uid, GuardianHostComponent component, ComponentInit args)
@@ -95,14 +116,16 @@ private void OnHostInit(EntityUid uid, GuardianHostComponent component, Componen
private void OnHostShutdown(EntityUid uid, GuardianHostComponent component, ComponentShutdown args)
{
- if (component.HostedGuardian == null)
+ if (component.HostedGuardian is not {} guardian)
return;
- if (HasComp(component.HostedGuardian.Value))
+ // Ensure held items are dropped before deleting guardian.
+ if (HasComp(guardian))
_bodySystem.GibBody(component.HostedGuardian.Value);
- EntityManager.QueueDeleteEntity(component.HostedGuardian.Value);
- _actionSystem.RemoveAction(uid, component.ActionEntity);
+ QueueDel(guardian);
+ QueueDel(component.ActionEntity);
+ component.ActionEntity = null;
}
private void OnGuardianAttackAttempt(EntityUid uid, GuardianComponent component, AttackAttemptEvent args)
@@ -117,7 +140,7 @@ private void OnGuardianAttackAttempt(EntityUid uid, GuardianComponent component,
public void ToggleGuardian(EntityUid user, GuardianHostComponent hostComponent)
{
- if (hostComponent.HostedGuardian == null || !TryComp(hostComponent.HostedGuardian, out var guardianComponent))
+ if (!TryComp(hostComponent.HostedGuardian, out var guardianComponent))
return;
if (guardianComponent.GuardianLoose)
@@ -134,7 +157,7 @@ private void OnCreatorUse(EntityUid uid, GuardianCreatorComponent component, Use
if (args.Handled)
return;
- //args.Handled = true;
+ args.Handled = true;
UseCreator(args.User, args.User, uid, component);
}
@@ -143,7 +166,7 @@ private void OnCreatorInteract(EntityUid uid, GuardianCreatorComponent component
if (args.Handled || args.Target == null || !args.CanReach)
return;
- //args.Handled = true;
+ args.Handled = true;
UseCreator(args.User, args.Target.Value, uid, component);
}
private void UseCreator(EntityUid user, EntityUid target, EntityUid injector, GuardianCreatorComponent component)
@@ -194,6 +217,7 @@ private void OnDoAfter(EntityUid uid, GuardianCreatorComponent component, DoAfte
if (TryComp(guardian, out var guardianComp))
{
guardianComp.Host = args.Args.Target.Value;
+ // TODO this should be a data field, not a hardcoded path
_audio.Play("/Audio/Effects/guardian_inject.ogg", Filter.Pvs(args.Args.Target.Value), args.Args.Target.Value, true);
_popupSystem.PopupEntity(Loc.GetString("guardian-created"), args.Args.Target.Value, args.Args.Target.Value);
// Exhaust the activator
@@ -201,8 +225,8 @@ private void OnDoAfter(EntityUid uid, GuardianCreatorComponent component, DoAfte
}
else
{
- Logger.ErrorS("guardian", $"Tried to spawn a guardian that doesn't have {nameof(GuardianComponent)}");
- EntityManager.QueueDeleteEntity(guardian);
+ Log.Error($"Tried to spawn a guardian that doesn't have {nameof(GuardianComponent)}");
+ QueueDel(guardian);
}
args.Handled = true;
@@ -219,13 +243,14 @@ private void OnHostStateChange(EntityUid uid, GuardianHostComponent component, M
if (args.NewMobState == MobState.Critical)
{
_popupSystem.PopupEntity(Loc.GetString("guardian-host-critical-warn"), component.HostedGuardian.Value, component.HostedGuardian.Value);
+ // TODO this should be a data field, not a hardcoded path
_audio.Play("/Audio/Effects/guardian_warn.ogg", Filter.Pvs(component.HostedGuardian.Value), component.HostedGuardian.Value, true);
}
else if (args.NewMobState == MobState.Dead)
{
//TODO: Replace WithVariation with datafield
_audio.Play("/Audio/Voice/Human/malescream_guardian.ogg", Filter.Pvs(uid), uid, true, AudioHelpers.WithVariation(0.20f));
- EntityManager.RemoveComponent(uid);
+ RemComp(uid);
}
}
@@ -234,11 +259,11 @@ private void OnHostStateChange(EntityUid uid, GuardianHostComponent component, M
///
private void OnGuardianDamaged(EntityUid uid, GuardianComponent component, DamageChangedEvent args)
{
- if (args.DamageDelta == null)
+ if (args.DamageDelta == null || component.Host == null || component.DamageShare > 0)
return;
_damageSystem.TryChangeDamage(component.Host, args.DamageDelta * component.DamageShare, origin: args.Origin);
- _popupSystem.PopupEntity(Loc.GetString("guardian-entity-taking-damage"), component.Host, component.Host);
+ _popupSystem.PopupEntity(Loc.GetString("guardian-entity-taking-damage"), component.Host.Value, component.Host.Value);
}
@@ -256,8 +281,7 @@ private void OnCreatorExamine(EntityUid uid, GuardianCreatorComponent component,
///
private void OnHostMove(EntityUid uid, GuardianHostComponent component, ref MoveEvent args)
{
- if (component.HostedGuardian == null ||
- !TryComp(component.HostedGuardian, out GuardianComponent? guardianComponent) ||
+ if (!TryComp(component.HostedGuardian, out GuardianComponent? guardianComponent) ||
!guardianComponent.GuardianLoose)
{
return;
@@ -271,10 +295,10 @@ private void OnHostMove(EntityUid uid, GuardianHostComponent component, ref Move
///
private void OnGuardianMove(EntityUid uid, GuardianComponent component, ref MoveEvent args)
{
- if (!component.GuardianLoose)
+ if (!component.GuardianLoose || component.Host == null)
return;
- CheckGuardianMove(component.Host, uid, guardianComponent: component);
+ CheckGuardianMove(component.Host.Value, uid, guardianComponent: component);
}
///
@@ -288,6 +312,9 @@ private void CheckGuardianMove(
TransformComponent? hostXform = null,
TransformComponent? guardianXform = null)
{
+ if (TerminatingOrDeleted(guardianUid) || TerminatingOrDeleted(hostUid))
+ return;
+
if (!Resolve(hostUid, ref hostComponent, ref hostXform) ||
!Resolve(guardianUid, ref guardianComponent, ref guardianXform))
{