diff --git a/Assets/PerfectWorld/Scripts/Common/MonoSingleton.cs b/Assets/PerfectWorld/Scripts/Common/MonoSingleton.cs index ed75f8764b..752c9cb5ee 100644 --- a/Assets/PerfectWorld/Scripts/Common/MonoSingleton.cs +++ b/Assets/PerfectWorld/Scripts/Common/MonoSingleton.cs @@ -26,7 +26,6 @@ namespace BrewMonster protected virtual void Awake() { _instance = this as T; - BrewMonster.BMLogger.Log("HoangDev : " + gameObject.name); Initialize(); } diff --git a/Assets/PerfectWorld/Scripts/Managers/CECNPCMan.cs b/Assets/PerfectWorld/Scripts/Managers/CECNPCMan.cs index d2ab1ac931..6d810429ed 100644 --- a/Assets/PerfectWorld/Scripts/Managers/CECNPCMan.cs +++ b/Assets/PerfectWorld/Scripts/Managers/CECNPCMan.cs @@ -1,4 +1,4 @@ -using BrewMonster; +using BrewMonster; using CSNetwork; using CSNetwork.GPDataType; using DG.Tweening; @@ -13,6 +13,8 @@ public class CECNPCMan : CECObject, IMsgHandler { private Dictionary m_NPCTab = new Dictionary(512); private Dictionary m_UkNPCTab = new Dictionary(32); + + List m_aDisappearNPCs = new List(32); Vector3 m_vServerPos; public int HandlerId => (int)MANAGER_INDEX.MAN_NPC; @@ -30,11 +32,138 @@ public class CECNPCMan : CECObject, IMsgHandler case long value when value == EC_MsgDef.MSG_NM_NPCINFO: OnMsgNPCInfo(Msg); break; case long value when value == EC_MsgDef.MSG_NM_NPCMOVE: OnMsgNPCMove(Msg); break; case long value when value == EC_MsgDef.MSG_NM_NPCSTOPMOVE: OnMsgNPCStopMove(Msg); break; + case long value when value == EC_MsgDef.MSG_NM_NPCDIED: OnMsgNPCDied(Msg); break; + case long value when value == EC_MsgDef.MSG_NM_NPCDISAPPEAR: OnMsgNPCDisappear(Msg); break; + case long value when value == EC_MsgDef.MSG_NM_NPCATKRESULT: TransmitMessage(Msg); break; } } return true; } + private void OnMsgNPCDisappear(ECMSG Msg) + { + var pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + NPCDisappear(pCmd.id); + } + void NPCDisappear(int nid) + { + CECNPC pNPC = GetNPC(nid); + if (pNPC) + { + if (!pNPC.IsDead()) + { + // NPC Ïûʧʱ£¨¿ÉÄÜÉíÉÏ»¹ÓÐÏà¹ØÌØÐ§£¬ÐèÒª´¥·¢£¬Èç×Ô±¬Ê±±¬Õ¨ÌØÐ§£© + // ËäÈ»ÔÚ CECNPC::Killed ÖÐÒÑ×ö´¦Àí£¬µ«¿Í»§¶Ë¿ÉÄÜ»áÖ±½ÓÊÕµ½ disappear ÏûÏ¢£¨Èç×Ô±¬¼¼ÄÜ£© + // Òò´ËÕâÀïÐèÒªÔö¼Ó´¥·¢µ÷Óà + // Èô֮ǰ NPC ÒÑËÀÍö£¬Ôò˵Ã÷Òѵ÷Óùý + pNPC.ClearComActFlag(true); + } + + pNPC.Disappear(); + + // From npc from active table and add it to disappear table + //NPCLeave(nid, true, false); + m_aDisappearNPCs.Add(pNPC); + } + } + private bool TransmitMessage(ECMSG Msg) + { + int nid = 0; + + switch (Msg.dwMsg) + { + case long value when value == EC_MsgDef.MSG_NM_NPCATKRESULT: + nid = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1).attacker_id; + break; + + /* case long value when value == EC_MsgDef.MSG_NM_NPCEXTSTATE: + nbvlijuhygtfrde4dws84wi7ujyxfsdcefvgbhjzsxdcfvcgvhjaqzsDRa + nid = ((cmd_update_ext_state*)Msg.dwParam1)->id; + break; + + case long value when value == EC_MsgDef.MSG_NM_NPCCASTSKILL: + + nid = ((cmd_object_cast_skill*)Msg.dwParam1)->caster; + break; + + case long value when value == EC_MsgDef.MSG_NM_ENCHANTRESULT: + + nid = ((cmd_enchant_result*)Msg.dwParam1)->caster; + break; + + case long value when value == EC_MsgDef.MSG_NM_NPCROOT: + + nid = ((cmd_object_root*)Msg.dwParam1)->id; + break; + + case long value when value == EC_MsgDef.MSG_NM_NPCSKILLRESULT: + + nid = ((cmd_object_skill_attack_result*)Msg.dwParam1)->attacker_id; + break; + + case long value when value == EC_MsgDef.MSG_NM_NPCLEVELUP: + + nid = ((cmd_level_up*)Msg.dwParam1)->id; + break; + + case long value when value == EC_MsgDef.MSG_NM_NPCINVISIBLE: + + nid = ((cmd_object_invisible*)Msg.dwParam1)->id; + break; + + case long value when value == EC_MsgDef.MSG_NM_NPCSTARTPLAYACTION: + nid = ((cmd_object_start_play_action*)Msg.dwParam1)->id; + break; + + case long value when value == EC_MsgDef.MSG_NM_NPCSTOPPLAYACTION: + nid = ((cmd_object_stop_play_action*)Msg.dwParam1)->id; + break; + case long value when value == EC_MsgDef.MSG_NM_MULTIOBJECT_EFFECT: + nid = ((cmd_multiobj_effect*)Msg.dwParam1)->id; + break; + + default: + return false;*/ + } + return true; + } + + private bool OnMsgNPCDied(ECMSG msg) + { + int nid = 0, idKiller = 0; + bool bDelay = false; + + var stateNPC = Convert.ToInt32(msg.dwParam2); + var byteArray = (byte[])msg.dwParam1; + if (stateNPC == CommandID.NPC_DIED) + { + cmd_npc_died pCmd = EC_Utility.ByteArrayToStructure(byteArray); + nid = pCmd.id; + idKiller = pCmd.idKiller; + } + else if (stateNPC == CommandID.NPC_DIED2) + { + cmd_npc_died2 pCmd = EC_Utility.ByteArrayToStructure(byteArray); + nid = pCmd.id; + idKiller = pCmd.idKiller; + bDelay = true; + } + if (!GPDataTypeHelper.ISNPCID(nid)) + return false; + + CECNPC pNPC = GetNPC(nid); + if (pNPC && !pNPC.IsAboutToDie()) + { + pNPC.Killed(bDelay); + + // Below codes may case the last damaged bubble number before + // npc died couldn't popup + // if (!bDelay) + // NPCDisappear(nid); + } + return true; + } + private bool OnMsgNPCStopMove(ECMSG msg) { cmd_object_stop_move pCmd = EC_Utility.ByteArrayToStructure((byte[])msg.dwParam1); @@ -144,8 +273,8 @@ public class CECNPCMan : CECObject, IMsgHandler CECNPC pNPC = SeekOutNPC(pCmd.idNPC); if (pNPC) { - ROLEBASICPROP bp = pNPC.GetBasicProps(); - ROLEEXTPROP ep = pNPC.GetExtendProps(); + ROLEBASICPROP bp = pNPC.GetBasicProps(); + ROLEEXTPROP ep = pNPC.GetExtendProps(); bp.iCurHP = pCmd.iHP; ep.bs.max_hp = pCmd.iMaxHP; @@ -181,7 +310,7 @@ public class CECNPCMan : CECObject, IMsgHandler // Tạo NPC mới npc = CreateNPC(Info, bBornInSight, packet, infoOffset); - if(npc != null) + if (npc != null) { npc.SetUpCECNPC(this); } @@ -204,7 +333,7 @@ public class CECNPCMan : CECObject, IMsgHandler return npc; } - public CECNPC GetNPCFromAll(int nid) + public CECNPC GetNPCFromAll(int nid) { CECNPC pNPC = GetNPC(nid); if (pNPC) @@ -249,9 +378,7 @@ public class CECNPCMan : CECObject, IMsgHandler { case DATA_TYPE.DT_NPC_ESSENCE: /*pNPC = new CECNPCServer(this);*/ break; case DATA_TYPE.DT_MONSTER_ESSENCE: - pNPC = GameController.Instance.GetMonster(); - break; case DATA_TYPE.DT_PET_ESSENCE:/* pNPC = new CECPet(this);*/ break; default: diff --git a/Assets/PerfectWorld/Scripts/Move/CECCounter.cs b/Assets/PerfectWorld/Scripts/Move/CECCounter.cs index 1fac1cb408..1a9664de04 100644 --- a/Assets/PerfectWorld/Scripts/Move/CECCounter.cs +++ b/Assets/PerfectWorld/Scripts/Move/CECCounter.cs @@ -1,10 +1,10 @@ -using UnityEngine; +using UnityEngine; public class CECCounter { // Thuộc tính - protected float m_dwCounter; // Counter - protected float m_dwPeriod; // Count period + protected uint m_dwCounter; // Counter + protected uint m_dwPeriod; // Count period // Constructor public CECCounter() @@ -14,17 +14,16 @@ public class CECCounter } // Set / Get period - public void SetPeriod(float dwPeriod) { m_dwPeriod = dwPeriod; } - public float GetPeriod() { return m_dwPeriod; } + public void SetPeriod(uint dwPeriod) { m_dwPeriod = dwPeriod; } + public uint GetPeriod() { return m_dwPeriod; } // Set / Get counter - public void SetCounter(float dwCounter) { m_dwCounter = dwCounter; } - public float GetCounter() { return m_dwCounter; } + public void SetCounter(uint dwCounter) { m_dwCounter = dwCounter; } + public uint GetCounter() { return m_dwCounter; } // Has counter reached period ? public bool IsFull() { - Debug.LogWarning($"HoangDev : {m_dwCounter} {m_dwPeriod} "); return (m_dwCounter >= m_dwPeriod); } @@ -35,14 +34,14 @@ public class CECCounter } // Increase counter - public bool IncCounter(float dwCounter) + public bool IncCounter(uint dwCounter) { m_dwCounter += dwCounter; return (m_dwCounter >= m_dwPeriod); } // Decrease counter - public void DecCounter(float dwCounter) + public void DecCounter(uint dwCounter) { if (m_dwCounter <= dwCounter) m_dwCounter = 0; diff --git a/Assets/PerfectWorld/Scripts/NPC/CECModel.cs b/Assets/PerfectWorld/Scripts/NPC/CECModel.cs index 3a0f1d58b9..b37698daf1 100644 --- a/Assets/PerfectWorld/Scripts/NPC/CECModel.cs +++ b/Assets/PerfectWorld/Scripts/NPC/CECModel.cs @@ -1,8 +1,40 @@ +using System; +using Unity.VisualScripting; +using UnityEditor.ShaderGraph.Internal; using UnityEngine; +using UnityEngine.UIElements; +using static CECNPC; public class CECModel { + private const uint COMACT_FLAG_MODE_NONE = 0; + public void ClearComActFlag(bool bSignalCurrent) { ClearComActFlag(0, bSignalCurrent); } + public void ClearComActFlag(int nChannel, bool bSignalCurrent) + { + /* ChannelAct & ca = m_ChannelActs[nChannel]; + ChannelActNode* pNode = ca.GetHighestRankNode(); + if (pNode) + { + if (pNode->m_pActFlag && bSignalCurrent) + *pNode->m_pActFlag = true; + + //ca.m_dwFlagMode = COMACT_FLAG_MODE_NONE; + pNode->m_pActFlag = NULL; + }*/ + } + public bool QueueAction(CECNPC.INFO iNFO, string szActName, ref bool pNewActFlag, int nTransTime = 200, uint dwUserData = 0, bool bForceStopPrevAct = false, bool bCheckTailDup = false, bool bNoFx = false, bool bResetSpeed = false + /*joslian*/, bool bResetActFlag = false, uint dwNewFlagMode = COMACT_FLAG_MODE_NONE) + { + QueueAction(iNFO,0, szActName, ref bResetActFlag, nTransTime, dwUserData, bForceStopPrevAct, bCheckTailDup, bNoFx, bResetSpeed/*joslian*/, pNewActFlag, dwNewFlagMode); + return true; + } + public bool QueueAction(CECNPC.INFO iNFO, int nChannel, string szActName, ref bool pNewActFlag, int nTransTime, uint dwUserData/* 0 */, bool bForceStopPrevAct, bool bCheckTailDup, bool bNoFx, bool bResetSpeed + /*joslian*/, bool bResetActFlag, uint dwNewFlagMode) + { + EventBus.PublishChannel(iNFO.nid, new QueueActionEvent(szActName, ref pNewActFlag, false)); + return true; + } } // Action channel public enum ActionChannel diff --git a/Assets/PerfectWorld/Scripts/NPC/CECNPC.cs b/Assets/PerfectWorld/Scripts/NPC/CECNPC.cs index fb3e92850b..7103085522 100644 --- a/Assets/PerfectWorld/Scripts/NPC/CECNPC.cs +++ b/Assets/PerfectWorld/Scripts/NPC/CECNPC.cs @@ -1,4 +1,4 @@ -using CSNetwork.GPDataType; +using CSNetwork.GPDataType; using System.Text; using System; using UnityEngine; @@ -32,7 +32,9 @@ public class CECNPC : CECObject protected int m_idSelTarget; protected int m_iCurWorkType; protected int m_iCurWork; - protected int m_DisappearCnt; + protected CECCounter m_DisappearCnt; + protected CECCounter m_TransCnt; + protected int m_StartDisappearCnt; protected bool m_bAboutToDie; protected Vector3 m_vStopDir; protected ROLEEXTPROP m_ExtProps; @@ -67,7 +69,8 @@ public class CECNPC : CECObject m_iCurWork = 0; m_bStartFight = false; m_bAboutToDie = false; - m_DisappearCnt = 5000; + m_DisappearCnt.SetPeriod(5000); + m_StartDisappearCnt = 0; m_BasicProps = new ROLEBASICPROP(true); // struct mặc định, các trường số = 0, mảng đã tạo m_ExtProps = new ROLEEXTPROP(true); @@ -152,7 +155,62 @@ public class CECNPC : CECObject { case (int)WorkID.WORK_MOVE: TickWork_Move(Time.deltaTime); break; } + + if (IsDisappearing()) + { + // When m_DisappearCnt passed half length, start changing model's transparence + uint dwOldCnt = m_DisappearCnt.GetCounter(); + m_DisappearCnt.IncCounter((uint)Time.deltaTime * 1000); + uint dwHalf = m_DisappearCnt.GetPeriod() / 2; + + if (dwOldCnt < dwHalf && m_DisappearCnt.GetCounter() >= dwHalf) + StartAdjustTransparency(-1.0f, 1.0f, dwHalf); + } + else + { + StartAdjustTransparency(-1.0f, GetTransparentLimit(), 500); + } } + float GetTransparentLimit() + { + if ((m_dwStates & (uint)PlayerNPCState.GP_STATE_INVISIBLE) != 0) + { + return 0.7f;//ÒþÉí + } + else if (!IsSelectable()) + { + return 0.5f;//ÎÞ·¨Ñ¡ÖÐ + } + + return -1.0f; + } + bool StartAdjustTransparency(float fCur, float fDest, uint dwTime) + { + // use current value for starting + /*if (fCur < 0.0f) + { + if (!m_pNPCModelPolicy->GetTransparent(fCur)) + { + fCur = m_fCurTrans; + } + } + + if (fDest < 0.f) fDest = 0.f; + + // ignore the invalid params + if (dwTime == 0 || fabs(fDest - m_fDstTrans) < 0.0001f || fabs(fDest - fCur) < 0.0001f) + return false; + + m_fCurTrans = fCur; + m_fDstTrans = fDest; + m_fTransDelta = (fDest - m_fCurTrans) / dwTime; + + m_TransCnt.SetPeriod(dwTime); + m_TransCnt.Reset();*/ + + return true; + } + public void TickWork_Move(float dwDeltaTime) { if (m_bAboutToDie) @@ -264,6 +322,32 @@ public class CECNPC : CECObject } } } + public bool IsAboutToDie() { return m_bAboutToDie; } + public void Killed(bool bDelay) + { + ClearComActFlag(true); + + m_dwStates |= PlayerNPCState.GP_STATE_CORPSE; + + // No delay die, enter disappear process immediately + if (!bDelay) + Disappear(); + + StartWork((int)WorkType.WT_NORMAL, (int)WorkID.WORK_DEAD, m_dwStates); + + SetUseGroundNormal(true); + } + public void Disappear() + { + // Trigger disappear counting to start + m_DisappearCnt.SetCounter(1); + PlayModelAction((int)NPCActionIndex.ACT_NPC_DISAPPEAR); + } + public void ClearComActFlag(bool bSignalCurrent) + { + m_pNPCModelPolicy.ClearComActFlag(bSignalCurrent); + } + public void Damaged(int iDamage, uint dwModifier/* 0 */) { if (iDamage == -1 || iDamage == -2) @@ -271,7 +355,7 @@ public class CECNPC : CECObject // when else player hit this npc iDamage is -1, // so if iDamage is -1 we will shoud the wounded animation if (iDamage == -1) - PlayModelAction((int)NPCActionIndex. ACT_WOUNDED); + PlayModelAction((int)NPCActionIndex.ACT_WOUNDED); DamageTextManager.Instance.SpawnDamage(transform.position, iDamage, Color.red, 1.0f); /*if ((dwModifier & (uint)MOD.MOD_IMMUNE) != 0 *//* && !IsImmuneDisable()*//*) @@ -289,13 +373,13 @@ public class CECNPC : CECObject { // this message is related to the host, so we should show a pop up message // Popup a damage decal - /* bool bDeadlyStrike = (dwModifier & CECAttackEvent::MOD_CRITICAL_STRIKE) ? true : false; - bool bRetort = (dwModifier & CECAttackEvent::MOD_RETORT) ? true : false;*/ + /* bool bDeadlyStrike = (dwModifier & CECAttackEvent::MOD_CRITICAL_STRIKE) ? true : false; + bool bRetort = (dwModifier & CECAttackEvent::MOD_RETORT) ? true : false;*/ if (iDamage > 0) { PlayModelAction((int)NPCActionIndex.ACT_WOUNDED); - DamageTextManager.Instance.SpawnDamage(transform.position, iDamage, Color.red, 1.0f); + DamageTextManager.Instance.SpawnDamage(transform.position, iDamage, Color.red, 1.0f); /* int p1 = 0; if (bDeadlyStrike) p1 |= 0x0001; @@ -309,16 +393,16 @@ public class CECNPC : CECObject else BubbleText(BUBBLE_DAMAGE, (DWORD)iDamage, p1);*/ } - /* else if ((dwModifier & CECAttackEvent::MOD_IMMUNE) && !IsImmuneDisable()) - BubbleText(BUBBLE_IMMUNE, 0); - else if (dwModifier & CECAttackEvent::MOD_NULLITY) - BubbleText(BUBBLE_INVALIDHIT, 0); - else if (dwModifier & CECAttackEvent::MOD_ENCHANT_FAILED) - BubbleText(BUBBLE_LOSE, 0); - else if (dwModifier & CECAttackEvent::MOD_SUCCESS) - BubbleText(BUBBLE_SUCCESS, 0); - else - BubbleText(BUBBLE_HITMISSED, 0);*/ + /* else if ((dwModifier & CECAttackEvent::MOD_IMMUNE) && !IsImmuneDisable()) + BubbleText(BUBBLE_IMMUNE, 0); + else if (dwModifier & CECAttackEvent::MOD_NULLITY) + BubbleText(BUBBLE_INVALIDHIT, 0); + else if (dwModifier & CECAttackEvent::MOD_ENCHANT_FAILED) + BubbleText(BUBBLE_LOSE, 0); + else if (dwModifier & CECAttackEvent::MOD_SUCCESS) + BubbleText(BUBBLE_SUCCESS, 0); + else + BubbleText(BUBBLE_HITMISSED, 0);*/ } } @@ -326,7 +410,7 @@ public class CECNPC : CECObject { // Note: below judge can prevent many problems when we attempt to // finish a work but don't assure we are doing this work - BrewMonster.BMLogger.Log("HoangDev : WorkFinished :"+ iWorkID); + BrewMonster.BMLogger.Log("HoangDev : WorkFinished :" + iWorkID); if (m_iCurWork != iWorkID) return; @@ -397,7 +481,7 @@ public class CECNPC : CECObject var monsterModel = Instantiate(model, transform); monsterModel.SetActive(true); var npcVisual = GetComponent(); - npcVisual.InitNPCEventDoneHandler(); + npcVisual.InitNPCEventDoneHandler(m_NPCInfo); //QueueECModelForLoad(MTL_ECM_NPC, GetNPCInfo().nid, GetBornStamp(), GetServerPos(), szModelFile, tid); } @@ -858,7 +942,7 @@ public class CECNPC : CECObject bool IsMonsterNPC() { return (int)Class_ID.OCID_MONSTER == m_iCID; } bool IsPetNPC() { return (int)Class_ID.OCID_PET == m_iCID; } - public bool IsDead(){ return (m_dwStates & PlayerNPCState.GP_STATE_CORPSE) != 0; } + public bool IsDead() { return (m_dwStates & PlayerNPCState.GP_STATE_CORPSE) != 0; } public void PlayMoveAction(int iMoveMode) { //BrewMonster.BMLogger.LogError($"HoangDev: PlayMoveAction {iMoveMode}"); @@ -883,32 +967,32 @@ public class CECNPC : CECObject public void PlayModelAction(int iAction, bool bRestart = false) { m_iAction = iAction; - /* if (IsDead()) - { - // ¼ì²éËÀÍö״̬£¬ÒÔÆÁ±ÎÆäËü¶¯×÷ - // ËÀÍö״̬ÉèÖúó£¬Ö»ÔÊÐí²¥·ÅËÀÍö¶¯×÷ - // Íæ¼Ò¹¥»÷NPCʱ£¬»áÊ×ÏȲ¥·ÅÍæ¼ÒµÄ¹¥»÷¶¯×÷£¬Íê³Éºó²¥·Å¹ÖÎïµÄÊÜÉ˶¯×÷ - // µ«ÔÚÍæ¼Ò×ÔÉíµÄ¹¥»÷¶¯×÷δÍê³Éʱ£¬¿ÉÄܾÍÊÕµ½NPCËÀÍöµÄÏûÏ¢ - // Òò´Ë£¬¿ÉÄÜ»áÏȲ¥·ÅËÀÍö¶¯×÷£¬¶øºóÓÖ²¥·ÅÊÜÉ˶¯×÷£¬µ¼ÖÂËÀÍö¶¯×÷²»ÄÜÕý³£²¥·ÅµÄ±íÏÖ½á¹û - // ²»·ûºÏÆÚÍû - if (IsMonsterOrPet()) - { - if (iAction != CECNPC::ACT_DIE) - { - return; - } - } - else - { - if (iAction != CECNPC::ACT_NPC_DIE) - { - return; - } - } - }*/ + if (IsDead()) + { + // ¼ì²éËÀÍö״̬£¬ÒÔÆÁ±ÎÆäËü¶¯×÷ + // ËÀÍö״̬ÉèÖúó£¬Ö»ÔÊÐí²¥·ÅËÀÍö¶¯×÷ + // Íæ¼Ò¹¥»÷NPCʱ£¬»áÊ×ÏȲ¥·ÅÍæ¼ÒµÄ¹¥»÷¶¯×÷£¬Íê³Éºó²¥·Å¹ÖÎïµÄÊÜÉ˶¯×÷ + // µ«ÔÚÍæ¼Ò×ÔÉíµÄ¹¥»÷¶¯×÷δÍê³Éʱ£¬¿ÉÄܾÍÊÕµ½NPCËÀÍöµÄÏûÏ¢ + // Òò´Ë£¬¿ÉÄÜ»áÏȲ¥·ÅËÀÍö¶¯×÷£¬¶øºóÓÖ²¥·ÅÊÜÉ˶¯×÷£¬µ¼ÖÂËÀÍö¶¯×÷²»ÄÜÕý³£²¥·ÅµÄ±íÏÖ½á¹û + // ²»·ûºÏÆÚÍû + if (IsMonsterOrPet()) + { + if (iAction != (int)NPCActionIndex.ACT_DIE) + { + return; + } + } + else + { + if (iAction != (int)NPCActionIndex.ACT_NPC_DIE) + { + return; + } + } + } m_pNPCModelPolicy.PlayModelAction(iAction, bRestart); } - bool IsDisappearing() { return m_DisappearCnt == 0 ? true : false; } + bool IsDisappearing() { return m_DisappearCnt.GetCounter() != 0 ? true : false; } public float GetTouchRadius() { return m_fTouchRad; } @@ -928,8 +1012,8 @@ public class CECNPC : CECObject // Get NPC's real position on server public A3DVECTOR3 GetServerPos() - { - return EC_Utility.ToA3DVECTOR3(m_vServerPos); + { + return EC_Utility.ToA3DVECTOR3(m_vServerPos); } // Get master id @@ -940,22 +1024,22 @@ public class CECNPC : CECObject public virtual bool IsInBattleDefenderCamp() { return false; } // Get role in battle public virtual int GetRoleInBattle() { return 0; } - public int GetOwnerFaction(){ return m_idOwnerFaction; } + public int GetOwnerFaction() { return m_idOwnerFaction; } public bool IsFactionPVPMineCar() - { - //if (const MONSTER_ESSENCE* pMonsterEssence = GetMonsterEssence()){ - // return (pMonsterEssence.faction & (1 << 19)) != 0; - //} - return false; + { + //if (const MONSTER_ESSENCE* pMonsterEssence = GetMonsterEssence()){ + // return (pMonsterEssence.faction & (1 << 19)) != 0; + //} + return false; } public bool IsFactionPVPMineBase() - { - //if (const MONSTER_ESSENCE *pMonsterEssence = GetMonsterEssence()){ - // return (pMonsterEssence->faction & (1 << 20)) != 0; - //} - return false; + { + //if (const MONSTER_ESSENCE *pMonsterEssence = GetMonsterEssence()){ + // return (pMonsterEssence->faction & (1 << 20)) != 0; + //} + return false; } // Get NPC ID diff --git a/Assets/PerfectWorld/Scripts/NPC/CECNPCModelDefaultPolicy.cs b/Assets/PerfectWorld/Scripts/NPC/CECNPCModelDefaultPolicy.cs index beb5d38035..e6a4dca8e1 100644 --- a/Assets/PerfectWorld/Scripts/NPC/CECNPCModelDefaultPolicy.cs +++ b/Assets/PerfectWorld/Scripts/NPC/CECNPCModelDefaultPolicy.cs @@ -1,4 +1,5 @@ -using CSNetwork.Protocols; +using BrewMonster; +using CSNetwork.Protocols; using UnityEngine; public class CECNPCModelDefaultPolicy @@ -31,16 +32,23 @@ public class CECNPCModelDefaultPolicy // Trả về kết quả đã clean return result; } - + public override void ClearComActFlag(bool bSignalCurrent) + { + if (m_pNPCModel != null) + { + m_pNPCModel.ClearComActFlag(bSignalCurrent); + } + } public override bool PlayModelAction(int iAction, bool bRestart) { - /* if (m_pNPCModel == null) - { - return false; - } -*/ + /* if (m_pNPCModel == null) + { + return false; + } + */ bool result = false; + bool ignoreRef = false; if (iAction == (int)NPCActionIndex.ACT_WOUNDED) { @@ -57,8 +65,17 @@ public class CECNPCModelDefaultPolicy 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);*/ + string szAct = GetActionName(iAction, false); + string szAct2 = GetActionName((int)NPCActionIndex.ACT_GUARD); + + if (!_npcVisual.IsAnimationExist(szAct)) + { + m_pNPCModel.QueueAction(_npcVisual.GetNPCINFO, szAct, ref ignoreRef, 0, 0, false, false, false); + } + if (!_npcVisual.IsAnimationExist(szAct2)) + { + m_pNPCModel.QueueAction(_npcVisual.GetNPCINFO, szAct2, ref ignoreRef, 300); + } } } else if (iAction == (int)NPCActionIndex.ACT_IDLE) @@ -66,6 +83,11 @@ public class CECNPCModelDefaultPolicy result = _npcVisual.TryPlayAction(GetActionName(iAction)); if (result) { + string szAct2 = GetActionName((int)NPCActionIndex.ACT_STAND); + if (!_npcVisual.IsAnimationExist(szAct2)) + { + m_pNPCModel.QueueAction(_npcVisual.GetNPCINFO, szAct2, ref ignoreRef, 300); + } //m_pNPCModel->QueueAction(GetActionName((int)NPCActionIndex.ACT_STAND)); } } @@ -74,17 +96,30 @@ public class CECNPCModelDefaultPolicy result = _npcVisual.TryPlayAction(GetActionName(iAction)); if (result) { + string szAct2 = GetActionName((int)NPCActionIndex.ACT_NPC_STAND); + if (!_npcVisual.IsAnimationExist(szAct2)) + { + m_pNPCModel.QueueAction(_npcVisual.GetNPCINFO, szAct2, ref ignoreRef, 300); + } //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)); ; + 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_NPC_STAND), 300);*/ + string szAct = GetActionName(iAction, false); + string szAct2 = GetActionName((int)NPCActionIndex.ACT_NPC_STAND); + if (!_npcVisual.IsAnimationExist(szAct)) + { + m_pNPCModel.QueueAction(_npcVisual.GetNPCINFO, szAct, ref ignoreRef, 0, 0, false, false, false); + } + if (!_npcVisual.IsAnimationExist(szAct2)) + { + m_pNPCModel.QueueAction(_npcVisual.GetNPCINFO, szAct2, ref ignoreRef, 300); + } } } else if (iAction == (int)NPCActionIndex.ACT_COMMON_BORN) @@ -92,11 +127,20 @@ public class CECNPCModelDefaultPolicy result = _npcVisual.TryPlayAction(GetActionName(iAction)); if (result) { + string szAct2 = GetActionName((int)NPCActionIndex.ACT_STAND); + if (!_npcVisual.IsAnimationExist(szAct2)) + { + m_pNPCModel.QueueAction(_npcVisual.GetNPCINFO, szAct2, ref ignoreRef, 300); + } //m_pNPCModel->QueueAction(GetActionName((int)NPCActionIndex.ACT_STAND)); } } else { + if (iAction == (int)NPCActionIndex.ACT_DIE || iAction == (int)NPCActionIndex.ACT_NPC_DIE) + { + BMLogger.LogError(GetActionName(iAction)); + } result = _npcVisual.TryPlayAction(GetActionName(iAction)); } return result; @@ -117,4 +161,5 @@ public class CECNPCModelDefaultPolicy { _npcVisual = npcVisual; } + } diff --git a/Assets/PerfectWorld/Scripts/NPC/CECNPCModelPolicy.cs b/Assets/PerfectWorld/Scripts/NPC/CECNPCModelPolicy.cs index 26ab3ab3ea..0fc2b04bb2 100644 --- a/Assets/PerfectWorld/Scripts/NPC/CECNPCModelPolicy.cs +++ b/Assets/PerfectWorld/Scripts/NPC/CECNPCModelPolicy.cs @@ -1,18 +1,13 @@ -using UnityEngine; +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; - } + public abstract bool PlayModelAction(int iAction, bool bRestart); + public abstract bool IsPlayingAction(); + public abstract bool IsPlayingAction(int iActions); + public abstract void SetNpcVisual(NPCVisual npcVisual); + public abstract bool HasAction(int iAction); + public abstract void ClearComActFlag(bool bSignalCurrent); } diff --git a/Assets/PerfectWorld/Scripts/NPC/NPCVisual.cs b/Assets/PerfectWorld/Scripts/NPC/NPCVisual.cs index 75c2e54822..c31a947663 100644 --- a/Assets/PerfectWorld/Scripts/NPC/NPCVisual.cs +++ b/Assets/PerfectWorld/Scripts/NPC/NPCVisual.cs @@ -1,15 +1,23 @@ -using Animancer; +using Animancer; using BrewMonster; +using System; +using System.Collections.Generic; using UnityEngine; public class NPCVisual : MonoBehaviour { [SerializeField] NamedAnimancerComponent namedAnimancer; + protected CECNPC.INFO m_NPCInfo; + [SerializeField] private Queue _animationQueue = new Queue(); + [SerializeField] private bool pActFlag; + [SerializeField] private bool isHit; + [SerializeField] private AnimancerState _currentState; + public CECNPC.INFO GetNPCINFO => m_NPCInfo; #if UNITY_EDITOR - [SerializeField] bool isDebug; + [SerializeField] bool isDebug; public void DEBUG(string text) { - if(!isDebug) return; + if (!isDebug) return; BMLogger.LogError(text); } #endif @@ -18,22 +26,65 @@ public class NPCVisual : MonoBehaviour DEBUG("HoangDev: TryPlayAction: " + animationName); if (namedAnimancer == null) return false; if (namedAnimancer.IsPlaying(animationName)) return false; - - return namedAnimancer.TryPlay(animationName) == null; + _currentState = namedAnimancer.TryPlay(animationName); + return _currentState == null; } - public void InitNPCEventDoneHandler() + public void InitNPCEventDoneHandler(CECNPC.INFO iNFO) { + m_NPCInfo = iNFO; namedAnimancer = GetComponentInChildren(); if (namedAnimancer == null) { BrewMonster.BMLogger.LogError("animancer == null"); return; } + EventBus.SubscribeChannel(m_NPCInfo.nid, OnQueueAction); + } + private void Update() + { + PlayNext(); + } + private void OnQueueAction(QueueActionEvent @event) + { + if (!EnqueueAnimation(@event)) + { + BMLogger.LogError("HoangDev : EnqueueAnimation Failed"); + } + } + public bool EnqueueAnimation(QueueActionEvent @event) + { + if (namedAnimancer == null) return false; + + _animationQueue.Enqueue(@event.AnimationName); + pActFlag = @event.PActFlag; + isHit = @event.IsHitAnim; + return true; + } + private void PlayNext() + { + if (_animationQueue.Count == 0) + { + return; + } + if (_currentState == null) return; + if (_currentState.IsPlaying) return; + if (isHit) + { + SetpActFlagTrue(); + isHit = false; + return; + } + string animName = _animationQueue.Dequeue(); + _currentState = namedAnimancer.TryPlay(animName); + } + private void SetpActFlagTrue() + { + pActFlag = true; } private void OnDestroy() { - + EventBus.UnsubscribeAllInChannel(m_NPCInfo.nid); } public bool IsAnimationExist(string animationName) { diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/EC_ManMessage.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/EC_ManMessage.cs index a7de0199cd..3d34ba5156 100644 --- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/EC_ManMessage.cs +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/EC_ManMessage.cs @@ -58,7 +58,6 @@ namespace CSNetwork public static void Tick() { int i, count = Instance.m_MsgList.Count; - _logger.Info($"HoangDev : "+ Instance.m_MsgList.Count); for (i = 0; i < count; i++) { ECMSG msg = Instance.m_MsgList.Dequeue(); diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/GPDataType.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/GPDataType.cs index bf7772adde..01c8cfffa1 100644 --- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/GPDataType.cs +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/GPDataType.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Buffers.Binary; using System.Collections.Generic; using System.Numerics; @@ -562,7 +562,32 @@ namespace CSNetwork.GPDataType public const int PROF_YUEXIAN = 11; // 11:ÔÂÏÉ public const int NUM_PROFESSION = 12; }; - + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct cmd_npc_died + { + public int id; + public int idKiller; + }; + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct cmd_npc_died2 + { + public int id; + public int idKiller; + }; + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct cmd_object_atk_result + { + public int attacker_id; + public int target_id; + public int damage; + public int attack_flag; //±ê¼Ç¸Ã¹¥»÷ÊÇ·ñÓй¥»÷ÓÅ»¯·ûºÍ·ÀÓùÓÅ»¯·ûºÍÖØ»÷·¢Éú + public char speed; //¹¥»÷ËÙ¶È speed * 50 ms + }; + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct cmd_object_disappear + { + public int id; + }; [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct cmd_object_move { diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs index f3e9204c67..76d43dccf0 100644 --- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs @@ -1,4 +1,4 @@ -using System.Text; +using System.Text; using System; using CSNetwork.Protocols; using CSNetwork.Protocols.RPCData; @@ -436,6 +436,23 @@ namespace CSNetwork EC_ManMessage.PostMessage(EC_MsgDef.MSG_HST_SELTARGET, MANAGER_INDEX.MAN_PLAYER, 0, pDataBuf, pCmdHeader); break; + case CommandID.NPC_DIED: + case CommandID.NPC_DIED2: + + EC_ManMessage.PostMessage(EC_MsgDef.MSG_NM_NPCDIED, MANAGER_INDEX.MAN_NPC, 0, pDataBuf, pCmdHeader); + break; + case CommandID.OBJECT_DISAPPEAR: + { + int lenghtDataType1 = Marshal.SizeOf(); + byte[] arrByteData1 = GetBytes(pDataBuf, lenghtDataType1, 0); + int idObjMove1 = BitConverter.ToInt32(arrByteData1); + if (ISPLAYERID(idObjMove1)) + EC_ManMessage.PostMessage(EC_MsgDef.MSG_PM_PLAYERDISAPPEAR, MANAGER_INDEX.MAN_PLAYER, -1, pDataBuf, pCmdHeader); + else if (ISNPCID(idObjMove1)) + EC_ManMessage.PostMessage(EC_MsgDef.MSG_NM_NPCDISAPPEAR, MANAGER_INDEX.MAN_NPC, 0, pDataBuf, pCmdHeader); + + break; + } } } diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/NetworkManager.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/NetworkManager.cs index 1dca8a8da7..1d3eb30f6d 100644 --- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/NetworkManager.cs +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/NetworkManager.cs @@ -370,6 +370,7 @@ namespace CSNetwork BaseSecurity? currentIsec = null; lock (_securityLock) { + //_inputSecurity = BaseSecurity.Create(SecurityType.DECOMPRESSARCFOURSECURITY); currentIsec = _inputSecurity; } @@ -388,7 +389,7 @@ namespace CSNetwork Octets currentData = new Octets( _receiveOctets.RawBuffer, 0, - originalBlockLength + originalBlockLength ); _logger.Log(LogType.Info, $"ProcessBuffer:: raw first byte {currentData.RawBuffer[0]} - Length: {currentData.Length}"); // Update returns a NEW Octets object with processed data @@ -420,6 +421,8 @@ namespace CSNetwork Protocol._logger = _logger; while (processingStream.Position < dataToProcess.Length) { + _logger.Log(LogType.Info, $"ProcessBuffer:: processingStream.Position {processingStream.Position} "); + int streamPosBeforeDecode = processingStream.Position; var (p, consumedBytes) = (null as Protocol, 0); @@ -485,6 +488,7 @@ namespace CSNetwork EndProcessing: // 4. Compact the *original* _receiveOctets buffer CompactOriginalBuffer(bytesConsumedFromOriginal, originalBlockLength); + //_inputSecurity = BaseSecurity.Create(SecurityType.DECOMPRESSARCFOURSECURITY); } // *** Helper to compact the original receive buffer *** diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/Protocol.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/Protocol.cs index 9268408d89..78495654c6 100644 --- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/Protocol.cs +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/Protocol.cs @@ -80,6 +80,8 @@ namespace CSNetwork.Protocols // Check if enough data is available in the stream for the declared payload size int bytesAvailableForPayload = stream.Length - positionAfterHeader; + _logger.Debug($"Try Decode: bytesAvailableForPayload({bytesAvailableForPayload}) stream.Length:{stream.Length} - headerSize {headerSize}. positionAfterHeader: {positionAfterHeader},"); + if (bytesAvailableForPayload < size) { _logger.Debug($"Decode failed: Insufficient data. Need {size} payload bytes, have {bytesAvailableForPayload}. Rolling back."); diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/Security/DecompressArcFourSecurity.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Security/DecompressArcFourSecurity.cs index 769a67a446..db0a3dc0ba 100644 --- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/Security/DecompressArcFourSecurity.cs +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Security/DecompressArcFourSecurity.cs @@ -42,7 +42,9 @@ namespace CSNetwork.Security /// The Octets containing the encrypted and compressed data. /// A new Octets object containing the decrypted and decompressed data. public override Octets Update(Octets data) - { + { + _logger.Log(LogType.Debug, $"HoangDev: AF co vao dau {data.RawBuffer[0]} - Length: {data.Length}"); + if (data == null || data.Length == 0) { _logger.Log(LogType.Debug,$"HoangDev: AF _arcFour data{data.RawBuffer[0]} - Length: {data.Length}"); diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/Security/NullSecurity.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Security/NullSecurity.cs index dffd57284d..a5e18b9653 100644 --- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/Security/NullSecurity.cs +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Security/NullSecurity.cs @@ -5,6 +5,8 @@ namespace CSNetwork.Security /// public class NullSecurity : BaseSecurity // Inherit from Security { + private static readonly IPrefixedLogger _logger = LoggerFactory.GetLogger(nameof(DecompressArcFourSecurity)); + // Constructor to register the type public NullSecurity() : base(SecurityType.NULLSECURITY) @@ -20,6 +22,7 @@ namespace CSNetwork.Security // Update returns the data unchanged public override Octets Update(Octets data) { + _logger.Log(LogType.Debug, $"HoangDev: NullSecurity)"); return data; // No transformation } diff --git a/Assets/PerfectWorld/Scripts/UI/Login/LoginScreenUI.cs b/Assets/PerfectWorld/Scripts/UI/Login/LoginScreenUI.cs index b0622b5cd5..ea6d13aa48 100644 --- a/Assets/PerfectWorld/Scripts/UI/Login/LoginScreenUI.cs +++ b/Assets/PerfectWorld/Scripts/UI/Login/LoginScreenUI.cs @@ -57,7 +57,7 @@ namespace BrewMonster.UI } if (Input.GetKeyUp(KeyCode.Tab)) { - _usernameInputField.text = "test002"; + _usernameInputField.text = "test025"; _passwordInputField.text = "123456"; OnLoginButtonClicked(); } diff --git a/Assets/Scripts/PlayerVisual.cs b/Assets/Scripts/PlayerVisual.cs index d999f85314..bc7bdfac30 100644 --- a/Assets/Scripts/PlayerVisual.cs +++ b/Assets/Scripts/PlayerVisual.cs @@ -12,7 +12,7 @@ public class PlayerVisual : MonoBehaviour [SerializeField] private INFO _playerInfo; [SerializeField] private AnimancerState _currentState; - private readonly Queue _animationQueue = new Queue(); + [SerializeField] private Queue _animationQueue = new Queue(); [SerializeField] private bool pActFlag; [SerializeField] private bool isHit; @@ -80,8 +80,7 @@ public class PlayerVisual : MonoBehaviour return; } string animName = _animationQueue.Dequeue(); - var state = namedAnimancer.TryPlay(animName); - + _currentState = namedAnimancer.TryPlay(animName); } private void SetpActFlagTrue() {