using System;
|
using System.Collections.Generic;
|
using UnityEngine;
|
using LitJson;
|
|
public class ViewNPCManager : GameSystemManager<ViewNPCManager>
|
{
|
// 缓存字典结构: MapID -> FuncLineID -> NPCID -> Attr
|
public Dictionary<uint, Dictionary<uint, Dictionary<uint, ViewNPCAttr>>> dict = new Dictionary<uint, Dictionary<uint, Dictionary<uint, ViewNPCAttr>>>();
|
private BattleClickHeroData pendingData; // 用于记录当前正在请求查看的 NPC 信息,以便回包时自动打开界面 ---
|
private bool isPendingOpen = false; // 是否是点击触发的请求(需要自动打开界面)
|
OtherPlayerDetailManager otherPlayerManager { get { return OtherPlayerDetailManager.Instance; } }
|
public override void Init()
|
{
|
DTC0102_tagCDBPlayer.beforePlayerDataInitializeEventOnRelogin += OnBeforePlayerDataInitializeEventOnRelogin;
|
EventBroadcast.Instance.AddListener<BattleClickHeroData>(EventName.BATTLE_CLICK_HERO, OnBattleClickHero);
|
OtherPlayerDetailManager.Instance.OnRevPackage += OnRevPackage;
|
}
|
|
public override void Release()
|
{
|
DTC0102_tagCDBPlayer.beforePlayerDataInitializeEventOnRelogin -= OnBeforePlayerDataInitializeEventOnRelogin;
|
EventBroadcast.Instance.RemoveListener<BattleClickHeroData>(EventName.BATTLE_CLICK_HERO, OnBattleClickHero);
|
OtherPlayerDetailManager.Instance.OnRevPackage -= OnRevPackage;
|
}
|
|
|
private void OnBeforePlayerDataInitializeEventOnRelogin()
|
{
|
dict.Clear();
|
ResetPendingState();
|
}
|
|
private void ResetPendingState()
|
{
|
isPendingOpen = false;
|
viewNPCAttr = null;
|
pendingData.isMySide = false;
|
pendingData.funcLineID = 0;
|
pendingData.mapID = 0;
|
pendingData.npcID = 0;
|
pendingData.teams = null;
|
}
|
|
private void OnBattleClickHero(BattleClickHeroData data)
|
{
|
pendingData = data;
|
// 主线不显示NPC信息
|
if (data.mapID == 1)
|
return;
|
|
// 自己的数据直接读背包
|
if (data.isMySide)
|
{
|
OtherPlayerDetailManager.Instance.OpenOtherHeroDetailWin(new ViewHeroDetailData()
|
{
|
viewHeroType = 0,
|
clickHeroData = data,
|
});
|
return;
|
}
|
|
// pvp的走查看玩家的
|
if (BattleManager.Instance.IsPvpBattle(data.battleName))
|
{
|
switch (data.battleName)
|
{
|
case BattleConst.ArenaBattleField:
|
int playerId = (int)ArenaManager.Instance.atkPlayerId;
|
OtherPlayerDetailManager.Instance.ViewPlayerDetail(playerId, 0, (int)ViewPlayerType.viewArenaBattleEnemyHero, (int)BattlePreSetType.Arena);
|
break;
|
}
|
return;
|
}
|
// 非pvp的走查看npc的
|
// 尝试直接从缓存获取数据
|
if (TryGetNPCAttr((uint)data.mapID, (uint)data.funcLineID, (uint)data.npcID, out ViewNPCAttr attr))
|
{
|
OpenNPCDetailWin(attr);
|
}
|
else
|
{
|
isPendingOpen = true;
|
SendViewNPCAttr(data);
|
}
|
}
|
|
private void OnRevPackage(int viewPlayerType, int playerID)
|
{
|
switch (viewPlayerType)
|
{
|
case (int)ViewPlayerType.viewArenaBattleEnemyHero:
|
ViewArenaBattleEnemyHero(playerID);
|
break;
|
}
|
}
|
|
private void ViewArenaBattleEnemyHero(int playerID)
|
{
|
int presetID = otherPlayerManager.GetFuncPresetID(playerID, OtherPlayerDetailManager.Instance.viewPreSetType, (int)FuncPresetType.Global);
|
var heroList = otherPlayerManager.GetHeroDataSortList(playerID, presetID);
|
if (heroList.IsNullOrEmpty())
|
{
|
heroList = otherPlayerManager.GetHeroDataSortList(playerID, FuncPresetManager.FuncDefaultPresetID);
|
}
|
var heroData = otherPlayerManager.GetHeroDataDict(playerID, presetID);
|
if (heroList.IsNullOrEmpty())
|
{
|
heroList = otherPlayerManager.GetHeroDataSortList(playerID, FuncPresetManager.FuncDefaultPresetID);
|
}
|
if (heroList == null || heroData == null)
|
return;
|
int posNum = pendingData.posNum + 1;
|
if (!heroData.ContainsKey(posNum))
|
return;
|
|
OtherPlayerDetailManager.Instance.OpenOtherHeroDetailWin(new ViewHeroDetailData()
|
{
|
viewHeroType = 0,
|
clickHeroData = pendingData,
|
heroData = heroData[posNum],
|
heroDatas = heroList,
|
});
|
}
|
|
public void TryOpenNPCDetailWin(uint mapID, uint funcLineID, uint npcID)
|
{
|
if (TryGetNPCAttr(mapID, funcLineID, npcID, out ViewNPCAttr attr))
|
{
|
OpenNPCDetailWin(attr);
|
}
|
}
|
|
public ViewNPCAttr viewNPCAttr;
|
public void OpenNPCDetailWin(ViewNPCAttr viewNPCAttr)
|
{
|
this.viewNPCAttr = viewNPCAttr;
|
if (!UIManager.Instance.IsOpened<OtherNPCDetailWin>())
|
{
|
UIManager.Instance.OpenWindow<OtherNPCDetailWin>();
|
}
|
}
|
|
// --- 解析属性字典 ---
|
private Dictionary<int, long> ParseAttrDict(string jsonStr)
|
{
|
Dictionary<int, long> result = new Dictionary<int, long>();
|
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.TryParse(v.ToString(), out long val);
|
result[attrId] = val;
|
}
|
}
|
}
|
catch (Exception e)
|
{
|
Debug.LogWarning($"解析NPC属性JSON失败: {e.Message}");
|
}
|
return result;
|
}
|
|
public event Action<uint, uint> OnUpdateViewNPCAttrRet;
|
|
public void UpdateViewNPCAttrRet(HB432_tagSCViewNPCAttrRet vNetData)
|
{
|
// 1. 更新字典数据
|
if (!dict.ContainsKey(vNetData.MapID))
|
{
|
dict[vNetData.MapID] = new Dictionary<uint, Dictionary<uint, ViewNPCAttr>>();
|
}
|
|
var mapDict = dict[vNetData.MapID];
|
|
if (!mapDict.ContainsKey(vNetData.FuncLineID))
|
{
|
mapDict[vNetData.FuncLineID] = new Dictionary<uint, ViewNPCAttr>();
|
}
|
|
var funcLineDict = mapDict[vNetData.FuncLineID];
|
|
if (vNetData.NPCAttrList != null)
|
{
|
// 使用临时字典按NPCID分组
|
Dictionary<uint, List<HB432_tagSCViewNPCAttrRet.tagSCViewNPCAttr>> tempGroup =
|
new Dictionary<uint, List<HB432_tagSCViewNPCAttrRet.tagSCViewNPCAttr>>();
|
|
foreach (var npcAttr in vNetData.NPCAttrList)
|
{
|
uint npcID = npcAttr.NPCID;
|
if (!tempGroup.ContainsKey(npcID))
|
{
|
tempGroup[npcID] = new List<HB432_tagSCViewNPCAttrRet.tagSCViewNPCAttr>();
|
}
|
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)
|
};
|
}
|
}
|
|
// 检查是否需要自动打开界面 (Pending 逻辑)
|
if (isPendingOpen)
|
{
|
// 检查回包是否对应当前的请求 (MapID 和 FuncLineID 匹配)
|
if (vNetData.MapID == pendingData.mapID && vNetData.FuncLineID == pendingData.funcLineID)
|
{
|
if (TryGetNPCAttr((uint)pendingData.mapID, (uint)pendingData.funcLineID, (uint)pendingData.npcID, out ViewNPCAttr targetAttr))
|
{
|
OpenNPCDetailWin(targetAttr);
|
}
|
// 处理完毕,重置状态
|
ResetPendingState();
|
}
|
return;
|
}
|
|
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(BattleClickHeroData data)
|
{
|
SendViewNPCAttr((uint)data.mapID, (uint)data.funcLineID, (uint)data.npcID);
|
}
|
|
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<int, long> AttrDict = new Dictionary<int, long>(); // 属性;
|
}
|
|
public struct BattleClickHeroData
|
{
|
public string battleName;
|
public bool isMySide;
|
public int heroID;
|
public int funcLineID;
|
public int mapID;
|
public int npcID;
|
public int posNum;
|
public List<BattleObject> teams;
|
}
|