Files
test/Assets/PerfectWorld/Scripts/NPC/CECNPC.cs
T
2025-09-25 17:38:33 +07:00

226 lines
7.4 KiB
C#

using CSNetwork.GPDataType;
using System.Text;
using System;
using UnityEditor.Rendering;
using UnityEngine;
using BrewMonster;
using CSNetwork;
using ModelRenderer.Scripts.Common;
public class CECNPC : CECObject
{
protected INFO m_NPCInfo;
protected private uint m_dwStates;
protected private uint m_dwStates2;
protected private A3DVECTOR3 m_vServerPos;
protected private int m_iRandomProp;
protected private int m_iMoveEnv;
protected int m_idMaster;
protected string m_strName;
protected int m_idOwnerFaction;
protected float m_fDistToHost;
protected float m_fDistToHostH;
protected OtherPlayer_Move_Info m_cdr;
protected float m_fTouchRad;
protected ROLEBASICPROP m_BasicProps;
public CECNPC(CECNPCMan pNPCMan)
{
}
public virtual bool Init(int tid, in info_npc info, ReadOnlySpan<byte> packet, int infoOffset)
{
m_NPCInfo.nid = info.nid;
m_NPCInfo.tid = tid;
m_NPCInfo.vis_tid = info.vis_tid;
m_dwStates = (uint)info.state;
m_dwStates2 = (uint)info.state2;
m_vServerPos = info.pos;
m_iRandomProp = (info.state & 0x0f00) >> 8;
m_iMoveEnv = (int)((info.state & PlayerNPCState.GP_STATE_NPC_FLY) != 0 ? EnviromentMoveType.MOVEENV_AIR
: (info.state & PlayerNPCState.GP_STATE_NPC_SWIM) != 0 ? EnviromentMoveType.MOVEENV_WATER
: EnviromentMoveType.MOVEENV_GROUND);
// 2) Cắt “đuôi” ngay sau phần cố định info_npc
int fixedSize = System.Runtime.InteropServices.Marshal.SizeOf<info_npc>();
var tail = packet.Slice(infoOffset + fixedSize);
var r = new ByteReader(tail);
// 3) Đọc theo cờ state, giống C++ (pData tăng dần)
// EXTEND_PROPERTY
var ojexitStateCount = (uint)OBJECT_EXT_STATE.OBJECT_EXT_STATE_COUNT;
var ext = new uint[ojexitStateCount];
if ((info.state & PlayerNPCState.GP_STATE_EXTEND_PROPERTY) != 0)
r.ReadInto(ext);
//SetNewExtendStates(0, ext, ojexitStateCount );
// PET
m_idMaster = 0;
if ((info.state & PlayerNPCState.GP_STATE_NPC_PET) != 0)
m_idMaster = r.ReadInt32();
// NAME
if ((info.state & PlayerNPCState.GP_STATE_NPC_NAME) != 0)
{
byte len = r.ReadByte();
if (len > 0)
{
// ACHAR thường là UTF-16LE → len là số byte
var nameBytes = r.ReadBytes(len);
m_strName = System.Text.Encoding.Unicode.GetString(nameBytes);
}
}
SetSelectable((info.state & PlayerNPCState.GP_STATE_FORBIDBESELECTED) == 0);
// MULTIOBJ_EFFECT
if ((info.state & PlayerNPCState.GP_STATE_MULTIOBJ_EFFECT) != 0)
{
int n = r.ReadInt32();
for (int i = 0; i < n; i++)
{
int idTarget = r.ReadInt32();
char cType = (char)r.ReadByte();
//AddMultiObjectEffect(idTarget, cType);
}
}
// MAFIA
m_idOwnerFaction = 0;
if ((info.state & PlayerNPCState.GP_STATE_NPC_MAFIA) != 0)
m_idOwnerFaction = r.ReadInt32();
m_cdr.fStepHeight = 0.4f;
m_cdr.vVelocity.Clear();
var pHost = GameController.Instance.GetHostPlayer();
if (pHost != null)
{
m_fDistToHost = Vector3.Distance(EC_Utility.ToVector3(m_vServerPos), pHost.transform.position);
m_fDistToHostH = Vector2.Distance(
new Vector2(m_vServerPos.x, m_vServerPos.z),
new Vector2(pHost.transform.position.x, pHost.transform.position.z));
}
return true;
}
public void QueueLoadNPCModel()
{
/* if (ShouldUseMasterModel())
{
if (GetMaster())
{
return; // ÄÜ»ñÈ¡½ÇɫģÐÍʱ£¬µ½Ï¸ö Tick ¼ÓÔØÄ£ÐÍ
} // ÎÞ·¨»ñÈ¡½Çɫʱ¡¢ÔÝʱʹÓà NPC Ä£ÐÍ
}*/
int tid = 0;
string szModelFile = "";
if (!GetVisibleModel( out tid, out szModelFile))
{
return;
}
//QueueECModelForLoad(MTL_ECM_NPC, GetNPCInfo().nid, GetBornStamp(), GetServerPos(), szModelFile, tid);
}
public bool GetVisibleModel(out int tid, out string szModelFile)
{
tid = 0;
szModelFile = string.Empty;
// nếu vis_tid có model file
if (GetModelFile(GetNPCInfo().vis_tid, out szModelFile))
{
tid = GetNPCInfo().vis_tid;
}
// nếu không có thì thử lấy từ tid thường
else if (GetModelFile(GetNPCInfo().tid, out szModelFile))
{
tid = GetNPCInfo().tid;
}
return tid > 0;
}
public bool GetModelFile(int tid, out string szModelFile)
{
szModelFile = string.Empty;
// Lấy database
var pDB = ElementDataManProvider.GetElementDataMan(); // g_pGame->GetElementDataMan()
DATA_TYPE dataType = default;
// Giả định get_data_ptr trả về object (Essence) và out DataType
var pDBEssence = pDB.get_data_ptr((uint)tid, ID_SPACE.ID_SPACE_ESSENCE, ref dataType);
if (pDBEssence == null)
return false;
bool ret = true;
Debug.Log($"HoangDev : DataType : {dataType}");
switch (dataType)
{
case DATA_TYPE.DT_MONSTER_ESSENCE:
{
var ess = (MONSTER_ESSENCE)pDBEssence;
szModelFile = ByteToStringUtils.ByteArrayToCP936String( ess.file_model);
Debug.Log($"HoangDev : MONSTER_ESSENCE path : {szModelFile}");
break;
}
case DATA_TYPE.DT_PET_ESSENCE:
{
var ess = (PET_ESSENCE)pDBEssence;
szModelFile = ByteToStringUtils.ByteArrayToCP936String(ess.file_model);
break;
}
case DATA_TYPE.DT_NPC_ESSENCE:
{
var ess = (NPC_ESSENCE)pDBEssence;
szModelFile = ByteToStringUtils.ByteArrayToCP936String(ess.file_model);
break;
}
default:
ret = false;
break;
}
Debug.Log($"HoangDev : path 99 : {szModelFile}");
return ret;
}
public INFO GetNPCInfo() { return m_NPCInfo; }
public struct INFO
{
public int nid; // NPC id
public int tid; // Template id
public int vis_tid;// template id for shape
};
}
public ref struct ByteReader
{
private ReadOnlySpan<byte> _span;
private int _offset;
public ByteReader(ReadOnlySpan<byte> span) { _span = span; _offset = 0; }
public bool Eof => _offset >= _span.Length;
public byte ReadByte() => _span[_offset++];
public int ReadInt32()
{
int v = BitConverter.ToInt32(_span.Slice(_offset, 4));
_offset += 4; return v;
}
public void ReadInto(uint[] dst)
{
// OBJECT_EXT_STATE_COUNT * sizeof(DWORD)
int bytes = dst.Length * 4;
var s = _span.Slice(_offset, bytes);
for (int i = 0; i < dst.Length; i++)
dst[i] = BitConverter.ToUInt32(s.Slice(i * 4, 4));
_offset += bytes;
}
public byte[] ReadBytes(int len)
{
var s = _span.Slice(_offset, len).ToArray();
_offset += len; return s;
}
}