Compare commits

...

5 Commits

Author SHA1 Message Date
何冠峰
354ca5197f refactor : 重构异步操作模块 2026-01-13 14:55:31 +08:00
何冠峰
ce4d6911db refactor : 重构异步操作模块 2026-01-13 12:08:02 +08:00
何冠峰
b796b1a44e refactor : 重构异步操作模块 2026-01-13 11:23:50 +08:00
何冠峰
7198e639d9 refactor : 重构异步操作模块 2026-01-12 16:10:24 +08:00
何冠峰
294fa18fec refactor : 重构异步操作模块 2026-01-12 15:35:00 +08:00
12 changed files with 271 additions and 91 deletions

View File

@@ -255,12 +255,7 @@ namespace YooAsset
if (_watchdogAborted) if (_watchdogAborted)
return; return;
#if UNITY_2020_3_OR_NEWER double realtimeSinceStartup = TimeUtility.RealtimeSinceStartup;
double realtimeSinceStartup = UnityEngine.Time.realtimeSinceStartupAsDouble;
#else
double realtimeSinceStartup = UnityEngine.Time.realtimeSinceStartup;
#endif
if (DownloadedBytes != _lastDownloadBytes) if (DownloadedBytes != _lastDownloadBytes)
{ {
_lastDownloadBytes = DownloadedBytes; _lastDownloadBytes = DownloadedBytes;

View File

@@ -87,7 +87,7 @@ namespace YooAsset
if (Status == EDownloadRequestStatus.None) if (Status == EDownloadRequestStatus.None)
{ {
Status = EDownloadRequestStatus.Running; Status = EDownloadRequestStatus.Running;
_lastUpdateTime = GetUnityEngineRealtime(); _lastUpdateTime = TimeUtility.RealtimeSinceStartup;
} }
} }
@@ -99,7 +99,7 @@ namespace YooAsset
if (Status != EDownloadRequestStatus.Running) if (Status != EDownloadRequestStatus.Running)
return; return;
double currentTime = GetUnityEngineRealtime(); double currentTime = TimeUtility.RealtimeSinceStartup;
double deltaTime = currentTime - _lastUpdateTime; double deltaTime = currentTime - _lastUpdateTime;
_lastUpdateTime = currentTime; _lastUpdateTime = currentTime;
@@ -137,14 +137,5 @@ namespace YooAsset
public void Dispose() public void Dispose()
{ {
} }
private double GetUnityEngineRealtime()
{
#if UNITY_2020_3_OR_NEWER
return UnityEngine.Time.realtimeSinceStartupAsDouble;
#else
return UnityEngine.Time.realtimeSinceStartup;
#endif
}
} }
} }

View File

@@ -17,7 +17,7 @@ namespace YooAsset
private readonly DefaultCacheFileSystem _fileSystem; private readonly DefaultCacheFileSystem _fileSystem;
private IEnumerator<string> _filesEnumerator = null; private IEnumerator<string> _filesEnumerator = null;
private float _verifyStartTime; private double _verifyStartTime;
private ESteps _steps = ESteps.None; private ESteps _steps = ESteps.None;
/// <summary> /// <summary>
@@ -33,7 +33,7 @@ namespace YooAsset
internal override void InternalStart() internal override void InternalStart()
{ {
_steps = ESteps.Prepare; _steps = ESteps.Prepare;
_verifyStartTime = UnityEngine.Time.realtimeSinceStartup; _verifyStartTime = TimeUtility.RealtimeSinceStartup;
} }
internal override void InternalUpdate() internal override void InternalUpdate()
{ {
@@ -58,7 +58,7 @@ namespace YooAsset
_steps = ESteps.Done; _steps = ESteps.Done;
Status = EOperationStatus.Succeed; Status = EOperationStatus.Succeed;
float costTime = UnityEngine.Time.realtimeSinceStartup - _verifyStartTime; double costTime = TimeUtility.RealtimeSinceStartup - _verifyStartTime;
YooLogger.Log($"Search cache files elapsed time {costTime:f1} seconds"); YooLogger.Log($"Search cache files elapsed time {costTime:f1} seconds");
} }
} }

View File

@@ -25,7 +25,7 @@ namespace YooAsset
private List<VerifyFileElement> _verifyingList; private List<VerifyFileElement> _verifyingList;
private int _verifyMaxNum; private int _verifyMaxNum;
private int _verifyTotalCount; private int _verifyTotalCount;
private float _verifyStartTime; private double _verifyStartTime;
private int _succeedCount; private int _succeedCount;
private int _failedCount; private int _failedCount;
private ESteps _steps = ESteps.None; private ESteps _steps = ESteps.None;
@@ -40,7 +40,7 @@ namespace YooAsset
internal override void InternalStart() internal override void InternalStart()
{ {
_steps = ESteps.InitVerify; _steps = ESteps.InitVerify;
_verifyStartTime = UnityEngine.Time.realtimeSinceStartup; _verifyStartTime = TimeUtility.RealtimeSinceStartup;
} }
internal override void InternalUpdate() internal override void InternalUpdate()
{ {
@@ -84,7 +84,7 @@ namespace YooAsset
{ {
_steps = ESteps.Done; _steps = ESteps.Done;
Status = EOperationStatus.Succeed; Status = EOperationStatus.Succeed;
float costTime = UnityEngine.Time.realtimeSinceStartup - _verifyStartTime; double costTime = TimeUtility.RealtimeSinceStartup - _verifyStartTime;
YooLogger.Log($"Verify cache files elapsed time {costTime:f1} seconds"); YooLogger.Log($"Verify cache files elapsed time {costTime:f1} seconds");
} }

View File

@@ -155,9 +155,19 @@ namespace YooAsset
if (_childs == null) if (_childs == null)
_childs = new List<AsyncOperationBase>(10); _childs = new List<AsyncOperationBase>(10);
#if UNITY_EDITOR #if UNITY_EDITOR || DEBUG
if (child == null)
throw new YooInternalException("The child node is null !");
if (ReferenceEquals(child, this))
throw new YooInternalException("The child node cannot be itself !");
if (_childs.Contains(child)) if (_childs.Contains(child))
throw new YooInternalException($"The child node {child.GetType().Name} already exists !"); throw new YooInternalException($"The child node {child.GetType().Name} already exists !");
// 禁止形成环依赖
if (WouldCreateCycle(child))
throw new YooInternalException($"AddChildOperation would create a cycle : {this.GetType().Name} -> {child.GetType().Name}");
#endif #endif
_childs.Add(child); _childs.Add(child);
@@ -171,7 +181,10 @@ namespace YooAsset
if (_childs == null) if (_childs == null)
return; return;
#if UNITY_EDITOR #if UNITY_EDITOR || DEBUG
if (child == null)
throw new YooInternalException("The child node is null !");
if (_childs.Contains(child) == false) if (_childs.Contains(child) == false)
throw new YooInternalException($"The child node {child.GetType().Name} not exists !"); throw new YooInternalException($"The child node {child.GetType().Name} not exists !");
#endif #endif
@@ -200,8 +213,17 @@ namespace YooAsset
DebugBeginRecording(); DebugBeginRecording();
// 开始任务 // 开始任务
try
{
InternalStart(); InternalStart();
} }
catch (Exception ex)
{
Status = EOperationStatus.Failed;
Error = ex.ToString();
YooLogger.Error($"Exception in {this.GetType().Name}.InternalStart : {ex}");
}
}
} }
/// <summary> /// <summary>
@@ -215,8 +237,19 @@ namespace YooAsset
DebugUpdateRecording(); DebugUpdateRecording();
// 更新任务 // 更新任务
// 注意:兜底隔离机制
// 说明检测的异常源包含I/O解压/读写权限/磁盘满),平台差异等
try
{
InternalUpdate(); InternalUpdate();
} }
catch (Exception ex)
{
Status = EOperationStatus.Failed;
Error = ex.ToString();
YooLogger.Error($"Exception in {this.GetType().Name}.InternalUpdate : {ex}");
}
}
if (IsDone && IsFinish == false) if (IsDone && IsFinish == false)
{ {
@@ -244,12 +277,15 @@ namespace YooAsset
Error = "user abort"; Error = "user abort";
YooLogger.Warning($"Async operation {this.GetType().Name} has been aborted !"); YooLogger.Warning($"Async operation {this.GetType().Name} has been aborted !");
} }
//注意强制收尾确保Task能完成
FinishOperation();
} }
/// <summary> /// <summary>
/// 强制结束异步任务 /// 强制结束异步任务
/// </summary> /// </summary>
internal void FinishOperation() private void FinishOperation()
{ {
if (IsFinish == false) if (IsFinish == false)
{ {
@@ -261,6 +297,7 @@ namespace YooAsset
try try
{ {
//TODO 单个回调异常会阻断后续回调
_callback?.Invoke(this); _callback?.Invoke(this);
} }
catch (Exception ex) catch (Exception ex)
@@ -307,14 +344,9 @@ namespace YooAsset
// 当执行次数用完时 // 当执行次数用完时
runCount--; runCount--;
if (runCount <= 0) if (runCount <= 0)
{
Status = EOperationStatus.Failed;
Error = $"Operation {this.GetType().Name} failed to wait for async complete !";
YooLogger.Error(Error);
break; break;
} }
} }
}
/// <summary> /// <summary>
/// 无限次数的执行更新逻辑,直到任务完成 /// 无限次数的执行更新逻辑,直到任务完成
@@ -341,11 +373,7 @@ namespace YooAsset
/// </summary> /// </summary>
public void WaitForAsyncComplete() public void WaitForAsyncComplete()
{ {
if (IsDone)
return;
//TODO 防止异步操作被挂起陷入无限死循环! //TODO 防止异步操作被挂起陷入无限死循环!
// 例如:文件解压任务或者文件导入任务!
if (Status == EOperationStatus.None) if (Status == EOperationStatus.None)
{ {
StartOperation(); StartOperation();
@@ -354,7 +382,19 @@ namespace YooAsset
if (IsWaitForAsyncComplete == false) if (IsWaitForAsyncComplete == false)
{ {
IsWaitForAsyncComplete = true; IsWaitForAsyncComplete = true;
if (IsDone == false)
InternalWaitForAsyncComplete(); InternalWaitForAsyncComplete();
if (IsDone == false)
{
Status = EOperationStatus.Failed;
Error = $"Operation {this.GetType().Name} failed to wait for async complete !";
YooLogger.Error(Error);
}
//注意强制收尾确保Task能完成
FinishOperation();
} }
} }
@@ -362,7 +402,7 @@ namespace YooAsset
/// <summary> /// <summary>
/// 开始的时间 /// 开始的时间
/// </summary> /// </summary>
public string BeginTime = string.Empty; public string BeginTime { protected set; get; }
/// <summary> /// <summary>
/// 处理耗时(单位:毫秒) /// 处理耗时(单位:毫秒)
@@ -377,7 +417,7 @@ namespace YooAsset
{ {
if (_watch == null) if (_watch == null)
{ {
BeginTime = SpawnTimeToString(UnityEngine.Time.realtimeSinceStartup); BeginTime = SpawnTimeToString(TimeUtility.RealtimeSinceStartup);
_watch = Stopwatch.StartNew(); _watch = Stopwatch.StartNew();
} }
} }
@@ -401,13 +441,46 @@ namespace YooAsset
} }
} }
private string SpawnTimeToString(float spawnTime) private string SpawnTimeToString(double spawnTime)
{ {
float h = UnityEngine.Mathf.FloorToInt(spawnTime / 3600f); double h = System.Math.Floor(spawnTime / 3600);
float m = UnityEngine.Mathf.FloorToInt(spawnTime / 60f - h * 60f); double m = System.Math.Floor(spawnTime / 60 - h * 60);
float s = UnityEngine.Mathf.FloorToInt(spawnTime - m * 60f - h * 3600f); double s = System.Math.Floor(spawnTime - m * 60 - h * 3600);
return h.ToString("00") + ":" + m.ToString("00") + ":" + s.ToString("00"); return h.ToString("00") + ":" + m.ToString("00") + ":" + s.ToString("00");
} }
private bool WouldCreateCycle(AsyncOperationBase child)
{
const int maxVisited = 4096;
var stack = new Stack<AsyncOperationBase>();
var visited = new HashSet<AsyncOperationBase>();
stack.Push(child);
while (stack.Count > 0)
{
var node = stack.Pop();
if (node == null)
continue;
if (visited.Add(node) == false)
continue;
if (visited.Count > maxVisited)
throw new YooInternalException("Child operation graph is too large, cycle check aborted !");
if (ReferenceEquals(node, this))
return true;
if (node._childs == null)
continue;
for (int i = 0; i < node._childs.Count; i++)
{
stack.Push(node._childs[i]);
}
}
return false;
}
internal DebugOperationInfo GetDebugOperationInfo() internal DebugOperationInfo GetDebugOperationInfo()
{ {

View File

@@ -10,6 +10,7 @@ namespace YooAsset
{ {
private readonly List<AsyncOperationBase> _operations = new List<AsyncOperationBase>(100); private readonly List<AsyncOperationBase> _operations = new List<AsyncOperationBase>(100);
private readonly List<AsyncOperationBase> _newList = new List<AsyncOperationBase>(100); private readonly List<AsyncOperationBase> _newList = new List<AsyncOperationBase>(100);
private uint _priority = 0;
/// <summary> /// <summary>
/// 所属包裹名称 /// 所属包裹名称
@@ -19,7 +20,23 @@ namespace YooAsset
/// <summary> /// <summary>
/// 调度器优先级(值越大越优先) /// 调度器优先级(值越大越优先)
/// </summary> /// </summary>
public int Priority { private set; get; } public uint Priority
{
get { return _priority; }
set
{
if (_priority != value)
{
_priority = value;
IsDirty = true;
}
}
}
/// <summary>
/// 优先级是否已变更(需要重新排序)
/// </summary>
public bool IsDirty { set; get; } = false;
/// <summary> /// <summary>
/// 创建顺序(用于同优先级稳定排序) /// 创建顺序(用于同优先级稳定排序)
@@ -27,10 +44,9 @@ namespace YooAsset
public int CreateIndex { private set; get; } public int CreateIndex { private set; get; }
public OperationScheduler(string packageName, int priority, int createIndex) public OperationScheduler(string packageName, int createIndex)
{ {
PackageName = packageName; PackageName = packageName;
Priority = priority;
CreateIndex = createIndex; CreateIndex = createIndex;
} }
@@ -104,7 +120,6 @@ namespace YooAsset
foreach (var operation in _newList) foreach (var operation in _newList)
{ {
operation.AbortOperation(); operation.AbortOperation();
operation.FinishOperation(); //注意强制收尾确保Task能完成
} }
_newList.Clear(); _newList.Clear();
@@ -112,7 +127,6 @@ namespace YooAsset
foreach (var operation in _operations) foreach (var operation in _operations)
{ {
operation.AbortOperation(); operation.AbortOperation();
operation.FinishOperation(); //注意强制收尾确保Task能完成
} }
_operations.Clear(); _operations.Clear();
} }

View File

@@ -5,7 +5,7 @@ using System.Diagnostics;
namespace YooAsset namespace YooAsset
{ {
internal class OperationSystem internal static class OperationSystem
{ {
#if UNITY_EDITOR #if UNITY_EDITOR
[UnityEngine.RuntimeInitializeOnLoadMethod(UnityEngine.RuntimeInitializeLoadType.SubsystemRegistration)] [UnityEngine.RuntimeInitializeOnLoadMethod(UnityEngine.RuntimeInitializeLoadType.SubsystemRegistration)]
@@ -21,7 +21,6 @@ namespace YooAsset
private static readonly Dictionary<string, OperationScheduler> _schedulerDic = new Dictionary<string, OperationScheduler>(100); private static readonly Dictionary<string, OperationScheduler> _schedulerDic = new Dictionary<string, OperationScheduler>(100);
private static readonly List<OperationScheduler> _schedulerList = new List<OperationScheduler>(100); private static readonly List<OperationScheduler> _schedulerList = new List<OperationScheduler>(100);
private static bool _isInitialize = false; private static bool _isInitialize = false;
private static bool _schedulerListDirty = false;
private static int _createIndex = 0; private static int _createIndex = 0;
// 计时器相关 // 计时器相关
@@ -56,12 +55,15 @@ namespace YooAsset
/// 初始化异步操作系统 /// 初始化异步操作系统
/// </summary> /// </summary>
public static void Initialize() public static void Initialize()
{
if (_isInitialize == false)
{ {
_isInitialize = true; _isInitialize = true;
_watch = Stopwatch.StartNew(); _watch = Stopwatch.StartNew();
// 创建全局调度器 // 创建全局调度器
CreatePackageScheduler(GLOBAL_SCHEDULER_NAME, 0); CreatePackageScheduler(GLOBAL_SCHEDULER_NAME, uint.MaxValue);
}
} }
/// <summary> /// <summary>
@@ -72,10 +74,18 @@ namespace YooAsset
if (_isInitialize == false) if (_isInitialize == false)
return; return;
// 重新排序调度器 // 检测是否需要执行排序
if (_schedulerListDirty) bool isDirty = false;
foreach (var scheduler in _schedulerList)
{
if (scheduler.IsDirty)
{
scheduler.IsDirty = false;
isDirty = true;
}
}
if (isDirty)
{ {
_schedulerListDirty = false;
_schedulerList.Sort(); _schedulerList.Sort();
} }
@@ -97,6 +107,9 @@ namespace YooAsset
/// </summary> /// </summary>
public static void DestroyAll() public static void DestroyAll()
{ {
_isInitialize = false;
YooLogger.Log("Operation system destroy all !");
// 清空所有调度器 // 清空所有调度器
foreach (var scheduler in _schedulerList) foreach (var scheduler in _schedulerList)
{ {
@@ -104,9 +117,7 @@ namespace YooAsset
} }
_schedulerDic.Clear(); _schedulerDic.Clear();
_schedulerList.Clear(); _schedulerList.Clear();
_schedulerListDirty = false;
_createIndex = 0; _createIndex = 0;
_isInitialize = false;
_watch = null; _watch = null;
_frameTime = 0; _frameTime = 0;
@@ -116,17 +127,20 @@ namespace YooAsset
/// <summary> /// <summary>
/// 创建包裹调度器 /// 创建包裹调度器
/// </summary> /// </summary>
public static void CreatePackageScheduler(string packageName, int priority) public static OperationScheduler CreatePackageScheduler(string packageName, uint priority)
{ {
DebugCheckInitialize(packageName);
if (_schedulerDic.ContainsKey(packageName)) if (_schedulerDic.ContainsKey(packageName))
{ {
throw new YooInternalException($"Package scheduler already exists: {packageName}"); throw new YooInternalException($"Package scheduler already exists: {packageName}");
} }
var scheduler = new OperationScheduler(packageName, priority, _createIndex++); var scheduler = new OperationScheduler(packageName, _createIndex++);
_schedulerDic.Add(packageName, scheduler); _schedulerDic.Add(packageName, scheduler);
_schedulerList.Add(scheduler); _schedulerList.Add(scheduler);
_schedulerListDirty = true; scheduler.Priority = priority;
return scheduler;
} }
/// <summary> /// <summary>
@@ -134,6 +148,8 @@ namespace YooAsset
/// </summary> /// </summary>
public static void DestroyPackageScheduler(string packageName) public static void DestroyPackageScheduler(string packageName)
{ {
DebugCheckInitialize(packageName);
// 不允许销毁默认调度器 // 不允许销毁默认调度器
if (packageName == GLOBAL_SCHEDULER_NAME) if (packageName == GLOBAL_SCHEDULER_NAME)
{ {
@@ -153,6 +169,8 @@ namespace YooAsset
/// </summary> /// </summary>
public static void ClearPackageOperation(string packageName) public static void ClearPackageOperation(string packageName)
{ {
DebugCheckInitialize(packageName);
var scheduler = GetScheduler(packageName); var scheduler = GetScheduler(packageName);
scheduler.ClearAll(); scheduler.ClearAll();
} }
@@ -162,10 +180,34 @@ namespace YooAsset
/// </summary> /// </summary>
public static void StartOperation(string packageName, AsyncOperationBase operation) public static void StartOperation(string packageName, AsyncOperationBase operation)
{ {
DebugCheckInitialize(packageName);
var scheduler = GetScheduler(packageName); var scheduler = GetScheduler(packageName);
scheduler.StartOperation(operation); scheduler.StartOperation(operation);
} }
/// <summary>
/// 设置调度器优先级
/// </summary>
public static void SetSchedulerPriority(string packageName, uint priority)
{
DebugCheckInitialize(packageName);
var scheduler = GetScheduler(packageName);
scheduler.Priority = priority;
}
/// <summary>
/// 获取调度器优先级
/// </summary>
public static uint GetSchedulerPriority(string packageName)
{
DebugCheckInitialize(packageName);
var scheduler = GetScheduler(packageName);
return scheduler.Priority;
}
/// <summary> /// <summary>
/// 获取调度器(严格模式) /// 获取调度器(严格模式)
/// </summary> /// </summary>
@@ -177,15 +219,29 @@ namespace YooAsset
} }
// 严格模式:非默认包裹必须先创建调度器 // 严格模式:非默认包裹必须先创建调度器
throw new YooInternalException($"Package scheduler not found: {packageName}. Please call YooAssets.CreatePackage() first!"); throw new YooInternalException($"Operation scheduler not found: {packageName}.");
} }
#region #region
internal static List<DebugOperationInfo> GetDebugOperationInfos(string packageName) internal static List<DebugOperationInfo> GetDebugOperationInfos(string packageName)
{ {
DebugCheckInitialize(packageName);
var scheduler = GetScheduler(packageName); var scheduler = GetScheduler(packageName);
return scheduler.GetDebugOperationInfos(); return scheduler.GetDebugOperationInfos();
} }
#endregion #endregion
#region
[Conditional("DEBUG")]
private static void DebugCheckInitialize(string packageName)
{
if (string.IsNullOrWhiteSpace(packageName))
throw new YooInternalException("Package name is null or empty.");
if (_isInitialize == false)
throw new YooInternalException($"{nameof(OperationSystem)} not initialized !");
}
#endregion
} }
} }

View File

@@ -217,6 +217,16 @@ public static void ClearPackageOperation(string packageName);
/// 启动异步操作 /// 启动异步操作
/// </summary> /// </summary>
public static void StartOperation(string packageName, AsyncOperationBase operation); public static void StartOperation(string packageName, AsyncOperationBase operation);
/// <summary>
/// 设置调度器优先级
/// </summary>
public static void SetSchedulerPriority(string packageName, uint priority);
/// <summary>
/// 获取调度器优先级
/// </summary>
public static uint GetSchedulerPriority(string packageName);
``` ```
#### 包裹调度说明 #### 包裹调度说明
@@ -227,16 +237,16 @@ public static void StartOperation(string packageName, AsyncOperationBase operati
#### 回调监听 #### 回调监听
```csharp OperationSystem **当前未提供**全局任务开始/结束回调的注册接口。
/// <summary>
/// 注册任务开始回调
/// </summary>
public static void RegisterStartCallback(Action<string, AsyncOperationBase> callback);
/// <summary> 如需监听任务结束(推荐),请直接订阅具体任务的 `Completed` 事件:
/// 注册任务结束回调
/// </summary> ```csharp
public static void RegisterFinishCallback(Action<string, AsyncOperationBase> callback); var operation = package.LoadAssetAsync<GameObject>(location);
operation.Completed += op =>
{
// TODO : 根据 op.Status 判断成功/失败
};
``` ```
--- ---
@@ -315,14 +325,36 @@ void LoadAssetSync()
操作按 `Priority` 属性降序排列,优先级高的操作先执行。 操作按 `Priority` 属性降序排列,优先级高的操作先执行。
#### 操作优先级
```csharp ```csharp
var operation = package.LoadAssetAsync<GameObject>(location); var operation = package.LoadAssetAsync<GameObject>(location);
operation.Priority = 100; // 设置高优先级 operation.Priority = 100; // 设置高优先级
``` ```
#### 包裹优先级
通过 `ResourcePackage.PackagePriority` 可以设置包裹的调度器优先级,值越大越优先更新。
```csharp
// 创建包裹时指定优先级
var package = YooAssets.CreatePackage("MyPackage", 100);
// 运行时动态调整优先级
package.PackagePriority = 200;
// 获取当前优先级
uint priority = package.PackagePriority;
```
**使用场景:**
- 多包裹场景下,可根据游戏状态动态调整包裹优先级
- 例如:进入战斗时提高战斗资源包的优先级,退出战斗时恢复默认优先级
**排序规则:** **排序规则:**
- 新操作添加时:若新增队列存在非零优先级,则触发排序 - 新操作添加时:若新增队列存在非零优先级,则触发排序
- 运行修改 `Priority`会在下一次调度器更新时自动触发重排(即时生效,通常为下一帧 - 运行修改 `Priority`调度器会在每帧 `Update()` 的排序阶段检测 `IsDirty` 并触发重排;若在某个操作的 `InternalUpdate()` 内修改(本帧排序已完成),则新的优先级会延后一帧生效(可能与预期不符
- 若期望本帧生效:请尽量在任务入队前或本帧调度器 `Update()` 开始前设置 `Priority`,避免在 `InternalUpdate()` 内临时调整
- 排序使用 `List.Sort()` 进行原地排序;频繁修改优先级会带来额外排序开销,建议按需使用 - 排序使用 `List.Sort()` 进行原地排序;频繁修改优先级会带来额外排序开销,建议按需使用
### 时间切片 ### 时间切片
@@ -514,4 +546,4 @@ IEnumerator + IComparable<AsyncOperationBase>
4. **子任务中止**:父操作中止时会自动中止所有子操作 4. **子任务中止**:父操作中止时会自动中止所有子操作
5. **回调异常**`Completed` 回调中的异常会被捕获并记录,不会中断系统 5. **回调异常**`Completed` 回调中的异常会被捕获并记录,不会中断系统
6. **编辑器重置**:编辑器中使用 `RuntimeInitializeOnLoadMethod` 自动重置状态 6. **编辑器重置**:编辑器中使用 `RuntimeInitializeOnLoadMethod` 自动重置状态
7. **循环保护**:在 `InternalWaitForAsyncComplete()`如果使用 `ExecuteWhileDone()`,内部默认 1000 次执行保护,防止无限循环 7. **循环保护**:在 `InternalWaitForAsyncComplete()`建议使用 `RunBatchExecution()`默认 1000 次)限制单次推进次数,避免陷入无限循环或长时间占用主线程

View File

@@ -44,6 +44,15 @@ namespace YooAsset
} }
} }
/// <summary>
/// 包裹优先级(值越大越优先更新)
/// </summary>
public uint PackagePriority
{
get { return OperationSystem.GetSchedulerPriority(PackageName); }
set { OperationSystem.SetSchedulerPriority(PackageName, value); }
}
internal ResourcePackage(string packageName) internal ResourcePackage(string packageName)
{ {

View File

@@ -5,6 +5,27 @@ using System.Text;
namespace YooAsset namespace YooAsset
{ {
/// <summary>
/// 时间工具类
/// </summary>
internal static class TimeUtility
{
/// <summary>
/// The real time in seconds since the game started
/// </summary>
public static double RealtimeSinceStartup
{
get
{
#if UNITY_2020_3_OR_NEWER
return UnityEngine.Time.realtimeSinceStartupAsDouble;
#else
return UnityEngine.Time.realtimeSinceStartup;
#endif
}
}
}
/// <summary> /// <summary>
/// 路径工具类 /// 路径工具类
/// </summary> /// </summary>

View File

@@ -59,6 +59,7 @@ namespace YooAsset
_driver.AddComponent<RemoteDebuggerInRuntime>(); _driver.AddComponent<RemoteDebuggerInRuntime>();
#endif #endif
// 初始化异步操作系统
OperationSystem.Initialize(); OperationSystem.Initialize();
} }
} }
@@ -75,8 +76,8 @@ namespace YooAsset
if (_driver != null) if (_driver != null)
GameObject.Destroy(_driver); GameObject.Destroy(_driver);
// 终止并清空所有包裹的异步操作 // 销毁异步操作系统
ClearAllPackageOperation(); OperationSystem.DestroyAll();
// 卸载所有AssetBundle // 卸载所有AssetBundle
AssetBundle.UnloadAllAssetBundles(true); AssetBundle.UnloadAllAssetBundles(true);
@@ -97,18 +98,6 @@ namespace YooAsset
} }
} }
/// <summary>
/// 终止并清空所有包裹的异步操作
/// </summary>
internal static void ClearAllPackageOperation()
{
foreach (var package in _packages)
{
OperationSystem.ClearPackageOperation(package.PackageName);
}
OperationSystem.DestroyAll();
}
/// <summary> /// <summary>
/// 创建资源包裹 /// 创建资源包裹
/// </summary> /// </summary>
@@ -123,7 +112,7 @@ namespace YooAsset
/// </summary> /// </summary>
/// <param name="packageName">包裹名称</param> /// <param name="packageName">包裹名称</param>
/// <param name="packagePriority">包裹优先级(值越大越优先更新)</param> /// <param name="packagePriority">包裹优先级(值越大越优先更新)</param>
public static ResourcePackage CreatePackage(string packageName, int packagePriority) public static ResourcePackage CreatePackage(string packageName, uint packagePriority)
{ {
CheckException(packageName); CheckException(packageName);
if (ContainsPackage(packageName)) if (ContainsPackage(packageName))

View File

@@ -25,7 +25,7 @@ namespace YooAsset
void OnApplicationQuit() void OnApplicationQuit()
{ {
// 说明在编辑器下确保播放被停止时IO类操作被终止。 // 说明在编辑器下确保播放被停止时IO类操作被终止。
YooAssets.ClearAllPackageOperation(); YooAssets.Destroy();
} }
#endif #endif