com.wallstop-studios.unity-helpers 2.0.0-rc55 → 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
@@ -67,17 +65,17 @@
67
65
 
68
66
  return new DeferredDisposalResult<T[]>(
69
67
  result,
70
- () =>
68
+ async () =>
71
69
  {
72
70
  TaskCompletionSource<bool> disposalComplete = new();
73
71
  UnityMainThreadDispatcher.Instance.RunOnMainThread(
74
72
  () =>
75
- sceneScope
73
+ _ = sceneScope
76
74
  .DisposeAsync()
77
- .ContinueWith(_ => disposalComplete.SetResult(true))
75
+ .WithContinuation(() => disposalComplete.SetResult(true))
78
76
  );
79
77
 
80
- return disposalComplete.Task;
78
+ await disposalComplete.Task;
81
79
  }
82
80
  );
83
81
 
@@ -105,9 +103,17 @@
105
103
  }
106
104
  }
107
105
 
108
- public sealed class SceneLoadScope
106
+ public
107
+ #if UNITY_EDITOR
108
+ readonly
109
+ #endif
110
+ struct SceneLoadScope
109
111
  {
110
- private Scene? _openedScene;
112
+ private
113
+ #if UNITY_EDITOR
114
+ readonly
115
+ #endif
116
+ Scene? _openedScene;
111
117
  private readonly UnityAction<Scene, LoadSceneMode> _onSceneLoaded;
112
118
  private readonly bool _eventAdded;
113
119
 
@@ -166,7 +172,7 @@
166
172
  }
167
173
  }
168
174
 
169
- public async Task DisposeAsync()
175
+ public async ValueTask DisposeAsync()
170
176
  {
171
177
  if (_eventAdded)
172
178
  {
@@ -192,22 +198,14 @@
192
198
  #if UNITY_EDITOR
193
199
  if (Application.isPlaying)
194
200
  {
195
- AsyncOperation asyncOperation = SceneManager.UnloadSceneAsync(
196
- openedScene,
197
- UnloadSceneOptions.None
198
- );
199
- await asyncOperation.AsTask();
201
+ await SceneManager.UnloadSceneAsync(openedScene, UnloadSceneOptions.None);
200
202
  }
201
203
  else
202
204
  {
203
205
  EditorSceneManager.CloseScene(openedScene, true);
204
206
  }
205
207
  #else
206
- AsyncOperation asyncOperation = SceneManager.UnloadSceneAsync(
207
- openedScene,
208
- UnloadSceneOptions.None
209
- );
210
- await asyncOperation.AsTask();
208
+ await SceneManager.UnloadSceneAsync(openedScene, UnloadSceneOptions.None);
211
209
  #endif
212
210
  }
213
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-rc55",
3
+ "version": "2.0.0-rc56",
4
4
  "displayName": "Unity Helpers",
5
5
  "description": "Various Unity Helper Library",
6
6
  "dependencies": {},