diff --git a/Assets/TEngine/Runtime/GameFramework/Resource/AssetTag.cs b/Assets/TEngine/Runtime/GameFramework/Resource/AssetTag.cs new file mode 100644 index 00000000..3b5790c2 --- /dev/null +++ b/Assets/TEngine/Runtime/GameFramework/Resource/AssetTag.cs @@ -0,0 +1,42 @@ +using UnityEngine; +using YooAsset; + +namespace TEngine +{ + /// + /// 资源标识。 + /// + [DisallowMultipleComponent, AddComponentMenu("")] + public sealed class AssetTag: MonoBehaviour + { + private AssetOperationHandle _operationHandle; + + private int _instanceID = 0; + + private string location; + + private void Awake() + { + if (location != null && (_instanceID == -1 || _instanceID != gameObject.GetInstanceID())) + { + // Bind(GetAsset(operation, assetLocation)); + } + } + + public void Bind(AssetOperationHandle operation,string assetLocation) + { + _operationHandle = operation; + this.location = assetLocation; + _instanceID = gameObject.GetInstanceID(); + } + + private void OnDestroy() + { + if (_operationHandle != null) + { + _operationHandle.Release(); + _operationHandle = null; + } + } + } +} \ No newline at end of file diff --git a/Assets/TEngine/Runtime/GameFramework/Resource/AssetTag.cs.meta b/Assets/TEngine/Runtime/GameFramework/Resource/AssetTag.cs.meta new file mode 100644 index 00000000..55aa5b44 --- /dev/null +++ b/Assets/TEngine/Runtime/GameFramework/Resource/AssetTag.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 854f63fe041d43f0ab0f76b1059eab89 +timeCreated: 1680592471 \ No newline at end of file diff --git a/Assets/TEngine/Runtime/GameFramework/Resource/HasAssetResult.cs b/Assets/TEngine/Runtime/GameFramework/Resource/HasAssetResult.cs index 99bcf951..c599bbc1 100644 --- a/Assets/TEngine/Runtime/GameFramework/Resource/HasAssetResult.cs +++ b/Assets/TEngine/Runtime/GameFramework/Resource/HasAssetResult.cs @@ -11,9 +11,9 @@ NotExist = 0, /// - /// 资源尚未准备完毕。 + /// 资源需要从远端更新下载。 /// - NotReady, + AssetOnline, /// /// 存在资源且存储在磁盘上。 @@ -33,6 +33,11 @@ /// /// 存在二进制资源且存储在文件系统里。 /// - BinaryOnFileSystem + BinaryOnFileSystem, + + /// + /// 资源定位地址无效。 + /// + Valid, } } diff --git a/Assets/TEngine/Runtime/GameFramework/Resource/IResourceManager.cs b/Assets/TEngine/Runtime/GameFramework/Resource/IResourceManager.cs index 1e66d407..74dd0789 100644 --- a/Assets/TEngine/Runtime/GameFramework/Resource/IResourceManager.cs +++ b/Assets/TEngine/Runtime/GameFramework/Resource/IResourceManager.cs @@ -1,6 +1,7 @@ using System.Threading; using Cysharp.Threading.Tasks; using UnityEngine; +using UnityEngine.SceneManagement; using YooAsset; namespace TEngine @@ -103,6 +104,70 @@ namespace TEngine /// 检查资源是否存在的结果。 HasAssetResult HasAsset(string assetName); + /// + /// 设置默认资源包。 + /// + /// 资源包。 + void SetDefaultPackage(ResourcePackage package); + + /// + /// 是否需要从远端更新下载。 + /// + /// 资源的定位地址。 + /// + bool IsNeedDownloadFromRemote(string location); + + /// + /// 是否需要从远端更新下载。 + /// + /// 资源信息。 + /// + bool IsNeedDownloadFromRemote(AssetInfo assetInfo); + + /// + /// 获取资源信息列表。 + /// + /// 资源标签。 + /// 资源信息列表。 + AssetInfo[] GetAssetInfos(string tag); + + /// + /// 获取资源信息列表。 + /// + /// 资源标签列表。 + /// 资源信息列表。 + AssetInfo[] GetAssetInfos(string[] tags); + + /// + /// 获取资源信息。 + /// + /// 资源的定位地址。 + /// 资源信息。 + AssetInfo GetAssetInfo(string location); + + /// + /// 检查资源定位地址是否有效。 + /// + /// 资源的定位地址 + bool CheckLocationValid(string location); + + /// + /// 同步加载资源。 + /// + /// 要加载资源的名称。 + /// 要加载资源的类型。 + /// 资源实例。 + T LoadAsset(string assetName) where T : Object; + + /// + /// 同步加载资源。 + /// + /// 要加载资源的名称。 + /// 父节点位置。 + /// 要加载资源的类型。 + /// 资源实例。 + T LoadAsset(string assetName, Transform parent) where T :Object; + /// /// 同步加载资源。 /// @@ -110,7 +175,7 @@ namespace TEngine /// 要加载资源的名称。 /// 要加载资源的类型。 /// 资源实例。 - T LoadAsset(string assetName,out AssetOperationHandle handle) where T : UnityEngine.Object; + T LoadAsset(string assetName,out AssetOperationHandle handle) where T : Object; /// /// 同步加载资源。 @@ -120,7 +185,7 @@ namespace TEngine /// 父节点位置。 /// 要加载资源的类型。 /// 资源实例。 - T LoadAsset(string assetName, Transform parent,out AssetOperationHandle handle) where T : UnityEngine.Object; + T LoadAsset(string assetName, Transform parent,out AssetOperationHandle handle) where T :Object; /// /// 异步加载资源。 @@ -129,7 +194,7 @@ namespace TEngine /// 取消操作Token。 /// 要加载资源的类型。 /// 异步资源实例。 - UniTask LoadAssetAsync(string assetName,CancellationToken cancellationToken) where T : UnityEngine.Object; + UniTask LoadAssetAsync(string assetName,CancellationToken cancellationToken) where T : Object; /// /// 异步加载游戏物体。 @@ -145,14 +210,34 @@ namespace TEngine /// 要加载资源的名称。 /// 要加载资源的类型。 /// 同步加载资源句柄。 - AssetOperationHandle LoadAssetGetOperation(string assetName) where T : UnityEngine.Object; + AssetOperationHandle LoadAssetGetOperation(string assetName) where T : Object; /// /// 异步加载资源并获取句柄。 /// /// 要加载资源的名称。 /// 要加载资源的类型。 - /// 同步加载资源句柄。 - AssetOperationHandle LoadAssetAsyncHandle(string assetName) where T : UnityEngine.Object; + /// 异步加载资源句柄。 + AssetOperationHandle LoadAssetAsyncHandle(string assetName) where T : Object; + + /// + /// 异步加载场景。 + /// + /// 场景的定位地址 + /// 场景加载模式 + /// 加载完毕时是否主动激活 + /// 优先级 + /// 异步加载场景句柄。 + SceneOperationHandle LoadSceneAsync(string location, LoadSceneMode sceneMode = LoadSceneMode.Single, bool activateOnLoad = true, int priority = 100); + + /// + /// 异步加载场景 + /// + /// 场景的资源信息 + /// 场景加载模式 + /// 加载完毕时是否主动激活 + /// 优先级 + /// 异步加载场景句柄。 + SceneOperationHandle LoadSceneAsync(AssetInfo assetInfo, LoadSceneMode sceneMode = LoadSceneMode.Single, bool activateOnLoad = true, int priority = 100); } } \ No newline at end of file diff --git a/Assets/TEngine/Runtime/GameFramework/Resource/ResourceManager.cs b/Assets/TEngine/Runtime/GameFramework/Resource/ResourceManager.cs index 6d528b11..365b7dd9 100644 --- a/Assets/TEngine/Runtime/GameFramework/Resource/ResourceManager.cs +++ b/Assets/TEngine/Runtime/GameFramework/Resource/ResourceManager.cs @@ -1,7 +1,7 @@ -using System.Diagnostics; -using System.Threading; +using System.Threading; using Cysharp.Threading.Tasks; using UnityEngine; +using UnityEngine.SceneManagement; using YooAsset; namespace TEngine @@ -70,40 +70,28 @@ namespace TEngine /// public long Milliseconds { get; set; } - /// - /// The total number of frames since the start of the game (Read Only). - /// - private static int _lastUpdateFrame = 0; - /// /// 获取游戏框架模块优先级。 /// /// 优先级较高的模块会优先轮询,并且关闭操作会后进行。 internal override int Priority => 4; + + /// + /// 资源服务器地址。 + /// + public string HostServerURL { get; set; } #endregion + #region 生命周期 internal override void Update(float elapseSeconds, float realElapseSeconds) { - DebugCheckDuplicateDriver(); - YooAssets.Update(); - } - - [Conditional("DEBUG")] - private void DebugCheckDuplicateDriver() - { - if (_lastUpdateFrame > 0) - { - if (_lastUpdateFrame == Time.frameCount) - YooLogger.Warning($"There are two {nameof(YooAssetsDriver)} in the scene. Please ensure there is always exactly one driver in the scene."); - } - - _lastUpdateFrame = Time.frameCount; } internal override void Shutdown() { YooAssets.Destroy(); } + #endregion #region 设置接口 /// @@ -137,14 +125,63 @@ namespace TEngine public void Initialize() { - throw new System.NotImplementedException(); + // 初始化资源系统 + YooAssets.Initialize(new YooAssetsLogger()); + YooAssets.SetOperationSystemMaxTimeSlice(Milliseconds); + YooAssets.SetCacheSystemCachedFileVerifyLevel(VerifyLevel); + + // 创建默认的资源包 + string packageName = PackageName; + var defaultPackage = YooAssets.TryGetPackage(packageName); + if (defaultPackage == null) + { + defaultPackage = YooAssets.CreatePackage(packageName); + YooAssets.SetDefaultPackage(defaultPackage); + } } public InitializationOperation InitPackage() { - throw new System.NotImplementedException(); - } + // 创建默认的资源包 + string packageName = PackageName; + var package = YooAssets.TryGetPackage(packageName); + if (package == null) + { + package = YooAssets.CreatePackage(packageName); + YooAssets.SetDefaultPackage(package); + } + // 编辑器下的模拟模式 + InitializationOperation initializationOperation = null; + if (PlayMode == EPlayMode.EditorSimulateMode) + { + var createParameters = new EditorSimulateModeParameters(); + createParameters.SimulateManifestFilePath = EditorSimulateModeHelper.SimulateBuild(packageName); + initializationOperation = package.InitializeAsync(createParameters); + } + + // 单机运行模式 + if (PlayMode == EPlayMode.OfflinePlayMode) + { + var createParameters = new OfflinePlayModeParameters(); + createParameters.DecryptionServices = new GameDecryptionServices(); + initializationOperation = package.InitializeAsync(createParameters); + } + + // 联机运行模式 + if (PlayMode == EPlayMode.HostPlayMode) + { + var createParameters = new HostPlayModeParameters(); + createParameters.DecryptionServices = new GameDecryptionServices(); + createParameters.QueryServices = new GameQueryServices(); + createParameters.DefaultHostServer = HostServerURL; + createParameters.FallbackHostServer = HostServerURL; + initializationOperation = package.InitializeAsync(createParameters); + } + + return initializationOperation; + } + public void UnloadAsset(object asset) { throw new System.NotImplementedException(); @@ -152,47 +189,318 @@ namespace TEngine public void UnloadUnusedAssets() { - throw new System.NotImplementedException(); + YooAssets.UnloadUnusedAssets(); } public void ForceUnloadAllAssets() { - throw new System.NotImplementedException(); + YooAssets.ForceUnloadAllAssets(); } public HasAssetResult HasAsset(string assetName) { - throw new System.NotImplementedException(); + if (string.IsNullOrEmpty(assetName)) + { + throw new GameFrameworkException("Asset name is invalid."); + } + + AssetInfo assetInfo = YooAssets.GetAssetInfo(assetName); + + if (!CheckLocationValid(assetName)) + { + return HasAssetResult.Valid; + } + + if (assetInfo == null) + { + return HasAssetResult.NotExist; + } + + if (IsNeedDownloadFromRemote(assetInfo)) + { + return HasAssetResult.AssetOnline; + } + + return HasAssetResult.AssetOnDisk; } + /// + /// 设置默认的资源包。 + /// + public void SetDefaultPackage(ResourcePackage package) + { + YooAssets.SetDefaultPackage(package); + } + + #region 资源信息 + + /// + /// 是否需要从远端更新下载。 + /// + /// 资源的定位地址 + public bool IsNeedDownloadFromRemote(string location) + { + return YooAssets.IsNeedDownloadFromRemote(location); + } + + /// + /// 是否需要从远端更新下载。 + /// + /// 资源信息。 + public bool IsNeedDownloadFromRemote(AssetInfo assetInfo) + { + return YooAssets.IsNeedDownloadFromRemote(assetInfo); + } + + /// + /// 获取资源信息列表。 + /// + /// 资源标签。 + /// 资源信息列表。 + public AssetInfo[] GetAssetInfos(string tag) + { + return YooAssets.GetAssetInfos(tag); + } + + /// + /// 获取资源信息列表。 + /// + /// 资源标签列表。 + /// 资源信息列表。 + public AssetInfo[] GetAssetInfos(string[] tags) + { + return YooAssets.GetAssetInfos(tags); + } + + /// + /// 获取资源信息。 + /// + /// 资源的定位地址。 + /// 资源信息。 + public AssetInfo GetAssetInfo(string location) + { + return YooAssets.GetAssetInfo(location); + } + + /// + /// 检查资源定位地址是否有效。 + /// + /// 资源的定位地址 + public bool CheckLocationValid(string location) + { + return YooAssets.CheckLocationValid(location); + } + + #endregion + /// + /// 同步加载资源。 + /// + /// 要加载资源的名称。 + /// 要加载资源的类型。 + /// 资源实例。 + public T LoadAsset(string assetName) where T : Object + { + if (string.IsNullOrEmpty(assetName)) + { + Log.Error("Asset name is invalid."); + return default; + } + AssetOperationHandle handle = YooAssets.LoadAssetSync(assetName); + + if (typeof(T) == typeof(GameObject)) + { + GameObject ret = handle.InstantiateSync(); + BindAssetTag(ret, handle, assetName); + return ret as T; + } + else + { + return handle.AssetObject as T; + } + } + + /// + /// 同步加载资源。 + /// + /// 要加载资源的名称。 + /// 父节点位置。 + /// 要加载资源的类型。 + /// 资源实例。 + public T LoadAsset(string assetName, Transform parent) where T : Object + { + if (string.IsNullOrEmpty(assetName)) + { + Log.Error("Asset name is invalid."); + return default; + } + AssetOperationHandle handle = YooAssets.LoadAssetSync(assetName); + + if (typeof(T) == typeof(GameObject)) + { + GameObject ret = handle.InstantiateSync(parent); + BindAssetTag(ret, handle, assetName); + return ret as T; + } + else + { + return handle.AssetObject as T; + } + } + + /// + /// 同步加载资源。 + /// + /// 资源操作句柄。 + /// 要加载资源的名称。 + /// 要加载资源的类型。 + /// 资源实例。 public T LoadAsset(string assetName,out AssetOperationHandle handle) where T : Object { - throw new System.NotImplementedException(); + handle = YooAssets.LoadAssetSync(assetName); + + if (string.IsNullOrEmpty(assetName)) + { + Log.Error("Asset name is invalid."); + return default; + } + + if (typeof(T) == typeof(GameObject)) + { + GameObject ret = handle.InstantiateSync(); + return ret as T; + } + else + { + return handle.AssetObject as T; + } } + /// + /// 同步加载资源。 + /// + /// 要加载资源的名称。 + /// 资源操作句柄。 + /// 父节点位置。 + /// 要加载资源的类型。 + /// 资源实例。 public T LoadAsset(string assetName, Transform parent,out AssetOperationHandle handle) where T : Object { - throw new System.NotImplementedException(); + handle = YooAssets.LoadAssetSync(assetName); + + if (string.IsNullOrEmpty(assetName)) + { + Log.Error("Asset name is invalid."); + return default; + } + + if (typeof(T) == typeof(GameObject)) + { + GameObject ret = handle.InstantiateSync(parent); + return ret as T; + } + else + { + return handle.AssetObject as T; + } } - public UniTask LoadAssetAsync(string assetName, CancellationToken cancellationToken) where T : Object + /// + /// 异步加载资源实例。 + /// + /// 要加载的实例名称。 + /// 取消操作Token。 + /// 资源实实例。 + public async UniTask LoadAssetAsync(string assetName, CancellationToken cancellationToken) where T : Object { - throw new System.NotImplementedException(); + AssetOperationHandle handle = LoadAssetAsyncHandle(assetName); + + await handle.ToUniTask(cancellationToken:cancellationToken); + + return handle.AssetObject as T; } - public UniTask LoadGameObjectAsync(string assetName, CancellationToken cancellationToken) + /// + /// 异步加载游戏物体。 + /// + /// 要加载的游戏物体名称。 + /// 取消操作Token。 + /// 异步游戏物体实例。 + public async UniTask LoadGameObjectAsync(string assetName, CancellationToken cancellationToken) { - throw new System.NotImplementedException(); + AssetOperationHandle handle = LoadAssetAsyncHandle(assetName); + + await handle.ToUniTask(cancellationToken:cancellationToken); + + GameObject ret = handle.InstantiateSync(); + + BindAssetTag(ret, handle, assetName); + + return ret; } + /// + /// 同步加载资源并获取句柄。 + /// + /// 要加载资源的名称。 + /// 要加载资源的类型。 + /// 同步加载资源句柄。 public AssetOperationHandle LoadAssetGetOperation(string assetName) where T : Object { - throw new System.NotImplementedException(); + return YooAssets.LoadAssetSync(assetName); } + /// + /// 异步加载资源并获取句柄。 + /// + /// 要加载资源的名称。 + /// 要加载资源的类型。 + /// 异步加载资源句柄。 public AssetOperationHandle LoadAssetAsyncHandle(string assetName) where T : Object { - throw new System.NotImplementedException(); + return YooAssets.LoadAssetAsync(assetName); + } + + /// + /// 异步加载场景。 + /// + /// 场景的定位地址 + /// 场景加载模式 + /// 加载完毕时是否主动激活 + /// 优先级 + /// 异步加载场景句柄。 + public SceneOperationHandle LoadSceneAsync(string location, LoadSceneMode sceneMode = LoadSceneMode.Single, bool activateOnLoad = true, int priority = 100) + { + return YooAssets.LoadSceneAsync(location,sceneMode,activateOnLoad,priority); + } + + /// + /// 异步加载场景 + /// + /// 场景的资源信息 + /// 场景加载模式 + /// 加载完毕时是否主动激活 + /// 优先级 + /// 异步加载场景句柄。 + public SceneOperationHandle LoadSceneAsync(AssetInfo assetInfo, LoadSceneMode sceneMode = LoadSceneMode.Single, bool activateOnLoad = true, int priority = 100) + { + return YooAssets.LoadSceneAsync(assetInfo,sceneMode,activateOnLoad,priority); + } + + private bool BindAssetTag(GameObject go,AssetOperationHandle handle,string location) + { + if (go == null) + { + throw new GameFrameworkException($"ResourceMgr BindAssetTag Failed! GameObject is null!"); + } + + if (handle == null) + { + throw new GameFrameworkException($"ResourceMgr BindAssetTag Failed! AssetOperationHandle is null!"); + } + + go.AddComponent().Bind(handle,location); + + return true; } } } \ No newline at end of file diff --git a/Assets/TEngine/Runtime/GameFramework/Resource/YooAsset/YooAssetsExtension.cs b/Assets/TEngine/Runtime/GameFramework/Resource/YooAsset/YooAssetsExtension.cs index 1e0220bf..5f7ebb6c 100644 --- a/Assets/TEngine/Runtime/GameFramework/Resource/YooAsset/YooAssetsExtension.cs +++ b/Assets/TEngine/Runtime/GameFramework/Resource/YooAsset/YooAssetsExtension.cs @@ -405,6 +405,28 @@ namespace YooAsset return _defaultPackage.CreateResourceUnpacker(unpackingMaxNumber, failedTryAgain); } #endregion + + #region 资源卸载 + + /// + /// 资源回收(卸载引用计数为零的资源) + /// + public static void UnloadUnusedAssets() + { + DebugCheckDefaultPackageValid(); + _defaultPackage.UnloadUnusedAssets(); + } + + /// + /// 强制回收所有资源 + /// + public static void ForceUnloadAllAssets() + { + DebugCheckDefaultPackageValid(); + _defaultPackage.ForceUnloadAllAssets(); + } + + #endregion #region 调试方法 [Conditional("DEBUG")]