From e59127a42559673d892e2b6dbcc86d21128df805 Mon Sep 17 00:00:00 2001 From: NguyenVanDat Date: Mon, 17 Nov 2025 18:24:12 +0700 Subject: [PATCH] catch message start and stop attack --- Assets/PerfectWorld/Scripts/Move/CECPlayer.cs | 3 +- .../Scripts/Network/CSNetwork/GPDataType.cs | 14 ++ .../Scripts/Network/CSNetwork/GameSession.cs | 6 + .../Scripts/Skills/PlayerWrapper.cs | 18 +++ Assets/Scripts/CECHostPlayer.cs | 128 +++++++++++++++++- 5 files changed, 166 insertions(+), 3 deletions(-) diff --git a/Assets/PerfectWorld/Scripts/Move/CECPlayer.cs b/Assets/PerfectWorld/Scripts/Move/CECPlayer.cs index 33dd803b62..db1ef4e8c8 100644 --- a/Assets/PerfectWorld/Scripts/Move/CECPlayer.cs +++ b/Assets/PerfectWorld/Scripts/Move/CECPlayer.cs @@ -597,7 +597,7 @@ public abstract partial class CECPlayer : CECObject //} } - private void ClearComActFlagAllRankNodes(bool v) + protected void ClearComActFlagAllRankNodes(bool v) { EventBus.PublishChannel(m_PlayerInfo.cid, new ClearComActFlagAllRankNodesEvent(v)); } @@ -1210,7 +1210,6 @@ public abstract partial class CECPlayer : CECObject _levelUpVfx.Play(); // vfx.transform.SetParent(transform); transform.position, prefab.transform.rotation _levelUpVfx.transform.localPosition = Vector3.zero; - Debug.LogError("Parent: "+transform.name); } else { diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/GPDataType.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/GPDataType.cs index fe1432b95f..0cbb8b5287 100644 --- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/GPDataType.cs +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/GPDataType.cs @@ -946,6 +946,20 @@ namespace CSNetwork.GPDataType public uint content_length; public byte[] content; }; + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct cmd_host_start_attack + { + public int idTarget; // target id + public uint ammo_remain; + public byte attack_speed; + }; + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct cmd_host_stop_attack + { + public int iReason; // Stop reason + }; [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct cmd_host_attack_result diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs index 2cd20760fc..f706650f10 100644 --- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs @@ -690,6 +690,12 @@ namespace CSNetwork EC_ManMessage.PostMessage(EC_MsgDef.MSG_NM_NPCLEVELUP, MANAGER_INDEX.MAN_NPC, 0, pDataBuf, pCmdHeader); break; } + case CommandID.HOST_START_ATTACK: + EC_ManMessage.PostMessage(EC_MsgDef.MSG_HST_STARTATTACK, MANAGER_INDEX.MAN_PLAYER, 0, pDataBuf, pCmdHeader, dwDataSize); + break; + case CommandID.HOST_STOPATTACK: + EC_ManMessage.PostMessage(EC_MsgDef.MSG_HST_STOPATTACK, MANAGER_INDEX.MAN_PLAYER, 0, pDataBuf, pCmdHeader, dwDataSize); + break; } } diff --git a/Assets/PerfectWorld/Scripts/Skills/PlayerWrapper.cs b/Assets/PerfectWorld/Scripts/Skills/PlayerWrapper.cs index c195910128..42e4930baf 100644 --- a/Assets/PerfectWorld/Scripts/Skills/PlayerWrapper.cs +++ b/Assets/PerfectWorld/Scripts/Skills/PlayerWrapper.cs @@ -174,6 +174,24 @@ namespace BrewMonster public ref ComboArg GetComboarg() { return ref comboarg; } public int GetForm() { return 0; } + + // Respond to some events of automatic policy behavior + public void AP_ActionEvent(int iEvent, int iParam) + { + // if (!CECAutoPolicy.GetInstance().IsAutoPolicyEnabled()) + // return; + + // Cannot convert: CECAutoPolicy class does not exist + // PlayerWrapper pWrapper = CECAutoPolicy.GetInstance().GetPlayerWrapper(); + // if (pWrapper != null) + // pWrapper.OnActionEvent(iEvent, iParam); + +#if _SHOW_AUTOPOLICY_DEBUG + // Cannot convert: a_LogOutput function does not exist + // Debug.LogFormat("AP_ActionEvent: {0}, Param = {1}", AP_GetEventName(iEvent), iParam); + // g_pGame.RuntimeDebugInfo(0xff0000ff, string.Format("AP_ActionEvent: {0}, Param = {1}", EVENT_NAME[iEvent], iParam)); +#endif + } } public class TargetWrapper diff --git a/Assets/Scripts/CECHostPlayer.cs b/Assets/Scripts/CECHostPlayer.cs index 4529507dda..9bb50e31eb 100644 --- a/Assets/Scripts/CECHostPlayer.cs +++ b/Assets/Scripts/CECHostPlayer.cs @@ -431,6 +431,8 @@ public partial class CECHostPlayer : CECPlayer case int value when value == EC_MsgDef.MSG_HST_SKILLDATA: OnMsgHstSkillData(Msg); break; case int value when value == EC_MsgDef.MSG_HST_DIED: OnMsgHstDied(Msg); break; case int value when value == EC_MsgDef.MSG_HST_GOTO: OnMsgHstGoto(Msg); break; + case int value when value == EC_MsgDef.MSG_HST_STARTATTACK: OnMsgHstStartAttack(Msg); break; + case int value when value == EC_MsgDef.MSG_HST_STOPATTACK: OnMsgHstStopAttack(Msg); break; } } @@ -642,7 +644,6 @@ public partial class CECHostPlayer : CECPlayer public void OnMsgHstAttackResult(ECMSG Msg) { - BMLogger.LogError($"HoangDev OnMsgHstAttackResult "); byte[] data = Msg.dwParam1 as byte[]; cmd_host_attack_result pCmd = EC_Utility.ByteArrayToStructure(data); @@ -1046,6 +1047,94 @@ public partial class CECHostPlayer : CECPlayer SetPos(new Vector3(pCmd.vPos.x, pCmd.vPos.y, pCmd.vPos.z)); } + + private void OnMsgHstStartAttack(in ECMSG Msg) + { +// cmd_host_start_attack pCmd = (cmd_host_start_attack*)Msg.dwParam1; +// ASSERT(pCmd); +// +// // test code... +// // g_pGame->GetRTDebug()->OutputNotifyMessage(RTDCOL_WARNING, _AL("start attack !")); +// +// // Check whether target is the one that we have selected +// if (m_idSelTarget != pCmd->idTarget) +// g_pGame->RuntimeDebugInfo(RTDCOL_WARNING, _AL("Target has changed !")); +// +// // If target turn to be un-attackable, cancel action +// if (!AttackableJudge(pCmd->idTarget, true)) +// { +// g_pGame->GetGameSession()->c2s_CmdCancelAction(); +// g_pGame->RuntimeDebugInfo(RTDCOL_WARNING, _AL("Cannel attacking !")); +// return; +// } +// +// // Synchronize ammo amount +// CECIvtrItem* pItem = m_pEquipPack->GetItem(EQUIPIVTR_PROJECTILE); +// if (pItem) +// { +// if (!pCmd->ammo_remain) +// m_pEquipPack->SetItem(EQUIPIVTR_PROJECTILE, NULL); +// else +// pItem->SetAmount(pCmd->ammo_remain); +// } +// +// CECHPWorkMelee* pWork = (CECHPWorkMelee*)m_pWorkMan->CreateWork(CECHPWork::WORK_HACKOBJECT); +// m_pWorkMan->StartWork_p1(pWork); +// +// m_bMelee = true; +// AP_ActionEvent(AP_EVENT_STARTMELEE); + } + + private void OnMsgHstStopAttack(in ECMSG Msg) + { +// using namespace S2C; +// + // m_bMelee = false; +// +// // if there is an attack event currently, we should let it fire now. + ClearComActFlagAllRankNodes(true); + + cmd_host_stop_attack pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + // ASSERT(pCmd); + + /* If attack stopped for target is leave too far, trace it and continue + attacking. Stop reason defined as below: + + 0x00: attack is canceled or host want to do some other things. + 0x01: unable to attack anymore (no ammo, weapon is broken etc.) + 0x02: invalid target (target missed or died) + 0x04: target is out of range + */ + if ((pCmd.iReason & 0x04) !=0) + { + if (!m_pWorkMan.IsMovingToPosition() && + !m_pWorkMan.IsTracing()) + { + if (CmdNormalAttack(false, false, 0, -1)) //m_pComboSkill != NULL + { + // AP_ActionEvent(AP_EVENT_MELEEOUTOFRANGE, 1); + } + else + { + m_pWorkMan.FinishRunningWork(Host_work_ID.WORK_HACKOBJECT); + // AP_ActionEvent(AP_EVENT_STOPMELEE); + } + } + else + { + // AP_ActionEvent(AP_EVENT_STOPMELEE); + } + } + else + { + m_pWorkMan.FinishRunningWork(Host_work_ID.WORK_HACKOBJECT); + // AP_ActionEvent(AP_EVENT_STOPMELEE); + } + +// #ifdef _SHOW_AUTOPOLICY_DEBUG +// a_LogOutput(1, "Stop Attack, Reason = %d", pCmd->iReason); +// #endif + } // Message MSG_HST_SELTARGET handler void OnMsgHstSelTarget(ECMSG Msg) @@ -2483,6 +2572,43 @@ public partial class CECHostPlayer : CECPlayer // Apply cursor change EC_Game.ChangeCursor((int)cursorType); } + + // Start normal attacking to selected target + private bool CmdNormalAttack(bool bMoreClose/* false */, bool bCombo/* false */, + int idTarget/* 0 */, int iForceAtk/* -1 */) + { + // StackChecker::ACTrace(2); + + // first of all see if we need to cancel sitdown work. + // if (m_pWorkMan.IsSitting()) + // { + // g_pGame->GetGameSession()->c2s_CmdStandUp(); + // return false; + // } + + if (!CanDo(ActionCanDo.CANDO_MELEE)) + return false; + + // if (InSlidingState()) + // return false; + + // if (!bCombo) + // ClearComboSkill(); + + if (idTarget<=0) + idTarget = m_idSelTarget; + + bool bForceAttack; + if (iForceAtk < 0) + bForceAttack = glb_GetForceAttackFlag(0); + else + bForceAttack = iForceAtk > 0 ? true : false; + + if (AttackableJudge(idTarget, bForceAttack) != 1) + return false; + + return NormalAttackObject(idTarget, bForceAttack, bMoreClose); + } } public enum StateAnim