diff --git a/Assets/Addressable.meta b/Assets/Addressable.meta new file mode 100644 index 0000000000..d945c2191d --- /dev/null +++ b/Assets/Addressable.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 296cac0f54860484f8e9c81696536cf2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Addressable/elements.txt b/Assets/Addressable/elements.txt new file mode 100644 index 0000000000..abd564ec7f Binary files /dev/null and b/Assets/Addressable/elements.txt differ diff --git a/Assets/Addressable/elements.txt.meta b/Assets/Addressable/elements.txt.meta new file mode 100644 index 0000000000..c9ce2a827b --- /dev/null +++ b/Assets/Addressable/elements.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 4e7b437eecb43c64b87ab9700f5850c9 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Addressable/gshop.txt b/Assets/Addressable/gshop.txt new file mode 100644 index 0000000000..60cdbd69ae Binary files /dev/null and b/Assets/Addressable/gshop.txt differ diff --git a/Assets/Addressable/gshop.txt.meta b/Assets/Addressable/gshop.txt.meta new file mode 100644 index 0000000000..83ea29658a --- /dev/null +++ b/Assets/Addressable/gshop.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 6e02334765e10654e874714298f4eef1 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Addressable/gshop1.txt b/Assets/Addressable/gshop1.txt new file mode 100644 index 0000000000..3e74172f6d Binary files /dev/null and b/Assets/Addressable/gshop1.txt differ diff --git a/Assets/Addressable/gshop1.txt.meta b/Assets/Addressable/gshop1.txt.meta new file mode 100644 index 0000000000..72b5247e9a --- /dev/null +++ b/Assets/Addressable/gshop1.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 98b87a70ddccda2459742976c2b90262 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AddressableAssetsData/AssetGroups/configuration.asset b/Assets/AddressableAssetsData/AssetGroups/configuration.asset index e38dbe1fed..21b2b75d11 100644 --- a/Assets/AddressableAssetsData/AssetGroups/configuration.asset +++ b/Assets/AddressableAssetsData/AssetGroups/configuration.asset @@ -15,18 +15,18 @@ MonoBehaviour: m_GroupName: configuration m_GUID: 402389c9c8797a8489a1d8188e497c23 m_SerializeEntries: - - m_GUID: 1d3ff15805e2a8548ac19cce5f6d4e09 - m_Address: Assets/PerfectWorld/Data/tasks.bytes + - m_GUID: 4e7b437eecb43c64b87ab9700f5850c9 + m_Address: Assets/Addressable/elements.txt m_ReadOnly: 0 m_SerializedLabels: [] FlaggedDuringContentUpdateRestriction: 0 - - m_GUID: 26ddd95c5aad09441ad4f582e1fde148 - m_Address: Assets/PerfectWorld/Data/dyn_tasks.bytes + - m_GUID: 6e02334765e10654e874714298f4eef1 + m_Address: Assets/Addressable/gshop.txt m_ReadOnly: 0 m_SerializedLabels: [] FlaggedDuringContentUpdateRestriction: 0 - - m_GUID: 97ca8e0d62d124346a82d5a441c55cf8 - m_Address: Assets/PerfectWorld/Data/task_npc.bytes + - m_GUID: 98b87a70ddccda2459742976c2b90262 + m_Address: Assets/Addressable/gshop1.txt m_ReadOnly: 0 m_SerializedLabels: [] FlaggedDuringContentUpdateRestriction: 0 diff --git a/Assets/PerfectWorld/Scripts/Addressable/AddressableManager.cs b/Assets/PerfectWorld/Scripts/Addressable/AddressableManager.cs index 1d1ba9fdfa..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,7 +44,8 @@ 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). /// /// /// @@ -54,21 +56,119 @@ namespace BrewMonster.Scripts { return _loadedTextAssets[assetPath].Result; } + try { - var handle = Addressables.LoadAssetAsync(assetPath); - await handle.Task; + // 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; - _loadedTextAssets[assetPath] = handle; - return handle.Result; + 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)) { diff --git a/Assets/PerfectWorld/Scripts/GameData/GShopLoader.cs b/Assets/PerfectWorld/Scripts/GameData/GShopLoader.cs index 00f332c41d..00c3795227 100644 --- a/Assets/PerfectWorld/Scripts/GameData/GShopLoader.cs +++ b/Assets/PerfectWorld/Scripts/GameData/GShopLoader.cs @@ -2,108 +2,74 @@ using System; using System.Collections.Generic; using System.IO; using BrewMonster; +using BrewMonster.Scripts; using Cysharp.Threading.Tasks; using UnityEngine; -using UnityEngine.Networking; public class GShopLoader : MonoBehaviour { - [Header("File Paths")] - public string gshopDataPath = "gshop.data"; - public string gshop1DataPath = "gshop1.data"; + // Addressables-only: do NOT load gshop/gshop1 from file system paths. + // These must match the configured Addressables "Address" values in + // `Assets/AddressableAssetsData/AssetGroups/configuration.asset`. + private const string GSHOP_ADDRESS = "Assets/Addressable/gshop.txt"; + private const string GSHOP1_ADDRESS = "Assets/Addressable/gshop1.txt"; [Header("Loaded Data")] public GShopData primaryShop = new GShopData(); public GShopData secondaryShop = new GShopData(); - - async void Start() { - #if UNITY_ANDROID && !UNITY_EDITOR - bool result = await MoveShopDataToPersistentPath(); - if (!result) + // Wait for AddressableManager to be initialized + while (!AddressableManager.Instance.IsInitialized()) { - BMLogger.LogError($"ElementDataMan: Failed to move element file to persistent path"); - return; + await UniTask.DelayFrame(1); } - #endif - LoadGShopData(); - } - - public async UniTask MoveShopDataToPersistentPath() - { - var destinationPath = Path.Combine(UnityEngine.Application.persistentDataPath, gshopDataPath); - var sourcePath = Path.Combine(UnityEngine.Application.streamingAssetsPath, gshopDataPath); - - - if (!File.Exists(destinationPath)) - { - UnityWebRequest request = UnityWebRequest.Get(sourcePath); - await request.SendWebRequest(); - if (request.result != UnityWebRequest.Result.Success) - { - BMLogger.LogError($"ElementDataMan: Failed to move element file to persistent path: {request.error}"); - return false; - } - File.WriteAllBytes(destinationPath, request.downloadHandler.data); - } - - BMLogger.Log($"ElementDataMan: Successfully moved element file to persistent path: {destinationPath}"); - - destinationPath = Path.Combine(UnityEngine.Application.persistentDataPath, gshop1DataPath); - sourcePath = Path.Combine(UnityEngine.Application.streamingAssetsPath, gshop1DataPath); - - if (!File.Exists(destinationPath)) - { - var request = UnityWebRequest.Get(sourcePath); - await request.SendWebRequest(); - if (request.result != UnityWebRequest.Result.Success) - { - BMLogger.LogError($"ElementDataMan: Failed to move element file to persistent path: {request.error}"); - return false; - } - File.WriteAllBytes(destinationPath, request.downloadHandler.data); - } - - BMLogger.Log($"ElementDataMan: Successfully moved element file to persistent path: {destinationPath}"); - return true; + await LoadGShopData(); } - public void LoadGShopData() + public async UniTask LoadGShopData() { Debug.Log("=== Loading GShop Data ==="); // Load primary shop - if (LoadShopData(gshopDataPath, primaryShop)) + if (await LoadShopData(GSHOP_ADDRESS, primaryShop)) { Debug.Log($"Primary shop loaded: {primaryShop.items.Count} items, {primaryShop.mainTypes.Count} categories"); //LogShopData("Primary Shop", primaryShop); } // Load secondary shop - if (LoadShopData(gshop1DataPath, secondaryShop)) + if (await LoadShopData(GSHOP1_ADDRESS, secondaryShop)) { Debug.Log($"Secondary shop loaded: {secondaryShop.items.Count} items, {secondaryShop.mainTypes.Count} categories"); //LogShopData("Secondary Shop", secondaryShop); } } - private bool LoadShopData(string filePath, GShopData shopData) + private async UniTask LoadShopData(string filePath, GShopData shopData) { try { - string fullPath = Path.Combine(Application.streamingAssetsPath, filePath); + // Load from Addressables + var textAsset = await AddressableManager.Instance.LoadTextAssetAsync(filePath); - if (!File.Exists(fullPath)) + if (textAsset == null) { - Debug.LogError($"GShop file not found: {fullPath}"); + BMLogger.LogError($"GShopLoader: Failed to load {filePath} from Addressables. File not found or load failed."); return false; } - using (FileStream fs = new FileStream(fullPath, FileMode.Open, FileAccess.Read)) - using (BinaryReader reader = new BinaryReader(fs)) + if (textAsset.bytes == null || textAsset.bytes.Length == 0) + { + BMLogger.LogError($"GShopLoader: {filePath} loaded from Addressables but bytes array is null or empty."); + return false; + } + + // Read binary data from TextAsset.bytes using MemoryStream + using (MemoryStream ms = new MemoryStream(textAsset.bytes)) + using (BinaryReader reader = new BinaryReader(ms)) { // Read timestamp shopData.timestamp = reader.ReadUInt32(); @@ -133,7 +99,7 @@ public class GShopLoader : MonoBehaviour } catch (Exception e) { - Debug.LogError($"Error loading GShop data from {filePath}: {e.Message}"); + BMLogger.LogError($"GShopLoader: Error loading GShop data from {filePath}: {e.Message}\nStackTrace: {e.StackTrace}"); return false; } } diff --git a/Assets/Prefabs/UI/MallUI.prefab b/Assets/Prefabs/UI/MallUI.prefab index da54c021e9..f33c2c6dcf 100644 --- a/Assets/Prefabs/UI/MallUI.prefab +++ b/Assets/Prefabs/UI/MallUI.prefab @@ -5290,8 +5290,6 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 20694866a3163b342953396044c25a4e, type: 3} m_Name: m_EditorClassIdentifier: - gshopDataPath: gshop.data - gshop1DataPath: gshop1.data --- !u!1 &7409039696840300032 GameObject: m_ObjectHideFlags: 0