Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ All notable changes to this package will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [0.15.0] - 2025-01-05

**New**:
- Added *StartDelayCall* method to *ICoroutineService* to allow deferred methods to be safely executed within the bounds of a Unity Coroutine
- Added the possibility to know the current state of an *IAsyncCoroutine*
- Added the access to the Sample Entity used to generete new entites within an *IObjectPool<T>* and destroy it when disposing the object pool
- Added the possibility to reset an *IObjectPool<T>* to a new state

## [0.14.1] - 2024-11-30

**Fixed**:
Comment on lines 4 to 17
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image description CodeRabbit

Note: This review was outside of the patch, but no patch was found that overlapped with it. Original lines [22-25]

The code changes in the CHANGELOG.md file look good. They accurately reflect the new features and additions in the release.

Overall, the changes in this pull request seem to be focused on adding new methods and functionalities related to coroutines and object pooling. The changes are well-documented in the CHANGELOG.md file, which is great for transparency and communication with other developers.

Since the provided code snippets are incomplete, it's difficult to provide a comprehensive review. However, based on the information provided, it seems that the changes are reasonable and aligned with the stated goals.

If you have any specific concerns or questions about particular code sections, please provide the complete code snippets, and I'll be happy to review them in more detail.

Expand Down
135 changes: 97 additions & 38 deletions Runtime/CoroutineService.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections;
using UnityEngine;
using Action = System.Action;
using Object = UnityEngine.Object;

// ReSharper disable once CheckNamespace
Expand All @@ -13,6 +14,10 @@ namespace GameLovers.Services
/// </summary>
public interface IAsyncCoroutine
{
/// <summary>
/// Get the execution status of the coroutine
/// </summary>
bool IsRunning { get; }
/// <summary>
/// Get the complete operation status of the coroutine
/// </summary>
Expand All @@ -21,30 +26,34 @@ public interface IAsyncCoroutine
/// Get the current coroutine being executed
/// </summary>
Coroutine Coroutine { get; }
/// <summary>
/// The Unity time the coroutine started
/// </summary>
float StartTime { get; }

/// <summary>
/// Sets the action <paramref name="onComplete"/> callback to be invoked when the coroutine is completed
/// </summary>
void OnComplete(Action onComplete);
/// <summary>
/// Stops the execution of this coroutine
/// </summary>
void StopCoroutine(bool triggerOnComplete = false);
}

/// <inheritdoc cref="IAsyncCoroutine"/>
public interface IAsyncCoroutine<T>
/// <inheritdoc />
public interface IAsyncCoroutine<T> : IAsyncCoroutine
{
/// <inheritdoc cref="IAsyncCoroutine.IsCompleted"/>
bool IsCompleted { get; }
/// <inheritdoc cref="IAsyncCoroutine.Coroutine"/>
Coroutine Coroutine { get; }
/// <summary>
/// The data to be returned on the coroutine completion
/// </summary>
T Data { get; }
T Data { get; set; }

/// <summary>
/// Sets the action <paramref name="onComplete"/> callback to be invoked when the coroutine is completed with the
/// <paramref name="data"/> reference in the callback
/// <seealso cref="Data"/> reference in the callback
/// </summary>
void OnComplete(T data, Action<T> onComplete);
void OnComplete(Action<T> onComplete);
}

/// <summary>
Expand All @@ -70,9 +79,20 @@ public interface ICoroutineService : IDisposable
IAsyncCoroutine StartAsyncCoroutine(IEnumerator routine);
/// <summary>
/// Follows the same principle and execution of <see cref="MonoBehaviour.StartCoroutine(IEnumerator)"/> but returns
/// a <see cref="IAsyncCoroutine{T}"/> to provide a callback on complete of the coroutine with given <typeparamref name="T"/> type
/// a <see cref="IAsyncCoroutine{T}"/> to provide a callback on complete of the coroutine with given <paramref name="data"/>
/// </summary>
IAsyncCoroutine<T> StartAsyncCoroutine<T>(IEnumerator routine);
IAsyncCoroutine<T> StartAsyncCoroutine<T>(IEnumerator routine, T data);
/// <summary>
/// Executes <paramref name="call"/> in a <see cref="StartAsyncCoroutine"/> with the given <paramref name="delay"/>.
/// Useful for delay callbacks
/// </summary>
IAsyncCoroutine StartDelayCall(Action call, float delay);
/// <summary>
/// Executes <paramref name="call"/> in a <see cref="StartAsyncCoroutine"/> with the given <paramref name="delay"/>
/// and <paramref name="data"/> data type.
/// Useful for delay callbacks
/// </summary>
IAsyncCoroutine<T> StartDelayCall<T>(Action<T> call, T data,float delay);
/// <inheritdoc cref="MonoBehaviour.StopCoroutine(Coroutine)"/>
void StopCoroutine(Coroutine coroutine);
/// <inheritdoc cref="MonoBehaviour.StopAllCoroutines"/>
Expand All @@ -86,7 +106,7 @@ public class CoroutineService : ICoroutineService

public CoroutineService()
{
var gameObject = new GameObject(typeof(CoroutineServiceMonoBehaviour).Name);
var gameObject = new GameObject(nameof(CoroutineServiceMonoBehaviour));

_serviceObject = gameObject.AddComponent<CoroutineServiceMonoBehaviour>();

Expand Down Expand Up @@ -120,23 +140,45 @@ public Coroutine StartCoroutine(IEnumerator routine)
/// <inheritdoc />
public IAsyncCoroutine StartAsyncCoroutine(IEnumerator routine)
{
var asyncCoroutine = new AsyncCoroutine();
var asyncCoroutine = new AsyncCoroutine(this);

asyncCoroutine.SetCoroutine(_serviceObject.ExternalStartCoroutine(InternalCoroutine(routine, asyncCoroutine)));

return asyncCoroutine;
}

/// <inheritdoc />
public IAsyncCoroutine<T> StartAsyncCoroutine<T>(IEnumerator routine)
public IAsyncCoroutine<T> StartAsyncCoroutine<T>(IEnumerator routine, T data)
{
var asyncCoroutine = new AsyncCoroutine<T>();
var asyncCoroutine = new AsyncCoroutine<T>(this, data);

asyncCoroutine.SetCoroutine(_serviceObject.ExternalStartCoroutine(InternalCoroutine(routine, asyncCoroutine)));

return asyncCoroutine;
}


/// <inheritdoc />
public IAsyncCoroutine StartDelayCall(Action call, float delay)
{
var asyncCoroutine = new AsyncCoroutine(this);

asyncCoroutine.OnComplete(call);
asyncCoroutine.SetCoroutine(_serviceObject.ExternalStartCoroutine(InternalDelayCoroutine(delay, asyncCoroutine)));

return asyncCoroutine;
}

/// <inheritdoc />
public IAsyncCoroutine<T> StartDelayCall<T>(Action<T> call, T data, float delay)
{
var asyncCoroutine = new AsyncCoroutine<T>(this, data);

asyncCoroutine.OnComplete(call);
asyncCoroutine.SetCoroutine(_serviceObject.ExternalStartCoroutine(InternalDelayCoroutine(delay, asyncCoroutine)));

return asyncCoroutine;
}

/// <inheritdoc />
public void StopCoroutine(Coroutine coroutine)
{
Expand Down Expand Up @@ -165,22 +207,38 @@ private static IEnumerator InternalCoroutine(IEnumerator routine, ICompleteCorou

completed.Completed();
}

private static IEnumerator InternalDelayCoroutine(float delayInSeconds, ICompleteCoroutine completed)
{
yield return new WaitForSeconds(delayInSeconds);

completed.Completed();
}

#region Private Interfaces

private interface ICompleteCoroutine
{
void Completed();

void SetCoroutine(Coroutine coroutine);
}

private class AsyncCoroutine : IAsyncCoroutine, ICompleteCoroutine
{
private readonly ICoroutineService _coroutineService;

private Action _onComplete;

public bool IsRunning => Coroutine != null;
public bool IsCompleted { get; private set; }
public Coroutine Coroutine { get; private set; }
public float StartTime { get; } = Time.time;

private AsyncCoroutine() {}

public AsyncCoroutine(ICoroutineService coroutineService)
{
_coroutineService = coroutineService;
}

public void SetCoroutine(Coroutine coroutine)
{
Expand All @@ -192,6 +250,13 @@ public void OnComplete(Action onComplete)
_onComplete = onComplete;
}

public void StopCoroutine(bool triggerOnComplete = false)
{
_coroutineService.StopCoroutine(Coroutine);

OnCompleteTrigger();
}

Comment on lines +253 to +259
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

StopCoroutine body completeness.
Implementation stops the coroutine, then triggers the completion callback if requested. If stopping means incomplete, consider skipping OnCompleteTrigger altogether.

public void Completed()
{
if (IsCompleted)
Expand All @@ -201,41 +266,35 @@ public void Completed()

IsCompleted = true;
Coroutine = null;


OnCompleteTrigger();
}

protected virtual void OnCompleteTrigger()
{
_onComplete?.Invoke();
}
}

private class AsyncCoroutine<T> : IAsyncCoroutine<T>, ICompleteCoroutine
private class AsyncCoroutine<T> : AsyncCoroutine, IAsyncCoroutine<T>
{
private Action<T> _onComplete;

public bool IsCompleted { get; private set; }
public Coroutine Coroutine { get; private set; }
public T Data { get; private set; }

public T Data { get; set; }

public void SetCoroutine(Coroutine coroutine)
public AsyncCoroutine(ICoroutineService coroutineService, T data) : base(coroutineService)
{
Coroutine = coroutine;
Data = data;
}

public void OnComplete(T data, Action<T> onComplete)
public void OnComplete(Action<T> onComplete)
{
_onComplete = onComplete;

Data = data;
}

public void Completed()
protected override void OnCompleteTrigger()
{
if (IsCompleted)
{
return;
}

IsCompleted = true;
Coroutine = null;

base.OnCompleteTrigger();
_onComplete?.Invoke(Data);
}
}
Expand Down
Loading
Loading