using XGame.Framework.Asyncs;
using System.Collections.Generic;
namespace XGame.Framework.Asset
{
///
/// 加载任务的异步操作池
///
internal sealed class AssetAsyncPool
{
///
/// 未使用的Agents
///
Stack FreeAgents { set; get; }
///
/// 使用中的Agents
///
//LinkedList WorkingAgents { set; get; }
Dictionary WorkingAgents { set; get; }
///
/// 等待处理的Async
///
LinkedList WaitingAsyncs { set; get; }
///
/// 存储所有未完成的Async,方便查找
///
Dictionary AssetAsyncMap { set; get; }
///
/// 是否被暂停。
///
public bool Paused { set; get; }
///
/// agent的数量上限
///
public int AgentLimit { set; get; }
///
/// 构造函数。
///
public AssetAsyncPool()
{
FreeAgents = new Stack();
WorkingAgents = new Dictionary();
WaitingAsyncs = new LinkedList();
AssetAsyncMap = new Dictionary();
Paused = false;
AgentLimit = 0;
}
///
/// 获取代理总数量。
/// 包括使用中和未使用的代理,不一定等于AgentLimit
///
public int TotalAgentCount => (FreeAgentCount + WorkingAgentCount);
///
/// 获取可用代理数量。
/// 仅返回缓存池中未使用的代理数量
///
public int FreeAgentCount => FreeAgents.Count;
///
/// 获取工作中代理数量。
///
public int WorkingAgentCount => WorkingAgents.Count;
///
/// 获取等待Async数量。
///
public int WaitingAsyncCount => WaitingAsyncs.Count;
///
/// 获取未完成的Async
///
///
///
public IAssetAsync GetAssetAsync(string addressableName)
{
AssetAsyncMap.TryGetValue(addressableName, out IAssetAsync assetAsync);
return assetAsync;
}
///
/// 是否包含指定的Async
///
///
///
public bool ContainsAssetAsync(string addressableName)
{
return AssetAsyncMap.ContainsKey(addressableName);
}
///
/// 获取未使用的Agent
/// 可能从缓存里取,也可能是新建的Agent
///
///
private IAssetAsyncAgent GetFreeAgent()
{
if (FreeAgents.Count > 0)
{
return FreeAgents.Pop();
}
if (TotalAgentCount < AgentLimit)
{
var agent = new AssetAsyncAgent();
return agent;
}
return null;
}
///
/// 增加AssetAsync。
///
///
public void AddAsync(IAssetAsync assetAsync)
{
if (AssetAsyncMap.ContainsKey(assetAsync.AddressableName))
{
//AssetsLog.Debug("Asset Add Async Repeat. Name:{0}", assetAsync.AddressableName);
return;
}
AssetAsyncMap.Add(assetAsync.AddressableName, assetAsync);
LinkedListNode current = WaitingAsyncs.Last;
if (current != null)
{
WaitingAsyncs.AddAfter(current, assetAsync);
}
else
{
WaitingAsyncs.AddFirst(assetAsync);
}
ProcessWaitingAsync();
}
/////
///// 移除任务。
/////
///// 要移除任务的序列编号。
///// 被移除的任务。
//public bool RemoveAsync(int serialId)
//{
// foreach (IAssetAsync waitingAsync in WaitingAsyncs)
// {
// if (waitingAsync.SerialId == serialId)
// {
// WaitingAsyncs.Remove(waitingAsync);
// return true;
// }
// }
// foreach (IAssetAsyncAgent workingAgent in WorkingAgents)
// {
// if (workingAgent.Task.SerialId == serialId)
// {
// workingAgent.Stop();
// m_FreeAgents.Push(workingAgent);
// WorkingAgents.Remove(workingAgent);
// return true;
// }
// }
// return false;
//}
private void ProcessWaitingAsync()
{
LinkedListNode current = WaitingAsyncs.First;
IAssetAsyncAgent agent;
while (current != null && (agent = GetFreeAgent()) != null)
{
LinkedListNode next = current.Next;
AgentStatus status = agent.Start(current.Value);
if (status == AgentStatus.CanResume)
{//设置监听
current.Value.On(OnAsyncCompleted);
WorkingAgents.Add(current.Value, agent);
}
else
{
agent.Stop();
FreeAgents.Push(agent);
if (status == AgentStatus.Done || status == AgentStatus.UnknownError)
{
AssetAsyncMap.Remove(current.Value.AddressableName);
}
}
if (status != AgentStatus.HasToWait)
{
WaitingAsyncs.Remove(current);
}
current = next;
}
}
void OnAsyncCompleted(IAsync aAsync)
{
IAssetAsync assetAsync = aAsync as IAssetAsync;
if (assetAsync != null)
{
if (WorkingAgents.TryGetValue(assetAsync, out IAssetAsyncAgent agent))
{
agent.Stop();
WorkingAgents.Remove(assetAsync);
FreeAgents.Push(agent);
}
AssetAsyncMap.Remove(assetAsync.AddressableName);
}
ProcessWaitingAsync();
}
///
/// 移除所有任务。
///
public void Clear()
{
WaitingAsyncs.Clear();
AssetAsyncMap.Clear();
foreach (var it in WorkingAgents)
{
it.Value.Stop();
FreeAgents.Push(it.Value);
}
WorkingAgents.Clear();
}
public void Dispose()
{
WaitingAsyncs.Clear();
while (FreeAgentCount > 0)
{
FreeAgents.Pop().Dispose();
}
foreach (var it in WorkingAgents)
{
it.Value.Dispose();
}
WorkingAgents.Clear();
AssetAsyncMap.Clear();
}
}
}