using System; using System.Collections.Generic; using UnityEngine; using LitJson; public class ViewNPCManager : GameSystemManager { public Dictionary>> dict = new Dictionary>>(); public override void Init() { DTC0102_tagCDBPlayer.beforePlayerDataInitializeEventOnRelogin += OnBeforePlayerDataInitializeEventOnRelogin; } public override void Release() { DTC0102_tagCDBPlayer.beforePlayerDataInitializeEventOnRelogin -= OnBeforePlayerDataInitializeEventOnRelogin; } private void OnBeforePlayerDataInitializeEventOnRelogin() { dict.Clear(); } // --- 解析属性字典 --- private Dictionary ParseAttrDict(string jsonStr) { Dictionary result = new Dictionary(); if (string.IsNullOrEmpty(jsonStr)) return result; try { JsonData jd = JsonMapper.ToObject(jsonStr); foreach (string attrKey in jd.Keys) { if (int.TryParse(attrKey, out int attrId)) { JsonData v = jd[attrKey]; long val = 0; // 健壮性数值转换 if (v.IsLong) val = (long)v; else if (v.IsInt) val = (long)(int)v; else if (v.IsDouble) val = (long)(double)v; else if (v.IsString) long.TryParse(v.ToString(), out val); result[attrId] = val; } } } catch (System.Exception e) { Debug.LogWarning($"解析NPC属性JSON失败: {e.Message}"); } return result; } public event Action OnUpdateViewNPCAttrRet; public void UpdateViewNPCAttrRet(HB432_tagSCViewNPCAttrRet vNetData) { if (!dict.ContainsKey(vNetData.MapID)) { dict[vNetData.MapID] = new Dictionary>(); } var mapDict = dict[vNetData.MapID]; if (!mapDict.ContainsKey(vNetData.FuncLineID)) { mapDict[vNetData.FuncLineID] = new Dictionary(); } var funcLineDict = mapDict[vNetData.FuncLineID]; if (vNetData.NPCAttrList != null) { // 使用临时字典按NPCID分组 Dictionary> tempGroup = new Dictionary>(); foreach (var npcAttr in vNetData.NPCAttrList) { uint npcID = npcAttr.NPCID; if (!tempGroup.ContainsKey(npcID)) { tempGroup[npcID] = new List(); } tempGroup[npcID].Add(npcAttr); } // 存入第3层字典 foreach (var kvp in tempGroup) { var firstAttr = kvp.Value[0]; funcLineDict[kvp.Key] = new ViewNPCAttr { PosNum = firstAttr.PosNum, NPCID = firstAttr.NPCID, HeroID = firstAttr.HeroID, LV = firstAttr.LV, Star = firstAttr.Star, BreakLV = firstAttr.BreakLV, AwakeLV = firstAttr.AwakeLV, AttrDict = ParseAttrDict(firstAttr.AttrMsg) }; } } OnUpdateViewNPCAttrRet?.Invoke(vNetData.MapID, vNetData.FuncLineID); } public bool TryGetNPCAttr(uint mapID, uint funcLineID, uint npcID, out ViewNPCAttr npcAttr) { npcAttr = null; if (!dict.TryGetValue(mapID, out var mapDict)) { return false; } if (!mapDict.TryGetValue(funcLineID, out var funcLineDict)) { return false; } return funcLineDict.TryGetValue(npcID, out npcAttr); } public void SendViewNPCAttr(uint mapID, uint funcLineID, uint viewNPCID) { CB416_tagCSViewNPCAttr pack = new CB416_tagCSViewNPCAttr(); pack.MapID = mapID; pack.FuncLineID = funcLineID; pack.ViewNPCID = viewNPCID; GameNetSystem.Instance.SendInfo(pack); } } public class ViewNPCAttr { public byte PosNum; // 在本阵容中的站位,从1开始 public uint NPCID; // 战斗NPCID,不同的实例ID对应的NPCID可能一样 public uint HeroID; // 武将ID,玩家或NPC均可能有,如果有值则外观相关以该武将为准,否则以NPCID为准 public ushort LV; // 等级,玩家的武将等级或NPC成长等级,等级显示以该值为准 public byte Star; // 星级 public byte BreakLV; // 突破 public byte AwakeLV; // 觉醒 public Dictionary AttrDict = new Dictionary(); // 属性; }