documentation

This commit is contained in:
Ellpeck 2020-06-13 03:12:26 +02:00
parent f199112d99
commit ca2350592e
6 changed files with 88 additions and 3 deletions

View file

@ -2,19 +2,38 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace Coroutine { namespace Coroutine {
/// <summary>
/// A reference to a currently running coroutine.
/// This is returned by <see cref="CoroutineHandler.Start(IEnumerator{Wait})"/>.
/// </summary>
public class ActiveCoroutine { public class ActiveCoroutine {
private readonly IEnumerator<Wait> enumerator; private readonly IEnumerator<Wait> enumerator;
private Wait current; private Wait current;
/// <summary>
/// This property stores whether or not this active coroutine is finished.
/// A coroutine is finished if all of its waits have passed, or if it <see cref="WasCanceled"/>.
/// </summary>
public bool IsFinished { get; private set; } public bool IsFinished { get; private set; }
/// <summary>
/// This property stores whether or not this active coroutine was cancelled using <see cref="Cancel"/>.
/// </summary>
public bool WasCanceled { get; private set; } public bool WasCanceled { get; private set; }
public FinishCallback OnFinished; /// <summary>
/// An event that gets fired when this active coroutine finishes or gets cancelled.
/// When this event is called, <see cref="IsFinished"/> is always true.
/// </summary>
public event FinishCallback OnFinished;
internal ActiveCoroutine(IEnumerator<Wait> enumerator) { internal ActiveCoroutine(IEnumerator<Wait> enumerator) {
this.enumerator = enumerator; this.enumerator = enumerator;
} }
/// <summary>
/// Cancels this coroutine, causing all subsequent <see cref="Wait"/>s and any code in between to be skipped.
/// </summary>
/// <returns>Whether the cancellation was successful, or this coroutine was already cancelled or finished</returns>
public bool Cancel() { public bool Cancel() {
if (this.IsFinished || this.WasCanceled) if (this.IsFinished || this.WasCanceled)
return false; return false;
@ -54,6 +73,10 @@ namespace Coroutine {
return this.current.IsWaitingForEvent(); return this.current.IsWaitingForEvent();
} }
/// <summary>
/// A delegate method used by <see cref="ActiveCoroutine.OnFinished"/>.
/// </summary>
/// <param name="coroutine">The coroutine that finished</param>
public delegate void FinishCallback(ActiveCoroutine coroutine); public delegate void FinishCallback(ActiveCoroutine coroutine);
} }

View file

@ -1,6 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>

View file

@ -3,30 +3,40 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
namespace Coroutine { namespace Coroutine {
/// <summary>
/// This class can be used for static coroutine handling of any kind.
/// Note that it uses an underlying <see cref="CoroutineHandlerInstance"/> object for management.
/// </summary>
public static class CoroutineHandler { public static class CoroutineHandler {
private static readonly CoroutineHandlerInstance Instance = new CoroutineHandlerInstance(); private static readonly CoroutineHandlerInstance Instance = new CoroutineHandlerInstance();
/// <inheritdoc cref="CoroutineHandlerInstance.Start(IEnumerable{Wait})"/>
public static ActiveCoroutine Start(IEnumerable<Wait> coroutine) { public static ActiveCoroutine Start(IEnumerable<Wait> coroutine) {
return Instance.Start(coroutine); return Instance.Start(coroutine);
} }
/// <inheritdoc cref="CoroutineHandlerInstance.Start(IEnumerator{Wait})"/>
public static ActiveCoroutine Start(IEnumerator<Wait> coroutine) { public static ActiveCoroutine Start(IEnumerator<Wait> coroutine) {
return Instance.Start(coroutine); return Instance.Start(coroutine);
} }
/// <inheritdoc cref="CoroutineHandlerInstance.InvokeLater"/>
public static void InvokeLater(Wait wait, Action action) { public static void InvokeLater(Wait wait, Action action) {
Instance.InvokeLater(wait, action); Instance.InvokeLater(wait, action);
} }
/// <inheritdoc cref="CoroutineHandlerInstance.Tick"/>
public static void Tick(double deltaSeconds) { public static void Tick(double deltaSeconds) {
Instance.Tick(deltaSeconds); Instance.Tick(deltaSeconds);
} }
/// <inheritdoc cref="CoroutineHandlerInstance.RaiseEvent"/>
public static void RaiseEvent(Event evt) { public static void RaiseEvent(Event evt) {
Instance.RaiseEvent(evt); Instance.RaiseEvent(evt);
} }
/// <inheritdoc cref="CoroutineHandlerInstance.GetActiveCoroutines"/>
public static IEnumerable<ActiveCoroutine> GetActiveCoroutines() { public static IEnumerable<ActiveCoroutine> GetActiveCoroutines() {
return Instance.GetActiveCoroutines(); return Instance.GetActiveCoroutines();
} }

View file

@ -3,15 +3,30 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
namespace Coroutine { namespace Coroutine {
/// <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>
public class CoroutineHandlerInstance { public class CoroutineHandlerInstance {
private readonly List<ActiveCoroutine> tickingCoroutines = new List<ActiveCoroutine>(); private readonly List<ActiveCoroutine> tickingCoroutines = new List<ActiveCoroutine>();
private readonly List<ActiveCoroutine> eventCoroutines = new List<ActiveCoroutine>(); private readonly List<ActiveCoroutine> eventCoroutines = new List<ActiveCoroutine>();
/// <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>
/// <returns>An active coroutine object representing this coroutine</returns>
public ActiveCoroutine Start(IEnumerable<Wait> coroutine) { public ActiveCoroutine Start(IEnumerable<Wait> coroutine) {
return this.Start(coroutine.GetEnumerator()); return this.Start(coroutine.GetEnumerator());
} }
/// <summary>
/// Starts the given coroutine, returning a <see cref="ActiveCoroutine"/> object for management.
/// </summary>
/// <param name="coroutine">The coroutine to start</param>
/// <returns>An active coroutine object representing this coroutine</returns>
public ActiveCoroutine Start(IEnumerator<Wait> coroutine) { public ActiveCoroutine Start(IEnumerator<Wait> coroutine) {
var inst = new ActiveCoroutine(coroutine); var inst = new ActiveCoroutine(coroutine);
if (inst.MoveNext()) { if (inst.MoveNext()) {
@ -24,10 +39,20 @@ namespace Coroutine {
return inst; return inst;
} }
/// <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>
public void InvokeLater(Wait wait, Action action) { public void InvokeLater(Wait wait, Action action) {
this.Start(InvokeLaterImpl(wait, action)); this.Start(InvokeLaterImpl(wait, action));
} }
/// <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>
public void Tick(double deltaSeconds) { public void Tick(double deltaSeconds) {
for (var i = this.tickingCoroutines.Count - 1; i >= 0; i--) { for (var i = this.tickingCoroutines.Count - 1; i >= 0; i--) {
var coroutine = this.tickingCoroutines[i]; var coroutine = this.tickingCoroutines[i];
@ -40,6 +65,10 @@ namespace Coroutine {
} }
} }
/// <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>
public void RaiseEvent(Event evt) { public void RaiseEvent(Event evt) {
for (var i = this.eventCoroutines.Count - 1; i >= 0; i--) { for (var i = this.eventCoroutines.Count - 1; i >= 0; i--) {
var coroutine = this.eventCoroutines[i]; var coroutine = this.eventCoroutines[i];
@ -52,6 +81,10 @@ namespace Coroutine {
} }
} }
/// <summary>
/// Returns a list of all currently active <see cref="ActiveCoroutine"/> objects under this handler.
/// </summary>
/// <returns>All active coroutines</returns>
public IEnumerable<ActiveCoroutine> GetActiveCoroutines() { public IEnumerable<ActiveCoroutine> GetActiveCoroutines() {
return this.tickingCoroutines.Concat(this.eventCoroutines); return this.tickingCoroutines.Concat(this.eventCoroutines);
} }

View file

@ -1,7 +1,9 @@
namespace Coroutine { namespace Coroutine {
/// <summary>
/// An event is any kind of action that a <see cref="Wait"/> can listen for.
/// Note that, by default, events don't have a custom <see cref="object.Equals(object)"/> implementation.
/// </summary>
public class Event { public class Event {
} }
} }

View file

@ -1,21 +1,37 @@
using System; using System;
namespace Coroutine { namespace Coroutine {
/// <summary>
/// Represents either an amount of time, or an <see cref="Event"/> that is being waited for by an <see cref="ActiveCoroutine"/>.
/// </summary>
public struct Wait { public struct Wait {
private readonly Event evt; private readonly Event evt;
private double seconds; private double seconds;
/// <summary>
/// Creates a new wait that waits for the given <see cref="Event"/>.
/// </summary>
/// <param name="evt">The event to wait for</param>
public Wait(Event evt) { public Wait(Event evt) {
this.evt = evt; this.evt = evt;
this.seconds = 0; this.seconds = 0;
} }
/// <summary>
/// Creates a new wait that waits for the given amount of seconds.
/// </summary>
/// <param name="seconds">The amount of seconds to wait for</param>
public Wait(double seconds) { public Wait(double seconds) {
this.seconds = seconds; this.seconds = seconds;
this.evt = null; this.evt = null;
} }
/// <summary>
/// Creates a new wait that waits for the given <see cref="TimeSpan"/>.
/// Note that the exact value may be slightly different, since waits operate in <see cref="TimeSpan.TotalSeconds"/> rather than ticks.
/// </summary>
/// <param name="time">The time span to wait for</param>
public Wait(TimeSpan time) : this(time.TotalSeconds) { public Wait(TimeSpan time) : this(time.TotalSeconds) {
} }