diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_ManMatter.cs b/Assets/PerfectWorld/Scripts/Managers/EC_ManMatter.cs index 5a95295b3f..6cd46fd755 100644 --- a/Assets/PerfectWorld/Scripts/Managers/EC_ManMatter.cs +++ b/Assets/PerfectWorld/Scripts/Managers/EC_ManMatter.cs @@ -5,10 +5,12 @@ using CSNetwork; using CSNetwork.GPDataType; using CSNetwork.Protocols; using CSNetwork.Protocols.RPCData; +using ModelRenderer.Scripts.Common; using System; using System.Collections; using System.Collections.Generic; using System.Linq; +using System.Reflection; using System.Runtime.InteropServices; using System.Threading.Tasks; using TMPro; @@ -110,20 +112,99 @@ namespace PerfectWorld.Scripts.Managers // Parse each info_matter entry for (int i = 0; i < count; i++) { + int entryOffset = offset; + // Parse info_matter structure - info_matter info = CSNetwork.GPDataType.GPDataTypeHelper.FromBytes(data, offset); + info_matter info; + try + { + info = CSNetwork.GPDataType.GPDataTypeHelper.FromBytes(data, offset); + } + catch (Exception ex) + { + Debug.LogError( + $"Failed to parse info_matter entry. index={i}/{count}, offset={entryOffset}, remaining={(data != null ? data.Length - entryOffset : 0)}. ex={ex}"); + break; // buffer likely misaligned; stop to avoid cascading errors + } offset += Marshal.SizeOf(typeof(info_matter)); - + // Store the matter data for later player access matterDataStorage[info.mid] = info; - - await MatterEnter(info); + + try + { + await MatterEnter(info); + } + catch (Exception ex) + { + TryResolveMatterTemplateDebugInfo(info.tid, out string templName, out string filePath, out string normalizedPath, out DATA_TYPE dt); + Debug.LogError( + $"MatterEnter failed. mid={info.mid}, tid={(info.tid & 0x0000ffff)}, name='{templName}', file='{filePath}', normalized='{normalizedPath}', dataType={dt}, index={i}/{count}, entryOffset={entryOffset}. ex={ex}"); + } } } catch (Exception ex) { - Debug.LogError($"Failed to parse matter info data: {ex.Message}"); + Debug.LogError($"Failed to parse matter info data: {ex}"); + } + } + + private static bool TryResolveMatterTemplateDebugInfo(int tid, out string name, out string filePath, out string normalizedPath, out DATA_TYPE dataType) + { + name = string.Empty; + filePath = string.Empty; + normalizedPath = string.Empty; + dataType = DATA_TYPE.DT_INVALID; + + try + { + var edm = ElementDataManProvider.GetElementDataMan(); + if (edm == null) + return false; + + int templTid = tid & 0x0000ffff; + object templ = edm.get_data_ptr((uint)templTid, ID_SPACE.ID_SPACE_ESSENCE, ref dataType); + if (templ == null) + return false; + + const BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; + var t = templ.GetType(); + + // Resolve template name (usually `ushort[] name` in element data) + var nameField = t.GetField("name", flags) ?? t.GetField("Name", flags); + if (nameField != null) + { + object v = nameField.GetValue(templ); + if (v is ushort[] us) + name = ByteToStringUtils.UshortArrayToCP936String(us); + else if (v is byte[] bs) + name = ByteToStringUtils.ByteArrayToCP936String(bs); + else if (v != null) + name = v.ToString(); + } + + // Resolve model/matter file path + var fileField = t.GetField("file_matter", flags) ?? t.GetField("file_model", flags); + if (fileField != null) + { + object v = fileField.GetValue(templ); + if (v is byte[] bs) + filePath = ByteToStringUtils.ByteArrayToCP936String(bs); + else if (v is ushort[] us) + filePath = ByteToStringUtils.UshortArrayToCP936String(us); + else if (v != null) + filePath = v.ToString(); + + if (!string.IsNullOrWhiteSpace(filePath)) + normalizedPath = AFile.NormalizePath(filePath.ToLower(), true); + } + + return true; + } + catch + { + return false; } }