animation npc Process

This commit is contained in:
VDH
2025-09-29 18:26:02 +07:00
parent 586e2f834b
commit 1b2de221b4
18 changed files with 825 additions and 52 deletions
Binary file not shown.
@@ -1,4 +1,9 @@
using UnityEngine;
using UnityEngine;
public static class GameConstants
{
public static int NUM_MAGICCLASS = 5;
}
public struct ROLEBASICPROP
{
@@ -16,7 +21,174 @@ public struct ROLEBASICPROP
public int iCritDamageBonus;// Critical damage bonus
public int iInvisibleDegree;// Invisible degree
public int iAntiInvisibleDegree; // Anti-invisible degree
public int iPenetration; // ´©Í¸Á¦
public int iResilience; // µÖ¿¹Á¦
public int iVigour; // ÆøÆÇ
public int iPenetration; // ´©Í¸Á¦
public int iResilience; // µÖ¿¹Á¦
public int iVigour;
public ROLEBASICPROP(bool initialize = true)
{
iLevel = 0;
iLevel2 = 0;
iCurHP = 0;
iCurMP = 0;
iExp = 0;
iSP = 0;
iStatusPt = 0;
iCurAP = 0;
iAtkDegree = 0;
iDefDegree = 0;
iCritRate = 0;
iCritDamageBonus = 0;
iInvisibleDegree = 0;
iAntiInvisibleDegree = 0;
iPenetration = 0;
iResilience = 0;
iVigour = 0;
}
};
public struct ROLEEXTPROP
{
public ROLEEXTPROP_BASE bs;
public ROLEEXTPROP_MOVE mv;
public ROLEEXTPROP_ATK ak;
public ROLEEXTPROP_DEF df;
int max_ap;
public ROLEEXTPROP(bool initialize = true)
{
bs = new ROLEEXTPROP_BASE();
mv = new ROLEEXTPROP_MOVE();
ak = new ROLEEXTPROP_ATK();
df = new ROLEEXTPROP_DEF();
max_ap = 0;
}
};
public struct ROLEEXTPROP_BASE
{
/* »ù´¡ÊôÐÔ */
public int vitality; // Ãü
public int energy; // Éñ
public int strength; // Á¦
public int agility; // Ãô
public int max_hp; // ×î´óhp
public int max_mp; // ×î´ómp
public int hp_gen; // hp»Ö¸´ËÙ¶È
public int mp_gen; // mp»Ö¸´ËÙ¶È
public ROLEEXTPROP_BASE(bool initialize = true)
{
vitality = 0;
energy = 0;
strength = 0;
agility = 0;
max_hp = 0;
max_mp = 0;
hp_gen = 0;
mp_gen = 0;
}
// Nếu muốn có constructor với tham số
public ROLEEXTPROP_BASE(int vitality, int energy, int strength, int agility,
int max_hp, int max_mp, int hp_gen, int mp_gen)
{
this.vitality = vitality;
this.energy = energy;
this.strength = strength;
this.agility = agility;
this.max_hp = max_hp;
this.max_mp = max_mp;
this.hp_gen = hp_gen;
this.mp_gen = mp_gen;
}
};
public struct ROLEEXTPROP_MOVE
{
/* Ô˶¯ËÙ¶È*/
public float walk_speed; // ÐÐ×ßËÙ¶È µ¥Î» m/s
public float run_speed; // ±¼ÅÜËÙ¶È µ¥Î» m/s
public float swim_speed; // ÓÎÓ¾ËÙ¶È µ¥Î» m/s
public float flight_speed; // ·ÉÐÐËÙ¶È µ¥Î» m/s
public ROLEEXTPROP_MOVE(bool initialize = true)
{
walk_speed = 0f;
run_speed = 0f;
swim_speed = 0f;
flight_speed = 0f;
}
// Constructor truyền tham số nếu muốn
public ROLEEXTPROP_MOVE(float walk_speed, float run_speed, float swim_speed, float flight_speed)
{
this.walk_speed = walk_speed;
this.run_speed = run_speed;
this.swim_speed = swim_speed;
this.flight_speed = flight_speed;
}
};
public struct ROLEEXTPROP_ATK
{
// 物理攻击属性 / Attack properties
public int Attack; // 攻击率 (attack rate)
public int DamageLow; // 最小物理伤害 (minimum physical damage)
public int DamageHigh; // 最大物理伤害 (maximum physical damage)
public int AttackSpeed; // 攻击速度 (单位可能是 tick)
public float AttackRange; // 攻击范围
// 附加魔法伤害倍数(或附加魔法伤害范围)数组
public AddonDamageEntry[] AddonDamage;
// 魔法攻击伤害
public int DamageMagicLow; // 最小魔法伤害
public int DamageMagicHigh; // 最大魔法伤害
public struct AddonDamageEntry
{
public int DamageLow;
public int DamageHigh;
}
public ROLEEXTPROP_ATK(bool initialize = true)
{
Attack = 0;
DamageLow = 0;
DamageHigh = 0;
AttackSpeed = 0;
AttackRange = 0f;
AddonDamage = new AddonDamageEntry[GameConstants.NUM_MAGICCLASS];
DamageMagicLow = 0;
DamageMagicHigh = 0;
}
public ROLEEXTPROP_ATK(int attack, int damageLow, int damageHigh,
int attackSpeed, float attackRange,
int damageMagicLow, int damageMagicHigh)
{
Attack = attack;
DamageLow = damageLow;
DamageHigh = damageHigh;
AttackSpeed = attackSpeed;
AttackRange = attackRange;
AddonDamage = new AddonDamageEntry[GameConstants.NUM_MAGICCLASS];
DamageMagicLow = damageMagicLow;
DamageMagicHigh = damageMagicHigh;
}
}
// Role (Player and NPC) extended properties, defense part
public struct ROLEEXTPROP_DEF
{
/* ·ÀÓùÊôÐÔ */
public int[] resistance; // ħ·¨¿¹ÐÔ
public int defense; // ·ÀÓùÁ¦
public int armor; // ÉÁ¶ãÂÊ£¨×°¼×µÈ¼¶£©
public ROLEEXTPROP_DEF(int defense, int armor)
{
resistance = new int[GameConstants.NUM_MAGICCLASS];
this.defense = defense;
this.armor = armor;
}
public ROLEEXTPROP_DEF(bool initialize = true)
{
resistance = new int[GameConstants.NUM_MAGICCLASS];
defense = 0;
armor = 0;
}
};
@@ -38,12 +38,15 @@ public class CECNPCMan : CECObject, IMsgHandler
private bool OnMsgNPCMove(ECMSG msg)
{
cmd_object_move pCmd = (cmd_object_move)msg.dwParam1;
cmd_object_move pCmd = EC_Utility.ByteArrayToStructure<cmd_object_move>((byte[])msg.dwParam1);
if (pCmd.use_time == 0)
return true;
CECNPC pNPC = SeekOutNPC(pCmd.id);
BrewMonster.Logger.LogError("HoangDev: OnMsgNPCMove MPC : " + pNPC);
if (pNPC)
pNPC.MoveTo(pCmd);
@@ -66,6 +69,7 @@ public class CECNPCMan : CECObject, IMsgHandler
{
case CommandID.NPC_INFO_LIST:
{
// msg.dwParam1 chính là buffer chứa placeholder data (không có header cmd_npc_info_list)
cmd_npc_info_list pCmd = MemoryMarshal.Read<cmd_npc_info_list>(
((byte[])msg.dwParam1).AsSpan());
@@ -122,6 +126,29 @@ public class CECNPCMan : CECObject, IMsgHandler
NPCEnter(info, true, buffer, info_npc.HEADER_SIZE);
break;
}
case CommandID.NPC_INFO_00:
{
cmd_npc_info_00 pCmd = (cmd_npc_info_00)msg.dwParam1;
CECNPC pNPC = SeekOutNPC(pCmd.idNPC);
if (pNPC)
{
ROLEBASICPROP bp = pNPC.GetBasicProps();
ROLEEXTPROP ep = pNPC.GetExtendProps();
bp.iCurHP = pCmd.iHP;
ep.bs.max_hp = pCmd.iMaxHP;
pNPC.SetSelectedTarget(pCmd.iTargetID);
}
break;
}
case CommandID.NPC_VISIBLE_TID_NOTIFY:
{
cmd_npc_visible_tid_notify pCmd = (cmd_npc_visible_tid_notify)msg.dwParam1;
CECNPC pNPC = SeekOutNPC(pCmd.nid);
if (pNPC)
pNPC.TransformShape(pCmd.vis_tid);
break;
}
}
return true;
}
@@ -0,0 +1,11 @@
using UnityEngine;
public class CECModel
{
}
// Action channel
public enum ActionChannel
{
ACTCHA_WOUND = 1,
};
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 90988058e72b81340ac0270a4e6a74e3
+23 -3
View File
@@ -4,6 +4,7 @@ using ModelRenderer.Scripts.GameData;
using System;
using Unity.VisualScripting;
using UnityEngine;
using static CECNPC;
public class CECMonster : CECNPC
{
@@ -17,15 +18,34 @@ public class CECMonster : CECNPC
}
public override bool Init(int tid, in info_npc info, ReadOnlySpan<byte> packet, int infoOffset)
{
base.Init(tid, info, packet,infoOffset);
base.Init(tid, info, packet, infoOffset);
BrewMonster.Logger.Log("HoangDev: MonsterInit");
var pDB = ElementDataManProvider.GetElementDataMan();
DATA_TYPE DataType = default ;
m_pDBEssence = (MONSTER_ESSENCE)pDB.get_data_ptr((uint)tid, ID_SPACE.ID_SPACE_ESSENCE,ref DataType);
DATA_TYPE DataType = default;
m_pDBEssence = (MONSTER_ESSENCE)pDB.get_data_ptr((uint)tid, ID_SPACE.ID_SPACE_ESSENCE, ref DataType);
m_fTouchRad = m_pDBEssence.size;
m_BasicProps.iLevel = m_pDBEssence.level;
QueueLoadNPCModel();
/* float fExt = m_fTouchRad * 1.5f;
m_cdr.vExts.Set(fExt, fExt, fExt);
m_pNPCModelPolicy.SetDefaultPickAABBExt(m_cdr.vExts);*/
// If NPC doesn't have specific name, use the name in database
if ((info.state & (int)PlayerNPCState.GP_STATE_NPC_NAME) == 0)
{
m_strName = m_pDBEssence.name.ToString();
/* if (m_pPateName)
m_pPateName->SetText(m_strName, false);*/
}
if ((m_pDBEssence.combined_switch & (uint)MONSTER_COMBINED_SWITCH. MCS_FORBID_SELECTION) != 0)
SetSelectable(false);
transform.position = EC_Utility.ToVector3(info.pos);
StartWork((int)WorkType.WT_NOTHING, (int)WorkID.WORK_STAND);
return true;
}
}
+301 -30
View File
@@ -27,8 +27,14 @@ public class CECNPC : CECObject
protected A3DVECTOR3 m_vMoveDir;
protected int m_iPassiveMove;
protected bool m_bStopMove;
protected bool m_bStartFight;
protected int[] m_aWorks = new int[4];
protected int m_iAction;
protected int m_idSelTarget;
protected int m_iCurWorkType;
protected int m_iCurWork;
protected ROLEEXTPROP m_ExtProps;
protected CECNPCModelPolicy m_pNPCModelPolicy;
[SerializeField] protected float m_fMoveSpeed;
protected static CECStringTab m_ActionNames;
@@ -42,8 +48,6 @@ public class CECNPC : CECObject
}
public virtual bool Init(int tid, in info_npc info, ReadOnlySpan<byte> packet, int infoOffset)
{
BrewMonster.Logger.Log("HoangDev: NPCInit");
m_NPCInfo.nid = info.nid;
m_NPCInfo.tid = tid;
m_NPCInfo.vis_tid = info.vis_tid;
@@ -51,11 +55,22 @@ public class CECNPC : CECObject
m_dwStates2 = (uint)info.state2;
m_vServerPos = info.pos;
m_iRandomProp = (info.state & 0x0f00) >> 8;
m_pNPCModelPolicy = new CECNPCModelDefaultPolicy(this);
m_idSelTarget = 0;
m_iCurWorkType = -1;
m_iCurWork = 0;
m_bStartFight = false;
m_BasicProps = new ROLEBASICPROP(true); // struct mặc định, các trường số = 0, mảng đã tạo
m_ExtProps = new ROLEEXTPROP(true);
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);
var npcVisual = GetComponent<NPCVisual>();
m_pNPCModelPolicy.SetNpcVisual(npcVisual);
// 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);
@@ -123,12 +138,24 @@ public class CECNPC : CECObject
}
public static bool InitStaticRes()
{
m_ActionNames = new CECStringTab();
// Load action names from file
if (!m_ActionNames.IsInitialized())
m_ActionNames.Init("actions_npc.txt", false);
m_ActionNames.Init("actions_npc", false);
return true;
}
public void TransformShape(int vis_tid)
{
if (m_NPCInfo.vis_tid == vis_tid)
{
return;
}
m_NPCInfo.vis_tid = vis_tid;
QueueLoadNPCModel();
}
public void QueueLoadNPCModel()
{
/* if (ShouldUseMasterModel())
@@ -144,15 +171,21 @@ public class CECNPC : CECObject
{
return;
}
var nameMonster = Path.GetFileNameWithoutExtension(szModelFile);
BrewMonster.Logger.Log("HoangDev: nameMonster :" + nameMonster);
var model = NPCBuilder.Instance.GetModelByName(nameMonster);
BrewMonster.Logger.Log("HoangDev: model.name :" + model.name);
var nameMonster = Path.GetFileNameWithoutExtension(szModelFile);
var model = NPCBuilder.Instance.GetModelByName(nameMonster);
if (model == null) return;
var monsterModel = Instantiate(model, transform);
monsterModel.SetActive(true);
var npcVisual = GetComponent<NPCVisual>();
npcVisual.InitNPCEventDoneHandler();
//QueueECModelForLoad(MTL_ECM_NPC, GetNPCInfo().nid, GetBornStamp(), GetServerPos(), szModelFile, tid);
}
public ROLEBASICPROP GetBasicProps() { return m_BasicProps; }
public ROLEEXTPROP GetExtendProps() { return m_ExtProps; }
public void SetSelectedTarget(int id) { m_idSelTarget = id; }
public bool GetVisibleModel(out int tid, out string szModelFile)
{
tid = 0;
@@ -185,7 +218,6 @@ public class CECNPC : CECObject
return false;
bool ret = true;
Debug.Log($"HoangDev : DataType : {dataType}");
switch (dataType)
{
@@ -193,7 +225,6 @@ public class CECNPC : CECObject
{
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:
@@ -213,16 +244,26 @@ public class CECNPC : CECObject
break;
}
Debug.Log($"HoangDev : path 99 : {szModelFile}");
return ret;
}
public static void ReleaseStaticRes()
{
m_ActionNames.Release();
}
public static string GetBaseActionName(int iAct)
{
return m_ActionNames.GetANSIString(iAct);
}
public static bool IsAttackAction(int iAct)
{
return iAct == (int)NPCActionIndex.ACT_ATTACK1
|| iAct == (int)NPCActionIndex.ACT_ATTACK2
|| iAct == (int)NPCActionIndex.ACT_NPC_ATTACK;
}
public void MoveTo(cmd_object_move Cmd)
{
BrewMonster.Logger.LogError("HoangDev : MoveTo");
if (Cmd.use_time == 0)
return;
@@ -230,12 +271,14 @@ public class CECNPC : CECObject
m_vMoveDir = Cmd.dest - EC_Utility.ToA3DVECTOR3(transform.position);
float fDist = m_vMoveDir.Normalize(); // giả sử Normalize() trả về độ dài trước khi chuẩn hóa
BrewMonster.Logger.LogError("HoangDev : MoveTo : Cmd.use_time");
// If destination position is too far, forcely pull player
if (IsLag(fDist))
{
transform.position = EC_Utility.ToVector3(Cmd.dest);
return;
}
BrewMonster.Logger.LogError("HoangDev : MoveTo : IsLag");
int iMoveMode = Cmd.move_mode & (int)GPMoveMode.GP_MOVE_MASK;
@@ -247,6 +290,7 @@ public class CECNPC : CECObject
UnityEngine.Debug.Assert(false, "Invalid move mode: push/pull inside MoveTo");
return;
}
BrewMonster.Logger.LogError("HoangDev : MoveTo : (int)GPMoveMode.GP_MOVE_PUSH");
m_cdr.bTraceGround = true;
@@ -270,33 +314,257 @@ public class CECNPC : CECObject
}
m_fMoveSpeed = fDist / (Cmd.use_time * 0.001f);
// float fSpeed = FIX8TOFLOAT(Cmd.sSpeed);
// m_fMoveSpeed = Mathf.Clamp(m_fMoveSpeed, 0.0f, fSpeed * 1.2f);
// Adjust NPC's direction
/* if (!IsDirFixed())
{
var vDir = m_vMoveDir;
vDir.y = 0.0f;
if (!vDir.IsZero())
{
vDir.Normalize();
SetDestDirAndUp(vDir, g_vAxisY, 150);
}
}
*/
/* if (m_aWorks[(int)WorkType.WT_NORMAL] != (int)WorkID.WORK_MOVE || ShouldPlayNewActionFor(iMoveMode))
{
StartWork(WT_NORMAL, WORK_MOVE);
// Play run or walk action
PlayMoveAction(iMoveMode);
}*/
/*if (!IsDirFixed())
{
var vDir = m_vMoveDir;
vDir.y = 0.0f;
if (!vDir.IsZero())
{
vDir.Normalize();
SetDestDirAndUp(vDir, g_vAxisY, 150);
}
}
*/
BrewMonster.Logger.LogError("HoangDev : MoveTo : m_aWorks[(int)WorkType.WT_NORMAL] " + m_aWorks[(int)WorkType.WT_NORMAL]);
if (m_aWorks[(int)WorkType.WT_NORMAL] != (int)WorkID.WORK_MOVE || ShouldPlayNewActionFor(iMoveMode))
{
StartWork((int)WorkType.WT_NORMAL, (int)WorkID.WORK_MOVE);
// Play run or walk action
BrewMonster.Logger.LogError("HoangDev : MoveTo : PlayMoveAction");
PlayMoveAction(iMoveMode);
}
}
public void ReleaseWork(int iWorkType)
{
Debug.Assert(iWorkType >= 0 && iWorkType < (int)WorkType.NUM_WORKTYPE);
switch (m_aWorks[iWorkType])
{
case (int)WorkID.WORK_STAND:
break;
case (int)WorkID.WORK_FIGHT:
break;
case (int)WorkID.WORK_SPELL:
break;
case (int)WorkID.WORK_DEAD:
break;
case (int)WorkID.WORK_MOVE:
{
// Để tránh trường hợp WORK_MOVE bị ghi đè bởi WORK_SPELL hoặc WORK khác
// dẫn đến NPC sai vị trí, ta sẽ kiểm tra và kéo NPC về đúng server position
var pos = EC_Utility.ToVector3(m_vServerPos);
var vDelta = pos - transform.position;
float fDist = vDelta.magnitude; // Vector3.magnitude trong Unity
if (fDist > 0.1f)
{
transform.position = (pos);
/* if (!IsDirFixed())
{
SetDestDirAndUp(m_vStopDir, Vector3.up, 150);
}*/
//RebuildTraceBrush();
}
break;
}
case (int)WorkID.WORK_POLICYACTION:
{
/* m_pNPCModelPolicy?.StopChannelAction();
m_pPolicyAction = null;
m_nPolicyActionIntervalTimer = 0;*/
break;
}
}
m_aWorks[iWorkType] = 0;
if (m_iCurWorkType == iWorkType)
m_iCurWork = 0;
}
public void StartWork(int iWorkType, int iNewWork, uint dwParam = 0)
{
Debug.Assert(iWorkType >= 0 && iWorkType < (int)WorkType.NUM_WORKTYPE);
if (iNewWork == (int)WorkID.WORK_DEAD)
{
// Dead is a special work
ReleaseWork((int)WorkType.WT_INTERRUPT);
ReleaseWork((int)WorkType.WT_NORMAL);
m_aWorks[(int)WorkType.WT_NORMAL] = iNewWork;
m_iCurWorkType = (int)WorkType.WT_NORMAL;
}
else if (iWorkType == (int)WorkType.WT_INTERRUPT)
{
// Release old work
ReleaseWork((int)WorkType.WT_INTERRUPT);
m_aWorks[(int)WorkType.WT_INTERRUPT] = iNewWork;
if (m_iCurWorkType == (int)WorkType.WT_NORMAL || m_iCurWorkType == (int)WorkType.WT_NOTHING)
StopWork(m_iCurWorkType);
m_aWorks[(int)WorkType.WT_INTERRUPT] = iNewWork;
m_iCurWorkType = (int)WorkType.WT_INTERRUPT;
}
else if (iWorkType == (int)WorkType.WT_NORMAL)
{
// Release old work
ReleaseWork((int)WorkType.WT_NORMAL);
m_aWorks[(int)WorkType.WT_NORMAL] = iNewWork;
if (m_iCurWorkType < 0 || m_iCurWorkType == (int)WorkType.WT_NORMAL || m_iCurWorkType == (int)WorkType.WT_NOTHING)
{
if (m_iCurWorkType == (int)WorkType.WT_NOTHING)
StopWork((int)WorkType.WT_NOTHING);
m_iCurWorkType = (int)WorkType.WT_NORMAL;
}
else
return;
}
else // iWorkType == WT_NOTHING
{
// Release old work
ReleaseWork((int)WorkType.WT_NOTHING);
m_aWorks[(int)WorkType.WT_NOTHING] = iNewWork;
if (m_iCurWorkType < 0 || m_iCurWorkType == (int)WorkType.WT_NOTHING)
m_iCurWorkType = (int)WorkType.WT_NOTHING;
else
return;
}
StartWorkByID(iNewWork, dwParam);
}
public void StopWork(int iWorkType)
{
}
public void StartWorkByID(int iWorkID, uint dwParam)
{
// Ignore all message if this NPC is dead.
// if (IsDead())
// return;
switch (iWorkID)
{
case (int)WorkID.WORK_STAND: StartWork_Stand(dwParam); break;
case (int)WorkID.WORK_FIGHT: StartWork_Fight(dwParam); break;
case (int)WorkID.WORK_SPELL: StartWork_Spell(dwParam); break;
case (int)WorkID.WORK_DEAD: StartWork_Dead(dwParam); break;
case (int)WorkID.WORK_MOVE: StartWork_Move(dwParam); break;
case (int)WorkID.WORK_POLICYACTION: StartWork_PolicyAction(dwParam); break;
}
// if (iWorkID != WORK_MOVE) m_iPassiveMove = 0;
m_iCurWork = iWorkID;
}
public void StartWork_Stand(uint dwParam)
{
if (!m_bStartFight)
{
if (IsMonsterOrPet())
PlayModelAction((int)NPCActionIndex.ACT_STAND);
else
PlayModelAction((int)NPCActionIndex.ACT_NPC_STAND);
}
}
public void StartWork_Fight(uint dwParam)
{
// dwParam được dùng như “thời gian chiến đấu còn lại”
//m_nFightTimeLeft = (int)dwParam;
// Không play animation ở đây vì animation được điều khiển bởi message tấn công
}
public void StartWork_Spell(uint dwParam)
{
// Trong C++ không có xử lý gì, giữ nguyên
}
public void StartWork_Dead(uint dwParam)
{
if (IsMonsterOrPet())
PlayModelAction((int)NPCActionIndex.ACT_DIE);
else
PlayModelAction((int)NPCActionIndex.ACT_NPC_DIE);
}
public void StartWork_Move(uint dwParam)
{
m_bStartFight = false;
/*
if (m_pNPCModelPolicy != null && m_pNPCModelPolicy.IsModelLoaded())
{
ClearComActFlag(true);
// Khi NPC đang di chuyển thì bỏ trace brush (không cần va chạm)
ReleaseTraceBrush();
}*/
}
public void StartWork_PolicyAction(uint dwParam)
{
/* if (m_pPolicyAction == null)
m_pPolicyAction = new CECPolicyAction();
// Trong C++: m_pPolicyAction->Init((const S2C::cmd_object_start_play_action *)dwParam);
// Sang C#: dwParam không thể cast trực tiếp. Bạn sẽ cần truyền object phù hợp vào.
m_pPolicyAction.Init((S2C.cmd_object_start_play_action)dwParam);
m_pPolicyAction.Tick(0);
m_nPolicyActionIntervalTimer = 0;
CheckStartPolicyAction();*/
}
public bool ShouldPlayNewActionFor(int iMoveMode)
{
if (m_pNPCModelPolicy.IsPlayingAction())
{
int iAction = GetMoveAction(iMoveMode);
return !m_pNPCModelPolicy.IsPlayingAction(iAction)
&& m_pNPCModelPolicy.HasAction(iAction);
}
return false;
}
public int GetMoveAction(int iMoveMode)
{
if (iMoveMode == (int)GPMoveMode.GP_MOVE_RUN || iMoveMode == (int)GPMoveMode.GP_MOVE_RETURN)
{
if (IsMonsterOrPet())
return (int)NPCActionIndex.ACT_RUN;
else
return (int)NPCActionIndex.ACT_NPC_RUN;
}
else
{
if (IsMonsterOrPet())
return (int)NPCActionIndex.ACT_WALK;
else
return (int)NPCActionIndex.ACT_NPC_WALK;
}
}
bool IsMonsterOrPet() { return IsMonsterNPC() || IsPetNPC(); }
bool IsMonsterNPC() { return (int)ClassID.OCID_MONSTER == m_iCID; }
bool IsPetNPC() { return (int)ClassID.OCID_PET == m_iCID; }
public void PlayMoveAction(int iMoveMode)
{
BrewMonster.Logger.LogError("HoangDev : MoveTo : PlayMoveAction 2");
// Play run or walk aciton
if (iMoveMode == (int)GPMoveMode.GP_MOVE_RUN || iMoveMode == (int)GPMoveMode.GP_MOVE_RETURN)
{
PlayModelAction((int)NPCActionIndex.ACT_WALK, false);
/*if (IsMonsterOrPet())
PlayModelAction(ACT_RUN, false);
else
@@ -311,8 +579,10 @@ public class CECNPC : CECObject
PlayModelAction(ACT_NPC_WALK, false);*/
}
}
public void PlayModelAction(int iAction, bool bRestart/* =true */)
public void PlayModelAction(int iAction, bool bRestart = false)
{
BrewMonster.Logger.LogError("HoangDev : MoveTo : PlayModelAction 3");
m_iAction = iAction;
/* if (IsDead())
{
@@ -337,6 +607,7 @@ public class CECNPC : CECObject
}
}
}*/
m_pNPCModelPolicy.PlayModelAction(iAction, bRestart);
}
bool IsLag(float fDist)
@@ -0,0 +1,125 @@
using CSNetwork.Protocols;
using UnityEngine;
public class CECNPCModelDefaultPolicy
: CECNPCModelPolicy
{
CECModel m_pNPCModel;
public CECNPCModelDefaultPolicy(CECNPC pNPC)
{
}
public string GetActionName(int iAct, bool bAttackStart = false)
{
// Tạo builder thay cho static char[128]
var sb = new System.Text.StringBuilder();
// Thêm tên base action
sb.Append(CECNPC.GetBaseActionName(iAct));
// Nếu là attack action thì thêm hậu tố
if (CECNPC.IsAttackAction(iAct))
{
sb.Append(bAttackStart ? "Æð" : "Âä");
}
// Thêm chuỗi môi trường lien quan toi pet
//string szEnv = GetActionEnvString();
/* if (!string.IsNullOrEmpty(szEnv))
{
sb.Append("_");
sb.Append(szEnv);
}*/
return sb.ToString();
}
public override bool PlayModelAction(int iAction, bool bRestart)
{
BrewMonster.Logger.LogError("HoangDev : MoveTo : PlayModelAction 4 : " + iAction);
/* if (m_pNPCModel == null)
{
return false;
}
*/
bool result = false;
if (iAction == (int)NPCActionIndex.ACT_WOUNDED)
{
string szAct = GetActionName(iAction);
if (!_npcVisual.IsAnimationExist(szAct))
{
szAct = GetActionName((int)NPCActionIndex.ACT_WOUNDED2);
}
result = _npcVisual.TryPlayAction(szAct);
}
else if (iAction == (int)NPCActionIndex.ACT_ATTACK1 || iAction == (int)NPCActionIndex.ACT_ATTACK2)
{
//bool bHideFX = !CECOptimize::Instance().GetGFX().CanShowAttack(m_pNPC->GetNPCID(), m_pNPC->GetClassID());
result = _npcVisual.TryPlayAction(GetActionName(iAction, true));
if (result)
{
/* m_pNPCModel->QueueAction(GetActionName(iAction, false), 0, 0, false, false, bHideFX);
m_pNPCModel->QueueAction(GetActionName(CECNPC::ACT_GUARD), 300);*/
}
}
else if (iAction == (int)NPCActionIndex.ACT_IDLE)
{
result = _npcVisual.TryPlayAction(GetActionName(iAction));
if (result)
{
//m_pNPCModel->QueueAction(GetActionName((int)NPCActionIndex.ACT_STAND));
}
}
else if (iAction == (int)NPCActionIndex.ACT_NPC_IDLE1 || iAction == (int)NPCActionIndex.ACT_NPC_IDLE2)
{
result = _npcVisual.TryPlayAction(GetActionName(iAction));
if (result)
{
//m_pNPCModel->QueueAction(GetActionName((int)NPCActionIndex.ACT_NPC_STAND));
}
}
else if (iAction == (int)NPCActionIndex.ACT_NPC_ATTACK)
{
//bool bHideFX = !CECOptimize::Instance().GetGFX().CanShowAttack(m_pNPC->GetNPCID(), m_pNPC->GetClassID());
result = _npcVisual.TryPlayAction(GetActionName(iAction)); ;
if (result)
{
/*m_pNPCModel->QueueAction(GetActionName(iAction, false), 0, 0, false, false, bHideFX);
m_pNPCModel->QueueAction(GetActionName(CECNPC::ACT_NPC_STAND), 300);*/
}
}
else if (iAction == (int)NPCActionIndex.ACT_COMMON_BORN)
{
result = _npcVisual.TryPlayAction(GetActionName(iAction));
if (result)
{
//m_pNPCModel->QueueAction(GetActionName((int)NPCActionIndex.ACT_STAND));
}
}
else
{
BrewMonster.Logger.LogError("HoangDev : MoveTo : PlayModelAction 4 : " + GetActionName(iAction));
result = _npcVisual.TryPlayAction(GetActionName(iAction));
}
return result;
}
public override bool IsPlayingAction()
{
return _npcVisual.IsPlayAnimation();
}
public override bool IsPlayingAction(int iAction)
{
return _npcVisual.IsPlayAnimation(GetActionName(iAction));
}
public override bool HasAction(int iAction)
{
return _npcVisual.IsAnimationExist(GetActionName(iAction));
}
public override void SetNpcVisual(NPCVisual npcVisual)
{
_npcVisual = npcVisual;
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: c6c8a7068612e5f46a7231b8fd589baf
@@ -0,0 +1,18 @@
using UnityEngine;
public abstract class CECNPCModelPolicy
{
protected NPCVisual _npcVisual;
public virtual bool PlayModelAction(int iAction, bool bRestart) { return false; }
public virtual bool IsPlayingAction() { return false; }
public virtual bool IsPlayingAction(int iActions) { return false; }
public virtual void SetNpcVisual(NPCVisual npcVisual)
{
}
public virtual bool HasAction(int iAction)
{
return false;
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: ef759b50028f2f24b9562dd1dd04f021
+27 -8
View File
@@ -1,16 +1,35 @@
using Animancer;
using UnityEngine;
public class NPCVisual : MonoBehaviour
{
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
}
[SerializeField] NamedAnimancerComponent namedAnimancer;
// Update is called once per frame
void Update()
public bool TryPlayAction(string animationName)
{
if(namedAnimancer == null) return false;
if(namedAnimancer.IsPlaying(animationName)) return false;
BrewMonster.Logger.LogError("TryPlayAction "+ animationName);
return namedAnimancer.TryPlay(animationName) == null;
}
public void InitNPCEventDoneHandler()
{
namedAnimancer = GetComponentInChildren<NamedAnimancerComponent>();
if (namedAnimancer == null)
{
BrewMonster.Logger.LogError("animancer == null");
return;
}
}
private void OnDestroy()
{
}
public bool IsAnimationExist(string animationName)
{
return namedAnimancer.States.TryGet("ActionName", out var existingState) ? true : false;
}
public bool IsPlayAnimation() => namedAnimancer.IsPlaying();
public bool IsPlayAnimation(string animationName) => namedAnimancer.IsPlaying(animationName);
}
+15
View File
@@ -10,6 +10,7 @@ GameObject:
m_Component:
- component: {fileID: 3521696612905468212}
- component: {fileID: 2542060226037108388}
- component: {fileID: -3520322077839857420}
m_Layer: 0
m_Name: MonsterPrefab
m_TagString: Untagged
@@ -44,3 +45,17 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 2cd22b82fc76bed46ac948cef9c7119d, type: 3}
m_Name:
m_EditorClassIdentifier:
m_fMoveSpeed: 0
--- !u!114 &-3520322077839857420
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6975799234359536760}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 8c7b669b45068cf469ae3116991b9026, type: 3}
m_Name:
m_EditorClassIdentifier:
namedAnimancer: {fileID: 0}
+14
View File
@@ -10,6 +10,7 @@ GameObject:
m_Component:
- component: {fileID: 3521696612905468212}
- component: {fileID: 2999449018738386437}
- component: {fileID: -6135441729487348920}
m_Layer: 0
m_Name: NPCPrefab
m_TagString: Untagged
@@ -44,3 +45,16 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: e7f08b1c572f8f140b1f25edb7e5dd47, type: 3}
m_Name:
m_EditorClassIdentifier:
m_fMoveSpeed: 0
--- !u!114 &-6135441729487348920
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6975799234359536760}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 8c7b669b45068cf469ae3116991b9026, type: 3}
m_Name:
m_EditorClassIdentifier:
+60 -1
View File
@@ -2429,6 +2429,7 @@ GameObject:
m_Component:
- component: {fileID: 1295080370}
- component: {fileID: 1295080373}
- component: {fileID: 1295080374}
m_Layer: 0
m_Name: A3DSkinnedMeshRenderer(Clone)
m_TagString: Untagged
@@ -2476,6 +2477,28 @@ Animator:
m_AllowConstantClipSamplingOptimization: 1
m_KeepAnimatorStateOnDisable: 0
m_WriteDefaultValuesOnDisable: 0
--- !u!114 &1295080374
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1295080369}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: c75c0dcb6d50eb64abd727a90406ca2b, type: 3}
m_Name:
m_EditorClassIdentifier:
_Animator: {fileID: 1295080373}
_ActionOnDisable: 0
_PlayAutomatically: 1
_Animations:
- {fileID: 7400000, guid: e7a5b03a5002f406b9a394e553a2ac9a, type: 2}
- {fileID: 7400000, guid: 8f804a48aaae74ea584994f54c2b3bb7, type: 2}
- {fileID: 7400000, guid: 9aac5b94918534a069b5d9b0f0dbcdab, type: 2}
- {fileID: 7400000, guid: 6ce7ea75839424db88c6e2e1fac83603, type: 2}
- {fileID: 7400000, guid: d95521e8bd8664f69a0b8f5dac6fa152, type: 2}
- {fileID: 7400000, guid: 6bd82249f37b94af7b2270cca56e85aa, type: 2}
--- !u!1 &1328669173
GameObject:
m_ObjectHideFlags: 0
@@ -3798,6 +3821,7 @@ GameObject:
m_Component:
- component: {fileID: 1761919880}
- component: {fileID: 1761919883}
- component: {fileID: 1761919884}
m_Layer: 0
m_Name: A3DSkinnedMeshRenderer(Clone)
m_TagString: Untagged
@@ -3845,6 +3869,41 @@ Animator:
m_AllowConstantClipSamplingOptimization: 1
m_KeepAnimatorStateOnDisable: 0
m_WriteDefaultValuesOnDisable: 0
--- !u!114 &1761919884
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1761919879}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: c75c0dcb6d50eb64abd727a90406ca2b, type: 3}
m_Name:
m_EditorClassIdentifier:
_Animator: {fileID: 1761919883}
_ActionOnDisable: 0
_PlayAutomatically: 1
_Animations:
- {fileID: 7400000, guid: 455f73dbc706f4f01be2a49237758abf, type: 2}
- {fileID: 7400000, guid: 6ff013485dd2f4822bd7e5062683a98d, type: 2}
- {fileID: 7400000, guid: 7fc83c309c6eb481089ad03465d170e4, type: 2}
- {fileID: 7400000, guid: d967418450b764b1fb5cde162add119c, type: 2}
- {fileID: 7400000, guid: 8dd91c33e4b4244f8b2f1dffac73b915, type: 2}
- {fileID: 7400000, guid: 54ed398049959439abd1f20dba285f02, type: 2}
- {fileID: 7400000, guid: 9d4148203261d48d499b3805b3ca6493, type: 2}
- {fileID: 7400000, guid: e7e87d5056bec4e20b65789d14fddaf4, type: 2}
- {fileID: 7400000, guid: 1d3b556541aaf40cb83ac55256edd614, type: 2}
- {fileID: 7400000, guid: 073ead96c59c24c96adc3c4ec1f960f2, type: 2}
- {fileID: 7400000, guid: d6256486e9d294bc59ca3964e00d4ee0, type: 2}
- {fileID: 7400000, guid: 0b93f45e94ed249e8bb3ce16c8765603, type: 2}
- {fileID: 7400000, guid: 89616b414c43a487d8c9d9b9ee5336a3, type: 2}
- {fileID: 7400000, guid: 28e870607d15e42a2b7186825c603e13, type: 2}
- {fileID: 7400000, guid: 082e512e1d70747f9ab1c5d7bcdf40f8, type: 2}
- {fileID: 7400000, guid: 5092575ab0ff14211a7e18068de530f9, type: 2}
- {fileID: 7400000, guid: 6dffa0347f1134368953849c2918cee5, type: 2}
- {fileID: 7400000, guid: 779009ded4fb841e9b2e33b3a726fbc1, type: 2}
- {fileID: 7400000, guid: c7cd31ecc034444feb17d7e164c0323b, type: 2}
--- !u!1 &1770128547
GameObject:
m_ObjectHideFlags: 0
@@ -4239,7 +4298,7 @@ GameObject:
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
m_IsActive: 0
--- !u!4 &2107333969
Transform:
m_ObjectHideFlags: 0
+13
View File
@@ -2,6 +2,7 @@
using CSNetwork.GPDataType;
using System;
using System.Collections;
using System.Runtime.InteropServices;
using UnityEngine;
using static EC_Player;
@@ -30,6 +31,18 @@ public static class EC_Utility
return (byte)(fDeg * fInvInter);
}
}
public static T ByteArrayToStructure<T>(byte[] bytes) where T : struct
{
GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
try
{
return Marshal.PtrToStructure<T>(handle.AddrOfPinnedObject());
}
finally
{
handle.Free();
}
}
public static System.Numerics.Vector3 ToNumerics(this UnityEngine.Vector3 v)
{
return new System.Numerics.Vector3(v.x, v.y, v.z);
-1
View File
@@ -45,7 +45,6 @@ public class GameController : MonoBehaviour
{
hostPlayer = FindAnyObjectByType<CECHostPlayer>();
}
Debug.Log("hostPlayer " + hostPlayer);
return hostPlayer;
}
public void InitCharacter(cmd_self_info_1 info)
+8 -4
View File
@@ -4,7 +4,7 @@ using UnityEngine;
public class PlayerVisual : MonoBehaviour
{
[SerializeField] NamedAnimancerComponent animancer;
[SerializeField] NamedAnimancerComponent namedAnimancer;
[SerializeField] private INFO _playerInfo;
@@ -12,13 +12,13 @@ public class PlayerVisual : MonoBehaviour
private void PlayActionEventHandler(PlayActionEvent @event)
{
BrewMonster.Logger.Log("PlayActionEventHandler : "+@event.AnimationName);
animancer.TryPlay(@event.AnimationName);
namedAnimancer.TryPlay(@event.AnimationName);
}
public void InitHostPlayerEventDoneHandler()
{
animancer = GetComponentInChildren<NamedAnimancerComponent>();
if(animancer == null)
namedAnimancer = GetComponentInChildren<NamedAnimancerComponent>();
if(namedAnimancer == null)
{
BrewMonster.Logger.LogError("animancer == null");
return;
@@ -36,4 +36,8 @@ public class PlayerVisual : MonoBehaviour
{
EventBus.UnsubscribeAllInChannel(_playerInfo.cid);
}
public bool IsAnimationExist(string animationName)
{
return namedAnimancer.States.TryGet("ActionName", out var existingState) ? true : false;
}
}