//------------------------------------------------------------ // 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 dependencyAssets = m_Task.GetDependencyAssets(); assetObject = AssetObject.Create(m_Task.AssetName, e.Asset, dependencyAssets, m_Task.ResourceObject.Target, m_ResourceHelper, m_ResourceLoader); m_ResourceLoader.m_AssetPool.Register(assetObject, true); m_ResourceLoader.m_AssetToResourceMap.Add(e.Asset, m_Task.ResourceObject.Target); foreach (object dependencyAsset in dependencyAssets) { object dependencyResource = null; if (m_ResourceLoader.m_AssetToResourceMap.TryGetValue(dependencyAsset, out dependencyResource)) { m_Task.ResourceObject.AddDependencyResource(dependencyResource); } else { throw new GameFrameworkException("Can not find dependency resource."); } } } s_LoadingAssetNames.Remove(m_Task.AssetName); OnAssetObjectReady(assetObject); } private void OnLoadResourceAgentHelperError(object sender, LoadResourceAgentHelperErrorEventArgs e) { OnError(e.Status, e.ErrorMessage); } } } } }