| | |
| | | using UnityEngine; |
| | | using UnityEngine; |
| | | using System.Collections.Generic; |
| | | using System; |
| | | using UnityEngine.U2D; |
| | |
| | | using Cysharp.Threading.Tasks; |
| | | using System.Threading; |
| | | using ProjSG.Resource; |
| | | |
| | | |
| | | |
| | | using YooAsset; |
| | | |
| | | |
| | | #if UNITY_EDITOR |
| | |
| | | |
| | | public void Init() |
| | | { |
| | | |
| | | |
| | | } |
| | | |
| | | public void Release() |
| | |
| | | } |
| | | #endif |
| | | |
| | | // ==================================================================== |
| | | // 同步方法(仅非 WebGL 平台) |
| | | // ==================================================================== |
| | | #if !UNITY_WEBGL |
| | | //needExt 是否需要函数内部添加后缀 |
| | | [System.Obsolete("US2: Use LoadAssetAsync<T>(directory, name, needExt) returning UniTask<T> instead.")] |
| | | public T LoadAsset<T>(string directory, string name, bool needExt = true) where T : UnityEngine.Object |
| | | { |
| | | directory = directory.Replace("\\", "/"); |
| | |
| | | directory += name.Substring(0, name.LastIndexOf("/")); |
| | | name = name.Substring(name.LastIndexOf("/") + 1); |
| | | } |
| | | |
| | | } |
| | | |
| | | return LoadAssetInternal<T>(directory, name, needExt); |
| | |
| | | } |
| | | else |
| | | { |
| | | // US1: Route through YooAssetService sync wrapper (transitional) |
| | | #pragma warning disable CS0612, CS0618 |
| | | asset = YooAssetService.Instance.LoadAssetSync<T>(path); |
| | | #pragma warning restore CS0612, CS0618 |
| | | } |
| | | |
| | | if (asset == null) |
| | |
| | | return asset; |
| | | } |
| | | |
| | | [System.Obsolete("US2: Use LoadConfigAsync returning UniTask<string[]> instead.")] |
| | | public string[] LoadConfig(string name) |
| | | { |
| | | string path = string.Empty; |
| | | #if UNITY_EDITOR |
| | | if (!AssetSource.isUseAssetBundle) |
| | | { |
| | | path = ResourcesPath.CONFIG_FODLER + "/" + name + ".txt"; |
| | | string path = ResourcesPath.CONFIG_FODLER + "/" + name + ".txt"; |
| | | return File.ReadAllLines(path); |
| | | } |
| | | else |
| | | #endif |
| | | { |
| | | path = AssetVersionUtility.GetAssetFilePath($"config/{name}.txt"); |
| | | } |
| | | |
| | | return File.ReadAllLines(path); |
| | | // AB 模式:通过 YooAsset 同步加载 TextAsset |
| | | var location = $"Assets/ResourcesOut/Config/{name}.txt"; |
| | | var textAsset = YooAssetService.Instance.LoadAssetSync<TextAsset>(location); |
| | | if (textAsset != null && !string.IsNullOrEmpty(textAsset.text)) |
| | | return textAsset.text.Split(new[] { "\r\n", "\n" }, StringSplitOptions.None); |
| | | Debug.LogError($"[ResManager] LoadConfig failed for '{name}'"); |
| | | return Array.Empty<string>(); |
| | | } |
| | | |
| | | private Sprite LoadSprite(string atlasName, string spriteName) |
| | | { |
| | | if (!AssetSource.isUseAssetBundle) |
| | | { |
| | | #pragma warning disable CS0618 // Obsolete — legacy sync fallback |
| | | SpriteAtlas atlas = LoadAsset<SpriteAtlas>("Sprite", atlasName.Replace("Sprite/", "")); |
| | | #pragma warning restore CS0618 |
| | | if (null == atlas) |
| | | { |
| | | return null; |
| | |
| | | return atlas.GetSprite(spriteName); |
| | | } |
| | | else |
| | | return LoadAssetInternal<Sprite>(atlasName, spriteName); |
| | | { |
| | | // YooAsset 使用完整路径直接加载 Sprite |
| | | var path = $"Assets/ResourcesOut/{atlasName}/{spriteName}.png".Replace("//", "/"); |
| | | return YooAssetService.Instance.LoadAssetSync<Sprite>(path); |
| | | } |
| | | } |
| | | #endif |
| | | |
| | | //needExt 是否需要函数内部添加后缀 |
| | | [System.Obsolete("US2: Use LoadAssetAsync<T>(directory, name, needExt) returning UniTask<T> instead.")] |
| | | // ==================================================================== |
| | | // 异步加载方法(所有平台统一) |
| | | // ==================================================================== |
| | | |
| | | //needExt 是否需要函数内部添加后缀(回调版本) |
| | | public void LoadAssetAsync<T>(string directory, string name, Action<bool, UnityEngine.Object> callBack, bool needExt = true) where T : UnityEngine.Object |
| | | { |
| | | directory = directory.Replace("\\", "/"); |
| | |
| | | LoadSpriteAsync<T>(directory, name, callBack); |
| | | return; |
| | | } |
| | | else if (typeof(T) == typeof(SkeletonDataAsset)) |
| | | { |
| | | //文件目录调整,name中包含了路径 |
| | | if (name.Contains("/")) |
| | | { |
| | | directory += name.Substring(0, name.LastIndexOf("/")); |
| | | name = name.Substring(name.LastIndexOf("/") + 1); |
| | | } |
| | | } |
| | | |
| | | LoadAssetAsyncInternal<T>(directory, name, callBack, needExt); |
| | | } |
| | | |
| | | public async UniTask<T> LoadAssetAsync<T>(string directory, string name) where T : UnityEngine.Object |
| | | { |
| | | return await LoadAssetAsync<T>(directory, name, needExt: true); |
| | | } |
| | | |
| | | public async UniTask<T> LoadAssetAsync<T>(string directory, string name, bool needExt = true, CancellationToken ct = default) where T : UnityEngine.Object |
| | | { |
| | | directory = directory.Replace("\\", "/"); |
| | | name = name.Replace("\\", "/"); |
| | | |
| | | if (typeof(T) == typeof(Sprite)) |
| | | { |
| | | return await LoadSpriteAsyncUniTask(directory, name, ct) as T; |
| | | } |
| | | |
| | | if (typeof(T) == typeof(SkeletonDataAsset)) |
| | | { |
| | | if (name.Contains("/")) |
| | | { |
| | | directory += name.Substring(0, name.LastIndexOf("/")); |
| | | name = name.Substring(name.LastIndexOf("/") + 1); |
| | | } |
| | | } |
| | | |
| | | var path = ($"Assets/ResourcesOut/{directory}/{name}" + (needExt ? GetExtension(typeof(T)) : "")) |
| | | .Replace("//", "/").Trim().Replace("\\", "/"); |
| | | // 音频文件扩展名统一转小写,避免 .WAV/.MP3 大小写不匹配 |
| | | if (typeof(T) == typeof(AudioClip)) |
| | | { |
| | | var pathExt = System.IO.Path.GetExtension(path); |
| | | if (!string.IsNullOrEmpty(pathExt) && pathExt != pathExt.ToLower()) |
| | | path = path.Substring(0, path.Length - pathExt.Length) + pathExt.ToLower(); |
| | | } |
| | | if (!AssetSource.isUseAssetBundle) |
| | | { |
| | | #if UNITY_EDITOR |
| | | return UnityEditor.AssetDatabase.LoadAssetAtPath<T>(path); |
| | | #else |
| | | return null; |
| | | #endif |
| | | } |
| | | |
| | | return await YooAssetService.Instance.LoadAssetAsync<T>(path, ct: ct); |
| | | } |
| | | |
| | | // ==================================================================== |
| | | // 异步内部实现(统一) |
| | | // ==================================================================== |
| | | |
| | | private void LoadSpriteAsync<T>(string atlasName, string spriteName, Action<bool, UnityEngine.Object> callBack) where T : UnityEngine.Object |
| | | { |
| | |
| | | } |
| | | else |
| | | { |
| | | // US1: Route through YooAssetService async |
| | | CoLoadViaYooAsset<T>(path, callBack).Forget(); |
| | | } |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | [System.Obsolete("US1: Use YooAssetService.ReleaseHandle or UnloadUnusedAssetsAsync instead.")] |
| | | public void UnloadAsset(string assetBundleName, string assetName) |
| | | public void UnloadAsset(string directory, string assetName) |
| | | { |
| | | // US1: AssetBundleUtility unload no longer effective since assets loaded via YooAsset. |
| | | // Proper unload handled via YooAssetService handle-based release. |
| | | } |
| | | if (!AssetSource.isUseAssetBundle) |
| | | return; |
| | | |
| | | [System.Obsolete("US1: Use YooAssetService.UnloadUnusedAssetsAsync instead.")] |
| | | public void UnloadAssetBundle(string assetBundleName, bool unloadAllLoadedObjects, bool includeDependenice) |
| | | { |
| | | // US1: AssetBundleUtility unload no longer effective since assets loaded via YooAsset. |
| | | directory = directory.Replace("\\", "/").TrimEnd('/'); |
| | | assetName = assetName.Replace("\\", "/"); |
| | | string path = ($"Assets/ResourcesOut/{directory}/{assetName}").Replace("//", "/"); |
| | | YooAssetService.Instance.UnloadAsset(path); |
| | | } |
| | | |
| | | public string GetAssetFilePath(string _assetKey) |
| | |
| | | } |
| | | |
| | | // ==================================================================== |
| | | // US1: New UniTask-based async variants |
| | | // LoadConfigAsync(所有平台统一) |
| | | // ==================================================================== |
| | | |
| | | /// <summary> |
| | | /// 异步加载资源(UniTask 版本,US1 新增)。 |
| | | /// 异步加载配置文件。 |
| | | /// AB 模式使用 YooAsset 异步加载 TextAsset,非 AB 模式直接读文件。 |
| | | /// </summary> |
| | | public async UniTask<T> LoadAssetAsync<T>(string directory, string name, bool needExt = true, CancellationToken ct = default) where T : UnityEngine.Object |
| | | public async UniTask<string[]> LoadConfigAsync(string name, bool needExt = true, CancellationToken ct = default) |
| | | { |
| | | directory = directory.Replace("\\", "/"); |
| | | name = name.Replace("\\", "/"); |
| | | |
| | | if (typeof(T) == typeof(Sprite)) |
| | | if (AssetSource.isUseAssetBundle) |
| | | { |
| | | return await LoadSpriteAsyncUniTask(directory, name, ct) as T; |
| | | } |
| | | |
| | | if (typeof(T) == typeof(SkeletonDataAsset)) |
| | | { |
| | | if (name.Contains("/")) |
| | | if (name.EndsWith(".txt") && needExt) |
| | | { |
| | | directory += name.Substring(0, name.LastIndexOf("/")); |
| | | name = name.Substring(name.LastIndexOf("/") + 1); |
| | | name = name.Substring(0, name.Length - 4); |
| | | } |
| | | var location = $"Assets/ResourcesOut/Config/{name}" + (needExt ? ".txt" : ""); |
| | | try |
| | | { |
| | | var asset = await YooAssetService.Instance.LoadAssetAsync( |
| | | location, typeof(TextAsset), 0, ct) as TextAsset; |
| | | if (asset != null && !string.IsNullOrEmpty(asset.text)) |
| | | return asset.text.Split(new[] { "\r\n", "\n" }, StringSplitOptions.None); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | Debug.LogError($"[ResManager] LoadConfigAsync YooAsset failed for '{name}': {ex.Message}"); |
| | | } |
| | | return Array.Empty<string>(); |
| | | } |
| | | |
| | | var path = ($"Assets/ResourcesOut/{directory}/{name}" + (needExt ? GetExtension(typeof(T)) : "")) |
| | | .Replace("//", "/").Trim().Replace("\\", "/"); |
| | | |
| | | if (!AssetSource.isUseAssetBundle) |
| | | { |
| | | // 非 AB 模式: 直接读文件(Editor 开发模式) |
| | | #if UNITY_EDITOR |
| | | return UnityEditor.AssetDatabase.LoadAssetAtPath<T>(path); |
| | | string path = ResourcesPath.CONFIG_FODLER + "/" + name + (needExt ? ".txt" : ""); |
| | | return await UniTask.RunOnThreadPool(() => File.ReadAllLines(path)); |
| | | #else |
| | | return null; |
| | | return Array.Empty<string>(); |
| | | #endif |
| | | } |
| | | |
| | | return await YooAssetService.Instance.LoadAssetAsync<T>(path, ct: ct); |
| | | } |
| | | |
| | | // ==================================================================== |
| | | // 缓存加载 & Sprite 异步加载(所有平台) |
| | | // ==================================================================== |
| | | |
| | | /// <summary> |
| | | /// US4: 异步加载资源并走缓存层(缓存命中直接返回,未命中则加载并缓存)。 |
| | | /// 异步加载资源并走缓存层(缓存命中直接返回,未命中则加载并缓存)。 |
| | | /// </summary> |
| | | public async UniTask<T> LoadAssetCachedAsync<T>(string directory, string name, bool needExt = true, CancellationToken ct = default) where T : UnityEngine.Object |
| | | { |
| | |
| | | |
| | | var path = ($"Assets/ResourcesOut/{directory}/{name}" + (needExt ? GetExtension(typeof(T)) : "")) |
| | | .Replace("//", "/").Trim().Replace("\\", "/"); |
| | | |
| | | // 音频文件扩展名统一转小写 |
| | | if (typeof(T) == typeof(AudioClip)) |
| | | { |
| | | var pathExt2 = System.IO.Path.GetExtension(path); |
| | | if (!string.IsNullOrEmpty(pathExt2) && pathExt2 != pathExt2.ToLower()) |
| | | path = path.Substring(0, path.Length - pathExt2.Length) + pathExt2.ToLower(); |
| | | } |
| | | if (!AssetSource.isUseAssetBundle) |
| | | { |
| | | #if UNITY_EDITOR |
| | |
| | | { |
| | | var path = $"Assets/ResourcesOut/{atlasName}/{spriteName}.png" |
| | | .Replace("//", "/").Trim().Replace("\\", "/"); |
| | | return await YooAssetService.Instance.LoadAssetAsync<Sprite>(path, ct: ct); |
| | | var sprite = await YooAssetService.Instance.LoadAssetAsync<Sprite>(path, ct: ct); |
| | | if (sprite == null) |
| | | Debug.LogWarning($"[ResManager] Sprite load returned NULL: path={path}"); |
| | | return sprite; |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 异步加载配置文件(UniTask 版本)。 |
| | | /// WebGL 平台使用 YooAsset RawFile 异步加载,其他平台使用线程池。 |
| | | /// </summary> |
| | | public async UniTask<string[]> LoadConfigAsync(string name, CancellationToken ct = default) |
| | | { |
| | | #if UNITY_WEBGL && !UNITY_EDITOR |
| | | // WebGL 不支持多线程和 File.ReadAllLines,使用 YooAsset RawFile |
| | | try |
| | | { |
| | | var text = await ProjSG.Resource.YooAssetService.Instance.LoadRawFileTextAsync($"config/{name}", ct); |
| | | if (!string.IsNullOrEmpty(text)) |
| | | { |
| | | return text.Split(new[] { "\r\n", "\n" }, System.StringSplitOptions.None); |
| | | } |
| | | } |
| | | catch (System.Exception ex) |
| | | { |
| | | UnityEngine.Debug.LogError($"[ResManager] LoadConfigAsync WebGL fallback failed for '{name}': {ex.Message}"); |
| | | } |
| | | return System.Array.Empty<string>(); |
| | | #else |
| | | #pragma warning disable CS0618 // LoadConfig is obsolete — used here as thread-pool fallback for non-WebGL |
| | | return await UniTask.RunOnThreadPool(() => LoadConfig(name)); |
| | | #pragma warning restore CS0618 |
| | | #endif |
| | | } |
| | | |
| | | } |
| | | } |