Merge branch 'develop' into feature/TaskThread
# Conflicts: # Assets/AddressableAssetsData/AssetGroups/configuration.asset # Assets/PerfectWorld/Scripts/Addressable/AddressableManager.cs
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 296cac0f54860484f8e9c81696536cf2
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4e7b437eecb43c64b87ab9700f5850c9
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6e02334765e10654e874714298f4eef1
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 98b87a70ddccda2459742976c2b90262
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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).
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="assetPath"></param>
|
||||
@@ -54,21 +56,119 @@ namespace BrewMonster.Scripts
|
||||
{
|
||||
return _loadedTextAssets[assetPath].Result;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var handle = Addressables.LoadAssetAsync<TextAsset>(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<TextAsset>(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<string> 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<string>(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
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load an asset asynchronously. The address should look like this: "models/npcs/npc/魅灵首领/魅灵首领/魅灵首领.prefab"
|
||||
/// </summary>
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
|
||||
@@ -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<bool> 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<bool> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user