Files
test/Assets/PerfectWorld/Scripts/Managers/CECNPCMan.cs
T
2025-09-25 13:55:07 +07:00

186 lines
6.2 KiB
C#

using BrewMonster;
using CSNetwork;
using CSNetwork.GPDataType;
using DG.Tweening;
using System;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;
public class CECNPCMan : IMsgHandler
{
private Dictionary<int, CECNPC> m_NPCTab = new Dictionary<int, CECNPC>(512);
private Dictionary<int, int> m_UkNPCTab = new Dictionary<int, int>(32);
public int HandlerId => (int)MANAGER_INDEX.MAN_NPC;
public bool ProcessMessage(ECMSG Msg)
{
if (Msg.iSubID == 0)
{
switch (Msg.dwMsg)
{
case long value when value == EC_MsgDef.MSG_NM_NPCINFO: OnMsgNPCInfo(Msg); break;
}
}
return true;
}
private bool OnMsgNPCInfo(ECMSG msg)
{
switch (msg.dwParam2) // Msg.dwParam2 giữ nguyên như C++
{
case CommandID.NPC_INFO_LIST:
{
// Msg.dwParam1: giả sử đã được cast thành byte[]
var buffer = (byte[])msg.dwParam1;
int offset = 0;
// Đọc count (2 byte đầu tiên)
if (buffer.Length < 2) return false;
ushort count = BinaryPrimitives.ReadUInt16LittleEndian(buffer.AsSpan(offset, 2));
offset += 2;
for (int i = 0; i < count; i++)
{
if (buffer.Length - offset < info_npc.HEADER_SIZE)
return false;
// đọc info_npc từ buffer
info_npc info = MemoryMarshal.Read<info_npc>(
buffer.AsSpan(offset, info_npc.HEADER_SIZE));
int iSize = info_npc.HEADER_SIZE;
if ((info.state & info_npc.GP_STATE_EXTEND_PROPERTY) != 0)
iSize += sizeof(uint) * NumberDWORDsPlayerNPC.OBJECT_EXT_STATE_COUNT;
if ((info.state & info_npc.GP_STATE_NPC_PET) != 0)
iSize += sizeof(int);
if ((info.state & info_npc.GP_STATE_NPC_NAME) != 0)
{
if (buffer.Length < offset + iSize + 1) return false;
byte len = buffer[offset + iSize];
iSize += 1 + len;
}
if ((info.state & info_npc.GP_STATE_MULTIOBJ_EFFECT) != 0)
{
if (buffer.Length < offset + iSize + sizeof(int)) return false;
int countEff = BinaryPrimitives.ReadInt32LittleEndian(
buffer.AsSpan(offset + iSize, sizeof(int)));
iSize += sizeof(int);
iSize += countEff * (sizeof(int) + 1);
}
if ((info.state & info_npc.GP_STATE_NPC_MAFIA) != 0)
iSize += sizeof(int);
Console.WriteLine(
$"HoangDev: NPC_INFO_LIST, nid: {info.nid}, tid: {info.tid}, vis_tid: {info.vis_tid}, pos: {info.pos.x} {info.pos.y} {info.pos.z}");
NPCEnter(info, false);
offset += iSize;
}
break;
}
}
return false;
}
public bool NPCEnter(in info_npc Info, bool bBornInSight)
{
var npc = GetNPC(Info.nid);
if (npc != null)
{
m_NPCTab.Remove(Info.nid);
}
// Nếu id này có trong bảng unknown thì xóa nó
if (m_UkNPCTab.ContainsKey(Info.nid))
{
m_UkNPCTab.Remove(Info.nid);
}
// Tạo NPC mới
npc = CreateNPC(Info, bBornInSight);
if (npc == null)
{
BrewMonster.Logger.LogError($"Failed to create NPC ({Info.tid})");
return false;
}
// Thêm NPC vào bảng
m_NPCTab[Info.nid] = npc;
return true;
}
// Get NPC by id and optional bornStamp
public CECNPC GetNPC(int nid, uint bornStamp = 0)
{
if (!m_NPCTab.TryGetValue(nid, out var npc))
return null;
return npc;
}
public CECNPC CreateNPC(info_npc Info, bool bBornInSight)
{
CECNPC pNPC = null;
int tid = Info.tid;
bool bPet = (Info.state & PlayerNPCState.GP_STATE_NPC_PET) != 0;
// Get data type from database
var edm = ElementDataManProvider.GetElementDataMan(); // tương đương g_pGame->GetElementDataMan()
DATA_TYPE dataType = edm.get_data_type((uint)tid, ID_SPACE.ID_SPACE_ESSENCE);
if (dataType != DATA_TYPE.DT_NPC_ESSENCE &&
dataType != DATA_TYPE.DT_MONSTER_ESSENCE &&
dataType != DATA_TYPE.DT_PET_ESSENCE)
{
// Try default npc
tid = 4249;
dataType = edm.get_data_type((uint)tid, ID_SPACE.ID_SPACE_ESSENCE);
}
if (bPet)
{
//pNPC = new CECPet(this);
}
else
{
switch (dataType)
{
//case DATA_TYPE.DT_NPC_ESSENCE: pNPC = new CECNPCServer(this); break;
case DATA_TYPE.DT_MONSTER_ESSENCE: pNPC = new CECMonster(this); break;
//case DATA_TYPE.DT_PET_ESSENCE: pNPC = new CECPet(this); break;
default:
UnityEngine.Debug.Assert(false, "Invalid DATA_TYPE in CreateNPC");
return null;
}
}
// Set born stamp & born-in-sight (giữ nguyên semantics)
uint bornStamp = CECWorld.Instance.GetBornStamp();
pNPC.SetBornStamp(bornStamp);
pNPC.SetBornInSight(bBornInSight);
// Init với tid + Info như C++
if (pNPC == null || !pNPC.Init(tid, Info))
{
// đảm bảo giải phóng nếu bạn có tài nguyên kèm theo
//pNPC?.Release();
pNPC = null;
// log lỗi tương tự glb_ErrorOutput
UnityEngine.Debug.LogError($"CECNPCMan::CreateNPC failed, tid={tid}");
return null;
}
return pNPC;
}
}