Files
JJBB/Assets/Project/Script/AssetManagement/AsyncLoadBase/AsyncLoadHub.cs
2024-08-23 15:49:34 +08:00

209 lines
6.3 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
namespace AssetManagement
{
/// <summary>
/// 抽象类型:异步加载管理工具
/// </summary>
public abstract class AsyncLoadHub<T> where T : AsyncLoadUnit, new()
{
public event UnityAction<T> onComplete;
public List<AsyncLoadRule> rules;
public readonly List<T> activeUnits = new List<T>();
public readonly AsyncLoadQueue<T> waitQueue = new AsyncLoadQueue<T>();
protected AssetPathHub pathHub;
public void Init(AssetPathHub pathHub, List<AsyncLoadRule> rules)
{
this.pathHub = pathHub;
this.rules = rules;
this.rules.Sort((a, b) => a.priority.CompareTo(b.priority));
}
public T LoadUnit(string assetName, int priority = 0)
{
var unit = activeUnits.Find(a => a.name == assetName);
if (unit == null)
{
var waitState = waitQueue.TrySetPriority(assetName, priority, out unit);
switch (waitState)
{
case SetPriorityResult.NoItem:
{
unit = new T();
unit.Init(pathHub, assetName, priority);
if (CanActive(unit.priority))
ActivateUnit(unit);
else
waitQueue.AddInQueue(unit);
break;
}
case SetPriorityResult.NoUpdate:
// Nothing Happened
break;
case SetPriorityResult.Update:
if (CanActive(priority))
ActivateWaitUnits(1);
break;
default:
throw new ArgumentOutOfRangeException();
}
}
else if (unit.priority < priority)
unit.priority = priority;
return unit;
}
// 注加载中的单位是不可停止的Unity机制限制
/// <summary>
/// 停止一个加载单位,返回是否可以停止
/// </summary>
public bool StopUnit(T unit)
{
var result = false;
if (waitQueue.RemoveInQueue(unit.name))
result = true;
else if (activeUnits.Find(a => a.name == unit.name) == null)
result = true;
return result;
}
private void OnLoadComplete(AsyncLoadUnit unit)
{
var activeUnit = unit as T;
if (activeUnit == null)
Debug.LogError(string.Format("Cannot convert unit {0} to {1}!", unit.GetType(), typeof(T)));
else
{
activeUnits.Remove(activeUnit);
if (onComplete != null)
onComplete.Invoke(activeUnit);
ActivateWaitUnits(1);
}
}
private void ActivateWaitUnits(int count)
{
for (var i = 0; i < count; i++)
{
if (waitQueue.list.Count < 1)
break;
var last = waitQueue.list.Count - 1;
var unit = waitQueue.list[last];
if (!CanActive(unit.priority))
break;
waitQueue.list.RemoveAt(last);
ActivateUnit(unit);
}
}
private void ActivateUnit(T unit)
{
activeUnits.Add(unit);
unit.onComplete += OnLoadComplete;
unit.Load();
}
private bool CanActive(int priority)
{
return GetMaxActive(priority) > activeUnits.Count;
}
private int GetMaxActive(int priority)
{
var result = -1;
foreach (var rule in rules)
{
if (rule.priority > priority)
result = rule.maxActive;
}
return result;
}
}
public class AsyncLoadQueue<T> where T : AsyncLoadUnit, new()
{
public readonly List<T> list = new List<T>();
public bool RemoveInQueue(string name)
{
var result = false;
for (var i = 0; i < list.Count; i++)
{
if (list[i].name == name)
{
result = true;
list.RemoveAt(i);
break;
}
}
return result;
}
public void AddInQueue(T actionUnit)
{
var add = true;
for (var i = 0; i < list.Count; i++)
{
if (list[i].priority >= actionUnit.priority)
{
add = false;
list.Insert(i, actionUnit);
break;
}
}
if (add)
list.Add(actionUnit);
}
public SetPriorityResult TrySetPriority(string name, int priority, out T unit)
{
unit = null;
var result = SetPriorityResult.NoItem;
for (var i = 0; i < list.Count; i++)
if (list[i].name == name)
{
unit = list[i];
if (priority > list[i].priority && i < list.Count - 1)
{
result = SetPriorityResult.Update;
var actionUnit = list[i];
actionUnit.priority = priority;
list.RemoveAt(i);
AddInQueue(actionUnit);
}
else
result = SetPriorityResult.NoUpdate;
break;
}
return result;
}
}
public enum SetPriorityResult
{
NoItem,
NoUpdate,
Update,
}
/// <summary>
/// 加载规则小于该优先的物体不能同时加载超过maxActive
/// </summary>
public class AsyncLoadRule
{
public int priority;
public int maxActive;
public AsyncLoadRule(int priority, int maxActive)
{
this.priority = priority;
this.maxActive = maxActive;
}
}
}