diff --git a/.github/workflows/publish-nuget.yml b/.github/workflows/publish-nuget.yml
index 0c3e7a5d..26fd6966 100644
--- a/.github/workflows/publish-nuget.yml
+++ b/.github/workflows/publish-nuget.yml
@@ -30,6 +30,10 @@ jobs:
echo "version ${VERSION} not found in ProtoPromise.csproj"
exit 1
fi
+ if ! grep -q "${VERSION}" ProtoPromiseUnityHelpers/ProtoPromiseUnityHelpers.csproj; then
+ echo "version ${VERSION} not found in ProtoPromiseUnityHelpers.csproj"
+ exit 1
+ fi
if ! grep -q "\"version\": \"${VERSION}\"" ProtoPromise_Unity/Assets/Plugins/ProtoPromise/package.json; then
echo "version ${VERSION} not found in package.json"
exit 1
@@ -43,17 +47,22 @@ jobs:
with:
tag: v${{ steps.set_tag.outputs.version }}
- - name: Overwrite nuspec version
+ - name: Overwrite ProtoPromise nuspec version
run: sed -i "{s/{VERSION}/${{ steps.set_tag.outputs.version }}/g}" ProtoPromise/nuget/ProtoPromise.nuspec
- - name: Overwrite nuspec release notes
+ - name: Overwrite ProtoPromiseUnityHelpers nuspec version
+ run: sed -i "{s/{VERSION}/${{ steps.set_tag.outputs.version }}/g}" ProtoPromiseUnityHelpers/nuget/ProtoPromiseUnityHelpers.nuspec
+
+ - name: Overwrite ProtoPromise nuspec release notes
run: |
RELEASE_NOTES='${{ steps.get_release.outputs.body }}'
- export REPLACE_RELEASE_NOTES=$(echo "$RELEASE_NOTES" | sed -e ':a' -e 'N' -e '$!ba' -e 's|\n|\n |g; s/&/\&/g; s/\</g; s/>/\>/g; s/"/\"/g; s/'"'"'/\'/g')
+ export REPLACE_RELEASE_NOTES=$(echo "$RELEASE_NOTES" | sed -e ':a' -e 'N' -e '$!ba' -e 's/&/\&/g; s/\</g; s/>/\>/g; s/"/\"/g; s/'"'"'/\'/g')
perl -l -p -i -e 's/{RELEASE_NOTES}/$ENV{REPLACE_RELEASE_NOTES}/g' ProtoPromise/nuget/ProtoPromise.nuspec
- - name: Print nuspec
- run: cat ProtoPromise/nuget/ProtoPromise.nuspec
+ - name: Print nuspecs
+ run: |
+ cat ProtoPromise/nuget/ProtoPromise.nuspec
+ cat ProtoPromiseUnityHelpers/nuget/ProtoPromiseUnityHelpers.nuspec
- name: Setup nuget
uses: nuget/setup-nuget@v1
@@ -71,10 +80,18 @@ jobs:
- name: Build Release
run: dotnet build -c Release
- - name: Pack
+ - name: Pack ProtoPromise
run: nuget pack ProtoPromise/nuget/ProtoPromise.nuspec
- - name: Push
+ - name: Pack Unity Helpers
+ run: nuget pack ProtoPromiseUnityHelpers/nuget/ProtoPromiseUnityHelpers.nuspec
+
+ - name: Push ProtoPromise
run: dotnet nuget push ProtoPromise.${VERSION}.nupkg --api-key ${NUGET_API_KEY} --source https://api.nuget.org/v3/index.json
+ env:
+ NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
+
+ - name: Push Unity Helpers
+ run: dotnet nuget push ProtoPromiseUnityHelpers.${VERSION}.nupkg --api-key ${NUGET_API_KEY} --source https://api.nuget.org/v3/index.json
env:
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
\ No newline at end of file
diff --git a/DeveloperNotes.txt b/DeveloperNotes.txt
index 9aef2049..99f66f66 100644
--- a/DeveloperNotes.txt
+++ b/DeveloperNotes.txt
@@ -5,7 +5,7 @@ VERY IMPORTANT - Before doing any of this, run unit tests locally on the IL2CPP
Also test the demo scene in Unity 5.5 to make sure it works (no need to run tests as the test runner didn't exist back then).
-Update the version in both `ProtoPromise.csproj` and `package.json`.
+Update the version in `ProtoPromise.csproj`, `ProtoPromiseUnityHelpers.csproj`, and `package.json`.
To create the UnityPackage for releases:
diff --git a/ProtoPromise.sln b/ProtoPromise.sln
index cebc4b3e..dc2a2d0e 100644
--- a/ProtoPromise.sln
+++ b/ProtoPromise.sln
@@ -7,6 +7,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtoPromiseTests", "ProtoP
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProtoPromise", "ProtoPromise\ProtoPromise.csproj", "{2A0BBD14-FA01-467C-8A42-55C5C287F66D}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtoPromiseUnityHelpers", "ProtoPromiseUnityHelpers\ProtoPromiseUnityHelpers.csproj", "{5B1E6550-0342-4240-AF91-F8059F84BF67}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug_NoProgress|Any CPU = Debug_NoProgress|Any CPU
@@ -31,6 +33,14 @@ Global
{2A0BBD14-FA01-467C-8A42-55C5C287F66D}.Release_NoProgress|Any CPU.Build.0 = Release_NoProgress|Any CPU
{2A0BBD14-FA01-467C-8A42-55C5C287F66D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2A0BBD14-FA01-467C-8A42-55C5C287F66D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5B1E6550-0342-4240-AF91-F8059F84BF67}.Debug_NoProgress|Any CPU.ActiveCfg = Debug_NoProgress|Any CPU
+ {5B1E6550-0342-4240-AF91-F8059F84BF67}.Debug_NoProgress|Any CPU.Build.0 = Debug_NoProgress|Any CPU
+ {5B1E6550-0342-4240-AF91-F8059F84BF67}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5B1E6550-0342-4240-AF91-F8059F84BF67}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5B1E6550-0342-4240-AF91-F8059F84BF67}.Release_NoProgress|Any CPU.ActiveCfg = Release_NoProgress|Any CPU
+ {5B1E6550-0342-4240-AF91-F8059F84BF67}.Release_NoProgress|Any CPU.Build.0 = Release_NoProgress|Any CPU
+ {5B1E6550-0342-4240-AF91-F8059F84BF67}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5B1E6550-0342-4240-AF91-F8059F84BF67}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/ProtoPromise/ProtoPromise.csproj b/ProtoPromise/ProtoPromise.csproj
index a08a3143..ea25a701 100644
--- a/ProtoPromise/ProtoPromise.csproj
+++ b/ProtoPromise/ProtoPromise.csproj
@@ -50,7 +50,6 @@
-
diff --git a/ProtoPromise/nuget/ProtoPromise.nuspec b/ProtoPromise/nuget/ProtoPromise.nuspec
index 441cbeb8..4971346b 100644
--- a/ProtoPromise/nuget/ProtoPromise.nuspec
+++ b/ProtoPromise/nuget/ProtoPromise.nuspec
@@ -11,10 +11,8 @@
https://github.com/timcassell/ProtoPromise
Robust and efficient library for management of asynchronous operations.
-
- {RELEASE_NOTES}
-
- Copyright 2022
+ {RELEASE_NOTES}
+ Copyright ©2022 Tim Cassell
promise promises task tasks csharp unity dotnet mono coroutine coroutines concurrency concurrent parallel asynchronous async await thread threads threading then thenable callback callbacks
diff --git a/ProtoPromiseUnityHelpers/ProtoPromiseUnityHelpers.csproj b/ProtoPromiseUnityHelpers/ProtoPromiseUnityHelpers.csproj
new file mode 100644
index 00000000..e777b209
--- /dev/null
+++ b/ProtoPromiseUnityHelpers/ProtoPromiseUnityHelpers.csproj
@@ -0,0 +1,44 @@
+
+
+
+
+ net35;netstandard2.1
+ Release;Debug;
+ 2.2.0
+ true
+
+ 4
+
+
+
+
+ $(DefineConstants);NET_LEGACY
+
+
+
+ true
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+ false
+
+
+
+
+
+ UnityEngine.dll
+ false
+
+
+
+
diff --git a/ProtoPromiseUnityHelpers/UnityEngine.dll b/ProtoPromiseUnityHelpers/UnityEngine.dll
new file mode 100644
index 00000000..ff7cedd6
Binary files /dev/null and b/ProtoPromiseUnityHelpers/UnityEngine.dll differ
diff --git a/ProtoPromiseUnityHelpers/nuget/ProtoPromiseUnityHelpers.nuspec b/ProtoPromiseUnityHelpers/nuget/ProtoPromiseUnityHelpers.nuspec
new file mode 100644
index 00000000..4ff3509a
--- /dev/null
+++ b/ProtoPromiseUnityHelpers/nuget/ProtoPromiseUnityHelpers.nuspec
@@ -0,0 +1,36 @@
+
+
+
+ ProtoPromiseUnityHelpers
+ {VERSION}
+ ProtoPromise Unity Helpers
+ Tim Cassell
+ Tim Cassell
+ false
+ MIT
+ https://github.com/timcassell/ProtoPromise
+
+ ProtoPromise helpers for UnityEngine.
+
+ Copyright ©2022 Tim Cassell
+ promise promises task tasks csharp unity dotnet mono coroutine coroutines concurrency concurrent parallel asynchronous async await thread threads threading then thenable callback callbacks
+
+
+
+
+
+
+
+
+
+
+ readme.md
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ProtoPromiseUnityHelpers/nuget/readme.md b/ProtoPromiseUnityHelpers/nuget/readme.md
new file mode 100644
index 00000000..ce5ef122
--- /dev/null
+++ b/ProtoPromiseUnityHelpers/nuget/readme.md
@@ -0,0 +1,3 @@
+Helpers to assist with using Promises in UnityEngine.
+
+Note: it is not recommended to use this nuget package. Instead, you should use the Unity package available on [GitHub](https://github.com/timcassell/ProtoPromise/releases) or the [Unity Asset Store](https://assetstore.unity.com/packages/tools/integration/protopromise-181997).
\ No newline at end of file
diff --git a/ProtoPromise_Unity/Assets/Plugins/ProtoPromise/Core/InternalShared/AssemblyAttributes.cs b/ProtoPromise_Unity/Assets/Plugins/ProtoPromise/Core/InternalShared/AssemblyAttributes.cs
new file mode 100644
index 00000000..8b358b2b
--- /dev/null
+++ b/ProtoPromise_Unity/Assets/Plugins/ProtoPromise/Core/InternalShared/AssemblyAttributes.cs
@@ -0,0 +1,6 @@
+// File named AssemblyAttributes.cs instead of AssemblyInfo.cs to avoid conflicts with an auto-generated file of the same name.
+
+using System.Runtime.CompilerServices;
+
+[assembly: InternalsVisibleTo("ProtoPromiseUnityHelpers")]
+[assembly: InternalsVisibleTo("ProtoPromiseTests")]
\ No newline at end of file
diff --git a/ProtoPromise_Unity/Assets/Plugins/ProtoPromise/Core/InternalShared/AssemblyAttributes.cs.meta b/ProtoPromise_Unity/Assets/Plugins/ProtoPromise/Core/InternalShared/AssemblyAttributes.cs.meta
new file mode 100644
index 00000000..e32f2730
--- /dev/null
+++ b/ProtoPromise_Unity/Assets/Plugins/ProtoPromise/Core/InternalShared/AssemblyAttributes.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: ab000ef7195297e4094affcfeb28386d
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/ProtoPromise_Unity/Assets/Plugins/ProtoPromise/Core/InternalShared/PoolInternal.cs b/ProtoPromise_Unity/Assets/Plugins/ProtoPromise/Core/InternalShared/PoolInternal.cs
index b6d13711..f3767685 100644
--- a/ProtoPromise_Unity/Assets/Plugins/ProtoPromise/Core/InternalShared/PoolInternal.cs
+++ b/ProtoPromise_Unity/Assets/Plugins/ProtoPromise/Core/InternalShared/PoolInternal.cs
@@ -14,13 +14,11 @@
using System.Diagnostics;
using System.Runtime.CompilerServices;
-[assembly: InternalsVisibleTo("ProtoPromiseTests")]
-
namespace Proto.Promises
{
partial class Internal
{
- private static event Action OnClearPool;
+ internal static event Action OnClearPool;
internal static void ClearPool()
{
diff --git a/ProtoPromise_Unity/Assets/Plugins/ProtoPromise/Core/Promises/Unity.meta b/ProtoPromise_Unity/Assets/Plugins/ProtoPromise/UnityHelpers.meta
similarity index 77%
rename from ProtoPromise_Unity/Assets/Plugins/ProtoPromise/Core/Promises/Unity.meta
rename to ProtoPromise_Unity/Assets/Plugins/ProtoPromise/UnityHelpers.meta
index b2ccd170..76afd0e8 100644
--- a/ProtoPromise_Unity/Assets/Plugins/ProtoPromise/Core/Promises/Unity.meta
+++ b/ProtoPromise_Unity/Assets/Plugins/ProtoPromise/UnityHelpers.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: 64ed5f1f2a934714cab9081c85d437dd
+guid: ef043f32de84cc8438e0affc5f0fc367
folderAsset: yes
DefaultImporter:
externalObjects: {}
diff --git a/ProtoPromise_Unity/Assets/Plugins/ProtoPromise/Core/Promises/Unity/PromiseBehaviour.cs b/ProtoPromise_Unity/Assets/Plugins/ProtoPromise/UnityHelpers/PromiseBehaviour.cs
similarity index 51%
rename from ProtoPromise_Unity/Assets/Plugins/ProtoPromise/Core/Promises/Unity/PromiseBehaviour.cs
rename to ProtoPromise_Unity/Assets/Plugins/ProtoPromise/UnityHelpers/PromiseBehaviour.cs
index ae66bb65..ed27242b 100644
--- a/ProtoPromise_Unity/Assets/Plugins/ProtoPromise/Core/Promises/Unity/PromiseBehaviour.cs
+++ b/ProtoPromise_Unity/Assets/Plugins/ProtoPromise/UnityHelpers/PromiseBehaviour.cs
@@ -3,100 +3,38 @@
using Proto.Promises.Threading;
using System.Collections;
using System.Collections.Generic;
-using System.ComponentModel;
using System.Diagnostics;
-using System.Runtime.CompilerServices;
using UnityEngine;
namespace Proto.Promises
{
- partial struct Promise
+#if !PROTO_PROMISE_DEVELOPER_MODE
+ [DebuggerNonUserCode, StackTraceHidden]
+#endif
+ internal static partial class InternalHelper
{
- static Promise()
+ // We initialize the config as early as possible. Ideally we would just do this in static constructors of Promise() and Promise.Config,
+ // but since this is in a separate assembly, that's not possible.
+ // Also, using static constructors would slightly slow down promises in IL2CPP where it would have to check if it already ran on every call.
+#if UNITY_2019_2_OR_NEWER
+ [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
+#elif UNITY_2019_1_OR_NEWER
+ [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)]
+#else
+ [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
+#endif
+ internal static void InitializePromiseConfig()
{
- Unity.PromiseBehaviour.Init();
+ PromiseBehaviour.Init();
}
- partial class Config
- {
- // Static constructor on Config to make sure the ForegroundContext is set (in case users want to copy it to the BackgroundContext for WebGL).
- // This also prevents the PromiseBehaviour from overwriting it in case users set their own ForegroundContext before the Promise static constructor is ran.
- static Config()
- {
- Unity.PromiseBehaviour.Init();
- }
- }
- }
-
- partial struct Promise
- {
- static Promise()
- {
- Unity.PromiseBehaviour.Init();
- }
- }
-
- namespace Unity
- {
- // I would have nested this within Internal, but it had to be public for old versions, and I don't want to cause a compile error if for some strange reason a user is relying on this type.
- // So I added the EditorBrowsableAttribute to hide it in the IDE, and AddComponentMenuAttribute to hide it in the editor instead.
#if !PROTO_PROMISE_DEVELOPER_MODE
[DebuggerNonUserCode, StackTraceHidden]
#endif
- [EditorBrowsable(EditorBrowsableState.Never)]
- [AddComponentMenu("")]
- public sealed class PromiseBehaviour : MonoBehaviour
+ [AddComponentMenu("")] // Hide this in the add component menu.
+ internal sealed class PromiseBehaviour : MonoBehaviour
{
- // Dummy class is to prevent error:
- // UnityException: get_isPlayingOrWillChangePlaymode is not allowed to be called from a MonoBehaviour constructor (or instance field initializer),
- // call it in Awake or Start instead.
-#if !PROTO_PROMISE_DEVELOPER_MODE
- [DebuggerNonUserCode, StackTraceHidden]
-#endif
- private static class Dummy
- {
- // NoInlining is to ensure that the static constructor runs.
- [MethodImpl(MethodImplOptions.NoInlining)]
- public static void Init() { }
-#if UNITY_EDITOR
- private static readonly System.Threading.SynchronizationContext s_unityContext;
-#endif
-
- static Dummy()
- {
-#pragma warning disable 0612 // Type or member is obsolete
- // Set default warning handler to route to UnityEngine.Debug.
- Promise.Config.WarningHandler = UnityEngine.Debug.LogWarning;
-#pragma warning restore 0612 // Type or member is obsolete
-
-#if UNITY_EDITOR
- if (!UnityEditor.EditorApplication.isPlayingOrWillChangePlaymode)
- {
- // If we're in edit mode, just use Unity's synchronization context instead of ours.
- // It may not exist in older Unity versions, in which case we just warn the user.
- s_unityContext = System.Threading.SynchronizationContext.Current;
- if (s_unityContext == null)
- {
- Promise.Config.UncaughtRejectionHandler = UnityEngine.Debug.LogException;
- UnityEngine.Debug.LogWarning("There is no current SynchronizationContext, scheduling continuations on the foreground context may not work in edit mode. Set Promise.Config.ForegroundContext to enable foreground scheduling.");
- return;
- }
- Promise.Config.ForegroundContext = s_unityContext;
- Promise.Config.UncaughtRejectionHandler = e =>
- {
- // Route the exception through the context to avoid extra stack traces in the log.
- s_unityContext.Post(ex => UnityEngine.Debug.LogException(ex as System.Exception), e);
- };
- return;
- }
-#endif
- // Create a PromiseBehaviour instance before any promise actions are made.
- // Unity will throw if this is not ran on the main thread.
- new GameObject("Proto.Promises.Unity.PromiseBehaviour")
- .AddComponent()
- .SetSynchronizationContext();
- }
- }
+ internal static bool s_isApplicationQuitting = false;
private static PromiseBehaviour s_instance;
@@ -104,17 +42,34 @@ static Dummy()
private Queue _currentlyReportingExceptions = new Queue();
private Queue _unhandledExceptions = new Queue();
- [MethodImpl(Internal.InlineOption)]
internal static void Init()
{
- Dummy.Init();
+ // Even though we try to initialize this as early as possible, it is possible for other code to run before this.
+ // So we need to be careful to not overwrite non-default values.
+
+#pragma warning disable 0612 // Type or member is obsolete
+ if (Promise.Config.WarningHandler == null)
+ {
+ // Set default warning handler to route to UnityEngine.Debug.
+ Promise.Config.WarningHandler = UnityEngine.Debug.LogWarning;
+ }
+#pragma warning restore 0612 // Type or member is obsolete
+
+ // Create a PromiseBehaviour instance before any promise actions are made.
+ // Unity will throw if this is not ran on the main thread.
+ new GameObject("Proto.Promises.Unity.PromiseBehaviour")
+ .AddComponent()
+ .SetSynchronizationContext();
}
private void SetSynchronizationContext()
{
- if (s_instance == null)
+ if (Promise.Config.ForegroundContext == null)
{
Promise.Config.ForegroundContext = _syncContext;
+ }
+ if (Promise.Config.UncaughtRejectionHandler == null)
+ {
// Intercept uncaught rejections and report them in Update instead of directly sending them to UnityEngine.Debug.LogException
// so that we can minimize the extra stack frames in the logs that we don't care about.
Promise.Config.UncaughtRejectionHandler = HandleRejection;
@@ -139,24 +94,23 @@ private void Start()
// Users would have to go out of their way to find and destroy the PromiseBehaviour instance.
private void OnDestroy()
{
-#if UNITY_EDITOR
- if (UnityEditor.EditorApplication.isPlayingOrWillChangePlaymode)
-#endif
+ if (s_isApplicationQuitting)
+ {
+ return;
+ }
+ if (s_instance == this)
{
- if (s_instance == this)
+ UnityEngine.Debug.LogWarning("PromiseBehaviour destroyed! Removing PromiseSynchronizationContext from Promise.Config.ForegroundContext.");
+ s_instance = null;
+ if (Promise.Config.ForegroundContext == _syncContext)
+ {
+ Promise.Config.ForegroundContext = null;
+ }
+ if (Promise.Config.UncaughtRejectionHandler == HandleRejection)
{
- UnityEngine.Debug.LogWarning("PromiseBehaviour destroyed! Removing PromiseSynchronizationContext from Promise.Config.ForegroundContext.");
- s_instance = null;
- if (Promise.Config.ForegroundContext == _syncContext)
- {
- Promise.Config.ForegroundContext = null;
- }
- if (Promise.Config.UncaughtRejectionHandler == HandleRejection)
- {
- Promise.Config.UncaughtRejectionHandler = null;
- }
- _syncContext.Execute(); // Clear out any pending callbacks.
+ Promise.Config.UncaughtRejectionHandler = null;
}
+ _syncContext.Execute(); // Clear out any pending callbacks.
}
}
@@ -205,6 +159,11 @@ private void Update()
UnityEngine.Debug.LogException(_currentlyReportingExceptions.Dequeue());
}
}
+
+ private void OnApplicationQuit()
+ {
+ s_isApplicationQuitting = true;
+ }
}
}
}
\ No newline at end of file
diff --git a/ProtoPromise_Unity/Assets/Plugins/ProtoPromise/Core/Promises/Unity/PromiseBehaviour.cs.meta b/ProtoPromise_Unity/Assets/Plugins/ProtoPromise/UnityHelpers/PromiseBehaviour.cs.meta
similarity index 100%
rename from ProtoPromise_Unity/Assets/Plugins/ProtoPromise/Core/Promises/Unity/PromiseBehaviour.cs.meta
rename to ProtoPromise_Unity/Assets/Plugins/ProtoPromise/UnityHelpers/PromiseBehaviour.cs.meta
diff --git a/ProtoPromise_Unity/Assets/Plugins/ProtoPromise/Core/Promises/Unity/PromiseYieldInstruction.cs b/ProtoPromise_Unity/Assets/Plugins/ProtoPromise/UnityHelpers/PromiseYieldInstruction.cs
similarity index 86%
rename from ProtoPromise_Unity/Assets/Plugins/ProtoPromise/Core/Promises/Unity/PromiseYieldInstruction.cs
rename to ProtoPromise_Unity/Assets/Plugins/ProtoPromise/UnityHelpers/PromiseYieldInstruction.cs
index 8b15d267..4c009fab 100644
--- a/ProtoPromise_Unity/Assets/Plugins/ProtoPromise/Core/Promises/Unity/PromiseYieldInstruction.cs
+++ b/ProtoPromise_Unity/Assets/Plugins/ProtoPromise/UnityHelpers/PromiseYieldInstruction.cs
@@ -2,13 +2,8 @@
#define NET_LEGACY
#endif
-#if PROTO_PROMISE_DEBUG_ENABLE || (!PROTO_PROMISE_DEBUG_DISABLE && DEBUG)
-#define PROMISE_DEBUG
-#else
-#undef PROMISE_DEBUG
-#endif
-
#pragma warning disable 0420 // A reference to a volatile field will not be treated as volatile
+#pragma warning disable 1591 // Missing XML comment for publicly visible type or member
using System;
using System.Diagnostics;
@@ -17,20 +12,28 @@
namespace Proto.Promises
{
- partial class Extensions
+ ///
+ /// Extensions to convert Promises to Yield Instructions for Coroutines.
+ ///
+ public static class UnityHelperExtensions
{
+ ///
+ /// Convert the to a .
+ ///
public static PromiseYieldInstruction ToYieldInstruction(this Promise promise)
{
- return Internal.YieldInstructionVoid.GetOrCreate(promise);
+ return InternalHelper.YieldInstructionVoid.GetOrCreate(promise);
}
+ ///
+ /// Convert the to a .
+ ///
public static PromiseYieldInstruction ToYieldInstruction(this Promise promise)
{
- return Internal.YieldInstruction.GetOrCreate(promise);
+ return InternalHelper.YieldInstruction.GetOrCreate(promise);
}
}
-
///
/// Yield instruction that can be yielded in a coroutine to wait until the it came from has settled.
///
@@ -43,7 +46,6 @@ public abstract class PromiseYieldInstruction : CustomYieldInstruction, IDisposa
volatile protected Promise.State _state;
volatile protected int _retainCounter;
-
internal PromiseYieldInstruction() { }
///
@@ -151,24 +153,24 @@ internal PromiseYieldInstruction() { }
}
}
- partial class Internal
+ partial class InternalHelper
{
#if !PROTO_PROMISE_DEVELOPER_MODE
[DebuggerNonUserCode, StackTraceHidden]
#endif
- internal sealed class YieldInstructionVoid : PromiseYieldInstruction, ILinked
+ internal sealed class YieldInstructionVoid : PromiseYieldInstruction, Internal.ILinked
{
// These must not be readonly.
- private static ValueLinkedStack s_pool;
- private static SpinLocker s_spinLocker;
+ private static Internal.ValueLinkedStack s_pool;
+ private static Internal.SpinLocker s_spinLocker;
private int _disposeChecker; // To detect if Dispose is called from multiple threads.
- YieldInstructionVoid ILinked.Next { get; set; }
+ YieldInstructionVoid Internal.ILinked.Next { get; set; }
static YieldInstructionVoid()
{
- OnClearPool += () => s_pool = new ValueLinkedStack();
+ Internal.OnClearPool += () => s_pool = new Internal.ValueLinkedStack();
}
private YieldInstructionVoid() { }
@@ -208,7 +210,7 @@ public override void Dispose()
if (Interlocked.Exchange(ref _disposeChecker, 1) == 1)
#endif
{
- throw new InvalidOperationException("Promise yield instruction is not valid after you have disposed. You can get a valid yield instruction by calling promise.ToYieldInstruction().", GetFormattedStacktrace(1));
+ throw new InvalidOperationException("Promise yield instruction is not valid after you have disposed. You can get a valid yield instruction by calling promise.ToYieldInstruction().", Internal.GetFormattedStacktrace(1));
}
MaybeDispose();
}
@@ -218,14 +220,12 @@ private void MaybeDispose()
if (Interlocked.Decrement(ref _retainCounter) == 0)
{
_rejectContainer = null;
-#if !PROMISE_DEBUG // Don't repool in DEBUG mode.
if (Promise.Config.ObjectPoolingEnabled)
{
s_spinLocker.Enter();
s_pool.Push(this);
s_spinLocker.Exit();
}
-#endif
}
}
}
@@ -233,19 +233,19 @@ private void MaybeDispose()
#if !PROTO_PROMISE_DEVELOPER_MODE
[DebuggerNonUserCode, StackTraceHidden]
#endif
- internal sealed class YieldInstruction : PromiseYieldInstruction, ILinked>
+ internal sealed class YieldInstruction : PromiseYieldInstruction, Internal.ILinked>
{
// These must not be readonly.
- private static ValueLinkedStack> s_pool;
- private static SpinLocker s_spinLocker;
+ private static Internal.ValueLinkedStack> s_pool;
+ private static Internal.SpinLocker s_spinLocker;
private int _disposeChecker; // To detect if Dispose is called from multiple threads.
- YieldInstruction ILinked>.Next { get; set; }
+ YieldInstruction Internal.ILinked>.Next { get; set; }
static YieldInstruction()
{
- OnClearPool += () => s_pool = new ValueLinkedStack>();
+ Internal.OnClearPool += () => s_pool = new Internal.ValueLinkedStack>();
}
private YieldInstruction() { }
@@ -289,7 +289,7 @@ public override void Dispose()
if (Interlocked.Exchange(ref _disposeChecker, 1) == 1)
#endif
{
- throw new InvalidOperationException("Promise yield instruction is not valid after you have disposed. You can get a valid yield instruction by calling promise.ToYieldInstruction().", GetFormattedStacktrace(1));
+ throw new InvalidOperationException("Promise yield instruction is not valid after you have disposed. You can get a valid yield instruction by calling promise.ToYieldInstruction().", Internal.GetFormattedStacktrace(1));
}
MaybeDispose();
}
@@ -299,14 +299,12 @@ private void MaybeDispose()
if (Interlocked.Decrement(ref _retainCounter) == 0)
{
_rejectContainer = null;
-#if !PROMISE_DEBUG // Don't repool in DEBUG mode.
if (Promise.Config.ObjectPoolingEnabled)
{
s_spinLocker.Enter();
s_pool.Push(this);
s_spinLocker.Exit();
}
-#endif
}
}
}
diff --git a/ProtoPromise_Unity/Assets/Plugins/ProtoPromise/Core/Promises/Unity/PromiseYieldInstruction.cs.meta b/ProtoPromise_Unity/Assets/Plugins/ProtoPromise/UnityHelpers/PromiseYieldInstruction.cs.meta
similarity index 100%
rename from ProtoPromise_Unity/Assets/Plugins/ProtoPromise/Core/Promises/Unity/PromiseYieldInstruction.cs.meta
rename to ProtoPromise_Unity/Assets/Plugins/ProtoPromise/UnityHelpers/PromiseYieldInstruction.cs.meta
diff --git a/ProtoPromise_Unity/Assets/Plugins/ProtoPromise/Core/Promises/Unity/PromiseYielder.cs b/ProtoPromise_Unity/Assets/Plugins/ProtoPromise/UnityHelpers/PromiseYielder.cs
similarity index 71%
rename from ProtoPromise_Unity/Assets/Plugins/ProtoPromise/Core/Promises/Unity/PromiseYielder.cs
rename to ProtoPromise_Unity/Assets/Plugins/ProtoPromise/UnityHelpers/PromiseYielder.cs
index bc6d59b3..f932bd93 100644
--- a/ProtoPromise_Unity/Assets/Plugins/ProtoPromise/Core/Promises/Unity/PromiseYielder.cs
+++ b/ProtoPromise_Unity/Assets/Plugins/ProtoPromise/UnityHelpers/PromiseYielder.cs
@@ -1,10 +1,4 @@
-#if PROTO_PROMISE_DEBUG_ENABLE || (!PROTO_PROMISE_DEBUG_DISABLE && DEBUG)
-#define PROMISE_DEBUG
-#else
-#undef PROMISE_DEBUG
-#endif
-
-#pragma warning disable IDE0034 // Simplify 'default' expression
+#pragma warning disable IDE0034 // Simplify 'default' expression
#pragma warning disable IDE0051 // Remove unused private members
using System;
@@ -20,46 +14,51 @@ namespace Proto.Promises
#if !PROTO_PROMISE_DEVELOPER_MODE
[DebuggerNonUserCode, StackTraceHidden]
#endif
- [AddComponentMenu("")] // Hide this in the add component menu.
- public sealed class PromiseYielder : MonoBehaviour
+ public static class PromiseYielder
{
- private static PromiseYielder s_instance;
-
- static PromiseYielder Instance
+#if !PROTO_PROMISE_DEVELOPER_MODE
+ [DebuggerNonUserCode, StackTraceHidden]
+#endif
+ [AddComponentMenu("")] // Hide this in the add component menu.
+ private sealed class PromiseYielderBehaviour : MonoBehaviour
{
- get
+ private static PromiseYielderBehaviour s_instance;
+
+ internal static MonoBehaviour Instance
{
- if (s_instance == null)
+ get
{
- s_instance = new GameObject("Proto.Promises.PromiseYielder").AddComponent();
+ if (s_instance == null)
+ {
+ s_instance = new GameObject("Proto.Promises.PromiseYielderBehaviour").AddComponent();
+ }
+ return s_instance;
}
- return s_instance;
}
- }
- private PromiseYielder() { }
+ private PromiseYielderBehaviour() { }
- private void Start()
- {
- if (s_instance != this)
+ private void Start()
{
- UnityEngine.Debug.LogWarning("There can only be one instance of PromiseYielder. Destroying new instance.");
- Destroy(this);
- return;
+ if (s_instance != this)
+ {
+ UnityEngine.Debug.LogWarning("There can only be one instance of PromiseYielder. Destroying new instance.");
+ Destroy(this);
+ return;
+ }
+ DontDestroyOnLoad(gameObject);
+ gameObject.hideFlags = HideFlags.HideAndDontSave; // Don't show in hierarchy and don't destroy.
}
- DontDestroyOnLoad(gameObject);
- gameObject.hideFlags = HideFlags.HideAndDontSave; // Don't show in hierarchy and don't destroy.
- }
- private void OnDestroy()
- {
-#if UNITY_EDITOR
- if (UnityEditor.EditorApplication.isPlayingOrWillChangePlaymode)
-#endif
+ private void OnDestroy()
{
+ if (InternalHelper.PromiseBehaviour.s_isApplicationQuitting)
+ {
+ return;
+ }
if (s_instance == this)
{
- UnityEngine.Debug.LogWarning("PromiseYielder destroyed! Any pending PromiseYielder.WaitFor promises will not be resolved!");
+ UnityEngine.Debug.LogWarning("PromiseYielderBehaviour destroyed! Any pending PromiseYielder.WaitFor promises running on the default MonoBehaviour will not be resolved!");
s_instance = null;
}
}
@@ -87,7 +86,7 @@ internal static Promise WaitForInstruction(object yieldInstruction, MonoBehaviou
?? new Routine();
routine._deferred = Promise.NewDeferred();
bool validRunner = runner != null;
- runner = validRunner ? runner : Instance;
+ runner = validRunner ? runner : PromiseYielderBehaviour.Instance;
bool sameRunner = ReferenceEquals(runner, routine._currentRunnerRef.Target);
routine._currentRunnerRef.Target = runner;
routine.Current = yieldInstruction;
@@ -140,6 +139,7 @@ void IEnumerator.Reset() { }
/// If is provided, the coroutine will be ran on it, otherwise it will be ran on the singleton PromiseYielder instance.
///
/// The yield instruction to wait for.
+ /// The object on which the will be ran.
public static Promise WaitFor(object yieldInstruction, MonoBehaviour runner = null)
{
return Routine.WaitForInstruction(yieldInstruction, runner);
@@ -149,6 +149,7 @@ public static Promise WaitFor(object yieldInstruction, MonoBehaviour runner = nu
/// Returns a that will resolve after 1 frame.
/// If is provided, the coroutine will be ran on it, otherwise it will be ran on the singleton PromiseYielder instance.
///
+ /// The object on which the wait will be ran.
public static Promise WaitOneFrame(MonoBehaviour runner = null)
{
return Routine.WaitForInstruction(null, runner);
diff --git a/ProtoPromise_Unity/Assets/Plugins/ProtoPromise/Core/Promises/Unity/PromiseYielder.cs.meta b/ProtoPromise_Unity/Assets/Plugins/ProtoPromise/UnityHelpers/PromiseYielder.cs.meta
similarity index 100%
rename from ProtoPromise_Unity/Assets/Plugins/ProtoPromise/Core/Promises/Unity/PromiseYielder.cs.meta
rename to ProtoPromise_Unity/Assets/Plugins/ProtoPromise/UnityHelpers/PromiseYielder.cs.meta
diff --git a/ProtoPromise_Unity/Assets/Plugins/ProtoPromise/UnityHelpers/ProtoPromiseUnityHelpers.asmdef b/ProtoPromise_Unity/Assets/Plugins/ProtoPromise/UnityHelpers/ProtoPromiseUnityHelpers.asmdef
new file mode 100644
index 00000000..ce8f01d6
--- /dev/null
+++ b/ProtoPromise_Unity/Assets/Plugins/ProtoPromise/UnityHelpers/ProtoPromiseUnityHelpers.asmdef
@@ -0,0 +1,14 @@
+{
+ "name": "ProtoPromiseUnityHelpers",
+ "references": [
+ "ProtoPromise"
+ ],
+ "optionalUnityReferences": [],
+ "includePlatforms": [],
+ "excludePlatforms": [],
+ "allowUnsafeCode": false,
+ "overrideReferences": false,
+ "precompiledReferences": [],
+ "autoReferenced": true,
+ "defineConstraints": []
+}
\ No newline at end of file
diff --git a/ProtoPromise_Unity/Assets/Plugins/ProtoPromise/UnityHelpers/ProtoPromiseUnityHelpers.asmdef.meta b/ProtoPromise_Unity/Assets/Plugins/ProtoPromise/UnityHelpers/ProtoPromiseUnityHelpers.asmdef.meta
new file mode 100644
index 00000000..29e5dd7d
--- /dev/null
+++ b/ProtoPromise_Unity/Assets/Plugins/ProtoPromise/UnityHelpers/ProtoPromiseUnityHelpers.asmdef.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 5aa80380c7d32394bb76a6ad338b52bc
+AssemblyDefinitionImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/ProtoPromise_Unity/Assets/Plugins/ProtoPromiseTests/ProtoPromiseTests.asmdef b/ProtoPromise_Unity/Assets/Plugins/ProtoPromiseTests/ProtoPromiseTests.asmdef
index 37efc07d..ddd7648a 100644
--- a/ProtoPromise_Unity/Assets/Plugins/ProtoPromiseTests/ProtoPromiseTests.asmdef
+++ b/ProtoPromise_Unity/Assets/Plugins/ProtoPromiseTests/ProtoPromiseTests.asmdef
@@ -1,7 +1,8 @@
{
"name": "ProtoPromiseTests",
"references": [
- "ProtoPromise"
+ "ProtoPromise",
+ "ProtoPromiseUnityHelpers"
],
"optionalUnityReferences": [
"TestAssemblies"