diff --git a/OpenRA.Game/Activities/Activity.cs b/OpenRA.Game/Activities/Activity.cs index 9dec312bde..efa4a5c7db 100644 --- a/OpenRA.Game/Activities/Activity.cs +++ b/OpenRA.Game/Activities/Activity.cs @@ -200,6 +200,24 @@ namespace OpenRA.Activities /// protected virtual void OnLastRun(Actor self) { } + /// + /// Runs once on Actor.Dispose() (through OnActorDisposeOuter) and can be used to perform activity clean-up on actor death/disposal, + /// for example by force-triggering OnLastRun (which would otherwise be skipped). + /// + protected virtual void OnActorDispose(Actor self) { } + + /// + /// Runs once on Actor.Dispose(). + /// Main purpose is to ensure ChildActivity.OnActorDispose runs as well (which isn't otherwise accessible due to protection level). + /// + internal void OnActorDisposeOuter(Actor self) + { + if (ChildActivity != null) + ChildActivity.OnActorDisposeOuter(self); + + OnActorDispose(self); + } + public virtual bool Cancel(Actor self, bool keepQueue = false) { if (!IsInterruptible) diff --git a/OpenRA.Game/Actor.cs b/OpenRA.Game/Actor.cs index 7e9b402620..f5bfca8f6f 100644 --- a/OpenRA.Game/Actor.cs +++ b/OpenRA.Game/Actor.cs @@ -265,6 +265,11 @@ namespace OpenRA public void Dispose() { + // If CurrentActivity isn't null, run OnActorDisposeOuter in case some cleanups are needed. + // This should be done before the FrameEndTask to avoid dependency issues. + if (CurrentActivity != null) + CurrentActivity.RootActivity.OnActorDisposeOuter(this); + World.AddFrameEndTask(w => { if (Disposed)