diff --git a/Assets/PerfectWorld/Scripts/Common/ByteToStringUtils.cs b/Assets/PerfectWorld/Scripts/Common/ByteToStringUtils.cs index 3175d971c3..9cf269881d 100644 --- a/Assets/PerfectWorld/Scripts/Common/ByteToStringUtils.cs +++ b/Assets/PerfectWorld/Scripts/Common/ByteToStringUtils.cs @@ -9,21 +9,33 @@ namespace ModelRenderer.Scripts.Common { if (ushortArray == null || ushortArray.Length == 0) return string.Empty; - - // First convert ushort array to byte array - // Each ushort (16 bits) can be up to two bytes in GBK - byte[] byteArray = new byte[ushortArray.Length * 2]; - + + // Determine actual length up to the first null terminator + int codeUnitCount = ushortArray.Length; + for (int i = 0; i < ushortArray.Length; i++) + { + if (ushortArray[i] == 0) + { + codeUnitCount = i; + break; + } + } + + if (codeUnitCount == 0) + return string.Empty; + + // Convert ushort code units to a byte array (UTF-16LE expected) + byte[] byteArray = new byte[codeUnitCount * 2]; Buffer.BlockCopy(ushortArray, 0, byteArray, 0, byteArray.Length); - - // Convert bytes to string using GBK encoding + + // Convert bytes to string using Unicode (UTF-16LE) try { return Encoding.Unicode.GetString(byteArray); } catch (Exception ex) { - UnityEngine.Debug.LogError($"Error converting bytes to GBK string: {ex.Message}"); + UnityEngine.Debug.LogError($"Error converting bytes to Unicode string: {ex.Message}"); return string.Empty; } } @@ -46,15 +58,29 @@ namespace ModelRenderer.Scripts.Common { if (byteArray == null || byteArray.Length == 0) return string.Empty; - + try { // Code page 936 is the code page for Simplified Chinese (GB2312/GBK) // You may need to import System.Text.Encoding.CodePages package for Unity/modern .NET Encoding cp936Encoding = Encoding.GetEncoding(936); - + + // Trim at first null terminator, if present + int length = byteArray.Length; + for (int i = 0; i < byteArray.Length; i++) + { + if (byteArray[i] == 0) + { + length = i; + break; + } + } + + if (length <= 0) + return string.Empty; + // Convert the byte array to a string using code page 936 encoding - return cp936Encoding.GetString(byteArray); + return cp936Encoding.GetString(byteArray, 0, length); } catch (Exception ex) { @@ -68,7 +94,51 @@ namespace ModelRenderer.Scripts.Common if (byteArray == null || byteArray.Length == 0) return string.Empty; - return Encoding.Unicode.GetString(byteArray); + // Trim at first null terminator (two-byte aligned not guaranteed; treat any 0 byte as terminator) + int length = byteArray.Length; + for (int i = 0; i < byteArray.Length; i++) + { + if (byteArray[i] == 0) + { + length = i; + break; + } + } + + if (length <= 0) + return string.Empty; + + return Encoding.Unicode.GetString(byteArray, 0, length); + } + + public static string ByteArrayToUTF8String(byte[] byteArray) + { + if (byteArray == null || byteArray.Length == 0) + return string.Empty; + + // Trim at first null terminator + int length = byteArray.Length; + for (int i = 0; i < byteArray.Length; i++) + { + if (byteArray[i] == 0) + { + length = i; + break; + } + } + + if (length <= 0) + return string.Empty; + + try + { + return Encoding.UTF8.GetString(byteArray, 0, length); + } + catch (Exception ex) + { + UnityEngine.Debug.LogError($"Error converting bytes to UTF-8 string: {ex.Message}"); + return string.Empty; + } } } } \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/Common/DataProcess/ElementDataManProvider.cs b/Assets/PerfectWorld/Scripts/Common/DataProcess/ElementDataManProvider.cs index c7a9d5def9..f40ab55507 100644 --- a/Assets/PerfectWorld/Scripts/Common/DataProcess/ElementDataManProvider.cs +++ b/Assets/PerfectWorld/Scripts/Common/DataProcess/ElementDataManProvider.cs @@ -1,5 +1,6 @@ using System; using ModelRenderer.Scripts.GameData; +using UnityEngine; namespace BrewMonster { @@ -24,7 +25,7 @@ namespace BrewMonster } catch (Exception ex) { - Logger.LogError($"ElementDataManProvider: Failed to load element data: {ex}"); + Logger.LogError($"ElementDataManProvider: Failed to load element data: {ex} - {ex.StackTrace}"); } } diff --git a/Assets/PerfectWorld/Scripts/Common/DataProcess/elementdataman.cs b/Assets/PerfectWorld/Scripts/Common/DataProcess/elementdataman.cs index 4f215c16fd..444ef356ba 100644 --- a/Assets/PerfectWorld/Scripts/Common/DataProcess/elementdataman.cs +++ b/Assets/PerfectWorld/Scripts/Common/DataProcess/elementdataman.cs @@ -586,11 +586,11 @@ namespace ModelRenderer.Scripts.GameData add_id_data(ID_SPACE.ID_SPACE_ESSENCE, item.id, item); } - //foreach (var item in unionscroll_essence_array) - //{ - // add_id_index(ID_SPACE.ID_SPACE_ESSENCE, item.id, DATA_TYPE.DT_UNIONSCROLL_ESSENCE); - // add_id_data(ID_SPACE.ID_SPACE_ESSENCE, item.id, item); - //} + /*foreach (var item in unionscroll_essence_array) + { + add_id_index(ID_SPACE.ID_SPACE_ESSENCE, item.id, DATA_TYPE.DT_UNIONSCROLL_ESSENCE); + add_id_data(ID_SPACE.ID_SPACE_ESSENCE, item.id, item); + }*/ } public void SaveDataToTextFile() diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_Inventory.cs b/Assets/PerfectWorld/Scripts/Managers/EC_Inventory.cs new file mode 100644 index 0000000000..1597f99bbb --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Managers/EC_Inventory.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace PerfectWorld.Scripts.Managers +{ + + public static class EC_Inventory + { + private static readonly Dictionary _packSizeByPackage = new Dictionary(); + private static readonly Dictionary> _itemsByPackage = new Dictionary>(); + private const int MaxContentHexToLog = 64; + + private static string GetPackageName(byte pkg) + { + switch (pkg) + { + case 0: return "PACK_INVENTORY"; + case 1: return "PACK_EQUIPMENT"; + case 2: return "PACK_TASKINVENTORY"; + default: return "PACK_UNKNOWN"; + } + } + + private static string BytesToHex(byte[] bytes, int max) + { + if (bytes == null || bytes.Length == 0) return ""; + int len = Math.Min(bytes.Length, max); + string hex = BitConverter.ToString(bytes, 0, len); + if (bytes.Length > len) hex += "-..."; + return hex; + } + + + + public static void UpdatePack(byte byPackage, int ivtrSize, IEnumerable items) + { + _packSizeByPackage[byPackage] = ivtrSize; + if (!_itemsByPackage.TryGetValue(byPackage, out var slots)) + { + slots = new Dictionary(); + _itemsByPackage[byPackage] = slots; + } + slots.Clear(); + if (items != null) + { + foreach (var it in items) + { + if (it != null && it.Slot >= 0) + { + slots[it.Slot] = it; + } + } + } + // Log this pack's items + LogPackInternal(byPackage, ivtrSize, slots); + } + + + private static void LogPackInternal(byte byPackage, int ivtrSize, IReadOnlyDictionary slots) + { + Debug.Log($"[Inventory] === Pack {GetPackageName(byPackage)}({byPackage}) size={ivtrSize}, items={(slots?.Count ?? 0)} ==="); + if (slots == null || slots.Count == 0) + { + Debug.Log("[Inventory] (empty)"); + return; + } + foreach (var kv in slots) + { + var it = kv.Value; + string itemName = EC_IvtrItem.ResolveItemName(it.TemplateId); + string extraHex = it.Content != null && it.Content.Length > 0 ? EC_IvtrItem.BytesToHex(it.Content, MaxContentHexToLog) : ""; + int extraLen = it.Content?.Length ?? 0; + Debug.Log( + $"[Inventory] pkg={GetPackageName(it.Package)}({it.Package}) slot={it.Slot} tid={it.TemplateId}{(string.IsNullOrEmpty(itemName) ? "" : " \"" + itemName + "\"")} count={it.Count} state={it.State} expire={it.ExpireDate} crc={it.Crc} content_len={extraLen}{(extraLen > 0 ? ", content_hex=" + extraHex : "")}" + ); + } + } + + public static void LogInventoryPacket(string tag, byte[] buffer, int hostId) + { + if (buffer == null) + { + Debug.LogWarning($"[Inventory] {tag}: buffer is null (hostId={hostId})"); + return; + } + + int index = 0; + if (buffer.Length < 6) + { + Debug.LogWarning($"[Inventory] {tag}: buffer too small: {buffer.Length} bytes (hostId={hostId})"); + LogInventoryRaw(tag, buffer); + return; + } + + byte byPackage = buffer[index++]; + byte ivtrSize = buffer[index++]; + uint contentLength = BitConverter.ToUInt32(buffer, index); index += 4; + + int remaining = buffer.Length - index; + int contentBytes = remaining; + if (contentLength < (uint)remaining) + { + contentBytes = (int)contentLength; + } + + Debug.Log($"[Inventory] {tag}: hostId={hostId}, totalBytes={buffer.Length}, byPackage={byPackage}, ivtrSize={ivtrSize}, contentLength={contentLength}, actualContentBytes={contentBytes}"); + + if (contentBytes > 0) + { + byte[] content = new byte[contentBytes]; + Buffer.BlockCopy(buffer, index, content, 0, contentBytes); + Debug.Log($"[Inventory] {tag}: content HEX=\n{BitConverter.ToString(content)}"); + } + + int trailing = buffer.Length - (index + contentBytes); + if (trailing > 0) + { + byte[] tail = new byte[trailing]; + Buffer.BlockCopy(buffer, index + contentBytes, tail, 0, trailing); + Debug.Log($"[Inventory] {tag}: trailing {trailing} byte(s) HEX=\n{BitConverter.ToString(tail)}"); + } + } + + public static void LogInventoryRaw(string tag, byte[] buffer) + { + Debug.Log($"[Inventory] {tag}: RAW HEX (len={buffer?.Length ?? 0})=\n{(buffer == null ? "" : BitConverter.ToString(buffer))}"); + } + + } +} + + diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_Inventory.cs.meta b/Assets/PerfectWorld/Scripts/Managers/EC_Inventory.cs.meta new file mode 100644 index 0000000000..2a2e71aaea --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Managers/EC_Inventory.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: b060723330d7f49409ca241f4e460bed \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_InventoryUI.cs b/Assets/PerfectWorld/Scripts/Managers/EC_InventoryUI.cs new file mode 100644 index 0000000000..78b2ced562 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Managers/EC_InventoryUI.cs @@ -0,0 +1,238 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.UI; + +namespace PerfectWorld.Scripts.Managers +{ + public class EC_InventoryUI : MonoBehaviour + { + [Header("UI References")] + [SerializeField] private GridLayoutGroup gridLayoutGroup; + [SerializeField] private GameObject inventoryButtonPrefab; + [SerializeField] private Transform inventoryContainer; + + [Header("Inventory Settings")] + [SerializeField] private byte targetPackage = 0; // 0 = PACK_INVENTORY, 1 = PACK_EQUIPMENT, 2 = PACK_TASKINVENTORY + [SerializeField] private bool autoRefresh = true; + [SerializeField] private float refreshInterval = 1.0f; + + private List inventoryButtons = new List(); + private float lastRefreshTime; + + private void Start() + { + InitializeUI(); + RefreshInventory(); + } + + private void Update() + { + if (autoRefresh && Time.time - lastRefreshTime >= refreshInterval) + { + RefreshInventory(); + } + } + + private void InitializeUI() + { + if (gridLayoutGroup == null) + { + Debug.LogError("[InventoryUI] GridLayoutGroup is not assigned!"); + return; + } + + if (inventoryButtonPrefab == null) + { + Debug.LogError("[InventoryUI] Inventory Button Prefab is not assigned!"); + return; + } + + if (inventoryContainer == null) + { + inventoryContainer = gridLayoutGroup.transform; + } + } + + public void RefreshInventory() + { + lastRefreshTime = Time.time; + ClearInventoryButtons(); + + // Get inventory data from EC_Inventory + var inventoryData = GetInventoryData(targetPackage); + + if (inventoryData == null || inventoryData.Count == 0) + { + Debug.Log($"[InventoryUI] No items found in package {targetPackage}"); + return; + } + + // Create buttons for each inventory item + foreach (var item in inventoryData.Values.OrderBy(x => x.Slot)) + { + CreateInventoryButton(item); + } + + Debug.Log($"[InventoryUI] Refreshed inventory with {inventoryData.Count} items"); + } + + private Dictionary GetInventoryData(byte package) + { + // Access the private _itemsByPackage dictionary from EC_Inventory using reflection + var inventoryType = typeof(EC_Inventory); + var itemsByPackageField = inventoryType.GetField("_itemsByPackage", + System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); + + if (itemsByPackageField == null) + { + Debug.LogError("[InventoryUI] Could not access _itemsByPackage field from EC_Inventory"); + return new Dictionary(); + } + + var itemsByPackage = itemsByPackageField.GetValue(null) as Dictionary>; + if (itemsByPackage == null) + { + Debug.LogError("[InventoryUI] _itemsByPackage is null"); + return new Dictionary(); + } + + if (itemsByPackage.TryGetValue(package, out var packageItems)) + { + return packageItems; + } + + return new Dictionary(); + } + + private void CreateInventoryButton(InventoryItemData itemData) + { + if (inventoryButtonPrefab == null) return; + + // Instantiate button + GameObject buttonObj = Instantiate(inventoryButtonPrefab, inventoryContainer); + inventoryButtons.Add(buttonObj); + + // Get button components + Button button = buttonObj.GetComponent