2025-10-31 11:18:23 +08:00
#if UNITASK_YOOASSET_SUPPORT
#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
{
public static class HandleBaseExtensions
{
public static UniTask . Awaiter GetAwaiter ( this HandleBase handle )
{
return ToUniTask ( handle ) . GetAwaiter ( ) ;
}
public static UniTask ToUniTask ( this HandleBase handle , IProgress < float > progress = null , PlayerLoopTiming timing = PlayerLoopTiming . Update )
{
ThrowArgumentNullException ( handle , nameof ( handle ) ) ;
if ( ! handle . IsValid )
{
return UniTask . CompletedTask ;
}
return new UniTask (
HandleBaserConfiguredSource . Create ( handle , timing , progress , out var token ) ,
token
) ;
}
sealed class HandleBaserConfiguredSource : IUniTaskSource , IPlayerLoopItem , ITaskPoolNode < HandleBaserConfiguredSource >
{
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 ;
public ref HandleBaserConfiguredSource NextNode = > ref _nextNode ;
static HandleBaserConfiguredSource ( )
{
TaskPool . RegisterSizeGetter ( typeof ( HandleBaserConfiguredSource ) , ( ) = > _pool . Size ) ;
}
HandleBaserConfiguredSource ( ) { _continuationAction = Continuation ; }
public static IUniTaskSource Create ( HandleBase handle , PlayerLoopTiming timing , IProgress < float > progress , out short token )
{
if ( ! _pool . TryPop ( out var result ) )
{
result = new HandleBaserConfiguredSource ( ) ;
}
result . _handle = handle ;
result . _progress = progress ;
result . _completed = false ;
TaskTracker . TrackActiveTask ( result , 3 ) ;
if ( progress ! = null )
{
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
// BUG 此处不得不这么修改, 如果后续 Unity 修复了这个问题, 可以恢复之前的写法
#if UNITY_2020_BUG
switch ( handle )
{
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 :
2026-04-13 22:36:57 +08:00
asset_handle . Completed + = result . _continuationAction ;
2025-10-31 11:18:23 +08:00
break ;
case SceneHandle scene_handle :
2026-04-13 22:36:57 +08:00
scene_handle . Completed + = result . _continuationAction ;
2025-10-31 11:18:23 +08:00
break ;
case SubAssetsHandle sub_asset_handle :
2026-04-13 22:36:57 +08:00
sub_asset_handle . Completed + = result . _continuationAction ;
2025-10-31 11:18:23 +08:00
break ;
case RawFileHandle raw_file_handle :
2026-04-13 22:36:57 +08:00
raw_file_handle . Completed + = result . _continuationAction ;
2025-10-31 11:18:23 +08:00
break ;
case AllAssetsHandle all_assets_handle :
2026-04-13 22:36:57 +08:00
all_assets_handle . Completed + = result . _continuationAction ;
2025-10-31 11:18:23 +08:00
break ;
}
#endif
token = result . _core . Version ;
return result ;
}
#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 )
{
handle . Completed - = AllAssetsContinuation ;
BaseContinuation ( ) ;
}
#endif
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void BaseContinuation ( )
{
if ( _completed )
{
TryReturn ( ) ;
}
else
{
_completed = true ;
if ( _handle . Status = = EOperationStatus . Failed )
{
_core . TrySetException ( new Exception ( _handle . LastError ) ) ;
}
else
{
_core . TrySetResult ( AsyncUnit . Default ) ;
}
}
}
private void Continuation ( HandleBase _ )
{
switch ( _handle )
{
case AssetHandle asset_handle :
asset_handle . Completed - = _continuationAction ;
break ;
case SceneHandle scene_handle :
scene_handle . Completed - = _continuationAction ;
break ;
case SubAssetsHandle sub_asset_handle :
sub_asset_handle . Completed - = _continuationAction ;
break ;
case RawFileHandle raw_file_handle :
raw_file_handle . Completed - = _continuationAction ;
break ;
case AllAssetsHandle all_assets_handle :
all_assets_handle . Completed - = _continuationAction ;
break ;
}
BaseContinuation ( ) ;
}
private bool TryReturn ( )
{
TaskTracker . RemoveTracking ( this ) ;
_core . Reset ( ) ;
_handle = default ;
_progress = default ;
return _pool . TryPush ( this ) ;
}
public UniTaskStatus GetStatus ( short token ) = > _core . GetStatus ( token ) ;
public void OnCompleted ( Action < object > continuation , object state , short token )
{
_core . OnCompleted ( continuation , state , token ) ;
}
public void GetResult ( short token ) { _core . GetResult ( token ) ; }
public UniTaskStatus UnsafeGetStatus ( ) = > _core . UnsafeGetStatus ( ) ;
public bool MoveNext ( )
{
if ( _completed )
{
TryReturn ( ) ;
return false ;
}
if ( _handle . IsValid )
{
_progress ? . Report ( _handle . Progress ) ;
}
return true ;
}
}
}
}
#endif