1
+ // AsyncInstantiateOperation was added since Unity 2022.3.20 / 2023.3.0b7
2
+ #if ( UNITY_2022_3 && ! ( UNITY_2022_3_0 || UNITY_2022_3_1 || UNITY_2022_3_2 || UNITY_2022_3_3 || UNITY_2022_3_4 || UNITY_2022_3_5 || UNITY_2022_3_6 || UNITY_2022_3_7 || UNITY_2022_3_8 || UNITY_2022_3_9 || UNITY_2022_3_10 || UNITY_2022_3_11 || UNITY_2022_3_12 || UNITY_2022_3_13 || UNITY_2022_3_14 || UNITY_2022_3_15 || UNITY_2022_3_16 || UNITY_2022_3_17 || UNITY_2022_3_18 || UNITY_2022_3_19 ) )
3
+ #define UNITY_2022_SUPPORT
4
+ #endif
5
+
6
+ #if UNITY_2022_SUPPORT || UNITY_2023_3_OR_NEWER
7
+
8
+ using Cysharp . Threading . Tasks . Internal ;
9
+ using System ;
10
+ using System . Threading ;
11
+ using UnityEngine ;
12
+
13
+ namespace Cysharp . Threading . Tasks
14
+ {
15
+ public static class AsyncInstantiateOperationExtensions
16
+ {
17
+ // AsyncInstantiateOperation<T> has GetAwaiter so no need to impl
18
+ // public static UniTask<T[]>.Awaiter GetAwaiter<T>(this AsyncInstantiateOperation<T> operation) where T : Object
19
+
20
+ public static UniTask < UnityEngine . Object [ ] > WithCancellation < T > ( this AsyncInstantiateOperation asyncOperation , CancellationToken cancellationToken )
21
+ {
22
+ return ToUniTask ( asyncOperation , cancellationToken : cancellationToken ) ;
23
+ }
24
+
25
+ public static UniTask < UnityEngine . Object [ ] > WithCancellation < T > ( this AsyncInstantiateOperation asyncOperation , CancellationToken cancellationToken , bool cancelImmediately )
26
+ {
27
+ return ToUniTask ( asyncOperation , cancellationToken : cancellationToken , cancelImmediately : cancelImmediately ) ;
28
+ }
29
+
30
+ public static UniTask < UnityEngine . Object [ ] > ToUniTask ( this AsyncInstantiateOperation asyncOperation , IProgress < float > progress = null , PlayerLoopTiming timing = PlayerLoopTiming . Update , CancellationToken cancellationToken = default ( CancellationToken ) , bool cancelImmediately = false )
31
+ {
32
+ Error . ThrowArgumentNullException ( asyncOperation , nameof ( asyncOperation ) ) ;
33
+ if ( cancellationToken . IsCancellationRequested ) return UniTask . FromCanceled < UnityEngine . Object [ ] > ( cancellationToken ) ;
34
+ if ( asyncOperation . isDone ) return UniTask . FromResult ( asyncOperation . Result ) ;
35
+ return new UniTask < UnityEngine . Object [ ] > ( AsyncInstantiateOperationConfiguredSource . Create ( asyncOperation , timing , progress , cancellationToken , cancelImmediately , out var token ) , token ) ;
36
+ }
37
+
38
+ public static UniTask < T [ ] > WithCancellation < T > ( this AsyncInstantiateOperation < T > asyncOperation , CancellationToken cancellationToken )
39
+ where T : UnityEngine . Object
40
+ {
41
+ return ToUniTask ( asyncOperation , cancellationToken : cancellationToken ) ;
42
+ }
43
+
44
+ public static UniTask < T [ ] > WithCancellation < T > ( this AsyncInstantiateOperation < T > asyncOperation , CancellationToken cancellationToken , bool cancelImmediately )
45
+ where T : UnityEngine . Object
46
+ {
47
+ return ToUniTask ( asyncOperation , cancellationToken : cancellationToken , cancelImmediately : cancelImmediately ) ;
48
+ }
49
+
50
+ public static UniTask < T [ ] > ToUniTask < T > ( this AsyncInstantiateOperation < T > asyncOperation , IProgress < float > progress = null , PlayerLoopTiming timing = PlayerLoopTiming . Update , CancellationToken cancellationToken = default ( CancellationToken ) , bool cancelImmediately = false )
51
+ where T : UnityEngine . Object
52
+ {
53
+ Error . ThrowArgumentNullException ( asyncOperation , nameof ( asyncOperation ) ) ;
54
+ if ( cancellationToken . IsCancellationRequested ) return UniTask . FromCanceled < T [ ] > ( cancellationToken ) ;
55
+ if ( asyncOperation . isDone ) return UniTask . FromResult ( asyncOperation . Result ) ;
56
+ return new UniTask < T [ ] > ( AsyncInstantiateOperationConfiguredSource < T > . Create ( asyncOperation , timing , progress , cancellationToken , cancelImmediately , out var token ) , token ) ;
57
+ }
58
+
59
+ sealed class AsyncInstantiateOperationConfiguredSource : IUniTaskSource < UnityEngine . Object [ ] > , IPlayerLoopItem , ITaskPoolNode < AsyncInstantiateOperationConfiguredSource >
60
+ {
61
+ static TaskPool < AsyncInstantiateOperationConfiguredSource > pool ;
62
+ AsyncInstantiateOperationConfiguredSource nextNode ;
63
+ public ref AsyncInstantiateOperationConfiguredSource NextNode => ref nextNode ;
64
+
65
+ static AsyncInstantiateOperationConfiguredSource ( )
66
+ {
67
+ TaskPool . RegisterSizeGetter ( typeof ( AsyncInstantiateOperationConfiguredSource ) , ( ) => pool . Size ) ;
68
+ }
69
+
70
+ AsyncInstantiateOperation asyncOperation ;
71
+ IProgress < float > progress ;
72
+ CancellationToken cancellationToken ;
73
+ CancellationTokenRegistration cancellationTokenRegistration ;
74
+ bool cancelImmediately ;
75
+ bool completed ;
76
+
77
+ UniTaskCompletionSourceCore < UnityEngine . Object [ ] > core ;
78
+
79
+ Action < AsyncOperation > continuationAction ;
80
+
81
+ AsyncInstantiateOperationConfiguredSource ( )
82
+ {
83
+ continuationAction = Continuation ;
84
+ }
85
+
86
+ public static IUniTaskSource < UnityEngine . Object [ ] > Create ( AsyncInstantiateOperation asyncOperation , PlayerLoopTiming timing , IProgress < float > progress , CancellationToken cancellationToken , bool cancelImmediately , out short token )
87
+ {
88
+ if ( cancellationToken . IsCancellationRequested )
89
+ {
90
+ return AutoResetUniTaskCompletionSource < UnityEngine . Object [ ] > . CreateFromCanceled ( cancellationToken , out token ) ;
91
+ }
92
+
93
+ if ( ! pool . TryPop ( out var result ) )
94
+ {
95
+ result = new AsyncInstantiateOperationConfiguredSource ( ) ;
96
+ }
97
+
98
+ result . asyncOperation = asyncOperation ;
99
+ result . progress = progress ;
100
+ result . cancellationToken = cancellationToken ;
101
+ result . cancelImmediately = cancelImmediately ;
102
+ result . completed = false ;
103
+
104
+ asyncOperation . completed += result . continuationAction ;
105
+
106
+ if ( cancelImmediately && cancellationToken . CanBeCanceled )
107
+ {
108
+ result . cancellationTokenRegistration = cancellationToken . RegisterWithoutCaptureExecutionContext ( state =>
109
+ {
110
+ var source = ( AsyncInstantiateOperationConfiguredSource ) state ;
111
+ source . core . TrySetCanceled ( source . cancellationToken ) ;
112
+ } , result ) ;
113
+ }
114
+
115
+ TaskTracker . TrackActiveTask ( result , 3 ) ;
116
+
117
+ PlayerLoopHelper . AddAction ( timing , result ) ;
118
+
119
+ token = result . core . Version ;
120
+ return result ;
121
+ }
122
+
123
+ public UnityEngine . Object [ ] GetResult ( short token )
124
+ {
125
+ try
126
+ {
127
+ return core . GetResult ( token ) ;
128
+ }
129
+ finally
130
+ {
131
+ if ( ! ( cancelImmediately && cancellationToken . IsCancellationRequested ) )
132
+ {
133
+ TryReturn ( ) ;
134
+ }
135
+ else
136
+ {
137
+ TaskTracker . RemoveTracking ( this ) ;
138
+ }
139
+ }
140
+ }
141
+
142
+ void IUniTaskSource . GetResult ( short token )
143
+ {
144
+ GetResult ( token ) ;
145
+ }
146
+
147
+ public UniTaskStatus GetStatus ( short token )
148
+ {
149
+ return core . GetStatus ( token ) ;
150
+ }
151
+
152
+ public UniTaskStatus UnsafeGetStatus ( )
153
+ {
154
+ return core . UnsafeGetStatus ( ) ;
155
+ }
156
+
157
+ public void OnCompleted ( Action < object > continuation , object state , short token )
158
+ {
159
+ core . OnCompleted ( continuation , state , token ) ;
160
+ }
161
+
162
+ public bool MoveNext ( )
163
+ {
164
+ // Already completed
165
+ if ( completed || asyncOperation == null )
166
+ {
167
+ return false ;
168
+ }
169
+
170
+ if ( cancellationToken . IsCancellationRequested )
171
+ {
172
+ core . TrySetCanceled ( cancellationToken ) ;
173
+ return false ;
174
+ }
175
+
176
+ if ( progress != null )
177
+ {
178
+ progress . Report ( asyncOperation . progress ) ;
179
+ }
180
+
181
+ if ( asyncOperation . isDone )
182
+ {
183
+ core . TrySetResult ( asyncOperation . Result ) ;
184
+ return false ;
185
+ }
186
+
187
+ return true ;
188
+ }
189
+
190
+ bool TryReturn ( )
191
+ {
192
+ TaskTracker . RemoveTracking ( this ) ;
193
+ core . Reset ( ) ;
194
+ asyncOperation . completed -= continuationAction ;
195
+ asyncOperation = default ;
196
+ progress = default ;
197
+ cancellationToken = default ;
198
+ cancellationTokenRegistration . Dispose ( ) ;
199
+ cancelImmediately = default ;
200
+ return pool . TryPush ( this ) ;
201
+ }
202
+
203
+ void Continuation ( AsyncOperation _ )
204
+ {
205
+ if ( completed )
206
+ {
207
+ return ;
208
+ }
209
+ completed = true ;
210
+ if ( cancellationToken . IsCancellationRequested )
211
+ {
212
+ core . TrySetCanceled ( cancellationToken ) ;
213
+ }
214
+ else
215
+ {
216
+ core . TrySetResult ( asyncOperation . Result ) ;
217
+ }
218
+ }
219
+ }
220
+
221
+ sealed class AsyncInstantiateOperationConfiguredSource < T > : IUniTaskSource < T [ ] > , IPlayerLoopItem , ITaskPoolNode < AsyncInstantiateOperationConfiguredSource < T > >
222
+ where T : UnityEngine . Object
223
+ {
224
+ static TaskPool < AsyncInstantiateOperationConfiguredSource < T > > pool ;
225
+ AsyncInstantiateOperationConfiguredSource < T > nextNode ;
226
+ public ref AsyncInstantiateOperationConfiguredSource < T > NextNode => ref nextNode ;
227
+
228
+ static AsyncInstantiateOperationConfiguredSource ( )
229
+ {
230
+ TaskPool . RegisterSizeGetter ( typeof ( AsyncInstantiateOperationConfiguredSource < T > ) , ( ) => pool . Size ) ;
231
+ }
232
+
233
+ AsyncInstantiateOperation < T > asyncOperation ;
234
+ IProgress < float > progress ;
235
+ CancellationToken cancellationToken ;
236
+ CancellationTokenRegistration cancellationTokenRegistration ;
237
+ bool cancelImmediately ;
238
+ bool completed ;
239
+
240
+ UniTaskCompletionSourceCore < T [ ] > core ;
241
+
242
+ Action < AsyncOperation > continuationAction ;
243
+
244
+ AsyncInstantiateOperationConfiguredSource ( )
245
+ {
246
+ continuationAction = Continuation ;
247
+ }
248
+
249
+ public static IUniTaskSource < T [ ] > Create ( AsyncInstantiateOperation < T > asyncOperation , PlayerLoopTiming timing , IProgress < float > progress , CancellationToken cancellationToken , bool cancelImmediately , out short token )
250
+ {
251
+ if ( cancellationToken . IsCancellationRequested )
252
+ {
253
+ return AutoResetUniTaskCompletionSource < T [ ] > . CreateFromCanceled ( cancellationToken , out token ) ;
254
+ }
255
+
256
+ if ( ! pool . TryPop ( out var result ) )
257
+ {
258
+ result = new AsyncInstantiateOperationConfiguredSource < T > ( ) ;
259
+ }
260
+
261
+ result . asyncOperation = asyncOperation ;
262
+ result . progress = progress ;
263
+ result . cancellationToken = cancellationToken ;
264
+ result . cancelImmediately = cancelImmediately ;
265
+ result . completed = false ;
266
+
267
+ asyncOperation . completed += result . continuationAction ;
268
+
269
+ if ( cancelImmediately && cancellationToken . CanBeCanceled )
270
+ {
271
+ result . cancellationTokenRegistration = cancellationToken . RegisterWithoutCaptureExecutionContext ( state =>
272
+ {
273
+ var source = ( AsyncInstantiateOperationConfiguredSource < T > ) state ;
274
+ source . core . TrySetCanceled ( source . cancellationToken ) ;
275
+ } , result ) ;
276
+ }
277
+
278
+ TaskTracker . TrackActiveTask ( result , 3 ) ;
279
+
280
+ PlayerLoopHelper . AddAction ( timing , result ) ;
281
+
282
+ token = result . core . Version ;
283
+ return result ;
284
+ }
285
+
286
+ public T [ ] GetResult ( short token )
287
+ {
288
+ try
289
+ {
290
+ return core . GetResult ( token ) ;
291
+ }
292
+ finally
293
+ {
294
+ if ( ! ( cancelImmediately && cancellationToken . IsCancellationRequested ) )
295
+ {
296
+ TryReturn ( ) ;
297
+ }
298
+ else
299
+ {
300
+ TaskTracker . RemoveTracking ( this ) ;
301
+ }
302
+ }
303
+ }
304
+
305
+ void IUniTaskSource . GetResult ( short token )
306
+ {
307
+ GetResult ( token ) ;
308
+ }
309
+
310
+ public UniTaskStatus GetStatus ( short token )
311
+ {
312
+ return core . GetStatus ( token ) ;
313
+ }
314
+
315
+ public UniTaskStatus UnsafeGetStatus ( )
316
+ {
317
+ return core . UnsafeGetStatus ( ) ;
318
+ }
319
+
320
+ public void OnCompleted ( Action < object > continuation , object state , short token )
321
+ {
322
+ core . OnCompleted ( continuation , state , token ) ;
323
+ }
324
+
325
+ public bool MoveNext ( )
326
+ {
327
+ // Already completed
328
+ if ( completed || asyncOperation == null )
329
+ {
330
+ return false ;
331
+ }
332
+
333
+ if ( cancellationToken . IsCancellationRequested )
334
+ {
335
+ core . TrySetCanceled ( cancellationToken ) ;
336
+ return false ;
337
+ }
338
+
339
+ if ( progress != null )
340
+ {
341
+ progress . Report ( asyncOperation . progress ) ;
342
+ }
343
+
344
+ if ( asyncOperation . isDone )
345
+ {
346
+ core . TrySetResult ( asyncOperation . Result ) ;
347
+ return false ;
348
+ }
349
+
350
+ return true ;
351
+ }
352
+
353
+ bool TryReturn ( )
354
+ {
355
+ TaskTracker . RemoveTracking ( this ) ;
356
+ core . Reset ( ) ;
357
+ asyncOperation . completed -= continuationAction ;
358
+ asyncOperation = default ;
359
+ progress = default ;
360
+ cancellationToken = default ;
361
+ cancellationTokenRegistration . Dispose ( ) ;
362
+ cancelImmediately = default ;
363
+ return pool . TryPush ( this ) ;
364
+ }
365
+
366
+ void Continuation ( AsyncOperation _ )
367
+ {
368
+ if ( completed )
369
+ {
370
+ return ;
371
+ }
372
+ completed = true ;
373
+ if ( cancellationToken . IsCancellationRequested )
374
+ {
375
+ core . TrySetCanceled ( cancellationToken ) ;
376
+ }
377
+ else
378
+ {
379
+ core . TrySetResult ( asyncOperation . Result ) ;
380
+ }
381
+ }
382
+ }
383
+ }
384
+ }
385
+
386
+ #endif
0 commit comments