195 lines
5.3 KiB
C#
195 lines
5.3 KiB
C#
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Linq;
|
|
using ModestTree;
|
|
|
|
namespace Zenject
|
|
{
|
|
// Update tasks once per frame based on a priority
|
|
[DebuggerStepThrough]
|
|
public abstract class TaskUpdater<TTask>
|
|
{
|
|
readonly LinkedList<TaskInfo> _tasks = new LinkedList<TaskInfo>();
|
|
readonly List<TaskInfo> _queuedTasks = new List<TaskInfo>();
|
|
|
|
IEnumerable<TaskInfo> AllTasks
|
|
{
|
|
get { return ActiveTasks.Concat(_queuedTasks); }
|
|
}
|
|
|
|
IEnumerable<TaskInfo> ActiveTasks
|
|
{
|
|
get { return _tasks; }
|
|
}
|
|
|
|
public void AddTask(TTask task, int priority)
|
|
{
|
|
AddTaskInternal(task, priority);
|
|
}
|
|
|
|
void AddTaskInternal(TTask task, int priority)
|
|
{
|
|
Assert.That(!AllTasks.Select(x => x.Task).ContainsItem(task),
|
|
"Duplicate task added to DependencyRoot with name '" + task.GetType().FullName + "'");
|
|
|
|
// Wait until next frame to add the task, otherwise whether it gets updated
|
|
// on the current frame depends on where in the update order it was added
|
|
// from, so you might get off by one frame issues
|
|
_queuedTasks.Add(new TaskInfo(task, priority));
|
|
}
|
|
|
|
public void RemoveTask(TTask task)
|
|
{
|
|
var info = AllTasks.Where(x => ReferenceEquals(x.Task, task)).SingleOrDefault();
|
|
|
|
Assert.IsNotNull(info, "Tried to remove a task not added to DependencyRoot, task = " + task.GetType().Name);
|
|
|
|
Assert.That(!info.IsRemoved, "Tried to remove task twice, task = " + task.GetType().Name);
|
|
info.IsRemoved = true;
|
|
}
|
|
|
|
public void OnFrameStart()
|
|
{
|
|
// See above comment
|
|
AddQueuedTasks();
|
|
}
|
|
|
|
public void UpdateAll()
|
|
{
|
|
UpdateRange(int.MinValue, int.MaxValue);
|
|
}
|
|
|
|
public void UpdateRange(int minPriority, int maxPriority)
|
|
{
|
|
var node = _tasks.First;
|
|
|
|
while (node != null)
|
|
{
|
|
var next = node.Next;
|
|
var taskInfo = node.Value;
|
|
|
|
// Make sure that tasks with priority of int.MaxValue are updated when maxPriority is int.MaxValue
|
|
if (!taskInfo.IsRemoved && taskInfo.Priority >= minPriority
|
|
&& (maxPriority == int.MaxValue || taskInfo.Priority < maxPriority))
|
|
{
|
|
UpdateItem(taskInfo.Task);
|
|
}
|
|
|
|
node = next;
|
|
}
|
|
|
|
ClearRemovedTasks(_tasks);
|
|
}
|
|
|
|
void ClearRemovedTasks(LinkedList<TaskInfo> tasks)
|
|
{
|
|
var node = tasks.First;
|
|
|
|
while (node != null)
|
|
{
|
|
var next = node.Next;
|
|
var info = node.Value;
|
|
|
|
if (info.IsRemoved)
|
|
{
|
|
//ModestTree.Log.Debug("Removed task '" + info.Task.GetType().ToString() + "'");
|
|
tasks.Remove(node);
|
|
}
|
|
|
|
node = next;
|
|
}
|
|
}
|
|
|
|
void AddQueuedTasks()
|
|
{
|
|
for (int i = 0; i < _queuedTasks.Count; i++)
|
|
{
|
|
var task = _queuedTasks[i];
|
|
|
|
if (!task.IsRemoved)
|
|
{
|
|
InsertTaskSorted(task);
|
|
}
|
|
}
|
|
_queuedTasks.Clear();
|
|
}
|
|
|
|
void InsertTaskSorted(TaskInfo task)
|
|
{
|
|
for (var current = _tasks.First; current != null; current = current.Next)
|
|
{
|
|
if (current.Value.Priority > task.Priority)
|
|
{
|
|
_tasks.AddBefore(current, task);
|
|
return;
|
|
}
|
|
}
|
|
|
|
_tasks.AddLast(task);
|
|
}
|
|
|
|
protected abstract void UpdateItem(TTask task);
|
|
|
|
class TaskInfo
|
|
{
|
|
public TTask Task;
|
|
public int Priority;
|
|
public bool IsRemoved;
|
|
|
|
public TaskInfo(TTask task, int priority)
|
|
{
|
|
Task = task;
|
|
Priority = priority;
|
|
}
|
|
}
|
|
}
|
|
|
|
public class TickablesTaskUpdater : TaskUpdater<ITickable>
|
|
{
|
|
protected override void UpdateItem(ITickable task)
|
|
{
|
|
#if ZEN_INTERNAL_PROFILING
|
|
using (ProfileTimers.CreateTimedBlock("User Code"))
|
|
#endif
|
|
#if UNITY_EDITOR
|
|
using (ProfileBlock.Start("{0}.Tick()", task.GetType()))
|
|
#endif
|
|
{
|
|
task.Tick();
|
|
}
|
|
}
|
|
}
|
|
|
|
public class LateTickablesTaskUpdater : TaskUpdater<ILateTickable>
|
|
{
|
|
protected override void UpdateItem(ILateTickable task)
|
|
{
|
|
#if ZEN_INTERNAL_PROFILING
|
|
using (ProfileTimers.CreateTimedBlock("User Code"))
|
|
#endif
|
|
#if UNITY_EDITOR
|
|
using (ProfileBlock.Start("{0}.LateTick()", task.GetType()))
|
|
#endif
|
|
{
|
|
task.LateTick();
|
|
}
|
|
}
|
|
}
|
|
|
|
public class FixedTickablesTaskUpdater : TaskUpdater<IFixedTickable>
|
|
{
|
|
protected override void UpdateItem(IFixedTickable task)
|
|
{
|
|
#if ZEN_INTERNAL_PROFILING
|
|
using (ProfileTimers.CreateTimedBlock("User Code"))
|
|
#endif
|
|
#if UNITY_EDITOR
|
|
using (ProfileBlock.Start("{0}.FixedTick()", task.GetType()))
|
|
#endif
|
|
{
|
|
task.FixedTick();
|
|
}
|
|
}
|
|
}
|
|
}
|