From 325e1e25b68eb3b5e9aa31f335cd15add21b5e6b Mon Sep 17 00:00:00 2001 From: HungDK <> Date: Thu, 25 Dec 2025 16:41:11 +0700 Subject: [PATCH] Update Addressable manager --- .../Scripts/Addressable/AddressableManager.cs | 114 ++++++++++++++++-- .../Common/DataProcess/elementdataman.cs | 10 +- 2 files changed, 116 insertions(+), 8 deletions(-) diff --git a/Assets/PerfectWorld/Scripts/Addressable/AddressableManager.cs b/Assets/PerfectWorld/Scripts/Addressable/AddressableManager.cs index 5661a263a8..4938674568 100644 --- a/Assets/PerfectWorld/Scripts/Addressable/AddressableManager.cs +++ b/Assets/PerfectWorld/Scripts/Addressable/AddressableManager.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using UnityEngine; using UnityEngine.AddressableAssets; @@ -43,32 +44,131 @@ namespace BrewMonster.Scripts } /// - /// Load a text asset asynchronously. The address should look like this: "elements.data" + /// Load a text asset asynchronously. + /// NOTE: The key must match the Addressables "Address" (or another valid key like a label/GUID). /// /// /// /// public async Task LoadTextAssetAsync(string assetPath) { - if (_loadedAssets.ContainsKey(assetPath)) + if (_loadedTextAssets.ContainsKey(assetPath)) { return _loadedTextAssets[assetPath].Result; } try { - var handle = Addressables.LoadAssetAsync(assetPath); - await handle.Task; - _loadedTextAssets[assetPath] = handle; - return handle.Result; + // First, try the key exactly as provided. If it doesn't exist in the catalog, + // fall back to common project conventions (e.g. full Asset path). + foreach (var key in GetCandidateKeys(assetPath)) + { + var locationsHandle = Addressables.LoadResourceLocationsAsync(key, typeof(TextAsset)); + await locationsHandle.Task; + + if (locationsHandle.Status != AsyncOperationStatus.Succeeded || locationsHandle.Result == null || locationsHandle.Result.Count == 0) + { + Addressables.Release(locationsHandle); + continue; + } + + Addressables.Release(locationsHandle); + + var handle = Addressables.LoadAssetAsync(key); + await handle.Task; + + if (handle.Status == AsyncOperationStatus.Succeeded && handle.Result != null) + { + _loadedTextAssets[assetPath] = handle; + return handle.Result; + } + + // If load failed, release and try next candidate. + if (handle.IsValid()) + { + Addressables.Release(handle); + } + } + + BMLogger.LogError($"AddressableManager: No Location found for TextAsset key='{assetPath}'. " + + $"Tried: {string.Join(", ", GetCandidateKeys(assetPath).Select(k => $"'{k}'"))}"); + LogSimilarKeys(assetPath); + return null; } catch (Exception e) { - BMLogger.LogError(e.StackTrace); + BMLogger.LogError($"AddressableManager: Failed to load TextAsset '{assetPath}': {e}"); return null; } } + private static IEnumerable GetCandidateKeys(string assetPath) + { + if (string.IsNullOrWhiteSpace(assetPath)) + { + yield break; + } + + // Exact key (what caller asked for) + yield return assetPath; + + // Common fallback used by this repo's Addressables settings: full asset path address. + // Example in `Assets/AddressableAssetsData/AssetGroups/configuration.asset`: + // m_Address: Assets/Addressable/elements.txt + if (!assetPath.Contains("/") && !assetPath.Contains("\\")) + { + yield return $"Assets/Addressable/{assetPath}"; + } + } + + private static void LogSimilarKeys(string needle) + { + // Helpful diagnostics in dev builds: show a few keys containing the substring. + try + { + var lower = needle?.ToLowerInvariant(); + if (string.IsNullOrEmpty(lower)) + { + return; + } + + const int max = 20; + var matches = new List(max); + + foreach (var locator in Addressables.ResourceLocators) + { + foreach (var keyObj in locator.Keys) + { + if (keyObj is not string keyStr) + { + continue; + } + + if (!keyStr.ToLowerInvariant().Contains(lower)) + { + continue; + } + + matches.Add(keyStr); + if (matches.Count >= max) + { + goto Done; + } + } + } + + Done: + if (matches.Count > 0) + { + BMLogger.LogWarning($"AddressableManager: Similar Addressables keys for '{needle}': {string.Join(", ", matches)}"); + } + } + catch + { + // ignore diagnostics failures + } + } + /// /// Load an asset asynchronously. The address should look like this: "models/npcs/npc/魅灵首领/魅灵首领/魅灵首领.prefab" /// diff --git a/Assets/PerfectWorld/Scripts/Common/DataProcess/elementdataman.cs b/Assets/PerfectWorld/Scripts/Common/DataProcess/elementdataman.cs index 5e7e12c927..085a7974ea 100644 --- a/Assets/PerfectWorld/Scripts/Common/DataProcess/elementdataman.cs +++ b/Assets/PerfectWorld/Scripts/Common/DataProcess/elementdataman.cs @@ -321,7 +321,15 @@ namespace ModelRenderer.Scripts.GameData // if (!File.Exists(pathname)) return -1; - var dataFile = await AddressableManager.Instance.LoadTextAssetAsync("elements.data"); + // Addressables key must match the configured "Address". This repo currently uses full asset paths + // (see `Assets/AddressableAssetsData/AssetGroups/configuration.asset`). + // `AddressableManager.LoadTextAssetAsync` also has fallbacks, so "elements.txt" will work too. + var dataFile = await AddressableManager.Instance.LoadTextAssetAsync("Assets/Addressable/elements.txt"); + if (dataFile == null) + { + BMLogger.LogError("ElementDataMan: Failed to load Addressable TextAsset for elements data."); + return -1; + } using (var file = new MemoryStream(dataFile.bytes)) {