diff --git a/OpenRA.Game/Activities/Activity.cs b/OpenRA.Game/Activities/Activity.cs index 8c82cc43bc..36d4177765 100644 --- a/OpenRA.Game/Activities/Activity.cs +++ b/OpenRA.Game/Activities/Activity.cs @@ -19,122 +19,26 @@ namespace OpenRA.Activities public enum ActivityState { Queued, Active, Canceling, Done } /* - * Activities are actions carried out by actors during each tick. - * - * Activities exist in a graph data structure built up amongst themselves. Each activity has a parent activity, - * optionally child activities, and usually a next activity. An actor's CurrentActivity is a pointer into that graph - * and moves through it as activities run. - * - * * Things to be aware of when writing activities: * * - Use "return NextActivity" at least once somewhere in the tick method. - * - Do not use "return new SomeActivity()" as that will break the graph. Queue the new activity and use "return NextActivity" instead. - * - Do not "reuse" (with "SequenceActivities", for example) activity objects that have already finished running. + * - Do not use "return new SomeActivity()" as that will break the queue. Queue the new activity and use "return NextActivity" instead. + * - Do not "reuse" (with "SequenceActivities", for example) activity objects that have already started running. * Queue a new instance instead. * - Avoid calling actor.CancelActivity(). It is almost always a bug. Call activity.Cancel() instead. - * - Do not return the Parent explicitly unless you have an extremly good reason. "return NextActivity" - * will do the right thing in all circumstances. - * - You do not need to care about the ChildActivity pointer advancing through the list of children, - * the activity code already takes care of that. - * - If you want to check whether there are any follow-up activities queued, check against "NextInQueue" - * in favour of "NextActivity" to avoid checking against the Parent activity. */ public abstract class Activity { public ActivityState State { get; private set; } - /// - /// Returns the top-most activity *from the point of view of the calling activity*. Note that the root activity - /// can and likely will have next activities of its own, which would in turn be the root for their children. - /// - public Activity RootActivity - { - get - { - var p = this; - while (p.ParentActivity != null) - p = p.ParentActivity; - - return p; - } - } - - Activity parentActivity; - public Activity ParentActivity - { - get - { - return parentActivity; - } - - protected set - { - parentActivity = value; - - var next = NextInQueue; - if (next != null) - next.ParentActivity = parentActivity; - } - } - Activity childActivity; protected Activity ChildActivity { - get - { - return childActivity != null && childActivity.State < ActivityState.Done ? childActivity : null; - } - - set - { - if (value == this || value == ParentActivity || value == NextInQueue) - childActivity = null; - else - { - childActivity = value; - - if (childActivity != null) - childActivity.ParentActivity = this; - } - } + get { return childActivity != null && childActivity.State < ActivityState.Done ? childActivity : null; } + set { childActivity = value; } } - Activity nextActivity; - - /// - /// The getter will return either the next activity or, if there is none, the parent one. - /// - public virtual Activity NextActivity - { - get - { - return nextActivity != null ? nextActivity : ParentActivity; - } - - set - { - if (value == this || value == ParentActivity || (value != null && value.ParentActivity == this)) - nextActivity = null; - else - { - nextActivity = value; - - if (nextActivity != null) - nextActivity.ParentActivity = ParentActivity; - } - } - } - - /// - /// The getter will return the next activity on the same level _only_, in contrast to NextActivity. - /// Use this to check whether there are any follow-up activities queued. - /// - public Activity NextInQueue - { - get { return nextActivity; } - set { NextActivity = value; } - } + public Activity NextActivity { get; protected set; } public bool IsInterruptible { get; protected set; } public bool IsCanceling { get { return State == ActivityState.Canceling; } } @@ -156,15 +60,9 @@ namespace OpenRA.Activities } var ret = Tick(self); - if (ret == null || (ret != this && ret.ParentActivity != this)) + if (ret != this) { - // Make sure that the Parent's ChildActivity pointer is moved forwards as the child queue advances. - // The Child's ParentActivity will be set automatically during assignment. - if (ParentActivity != null && ParentActivity != ret) - ParentActivity.ChildActivity = ret; - State = ActivityState.Done; - OnLastRun(self); } @@ -204,7 +102,7 @@ namespace OpenRA.Activities public virtual void Cancel(Actor self, bool keepQueue = false) { if (!keepQueue) - NextInQueue = null; + NextActivity = null; if (!IsInterruptible) return; @@ -217,10 +115,10 @@ namespace OpenRA.Activities public virtual void Queue(Actor self, Activity activity) { - if (NextInQueue != null) - NextInQueue.Queue(self, activity); + if (NextActivity != null) + NextActivity.Queue(self, activity); else - NextInQueue = activity; + NextActivity = activity; } public virtual void QueueChild(Actor self, Activity activity, bool pretick = false) @@ -232,17 +130,17 @@ namespace OpenRA.Activities } /// - /// Prints the activity tree, starting from the root or optionally from a given origin. + /// Prints the activity tree, starting from the top or optionally from a given origin. /// /// Call this method from any place that's called during a tick, such as the Tick() method itself or /// the Before(First|Last)Run() methods. The origin activity will be marked in the output. /// - /// Activity from which to start traversing, and which to mark. If null, mark the calling activity, and start traversal from the root. + /// Activity from which to start traversing, and which to mark. If null, mark the calling activity, and start traversal from the top. /// Initial level of indentation. protected void PrintActivityTree(Actor self, Activity origin = null, int level = 0) { if (origin == null) - RootActivity.PrintActivityTree(self, this); + self.CurrentActivity.PrintActivityTree(self, this); else { Console.Write(new string(' ', level * 2)); @@ -254,8 +152,8 @@ namespace OpenRA.Activities if (ChildActivity != null) ChildActivity.PrintActivityTree(self, origin, level + 1); - if (NextInQueue != null) - NextInQueue.PrintActivityTree(self, origin, level); + if (NextActivity != null) + NextActivity.PrintActivityTree(self, origin, level); } } diff --git a/OpenRA.Game/Actor.cs b/OpenRA.Game/Actor.cs index 9404259f63..2de9feacc5 100644 --- a/OpenRA.Game/Actor.cs +++ b/OpenRA.Game/Actor.cs @@ -222,13 +222,13 @@ namespace OpenRA if (CurrentActivity == null) CurrentActivity = nextActivity; else - CurrentActivity.RootActivity.Queue(this, nextActivity); + CurrentActivity.Queue(this, nextActivity); } public void CancelActivity() { if (CurrentActivity != null) - CurrentActivity.RootActivity.Cancel(this); + CurrentActivity.Cancel(this); } public override int GetHashCode() @@ -281,7 +281,7 @@ namespace OpenRA // 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); + CurrentActivity.OnActorDisposeOuter(this); // Allow traits/activities to prevent a race condition when they depend on disposing the actor (e.g. Transforms) WillDispose = true; diff --git a/OpenRA.Game/Traits/ActivityUtils.cs b/OpenRA.Game/Traits/ActivityUtils.cs index e0feb07456..f78c3ec24d 100644 --- a/OpenRA.Game/Traits/ActivityUtils.cs +++ b/OpenRA.Game/Traits/ActivityUtils.cs @@ -44,7 +44,7 @@ namespace OpenRA.Traits else start = current; - if (act == prev || act == prev.ParentActivity) + if (act == prev) break; } diff --git a/OpenRA.Mods.Common/Activities/Air/ResupplyAircraft.cs b/OpenRA.Mods.Common/Activities/Air/ResupplyAircraft.cs index 61e5d95a19..39b219e0bd 100644 --- a/OpenRA.Mods.Common/Activities/Air/ResupplyAircraft.cs +++ b/OpenRA.Mods.Common/Activities/Air/ResupplyAircraft.cs @@ -32,13 +32,13 @@ namespace OpenRA.Mods.Common.Activities { ChildActivity = ActivityUtils.SequenceActivities(self, aircraft.GetResupplyActivities(host).ToArray()); QueueChild(self, new AllowYieldingReservation(self)); - QueueChild(self, new WaitFor(() => NextInQueue != null || aircraft.ReservedActor == null)); + QueueChild(self, new WaitFor(() => NextActivity != null || aircraft.ReservedActor == null)); } else { ChildActivity = ActivityUtils.SequenceActivities(self, aircraft.GetResupplyActivities(host).ToArray()); QueueChild(self, new AllowYieldingReservation(self)); - QueueChild(self, new TakeOff(self, (a, b, c) => NextInQueue == null && b.NextInQueue == null)); + QueueChild(self, new TakeOff(self, (a, b, c) => NextActivity == null && b.NextActivity == null)); } } diff --git a/OpenRA.Mods.Common/Activities/DeliverResources.cs b/OpenRA.Mods.Common/Activities/DeliverResources.cs index 9d0767c47d..79085c5d5b 100644 --- a/OpenRA.Mods.Common/Activities/DeliverResources.cs +++ b/OpenRA.Mods.Common/Activities/DeliverResources.cs @@ -35,8 +35,8 @@ namespace OpenRA.Mods.Common.Activities public override Activity Tick(Actor self) { - if (NextInQueue != null) - return NextInQueue; + if (NextActivity != null) + return NextActivity; // Find the nearest best refinery if not explicitly ordered to a specific refinery: if (harv.OwnerLinkedProc == null || !harv.OwnerLinkedProc.IsInWorld) diff --git a/OpenRA.Mods.Common/Activities/FindResources.cs b/OpenRA.Mods.Common/Activities/FindResources.cs index df68d33c29..96eea3915f 100644 --- a/OpenRA.Mods.Common/Activities/FindResources.cs +++ b/OpenRA.Mods.Common/Activities/FindResources.cs @@ -80,8 +80,8 @@ namespace OpenRA.Mods.Common.Activities var randFrames = self.World.SharedRandom.Next(100, 175); // Avoid creating an activity cycle - var next = NextInQueue; - NextInQueue = null; + var next = NextActivity; + NextActivity = null; return ActivityUtils.SequenceActivities(self, next, new Wait(randFrames), this); } else