Fix followers getting sent to nullspace when target is polymorphed (#33878)

* Add an event for polymorph actions

* Subscribe FollowerSystem to the event

* Add check that unfollow target is actually current target.

* Make followers try to follow on state update; Dirty follower on follow.
This commit is contained in:
Tayrtahn
2025-02-11 16:34:24 -05:00
committed by GitHub
parent fa020ceef3
commit 46b19291ea
4 changed files with 38 additions and 2 deletions

View File

@@ -267,6 +267,10 @@ public sealed partial class PolymorphSystem : EntitySystem
if (PausedMap != null) if (PausedMap != null)
_transform.SetParent(uid, targetTransformComp, PausedMap.Value); _transform.SetParent(uid, targetTransformComp, PausedMap.Value);
// Raise an event to inform anything that wants to know about the entity swap
var ev = new PolymorphedEvent(uid, child, false);
RaiseLocalEvent(uid, ref ev);
return child; return child;
} }
@@ -339,6 +343,10 @@ public sealed partial class PolymorphSystem : EntitySystem
// if an item polymorph was picked up, put it back down after reverting // if an item polymorph was picked up, put it back down after reverting
_transform.AttachToGridOrMap(parent, parentXform); _transform.AttachToGridOrMap(parent, parentXform);
// Raise an event to inform anything that wants to know about the entity swap
var ev = new PolymorphedEvent(uid, parent, true);
RaiseLocalEvent(uid, ref ev);
_popup.PopupEntity(Loc.GetString("polymorph-revert-popup-generic", _popup.PopupEntity(Loc.GetString("polymorph-revert-popup-generic",
("parent", Identity.Entity(uid, EntityManager)), ("parent", Identity.Entity(uid, EntityManager)),
("child", Identity.Entity(parent, EntityManager))), ("child", Identity.Entity(parent, EntityManager))),

View File

@@ -4,7 +4,7 @@ namespace Content.Shared.Follower.Components;
[RegisterComponent] [RegisterComponent]
[Access(typeof(FollowerSystem))] [Access(typeof(FollowerSystem))]
[NetworkedComponent, AutoGenerateComponentState] [NetworkedComponent, AutoGenerateComponentState(RaiseAfterAutoHandleState = true)]
public sealed partial class FollowerComponent : Component public sealed partial class FollowerComponent : Component
{ {
[AutoNetworkedField, DataField("following")] [AutoNetworkedField, DataField("following")]

View File

@@ -6,6 +6,7 @@ using Content.Shared.Ghost;
using Content.Shared.Hands; using Content.Shared.Hands;
using Content.Shared.Movement.Events; using Content.Shared.Movement.Events;
using Content.Shared.Movement.Pulling.Events; using Content.Shared.Movement.Pulling.Events;
using Content.Shared.Polymorph;
using Content.Shared.Tag; using Content.Shared.Tag;
using Content.Shared.Verbs; using Content.Shared.Verbs;
using Robust.Shared.Containers; using Robust.Shared.Containers;
@@ -38,10 +39,12 @@ public sealed class FollowerSystem : EntitySystem
SubscribeLocalEvent<FollowerComponent, MoveInputEvent>(OnFollowerMove); SubscribeLocalEvent<FollowerComponent, MoveInputEvent>(OnFollowerMove);
SubscribeLocalEvent<FollowerComponent, PullStartedMessage>(OnPullStarted); SubscribeLocalEvent<FollowerComponent, PullStartedMessage>(OnPullStarted);
SubscribeLocalEvent<FollowerComponent, EntityTerminatingEvent>(OnFollowerTerminating); SubscribeLocalEvent<FollowerComponent, EntityTerminatingEvent>(OnFollowerTerminating);
SubscribeLocalEvent<FollowerComponent, AfterAutoHandleStateEvent>(OnAfterHandleState);
SubscribeLocalEvent<FollowedComponent, ComponentGetStateAttemptEvent>(OnFollowedAttempt); SubscribeLocalEvent<FollowedComponent, ComponentGetStateAttemptEvent>(OnFollowedAttempt);
SubscribeLocalEvent<FollowerComponent, GotEquippedHandEvent>(OnGotEquippedHand); SubscribeLocalEvent<FollowerComponent, GotEquippedHandEvent>(OnGotEquippedHand);
SubscribeLocalEvent<FollowedComponent, EntityTerminatingEvent>(OnFollowedTerminating); SubscribeLocalEvent<FollowedComponent, EntityTerminatingEvent>(OnFollowedTerminating);
SubscribeLocalEvent<FollowedComponent, PolymorphedEvent>(OnFollowedPolymorphed);
SubscribeLocalEvent<BeforeSaveEvent>(OnBeforeSave); SubscribeLocalEvent<BeforeSaveEvent>(OnBeforeSave);
} }
@@ -135,6 +138,11 @@ public sealed class FollowerSystem : EntitySystem
StopFollowingEntity(uid, component.Following, deparent: false); StopFollowingEntity(uid, component.Following, deparent: false);
} }
private void OnAfterHandleState(Entity<FollowerComponent> entity, ref AfterAutoHandleStateEvent args)
{
StartFollowingEntity(entity, entity.Comp.Following);
}
// Since we parent our observer to the followed entity, we need to detach // Since we parent our observer to the followed entity, we need to detach
// before they get deleted so that we don't get recursively deleted too. // before they get deleted so that we don't get recursively deleted too.
private void OnFollowedTerminating(EntityUid uid, FollowedComponent component, ref EntityTerminatingEvent args) private void OnFollowedTerminating(EntityUid uid, FollowedComponent component, ref EntityTerminatingEvent args)
@@ -142,6 +150,15 @@ public sealed class FollowerSystem : EntitySystem
StopAllFollowers(uid, component); StopAllFollowers(uid, component);
} }
private void OnFollowedPolymorphed(Entity<FollowedComponent> entity, ref PolymorphedEvent args)
{
foreach (var follower in entity.Comp.Following)
{
// Stop following the target's old entity and start following the new one
StartFollowingEntity(follower, args.NewEntity);
}
}
/// <summary> /// <summary>
/// Makes an entity follow another entity, by parenting to it. /// Makes an entity follow another entity, by parenting to it.
/// </summary> /// </summary>
@@ -202,6 +219,7 @@ public sealed class FollowerSystem : EntitySystem
RaiseLocalEvent(follower, followerEv); RaiseLocalEvent(follower, followerEv);
RaiseLocalEvent(entity, entityEv); RaiseLocalEvent(entity, entityEv);
Dirty(entity, followedComp); Dirty(entity, followedComp);
Dirty(follower, followerComp);
} }
/// <summary> /// <summary>
@@ -213,7 +231,7 @@ public sealed class FollowerSystem : EntitySystem
if (!Resolve(target, ref followed, false)) if (!Resolve(target, ref followed, false))
return; return;
if (!HasComp<FollowerComponent>(uid)) if (!TryComp<FollowerComponent>(uid, out var followerComp) || followerComp.Following != target)
return; return;
followed.Following.Remove(uid); followed.Following.Remove(uid);

View File

@@ -0,0 +1,10 @@
namespace Content.Shared.Polymorph;
/// <summary>
/// Raised locally on an entity when it polymorphs into another entity
/// </summary>
/// <param name="OldEntity">EntityUid of the entity before the polymorph</param>
/// <param name="NewEntity">EntityUid of the entity after the polymorph</param>
/// <param name="IsRevert">Whether this polymorph event was a revert back to the original entity</param>
[ByRefEvent]
public record struct PolymorphedEvent(EntityUid OldEntity, EntityUid NewEntity, bool IsRevert);