2025-02-28 16:08:26 +08:00
#if UNITY_2020_1_OR_NEWER & & ! UNITY_2021
#define UNITY_2020_BUG
#endif
using System ;
using System.Runtime.CompilerServices ;
using YooAsset ;
using static Cysharp . Threading . Tasks . Internal . Error ;
namespace Cysharp.Threading.Tasks
{
2025-09-10 16:04:08 +08:00
public static class HandleBaseExtensions
2025-02-28 16:08:26 +08:00
{
public static UniTask . Awaiter GetAwaiter ( this HandleBase handle )
{
return ToUniTask ( handle ) . GetAwaiter ( ) ;
}
2025-09-10 16:04:08 +08:00
public static UniTask ToUniTask ( this HandleBase handle , IProgress < float > progress = null , PlayerLoopTiming timing = PlayerLoopTiming . Update )
2025-02-28 16:08:26 +08:00
{
ThrowArgumentNullException ( handle , nameof ( handle ) ) ;
2025-09-10 16:04:08 +08:00
if ( ! handle . IsValid )
2025-02-28 16:08:26 +08:00
{
return UniTask . CompletedTask ;
}
return new UniTask (
2025-09-10 16:04:08 +08:00
HandleBaserConfiguredSource . Create ( handle , timing , progress , out var token ) ,
2025-02-28 16:08:26 +08:00
token
) ;
}
2025-09-10 16:04:08 +08:00
sealed class HandleBaserConfiguredSource : IUniTaskSource , IPlayerLoopItem , ITaskPoolNode < HandleBaserConfiguredSource >
2025-02-28 16:08:26 +08:00
{
2025-09-10 16:04:08 +08:00
private static TaskPool < HandleBaserConfiguredSource > _pool ;
private HandleBaserConfiguredSource _nextNode ;
private readonly Action < HandleBase > _continuationAction ;
private HandleBase _handle ;
private IProgress < float > _progress ;
private bool _completed ;
private UniTaskCompletionSourceCore < AsyncUnit > _core ;
2025-02-28 16:08:26 +08:00
2025-09-10 16:04:08 +08:00
public ref HandleBaserConfiguredSource NextNode = > ref _nextNode ;
2025-02-28 16:08:26 +08:00
2025-09-10 16:04:08 +08:00
static HandleBaserConfiguredSource ( )
2025-02-28 16:08:26 +08:00
{
2025-09-10 16:04:08 +08:00
TaskPool . RegisterSizeGetter ( typeof ( HandleBaserConfiguredSource ) , ( ) = > _pool . Size ) ;
2025-02-28 16:08:26 +08:00
}
2025-09-10 16:04:08 +08:00
HandleBaserConfiguredSource ( ) { _continuationAction = Continuation ; }
2025-02-28 16:08:26 +08:00
2025-09-10 16:04:08 +08:00
public static IUniTaskSource Create ( HandleBase handle , PlayerLoopTiming timing , IProgress < float > progress , out short token )
2025-02-28 16:08:26 +08:00
{
2025-09-10 16:04:08 +08:00
if ( ! _pool . TryPop ( out var result ) )
2025-02-28 16:08:26 +08:00
{
2025-09-10 16:04:08 +08:00
result = new HandleBaserConfiguredSource ( ) ;
2025-02-28 16:08:26 +08:00
}
2025-09-10 16:04:08 +08:00
result . _handle = handle ;
result . _progress = progress ;
result . _completed = false ;
2025-02-28 16:08:26 +08:00
TaskTracker . TrackActiveTask ( result , 3 ) ;
2025-09-10 16:04:08 +08:00
if ( progress ! = null )
2025-02-28 16:08:26 +08:00
{
PlayerLoopHelper . AddAction ( timing , result ) ;
}
// BUG 在 Unity 2020.3.36 版本测试中, IL2Cpp 会报 如下错误
// BUG ArgumentException: Incompatible Delegate Types. First is System.Action`1[[YooAsset.AssetHandle, YooAsset, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]] second is System.Action`1[[YooAsset.OperationHandleBase, YooAsset, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]]
// BUG 也可能报的是 Action '1' Action '1' 的 InvalidCastException
2025-09-10 16:04:08 +08:00
// BUG 此处不得不这么修改, 如果后续 Unity 修复了这个问题, 可以恢复之前的写法
2025-02-28 16:08:26 +08:00
#if UNITY_2020_BUG
2025-09-10 16:04:08 +08:00
switch ( handle )
2025-02-28 16:08:26 +08:00
{
case AssetHandle asset_handle :
asset_handle . Completed + = result . AssetContinuation ;
break ;
case SceneHandle scene_handle :
scene_handle . Completed + = result . SceneContinuation ;
break ;
case SubAssetsHandle sub_asset_handle :
sub_asset_handle . Completed + = result . SubContinuation ;
break ;
case RawFileHandle raw_file_handle :
raw_file_handle . Completed + = result . RawFileContinuation ;
break ;
case AllAssetsHandle all_assets_handle :
all_assets_handle . Completed + = result . AllAssetsContinuation ;
break ;
}
#else
switch ( handle )
{
case AssetHandle asset_handle :
asset_handle . Completed + = result . continuationAction ;
break ;
case SceneHandle scene_handle :
scene_handle . Completed + = result . continuationAction ;
break ;
case SubAssetsHandle sub_asset_handle :
sub_asset_handle . Completed + = result . continuationAction ;
break ;
case RawFileHandle raw_file_handle :
raw_file_handle . Completed + = result . continuationAction ;
break ;
case AllAssetsHandle all_assets_handle :
all_assets_handle . Completed + = result . continuationAction ;
break ;
}
#endif
2025-09-10 16:04:08 +08:00
token = result . _core . Version ;
2025-02-28 16:08:26 +08:00
return result ;
}
2025-09-10 16:04:08 +08:00
2025-02-28 16:08:26 +08:00
#if UNITY_2020_BUG
private void AssetContinuation ( AssetHandle handle )
{
handle . Completed - = AssetContinuation ;
BaseContinuation ( ) ;
}
private void SceneContinuation ( SceneHandle handle )
{
handle . Completed - = SceneContinuation ;
BaseContinuation ( ) ;
}
private void SubContinuation ( SubAssetsHandle handle )
{
handle . Completed - = SubContinuation ;
BaseContinuation ( ) ;
}
private void RawFileContinuation ( RawFileHandle handle )
{
handle . Completed - = RawFileContinuation ;
BaseContinuation ( ) ;
}
private void AllAssetsContinuation ( AllAssetsHandle handle )
2025-09-10 16:04:08 +08:00
{
2025-02-28 16:08:26 +08:00
handle . Completed - = AllAssetsContinuation ;
BaseContinuation ( ) ;
}
#endif
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void BaseContinuation ( )
{
2025-09-10 16:04:08 +08:00
if ( _completed )
2025-02-28 16:08:26 +08:00
{
TryReturn ( ) ;
}
else
{
2025-09-10 16:04:08 +08:00
_completed = true ;
if ( _handle . Status = = EOperationStatus . Failed )
2025-02-28 16:08:26 +08:00
{
2025-09-10 16:04:08 +08:00
_core . TrySetException ( new Exception ( _handle . LastError ) ) ;
2025-02-28 16:08:26 +08:00
}
else
{
2025-09-10 16:04:08 +08:00
_core . TrySetResult ( AsyncUnit . Default ) ;
2025-02-28 16:08:26 +08:00
}
}
}
private void Continuation ( HandleBase _ )
{
2025-09-10 16:04:08 +08:00
switch ( _handle )
2025-02-28 16:08:26 +08:00
{
case AssetHandle asset_handle :
2025-09-10 16:04:08 +08:00
asset_handle . Completed - = _continuationAction ;
2025-02-28 16:08:26 +08:00
break ;
case SceneHandle scene_handle :
2025-09-10 16:04:08 +08:00
scene_handle . Completed - = _continuationAction ;
2025-02-28 16:08:26 +08:00
break ;
case SubAssetsHandle sub_asset_handle :
2025-09-10 16:04:08 +08:00
sub_asset_handle . Completed - = _continuationAction ;
2025-02-28 16:08:26 +08:00
break ;
case RawFileHandle raw_file_handle :
2025-09-10 16:04:08 +08:00
raw_file_handle . Completed - = _continuationAction ;
2025-02-28 16:08:26 +08:00
break ;
case AllAssetsHandle all_assets_handle :
2025-09-10 16:04:08 +08:00
all_assets_handle . Completed - = _continuationAction ;
2025-02-28 16:08:26 +08:00
break ;
}
BaseContinuation ( ) ;
}
2025-09-10 16:04:08 +08:00
private bool TryReturn ( )
2025-02-28 16:08:26 +08:00
{
TaskTracker . RemoveTracking ( this ) ;
2025-09-10 16:04:08 +08:00
_core . Reset ( ) ;
_handle = default ;
_progress = default ;
return _pool . TryPush ( this ) ;
2025-02-28 16:08:26 +08:00
}
2025-09-10 16:04:08 +08:00
public UniTaskStatus GetStatus ( short token ) = > _core . GetStatus ( token ) ;
2025-02-28 16:08:26 +08:00
public void OnCompleted ( Action < object > continuation , object state , short token )
{
2025-09-10 16:04:08 +08:00
_core . OnCompleted ( continuation , state , token ) ;
2025-02-28 16:08:26 +08:00
}
2025-09-10 16:04:08 +08:00
public void GetResult ( short token ) { _core . GetResult ( token ) ; }
public UniTaskStatus UnsafeGetStatus ( ) = > _core . UnsafeGetStatus ( ) ;
2025-02-28 16:08:26 +08:00
public bool MoveNext ( )
{
2025-09-10 16:04:08 +08:00
if ( _completed )
2025-02-28 16:08:26 +08:00
{
TryReturn ( ) ;
return false ;
}
2025-09-10 16:04:08 +08:00
if ( _handle . IsValid )
2025-02-28 16:08:26 +08:00
{
2025-09-10 16:04:08 +08:00
_progress ? . Report ( _handle . Progress ) ;
2025-02-28 16:08:26 +08:00
}
return true ;
}
}
}
2025-09-10 16:04:08 +08:00
}