//------------------------------------------------------------
// Game Framework
// Copyright © 2013-2021 loyalsoft. All rights reserved.
// Homepage: http://www.game7000.com/
// Feedback: http://www.game7000.com/
//------------------------------------------------------------
using GameFramework.FileSystem;
using System;
using System.Collections.Generic;
using System.IO;
namespace GameFramework.Resource
{
internal sealed partial class ResourceManager : GameFrameworkModule, IResourceManager
{
private sealed partial class ResourceLoader
{
///
/// 加载资源代理。
///
private sealed partial class LoadResourceAgent : ITaskAgent
{
private static readonly Dictionary s_CachedResourceNames = new Dictionary(StringComparer.Ordinal);
private static readonly HashSet s_LoadingAssetNames = new HashSet(StringComparer.Ordinal);
private static readonly HashSet s_LoadingResourceNames = new HashSet(StringComparer.Ordinal);
private readonly ILoadResourceAgentHelper m_Helper;
private readonly IResourceHelper m_ResourceHelper;
private readonly ResourceLoader m_ResourceLoader;
private readonly string m_ReadOnlyPath;
private readonly string m_ReadWritePath;
private readonly DecryptResourceCallback m_DecryptResourceCallback;
private LoadResourceTaskBase m_Task;
///
/// 初始化加载资源代理的新实例。
///
/// 加载资源代理辅助器。
/// 资源辅助器。
/// 加载资源器。
/// 资源只读区路径。
/// 资源读写区路径。
/// 解密资源回调函数。
public LoadResourceAgent(ILoadResourceAgentHelper loadResourceAgentHelper, IResourceHelper resourceHelper, ResourceLoader resourceLoader, string readOnlyPath, string readWritePath, DecryptResourceCallback decryptResourceCallback)
{
if (loadResourceAgentHelper == null)
{
throw new GameFrameworkException("Load resource agent helper is invalid.");
}
if (resourceHelper == null)
{
throw new GameFrameworkException("Resource helper is invalid.");
}
if (resourceLoader == null)
{
throw new GameFrameworkException("Resource loader is invalid.");
}
if (decryptResourceCallback == null)
{
throw new GameFrameworkException("Decrypt resource callback is invalid.");
}
m_Helper = loadResourceAgentHelper;
m_ResourceHelper = resourceHelper;
m_ResourceLoader = resourceLoader;
m_ReadOnlyPath = readOnlyPath;
m_ReadWritePath = readWritePath;
m_DecryptResourceCallback = decryptResourceCallback;
m_Task = null;
}
public ILoadResourceAgentHelper Helper
{
get
{
return m_Helper;
}
}
///
/// 获取加载资源任务。
///
public LoadResourceTaskBase Task
{
get
{
return m_Task;
}
}
///
/// 初始化加载资源代理。
///
public void Initialize()
{
m_Helper.LoadResourceAgentHelperUpdate += OnLoadResourceAgentHelperUpdate;
m_Helper.LoadResourceAgentHelperReadFileComplete += OnLoadResourceAgentHelperReadFileComplete;
m_Helper.LoadResourceAgentHelperReadBytesComplete += OnLoadResourceAgentHelperReadBytesComplete;
m_Helper.LoadResourceAgentHelperParseBytesComplete += OnLoadResourceAgentHelperParseBytesComplete;
m_Helper.LoadResourceAgentHelperLoadComplete += OnLoadResourceAgentHelperLoadComplete;
m_Helper.LoadResourceAgentHelperError += OnLoadResourceAgentHelperError;
}
///
/// 加载资源代理轮询。
///
/// 逻辑流逝时间,以秒为单位。
/// 真实流逝时间,以秒为单位。
public void Update(float elapseSeconds, float realElapseSeconds)
{
}
///
/// 关闭并清理加载资源代理。
///
public void Shutdown()
{
Reset();
m_Helper.LoadResourceAgentHelperUpdate -= OnLoadResourceAgentHelperUpdate;
m_Helper.LoadResourceAgentHelperReadFileComplete -= OnLoadResourceAgentHelperReadFileComplete;
m_Helper.LoadResourceAgentHelperReadBytesComplete -= OnLoadResourceAgentHelperReadBytesComplete;
m_Helper.LoadResourceAgentHelperParseBytesComplete -= OnLoadResourceAgentHelperParseBytesComplete;
m_Helper.LoadResourceAgentHelperLoadComplete -= OnLoadResourceAgentHelperLoadComplete;
m_Helper.LoadResourceAgentHelperError -= OnLoadResourceAgentHelperError;
}
public static void Clear()
{
s_CachedResourceNames.Clear();
s_LoadingAssetNames.Clear();
s_LoadingResourceNames.Clear();
}
///
/// 开始处理加载资源任务。
///
/// 要处理的加载资源任务。
/// 开始处理任务的状态。
public StartTaskStatus Start(LoadResourceTaskBase task)
{
if (task == null)
{
throw new GameFrameworkException("Task is invalid.");
}
m_Task = task;
m_Task.StartTime = DateTime.UtcNow;
ResourceInfo resourceInfo = m_Task.ResourceInfo;
if (!resourceInfo.Ready)
{
m_Task.StartTime = default(DateTime);
return StartTaskStatus.HasToWait;
}
if (IsAssetLoading(m_Task.AssetName))
{
m_Task.StartTime = default(DateTime);
return StartTaskStatus.HasToWait;
}
if (!m_Task.IsScene)
{
AssetObject assetObject = m_ResourceLoader.m_AssetPool.Spawn(m_Task.AssetName);
if (assetObject != null)
{
OnAssetObjectReady(assetObject);
return StartTaskStatus.Done;
}
}
foreach (string dependencyAssetName in m_Task.GetDependencyAssetNames())
{
if (!m_ResourceLoader.m_AssetPool.CanSpawn(dependencyAssetName))
{
m_Task.StartTime = default(DateTime);
return StartTaskStatus.HasToWait;
}
}
string resourceName = resourceInfo.ResourceName.Name;
if (IsResourceLoading(resourceName))
{
m_Task.StartTime = default(DateTime);
return StartTaskStatus.HasToWait;
}
s_LoadingAssetNames.Add(m_Task.AssetName);
ResourceObject resourceObject = m_ResourceLoader.m_ResourcePool.Spawn(resourceName);
if (resourceObject != null)
{
OnResourceObjectReady(resourceObject);
return StartTaskStatus.CanResume;
}
s_LoadingResourceNames.Add(resourceName);
string fullPath = null;
if (!s_CachedResourceNames.TryGetValue(resourceName, out fullPath))
{
fullPath = Utility.Path.GetRegularPath(Path.Combine(resourceInfo.StorageInReadOnly ? m_ReadOnlyPath : m_ReadWritePath, resourceInfo.UseFileSystem ? resourceInfo.FileSystemName : resourceInfo.ResourceName.FullName));
s_CachedResourceNames.Add(resourceName, fullPath);
}
if (resourceInfo.LoadType == LoadType.LoadFromFile)
{
if (resourceInfo.UseFileSystem)
{
IFileSystem fileSystem = m_ResourceLoader.m_ResourceManager.GetFileSystem(resourceInfo.FileSystemName, resourceInfo.StorageInReadOnly);
m_Helper.ReadFile(fileSystem, resourceInfo.ResourceName.FullName);
}
else
{
m_Helper.ReadFile(fullPath);
}
}
else if (resourceInfo.LoadType == LoadType.LoadFromMemory || resourceInfo.LoadType == LoadType.LoadFromMemoryAndQuickDecrypt || resourceInfo.LoadType == LoadType.LoadFromMemoryAndDecrypt)
{
if (resourceInfo.UseFileSystem)
{
IFileSystem fileSystem = m_ResourceLoader.m_ResourceManager.GetFileSystem(resourceInfo.FileSystemName, resourceInfo.StorageInReadOnly);
m_Helper.ReadBytes(fileSystem, resourceInfo.ResourceName.FullName);
}
else
{
m_Helper.ReadBytes(fullPath);
}
}
else
{
throw new GameFrameworkException(Utility.Text.Format("Resource load type '{0}' is not supported.", resourceInfo.LoadType));
}
return StartTaskStatus.CanResume;
}
///
/// 重置加载资源代理。
///
public void Reset()
{
m_Helper.Reset();
m_Task = null;
}
private static bool IsAssetLoading(string assetName)
{
return s_LoadingAssetNames.Contains(assetName);
}
private static bool IsResourceLoading(string resourceName)
{
return s_LoadingResourceNames.Contains(resourceName);
}
private void OnAssetObjectReady(AssetObject assetObject)
{
m_Helper.Reset();
object asset = assetObject.Target;
if (m_Task.IsScene)
{
m_ResourceLoader.m_SceneToAssetMap.Add(m_Task.AssetName, asset);
}
m_Task.OnLoadAssetSuccess(this, asset, (float)(DateTime.UtcNow - m_Task.StartTime).TotalSeconds);
m_Task.Done = true;
}
private void OnResourceObjectReady(ResourceObject resourceObject)
{
m_Task.LoadMain(this, resourceObject);
}
private void OnError(LoadResourceStatus status, string errorMessage)
{
m_Helper.Reset();
m_Task.OnLoadAssetFailure(this, status, errorMessage);
s_LoadingAssetNames.Remove(m_Task.AssetName);
s_LoadingResourceNames.Remove(m_Task.ResourceInfo.ResourceName.Name);
m_Task.Done = true;
}
private void OnLoadResourceAgentHelperUpdate(object sender, LoadResourceAgentHelperUpdateEventArgs e)
{
m_Task.OnLoadAssetUpdate(this, e.Type, e.Progress);
}
private void OnLoadResourceAgentHelperReadFileComplete(object sender, LoadResourceAgentHelperReadFileCompleteEventArgs e)
{
ResourceObject resourceObject = ResourceObject.Create(m_Task.ResourceInfo.ResourceName.Name, e.Resource, m_ResourceHelper, m_ResourceLoader);
m_ResourceLoader.m_ResourcePool.Register(resourceObject, true);
s_LoadingResourceNames.Remove(m_Task.ResourceInfo.ResourceName.Name);
OnResourceObjectReady(resourceObject);
}
private void OnLoadResourceAgentHelperReadBytesComplete(object sender, LoadResourceAgentHelperReadBytesCompleteEventArgs e)
{
byte[] bytes = e.GetBytes();
ResourceInfo resourceInfo = m_Task.ResourceInfo;
if (resourceInfo.LoadType == LoadType.LoadFromMemoryAndQuickDecrypt || resourceInfo.LoadType == LoadType.LoadFromMemoryAndDecrypt)
{
m_DecryptResourceCallback(bytes, 0, bytes.Length, resourceInfo.ResourceName.Name, resourceInfo.ResourceName.Variant, resourceInfo.ResourceName.Extension, resourceInfo.StorageInReadOnly, resourceInfo.FileSystemName, (byte)resourceInfo.LoadType, resourceInfo.Length, resourceInfo.HashCode);
}
m_Helper.ParseBytes(bytes);
}
private void OnLoadResourceAgentHelperParseBytesComplete(object sender, LoadResourceAgentHelperParseBytesCompleteEventArgs e)
{
ResourceObject resourceObject = ResourceObject.Create(m_Task.ResourceInfo.ResourceName.Name, e.Resource, m_ResourceHelper, m_ResourceLoader);
m_ResourceLoader.m_ResourcePool.Register(resourceObject, true);
s_LoadingResourceNames.Remove(m_Task.ResourceInfo.ResourceName.Name);
OnResourceObjectReady(resourceObject);
}
private void OnLoadResourceAgentHelperLoadComplete(object sender, LoadResourceAgentHelperLoadCompleteEventArgs e)
{
AssetObject assetObject = null;
if (m_Task.IsScene)
{
assetObject = m_ResourceLoader.m_AssetPool.Spawn(m_Task.AssetName);
}
if (assetObject == null)
{
List