Skip to content

Commit

Permalink
Merge pull request #4 from BastianBlokland/feature/run-while-disabled
Browse files Browse the repository at this point in the history
'UpdateWhileComponentDisabled' task runtime option
  • Loading branch information
BastianBlokland authored Jul 23, 2019
2 parents 10f0bd5 + c2e7feb commit c9fbf6e
Show file tree
Hide file tree
Showing 8 changed files with 163 additions and 24 deletions.
2 changes: 2 additions & 0 deletions .example/Assets/csc.rsp
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-nowarn:649
-warnaserror+
7 changes: 7 additions & 0 deletions .example/Assets/csc.rsp.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

80 changes: 60 additions & 20 deletions src/ComponentExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,14 @@ public static class ComponentExtensions
/// </exception>
/// <param name="component">Component to run the task 'on'.</param>
/// <param name="taskCreator">Function for creating the task.</param>
/// <param name="options">Options for configuring how the task is run.</param>
/// <returns>
/// Task that completes when the original task completes or when the component gets destroyed.
/// </returns>
public static Task StartTask(this Component component, Func<Task> taskCreator)
public static Task StartTask(
this Component component,
Func<Task> taskCreator,
TaskRunOptions options = TaskRunOptions.Default)
{
// Validate params.
UnityHelper.ThrowForInvalidObjectParam(component, nameof(component));
Expand All @@ -52,7 +56,7 @@ public static Task StartTask(this Component component, Func<Task> taskCreator)
UnityHelper.ThrowForNonUnityThreadOrEditMode();

// Start the task on a runner for the component.
return GetTaskRunnerUnchecked(component).StartTask(taskCreator);
return GetTaskRunnerUnchecked(component, options).StartTask(taskCreator);
}

/// <summary>
Expand Down Expand Up @@ -81,10 +85,14 @@ public static Task StartTask(this Component component, Func<Task> taskCreator)
/// </exception>
/// <param name="component">Component to run the task 'on'.</param>
/// <param name="taskCreator">Function for creating the task.</param>
/// <param name="options">Options for configuring how the task is run.</param>
/// <returns>
/// Task that completes when the original task completes or when the component gets destroyed.
/// </returns>
public static Task StartTask(this Component component, Func<CancellationToken, Task> taskCreator)
public static Task StartTask(
this Component component,
Func<CancellationToken, Task> taskCreator,
TaskRunOptions options = TaskRunOptions.Default)
{
// Validate params.
UnityHelper.ThrowForInvalidObjectParam(component, nameof(component));
Expand All @@ -95,7 +103,7 @@ public static Task StartTask(this Component component, Func<CancellationToken, T
UnityHelper.ThrowForNonUnityThreadOrEditMode();

// Start the task on a runner for the component.
return GetTaskRunnerUnchecked(component).StartTask(taskCreator);
return GetTaskRunnerUnchecked(component, options).StartTask(taskCreator);
}

/// <summary>
Expand All @@ -122,10 +130,15 @@ public static Task StartTask(this Component component, Func<CancellationToken, T
/// </exception>
/// <param name="component">Component to run the task 'on'.</param>
/// <param name="taskCreator">Function for creating the task.</param>
/// <param name="options">Options for configuring how the task is run.</param>
/// <returns>
/// Task that completes when the original task completes or when the component gets destroyed.
/// </returns>
public static Task StartTask<TIn>(this Component component, Func<TIn, Task> taskCreator, TIn data)
public static Task StartTask<TIn>(
this Component component,
Func<TIn, Task> taskCreator,
TIn data,
TaskRunOptions options = TaskRunOptions.Default)
{
// Validate params.
UnityHelper.ThrowForInvalidObjectParam(component, nameof(component));
Expand All @@ -136,7 +149,7 @@ public static Task StartTask<TIn>(this Component component, Func<TIn, Task> task
UnityHelper.ThrowForNonUnityThreadOrEditMode();

// Start the task on a runner for the component.
return GetTaskRunnerUnchecked(component).StartTask(taskCreator, data);
return GetTaskRunnerUnchecked(component, options).StartTask(taskCreator, data);
}

/// <summary>
Expand Down Expand Up @@ -165,10 +178,15 @@ public static Task StartTask<TIn>(this Component component, Func<TIn, Task> task
/// </exception>
/// <param name="component">Component to run the task 'on'.</param>
/// <param name="taskCreator">Function for creating the task.</param>
/// <param name="options">Options for configuring how the task is run.</param>
/// <returns>
/// Task that completes when the original task completes or when the component gets destroyed.
/// </returns>
public static Task StartTask<TIn>(this Component component, Func<TIn, CancellationToken, Task> taskCreator, TIn data)
public static Task StartTask<TIn>(
this Component component,
Func<TIn, CancellationToken, Task> taskCreator,
TIn data,
TaskRunOptions options = TaskRunOptions.Default)
{
// Validate params.
UnityHelper.ThrowForInvalidObjectParam(component, nameof(component));
Expand All @@ -179,7 +197,7 @@ public static Task StartTask<TIn>(this Component component, Func<TIn, Cancellati
UnityHelper.ThrowForNonUnityThreadOrEditMode();

// Start the task on a runner for the component.
return GetTaskRunnerUnchecked(component).StartTask(taskCreator, data);
return GetTaskRunnerUnchecked(component, options).StartTask(taskCreator, data);
}

/// <summary>
Expand All @@ -206,10 +224,14 @@ public static Task StartTask<TIn>(this Component component, Func<TIn, Cancellati
/// </exception>
/// <param name="component">Component to run the task 'on'.</param>
/// <param name="taskCreator">Function for creating the task.</param>
/// <param name="options">Options for configuring how the task is run.</param>
/// <returns>
/// Task that completes when the original task completes or when the component gets destroyed.
/// </returns>
public static Task<TOut> StartTask<TOut>(this Component component, Func<Task<TOut>> taskCreator)
public static Task<TOut> StartTask<TOut>(
this Component component,
Func<Task<TOut>> taskCreator,
TaskRunOptions options = TaskRunOptions.Default)
{
// Validate params.
UnityHelper.ThrowForInvalidObjectParam(component, nameof(component));
Expand All @@ -220,7 +242,7 @@ public static Task<TOut> StartTask<TOut>(this Component component, Func<Task<TOu
UnityHelper.ThrowForNonUnityThreadOrEditMode();

// Start the task on a runner for the component.
return GetTaskRunnerUnchecked(component).StartTask(taskCreator);
return GetTaskRunnerUnchecked(component, options).StartTask(taskCreator);
}

/// <summary>
Expand Down Expand Up @@ -249,10 +271,14 @@ public static Task<TOut> StartTask<TOut>(this Component component, Func<Task<TOu
/// </exception>
/// <param name="component">Component to run the task 'on'.</param>
/// <param name="taskCreator">Function for creating the task.</param>
/// <param name="options">Options for configuring how the task is run.</param>
/// <returns>
/// Task that completes when the original task completes or when the component gets destroyed.
/// </returns>
public static Task<TOut> StartTask<TOut>(this Component component, Func<CancellationToken, Task<TOut>> taskCreator)
public static Task<TOut> StartTask<TOut>(
this Component component,
Func<CancellationToken, Task<TOut>> taskCreator,
TaskRunOptions options = TaskRunOptions.Default)
{
// Validate params.
UnityHelper.ThrowForInvalidObjectParam(component, nameof(component));
Expand All @@ -263,7 +289,7 @@ public static Task<TOut> StartTask<TOut>(this Component component, Func<Cancella
UnityHelper.ThrowForNonUnityThreadOrEditMode();

// Start the task on a runner for the component.
return GetTaskRunnerUnchecked(component).StartTask(taskCreator);
return GetTaskRunnerUnchecked(component, options).StartTask(taskCreator);
}

/// <summary>
Expand All @@ -290,10 +316,15 @@ public static Task<TOut> StartTask<TOut>(this Component component, Func<Cancella
/// </exception>
/// <param name="component">Component to run the task 'on'.</param>
/// <param name="taskCreator">Function for creating the task.</param>
/// <param name="options">Options for configuring how the task is run.</param>
/// <returns>
/// Task that completes when the original task completes or when the component gets destroyed.
/// </returns>
public static Task<TOut> StartTask<TIn, TOut>(this Component component, Func<TIn, Task<TOut>> taskCreator, TIn data)
public static Task<TOut> StartTask<TIn, TOut>(
this Component component,
Func<TIn, Task<TOut>> taskCreator,
TIn data,
TaskRunOptions options = TaskRunOptions.Default)
{
// Validate params.
UnityHelper.ThrowForInvalidObjectParam(component, nameof(component));
Expand All @@ -304,7 +335,7 @@ public static Task<TOut> StartTask<TIn, TOut>(this Component component, Func<TIn
UnityHelper.ThrowForNonUnityThreadOrEditMode();

// Start the task on a runner for the component.
return GetTaskRunnerUnchecked(component).StartTask(taskCreator, data);
return GetTaskRunnerUnchecked(component, options).StartTask(taskCreator, data);
}

/// <summary>
Expand Down Expand Up @@ -333,10 +364,15 @@ public static Task<TOut> StartTask<TIn, TOut>(this Component component, Func<TIn
/// </exception>
/// <param name="component">Component to run the task 'on'.</param>
/// <param name="taskCreator">Function for creating the task.</param>
/// <param name="options">Options for configuring how the task is run.</param>
/// <returns>
/// Task that completes when the original task completes or when the component gets destroyed.
/// </returns>
public static Task<TOut> StartTask<TIn, TOut>(this Component component, Func<TIn, CancellationToken, Task<TOut>> taskCreator, TIn data)
public static Task<TOut> StartTask<TIn, TOut>(
this Component component,
Func<TIn, CancellationToken, Task<TOut>> taskCreator,
TIn data,
TaskRunOptions options = TaskRunOptions.Default)
{
// Validate params.
UnityHelper.ThrowForInvalidObjectParam(component, nameof(component));
Expand All @@ -347,7 +383,7 @@ public static Task<TOut> StartTask<TIn, TOut>(this Component component, Func<TIn
UnityHelper.ThrowForNonUnityThreadOrEditMode();

// Start the task on a runner for the component.
return GetTaskRunnerUnchecked(component).StartTask(taskCreator, data);
return GetTaskRunnerUnchecked(component, options).StartTask(taskCreator, data);
}

/// <summary>
Expand All @@ -366,8 +402,11 @@ public static Task<TOut> StartTask<TIn, TOut>(this Component component, Func<TIn
/// Thrown when called from a non-unity thread.
/// </exception>
/// <param name="component">Component to get the runner for.</param>
/// <param name="options">Options for configuring how tasks are run on this runner.</param>
/// <returns><see cref="ITaskRunner"/> scoped to the given component.</returns>
public static ITaskRunner GetTaskRunner(this Component component)
public static ITaskRunner GetTaskRunner(
this Component component,
TaskRunOptions options = TaskRunOptions.Default)
{
// Validate params.
UnityHelper.ThrowForInvalidObjectParam(component, nameof(component));
Expand All @@ -376,10 +415,10 @@ public static ITaskRunner GetTaskRunner(this Component component)
UnityHelper.ThrowForNonUnityThreadOrEditMode();

// Start the task on a runner for the component.
return GetTaskRunnerUnchecked(component);
return GetTaskRunnerUnchecked(component, options);
}

internal static ITaskRunner GetTaskRunnerUnchecked(this Component component)
internal static ITaskRunner GetTaskRunnerUnchecked(Component component, TaskRunOptions options)
{
var owner = component.gameObject;

Expand All @@ -388,12 +427,13 @@ internal static ITaskRunner GetTaskRunnerUnchecked(this Component component)
foreach (var runner in monoBehaviourRunners)
{
// If there is a runner for that component then return that.
if (runner.ComponentToFollow == component)
if (!runner.IsFinished && runner.RunOptions == options && runner.ComponentToFollow == component)
return runner;
}

// Otherwise create a new runner for this component.
var newRunner = owner.AddComponent<MonoBehaviourTaskRunner>();
newRunner.RunOptions = options;
newRunner.ComponentToFollow = component;
newRunner.hideFlags = HideFlags.HideInInspector;
return newRunner;
Expand Down
11 changes: 8 additions & 3 deletions src/ComponentTask/Internal/MonoBehaviourTaskRunner.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;

namespace ComponentTask.Internal
{
internal sealed class MonoBehaviourTaskRunner : UnityEngine.MonoBehaviour, ITaskRunner, IExceptionHandler
internal sealed class MonoBehaviourTaskRunner : MonoBehaviour, ITaskRunner, IExceptionHandler
{
private readonly LocalTaskRunner taskRunner;

Expand All @@ -13,7 +14,9 @@ public MonoBehaviourTaskRunner()
this.taskRunner = new LocalTaskRunner(exceptionHandler: this);
}

public UnityEngine.Component ComponentToFollow { get; set; }
public TaskRunOptions RunOptions { get; set; }

public Component ComponentToFollow { get; set; }

public bool IsFinished { get; private set; }

Expand Down Expand Up @@ -86,7 +89,9 @@ private void LateUpdate()
// If the component is a 'Behaviour' then we update when its enabled.
if (ComponentToFollow is UnityEngine.Behaviour behaviour)
{
if (behaviour.isActiveAndEnabled)
var updateWhileDisabled =
(this.RunOptions & TaskRunOptions.UpdateWhileComponentDisabled) == TaskRunOptions.UpdateWhileComponentDisabled;
if (updateWhileDisabled || behaviour.isActiveAndEnabled)
this.Execute();
}
else
Expand Down
1 change: 1 addition & 0 deletions src/GameObjectExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public static ITaskRunner CreateTaskRunner(this GameObject gameObject)

// Create runner.
var runner = gameObject.AddComponent<MonoBehaviourTaskRunner>();
runner.RunOptions = TaskRunOptions.Default;
runner.hideFlags = HideFlags.HideInInspector;

return runner;
Expand Down
24 changes: 24 additions & 0 deletions src/TaskRunOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System;

namespace UnityEngine
{
/// <summary>
/// Flags for configuring how tasks are being run.
/// </summary>
[Flags]
public enum TaskRunOptions : int
{
/// <summary>
/// Default run options.
/// </summary>
/// <remarks>
/// Tasks are updated in 'LateUpdate' when the component is enabled.
/// </remarks>
Default = 0,

/// <summary>
/// Tasks are updated even if the component is disabled.
/// </summary>
UpdateWhileComponentDisabled = 1 << 0,
}
}
11 changes: 11 additions & 0 deletions src/TaskRunOptions.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit c9fbf6e

Please sign in to comment.