Skip to content

Commit

Permalink
fix: MonoSingleton and MonoBehaviourCallback improvements (#112)
Browse files Browse the repository at this point in the history
* fix: solid MonoBehaviourCallback impl + MonoSingleton fix

* fix: made MonoSingleton.Instantiate method private, added test for single Instance validation

* chore: incremented version to 2.0.0 due to breaking changes
  • Loading branch information
pavlo-klymentenko authored Jul 25, 2023
1 parent 99a71f5 commit 15b85d3
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 20 deletions.
65 changes: 48 additions & 17 deletions Runtime/Async/Coroutine/MonoBehaviourCallback.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,53 +12,84 @@ namespace StansAssets.Foundation.Async
/// </summary>
public class MonoBehaviourCallback : MonoSingleton<MonoBehaviourCallback>
{
event Action m_OnUpdate = delegate { };
event Action m_OnLateUpdate = delegate { };
event Action m_OnFixedUpdate = delegate { };
event Action m_OnApplicationQuit = delegate { };
event Action<bool> m_ApplicationOnPause = delegate { };
event Action<bool> m_OnApplicationFocus = delegate { };

/// <summary>
/// Update is called every frame.
/// Learn more: [MonoBehaviour.Update](https://docs.unity3d.com/ScriptReference/MonoBehaviour.Update.html)
/// </summary>
public static event Action OnUpdate;
public static event Action OnUpdate
{
add => Instance.m_OnUpdate += value;
remove => Instance.m_OnUpdate -= value;
}

/// <summary>
/// LateUpdate is called after all Update functions have been called. This is useful to order script execution.
/// For example a follow camera should always be implemented in LateUpdate because it tracks objects that might have moved inside Update.
/// Learn more: [MonoBehaviour.LateUpdate](https://docs.unity3d.com/ScriptReference/MonoBehaviour.LateUpdate.html)
/// </summary>
public static event Action OnLateUpdate;
public static event Action OnLateUpdate
{
add => Instance.m_OnLateUpdate += value;
remove => Instance.m_OnLateUpdate -= value;
}

/// <summary>
/// Frame-rate independent MonoBehaviour.FixedUpdate message for physics calculations.
/// Learn more: [MonoBehaviour.FixedUpdate](https://docs.unity3d.com/ScriptReference/MonoBehaviour.FixedUpdate.html)
/// </summary>
public static event Action OnFixedUpdate
{
add => Instance.m_OnFixedUpdate += value;
remove => Instance.m_OnFixedUpdate -= value;
}

/// <summary>
/// In the editor this is called when the user stops playmode.
/// Learn more: [MonoBehaviour.OnApplicationQuit](https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnApplicationQuit.html)
/// </summary>
public static event Action ApplicationOnQuit;
public static event Action ApplicationOnQuit
{
add => Instance.m_OnApplicationQuit += value;
remove => Instance.m_OnApplicationQuit -= value;
}

/// <summary>
/// Sent to all GameObjects when the application pauses.
/// Learn more: [MonoBehaviour.OnApplicationPause](https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnApplicationPause.html)
/// </summary>
public static event Action<bool> ApplicationOnPause;
public static event Action<bool> ApplicationOnPause
{
add => Instance.m_ApplicationOnPause += value;
remove => Instance.m_ApplicationOnPause -= value;
}

/// <summary>
/// Sent to all GameObjects when the player gets or loses focus.
/// Learn more: [MonoBehaviour.OnApplicationFocus](https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnApplicationFocus.html)
/// </summary>
public static event Action<bool> ApplicationOnFocus;

/// <summary>
/// Frame-rate independent MonoBehaviour.FixedUpdate message for physics calculations.
/// Learn more: [MonoBehaviour.FixedUpdate](https://docs.unity3d.com/ScriptReference/MonoBehaviour.FixedUpdate.html)
/// </summary>
public static event Action OnFixedUpdate;
public static event Action<bool> ApplicationOnFocus
{
add => Instance.m_OnApplicationFocus += value;
remove => Instance.m_OnApplicationFocus -= value;
}

void Update() => OnUpdate?.Invoke();
void LateUpdate() => OnLateUpdate?.Invoke();
void FixedUpdate() => OnFixedUpdate?.Invoke();
void OnApplicationPause(bool pauseStatus) => ApplicationOnPause?.Invoke(pauseStatus);
void OnApplicationFocus(bool hasFocus) => ApplicationOnFocus?.Invoke(hasFocus);
void Update() => m_OnUpdate.Invoke();
void LateUpdate() => m_OnLateUpdate.Invoke();
void FixedUpdate() => m_OnFixedUpdate.Invoke();
void OnApplicationPause(bool pauseStatus) => m_ApplicationOnPause.Invoke(pauseStatus);
void OnApplicationFocus(bool hasFocus) => m_OnApplicationFocus.Invoke(hasFocus);

protected override void OnApplicationQuit()
{
base.OnApplicationQuit();
ApplicationOnQuit?.Invoke();
m_OnApplicationQuit.Invoke();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ class MainThreadDispatcherRuntime : MainThreadDispatcherBase
{
public override void Init()
{
MonoBehaviourCallback.Instantiate();
MonoBehaviourCallback.OnUpdate += Update;
}
}
Expand Down
8 changes: 7 additions & 1 deletion Runtime/Patterns/Singleton/MonoSingleton.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,14 @@ public static T Instance
/// But it may be useful if you want manually control when the instance is created,
/// even if you do not this specific instance at the moment
/// </summary>
public static void Instantiate()
static void Instantiate()
{
if (HasInstance)
{
Debug.LogWarning($"You are trying to Instantiate {typeof(T).FullName}, but it already has an Instance. Please use Instance property instead.");
return;
}

var name = typeof(T).FullName;
s_Instance = new GameObject(name).AddComponent<T>();
}
Expand Down
28 changes: 28 additions & 0 deletions Tests/Editor/Patterns/MonoSingletonTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System;
using NUnit.Framework;
using StansAssets.Foundation.Patterns;

namespace StansAssets.Foundation.Tests.Patterns
{
class TestSingleton : MonoSingleton<TestSingleton>
{
public readonly string Id;

public TestSingleton()
{
Id = Guid.NewGuid().ToString();
}
}

public class MonoSingletonTests
{
[Test]
public void SingleInstanceTest()
{
var a = TestSingleton.Instance;
var b = TestSingleton.Instance;
var c = TestSingleton.Instance;
Assert.IsTrue(a.Id.Equals(b.Id) && b.Id.Equals(c.Id));
}
}
}
11 changes: 11 additions & 0 deletions Tests/Editor/Patterns/MonoSingletonTests.cs.meta

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

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "com.stansassets.foundation",
"displayName": "Stans Assets - Foundation",
"version": "1.0.27",
"version": "2.0.0",
"unity": "2018.4",
"description": "Foundation package is a collection of utility methods, design patterns, and extensions for Unity.",
"keywords": [
Expand Down

0 comments on commit 15b85d3

Please sign in to comment.