Simplify Activity class

After the removal of the CompositeActivity class, all the supporting
code that made it work can be removed as well.
This commit is contained in:
Oliver Brakmann
2019-03-26 03:11:03 +01:00
committed by Paul Chote
parent 19977bb7da
commit b4fd7331b2
6 changed files with 25 additions and 127 deletions

View File

@@ -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; }
/// <summary>
/// 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.
/// </summary>
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;
/// <summary>
/// The getter will return either the next activity or, if there is none, the parent one.
/// </summary>
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;
}
}
}
/// <summary>
/// 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.
/// </summary>
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
}
/// <summary>
/// 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.
/// </summary>
/// <param name="origin">Activity from which to start traversing, and which to mark. If null, mark the calling activity, and start traversal from the root.</param>
/// <param name="origin">Activity from which to start traversing, and which to mark. If null, mark the calling activity, and start traversal from the top.</param>
/// <param name="level">Initial level of indentation.</param>
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);
}
}