com.wallstop-studios.unity-helpers 2.0.0-rc54 → 2.0.0-rc56

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,108 @@
1
+ namespace UnityHelpers.Core.Extension
2
+ {
3
+ using System;
4
+ using System.Collections.Concurrent;
5
+ using System.Collections.Generic;
6
+ using System.Runtime.CompilerServices;
7
+ using System.Threading.Tasks;
8
+ using UnityEngine;
9
+
10
+ public static class AsyncOperationExtensions
11
+ {
12
+ private static readonly ConcurrentDictionary<
13
+ AsyncOperation,
14
+ Action<AsyncOperation>
15
+ > Handlers = new();
16
+ private static readonly ConcurrentDictionary<AsyncOperation, Action> Continuations = new();
17
+
18
+ public readonly struct AsyncOperationAwaiter : INotifyCompletion
19
+ {
20
+ private readonly AsyncOperation _operation;
21
+
22
+ public AsyncOperationAwaiter(AsyncOperation operation)
23
+ {
24
+ _operation = operation ?? throw new ArgumentNullException(nameof(operation));
25
+ }
26
+
27
+ public bool IsCompleted => _operation.isDone;
28
+
29
+ public void OnCompleted(Action continuation)
30
+ {
31
+ Continuations[_operation] = continuation;
32
+
33
+ Action<AsyncOperation> handler = CachedHandler;
34
+ if (!Handlers.TryAdd(_operation, handler))
35
+ {
36
+ return;
37
+ }
38
+
39
+ Handlers[_operation] = handler;
40
+ _operation.completed += handler;
41
+ }
42
+
43
+ public void GetResult() { }
44
+ }
45
+
46
+ private static readonly Action<AsyncOperation> CachedHandler = OnOperationCompleted;
47
+
48
+ private static void OnOperationCompleted(AsyncOperation operation)
49
+ {
50
+ Handlers.Remove(operation, out Action<AsyncOperation> _);
51
+ if (!Continuations.Remove(operation, out Action completionCondition))
52
+ {
53
+ return;
54
+ }
55
+
56
+ completionCondition?.Invoke();
57
+ }
58
+
59
+ public static async Task AsTask(this AsyncOperation asyncOp)
60
+ {
61
+ if (asyncOp.isDone)
62
+ {
63
+ return;
64
+ }
65
+
66
+ await asyncOp;
67
+ }
68
+
69
+ public static async ValueTask AsValueTask(this AsyncOperation asyncOp)
70
+ {
71
+ if (asyncOp.isDone)
72
+ {
73
+ return;
74
+ }
75
+
76
+ await asyncOp;
77
+ }
78
+
79
+ public static AsyncOperationAwaiter GetAwaiter(this AsyncOperation op)
80
+ {
81
+ return new AsyncOperationAwaiter(op);
82
+ }
83
+
84
+ public static async ValueTask WithContinuation(this ValueTask task, Action continuation)
85
+ {
86
+ await task;
87
+ continuation?.Invoke();
88
+ }
89
+
90
+ public static async ValueTask<TResult> WithContinuation<TResult>(
91
+ this ValueTask<TResult> task,
92
+ Func<TResult, TResult> continuation
93
+ )
94
+ {
95
+ TResult result = await task;
96
+ return continuation(result);
97
+ }
98
+
99
+ public static async ValueTask WithContinuation<TResult>(
100
+ this ValueTask<TResult> task,
101
+ Action<TResult> continuation
102
+ )
103
+ {
104
+ TResult result = await task;
105
+ continuation(result);
106
+ }
107
+ }
108
+ }
@@ -0,0 +1,3 @@
1
+ fileFormatVersion: 2
2
+ guid: 198fd29beff34b32b0d4c19eb0ce843b
3
+ timeCreated: 1743991510
@@ -1578,13 +1578,6 @@
1578
1578
  return false;
1579
1579
  }
1580
1580
 
1581
- public static Task AsTask(this AsyncOperation asyncOp)
1582
- {
1583
- TaskCompletionSource<bool> taskCompletionSource = new();
1584
- asyncOp.completed += _ => taskCompletionSource.SetResult(true);
1585
- return taskCompletionSource.Task;
1586
- }
1587
-
1588
1581
  #if UNITY_EDITOR
1589
1582
  public static IEnumerable<Sprite> GetSpritesFromClip(this AnimationClip clip)
1590
1583
  {
@@ -41,19 +41,17 @@
41
41
  #endif
42
42
  }
43
43
 
44
- public static async Task<DeferredDisposalResult<T>> GetObjectOfTypeInScene<T>(
44
+ public static async ValueTask<DeferredDisposalResult<T>> GetObjectOfTypeInScene<T>(
45
45
  string scenePath
46
46
  )
47
47
  where T : Object
48
48
  {
49
49
  DeferredDisposalResult<T[]> result = await GetAllObjectsOfTypeInScene<T>(scenePath);
50
- return new DeferredDisposalResult<T>(
51
- result.result.FirstOrDefault(),
52
- result.DisposeAsync
53
- );
50
+ T value = result.result.Length == 0 ? default : result.result[0];
51
+ return new DeferredDisposalResult<T>(value, result.DisposeAsync);
54
52
  }
55
53
 
56
- public static async Task<DeferredDisposalResult<T[]>> GetAllObjectsOfTypeInScene<T>(
54
+ public static async ValueTask<DeferredDisposalResult<T[]>> GetAllObjectsOfTypeInScene<T>(
57
55
  string scenePath
58
56
  )
59
57
  where T : Object
@@ -63,24 +61,23 @@
63
61
  TaskCompletionSource<T[]> taskCompletionSource = new();
64
62
 
65
63
  SceneLoadScope sceneScope = new(scenePath, OnSceneLoaded);
66
- return await taskCompletionSource.Task.ContinueWith(result =>
67
- {
68
- return new DeferredDisposalResult<T[]>(
69
- result.Result,
70
- async () =>
71
- {
72
- TaskCompletionSource<bool> disposalComplete = new();
73
- UnityMainThreadDispatcher.Instance.RunOnMainThread(
74
- () =>
75
- sceneScope
76
- .DisposeAsync()
77
- .ContinueWith(_ => disposalComplete.SetResult(true))
78
- );
64
+ T[] result = await taskCompletionSource.Task;
79
65
 
80
- await disposalComplete.Task;
81
- }
82
- );
83
- });
66
+ return new DeferredDisposalResult<T[]>(
67
+ result,
68
+ async () =>
69
+ {
70
+ TaskCompletionSource<bool> disposalComplete = new();
71
+ UnityMainThreadDispatcher.Instance.RunOnMainThread(
72
+ () =>
73
+ _ = sceneScope
74
+ .DisposeAsync()
75
+ .WithContinuation(() => disposalComplete.SetResult(true))
76
+ );
77
+
78
+ await disposalComplete.Task;
79
+ }
80
+ );
84
81
 
85
82
  void OnSceneLoaded(Scene scene, LoadSceneMode mode)
86
83
  {
@@ -102,13 +99,21 @@
102
99
  return go.scene == scene;
103
100
  })
104
101
  .ToArray();
105
- taskCompletionSource.TrySetResult(foundObjects);
102
+ taskCompletionSource.SetResult(foundObjects);
106
103
  }
107
104
  }
108
105
 
109
- public sealed class SceneLoadScope
106
+ public
107
+ #if UNITY_EDITOR
108
+ readonly
109
+ #endif
110
+ struct SceneLoadScope
110
111
  {
111
- private Scene? _openedScene;
112
+ private
113
+ #if UNITY_EDITOR
114
+ readonly
115
+ #endif
116
+ Scene? _openedScene;
112
117
  private readonly UnityAction<Scene, LoadSceneMode> _onSceneLoaded;
113
118
  private readonly bool _eventAdded;
114
119
 
@@ -167,7 +172,7 @@
167
172
  }
168
173
  }
169
174
 
170
- public async Task DisposeAsync()
175
+ public async ValueTask DisposeAsync()
171
176
  {
172
177
  if (_eventAdded)
173
178
  {
@@ -193,22 +198,14 @@
193
198
  #if UNITY_EDITOR
194
199
  if (Application.isPlaying)
195
200
  {
196
- AsyncOperation asyncOperation = SceneManager.UnloadSceneAsync(
197
- openedScene,
198
- UnloadSceneOptions.None
199
- );
200
- await asyncOperation.AsTask();
201
+ await SceneManager.UnloadSceneAsync(openedScene, UnloadSceneOptions.None);
201
202
  }
202
203
  else
203
204
  {
204
205
  EditorSceneManager.CloseScene(openedScene, true);
205
206
  }
206
207
  #else
207
- AsyncOperation asyncOperation = SceneManager.UnloadSceneAsync(
208
- openedScene,
209
- UnloadSceneOptions.None
210
- );
211
- await asyncOperation.AsTask();
208
+ await SceneManager.UnloadSceneAsync(openedScene, UnloadSceneOptions.None);
212
209
  #endif
213
210
  }
214
211
  }
@@ -3,19 +3,19 @@
3
3
  using System;
4
4
  using System.Threading.Tasks;
5
5
 
6
- public sealed class DeferredDisposalResult<T>
6
+ public readonly struct DeferredDisposalResult<T>
7
7
  {
8
8
  public readonly T result;
9
9
 
10
- private readonly Func<Task> _disposeAsync;
10
+ private readonly Func<ValueTask> _disposeAsync;
11
11
 
12
- public DeferredDisposalResult(T result, Func<Task> disposeAsync)
12
+ public DeferredDisposalResult(T result, Func<ValueTask> disposeAsync)
13
13
  {
14
14
  this.result = result;
15
15
  _disposeAsync = disposeAsync ?? throw new ArgumentNullException(nameof(disposeAsync));
16
16
  }
17
17
 
18
- public async Task DisposeAsync()
18
+ public async ValueTask DisposeAsync()
19
19
  {
20
20
  await _disposeAsync();
21
21
  }
@@ -13,12 +13,14 @@
13
13
 
14
14
  public sealed class SceneHelperTests
15
15
  {
16
- private readonly List<Func<Task>> _disposalTasks = new();
16
+ private readonly List<Func<ValueTask>> _disposalTasks = new();
17
17
 
18
18
  [UnityTearDown]
19
19
  public IEnumerator TearDown()
20
20
  {
21
- foreach (Task disposal in _disposalTasks.Select(disposalProducer => disposalProducer()))
21
+ foreach (
22
+ ValueTask disposal in _disposalTasks.Select(disposalProducer => disposalProducer())
23
+ )
22
24
  {
23
25
  while (!disposal.IsCompleted)
24
26
  {
@@ -55,7 +57,7 @@
55
57
  [UnityTest]
56
58
  public IEnumerator GetObjectOfTypeInScene()
57
59
  {
58
- Task<DeferredDisposalResult<SpriteRenderer>> task =
60
+ ValueTask<DeferredDisposalResult<SpriteRenderer>> task =
59
61
  SceneHelper.GetObjectOfTypeInScene<SpriteRenderer>(
60
62
  @"Packages\com.wallstop-studios.unity-helpers\Tests\Runtime\Scenes\Test1.unity"
61
63
  );
@@ -63,7 +65,7 @@
63
65
  {
64
66
  yield return null;
65
67
  }
66
- Assert.IsTrue(task.IsCompletedSuccessfully, task.Exception?.ToString() ?? string.Empty);
68
+ Assert.IsTrue(task.IsCompletedSuccessfully);
67
69
 
68
70
  _disposalTasks.Add(task.Result.DisposeAsync);
69
71
  SpriteRenderer found = task.Result.result;
@@ -73,7 +75,7 @@
73
75
  [UnityTest]
74
76
  public IEnumerator GetAllObjectOfTypeInScene()
75
77
  {
76
- Task<DeferredDisposalResult<SpriteRenderer[]>> task =
78
+ ValueTask<DeferredDisposalResult<SpriteRenderer[]>> task =
77
79
  SceneHelper.GetAllObjectsOfTypeInScene<SpriteRenderer>(
78
80
  @"Packages\com.wallstop-studios.unity-helpers\Tests\Runtime\Scenes\Test1.unity"
79
81
  );
@@ -83,7 +85,7 @@
83
85
  yield return null;
84
86
  }
85
87
 
86
- Assert.IsTrue(task.IsCompletedSuccessfully, task.Exception?.ToString() ?? string.Empty);
88
+ Assert.IsTrue(task.IsCompletedSuccessfully);
87
89
  _disposalTasks.Add(task.Result.DisposeAsync);
88
90
  SpriteRenderer[] found = task.Result.result;
89
91
  Assert.That(found, Has.Length.EqualTo(7));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "com.wallstop-studios.unity-helpers",
3
- "version": "2.0.0-rc54",
3
+ "version": "2.0.0-rc56",
4
4
  "displayName": "Unity Helpers",
5
5
  "description": "Various Unity Helper Library",
6
6
  "dependencies": {},