2020-06-13 03:02:11 +02:00
using System ;
using System.Collections.Generic ;
2020-12-20 17:12:43 +01:00
using System.Diagnostics ;
2020-06-13 03:02:11 +02:00
using System.Linq ;
namespace Coroutine {
2020-06-13 03:12:26 +02:00
/// <summary>
/// An object of this class can be used to start, tick and otherwise manage active <see cref="ActiveCoroutine"/>s as well as their <see cref="Event"/>s.
/// Note that a static implementation of this can be found in <see cref="CoroutineHandler"/>.
/// </summary>
2020-06-13 03:02:11 +02:00
public class CoroutineHandlerInstance {
private readonly List < ActiveCoroutine > tickingCoroutines = new List < ActiveCoroutine > ( ) ;
private readonly List < ActiveCoroutine > eventCoroutines = new List < ActiveCoroutine > ( ) ;
2020-12-20 17:12:43 +01:00
private readonly Stopwatch stopwatch = new Stopwatch ( ) ;
/// <summary>
/// The amount of <see cref="ActiveCoroutine"/> instances that are currently waiting for a tick (waiting for time to pass)
/// </summary>
public int TickingCount = > this . tickingCoroutines . Count ;
/// <summary>
/// The amount of <see cref="ActiveCoroutine"/> instances that are currently waiting for an <see cref="Event"/>
/// </summary>
public int EventCount = > this . eventCoroutines . Count ;
2020-06-13 03:02:11 +02:00
2020-06-13 03:12:26 +02:00
/// <summary>
/// Starts the given coroutine, returning a <see cref="ActiveCoroutine"/> object for management.
/// Note that this calls <see cref="IEnumerable{T}.GetEnumerator"/> to get the enumerator.
/// </summary>
/// <param name="coroutine">The coroutine to start</param>
2021-03-16 19:07:28 +01:00
/// <param name="name">The <see cref="ActiveCoroutine.Name"/> that this coroutine should have. Defaults to an empty string.</param>
/// <param name="priority">The <see cref="ActiveCoroutine.Priority"/> that this coroutine should have. The higher the priority, the earlier it is advanced. Defaults to 0.</param>
2020-06-13 03:12:26 +02:00
/// <returns>An active coroutine object representing this coroutine</returns>
2021-03-16 19:07:28 +01:00
public ActiveCoroutine Start ( IEnumerable < Wait > coroutine , string name = "" , int priority = 0 ) {
return this . Start ( coroutine . GetEnumerator ( ) , name , priority ) ;
2020-06-13 03:02:11 +02:00
}
2020-06-13 03:12:26 +02:00
/// <summary>
/// Starts the given coroutine, returning a <see cref="ActiveCoroutine"/> object for management.
/// </summary>
/// <param name="coroutine">The coroutine to start</param>
2021-03-16 19:07:28 +01:00
/// <param name="name">The <see cref="ActiveCoroutine.Name"/> that this coroutine should have. Defaults to an empty string.</param>
/// <param name="priority">The <see cref="ActiveCoroutine.Priority"/> that this coroutine should have. The higher the priority, the earlier it is advanced compared to other coroutines that advance around the same time. Defaults to 0.</param>
2020-06-13 03:12:26 +02:00
/// <returns>An active coroutine object representing this coroutine</returns>
2021-03-16 19:07:28 +01:00
public ActiveCoroutine Start ( IEnumerator < Wait > coroutine , string name = "" , int priority = 0 ) {
var inst = new ActiveCoroutine ( coroutine , name , priority , this . stopwatch ) ;
if ( inst . MoveNext ( ) )
AddSorted ( inst . IsWaitingForEvent ( ) ? this . eventCoroutines : this . tickingCoroutines , inst ) ;
2020-06-13 03:02:11 +02:00
return inst ;
}
2020-06-13 03:12:26 +02:00
/// <summary>
/// Causes the given action to be invoked after the given <see cref="Wait"/>.
/// This is equivalent to a coroutine that waits for the given wait and then executes the given <see cref="Action"/>.
/// </summary>
/// <param name="wait">The wait to wait for</param>
/// <param name="action">The action to execute after waiting</param>
2021-03-16 19:07:28 +01:00
/// <param name="name">The <see cref="ActiveCoroutine.Name"/> that the underlying coroutine should have. Defaults to an empty string.</param>
/// <param name="priority">The <see cref="ActiveCoroutine.Priority"/> that the underlying coroutine should have. The higher the priority, the earlier it is advanced compared to other coroutines that advance around the same time. Defaults to 0.</param>
2020-12-20 17:12:43 +01:00
/// <returns>An active coroutine object representing this coroutine</returns>
2021-03-16 19:07:28 +01:00
public ActiveCoroutine InvokeLater ( Wait wait , Action action , string name = "" , int priority = 0 ) {
return this . Start ( InvokeLaterImpl ( wait , action ) , name , priority ) ;
2020-06-13 03:02:11 +02:00
}
2020-06-13 03:12:26 +02:00
/// <summary>
/// Ticks this coroutine handler, causing all time-based <see cref="Wait"/>s to be ticked.
/// </summary>
/// <param name="deltaSeconds">The amount of seconds that have passed since the last time this method was invoked</param>
2020-06-13 03:02:11 +02:00
public void Tick ( double deltaSeconds ) {
2021-03-16 19:07:28 +01:00
this . tickingCoroutines . RemoveAll ( c = > {
if ( c . Tick ( deltaSeconds ) ) {
return true ;
} else if ( c . IsWaitingForEvent ( ) ) {
AddSorted ( this . eventCoroutines , c ) ;
return true ;
2020-06-13 03:02:11 +02:00
}
2021-03-16 19:07:28 +01:00
return false ;
} ) ;
2020-06-13 03:02:11 +02:00
}
2020-06-13 03:12:26 +02:00
/// <summary>
/// Raises the given event, causing all event-based <see cref="Wait"/>s to be updated.
/// </summary>
/// <param name="evt">The event to raise</param>
2020-06-13 03:02:11 +02:00
public void RaiseEvent ( Event evt ) {
2021-03-16 19:07:28 +01:00
this . eventCoroutines . RemoveAll ( c = > {
if ( c . OnEvent ( evt ) ) {
return true ;
} else if ( ! c . IsWaitingForEvent ( ) ) {
AddSorted ( this . tickingCoroutines , c ) ;
return true ;
2020-06-13 03:02:11 +02:00
}
2021-03-16 19:07:28 +01:00
return false ;
} ) ;
2020-06-13 03:02:11 +02:00
}
2020-06-13 03:12:26 +02:00
/// <summary>
/// Returns a list of all currently active <see cref="ActiveCoroutine"/> objects under this handler.
/// </summary>
/// <returns>All active coroutines</returns>
2020-06-13 03:02:11 +02:00
public IEnumerable < ActiveCoroutine > GetActiveCoroutines ( ) {
return this . tickingCoroutines . Concat ( this . eventCoroutines ) ;
}
private static IEnumerator < Wait > InvokeLaterImpl ( Wait wait , Action action ) {
yield return wait ;
action ( ) ;
}
2021-03-16 19:07:28 +01:00
private static void AddSorted ( List < ActiveCoroutine > list , ActiveCoroutine coroutine ) {
var position = list . BinarySearch ( coroutine ) ;
list . Insert ( position < 0 ? ~ position : position , coroutine ) ;
}
2020-06-13 03:02:11 +02:00
}
}