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)) {