mirror of
https://github.com/tuyoogame/YooAsset.git
synced 2026-05-28 19:48:47 +00:00
Compare commits
8 Commits
2.3.13
...
956b3db71d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
956b3db71d | ||
|
|
fb56959c61 | ||
|
|
b9b9f4e37d | ||
|
|
c050d6d172 | ||
|
|
baf76a454b | ||
|
|
385d343262 | ||
|
|
1f5ad24d44 | ||
|
|
fefc0043cf |
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
All notable changes to this package will be documented in this file.
|
All notable changes to this package will be documented in this file.
|
||||||
|
|
||||||
## [2.3.13] - 2025-07-23
|
## [2.3.14] - 2025-07-23
|
||||||
|
|
||||||
**重要**:**所有下载相关的超时参数(timeout)已更新判定逻辑**
|
**重要**:**所有下载相关的超时参数(timeout)已更新判定逻辑**
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 275b87293edc6634f9d72387851dbbdf
|
guid: 7d2280a83472bd14bb033f506647284d
|
||||||
folderAsset: yes
|
folderAsset: yes
|
||||||
DefaultImporter:
|
DefaultImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
@@ -0,0 +1,280 @@
|
|||||||
|
#if UNITY_WEBGL && UNITY_ALIMINIGAME
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
using YooAsset;
|
||||||
|
using AlipaySdk;
|
||||||
|
|
||||||
|
public static class AlipayFileSystemCreater
|
||||||
|
{
|
||||||
|
public static FileSystemParameters CreateFileSystemParameters(string packageRoot, IRemoteServices remoteServices)
|
||||||
|
{
|
||||||
|
string fileSystemClass = $"{nameof(AlipayFileSystem)},YooAsset.MiniGame";
|
||||||
|
var fileSystemParams = new FileSystemParameters(fileSystemClass, packageRoot);
|
||||||
|
fileSystemParams.AddParameter(FileSystemParametersDefine.REMOTE_SERVICES, remoteServices);
|
||||||
|
return fileSystemParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FileSystemParameters CreateFileSystemParameters(string packageRoot, IRemoteServices remoteServices, IWebDecryptionServices decryptionServices)
|
||||||
|
{
|
||||||
|
string fileSystemClass = $"{nameof(AlipayFileSystem)},YooAsset.MiniGame";
|
||||||
|
var fileSystemParams = new FileSystemParameters(fileSystemClass, packageRoot);
|
||||||
|
fileSystemParams.AddParameter(FileSystemParametersDefine.REMOTE_SERVICES, remoteServices);
|
||||||
|
fileSystemParams.AddParameter(FileSystemParametersDefine.DECRYPTION_SERVICES, decryptionServices);
|
||||||
|
return fileSystemParams;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 支付宝小游戏文件系统
|
||||||
|
/// 参考:https://opendocs.alipay.com/mini-game/0ftleg
|
||||||
|
/// </summary>
|
||||||
|
internal class AlipayFileSystem : IFileSystem
|
||||||
|
{
|
||||||
|
private class WebRemoteServices : IRemoteServices
|
||||||
|
{
|
||||||
|
private readonly string _webPackageRoot;
|
||||||
|
protected readonly Dictionary<string, string> _mapping = new Dictionary<string, string>(10000);
|
||||||
|
|
||||||
|
public WebRemoteServices(string buildinPackRoot)
|
||||||
|
{
|
||||||
|
_webPackageRoot = buildinPackRoot;
|
||||||
|
}
|
||||||
|
string IRemoteServices.GetRemoteMainURL(string fileName)
|
||||||
|
{
|
||||||
|
return GetFileLoadURL(fileName);
|
||||||
|
}
|
||||||
|
string IRemoteServices.GetRemoteFallbackURL(string fileName)
|
||||||
|
{
|
||||||
|
return GetFileLoadURL(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetFileLoadURL(string fileName)
|
||||||
|
{
|
||||||
|
if (_mapping.TryGetValue(fileName, out string url) == false)
|
||||||
|
{
|
||||||
|
string filePath = PathUtility.Combine(_webPackageRoot, fileName);
|
||||||
|
url = DownloadSystemHelper.ConvertToWWWPath(filePath);
|
||||||
|
_mapping.Add(fileName, url);
|
||||||
|
}
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly Dictionary<string, string> _cacheFilePathMapping = new Dictionary<string, string>(10000);
|
||||||
|
private AlipayFSManager _fileSystemMgr;
|
||||||
|
private string _aliCacheRoot = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 包裹名称
|
||||||
|
/// </summary>
|
||||||
|
public string PackageName { private set; get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 文件根目录
|
||||||
|
/// </summary>
|
||||||
|
public string FileRoot
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _aliCacheRoot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 文件数量
|
||||||
|
/// </summary>
|
||||||
|
public int FileCount
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#region 自定义参数
|
||||||
|
/// <summary>
|
||||||
|
/// 自定义参数:远程服务接口
|
||||||
|
/// </summary>
|
||||||
|
public IRemoteServices RemoteServices { private set; get; } = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 自定义参数:解密方法类
|
||||||
|
/// </summary>
|
||||||
|
public IWebDecryptionServices DecryptionServices { private set; get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 自定义参数:资源清单服务类
|
||||||
|
/// </summary>
|
||||||
|
public IManifestRestoreServices ManifestServices { private set; get; }
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
public AlipayFileSystem()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public virtual FSInitializeFileSystemOperation InitializeFileSystemAsync()
|
||||||
|
{
|
||||||
|
var operation = new APFSInitializeOperation(this);
|
||||||
|
return operation;
|
||||||
|
}
|
||||||
|
public virtual FSLoadPackageManifestOperation LoadPackageManifestAsync(string packageVersion, int timeout)
|
||||||
|
{
|
||||||
|
var operation = new APFSLoadPackageManifestOperation(this, packageVersion, timeout);
|
||||||
|
return operation;
|
||||||
|
}
|
||||||
|
public virtual FSRequestPackageVersionOperation RequestPackageVersionAsync(bool appendTimeTicks, int timeout)
|
||||||
|
{
|
||||||
|
var operation = new APFSRequestPackageVersionOperation(this, appendTimeTicks, timeout);
|
||||||
|
return operation;
|
||||||
|
}
|
||||||
|
public virtual FSClearCacheFilesOperation ClearCacheFilesAsync(PackageManifest manifest, ClearCacheFilesOptions options)
|
||||||
|
{
|
||||||
|
var operation = new FSClearCacheFilesCompleteOperation();
|
||||||
|
return operation;
|
||||||
|
}
|
||||||
|
public virtual FSDownloadFileOperation DownloadFileAsync(PackageBundle bundle, DownloadFileOptions options)
|
||||||
|
{
|
||||||
|
string mainURL = RemoteServices.GetRemoteMainURL(bundle.FileName);
|
||||||
|
string fallbackURL = RemoteServices.GetRemoteFallbackURL(bundle.FileName);
|
||||||
|
options.SetURL(mainURL, fallbackURL);
|
||||||
|
var operation = new APFSDownloadFileOperation(this, bundle, options);
|
||||||
|
return operation;
|
||||||
|
}
|
||||||
|
public virtual FSLoadBundleOperation LoadBundleFile(PackageBundle bundle)
|
||||||
|
{
|
||||||
|
if (bundle.BundleType == (int)EBuildBundleType.AssetBundle)
|
||||||
|
{
|
||||||
|
var operation = new APFSLoadBundleOperation(this, bundle);
|
||||||
|
return operation;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string error = $"{nameof(AlipayFileSystem)} not support load bundle type : {bundle.BundleType}";
|
||||||
|
var operation = new FSLoadBundleCompleteOperation(error);
|
||||||
|
return operation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void SetParameter(string name, object value)
|
||||||
|
{
|
||||||
|
if (name == FileSystemParametersDefine.REMOTE_SERVICES)
|
||||||
|
{
|
||||||
|
RemoteServices = (IRemoteServices)value;
|
||||||
|
}
|
||||||
|
else if (name == FileSystemParametersDefine.DECRYPTION_SERVICES)
|
||||||
|
{
|
||||||
|
DecryptionServices = (IWebDecryptionServices)value;
|
||||||
|
}
|
||||||
|
else if (name == FileSystemParametersDefine.MANIFEST_SERVICES)
|
||||||
|
{
|
||||||
|
ManifestServices = (IManifestRestoreServices)value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
YooLogger.Warning($"Invalid parameter : {name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public virtual void OnCreate(string packageName, string rootDirectory)
|
||||||
|
{
|
||||||
|
PackageName = packageName;
|
||||||
|
_aliCacheRoot = rootDirectory;
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(_aliCacheRoot))
|
||||||
|
{
|
||||||
|
throw new System.Exception("请配置支付宝小游戏的缓存根目录!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 注意:CDN服务未启用的情况下,使用支付宝WEB服务器
|
||||||
|
if (RemoteServices == null)
|
||||||
|
{
|
||||||
|
string webRoot = PathUtility.Combine(Application.streamingAssetsPath, YooAssetSettingsData.Setting.DefaultYooFolderName, packageName);
|
||||||
|
RemoteServices = new WebRemoteServices(webRoot);
|
||||||
|
}
|
||||||
|
|
||||||
|
_fileSystemMgr = AlipaySDK.API.GetFileSystemManager();
|
||||||
|
}
|
||||||
|
public virtual void OnDestroy()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual bool Belong(PackageBundle bundle)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public virtual bool Exists(PackageBundle bundle)
|
||||||
|
{
|
||||||
|
return CheckCacheFileExist(bundle);
|
||||||
|
}
|
||||||
|
public virtual bool NeedDownload(PackageBundle bundle)
|
||||||
|
{
|
||||||
|
if (Belong(bundle) == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return Exists(bundle) == false;
|
||||||
|
}
|
||||||
|
public virtual bool NeedUnpack(PackageBundle bundle)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
public virtual bool NeedImport(PackageBundle bundle)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual string GetBundleFilePath(PackageBundle bundle)
|
||||||
|
{
|
||||||
|
return GetCacheFileLoadPath(bundle);
|
||||||
|
}
|
||||||
|
public virtual byte[] ReadBundleFileData(PackageBundle bundle)
|
||||||
|
{
|
||||||
|
if (CheckCacheFileExist(bundle))
|
||||||
|
{
|
||||||
|
string filePath = GetCacheFileLoadPath(bundle);
|
||||||
|
return _fileSystemMgr.ReadFileSync(filePath);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Array.Empty<byte>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public virtual string ReadBundleFileText(PackageBundle bundle)
|
||||||
|
{
|
||||||
|
if (CheckCacheFileExist(bundle))
|
||||||
|
{
|
||||||
|
string filePath = GetCacheFileLoadPath(bundle);
|
||||||
|
return _fileSystemMgr.ReadFileSync(filePath, "utf8");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#region 内部方法
|
||||||
|
public AlipayFSManager GetFileSystemMgr()
|
||||||
|
{
|
||||||
|
return _fileSystemMgr;
|
||||||
|
}
|
||||||
|
public bool CheckCacheFileExist(PackageBundle bundle)
|
||||||
|
{
|
||||||
|
//TODO : 效率极低
|
||||||
|
/*
|
||||||
|
string filePath = GetCacheFileLoadPath(bundle);
|
||||||
|
string result = _fileSystemMgr.AccessSync(filePath);
|
||||||
|
return result.Equals("access:ok", StringComparison.Ordinal);
|
||||||
|
*/
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
private string GetCacheFileLoadPath(PackageBundle bundle)
|
||||||
|
{
|
||||||
|
if (_cacheFilePathMapping.TryGetValue(bundle.BundleGUID, out string filePath) == false)
|
||||||
|
{
|
||||||
|
filePath = PathUtility.Combine(_aliCacheRoot, bundle.FileName);
|
||||||
|
_cacheFilePathMapping.Add(bundle.BundleGUID, filePath);
|
||||||
|
}
|
||||||
|
return filePath;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 5bee3e3860e37484aa3b861bf76d129f
|
guid: 61be9965c7f7aae468a34b3ed38116b5
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 25cb2f742bfeb1d48a4e65d3140b955d
|
guid: 44b9746ed3270394eb54d85b27a2ef04
|
||||||
folderAsset: yes
|
folderAsset: yes
|
||||||
DefaultImporter:
|
DefaultImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
#if UNITY_WEBGL && UNITY_ALIMINIGAME
|
||||||
|
using System.IO;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.SceneManagement;
|
||||||
|
using AlipaySdk;
|
||||||
|
|
||||||
|
namespace YooAsset
|
||||||
|
{
|
||||||
|
internal class APAssetBundleResult : BundleResult
|
||||||
|
{
|
||||||
|
private readonly IFileSystem _fileSystem;
|
||||||
|
private readonly PackageBundle _packageBundle;
|
||||||
|
private readonly AssetBundle _assetBundle;
|
||||||
|
|
||||||
|
public APAssetBundleResult(IFileSystem fileSystem, PackageBundle packageBundle, AssetBundle assetBundle)
|
||||||
|
{
|
||||||
|
_fileSystem = fileSystem;
|
||||||
|
_packageBundle = packageBundle;
|
||||||
|
_assetBundle = assetBundle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void UnloadBundleFile()
|
||||||
|
{
|
||||||
|
if (_assetBundle != null)
|
||||||
|
{
|
||||||
|
if (_packageBundle.Encrypted)
|
||||||
|
_assetBundle.Unload(true);
|
||||||
|
else
|
||||||
|
_assetBundle.APUnload(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public override string GetBundleFilePath()
|
||||||
|
{
|
||||||
|
return _fileSystem.GetBundleFilePath(_packageBundle);
|
||||||
|
}
|
||||||
|
public override byte[] ReadBundleFileData()
|
||||||
|
{
|
||||||
|
return _fileSystem.ReadBundleFileData(_packageBundle);
|
||||||
|
}
|
||||||
|
public override string ReadBundleFileText()
|
||||||
|
{
|
||||||
|
return _fileSystem.ReadBundleFileText(_packageBundle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override FSLoadAssetOperation LoadAssetAsync(AssetInfo assetInfo)
|
||||||
|
{
|
||||||
|
var operation = new AssetBundleLoadAssetOperation(_packageBundle, _assetBundle, assetInfo);
|
||||||
|
return operation;
|
||||||
|
}
|
||||||
|
public override FSLoadAllAssetsOperation LoadAllAssetsAsync(AssetInfo assetInfo)
|
||||||
|
{
|
||||||
|
var operation = new AssetBundleLoadAllAssetsOperation(_packageBundle, _assetBundle, assetInfo);
|
||||||
|
return operation;
|
||||||
|
}
|
||||||
|
public override FSLoadSubAssetsOperation LoadSubAssetsAsync(AssetInfo assetInfo)
|
||||||
|
{
|
||||||
|
var operation = new AssetBundleLoadSubAssetsOperation(_packageBundle, _assetBundle, assetInfo);
|
||||||
|
return operation;
|
||||||
|
}
|
||||||
|
public override FSLoadSceneOperation LoadSceneOperation(AssetInfo assetInfo, LoadSceneParameters loadParams, bool suspendLoad)
|
||||||
|
{
|
||||||
|
var operation = new AssetBundleLoadSceneOperation(assetInfo, loadParams, suspendLoad);
|
||||||
|
return operation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 01d1404ca421466419a7db7340ff5e77
|
guid: 1de437726bd89584da56aaddfdb1a07c
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 64b064347ca7a404494a996b072e2e29
|
guid: 18ae5147de9585045ab40941d945696b
|
||||||
folderAsset: yes
|
folderAsset: yes
|
||||||
DefaultImporter:
|
DefaultImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
#if UNITY_WEBGL && UNITY_ALIMINIGAME
|
||||||
|
using UnityEngine;
|
||||||
|
using YooAsset;
|
||||||
|
|
||||||
|
internal class APFSDownloadFileOperation : FSDownloadFileOperation
|
||||||
|
{
|
||||||
|
protected enum ESteps
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
CreateRequest,
|
||||||
|
CheckRequest,
|
||||||
|
TryAgain,
|
||||||
|
Done,
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly AlipayFileSystem _fileSystem;
|
||||||
|
private readonly DownloadFileOptions _options;
|
||||||
|
private UnityWebCacheRequestOperation _webCacheRequestOp;
|
||||||
|
private int _requestCount = 0;
|
||||||
|
private float _tryAgainTimer;
|
||||||
|
private int _failedTryAgain;
|
||||||
|
private ESteps _steps = ESteps.None;
|
||||||
|
|
||||||
|
internal APFSDownloadFileOperation(AlipayFileSystem fileSystem, PackageBundle bundle, DownloadFileOptions options) : base(bundle)
|
||||||
|
{
|
||||||
|
_fileSystem = fileSystem;
|
||||||
|
_options = options;
|
||||||
|
}
|
||||||
|
internal override void InternalStart()
|
||||||
|
{
|
||||||
|
_steps = ESteps.CreateRequest;
|
||||||
|
}
|
||||||
|
internal override void InternalUpdate()
|
||||||
|
{
|
||||||
|
// 创建下载器
|
||||||
|
if (_steps == ESteps.CreateRequest)
|
||||||
|
{
|
||||||
|
string url = GetRequestURL();
|
||||||
|
_webCacheRequestOp = new UnityWebCacheRequestOperation(url);
|
||||||
|
_webCacheRequestOp.StartOperation();
|
||||||
|
AddChildOperation(_webCacheRequestOp);
|
||||||
|
_steps = ESteps.CheckRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检测下载结果
|
||||||
|
if (_steps == ESteps.CheckRequest)
|
||||||
|
{
|
||||||
|
_webCacheRequestOp.UpdateOperation();
|
||||||
|
Progress = _webCacheRequestOp.Progress;
|
||||||
|
DownloadProgress = _webCacheRequestOp.DownloadProgress;
|
||||||
|
DownloadedBytes = _webCacheRequestOp.DownloadedBytes;
|
||||||
|
if (_webCacheRequestOp.IsDone == false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_webCacheRequestOp.Status == EOperationStatus.Succeed)
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
Status = EOperationStatus.Succeed;
|
||||||
|
|
||||||
|
//TODO 需要验证插件请求器的下载进度
|
||||||
|
DownloadProgress = 1f;
|
||||||
|
DownloadedBytes = Bundle.FileSize;
|
||||||
|
Progress = 1f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_failedTryAgain > 0)
|
||||||
|
{
|
||||||
|
_steps = ESteps.TryAgain;
|
||||||
|
YooLogger.Warning($"Failed download : {_webCacheRequestOp.URL} Try again !");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
Status = EOperationStatus.Failed;
|
||||||
|
Error = _webCacheRequestOp.Error;
|
||||||
|
YooLogger.Error(Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重新尝试下载
|
||||||
|
if (_steps == ESteps.TryAgain)
|
||||||
|
{
|
||||||
|
_tryAgainTimer += Time.unscaledDeltaTime;
|
||||||
|
if (_tryAgainTimer > 1f)
|
||||||
|
{
|
||||||
|
_tryAgainTimer = 0f;
|
||||||
|
_failedTryAgain--;
|
||||||
|
Progress = 0f;
|
||||||
|
DownloadProgress = 0f;
|
||||||
|
DownloadedBytes = 0;
|
||||||
|
_steps = ESteps.CreateRequest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取网络请求地址
|
||||||
|
/// </summary>
|
||||||
|
private string GetRequestURL()
|
||||||
|
{
|
||||||
|
// 轮流返回请求地址
|
||||||
|
_requestCount++;
|
||||||
|
if (_requestCount % 2 == 0)
|
||||||
|
return _options.FallbackURL;
|
||||||
|
else
|
||||||
|
return _options.MainURL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 40ef2e46f900131419e869398a8d3c9d
|
guid: bc47317a416e9f542b7ec6b77485a8b7
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#if UNITY_WEBGL && UNITY_ALIMINIGAME
|
||||||
|
using YooAsset;
|
||||||
|
|
||||||
|
internal partial class APFSInitializeOperation : FSInitializeFileSystemOperation
|
||||||
|
{
|
||||||
|
private readonly AlipayFileSystem _fileSystem;
|
||||||
|
|
||||||
|
public APFSInitializeOperation(AlipayFileSystem fileSystem)
|
||||||
|
{
|
||||||
|
_fileSystem = fileSystem;
|
||||||
|
}
|
||||||
|
internal override void InternalStart()
|
||||||
|
{
|
||||||
|
Status = EOperationStatus.Succeed;
|
||||||
|
}
|
||||||
|
internal override void InternalUpdate()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 52e2d973a2156674e8c1c9433ed031f7
|
guid: 71a99a94d7563fe4a9d56ea0e15aa8d1
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
#if UNITY_WEBGL && UNITY_ALIMINIGAME
|
||||||
|
using YooAsset;
|
||||||
|
|
||||||
|
internal class APFSLoadBundleOperation : FSLoadBundleOperation
|
||||||
|
{
|
||||||
|
private enum ESteps
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
LoadAssetBundle,
|
||||||
|
Done,
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly AlipayFileSystem _fileSystem;
|
||||||
|
private readonly PackageBundle _bundle;
|
||||||
|
private LoadWebAssetBundleOperation _loadWebAssetBundleOp;
|
||||||
|
private ESteps _steps = ESteps.None;
|
||||||
|
|
||||||
|
internal APFSLoadBundleOperation(AlipayFileSystem fileSystem, PackageBundle bundle)
|
||||||
|
{
|
||||||
|
_fileSystem = fileSystem;
|
||||||
|
_bundle = bundle;
|
||||||
|
}
|
||||||
|
internal override void InternalStart()
|
||||||
|
{
|
||||||
|
_steps = ESteps.LoadAssetBundle;
|
||||||
|
}
|
||||||
|
internal override void InternalUpdate()
|
||||||
|
{
|
||||||
|
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_steps == ESteps.LoadAssetBundle)
|
||||||
|
{
|
||||||
|
if (_loadWebAssetBundleOp == null)
|
||||||
|
{
|
||||||
|
string mainURL = _fileSystem.RemoteServices.GetRemoteMainURL(_bundle.FileName);
|
||||||
|
string fallbackURL = _fileSystem.RemoteServices.GetRemoteFallbackURL(_bundle.FileName);
|
||||||
|
DownloadFileOptions options = new DownloadFileOptions(int.MaxValue);
|
||||||
|
options.SetURL(mainURL, fallbackURL);
|
||||||
|
|
||||||
|
if (_bundle.Encrypted)
|
||||||
|
{
|
||||||
|
_loadWebAssetBundleOp = new LoadWebEncryptAssetBundleOperation(_bundle, options, _fileSystem.DecryptionServices);
|
||||||
|
_loadWebAssetBundleOp.StartOperation();
|
||||||
|
AddChildOperation(_loadWebAssetBundleOp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_loadWebAssetBundleOp = new LoadAlipayAssetBundleOperation(_bundle, options);
|
||||||
|
_loadWebAssetBundleOp.StartOperation();
|
||||||
|
AddChildOperation(_loadWebAssetBundleOp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_loadWebAssetBundleOp.UpdateOperation();
|
||||||
|
Progress = _loadWebAssetBundleOp.Progress;
|
||||||
|
DownloadProgress = _loadWebAssetBundleOp.DownloadProgress;
|
||||||
|
DownloadedBytes = _loadWebAssetBundleOp.DownloadedBytes;
|
||||||
|
if (_loadWebAssetBundleOp.IsDone == false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_loadWebAssetBundleOp.Status == EOperationStatus.Succeed)
|
||||||
|
{
|
||||||
|
var assetBundle = _loadWebAssetBundleOp.Result;
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
Result = new APAssetBundleResult(_fileSystem, _bundle, assetBundle);
|
||||||
|
Status = EOperationStatus.Succeed;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
Status = EOperationStatus.Failed;
|
||||||
|
Error = _loadWebAssetBundleOp.Error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal override void InternalWaitForAsyncComplete()
|
||||||
|
{
|
||||||
|
if (_steps != ESteps.Done)
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
Status = EOperationStatus.Failed;
|
||||||
|
Error = "WebGL platform not support sync load method !";
|
||||||
|
UnityEngine.Debug.LogError(Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f71fc4fc468d41441b00be64938b2fe9
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
#if UNITY_WEBGL && UNITY_ALIMINIGAME
|
||||||
|
using YooAsset;
|
||||||
|
|
||||||
|
internal class APFSLoadPackageManifestOperation : FSLoadPackageManifestOperation
|
||||||
|
{
|
||||||
|
private enum ESteps
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
RequestPackageHash,
|
||||||
|
LoadPackageManifest,
|
||||||
|
Done,
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly AlipayFileSystem _fileSystem;
|
||||||
|
private readonly string _packageVersion;
|
||||||
|
private readonly int _timeout;
|
||||||
|
private RequestAlipayPackageHashOperation _requestPackageHashOp;
|
||||||
|
private LoadAlipayPackageManifestOperation _loadPackageManifestOp;
|
||||||
|
private ESteps _steps = ESteps.None;
|
||||||
|
|
||||||
|
|
||||||
|
public APFSLoadPackageManifestOperation(AlipayFileSystem fileSystem, string packageVersion, int timeout)
|
||||||
|
{
|
||||||
|
_fileSystem = fileSystem;
|
||||||
|
_packageVersion = packageVersion;
|
||||||
|
_timeout = timeout;
|
||||||
|
}
|
||||||
|
internal override void InternalStart()
|
||||||
|
{
|
||||||
|
_steps = ESteps.RequestPackageHash;
|
||||||
|
}
|
||||||
|
internal override void InternalUpdate()
|
||||||
|
{
|
||||||
|
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_steps == ESteps.RequestPackageHash)
|
||||||
|
{
|
||||||
|
if (_requestPackageHashOp == null)
|
||||||
|
{
|
||||||
|
_requestPackageHashOp = new RequestAlipayPackageHashOperation(_fileSystem, _packageVersion, _timeout);
|
||||||
|
_requestPackageHashOp.StartOperation();
|
||||||
|
AddChildOperation(_requestPackageHashOp);
|
||||||
|
}
|
||||||
|
|
||||||
|
_requestPackageHashOp.UpdateOperation();
|
||||||
|
if (_requestPackageHashOp.IsDone == false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_requestPackageHashOp.Status == EOperationStatus.Succeed)
|
||||||
|
{
|
||||||
|
_steps = ESteps.LoadPackageManifest;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
Status = EOperationStatus.Failed;
|
||||||
|
Error = _requestPackageHashOp.Error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_steps == ESteps.LoadPackageManifest)
|
||||||
|
{
|
||||||
|
if (_loadPackageManifestOp == null)
|
||||||
|
{
|
||||||
|
string packageHash = _requestPackageHashOp.PackageHash;
|
||||||
|
_loadPackageManifestOp = new LoadAlipayPackageManifestOperation(_fileSystem, _packageVersion, packageHash, _timeout);
|
||||||
|
_loadPackageManifestOp.StartOperation();
|
||||||
|
AddChildOperation(_loadPackageManifestOp);
|
||||||
|
}
|
||||||
|
|
||||||
|
_loadPackageManifestOp.UpdateOperation();
|
||||||
|
Progress = _loadPackageManifestOp.Progress;
|
||||||
|
if (_loadPackageManifestOp.IsDone == false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_loadPackageManifestOp.Status == EOperationStatus.Succeed)
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
Manifest = _loadPackageManifestOp.Manifest;
|
||||||
|
Status = EOperationStatus.Succeed;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
Status = EOperationStatus.Failed;
|
||||||
|
Error = _loadPackageManifestOp.Error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 335885fb4e1977a4ca5c26263eda03d7
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
#if UNITY_WEBGL && UNITY_ALIMINIGAME
|
||||||
|
using YooAsset;
|
||||||
|
|
||||||
|
internal class APFSRequestPackageVersionOperation : FSRequestPackageVersionOperation
|
||||||
|
{
|
||||||
|
private enum ESteps
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
RequestPackageVersion,
|
||||||
|
Done,
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly AlipayFileSystem _fileSystem;
|
||||||
|
private readonly bool _appendTimeTicks;
|
||||||
|
private readonly int _timeout;
|
||||||
|
private RequestAlipayPackageVersionOperation _requestWebPackageVersionOp;
|
||||||
|
private ESteps _steps = ESteps.None;
|
||||||
|
|
||||||
|
|
||||||
|
internal APFSRequestPackageVersionOperation(AlipayFileSystem fileSystem, bool appendTimeTicks, int timeout)
|
||||||
|
{
|
||||||
|
_fileSystem = fileSystem;
|
||||||
|
_appendTimeTicks = appendTimeTicks;
|
||||||
|
_timeout = timeout;
|
||||||
|
}
|
||||||
|
internal override void InternalStart()
|
||||||
|
{
|
||||||
|
_steps = ESteps.RequestPackageVersion;
|
||||||
|
}
|
||||||
|
internal override void InternalUpdate()
|
||||||
|
{
|
||||||
|
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_steps == ESteps.RequestPackageVersion)
|
||||||
|
{
|
||||||
|
if (_requestWebPackageVersionOp == null)
|
||||||
|
{
|
||||||
|
_requestWebPackageVersionOp = new RequestAlipayPackageVersionOperation(_fileSystem, _appendTimeTicks, _timeout);
|
||||||
|
_requestWebPackageVersionOp.StartOperation();
|
||||||
|
AddChildOperation(_requestWebPackageVersionOp);
|
||||||
|
}
|
||||||
|
|
||||||
|
_requestWebPackageVersionOp.UpdateOperation();
|
||||||
|
Progress = _requestWebPackageVersionOp.Progress;
|
||||||
|
if (_requestWebPackageVersionOp.IsDone == false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_requestWebPackageVersionOp.Status == EOperationStatus.Succeed)
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
PackageVersion = _requestWebPackageVersionOp.PackageVersion;
|
||||||
|
Status = EOperationStatus.Succeed;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
Status = EOperationStatus.Failed;
|
||||||
|
Error = _requestWebPackageVersionOp.Error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: a879fd6a506b37345b4b9ea6c5de20bc
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: a5b9231662e24c942b544bd85d4b39cb
|
guid: b94d7bcfa19151046a1f0ed8e089a474
|
||||||
folderAsset: yes
|
folderAsset: yes
|
||||||
DefaultImporter:
|
DefaultImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
#if UNITY_WEBGL && UNITY_ALIMINIGAME
|
||||||
|
using UnityEngine;
|
||||||
|
using AlipaySdk;
|
||||||
|
|
||||||
|
namespace YooAsset
|
||||||
|
{
|
||||||
|
internal class LoadAlipayAssetBundleOperation : LoadWebAssetBundleOperation
|
||||||
|
{
|
||||||
|
protected enum ESteps
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
CreateRequest,
|
||||||
|
CheckRequest,
|
||||||
|
TryAgain,
|
||||||
|
Done,
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly PackageBundle _bundle;
|
||||||
|
private readonly DownloadFileOptions _options;
|
||||||
|
private UnityAlipayAssetBundleRequestOperation _unityAssetBundleRequestOp;
|
||||||
|
|
||||||
|
private int _requestCount = 0;
|
||||||
|
private float _tryAgainTimer;
|
||||||
|
private int _failedTryAgain;
|
||||||
|
private ESteps _steps = ESteps.None;
|
||||||
|
|
||||||
|
|
||||||
|
internal LoadAlipayAssetBundleOperation(PackageBundle bundle, DownloadFileOptions options)
|
||||||
|
{
|
||||||
|
_bundle = bundle;
|
||||||
|
_options = options;
|
||||||
|
}
|
||||||
|
internal override void InternalStart()
|
||||||
|
{
|
||||||
|
_steps = ESteps.CreateRequest;
|
||||||
|
}
|
||||||
|
internal override void InternalUpdate()
|
||||||
|
{
|
||||||
|
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// 创建下载器
|
||||||
|
if (_steps == ESteps.CreateRequest)
|
||||||
|
{
|
||||||
|
string url = GetRequestURL();
|
||||||
|
_unityAssetBundleRequestOp = new UnityAlipayAssetBundleRequestOperation(_bundle, url);
|
||||||
|
_unityAssetBundleRequestOp.StartOperation();
|
||||||
|
AddChildOperation(_unityAssetBundleRequestOp);
|
||||||
|
_steps = ESteps.CheckRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检测下载结果
|
||||||
|
if (_steps == ESteps.CheckRequest)
|
||||||
|
{
|
||||||
|
_unityAssetBundleRequestOp.UpdateOperation();
|
||||||
|
Progress = _unityAssetBundleRequestOp.Progress;
|
||||||
|
DownloadProgress = _unityAssetBundleRequestOp.DownloadProgress;
|
||||||
|
DownloadedBytes = _unityAssetBundleRequestOp.DownloadedBytes;
|
||||||
|
if (_unityAssetBundleRequestOp.IsDone == false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_unityAssetBundleRequestOp.Status == EOperationStatus.Succeed)
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
Status = EOperationStatus.Succeed;
|
||||||
|
Result = _unityAssetBundleRequestOp.Result;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_failedTryAgain > 0)
|
||||||
|
{
|
||||||
|
_steps = ESteps.TryAgain;
|
||||||
|
YooLogger.Warning($"Failed download : {_unityAssetBundleRequestOp.URL} Try again !");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
Status = EOperationStatus.Failed;
|
||||||
|
Error = _unityAssetBundleRequestOp.Error;
|
||||||
|
YooLogger.Error(Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重新尝试下载
|
||||||
|
if (_steps == ESteps.TryAgain)
|
||||||
|
{
|
||||||
|
_tryAgainTimer += Time.unscaledDeltaTime;
|
||||||
|
if (_tryAgainTimer > 1f)
|
||||||
|
{
|
||||||
|
_tryAgainTimer = 0f;
|
||||||
|
_failedTryAgain--;
|
||||||
|
Progress = 0f;
|
||||||
|
DownloadProgress = 0f;
|
||||||
|
DownloadedBytes = 0;
|
||||||
|
_steps = ESteps.CreateRequest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取网络请求地址
|
||||||
|
/// </summary>
|
||||||
|
private string GetRequestURL()
|
||||||
|
{
|
||||||
|
// 轮流返回请求地址
|
||||||
|
_requestCount++;
|
||||||
|
if (_requestCount % 2 == 0)
|
||||||
|
return _options.FallbackURL;
|
||||||
|
else
|
||||||
|
return _options.MainURL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 62249d32580e2ef48a33afb58515312a
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
#if UNITY_WEBGL && UNITY_ALIMINIGAME
|
||||||
|
using YooAsset;
|
||||||
|
|
||||||
|
internal class LoadAlipayPackageManifestOperation : AsyncOperationBase
|
||||||
|
{
|
||||||
|
private enum ESteps
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
RequestFileData,
|
||||||
|
VerifyFileData,
|
||||||
|
LoadManifest,
|
||||||
|
Done,
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly AlipayFileSystem _fileSystem;
|
||||||
|
private readonly string _packageVersion;
|
||||||
|
private readonly string _packageHash;
|
||||||
|
private readonly int _timeout;
|
||||||
|
private UnityWebDataRequestOperation _webDataRequestOp;
|
||||||
|
private DeserializeManifestOperation _deserializer;
|
||||||
|
private int _requestCount = 0;
|
||||||
|
private ESteps _steps = ESteps.None;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 包裹清单
|
||||||
|
/// </summary>
|
||||||
|
public PackageManifest Manifest { private set; get; }
|
||||||
|
|
||||||
|
|
||||||
|
internal LoadAlipayPackageManifestOperation(AlipayFileSystem fileSystem, string packageVersion, string packageHash, int timeout)
|
||||||
|
{
|
||||||
|
_fileSystem = fileSystem;
|
||||||
|
_packageVersion = packageVersion;
|
||||||
|
_packageHash = packageHash;
|
||||||
|
_timeout = timeout;
|
||||||
|
}
|
||||||
|
internal override void InternalStart()
|
||||||
|
{
|
||||||
|
_requestCount = WebRequestCounter.GetRequestFailedCount(_fileSystem.PackageName, nameof(LoadAlipayPackageManifestOperation));
|
||||||
|
_steps = ESteps.RequestFileData;
|
||||||
|
}
|
||||||
|
internal override void InternalUpdate()
|
||||||
|
{
|
||||||
|
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_steps == ESteps.RequestFileData)
|
||||||
|
{
|
||||||
|
if (_webDataRequestOp == null)
|
||||||
|
{
|
||||||
|
string fileName = YooAssetSettingsData.GetManifestBinaryFileName(_fileSystem.PackageName, _packageVersion);
|
||||||
|
string url = GetRequestURL(fileName);
|
||||||
|
_webDataRequestOp = new UnityWebDataRequestOperation(url, _timeout);
|
||||||
|
_webDataRequestOp.StartOperation();
|
||||||
|
AddChildOperation(_webDataRequestOp);
|
||||||
|
}
|
||||||
|
|
||||||
|
_webDataRequestOp.UpdateOperation();
|
||||||
|
Progress = _webDataRequestOp.Progress;
|
||||||
|
if (_webDataRequestOp.IsDone == false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_webDataRequestOp.Status == EOperationStatus.Succeed)
|
||||||
|
{
|
||||||
|
_steps = ESteps.VerifyFileData;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
Status = EOperationStatus.Failed;
|
||||||
|
Error = _webDataRequestOp.Error;
|
||||||
|
WebRequestCounter.RecordRequestFailed(_fileSystem.PackageName, nameof(LoadAlipayPackageManifestOperation));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_steps == ESteps.VerifyFileData)
|
||||||
|
{
|
||||||
|
string fileHash = HashUtility.BytesCRC32(_webDataRequestOp.Result);
|
||||||
|
if (fileHash == _packageHash)
|
||||||
|
{
|
||||||
|
_steps = ESteps.LoadManifest;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
Status = EOperationStatus.Failed;
|
||||||
|
Error = "Failed to verify package manifest file!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_steps == ESteps.LoadManifest)
|
||||||
|
{
|
||||||
|
if (_deserializer == null)
|
||||||
|
{
|
||||||
|
_deserializer = new DeserializeManifestOperation(_fileSystem.ManifestServices, _webDataRequestOp.Result);
|
||||||
|
_deserializer.StartOperation();
|
||||||
|
AddChildOperation(_deserializer);
|
||||||
|
}
|
||||||
|
|
||||||
|
_deserializer.UpdateOperation();
|
||||||
|
Progress = _deserializer.Progress;
|
||||||
|
if (_deserializer.IsDone == false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_deserializer.Status == EOperationStatus.Succeed)
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
Manifest = _deserializer.Manifest;
|
||||||
|
Status = EOperationStatus.Succeed;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
Status = EOperationStatus.Failed;
|
||||||
|
Error = _deserializer.Error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetRequestURL(string fileName)
|
||||||
|
{
|
||||||
|
// 轮流返回请求地址
|
||||||
|
if (_requestCount % 2 == 0)
|
||||||
|
return _fileSystem.RemoteServices.GetRemoteMainURL(fileName);
|
||||||
|
else
|
||||||
|
return _fileSystem.RemoteServices.GetRemoteFallbackURL(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c802e6ad51754e144bb4e08942da9592
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
#if UNITY_WEBGL && UNITY_ALIMINIGAME
|
||||||
|
using YooAsset;
|
||||||
|
|
||||||
|
internal class RequestAlipayPackageHashOperation : AsyncOperationBase
|
||||||
|
{
|
||||||
|
private enum ESteps
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
RequestPackageHash,
|
||||||
|
Done,
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly AlipayFileSystem _fileSystem;
|
||||||
|
private readonly string _packageVersion;
|
||||||
|
private readonly int _timeout;
|
||||||
|
private UnityWebTextRequestOperation _webTextRequestOp;
|
||||||
|
private int _requestCount = 0;
|
||||||
|
private ESteps _steps = ESteps.None;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 包裹哈希值
|
||||||
|
/// </summary>
|
||||||
|
public string PackageHash { private set; get; }
|
||||||
|
|
||||||
|
|
||||||
|
public RequestAlipayPackageHashOperation(AlipayFileSystem fileSystem, string packageVersion, int timeout)
|
||||||
|
{
|
||||||
|
_fileSystem = fileSystem;
|
||||||
|
_packageVersion = packageVersion;
|
||||||
|
_timeout = timeout;
|
||||||
|
}
|
||||||
|
internal override void InternalStart()
|
||||||
|
{
|
||||||
|
_requestCount = WebRequestCounter.GetRequestFailedCount(_fileSystem.PackageName, nameof(RequestAlipayPackageHashOperation));
|
||||||
|
_steps = ESteps.RequestPackageHash;
|
||||||
|
}
|
||||||
|
internal override void InternalUpdate()
|
||||||
|
{
|
||||||
|
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_steps == ESteps.RequestPackageHash)
|
||||||
|
{
|
||||||
|
if (_webTextRequestOp == null)
|
||||||
|
{
|
||||||
|
string fileName = YooAssetSettingsData.GetPackageHashFileName(_fileSystem.PackageName, _packageVersion);
|
||||||
|
string url = GetRequestURL(fileName);
|
||||||
|
_webTextRequestOp = new UnityWebTextRequestOperation(url, _timeout);
|
||||||
|
_webTextRequestOp.StartOperation();
|
||||||
|
AddChildOperation(_webTextRequestOp);
|
||||||
|
}
|
||||||
|
|
||||||
|
_webTextRequestOp.UpdateOperation();
|
||||||
|
Progress = _webTextRequestOp.Progress;
|
||||||
|
if (_webTextRequestOp.IsDone == false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_webTextRequestOp.Status == EOperationStatus.Succeed)
|
||||||
|
{
|
||||||
|
PackageHash = _webTextRequestOp.Result;
|
||||||
|
if (string.IsNullOrEmpty(PackageHash))
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
Status = EOperationStatus.Failed;
|
||||||
|
Error = $"Web package hash file content is empty !";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
Status = EOperationStatus.Succeed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
Status = EOperationStatus.Failed;
|
||||||
|
Error = _webTextRequestOp.Error;
|
||||||
|
WebRequestCounter.RecordRequestFailed(_fileSystem.PackageName, nameof(RequestAlipayPackageHashOperation));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetRequestURL(string fileName)
|
||||||
|
{
|
||||||
|
// 轮流返回请求地址
|
||||||
|
if (_requestCount % 2 == 0)
|
||||||
|
return _fileSystem.RemoteServices.GetRemoteMainURL(fileName);
|
||||||
|
else
|
||||||
|
return _fileSystem.RemoteServices.GetRemoteFallbackURL(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 3b4f8cf6fe34a7e419f8e3a0063f591b
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
#if UNITY_WEBGL && UNITY_ALIMINIGAME
|
||||||
|
using YooAsset;
|
||||||
|
|
||||||
|
internal class RequestAlipayPackageVersionOperation : AsyncOperationBase
|
||||||
|
{
|
||||||
|
private enum ESteps
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
RequestPackageVersion,
|
||||||
|
Done,
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly AlipayFileSystem _fileSystem;
|
||||||
|
private readonly bool _appendTimeTicks;
|
||||||
|
private readonly int _timeout;
|
||||||
|
private UnityWebTextRequestOperation _webTextRequestOp;
|
||||||
|
private int _requestCount = 0;
|
||||||
|
private ESteps _steps = ESteps.None;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 包裹版本
|
||||||
|
/// </summary>
|
||||||
|
public string PackageVersion { private set; get; }
|
||||||
|
|
||||||
|
|
||||||
|
public RequestAlipayPackageVersionOperation(AlipayFileSystem fileSystem, bool appendTimeTicks, int timeout)
|
||||||
|
{
|
||||||
|
_fileSystem = fileSystem;
|
||||||
|
_appendTimeTicks = appendTimeTicks;
|
||||||
|
_timeout = timeout;
|
||||||
|
}
|
||||||
|
internal override void InternalStart()
|
||||||
|
{
|
||||||
|
_requestCount = WebRequestCounter.GetRequestFailedCount(_fileSystem.PackageName, nameof(RequestAlipayPackageVersionOperation));
|
||||||
|
_steps = ESteps.RequestPackageVersion;
|
||||||
|
}
|
||||||
|
internal override void InternalUpdate()
|
||||||
|
{
|
||||||
|
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_steps == ESteps.RequestPackageVersion)
|
||||||
|
{
|
||||||
|
if (_webTextRequestOp == null)
|
||||||
|
{
|
||||||
|
string fileName = YooAssetSettingsData.GetPackageVersionFileName(_fileSystem.PackageName);
|
||||||
|
string url = GetRequestURL(fileName);
|
||||||
|
_webTextRequestOp = new UnityWebTextRequestOperation(url, _timeout);
|
||||||
|
_webTextRequestOp.StartOperation();
|
||||||
|
AddChildOperation(_webTextRequestOp);
|
||||||
|
}
|
||||||
|
|
||||||
|
_webTextRequestOp.UpdateOperation();
|
||||||
|
Progress = _webTextRequestOp.Progress;
|
||||||
|
if (_webTextRequestOp.IsDone == false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_webTextRequestOp.Status == EOperationStatus.Succeed)
|
||||||
|
{
|
||||||
|
PackageVersion = _webTextRequestOp.Result;
|
||||||
|
if (string.IsNullOrEmpty(PackageVersion))
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
Status = EOperationStatus.Failed;
|
||||||
|
Error = $"Web package version file content is empty !";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
Status = EOperationStatus.Succeed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
Status = EOperationStatus.Failed;
|
||||||
|
Error = _webTextRequestOp.Error;
|
||||||
|
WebRequestCounter.RecordRequestFailed(_fileSystem.PackageName, nameof(RequestAlipayPackageVersionOperation));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetRequestURL(string fileName)
|
||||||
|
{
|
||||||
|
string url;
|
||||||
|
|
||||||
|
// 轮流返回请求地址
|
||||||
|
if (_requestCount % 2 == 0)
|
||||||
|
url = _fileSystem.RemoteServices.GetRemoteMainURL(fileName);
|
||||||
|
else
|
||||||
|
url = _fileSystem.RemoteServices.GetRemoteFallbackURL(fileName);
|
||||||
|
|
||||||
|
// 在URL末尾添加时间戳
|
||||||
|
if (_appendTimeTicks)
|
||||||
|
return $"{url}?{System.DateTime.UtcNow.Ticks}";
|
||||||
|
else
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 0ef3d88ce51a6fa47be1b157316a740c
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
#if UNITY_WEBGL && UNITY_ALIMINIGAME
|
||||||
|
using UnityEngine.Networking;
|
||||||
|
using UnityEngine;
|
||||||
|
using AlipaySdk;
|
||||||
|
|
||||||
|
namespace YooAsset
|
||||||
|
{
|
||||||
|
internal class UnityAlipayAssetBundleRequestOperation : UnityWebRequestOperation
|
||||||
|
{
|
||||||
|
protected enum ESteps
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
CreateRequest,
|
||||||
|
Download,
|
||||||
|
Done,
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly PackageBundle _packageBundle;
|
||||||
|
private UnityWebRequestAsyncOperation _requestOperation;
|
||||||
|
private ESteps _steps = ESteps.None;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 请求结果
|
||||||
|
/// </summary>
|
||||||
|
public AssetBundle Result { private set; get; }
|
||||||
|
|
||||||
|
internal UnityAlipayAssetBundleRequestOperation(PackageBundle bundle, string url) : base(url)
|
||||||
|
{
|
||||||
|
_packageBundle = bundle;
|
||||||
|
}
|
||||||
|
internal override void InternalStart()
|
||||||
|
{
|
||||||
|
_steps = ESteps.CreateRequest;
|
||||||
|
}
|
||||||
|
internal override void InternalUpdate()
|
||||||
|
{
|
||||||
|
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_steps == ESteps.CreateRequest)
|
||||||
|
{
|
||||||
|
CreateWebRequest();
|
||||||
|
_steps = ESteps.Download;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_steps == ESteps.Download)
|
||||||
|
{
|
||||||
|
DownloadProgress = _webRequest.downloadProgress;
|
||||||
|
DownloadedBytes = (long)_webRequest.downloadedBytes;
|
||||||
|
Progress = _requestOperation.progress;
|
||||||
|
if (_requestOperation.isDone == false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (CheckRequestResult())
|
||||||
|
{
|
||||||
|
var downloadHanlder = (DownloadHandlerAPAssetBundle)_webRequest.downloadHandler;
|
||||||
|
AssetBundle assetBundle = downloadHanlder.assetBundle;
|
||||||
|
if (assetBundle == null)
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
Status = EOperationStatus.Failed;
|
||||||
|
Error = $"URL : {_requestURL} Download handler asset bundle object is null !";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
Result = assetBundle;
|
||||||
|
Status = EOperationStatus.Succeed;
|
||||||
|
|
||||||
|
//TODO 需要验证插件请求器的下载进度
|
||||||
|
DownloadProgress = 1f;
|
||||||
|
DownloadedBytes = _packageBundle.FileSize;
|
||||||
|
Progress = 1f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
Status = EOperationStatus.Failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 注意:最终释放请求器
|
||||||
|
DisposeRequest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateWebRequest()
|
||||||
|
{
|
||||||
|
_webRequest = APAssetBundle.GetAssetBundle(_requestURL);
|
||||||
|
_webRequest.disposeDownloadHandlerOnDispose = true;
|
||||||
|
_requestOperation = _webRequest.SendWebRequest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: a2e7a4e37ac067f4ba0a43ebea0aa3f6
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -48,7 +48,7 @@ internal class TTFSDownloadFileOperation : FSDownloadFileOperation
|
|||||||
_webCacheRequestOp.UpdateOperation();
|
_webCacheRequestOp.UpdateOperation();
|
||||||
Progress = _webCacheRequestOp.Progress;
|
Progress = _webCacheRequestOp.Progress;
|
||||||
DownloadProgress = _webCacheRequestOp.DownloadProgress;
|
DownloadProgress = _webCacheRequestOp.DownloadProgress;
|
||||||
DownloadedBytes = (long)_webCacheRequestOp.DownloadedBytes;
|
DownloadedBytes = _webCacheRequestOp.DownloadedBytes;
|
||||||
if (_webCacheRequestOp.IsDone == false)
|
if (_webCacheRequestOp.IsDone == false)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -57,7 +57,7 @@ internal class TTFSDownloadFileOperation : FSDownloadFileOperation
|
|||||||
_steps = ESteps.Done;
|
_steps = ESteps.Done;
|
||||||
Status = EOperationStatus.Succeed;
|
Status = EOperationStatus.Succeed;
|
||||||
|
|
||||||
//TODO 需要验证抖音插件请求器的下载进度
|
//TODO 需要验证插件请求器的下载进度
|
||||||
DownloadProgress = 1f;
|
DownloadProgress = 1f;
|
||||||
DownloadedBytes = Bundle.FileSize;
|
DownloadedBytes = Bundle.FileSize;
|
||||||
Progress = 1f;
|
Progress = 1f;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#if UNITY_WEBGL && DOUYINMINIGAME
|
#if UNITY_WEBGL && DOUYINMINIGAME
|
||||||
using UnityEngine;
|
|
||||||
using YooAsset;
|
using YooAsset;
|
||||||
|
|
||||||
internal class TTFSLoadBundleOperation : FSLoadBundleOperation
|
internal class TTFSLoadBundleOperation : FSLoadBundleOperation
|
||||||
@@ -7,7 +6,7 @@ internal class TTFSLoadBundleOperation : FSLoadBundleOperation
|
|||||||
private enum ESteps
|
private enum ESteps
|
||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
DownloadAssetBundle,
|
LoadAssetBundle,
|
||||||
Done,
|
Done,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,14 +22,14 @@ internal class TTFSLoadBundleOperation : FSLoadBundleOperation
|
|||||||
}
|
}
|
||||||
internal override void InternalStart()
|
internal override void InternalStart()
|
||||||
{
|
{
|
||||||
_steps = ESteps.DownloadAssetBundle;
|
_steps = ESteps.LoadAssetBundle;
|
||||||
}
|
}
|
||||||
internal override void InternalUpdate()
|
internal override void InternalUpdate()
|
||||||
{
|
{
|
||||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_steps == ESteps.DownloadAssetBundle)
|
if (_steps == ESteps.LoadAssetBundle)
|
||||||
{
|
{
|
||||||
if (_loadWebAssetBundleOp == null)
|
if (_loadWebAssetBundleOp == null)
|
||||||
{
|
{
|
||||||
@@ -56,7 +55,7 @@ internal class TTFSLoadBundleOperation : FSLoadBundleOperation
|
|||||||
_loadWebAssetBundleOp.UpdateOperation();
|
_loadWebAssetBundleOp.UpdateOperation();
|
||||||
Progress = _loadWebAssetBundleOp.Progress;
|
Progress = _loadWebAssetBundleOp.Progress;
|
||||||
DownloadProgress = _loadWebAssetBundleOp.DownloadProgress;
|
DownloadProgress = _loadWebAssetBundleOp.DownloadProgress;
|
||||||
DownloadedBytes = (long)_loadWebAssetBundleOp.DownloadedBytes;
|
DownloadedBytes = _loadWebAssetBundleOp.DownloadedBytes;
|
||||||
if (_loadWebAssetBundleOp.IsDone == false)
|
if (_loadWebAssetBundleOp.IsDone == false)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ namespace YooAsset
|
|||||||
|
|
||||||
private readonly PackageBundle _bundle;
|
private readonly PackageBundle _bundle;
|
||||||
private readonly DownloadFileOptions _options;
|
private readonly DownloadFileOptions _options;
|
||||||
private UnityTiktokAssetBundleRequestOperation _unityTiktokAssetBundleRequestOp;
|
private UnityTiktokAssetBundleRequestOperation _unityAssetBundleRequestOp;
|
||||||
|
|
||||||
private int _requestCount = 0;
|
private int _requestCount = 0;
|
||||||
private float _tryAgainTimer;
|
private float _tryAgainTimer;
|
||||||
@@ -42,40 +42,40 @@ namespace YooAsset
|
|||||||
if (_steps == ESteps.CreateRequest)
|
if (_steps == ESteps.CreateRequest)
|
||||||
{
|
{
|
||||||
string url = GetRequestURL();
|
string url = GetRequestURL();
|
||||||
_unityTiktokAssetBundleRequestOp = new UnityTiktokAssetBundleRequestOperation(_bundle, url);
|
_unityAssetBundleRequestOp = new UnityTiktokAssetBundleRequestOperation(_bundle, url);
|
||||||
_unityTiktokAssetBundleRequestOp.StartOperation();
|
_unityAssetBundleRequestOp.StartOperation();
|
||||||
AddChildOperation(_unityTiktokAssetBundleRequestOp);
|
AddChildOperation(_unityAssetBundleRequestOp);
|
||||||
_steps = ESteps.CheckRequest;
|
_steps = ESteps.CheckRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检测下载结果
|
// 检测下载结果
|
||||||
if (_steps == ESteps.CheckRequest)
|
if (_steps == ESteps.CheckRequest)
|
||||||
{
|
{
|
||||||
_unityTiktokAssetBundleRequestOp.UpdateOperation();
|
_unityAssetBundleRequestOp.UpdateOperation();
|
||||||
Progress = _unityTiktokAssetBundleRequestOp.Progress;
|
Progress = _unityAssetBundleRequestOp.Progress;
|
||||||
DownloadProgress = _unityTiktokAssetBundleRequestOp.DownloadProgress;
|
DownloadProgress = _unityAssetBundleRequestOp.DownloadProgress;
|
||||||
DownloadedBytes = (long)_unityTiktokAssetBundleRequestOp.DownloadedBytes;
|
DownloadedBytes = _unityAssetBundleRequestOp.DownloadedBytes;
|
||||||
if (_unityTiktokAssetBundleRequestOp.IsDone == false)
|
if (_unityAssetBundleRequestOp.IsDone == false)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_unityTiktokAssetBundleRequestOp.Status == EOperationStatus.Succeed)
|
if (_unityAssetBundleRequestOp.Status == EOperationStatus.Succeed)
|
||||||
{
|
{
|
||||||
_steps = ESteps.Done;
|
_steps = ESteps.Done;
|
||||||
Status = EOperationStatus.Succeed;
|
Status = EOperationStatus.Succeed;
|
||||||
Result = _unityTiktokAssetBundleRequestOp.Result;
|
Result = _unityAssetBundleRequestOp.Result;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (_failedTryAgain > 0)
|
if (_failedTryAgain > 0)
|
||||||
{
|
{
|
||||||
_steps = ESteps.TryAgain;
|
_steps = ESteps.TryAgain;
|
||||||
YooLogger.Warning($"Failed download : {_unityTiktokAssetBundleRequestOp.URL} Try again !");
|
YooLogger.Warning($"Failed download : {_unityAssetBundleRequestOp.URL} Try again !");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_steps = ESteps.Done;
|
_steps = ESteps.Done;
|
||||||
Status = EOperationStatus.Failed;
|
Status = EOperationStatus.Failed;
|
||||||
Error = _unityTiktokAssetBundleRequestOp.Error;
|
Error = _unityAssetBundleRequestOp.Error;
|
||||||
YooLogger.Error(Error);
|
YooLogger.Error(Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ internal class RequestTiktokPackageHashOperation : AsyncOperationBase
|
|||||||
{
|
{
|
||||||
_steps = ESteps.Done;
|
_steps = ESteps.Done;
|
||||||
Status = EOperationStatus.Failed;
|
Status = EOperationStatus.Failed;
|
||||||
Error = $"Wechat package hash file content is empty !";
|
Error = $"Web package hash file content is empty !";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ internal class RequestTiktokPackageVersionOperation : AsyncOperationBase
|
|||||||
{
|
{
|
||||||
_steps = ESteps.Done;
|
_steps = ESteps.Done;
|
||||||
Status = EOperationStatus.Failed;
|
Status = EOperationStatus.Failed;
|
||||||
Error = $"Wechat package version file content is empty !";
|
Error = $"Web package version file content is empty !";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ namespace YooAsset
|
|||||||
Result = assetBundle;
|
Result = assetBundle;
|
||||||
Status = EOperationStatus.Succeed;
|
Status = EOperationStatus.Succeed;
|
||||||
|
|
||||||
//TODO 需要验证抖音插件请求器的下载进度
|
//TODO 需要验证插件请求器的下载进度
|
||||||
DownloadProgress = 1f;
|
DownloadProgress = 1f;
|
||||||
DownloadedBytes = _packageBundle.FileSize;
|
DownloadedBytes = _packageBundle.FileSize;
|
||||||
Progress = 1f;
|
Progress = 1f;
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
#if UNITY_WEBGL && DOUYINMINIGAME
|
#if UNITY_WEBGL && DOUYINMINIGAME
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using YooAsset;
|
using YooAsset;
|
||||||
using TTSDK;
|
using TTSDK;
|
||||||
using System.Linq;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
public static class TiktokFileSystemCreater
|
public static class TiktokFileSystemCreater
|
||||||
{
|
{
|
||||||
@@ -107,7 +106,7 @@ internal class TiktokFileSystem : IFileSystem
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 自定义参数:资源清单服务类
|
/// 自定义参数:资源清单服务类
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IManifestServices ManifestServices { private set; get; }
|
public IManifestRestoreServices ManifestServices { private set; get; }
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
@@ -169,7 +168,7 @@ internal class TiktokFileSystem : IFileSystem
|
|||||||
}
|
}
|
||||||
else if (name == FileSystemParametersDefine.MANIFEST_SERVICES)
|
else if (name == FileSystemParametersDefine.MANIFEST_SERVICES)
|
||||||
{
|
{
|
||||||
ManifestServices = (IManifestServices)value;
|
ManifestServices = (IManifestRestoreServices)value;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ internal class WXFSDownloadFileOperation : FSDownloadFileOperation
|
|||||||
_webCacheRequestOp.UpdateOperation();
|
_webCacheRequestOp.UpdateOperation();
|
||||||
Progress = _webCacheRequestOp.Progress;
|
Progress = _webCacheRequestOp.Progress;
|
||||||
DownloadProgress = _webCacheRequestOp.DownloadProgress;
|
DownloadProgress = _webCacheRequestOp.DownloadProgress;
|
||||||
DownloadedBytes = (long)_webCacheRequestOp.DownloadedBytes;
|
DownloadedBytes = _webCacheRequestOp.DownloadedBytes;
|
||||||
if (_webCacheRequestOp.IsDone == false)
|
if (_webCacheRequestOp.IsDone == false)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ internal class WXFSLoadBundleOperation : FSLoadBundleOperation
|
|||||||
private enum ESteps
|
private enum ESteps
|
||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
DownloadAssetBundle,
|
LoadAssetBundle,
|
||||||
Done,
|
Done,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -22,14 +22,14 @@ internal class WXFSLoadBundleOperation : FSLoadBundleOperation
|
|||||||
}
|
}
|
||||||
internal override void InternalStart()
|
internal override void InternalStart()
|
||||||
{
|
{
|
||||||
_steps = ESteps.DownloadAssetBundle;
|
_steps = ESteps.LoadAssetBundle;
|
||||||
}
|
}
|
||||||
internal override void InternalUpdate()
|
internal override void InternalUpdate()
|
||||||
{
|
{
|
||||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_steps == ESteps.DownloadAssetBundle)
|
if (_steps == ESteps.LoadAssetBundle)
|
||||||
{
|
{
|
||||||
if (_loadWebAssetBundleOp == null)
|
if (_loadWebAssetBundleOp == null)
|
||||||
{
|
{
|
||||||
@@ -55,7 +55,7 @@ internal class WXFSLoadBundleOperation : FSLoadBundleOperation
|
|||||||
_loadWebAssetBundleOp.UpdateOperation();
|
_loadWebAssetBundleOp.UpdateOperation();
|
||||||
Progress = _loadWebAssetBundleOp.Progress;
|
Progress = _loadWebAssetBundleOp.Progress;
|
||||||
DownloadProgress = _loadWebAssetBundleOp.DownloadProgress;
|
DownloadProgress = _loadWebAssetBundleOp.DownloadProgress;
|
||||||
DownloadedBytes = (long)_loadWebAssetBundleOp.DownloadedBytes;
|
DownloadedBytes = _loadWebAssetBundleOp.DownloadedBytes;
|
||||||
if (_loadWebAssetBundleOp.IsDone == false)
|
if (_loadWebAssetBundleOp.IsDone == false)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ namespace YooAsset
|
|||||||
|
|
||||||
private readonly PackageBundle _bundle;
|
private readonly PackageBundle _bundle;
|
||||||
private readonly DownloadFileOptions _options;
|
private readonly DownloadFileOptions _options;
|
||||||
private UnityWechatAssetBundleRequestOperation _unityWechatAssetBundleRequestOp;
|
private UnityWechatAssetBundleRequestOperation _unityAssetBundleRequestOp;
|
||||||
|
|
||||||
private int _requestCount = 0;
|
private int _requestCount = 0;
|
||||||
private float _tryAgainTimer;
|
private float _tryAgainTimer;
|
||||||
@@ -42,40 +42,40 @@ namespace YooAsset
|
|||||||
if (_steps == ESteps.CreateRequest)
|
if (_steps == ESteps.CreateRequest)
|
||||||
{
|
{
|
||||||
string url = GetRequestURL();
|
string url = GetRequestURL();
|
||||||
_unityWechatAssetBundleRequestOp = new UnityWechatAssetBundleRequestOperation(_bundle, url);
|
_unityAssetBundleRequestOp = new UnityWechatAssetBundleRequestOperation(_bundle, url);
|
||||||
_unityWechatAssetBundleRequestOp.StartOperation();
|
_unityAssetBundleRequestOp.StartOperation();
|
||||||
AddChildOperation(_unityWechatAssetBundleRequestOp);
|
AddChildOperation(_unityAssetBundleRequestOp);
|
||||||
_steps = ESteps.CheckRequest;
|
_steps = ESteps.CheckRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检测下载结果
|
// 检测下载结果
|
||||||
if (_steps == ESteps.CheckRequest)
|
if (_steps == ESteps.CheckRequest)
|
||||||
{
|
{
|
||||||
_unityWechatAssetBundleRequestOp.UpdateOperation();
|
_unityAssetBundleRequestOp.UpdateOperation();
|
||||||
Progress = _unityWechatAssetBundleRequestOp.Progress;
|
Progress = _unityAssetBundleRequestOp.Progress;
|
||||||
DownloadProgress = _unityWechatAssetBundleRequestOp.DownloadProgress;
|
DownloadProgress = _unityAssetBundleRequestOp.DownloadProgress;
|
||||||
DownloadedBytes = (long)_unityWechatAssetBundleRequestOp.DownloadedBytes;
|
DownloadedBytes = _unityAssetBundleRequestOp.DownloadedBytes;
|
||||||
if (_unityWechatAssetBundleRequestOp.IsDone == false)
|
if (_unityAssetBundleRequestOp.IsDone == false)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_unityWechatAssetBundleRequestOp.Status == EOperationStatus.Succeed)
|
if (_unityAssetBundleRequestOp.Status == EOperationStatus.Succeed)
|
||||||
{
|
{
|
||||||
_steps = ESteps.Done;
|
_steps = ESteps.Done;
|
||||||
Status = EOperationStatus.Succeed;
|
Status = EOperationStatus.Succeed;
|
||||||
Result = _unityWechatAssetBundleRequestOp.Result;
|
Result = _unityAssetBundleRequestOp.Result;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (_failedTryAgain > 0)
|
if (_failedTryAgain > 0)
|
||||||
{
|
{
|
||||||
_steps = ESteps.TryAgain;
|
_steps = ESteps.TryAgain;
|
||||||
YooLogger.Warning($"Failed download : {_unityWechatAssetBundleRequestOp.URL} Try again !");
|
YooLogger.Warning($"Failed download : {_unityAssetBundleRequestOp.URL} Try again !");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_steps = ESteps.Done;
|
_steps = ESteps.Done;
|
||||||
Status = EOperationStatus.Failed;
|
Status = EOperationStatus.Failed;
|
||||||
Error = _unityWechatAssetBundleRequestOp.Error;
|
Error = _unityAssetBundleRequestOp.Error;
|
||||||
YooLogger.Error(Error);
|
YooLogger.Error(Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ internal class RequestWechatPackageHashOperation : AsyncOperationBase
|
|||||||
{
|
{
|
||||||
_steps = ESteps.Done;
|
_steps = ESteps.Done;
|
||||||
Status = EOperationStatus.Failed;
|
Status = EOperationStatus.Failed;
|
||||||
Error = $"Wechat package hash file content is empty !";
|
Error = $"Web package hash file content is empty !";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ internal class RequestWechatPackageVersionOperation : AsyncOperationBase
|
|||||||
{
|
{
|
||||||
_steps = ESteps.Done;
|
_steps = ESteps.Done;
|
||||||
Status = EOperationStatus.Failed;
|
Status = EOperationStatus.Failed;
|
||||||
Error = $"Wechat package version file content is empty !";
|
Error = $"Web package version file content is empty !";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ internal class WechatFileSystem : IFileSystem
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 自定义参数:资源清单服务类
|
/// 自定义参数:资源清单服务类
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IManifestServices ManifestServices { private set; get; }
|
public IManifestRestoreServices ManifestServices { private set; get; }
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
@@ -184,7 +184,7 @@ internal class WechatFileSystem : IFileSystem
|
|||||||
}
|
}
|
||||||
else if (name == FileSystemParametersDefine.MANIFEST_SERVICES)
|
else if (name == FileSystemParametersDefine.MANIFEST_SERVICES)
|
||||||
{
|
{
|
||||||
ManifestServices = (IManifestServices)value;
|
ManifestServices = (IManifestRestoreServices)value;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
"GUID:e34a5702dd353724aa315fb8011f08c3",
|
"GUID:e34a5702dd353724aa315fb8011f08c3",
|
||||||
"GUID:5efd170ecd8084500bed5692932fe14e",
|
"GUID:5efd170ecd8084500bed5692932fe14e",
|
||||||
"GUID:bb21d6197862c4c3e863390dec9859a7",
|
"GUID:bb21d6197862c4c3e863390dec9859a7",
|
||||||
|
"GUID:870f26a2ffa82429195df0861505c5d5",
|
||||||
"GUID:870f26a2ffa82429195df0861505c5d5"
|
"GUID:870f26a2ffa82429195df0861505c5d5"
|
||||||
],
|
],
|
||||||
"includePlatforms": [],
|
"includePlatforms": [],
|
||||||
|
|||||||
@@ -67,7 +67,6 @@ public class TestFileStreamDecryption : IDecryptionServices
|
|||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 同步方式获取解密的资源包对象
|
/// 同步方式获取解密的资源包对象
|
||||||
/// 注意:加载流对象在资源包对象释放的时候会自动释放
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
DecryptResult IDecryptionServices.LoadAssetBundle(DecryptFileInfo fileInfo)
|
DecryptResult IDecryptionServices.LoadAssetBundle(DecryptFileInfo fileInfo)
|
||||||
{
|
{
|
||||||
@@ -80,7 +79,6 @@ public class TestFileStreamDecryption : IDecryptionServices
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步方式获取解密的资源包对象
|
/// 异步方式获取解密的资源包对象
|
||||||
/// 注意:加载流对象在资源包对象释放的时候会自动释放
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
DecryptResult IDecryptionServices.LoadAssetBundleAsync(DecryptFileInfo fileInfo)
|
DecryptResult IDecryptionServices.LoadAssetBundleAsync(DecryptFileInfo fileInfo)
|
||||||
{
|
{
|
||||||
@@ -92,11 +90,17 @@ public class TestFileStreamDecryption : IDecryptionServices
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 后备方式获取解密的资源包对象
|
/// 后备方式获取解密的资源包
|
||||||
|
/// 注意:当正常解密方法失败后,会触发后备加载!
|
||||||
|
/// 说明:建议通过LoadFromMemory()方法加载资源包作为保底机制。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
DecryptResult IDecryptionServices.LoadAssetBundleFallback(DecryptFileInfo fileInfo)
|
DecryptResult IDecryptionServices.LoadAssetBundleFallback(DecryptFileInfo fileInfo)
|
||||||
{
|
{
|
||||||
return new DecryptResult();
|
byte[] fileData = File.ReadAllBytes(fileInfo.FileLoadPath);
|
||||||
|
var assetBundle = AssetBundle.LoadFromMemory(fileData);
|
||||||
|
DecryptResult decryptResult = new DecryptResult();
|
||||||
|
decryptResult.Result = assetBundle;
|
||||||
|
return decryptResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,62 +0,0 @@
|
|||||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using UnityEditor;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace Cysharp.Threading.Tasks.Editor
|
|
||||||
{
|
|
||||||
// reflection call of UnityEditor.SplitterGUILayout
|
|
||||||
internal static class SplitterGUILayout
|
|
||||||
{
|
|
||||||
static BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
|
|
||||||
|
|
||||||
static Lazy<Type> splitterStateType = new Lazy<Type>(() =>
|
|
||||||
{
|
|
||||||
var type = typeof(EditorWindow).Assembly.GetTypes().First(x => x.FullName == "UnityEditor.SplitterState");
|
|
||||||
return type;
|
|
||||||
});
|
|
||||||
|
|
||||||
static Lazy<ConstructorInfo> splitterStateCtor = new Lazy<ConstructorInfo>(() =>
|
|
||||||
{
|
|
||||||
var type = splitterStateType.Value;
|
|
||||||
return type.GetConstructor(flags, null, new Type[] { typeof(float[]), typeof(int[]), typeof(int[]) }, null);
|
|
||||||
});
|
|
||||||
|
|
||||||
static Lazy<Type> splitterGUILayoutType = new Lazy<Type>(() =>
|
|
||||||
{
|
|
||||||
var type = typeof(EditorWindow).Assembly.GetTypes().First(x => x.FullName == "UnityEditor.SplitterGUILayout");
|
|
||||||
return type;
|
|
||||||
});
|
|
||||||
|
|
||||||
static Lazy<MethodInfo> beginVerticalSplit = new Lazy<MethodInfo>(() =>
|
|
||||||
{
|
|
||||||
var type = splitterGUILayoutType.Value;
|
|
||||||
return type.GetMethod("BeginVerticalSplit", flags, null, new Type[] { splitterStateType.Value, typeof(GUILayoutOption[]) }, null);
|
|
||||||
});
|
|
||||||
|
|
||||||
static Lazy<MethodInfo> endVerticalSplit = new Lazy<MethodInfo>(() =>
|
|
||||||
{
|
|
||||||
var type = splitterGUILayoutType.Value;
|
|
||||||
return type.GetMethod("EndVerticalSplit", flags, null, Type.EmptyTypes, null);
|
|
||||||
});
|
|
||||||
|
|
||||||
public static object CreateSplitterState(float[] relativeSizes, int[] minSizes, int[] maxSizes)
|
|
||||||
{
|
|
||||||
return splitterStateCtor.Value.Invoke(new object[] { relativeSizes, minSizes, maxSizes });
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void BeginVerticalSplit(object splitterState, params GUILayoutOption[] options)
|
|
||||||
{
|
|
||||||
beginVerticalSplit.Value.Invoke(null, new object[] { splitterState, options });
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void EndVerticalSplit()
|
|
||||||
{
|
|
||||||
endVerticalSplit.Value.Invoke(null, Type.EmptyTypes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "UniTask.Editor",
|
|
||||||
"references": [
|
|
||||||
"UniTask"
|
|
||||||
],
|
|
||||||
"includePlatforms": [
|
|
||||||
"Editor"
|
|
||||||
],
|
|
||||||
"excludePlatforms": [],
|
|
||||||
"allowUnsafeCode": false,
|
|
||||||
"overrideReferences": false,
|
|
||||||
"precompiledReferences": [],
|
|
||||||
"autoReferenced": false,
|
|
||||||
"defineConstraints": [],
|
|
||||||
"versionDefines": [],
|
|
||||||
"noEngineReferences": false
|
|
||||||
}
|
|
||||||
@@ -1,182 +0,0 @@
|
|||||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
|
||||||
|
|
||||||
using UnityEngine;
|
|
||||||
using UnityEditor;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using System;
|
|
||||||
using UnityEditor.IMGUI.Controls;
|
|
||||||
using Cysharp.Threading.Tasks.Internal;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
|
|
||||||
namespace Cysharp.Threading.Tasks.Editor
|
|
||||||
{
|
|
||||||
public class UniTaskTrackerViewItem : TreeViewItem
|
|
||||||
{
|
|
||||||
static Regex removeHref = new Regex("<a href.+>(.+)</a>", RegexOptions.Compiled);
|
|
||||||
|
|
||||||
public string TaskType { get; set; }
|
|
||||||
public string Elapsed { get; set; }
|
|
||||||
public string Status { get; set; }
|
|
||||||
|
|
||||||
string position;
|
|
||||||
public string Position
|
|
||||||
{
|
|
||||||
get { return position; }
|
|
||||||
set
|
|
||||||
{
|
|
||||||
position = value;
|
|
||||||
PositionFirstLine = GetFirstLine(position);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string PositionFirstLine { get; private set; }
|
|
||||||
|
|
||||||
static string GetFirstLine(string str)
|
|
||||||
{
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
for (int i = 0; i < str.Length; i++)
|
|
||||||
{
|
|
||||||
if (str[i] == '\r' || str[i] == '\n')
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
sb.Append(str[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return removeHref.Replace(sb.ToString(), "$1");
|
|
||||||
}
|
|
||||||
|
|
||||||
public UniTaskTrackerViewItem(int id) : base(id)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class UniTaskTrackerTreeView : TreeView
|
|
||||||
{
|
|
||||||
const string sortedColumnIndexStateKey = "UniTaskTrackerTreeView_sortedColumnIndex";
|
|
||||||
|
|
||||||
public IReadOnlyList<TreeViewItem> CurrentBindingItems;
|
|
||||||
|
|
||||||
public UniTaskTrackerTreeView()
|
|
||||||
: this(new TreeViewState(), new MultiColumnHeader(new MultiColumnHeaderState(new[]
|
|
||||||
{
|
|
||||||
new MultiColumnHeaderState.Column() { headerContent = new GUIContent("TaskType"), width = 20},
|
|
||||||
new MultiColumnHeaderState.Column() { headerContent = new GUIContent("Elapsed"), width = 10},
|
|
||||||
new MultiColumnHeaderState.Column() { headerContent = new GUIContent("Status"), width = 10},
|
|
||||||
new MultiColumnHeaderState.Column() { headerContent = new GUIContent("Position")},
|
|
||||||
})))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
UniTaskTrackerTreeView(TreeViewState state, MultiColumnHeader header)
|
|
||||||
: base(state, header)
|
|
||||||
{
|
|
||||||
rowHeight = 20;
|
|
||||||
showAlternatingRowBackgrounds = true;
|
|
||||||
showBorder = true;
|
|
||||||
header.sortingChanged += Header_sortingChanged;
|
|
||||||
|
|
||||||
header.ResizeToFit();
|
|
||||||
Reload();
|
|
||||||
|
|
||||||
header.sortedColumnIndex = SessionState.GetInt(sortedColumnIndexStateKey, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ReloadAndSort()
|
|
||||||
{
|
|
||||||
var currentSelected = this.state.selectedIDs;
|
|
||||||
Reload();
|
|
||||||
Header_sortingChanged(this.multiColumnHeader);
|
|
||||||
this.state.selectedIDs = currentSelected;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Header_sortingChanged(MultiColumnHeader multiColumnHeader)
|
|
||||||
{
|
|
||||||
SessionState.SetInt(sortedColumnIndexStateKey, multiColumnHeader.sortedColumnIndex);
|
|
||||||
var index = multiColumnHeader.sortedColumnIndex;
|
|
||||||
var ascending = multiColumnHeader.IsSortedAscending(multiColumnHeader.sortedColumnIndex);
|
|
||||||
|
|
||||||
var items = rootItem.children.Cast<UniTaskTrackerViewItem>();
|
|
||||||
|
|
||||||
IOrderedEnumerable<UniTaskTrackerViewItem> orderedEnumerable;
|
|
||||||
switch (index)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
orderedEnumerable = ascending ? items.OrderBy(item => item.TaskType) : items.OrderByDescending(item => item.TaskType);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
orderedEnumerable = ascending ? items.OrderBy(item => double.Parse(item.Elapsed)) : items.OrderByDescending(item => double.Parse(item.Elapsed));
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
orderedEnumerable = ascending ? items.OrderBy(item => item.Status) : items.OrderByDescending(item => item.Elapsed);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
orderedEnumerable = ascending ? items.OrderBy(item => item.Position) : items.OrderByDescending(item => item.PositionFirstLine);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(index), index, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
CurrentBindingItems = rootItem.children = orderedEnumerable.Cast<TreeViewItem>().ToList();
|
|
||||||
BuildRows(rootItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override TreeViewItem BuildRoot()
|
|
||||||
{
|
|
||||||
var root = new TreeViewItem { depth = -1 };
|
|
||||||
|
|
||||||
var children = new List<TreeViewItem>();
|
|
||||||
|
|
||||||
TaskTracker.ForEachActiveTask((trackingId, awaiterType, status, created, stackTrace) =>
|
|
||||||
{
|
|
||||||
children.Add(new UniTaskTrackerViewItem(trackingId) { TaskType = awaiterType, Status = status.ToString(), Elapsed = (DateTime.UtcNow - created).TotalSeconds.ToString("00.00"), Position = stackTrace });
|
|
||||||
});
|
|
||||||
|
|
||||||
CurrentBindingItems = children;
|
|
||||||
root.children = CurrentBindingItems as List<TreeViewItem>;
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool CanMultiSelect(TreeViewItem item)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void RowGUI(RowGUIArgs args)
|
|
||||||
{
|
|
||||||
var item = args.item as UniTaskTrackerViewItem;
|
|
||||||
|
|
||||||
for (var visibleColumnIndex = 0; visibleColumnIndex < args.GetNumVisibleColumns(); visibleColumnIndex++)
|
|
||||||
{
|
|
||||||
var rect = args.GetCellRect(visibleColumnIndex);
|
|
||||||
var columnIndex = args.GetColumn(visibleColumnIndex);
|
|
||||||
|
|
||||||
var labelStyle = args.selected ? EditorStyles.whiteLabel : EditorStyles.label;
|
|
||||||
labelStyle.alignment = TextAnchor.MiddleLeft;
|
|
||||||
switch (columnIndex)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
EditorGUI.LabelField(rect, item.TaskType, labelStyle);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
EditorGUI.LabelField(rect, item.Elapsed, labelStyle);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
EditorGUI.LabelField(rect, item.Status, labelStyle);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
EditorGUI.LabelField(rect, item.PositionFirstLine, labelStyle);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(columnIndex), columnIndex, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,209 +0,0 @@
|
|||||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
|
||||||
|
|
||||||
using UnityEngine;
|
|
||||||
using UnityEditor;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using System;
|
|
||||||
using UnityEditor.IMGUI.Controls;
|
|
||||||
using Cysharp.Threading.Tasks.Internal;
|
|
||||||
|
|
||||||
namespace Cysharp.Threading.Tasks.Editor
|
|
||||||
{
|
|
||||||
public class UniTaskTrackerWindow : EditorWindow
|
|
||||||
{
|
|
||||||
static int interval;
|
|
||||||
|
|
||||||
static UniTaskTrackerWindow window;
|
|
||||||
|
|
||||||
[MenuItem("Window/UniTask Tracker")]
|
|
||||||
public static void OpenWindow()
|
|
||||||
{
|
|
||||||
if (window != null)
|
|
||||||
{
|
|
||||||
window.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
// will called OnEnable(singleton instance will be set).
|
|
||||||
GetWindow<UniTaskTrackerWindow>("UniTask Tracker").Show();
|
|
||||||
}
|
|
||||||
|
|
||||||
static readonly GUILayoutOption[] EmptyLayoutOption = new GUILayoutOption[0];
|
|
||||||
|
|
||||||
UniTaskTrackerTreeView treeView;
|
|
||||||
object splitterState;
|
|
||||||
|
|
||||||
void OnEnable()
|
|
||||||
{
|
|
||||||
window = this; // set singleton.
|
|
||||||
splitterState = SplitterGUILayout.CreateSplitterState(new float[] { 75f, 25f }, new int[] { 32, 32 }, null);
|
|
||||||
treeView = new UniTaskTrackerTreeView();
|
|
||||||
TaskTracker.EditorEnableState.EnableAutoReload = EditorPrefs.GetBool(TaskTracker.EnableAutoReloadKey, false);
|
|
||||||
TaskTracker.EditorEnableState.EnableTracking = EditorPrefs.GetBool(TaskTracker.EnableTrackingKey, false);
|
|
||||||
TaskTracker.EditorEnableState.EnableStackTrace = EditorPrefs.GetBool(TaskTracker.EnableStackTraceKey, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnGUI()
|
|
||||||
{
|
|
||||||
// Head
|
|
||||||
RenderHeadPanel();
|
|
||||||
|
|
||||||
// Splittable
|
|
||||||
SplitterGUILayout.BeginVerticalSplit(this.splitterState, EmptyLayoutOption);
|
|
||||||
{
|
|
||||||
// Column Tabble
|
|
||||||
RenderTable();
|
|
||||||
|
|
||||||
// StackTrace details
|
|
||||||
RenderDetailsPanel();
|
|
||||||
}
|
|
||||||
SplitterGUILayout.EndVerticalSplit();
|
|
||||||
}
|
|
||||||
|
|
||||||
#region HeadPanel
|
|
||||||
|
|
||||||
public static bool EnableAutoReload => TaskTracker.EditorEnableState.EnableAutoReload;
|
|
||||||
public static bool EnableTracking => TaskTracker.EditorEnableState.EnableTracking;
|
|
||||||
public static bool EnableStackTrace => TaskTracker.EditorEnableState.EnableStackTrace;
|
|
||||||
static readonly GUIContent EnableAutoReloadHeadContent = EditorGUIUtility.TrTextContent("Enable AutoReload", "Reload automatically.", (Texture)null);
|
|
||||||
static readonly GUIContent ReloadHeadContent = EditorGUIUtility.TrTextContent("Reload", "Reload View.", (Texture)null);
|
|
||||||
static readonly GUIContent GCHeadContent = EditorGUIUtility.TrTextContent("GC.Collect", "Invoke GC.Collect.", (Texture)null);
|
|
||||||
static readonly GUIContent EnableTrackingHeadContent = EditorGUIUtility.TrTextContent("Enable Tracking", "Start to track async/await UniTask. Performance impact: low", (Texture)null);
|
|
||||||
static readonly GUIContent EnableStackTraceHeadContent = EditorGUIUtility.TrTextContent("Enable StackTrace", "Capture StackTrace when task is started. Performance impact: high", (Texture)null);
|
|
||||||
|
|
||||||
// [Enable Tracking] | [Enable StackTrace]
|
|
||||||
void RenderHeadPanel()
|
|
||||||
{
|
|
||||||
EditorGUILayout.BeginVertical(EmptyLayoutOption);
|
|
||||||
EditorGUILayout.BeginHorizontal(EditorStyles.toolbar, EmptyLayoutOption);
|
|
||||||
|
|
||||||
if (GUILayout.Toggle(EnableAutoReload, EnableAutoReloadHeadContent, EditorStyles.toolbarButton, EmptyLayoutOption) != EnableAutoReload)
|
|
||||||
{
|
|
||||||
TaskTracker.EditorEnableState.EnableAutoReload = !EnableAutoReload;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GUILayout.Toggle(EnableTracking, EnableTrackingHeadContent, EditorStyles.toolbarButton, EmptyLayoutOption) != EnableTracking)
|
|
||||||
{
|
|
||||||
TaskTracker.EditorEnableState.EnableTracking = !EnableTracking;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GUILayout.Toggle(EnableStackTrace, EnableStackTraceHeadContent, EditorStyles.toolbarButton, EmptyLayoutOption) != EnableStackTrace)
|
|
||||||
{
|
|
||||||
TaskTracker.EditorEnableState.EnableStackTrace = !EnableStackTrace;
|
|
||||||
}
|
|
||||||
|
|
||||||
GUILayout.FlexibleSpace();
|
|
||||||
|
|
||||||
if (GUILayout.Button(ReloadHeadContent, EditorStyles.toolbarButton, EmptyLayoutOption))
|
|
||||||
{
|
|
||||||
TaskTracker.CheckAndResetDirty();
|
|
||||||
treeView.ReloadAndSort();
|
|
||||||
Repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GUILayout.Button(GCHeadContent, EditorStyles.toolbarButton, EmptyLayoutOption))
|
|
||||||
{
|
|
||||||
GC.Collect(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
EditorGUILayout.EndHorizontal();
|
|
||||||
EditorGUILayout.EndVertical();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region TableColumn
|
|
||||||
|
|
||||||
Vector2 tableScroll;
|
|
||||||
GUIStyle tableListStyle;
|
|
||||||
|
|
||||||
void RenderTable()
|
|
||||||
{
|
|
||||||
if (tableListStyle == null)
|
|
||||||
{
|
|
||||||
tableListStyle = new GUIStyle("CN Box");
|
|
||||||
tableListStyle.margin.top = 0;
|
|
||||||
tableListStyle.padding.left = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
EditorGUILayout.BeginVertical(tableListStyle, EmptyLayoutOption);
|
|
||||||
|
|
||||||
this.tableScroll = EditorGUILayout.BeginScrollView(this.tableScroll, new GUILayoutOption[]
|
|
||||||
{
|
|
||||||
GUILayout.ExpandWidth(true),
|
|
||||||
GUILayout.MaxWidth(2000f)
|
|
||||||
});
|
|
||||||
var controlRect = EditorGUILayout.GetControlRect(new GUILayoutOption[]
|
|
||||||
{
|
|
||||||
GUILayout.ExpandHeight(true),
|
|
||||||
GUILayout.ExpandWidth(true)
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
treeView?.OnGUI(controlRect);
|
|
||||||
|
|
||||||
EditorGUILayout.EndScrollView();
|
|
||||||
EditorGUILayout.EndVertical();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Update()
|
|
||||||
{
|
|
||||||
if (EnableAutoReload)
|
|
||||||
{
|
|
||||||
if (interval++ % 120 == 0)
|
|
||||||
{
|
|
||||||
if (TaskTracker.CheckAndResetDirty())
|
|
||||||
{
|
|
||||||
treeView.ReloadAndSort();
|
|
||||||
Repaint();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Details
|
|
||||||
|
|
||||||
static GUIStyle detailsStyle;
|
|
||||||
Vector2 detailsScroll;
|
|
||||||
|
|
||||||
void RenderDetailsPanel()
|
|
||||||
{
|
|
||||||
if (detailsStyle == null)
|
|
||||||
{
|
|
||||||
detailsStyle = new GUIStyle("CN Message");
|
|
||||||
detailsStyle.wordWrap = false;
|
|
||||||
detailsStyle.stretchHeight = true;
|
|
||||||
detailsStyle.margin.right = 15;
|
|
||||||
}
|
|
||||||
|
|
||||||
string message = "";
|
|
||||||
var selected = treeView.state.selectedIDs;
|
|
||||||
if (selected.Count > 0)
|
|
||||||
{
|
|
||||||
var first = selected[0];
|
|
||||||
var item = treeView.CurrentBindingItems.FirstOrDefault(x => x.id == first) as UniTaskTrackerViewItem;
|
|
||||||
if (item != null)
|
|
||||||
{
|
|
||||||
message = item.Position;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
detailsScroll = EditorGUILayout.BeginScrollView(this.detailsScroll, EmptyLayoutOption);
|
|
||||||
var vector = detailsStyle.CalcSize(new GUIContent(message));
|
|
||||||
EditorGUILayout.SelectableLabel(message, detailsStyle, new GUILayoutOption[]
|
|
||||||
{
|
|
||||||
GUILayout.ExpandHeight(true),
|
|
||||||
GUILayout.ExpandWidth(true),
|
|
||||||
GUILayout.MinWidth(vector.x),
|
|
||||||
GUILayout.MinHeight(vector.y)
|
|
||||||
});
|
|
||||||
EditorGUILayout.EndScrollView();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: aa765154468d4b34eb34304100d39e64
|
guid: 2bbb725df946a6f49afbc3ef104fbd8f
|
||||||
folderAsset: yes
|
folderAsset: yes
|
||||||
DefaultImporter:
|
DefaultImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
|
|||||||
@@ -1,245 +0,0 @@
|
|||||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Cysharp.Threading.Tasks
|
|
||||||
{
|
|
||||||
public class AsyncLazy
|
|
||||||
{
|
|
||||||
static Action<object> continuation = SetCompletionSource;
|
|
||||||
|
|
||||||
Func<UniTask> taskFactory;
|
|
||||||
UniTaskCompletionSource completionSource;
|
|
||||||
UniTask.Awaiter awaiter;
|
|
||||||
|
|
||||||
object syncLock;
|
|
||||||
bool initialized;
|
|
||||||
|
|
||||||
public AsyncLazy(Func<UniTask> taskFactory)
|
|
||||||
{
|
|
||||||
this.taskFactory = taskFactory;
|
|
||||||
this.completionSource = new UniTaskCompletionSource();
|
|
||||||
this.syncLock = new object();
|
|
||||||
this.initialized = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal AsyncLazy(UniTask task)
|
|
||||||
{
|
|
||||||
this.taskFactory = null;
|
|
||||||
this.completionSource = new UniTaskCompletionSource();
|
|
||||||
this.syncLock = null;
|
|
||||||
this.initialized = true;
|
|
||||||
|
|
||||||
var awaiter = task.GetAwaiter();
|
|
||||||
if (awaiter.IsCompleted)
|
|
||||||
{
|
|
||||||
SetCompletionSource(awaiter);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.awaiter = awaiter;
|
|
||||||
awaiter.SourceOnCompleted(continuation, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public UniTask Task
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
EnsureInitialized();
|
|
||||||
return completionSource.Task;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public UniTask.Awaiter GetAwaiter() => Task.GetAwaiter();
|
|
||||||
|
|
||||||
void EnsureInitialized()
|
|
||||||
{
|
|
||||||
if (Volatile.Read(ref initialized))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
EnsureInitializedCore();
|
|
||||||
}
|
|
||||||
|
|
||||||
void EnsureInitializedCore()
|
|
||||||
{
|
|
||||||
lock (syncLock)
|
|
||||||
{
|
|
||||||
if (!Volatile.Read(ref initialized))
|
|
||||||
{
|
|
||||||
var f = Interlocked.Exchange(ref taskFactory, null);
|
|
||||||
if (f != null)
|
|
||||||
{
|
|
||||||
var task = f();
|
|
||||||
var awaiter = task.GetAwaiter();
|
|
||||||
if (awaiter.IsCompleted)
|
|
||||||
{
|
|
||||||
SetCompletionSource(awaiter);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.awaiter = awaiter;
|
|
||||||
awaiter.SourceOnCompleted(continuation, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
Volatile.Write(ref initialized, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetCompletionSource(in UniTask.Awaiter awaiter)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
awaiter.GetResult();
|
|
||||||
completionSource.TrySetResult();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
completionSource.TrySetException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void SetCompletionSource(object state)
|
|
||||||
{
|
|
||||||
var self = (AsyncLazy)state;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
self.awaiter.GetResult();
|
|
||||||
self.completionSource.TrySetResult();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
self.completionSource.TrySetException(ex);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
self.awaiter = default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class AsyncLazy<T>
|
|
||||||
{
|
|
||||||
static Action<object> continuation = SetCompletionSource;
|
|
||||||
|
|
||||||
Func<UniTask<T>> taskFactory;
|
|
||||||
UniTaskCompletionSource<T> completionSource;
|
|
||||||
UniTask<T>.Awaiter awaiter;
|
|
||||||
|
|
||||||
object syncLock;
|
|
||||||
bool initialized;
|
|
||||||
|
|
||||||
public AsyncLazy(Func<UniTask<T>> taskFactory)
|
|
||||||
{
|
|
||||||
this.taskFactory = taskFactory;
|
|
||||||
this.completionSource = new UniTaskCompletionSource<T>();
|
|
||||||
this.syncLock = new object();
|
|
||||||
this.initialized = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal AsyncLazy(UniTask<T> task)
|
|
||||||
{
|
|
||||||
this.taskFactory = null;
|
|
||||||
this.completionSource = new UniTaskCompletionSource<T>();
|
|
||||||
this.syncLock = null;
|
|
||||||
this.initialized = true;
|
|
||||||
|
|
||||||
var awaiter = task.GetAwaiter();
|
|
||||||
if (awaiter.IsCompleted)
|
|
||||||
{
|
|
||||||
SetCompletionSource(awaiter);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.awaiter = awaiter;
|
|
||||||
awaiter.SourceOnCompleted(continuation, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public UniTask<T> Task
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
EnsureInitialized();
|
|
||||||
return completionSource.Task;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public UniTask<T>.Awaiter GetAwaiter() => Task.GetAwaiter();
|
|
||||||
|
|
||||||
void EnsureInitialized()
|
|
||||||
{
|
|
||||||
if (Volatile.Read(ref initialized))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
EnsureInitializedCore();
|
|
||||||
}
|
|
||||||
|
|
||||||
void EnsureInitializedCore()
|
|
||||||
{
|
|
||||||
lock (syncLock)
|
|
||||||
{
|
|
||||||
if (!Volatile.Read(ref initialized))
|
|
||||||
{
|
|
||||||
var f = Interlocked.Exchange(ref taskFactory, null);
|
|
||||||
if (f != null)
|
|
||||||
{
|
|
||||||
var task = f();
|
|
||||||
var awaiter = task.GetAwaiter();
|
|
||||||
if (awaiter.IsCompleted)
|
|
||||||
{
|
|
||||||
SetCompletionSource(awaiter);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.awaiter = awaiter;
|
|
||||||
awaiter.SourceOnCompleted(continuation, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
Volatile.Write(ref initialized, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetCompletionSource(in UniTask<T>.Awaiter awaiter)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var result = awaiter.GetResult();
|
|
||||||
completionSource.TrySetResult(result);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
completionSource.TrySetException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void SetCompletionSource(object state)
|
|
||||||
{
|
|
||||||
var self = (AsyncLazy<T>)state;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var result = self.awaiter.GetResult();
|
|
||||||
self.completionSource.TrySetResult(result);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
self.completionSource.TrySetException(ex);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
self.awaiter = default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,644 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Cysharp.Threading.Tasks
|
|
||||||
{
|
|
||||||
public interface IReadOnlyAsyncReactiveProperty<T> : IUniTaskAsyncEnumerable<T>
|
|
||||||
{
|
|
||||||
T Value { get; }
|
|
||||||
IUniTaskAsyncEnumerable<T> WithoutCurrent();
|
|
||||||
UniTask<T> WaitAsync(CancellationToken cancellationToken = default);
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface IAsyncReactiveProperty<T> : IReadOnlyAsyncReactiveProperty<T>
|
|
||||||
{
|
|
||||||
new T Value { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class AsyncReactiveProperty<T> : IAsyncReactiveProperty<T>, IDisposable
|
|
||||||
{
|
|
||||||
TriggerEvent<T> triggerEvent;
|
|
||||||
|
|
||||||
#if UNITY_2018_3_OR_NEWER
|
|
||||||
[UnityEngine.SerializeField]
|
|
||||||
#endif
|
|
||||||
T latestValue;
|
|
||||||
|
|
||||||
public T Value
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return latestValue;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
this.latestValue = value;
|
|
||||||
triggerEvent.SetResult(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public AsyncReactiveProperty(T value)
|
|
||||||
{
|
|
||||||
this.latestValue = value;
|
|
||||||
this.triggerEvent = default;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IUniTaskAsyncEnumerable<T> WithoutCurrent()
|
|
||||||
{
|
|
||||||
return new WithoutCurrentEnumerable(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return new Enumerator(this, cancellationToken, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
triggerEvent.SetCompleted();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static implicit operator T(AsyncReactiveProperty<T> value)
|
|
||||||
{
|
|
||||||
return value.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
if (isValueType) return latestValue.ToString();
|
|
||||||
return latestValue?.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public UniTask<T> WaitAsync(CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
return new UniTask<T>(WaitAsyncSource.Create(this, cancellationToken, out var token), token);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isValueType;
|
|
||||||
|
|
||||||
static AsyncReactiveProperty()
|
|
||||||
{
|
|
||||||
isValueType = typeof(T).IsValueType;
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class WaitAsyncSource : IUniTaskSource<T>, ITriggerHandler<T>, ITaskPoolNode<WaitAsyncSource>
|
|
||||||
{
|
|
||||||
static Action<object> cancellationCallback = CancellationCallback;
|
|
||||||
|
|
||||||
static TaskPool<WaitAsyncSource> pool;
|
|
||||||
WaitAsyncSource nextNode;
|
|
||||||
ref WaitAsyncSource ITaskPoolNode<WaitAsyncSource>.NextNode => ref nextNode;
|
|
||||||
|
|
||||||
static WaitAsyncSource()
|
|
||||||
{
|
|
||||||
TaskPool.RegisterSizeGetter(typeof(WaitAsyncSource), () => pool.Size);
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncReactiveProperty<T> parent;
|
|
||||||
CancellationToken cancellationToken;
|
|
||||||
CancellationTokenRegistration cancellationTokenRegistration;
|
|
||||||
UniTaskCompletionSourceCore<T> core;
|
|
||||||
|
|
||||||
WaitAsyncSource()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IUniTaskSource<T> Create(AsyncReactiveProperty<T> parent, CancellationToken cancellationToken, out short token)
|
|
||||||
{
|
|
||||||
if (cancellationToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
return AutoResetUniTaskCompletionSource<T>.CreateFromCanceled(cancellationToken, out token);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!pool.TryPop(out var result))
|
|
||||||
{
|
|
||||||
result = new WaitAsyncSource();
|
|
||||||
}
|
|
||||||
|
|
||||||
result.parent = parent;
|
|
||||||
result.cancellationToken = cancellationToken;
|
|
||||||
|
|
||||||
if (cancellationToken.CanBeCanceled)
|
|
||||||
{
|
|
||||||
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallback, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
result.parent.triggerEvent.Add(result);
|
|
||||||
|
|
||||||
TaskTracker.TrackActiveTask(result, 3);
|
|
||||||
|
|
||||||
token = result.core.Version;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TryReturn()
|
|
||||||
{
|
|
||||||
TaskTracker.RemoveTracking(this);
|
|
||||||
core.Reset();
|
|
||||||
cancellationTokenRegistration.Dispose();
|
|
||||||
cancellationTokenRegistration = default;
|
|
||||||
parent.triggerEvent.Remove(this);
|
|
||||||
parent = null;
|
|
||||||
cancellationToken = default;
|
|
||||||
return pool.TryPush(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void CancellationCallback(object state)
|
|
||||||
{
|
|
||||||
var self = (WaitAsyncSource)state;
|
|
||||||
self.OnCanceled(self.cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
// IUniTaskSource
|
|
||||||
|
|
||||||
public T GetResult(short token)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return core.GetResult(token);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
TryReturn();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void IUniTaskSource.GetResult(short token)
|
|
||||||
{
|
|
||||||
GetResult(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnCompleted(Action<object> continuation, object state, short token)
|
|
||||||
{
|
|
||||||
core.OnCompleted(continuation, state, token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UniTaskStatus GetStatus(short token)
|
|
||||||
{
|
|
||||||
return core.GetStatus(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UniTaskStatus UnsafeGetStatus()
|
|
||||||
{
|
|
||||||
return core.UnsafeGetStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ITriggerHandler
|
|
||||||
|
|
||||||
ITriggerHandler<T> ITriggerHandler<T>.Prev { get; set; }
|
|
||||||
ITriggerHandler<T> ITriggerHandler<T>.Next { get; set; }
|
|
||||||
|
|
||||||
public void OnCanceled(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
core.TrySetCanceled(cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnCompleted()
|
|
||||||
{
|
|
||||||
// Complete as Cancel.
|
|
||||||
core.TrySetCanceled(CancellationToken.None);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnError(Exception ex)
|
|
||||||
{
|
|
||||||
core.TrySetException(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnNext(T value)
|
|
||||||
{
|
|
||||||
core.TrySetResult(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class WithoutCurrentEnumerable : IUniTaskAsyncEnumerable<T>
|
|
||||||
{
|
|
||||||
readonly AsyncReactiveProperty<T> parent;
|
|
||||||
|
|
||||||
public WithoutCurrentEnumerable(AsyncReactiveProperty<T> parent)
|
|
||||||
{
|
|
||||||
this.parent = parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
return new Enumerator(parent, cancellationToken, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator<T>, ITriggerHandler<T>
|
|
||||||
{
|
|
||||||
static Action<object> cancellationCallback = CancellationCallback;
|
|
||||||
|
|
||||||
readonly AsyncReactiveProperty<T> parent;
|
|
||||||
readonly CancellationToken cancellationToken;
|
|
||||||
readonly CancellationTokenRegistration cancellationTokenRegistration;
|
|
||||||
T value;
|
|
||||||
bool isDisposed;
|
|
||||||
bool firstCall;
|
|
||||||
|
|
||||||
public Enumerator(AsyncReactiveProperty<T> parent, CancellationToken cancellationToken, bool publishCurrentValue)
|
|
||||||
{
|
|
||||||
this.parent = parent;
|
|
||||||
this.cancellationToken = cancellationToken;
|
|
||||||
this.firstCall = publishCurrentValue;
|
|
||||||
|
|
||||||
parent.triggerEvent.Add(this);
|
|
||||||
TaskTracker.TrackActiveTask(this, 3);
|
|
||||||
|
|
||||||
if (cancellationToken.CanBeCanceled)
|
|
||||||
{
|
|
||||||
cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallback, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public T Current => value;
|
|
||||||
|
|
||||||
ITriggerHandler<T> ITriggerHandler<T>.Prev { get; set; }
|
|
||||||
ITriggerHandler<T> ITriggerHandler<T>.Next { get; set; }
|
|
||||||
|
|
||||||
public UniTask<bool> MoveNextAsync()
|
|
||||||
{
|
|
||||||
// raise latest value on first call.
|
|
||||||
if (firstCall)
|
|
||||||
{
|
|
||||||
firstCall = false;
|
|
||||||
value = parent.Value;
|
|
||||||
return CompletedTasks.True;
|
|
||||||
}
|
|
||||||
|
|
||||||
completionSource.Reset();
|
|
||||||
return new UniTask<bool>(this, completionSource.Version);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UniTask DisposeAsync()
|
|
||||||
{
|
|
||||||
if (!isDisposed)
|
|
||||||
{
|
|
||||||
isDisposed = true;
|
|
||||||
TaskTracker.RemoveTracking(this);
|
|
||||||
completionSource.TrySetCanceled(cancellationToken);
|
|
||||||
parent.triggerEvent.Remove(this);
|
|
||||||
}
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnNext(T value)
|
|
||||||
{
|
|
||||||
this.value = value;
|
|
||||||
completionSource.TrySetResult(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnCanceled(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
DisposeAsync().Forget();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnCompleted()
|
|
||||||
{
|
|
||||||
completionSource.TrySetResult(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnError(Exception ex)
|
|
||||||
{
|
|
||||||
completionSource.TrySetException(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void CancellationCallback(object state)
|
|
||||||
{
|
|
||||||
var self = (Enumerator)state;
|
|
||||||
self.DisposeAsync().Forget();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ReadOnlyAsyncReactiveProperty<T> : IReadOnlyAsyncReactiveProperty<T>, IDisposable
|
|
||||||
{
|
|
||||||
TriggerEvent<T> triggerEvent;
|
|
||||||
|
|
||||||
T latestValue;
|
|
||||||
IUniTaskAsyncEnumerator<T> enumerator;
|
|
||||||
|
|
||||||
public T Value
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return latestValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ReadOnlyAsyncReactiveProperty(T initialValue, IUniTaskAsyncEnumerable<T> source, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
latestValue = initialValue;
|
|
||||||
ConsumeEnumerator(source, cancellationToken).Forget();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ReadOnlyAsyncReactiveProperty(IUniTaskAsyncEnumerable<T> source, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
ConsumeEnumerator(source, cancellationToken).Forget();
|
|
||||||
}
|
|
||||||
|
|
||||||
async UniTaskVoid ConsumeEnumerator(IUniTaskAsyncEnumerable<T> source, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
enumerator = source.GetAsyncEnumerator(cancellationToken);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
while (await enumerator.MoveNextAsync())
|
|
||||||
{
|
|
||||||
var value = enumerator.Current;
|
|
||||||
this.latestValue = value;
|
|
||||||
triggerEvent.SetResult(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
await enumerator.DisposeAsync();
|
|
||||||
enumerator = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IUniTaskAsyncEnumerable<T> WithoutCurrent()
|
|
||||||
{
|
|
||||||
return new WithoutCurrentEnumerable(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return new Enumerator(this, cancellationToken, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
if (enumerator != null)
|
|
||||||
{
|
|
||||||
enumerator.DisposeAsync().Forget();
|
|
||||||
}
|
|
||||||
|
|
||||||
triggerEvent.SetCompleted();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static implicit operator T(ReadOnlyAsyncReactiveProperty<T> value)
|
|
||||||
{
|
|
||||||
return value.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
if (isValueType) return latestValue.ToString();
|
|
||||||
return latestValue?.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public UniTask<T> WaitAsync(CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
return new UniTask<T>(WaitAsyncSource.Create(this, cancellationToken, out var token), token);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isValueType;
|
|
||||||
|
|
||||||
static ReadOnlyAsyncReactiveProperty()
|
|
||||||
{
|
|
||||||
isValueType = typeof(T).IsValueType;
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class WaitAsyncSource : IUniTaskSource<T>, ITriggerHandler<T>, ITaskPoolNode<WaitAsyncSource>
|
|
||||||
{
|
|
||||||
static Action<object> cancellationCallback = CancellationCallback;
|
|
||||||
|
|
||||||
static TaskPool<WaitAsyncSource> pool;
|
|
||||||
WaitAsyncSource nextNode;
|
|
||||||
ref WaitAsyncSource ITaskPoolNode<WaitAsyncSource>.NextNode => ref nextNode;
|
|
||||||
|
|
||||||
static WaitAsyncSource()
|
|
||||||
{
|
|
||||||
TaskPool.RegisterSizeGetter(typeof(WaitAsyncSource), () => pool.Size);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReadOnlyAsyncReactiveProperty<T> parent;
|
|
||||||
CancellationToken cancellationToken;
|
|
||||||
CancellationTokenRegistration cancellationTokenRegistration;
|
|
||||||
UniTaskCompletionSourceCore<T> core;
|
|
||||||
|
|
||||||
WaitAsyncSource()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IUniTaskSource<T> Create(ReadOnlyAsyncReactiveProperty<T> parent, CancellationToken cancellationToken, out short token)
|
|
||||||
{
|
|
||||||
if (cancellationToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
return AutoResetUniTaskCompletionSource<T>.CreateFromCanceled(cancellationToken, out token);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!pool.TryPop(out var result))
|
|
||||||
{
|
|
||||||
result = new WaitAsyncSource();
|
|
||||||
}
|
|
||||||
|
|
||||||
result.parent = parent;
|
|
||||||
result.cancellationToken = cancellationToken;
|
|
||||||
|
|
||||||
if (cancellationToken.CanBeCanceled)
|
|
||||||
{
|
|
||||||
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallback, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
result.parent.triggerEvent.Add(result);
|
|
||||||
|
|
||||||
TaskTracker.TrackActiveTask(result, 3);
|
|
||||||
|
|
||||||
token = result.core.Version;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TryReturn()
|
|
||||||
{
|
|
||||||
TaskTracker.RemoveTracking(this);
|
|
||||||
core.Reset();
|
|
||||||
cancellationTokenRegistration.Dispose();
|
|
||||||
cancellationTokenRegistration = default;
|
|
||||||
parent.triggerEvent.Remove(this);
|
|
||||||
parent = null;
|
|
||||||
cancellationToken = default;
|
|
||||||
return pool.TryPush(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void CancellationCallback(object state)
|
|
||||||
{
|
|
||||||
var self = (WaitAsyncSource)state;
|
|
||||||
self.OnCanceled(self.cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
// IUniTaskSource
|
|
||||||
|
|
||||||
public T GetResult(short token)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return core.GetResult(token);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
TryReturn();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void IUniTaskSource.GetResult(short token)
|
|
||||||
{
|
|
||||||
GetResult(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnCompleted(Action<object> continuation, object state, short token)
|
|
||||||
{
|
|
||||||
core.OnCompleted(continuation, state, token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UniTaskStatus GetStatus(short token)
|
|
||||||
{
|
|
||||||
return core.GetStatus(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UniTaskStatus UnsafeGetStatus()
|
|
||||||
{
|
|
||||||
return core.UnsafeGetStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ITriggerHandler
|
|
||||||
|
|
||||||
ITriggerHandler<T> ITriggerHandler<T>.Prev { get; set; }
|
|
||||||
ITriggerHandler<T> ITriggerHandler<T>.Next { get; set; }
|
|
||||||
|
|
||||||
public void OnCanceled(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
core.TrySetCanceled(cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnCompleted()
|
|
||||||
{
|
|
||||||
// Complete as Cancel.
|
|
||||||
core.TrySetCanceled(CancellationToken.None);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnError(Exception ex)
|
|
||||||
{
|
|
||||||
core.TrySetException(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnNext(T value)
|
|
||||||
{
|
|
||||||
core.TrySetResult(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class WithoutCurrentEnumerable : IUniTaskAsyncEnumerable<T>
|
|
||||||
{
|
|
||||||
readonly ReadOnlyAsyncReactiveProperty<T> parent;
|
|
||||||
|
|
||||||
public WithoutCurrentEnumerable(ReadOnlyAsyncReactiveProperty<T> parent)
|
|
||||||
{
|
|
||||||
this.parent = parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
return new Enumerator(parent, cancellationToken, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator<T>, ITriggerHandler<T>
|
|
||||||
{
|
|
||||||
static Action<object> cancellationCallback = CancellationCallback;
|
|
||||||
|
|
||||||
readonly ReadOnlyAsyncReactiveProperty<T> parent;
|
|
||||||
readonly CancellationToken cancellationToken;
|
|
||||||
readonly CancellationTokenRegistration cancellationTokenRegistration;
|
|
||||||
T value;
|
|
||||||
bool isDisposed;
|
|
||||||
bool firstCall;
|
|
||||||
|
|
||||||
public Enumerator(ReadOnlyAsyncReactiveProperty<T> parent, CancellationToken cancellationToken, bool publishCurrentValue)
|
|
||||||
{
|
|
||||||
this.parent = parent;
|
|
||||||
this.cancellationToken = cancellationToken;
|
|
||||||
this.firstCall = publishCurrentValue;
|
|
||||||
|
|
||||||
parent.triggerEvent.Add(this);
|
|
||||||
TaskTracker.TrackActiveTask(this, 3);
|
|
||||||
|
|
||||||
if (cancellationToken.CanBeCanceled)
|
|
||||||
{
|
|
||||||
cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallback, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public T Current => value;
|
|
||||||
ITriggerHandler<T> ITriggerHandler<T>.Prev { get; set; }
|
|
||||||
ITriggerHandler<T> ITriggerHandler<T>.Next { get; set; }
|
|
||||||
|
|
||||||
public UniTask<bool> MoveNextAsync()
|
|
||||||
{
|
|
||||||
// raise latest value on first call.
|
|
||||||
if (firstCall)
|
|
||||||
{
|
|
||||||
firstCall = false;
|
|
||||||
value = parent.Value;
|
|
||||||
return CompletedTasks.True;
|
|
||||||
}
|
|
||||||
|
|
||||||
completionSource.Reset();
|
|
||||||
return new UniTask<bool>(this, completionSource.Version);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UniTask DisposeAsync()
|
|
||||||
{
|
|
||||||
if (!isDisposed)
|
|
||||||
{
|
|
||||||
isDisposed = true;
|
|
||||||
TaskTracker.RemoveTracking(this);
|
|
||||||
completionSource.TrySetCanceled(cancellationToken);
|
|
||||||
parent.triggerEvent.Remove(this);
|
|
||||||
}
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnNext(T value)
|
|
||||||
{
|
|
||||||
this.value = value;
|
|
||||||
completionSource.TrySetResult(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnCanceled(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
DisposeAsync().Forget();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnCompleted()
|
|
||||||
{
|
|
||||||
completionSource.TrySetResult(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnError(Exception ex)
|
|
||||||
{
|
|
||||||
completionSource.TrySetException(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void CancellationCallback(object state)
|
|
||||||
{
|
|
||||||
var self = (Enumerator)state;
|
|
||||||
self.DisposeAsync().Forget();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class StateExtensions
|
|
||||||
{
|
|
||||||
public static ReadOnlyAsyncReactiveProperty<T> ToReadOnlyAsyncReactiveProperty<T>(this IUniTaskAsyncEnumerable<T> source, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return new ReadOnlyAsyncReactiveProperty<T>(source, cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ReadOnlyAsyncReactiveProperty<T> ToReadOnlyAsyncReactiveProperty<T>(this IUniTaskAsyncEnumerable<T> source, T initialValue, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return new ReadOnlyAsyncReactiveProperty<T>(initialValue, source, cancellationToken);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 8ef320b87f537ee4fb2282e765dc6166
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or
|
|
||||||
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Cysharp.Threading.Tasks
|
|
||||||
{
|
|
||||||
public readonly struct AsyncUnit : IEquatable<AsyncUnit>
|
|
||||||
{
|
|
||||||
public static readonly AsyncUnit Default = new AsyncUnit();
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Equals(AsyncUnit other)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return "()";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 4f95ac245430d304bb5128d13b6becc8
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Cysharp.Threading.Tasks
|
|
||||||
{
|
|
||||||
public class CancellationTokenEqualityComparer : IEqualityComparer<CancellationToken>
|
|
||||||
{
|
|
||||||
public static readonly IEqualityComparer<CancellationToken> Default = new CancellationTokenEqualityComparer();
|
|
||||||
|
|
||||||
public bool Equals(CancellationToken x, CancellationToken y)
|
|
||||||
{
|
|
||||||
return x.Equals(y);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int GetHashCode(CancellationToken obj)
|
|
||||||
{
|
|
||||||
return obj.GetHashCode();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 7d739f510b125b74fa7290ac4335e46e
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,182 +0,0 @@
|
|||||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Cysharp.Threading.Tasks
|
|
||||||
{
|
|
||||||
public static class CancellationTokenExtensions
|
|
||||||
{
|
|
||||||
static readonly Action<object> cancellationTokenCallback = Callback;
|
|
||||||
static readonly Action<object> disposeCallback = DisposeCallback;
|
|
||||||
|
|
||||||
public static CancellationToken ToCancellationToken(this UniTask task)
|
|
||||||
{
|
|
||||||
var cts = new CancellationTokenSource();
|
|
||||||
ToCancellationTokenCore(task, cts).Forget();
|
|
||||||
return cts.Token;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static CancellationToken ToCancellationToken(this UniTask task, CancellationToken linkToken)
|
|
||||||
{
|
|
||||||
if (linkToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
return linkToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!linkToken.CanBeCanceled)
|
|
||||||
{
|
|
||||||
return ToCancellationToken(task);
|
|
||||||
}
|
|
||||||
|
|
||||||
var cts = CancellationTokenSource.CreateLinkedTokenSource(linkToken);
|
|
||||||
ToCancellationTokenCore(task, cts).Forget();
|
|
||||||
|
|
||||||
return cts.Token;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static CancellationToken ToCancellationToken<T>(this UniTask<T> task)
|
|
||||||
{
|
|
||||||
return ToCancellationToken(task.AsUniTask());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static CancellationToken ToCancellationToken<T>(this UniTask<T> task, CancellationToken linkToken)
|
|
||||||
{
|
|
||||||
return ToCancellationToken(task.AsUniTask(), linkToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
static async UniTaskVoid ToCancellationTokenCore(UniTask task, CancellationTokenSource cts)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await task;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
UniTaskScheduler.PublishUnobservedTaskException(ex);
|
|
||||||
}
|
|
||||||
cts.Cancel();
|
|
||||||
cts.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static (UniTask, CancellationTokenRegistration) ToUniTask(this CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
if (cancellationToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
return (UniTask.FromCanceled(cancellationToken), default(CancellationTokenRegistration));
|
|
||||||
}
|
|
||||||
|
|
||||||
var promise = new UniTaskCompletionSource();
|
|
||||||
return (promise.Task, cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationTokenCallback, promise));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Callback(object state)
|
|
||||||
{
|
|
||||||
var promise = (UniTaskCompletionSource)state;
|
|
||||||
promise.TrySetResult();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static CancellationTokenAwaitable WaitUntilCanceled(this CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return new CancellationTokenAwaitable(cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static CancellationTokenRegistration RegisterWithoutCaptureExecutionContext(this CancellationToken cancellationToken, Action callback)
|
|
||||||
{
|
|
||||||
var restoreFlow = false;
|
|
||||||
if (!ExecutionContext.IsFlowSuppressed())
|
|
||||||
{
|
|
||||||
ExecutionContext.SuppressFlow();
|
|
||||||
restoreFlow = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return cancellationToken.Register(callback, false);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (restoreFlow)
|
|
||||||
{
|
|
||||||
ExecutionContext.RestoreFlow();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static CancellationTokenRegistration RegisterWithoutCaptureExecutionContext(this CancellationToken cancellationToken, Action<object> callback, object state)
|
|
||||||
{
|
|
||||||
var restoreFlow = false;
|
|
||||||
if (!ExecutionContext.IsFlowSuppressed())
|
|
||||||
{
|
|
||||||
ExecutionContext.SuppressFlow();
|
|
||||||
restoreFlow = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return cancellationToken.Register(callback, state, false);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (restoreFlow)
|
|
||||||
{
|
|
||||||
ExecutionContext.RestoreFlow();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static CancellationTokenRegistration AddTo(this IDisposable disposable, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return cancellationToken.RegisterWithoutCaptureExecutionContext(disposeCallback, disposable);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void DisposeCallback(object state)
|
|
||||||
{
|
|
||||||
var d = (IDisposable)state;
|
|
||||||
d.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public struct CancellationTokenAwaitable
|
|
||||||
{
|
|
||||||
CancellationToken cancellationToken;
|
|
||||||
|
|
||||||
public CancellationTokenAwaitable(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
this.cancellationToken = cancellationToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Awaiter GetAwaiter()
|
|
||||||
{
|
|
||||||
return new Awaiter(cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
public struct Awaiter : ICriticalNotifyCompletion
|
|
||||||
{
|
|
||||||
CancellationToken cancellationToken;
|
|
||||||
|
|
||||||
public Awaiter(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
this.cancellationToken = cancellationToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsCompleted => !cancellationToken.CanBeCanceled || cancellationToken.IsCancellationRequested;
|
|
||||||
|
|
||||||
public void GetResult()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnCompleted(Action continuation)
|
|
||||||
{
|
|
||||||
UnsafeOnCompleted(continuation);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UnsafeOnCompleted(Action continuation)
|
|
||||||
{
|
|
||||||
cancellationToken.RegisterWithoutCaptureExecutionContext(continuation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 4be7209f04146bd45ac5ee775a5f7c26
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
|
||||||
|
|
||||||
using System.Threading;
|
|
||||||
using UnityEngine;
|
|
||||||
using Cysharp.Threading.Tasks.Triggers;
|
|
||||||
using System;
|
|
||||||
using Cysharp.Threading.Tasks.Internal;
|
|
||||||
|
|
||||||
namespace Cysharp.Threading.Tasks
|
|
||||||
{
|
|
||||||
|
|
||||||
public static partial class CancellationTokenSourceExtensions
|
|
||||||
{
|
|
||||||
readonly static Action<object> CancelCancellationTokenSourceStateDelegate = new Action<object>(CancelCancellationTokenSourceState);
|
|
||||||
|
|
||||||
static void CancelCancellationTokenSourceState(object state)
|
|
||||||
{
|
|
||||||
var cts = (CancellationTokenSource)state;
|
|
||||||
cts.Cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IDisposable CancelAfterSlim(this CancellationTokenSource cts, int millisecondsDelay, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update)
|
|
||||||
{
|
|
||||||
return CancelAfterSlim(cts, TimeSpan.FromMilliseconds(millisecondsDelay), delayType, delayTiming);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IDisposable CancelAfterSlim(this CancellationTokenSource cts, TimeSpan delayTimeSpan, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update)
|
|
||||||
{
|
|
||||||
return PlayerLoopTimer.StartNew(delayTimeSpan, false, delayType, delayTiming, cts.Token, CancelCancellationTokenSourceStateDelegate, cts);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void RegisterRaiseCancelOnDestroy(this CancellationTokenSource cts, Component component)
|
|
||||||
{
|
|
||||||
RegisterRaiseCancelOnDestroy(cts, component.gameObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void RegisterRaiseCancelOnDestroy(this CancellationTokenSource cts, GameObject gameObject)
|
|
||||||
{
|
|
||||||
var trigger = gameObject.GetAsyncDestroyTrigger();
|
|
||||||
trigger.CancellationToken.RegisterWithoutCaptureExecutionContext(CancelCancellationTokenSourceStateDelegate, cts);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 22d85d07f1e70ab42a7a4c25bd65e661
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,450 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Cysharp.Threading.Tasks
|
|
||||||
{
|
|
||||||
public static class Channel
|
|
||||||
{
|
|
||||||
public static Channel<T> CreateSingleConsumerUnbounded<T>()
|
|
||||||
{
|
|
||||||
return new SingleConsumerUnboundedChannel<T>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract class Channel<TWrite, TRead>
|
|
||||||
{
|
|
||||||
public ChannelReader<TRead> Reader { get; protected set; }
|
|
||||||
public ChannelWriter<TWrite> Writer { get; protected set; }
|
|
||||||
|
|
||||||
public static implicit operator ChannelReader<TRead>(Channel<TWrite, TRead> channel) => channel.Reader;
|
|
||||||
public static implicit operator ChannelWriter<TWrite>(Channel<TWrite, TRead> channel) => channel.Writer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract class Channel<T> : Channel<T, T>
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract class ChannelReader<T>
|
|
||||||
{
|
|
||||||
public abstract bool TryRead(out T item);
|
|
||||||
public abstract UniTask<bool> WaitToReadAsync(CancellationToken cancellationToken = default(CancellationToken));
|
|
||||||
|
|
||||||
public abstract UniTask Completion { get; }
|
|
||||||
|
|
||||||
public virtual UniTask<T> ReadAsync(CancellationToken cancellationToken = default(CancellationToken))
|
|
||||||
{
|
|
||||||
if (this.TryRead(out var item))
|
|
||||||
{
|
|
||||||
return UniTask.FromResult(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ReadAsyncCore(cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
async UniTask<T> ReadAsyncCore(CancellationToken cancellationToken = default(CancellationToken))
|
|
||||||
{
|
|
||||||
if (await WaitToReadAsync(cancellationToken))
|
|
||||||
{
|
|
||||||
if (TryRead(out var item))
|
|
||||||
{
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new ChannelClosedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract IUniTaskAsyncEnumerable<T> ReadAllAsync(CancellationToken cancellationToken = default(CancellationToken));
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract class ChannelWriter<T>
|
|
||||||
{
|
|
||||||
public abstract bool TryWrite(T item);
|
|
||||||
public abstract bool TryComplete(Exception error = null);
|
|
||||||
|
|
||||||
public void Complete(Exception error = null)
|
|
||||||
{
|
|
||||||
if (!TryComplete(error))
|
|
||||||
{
|
|
||||||
throw new ChannelClosedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public partial class ChannelClosedException : InvalidOperationException
|
|
||||||
{
|
|
||||||
public ChannelClosedException() :
|
|
||||||
base("Channel is already closed.")
|
|
||||||
{ }
|
|
||||||
|
|
||||||
public ChannelClosedException(string message) : base(message) { }
|
|
||||||
|
|
||||||
public ChannelClosedException(Exception innerException) :
|
|
||||||
base("Channel is already closed", innerException)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
public ChannelClosedException(string message, Exception innerException) : base(message, innerException) { }
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class SingleConsumerUnboundedChannel<T> : Channel<T>
|
|
||||||
{
|
|
||||||
readonly Queue<T> items;
|
|
||||||
readonly SingleConsumerUnboundedChannelReader readerSource;
|
|
||||||
UniTaskCompletionSource completedTaskSource;
|
|
||||||
UniTask completedTask;
|
|
||||||
|
|
||||||
Exception completionError;
|
|
||||||
bool closed;
|
|
||||||
|
|
||||||
public SingleConsumerUnboundedChannel()
|
|
||||||
{
|
|
||||||
items = new Queue<T>();
|
|
||||||
Writer = new SingleConsumerUnboundedChannelWriter(this);
|
|
||||||
readerSource = new SingleConsumerUnboundedChannelReader(this);
|
|
||||||
Reader = readerSource;
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class SingleConsumerUnboundedChannelWriter : ChannelWriter<T>
|
|
||||||
{
|
|
||||||
readonly SingleConsumerUnboundedChannel<T> parent;
|
|
||||||
|
|
||||||
public SingleConsumerUnboundedChannelWriter(SingleConsumerUnboundedChannel<T> parent)
|
|
||||||
{
|
|
||||||
this.parent = parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool TryWrite(T item)
|
|
||||||
{
|
|
||||||
bool waiting;
|
|
||||||
lock (parent.items)
|
|
||||||
{
|
|
||||||
if (parent.closed) return false;
|
|
||||||
|
|
||||||
parent.items.Enqueue(item);
|
|
||||||
waiting = parent.readerSource.isWaiting;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (waiting)
|
|
||||||
{
|
|
||||||
parent.readerSource.SingalContinuation();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool TryComplete(Exception error = null)
|
|
||||||
{
|
|
||||||
bool waiting;
|
|
||||||
lock (parent.items)
|
|
||||||
{
|
|
||||||
if (parent.closed) return false;
|
|
||||||
parent.closed = true;
|
|
||||||
waiting = parent.readerSource.isWaiting;
|
|
||||||
|
|
||||||
if (parent.items.Count == 0)
|
|
||||||
{
|
|
||||||
if (error == null)
|
|
||||||
{
|
|
||||||
if (parent.completedTaskSource != null)
|
|
||||||
{
|
|
||||||
parent.completedTaskSource.TrySetResult();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
parent.completedTask = UniTask.CompletedTask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (parent.completedTaskSource != null)
|
|
||||||
{
|
|
||||||
parent.completedTaskSource.TrySetException(error);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
parent.completedTask = UniTask.FromException(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (waiting)
|
|
||||||
{
|
|
||||||
parent.readerSource.SingalCompleted(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
parent.completionError = error;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class SingleConsumerUnboundedChannelReader : ChannelReader<T>, IUniTaskSource<bool>
|
|
||||||
{
|
|
||||||
readonly Action<object> CancellationCallbackDelegate = CancellationCallback;
|
|
||||||
readonly SingleConsumerUnboundedChannel<T> parent;
|
|
||||||
|
|
||||||
CancellationToken cancellationToken;
|
|
||||||
CancellationTokenRegistration cancellationTokenRegistration;
|
|
||||||
UniTaskCompletionSourceCore<bool> core;
|
|
||||||
internal bool isWaiting;
|
|
||||||
|
|
||||||
public SingleConsumerUnboundedChannelReader(SingleConsumerUnboundedChannel<T> parent)
|
|
||||||
{
|
|
||||||
this.parent = parent;
|
|
||||||
|
|
||||||
TaskTracker.TrackActiveTask(this, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override UniTask Completion
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (parent.completedTaskSource != null) return parent.completedTaskSource.Task;
|
|
||||||
|
|
||||||
if (parent.closed)
|
|
||||||
{
|
|
||||||
return parent.completedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
parent.completedTaskSource = new UniTaskCompletionSource();
|
|
||||||
return parent.completedTaskSource.Task;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool TryRead(out T item)
|
|
||||||
{
|
|
||||||
lock (parent.items)
|
|
||||||
{
|
|
||||||
if (parent.items.Count != 0)
|
|
||||||
{
|
|
||||||
item = parent.items.Dequeue();
|
|
||||||
|
|
||||||
// complete when all value was consumed.
|
|
||||||
if (parent.closed && parent.items.Count == 0)
|
|
||||||
{
|
|
||||||
if (parent.completionError != null)
|
|
||||||
{
|
|
||||||
if (parent.completedTaskSource != null)
|
|
||||||
{
|
|
||||||
parent.completedTaskSource.TrySetException(parent.completionError);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
parent.completedTask = UniTask.FromException(parent.completionError);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (parent.completedTaskSource != null)
|
|
||||||
{
|
|
||||||
parent.completedTaskSource.TrySetResult();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
parent.completedTask = UniTask.CompletedTask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
item = default;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override UniTask<bool> WaitToReadAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
if (cancellationToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
return UniTask.FromCanceled<bool>(cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
lock (parent.items)
|
|
||||||
{
|
|
||||||
if (parent.items.Count != 0)
|
|
||||||
{
|
|
||||||
return CompletedTasks.True;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parent.closed)
|
|
||||||
{
|
|
||||||
if (parent.completionError == null)
|
|
||||||
{
|
|
||||||
return CompletedTasks.False;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return UniTask.FromException<bool>(parent.completionError);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cancellationTokenRegistration.Dispose();
|
|
||||||
|
|
||||||
core.Reset();
|
|
||||||
isWaiting = true;
|
|
||||||
|
|
||||||
this.cancellationToken = cancellationToken;
|
|
||||||
if (this.cancellationToken.CanBeCanceled)
|
|
||||||
{
|
|
||||||
cancellationTokenRegistration = this.cancellationToken.RegisterWithoutCaptureExecutionContext(CancellationCallbackDelegate, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new UniTask<bool>(this, core.Version);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SingalContinuation()
|
|
||||||
{
|
|
||||||
core.TrySetResult(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SingalCancellation(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
TaskTracker.RemoveTracking(this);
|
|
||||||
core.TrySetCanceled(cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SingalCompleted(Exception error)
|
|
||||||
{
|
|
||||||
if (error != null)
|
|
||||||
{
|
|
||||||
TaskTracker.RemoveTracking(this);
|
|
||||||
core.TrySetException(error);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TaskTracker.RemoveTracking(this);
|
|
||||||
core.TrySetResult(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override IUniTaskAsyncEnumerable<T> ReadAllAsync(CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
return new ReadAllAsyncEnumerable(this, cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IUniTaskSource<bool>.GetResult(short token)
|
|
||||||
{
|
|
||||||
return core.GetResult(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IUniTaskSource.GetResult(short token)
|
|
||||||
{
|
|
||||||
core.GetResult(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
UniTaskStatus IUniTaskSource.GetStatus(short token)
|
|
||||||
{
|
|
||||||
return core.GetStatus(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IUniTaskSource.OnCompleted(Action<object> continuation, object state, short token)
|
|
||||||
{
|
|
||||||
core.OnCompleted(continuation, state, token);
|
|
||||||
}
|
|
||||||
|
|
||||||
UniTaskStatus IUniTaskSource.UnsafeGetStatus()
|
|
||||||
{
|
|
||||||
return core.UnsafeGetStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void CancellationCallback(object state)
|
|
||||||
{
|
|
||||||
var self = (SingleConsumerUnboundedChannelReader)state;
|
|
||||||
self.SingalCancellation(self.cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class ReadAllAsyncEnumerable : IUniTaskAsyncEnumerable<T>, IUniTaskAsyncEnumerator<T>
|
|
||||||
{
|
|
||||||
readonly Action<object> CancellationCallback1Delegate = CancellationCallback1;
|
|
||||||
readonly Action<object> CancellationCallback2Delegate = CancellationCallback2;
|
|
||||||
|
|
||||||
readonly SingleConsumerUnboundedChannelReader parent;
|
|
||||||
CancellationToken cancellationToken1;
|
|
||||||
CancellationToken cancellationToken2;
|
|
||||||
CancellationTokenRegistration cancellationTokenRegistration1;
|
|
||||||
CancellationTokenRegistration cancellationTokenRegistration2;
|
|
||||||
|
|
||||||
T current;
|
|
||||||
bool cacheValue;
|
|
||||||
bool running;
|
|
||||||
|
|
||||||
public ReadAllAsyncEnumerable(SingleConsumerUnboundedChannelReader parent, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
this.parent = parent;
|
|
||||||
this.cancellationToken1 = cancellationToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
if (running)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Enumerator is already running, does not allow call GetAsyncEnumerator twice.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.cancellationToken1 != cancellationToken)
|
|
||||||
{
|
|
||||||
this.cancellationToken2 = cancellationToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.cancellationToken1.CanBeCanceled)
|
|
||||||
{
|
|
||||||
this.cancellationTokenRegistration1 = this.cancellationToken1.RegisterWithoutCaptureExecutionContext(CancellationCallback1Delegate, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.cancellationToken2.CanBeCanceled)
|
|
||||||
{
|
|
||||||
this.cancellationTokenRegistration2 = this.cancellationToken2.RegisterWithoutCaptureExecutionContext(CancellationCallback2Delegate, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
running = true;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T Current
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (cacheValue)
|
|
||||||
{
|
|
||||||
return current;
|
|
||||||
}
|
|
||||||
parent.TryRead(out current);
|
|
||||||
return current;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public UniTask<bool> MoveNextAsync()
|
|
||||||
{
|
|
||||||
cacheValue = false;
|
|
||||||
return parent.WaitToReadAsync(CancellationToken.None); // ok to use None, registered in ctor.
|
|
||||||
}
|
|
||||||
|
|
||||||
public UniTask DisposeAsync()
|
|
||||||
{
|
|
||||||
cancellationTokenRegistration1.Dispose();
|
|
||||||
cancellationTokenRegistration2.Dispose();
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void CancellationCallback1(object state)
|
|
||||||
{
|
|
||||||
var self = (ReadAllAsyncEnumerable)state;
|
|
||||||
self.parent.SingalCancellation(self.cancellationToken1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void CancellationCallback2(object state)
|
|
||||||
{
|
|
||||||
var self = (ReadAllAsyncEnumerable)state;
|
|
||||||
self.parent.SingalCancellation(self.cancellationToken2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 5ceb3107bbdd1f14eb39091273798360
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
|
|
||||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
|
||||||
#pragma warning disable CS0436
|
|
||||||
|
|
||||||
namespace System.Runtime.CompilerServices
|
|
||||||
{
|
|
||||||
internal sealed class AsyncMethodBuilderAttribute : Attribute
|
|
||||||
{
|
|
||||||
public Type BuilderType { get; }
|
|
||||||
|
|
||||||
public AsyncMethodBuilderAttribute(Type builderType)
|
|
||||||
{
|
|
||||||
BuilderType = builderType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 02ce354d37b10454e8376062f7cbe57a
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,269 +0,0 @@
|
|||||||
|
|
||||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Security;
|
|
||||||
|
|
||||||
namespace Cysharp.Threading.Tasks.CompilerServices
|
|
||||||
{
|
|
||||||
[StructLayout(LayoutKind.Auto)]
|
|
||||||
public struct AsyncUniTaskMethodBuilder
|
|
||||||
{
|
|
||||||
IStateMachineRunnerPromise runnerPromise;
|
|
||||||
Exception ex;
|
|
||||||
|
|
||||||
// 1. Static Create method.
|
|
||||||
[DebuggerHidden]
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static AsyncUniTaskMethodBuilder Create()
|
|
||||||
{
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. TaskLike Task property.
|
|
||||||
public UniTask Task
|
|
||||||
{
|
|
||||||
[DebuggerHidden]
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (runnerPromise != null)
|
|
||||||
{
|
|
||||||
return runnerPromise.Task;
|
|
||||||
}
|
|
||||||
else if (ex != null)
|
|
||||||
{
|
|
||||||
return UniTask.FromException(ex);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return UniTask.CompletedTask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. SetException
|
|
||||||
[DebuggerHidden]
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void SetException(Exception exception)
|
|
||||||
{
|
|
||||||
if (runnerPromise == null)
|
|
||||||
{
|
|
||||||
ex = exception;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
runnerPromise.SetException(exception);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. SetResult
|
|
||||||
[DebuggerHidden]
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void SetResult()
|
|
||||||
{
|
|
||||||
if (runnerPromise != null)
|
|
||||||
{
|
|
||||||
runnerPromise.SetResult();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 5. AwaitOnCompleted
|
|
||||||
[DebuggerHidden]
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
|
|
||||||
where TAwaiter : INotifyCompletion
|
|
||||||
where TStateMachine : IAsyncStateMachine
|
|
||||||
{
|
|
||||||
if (runnerPromise == null)
|
|
||||||
{
|
|
||||||
AsyncUniTask<TStateMachine>.SetStateMachine(ref stateMachine, ref runnerPromise);
|
|
||||||
}
|
|
||||||
|
|
||||||
awaiter.OnCompleted(runnerPromise.MoveNext);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 6. AwaitUnsafeOnCompleted
|
|
||||||
[DebuggerHidden]
|
|
||||||
[SecuritySafeCritical]
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
|
|
||||||
where TAwaiter : ICriticalNotifyCompletion
|
|
||||||
where TStateMachine : IAsyncStateMachine
|
|
||||||
{
|
|
||||||
if (runnerPromise == null)
|
|
||||||
{
|
|
||||||
AsyncUniTask<TStateMachine>.SetStateMachine(ref stateMachine, ref runnerPromise);
|
|
||||||
}
|
|
||||||
|
|
||||||
awaiter.UnsafeOnCompleted(runnerPromise.MoveNext);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 7. Start
|
|
||||||
[DebuggerHidden]
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void Start<TStateMachine>(ref TStateMachine stateMachine)
|
|
||||||
where TStateMachine : IAsyncStateMachine
|
|
||||||
{
|
|
||||||
stateMachine.MoveNext();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 8. SetStateMachine
|
|
||||||
[DebuggerHidden]
|
|
||||||
public void SetStateMachine(IAsyncStateMachine stateMachine)
|
|
||||||
{
|
|
||||||
// don't use boxed stateMachine.
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DEBUG || !UNITY_2018_3_OR_NEWER
|
|
||||||
// Important for IDE debugger.
|
|
||||||
object debuggingId;
|
|
||||||
private object ObjectIdForDebugger
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (debuggingId == null)
|
|
||||||
{
|
|
||||||
debuggingId = new object();
|
|
||||||
}
|
|
||||||
return debuggingId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Auto)]
|
|
||||||
public struct AsyncUniTaskMethodBuilder<T>
|
|
||||||
{
|
|
||||||
IStateMachineRunnerPromise<T> runnerPromise;
|
|
||||||
Exception ex;
|
|
||||||
T result;
|
|
||||||
|
|
||||||
// 1. Static Create method.
|
|
||||||
[DebuggerHidden]
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static AsyncUniTaskMethodBuilder<T> Create()
|
|
||||||
{
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. TaskLike Task property.
|
|
||||||
public UniTask<T> Task
|
|
||||||
{
|
|
||||||
[DebuggerHidden]
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (runnerPromise != null)
|
|
||||||
{
|
|
||||||
return runnerPromise.Task;
|
|
||||||
}
|
|
||||||
else if (ex != null)
|
|
||||||
{
|
|
||||||
return UniTask.FromException<T>(ex);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return UniTask.FromResult(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. SetException
|
|
||||||
[DebuggerHidden]
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void SetException(Exception exception)
|
|
||||||
{
|
|
||||||
if (runnerPromise == null)
|
|
||||||
{
|
|
||||||
ex = exception;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
runnerPromise.SetException(exception);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. SetResult
|
|
||||||
[DebuggerHidden]
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void SetResult(T result)
|
|
||||||
{
|
|
||||||
if (runnerPromise == null)
|
|
||||||
{
|
|
||||||
this.result = result;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
runnerPromise.SetResult(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 5. AwaitOnCompleted
|
|
||||||
[DebuggerHidden]
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
|
|
||||||
where TAwaiter : INotifyCompletion
|
|
||||||
where TStateMachine : IAsyncStateMachine
|
|
||||||
{
|
|
||||||
if (runnerPromise == null)
|
|
||||||
{
|
|
||||||
AsyncUniTask<TStateMachine, T>.SetStateMachine(ref stateMachine, ref runnerPromise);
|
|
||||||
}
|
|
||||||
|
|
||||||
awaiter.OnCompleted(runnerPromise.MoveNext);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 6. AwaitUnsafeOnCompleted
|
|
||||||
[DebuggerHidden]
|
|
||||||
[SecuritySafeCritical]
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
|
|
||||||
where TAwaiter : ICriticalNotifyCompletion
|
|
||||||
where TStateMachine : IAsyncStateMachine
|
|
||||||
{
|
|
||||||
if (runnerPromise == null)
|
|
||||||
{
|
|
||||||
AsyncUniTask<TStateMachine, T>.SetStateMachine(ref stateMachine, ref runnerPromise);
|
|
||||||
}
|
|
||||||
|
|
||||||
awaiter.UnsafeOnCompleted(runnerPromise.MoveNext);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 7. Start
|
|
||||||
[DebuggerHidden]
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void Start<TStateMachine>(ref TStateMachine stateMachine)
|
|
||||||
where TStateMachine : IAsyncStateMachine
|
|
||||||
{
|
|
||||||
stateMachine.MoveNext();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 8. SetStateMachine
|
|
||||||
[DebuggerHidden]
|
|
||||||
public void SetStateMachine(IAsyncStateMachine stateMachine)
|
|
||||||
{
|
|
||||||
// don't use boxed stateMachine.
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DEBUG || !UNITY_2018_3_OR_NEWER
|
|
||||||
// Important for IDE debugger.
|
|
||||||
object debuggingId;
|
|
||||||
private object ObjectIdForDebugger
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (debuggingId == null)
|
|
||||||
{
|
|
||||||
debuggingId = new object();
|
|
||||||
}
|
|
||||||
return debuggingId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 68d72a45afdec574ebc26e7de2c38330
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,137 +0,0 @@
|
|||||||
|
|
||||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Security;
|
|
||||||
|
|
||||||
namespace Cysharp.Threading.Tasks.CompilerServices
|
|
||||||
{
|
|
||||||
[StructLayout(LayoutKind.Auto)]
|
|
||||||
public struct AsyncUniTaskVoidMethodBuilder
|
|
||||||
{
|
|
||||||
IStateMachineRunner runner;
|
|
||||||
|
|
||||||
// 1. Static Create method.
|
|
||||||
[DebuggerHidden]
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static AsyncUniTaskVoidMethodBuilder Create()
|
|
||||||
{
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. TaskLike Task property(void)
|
|
||||||
public UniTaskVoid Task
|
|
||||||
{
|
|
||||||
[DebuggerHidden]
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. SetException
|
|
||||||
[DebuggerHidden]
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void SetException(Exception exception)
|
|
||||||
{
|
|
||||||
// runner is finished, return first.
|
|
||||||
if (runner != null)
|
|
||||||
{
|
|
||||||
#if ENABLE_IL2CPP
|
|
||||||
// workaround for IL2CPP bug.
|
|
||||||
PlayerLoopHelper.AddContinuation(PlayerLoopTiming.LastPostLateUpdate, runner.ReturnAction);
|
|
||||||
#else
|
|
||||||
runner.Return();
|
|
||||||
#endif
|
|
||||||
runner = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
UniTaskScheduler.PublishUnobservedTaskException(exception);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. SetResult
|
|
||||||
[DebuggerHidden]
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void SetResult()
|
|
||||||
{
|
|
||||||
// runner is finished, return.
|
|
||||||
if (runner != null)
|
|
||||||
{
|
|
||||||
#if ENABLE_IL2CPP
|
|
||||||
// workaround for IL2CPP bug.
|
|
||||||
PlayerLoopHelper.AddContinuation(PlayerLoopTiming.LastPostLateUpdate, runner.ReturnAction);
|
|
||||||
#else
|
|
||||||
runner.Return();
|
|
||||||
#endif
|
|
||||||
runner = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 5. AwaitOnCompleted
|
|
||||||
[DebuggerHidden]
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
|
|
||||||
where TAwaiter : INotifyCompletion
|
|
||||||
where TStateMachine : IAsyncStateMachine
|
|
||||||
{
|
|
||||||
if (runner == null)
|
|
||||||
{
|
|
||||||
AsyncUniTaskVoid<TStateMachine>.SetStateMachine(ref stateMachine, ref runner);
|
|
||||||
}
|
|
||||||
|
|
||||||
awaiter.OnCompleted(runner.MoveNext);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 6. AwaitUnsafeOnCompleted
|
|
||||||
[DebuggerHidden]
|
|
||||||
[SecuritySafeCritical]
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
|
|
||||||
where TAwaiter : ICriticalNotifyCompletion
|
|
||||||
where TStateMachine : IAsyncStateMachine
|
|
||||||
{
|
|
||||||
if (runner == null)
|
|
||||||
{
|
|
||||||
AsyncUniTaskVoid<TStateMachine>.SetStateMachine(ref stateMachine, ref runner);
|
|
||||||
}
|
|
||||||
|
|
||||||
awaiter.UnsafeOnCompleted(runner.MoveNext);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 7. Start
|
|
||||||
[DebuggerHidden]
|
|
||||||
public void Start<TStateMachine>(ref TStateMachine stateMachine)
|
|
||||||
where TStateMachine : IAsyncStateMachine
|
|
||||||
{
|
|
||||||
stateMachine.MoveNext();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 8. SetStateMachine
|
|
||||||
[DebuggerHidden]
|
|
||||||
public void SetStateMachine(IAsyncStateMachine stateMachine)
|
|
||||||
{
|
|
||||||
// don't use boxed stateMachine.
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DEBUG || !UNITY_2018_3_OR_NEWER
|
|
||||||
// Important for IDE debugger.
|
|
||||||
object debuggingId;
|
|
||||||
private object ObjectIdForDebugger
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (debuggingId == null)
|
|
||||||
{
|
|
||||||
debuggingId = new object();
|
|
||||||
}
|
|
||||||
return debuggingId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: e891aaac17b933a47a9d7fa3b8e1226f
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,380 +0,0 @@
|
|||||||
#pragma warning disable CS1591
|
|
||||||
|
|
||||||
using Cysharp.Threading.Tasks.Internal;
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Cysharp.Threading.Tasks.CompilerServices
|
|
||||||
{
|
|
||||||
// #ENABLE_IL2CPP in this file is to avoid bug of IL2CPP VM.
|
|
||||||
// Issue is tracked on https://issuetracker.unity3d.com/issues/il2cpp-incorrect-results-when-calling-a-method-from-outside-class-in-a-struct
|
|
||||||
// but currently it is labeled `Won't Fix`.
|
|
||||||
|
|
||||||
internal interface IStateMachineRunner
|
|
||||||
{
|
|
||||||
Action MoveNext { get; }
|
|
||||||
void Return();
|
|
||||||
|
|
||||||
#if ENABLE_IL2CPP
|
|
||||||
Action ReturnAction { get; }
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
internal interface IStateMachineRunnerPromise : IUniTaskSource
|
|
||||||
{
|
|
||||||
Action MoveNext { get; }
|
|
||||||
UniTask Task { get; }
|
|
||||||
void SetResult();
|
|
||||||
void SetException(Exception exception);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal interface IStateMachineRunnerPromise<T> : IUniTaskSource<T>
|
|
||||||
{
|
|
||||||
Action MoveNext { get; }
|
|
||||||
UniTask<T> Task { get; }
|
|
||||||
void SetResult(T result);
|
|
||||||
void SetException(Exception exception);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static class StateMachineUtility
|
|
||||||
{
|
|
||||||
// Get AsyncStateMachine internal state to check IL2CPP bug
|
|
||||||
public static int GetState(IAsyncStateMachine stateMachine)
|
|
||||||
{
|
|
||||||
var info = stateMachine.GetType().GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
|
|
||||||
.First(x => x.Name.EndsWith("__state"));
|
|
||||||
return (int)info.GetValue(stateMachine);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal sealed class AsyncUniTaskVoid<TStateMachine> : IStateMachineRunner, ITaskPoolNode<AsyncUniTaskVoid<TStateMachine>>, IUniTaskSource
|
|
||||||
where TStateMachine : IAsyncStateMachine
|
|
||||||
{
|
|
||||||
static TaskPool<AsyncUniTaskVoid<TStateMachine>> pool;
|
|
||||||
|
|
||||||
#if ENABLE_IL2CPP
|
|
||||||
public Action ReturnAction { get; }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
TStateMachine stateMachine;
|
|
||||||
|
|
||||||
public Action MoveNext { get; }
|
|
||||||
|
|
||||||
public AsyncUniTaskVoid()
|
|
||||||
{
|
|
||||||
MoveNext = Run;
|
|
||||||
#if ENABLE_IL2CPP
|
|
||||||
ReturnAction = Return;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SetStateMachine(ref TStateMachine stateMachine, ref IStateMachineRunner runnerFieldRef)
|
|
||||||
{
|
|
||||||
if (!pool.TryPop(out var result))
|
|
||||||
{
|
|
||||||
result = new AsyncUniTaskVoid<TStateMachine>();
|
|
||||||
}
|
|
||||||
TaskTracker.TrackActiveTask(result, 3);
|
|
||||||
|
|
||||||
runnerFieldRef = result; // set runner before copied.
|
|
||||||
result.stateMachine = stateMachine; // copy struct StateMachine(in release build).
|
|
||||||
}
|
|
||||||
|
|
||||||
static AsyncUniTaskVoid()
|
|
||||||
{
|
|
||||||
TaskPool.RegisterSizeGetter(typeof(AsyncUniTaskVoid<TStateMachine>), () => pool.Size);
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncUniTaskVoid<TStateMachine> nextNode;
|
|
||||||
public ref AsyncUniTaskVoid<TStateMachine> NextNode => ref nextNode;
|
|
||||||
|
|
||||||
public void Return()
|
|
||||||
{
|
|
||||||
TaskTracker.RemoveTracking(this);
|
|
||||||
stateMachine = default;
|
|
||||||
pool.TryPush(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
[DebuggerHidden]
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
void Run()
|
|
||||||
{
|
|
||||||
stateMachine.MoveNext();
|
|
||||||
}
|
|
||||||
|
|
||||||
// dummy interface implementation for TaskTracker.
|
|
||||||
|
|
||||||
UniTaskStatus IUniTaskSource.GetStatus(short token)
|
|
||||||
{
|
|
||||||
return UniTaskStatus.Pending;
|
|
||||||
}
|
|
||||||
|
|
||||||
UniTaskStatus IUniTaskSource.UnsafeGetStatus()
|
|
||||||
{
|
|
||||||
return UniTaskStatus.Pending;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IUniTaskSource.OnCompleted(Action<object> continuation, object state, short token)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void IUniTaskSource.GetResult(short token)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal sealed class AsyncUniTask<TStateMachine> : IStateMachineRunnerPromise, IUniTaskSource, ITaskPoolNode<AsyncUniTask<TStateMachine>>
|
|
||||||
where TStateMachine : IAsyncStateMachine
|
|
||||||
{
|
|
||||||
static TaskPool<AsyncUniTask<TStateMachine>> pool;
|
|
||||||
|
|
||||||
#if ENABLE_IL2CPP
|
|
||||||
readonly Action returnDelegate;
|
|
||||||
#endif
|
|
||||||
public Action MoveNext { get; }
|
|
||||||
|
|
||||||
TStateMachine stateMachine;
|
|
||||||
UniTaskCompletionSourceCore<AsyncUnit> core;
|
|
||||||
|
|
||||||
AsyncUniTask()
|
|
||||||
{
|
|
||||||
MoveNext = Run;
|
|
||||||
#if ENABLE_IL2CPP
|
|
||||||
returnDelegate = Return;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SetStateMachine(ref TStateMachine stateMachine, ref IStateMachineRunnerPromise runnerPromiseFieldRef)
|
|
||||||
{
|
|
||||||
if (!pool.TryPop(out var result))
|
|
||||||
{
|
|
||||||
result = new AsyncUniTask<TStateMachine>();
|
|
||||||
}
|
|
||||||
TaskTracker.TrackActiveTask(result, 3);
|
|
||||||
|
|
||||||
runnerPromiseFieldRef = result; // set runner before copied.
|
|
||||||
result.stateMachine = stateMachine; // copy struct StateMachine(in release build).
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncUniTask<TStateMachine> nextNode;
|
|
||||||
public ref AsyncUniTask<TStateMachine> NextNode => ref nextNode;
|
|
||||||
|
|
||||||
static AsyncUniTask()
|
|
||||||
{
|
|
||||||
TaskPool.RegisterSizeGetter(typeof(AsyncUniTask<TStateMachine>), () => pool.Size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Return()
|
|
||||||
{
|
|
||||||
TaskTracker.RemoveTracking(this);
|
|
||||||
core.Reset();
|
|
||||||
stateMachine = default;
|
|
||||||
pool.TryPush(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TryReturn()
|
|
||||||
{
|
|
||||||
TaskTracker.RemoveTracking(this);
|
|
||||||
core.Reset();
|
|
||||||
stateMachine = default;
|
|
||||||
return pool.TryPush(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
[DebuggerHidden]
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
void Run()
|
|
||||||
{
|
|
||||||
stateMachine.MoveNext();
|
|
||||||
}
|
|
||||||
|
|
||||||
public UniTask Task
|
|
||||||
{
|
|
||||||
[DebuggerHidden]
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return new UniTask(this, core.Version);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[DebuggerHidden]
|
|
||||||
public void SetResult()
|
|
||||||
{
|
|
||||||
core.TrySetResult(AsyncUnit.Default);
|
|
||||||
}
|
|
||||||
|
|
||||||
[DebuggerHidden]
|
|
||||||
public void SetException(Exception exception)
|
|
||||||
{
|
|
||||||
core.TrySetException(exception);
|
|
||||||
}
|
|
||||||
|
|
||||||
[DebuggerHidden]
|
|
||||||
public void GetResult(short token)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
core.GetResult(token);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
#if ENABLE_IL2CPP
|
|
||||||
// workaround for IL2CPP bug.
|
|
||||||
PlayerLoopHelper.AddContinuation(PlayerLoopTiming.LastPostLateUpdate, returnDelegate);
|
|
||||||
#else
|
|
||||||
TryReturn();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[DebuggerHidden]
|
|
||||||
public UniTaskStatus GetStatus(short token)
|
|
||||||
{
|
|
||||||
return core.GetStatus(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
[DebuggerHidden]
|
|
||||||
public UniTaskStatus UnsafeGetStatus()
|
|
||||||
{
|
|
||||||
return core.UnsafeGetStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
[DebuggerHidden]
|
|
||||||
public void OnCompleted(Action<object> continuation, object state, short token)
|
|
||||||
{
|
|
||||||
core.OnCompleted(continuation, state, token);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal sealed class AsyncUniTask<TStateMachine, T> : IStateMachineRunnerPromise<T>, IUniTaskSource<T>, ITaskPoolNode<AsyncUniTask<TStateMachine, T>>
|
|
||||||
where TStateMachine : IAsyncStateMachine
|
|
||||||
{
|
|
||||||
static TaskPool<AsyncUniTask<TStateMachine, T>> pool;
|
|
||||||
|
|
||||||
#if ENABLE_IL2CPP
|
|
||||||
readonly Action returnDelegate;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
public Action MoveNext { get; }
|
|
||||||
|
|
||||||
TStateMachine stateMachine;
|
|
||||||
UniTaskCompletionSourceCore<T> core;
|
|
||||||
|
|
||||||
AsyncUniTask()
|
|
||||||
{
|
|
||||||
MoveNext = Run;
|
|
||||||
#if ENABLE_IL2CPP
|
|
||||||
returnDelegate = Return;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SetStateMachine(ref TStateMachine stateMachine, ref IStateMachineRunnerPromise<T> runnerPromiseFieldRef)
|
|
||||||
{
|
|
||||||
if (!pool.TryPop(out var result))
|
|
||||||
{
|
|
||||||
result = new AsyncUniTask<TStateMachine, T>();
|
|
||||||
}
|
|
||||||
TaskTracker.TrackActiveTask(result, 3);
|
|
||||||
|
|
||||||
runnerPromiseFieldRef = result; // set runner before copied.
|
|
||||||
result.stateMachine = stateMachine; // copy struct StateMachine(in release build).
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncUniTask<TStateMachine, T> nextNode;
|
|
||||||
public ref AsyncUniTask<TStateMachine, T> NextNode => ref nextNode;
|
|
||||||
|
|
||||||
static AsyncUniTask()
|
|
||||||
{
|
|
||||||
TaskPool.RegisterSizeGetter(typeof(AsyncUniTask<TStateMachine, T>), () => pool.Size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Return()
|
|
||||||
{
|
|
||||||
TaskTracker.RemoveTracking(this);
|
|
||||||
core.Reset();
|
|
||||||
stateMachine = default;
|
|
||||||
pool.TryPush(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TryReturn()
|
|
||||||
{
|
|
||||||
TaskTracker.RemoveTracking(this);
|
|
||||||
core.Reset();
|
|
||||||
stateMachine = default;
|
|
||||||
return pool.TryPush(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
[DebuggerHidden]
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
void Run()
|
|
||||||
{
|
|
||||||
// UnityEngine.Debug.Log($"MoveNext State:" + StateMachineUtility.GetState(stateMachine));
|
|
||||||
stateMachine.MoveNext();
|
|
||||||
}
|
|
||||||
|
|
||||||
public UniTask<T> Task
|
|
||||||
{
|
|
||||||
[DebuggerHidden]
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return new UniTask<T>(this, core.Version);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[DebuggerHidden]
|
|
||||||
public void SetResult(T result)
|
|
||||||
{
|
|
||||||
core.TrySetResult(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
[DebuggerHidden]
|
|
||||||
public void SetException(Exception exception)
|
|
||||||
{
|
|
||||||
core.TrySetException(exception);
|
|
||||||
}
|
|
||||||
|
|
||||||
[DebuggerHidden]
|
|
||||||
public T GetResult(short token)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return core.GetResult(token);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
#if ENABLE_IL2CPP
|
|
||||||
// workaround for IL2CPP bug.
|
|
||||||
PlayerLoopHelper.AddContinuation(PlayerLoopTiming.LastPostLateUpdate, returnDelegate);
|
|
||||||
#else
|
|
||||||
TryReturn();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[DebuggerHidden]
|
|
||||||
void IUniTaskSource.GetResult(short token)
|
|
||||||
{
|
|
||||||
GetResult(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
[DebuggerHidden]
|
|
||||||
public UniTaskStatus GetStatus(short token)
|
|
||||||
{
|
|
||||||
return core.GetStatus(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
[DebuggerHidden]
|
|
||||||
public UniTaskStatus UnsafeGetStatus()
|
|
||||||
{
|
|
||||||
return core.UnsafeGetStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
[DebuggerHidden]
|
|
||||||
public void OnCompleted(Action<object> continuation, object state, short token)
|
|
||||||
{
|
|
||||||
core.OnCompleted(continuation, state, token);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 98649642833cabf44a9dc060ce4c84a1
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Cysharp.Threading.Tasks
|
|
||||||
{
|
|
||||||
public static class EnumerableAsyncExtensions
|
|
||||||
{
|
|
||||||
// overload resolver - .Select(async x => { }) : IEnumerable<UniTask<T>>
|
|
||||||
|
|
||||||
public static IEnumerable<UniTask> Select<T>(this IEnumerable<T> source, Func<T, UniTask> selector)
|
|
||||||
{
|
|
||||||
return System.Linq.Enumerable.Select(source, selector);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<UniTask<TR>> Select<T, TR>(this IEnumerable<T> source, Func<T, UniTask<TR>> selector)
|
|
||||||
{
|
|
||||||
return System.Linq.Enumerable.Select(source, selector);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<UniTask> Select<T>(this IEnumerable<T> source, Func<T, int, UniTask> selector)
|
|
||||||
{
|
|
||||||
return System.Linq.Enumerable.Select(source, selector);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<UniTask<TR>> Select<T, TR>(this IEnumerable<T> source, Func<T, int, UniTask<TR>> selector)
|
|
||||||
{
|
|
||||||
return System.Linq.Enumerable.Select(source, selector);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: ff50260d74bd54c4b92cf99895549445
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,287 +0,0 @@
|
|||||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Runtime.ExceptionServices;
|
|
||||||
using System.Threading;
|
|
||||||
using Cysharp.Threading.Tasks.Internal;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace Cysharp.Threading.Tasks
|
|
||||||
{
|
|
||||||
public static class EnumeratorAsyncExtensions
|
|
||||||
{
|
|
||||||
public static UniTask.Awaiter GetAwaiter<T>(this T enumerator)
|
|
||||||
where T : IEnumerator
|
|
||||||
{
|
|
||||||
var e = (IEnumerator)enumerator;
|
|
||||||
Error.ThrowArgumentNullException(e, nameof(enumerator));
|
|
||||||
return new UniTask(EnumeratorPromise.Create(e, PlayerLoopTiming.Update, CancellationToken.None, out var token), token).GetAwaiter();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UniTask WithCancellation(this IEnumerator enumerator, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
Error.ThrowArgumentNullException(enumerator, nameof(enumerator));
|
|
||||||
return new UniTask(EnumeratorPromise.Create(enumerator, PlayerLoopTiming.Update, cancellationToken, out var token), token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UniTask ToUniTask(this IEnumerator enumerator, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
|
||||||
{
|
|
||||||
Error.ThrowArgumentNullException(enumerator, nameof(enumerator));
|
|
||||||
return new UniTask(EnumeratorPromise.Create(enumerator, timing, cancellationToken, out var token), token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UniTask ToUniTask(this IEnumerator enumerator, MonoBehaviour coroutineRunner)
|
|
||||||
{
|
|
||||||
var source = AutoResetUniTaskCompletionSource.Create();
|
|
||||||
coroutineRunner.StartCoroutine(Core(enumerator, coroutineRunner, source));
|
|
||||||
return source.Task;
|
|
||||||
}
|
|
||||||
|
|
||||||
static IEnumerator Core(IEnumerator inner, MonoBehaviour coroutineRunner, AutoResetUniTaskCompletionSource source)
|
|
||||||
{
|
|
||||||
yield return coroutineRunner.StartCoroutine(inner);
|
|
||||||
source.TrySetResult();
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class EnumeratorPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<EnumeratorPromise>
|
|
||||||
{
|
|
||||||
static TaskPool<EnumeratorPromise> pool;
|
|
||||||
EnumeratorPromise nextNode;
|
|
||||||
public ref EnumeratorPromise NextNode => ref nextNode;
|
|
||||||
|
|
||||||
static EnumeratorPromise()
|
|
||||||
{
|
|
||||||
TaskPool.RegisterSizeGetter(typeof(EnumeratorPromise), () => pool.Size);
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator innerEnumerator;
|
|
||||||
CancellationToken cancellationToken;
|
|
||||||
int initialFrame;
|
|
||||||
bool loopRunning;
|
|
||||||
bool calledGetResult;
|
|
||||||
|
|
||||||
UniTaskCompletionSourceCore<object> core;
|
|
||||||
|
|
||||||
EnumeratorPromise()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IUniTaskSource Create(IEnumerator innerEnumerator, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
|
|
||||||
{
|
|
||||||
if (cancellationToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!pool.TryPop(out var result))
|
|
||||||
{
|
|
||||||
result = new EnumeratorPromise();
|
|
||||||
}
|
|
||||||
TaskTracker.TrackActiveTask(result, 3);
|
|
||||||
|
|
||||||
result.innerEnumerator = ConsumeEnumerator(innerEnumerator);
|
|
||||||
result.cancellationToken = cancellationToken;
|
|
||||||
result.loopRunning = true;
|
|
||||||
result.calledGetResult = false;
|
|
||||||
result.initialFrame = -1;
|
|
||||||
|
|
||||||
token = result.core.Version;
|
|
||||||
|
|
||||||
// run immediately.
|
|
||||||
if (result.MoveNext())
|
|
||||||
{
|
|
||||||
PlayerLoopHelper.AddAction(timing, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void GetResult(short token)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
calledGetResult = true;
|
|
||||||
core.GetResult(token);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (!loopRunning)
|
|
||||||
{
|
|
||||||
TryReturn();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public UniTaskStatus GetStatus(short token)
|
|
||||||
{
|
|
||||||
return core.GetStatus(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UniTaskStatus UnsafeGetStatus()
|
|
||||||
{
|
|
||||||
return core.UnsafeGetStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnCompleted(Action<object> continuation, object state, short token)
|
|
||||||
{
|
|
||||||
core.OnCompleted(continuation, state, token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool MoveNext()
|
|
||||||
{
|
|
||||||
if (calledGetResult)
|
|
||||||
{
|
|
||||||
loopRunning = false;
|
|
||||||
TryReturn();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (innerEnumerator == null) // invalid status, returned but loop running?
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cancellationToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
loopRunning = false;
|
|
||||||
core.TrySetCanceled(cancellationToken);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (initialFrame == -1)
|
|
||||||
{
|
|
||||||
// Time can not touch in threadpool.
|
|
||||||
if (PlayerLoopHelper.IsMainThread)
|
|
||||||
{
|
|
||||||
initialFrame = Time.frameCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (initialFrame == Time.frameCount)
|
|
||||||
{
|
|
||||||
return true; // already executed in first frame, skip.
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (innerEnumerator.MoveNext())
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
loopRunning = false;
|
|
||||||
core.TrySetException(ex);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
loopRunning = false;
|
|
||||||
core.TrySetResult(null);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TryReturn()
|
|
||||||
{
|
|
||||||
TaskTracker.RemoveTracking(this);
|
|
||||||
core.Reset();
|
|
||||||
innerEnumerator = default;
|
|
||||||
cancellationToken = default;
|
|
||||||
|
|
||||||
return pool.TryPush(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unwrap YieldInstructions
|
|
||||||
|
|
||||||
static IEnumerator ConsumeEnumerator(IEnumerator enumerator)
|
|
||||||
{
|
|
||||||
while (enumerator.MoveNext())
|
|
||||||
{
|
|
||||||
var current = enumerator.Current;
|
|
||||||
if (current == null)
|
|
||||||
{
|
|
||||||
yield return null;
|
|
||||||
}
|
|
||||||
else if (current is CustomYieldInstruction cyi)
|
|
||||||
{
|
|
||||||
// WWW, WaitForSecondsRealtime
|
|
||||||
while (cyi.keepWaiting)
|
|
||||||
{
|
|
||||||
yield return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (current is YieldInstruction)
|
|
||||||
{
|
|
||||||
IEnumerator innerCoroutine = null;
|
|
||||||
switch (current)
|
|
||||||
{
|
|
||||||
case AsyncOperation ao:
|
|
||||||
innerCoroutine = UnwrapWaitAsyncOperation(ao);
|
|
||||||
break;
|
|
||||||
case WaitForSeconds wfs:
|
|
||||||
innerCoroutine = UnwrapWaitForSeconds(wfs);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (innerCoroutine != null)
|
|
||||||
{
|
|
||||||
while (innerCoroutine.MoveNext())
|
|
||||||
{
|
|
||||||
yield return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
goto WARN;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (current is IEnumerator e3)
|
|
||||||
{
|
|
||||||
var e4 = ConsumeEnumerator(e3);
|
|
||||||
while (e4.MoveNext())
|
|
||||||
{
|
|
||||||
yield return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
goto WARN;
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
|
|
||||||
WARN:
|
|
||||||
// WaitForEndOfFrame, WaitForFixedUpdate, others.
|
|
||||||
UnityEngine.Debug.LogWarning($"yield {current.GetType().Name} is not supported on await IEnumerator or IEnumerator.ToUniTask(), please use ToUniTask(MonoBehaviour coroutineRunner) instead.");
|
|
||||||
yield return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static readonly FieldInfo waitForSeconds_Seconds = typeof(WaitForSeconds).GetField("m_Seconds", BindingFlags.Instance | BindingFlags.GetField | BindingFlags.NonPublic);
|
|
||||||
|
|
||||||
static IEnumerator UnwrapWaitForSeconds(WaitForSeconds waitForSeconds)
|
|
||||||
{
|
|
||||||
var second = (float)waitForSeconds_Seconds.GetValue(waitForSeconds);
|
|
||||||
var elapsed = 0.0f;
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
yield return null;
|
|
||||||
|
|
||||||
elapsed += Time.deltaTime;
|
|
||||||
if (elapsed >= second)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
static IEnumerator UnwrapWaitAsyncOperation(AsyncOperation asyncOperation)
|
|
||||||
{
|
|
||||||
while (!asyncOperation.isDone)
|
|
||||||
{
|
|
||||||
yield return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: bc661232f11e4a741af54ba1c175d5ee
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Cysharp.Threading.Tasks
|
|
||||||
{
|
|
||||||
public static class ExceptionExtensions
|
|
||||||
{
|
|
||||||
public static bool IsOperationCanceledException(this Exception exception)
|
|
||||||
{
|
|
||||||
return exception is OperationCanceledException;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 930800098504c0d46958ce23a0495202
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: a3e874acee8398745b1dc3eddac09eaa
|
guid: a06b0036f802a1c48805344cdbdfff1f
|
||||||
folderAsset: yes
|
folderAsset: yes
|
||||||
DefaultImporter:
|
DefaultImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
|
|||||||
@@ -1,401 +0,0 @@
|
|||||||
// asmdef Version Defines, enabled when com.unity.addressables is imported.
|
|
||||||
|
|
||||||
#if UNITASK_ADDRESSABLE_SUPPORT
|
|
||||||
|
|
||||||
using Cysharp.Threading.Tasks.Internal;
|
|
||||||
using System;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.ExceptionServices;
|
|
||||||
using System.Threading;
|
|
||||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
|
||||||
|
|
||||||
namespace Cysharp.Threading.Tasks
|
|
||||||
{
|
|
||||||
public static class AddressablesAsyncExtensions
|
|
||||||
{
|
|
||||||
#region AsyncOperationHandle
|
|
||||||
|
|
||||||
public static UniTask.Awaiter GetAwaiter(this AsyncOperationHandle handle)
|
|
||||||
{
|
|
||||||
return ToUniTask(handle).GetAwaiter();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UniTask WithCancellation(this AsyncOperationHandle handle, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return ToUniTask(handle, cancellationToken: cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UniTask ToUniTask(this AsyncOperationHandle handle, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
|
||||||
{
|
|
||||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled(cancellationToken);
|
|
||||||
|
|
||||||
if (!handle.IsValid())
|
|
||||||
{
|
|
||||||
// autoReleaseHandle:true handle is invalid(immediately internal handle == null) so return completed.
|
|
||||||
return UniTask.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (handle.IsDone)
|
|
||||||
{
|
|
||||||
if (handle.Status == AsyncOperationStatus.Failed)
|
|
||||||
{
|
|
||||||
return UniTask.FromException(handle.OperationException);
|
|
||||||
}
|
|
||||||
return UniTask.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new UniTask(AsyncOperationHandleConfiguredSource.Create(handle, timing, progress, cancellationToken, out var token), token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public struct AsyncOperationHandleAwaiter : ICriticalNotifyCompletion
|
|
||||||
{
|
|
||||||
AsyncOperationHandle handle;
|
|
||||||
Action<AsyncOperationHandle> continuationAction;
|
|
||||||
|
|
||||||
public AsyncOperationHandleAwaiter(AsyncOperationHandle handle)
|
|
||||||
{
|
|
||||||
this.handle = handle;
|
|
||||||
this.continuationAction = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsCompleted => handle.IsDone;
|
|
||||||
|
|
||||||
public void GetResult()
|
|
||||||
{
|
|
||||||
if (continuationAction != null)
|
|
||||||
{
|
|
||||||
handle.Completed -= continuationAction;
|
|
||||||
continuationAction = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (handle.Status == AsyncOperationStatus.Failed)
|
|
||||||
{
|
|
||||||
var e = handle.OperationException;
|
|
||||||
handle = default;
|
|
||||||
ExceptionDispatchInfo.Capture(e).Throw();
|
|
||||||
}
|
|
||||||
|
|
||||||
var result = handle.Result;
|
|
||||||
handle = default;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnCompleted(Action continuation)
|
|
||||||
{
|
|
||||||
UnsafeOnCompleted(continuation);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UnsafeOnCompleted(Action continuation)
|
|
||||||
{
|
|
||||||
Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
|
|
||||||
continuationAction = PooledDelegate<AsyncOperationHandle>.Create(continuation);
|
|
||||||
handle.Completed += continuationAction;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class AsyncOperationHandleConfiguredSource : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<AsyncOperationHandleConfiguredSource>
|
|
||||||
{
|
|
||||||
static TaskPool<AsyncOperationHandleConfiguredSource> pool;
|
|
||||||
AsyncOperationHandleConfiguredSource nextNode;
|
|
||||||
public ref AsyncOperationHandleConfiguredSource NextNode => ref nextNode;
|
|
||||||
|
|
||||||
static AsyncOperationHandleConfiguredSource()
|
|
||||||
{
|
|
||||||
TaskPool.RegisterSizeGetter(typeof(AsyncOperationHandleConfiguredSource), () => pool.Size);
|
|
||||||
}
|
|
||||||
|
|
||||||
readonly Action<AsyncOperationHandle> continuationAction;
|
|
||||||
AsyncOperationHandle handle;
|
|
||||||
CancellationToken cancellationToken;
|
|
||||||
IProgress<float> progress;
|
|
||||||
bool completed;
|
|
||||||
|
|
||||||
UniTaskCompletionSourceCore<AsyncUnit> core;
|
|
||||||
|
|
||||||
AsyncOperationHandleConfiguredSource()
|
|
||||||
{
|
|
||||||
continuationAction = Continuation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IUniTaskSource Create(AsyncOperationHandle handle, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
|
|
||||||
{
|
|
||||||
if (cancellationToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!pool.TryPop(out var result))
|
|
||||||
{
|
|
||||||
result = new AsyncOperationHandleConfiguredSource();
|
|
||||||
}
|
|
||||||
|
|
||||||
result.handle = handle;
|
|
||||||
result.progress = progress;
|
|
||||||
result.cancellationToken = cancellationToken;
|
|
||||||
result.completed = false;
|
|
||||||
|
|
||||||
TaskTracker.TrackActiveTask(result, 3);
|
|
||||||
|
|
||||||
PlayerLoopHelper.AddAction(timing, result);
|
|
||||||
|
|
||||||
handle.Completed += result.continuationAction;
|
|
||||||
|
|
||||||
token = result.core.Version;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Continuation(AsyncOperationHandle _)
|
|
||||||
{
|
|
||||||
handle.Completed -= continuationAction;
|
|
||||||
|
|
||||||
if (completed)
|
|
||||||
{
|
|
||||||
TryReturn();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
completed = true;
|
|
||||||
if (cancellationToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
core.TrySetCanceled(cancellationToken);
|
|
||||||
}
|
|
||||||
else if (handle.Status == AsyncOperationStatus.Failed)
|
|
||||||
{
|
|
||||||
core.TrySetException(handle.OperationException);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
core.TrySetResult(AsyncUnit.Default);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void GetResult(short token)
|
|
||||||
{
|
|
||||||
core.GetResult(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UniTaskStatus GetStatus(short token)
|
|
||||||
{
|
|
||||||
return core.GetStatus(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UniTaskStatus UnsafeGetStatus()
|
|
||||||
{
|
|
||||||
return core.UnsafeGetStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnCompleted(Action<object> continuation, object state, short token)
|
|
||||||
{
|
|
||||||
core.OnCompleted(continuation, state, token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool MoveNext()
|
|
||||||
{
|
|
||||||
if (completed)
|
|
||||||
{
|
|
||||||
TryReturn();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cancellationToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
completed = true;
|
|
||||||
core.TrySetCanceled(cancellationToken);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (progress != null && handle.IsValid())
|
|
||||||
{
|
|
||||||
progress.Report(handle.PercentComplete);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TryReturn()
|
|
||||||
{
|
|
||||||
TaskTracker.RemoveTracking(this);
|
|
||||||
core.Reset();
|
|
||||||
handle = default;
|
|
||||||
progress = default;
|
|
||||||
cancellationToken = default;
|
|
||||||
return pool.TryPush(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region AsyncOperationHandle_T
|
|
||||||
|
|
||||||
public static UniTask<T>.Awaiter GetAwaiter<T>(this AsyncOperationHandle<T> handle)
|
|
||||||
{
|
|
||||||
return ToUniTask(handle).GetAwaiter();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UniTask<T> WithCancellation<T>(this AsyncOperationHandle<T> handle, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return ToUniTask(handle, cancellationToken: cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UniTask<T> ToUniTask<T>(this AsyncOperationHandle<T> handle, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
|
||||||
{
|
|
||||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<T>(cancellationToken);
|
|
||||||
|
|
||||||
if (!handle.IsValid())
|
|
||||||
{
|
|
||||||
throw new Exception("Attempting to use an invalid operation handle");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (handle.IsDone)
|
|
||||||
{
|
|
||||||
if (handle.Status == AsyncOperationStatus.Failed)
|
|
||||||
{
|
|
||||||
return UniTask.FromException<T>(handle.OperationException);
|
|
||||||
}
|
|
||||||
return UniTask.FromResult(handle.Result);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new UniTask<T>(AsyncOperationHandleConfiguredSource<T>.Create(handle, timing, progress, cancellationToken, out var token), token);
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class AsyncOperationHandleConfiguredSource<T> : IUniTaskSource<T>, IPlayerLoopItem, ITaskPoolNode<AsyncOperationHandleConfiguredSource<T>>
|
|
||||||
{
|
|
||||||
static TaskPool<AsyncOperationHandleConfiguredSource<T>> pool;
|
|
||||||
AsyncOperationHandleConfiguredSource<T> nextNode;
|
|
||||||
public ref AsyncOperationHandleConfiguredSource<T> NextNode => ref nextNode;
|
|
||||||
|
|
||||||
static AsyncOperationHandleConfiguredSource()
|
|
||||||
{
|
|
||||||
TaskPool.RegisterSizeGetter(typeof(AsyncOperationHandleConfiguredSource<T>), () => pool.Size);
|
|
||||||
}
|
|
||||||
|
|
||||||
readonly Action<AsyncOperationHandle<T>> continuationAction;
|
|
||||||
AsyncOperationHandle<T> handle;
|
|
||||||
CancellationToken cancellationToken;
|
|
||||||
IProgress<float> progress;
|
|
||||||
bool completed;
|
|
||||||
|
|
||||||
UniTaskCompletionSourceCore<T> core;
|
|
||||||
|
|
||||||
AsyncOperationHandleConfiguredSource()
|
|
||||||
{
|
|
||||||
continuationAction = Continuation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IUniTaskSource<T> Create(AsyncOperationHandle<T> handle, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
|
|
||||||
{
|
|
||||||
if (cancellationToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
return AutoResetUniTaskCompletionSource<T>.CreateFromCanceled(cancellationToken, out token);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!pool.TryPop(out var result))
|
|
||||||
{
|
|
||||||
result = new AsyncOperationHandleConfiguredSource<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
result.handle = handle;
|
|
||||||
result.cancellationToken = cancellationToken;
|
|
||||||
result.completed = false;
|
|
||||||
result.progress = progress;
|
|
||||||
|
|
||||||
TaskTracker.TrackActiveTask(result, 3);
|
|
||||||
|
|
||||||
PlayerLoopHelper.AddAction(timing, result);
|
|
||||||
|
|
||||||
handle.Completed += result.continuationAction;
|
|
||||||
|
|
||||||
token = result.core.Version;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Continuation(AsyncOperationHandle<T> argHandle)
|
|
||||||
{
|
|
||||||
handle.Completed -= continuationAction;
|
|
||||||
|
|
||||||
if (completed)
|
|
||||||
{
|
|
||||||
TryReturn();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
completed = true;
|
|
||||||
if (cancellationToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
core.TrySetCanceled(cancellationToken);
|
|
||||||
}
|
|
||||||
else if (argHandle.Status == AsyncOperationStatus.Failed)
|
|
||||||
{
|
|
||||||
core.TrySetException(argHandle.OperationException);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
core.TrySetResult(argHandle.Result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public T GetResult(short token)
|
|
||||||
{
|
|
||||||
return core.GetResult(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IUniTaskSource.GetResult(short token)
|
|
||||||
{
|
|
||||||
GetResult(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UniTaskStatus GetStatus(short token)
|
|
||||||
{
|
|
||||||
return core.GetStatus(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UniTaskStatus UnsafeGetStatus()
|
|
||||||
{
|
|
||||||
return core.UnsafeGetStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnCompleted(Action<object> continuation, object state, short token)
|
|
||||||
{
|
|
||||||
core.OnCompleted(continuation, state, token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool MoveNext()
|
|
||||||
{
|
|
||||||
if (completed)
|
|
||||||
{
|
|
||||||
TryReturn();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cancellationToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
completed = true;
|
|
||||||
core.TrySetCanceled(cancellationToken);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (progress != null && handle.IsValid())
|
|
||||||
{
|
|
||||||
progress.Report(handle.PercentComplete);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TryReturn()
|
|
||||||
{
|
|
||||||
TaskTracker.RemoveTracking(this);
|
|
||||||
core.Reset();
|
|
||||||
handle = default;
|
|
||||||
progress = default;
|
|
||||||
cancellationToken = default;
|
|
||||||
return pool.TryPush(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 3dc6441f9094f354b931dc3c79fb99e5
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "UniTask.Addressables",
|
|
||||||
"references": [
|
|
||||||
"UniTask",
|
|
||||||
"Unity.ResourceManager"
|
|
||||||
],
|
|
||||||
"includePlatforms": [],
|
|
||||||
"excludePlatforms": [],
|
|
||||||
"allowUnsafeCode": false,
|
|
||||||
"overrideReferences": false,
|
|
||||||
"precompiledReferences": [],
|
|
||||||
"autoReferenced": true,
|
|
||||||
"defineConstraints": [],
|
|
||||||
"versionDefines": [
|
|
||||||
{
|
|
||||||
"name": "com.unity.addressables",
|
|
||||||
"expression": "",
|
|
||||||
"define": "UNITASK_ADDRESSABLE_SUPPORT"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"noEngineReferences": false
|
|
||||||
}
|
|
||||||
@@ -1,470 +0,0 @@
|
|||||||
// asmdef Version Defines, enabled when com.demigiant.dotween is imported.
|
|
||||||
|
|
||||||
#if UNITASK_DOTWEEN_SUPPORT
|
|
||||||
|
|
||||||
using Cysharp.Threading.Tasks.Internal;
|
|
||||||
using DG.Tweening;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Cysharp.Threading.Tasks
|
|
||||||
{
|
|
||||||
public enum TweenCancelBehaviour
|
|
||||||
{
|
|
||||||
Kill,
|
|
||||||
KillWithCompleteCallback,
|
|
||||||
Complete,
|
|
||||||
CompleteWithSequenceCallback,
|
|
||||||
CancelAwait,
|
|
||||||
|
|
||||||
// AndCancelAwait
|
|
||||||
KillAndCancelAwait,
|
|
||||||
KillWithCompleteCallbackAndCancelAwait,
|
|
||||||
CompleteAndCancelAwait,
|
|
||||||
CompleteWithSequenceCallbackAndCancelAwait
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class DOTweenAsyncExtensions
|
|
||||||
{
|
|
||||||
enum CallbackType
|
|
||||||
{
|
|
||||||
Kill,
|
|
||||||
Complete,
|
|
||||||
Pause,
|
|
||||||
Play,
|
|
||||||
Rewind,
|
|
||||||
StepComplete
|
|
||||||
}
|
|
||||||
|
|
||||||
public static TweenAwaiter GetAwaiter(this Tween tween)
|
|
||||||
{
|
|
||||||
return new TweenAwaiter(tween);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UniTask WithCancellation(this Tween tween, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
Error.ThrowArgumentNullException(tween, nameof(tween));
|
|
||||||
|
|
||||||
if (!tween.IsActive()) return UniTask.CompletedTask;
|
|
||||||
return new UniTask(TweenConfiguredSource.Create(tween, TweenCancelBehaviour.Kill, cancellationToken, CallbackType.Kill, out var token), token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UniTask ToUniTask(this Tween tween, TweenCancelBehaviour tweenCancelBehaviour = TweenCancelBehaviour.Kill, CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
Error.ThrowArgumentNullException(tween, nameof(tween));
|
|
||||||
|
|
||||||
if (!tween.IsActive()) return UniTask.CompletedTask;
|
|
||||||
return new UniTask(TweenConfiguredSource.Create(tween, tweenCancelBehaviour, cancellationToken, CallbackType.Kill, out var token), token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UniTask AwaitForComplete(this Tween tween, TweenCancelBehaviour tweenCancelBehaviour = TweenCancelBehaviour.Kill, CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
Error.ThrowArgumentNullException(tween, nameof(tween));
|
|
||||||
|
|
||||||
if (!tween.IsActive()) return UniTask.CompletedTask;
|
|
||||||
return new UniTask(TweenConfiguredSource.Create(tween, tweenCancelBehaviour, cancellationToken, CallbackType.Complete, out var token), token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UniTask AwaitForPause(this Tween tween, TweenCancelBehaviour tweenCancelBehaviour = TweenCancelBehaviour.Kill, CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
Error.ThrowArgumentNullException(tween, nameof(tween));
|
|
||||||
|
|
||||||
if (!tween.IsActive()) return UniTask.CompletedTask;
|
|
||||||
return new UniTask(TweenConfiguredSource.Create(tween, tweenCancelBehaviour, cancellationToken, CallbackType.Pause, out var token), token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UniTask AwaitForPlay(this Tween tween, TweenCancelBehaviour tweenCancelBehaviour = TweenCancelBehaviour.Kill, CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
Error.ThrowArgumentNullException(tween, nameof(tween));
|
|
||||||
|
|
||||||
if (!tween.IsActive()) return UniTask.CompletedTask;
|
|
||||||
return new UniTask(TweenConfiguredSource.Create(tween, tweenCancelBehaviour, cancellationToken, CallbackType.Play, out var token), token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UniTask AwaitForRewind(this Tween tween, TweenCancelBehaviour tweenCancelBehaviour = TweenCancelBehaviour.Kill, CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
Error.ThrowArgumentNullException(tween, nameof(tween));
|
|
||||||
|
|
||||||
if (!tween.IsActive()) return UniTask.CompletedTask;
|
|
||||||
return new UniTask(TweenConfiguredSource.Create(tween, tweenCancelBehaviour, cancellationToken, CallbackType.Rewind, out var token), token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UniTask AwaitForStepComplete(this Tween tween, TweenCancelBehaviour tweenCancelBehaviour = TweenCancelBehaviour.Kill, CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
Error.ThrowArgumentNullException(tween, nameof(tween));
|
|
||||||
|
|
||||||
if (!tween.IsActive()) return UniTask.CompletedTask;
|
|
||||||
return new UniTask(TweenConfiguredSource.Create(tween, tweenCancelBehaviour, cancellationToken, CallbackType.StepComplete, out var token), token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public struct TweenAwaiter : ICriticalNotifyCompletion
|
|
||||||
{
|
|
||||||
readonly Tween tween;
|
|
||||||
|
|
||||||
// killed(non active) as completed.
|
|
||||||
public bool IsCompleted => !tween.IsActive();
|
|
||||||
|
|
||||||
public TweenAwaiter(Tween tween)
|
|
||||||
{
|
|
||||||
this.tween = tween;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TweenAwaiter GetAwaiter()
|
|
||||||
{
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void GetResult()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnCompleted(System.Action continuation)
|
|
||||||
{
|
|
||||||
UnsafeOnCompleted(continuation);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UnsafeOnCompleted(System.Action continuation)
|
|
||||||
{
|
|
||||||
// onKill is called after OnCompleted, both Complete(false/true) and Kill(false/true).
|
|
||||||
tween.onKill = PooledTweenCallback.Create(continuation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class TweenConfiguredSource : IUniTaskSource, ITaskPoolNode<TweenConfiguredSource>
|
|
||||||
{
|
|
||||||
static TaskPool<TweenConfiguredSource> pool;
|
|
||||||
TweenConfiguredSource nextNode;
|
|
||||||
public ref TweenConfiguredSource NextNode => ref nextNode;
|
|
||||||
|
|
||||||
static TweenConfiguredSource()
|
|
||||||
{
|
|
||||||
TaskPool.RegisterSizeGetter(typeof(TweenConfiguredSource), () => pool.Size);
|
|
||||||
}
|
|
||||||
|
|
||||||
readonly TweenCallback onCompleteCallbackDelegate;
|
|
||||||
readonly TweenCallback onUpdateDelegate;
|
|
||||||
|
|
||||||
Tween tween;
|
|
||||||
TweenCancelBehaviour cancelBehaviour;
|
|
||||||
CancellationToken cancellationToken;
|
|
||||||
CallbackType callbackType;
|
|
||||||
bool canceled;
|
|
||||||
|
|
||||||
TweenCallback originalUpdateAction;
|
|
||||||
TweenCallback originalCompleteAction;
|
|
||||||
UniTaskCompletionSourceCore<AsyncUnit> core;
|
|
||||||
|
|
||||||
TweenConfiguredSource()
|
|
||||||
{
|
|
||||||
onCompleteCallbackDelegate = OnCompleteCallbackDelegate;
|
|
||||||
onUpdateDelegate = OnUpdate;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IUniTaskSource Create(Tween tween, TweenCancelBehaviour cancelBehaviour, CancellationToken cancellationToken, CallbackType callbackType, out short token)
|
|
||||||
{
|
|
||||||
if (cancellationToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
DoCancelBeforeCreate(tween, cancelBehaviour);
|
|
||||||
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!pool.TryPop(out var result))
|
|
||||||
{
|
|
||||||
result = new TweenConfiguredSource();
|
|
||||||
}
|
|
||||||
|
|
||||||
result.tween = tween;
|
|
||||||
result.cancelBehaviour = cancelBehaviour;
|
|
||||||
result.cancellationToken = cancellationToken;
|
|
||||||
result.callbackType = callbackType;
|
|
||||||
|
|
||||||
result.originalUpdateAction = tween.onUpdate;
|
|
||||||
result.canceled = false;
|
|
||||||
|
|
||||||
if (result.originalUpdateAction == result.onUpdateDelegate)
|
|
||||||
{
|
|
||||||
result.originalUpdateAction = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
tween.onUpdate = result.onUpdateDelegate;
|
|
||||||
|
|
||||||
switch (callbackType)
|
|
||||||
{
|
|
||||||
case CallbackType.Kill:
|
|
||||||
result.originalCompleteAction = tween.onKill;
|
|
||||||
tween.onKill = result.onCompleteCallbackDelegate;
|
|
||||||
break;
|
|
||||||
case CallbackType.Complete:
|
|
||||||
result.originalCompleteAction = tween.onComplete;
|
|
||||||
tween.onComplete = result.onCompleteCallbackDelegate;
|
|
||||||
break;
|
|
||||||
case CallbackType.Pause:
|
|
||||||
result.originalCompleteAction = tween.onPause;
|
|
||||||
tween.onPause = result.onCompleteCallbackDelegate;
|
|
||||||
break;
|
|
||||||
case CallbackType.Play:
|
|
||||||
result.originalCompleteAction = tween.onPlay;
|
|
||||||
tween.onPlay = result.onCompleteCallbackDelegate;
|
|
||||||
break;
|
|
||||||
case CallbackType.Rewind:
|
|
||||||
result.originalCompleteAction = tween.onRewind;
|
|
||||||
tween.onRewind = result.onCompleteCallbackDelegate;
|
|
||||||
break;
|
|
||||||
case CallbackType.StepComplete:
|
|
||||||
result.originalCompleteAction = tween.onStepComplete;
|
|
||||||
tween.onStepComplete = result.onCompleteCallbackDelegate;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result.originalCompleteAction == result.onCompleteCallbackDelegate)
|
|
||||||
{
|
|
||||||
result.originalCompleteAction = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
TaskTracker.TrackActiveTask(result, 3);
|
|
||||||
|
|
||||||
token = result.core.Version;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnCompleteCallbackDelegate()
|
|
||||||
{
|
|
||||||
if (cancellationToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
if (this.cancelBehaviour == TweenCancelBehaviour.KillAndCancelAwait
|
|
||||||
|| this.cancelBehaviour == TweenCancelBehaviour.KillWithCompleteCallbackAndCancelAwait
|
|
||||||
|| this.cancelBehaviour == TweenCancelBehaviour.CompleteAndCancelAwait
|
|
||||||
|| this.cancelBehaviour == TweenCancelBehaviour.CompleteWithSequenceCallbackAndCancelAwait
|
|
||||||
|| this.cancelBehaviour == TweenCancelBehaviour.CancelAwait)
|
|
||||||
{
|
|
||||||
canceled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (canceled)
|
|
||||||
{
|
|
||||||
core.TrySetCanceled(cancellationToken);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
originalCompleteAction?.Invoke();
|
|
||||||
core.TrySetResult(AsyncUnit.Default);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnUpdate()
|
|
||||||
{
|
|
||||||
originalUpdateAction?.Invoke();
|
|
||||||
|
|
||||||
if (!cancellationToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (this.cancelBehaviour)
|
|
||||||
{
|
|
||||||
case TweenCancelBehaviour.Kill:
|
|
||||||
default:
|
|
||||||
this.tween.Kill(false);
|
|
||||||
break;
|
|
||||||
case TweenCancelBehaviour.KillAndCancelAwait:
|
|
||||||
this.canceled = true;
|
|
||||||
this.tween.Kill(false);
|
|
||||||
break;
|
|
||||||
case TweenCancelBehaviour.KillWithCompleteCallback:
|
|
||||||
this.tween.Kill(true);
|
|
||||||
break;
|
|
||||||
case TweenCancelBehaviour.KillWithCompleteCallbackAndCancelAwait:
|
|
||||||
this.canceled = true;
|
|
||||||
this.tween.Kill(true);
|
|
||||||
break;
|
|
||||||
case TweenCancelBehaviour.Complete:
|
|
||||||
this.tween.Complete(false);
|
|
||||||
break;
|
|
||||||
case TweenCancelBehaviour.CompleteAndCancelAwait:
|
|
||||||
this.canceled = true;
|
|
||||||
this.tween.Complete(false);
|
|
||||||
break;
|
|
||||||
case TweenCancelBehaviour.CompleteWithSequenceCallback:
|
|
||||||
this.tween.Complete(true);
|
|
||||||
break;
|
|
||||||
case TweenCancelBehaviour.CompleteWithSequenceCallbackAndCancelAwait:
|
|
||||||
this.canceled = true;
|
|
||||||
this.tween.Complete(true);
|
|
||||||
break;
|
|
||||||
case TweenCancelBehaviour.CancelAwait:
|
|
||||||
// restore to original callback
|
|
||||||
switch (callbackType)
|
|
||||||
{
|
|
||||||
case CallbackType.Kill:
|
|
||||||
tween.onKill = originalCompleteAction;
|
|
||||||
break;
|
|
||||||
case CallbackType.Complete:
|
|
||||||
tween.onComplete = originalCompleteAction;
|
|
||||||
break;
|
|
||||||
case CallbackType.Pause:
|
|
||||||
tween.onPause = originalCompleteAction;
|
|
||||||
break;
|
|
||||||
case CallbackType.Play:
|
|
||||||
tween.onPlay = originalCompleteAction;
|
|
||||||
break;
|
|
||||||
case CallbackType.Rewind:
|
|
||||||
tween.onRewind = originalCompleteAction;
|
|
||||||
break;
|
|
||||||
case CallbackType.StepComplete:
|
|
||||||
tween.onStepComplete = originalCompleteAction;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.core.TrySetCanceled(this.cancellationToken);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void DoCancelBeforeCreate(Tween tween, TweenCancelBehaviour tweenCancelBehaviour)
|
|
||||||
{
|
|
||||||
|
|
||||||
switch (tweenCancelBehaviour)
|
|
||||||
{
|
|
||||||
case TweenCancelBehaviour.Kill:
|
|
||||||
default:
|
|
||||||
tween.Kill(false);
|
|
||||||
break;
|
|
||||||
case TweenCancelBehaviour.KillAndCancelAwait:
|
|
||||||
tween.Kill(false);
|
|
||||||
break;
|
|
||||||
case TweenCancelBehaviour.KillWithCompleteCallback:
|
|
||||||
tween.Kill(true);
|
|
||||||
break;
|
|
||||||
case TweenCancelBehaviour.KillWithCompleteCallbackAndCancelAwait:
|
|
||||||
tween.Kill(true);
|
|
||||||
break;
|
|
||||||
case TweenCancelBehaviour.Complete:
|
|
||||||
tween.Complete(false);
|
|
||||||
break;
|
|
||||||
case TweenCancelBehaviour.CompleteAndCancelAwait:
|
|
||||||
tween.Complete(false);
|
|
||||||
break;
|
|
||||||
case TweenCancelBehaviour.CompleteWithSequenceCallback:
|
|
||||||
tween.Complete(true);
|
|
||||||
break;
|
|
||||||
case TweenCancelBehaviour.CompleteWithSequenceCallbackAndCancelAwait:
|
|
||||||
tween.Complete(true);
|
|
||||||
break;
|
|
||||||
case TweenCancelBehaviour.CancelAwait:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void GetResult(short token)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
core.GetResult(token);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
TryReturn();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public UniTaskStatus GetStatus(short token)
|
|
||||||
{
|
|
||||||
return core.GetStatus(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UniTaskStatus UnsafeGetStatus()
|
|
||||||
{
|
|
||||||
return core.UnsafeGetStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnCompleted(Action<object> continuation, object state, short token)
|
|
||||||
{
|
|
||||||
core.OnCompleted(continuation, state, token);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TryReturn()
|
|
||||||
{
|
|
||||||
TaskTracker.RemoveTracking(this);
|
|
||||||
core.Reset();
|
|
||||||
tween.onUpdate = originalUpdateAction;
|
|
||||||
|
|
||||||
switch (callbackType)
|
|
||||||
{
|
|
||||||
case CallbackType.Kill:
|
|
||||||
tween.onKill = originalCompleteAction;
|
|
||||||
break;
|
|
||||||
case CallbackType.Complete:
|
|
||||||
tween.onComplete = originalCompleteAction;
|
|
||||||
break;
|
|
||||||
case CallbackType.Pause:
|
|
||||||
tween.onPause = originalCompleteAction;
|
|
||||||
break;
|
|
||||||
case CallbackType.Play:
|
|
||||||
tween.onPlay = originalCompleteAction;
|
|
||||||
break;
|
|
||||||
case CallbackType.Rewind:
|
|
||||||
tween.onRewind = originalCompleteAction;
|
|
||||||
break;
|
|
||||||
case CallbackType.StepComplete:
|
|
||||||
tween.onStepComplete = originalCompleteAction;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
tween = default;
|
|
||||||
cancellationToken = default;
|
|
||||||
originalUpdateAction = default;
|
|
||||||
originalCompleteAction = default;
|
|
||||||
return pool.TryPush(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class PooledTweenCallback
|
|
||||||
{
|
|
||||||
static readonly ConcurrentQueue<PooledTweenCallback> pool = new ConcurrentQueue<PooledTweenCallback>();
|
|
||||||
|
|
||||||
readonly TweenCallback runDelegate;
|
|
||||||
|
|
||||||
Action continuation;
|
|
||||||
|
|
||||||
|
|
||||||
PooledTweenCallback()
|
|
||||||
{
|
|
||||||
runDelegate = Run;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static TweenCallback Create(Action continuation)
|
|
||||||
{
|
|
||||||
if (!pool.TryDequeue(out var item))
|
|
||||||
{
|
|
||||||
item = new PooledTweenCallback();
|
|
||||||
}
|
|
||||||
|
|
||||||
item.continuation = continuation;
|
|
||||||
return item.runDelegate;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
void Run()
|
|
||||||
{
|
|
||||||
var call = continuation;
|
|
||||||
continuation = null;
|
|
||||||
if (call != null)
|
|
||||||
{
|
|
||||||
pool.Enqueue(this);
|
|
||||||
call.Invoke();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 1f448d5bc5b232e4f98d89d5d1832e8e
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 029c1c1b674aaae47a6841a0b89ad80e
|
|
||||||
AssemblyDefinitionImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: f89da606bde9a4e4e94ae1189a029887
|
|
||||||
folderAsset: yes
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,224 +0,0 @@
|
|||||||
#if UNITASK_TEXTMESHPRO_SUPPORT
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Threading;
|
|
||||||
using TMPro;
|
|
||||||
|
|
||||||
namespace Cysharp.Threading.Tasks
|
|
||||||
{
|
|
||||||
public static partial class TextMeshProAsyncExtensions
|
|
||||||
{
|
|
||||||
public static IAsyncValueChangedEventHandler<string> GetAsyncValueChangedEventHandler(this TMP_InputField inputField)
|
|
||||||
{
|
|
||||||
return new AsyncUnityEventHandler<string>(inputField.onValueChanged, inputField.GetCancellationTokenOnDestroy(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IAsyncValueChangedEventHandler<string> GetAsyncValueChangedEventHandler(this TMP_InputField inputField, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return new AsyncUnityEventHandler<string>(inputField.onValueChanged, cancellationToken, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UniTask<string> OnValueChangedAsync(this TMP_InputField inputField)
|
|
||||||
{
|
|
||||||
return new AsyncUnityEventHandler<string>(inputField.onValueChanged, inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UniTask<string> OnValueChangedAsync(this TMP_InputField inputField, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return new AsyncUnityEventHandler<string>(inputField.onValueChanged, cancellationToken, true).OnInvokeAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IUniTaskAsyncEnumerable<string> OnValueChangedAsAsyncEnumerable(this TMP_InputField inputField)
|
|
||||||
{
|
|
||||||
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onValueChanged, inputField.GetCancellationTokenOnDestroy());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IUniTaskAsyncEnumerable<string> OnValueChangedAsAsyncEnumerable(this TMP_InputField inputField, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onValueChanged, cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IAsyncEndEditEventHandler<string> GetAsyncEndEditEventHandler(this TMP_InputField inputField)
|
|
||||||
{
|
|
||||||
return new AsyncUnityEventHandler<string>(inputField.onEndEdit, inputField.GetCancellationTokenOnDestroy(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IAsyncEndEditEventHandler<string> GetAsyncEndEditEventHandler(this TMP_InputField inputField, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return new AsyncUnityEventHandler<string>(inputField.onEndEdit, cancellationToken, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UniTask<string> OnEndEditAsync(this TMP_InputField inputField)
|
|
||||||
{
|
|
||||||
return new AsyncUnityEventHandler<string>(inputField.onEndEdit, inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UniTask<string> OnEndEditAsync(this TMP_InputField inputField, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return new AsyncUnityEventHandler<string>(inputField.onEndEdit, cancellationToken, true).OnInvokeAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IUniTaskAsyncEnumerable<string> OnEndEditAsAsyncEnumerable(this TMP_InputField inputField)
|
|
||||||
{
|
|
||||||
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onEndEdit, inputField.GetCancellationTokenOnDestroy());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IUniTaskAsyncEnumerable<string> OnEndEditAsAsyncEnumerable(this TMP_InputField inputField, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onEndEdit, cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IAsyncEndTextSelectionEventHandler<(string, int, int)> GetAsyncEndTextSelectionEventHandler(this TMP_InputField inputField)
|
|
||||||
{
|
|
||||||
return new AsyncUnityEventHandler<(string, int, int)>(new TextSelectionEventConverter(inputField.onEndTextSelection), inputField.GetCancellationTokenOnDestroy(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IAsyncEndTextSelectionEventHandler<(string, int, int)> GetAsyncEndTextSelectionEventHandler(this TMP_InputField inputField, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return new AsyncUnityEventHandler<(string, int, int)>(new TextSelectionEventConverter(inputField.onEndTextSelection), cancellationToken, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UniTask<(string, int, int)> OnEndTextSelectionAsync(this TMP_InputField inputField)
|
|
||||||
{
|
|
||||||
return new AsyncUnityEventHandler<(string, int, int)>(new TextSelectionEventConverter(inputField.onEndTextSelection), inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UniTask<(string, int, int)> OnEndTextSelectionAsync(this TMP_InputField inputField, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return new AsyncUnityEventHandler<(string, int, int)>(new TextSelectionEventConverter(inputField.onEndTextSelection), cancellationToken, true).OnInvokeAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IUniTaskAsyncEnumerable<(string, int, int)> OnEndTextSelectionAsAsyncEnumerable(this TMP_InputField inputField)
|
|
||||||
{
|
|
||||||
return new UnityEventHandlerAsyncEnumerable<(string, int, int)>(new TextSelectionEventConverter(inputField.onEndTextSelection), inputField.GetCancellationTokenOnDestroy());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IUniTaskAsyncEnumerable<(string, int, int)> OnEndTextSelectionAsAsyncEnumerable(this TMP_InputField inputField, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return new UnityEventHandlerAsyncEnumerable<(string, int, int)>(new TextSelectionEventConverter(inputField.onEndTextSelection), cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IAsyncTextSelectionEventHandler<(string, int, int)> GetAsyncTextSelectionEventHandler(this TMP_InputField inputField)
|
|
||||||
{
|
|
||||||
return new AsyncUnityEventHandler<(string, int, int)>(new TextSelectionEventConverter(inputField.onTextSelection), inputField.GetCancellationTokenOnDestroy(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IAsyncTextSelectionEventHandler<(string, int, int)> GetAsyncTextSelectionEventHandler(this TMP_InputField inputField, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return new AsyncUnityEventHandler<(string, int, int)>(new TextSelectionEventConverter(inputField.onTextSelection), cancellationToken, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UniTask<(string, int, int)> OnTextSelectionAsync(this TMP_InputField inputField)
|
|
||||||
{
|
|
||||||
return new AsyncUnityEventHandler<(string, int, int)>(new TextSelectionEventConverter(inputField.onTextSelection), inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UniTask<(string, int, int)> OnTextSelectionAsync(this TMP_InputField inputField, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return new AsyncUnityEventHandler<(string, int, int)>(new TextSelectionEventConverter(inputField.onTextSelection), cancellationToken, true).OnInvokeAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IUniTaskAsyncEnumerable<(string, int, int)> OnTextSelectionAsAsyncEnumerable(this TMP_InputField inputField)
|
|
||||||
{
|
|
||||||
return new UnityEventHandlerAsyncEnumerable<(string, int, int)>(new TextSelectionEventConverter(inputField.onTextSelection), inputField.GetCancellationTokenOnDestroy());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IUniTaskAsyncEnumerable<(string, int, int)> OnTextSelectionAsAsyncEnumerable(this TMP_InputField inputField, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return new UnityEventHandlerAsyncEnumerable<(string, int, int)>(new TextSelectionEventConverter(inputField.onTextSelection), cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IAsyncDeselectEventHandler<string> GetAsyncDeselectEventHandler(this TMP_InputField inputField)
|
|
||||||
{
|
|
||||||
return new AsyncUnityEventHandler<string>(inputField.onDeselect, inputField.GetCancellationTokenOnDestroy(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IAsyncDeselectEventHandler<string> GetAsyncDeselectEventHandler(this TMP_InputField inputField, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return new AsyncUnityEventHandler<string>(inputField.onDeselect, cancellationToken, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UniTask<string> OnDeselectAsync(this TMP_InputField inputField)
|
|
||||||
{
|
|
||||||
return new AsyncUnityEventHandler<string>(inputField.onDeselect, inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UniTask<string> OnDeselectAsync(this TMP_InputField inputField, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return new AsyncUnityEventHandler<string>(inputField.onDeselect, cancellationToken, true).OnInvokeAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IUniTaskAsyncEnumerable<string> OnDeselectAsAsyncEnumerable(this TMP_InputField inputField)
|
|
||||||
{
|
|
||||||
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onDeselect, inputField.GetCancellationTokenOnDestroy());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IUniTaskAsyncEnumerable<string> OnDeselectAsAsyncEnumerable(this TMP_InputField inputField, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onDeselect, cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IAsyncSelectEventHandler<string> GetAsyncSelectEventHandler(this TMP_InputField inputField)
|
|
||||||
{
|
|
||||||
return new AsyncUnityEventHandler<string>(inputField.onSelect, inputField.GetCancellationTokenOnDestroy(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IAsyncSelectEventHandler<string> GetAsyncSelectEventHandler(this TMP_InputField inputField, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return new AsyncUnityEventHandler<string>(inputField.onSelect, cancellationToken, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UniTask<string> OnSelectAsync(this TMP_InputField inputField)
|
|
||||||
{
|
|
||||||
return new AsyncUnityEventHandler<string>(inputField.onSelect, inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UniTask<string> OnSelectAsync(this TMP_InputField inputField, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return new AsyncUnityEventHandler<string>(inputField.onSelect, cancellationToken, true).OnInvokeAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IUniTaskAsyncEnumerable<string> OnSelectAsAsyncEnumerable(this TMP_InputField inputField)
|
|
||||||
{
|
|
||||||
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onSelect, inputField.GetCancellationTokenOnDestroy());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IUniTaskAsyncEnumerable<string> OnSelectAsAsyncEnumerable(this TMP_InputField inputField, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onSelect, cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IAsyncSubmitEventHandler<string> GetAsyncSubmitEventHandler(this TMP_InputField inputField)
|
|
||||||
{
|
|
||||||
return new AsyncUnityEventHandler<string>(inputField.onSubmit, inputField.GetCancellationTokenOnDestroy(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IAsyncSubmitEventHandler<string> GetAsyncSubmitEventHandler(this TMP_InputField inputField, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return new AsyncUnityEventHandler<string>(inputField.onSubmit, cancellationToken, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UniTask<string> OnSubmitAsync(this TMP_InputField inputField)
|
|
||||||
{
|
|
||||||
return new AsyncUnityEventHandler<string>(inputField.onSubmit, inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UniTask<string> OnSubmitAsync(this TMP_InputField inputField, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return new AsyncUnityEventHandler<string>(inputField.onSubmit, cancellationToken, true).OnInvokeAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IUniTaskAsyncEnumerable<string> OnSubmitAsAsyncEnumerable(this TMP_InputField inputField)
|
|
||||||
{
|
|
||||||
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onSubmit, inputField.GetCancellationTokenOnDestroy());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IUniTaskAsyncEnumerable<string> OnSubmitAsAsyncEnumerable(this TMP_InputField inputField, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onSubmit, cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 79f4f2475e0b2c44e97ed1dee760627b
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
<#@ template debug="false" hostspecific="false" language="C#" #>
|
|
||||||
<#@ assembly name="System.Core" #>
|
|
||||||
<#@ import namespace="System.Linq" #>
|
|
||||||
<#@ import namespace="System.Text" #>
|
|
||||||
<#@ import namespace="System.Collections.Generic" #>
|
|
||||||
<#@ output extension=".cs" #>
|
|
||||||
<#
|
|
||||||
var handlers = new (string name, string type)[] {
|
|
||||||
("ValueChanged", "string"),
|
|
||||||
("EndEdit", "string"),
|
|
||||||
("EndTextSelection", "(string, int, int)"),
|
|
||||||
("TextSelection", "(string, int, int)"),
|
|
||||||
("Deselect", "string"),
|
|
||||||
("Select", "string"),
|
|
||||||
("Submit", "string"),
|
|
||||||
};
|
|
||||||
|
|
||||||
Func<string, bool> shouldConvert = x => x.EndsWith("TextSelection");
|
|
||||||
Func<string, string> eventName = x => shouldConvert(x) ? $"new TextSelectionEventConverter(inputField.on{x})" : $"inputField.on{x}";
|
|
||||||
#>
|
|
||||||
#if UNITASK_TEXTMESHPRO_SUPPORT
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Threading;
|
|
||||||
using TMPro;
|
|
||||||
|
|
||||||
namespace Cysharp.Threading.Tasks
|
|
||||||
{
|
|
||||||
public static partial class TextMeshProAsyncExtensions
|
|
||||||
{
|
|
||||||
<# foreach(var (name, type) in handlers) { #>
|
|
||||||
public static IAsync<#= (name) #>EventHandler<<#= type #>> GetAsync<#= (name) #>EventHandler(this TMP_InputField inputField)
|
|
||||||
{
|
|
||||||
return new AsyncUnityEventHandler<<#= type #>>(<#= eventName(name) #>, inputField.GetCancellationTokenOnDestroy(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IAsync<#= (name) #>EventHandler<<#= type #>> GetAsync<#= (name) #>EventHandler(this TMP_InputField inputField, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return new AsyncUnityEventHandler<<#= type #>>(<#= eventName(name) #>, cancellationToken, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UniTask<<#= type #>> On<#= (name) #>Async(this TMP_InputField inputField)
|
|
||||||
{
|
|
||||||
return new AsyncUnityEventHandler<<#= type #>>(<#= eventName(name) #>, inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UniTask<<#= type #>> On<#= (name) #>Async(this TMP_InputField inputField, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return new AsyncUnityEventHandler<<#= type #>>(<#= eventName(name) #>, cancellationToken, true).OnInvokeAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IUniTaskAsyncEnumerable<<#= type #>> On<#= (name) #>AsAsyncEnumerable(this TMP_InputField inputField)
|
|
||||||
{
|
|
||||||
return new UnityEventHandlerAsyncEnumerable<<#= type #>>(<#= eventName(name) #>, inputField.GetCancellationTokenOnDestroy());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IUniTaskAsyncEnumerable<<#= type #>> On<#= (name) #>AsAsyncEnumerable(this TMP_InputField inputField, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return new UnityEventHandlerAsyncEnumerable<<#= type #>>(<#= eventName(name) #>, cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
<# } #>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: e9bb9fc551a975d44a7180e022a2debe
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,130 +0,0 @@
|
|||||||
#if UNITASK_TEXTMESHPRO_SUPPORT
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Threading;
|
|
||||||
using TMPro;
|
|
||||||
using UnityEngine.Events;
|
|
||||||
|
|
||||||
namespace Cysharp.Threading.Tasks
|
|
||||||
{
|
|
||||||
public static partial class TextMeshProAsyncExtensions
|
|
||||||
{
|
|
||||||
// <string> -> Text
|
|
||||||
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, TMP_Text text, bool rebindOnError = true)
|
|
||||||
{
|
|
||||||
BindToCore(source, text, text.GetCancellationTokenOnDestroy(), rebindOnError).Forget();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, TMP_Text text, CancellationToken cancellationToken, bool rebindOnError = true)
|
|
||||||
{
|
|
||||||
BindToCore(source, text, cancellationToken, rebindOnError).Forget();
|
|
||||||
}
|
|
||||||
|
|
||||||
static async UniTaskVoid BindToCore(IUniTaskAsyncEnumerable<string> source, TMP_Text text, CancellationToken cancellationToken, bool rebindOnError)
|
|
||||||
{
|
|
||||||
var repeat = false;
|
|
||||||
BIND_AGAIN:
|
|
||||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
bool moveNext;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
moveNext = await e.MoveNextAsync();
|
|
||||||
repeat = false;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
if (ex is OperationCanceledException) return;
|
|
||||||
|
|
||||||
if (rebindOnError && !repeat)
|
|
||||||
{
|
|
||||||
repeat = true;
|
|
||||||
goto BIND_AGAIN;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!moveNext) return;
|
|
||||||
|
|
||||||
text.text = e.Current;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (e != null)
|
|
||||||
{
|
|
||||||
await e.DisposeAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// <T> -> Text
|
|
||||||
|
|
||||||
public static void BindTo<T>(this IUniTaskAsyncEnumerable<T> source, TMP_Text text, bool rebindOnError = true)
|
|
||||||
{
|
|
||||||
BindToCore(source, text, text.GetCancellationTokenOnDestroy(), rebindOnError).Forget();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void BindTo<T>(this IUniTaskAsyncEnumerable<T> source, TMP_Text text, CancellationToken cancellationToken, bool rebindOnError = true)
|
|
||||||
{
|
|
||||||
BindToCore(source, text, cancellationToken, rebindOnError).Forget();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void BindTo<T>(this AsyncReactiveProperty<T> source, TMP_Text text, bool rebindOnError = true)
|
|
||||||
{
|
|
||||||
BindToCore(source, text, text.GetCancellationTokenOnDestroy(), rebindOnError).Forget();
|
|
||||||
}
|
|
||||||
|
|
||||||
static async UniTaskVoid BindToCore<T>(IUniTaskAsyncEnumerable<T> source, TMP_Text text, CancellationToken cancellationToken, bool rebindOnError)
|
|
||||||
{
|
|
||||||
var repeat = false;
|
|
||||||
BIND_AGAIN:
|
|
||||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
bool moveNext;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
moveNext = await e.MoveNextAsync();
|
|
||||||
repeat = false;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
if (ex is OperationCanceledException) return;
|
|
||||||
|
|
||||||
if (rebindOnError && !repeat)
|
|
||||||
{
|
|
||||||
repeat = true;
|
|
||||||
goto BIND_AGAIN;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!moveNext) return;
|
|
||||||
|
|
||||||
text.text = e.Current.ToString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (e != null)
|
|
||||||
{
|
|
||||||
await e.DisposeAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: b6ba480edafb67d4e91bb10feb64fae5
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "UniTask.TextMeshPro",
|
|
||||||
"references": [
|
|
||||||
"UniTask",
|
|
||||||
"Unity.TextMeshPro"
|
|
||||||
],
|
|
||||||
"includePlatforms": [],
|
|
||||||
"excludePlatforms": [],
|
|
||||||
"allowUnsafeCode": false,
|
|
||||||
"overrideReferences": false,
|
|
||||||
"precompiledReferences": [],
|
|
||||||
"autoReferenced": true,
|
|
||||||
"defineConstraints": [],
|
|
||||||
"versionDefines": [
|
|
||||||
{
|
|
||||||
"name": "com.unity.textmeshpro",
|
|
||||||
"expression": "",
|
|
||||||
"define": "UNITASK_TEXTMESHPRO_SUPPORT"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"noEngineReferences": false
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: dc47925d1a5fa2946bdd37746b2b5d48
|
|
||||||
AssemblyDefinitionImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#if UNITASK_YOOASSET_SUPPORT
|
||||||
using System;
|
using System;
|
||||||
using YooAsset;
|
using YooAsset;
|
||||||
using static Cysharp.Threading.Tasks.Internal.Error;
|
using static Cysharp.Threading.Tasks.Internal.Error;
|
||||||
@@ -143,3 +144,4 @@ namespace Cysharp.Threading.Tasks
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#if UNITASK_YOOASSET_SUPPORT
|
||||||
#if UNITY_2020_1_OR_NEWER && ! UNITY_2021
|
#if UNITY_2020_1_OR_NEWER && ! UNITY_2021
|
||||||
#define UNITY_2020_BUG
|
#define UNITY_2020_BUG
|
||||||
#endif
|
#endif
|
||||||
@@ -243,3 +244,4 @@ namespace Cysharp.Threading.Tasks
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
{
|
{
|
||||||
"name": "UniTask.DOTween",
|
"name": "UniTask.YooAsset",
|
||||||
|
"rootNamespace": "",
|
||||||
"references": [
|
"references": [
|
||||||
"UniTask",
|
"GUID:f51ebe6a0ceec4240a699833d6309b23",
|
||||||
"DOTween.Modules"
|
"GUID:e34a5702dd353724aa315fb8011f08c3"
|
||||||
],
|
],
|
||||||
"includePlatforms": [],
|
"includePlatforms": [],
|
||||||
"excludePlatforms": [],
|
"excludePlatforms": [],
|
||||||
@@ -13,9 +14,9 @@
|
|||||||
"defineConstraints": [],
|
"defineConstraints": [],
|
||||||
"versionDefines": [
|
"versionDefines": [
|
||||||
{
|
{
|
||||||
"name": "com.demigiant.dotween",
|
"name": "com.cysharp.unitask",
|
||||||
"expression": "",
|
"expression": "",
|
||||||
"define": "UNITASK_DOTWEEN_SUPPORT"
|
"define": "UNITASK_YOOASSET_SUPPORT"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"noEngineReferences": false
|
"noEngineReferences": false
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 593a5b492d29ac6448b1ebf7f035ef33
|
guid: 1278a46ce459c5a46b4eaeda148684ef
|
||||||
AssemblyDefinitionImporter:
|
AssemblyDefinitionImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
userData:
|
userData:
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Cysharp.Threading.Tasks
|
|
||||||
{
|
|
||||||
public interface IUniTaskAsyncEnumerable<out T>
|
|
||||||
{
|
|
||||||
IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default);
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface IUniTaskAsyncEnumerator<out T> : IUniTaskAsyncDisposable
|
|
||||||
{
|
|
||||||
T Current { get; }
|
|
||||||
UniTask<bool> MoveNextAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface IUniTaskAsyncDisposable
|
|
||||||
{
|
|
||||||
UniTask DisposeAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface IUniTaskOrderedAsyncEnumerable<TElement> : IUniTaskAsyncEnumerable<TElement>
|
|
||||||
{
|
|
||||||
IUniTaskOrderedAsyncEnumerable<TElement> CreateOrderedEnumerable<TKey>(Func<TElement, TKey> keySelector, IComparer<TKey> comparer, bool descending);
|
|
||||||
IUniTaskOrderedAsyncEnumerable<TElement> CreateOrderedEnumerable<TKey>(Func<TElement, UniTask<TKey>> keySelector, IComparer<TKey> comparer, bool descending);
|
|
||||||
IUniTaskOrderedAsyncEnumerable<TElement> CreateOrderedEnumerable<TKey>(Func<TElement, CancellationToken, UniTask<TKey>> keySelector, IComparer<TKey> comparer, bool descending);
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface IConnectableUniTaskAsyncEnumerable<out T> : IUniTaskAsyncEnumerable<T>
|
|
||||||
{
|
|
||||||
IDisposable Connect();
|
|
||||||
}
|
|
||||||
|
|
||||||
// don't use AsyncGrouping.
|
|
||||||
//public interface IUniTaskAsyncGrouping<out TKey, out TElement> : IUniTaskAsyncEnumerable<TElement>
|
|
||||||
//{
|
|
||||||
// TKey Key { get; }
|
|
||||||
//}
|
|
||||||
|
|
||||||
public static class UniTaskAsyncEnumerableExtensions
|
|
||||||
{
|
|
||||||
public static UniTaskCancelableAsyncEnumerable<T> WithCancellation<T>(this IUniTaskAsyncEnumerable<T> source, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return new UniTaskCancelableAsyncEnumerable<T>(source, cancellationToken);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Auto)]
|
|
||||||
public readonly struct UniTaskCancelableAsyncEnumerable<T>
|
|
||||||
{
|
|
||||||
private readonly IUniTaskAsyncEnumerable<T> enumerable;
|
|
||||||
private readonly CancellationToken cancellationToken;
|
|
||||||
|
|
||||||
internal UniTaskCancelableAsyncEnumerable(IUniTaskAsyncEnumerable<T> enumerable, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
this.enumerable = enumerable;
|
|
||||||
this.cancellationToken = cancellationToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Enumerator GetAsyncEnumerator()
|
|
||||||
{
|
|
||||||
return new Enumerator(enumerable.GetAsyncEnumerator(cancellationToken));
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Auto)]
|
|
||||||
public readonly struct Enumerator
|
|
||||||
{
|
|
||||||
private readonly IUniTaskAsyncEnumerator<T> enumerator;
|
|
||||||
|
|
||||||
internal Enumerator(IUniTaskAsyncEnumerator<T> enumerator)
|
|
||||||
{
|
|
||||||
this.enumerator = enumerator;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T Current => enumerator.Current;
|
|
||||||
|
|
||||||
public UniTask<bool> MoveNextAsync()
|
|
||||||
{
|
|
||||||
return enumerator.MoveNextAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public UniTask DisposeAsync()
|
|
||||||
{
|
|
||||||
return enumerator.DisposeAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: b20cf9f02ac585948a4372fa4ee06504
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,124 +0,0 @@
|
|||||||
#pragma warning disable CS1591
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Cysharp.Threading.Tasks
|
|
||||||
{
|
|
||||||
public enum UniTaskStatus
|
|
||||||
{
|
|
||||||
/// <summary>The operation has not yet completed.</summary>
|
|
||||||
Pending = 0,
|
|
||||||
/// <summary>The operation completed successfully.</summary>
|
|
||||||
Succeeded = 1,
|
|
||||||
/// <summary>The operation completed with an error.</summary>
|
|
||||||
Faulted = 2,
|
|
||||||
/// <summary>The operation completed due to cancellation.</summary>
|
|
||||||
Canceled = 3
|
|
||||||
}
|
|
||||||
|
|
||||||
// similar as IValueTaskSource
|
|
||||||
public interface IUniTaskSource
|
|
||||||
#if !UNITY_2018_3_OR_NEWER && !NETSTANDARD2_0
|
|
||||||
: System.Threading.Tasks.Sources.IValueTaskSource
|
|
||||||
#pragma warning disable CS0108
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
UniTaskStatus GetStatus(short token);
|
|
||||||
void OnCompleted(Action<object> continuation, object state, short token);
|
|
||||||
void GetResult(short token);
|
|
||||||
|
|
||||||
UniTaskStatus UnsafeGetStatus(); // only for debug use.
|
|
||||||
|
|
||||||
#if !UNITY_2018_3_OR_NEWER && !NETSTANDARD2_0
|
|
||||||
#pragma warning restore CS0108
|
|
||||||
|
|
||||||
System.Threading.Tasks.Sources.ValueTaskSourceStatus System.Threading.Tasks.Sources.IValueTaskSource.GetStatus(short token)
|
|
||||||
{
|
|
||||||
return (System.Threading.Tasks.Sources.ValueTaskSourceStatus)(int)((IUniTaskSource)this).GetStatus(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
void System.Threading.Tasks.Sources.IValueTaskSource.GetResult(short token)
|
|
||||||
{
|
|
||||||
((IUniTaskSource)this).GetResult(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
void System.Threading.Tasks.Sources.IValueTaskSource.OnCompleted(Action<object> continuation, object state, short token, System.Threading.Tasks.Sources.ValueTaskSourceOnCompletedFlags flags)
|
|
||||||
{
|
|
||||||
// ignore flags, always none.
|
|
||||||
((IUniTaskSource)this).OnCompleted(continuation, state, token);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface IUniTaskSource<out T> : IUniTaskSource
|
|
||||||
#if !UNITY_2018_3_OR_NEWER && !NETSTANDARD2_0
|
|
||||||
, System.Threading.Tasks.Sources.IValueTaskSource<T>
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
new T GetResult(short token);
|
|
||||||
|
|
||||||
#if !UNITY_2018_3_OR_NEWER && !NETSTANDARD2_0
|
|
||||||
|
|
||||||
new public UniTaskStatus GetStatus(short token)
|
|
||||||
{
|
|
||||||
return ((IUniTaskSource)this).GetStatus(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
new public void OnCompleted(Action<object> continuation, object state, short token)
|
|
||||||
{
|
|
||||||
((IUniTaskSource)this).OnCompleted(continuation, state, token);
|
|
||||||
}
|
|
||||||
|
|
||||||
System.Threading.Tasks.Sources.ValueTaskSourceStatus System.Threading.Tasks.Sources.IValueTaskSource<T>.GetStatus(short token)
|
|
||||||
{
|
|
||||||
return (System.Threading.Tasks.Sources.ValueTaskSourceStatus)(int)((IUniTaskSource)this).GetStatus(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
T System.Threading.Tasks.Sources.IValueTaskSource<T>.GetResult(short token)
|
|
||||||
{
|
|
||||||
return ((IUniTaskSource<T>)this).GetResult(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
void System.Threading.Tasks.Sources.IValueTaskSource<T>.OnCompleted(Action<object> continuation, object state, short token, System.Threading.Tasks.Sources.ValueTaskSourceOnCompletedFlags flags)
|
|
||||||
{
|
|
||||||
// ignore flags, always none.
|
|
||||||
((IUniTaskSource)this).OnCompleted(continuation, state, token);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class UniTaskStatusExtensions
|
|
||||||
{
|
|
||||||
/// <summary>status != Pending.</summary>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static bool IsCompleted(this UniTaskStatus status)
|
|
||||||
{
|
|
||||||
return status != UniTaskStatus.Pending;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>status == Succeeded.</summary>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static bool IsCompletedSuccessfully(this UniTaskStatus status)
|
|
||||||
{
|
|
||||||
return status == UniTaskStatus.Succeeded;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>status == Canceled.</summary>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static bool IsCanceled(this UniTaskStatus status)
|
|
||||||
{
|
|
||||||
return status == UniTaskStatus.Canceled;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>status == Faulted.</summary>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static bool IsFaulted(this UniTaskStatus status)
|
|
||||||
{
|
|
||||||
return status == UniTaskStatus.Faulted;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 3e4d023d8404ab742b5e808c98097c3c
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user