From 8ee24776816c1dafaf1088fe4e9a5918f12809d5 Mon Sep 17 00:00:00 2001 From: VDH Date: Tue, 18 Nov 2025 18:54:56 +0700 Subject: [PATCH] get config --- .../Scripts/Inventory/EC_IvtrType.cs | 15 +- .../Scripts/Managers/CECManager.cs | 2 + .../PerfectWorld/Scripts/Move/CECHostMove.cs | 630 +- .../Scripts/Network/CSNetwork/GameSession.cs | 101 +- .../CSNetwork/Protocols/getuiconfig_re.cs | 47 + .../Protocols/getuiconfig_re.cs.meta | 2 + .../Scripts/Network/CSNetwork/gnetdef.cs | 198 + .../Scripts/Network/CSNetwork/gnetdef.cs.meta | 2 + .../Scripts/Network/UnityGameSession.cs | 5 +- .../PerfectWorld/Scripts/Objet/Shortcut.meta | 8 + .../Scripts/Objet/Shortcut/CECShortcutSet.cs | 862 +++ .../Objet/Shortcut/CECShortcutSet.cs.meta | 2 + .../Scripts/PlayerState/PlayerIdleState.cs | 33 +- .../Scripts/PlayerState/PlayerMoveState.cs | 35 +- .../Scripts/PlayerState/PlayerState.cs | 2 +- .../Players/CECPlayerActionPlayPolicy.cs | 2 +- .../PerfectWorld/Scripts/Skills/CECSCSkill.cs | 17 +- .../PerfectWorld/Scripts/Utils/CECRTDebug.cs | 46 + .../Scripts/Utils/CECRTDebug.cs.meta | 2 + Assets/Scripts/CECGameRun.cs | 118 +- Assets/Scripts/CECHostPlayer.Task.cs | 204 +- Assets/Scripts/CECHostPlayer.cs | 5520 +++++++++-------- Assets/Scripts/CECHostPlayer_Inventory.cs | 71 +- Assets/Scripts/EC_Utility.cs | 43 + .../Scripts/ThirdPersonController.cs | 3 +- 25 files changed, 4788 insertions(+), 3182 deletions(-) create mode 100644 Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/getuiconfig_re.cs create mode 100644 Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/getuiconfig_re.cs.meta create mode 100644 Assets/PerfectWorld/Scripts/Network/CSNetwork/gnetdef.cs create mode 100644 Assets/PerfectWorld/Scripts/Network/CSNetwork/gnetdef.cs.meta create mode 100644 Assets/PerfectWorld/Scripts/Objet/Shortcut.meta create mode 100644 Assets/PerfectWorld/Scripts/Objet/Shortcut/CECShortcutSet.cs create mode 100644 Assets/PerfectWorld/Scripts/Objet/Shortcut/CECShortcutSet.cs.meta create mode 100644 Assets/PerfectWorld/Scripts/Utils/CECRTDebug.cs create mode 100644 Assets/PerfectWorld/Scripts/Utils/CECRTDebug.cs.meta diff --git a/Assets/PerfectWorld/Scripts/Inventory/EC_IvtrType.cs b/Assets/PerfectWorld/Scripts/Inventory/EC_IvtrType.cs index 0778f453d0..e712eaa3cc 100644 --- a/Assets/PerfectWorld/Scripts/Inventory/EC_IvtrType.cs +++ b/Assets/PerfectWorld/Scripts/Inventory/EC_IvtrType.cs @@ -44,7 +44,7 @@ namespace BrewMonster.Scripts public static int EQUIPIVTR_GENERALCARD6 = 37; public static int SIZE_ALL_EQUIPIVTR = 38; public static int SIZE_GENERALCARD_EQUIPIVTR = 6; // SIZE_ALL_EQUIPIVTR - EQUIPIVTR_GENERALCARD1 - + // Inventory size constants public static int IVTRSIZE_EQUIPPACK = 32; // Equipment (SIZE_ALL_EQUIPIVTR) public static int IVTRSIZE_TASKPACK = 32; // Task pack @@ -57,9 +57,18 @@ namespace BrewMonster.Scripts public static int IVTRSIZE_BOOTHBPACK = 12; // Default booth pack for buying public static int IVTRSIZE_BOOTHSPACK_MAX = 20; // Max booth pack for selling (player may use certificate...) public static int IVTRSIZE_BOOTHBPACK_MAX = 20; // Max booth pack for buying - + public static int IVTRSIZE_CLIENTCARDPACK = 32; // Client pack for general card collection - + public static int NUM_NPCIVTR = 8; // NPC inventory number } + public enum Shortcut + { + NUM_HOSTSCSETS1 = 5, // expanded from 3 to 5 (2009.05.27) + NUM_HOSTSCSETS2 = 3, + SIZE_HOSTSCSET1 = 9, // expanded from 6 to 9 (2009.05.27) + SIZE_HOSTSCSET2 = 8, + + SIZE_FASHIONSCSET = 240, + }; } \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/Managers/CECManager.cs b/Assets/PerfectWorld/Scripts/Managers/CECManager.cs index 20bd2fa0bb..f924d60126 100644 --- a/Assets/PerfectWorld/Scripts/Managers/CECManager.cs +++ b/Assets/PerfectWorld/Scripts/Managers/CECManager.cs @@ -105,3 +105,5 @@ namespace BrewMonster.Managers } + + diff --git a/Assets/PerfectWorld/Scripts/Move/CECHostMove.cs b/Assets/PerfectWorld/Scripts/Move/CECHostMove.cs index 659c9ca77d..8b0e05fe2d 100644 --- a/Assets/PerfectWorld/Scripts/Move/CECHostMove.cs +++ b/Assets/PerfectWorld/Scripts/Move/CECHostMove.cs @@ -12,364 +12,366 @@ using System.Text; using BrewMonster; using UnityEngine; -public class CECHostMove -{ - ushort m_wMoveStamp; - float m_fMoveTime; - CECHostPlayer m_pHost; - bool m_bStop; - const float MOVECMD_INTERVAL = .5f; - Vector3 m_vLastSevPos; - STOPMOVE m_DelayedStop; - ulong cmdstopdelayCounter = 500; - ulong cmdmovedelayCounter = 500; - ulong m_dwLastTime; - Vector3 m_vLastPos; - float m_fAverSpeedH; - int m_iBlockedCnt; // Move blocked counter - bool m_bSlideLock; // Locked when slide - float m_fBlockTime; // Block time counter - float m_fBlockMove; // Block move counter - A3DVECTOR3 m_vBlockMove; - bool m_bLocalMove; // true, Moving info isn't sent to server - - public CECHostMove(CECHostPlayer pHost) +namespace BrewMonster { + public class CECHostMove { - m_wMoveStamp = 0; - m_fMoveTime = 0.0f; - m_pHost = pHost; - m_bStop = false; - cmdstopdelayCounter = 500; - m_DelayedStop = new STOPMOVE(); - } + ushort m_wMoveStamp; + float m_fMoveTime; + CECHostPlayer m_pHost; + bool m_bStop; + const float MOVECMD_INTERVAL = .5f; + Vector3 m_vLastSevPos; + STOPMOVE m_DelayedStop; + ulong cmdstopdelayCounter = 500; + ulong cmdmovedelayCounter = 500; + ulong m_dwLastTime; + Vector3 m_vLastPos; + float m_fAverSpeedH; + int m_iBlockedCnt; // Move blocked counter + bool m_bSlideLock; // Locked when slide + float m_fBlockTime; // Block time counter + float m_fBlockMove; // Block move counter + A3DVECTOR3 m_vBlockMove; + bool m_bLocalMove; // true, Moving info isn't sent to server - public void Tick(ulong dwDeltaTime) - { - cmdstopdelayCounter += dwDeltaTime; - cmdmovedelayCounter += dwDeltaTime; - if (cmdstopdelayCounter >= 500 && m_DelayedStop.bValid) + public CECHostMove(CECHostPlayer pHost) { - var m = m_DelayedStop; + m_wMoveStamp = 0; + m_fMoveTime = 0.0f; + m_pHost = pHost; + m_bStop = false; + cmdstopdelayCounter = 500; + m_DelayedStop = new STOPMOVE(); + } - // a_GetTime() . Environment.TickCount (ms) - ulong dwCurrent = (ulong)Mathf.RoundToInt(Time.time * 1000); + public void Tick(ulong dwDeltaTime) + { + cmdstopdelayCounter += dwDeltaTime; + cmdmovedelayCounter += dwDeltaTime; + if (cmdstopdelayCounter >= 500 && m_DelayedStop.bValid) + { + var m = m_DelayedStop; - // iTime: thời gian tích lũy (ms) + delta từ timestamp đến hiện tại - int iTime = (int)((m.fTime * 1000f) - + ((dwCurrent > m.dwTimeStamp) ? (dwCurrent - m.dwTimeStamp) : 0)); + // a_GetTime() . Environment.TickCount (ms) + ulong dwCurrent = (ulong)Mathf.RoundToInt(Time.time * 1000); - // tính tốc độ trung bình (giây = iTime * 0.001f) - float fSpeed = l_CalcAverageSpeed(m_vLastSevPos, m.vPos, iTime * 0.001f, m.fSpeed); + // iTime: thời gian tích lũy (ms) + delta từ timestamp đến hiện tại + int iTime = (int)((m.fTime * 1000f) + + ((dwCurrent > m.dwTimeStamp) ? (dwCurrent - m.dwTimeStamp) : 0)); - int iMoveMode = m.iMoveMode; + // tính tốc độ trung bình (giây = iTime * 0.001f) + float fSpeed = l_CalcAverageSpeed(m_vLastSevPos, m.vPos, iTime * 0.001f, m.fSpeed); - // make a potential check with tuojigua + int iMoveMode = m.iMoveMode; + + // make a potential check with tuojigua + iMoveMode |= (int)GPMoveMode.GP_MOVE_DEAD; + + UnityGameSession.Instance.c2s_SendCmdStopMove( + m.vPos, fSpeed, iMoveMode, m.byDir, m_wMoveStamp++, iTime + ); + + // Record this position + m_vLastSevPos = m.vPos; + + Reset(); + } + + m_dwLastTime = Math.Max(m_dwLastTime, 1); + Vector3 vOffset = m_pHost.transform.position - m_vLastPos; + m_fAverSpeedH = EC_Utility.MagnitudeH(vOffset) * 1000.0f / m_dwLastTime; + m_vLastPos = m_pHost.transform.position; + m_dwLastTime = dwDeltaTime; + } + + public void SendStopMoveCmd() + { + int iMoveMode = (int)GPMoveMode.GP_MOVE_RUN; + float fSpeed = 0f; + switch (m_pHost.GetMoveEnv()) + { + case CECPlayer.Move_environment.MOVEENV_AIR: + + iMoveMode |= (int)GPMoveMode.GP_MOVE_AIR; + fSpeed = m_pHost.GetFlySpeed(); + break; + + //case EC_Player.Move_environment.MOVEENV_WATER: + + // iMoveMode |= (int)GPMoveMode.GP_MOVE_WATER; + // fSpeed = m_pHost.GetSwimSpeedSev(); + // break; + + default: + + fSpeed = m_pHost.GetGroundSpeed(); + break; + } + SendStopMoveCmd(EC_Utility.ToVector3(m_pHost.GetPos()), fSpeed, iMoveMode); + } + + public void SendStopMoveCmd(in Vector3 vPos, float fSpeed, int iMoveMode) + { + Debug.LogWarning("HoangDev : SendStopMoveCmd"); iMoveMode |= (int)GPMoveMode.GP_MOVE_DEAD; - UnityGameSession.Instance.c2s_SendCmdStopMove( - m.vPos, fSpeed, iMoveMode, m.byDir, m_wMoveStamp++, iTime - ); + if (cmdstopdelayCounter >= 500) + { + Vector3 vDir = m_pHost.transform.forward; + byte byDir = EC_Utility.glb_CompressDirH(vDir.x, vDir.z); + fSpeed = l_CalcAverageSpeed(m_vLastSevPos, vPos, m_fMoveTime, fSpeed); + int iTime = (int)(m_fMoveTime * 1000); - // Record this position - m_vLastSevPos = m.vPos; + UnityGameSession.Instance.c2s_SendCmdStopMove(vPos, fSpeed, iMoveMode, byDir, m_wMoveStamp++, iTime); - Reset(); + m_vLastSevPos = vPos; + Reset(); + } + else + { + Vector3 vDir = m_pHost.transform.forward; + byte byDir = EC_Utility.glb_CompressDirH(vDir.x, vDir.z); + + if (!m_DelayedStop.bValid) + { + m_DelayedStop.dwTimeStamp = (ulong)Mathf.RoundToInt(Time.time * 1000); + m_DelayedStop.fTime = m_fMoveTime; + } + + m_DelayedStop.bValid = true; + m_DelayedStop.byDir = byDir; + m_DelayedStop.vPos = vPos; + m_DelayedStop.iMoveMode = iMoveMode; + m_DelayedStop.fSpeed = fSpeed; + } + m_fMoveTime = 0.0f; + } + public void SendMoveCmd(in Vector3 vCurPos, in Vector3 vVel, int iMoveMode, bool bForceSend = false) + { + + Vector3 vMoveDir = vVel; + float fSpeed = vMoveDir.magnitude; + SendMoveCmd(vCurPos, fSpeed, iMoveMode, bForceSend); } - m_dwLastTime = Math.Max(m_dwLastTime, 1); - Vector3 vOffset = m_pHost.transform.position - m_vLastPos; - m_fAverSpeedH = EC_Utility.MagnitudeH(vOffset) * 1000.0f / m_dwLastTime; - m_vLastPos = m_pHost.transform.position; - m_dwLastTime = dwDeltaTime; - } - - public void SendStopMoveCmd() - { - int iMoveMode = (int)GPMoveMode.GP_MOVE_RUN; - float fSpeed = 0f; - switch (m_pHost.GetMoveEnv()) + public void SendMoveCmd(A3DVECTOR3 vCurPos, int iDestType, A3DVECTOR3 vDest, A3DVECTOR3 vVel, int iMoveMode, bool bForceSend = false) { - case CECPlayer.Move_environment.MOVEENV_AIR: - iMoveMode |= (int)GPMoveMode.GP_MOVE_AIR; - fSpeed = m_pHost.GetFlySpeed(); - break; - - //case EC_Player.Move_environment.MOVEENV_WATER: - - // iMoveMode |= (int)GPMoveMode.GP_MOVE_WATER; - // fSpeed = m_pHost.GetSwimSpeedSev(); - // break; - - default: - - fSpeed = m_pHost.GetGroundSpeed(); - break; + A3DVECTOR3 vMoveDir = vVel; + float fSpeed = vMoveDir.Normalize(); + SendMoveCmd(vCurPos, iDestType, vDest, vMoveDir, fSpeed, iMoveMode, bForceSend); } - SendStopMoveCmd(EC_Utility.ToVector3(m_pHost.GetPos()), fSpeed, iMoveMode); - } - public void SendStopMoveCmd(in Vector3 vPos, float fSpeed, int iMoveMode) - { - Debug.LogWarning("HoangDev : SendStopMoveCmd"); - iMoveMode |= (int)GPMoveMode.GP_MOVE_DEAD; + void SendMoveCmd(A3DVECTOR3 vCurPos, int iDestType, A3DVECTOR3 vDest, + A3DVECTOR3 vMoveDir, float fSpeed, int iMoveMode, bool bForceSend) - if (cmdstopdelayCounter >= 500) { - Vector3 vDir = m_pHost.transform.forward; - byte byDir = EC_Utility.glb_CompressDirH(vDir.x, vDir.z); - fSpeed = l_CalcAverageSpeed(m_vLastSevPos, vPos, m_fMoveTime, fSpeed); + Vector3 pos = new Vector3(vCurPos.x, vCurPos.y, vCurPos.z); + SendMoveCmd(pos, fSpeed, iMoveMode, bForceSend); + } + + void SendMoveCmd(in Vector3 vCurPos, + float fSpeed, int iMoveMode, bool bForceSend) + { + if (m_bStop) + { + // m_CmdTimeCnt.Reset(); + cmdmovedelayCounter = (ulong)(m_fMoveTime * 1000); + m_bStop = false; + } + if (!bForceSend && cmdmovedelayCounter < 500) + return; + int iTime = (int)(m_fMoveTime * 1000); - UnityGameSession.Instance.c2s_SendCmdStopMove(vPos, fSpeed, iMoveMode, byDir, m_wMoveStamp++, iTime); - - m_vLastSevPos = vPos; - Reset(); - } - else - { - Vector3 vDir = m_pHost.transform.forward; - byte byDir = EC_Utility.glb_CompressDirH(vDir.x, vDir.z); - - if (!m_DelayedStop.bValid) + if (iTime < 200) { - m_DelayedStop.dwTimeStamp = (ulong)Mathf.RoundToInt(Time.time * 1000); - m_DelayedStop.fTime = m_fMoveTime; + if (iTime == 0 || !bForceSend) + { + // if time is too little, wait again + cmdmovedelayCounter = (ulong)(iTime); + return; + } } - m_DelayedStop.bValid = true; - m_DelayedStop.byDir = byDir; - m_DelayedStop.vPos = vPos; - m_DelayedStop.iMoveMode = iMoveMode; - m_DelayedStop.fSpeed = fSpeed; + cmdmovedelayCounter = 0; + m_DelayedStop.bValid = false; + + fSpeed = l_CalcAverageSpeed(m_vLastSevPos, vCurPos, m_fMoveTime, fSpeed); + m_fMoveTime = 0.0f; + + iMoveMode |= (int)GPMoveMode.GP_MOVE_DEAD; + UnityGameSession.Instance.c2s_CmdPlayerMove(vCurPos, vCurPos, iTime/* MOVECMD_INTERVAL */, fSpeed, iMoveMode, m_wMoveStamp++); + + m_vLastSevPos = vCurPos; } - m_fMoveTime = 0.0f; - } - public void SendMoveCmd(in Vector3 vCurPos, in Vector3 vVel, int iMoveMode, bool bForceSend = false) - { - - Vector3 vMoveDir = vVel; - float fSpeed = vMoveDir.magnitude; - SendMoveCmd(vCurPos, fSpeed, iMoveMode, bForceSend); - } - public void SendMoveCmd(A3DVECTOR3 vCurPos, int iDestType, A3DVECTOR3 vDest, A3DVECTOR3 vVel, int iMoveMode, bool bForceSend = false) - { - - A3DVECTOR3 vMoveDir = vVel; - float fSpeed = vMoveDir.Normalize(); - SendMoveCmd(vCurPos, iDestType, vDest, vMoveDir, fSpeed, iMoveMode, bForceSend); - } - - void SendMoveCmd(A3DVECTOR3 vCurPos, int iDestType, A3DVECTOR3 vDest, - A3DVECTOR3 vMoveDir, float fSpeed, int iMoveMode, bool bForceSend) - - { - Vector3 pos = new Vector3(vCurPos.x, vCurPos.y, vCurPos.z); - SendMoveCmd(pos, fSpeed, iMoveMode, bForceSend); - } - - void SendMoveCmd(in Vector3 vCurPos, - float fSpeed, int iMoveMode, bool bForceSend) - { - if (m_bStop) + float l_CalcAverageSpeed(in Vector3 p1, in Vector3 p2, float fTime, float fDefSpeed) { - // m_CmdTimeCnt.Reset(); - cmdmovedelayCounter = (ulong)(m_fMoveTime * 1000); - m_bStop = false; - } - if (!bForceSend && cmdmovedelayCounter < 500) - return; + if (Mathf.Approximately(fTime, 0f)) + return fDefSpeed; - int iTime = (int)(m_fMoveTime * 1000); + Vector3 d = p2 - p1; + float fSpeed = d.magnitude / fTime; - if (iTime < 200) - { - if (iTime == 0 || !bForceSend) + if (fTime < 0.05f || fSpeed > 50.0f) { - // if time is too little, wait again - cmdmovedelayCounter = (ulong)(iTime); - return; - } - } - - cmdmovedelayCounter = 0; - m_DelayedStop.bValid = false; - - fSpeed = l_CalcAverageSpeed(m_vLastSevPos, vCurPos, m_fMoveTime, fSpeed); - m_fMoveTime = 0.0f; - - iMoveMode |= (int)GPMoveMode.GP_MOVE_DEAD; - UnityGameSession.Instance.c2s_CmdPlayerMove(vCurPos, vCurPos, iTime/* MOVECMD_INTERVAL */, fSpeed, iMoveMode, m_wMoveStamp++); - - m_vLastSevPos = vCurPos; - } - - float l_CalcAverageSpeed(in Vector3 p1, in Vector3 p2, float fTime, float fDefSpeed) - { - if (Mathf.Approximately(fTime, 0f)) - return fDefSpeed; - - Vector3 d = p2 - p1; - float fSpeed = d.magnitude / fTime; - - if (fTime < 0.05f || fSpeed > 50.0f) - { - // tương đương ASSERT(0) trong C++, ở đây có thể Debug.LogWarning - Debug.LogWarning("CalcAverageSpeed: invalid input, fallback to default speed."); - return fDefSpeed; - } - - return fSpeed; - } - private void Reset() - { - cmdstopdelayCounter = 0; - m_bStop = true; - m_fBlockTime = 0.0f; - m_fBlockMove = 0.0f; - m_DelayedStop.bValid = false; - } - - public void GroundMove(float ftime) - { - m_fMoveTime += ftime; - } - - struct STOPMOVE - { - public bool bValid; // Valid flag - public Vector3 vPos; - public float fSpeed; - public int iMoveMode; - public byte byDir; - public ulong dwTimeStamp; - public float fTime; - }; - - // Check whether host meet a slope - // vMoveDirH: normalized horizontal moving direction - // fMaxSpeed (out): maximum vertical speed - public bool MeetSlope(A3DVECTOR3 vMoveDirH, float fMaxSpeedV) - { - A3DVECTOR3 vTangent = m_pHost.m_GndInfo.vGndNormal; - - float d = vTangent.MagnitudeH(); - float tan = d / (float)Math.Abs(vTangent.y); - float max = m_pHost.GetGroundSpeed() * tan * 0.96f; - // Prevent max is too small, tan60 = 1.732 - EC_Utility.a_ClampFloor(max, m_pHost.GetGroundSpeed() * 1.732f); - fMaxSpeedV = EC_Utility.a_Min(max, 19.5f); - - // fMaxSpeedV = 100.0f; - - vTangent.y = 0.0f; - vTangent.Normalize(); - - if (A3DVECTOR3.DotProduct(vMoveDirH, vTangent) <= -0.85f) - return true; - - return false; - } - - public A3DVECTOR3 GroundMove(A3DVECTOR3 vDirH, float fSpeedH, float fTime, float fSpeedV = 0f, float fGravity = 9.8f) - { - A3DVECTOR3 vRealDirH = vDirH; - - if (Math.Abs(vRealDirH.y) > 0.0001) - { - vRealDirH.y = 0.0f; - vRealDirH.Normalize(); - } - - // OnGroundMove only accept positive speed value - if (fSpeedH < 0.0f) - { - vRealDirH = -vDirH; - fSpeedH = -fSpeedH; - } - - //int idInst = g_pGame.GetGameRun().GetWorld().GetInstanceID(); - //CECInstance pInstance = g_pGame.GetGameRun().GetInstance(idInst); - //if (pInstance.GetLimitJump()) - //fGravity *= 4.0f; - - CDR_INFO cdr = m_pHost.m_CDRInfo; - var pos = m_pHost.m_aabbServer.Center; - cdr.vCenter = new Vector3(pos.x, pos.y, pos.z); - cdr.vXOZVelDir = new Vector3(vRealDirH.x, vRealDirH.y, vRealDirH.z); - cdr.fSpeed = fSpeedH; - cdr.t = fTime; - cdr.fGravityAccel = fGravity; - cdr.fYVel += fSpeedV; - - EC_CDR.OnGroundMove(ref cdr); - - //if (g_pGame.GetGameRun().GetWorld().GetAssureMove()) - // g_pGame.GetGameRun().GetWorld().GetAssureMove().AssureMove(m_pHost.m_aabbServer.Center, cdr.vCenter); - - if (cdr.vTPNormal != Vector3.zero) - m_pHost.SetGroundNormal(new A3DVECTOR3(cdr.vTPNormal.x, cdr.vTPNormal.y, cdr.vTPNormal.z)); - else - m_pHost.SetGroundNormal(GPDataTypeHelper.g_vAxisY); - - A3DVECTOR3 vNewPos = new A3DVECTOR3(cdr.vCenter.x, cdr.vCenter.y, cdr.vCenter.z) - GPDataTypeHelper.g_vAxisY * m_pHost.m_aabbServer.Extents.y; - - m_iBlockedCnt = 0; - m_fBlockMove += (vNewPos - m_pHost.GetPos()).Magnitude(); - m_vBlockMove += vNewPos - m_pHost.GetPos(); - if ((m_fBlockTime += fTime) >= 1.0f) - { - if (m_fBlockMove < GPDataTypeHelper.MIN_MOVELEN_ON_GROUND || m_vBlockMove.Magnitude() < GPDataTypeHelper.MIN_MOVELEN_FOR_DETECT_VIBRATION) - { - m_iBlockedCnt = 5; + // tương đương ASSERT(0) trong C++, ở đây có thể Debug.LogWarning + Debug.LogWarning("CalcAverageSpeed: invalid input, fallback to default speed."); + return fDefSpeed; } + return fSpeed; + } + private void Reset() + { + cmdstopdelayCounter = 0; + m_bStop = true; m_fBlockTime = 0.0f; m_fBlockMove = 0.0f; - m_vBlockMove.Clear(); + m_DelayedStop.bValid = false; } - m_fMoveTime += fTime; - m_pHost.m_CDRInfo.vTPNormal = cdr.vTPNormal; - return vNewPos; + public void GroundMove(float ftime) + { + m_fMoveTime += ftime; + } + + struct STOPMOVE + { + public bool bValid; // Valid flag + public Vector3 vPos; + public float fSpeed; + public int iMoveMode; + public byte byDir; + public ulong dwTimeStamp; + public float fTime; + }; + + // Check whether host meet a slope + // vMoveDirH: normalized horizontal moving direction + // fMaxSpeed (out): maximum vertical speed + public bool MeetSlope(A3DVECTOR3 vMoveDirH, float fMaxSpeedV) + { + A3DVECTOR3 vTangent = m_pHost.m_GndInfo.vGndNormal; + + float d = vTangent.MagnitudeH(); + float tan = d / (float)Math.Abs(vTangent.y); + float max = m_pHost.GetGroundSpeed() * tan * 0.96f; + // Prevent max is too small, tan60 = 1.732 + EC_Utility.a_ClampFloor(max, m_pHost.GetGroundSpeed() * 1.732f); + fMaxSpeedV = EC_Utility.a_Min(max, 19.5f); + + // fMaxSpeedV = 100.0f; + + vTangent.y = 0.0f; + vTangent.Normalize(); + + if (A3DVECTOR3.DotProduct(vMoveDirH, vTangent) <= -0.85f) + return true; + + return false; + } + + public A3DVECTOR3 GroundMove(A3DVECTOR3 vDirH, float fSpeedH, float fTime, float fSpeedV = 0f, float fGravity = 9.8f) + { + A3DVECTOR3 vRealDirH = vDirH; + + if (Math.Abs(vRealDirH.y) > 0.0001) + { + vRealDirH.y = 0.0f; + vRealDirH.Normalize(); + } + + // OnGroundMove only accept positive speed value + if (fSpeedH < 0.0f) + { + vRealDirH = -vDirH; + fSpeedH = -fSpeedH; + } + + //int idInst = g_pGame.GetGameRun().GetWorld().GetInstanceID(); + //CECInstance pInstance = g_pGame.GetGameRun().GetInstance(idInst); + //if (pInstance.GetLimitJump()) + //fGravity *= 4.0f; + + CDR_INFO cdr = m_pHost.m_CDRInfo; + var pos = m_pHost.m_aabbServer.Center; + cdr.vCenter = new Vector3(pos.x, pos.y, pos.z); + cdr.vXOZVelDir = new Vector3(vRealDirH.x, vRealDirH.y, vRealDirH.z); + cdr.fSpeed = fSpeedH; + cdr.t = fTime; + cdr.fGravityAccel = fGravity; + cdr.fYVel += fSpeedV; + + EC_CDR.OnGroundMove(ref cdr); + + //if (g_pGame.GetGameRun().GetWorld().GetAssureMove()) + // g_pGame.GetGameRun().GetWorld().GetAssureMove().AssureMove(m_pHost.m_aabbServer.Center, cdr.vCenter); + + if (cdr.vTPNormal != Vector3.zero) + m_pHost.SetGroundNormal(new A3DVECTOR3(cdr.vTPNormal.x, cdr.vTPNormal.y, cdr.vTPNormal.z)); + else + m_pHost.SetGroundNormal(GPDataTypeHelper.g_vAxisY); + + A3DVECTOR3 vNewPos = new A3DVECTOR3(cdr.vCenter.x, cdr.vCenter.y, cdr.vCenter.z) - GPDataTypeHelper.g_vAxisY * m_pHost.m_aabbServer.Extents.y; + + m_iBlockedCnt = 0; + m_fBlockMove += (vNewPos - m_pHost.GetPos()).Magnitude(); + m_vBlockMove += vNewPos - m_pHost.GetPos(); + if ((m_fBlockTime += fTime) >= 1.0f) + { + if (m_fBlockMove < GPDataTypeHelper.MIN_MOVELEN_ON_GROUND || m_vBlockMove.Magnitude() < GPDataTypeHelper.MIN_MOVELEN_FOR_DETECT_VIBRATION) + { + m_iBlockedCnt = 5; + } + + m_fBlockTime = 0.0f; + m_fBlockMove = 0.0f; + m_vBlockMove.Clear(); + } + + m_fMoveTime += fTime; + m_pHost.m_CDRInfo.vTPNormal = cdr.vTPNormal; + return vNewPos; + } + + public int MoveBlocked() { return m_iBlockedCnt; } + public void SetSlideLock(bool bLock) { m_bSlideLock = bLock; } + // Is stoping ? + public bool IsStop() { return m_bStop; } } + public struct CDR_INFO + { + //the aabb + public Vector3 vCenter; + //@note : the caller should make sure ext(.x, .y, .z) > 0. By Kuiwu[22/9/2005] + public Vector3 vExtent; - public int MoveBlocked() { return m_iBlockedCnt; } - public void SetSlideLock(bool bLock) { m_bSlideLock = bLock; } - // Is stoping ? - public bool IsStop() { return m_bStop; } -} -public struct CDR_INFO -{ - //the aabb - public Vector3 vCenter; - //@note : the caller should make sure ext(.x, .y, .z) > 0. By Kuiwu[22/9/2005] - public Vector3 vExtent; + public float fStepHeight; - public float fStepHeight; + // Velocity Info + public Vector3 vXOZVelDir; + public float fYVel; + public float fSpeed; - // Velocity Info - public Vector3 vXOZVelDir; - public float fYVel; - public float fSpeed; + // time span ( sec ) + public float t; - // time span ( sec ) - public float t; + // Gravity acceleration + public float fGravityAccel; - // Gravity acceleration - public float fGravityAccel; + // the Climb Slope Thresh + public float fSlopeThresh; - // the Climb Slope Thresh - public float fSlopeThresh; + // Tangent plane Info + public Vector3 vTPNormal; - // Tangent plane Info - public Vector3 vTPNormal; - - // Absolute Velocity: output for forcast! - public Vector3 vAbsVelocity; + // Absolute Velocity: output for forcast! + public Vector3 vAbsVelocity; - //the moving dist - public float fMoveDist; -}; + //the moving dist + public float fMoveDist; + }; +} \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs index 174c3874aa..d684394c1a 100644 --- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs @@ -1,5 +1,7 @@ using BrewMonster; +using BrewMonster.Assets.PerfectWorld.Scripts.UI; using BrewMonster.Managers; +using BrewMonster.Network; using BrewMonster.Scripts.Player; using BrewMonster.Scripts.Skills; using CSNetwork.C2SCommand; @@ -354,6 +356,7 @@ namespace CSNetwork case ProtocolType.PROTOCOL_PLAYERBASEINFO_RE: OnPrtcPlayerBaseInfoRe(protocol); break; + case ProtocolType.PROTOCOL_GETUICONFIG_RE: OnPrtcGetConfigRe(protocol); break; default: _logger.Log(LogType.Warning, $"Received unhandled protocol type: {protocol.GetPType()}"); break; @@ -682,14 +685,14 @@ namespace CSNetwork break; } case CommandID.LEVEL_UP: - { - cmd_level_up pCmdLevelUp = GPDataTypeHelper.FromBytes(pDataBuf);; - if (ISPLAYERID(pCmdLevelUp.id)) - EC_ManMessage.PostMessage(EC_MsgDef.MSG_PM_PLAYERLEVELUP, MANAGER_INDEX.MAN_PLAYER, -1, pDataBuf, pCmdHeader); - else if (ISNPCID(pCmdLevelUp.id)) - EC_ManMessage.PostMessage(EC_MsgDef.MSG_NM_NPCLEVELUP, MANAGER_INDEX.MAN_NPC, 0, pDataBuf, pCmdHeader); - break; - } + { + cmd_level_up pCmdLevelUp = GPDataTypeHelper.FromBytes(pDataBuf); ; + if (ISPLAYERID(pCmdLevelUp.id)) + EC_ManMessage.PostMessage(EC_MsgDef.MSG_PM_PLAYERLEVELUP, MANAGER_INDEX.MAN_PLAYER, -1, pDataBuf, pCmdHeader); + else if (ISNPCID(pCmdLevelUp.id)) + EC_ManMessage.PostMessage(EC_MsgDef.MSG_NM_NPCLEVELUP, MANAGER_INDEX.MAN_NPC, 0, pDataBuf, pCmdHeader); + break; + } } } @@ -962,7 +965,12 @@ namespace CSNetwork _logger.Log(LogType.Warning, $"HoangDev : publicChat {publicChat}"); SendProtocol(publicChat); } - + public void LoadConfigData() + { + getuiconfig p = new getuiconfig(); + p.Roleid = m_iCharID; + SendProtocol(p); + } private void SetCharacterID(int iCharID) { m_iCharID = iCharID; @@ -987,7 +995,68 @@ namespace CSNetwork this.context = context; } } + public void OnPrtcGetConfigRe(Protocol pProtocol) + { + getuiconfig_re p = (getuiconfig_re)pProtocol; + if (p.Result != (int)ErrCode.ERR_SUCCESS) + BMLogger.LogError("CECGameSession::OnPrtcGetConfigRe, link return error code of " + p.Result); + else + { + if (!EC_Game.GetGameRun().LoadConfigsFromServer(p.UiConfig.RawBuffer, p.UiConfig.Size)) + { + // if load failed then use current setting directly + //TODO : fix later + //g_pGame.GetConfigs().ApplyUserSetting(); + } + // Now, Get config data request is sent after all host initial data ready. + // so when we receive this reply, we can do some last work before game + // really starts. Maybe it's not the best place to do these work, but + // now we do it here. + // Enalbe game UI + //CECGameUIMan* pGameUI = (CECGameUIMan*)g_pGame->GetGameRun()->GetUIManager()->GetInGameUIMan(); + //if (pGameUI) + //{ + // pGameUI->EnableUI(true); + + // // Get referral name for adding friend or other display + // RoleInfo info = g_pGame->GetGameRun()->GetSelectedRoleInfo(); + // if (info.referrer_role > 0) + // GetPlayerBriefInfo(1, &info.referrer_role, 2); + //} + + //CECHostPlayer* pHost = g_pGame->GetGameRun()->GetHostPlayer(); + //pHost->OnAllInitDataReady(); + + //if (pHost->IsGM()) + //{ + // CDlgCountryMap* pDlgCountryMap = (CDlgCountryMap*)pGameUI->GetDialog("Win_CountryMap"); + // pDlgCountryMap->GetConfig(); + //} + + //g_pGame->GetConfigs()->ApplyOptimizeSetting(); + + //if (g_pGame->GetConfigs()->IsMiniClient()) + // CECMCDownload::GetInstance().SendGetDownloadOK(); + + // if (g_pGame->GetConfigs()->IsSendLogicCheckInfo()){ + // // Ïò·þÎñÆ÷·¢ËÍ»úÆ÷ʶ±ðÂë + // LogicHelp::LogicCheck logicChecker; + // unsigned char buffer[1024] = {0}; + // int actualSize = logicChecker.ReceiveMessage(buffer, sizeof(buffer)/sizeof(buffer[0])); + // if (actualSize <= 0){ + //#ifdef LOG_PROTOCOL + // a_LogOutput(1, "LogicHelp::LogicCheck ReceiveMessage returns %d", actualSize); + //#endif + // }else{ + //#ifdef LOG_PROTOCOL + // a_LogOutput(1, "LogicHelp::LogicCheck ReceiveMessage returns %d bytes:%s", actualSize, glb_FormatOctets(Octets(buffer, actualSize))); + //#endif + // sendClientMachineInfo(buffer, actualSize); + // } + // } + } + } private void OnPrtcPlayerBaseInfoRe(Protocol pProtocol) { playerbaseinfo_re p = (playerbaseinfo_re)pProtocol; @@ -1060,16 +1129,16 @@ namespace CSNetwork int iNumSend = iNumLimit; if (iCount + iNumLimit > iNumRole) iNumSend = iNumRole - iCount; - + if (iNumSend > 0) { p.playerList = new(); for (int i = 0; i < iNumSend; i++) - p.playerList.Add(aRoleIDs[iCount + i]); + p.playerList.Add(aRoleIDs[iCount + i]); SendProtocol(p); } - + iCount += iNumSend; } @@ -1085,7 +1154,7 @@ namespace CSNetwork // int iNumSend = iNumLimit; // if (iCount + iNumLimit > iNumID) // iNumSend = iNumID - iCount; - + // if (iNumSend > 0) // { // } @@ -1095,7 +1164,7 @@ namespace CSNetwork public void GetRoleCustomizeData(int iNumRole, List aRoleIDs) { if (iNumRole <= 0 || aRoleIDs == null || aRoleIDs.Count == 0) return; - + int iNumLimit = 240; int iCount = 0; @@ -1108,8 +1177,8 @@ namespace CSNetwork if (iCount + iNumLimit > iNumRole) iNumSend = iNumRole - iCount; - for (int i=0; i < iNumSend; i++) - p.playerlist.Add(aRoleIDs[iCount+i]); + for (int i = 0; i < iNumSend; i++) + p.playerlist.Add(aRoleIDs[iCount + i]); SendProtocol(p); diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/getuiconfig_re.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/getuiconfig_re.cs new file mode 100644 index 0000000000..379b25b6f3 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/getuiconfig_re.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; + +namespace CSNetwork.Protocols +{ + public class getuiconfig_re : Protocol + { + public int Result { get; set; } + public int Roleid { get; set; } + public int Localsid { get; set; } + public Octets UiConfig { get; set; } + + public getuiconfig_re() : base(ProtocolType.PROTOCOL_GETUICONFIG_RE) + { + UiConfig = new Octets(); + } + + public override Protocol Clone() => new getuiconfig_re + { + Result = Result, + Roleid = Roleid, + Localsid = Localsid, + UiConfig = UiConfig + }; + + public override void Marshal(OctetsStream os) + { + os.Write(Result); + os.Write(Roleid); + os.Write(Localsid); + os.Write(UiConfig); + } + + public override void Unmarshal(OctetsStream os) + { + Result = os.ReadInt32(); + Roleid = os.ReadInt32(); + Localsid = os.ReadInt32(); + UiConfig = os.ReadOctets(); + } + + public override int PriorPolicy() => 1; + + public override bool SizePolicy(int size) => size <= 4096; + } +} + diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/getuiconfig_re.cs.meta b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/getuiconfig_re.cs.meta new file mode 100644 index 0000000000..908c069cf6 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/getuiconfig_re.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 2f1504051817c6c4486bc9ea6123022f \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/gnetdef.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/gnetdef.cs new file mode 100644 index 0000000000..0f4b7d3144 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/gnetdef.cs @@ -0,0 +1,198 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BrewMonster +{ + enum ErrCode + { + ERR_SUCCESS = 0, //³É¹¦ + ERR_TOBECONTINUE = 1, //³É¹¦£¬²¢ÇÒ»¹Óиü¶àÊý¾Ýδ´«µÝÍ꣬ĿǰδÓà + + ERR_INVALID_ACCOUNT = 2, //ÕʺŲ»´æÔÚ + ERR_INVALID_PASSWORD = 3, //ÃÜÂë´íÎó + ERR_TIMEOUT = 4, //³¬Ê± + ERR_INVALID_ARGUMENT = 5, //²ÎÊý´íÎó + ERR_FRIEND_SYNCHRONIZE = 6, //ºÃÓÑÐÅÏ¢±£´æµ½Êý¾Ý¿âʱÎÞ·¨Í¬²½ + ERR_SERVERNOTSUPPLY = 7, //¸Ã·þÎñÆ÷²»Ö§³Ö¸ÃÇëÇó + ERR_COMMUNICATION = 8, //ÍøÂçͨѶ´íÎó + ERR_ACCOUNTLOCKED = 9, //¶à´ÎÖØ¸´µÇ½£¬µ±Ç°Óû§µÄÒ»¸öµÇ½ÕýÔÚ±»´¦Àí£¬´¦ÓÚËø¶¨×´Ì¬ + ERR_MULTILOGIN = 10, //¶à´ÎÖØ¸´µÇ½£¬ÇÒÓû§Ñ¡Ôñ×Ô¶¯ÏÂÏß + // keyexchange + ERR_INVALID_NONCE = 11, //ÎÞЧµÄnonceÖµ + // deliver use + ERR_DELIVER_SEND = 21, //ת·¢Ê§°Ü + ERR_DELIVER_TIMEOUT = 22, //ת·¢³¬Ê± + //player login + ERR_LOGINFAIL = 31, //µÇ½ÓÎϷʧ°Ü + ERR_KICKOUT = 32, //±»ÌßÏÂÏß + ERR_CREATEROLE = 33, //´´½¨½Çɫʧ°Ü + ERR_DELETEROLE = 34, //ɾ³ý½Çɫʧ°Ü + ERR_ROLELIST = 35, //»ñµÃ½ÇÉ«Áбíʧ°Ü + ERR_UNDODELROLE = 36, //³·Ïúɾ³ý½Çɫʧ°Ü + ERR_LINKISFULL = 39, //·þÎñÆ÷ÈËÊýÒÑÂú + //add friend + ERR_ADDFRD_REQUEST = 51, //ÇëÇó¼ÓΪºÃÓÑ + ERR_ADDFRD_REFUSE = 52, //¾Ü¾ø¼ÓΪºÃÓÑ + ERR_ADDFRD_AGREE = 53, //ͬÒâ¼ÓΪºÃÓÑ + ERR_ADDFRD_AGREEANDADD = 54, //ͬÒⲢϣÍû½«¶Ô·½¼ÓΪºÃÓÑ + + //QQ DB retcode + ERR_FAILED = 41, + ERR_EXCEPTION = 42, + ERR_NOTFOUND = 43, + ERR_INVALIDHANDLE = 44, + ERR_DUPLICATRECORD = 45, + ERR_NOFREESPACE = 46, + + //game DB + ERR_DATANOTFIND = 60, //Êý¾Ý²»´æÔÚ + ERR_GENERAL = 61, + ERR_ERR_UNAVAILABLE = 65, //ÒÑ»éÈËÊ¿²»ÄÜɾ³ý½ÇÉ« + + //faction error code (101-200) + ERR_FC_NETWORKERR = 101, //·þÎñÆ÷ÍøÂçͨѶ´íÎó + ERR_FC_INVALID_OPERATION = 102, //ÎÞЧµÄ²Ù×÷ÀàÐÍ + ERR_FC_OP_TIMEOUT = 103, //²Ù×÷³¬Ê± + ERR_FC_CREATE_ALREADY = 104, //Íæ¼ÒÒѾ­ÊÇij¸ö°ïÅɵijÉÔ±£¬²»ÄÜÔÙ´´½¨°ïÅÉ + ERR_FC_CREATE_DUP = 105, //°ïÅÉÃû³ÆÖظ´ + ERR_FC_DBFAILURE = 106, //Êý¾Ý¿âIO´íÎó + ERR_FC_NO_PRIVILEGE = 107, //ûÓÐÏà¹Ø²Ù×÷µÄȨÏÞ + ERR_FC_INVALIDNAME = 108, //²»ÄÜʹÓôËÃû³Æ + ERR_FC_FULL = 109, //ÈËÊýÒÑ´ïÉÏÏÞ + ERR_FC_APPLY_REJOIN = 110, //ÒѾ­ÊÇij¸ö°ïÅɵijÉÔ±£¬ÉêÇëʧ°Ü + ERR_FC_JOIN_SUCCESS = 111, //³É¹¦¼ÓÈë°ïÅÉ + ERR_FC_JOIN_REFUSE = 112, //ÉêÇë±»¾Ü¾ø + ERR_FC_ACCEPT_REACCEPT = 113, //±»Åú×¼¼ÓÈë°ïÅɵÄÍæ¼ÒÒѾ­¼ÓÈë°ïÅÉ + ERR_FC_FACTION_NOTEXIST = 114, //°ïÅɲ»´æÔÚorÍæ¼ÒûÓÐÉêÇë¹ý¼ÓÈë±¾°ïÅÉ + ERR_FC_NOTAMEMBER = 115, //Íæ¼Ò²»ÊDZ¾°ïÅɵİïÖÚ + ERR_FC_CHECKCONDITION = 116, //²»Âú×ã²Ù×÷Ìõ¼þ£¬ÈçSP²»¹»£¬×ʽ𲻹» + ERR_FC_DATAERROR = 117, //²Ù×÷²ÎÊýÀàÐÍ´íÎ󣬿ͻ§¶ËÌá½»µÄ²Ù×÷²ÎÊý¸ñʽ´íÎó + ERR_FC_OFFLINE = 118, //Íæ¼Ò²»ÔÚÏß + + ERR_FC_INVALID_IN_PVP = 441, //°ïÅÉ¿ªÆôÂÓ¶áģʽÆÚ¼ä²»ÄܽøÐиòÙ×÷ + + + //ÁÄÌìÊÒ´íÎó´úÂë + ERR_CHAT_CREATE_FAILED = 151, //´´½¨Ê§°Ü + ERR_CHAT_INVALID_SUBJECT = 152, //·Ç·¨Ö÷Ìâ + ERR_CHAT_ROOM_NOT_FOUND = 153, //ÁÄÌìÊÒ²»´æÔÚ + ERR_CHAT_JOIN_REFUSED = 154, //¼ÓÈëÇëÇ󱻾ܾø + ERR_CHAT_INVITE_REFUSED = 155, //ÁÄÌìÑûÇë±»¾Ü¾ø + ERR_CHAT_INVALID_PASSWORD = 156, //ÁÄÌìÊÒÃÜÂë´íÎó + ERR_CHAT_INVALID_ROLE = 157, //½ÇɫδÕÒµ½ + ERR_CHAT_PERMISSION_DENY = 158, //ûÓÐȨÏÞ + ERR_CHAT_EXCESSIVE = 159, //¼ÓÈëÁÄÌìÊÒ¹ý¶à + ERR_CHAT_ROOM_FULL = 160, //ÈËÊýÒÑ´ïÉÏÏÞ + ERR_CHAT_SEND_FAILURE = 161, //·¢ËÍʧ°Ü + + + //ÓÊÏäϵͳ´íÎó´úÂë + ERR_MS_DBSVR_INV = 211, //Êý¾Ý¿â·þÎñ²»¿ÉÁ¬½Ó + ERR_MS_MAIL_INV = 212, //Óʼþ²»´æÔÚ + ERR_MS_ATTACH_INV = 213, //´íÎóµÄ¸½¼þÐÅÏ¢ + ERR_MS_SEND_SELF = 214, //½ûÖ¹¸ø×Ô¼º·¢ËÍÓʼþ + ERR_MS_ACCOUNTFROZEN = 215, //Ä¿±êÓÊÏäÒѾ­¶³½á + ERR_MS_AGAIN = 216, //ÓÊÏä·þÎñÔÝʱ²»¿ÉÓà + ERR_MS_BOXFULL = 217, //Ä¿±êÓÊÏäÒÑÂú + + //ÅÄÂô´íÎó´úÂë + ERR_AS_MAILBOXFULL = 220, //Íæ¼ÒÐÅÏäÎÞÊ£Óà¿Õ¼ä + ERR_AS_ITEM_INV = 221, //´íÎóµÄÅÄÂôÎïÆ·ÐÅÏ¢ + ERR_AS_MARKET_UNOPEN = 222, //ÅÄÂô³¡Î´¿ª·Å£¨Î´Íê³É³õʼ»¯£© + ERR_AS_ID_EXHAUSE = 223, //ÅÄÂôºÅÓþ¡ + ERR_AS_ATTEND_OVF = 224, //²ÎÓëµÄÅÄÂôÊý´ïµ½ÉÏÏÞ + ERR_AS_BID_LOWBID = 225, //³ö¼Û¹ýµÍ¾ºÅÄʧ°Ü + ERR_AS_BID_NOTFOUND = 226, //δÕÒµ½¸ÃÅÄÂôʼþ + ERR_AS_BID_BINSUCCESS = 227, //Ò»¿Ú¼ÛÂò¶Ï + ERR_AS_BID_UNREDEEMABLE = 228, //²»ÄÜÊê»Ø + ERR_AS_BID_INVALIDPRICE = 229, //¾º¼ÛÔö·ù³¬¹ýϵͳÔÊÐí°²È«É趨£¬Çë¼ì²éÊäÈë¼Û¸ñ + + ERR_SP_NOT_INIT = 231, //ϵͳûÓгõʼ»¯Íê³É + ERR_SP_SPARETIME = 232, //Ê£Óàʱ¼ä²»Âú×ã¹ÒÊÛÌõ¼þ + ERR_SP_INVA_POINT = 233, //ÎÞЧµÄ¹ÒÊÛµãÊý£¬±ØÐëÊÇ30ÔªµÄÕûÊý±¶ + ERR_SP_EXPIRED = 234, //¸Ãµã¿¨ÒѾ­¹ýÆÚ + ERR_SP_NOMONEY = 237, //ÐéÄâ±Ò²»×ã + ERR_SP_SELLING = 239, //µã¿¨ÒѾ­´¦ÓÚÏúÊÛ״̬ + ERR_SP_MONEYEXCEED = 242, //½ðÇ®Êý´ïµ½ÉÏÏÞ + ERR_SP_BUYSELF = 243, //²»ÄܹºÂò×Ô¼º¹ÒÊ۵ĵ㿨 + ERR_SP_EXCESS = 245, //½ûÖ¹¹ý¶È½»Ò׳´Âôµã¿¨ + + //³ÇÕ½´íÎó´úÂë + ERR_BS_INVALIDROLE = 260, //½ÇÉ«Éí·Ý²»·ûºÏ + ERR_BS_FAILED = 261, //¾º¼Ûʧ°Ü + ERR_BS_OUTOFSERVICE = 262, //³ÇÕ½·þÎñÔÝʱ²»¿ÉÓà + ERR_BS_NEWBIE_BANNED = 263, //¼ÓÈë°ïÅÉ72СʱÄÚ²»ÔÊÐí½øÈë³ÇÕ½ + + //ÏßÉÏÍÆ¹ã(online promote)´íÎó´úÂë (¶ÔÓ¦server_error.txtÖеĴíÎóÐÅÏ¢) + ERR_OP_DOWN_OFFLINE = 281, //"Íæ¼ÒûÓÐÔÚÏßµÄÏÂÏß" + ERR_OP_UP_NOT_LOAD = 282, //"Íæ¼ÒµÄÉÏÏßÐÅÏ¢»¹Î´¼ÓÔØ" + ERR_OP_PICKINGUP = 283, //"Íæ¼ÒÕýÔÚÌáÈ¡ºèÀûÖµ" + ERR_OP_NO_DIVIDEND = 284, //"ÉÏÏßûÓпÉÌáÈ¡µÄºèÀûÖµ" + ERR_OP_DB_ERROR = 285, //"Êý¾Ý¿â·ÃÎÊ´íÎó" + ERR_OR_INVALID_PCODE = 286, //"ÍÆ¹ãÂë²»ÕýÈ·" + ERR_OP_NOT_IN_CURR_SERVER = 287, //"ÍÆ¹ãÈ˲»ÔÚ±¾·þÎñÆ÷" + ERR_OP_INVALID_LEVEL = 288, //"20¼¶ÒÔÏÂÍæ¼Ò²»ÄÜÍÆ¹ãÏÂÏß" + ERR_OP_NOT_IN_CURR_REGION = 289, //"ÍÆ¹ãÈ˲»ÔÚ±¾Çø" + ERR_OP_ALREADY_BINDED = 290, //"ÉÏÏßÒѾ­°ó¶¨£¬ÎÞ·¨Ôٴΰó¶¨" + ERR_OP_REPUATION = 291, //"»ñÈ¡ÍÆ¹ãÁ´½ÓÉùÍûÖµ²»¹»" + + //Ïû·Ñ·µ»ý·Ö(consume return points)´íÎó´úÂë (¶ÔÓ¦server_error.txtÖеĴíÎóÐÅÏ¢) + ERR_CRP_PLAYER_OFFLINE = 301, //"Íæ¼ÒÒѾ­ÀëÏß" + ERR_CRP_DB_BUSY = 302, //"Êý¾Ý¿â·±Ã¦" + ERR_CRP_DB_ERROR = 303, //"Êý¾Ý¿â·ÃÎÊ´íÎó" + ERR_CRP_NOT_ENOUGH_POINTS = 304, //"»ý·Ö²»×ã" + ERR_CRP_INVALID_CHANGE_TIME = 305, //"δÔڻÆÚÄÚ²»Äܶһ»»ý·Ö" + ERR_CRP_INVALID_RETURN_TYPE = 306, //"ÎÞЧµÄ·µ»¹·½Ê½" + + //½»Òׯ½Ì¨´íÎó´úÂë (¶ÔÓ¦server_error.txtÖеĴíÎóÐÅÏ¢) + ERR_WT_UNOPEN = 311, // ½»Ò×먦·Å + ERR_WT_SN_EXHAUSE = 312, // ÎÞ·¨»ñµÃÓÐЧ½»Ò׺Š+ ERR_WT_CANNOT_POST = 313, // ÎÞ·¨¼ÄÊÛ + ERR_WT_CANNOT_CANCELPOST = 314, // ÎÞ·¨È¡Ïû¼ÄÊÛ + ERR_WT_NOT_ENOUGH_DEPOSIT = 315, // ½»Ò×±£Ö¤½ð²»×ã + ERR_WT_ILLEGAL_SELL_PERIOD = 316, // ½»Ò×ÉϼÜʱ¼ä²»ºÏ·¨ + ERR_WT_ENTRY_NOT_FOUND = 317, // ½»Ò׺ŶÔÓ¦ÎïÆ·²»´æÔÚ + ERR_WT_ENTRY_IS_BUSY = 318, // ͬ²½²Ù×÷ÖУ¬ÎÞ·¨½ÓÊܽ»Ò×ÇëÇó + ERR_WT_SN_ROLEID_MISMATCH = 319, // ½»Ò׺ÅÓë½ÇÉ«²»Æ¥Åä + ERR_WT_TIMESTAMP_MISMATCH = 320, // ½»ÒײÙ×÷ʱ´Á²»Æ¥Åä + ERR_WT_ENTRY_HAS_BEEN_SOLD = 321, // ÎïÆ·ÒÑÊÛ³ö + ERR_WT_BUYER_NOT_EXIST = 322, // Âò¼Ò²»´æÔÚ + ERR_WT_SN_USERID_MISMATCH = 323, // ½»Ò׺ÅÓëÕʺŲ»Æ¥Åä + ERR_WT_ILLEGAL_SELL_PRICE = 324, // Éϼܼ۸ñ²»ºÏ·¨ + ERR_WT_TOO_MANY_ATTEND_SELL = 325, // ¼ÄÊÛÎïÆ·¹ý¶à + ERR_WT_MAILBOX_FULL = 326, // ÓÊÏäÒÑÂú£¬²»¿É½øÐвÙ×÷ + ERR_WT_BUYER_STATUS_INAPPROPRIATE, + ERR_WT_BUYER_NOT_EXIST_2, + ERR_WT_SELLER_NOT_EXIST, + ERR_WT_BUYER_CONDITION_NOT_MATCH, + ERR_WT_HAS_ATTEND_SELL, + ERR_WT_USER_OTHER_ROLE_ON_SALE, + + //É̳ǾºÅÄ´íÎó´úÂë (¶ÔÓ¦server_error.txtÖеĴíÎóÐÅÏ¢) + ERR_SA_ENTRY_NOT_FOUND = 341, // ¾º¼ÛÎïÆ·²»´æÔÚ + ERR_SA_ENTRY_IS_BUSY = 342, // ¾º¼ÛÎïÆ·Í¬²½²Ù×÷ÖУ¬ÎÞ·¨½ÓÊܾº¼ÛÇëÇó + ERR_SA_CANNOT_BID = 343, // µ±Ç°ÎÞ·¨¾º¼Û + ERR_SA_LOW_BIDPRICE = 344, // ¾º¼Û¹ýµÍ + ERR_SA_BID_FAILED = 345, // ¾º¼Ûʧ°Ü£¬ÓÐÈ˸øÁ˸ü¸ßµÄ¾º¼Û + ERR_SA_USER_NOT_FOUND = 346, // ²ÎÓ뾺¼ÛÕ˺Ų»´æÔÚ + ERR_SA_USER_IS_BUSY = 347, // Õ˺Åͬ²½²Ù×÷ÖУ¬ÎÞ·¨½ÓÊܾº¼ÛÇëÇó + ERR_SA_CASH_NOT_ENOUGH = 348, // ¾º¼ÛÔª±¦²»×ã + ERR_SA_CASH_OVERFLOW = 349, // ¾º¼ÛÔª±¦Ïà¹ØµÄÒç³ö´íÎ󣨴æÈë»òÈ¡³ö£© + ERR_SA_CASH_NOT_ENOUGH_FOR_TRANSFER, + + // ¹úÍõÑ¡¾Ù´íÎó´úÂë + ERR_KE_CANNOT_APPLY_CANDIDATE = 471, + ERR_KE_CANDIDATE_APPLY_EXCEED_UPPER_LIMIT, + ERR_KE_ALREADY_APPLY_CANDIDATE, + ERR_KE_CANNOT_VOTE, + ERR_KE_CANDIDATE_NOT_EXIST, + + ERR_TANK_BATTLE_NOT_OPEN = 490, + ERR_TANK_BATTLE_ALREADY_APPLY, + ERR_TANK_BATTLE_SWITCH_TIMEOUT, + ERR_TANK_BATTLE_NOT_APPLY_MAP, + }; +} diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/gnetdef.cs.meta b/Assets/PerfectWorld/Scripts/Network/CSNetwork/gnetdef.cs.meta new file mode 100644 index 0000000000..a6f97d8812 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/gnetdef.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 21f97ff846f97be4bbcaf0d2e6fe93a1 \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/Network/UnityGameSession.cs b/Assets/PerfectWorld/Scripts/Network/UnityGameSession.cs index afa6725627..a16e3732a4 100644 --- a/Assets/PerfectWorld/Scripts/Network/UnityGameSession.cs +++ b/Assets/PerfectWorld/Scripts/Network/UnityGameSession.cs @@ -180,6 +180,10 @@ namespace BrewMonster.Network { Instance._gameSession.RequestDropIvtrItem(index, amount); } + public static void LoadConfigData() + { + Instance._gameSession.LoadConfigData(); + } public static void RequestCheckSecurityPassWd(string password) { Instance._gameSession.RequestCheckSecurityPassWd(password); @@ -298,7 +302,6 @@ namespace BrewMonster.Network } actDone?.Invoke(true); } - void OnDestroy() { _gameSession.Disconnect(); diff --git a/Assets/PerfectWorld/Scripts/Objet/Shortcut.meta b/Assets/PerfectWorld/Scripts/Objet/Shortcut.meta new file mode 100644 index 0000000000..ec50aeece5 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Objet/Shortcut.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0f3afd074eb1e4348a1732d7c1e12c7e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/PerfectWorld/Scripts/Objet/Shortcut/CECShortcutSet.cs b/Assets/PerfectWorld/Scripts/Objet/Shortcut/CECShortcutSet.cs new file mode 100644 index 0000000000..71e85c6998 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Objet/Shortcut/CECShortcutSet.cs @@ -0,0 +1,862 @@ +/* + * FILE: CECShortcutSet.cs + * + * DESCRIPTION: Shortcut set management + * + * CREATED BY: Duyuxin, 2005/1/5 + * CONVERTED TO C#: 2025 + * + * HISTORY: + * + * Copyright (c) 2005 Archosaur Studio, All Rights Reserved. + */ + +using BrewMonster.Assets.PerfectWorld.Scripts.Skills; +using BrewMonster.Network; +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace BrewMonster +{ + /// + /// Manages a set of shortcuts for quick access to items, skills, commands, etc. + /// + public class CECShortcutSet + { + #region Fields + + private List m_aShortcuts; // Shortcut array + + #endregion + + #region Constructor and Destructor + + public CECShortcutSet() + { + m_aShortcuts = new List(); + } + + #endregion + + #region Initialization and Release + + /// + /// Initialize the shortcut set with a specified size + /// + /// Number of shortcut slots + /// True if successful + public bool Init(int iSize) + { + m_aShortcuts = new List(iSize); + for (int i = 0; i < iSize; i++) + { + m_aShortcuts.Add(null); + } + + return true; + } + + /// + /// Release all shortcuts and clear the set + /// + public void Release() + { + // Clear all shortcuts + for (int i = 0; i < m_aShortcuts.Count; i++) + { + if (m_aShortcuts[i] != null) + { + // In C#, we don't need explicit deletion, just clear references + m_aShortcuts[i] = null; + } + } + + m_aShortcuts.Clear(); + } + + #endregion + + #region Shortcut Creation Methods + + /// + /// Create an item shortcut at specified position + /// + /* public bool CreateItemShortcut(int iSlot, int iIvtr, int iIvtrSlot, CECIvtrItem pItem) + { + CECSCItem pItemSC = new CECSCItem(); + if (pItemSC == null) + return false; + + if (!pItemSC.Init(iIvtr, iIvtrSlot, pItem)) + { + Debug.LogError("CECShortcutSet::CreateItemShortcut, Failed to initialize item shortcut"); + return false; + } + + SetShortcut(iSlot, pItemSC); + return true; + }*/ + + /// + /// Create a skill shortcut at specified position + /// + public bool CreateSkillShortcut(int iSlot, CECSkill pSkill) + { + CECSCSkill pSkillSC = new CECSCSkill(); + if (pSkillSC == null) + return false; + + if (!pSkillSC.Init(pSkill)) + { + Debug.LogError("CECShortcutSet::CreateSkillShortcut, Failed to initialize skill shortcut"); + return false; + } + + SetShortcut(iSlot, pSkillSC); + return true; + } + + /// + /// Create a skill group shortcut at specified position + /// + /* public bool CreateSkillGroupShortcut(int iSlot, int iGroupIdx) + { + CECSCSkillGrp pSkillGrpSC = new CECSCSkillGrp(); + if (pSkillGrpSC == null) + return false; + + if (!pSkillGrpSC.Init(iGroupIdx)) + { + Debug.LogError("CECShortcutSet::CreateSkillGroupShortcut, Failed to initialize skill group shortcut"); + return false; + } + + SetShortcut(iSlot, pSkillGrpSC); + return true; + }*/ + + /// + /// Create a pet shortcut at specified position + /// + /* public bool CreatePetShortcut(int iSlot, int iPetIndex) + { + CECSCPet pPetSC = new CECSCPet(); + if (pPetSC == null) + return false; + + if (!pPetSC.Init(iPetIndex)) + { + Debug.LogError("CECShortcutSet::CreatePetShortcut, Failed to initialize pet shortcut"); + return false; + } + + SetShortcut(iSlot, pPetSC); + return true; + }*/ + + /// + /// Create an auto fashion shortcut at specified position + /// + /* public bool CreateAutoFashionShortcut(int iSlot, int iFashionIdx) + { + CECSCAutoFashion pAutoFashionSC = new CECSCAutoFashion(); + if (pAutoFashionSC == null) + return false; + + if (!pAutoFashionSC.Init(iFashionIdx)) + { + Debug.LogError("CECShortcutSet::CreateAutoFashionShortcut, Failed to initialize auto fashion shortcut"); + return false; + } + + SetShortcut(iSlot, pAutoFashionSC); + return true; + } + + /// + /// Create a system module shortcut at specified position + /// + public bool CreateSystemModuleShortcut(int iSlot, int iSys) + { + CECSCSysModule pSysModule = new CECSCSysModule(); + if (pSysModule == null) + return false; + + if (!pSysModule.Init(iSys)) + { + Debug.LogError("CECShortcutSet::CreateSystemModuleShortcut, Failed to initialize system module shortcut"); + return false; + } + + SetShortcut(iSlot, pSysModule); + return true; + }*/ + + /// + /// Duplicate a shortcut to specified position + /// + public bool CreateClonedShortcut(int iSlot, CECShortcut pShortcut) + { + CECShortcut pDest = pShortcut.Clone(); + if (pDest == null) + return false; + + SetShortcut(iSlot, pDest); + return true; + } + + #endregion + + #region Shortcut Management + + /// + /// Put a shortcut into set and return the old shortcut at that position + /// + /// Slot index + /// Shortcut to place + /// Previous shortcut at that position + public CECShortcut PutShortcut(int iSlot, CECShortcut pShortcut) + { + if (iSlot < 0 || iSlot >= m_aShortcuts.Count) + return null; + + CECShortcut pOldShortcut = m_aShortcuts[iSlot]; + m_aShortcuts[iSlot] = pShortcut; + return pOldShortcut; + } + + /// + /// Get a shortcut from set + /// + /// Slot index + /// If true, remove the shortcut from the set + /// Shortcut at the specified position + public CECShortcut GetShortcut(int iSlot, bool bRemove = false) + { + if (iSlot < 0 || iSlot >= m_aShortcuts.Count) + return null; + + CECShortcut pShortcut = m_aShortcuts[iSlot]; + if (bRemove) + m_aShortcuts[iSlot] = null; + + return pShortcut; + } + + /// + /// Set a shortcut into set and release old shortcut at this position automatically + /// + public void SetShortcut(int iSlot, CECShortcut pShortcut) + { + if (iSlot < 0 || iSlot >= m_aShortcuts.Count) + return; + + // Clear old shortcut (C# garbage collection will handle cleanup) + if (m_aShortcuts[iSlot] != null) + { + m_aShortcuts[iSlot] = null; + } + + m_aShortcuts[iSlot] = pShortcut; + } + + /// + /// Exchange shortcuts in two slots + /// + public void ExchangeShortcut(int iSlot1, int iSlot2) + { + if (iSlot1 < 0 || iSlot1 >= m_aShortcuts.Count || + iSlot2 < 0 || iSlot2 >= m_aShortcuts.Count) + return; + + if (iSlot1 != iSlot2) + { + CECShortcut pShortcut = m_aShortcuts[iSlot1]; + m_aShortcuts[iSlot1] = m_aShortcuts[iSlot2]; + m_aShortcuts[iSlot2] = pShortcut; + } + } + + /// + /// Remove all shortcuts + /// + public void RemoveAllShortcuts() + { + for (int i = 0; i < m_aShortcuts.Count; i++) + { + if (m_aShortcuts[i] != null) + { + m_aShortcuts[i] = null; + } + } + } + + /// + /// Remove skill and skill group shortcuts + /// + public void RemoveSkillShortcuts() + { + for (int i = 0; i < m_aShortcuts.Count; i++) + { + CECShortcut pSC = m_aShortcuts[i]; + if (pSC == null) + continue; + + if (pSC.GetType() == CECShortcut.ShortcutType.SCT_SKILL || + pSC.GetType() == CECShortcut.ShortcutType.SCT_SKILLGRP) + { + m_aShortcuts[i] = null; + } + } + } + + #endregion + + #region Update Methods + + /// + /// Update item shortcut when item position changed + /// + /* public void UpdateMovedItemSC(int tidItem, int iSrcIvtr, int iSrcSlot, int iDstIvtr, int iDstSlot) + { + for (int i = 0; i < m_aShortcuts.Count; i++) + { + CECShortcut pSC = m_aShortcuts[i]; + if (pSC == null || pSC.GetType() != CECShortcut.ShortcutType.SCT_ITEM) + continue; + + CECSCItem pItemSC = (CECSCItem)pSC; + if (pItemSC.GetInventory() == iSrcIvtr && pItemSC.GetIvtrSlot() == iSrcSlot) + { + Debug.Assert(pItemSC.GetItemTID() == tidItem); + pItemSC.MoveItem(iDstIvtr, iDstSlot); + } + } + }*/ + + /// + /// Update item shortcut when item removed + /// + /* public void UpdateRemovedItemSC(int tidItem, int iIvtr, int iSlot, int iSameItem) + { + for (int i = 0; i < m_aShortcuts.Count; i++) + { + CECShortcut pSC = m_aShortcuts[i]; + if (pSC == null || pSC.GetType() != CECShortcut.ShortcutType.SCT_ITEM) + continue; + + CECSCItem pItemSC = (CECSCItem)pSC; + if (pItemSC.GetInventory() == iIvtr && pItemSC.GetIvtrSlot() == iSlot) + { + Debug.Assert(pItemSC.GetItemTID() == tidItem); + + if (pItemSC.GetAutoFindFlag() && iSameItem >= 0) + pItemSC.MoveItem(iIvtr, iSameItem); + else + SetShortcut(i, null); + } + } + }*/ + + /// + /// Update item shortcut when two items exchanged + /// + /*public void UpdateExchangedItemSC(int tidItem1, int iIvtr1, int iSlot1, + int tidItem2, int iIvtr2, int iSlot2) + { + for (int i = 0; i < m_aShortcuts.Count; i++) + { + CECShortcut pSC = m_aShortcuts[i]; + if (pSC == null || pSC.GetType() != CECShortcut.ShortcutType.SCT_ITEM) + continue; + + CECSCItem pItemSC = (CECSCItem)pSC; + + if (pItemSC.GetInventory() == iIvtr1 && pItemSC.GetIvtrSlot() == iSlot1) + { + Debug.Assert(pItemSC.GetItemTID() == tidItem1); + pItemSC.MoveItem(iIvtr2, iSlot2); + } + else if (pItemSC.GetInventory() == iIvtr2 && pItemSC.GetIvtrSlot() == iSlot2) + { + Debug.Assert(pItemSC.GetItemTID() == tidItem2); + pItemSC.MoveItem(iIvtr1, iSlot1); + } + } + } + + /// + /// Update pet shortcut when pet freed + /// + public void UpdateFreedPetSC(int iPetIndex) + { + for (int i = 0; i < m_aShortcuts.Count; i++) + { + CECShortcut pSC = m_aShortcuts[i]; + if (pSC == null || pSC.GetType() != CECShortcut.ShortcutType.SCT_PET) + continue; + + CECSCPet pPetSC = (CECSCPet)pSC; + if (pPetSC.GetPetIndex() == iPetIndex) + SetShortcut(i, null); + } + }*/ + + #endregion + + #region Skill Management + + /// + /// Replace skill id in skill shortcuts + /// + public void ReplaceSkillID(int idOld, CECSkill pNewSkill) + { + for (int i = 0; i < m_aShortcuts.Count; i++) + { + CECShortcut pSC = m_aShortcuts[i]; + if (pSC == null || pSC.GetType() != CECShortcut.ShortcutType.SCT_SKILL) + continue; + + // Replace skill + CECSCSkill pSkillSC = (CECSCSkill)pSC; + CECSkill pSkill = pSkillSC.GetSkill(); + if (pSkill.GetSkillID() == idOld) + pSkillSC.SetSkill(pNewSkill); + } + } + + /// + /// Replace skill id in skill shortcuts using skill array + /// + public void ReplaceSkillID(SkillArrayWrapper skillArray, CECSkill pNewSkill) + { + for (int i = 0; i < skillArray.Count(); i++) + { + ReplaceSkillID((int)skillArray[i], pNewSkill); + } + } + + /// + /// Remove skill shortcut by skill ID + /// + public bool RemoveSkillShortcut(int idSkill) + { + bool bRemove = false; + + for (int i = 0; i < GetShortcutNum(); i++) + { + CECShortcut pSC = GetShortcut(i); + if (pSC == null) + continue; + + if (pSC.GetType() == CECShortcut.ShortcutType.SCT_SKILL) + { + CECSCSkill pSkillSC = (CECSCSkill)pSC; + CECSkill pSkill = pSkillSC.GetSkill(); + if (pSkill != null && pSkill.GetSkillID() == idSkill) + { + SetShortcut(i, null); + bRemove = true; + continue; + } + } + } + + return bRemove; + } + + #endregion + + #region Serialization + + /// + /// Save shortcut configs to specified buffer + /// + public bool SaveConfigData(out byte[] dataBuffer) + { + List data = new List(); + + for (int i = 0; i < m_aShortcuts.Count; i++) + { + CECShortcut pSC = m_aShortcuts[i]; + if (pSC == null) + continue; + + // Record shortcut's position and type + data.AddRange(BitConverter.GetBytes(i)); + data.AddRange(BitConverter.GetBytes((int)pSC.GetType())); + + switch (pSC.GetType()) + { + /* case CECShortcut.ShortcutType.SCT_COMMAND: + { + CECSCCommand cmdSC = (CECSCCommand)pSC; + data.AddRange(BitConverter.GetBytes(cmdSC.GetCommandID())); + data.AddRange(BitConverter.GetBytes((int)cmdSC.GetParam())); + break; + } +*/ + case CECShortcut.ShortcutType.SCT_SKILL: + { + CECSCSkill skillSC = (CECSCSkill)pSC; + data.AddRange(BitConverter.GetBytes(skillSC.GetSkill().GetSkillID())); + break; + } + + /* case CECShortcut.ShortcutType.SCT_ITEM: + { + CECSCItem itemSC = (CECSCItem)pSC; + data.AddRange(BitConverter.GetBytes(itemSC.GetInventory())); + data.AddRange(BitConverter.GetBytes(itemSC.GetIvtrSlot())); + data.AddRange(BitConverter.GetBytes(itemSC.GetItemTID())); + break; + } + + case CECShortcut.ShortcutType.SCT_SKILLGRP: + { + CECSCSkillGrp skillGrpSC = (CECSCSkillGrp)pSC; + data.AddRange(BitConverter.GetBytes(skillGrpSC.GetGroupIndex())); + break; + } + + case CECShortcut.ShortcutType.SCT_PET: + { + CECSCPet petSC = (CECSCPet)pSC; + data.AddRange(BitConverter.GetBytes(petSC.GetPetIndex())); + break; + } + + case CECShortcut.ShortcutType.SCT_AUTOFASHION: + { + CECSCAutoFashion fashionSC = (CECSCAutoFashion)pSC; + data.AddRange(BitConverter.GetBytes(fashionSC.GetAutoFashionIndex())); + break; + } + + case CECShortcut.ShortcutType.SCT_SYSMODULE: + { + CECSCSysModule sysSC = (CECSCSysModule)pSC; + data.AddRange(BitConverter.GetBytes(sysSC.GetSysModID())); + break; + }*/ + + default: + Debug.LogError("CECShortcutSet::SaveConfigData - Unknown shortcut type"); + break; + } + } + + // Add the end flag + data.AddRange(BitConverter.GetBytes(-1)); + + dataBuffer = data.ToArray(); + return true; + } + + /// + /// Load shortcut configs from specified buffer + /// + public bool LoadConfigData(byte[] pDataBuf, uint dwVer) + { + if (pDataBuf == null || pDataBuf.Length == 0) + return false; + + int offset = 0; + + CECGameRun pGameRun = EC_Game.GetGameRun(); + CECHostPlayer pHost = pGameRun.GetHostPlayer(); + Debug.Assert(pHost != null); + + while (offset < pDataBuf.Length) + { + int iSlot = BitConverter.ToInt32(pDataBuf, offset); + offset += sizeof(int); + + if (iSlot < 0) + break; // Meet end flag + + int iSCType = BitConverter.ToInt32(pDataBuf, offset); + offset += sizeof(int); + + switch ((CECShortcut.ShortcutType)iSCType) + { + /*case CECShortcut.ShortcutType.SCT_COMMAND: + { + int iCommand = BitConverter.ToInt32(pDataBuf, offset); + offset += sizeof(int); + + int iParam = 0; + if (dwVer >= 2) + { + iParam = BitConverter.ToInt32(pDataBuf, offset); + offset += sizeof(int); + } + + CECSCCommand pCmdSC = null; + if (iCommand == CECSCCommand.CMD_PLAYPOSE) + pCmdSC = pGameRun.GetPoseCmdShortcut(iParam); + else + pCmdSC = pGameRun.GetCmdShortcut(iCommand); + + if (pCmdSC != null) + CreateClonedShortcut(iSlot, pCmdSC); + + break; + }*/ + + case CECShortcut.ShortcutType.SCT_SKILL: + { + int idSkill = BitConverter.ToInt32(pDataBuf, offset); + offset += sizeof(int); + + CECSkill pSkill = pHost.GetPositiveSkillByID(idSkill, true); + if (pSkill == null) + pSkill = pHost.GetEquipSkillByID(idSkill); + + CECSkill pSkill2 = null; + /* CECHostGoblin pGoblin = (CECHostGoblin)pHost.GetGoblinModel(); + if (pGoblin != null) + { + pSkill2 = pGoblin.GetSkillByID(idSkill); + }*/ + + if (pSkill != null) + CreateSkillShortcut(iSlot, pSkill); + else if (pSkill2 != null) + CreateSkillShortcut(iSlot, pSkill2); + + break; + } + + /* case CECShortcut.ShortcutType.SCT_ITEM: + { + int iPack = BitConverter.ToInt32(pDataBuf, offset); + offset += sizeof(int); + int iIvtrSlot = BitConverter.ToInt32(pDataBuf, offset); + offset += sizeof(int); + int idItem = BitConverter.ToInt32(pDataBuf, offset); + offset += sizeof(int); + + CECInventory pPack = pHost.GetPack(iPack); + if (pPack == null) + { + Debug.LogError("CECShortcutSet::LoadConfigData - Invalid inventory"); + return false; + } + + CECIvtrItem pItem = pPack.GetItem(iIvtrSlot); + if (pItem != null) + CreateItemShortcut(iSlot, iPack, iIvtrSlot, pItem); + + break; + } + + case CECShortcut.ShortcutType.SCT_SKILLGRP: + { + if (dwVer >= 3) + { + int iGroupIdx = BitConverter.ToInt32(pDataBuf, offset); + offset += sizeof(int); + + if (iGroupIdx >= 0) + CreateSkillGroupShortcut(iSlot, iGroupIdx); + } + else + { + Debug.LogError("CECShortcutSet::LoadConfigData - Invalid version for skill group"); + return false; + } + break; + } + + case CECShortcut.ShortcutType.SCT_PET: + { + if (dwVer >= 4) + { + int iPetIndex = BitConverter.ToInt32(pDataBuf, offset); + offset += sizeof(int); + + if (iPetIndex >= 0) + CreatePetShortcut(iSlot, iPetIndex); + } + else + { + Debug.LogError("CECShortcutSet::LoadConfigData - Invalid version for pet"); + return false; + } + break; + } + + case CECShortcut.ShortcutType.SCT_AUTOFASHION: + { + if (dwVer >= 5) + { + int iAutoFashionIndex = BitConverter.ToInt32(pDataBuf, offset); + offset += sizeof(int); + + if (iAutoFashionIndex >= 0) + CreateAutoFashionShortcut(iSlot, iAutoFashionIndex); + } + else + { + Debug.LogError("CECShortcutSet::LoadConfigData - Invalid version for auto fashion"); + return false; + } + break; + } + + case CECShortcut.ShortcutType.SCT_SYSMODULE: + { + if (dwVer > 10) + { + int iSys = BitConverter.ToInt32(pDataBuf, offset); + offset += sizeof(int); + + if (iSys >= 0) + CreateSystemModuleShortcut(iSlot, iSys); + } + else + { + Debug.LogError("CECShortcutSet::LoadConfigData - Invalid version for system module"); + return false; + } + break; + }*/ + + default: + Debug.LogError("CECShortcutSet::LoadConfigData - Unknown shortcut type"); + return false; + } + } + + return true; + } + + #endregion + + #region Properties + + /// + /// Get the number of shortcuts in the set + /// + public int GetShortcutNum() + { + return m_aShortcuts.Count; + } + + #endregion + } + + #region Placeholder Classes + // These classes are referenced but not defined in the provided files + // They should be implemented separately based on EC_Shortcut.h/cpp + + public abstract class CECShortcut + { + public enum ShortcutType + { + SCT_NONE = 0, + SCT_COMMAND, + SCT_SKILL, + SCT_ITEM, + SCT_SKILLGRP, + SCT_PET, + SCT_AUTOFASHION, + SCT_SYSMODULE + } + + public abstract ShortcutType GetType(); + public abstract CECShortcut Clone(); + } + + /* public class CECSCCommand : CECShortcut + { + public const int CMD_PLAYPOSE = 1; // Example constant + public override ShortcutType GetType() => ShortcutType.SCT_COMMAND; + public override CECShortcut Clone() => null; + public int GetCommandID() => 0; + public int GetParam() => 0; + } + + public class CECSCSkill : CECShortcut + { + private CECSkill m_pSkill; + public override ShortcutType GetType() => ShortcutType.SCT_SKILL; + public override CECShortcut Clone() => null; + public bool Init(CECSkill pSkill) { m_pSkill = pSkill; return true; } + public CECSkill GetSkill() => m_pSkill; + public void SetSkill(CECSkill pSkill) { m_pSkill = pSkill; } + } + + public class CECSCItem : CECShortcut + { + private int m_iInventory; + private int m_iIvtrSlot; + private int m_iItemTID; + private bool m_bAutoFind; + + public override ShortcutType GetType() => ShortcutType.SCT_ITEM; + public override CECShortcut Clone() => null; + public bool Init(int iIvtr, int iSlot, CECIvtrItem pItem) + { + m_iInventory = iIvtr; + m_iIvtrSlot = iSlot; + return true; + } + public int GetInventory() => m_iInventory; + public int GetIvtrSlot() => m_iIvtrSlot; + public int GetItemTID() => m_iItemTID; + public bool GetAutoFindFlag() => m_bAutoFind; + public void MoveItem(int iIvtr, int iSlot) { m_iInventory = iIvtr; m_iIvtrSlot = iSlot; } + }*/ + + /* public class CECSCSkillGrp : CECShortcut + { + private int m_iGroupIdx; + public override ShortcutType GetType() => ShortcutType.SCT_SKILLGRP; + public override CECShortcut Clone() => null; + public bool Init(int iGroupIdx) { m_iGroupIdx = iGroupIdx; return true; } + public int GetGroupIndex() => m_iGroupIdx; + } + + public class CECSCPet : CECShortcut + { + private int m_iPetIndex; + public override ShortcutType GetType() => ShortcutType.SCT_PET; + public override CECShortcut Clone() => null; + public bool Init(int iPetIndex) { m_iPetIndex = iPetIndex; return true; } + public int GetPetIndex() => m_iPetIndex; + } + + public class CECSCAutoFashion : CECShortcut + { + private int m_iFashionIdx; + public override ShortcutType GetType() => ShortcutType.SCT_AUTOFASHION; + public override CECShortcut Clone() => null; + public bool Init(int iFashionIdx) { m_iFashionIdx = iFashionIdx; return true; } + public int GetAutoFashionIndex() => m_iFashionIdx; + } + + public class CECSCSysModule : CECShortcut + { + private int m_iSysModID; + public override ShortcutType GetType() => ShortcutType.SCT_SYSMODULE; + public override CECShortcut Clone() => null; + public bool Init(int iSys) { m_iSysModID = iSys; return true; } + public int GetSysModID() => m_iSysModID; + } + + // Placeholder classes for dependencies + public class CECIvtrItem { } + public class CECInventory + { + public CECIvtrItem GetItem(int slot) => null; + } + public class CECHostGoblin + { + public CECSkill GetSkillByID(int id) => null; + }*/ + #endregion +} + diff --git a/Assets/PerfectWorld/Scripts/Objet/Shortcut/CECShortcutSet.cs.meta b/Assets/PerfectWorld/Scripts/Objet/Shortcut/CECShortcutSet.cs.meta new file mode 100644 index 0000000000..f2b74df457 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Objet/Shortcut/CECShortcutSet.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c8c517455cc397744bae3b6f9ddc1c38 \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/PlayerState/PlayerIdleState.cs b/Assets/PerfectWorld/Scripts/PlayerState/PlayerIdleState.cs index 1d95133c92..7292af5ecc 100644 --- a/Assets/PerfectWorld/Scripts/PlayerState/PlayerIdleState.cs +++ b/Assets/PerfectWorld/Scripts/PlayerState/PlayerIdleState.cs @@ -2,24 +2,27 @@ using BrewMonster.Scripts.Player; using UnityEngine; using static CECPlayer; -public class PlayerIdleState : PlayerState +namespace BrewMonster { - public PlayerIdleState(CECHostPlayer characterCtrl) : base(characterCtrl) + public class PlayerIdleState : PlayerState { - } + public PlayerIdleState(CECHostPlayer characterCtrl) : base(characterCtrl) + { + } - public override void Enter() - { - _characterCtrl.PlayAction((int)PLAYER_ACTION_TYPE.ACT_STAND, true, 1, false); - } + public override void Enter() + { + _characterCtrl.PlayAction((int)PLAYER_ACTION_TYPE.ACT_STAND, true, 1, false); + } - public override void Exit() - { - - } + public override void Exit() + { - public override void Update() - { - + } + + public override void Update() + { + + } } -} +} \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/PlayerState/PlayerMoveState.cs b/Assets/PerfectWorld/Scripts/PlayerState/PlayerMoveState.cs index 66c69102c7..7c96224e33 100644 --- a/Assets/PerfectWorld/Scripts/PlayerState/PlayerMoveState.cs +++ b/Assets/PerfectWorld/Scripts/PlayerState/PlayerMoveState.cs @@ -2,25 +2,28 @@ using BrewMonster.Scripts.Player; using UnityEngine; using static CECPlayer; -public class PlayerMoveState : PlayerState +namespace BrewMonster { - public PlayerMoveState(CECHostPlayer characterCtrl) : base(characterCtrl) + public class PlayerMoveState : PlayerState { - } + public PlayerMoveState(CECHostPlayer characterCtrl) : base(characterCtrl) + { + } - public override void Enter() - { - _characterCtrl.PlayAction((int)PLAYER_ACTION_TYPE.ACT_WALK,true,1,false); - } + public override void Enter() + { + _characterCtrl.PlayAction((int)PLAYER_ACTION_TYPE.ACT_WALK, true, 1, false); + } - public override void Exit() - { - _characterCtrl.StopMovement(); - } + public override void Exit() + { + _characterCtrl.StopMovement(); + } - public override void Update() - { - _characterCtrl.HandleMovement(); - } + public override void Update() + { + _characterCtrl.HandleMovement(); + } -} + } +} \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/PlayerState/PlayerState.cs b/Assets/PerfectWorld/Scripts/PlayerState/PlayerState.cs index e9fc80c320..2733c8dfd4 100644 --- a/Assets/PerfectWorld/Scripts/PlayerState/PlayerState.cs +++ b/Assets/PerfectWorld/Scripts/PlayerState/PlayerState.cs @@ -1,6 +1,6 @@ using UnityEngine; -namespace BrewMonster.Scripts.Player +namespace BrewMonster { public abstract class PlayerState { diff --git a/Assets/PerfectWorld/Scripts/Players/CECPlayerActionPlayPolicy.cs b/Assets/PerfectWorld/Scripts/Players/CECPlayerActionPlayPolicy.cs index 47f51706c8..e76b3fa427 100644 --- a/Assets/PerfectWorld/Scripts/Players/CECPlayerActionPlayPolicy.cs +++ b/Assets/PerfectWorld/Scripts/Players/CECPlayerActionPlayPolicy.cs @@ -304,7 +304,7 @@ public class CECPlayerActionPlayPolicy { if (m_pPlayer != null) { - EventBus.PublishChannel(m_pPlayer.GetPlayerInfo().cid, new CECPlayer.CleearComActFlagAllRankNodesEvent(bSignalCurrent)); + EventBus.PublishChannel(m_pPlayer.GetPlayerInfo().cid, new CECPlayer.ClearComActFlagAllRankNodesEvent(bSignalCurrent)); } } diff --git a/Assets/PerfectWorld/Scripts/Skills/CECSCSkill.cs b/Assets/PerfectWorld/Scripts/Skills/CECSCSkill.cs index 759cd0a6de..ec8fec9912 100644 --- a/Assets/PerfectWorld/Scripts/Skills/CECSCSkill.cs +++ b/Assets/PerfectWorld/Scripts/Skills/CECSCSkill.cs @@ -8,9 +8,9 @@ using System.Threading.Tasks; using Unity.VisualScripting; using static BrewMonster.SkillArrayWrapper; -namespace BrewMonster.Assets.PerfectWorld.Scripts.Skills +namespace BrewMonster { - public class CECSCSkill + public class CECSCSkill : CECShortcut { CECSkill m_pSkill; public bool Init(CECSkill pSkill) @@ -59,5 +59,18 @@ namespace BrewMonster.Assets.PerfectWorld.Scripts.Skills return true; } + public CECSkill GetSkill() { return m_pSkill; } + public void SetSkill(CECSkill pSkill) { m_pSkill = pSkill; } + + public override ShortcutType GetType() + { + //TODO: Fix later + return ShortcutType.SCT_ITEM; + } + + public override CECShortcut Clone() + { + return this; + } } } diff --git a/Assets/PerfectWorld/Scripts/Utils/CECRTDebug.cs b/Assets/PerfectWorld/Scripts/Utils/CECRTDebug.cs new file mode 100644 index 0000000000..7de115ac55 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Utils/CECRTDebug.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BrewMonster +{ + public class CECRTDebug + { + } + public class CECDataReader + { + private byte[] data; + private int offset; + private int length; + + public CECDataReader(byte[] data, int offset, int length) + { + this.data = data; + this.offset = offset; + this.length = length; + } + + public int ReadInt() + { + if (offset + sizeof(int) > offset + length) + throw new System.InvalidOperationException("Not enough data to read int"); + + int value = System.BitConverter.ToInt32(data, offset); + offset += sizeof(int); + return value; + } + + public byte[] ReadData(int size) + { + if (offset + size > offset + length) + throw new System.InvalidOperationException($"Not enough data to read {size} bytes"); + + byte[] result = new byte[size]; + System.Array.Copy(data, offset, result, 0, size); + offset += size; + return result; + } + } +} diff --git a/Assets/PerfectWorld/Scripts/Utils/CECRTDebug.cs.meta b/Assets/PerfectWorld/Scripts/Utils/CECRTDebug.cs.meta new file mode 100644 index 0000000000..7ee5e63681 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Utils/CECRTDebug.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 05e5b2cfadf599b45a6a7439a1ccd200 \ No newline at end of file diff --git a/Assets/Scripts/CECGameRun.cs b/Assets/Scripts/CECGameRun.cs index 40aab69b2b..7bb0337ae1 100644 --- a/Assets/Scripts/CECGameRun.cs +++ b/Assets/Scripts/CECGameRun.cs @@ -21,7 +21,6 @@ public partial class CECGameRun : MonoBehaviour, IMsgHandler //[SerializeField] private Transform ground; CECHostPlayer hostPlayer; - public CinemachineFreeLook freeLookCam; public float rotateSpeedX = 300f; // tốc độ xoay ngang public float rotateSpeedY = 2f; // tốc độ xoay dọc private CECWorld m_pWorld; @@ -61,7 +60,6 @@ public partial class CECGameRun : MonoBehaviour, IMsgHandler EC_ManMessage.RegisterHandler(this); } - public void Log(string s) { Debug.LogError(s); @@ -160,4 +158,120 @@ public partial class CECGameRun : MonoBehaviour, IMsgHandler // freeLookCam.m_YAxis.m_MaxSpeed = 0; // } //} + + /// + /// Load necessary user configs (UI, shortcut, accelerate keys) from server + /// 从服务器加载必要的用户配置(UI、快捷键、加速键) + /// + /// Config data buffer / 配置数据缓冲区 + /// Data size / 数据大小 + /// True if loaded successfully / 加载成功返回true + public bool LoadConfigsFromServer(byte[] pDataBuf, int iDataSize) + { + const uint USERCFG_VERSION = 3; + + if (pDataBuf == null || iDataSize == 0) + { + BMLogger.LogError("CECGameRun::LoadConfigsFromServer, configs data is empty"); + return false; + } + + // TODO: Uncomment when these objects are available + // Debug.Assert(m_pWorld != null && m_pWorld.GetHostPlayer() != null && m_pUIManager.GetInGameUIMan() != null); + + int offset = 0; + + // Read version / 读取版本号 + uint dwVer = System.BitConverter.ToUInt32(pDataBuf, offset); + offset += sizeof(uint); + + if (dwVer > USERCFG_VERSION) + { + Debug.LogError($"CECGameRun::LoadConfigsFromServer, version {dwVer} > {USERCFG_VERSION}"); + return false; + } + + byte[] pUncompBuf = null; + uint dwRealLen = (uint)(iDataSize - sizeof(uint)); + byte[] pData = pDataBuf; + int dataOffset = offset; + + if (dwVer >= 3) + { + // Uncompress config data / 解压配置数据 + dwRealLen = 4096; + pUncompBuf = new byte[dwRealLen]; + + // Extract compressed data / 提取压缩数据 + byte[] compressedData = new byte[iDataSize - sizeof(uint)]; + System.Array.Copy(pDataBuf, offset, compressedData, 0, compressedData.Length); + + // TODO: Implement AFilePackage::Uncompress equivalent + int iRes = EC_Utility.UncompressData(compressedData, compressedData.Length, pUncompBuf, ref dwRealLen); + + if (iRes != 0) + { + // 解压失败,过程出错 / Decompression failed, process error + BMLogger.LogError($"CECGameRun::LoadConfigsFromServer, Failed to uncompress configs data ({iRes}:{iDataSize})"); + return false; + } + + pData = pUncompBuf; + dataOffset = 0; + } + + try + { + // Create data reader / 创建数据读取器 + CECDataReader dr = new CECDataReader(pData, dataOffset, (int)dwRealLen); + + // Load host configs / 加载主机配置 + CECHostPlayer pHost = GetHostPlayer(); + if (pHost != null) + { + int iSize = dr.ReadInt(); + byte[] hostConfigData = dr.ReadData(iSize); + if (!pHost.LoadConfigData(hostConfigData)) + { + BMLogger.LogError("CECGameRun::LoadConfigsFromServer, Failed to load host configs"); + return false; + } + } + + // TODO: Uncomment when UI manager is available + // Load UI configs / 加载UI配置 + // CECGameUIMan pGameUI = m_pUIManager.GetInGameUIMan(); + // if (pGameUI != null) + // { + // int iSize = dr.ReadInt(); + // byte[] uiConfigData = dr.ReadData(iSize); + // if (!pGameUI.SetUserLayout(uiConfigData, iSize)) + // { + // BMLogger.LogError("CECGameRun::LoadConfigsFromServer, Failed to set user layout"); + // return false; + // } + // } + + // Load user settings / 加载用户设置 + if (dwVer >= 2) + { + // TODO: Uncomment when game configs are available + // int iSize = dr.ReadInt(); + // byte[] settingsData = dr.ReadData(iSize); + // if (!g_pGame.GetConfigs().LoadUserConfigData(settingsData, iSize)) + // { + // BMLogger.LogError("CECGameRun::LoadConfigsFromServer, Failed to load user config data"); + // return false; + // } + } + } + catch (System.Exception e) + { + BMLogger.LogError($"CECGameRun::LoadConfigsFromServer, data read error: {e.Message}"); + return false; + } + + return true; + } + } diff --git a/Assets/Scripts/CECHostPlayer.Task.cs b/Assets/Scripts/CECHostPlayer.Task.cs index a4c9e519f9..631992aa39 100644 --- a/Assets/Scripts/CECHostPlayer.Task.cs +++ b/Assets/Scripts/CECHostPlayer.Task.cs @@ -4,118 +4,128 @@ using CSNetwork; using CSNetwork.GPDataType; using UnityEngine; using System.Runtime.InteropServices; +using BrewMonster.Network; -// ���׶� // Contribution info -[StructLayout(LayoutKind.Sequential, Pack = 1)] -public struct CONTRIB_INFO +namespace BrewMonster { - public int consume_contrib; // �����ѵ� // Consume contribution - public int exp_contrib; // �ɶһ����ɾ���� // Experience contribution - public int cumulate_contrib; // �ۻ�ֵ // Cumulative contribution - - // public CONTRIB_INFO() - // { - // consume_contrib = 0; - // exp_contrib = 0; - // cumulate_contrib = 0; - // } -} - -public partial class CECHostPlayer -{ - private int m_idTradePlayer; // ID of player who is trading with us - private CECTaskInterface m_pTaskInterface; - private int m_iBoothState; // Booth state. 0, none; 1, prepare; 2, open booth; 3, visite other's booth - private CONTRIB_INFO m_contribInfo; - - public CECTaskInterface GetTaskInterface() + // ���׶� // Contribution info + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct CONTRIB_INFO { - return m_pTaskInterface; + public int consume_contrib; // �����ѵ� // Consume contribution + public int exp_contrib; // �ɶһ����ɾ���� // Experience contribution + public int cumulate_contrib; // �ۻ�ֵ // Cumulative contribution + + // public CONTRIB_INFO() + // { + // consume_contrib = 0; + // exp_contrib = 0; + // cumulate_contrib = 0; + // } } - - // Is host player trading ? - public bool IsTrading() { return m_idTradePlayer != 0; } - - public CONTRIB_INFO GetContribInfo() + + public partial class CECHostPlayer { - return m_contribInfo; - } - - public int GetBoothState() - { - return m_iBoothState; - } - - private void OnMsgHstTaskData(ECMSG Msg) - { - // decode header to distinguish TASK_DATA vs TASK_VAR_DATA - // if (!(Msg.dwParam2 is cmd_header header)) - // { - // Debug.LogError("OnMsgHstTaskData: invalid header"); - // return; - // } + private int m_idTradePlayer; // ID of player who is trading with us + private CECTaskInterface m_pTaskInterface; + private int m_iBoothState; // Booth state. 0, none; 1, prepare; 2, open booth; 3, visite other's booth + private CONTRIB_INFO m_contribInfo; - int header = Convert.ToInt32(Msg.dwParam2); + public CECTaskInterface GetTaskInterface() + { + return m_pTaskInterface; + } - byte[] pDataBuf = Msg.dwParam1 as byte[]; - if (pDataBuf == null) - { - Debug.LogError("OnMsgHstTaskData: missing payload buffer"); - return; - } + // Is host player trading ? + public bool IsTrading() { return m_idTradePlayer != 0; } - if (header == CommandID.TASK_DATA) - { -#if !LOAD_TASK_TEMPL - return; // Task templates loading not implemented in C# + public CONTRIB_INFO GetContribInfo() + { + return m_contribInfo; + } + + public int GetBoothState() + { + return m_iBoothState; + } + + private void OnMsgHstTaskData(ECMSG Msg) + { + // decode header to distinguish TASK_DATA vs TASK_VAR_DATA + // if (!(Msg.dwParam2 is cmd_header header)) + // { + // Debug.LogError("OnMsgHstTaskData: invalid header"); + // return; + // } + + int header = Convert.ToInt32(Msg.dwParam2); + + byte[] pDataBuf = Msg.dwParam1 as byte[]; + if (pDataBuf == null) + { + Debug.LogError("OnMsgHstTaskData: missing payload buffer"); + return; + } + + if (header == CommandID.TASK_DATA) + { +#if LOAD_TASK_TEMPL + return; // Task templates loading not implemented in C# + + // Parse aggregated task buffers + cmd_task_data pCmd = cmd_task_data.FromBuffer(pDataBuf); + // cmd_task_data pCmd = GPDataTypeHelper.FromBytes(pDataBuf); + + // Release and recreate task interface + m_pTaskInterface = null; + m_pTaskInterface = new CECTaskInterface(this); + + if (!m_pTaskInterface.Init( + pCmd.active_list, (int)pCmd.active_list_size, + pCmd.finished_list, (int)pCmd.finished_list_size, + pCmd.finished_time_list, (int)pCmd.finished_time_list_size, + pCmd.finished_count, (int)pCmd.finished_count_size, + pCmd.storage_task, (int)pCmd.storage_task_size)) + { + Debug.LogError("CECHostPlayer::OnMsgHstTaskData, failed to initialize task interface"); + return; + } + + + m_pTaskInterface.CheckPQEnterWorldInit(); #endif - // Parse aggregated task buffers - cmd_task_data pCmd = cmd_task_data.FromBuffer(pDataBuf); - // cmd_task_data pCmd = GPDataTypeHelper.FromBytes(pDataBuf); - // Release and recreate task interface - m_pTaskInterface = null; - m_pTaskInterface = new CECTaskInterface(this); + // check if player has equipped goblin (not yet implemented in C#) + // TODO: implement goblin initialization when equipment system is ready - if (!m_pTaskInterface.Init( - pCmd.active_list, (int)pCmd.active_list_size, - pCmd.finished_list, (int)pCmd.finished_list_size, - pCmd.finished_time_list, (int)pCmd.finished_time_list_size, - pCmd.finished_count, (int)pCmd.finished_count_size, - pCmd.storage_task, (int)pCmd.storage_task_size)) - { - Debug.LogError("CECHostPlayer::OnMsgHstTaskData, failed to initialize task interface"); - return; - } + // GET_ALL_DATA end flag tasks were here in C++ (LoadConfigData), omitted in C# + UnityGameSession.LoadConfigData(); - m_pTaskInterface.CheckPQEnterWorldInit(); + // if (UpdateEquipSkills()) UpdateEquipSkillCoolDown(); // methods not ported yet + } +#if LOAD_TASK_TEMPL - // check if player has equipped goblin (not yet implemented in C#) - // TODO: implement goblin initialization when equipment system is ready + else if (header == CommandID.TASK_VAR_DATA) + { + // Minimal forwarding; original code passes inner data pointer and size + if (m_pTaskInterface != null) + { + OnServerNotify(m_pTaskInterface, pDataBuf, pDataBuf.Length); + } + else + { + Debug.LogError("OnMsgHstTaskData: m_pTaskInterface is null on TASK_VAR_DATA"); + } + } +#endif - // GET_ALL_DATA end flag tasks were here in C++ (LoadConfigData), omitted in C# + } - // if (UpdateEquipSkills()) UpdateEquipSkillCoolDown(); // methods not ported yet - } - else if (header == CommandID.TASK_VAR_DATA) - { - // Minimal forwarding; original code passes inner data pointer and size - if (m_pTaskInterface != null) - { - OnServerNotify(m_pTaskInterface, pDataBuf, pDataBuf.Length); - } - else - { - Debug.LogError("OnMsgHstTaskData: m_pTaskInterface is null on TASK_VAR_DATA"); - } - } + + private void OnServerNotify(CECTaskInterface pInterface, byte[] data, int size) + { + // TODO: Implement server notify handling for task var data + } } - - private void OnServerNotify(CECTaskInterface pInterface, byte[] data, int size) - { - // TODO: Implement server notify handling for task var data - } } - - diff --git a/Assets/Scripts/CECHostPlayer.cs b/Assets/Scripts/CECHostPlayer.cs index 04de5f20a5..f3b06c7e02 100644 --- a/Assets/Scripts/CECHostPlayer.cs +++ b/Assets/Scripts/CECHostPlayer.cs @@ -26,1149 +26,1106 @@ using TMPro; using Unity.VisualScripting; using UnityEditor.Experimental.GraphView; using UnityEngine; -using UnityEngine.InputSystem; -using UnityEngine.SceneManagement; using UnityEngine.UI; -using static Unity.Burst.Intrinsics.X86.Avx; -using static UnityEditor.PlayerSettings; -using Scene = UnityEngine.SceneManagement.Scene; using Trace_reason = CECHPWorkTrace.Trace_reason; using Host_work_ID = BrewMonster.Scripts.CECHPWork.Host_work_ID; -using BrewMonster.Scripts; -using BrewMonster.Scripts.World; -public partial class CECHostPlayer : CECPlayer +namespace BrewMonster { - [SerializeField] private CharacterController controller; - - [SerializeField] private Joystick joystick; - [SerializeField] private Button btnJump; - [SerializeField] private Button btnRun; - - private PlayerStateMachine _playerStateMachine; - private PlayerMoveState _moveState; - private PlayerIdleState _idleState; - public CECHostMove m_MoveCtrl; - - private CECHPWorkMan m_pWorkMan; // Host work manager - private uint m_dwLIES; // Logic-influence extend states - private FACTION_FORTRESS_ENTER m_fortressEnter; // ½øÈë»ùµØÐÅÏ¢ - private PVPINFO m_pvp; // pvp information - private bool m_bInSanctuary = false; // true, player is in sanctuary - private int m_idFaction = 0; // ID of player's faction - public bool m_bPrepareFight = false; // true, prepare to fight - private int m_iJumpCount = 0; - private bool m_bJumpInWater = false; - public A3DVECTOR3 m_vVelocity; // Velocity - - bool m_bChangingFace; // true, host is changing face - private int m_iRoleCreateTime; - private int m_iRoleLastLoginTime; // Role last login time - private int m_iAccountTotalCash; - - private List m_aTabSels = new List(); - private List m_aPtSkills = new List(); - private List m_aPsSkills = new List(); - private List m_aEquipSkills = new List(); - private List m_aGoblinSkills = new List(); - - private bool m_bSpellDSkill; - private bool m_bEnterGame; - public CECSkill m_pPrepSkill; - private CECSkill m_pCurSkill; - private CECCounter m_IncantCnt; - private float playerSpeed = 5.0f; - private float jumpHeight = 1.5f; - private float gravityValue = -9.81f; - private StateAnim stateAnim = StateAnim.Idle; - private Vector3 playerVelocity; - private bool isGrounded = false; - private bool isRun = false; - private Vector3 m_vLastSevPos; - public CDR_INFO m_CDRInfo; - public GNDINFO m_GndInfo; - private int m_idUCSelTarget; // Uncertificately selected object's ID - public float m_fVertSpeed = 0f; - CECActionSwitcherBase m_pActionSwitcher; - - // ====== Ground cast config ====== - [Header("Ground Cast")] - [Tooltip("Khoảng thêm ngoài skinWidth để SphereCast xuống (m ngắn)")] - [SerializeField] - private float extraGroundDistance = 1f; - - [Tooltip("Bớt bán kính một chút để tránh tự va vào capsule (epsilon)")] - [SerializeField] - private float radiusEpsilon = 0.005f; - - [Tooltip("Layer mặt đất")] - [SerializeField] - private LayerMask groundMask = 1 << 6; - - [Tooltip("Layer mặt đất")] - [SerializeField] - private float slopeToleranceDeg = 2f; - - // cache tùy chọn (không bắt buộc) - float ccRadius, ccSkin; - RaycastHit lastGroundHit; - Camera mainCam; - - private BaseVfxObject m_pSelectedGFX; - private BaseVfxObject m_pHoverGFX; - - // Cursor estimation optimization - private Vector2 m_lastMousePosition; - private float m_cursorUpdateTimer; - private const float CURSOR_UPDATE_INTERVAL = 0.05f; // 20 times per second instead of 60+ - private UnityEngine.InputSystem.Mouse m_cachedMouse; - private UnityEngine.InputSystem.Keyboard m_cachedKeyboard; - - public bool IsChangingFace() { return m_bChangingFace; } - - private void Awake() + public partial class CECHostPlayer : CECPlayer { - base.Awake(); - _moveState = new PlayerMoveState(this); - _idleState = new PlayerIdleState(this); - _playerStateMachine = new PlayerStateMachine(); - m_MoveCtrl = new CECHostMove(this); + [SerializeField] private CharacterController controller; - // Cache: không bắt buộc, nhưng gọn tay và ít gọi property lặp. - if (controller != null) + [SerializeField] private Joystick joystick; + [SerializeField] private Button btnJump; + [SerializeField] private Button btnRun; + + private PlayerStateMachine _playerStateMachine; + private PlayerMoveState _moveState; + private PlayerIdleState _idleState; + public CECHostMove m_MoveCtrl; + + private CECHPWorkMan m_pWorkMan; // Host work manager + private uint m_dwLIES; // Logic-influence extend states + private FACTION_FORTRESS_ENTER m_fortressEnter; // ½øÈë»ùµØÐÅÏ¢ + private PVPINFO m_pvp; // pvp information + private bool m_bInSanctuary = false; // true, player is in sanctuary + private int m_idFaction = 0; // ID of player's faction + public bool m_bPrepareFight = false; // true, prepare to fight + private int m_iJumpCount = 0; + private bool m_bJumpInWater = false; + public A3DVECTOR3 m_vVelocity; // Velocity + // Shortcut sets (converted from C++: m_aSCSets1[NUM_HOSTSCSETS1], m_aSCSets2[NUM_HOSTSCSETS2]) + public CECShortcutSet[] m_aSCSets1 = new CECShortcutSet[HostCfgConstants.NUM_HOSTSCSETS1]; // SC set 1 + public CECShortcutSet[] m_aSCSets2 = new CECShortcutSet[HostCfgConstants.NUM_HOSTSCSETS2]; // SC set 2 + bool m_bChangingFace; // true, host is changing face + private int m_iRoleCreateTime; + private int m_iRoleLastLoginTime; // Role last login time + private int m_iAccountTotalCash; + + private List m_aTabSels = new List(); + private List m_aPtSkills = new List(); + private List m_aPsSkills = new List(); + private List m_aEquipSkills = new List(); + private List m_aGoblinSkills = new List(); + + private bool m_bSpellDSkill; + private bool m_bEnterGame; + public CECSkill m_pPrepSkill; + private CECSkill m_pCurSkill; + private CECCounter m_IncantCnt; + private float playerSpeed = 5.0f; + private float jumpHeight = 1.5f; + private float gravityValue = -9.81f; + private StateAnim stateAnim = StateAnim.Idle; + private Vector3 playerVelocity; + private bool isGrounded = false; + private bool isRun = false; + private Vector3 m_vLastSevPos; + public CDR_INFO m_CDRInfo; + public GNDINFO m_GndInfo; + private int m_idUCSelTarget; // Uncertificately selected object's ID + public float m_fVertSpeed = 0f; + CECActionSwitcherBase m_pActionSwitcher; + + // ====== Ground cast config ====== + [Header("Ground Cast")] + [Tooltip("Khoảng thêm ngoài skinWidth để SphereCast xuống (m ngắn)")] + [SerializeField] + private float extraGroundDistance = 1f; + + [Tooltip("Bớt bán kính một chút để tránh tự va vào capsule (epsilon)")] + [SerializeField] + private float radiusEpsilon = 0.005f; + + [Tooltip("Layer mặt đất")] + [SerializeField] + private LayerMask groundMask = 1 << 6; + + [Tooltip("Layer mặt đất")] + [SerializeField] + private float slopeToleranceDeg = 2f; + + // cache tùy chọn (không bắt buộc) + float ccRadius, ccSkin; + RaycastHit lastGroundHit; + Camera mainCam; + + private BaseVfxObject m_pSelectedGFX; + private BaseVfxObject m_pHoverGFX; + + // Cursor estimation optimization + private Vector2 m_lastMousePosition; + private float m_cursorUpdateTimer; + private const float CURSOR_UPDATE_INTERVAL = 0.05f; // 20 times per second instead of 60+ + private UnityEngine.InputSystem.Mouse m_cachedMouse; + private UnityEngine.InputSystem.Keyboard m_cachedKeyboard; + + public bool IsChangingFace() { return m_bChangingFace; } + + // Host config constants (mirrors native values used in EC_HostPlayer.cpp/EC_IvtrTypes.h) + private static class HostCfgConstants { - ccRadius = controller.radius; - ccSkin = controller.skinWidth; - } - } - - public bool LoadResources() - { - RoleInfo RoleInfo = UnityGameSession.Instance.GetRoleInfo(); - m_iProfession = RoleInfo.occupation; - m_iGender = RoleInfo.gender; - - m_iRoleCreateTime = RoleInfo.create_time; - m_iRoleLastLoginTime = RoleInfo.lastlogin_time; - m_iAccountTotalCash = RoleInfo.cash_add; - - if (!LoadPlayerSkeleton(true)) - { - BMLogger.LogError("HoangDev CECHostPlayer::LoadResources, Failed to load skeleton"); - return false; - } - return true; - } - - private bool LoadPlayerSkeleton(bool bAtOnce) - { - EC_PLAYERLOADRESULT Ret = default; - if (bAtOnce /*|| !IsLoadThreadReady()*/) - { - // Under normal circumstances, only HostPlayer can reach here - /* if (!LoadPlayerModel(m_iProfession, m_iGender, m_CustomizeData.bodyID, aEquips, szPetPath, Ret, false, false)) - { - a_LogOutput(1, "CECPlayer::Init, failed to call LoadPlayerModel() !"); - return false; - }*/ - - SetPlayerLoadedResult(Ret); - - /* if (IsShapeChanged() && !QueueLoadDummyModel(m_iShape, true)) - { - // ignore the dummy model loading failure - a_LogOutput(1, "CECPlayer::Init, failed to call QueueLoadDummyModel() !"); - }*/ - } - return true; - } - - private bool SetPlayerLoadedResult(EC_PLAYERLOADRESULT ret) - { - OnAllResourceReady(); - return true; - } - - private void OnAllResourceReady() - { - CECHostSkillModel.Instance.Initialize(); - } - - private void Start() - { - mainCam = Camera.main; - if (mainCam == null) - { - mainCam = FindFirstObjectByType(); + public const int HOSTCFG_VERSION = 11; + public const int NUM_HOSTSCSETS1 = 5; // expanded from 3 to 5 (2009.05.27) + public const int NUM_HOSTSCSETS2 = 3; + public const int SIZE_HOSTSCSET1 = 9; // expanded from 6 to 9 (2009.05.27) + public const int SIZE_HOSTSCSET2 = 8; } - _playerStateMachine.InitState(_idleState); - // btnJump.onClick.AddListener(HandleJump); - - // Cache input devices for better performance - m_cachedMouse = UnityEngine.InputSystem.Mouse.current; - m_cachedKeyboard = UnityEngine.InputSystem.Keyboard.current; - } - - protected override void Update() - { - base.Update(); -#if UNITY_EDITOR - if (Input.GetKeyDown(KeyCode.C)) + private void Awake() { - ApplySkillShortcut(1); - } -#endif - - //Debug.Log($"(ulong)Time.deltaTime * 1000 {(ulong)(Time.deltaTime * 1000)}"); - m_MoveCtrl.Tick((ulong)(Time.deltaTime * 1000)); - // Nếu có thay đổi runtime, có thể lấy lại mỗi vài giây/Start nếu bạn thích: - // ccRadius = controller.radius; ccSkin = controller.skinWidth; + base.Awake(); + _moveState = new PlayerMoveState(this); + _idleState = new PlayerIdleState(this); + _playerStateMachine = new PlayerStateMachine(); + m_MoveCtrl = new CECHostMove(this); - _playerStateMachine.UpdateState(); - if (Input.GetMouseButtonDown(0) && mainCam != null) - { - int idTraceTarget = 0, idSelTarget = 0; - bool bForceAttack = false; - int iTraceReason = CECHPWorkTrace.Trace_reason.TRACE_NONE; - bool bWikiMonster = false; - - Ray ray = mainCam.ScreenPointToRay(Input.mousePosition); - RaycastHit hit; - - if (Physics.Raycast(ray, out hit)) + // Cache: không bắt buộc, nhưng gọn tay và ít gọi property lặp. + if (controller != null) { - CECObject clickedObject = hit.collider.gameObject.GetComponent(); + ccRadius = controller.radius; + ccSkin = controller.skinWidth; + } + } - if (clickedObject != null) + public bool LoadResources() + { + RoleInfo RoleInfo = UnityGameSession.Instance.GetRoleInfo(); + m_iProfession = RoleInfo.occupation; + m_iGender = RoleInfo.gender; + + m_iRoleCreateTime = RoleInfo.create_time; + m_iRoleLastLoginTime = RoleInfo.lastlogin_time; + m_iAccountTotalCash = RoleInfo.cash_add; + + if (!LoadPlayerSkeleton(true)) + { + BMLogger.LogError("HoangDev CECHostPlayer::LoadResources, Failed to load skeleton"); + return false; + } + return true; + } + + private bool LoadPlayerSkeleton(bool bAtOnce) + { + EC_PLAYERLOADRESULT Ret = default; + if (bAtOnce /*|| !IsLoadThreadReady()*/) + { + // Under normal circumstances, only HostPlayer can reach here + /* if (!LoadPlayerModel(m_iProfession, m_iGender, m_CustomizeData.bodyID, aEquips, szPetPath, Ret, false, false)) + { + a_LogOutput(1, "CECPlayer::Init, failed to call LoadPlayerModel() !"); + return false; + }*/ + + SetPlayerLoadedResult(Ret); + + /* if (IsShapeChanged() && !QueueLoadDummyModel(m_iShape, true)) + { + // ignore the dummy model loading failure + a_LogOutput(1, "CECPlayer::Init, failed to call QueueLoadDummyModel() !"); + }*/ + } + return true; + } + + private bool SetPlayerLoadedResult(EC_PLAYERLOADRESULT ret) + { + OnAllResourceReady(); + return true; + } + + private void OnAllResourceReady() + { + CECHostSkillModel.Instance.Initialize(); + } + + private void Start() + { + mainCam = Camera.main; + if (mainCam == null) + { + mainCam = FindFirstObjectByType(); + } + + _playerStateMachine.InitState(_idleState); + // btnJump.onClick.AddListener(HandleJump); + + // Cache input devices for better performance + m_cachedMouse = UnityEngine.InputSystem.Mouse.current; + m_cachedKeyboard = UnityEngine.InputSystem.Keyboard.current; + } + + protected override void Update() + { + base.Update(); +#if UNITY_EDITOR + if (Input.GetKeyDown(KeyCode.C)) + { + ApplySkillShortcut(1); + } +#endif + + //Debug.Log($"(ulong)Time.deltaTime * 1000 {(ulong)(Time.deltaTime * 1000)}"); + m_MoveCtrl.Tick((ulong)(Time.deltaTime * 1000)); + // Nếu có thay đổi runtime, có thể lấy lại mỗi vài giây/Start nếu bạn thích: + // ccRadius = controller.radius; ccSkin = controller.skinWidth; + + _playerStateMachine.UpdateState(); + if (Input.GetMouseButtonDown(0) && mainCam != null) + { + int idTraceTarget = 0, idSelTarget = 0; + bool bForceAttack = false; + int iTraceReason = CECHPWorkTrace.Trace_reason.TRACE_NONE; + bool bWikiMonster = false; + + Ray ray = mainCam.ScreenPointToRay(Input.mousePosition); + RaycastHit hit; + + if (Physics.Raycast(ray, out hit)) { - int idObject = CECObject.GetObjectID(clickedObject); - if (idObject != 0) - { - CECNPC pNPC = EC_ManMessageMono.Instance._CECNPCMan.GetNPC(idObject); - if (pNPC != null) - { - if (!pNPC.IsDead() /* && m_idSelTarget == idObject*/) - { - idTraceTarget = idObject; - idSelTarget = idObject; - } + CECObject clickedObject = hit.collider.gameObject.GetComponent(); - if (idTraceTarget != 0) + if (clickedObject != null) + { + int idObject = CECObject.GetObjectID(clickedObject); + if (idObject != 0) + { + CECNPC pNPC = EC_ManMessageMono.Instance._CECNPCMan.GetNPC(idObject); + if (pNPC != null) { - if (AttackableJudge(idObject, bForceAttack) == 1) - iTraceReason = CECHPWorkTrace.Trace_reason.TRACE_ATTACK; - else if (pNPC.IsServerNPC()) + if (!pNPC.IsDead() /* && m_idSelTarget == idObject*/) { - if (!IsInBattle() || InSameBattleCamp(pNPC)) - iTraceReason = CECHPWorkTrace.Trace_reason.TRACE_TALK; + idTraceTarget = idObject; + idSelTarget = idObject; + } + + if (idTraceTarget != 0) + { + if (AttackableJudge(idObject, bForceAttack) == 1) + iTraceReason = CECHPWorkTrace.Trace_reason.TRACE_ATTACK; + else if (pNPC.IsServerNPC()) + { + if (!IsInBattle() || InSameBattleCamp(pNPC)) + iTraceReason = CECHPWorkTrace.Trace_reason.TRACE_TALK; + } } } } } } - } - // Tell server we select a target - if (idSelTarget != 0 && m_idSelTarget != idSelTarget) + // Tell server we select a target + if (idSelTarget != 0 && m_idSelTarget != idSelTarget) + { + m_idUCSelTarget = idSelTarget; + SelectTarget(m_idUCSelTarget); + } + + if (idTraceTarget != 0) + { + if (iTraceReason == CECHPWorkTrace.Trace_reason.TRACE_ATTACK) + { + if (!CanDo(ActionCanDo.CANDO_MELEE)) + return; + NormalAttackObject(idTraceTarget, bForceAttack); + } + } + } + m_pWorkMan?.Tick(Time.deltaTime); + + // Update cursor based on what's under mouse + EstimateCursor(); + + // Update GFXs + UpdateGFXs(Time.deltaTime); + } + + public void StopMovement() + { + m_MoveCtrl.SendStopMoveCmd(transform.position, 5f, (int)GPMoveMode.GP_MOVE_WALK); + } + + public void HandleMovement() + { + // 1) Kiểm tra grounded bằng SphereCast ngắn dựa trên radius + skinWidth + isGrounded = GroundCheck(out lastGroundHit); + m_GndInfo.bOnGround = isGrounded; + // 2) Input tạm thời: giữ nguyên như bạn + if (UnityEngine.Input.GetKeyDown(KeyCode.LeftShift)) SetStatusRun(true); + if (UnityEngine.Input.GetKeyUp(KeyCode.LeftShift)) SetStatusRun(false); + if (UnityEngine.Input.GetKeyDown(KeyCode.Space)) HandleJump(); + + // 3) Trọng lực / sticky + if (isGrounded && playerVelocity.y < 0f) { - m_idUCSelTarget = idSelTarget; - SelectTarget(m_idUCSelTarget); + // Đè nhẹ để bám đất (tránh nhấp-nháy) + playerVelocity.y = -2f; } - - if (idTraceTarget != 0) + else + { + playerVelocity.y += gravityValue * Time.deltaTime; + } + + // 4) Chuyển động phẳng + float x = joystick.Horizontal; + float z = joystick.Vertical; + + Vector3 move = new Vector3(x, 0, z); + move = Vector3.ClampMagnitude(move, 1f); + if (move != Vector3.zero) + { + Vector3 finalMove = (move * playerSpeed) + (playerVelocity.y * Vector3.up); + controller.Move(finalMove * Time.deltaTime); + transform.forward = move; + m_MoveCtrl.GroundMove(Time.deltaTime); + m_MoveCtrl.SendMoveCmd(transform.position, controller.velocity, (int)GPMoveMode.GP_MOVE_RUN); + m_aabb.Center = EC_Utility.ToA3DVECTOR3(transform.position) + new A3DVECTOR3(0.0f, m_aabb.Extents.y, 0.0f); + m_aabb.CompleteMinsMaxs(); + m_aabbServer.Center = EC_Utility.ToA3DVECTOR3(transform.position) + new A3DVECTOR3(0.0f, m_aabbServer.Extents.y, 0.0f); + m_aabbServer.CompleteMinsMaxs(); + } + else { - if (iTraceReason == CECHPWorkTrace.Trace_reason.TRACE_ATTACK) - { - if (!CanDo(ActionCanDo.CANDO_MELEE)) - return; - NormalAttackObject(idTraceTarget, bForceAttack); - } } } - m_pWorkMan?.Tick(Time.deltaTime); - - // Update cursor based on what's under mouse - EstimateCursor(); - - // Update GFXs - UpdateGFXs(Time.deltaTime); - } - public void StopMovement() - { - m_MoveCtrl.SendStopMoveCmd(transform.position, 5f, (int)GPMoveMode.GP_MOVE_WALK); - } - - public void HandleMovement() - { - // 1) Kiểm tra grounded bằng SphereCast ngắn dựa trên radius + skinWidth - isGrounded = GroundCheck(out lastGroundHit); - m_GndInfo.bOnGround = isGrounded; - // 2) Input tạm thời: giữ nguyên như bạn - if (UnityEngine.Input.GetKeyDown(KeyCode.LeftShift)) SetStatusRun(true); - if (UnityEngine.Input.GetKeyUp(KeyCode.LeftShift)) SetStatusRun(false); - if (UnityEngine.Input.GetKeyDown(KeyCode.Space)) HandleJump(); - - // 3) Trọng lực / sticky - if (isGrounded && playerVelocity.y < 0f) + private void JoystickRelease(JoystickRealeaseEvent joystickRealeaseEvent) { - // Đè nhẹ để bám đất (tránh nhấp-nháy) - playerVelocity.y = -2f; - } - else - { - playerVelocity.y += gravityValue * Time.deltaTime; + _playerStateMachine.ChangeState(_idleState); } - // 4) Chuyển động phẳng - float x = joystick.Horizontal; - float z = joystick.Vertical; - - Vector3 move = new Vector3(x, 0, z); - move = Vector3.ClampMagnitude(move, 1f); - if (move != Vector3.zero) + public bool GroundCheck(out RaycastHit hit) { - Vector3 finalMove = (move * playerSpeed) + (playerVelocity.y * Vector3.up); - controller.Move(finalMove * Time.deltaTime); - transform.forward = move; - m_MoveCtrl.GroundMove(Time.deltaTime); - m_MoveCtrl.SendMoveCmd(transform.position, controller.velocity, (int)GPMoveMode.GP_MOVE_RUN); - m_aabb.Center = EC_Utility.ToA3DVECTOR3(transform.position) + new A3DVECTOR3(0.0f, m_aabb.Extents.y, 0.0f); - m_aabb.CompleteMinsMaxs(); - m_aabbServer.Center = EC_Utility.ToA3DVECTOR3(transform.position) + new A3DVECTOR3(0.0f, m_aabbServer.Extents.y, 0.0f); - m_aabbServer.CompleteMinsMaxs(); + float radius = controller.radius; + float skin = controller.skinWidth; + float height = controller.height; + + // Tâm capsule theo world + Vector3 cWorld = transform.TransformPoint(controller.center); + float hemi = Mathf.Max(0f, (height * 0.5f) - radius); + + // Hai điểm top/bottom của capsule nhân vật (đang đứng) + Vector3 pTop = cWorld + Vector3.up * hemi; + Vector3 pBottom = cWorld - Vector3.up * hemi; + + // Ta tạo một "đoạn capsule ngắn" gần đáy để sweep xuống + // Nhấc đoạn bắt đầu lên 1 chút để không bắt đầu trong trạng thái giao nhau + Vector3 startBottom = pBottom + Vector3.up * (skin + 0.01f); + Vector3 startTop = startBottom + Vector3.up * (radius * 2f - 0.02f); // chiều cao đoạn ngắn ~2*radius + + float castRadius = Mathf.Max(0f, radius - radiusEpsilon); + float castDistance = skin + extraGroundDistance; // quãng sweep ngắn + + bool hitSomething = Physics.CapsuleCast( + startTop, startBottom, castRadius, + Vector3.down, out hit, castDistance, + groundMask, QueryTriggerInteraction.Ignore + ); + + if (!hitSomething) return false; + + // Lọc theo slope limit + float maxSlope = controller.slopeLimit + slopeToleranceDeg; + float slope = Vector3.Angle(hit.normal, Vector3.up); + if (slope > maxSlope) return false; + + return true; } - else + + private void HandleJump() { + if (isGrounded) + { + playerVelocity.y = Mathf.Sqrt(jumpHeight * -2f * gravityValue); + } } - } - private void JoystickRelease(JoystickRealeaseEvent joystickRealeaseEvent) - { - _playerStateMachine.ChangeState(_idleState); - } - - public bool GroundCheck(out RaycastHit hit) - { - float radius = controller.radius; - float skin = controller.skinWidth; - float height = controller.height; - - // Tâm capsule theo world - Vector3 cWorld = transform.TransformPoint(controller.center); - float hemi = Mathf.Max(0f, (height * 0.5f) - radius); - - // Hai điểm top/bottom của capsule nhân vật (đang đứng) - Vector3 pTop = cWorld + Vector3.up * hemi; - Vector3 pBottom = cWorld - Vector3.up * hemi; - - // Ta tạo một "đoạn capsule ngắn" gần đáy để sweep xuống - // Nhấc đoạn bắt đầu lên 1 chút để không bắt đầu trong trạng thái giao nhau - Vector3 startBottom = pBottom + Vector3.up * (skin + 0.01f); - Vector3 startTop = startBottom + Vector3.up * (radius * 2f - 0.02f); // chiều cao đoạn ngắn ~2*radius - - float castRadius = Mathf.Max(0f, radius - radiusEpsilon); - float castDistance = skin + extraGroundDistance; // quãng sweep ngắn - - bool hitSomething = Physics.CapsuleCast( - startTop, startBottom, castRadius, - Vector3.down, out hit, castDistance, - groundMask, QueryTriggerInteraction.Ignore - ); - - if (!hitSomething) return false; - - // Lọc theo slope limit - float maxSlope = controller.slopeLimit + slopeToleranceDeg; - float slope = Vector3.Angle(hit.normal, Vector3.up); - if (slope > maxSlope) return false; - - return true; - } - - private void HandleJump() - { - if (isGrounded) + public void ProcessMessage(in ECMSG Msg) { - playerVelocity.y = Mathf.Sqrt(jumpHeight * -2f * gravityValue); - } - } - - public void ProcessMessage(in ECMSG Msg) - { - var msg = (int)Msg.dwMsg; - //Debug.LogError("HoangDev : ProcessMessageProcessMessageProcessMessage " + msg); - switch (msg) - { - case int value when value == EC_MsgDef.MSG_HST_CORRECTPOS: OnMsgHstCorrectPos(Msg); break; - case int value when value == EC_MsgDef.MSG_HST_GOTO: OnMsgHstGoto(Msg); break; - case int value when value == EC_MsgDef.MSG_HST_IVTRINFO: - { - OnMsgHstIvtrInfo(Msg); - break; - } - case int value when value == EC_MsgDef.MSG_HST_OWNITEMINFO: - { - OnMsgHstOwnItemInfo(Msg); - break; - } - case int value when value == EC_MsgDef.MSG_HST_TASKDATA: - { - OnMsgHstTaskData(Msg); - //Debug.LogError("[Dat]- OnMsgHstTaskData"); - break; - } - case int value when value == EC_MsgDef.MSG_HST_ITEMOPERATION: - OnMsgHstItemOperation(Msg); - break; - case int value when value == EC_MsgDef.MSG_HST_PICKUPITEM: - OnMsgHstPickupItem(Msg); - break; - case int value when value == EC_MsgDef.MSG_HST_SELTARGET: - OnMsgHstSelTarget(Msg); break; - case int value when value == EC_MsgDef.MSG_HST_ATKRESULT: OnMsgHstAttackResult(Msg); break; - case int value when value == EC_MsgDef.MSG_HST_ATTACKED: OnMsgHstAttacked(Msg); break; - case int value when value == EC_MsgDef.MSG_HST_HURTRESULT: OnMsgHstHurtResult(Msg); break; - case int value when value == EC_MsgDef.MSG_HST_INFO00: OnMsgHstInfo00(Msg); break; - 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_PM_CASTSKILL: OnMsgPlayerCastSkill(Msg); break; - } - } - - private void OnMsgPlayerCastSkill(ECMSG Msg) - { - // using namespace S2C; - bool bDoOtherThing = false; - int idTarget = 0; - - bool bActionStartSkill = false; - int iActionTime = 1000; - //CECPlayerWrapper pWrapper = CECAutoPolicy.GetInstance().GetPlayerWrapper(); - switch (Convert.ToInt32(Msg.dwParam2)) - { - case CommandID.OBJECT_CAST_SKILL: - { - var pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - - if (m_pCurSkill != null) + var msg = (int)Msg.dwMsg; + //Debug.LogError("HoangDev : ProcessMessageProcessMessageProcessMessage " + msg); + switch (msg) + { + case int value when value == EC_MsgDef.MSG_HST_CORRECTPOS: OnMsgHstCorrectPos(Msg); break; + case int value when value == EC_MsgDef.MSG_HST_GOTO: OnMsgHstGoto(Msg); break; + case int value when value == EC_MsgDef.MSG_HST_IVTRINFO: { - m_pCurSkill.EndCharging(); - } - - m_pCurSkill = GetPositiveSkillByID(pCmd.skill); - if (m_pCurSkill == null) m_pCurSkill = GetEquipSkillByID(pCmd.skill); - if (m_pCurSkill == null) m_pCurSkill = CECComboSkillState.Instance.GetInherentSkillByID((uint)pCmd.skill); - if (m_pCurSkill == null) - { - System.Diagnostics.Debug.Assert(m_pCurSkill != null); - return; - } - - if (m_pCurSkill.IsChargeable()) - m_pCurSkill.StartCharging(pCmd.time); - - int iWaitTime = -1; - if (m_pCurSkill.GetExecuteTime() >= 0) - iWaitTime = pCmd.time + m_pCurSkill.GetExecuteTime(); - - var pWork = (CECHPWorkSpell)m_pWorkMan.CreateWork(CECHPWork.Host_work_ID.WORK_SPELLOBJECT); - pWork.PrepareCast(pCmd.target, m_pCurSkill, iWaitTime); - m_pWorkMan.StartWork_p1(pWork); - - if (!m_pCurSkill.IsChargeable()) - { - int iTime = pCmd.time; - iTime = Math.Max(iTime, 10); - m_IncantCnt.SetPeriod(iTime); - m_IncantCnt.Reset(); - } - else - { - m_IncantCnt.Reset(true); - } - - m_bSpellDSkill = false; - - TurnFaceTo(pCmd.target); - - m_idCurSkillTarget = pCmd.target; - PlaySkillCastAction(m_pCurSkill.GetSkillID()); - - bActionStartSkill = true; - iActionTime = iWaitTime; - break; - } - - /* case CommandID.SKILL_PERFORM: - { - m_pPrepSkill = null; - - if (m_pCurSkill != null && m_pCurSkill.IsDurative()) - m_bSpellDSkill = true; - - break; - } - - case CommandID.HOST_STOP_SKILL: - { - m_pPrepSkill = null; - - CECSkill pSkillToMatch = m_pCurSkill; - if (m_pCurSkill != null) - { - ClearComActFlagAllRankNodes(true); - - if (((m_pComboSkill != null && !m_pComboSkill.IsStop()) || - m_pCurSkill.ChangeToMelee()) && !m_pWorkMan.HasDelayedWork()) - { - bDoOtherThing = true; - idTarget = m_idCurSkillTarget; - } - - m_pCurSkill.EndCharging(); - m_pCurSkill = null; - } - - AP_ActionEvent(AP_EVENT_STOPSKILL); - - if (pSkillToMatch != null) - { - m_pWorkMan.FinishWork(new CECHPWorkSpellMatcher(pSkillToMatch)); - } - StopSkillAttackAction(); - - m_idCurSkillTarget = 0; - break; - } - - case CommandID.SELF_SKILL_INTERRUPTED: - { - int skill_id = 0; - m_pPrepSkill = null; - - CECSkill pSkillToMatch = m_pCurSkill; - if (m_pCurSkill != null) - { - skill_id = m_pCurSkill.GetSkillID(); - - ClearComActFlagAllRankNodes(false); - - if (((m_pComboSkill != null && !m_pComboSkill.IsStop()) || - m_pCurSkill.ChangeToMelee()) && !m_pWorkMan.HasDelayedWork()) - { - bDoOtherThing = true; - idTarget = m_idCurSkillTarget; - } - - m_pCurSkill.EndCharging(); - m_pCurSkill = null; - } - - m_idCurSkillTarget = 0; - - if (pSkillToMatch != null) - { - m_pWorkMan.FinishWork(new CECHPWorkSpellMatcher(pSkillToMatch)); - } - StopSkillCastAction(); - - g_pGame.GetGameRun().AddFixedMessage(FIXMSG_SKILLINTERRUPT); - - AP_ActionEvent(AP_EVENT_STOPSKILL); - - CECAutoPolicy.GetInstance().SendEvent_SkillInterrupt(skill_id); - break; - } - - case CommandID.OBJECT_CAST_INSTANT_SKILL: - { - var pCmd = (S2C.cmd_object_cast_instant_skill)Msg.Param1; - System.Diagnostics.Debug.Assert(pCmd.caster == m_PlayerInfo.cid); - - CECSkill pSkill = GetPositiveSkillByID(pCmd.skill); - if (pSkill == null) pSkill = GetEquipSkillByID(pCmd.skill); - if (pSkill == null) - { - System.Diagnostics.Debug.Assert(pSkill != null); - return; - } - - if (pCmd.target != 0 && pCmd.target != m_PlayerInfo.cid) - TurnFaceTo(pCmd.target); - - PlaySkillCastAction(pSkill.GetSkillID()); - bActionStartSkill = true; - break; - } - - case CommandID.OBJECT_CAST_POS_SKILL: - { - var pCmd = (S2C.cmd_object_cast_pos_skill)Msg.Param1; - System.Diagnostics.Debug.Assert(pCmd.caster == m_PlayerInfo.cid); - - CECSkill pSkill = GetNormalSkill(pCmd.skill); - if (pSkill == null) pSkill = GetEquipSkillByID(pCmd.skill); - if (pSkill == null) - { - System.Diagnostics.Debug.Assert(pSkill != null); + OnMsgHstIvtrInfo(Msg); break; } - - TurnFaceTo(pCmd.target); - - if (pSkill.GetRangeType() != CECSkill.RangeType.RANGE_SLEF && - pSkill.GetRangeType() != CECSkill.RangeType.RANGE_SELFSPHERE && - (pSkill.GetSkillID() == 1095 || - pSkill.GetSkillID() == 1278 || - pSkill.GetSkillID() == 1279 || - pSkill.GetSkillID() == 2313)) + case int value when value == EC_MsgDef.MSG_HST_OWNITEMINFO: { - // Teleport-style placement - A3DVECTOR3 vPos = pCmd.pos; - if (!IsPosCollideFree(vPos)) + OnMsgHstOwnItemInfo(Msg); + break; + } + case int value when value == EC_MsgDef.MSG_HST_TASKDATA: + { + OnMsgHstTaskData(Msg); + //Debug.LogError("[Dat]- OnMsgHstTaskData"); + break; + } + case int value when value == EC_MsgDef.MSG_HST_ITEMOPERATION: + OnMsgHstItemOperation(Msg); + break; + case int value when value == EC_MsgDef.MSG_HST_PICKUPITEM: + OnMsgHstPickupItem(Msg); + break; + case int value when value == EC_MsgDef.MSG_HST_SELTARGET: + OnMsgHstSelTarget(Msg); break; + case int value when value == EC_MsgDef.MSG_HST_ATKRESULT: OnMsgHstAttackResult(Msg); break; + case int value when value == EC_MsgDef.MSG_HST_ATTACKED: OnMsgHstAttacked(Msg); break; + case int value when value == EC_MsgDef.MSG_HST_HURTRESULT: OnMsgHstHurtResult(Msg); break; + case int value when value == EC_MsgDef.MSG_HST_INFO00: OnMsgHstInfo00(Msg); break; + 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_PM_CASTSKILL: OnMsgPlayerCastSkill(Msg); break; + } + } + + private void OnMsgPlayerCastSkill(ECMSG Msg) + { + // using namespace S2C; + bool bDoOtherThing = false; + int idTarget = 0; + + bool bActionStartSkill = false; + int iActionTime = 1000; + //CECPlayerWrapper pWrapper = CECAutoPolicy.GetInstance().GetPlayerWrapper(); + switch (Convert.ToInt32(Msg.dwParam2)) + { + case CommandID.OBJECT_CAST_SKILL: + { + var pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + + if (m_pCurSkill != null) { - vPos += g_vAxisY * 0.1f; + m_pCurSkill.EndCharging(); } - A3DVECTOR3 vNormal; - float vTerrainHeight = g_pGame.GetGameRun().GetWorld().GetTerrainHeight(vPos, out vNormal); - if (vPos.y < vTerrainHeight) - vPos.y = vTerrainHeight; - - SetPos(vPos); - - m_CDRInfo.vTPNormal = (vPos.y <= vTerrainHeight + 0.1f) ? vNormal : g_vOrigin; - m_CDRInfo.fYVel = 0.0f; - m_CDRInfo.vAbsVelocity.Clear(); - ResetJump(); - - m_MoveCtrl.SetHostLastPos(vPos); - m_MoveCtrl.SetLastSevPos(vPos); - - UpdateFollowCamera(false, 10); - } - else - { - var pWork = (CECHPWorkFMove)m_pWorkMan.CreateWork(CECHPWork.WORK_FLASHMOVE); - - int nExecuteTime = pSkill.GetExecuteTime(); - nExecuteTime = Math.Max(nExecuteTime, 50); - - if (pSkill.GetSkillID() == 1145 || - pSkill.GetSkillID() == 1314 || - pSkill.GetSkillID() == 1315 || - pSkill.GetSkillID() == 1362 || - pSkill.GetSkillID() == 1690 || - pSkill.GetSkillID() == 1691 || - pSkill.GetSkillID() == 1845 || - pSkill.GetSkillID() == 1844 || - pSkill.GetSkillID() == 1815 || - pSkill.GetSkillID() == 2272 || - pSkill.GetSkillID() == 2315 || - pSkill.GetSkillID() == 2285 || - pSkill.GetSkillID() == 2340 || - pSkill.GetSkillID() == 2341 || - pSkill.GetSkillID() == 2342 || - pSkill.GetSkillID() == 2553 || - pSkill.GetSkillID() == 2740 || - pSkill.GetSkillID() == 2741 || - pSkill.GetSkillID() == 2559 || - pSkill.GetSkillID() == 2752 || - pSkill.GetSkillID() == 2753) + m_pCurSkill = GetPositiveSkillByID(pCmd.skill); + if (m_pCurSkill == null) m_pCurSkill = GetEquipSkillByID(pCmd.skill); + if (m_pCurSkill == null) m_pCurSkill = CECComboSkillState.Instance.GetInherentSkillByID((uint)pCmd.skill); + if (m_pCurSkill == null) { - A3DVECTOR3 vPos = pCmd.pos; - if (!IsPosCollideFree(vPos)) - { - vPos += g_vAxisY * 0.1f; - } + System.Diagnostics.Debug.Assert(m_pCurSkill != null); + return; + } - A3DVECTOR3 vNormal; - float vTerrainHeight = g_pGame.GetGameRun().GetWorld().GetTerrainHeight(vPos, out vNormal); - if (vPos.y < vTerrainHeight) - vPos.y = vTerrainHeight; + if (m_pCurSkill.IsChargeable()) + m_pCurSkill.StartCharging(pCmd.time); - m_CDRInfo.vTPNormal = (vPos.y <= vTerrainHeight + 0.1f) ? vNormal : g_vOrigin; - m_CDRInfo.fYVel = 0.0f; - m_CDRInfo.vAbsVelocity.Clear(); - ResetJump(); + int iWaitTime = -1; + if (m_pCurSkill.GetExecuteTime() >= 0) + iWaitTime = pCmd.time + m_pCurSkill.GetExecuteTime(); - pWork.PrepareMove(pCmd.pos, nExecuteTime * 0.001f, pSkill.GetSkillID()); + var pWork = (CECHPWorkSpell)m_pWorkMan.CreateWork(CECHPWork.Host_work_ID.WORK_SPELLOBJECT); + pWork.PrepareCast(pCmd.target, m_pCurSkill, iWaitTime); + m_pWorkMan.StartWork_p1(pWork); + + if (!m_pCurSkill.IsChargeable()) + { + int iTime = pCmd.time; + iTime = Math.Max(iTime, 10); + m_IncantCnt.SetPeriod(iTime); + m_IncantCnt.Reset(); } else { - if (pSkill.GetRangeType() == CECSkill.RangeType.RANGE_SLEF || - pSkill.GetRangeType() == CECSkill.RangeType.RANGE_SELFSPHERE) - { - m_CDRInfo.vTPNormal = m_MoveCtrl.m_vFlashTPNormal; - } - pWork.PrepareMove(pCmd.pos, nExecuteTime * 0.001f, 0); + m_IncantCnt.Reset(true); } - m_pWorkMan.StartWork_p2(pWork); - iActionTime = nExecuteTime; - } + m_bSpellDSkill = false; - bActionStartSkill = true; - break; - } - - case CommandID.PLAYER_CAST_RUNE_SKILL: - { - var pCmd = (S2C.cmd_player_cast_rune_skill)Msg.Param1; - System.Diagnostics.Debug.Assert(pCmd.caster == m_PlayerInfo.cid); - - if (m_pTargetItemSkill != null) - { - m_pTargetItemSkill = null; - } - - m_pTargetItemSkill = new CECSkill(pCmd.skill, pCmd.level); - if (m_pTargetItemSkill == null) - { - System.Diagnostics.Debug.Assert(m_pTargetItemSkill != null); - return; - } - - m_pCurSkill = m_pTargetItemSkill; - - if (m_pCurSkill.IsChargeable()) - m_pCurSkill.StartCharging(pCmd.time); - - int iWaitTime = -1; - if (m_pCurSkill.GetExecuteTime() >= 0) - iWaitTime = pCmd.time + m_pCurSkill.GetExecuteTime(); - - var pWork = (CECHPWorkSpell)m_pWorkMan.CreateWork(CECHPWork.WORK_SPELLOBJECT); - pWork.PrepareCast(pCmd.target, m_pCurSkill, iWaitTime); - m_pWorkMan.StartWork_p1(pWork); - - if (!m_pCurSkill.IsChargeable()) - { - int iTime = pCmd.time; - iTime = Math.Max(iTime, 10); - m_IncantCnt.SetPeriod(iTime); - m_IncantCnt.Reset(); - } - else - { - m_IncantCnt.Reset(true); - } - - m_bSpellDSkill = false; - - TurnFaceTo(pCmd.target); - - m_idCurSkillTarget = pCmd.target; - PlaySkillCastAction(m_pCurSkill.GetSkillID()); - - bActionStartSkill = true; - iActionTime = iWaitTime; - g_pGame.RuntimeDebugInfo(0xffffffff, $"Cast skill({m_pCurSkill.GetSkillID()}): {g_pGame.GetSkillDesc().GetWideString(m_pCurSkill.GetSkillID() * 10)}"); - break; - } - - case CommandID.PLAYER_CAST_RUNE_INSTANT_SKILL: - { - var pCmd = (S2C.cmd_player_cast_rune_instant_skill)Msg.Param1; - System.Diagnostics.Debug.Assert(pCmd.caster == m_PlayerInfo.cid); - - if (m_pTargetItemSkill != null) - { - m_pTargetItemSkill = null; - } - - m_pTargetItemSkill = new CECSkill(pCmd.skill, pCmd.level); - if (m_pTargetItemSkill == null) - { - System.Diagnostics.Debug.Assert(m_pTargetItemSkill != null); - return; - } - - if (pCmd.target != 0 && pCmd.target != m_PlayerInfo.cid) TurnFaceTo(pCmd.target); - PlaySkillCastAction(m_pTargetItemSkill.GetSkillID()); - bActionStartSkill = true; - break; - } + m_idCurSkillTarget = pCmd.target; + PlaySkillCastAction(m_pCurSkill.GetSkillID()); - case CommandID.ERROR_MESSAGE: - bDoOtherThing = true; - // m_pPrepSkill = null; - break; - - default: - System.Diagnostics.Debug.Assert(false); - break;*/ - } - - /* if (bActionStartSkill) - AP_ActionEvent(AP_EVENT_STARTSKILL, iActionTime); - - if (bDoOtherThing) - { - if (m_pComboSkill != null && !m_pComboSkill.IsStop()) - { - if (CECAutoPolicy.GetInstance().IsAutoPolicyEnabled()) - g_pGame.GetGameRun().PostMessage(MSG_HST_CONTINUECOMBOSKILL, MAN_PLAYER, 0, 0, m_pComboSkill.GetGroupIndex()); - else - m_pComboSkill.Continue(false); - } - else - { - if (idTarget != 0 && idTarget != m_PlayerInfo.cid) - NormalAttackObject(idTarget, true); - } - }*/ - } - private void OnMsgHstSkillData(ECMSG Msg) - { - cmd_skill_data pCmd = default; - pCmd.skill_count = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - int offset = sizeof(uint); - int skillSize = Marshal.SizeOf(); - pCmd.skill_list = new cmd_skill_data.SKILL[pCmd.skill_count]; - for (int i = 0; i < pCmd.skill_count; i++) - { - pCmd.skill_list[i] = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1, offset); - offset += skillSize; - } - if (pCmd.skill_list == null) - { - BMLogger.LogError("OnMsgHstSkillData: cmd is null"); - return; - } - - /* List skillSCConfigArray1 = new List(); - List skillSCConfigArray2 = new List(); - List skillGrpSCConfigArray1 = new List(); - List skillGrpSCConfigArray2 = new List();*/ - - if (HostIsReady()) - { - /* - for (int i = 0; i < HostConstants.NUM_HOSTSCSETS1; i++) - { - if (hostPlayer.m_aSCSets1[i] != null) - { - hostPlayer.m_aSCSets1[i].RemoveSkillShortcuts(); - } - } - - for (int i = 0; i < HostConstants.NUM_HOSTSCSETS2; i++) - { - if (hostPlayer.m_aSCSets2[i] != null) - { - hostPlayer.m_aSCSets2[i].RemoveSkillShortcuts(); - } - }*/ - - // Release passive skills - m_aPsSkills.Clear(); - } - - // Load skill data from command - // C++: GNET::ElementSkill::LoadSkillData(pCmd); - ElementSkill.LoadSkillData(pCmd); - // Create skill objects from command data - for (int i = 0; i < pCmd.skill_count; i++) - { - cmd_skill_data.SKILL data = pCmd.skill_list[i]; - CECSkill skill = new CECSkill(data.id_skill, data.level); - - // Categorize skills into positive and passive - int skillType = skill.GetType(); - if (skillType != (int)CECSkill.SkillType.TYPE_PASSIVE && - skillType != (int)CECSkill.SkillType.TYPE_PRODUCE && - skillType != (int)CECSkill.SkillType.TYPE_LIVE) - { - m_aPtSkills.Add(skill); - } - else - { - m_aPsSkills.Add(skill); - } - } - // Restore and convert shortcuts after loading new skills - /* if (hostPlayer.HostIsReady()) - { - hostPlayer.ConvertSkillShortcut(skillSCConfigArray1); - hostPlayer.AssignSkillShortcut(skillSCConfigArray1, hostPlayer.m_aSCSets1); - hostPlayer.ConvertSkillShortcut(skillSCConfigArray2); - hostPlayer.AssignSkillShortcut(skillSCConfigArray2, hostPlayer.m_aSCSets2); - hostPlayer.ConvertComboSkill(); - hostPlayer.ValidateSkillGrpShortcut(skillGrpSCConfigArray1); - hostPlayer.AssignSkillGrpShortcut(skillGrpSCConfigArray1, hostPlayer.m_aSCSets1); - hostPlayer.ValidateSkillGrpShortcut(skillGrpSCConfigArray2); - hostPlayer.AssignSkillGrpShortcut(skillGrpSCConfigArray2, hostPlayer.m_aSCSets2); - } - - if (hostPlayer.HostIsReady()) - { - // Update UI when profession changes, save all shortcut configurations - // to remove effects from intermediate skills (invalid pointers) - // C++: CECGameUIMan *pGameUIMan = g_pGame->GetGameRun()->GetUIManager()->GetInGameUIMan(); - // pGameUIMan->UpdateSkillRelatedUI(); - hostPlayer.UpdateSkillRelatedUI(); - }*/ - } - public bool HostIsReady() { return true /*m_bEnterGame*/; } - private void OnMsgHstDied(in ECMSG msg) - { - EventBus.PublishChannel(GetCharacterID(), new CECPlayer.ClearComActFlagAllRankNodesEvent(true)); - PlayAction((int)PLAYER_ACTION_TYPE.ACT_GROUNDDIE); - if (PopupManager.Instance != null) - { - PopupManager.Instance.OnPlayerDied(); - } - } - private void OnMsgHstInfo00(in ECMSG Msg) - { - cmd_self_info_00 pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - - bool bFirstTime = m_BasicProps.iLevel == 0 ? true : false; - if (!bFirstTime) - { - int iLimit = (int)(pCmd.iMaxHP * 0.3f); - if (pCmd.iHP < m_BasicProps.iCurHP && m_BasicProps.iCurHP >= iLimit && pCmd.iHP < iLimit) - { - - /*if (CECUIHelper::GetGameUIMan()->IsShowLowHP()) { - // ѪÁ¿µÍÓÚÁÙ½çÖµÔò²¥·ÅÌØÐ§ - const int GfxLastTime = 10000; // ³ÖÐøÊ±¼ä10Ãë - CECUIHelper::GetGameUIMan()->GetScreenEffectMan()->StartEffect(CECScreenEffect::EFFECT_REDSPARK, GfxLastTime); - }*/ - } - - /*if (pCmd.iHP >= iLimit || pCmd.iHP <= 0) { - // ѪÁ¿¸ßÓÚÁÙ½çÖµ»òËÀÍö£¬ÔòÍ£Ö¹²¥·ÅÌØÐ§ - CECUIHelper::GetGameUIMan()->GetScreenEffectMan()->FinishEffect(CECScreenEffect::EFFECT_REDSPARK); - }*/ - - /*iLimit = (int)(pCmd.iMaxMP * 0.2f); - if (pCmd.iMP < m_BasicProps.iCurMP && m_BasicProps.iCurMP >= iLimit && pCmd.iMP < iLimit) - BubbleText(BUBBLE_MPWARN, 0);*/ - - /*if (m_ExtProps.max_ap != pCmd->iMaxAP) - g_pGame->GetGameRun()->AddFixedMessage(FIXMSG_ADDMAXAP, pCmd->iMaxAP - m_ExtProps.max_ap);*/ - } - - m_BasicProps.iLevel = pCmd.sLevel; - SetLevel2(pCmd.Level2, bFirstTime); - m_BasicProps.iExp = pCmd.iExp; - m_BasicProps.iSP = pCmd.iSP; - m_BasicProps.iCurHP = pCmd.iHP; - m_BasicProps.iCurMP = pCmd.iMP; - m_BasicProps.iCurAP = pCmd.iAP; - m_ExtProps.bs.max_hp = pCmd.iMaxHP; - m_ExtProps.bs.max_mp = pCmd.iMaxMP; - m_ExtProps.max_ap = pCmd.iMaxAP; - - EventBus.Publish(new EXPToUpLevel(GetLevelUpExp(pCmd.sLevel))); - EventBus.Publish(pCmd); - // if (pCmd.State != 0 && m_bFight == false) PlayEnterBattleGfx(); - m_bFight = pCmd.State != 0 ? true : false; - - // UpdateGodEvilSprite(); - - /*CECGameUIMan* pGameUI = g_pGame->GetGameRun()->GetUIManager()->GetInGameUIMan(); - CDlgAutoHelp *pDlgHelp = dynamic_cast(pGameUI->GetDialog("Win_WikiPop"));*/ - /*if(pDlgHelp && m_bFight) - pDlgHelp->SetAutoHelpState(false);*/ - } - void SetLevel2(int level2, bool bFirstTime) - { - int lastLevel2 = m_BasicProps.iLevel2; - m_BasicProps.iLevel2 = level2; - /*if (CanPlayTaoistEffect(lastLevel2, level2, bFirstTime)){ - PlayTaoistEffect(); - }*/ - } - void OnMsgHstAttacked(ECMSG Msg) - { - var m_pPlayerMan = EC_ManMessageMono.Instance.EC_ManPlayer; - cmd_host_attacked pCmd = GPDataTypeHelper.FromBytes(Msg.dwParam1 as byte[]); - - if (pCmd.iDamage != 0 && (pCmd.cEquipment & 0x7f) != 0x7f) - { - /* char cEquip = (char)(pCmd.cEquipment & 0x7f); - CECIvtrEquip pEquip = (CECIvtrEquip)m_pEquipPack->GetItem(cEquip); - if (pEquip) - pEquip->AddCurEndurance(ARMOR_RUIN_SPEED);*/ - } - - // The host player is attacked, we should make an effect here - if (GPDataTypeHelper.ISPLAYERID(pCmd.idAttacker)) - { - EC_ElsePlayer pAttacker = m_pPlayerMan.GetElsePlayer(pCmd.idAttacker); - if (pAttacker) - { - if (!pAttacker.IsDead()) - { - // Face to target - pAttacker.TurnFaceTo(GetPlayerInfo().cid); - } - - int useless_attacktime = 0; - pAttacker.PlayAttackEffect(GetCharacterID(), 0, 0, pCmd.iDamage, (uint)pCmd.attack_flag, - pCmd.speed * 50, ref useless_attacktime); - pAttacker.EnterFightState(); - } - } - else if (GPDataTypeHelper.ISNPCID(pCmd.idAttacker)) - { - CECNPC pAttacker = EC_ManMessageMono.Instance._CECNPCMan.GetNPC(pCmd.idAttacker); - if (pAttacker) - { - pAttacker.OnMsgAttackHostResult(GetCharacterID(), pCmd.iDamage, pCmd.attack_flag, pCmd.speed); - } - } - - //CECAutoPolicy::GetInstance().SendEvent_BeHurt(pCmd.idAttacker); - } - - public void OnMsgHstAttackResult(ECMSG Msg) - { - BMLogger.LogError($"HoangDev OnMsgHstAttackResult "); - byte[] data = Msg.dwParam1 as byte[]; - cmd_host_attack_result pCmd = EC_Utility.ByteArrayToStructure(data); - - int iAttackTime = 0; - TurnFaceTo(pCmd.idTarget); - - PlayAttackEffect(pCmd.idTarget, 0, 0, pCmd.iDamage, (uint)pCmd.attack_flag, pCmd.attack_speed * 50, - ref iAttackTime); - - if (iAttackTime != 0) - { - if (m_pWorkMan.GetRunningWork(CECHPWork.Host_work_ID.WORK_HACKOBJECT) is CECHPWorkMelee pCurWork) - { - pCurWork.SetIdleTime(iAttackTime); - } - } - } - - /* public override bool IsWorkMoveRunning() - { - return m_pWorkMan.IsMovingToPosition(); - }*/ - private void OnMsgHstHurtResult(ECMSG Msg) - { - //BMLogger.LogError("HoangDev : OnMsgHstHurtResult"); - /* int cmd = Convert.ToInt32(Msg.dwParam2); - if (cmd == CommandID.BE_HURT) - { - cmd_be_hurt pCmd = (cmd_be_hurt)Msg.dwParam1; - if (pCmd.damage != 0) - Damaged(pCmd->damage); - } - else if (cmd == CommandID.HURT_RESULT) - { - cmd_hurt_result pCmd = (cmd_hurt_result)Msg.dwParam1; - if (pCmd.target_id == m_PlayerInfo.cid) - return; // Host himself will receive BE_HURT, so ignore this. - - if (UnityGameSession.Instance.GameSession.ISPLAYERID(pCmd.target_id)) - { - CECElsePlayer pTarget = m_pPlayerMan.GetElsePlayer(pCmd.target_id); - if (pTarget) - pTarget->Damaged(pCmd->damage); - } - else if (UnityGameSession.Instance.GameSession.ISNPCID(pCmd.target_id)) - { - CECNPC pTarget = EC_ManMessageMono.Instance._CECNPCMan.GetNPC(pCmd.target_id); - if (pTarget) - pTarget.Damaged(pCmd.damage); - } - }*/ - } - - public void OnMsgHstPickupItem(in ECMSG Msg) - { - var data = Msg.dwParam1 as byte[]; - int cmd = Convert.ToInt32(Msg.dwParam2); - switch (cmd) - { - case CommandID.HOST_OBTAIN_ITEM: - { - // Parse cmd_host_obtain_item struct data - int type = BitConverter.ToInt32(data, 0); - int expire_date = BitConverter.ToInt32(data, 4); - uint amount = BitConverter.ToUInt32(data, 8); - uint slot_amount = BitConverter.ToUInt32(data, 12); - byte where = data[16]; // Package index - byte index = data[17]; // Slot index in that package - // Create new inventory item data - var newItem = new EC_IvtrItem - { - Package = where, - Slot = index, - m_tid = type, - m_expire_date = expire_date, - State = 0, - m_iCount = (int)amount, - Crc = 0, - Content = null - }; - - // Add item to inventory - EC_Inventory.SetItem(where, index, newItem); - - Debug.Log( - $"[HOST_OBTAIN_ITEM] Successfully added item {type} to package {where}, slot {index} with count {amount}"); - - // Trigger UI refresh if an EC_InventoryUI is present in scene - var ui = GameObject.FindFirstObjectByType(); - if (ui != null) - { - ui.RefreshAll(); + bActionStartSkill = true; + iActionTime = iWaitTime; + break; } - } - break; - case CommandID.PICKUP_ITEM: + + /* case CommandID.SKILL_PERFORM: + { + m_pPrepSkill = null; + + if (m_pCurSkill != null && m_pCurSkill.IsDurative()) + m_bSpellDSkill = true; + + break; + } + + case CommandID.HOST_STOP_SKILL: + { + m_pPrepSkill = null; + + CECSkill pSkillToMatch = m_pCurSkill; + if (m_pCurSkill != null) + { + ClearComActFlagAllRankNodes(true); + + if (((m_pComboSkill != null && !m_pComboSkill.IsStop()) || + m_pCurSkill.ChangeToMelee()) && !m_pWorkMan.HasDelayedWork()) + { + bDoOtherThing = true; + idTarget = m_idCurSkillTarget; + } + + m_pCurSkill.EndCharging(); + m_pCurSkill = null; + } + + AP_ActionEvent(AP_EVENT_STOPSKILL); + + if (pSkillToMatch != null) + { + m_pWorkMan.FinishWork(new CECHPWorkSpellMatcher(pSkillToMatch)); + } + StopSkillAttackAction(); + + m_idCurSkillTarget = 0; + break; + } + + case CommandID.SELF_SKILL_INTERRUPTED: + { + int skill_id = 0; + m_pPrepSkill = null; + + CECSkill pSkillToMatch = m_pCurSkill; + if (m_pCurSkill != null) + { + skill_id = m_pCurSkill.GetSkillID(); + + ClearComActFlagAllRankNodes(false); + + if (((m_pComboSkill != null && !m_pComboSkill.IsStop()) || + m_pCurSkill.ChangeToMelee()) && !m_pWorkMan.HasDelayedWork()) + { + bDoOtherThing = true; + idTarget = m_idCurSkillTarget; + } + + m_pCurSkill.EndCharging(); + m_pCurSkill = null; + } + + m_idCurSkillTarget = 0; + + if (pSkillToMatch != null) + { + m_pWorkMan.FinishWork(new CECHPWorkSpellMatcher(pSkillToMatch)); + } + StopSkillCastAction(); + + g_pGame.GetGameRun().AddFixedMessage(FIXMSG_SKILLINTERRUPT); + + AP_ActionEvent(AP_EVENT_STOPSKILL); + + CECAutoPolicy.GetInstance().SendEvent_SkillInterrupt(skill_id); + break; + } + + case CommandID.OBJECT_CAST_INSTANT_SKILL: + { + var pCmd = (S2C.cmd_object_cast_instant_skill)Msg.Param1; + System.Diagnostics.Debug.Assert(pCmd.caster == m_PlayerInfo.cid); + + CECSkill pSkill = GetPositiveSkillByID(pCmd.skill); + if (pSkill == null) pSkill = GetEquipSkillByID(pCmd.skill); + if (pSkill == null) + { + System.Diagnostics.Debug.Assert(pSkill != null); + return; + } + + if (pCmd.target != 0 && pCmd.target != m_PlayerInfo.cid) + TurnFaceTo(pCmd.target); + + PlaySkillCastAction(pSkill.GetSkillID()); + bActionStartSkill = true; + break; + } + + case CommandID.OBJECT_CAST_POS_SKILL: + { + var pCmd = (S2C.cmd_object_cast_pos_skill)Msg.Param1; + System.Diagnostics.Debug.Assert(pCmd.caster == m_PlayerInfo.cid); + + CECSkill pSkill = GetNormalSkill(pCmd.skill); + if (pSkill == null) pSkill = GetEquipSkillByID(pCmd.skill); + if (pSkill == null) + { + System.Diagnostics.Debug.Assert(pSkill != null); + break; + } + + TurnFaceTo(pCmd.target); + + if (pSkill.GetRangeType() != CECSkill.RangeType.RANGE_SLEF && + pSkill.GetRangeType() != CECSkill.RangeType.RANGE_SELFSPHERE && + (pSkill.GetSkillID() == 1095 || + pSkill.GetSkillID() == 1278 || + pSkill.GetSkillID() == 1279 || + pSkill.GetSkillID() == 2313)) + { + // Teleport-style placement + A3DVECTOR3 vPos = pCmd.pos; + if (!IsPosCollideFree(vPos)) + { + vPos += g_vAxisY * 0.1f; + } + + A3DVECTOR3 vNormal; + float vTerrainHeight = g_pGame.GetGameRun().GetWorld().GetTerrainHeight(vPos, out vNormal); + if (vPos.y < vTerrainHeight) + vPos.y = vTerrainHeight; + + SetPos(vPos); + + m_CDRInfo.vTPNormal = (vPos.y <= vTerrainHeight + 0.1f) ? vNormal : g_vOrigin; + m_CDRInfo.fYVel = 0.0f; + m_CDRInfo.vAbsVelocity.Clear(); + ResetJump(); + + m_MoveCtrl.SetHostLastPos(vPos); + m_MoveCtrl.SetLastSevPos(vPos); + + UpdateFollowCamera(false, 10); + } + else + { + var pWork = (CECHPWorkFMove)m_pWorkMan.CreateWork(CECHPWork.WORK_FLASHMOVE); + + int nExecuteTime = pSkill.GetExecuteTime(); + nExecuteTime = Math.Max(nExecuteTime, 50); + + if (pSkill.GetSkillID() == 1145 || + pSkill.GetSkillID() == 1314 || + pSkill.GetSkillID() == 1315 || + pSkill.GetSkillID() == 1362 || + pSkill.GetSkillID() == 1690 || + pSkill.GetSkillID() == 1691 || + pSkill.GetSkillID() == 1845 || + pSkill.GetSkillID() == 1844 || + pSkill.GetSkillID() == 1815 || + pSkill.GetSkillID() == 2272 || + pSkill.GetSkillID() == 2315 || + pSkill.GetSkillID() == 2285 || + pSkill.GetSkillID() == 2340 || + pSkill.GetSkillID() == 2341 || + pSkill.GetSkillID() == 2342 || + pSkill.GetSkillID() == 2553 || + pSkill.GetSkillID() == 2740 || + pSkill.GetSkillID() == 2741 || + pSkill.GetSkillID() == 2559 || + pSkill.GetSkillID() == 2752 || + pSkill.GetSkillID() == 2753) + { + A3DVECTOR3 vPos = pCmd.pos; + if (!IsPosCollideFree(vPos)) + { + vPos += g_vAxisY * 0.1f; + } + + A3DVECTOR3 vNormal; + float vTerrainHeight = g_pGame.GetGameRun().GetWorld().GetTerrainHeight(vPos, out vNormal); + if (vPos.y < vTerrainHeight) + vPos.y = vTerrainHeight; + + m_CDRInfo.vTPNormal = (vPos.y <= vTerrainHeight + 0.1f) ? vNormal : g_vOrigin; + m_CDRInfo.fYVel = 0.0f; + m_CDRInfo.vAbsVelocity.Clear(); + ResetJump(); + + pWork.PrepareMove(pCmd.pos, nExecuteTime * 0.001f, pSkill.GetSkillID()); + } + else + { + if (pSkill.GetRangeType() == CECSkill.RangeType.RANGE_SLEF || + pSkill.GetRangeType() == CECSkill.RangeType.RANGE_SELFSPHERE) + { + m_CDRInfo.vTPNormal = m_MoveCtrl.m_vFlashTPNormal; + } + pWork.PrepareMove(pCmd.pos, nExecuteTime * 0.001f, 0); + } + + m_pWorkMan.StartWork_p2(pWork); + iActionTime = nExecuteTime; + } + + bActionStartSkill = true; + break; + } + + case CommandID.PLAYER_CAST_RUNE_SKILL: + { + var pCmd = (S2C.cmd_player_cast_rune_skill)Msg.Param1; + System.Diagnostics.Debug.Assert(pCmd.caster == m_PlayerInfo.cid); + + if (m_pTargetItemSkill != null) + { + m_pTargetItemSkill = null; + } + + m_pTargetItemSkill = new CECSkill(pCmd.skill, pCmd.level); + if (m_pTargetItemSkill == null) + { + System.Diagnostics.Debug.Assert(m_pTargetItemSkill != null); + return; + } + + m_pCurSkill = m_pTargetItemSkill; + + if (m_pCurSkill.IsChargeable()) + m_pCurSkill.StartCharging(pCmd.time); + + int iWaitTime = -1; + if (m_pCurSkill.GetExecuteTime() >= 0) + iWaitTime = pCmd.time + m_pCurSkill.GetExecuteTime(); + + var pWork = (CECHPWorkSpell)m_pWorkMan.CreateWork(CECHPWork.WORK_SPELLOBJECT); + pWork.PrepareCast(pCmd.target, m_pCurSkill, iWaitTime); + m_pWorkMan.StartWork_p1(pWork); + + if (!m_pCurSkill.IsChargeable()) + { + int iTime = pCmd.time; + iTime = Math.Max(iTime, 10); + m_IncantCnt.SetPeriod(iTime); + m_IncantCnt.Reset(); + } + else + { + m_IncantCnt.Reset(true); + } + + m_bSpellDSkill = false; + + TurnFaceTo(pCmd.target); + + m_idCurSkillTarget = pCmd.target; + PlaySkillCastAction(m_pCurSkill.GetSkillID()); + + bActionStartSkill = true; + iActionTime = iWaitTime; + g_pGame.RuntimeDebugInfo(0xffffffff, $"Cast skill({m_pCurSkill.GetSkillID()}): {g_pGame.GetSkillDesc().GetWideString(m_pCurSkill.GetSkillID() * 10)}"); + break; + } + + case CommandID.PLAYER_CAST_RUNE_INSTANT_SKILL: + { + var pCmd = (S2C.cmd_player_cast_rune_instant_skill)Msg.Param1; + System.Diagnostics.Debug.Assert(pCmd.caster == m_PlayerInfo.cid); + + if (m_pTargetItemSkill != null) + { + m_pTargetItemSkill = null; + } + + m_pTargetItemSkill = new CECSkill(pCmd.skill, pCmd.level); + if (m_pTargetItemSkill == null) + { + System.Diagnostics.Debug.Assert(m_pTargetItemSkill != null); + return; + } + + if (pCmd.target != 0 && pCmd.target != m_PlayerInfo.cid) + TurnFaceTo(pCmd.target); + + PlaySkillCastAction(m_pTargetItemSkill.GetSkillID()); + bActionStartSkill = true; + break; + } + + case CommandID.ERROR_MESSAGE: + bDoOtherThing = true; + // m_pPrepSkill = null; + break; + + default: + System.Diagnostics.Debug.Assert(false); + break;*/ + } + + /* if (bActionStartSkill) + AP_ActionEvent(AP_EVENT_STARTSKILL, iActionTime); + + if (bDoOtherThing) + { + if (m_pComboSkill != null && !m_pComboSkill.IsStop()) + { + if (CECAutoPolicy.GetInstance().IsAutoPolicyEnabled()) + g_pGame.GetGameRun().PostMessage(MSG_HST_CONTINUECOMBOSKILL, MAN_PLAYER, 0, 0, m_pComboSkill.GetGroupIndex()); + else + m_pComboSkill.Continue(false); + } + else + { + if (idTarget != 0 && idTarget != m_PlayerInfo.cid) + NormalAttackObject(idTarget, true); + } + }*/ + } + private void OnMsgHstSkillData(ECMSG Msg) + { + cmd_skill_data pCmd = default; + pCmd.skill_count = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + int offset = sizeof(uint); + int skillSize = Marshal.SizeOf(); + pCmd.skill_list = new cmd_skill_data.SKILL[pCmd.skill_count]; + for (int i = 0; i < pCmd.skill_count; i++) + { + pCmd.skill_list[i] = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1, offset); + offset += skillSize; + } + if (pCmd.skill_list == null) + { + BMLogger.LogError("OnMsgHstSkillData: cmd is null"); + return; + } + + /* List skillSCConfigArray1 = new List(); + List skillSCConfigArray2 = new List(); + List skillGrpSCConfigArray1 = new List(); + List skillGrpSCConfigArray2 = new List();*/ + + if (HostIsReady()) + { + /* + for (int i = 0; i < HostConstants.NUM_HOSTSCSETS1; i++) + { + if (hostPlayer.m_aSCSets1[i] != null) + { + hostPlayer.m_aSCSets1[i].RemoveSkillShortcuts(); + } + } + + for (int i = 0; i < HostConstants.NUM_HOSTSCSETS2; i++) + { + if (hostPlayer.m_aSCSets2[i] != null) + { + hostPlayer.m_aSCSets2[i].RemoveSkillShortcuts(); + } + }*/ + + // Release passive skills + m_aPsSkills.Clear(); + } + + // Load skill data from command + // C++: GNET::ElementSkill::LoadSkillData(pCmd); + ElementSkill.LoadSkillData(pCmd); + // Create skill objects from command data + for (int i = 0; i < pCmd.skill_count; i++) + { + cmd_skill_data.SKILL data = pCmd.skill_list[i]; + CECSkill skill = new CECSkill(data.id_skill, data.level); + + // Categorize skills into positive and passive + int skillType = skill.GetType(); + if (skillType != (int)CECSkill.SkillType.TYPE_PASSIVE && + skillType != (int)CECSkill.SkillType.TYPE_PRODUCE && + skillType != (int)CECSkill.SkillType.TYPE_LIVE) { - int tid = BitConverter.ToInt32(data, 0); - int expire_date = BitConverter.ToInt32(data, 4); - uint iAmount = BitConverter.ToUInt32(data, 8); - uint iSlotAmount = BitConverter.ToUInt32(data, 12); - byte byPackage = data[16]; - byte bySlot = data[17]; + m_aPtSkills.Add(skill); + } + else + { + m_aPsSkills.Add(skill); + } + } + // Restore and convert shortcuts after loading new skills + /* if (hostPlayer.HostIsReady()) + { + hostPlayer.ConvertSkillShortcut(skillSCConfigArray1); + hostPlayer.AssignSkillShortcut(skillSCConfigArray1, hostPlayer.m_aSCSets1); + hostPlayer.ConvertSkillShortcut(skillSCConfigArray2); + hostPlayer.AssignSkillShortcut(skillSCConfigArray2, hostPlayer.m_aSCSets2); + hostPlayer.ConvertComboSkill(); + hostPlayer.ValidateSkillGrpShortcut(skillGrpSCConfigArray1); + hostPlayer.AssignSkillGrpShortcut(skillGrpSCConfigArray1, hostPlayer.m_aSCSets1); + hostPlayer.ValidateSkillGrpShortcut(skillGrpSCConfigArray2); + hostPlayer.AssignSkillGrpShortcut(skillGrpSCConfigArray2, hostPlayer.m_aSCSets2); + } - //Debug.Log($"[Inventory] PICKUP_ITEM: tid={tid}, expire_date={expire_date}, iAmount={iAmount}, iSlotAmount={iSlotAmount}, byPackage={byPackage}, bySlot={bySlot}"); + if (hostPlayer.HostIsReady()) + { + // Update UI when profession changes, save all shortcut configurations + // to remove effects from intermediate skills (invalid pointers) + // C++: CECGameUIMan *pGameUIMan = g_pGame->GetGameRun()->GetUIManager()->GetInGameUIMan(); + // pGameUIMan->UpdateSkillRelatedUI(); + hostPlayer.UpdateSkillRelatedUI(); + }*/ + } + public bool HostIsReady() { return true /*m_bEnterGame*/; } + private void OnMsgHstDied(in ECMSG msg) + { + EventBus.PublishChannel(GetCharacterID(), new CECPlayer.ClearComActFlagAllRankNodesEvent(true)); + PlayAction((int)PLAYER_ACTION_TYPE.ACT_GROUNDDIE); + if (PopupManager.Instance != null) + { + PopupManager.Instance.OnPlayerDied(); + } + } + private void OnMsgHstInfo00(in ECMSG Msg) + { + cmd_self_info_00 pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - // Notify pickupItem script about successful pickup - pickupItem pickupScript = pickupItem.Instance; - if (pickupScript != null) + bool bFirstTime = m_BasicProps.iLevel == 0 ? true : false; + if (!bFirstTime) + { + int iLimit = (int)(pCmd.iMaxHP * 0.3f); + if (pCmd.iHP < m_BasicProps.iCurHP && m_BasicProps.iCurHP >= iLimit && pCmd.iHP < iLimit) + { + + /*if (CECUIHelper::GetGameUIMan()->IsShowLowHP()) { + // ѪÁ¿µÍÓÚÁÙ½çÖµÔò²¥·ÅÌØÐ§ + const int GfxLastTime = 10000; // ³ÖÐøÊ±¼ä10Ãë + CECUIHelper::GetGameUIMan()->GetScreenEffectMan()->StartEffect(CECScreenEffect::EFFECT_REDSPARK, GfxLastTime); + }*/ + } + + /*if (pCmd.iHP >= iLimit || pCmd.iHP <= 0) { + // ѪÁ¿¸ßÓÚÁÙ½çÖµ»òËÀÍö£¬ÔòÍ£Ö¹²¥·ÅÌØÐ§ + CECUIHelper::GetGameUIMan()->GetScreenEffectMan()->FinishEffect(CECScreenEffect::EFFECT_REDSPARK); + }*/ + + /*iLimit = (int)(pCmd.iMaxMP * 0.2f); + if (pCmd.iMP < m_BasicProps.iCurMP && m_BasicProps.iCurMP >= iLimit && pCmd.iMP < iLimit) + BubbleText(BUBBLE_MPWARN, 0);*/ + + /*if (m_ExtProps.max_ap != pCmd->iMaxAP) + g_pGame->GetGameRun()->AddFixedMessage(FIXMSG_ADDMAXAP, pCmd->iMaxAP - m_ExtProps.max_ap);*/ + } + + m_BasicProps.iLevel = pCmd.sLevel; + SetLevel2(pCmd.Level2, bFirstTime); + m_BasicProps.iExp = pCmd.iExp; + m_BasicProps.iSP = pCmd.iSP; + m_BasicProps.iCurHP = pCmd.iHP; + m_BasicProps.iCurMP = pCmd.iMP; + m_BasicProps.iCurAP = pCmd.iAP; + m_ExtProps.bs.max_hp = pCmd.iMaxHP; + m_ExtProps.bs.max_mp = pCmd.iMaxMP; + m_ExtProps.max_ap = pCmd.iMaxAP; + + EventBus.Publish(new EXPToUpLevel(GetLevelUpExp(pCmd.sLevel))); + EventBus.Publish(pCmd); + // if (pCmd.State != 0 && m_bFight == false) PlayEnterBattleGfx(); + m_bFight = pCmd.State != 0 ? true : false; + + // UpdateGodEvilSprite(); + + /*CECGameUIMan* pGameUI = g_pGame->GetGameRun()->GetUIManager()->GetInGameUIMan(); + CDlgAutoHelp *pDlgHelp = dynamic_cast(pGameUI->GetDialog("Win_WikiPop"));*/ + /*if(pDlgHelp && m_bFight) + pDlgHelp->SetAutoHelpState(false);*/ + } + void SetLevel2(int level2, bool bFirstTime) + { + int lastLevel2 = m_BasicProps.iLevel2; + m_BasicProps.iLevel2 = level2; + /*if (CanPlayTaoistEffect(lastLevel2, level2, bFirstTime)){ + PlayTaoistEffect(); + }*/ + } + void OnMsgHstAttacked(ECMSG Msg) + { + var m_pPlayerMan = EC_ManMessageMono.Instance.EC_ManPlayer; + cmd_host_attacked pCmd = GPDataTypeHelper.FromBytes(Msg.dwParam1 as byte[]); + + if (pCmd.iDamage != 0 && (pCmd.cEquipment & 0x7f) != 0x7f) + { + /* char cEquip = (char)(pCmd.cEquipment & 0x7f); + CECIvtrEquip pEquip = (CECIvtrEquip)m_pEquipPack->GetItem(cEquip); + if (pEquip) + pEquip->AddCurEndurance(ARMOR_RUIN_SPEED);*/ + } + + // The host player is attacked, we should make an effect here + if (GPDataTypeHelper.ISPLAYERID(pCmd.idAttacker)) + { + EC_ElsePlayer pAttacker = m_pPlayerMan.GetElsePlayer(pCmd.idAttacker); + if (pAttacker) + { + if (!pAttacker.IsDead()) { - //Debug.Log($"[Inventory] PICKUP_ITEM: tid={tid}, expire_date={expire_date}, iAmount={iAmount}, iSlotAmount={iSlotAmount}, byPackage={byPackage}, bySlot={bySlot}"); + // Face to target + pAttacker.TurnFaceTo(GetPlayerInfo().cid); + } - // Notify pickupItem script about successful pickup - pickupScript = UnityEngine.Object.FindFirstObjectByType(); - if (pickupScript != null) - { - pickupScript.OnPickupSuccess(tid); - } + int useless_attacktime = 0; + pAttacker.PlayAttackEffect(GetCharacterID(), 0, 0, pCmd.iDamage, (uint)pCmd.attack_flag, + pCmd.speed * 50, ref useless_attacktime); + pAttacker.EnterFightState(); + } + } + else if (GPDataTypeHelper.ISNPCID(pCmd.idAttacker)) + { + CECNPC pAttacker = EC_ManMessageMono.Instance._CECNPCMan.GetNPC(pCmd.idAttacker); + if (pAttacker) + { + pAttacker.OnMsgAttackHostResult(GetCharacterID(), pCmd.iDamage, pCmd.attack_flag, pCmd.speed); + } + } - // Create new inventory item data + //CECAutoPolicy::GetInstance().SendEvent_BeHurt(pCmd.idAttacker); + } + + public void OnMsgHstAttackResult(ECMSG Msg) + { + BMLogger.LogError($"HoangDev OnMsgHstAttackResult "); + byte[] data = Msg.dwParam1 as byte[]; + cmd_host_attack_result pCmd = EC_Utility.ByteArrayToStructure(data); + + int iAttackTime = 0; + TurnFaceTo(pCmd.idTarget); + + PlayAttackEffect(pCmd.idTarget, 0, 0, pCmd.iDamage, (uint)pCmd.attack_flag, pCmd.attack_speed * 50, + ref iAttackTime); + + if (iAttackTime != 0) + { + if (m_pWorkMan.GetRunningWork(CECHPWork.Host_work_ID.WORK_HACKOBJECT) is CECHPWorkMelee pCurWork) + { + pCurWork.SetIdleTime(iAttackTime); + } + } + } + + /* public override bool IsWorkMoveRunning() + { + return m_pWorkMan.IsMovingToPosition(); + }*/ + private void OnMsgHstHurtResult(ECMSG Msg) + { + //BMLogger.LogError("HoangDev : OnMsgHstHurtResult"); + /* int cmd = Convert.ToInt32(Msg.dwParam2); + if (cmd == CommandID.BE_HURT) + { + cmd_be_hurt pCmd = (cmd_be_hurt)Msg.dwParam1; + if (pCmd.damage != 0) + Damaged(pCmd->damage); + } + else if (cmd == CommandID.HURT_RESULT) + { + cmd_hurt_result pCmd = (cmd_hurt_result)Msg.dwParam1; + if (pCmd.target_id == m_PlayerInfo.cid) + return; // Host himself will receive BE_HURT, so ignore this. + + if (UnityGameSession.Instance.GameSession.ISPLAYERID(pCmd.target_id)) + { + CECElsePlayer pTarget = m_pPlayerMan.GetElsePlayer(pCmd.target_id); + if (pTarget) + pTarget->Damaged(pCmd->damage); + } + else if (UnityGameSession.Instance.GameSession.ISNPCID(pCmd.target_id)) + { + CECNPC pTarget = EC_ManMessageMono.Instance._CECNPCMan.GetNPC(pCmd.target_id); + if (pTarget) + pTarget.Damaged(pCmd.damage); + } + }*/ + } + + public void OnMsgHstPickupItem(in ECMSG Msg) + { + var data = Msg.dwParam1 as byte[]; + int cmd = Convert.ToInt32(Msg.dwParam2); + switch (cmd) + { + case CommandID.HOST_OBTAIN_ITEM: + { + // Parse cmd_host_obtain_item struct data + int type = BitConverter.ToInt32(data, 0); + int expire_date = BitConverter.ToInt32(data, 4); + uint amount = BitConverter.ToUInt32(data, 8); + uint slot_amount = BitConverter.ToUInt32(data, 12); + byte where = data[16]; // Package index + byte index = data[17]; // Slot index in that package + // Create new inventory item data var newItem = new EC_IvtrItem { - Package = byPackage, - Slot = bySlot, - m_tid = tid, + Package = where, + Slot = index, + m_tid = type, m_expire_date = expire_date, State = 0, - m_iCount = (int)iAmount, + m_iCount = (int)amount, Crc = 0, Content = null }; // Add item to inventory - EC_Inventory.SetItem(byPackage, bySlot, newItem); + EC_Inventory.SetItem(where, index, newItem); - //Debug.Log($"[Inventory] Successfully added item {tid} to package {byPackage}, slot {bySlot} with count {iAmount}"); + Debug.Log( + $"[HOST_OBTAIN_ITEM] Successfully added item {type} to package {where}, slot {index} with count {amount}"); // Trigger UI refresh if an EC_InventoryUI is present in scene var ui = GameObject.FindFirstObjectByType(); @@ -1177,41 +1134,48 @@ public partial class CECHostPlayer : CECPlayer ui.RefreshAll(); } } - else - { - Debug.LogWarning("[Inventory] PICKUP_ITEM: Invalid data length"); - } break; - } - } - } - public void OnMsgHstItemOperation(ECMSG Msg) - { - var data = Msg.dwParam1 as byte[]; - int cmd = Convert.ToInt32(Msg.dwParam2); - switch (cmd) - { - case CommandID.PLAYER_DROP_ITEM: - { - // Parse the drop item data from the server response - if (data != null && data.Length >= 6) + case CommandID.PICKUP_ITEM: { - byte byPackage = data[0]; - byte bySlot = data[1]; - int count = BitConverter.ToInt32(data, 2); - int tid = BitConverter.ToInt32(data, 6); - byte reason = data[10]; + int tid = BitConverter.ToInt32(data, 0); + int expire_date = BitConverter.ToInt32(data, 4); + uint iAmount = BitConverter.ToUInt32(data, 8); + uint iSlotAmount = BitConverter.ToUInt32(data, 12); + byte byPackage = data[16]; + byte bySlot = data[17]; - Debug.Log( - $"[Inventory] PLAYER_DROP_ITEM: package={byPackage}, slot={bySlot}, count={count}, tid={tid}, reason={reason}"); + //Debug.Log($"[Inventory] PICKUP_ITEM: tid={tid}, expire_date={expire_date}, iAmount={iAmount}, iSlotAmount={iSlotAmount}, byPackage={byPackage}, bySlot={bySlot}"); - // Update the inventory by removing the item - bool success = EC_Inventory.RemoveItem(byPackage, bySlot, count); - - if (success) + // Notify pickupItem script about successful pickup + pickupItem pickupScript = pickupItem.Instance; + if (pickupScript != null) { - Debug.Log( - $"[Inventory] Successfully removed {count} items from package {byPackage}, slot {bySlot}"); + //Debug.Log($"[Inventory] PICKUP_ITEM: tid={tid}, expire_date={expire_date}, iAmount={iAmount}, iSlotAmount={iSlotAmount}, byPackage={byPackage}, bySlot={bySlot}"); + + // Notify pickupItem script about successful pickup + pickupScript = UnityEngine.Object.FindFirstObjectByType(); + if (pickupScript != null) + { + pickupScript.OnPickupSuccess(tid); + } + + // Create new inventory item data + var newItem = new EC_IvtrItem + { + Package = byPackage, + Slot = bySlot, + m_tid = tid, + m_expire_date = expire_date, + State = 0, + m_iCount = (int)iAmount, + Crc = 0, + Content = null + }; + + // Add item to inventory + EC_Inventory.SetItem(byPackage, bySlot, newItem); + + //Debug.Log($"[Inventory] Successfully added item {tid} to package {byPackage}, slot {bySlot} with count {iAmount}"); // Trigger UI refresh if an EC_InventoryUI is present in scene var ui = GameObject.FindFirstObjectByType(); @@ -1222,1793 +1186,1991 @@ public partial class CECHostPlayer : CECPlayer } else { - Debug.LogWarning($"[Inventory] Failed to remove items from package {byPackage}, slot {bySlot}"); + Debug.LogWarning("[Inventory] PICKUP_ITEM: Invalid data length"); } + break; } - else - { - Debug.LogWarning("[Inventory] PLAYER_DROP_ITEM: Invalid data length"); - } - - break; - } - case CommandID.EQUIP_ITEM: - { - byte index_inv = data[0]; - byte index_equip = data[1]; - // Update client-side data: move item between PACK_INVENTORY and PACK_EQUIPMENT - var invItem = EC_Inventory.GetItem(EC_Inventory.IVTRTYPE_PACK, index_inv, true); - var equipItem = EC_Inventory.GetItem(EC_Inventory.IVTRTYPE_EQUIPPACK, index_equip, true); - if (invItem != null) - { - invItem.Package = EC_Inventory.IVTRTYPE_EQUIPPACK; - invItem.Slot = index_equip; - EC_Inventory.SetItem(EC_Inventory.IVTRTYPE_EQUIPPACK, index_equip, invItem); - } - - if (equipItem != null) - { - equipItem.Package = EC_Inventory.IVTRTYPE_PACK; - equipItem.Slot = index_inv; - EC_Inventory.SetItem(EC_Inventory.IVTRTYPE_PACK, index_inv, equipItem); - } - - // Trigger UI refresh if an EC_InventoryUI is present in scene - var ui = GameObject.FindObjectOfType(); - if (ui != null) - { - ui.RefreshAll(); - } - - break; - } + } } - } - - public void OnMsgHstOwnItemInfo(ECMSG Msg) - { - int cmd = Convert.ToInt32(Msg.dwParam2); - switch (cmd) + public void OnMsgHstItemOperation(ECMSG Msg) { - case CommandID.OWN_ITEM_INFO: - { - Debug.Log("[Inventory] OWN_ITEM_INFO received"); - var data = Msg.dwParam1 as byte[]; - int hostId = Convert.ToInt32(Msg.dwParam3); - EC_Inventory.LogInventoryPacket("OWN_ITEM_INFO", data, hostId); - break; - } - } - } - - public void OnMsgHstIvtrInfo(ECMSG Msg) - { - var data = Msg.dwParam1 as byte[]; - int cmd = Convert.ToInt32(Msg.dwParam2); - int hostId = Convert.ToInt32(Msg.dwParam3); - - switch (cmd) - { - case CommandID.OWN_IVTR_DATA: - { - EC_Inventory.LogInventoryPacket("OWN_IVTR_DATA", data, hostId); - break; - } - case CommandID.OWN_IVTR_DETAIL_DATA: - { - // EC_Inventory.LogInventoryPacket("OWN_IVTR_DETAIL_DATA", data, hostId); - // Parse and store - if (data != null && data.Length >= 6) + var data = Msg.dwParam1 as byte[]; + int cmd = Convert.ToInt32(Msg.dwParam2); + switch (cmd) + { + case CommandID.PLAYER_DROP_ITEM: { - byte byPackage = data[0]; - byte ivtrSize = data[1]; - if (EC_IvtrItemUtils.TryParseInventoryDetail(data, out var pkg, - out var size, out var items)) + // Parse the drop item data from the server response + if (data != null && data.Length >= 6) { - EC_Inventory.UpdatePack(pkg, size, items); - } + byte byPackage = data[0]; + byte bySlot = data[1]; + int count = BitConverter.ToInt32(data, 2); + int tid = BitConverter.ToInt32(data, 6); + byte reason = data[10]; - // check if we got the item from the Equipment Pack. If so, we have to load the equipment items - if (byPackage == EC_Inventory.IVTRTYPE_EQUIPPACK) - { - UpdateEquipSkins(); - } - } + Debug.Log( + $"[Inventory] PLAYER_DROP_ITEM: package={byPackage}, slot={bySlot}, count={count}, tid={tid}, reason={reason}"); - break; - } - case CommandID.GET_OWN_MONEY: - { - if (data != null) - { - try - { - var money = GPDataTypeHelper.FromBytes(data); - var ui = GameObject.FindFirstObjectByType(); - if (ui == null) + // Update the inventory by removing the item + bool success = EC_Inventory.RemoveItem(byPackage, bySlot, count); + + if (success) { - var all = Resources.FindObjectsOfTypeAll(); - if (all != null) + Debug.Log( + $"[Inventory] Successfully removed {count} items from package {byPackage}, slot {bySlot}"); + + // Trigger UI refresh if an EC_InventoryUI is present in scene + var ui = GameObject.FindFirstObjectByType(); + if (ui != null) { - for (int i = 0; i < all.Length; i++) - { - var candidate = all[i]; - if (candidate != null && candidate.gameObject.scene.IsValid()) - { - ui = candidate; - break; - } - } + ui.RefreshAll(); } } - - if (ui != null) - { - ui.UpdateMoney(money.amount, money.max_amount); - } else { - BrewMonster.Scripts.Managers.EC_InventoryUI.CacheMoney(money.amount, money.max_amount); + Debug.LogWarning($"[Inventory] Failed to remove items from package {byPackage}, slot {bySlot}"); } } - catch (Exception ex) + else { - Debug.LogWarning($"[Inventory] Failed to parse GET_OWN_MONEY: {ex.Message}"); + Debug.LogWarning("[Inventory] PLAYER_DROP_ITEM: Invalid data length"); } - } - break; - } - case CommandID.PLAYER_CASH: - { - if (data != null) + break; + } + case CommandID.EQUIP_ITEM: { - try + byte index_inv = data[0]; + byte index_equip = data[1]; + // Update client-side data: move item between PACK_INVENTORY and PACK_EQUIPMENT + var invItem = EC_Inventory.GetItem(EC_Inventory.IVTRTYPE_PACK, index_inv, true); + var equipItem = EC_Inventory.GetItem(EC_Inventory.IVTRTYPE_EQUIPPACK, index_equip, true); + if (invItem != null) { - var cash = GPDataTypeHelper.FromBytes(data); - var ui = GameObject.FindFirstObjectByType(); - if (ui == null) + invItem.Package = EC_Inventory.IVTRTYPE_EQUIPPACK; + invItem.Slot = index_equip; + EC_Inventory.SetItem(EC_Inventory.IVTRTYPE_EQUIPPACK, index_equip, invItem); + } + + if (equipItem != null) + { + equipItem.Package = EC_Inventory.IVTRTYPE_PACK; + equipItem.Slot = index_inv; + EC_Inventory.SetItem(EC_Inventory.IVTRTYPE_PACK, index_inv, equipItem); + } + + // Trigger UI refresh if an EC_InventoryUI is present in scene + var ui = GameObject.FindObjectOfType(); + if (ui != null) + { + ui.RefreshAll(); + } + + break; + } + } + } + + public void OnMsgHstOwnItemInfo(ECMSG Msg) + { + int cmd = Convert.ToInt32(Msg.dwParam2); + switch (cmd) + { + case CommandID.OWN_ITEM_INFO: + { + Debug.Log("[Inventory] OWN_ITEM_INFO received"); + var data = Msg.dwParam1 as byte[]; + int hostId = Convert.ToInt32(Msg.dwParam3); + EC_Inventory.LogInventoryPacket("OWN_ITEM_INFO", data, hostId); + break; + } + } + } + + public void OnMsgHstIvtrInfo(ECMSG Msg) + { + var data = Msg.dwParam1 as byte[]; + int cmd = Convert.ToInt32(Msg.dwParam2); + int hostId = Convert.ToInt32(Msg.dwParam3); + + switch (cmd) + { + case CommandID.OWN_IVTR_DATA: + { + EC_Inventory.LogInventoryPacket("OWN_IVTR_DATA", data, hostId); + break; + } + case CommandID.OWN_IVTR_DETAIL_DATA: + { + // EC_Inventory.LogInventoryPacket("OWN_IVTR_DETAIL_DATA", data, hostId); + // Parse and store + if (data != null && data.Length >= 6) + { + byte byPackage = data[0]; + byte ivtrSize = data[1]; + if (EC_IvtrItemUtils.TryParseInventoryDetail(data, out var pkg, + out var size, out var items)) { - var all = Resources.FindObjectsOfTypeAll(); - if (all != null) + EC_Inventory.UpdatePack(pkg, size, items); + } + + // check if we got the item from the Equipment Pack. If so, we have to load the equipment items + if (byPackage == EC_Inventory.IVTRTYPE_EQUIPPACK) + { + UpdateEquipSkins(); + } + } + + break; + } + case CommandID.GET_OWN_MONEY: + { + if (data != null) + { + try + { + var money = GPDataTypeHelper.FromBytes(data); + var ui = GameObject.FindFirstObjectByType(); + if (ui == null) { - for (int i = 0; i < all.Length; i++) + var all = Resources.FindObjectsOfTypeAll(); + if (all != null) { - var candidate = all[i]; - if (candidate != null && candidate.gameObject.scene.IsValid()) + for (int i = 0; i < all.Length; i++) { - ui = candidate; - break; + var candidate = all[i]; + if (candidate != null && candidate.gameObject.scene.IsValid()) + { + ui = candidate; + break; + } } } } - } - if (ui != null) - { - ui.UpdateCash(cash.cash_amount); + if (ui != null) + { + ui.UpdateMoney(money.amount, money.max_amount); + } + else + { + BrewMonster.Scripts.Managers.EC_InventoryUI.CacheMoney(money.amount, money.max_amount); + } } - else + catch (Exception ex) { - BrewMonster.Scripts.Managers.EC_InventoryUI.CacheCash(cash.cash_amount); + Debug.LogWarning($"[Inventory] Failed to parse GET_OWN_MONEY: {ex.Message}"); } } - catch (Exception ex) + + break; + } + case CommandID.PLAYER_CASH: + { + if (data != null) { - Debug.LogWarning($"[Inventory] Failed to parse PLAYER_CASH: {ex.Message}"); + try + { + var cash = GPDataTypeHelper.FromBytes(data); + var ui = GameObject.FindFirstObjectByType(); + if (ui == null) + { + var all = Resources.FindObjectsOfTypeAll(); + if (all != null) + { + for (int i = 0; i < all.Length; i++) + { + var candidate = all[i]; + if (candidate != null && candidate.gameObject.scene.IsValid()) + { + ui = candidate; + break; + } + } + } + } + + if (ui != null) + { + ui.UpdateCash(cash.cash_amount); + } + else + { + BrewMonster.Scripts.Managers.EC_InventoryUI.CacheCash(cash.cash_amount); + } + } + catch (Exception ex) + { + Debug.LogWarning($"[Inventory] Failed to parse PLAYER_CASH: {ex.Message}"); + } } + + break; } - - break; - } - } - } - - public void OnMsgHstCorrectPos(in ECMSG Msg) - { - Debug.LogWarning("HoangDev : OnMsgHstCorrectPos"); - byte[] buf = (byte[])Msg.dwParam1; // chỗ bạn lưu pDataBuf - GCHandle handle = GCHandle.Alloc(buf, GCHandleType.Pinned); - cmd_host_correct_pos pCmd = (cmd_host_correct_pos)Marshal.PtrToStructure( - handle.AddrOfPinnedObject(), typeof(cmd_host_correct_pos)); - handle.Free(); - Debug.LogWarning("HoangDev :pCmd.pos " + pCmd.pos); - SetPos(pCmd.pos); - } - - public void HandleRevive(short sReviveType, A3DVECTOR3 pos) - { - // Move to revive position and play revive animation - PlayAction((int)PLAYER_ACTION_TYPE.ACT_REVIVE); - // Clear any running dead work if exists - m_pWorkMan?.FinishRunningWork(CECHPWork.Host_work_ID.WORK_DEAD); - // Clear corpse state so player is alive again - m_dwStates &= ~(uint)PlayerNPCState.GP_STATE_CORPSE; - } - - public void OnMsgHstGoto(in ECMSG Msg) - { - Debug.Log("HoangDev :OnMsgHstGoto"); - PopupManager.Instance.OnPlayerRevived(); - // p1 is a byte[] buffer; parse into cmd_notify_hostpos then set position - byte[] buf = (byte[])Msg.dwParam1; - cmd_notify_hostpos pCmd = GPDataTypeHelper.FromBytes(buf); - SetPos(new Vector3(pCmd.vPos.x, pCmd.vPos.y, pCmd.vPos.z)); - - } - - // Message MSG_HST_SELTARGET handler - void OnMsgHstSelTarget(ECMSG Msg) - { - //BMLogger.LogError("HoangDev: OnMsgHstSelTarget"); - if (Convert.ToInt32(Msg.dwParam2) == CommandID.SELECT_TARGET) - { - var data = (byte[])Msg.dwParam1; - cmd_select_target pCmd = GPDataTypeHelper.FromBytes(data); - m_idSelTarget = pCmd.idTarget; - m_idUCSelTarget = 0; - } - else if (Convert.ToInt32(Msg.dwParam2) == CommandID.UNSELECT) - { - m_idSelTarget = 0; - } - } - - public void SetPos(Vector3 pos) - { - transform.position = pos; - - m_aabb.Center = EC_Utility.ToA3DVECTOR3(pos) + new A3DVECTOR3(0.0f, m_aabb.Extents.y, 0.0f); - m_aabb.CompleteMinsMaxs(); - m_aabbServer.Center = EC_Utility.ToA3DVECTOR3(pos) + new A3DVECTOR3(0.0f, m_aabbServer.Extents.y, 0.0f); - m_aabbServer.CompleteMinsMaxs(); - } - - public void SetStatusRun(bool value) - { - if (!isGrounded) - { - Debug.LogError("Player not in ground"); - return; - } - - isRun = value; - } - public override void SetUpPlayer() - { - base.SetUpPlayer(); - - m_IncantCnt = new CECCounter(); - m_IncantCnt.SetPeriod(1000); - m_IncantCnt.Reset(true); - } - public async void InitCharacter(cmd_self_info_1 role) - { - SetUpPlayer(); - controller = GetComponent(); - if (!controller) - { - BMLogger.LogError("HostPlayer InitCharacter no CharacterController"); - } - - //if (role.name != null && role.name.ByteArray != null) - //{ - // roleName = Encoding.UTF8.GetString(role.name.ByteArray, 0, role.name.Length); - //} - SetPlayerInfor(new INFO(role.cid, role.crc_e, role.crc_c)); - await SetPlayerModel(UnityGameSession.Instance.GetRoleInfo().occupation, UnityGameSession.Instance.GetRoleInfo().gender); - - Vector3 pos = new Vector3(role.pos.x, role.pos.y, role.pos.z); - string roleName = Encoding.Unicode.GetString(UnityGameSession.Instance.GetRoleInfo().name.ByteArray); - if (txtName != null) txtName.text = roleName; - EventBus.Publish(new InfoHostPlayer(roleName)); - transform.position = pos; - m_dwResFlags = (uint)PlayerResourcesReadyFlag.RESFG_ALL; - joystick = FindAnyObjectByType(); - EventBus.Subscribe(JoystickRelease); - EventBus.Subscribe(JoystickStartDrag); - if (TryGetComponent(out var visual)) - { - visual.InitPlayerEventDoneHandler(); - } - - m_aabb.Center = GPDataTypeHelper.g_vOrigin; - m_aabb.Extents.Set(0.3f, 0.9f, 0.3f); - m_aabbServer = m_aabb; - CalcPlayerAABB(); - SetPos(pos); - m_CDRInfo.fStepHeight = 0.8f; - //m_CDRInfo.vTPNormal = GroundCheck(out RaycastHit hit) ? hit.normal : Vector3.zero; - m_CDRInfo.vExtent = EC_Utility.ToVector3(m_aabbServer.Extents); - // Create work manager - m_pWorkMan = new CECHPWorkMan(this); - m_pWorkMan.StartWork_p0(m_pWorkMan.CreateWork(CECHPWork.Host_work_ID.WORK_STAND)); - /*if (IsDead()) - { - CECHPWorkDead pWork = (CECHPWorkDead*)m_pWorkMan->CreateWork(CECHPWork.Host_work_ID.WORK_DEAD); - pWork->SetBeDeadFlag(true); - m_pWorkMan->StartWork_p0(pWork); - } - else if (IsSitting()) - { - CECHPWorkSit* pWork = (CECHPWorkSit*)m_pWorkMan->CreateWork(CECHPWork.Host_work_ID.WORK_SIT); - pWork->SetBeSittingFlag(true); - m_pWorkMan->StartWork_p1(pWork); - }*/ - - LoadResources(); - if (m_pWorkMan == null) - { - return; - } - - LoadGfx(); - } - - public async void LoadGfx() - { - // Load GFX - var gfxCaster = EC_Game.GetGFXCaster(); - // m_pMoveTargetGFX = g_pGame->GetGFXCaster()->LoadGFXEx(res_GFXFile(RES_GFX_MOVETARGET)); - m_pSelectedGFX = await gfxCaster.LoadGFXEx(EC_Resource.res_GFXFile((int)GfxResourceType.RES_GFX_SELECTED)); - m_pHoverGFX = await gfxCaster.LoadGFXEx(EC_Resource.res_GFXFile((int)GfxResourceType.RES_GFX_CURSORHOVER)); - // m_pFloatDust = g_pGame->GetGFXCaster()->LoadGFXEx(res_GFXFile(RES_GFX_FLOATING_DUST)); - - if (true /*CECUIConfig::Instance().GetGameUI().bEnableActionSwitch*/) - { - m_pActionSwitcher = new CECActionSwitcher(this); - } - else - m_pActionSwitcher = new CECActionSwitcherBase(this); - - UnityGameSession.c2s_CmdGetAllData(true, true, false); - // TODO: Move this to right flow later , it's just for test now - UnityGameSession.c2s_CmdSendEnterPKPrecinct(); - } - - private void JoystickStartDrag(JoystickPressEvent joystickPressEvent) - { - _playerStateMachine.ChangeState(_moveState); - } - - private void OnDestroy() - { - EventBus.Unsubscribe(JoystickRelease); - EventBus.Unsubscribe(JoystickStartDrag); - } - - - //TODO: Remove this function. Since it has been deprecated. - public void InitCharacter(info_player_1 role) - { - string roleName = "(Error decoding name)"; - //if (role.name != null && role.name.ByteArray != null) - //{ - // roleName = Encoding.UTF8.GetString(role.name.ByteArray, 0, role.name.Length); - //} - Vector3 pos = new Vector3(role.pos.x, role.pos.y, role.pos.z); - if (txtName != null) txtName.text = roleName; - transform.position = pos; - // SetPlayerModel(); - //Debug.LogError("Pos Character = " + pos); - } - - private bool NormalAttackObject(int idTarget, bool bForceAttack, bool bMoreClose = false) - { - if (idTarget == 0 || idTarget == m_PlayerInfo.cid) - { - // We should have check target isn't dead - return false; - } - - //if (!EC_Game.GetGameRun().GetWorld().GetObject(idTarget, 1)) - // return false; - bool bStartNewWork = false; - - bool bUseAutoPF = false; - //CECPlayerWrapper* pWrapper = CECAutoPolicy::GetInstance().GetPlayerWrapper(); - //if (CECAutoPolicy::GetInstance().IsAutoPolicyEnabled() && pWrapper.GetAttackError() >= 2) - //bUseAutoPF = true; - - CECHPWorkTrace pWorkTrace = null; - CECHPWork pWork = null; - if ((pWork = m_pWorkMan.GetWork(CECHPWork.Host_work_ID.WORK_TRACEOBJECT)) != null) - { - pWorkTrace = pWork as CECHPWorkTrace; - } - else if ((pWork = m_pWorkMan.GetWork(CECHPWork.Host_work_ID.WORK_HACKOBJECT)) != null) - { - if ((pWork as CECHPWorkMelee).GetTarget() == idTarget) - return false; // Host is attacking the target - - pWorkTrace = (CECHPWorkTrace)m_pWorkMan.CreateWork(CECHPWork.Host_work_ID.WORK_TRACEOBJECT); - bStartNewWork = true; - } - else if (m_pWorkMan.CanStartWork(CECHPWork.Host_work_ID.WORK_TRACEOBJECT)) - { - pWorkTrace = (CECHPWorkTrace)m_pWorkMan.CreateWork(CECHPWork.Host_work_ID.WORK_TRACEOBJECT); - bStartNewWork = true; - } - - if (pWorkTrace != null) - { - pWorkTrace.SetTraceTarget( - pWorkTrace.CreatTraceTarget(idTarget, CECHPWorkTrace.Trace_reason.TRACE_ATTACK, bForceAttack), - bUseAutoPF); - pWorkTrace.SetMoveCloseFlag(bMoreClose); - - if (bStartNewWork) - m_pWorkMan.StartWork_p1(pWorkTrace); - return true; - } - - return false; - } - - public int AttackableJudge(int idTarget, bool bForceAttack) - { - if (CannotAttack()) - return 0; - - //if (CDlgAutoHelp::IsAutoHelp()) - // return 0; - - if (idTarget == 0 || idTarget == m_PlayerInfo.cid) - return -1; - - CECObject pObject = EC_ManMessageMono.Instance.GetObject(idTarget, 1); - if (!pObject) - return -1; - - // If target is pet, it's attacked possibility depends on it's monster - if (GPDataTypeHelper.ISNPCID(idTarget)) - { - CECNPC pNPC = (CECNPC)pObject; - int idMaster = pNPC.GetMasterID(); - if (idMaster != 0) - { - // master¿ÉÄÜÊÇhostplayer - if (idMaster == m_PlayerInfo.cid) - return 0; - - //// Follow pet cannot be attacked - //if (pNPC.IsPetNPC() && ((CECPet)pNPC).IsFollowPet()) - // return 0; - - idTarget = idMaster; - pObject = EC_ManMessageMono.Instance.GetObject(idTarget, 1); - if (!pObject) - return -1; } } - int iRet = 0; - - if (GPDataTypeHelper.ISNPCID(idTarget)) + public void OnMsgHstCorrectPos(in ECMSG Msg) { - CECNPC pNPC = (CECNPC)pObject; - - // If this npc is host's pet, cannot be attacked - //if (pNPC.GetMasterID() == m_PlayerInfo.cid) - // return 0; - - // If it's a pet and can not be attacked, pet can be attacked only if it's a fighting pet - //if (pNPC.IsPetNPC() && !((CECPet)pNPC).CanBeAttacked()) - // return 0; - - if (IsInBattle()) // Host is in battle - { - if (InSameBattleCamp(pNPC)) - iRet = 0; - else - { - if (pNPC.IsMonsterNPC()) - iRet = 1; - else if (pNPC.IsServerNPC() && - (IsInFortress() || pNPC.GetRoleInBattle() == 8)) // ¶Ô·þÎñÐÍNPCµÄ¹¥»÷£¬°ïÅÉ»ùµØ»ò³Çսʱ¿ÉÓà - iRet = 1; - else - iRet = 0; - } - } - else if (pNPC.IsServerNPC()) - { - // In sanctuary we cannot attack NPCs - if (!IsPVPOpen() || m_bInSanctuary || !bForceAttack) - iRet = 0; - else - iRet = 1; - } - else // Is monster - { - iRet = 1; - } - - if (iRet == 1 && pNPC.GetOwnerFaction() > 0) - { - // Õë¶Ô°ïÅÉ PVP Õ½ÕùÖнûÖ¹²¿·Ö¹¥»÷ - if (GetFactionID() == pNPC.GetOwnerFaction() || // ²»¹¥»÷ͬ°ï¹Ö - pNPC.IsFactionPVPMineCar() && !CanAttackFactionPVPMineCar() || // ÎÞ·¨ÔÙ¹¥»÷Ëû°ï¿ó³µÇé¿ö - pNPC.IsFactionPVPMineBase() && !CanAttackFactionPVPMineBase()) - { - // ÎÞ·¨ÔÙ¹¥»÷Ëû°ï´æ¿óµãÇé¿ö - iRet = 0; - } - } - } - // TO DO: fix later - //else if (GPDataTypeHelper.ISPLAYERID(idTarget)) - //{ - // // Check duel at first - // if (m_pvp.iDuelState == Duel_state.DUEL_ST_INDUEL && m_pvp.idDuelOpp == idTarget) - // return 1; - // else if (m_pvp.iDuelState == Duel_state.DUEL_ST_STOPPING && m_pvp.idDuelOpp == idTarget) - // return 0; - - // // In sanctuary we cannot attack other players - // if (m_bInSanctuary) - // return 0; - - // //ASSERT(pObject.GetClassID() == CECObject::OCID_ELSEPLAYER); - // EC_ElsePlayer pPlayer = (EC_ElsePlayer)pObject; - // ROLEBASICPROP bp = pPlayer.GetBasicProps(); - // EC_GAME_SETTING gs = g_pGame.GetConfigs().GetGameSettings(); - - // if (m_pvp.bFreePVP) - // { - // if (IsTeamMember(idTarget)) - // return 0; - - // // In free pvp mode, for example, host is in arena. - // if (bForceAttack) - // iRet = 1; - // else if (gs.bAtk_NoMafia && IsFactionMember(pPlayer.GetFactionID())) - // iRet = 0; - // else if (gs.bAtk_NoWhite && !pPlayer.IsInvader() && !pPlayer.IsPariah()) - // iRet = 0; - // else if (gs.bAtk_NoAlliance && g_pGame.GetFactionMan().IsFactionAlliance(pPlayer.GetFactionID())) - // iRet = 0; - // else if (gs.bAtk_NoForce && GetForce() > 0 && GetForce() == pPlayer.GetForce()) - // iRet = 0; - // else - // iRet = 1; - // } - // else if (m_iBattleCamp != GP_BATTLE_CAMP_NONE) - // { - // // Host is in battle - // int iCamp = pPlayer.GetBattleCamp(); - // if (iCamp != GP_BATTLE_CAMP_NONE && iCamp != m_iBattleCamp) - // iRet = 1; - // else - // iRet = 0; - // } - // else // Normal mode - // { - // if (IsTeamMember(idTarget)) - // return 0; - - // if (!IsPVPOpen() || !pPlayer.IsPVPOpen() || m_BasicProps.iLevel < EC_MAXNOPKLEVEL || bp.iLevel < EC_MAXNOPKLEVEL) - // iRet = 0; - // else if (bForceAttack) - // iRet = 1; - // else if (!gs.bAtk_Player) - // iRet = 0; - // else if (gs.bAtk_NoMafia && IsFactionMember(pPlayer.GetFactionID())) - // iRet = 0; - // else if (gs.bAtk_NoWhite && !pPlayer.IsInvader() && !pPlayer.IsPariah()) - // iRet = 0; - // else if (gs.bAtk_NoAlliance && g_pGame.GetFactionMan().IsFactionAlliance(pPlayer.GetFactionID())) - // iRet = 0; - // else if (gs.bAtk_NoForce && GetForce() > 0 && GetForce() == pPlayer.GetForce()) - // iRet = 0; - // else - // iRet = 1; - // } - //} - else - { - return -1; + Debug.LogWarning("HoangDev : OnMsgHstCorrectPos"); + byte[] buf = (byte[])Msg.dwParam1; // chỗ bạn lưu pDataBuf + GCHandle handle = GCHandle.Alloc(buf, GCHandleType.Pinned); + cmd_host_correct_pos pCmd = (cmd_host_correct_pos)Marshal.PtrToStructure( + handle.AddrOfPinnedObject(), typeof(cmd_host_correct_pos)); + handle.Free(); + Debug.LogWarning("HoangDev :pCmd.pos " + pCmd.pos); + SetPos(pCmd.pos); } - return iRet; - } - public CECActionSwitcherBase GetActionSwitcher() { return m_pActionSwitcher; } - private float A3d_Magnitude(A3DVECTOR3 v) - { - return Mathf.Sqrt(v.x * v.x + v.y * v.y + v.z * v.z); - } - - public int GetCharacterID() - { - return m_PlayerInfo.cid; - } - - public bool CannotAttack() - { - return (m_dwLIES & (uint)Logic_Influence_Extned_states.LIES_DISABLEFIGHT) != 0; - } - - public bool CanTouchTarget(A3DVECTOR3 vHostPos, A3DVECTOR3 vTargetPos, float fTargetRad, int iReason, - float fMaxCut = 1.0f) - { - float fDist = A3d_Magnitude(vTargetPos - vHostPos); - switch (iReason) + public void HandleRevive(short sReviveType, A3DVECTOR3 pos) { - case 1: // melee - { - float fRange; - if (fMaxCut >= 0.0f) - { - float fCutDist = m_ExtProps.ak.AttackRange * 0.3f; - if (fCutDist > fMaxCut) - fCutDist = fMaxCut; + // Move to revive position and play revive animation + PlayAction((int)PLAYER_ACTION_TYPE.ACT_REVIVE); + // Clear any running dead work if exists + m_pWorkMan?.FinishRunningWork(CECHPWork.Host_work_ID.WORK_DEAD); + // Clear corpse state so player is alive again + m_dwStates &= ~(uint)PlayerNPCState.GP_STATE_CORPSE; + } - fRange = m_ExtProps.ak.AttackRange - fCutDist; - } - else - { - fRange = m_ExtProps.ak.AttackRange * 0.7f; - } - // TO DO: fix later - fRange = 1f; - if (fDist - fTargetRad <= fRange) - return true; + public void OnMsgHstGoto(in ECMSG Msg) + { + Debug.Log("HoangDev :OnMsgHstGoto"); + PopupManager.Instance.OnPlayerRevived(); + // p1 is a byte[] buffer; parse into cmd_notify_hostpos then set position + byte[] buf = (byte[])Msg.dwParam1; + cmd_notify_hostpos pCmd = GPDataTypeHelper.FromBytes(buf); + SetPos(new Vector3(pCmd.vPos.x, pCmd.vPos.y, pCmd.vPos.z)); - break; - } - //case 2: // cast magic + } + + // Message MSG_HST_SELTARGET handler + void OnMsgHstSelTarget(ECMSG Msg) + { + //BMLogger.LogError("HoangDev: OnMsgHstSelTarget"); + if (Convert.ToInt32(Msg.dwParam2) == CommandID.SELECT_TARGET) + { + var data = (byte[])Msg.dwParam1; + cmd_select_target pCmd = GPDataTypeHelper.FromBytes(data); + m_idSelTarget = pCmd.idTarget; + m_idUCSelTarget = 0; + } + else if (Convert.ToInt32(Msg.dwParam2) == CommandID.UNSELECT) + { + m_idSelTarget = 0; + } + } + + public void SetPos(Vector3 pos) + { + transform.position = pos; + + m_aabb.Center = EC_Utility.ToA3DVECTOR3(pos) + new A3DVECTOR3(0.0f, m_aabb.Extents.y, 0.0f); + m_aabb.CompleteMinsMaxs(); + m_aabbServer.Center = EC_Utility.ToA3DVECTOR3(pos) + new A3DVECTOR3(0.0f, m_aabbServer.Extents.y, 0.0f); + m_aabbServer.CompleteMinsMaxs(); + } + + public void SetStatusRun(bool value) + { + if (!isGrounded) + { + Debug.LogError("Player not in ground"); + return; + } + + isRun = value; + } + public override void SetUpPlayer() + { + base.SetUpPlayer(); + + m_IncantCnt = new CECCounter(); + m_IncantCnt.SetPeriod(1000); + m_IncantCnt.Reset(true); + } + + public async void InitCharacter(cmd_self_info_1 role) + { + SetUpPlayer(); + controller = GetComponent(); + if (!controller) + { + BMLogger.LogError("HostPlayer InitCharacter no CharacterController"); + } + + //if (role.name != null && role.name.ByteArray != null) //{ - // if (m_pPrepSkill) - // { - // float fRange = m_pPrepSkill.GetCastRange(m_ExtProps.ak.AttackRange, GetPrayDistancePlus()); - // if (fRange > 0.0f) - // { - // if (fDist - fTargetRad <= fRange) - // return true; - // } - // else - // return true; - // } - - // break; + // roleName = Encoding.UTF8.GetString(role.name.ByteArray, 0, role.name.Length); //} - case 3: // talk - { - if (fDist - fTargetRad <= 5.0f) - return true; + SetPlayerInfor(new INFO(role.cid, role.crc_e, role.crc_c)); + await SetPlayerModel(UnityGameSession.Instance.GetRoleInfo().occupation, UnityGameSession.Instance.GetRoleInfo().gender); - break; - } - default: // no special reason - { - if (fDist < (fTargetRad + m_fTouchRad) * 3.0f) - return true; - - break; - } - } - - return false; - } - - public void RemoveObjectFromTabSels(CECObject pObject) - { - for (int i = 0; i < m_aTabSels.Count; i++) - { - if (m_aTabSels[i] == pObject) + Vector3 pos = new Vector3(role.pos.x, role.pos.y, role.pos.z); + string roleName = Encoding.Unicode.GetString(UnityGameSession.Instance.GetRoleInfo().name.ByteArray); + if (txtName != null) txtName.text = roleName; + EventBus.Publish(new InfoHostPlayer(roleName)); + transform.position = pos; + m_dwResFlags = (uint)PlayerResourcesReadyFlag.RESFG_ALL; + joystick = FindAnyObjectByType(); + EventBus.Subscribe(JoystickRelease); + EventBus.Subscribe(JoystickStartDrag); + if (TryGetComponent(out var visual)) { - m_aTabSels.RemoveAt(i); - break; + visual.InitPlayerEventDoneHandler(); } - } - } - public bool CanTouchTarget(A3DVECTOR3 vTargetPos, float fTargetRad, int iReason, float fMaxCut = 1.0f) - { - A3DVECTOR3 vector = new A3DVECTOR3(gameObject.transform.position.x, gameObject.transform.position.y, - gameObject.transform.position.z); - return CanTouchTarget(vector, vTargetPos, fTargetRad, iReason, fMaxCut); - } - - public bool IsRooting() - { - var mask = (uint)(Logic_Influence_Extned_states.LIES_ROOT - | Logic_Influence_Extned_states.LIES_SLEEP - | Logic_Influence_Extned_states.LIES_STUN); - return (m_dwLIES & mask) != 0; - } - - bool IsInFortress() - { - return m_fortressEnter.role_in_war != 0; - } - - bool IsPVPOpen() - { - return m_pvp.bEnable; - } - - // Get faction ID - int GetFactionID() - { - return m_idFaction; - } - - public bool IsJumping() - { - return m_iJumpCount > 0; - } - - public bool IsPlayingAction(int iAction) - { - if (iAction == (int)PLAYER_ACTION_TYPE.ACT_WALK && _playerStateMachine.State is PlayerMoveState) - { - return true; - } - - if (iAction == (int)PLAYER_ACTION_TYPE.ACT_STAND && _playerStateMachine.State is PlayerIdleState) - { - return true; - } - - return false; - } - - public void ResetJump() - { - m_iJumpCount = 0; - m_bJumpInWater = false; - } - - // Get move speed - public float GetFlySpeed() - { - return m_ExtProps.mv.flight_speed; - } - - public float GetSwimSpeed() - { - return m_ExtProps.mv.swim_speed; - } - public bool ApplySkillShortcut(int idSkill, bool bCombo = false /* false */, - int idSelTarget = 0/* 0 */, int iForceAtk = -1/* -1 */) - { - //StackChecker::ACTrace(4); - - if (m_pActionSwitcher != null) - m_pActionSwitcher.PostMessge((int)EMsgActionSwitcher.MSG_CASTSKILL); - - // Return-town skill is very special, handle it separately - //if (idSkill == ID_RETURNTOWN_SKILL) - // return ReturnToTargetTown(0, bCombo); - - //if (idSkill == ID_SUMMONPLAYER_SKILL) - // return SummonPlayer(idSelTarget, bCombo); - - //if (!CanDo(CANDO_SPELLMAGIC)) - // return false; - - //if (InSlidingState()) - // return false; - - if (!bCombo) - //ClearComboSkill(); - - if (idSelTarget == 0) - idSelTarget = m_idSelTarget; - - CECSkill pSkill = GetPositiveSkillByID(idSkill); - if (pSkill == null) pSkill = GetEquipSkillByID(idSkill); - if (pSkill == null) pSkill = CECComboSkillState.Instance.GetInherentSkillByID((uint)idSkill); - if (pSkill == null) - { - return false; - } - - //// If we press a chargeable skill again when it's being charged, - //// we cast it out at once - //if (IsSpellingMagic() && m_pCurSkill && m_pCurSkill->IsCharging() && - // m_pCurSkill->GetSkillID() == pSkill->GetSkillID()) - //{ - // m_pCurSkill->EndCharging(); - // g_pGame->GetGameSession()->c2s_CmdContinueAction(); - // return true; - //} - - //int iCon = CheckSkillCastCondition(pSkill); - //if (iCon) - //{ - // ProcessSkillCondition(iCon); - // return false; - //} - - //// Get force attack flag - bool bForceAttack = false; - //if (iForceAtk < 0) - // bForceAttack = glb_GetForceAttackFlag(0); - //else - // bForceAttack = iForceAtk > 0 ? true : false; - - //// Check negative effect skill - //if (pSkill->GetType() == CECSkill::TYPE_ATTACK || pSkill->GetType() == CECSkill::TYPE_CURSE) - //{ - // if (idSelTarget == m_PlayerInfo.cid) - // { - // // Host cannot spell negative effect magic to himself. - // g_pGame->GetGameRun()->AddFixedChannelMsg(FIXMSG_TARGETWRONG, GP_CHAT_FIGHT); - // return false; - // } - // else if (idSelTarget) - // { - // if (AttackableJudge(idSelTarget, bForceAttack) != 1) - // return false; - // } - //} - - //// Check whether target type match - int idCastTarget = idSelTarget; - int iTargetType = pSkill.GetTargetType(); - - //if (pSkill->GetType() == CECSkill::TYPE_BLESS || - // pSkill->GetType() == CECSkill::TYPE_NEUTRALBLESS) - //{ - // if (!iTargetType || !ISPLAYERID(idSelTarget)) - // idCastTarget = m_PlayerInfo.cid; - - // // In some case, we shouldn't add bless effect to other players - // if (ISPLAYERID(idCastTarget) && idCastTarget != m_PlayerInfo.cid) - // { - // // If host has set bless skill filter only to himself, bless skill couldn't add to other players - // BYTE byBLSMask = glb_BuildBLSMask(); - - // if (pSkill->GetRangeType() == CECSkill::RANGE_POINT) - // { - // if (!IsTeamMember(idCastTarget)) - // { - // if (byBLSMask & GP_BLSMASK_SELF) - // idCastTarget = m_PlayerInfo.cid; - // else - // { - // CECElsePlayer* pPlayer = (CECElsePlayer*)g_pGame->GetGameRun()->GetWorld()->GetPlayerMan()->GetPlayer(idCastTarget); - // if (!pPlayer) - // { - // // Ä¿±êÏûʧ - // return false; - // } - - // if (pPlayer->IsInvader() || pPlayer->IsPariah()) - // { - // if (byBLSMask & GP_BLSMASK_NORED) - // idCastTarget = m_PlayerInfo.cid; - // } - - // if (!IsFactionMember(pPlayer->GetFactionID())) - // { - // if (byBLSMask & GP_BLSMASK_NOMAFIA) - // idCastTarget = m_PlayerInfo.cid; - // } - - // if (!IsFactionAllianceMember(pPlayer->GetFactionID())) - // { - // if (byBLSMask & GP_BLSMASK_NOALLIANCE) - // idCastTarget = m_PlayerInfo.cid; - // } - // if (GetForce() != pPlayer->GetForce()) - // { - // if (byBLSMask & GP_BLSMASK_NOFORCE) - // idCastTarget = m_PlayerInfo.cid; - // } - // } - // } - // } - - // // If host is in duel, bless skill couldn't add to opponent - // if (IsInDuel() && idSelTarget == m_pvp.idDuelOpp) - // idCastTarget = m_PlayerInfo.cid; - - // // If host is in battle, bless skill couldn't add to enemies - // if (IsInBattle()) - // { - // CECElsePlayer* pPlayer = m_pPlayerMan->GetElsePlayer(idCastTarget); - // if (!InSameBattleCamp(pPlayer)) - // idCastTarget = m_PlayerInfo.cid; - // } - // } - //} - //else if (pSkill->GetType() == CECSkill::TYPE_BLESSPET) - //{ - // CECPet* pPet = g_pGame->GetGameRun()->GetWorld()->GetNPCMan()->GetPetByID(idSelTarget); - // if (!pPet || pPet->GetMasterID() == GetCharacterID()) - // { - // // Spell skill on host's pet - // CECPetData* pPetData = m_pPetCorral->GetActivePet(); - // if (!pPetData || - // pPetData->GetClass() != GP_PET_CLASS_COMBAT && - // pPetData->GetClass() != GP_PET_CLASS_SUMMON && - // pPetData->GetClass() != GP_PET_CLASS_EVOLUTION) - // return false; - - // idCastTarget = m_pPetCorral->GetActivePetNPCID(); - // } - // // Only fighting pet can be blessed. - // if (pPet && !pPet->CanBeAttacked()) - // return false; - //} - //else - //{ - // if (iTargetType != 0 && !idCastTarget) - // return false; - //} - - //// iTargetType == 4 means target must be pet. The problem is that pet will - //// disappear from world after it died, so GetWorld()->GetObject() will return - //// NULL when host spells revive-pet skill on his dead pet. So, the target - //// type of revive-pet skill should be 0 - //if (iTargetType) - //{ - // // Target shoundn't be a corpse ? - // int iAliveFlag = 0; - // if (iTargetType == 1) - // iAliveFlag = 1; - // else if (iTargetType == 2) - // iAliveFlag = 2; - - // CECObject* pObject = g_pGame->GetGameRun()->GetWorld()->GetObject(idCastTarget, iAliveFlag); - // if (!pObject) - // return false; - //} - - //if (!IsMeleeing() && !IsSpellingMagic() && - // (!iTargetType || idCastTarget == m_PlayerInfo.cid)) - //{ - // // Cast this skill need't checking cast distance - // if (!pSkill->ReadyToCast()) - // return false; - - // // Prepare to cast skill, if skill isn't INSTANT and FLASHMOVE, - // // we must stop moving and stand - // if (!pSkill->IsInstant() && pSkill->GetType() != CECSkill::TYPE_FLASHMOVE) - // { - // if (!NaturallyStopMoving()) - // return false; // Couldn't stop naturally, so cancel casting skill - // } - // else if (pSkill->GetType() == CECSkill::TYPE_FLASHMOVE) - // { - // if (!CanDo(CANDO_FLASHMOVE)) - // return false; - // } - - m_pPrepSkill = pSkill; - //CastSkill(m_idSelTarget, bForceAttack); - //} - //else if (IsSpellingMagic() && m_pCurSkill == pSkill) - //{ - // // If we are casting the same skill and it's in cooling time - // return false; - //} - //else // Have to trace selected object before cast skill - //{ - // if (!pSkill->ReadyToCast()) - // return false; - - // if (CECCastSkillWhenMove::Instance().IsSkillSupported(pSkill->GetSkillID(), this) && - // m_pWorkMan->IsMovingToPosition() && - // m_pWorkMan->CanCastSkillImmediately(pSkill->GetSkillID())) - // { - // m_pPrepSkill = pSkill; - // return CastSkill(idCastTarget, bForceAttack); - // } - // else - // { - bool bTraceOK = false; - bool bUseAutoPF = false; - /* CECPlayerWrapper* pWrapper = CECAutoPolicy::GetInstance().GetPlayerWrapper(); - if (CECAutoPolicy::GetInstance().IsAutoPolicyEnabled() && pWrapper->GetAttackError() >= 2) - bUseAutoPF = true;*/ - - if (idCastTarget == 0) - { - idCastTarget = GetCharacterID(); // ±ÜÃâË²ÒÆµÈ¼¼ÄÜʱ idCastTarget Ϊ0µ¼Ö CECWorkTrace::CreateTraceTarget ·µ»Ø¿Õ - } - CECHPWork pWork = m_pWorkMan.GetWork(Host_work_ID.WORK_TRACEOBJECT); - if (pWork != null) - { - CECHPWorkTrace pWorkTrace = (CECHPWorkTrace)(pWork); - if (pWorkTrace.GetTraceReason() == Trace_reason.TRACE_SPELL && - pWorkTrace.GetTarget() == idCastTarget && - pWorkTrace.GetPrepSkill() == pSkill) - return false; // We are just doing the same thing - - pWorkTrace.SetTraceTarget(pWorkTrace.CreatTraceTarget(idCastTarget, Trace_reason.TRACE_SPELL, bForceAttack), bUseAutoPF); - pWorkTrace.SetPrepSkill(pSkill); - bTraceOK = true; - } - else if (m_pWorkMan.CanStartWork(Host_work_ID.WORK_TRACEOBJECT)) - { - CECHPWorkTrace pWork2 = (CECHPWorkTrace)m_pWorkMan.CreateWork(Host_work_ID.WORK_TRACEOBJECT); - pWork2.SetTraceTarget(pWork2.CreatTraceTarget(idCastTarget, Trace_reason.TRACE_SPELL, bForceAttack), bUseAutoPF); - pWork2.SetPrepSkill(pSkill); - m_pWorkMan.StartWork_p1(pWork2); - bTraceOK = true; - } - - if (!bTraceOK) return false; - // } - //} - - return true; - } - - public bool CastSkill(int idTarget, bool bForceAttack, CECObject pTarget = null) - { - byte byPVPMask = glb_BuildPVPMask(bForceAttack); - UnityGameSession.c2s_CmdCastSkill(m_pPrepSkill.GetSkillID(), byPVPMask, 1, idTarget); - return true; - } - public byte glb_BuildPVPMask(bool bForceAttack) - { - byte byMask = 0; - if (bForceAttack) - byMask |= (byte)PVPMask.GP_PVPMASK_FORCE; - else - { - /* CECConfigs pConfigs = EC_Game.GetConfigs(); - - if (pConfigs->GetGameSettings().bAtk_Player) - { - byMask |= GP_PVPMASK_FORCE; - - if (pConfigs->GetGameSettings().bAtk_NoMafia) - byMask |= GP_PVPMASK_NOMAFIA; - - if (pConfigs->GetGameSettings().bAtk_NoWhite) - byMask |= GP_PVPMASK_NOWHITE; - - if (pConfigs->GetGameSettings().bAtk_NoAlliance) - byMask |= GP_PVPMASK_NOALLIANCE; - - if (pConfigs->GetGameSettings().bAtk_NoForce) - byMask |= GP_PVPMASK_NOFORCE; - }*/ - } - - return byMask; - } - public bool SelectTarget(int idTarget) - { - //BMLogger.LogError("HoangDev: HostPlayer SelectTarget"); - bool bRet = false; - bool canDo = CanDo(ActionCanDo.CANDO_CHANGESELECT); - bool canselect = CanSelectTarget(idTarget); - if (canDo && canselect) - { - bRet = true; - if (idTarget == 0) + m_aabb.Center = GPDataTypeHelper.g_vOrigin; + m_aabb.Extents.Set(0.3f, 0.9f, 0.3f); + m_aabbServer = m_aabb; + CalcPlayerAABB(); + SetPos(pos); + m_CDRInfo.fStepHeight = 0.8f; + //m_CDRInfo.vTPNormal = GroundCheck(out RaycastHit hit) ? hit.normal : Vector3.zero; + m_CDRInfo.vExtent = EC_Utility.ToVector3(m_aabbServer.Extents); + // Create work manager + m_pWorkMan = new CECHPWorkMan(this); + m_pWorkMan.StartWork_p0(m_pWorkMan.CreateWork(CECHPWork.Host_work_ID.WORK_STAND)); + /*if (IsDead()) { - //BMLogger.LogError("HoangDev: HostPlayer Unsetlect npc"); - UnityGameSession.c2s_CmdUnselect(); + CECHPWorkDead pWork = (CECHPWorkDead*)m_pWorkMan->CreateWork(CECHPWork.Host_work_ID.WORK_DEAD); + pWork->SetBeDeadFlag(true); + m_pWorkMan->StartWork_p0(pWork); + } + else if (IsSitting()) + { + CECHPWorkSit* pWork = (CECHPWorkSit*)m_pWorkMan->CreateWork(CECHPWork.Host_work_ID.WORK_SIT); + pWork->SetBeSittingFlag(true); + m_pWorkMan->StartWork_p1(pWork); + }*/ + + LoadResources(); + if (m_pWorkMan == null) + { + return; + } + + LoadGfx(); + } + + public async void LoadGfx() + { + // Load GFX + var gfxCaster = EC_Game.GetGFXCaster(); + // m_pMoveTargetGFX = g_pGame->GetGFXCaster()->LoadGFXEx(res_GFXFile(RES_GFX_MOVETARGET)); + m_pSelectedGFX = await gfxCaster.LoadGFXEx(EC_Resource.res_GFXFile((int)GfxResourceType.RES_GFX_SELECTED)); + m_pHoverGFX = await gfxCaster.LoadGFXEx(EC_Resource.res_GFXFile((int)GfxResourceType.RES_GFX_CURSORHOVER)); + // m_pFloatDust = g_pGame->GetGFXCaster()->LoadGFXEx(res_GFXFile(RES_GFX_FLOATING_DUST)); + + if (true /*CECUIConfig::Instance().GetGameUI().bEnableActionSwitch*/) + { + m_pActionSwitcher = new CECActionSwitcher(this); } else + m_pActionSwitcher = new CECActionSwitcherBase(this); + + UnityGameSession.c2s_CmdGetAllData(true, true, false); + // TODO: Move this to right flow later , it's just for test now + UnityGameSession.c2s_CmdSendEnterPKPrecinct(); + } + + private void JoystickStartDrag(JoystickPressEvent joystickPressEvent) + { + _playerStateMachine.ChangeState(_moveState); + } + + private void OnDestroy() + { + EventBus.Unsubscribe(JoystickRelease); + EventBus.Unsubscribe(JoystickStartDrag); + } + + + //TODO: Remove this function. Since it has been deprecated. + public void InitCharacter(info_player_1 role) + { + string roleName = "(Error decoding name)"; + //if (role.name != null && role.name.ByteArray != null) + //{ + // roleName = Encoding.UTF8.GetString(role.name.ByteArray, 0, role.name.Length); + //} + Vector3 pos = new Vector3(role.pos.x, role.pos.y, role.pos.z); + if (txtName != null) txtName.text = roleName; + transform.position = pos; + // SetPlayerModel(); + //Debug.LogError("Pos Character = " + pos); + } + + private bool NormalAttackObject(int idTarget, bool bForceAttack, bool bMoreClose = false) + { + if (idTarget == 0 || idTarget == m_PlayerInfo.cid) { - //BMLogger.LogError("HoangDev: HostPlayer setlect npc"); - UnityGameSession.c2s_CmdSelectTarget(idTarget); + // We should have check target isn't dead + return false; } - } - return bRet; - } - public CECSkill GetPositiveSkillByID(int id, bool bSenior = false) - { - CECSkill pSenior = null; + //if (!EC_Game.GetGameRun().GetWorld().GetObject(idTarget, 1)) + // return false; + bool bStartNewWork = false; - for (int i = 0; i < m_aPtSkills.Count; i++) - { - if (m_aPtSkills[i].GetSkillID() == id) - return m_aPtSkills[i]; - else if (m_aPtSkills[i].GetJunior().Find((uint)id)) - pSenior = m_aPtSkills[i]; - } + bool bUseAutoPF = false; + //CECPlayerWrapper* pWrapper = CECAutoPolicy::GetInstance().GetPlayerWrapper(); + //if (CECAutoPolicy::GetInstance().IsAutoPolicyEnabled() && pWrapper.GetAttackError() >= 2) + //bUseAutoPF = true; - if (bSenior && pSenior != null) - return pSenior; - - return null; - } - - // C# conversion of CECHostPlayer::GetEquipSkillByID - // Assumes: GetEquipSkillNum() returns the count of equipment skills - // GetEquipSkillByIndex(int) returns a CECSkill at the given index - public CECSkill GetEquipSkillByID(int id) - { - CECSkill pRet = null; - - for (int i = 0; i < GetEquipSkillNum(); i++) - { - CECSkill pSkill = GetEquipSkillByIndex(i); - if (pSkill != null && pSkill.GetSkillID() == id) + CECHPWorkTrace pWorkTrace = null; + CECHPWork pWork = null; + if ((pWork = m_pWorkMan.GetWork(CECHPWork.Host_work_ID.WORK_TRACEOBJECT)) != null) { - pRet = pSkill; - break; + pWorkTrace = pWork as CECHPWorkTrace; } + else if ((pWork = m_pWorkMan.GetWork(CECHPWork.Host_work_ID.WORK_HACKOBJECT)) != null) + { + if ((pWork as CECHPWorkMelee).GetTarget() == idTarget) + return false; // Host is attacking the target + + pWorkTrace = (CECHPWorkTrace)m_pWorkMan.CreateWork(CECHPWork.Host_work_ID.WORK_TRACEOBJECT); + bStartNewWork = true; + } + else if (m_pWorkMan.CanStartWork(CECHPWork.Host_work_ID.WORK_TRACEOBJECT)) + { + pWorkTrace = (CECHPWorkTrace)m_pWorkMan.CreateWork(CECHPWork.Host_work_ID.WORK_TRACEOBJECT); + bStartNewWork = true; + } + + if (pWorkTrace != null) + { + pWorkTrace.SetTraceTarget( + pWorkTrace.CreatTraceTarget(idTarget, CECHPWorkTrace.Trace_reason.TRACE_ATTACK, bForceAttack), + bUseAutoPF); + pWorkTrace.SetMoveCloseFlag(bMoreClose); + + if (bStartNewWork) + m_pWorkMan.StartWork_p1(pWorkTrace); + return true; + } + + return false; } - return pRet; - } - public int GetEquipSkillNum() { return m_aEquipSkills.Count; } - public CECSkill GetEquipSkillByIndex(int n) { return m_aEquipSkills[n]; } - bool CanSelectTarget(int idTarget) - { - if (idTarget == 0 || idTarget == this.GetCharacterID()) + public int AttackableJudge(int idTarget, bool bForceAttack) { - // 0 means unselect + if (CannotAttack()) + return 0; + + //if (CDlgAutoHelp::IsAutoHelp()) + // return 0; + + if (idTarget == 0 || idTarget == m_PlayerInfo.cid) + return -1; + + CECObject pObject = EC_ManMessageMono.Instance.GetObject(idTarget, 1); + if (!pObject) + return -1; + + // If target is pet, it's attacked possibility depends on it's monster + if (GPDataTypeHelper.ISNPCID(idTarget)) + { + CECNPC pNPC = (CECNPC)pObject; + int idMaster = pNPC.GetMasterID(); + if (idMaster != 0) + { + // master¿ÉÄÜÊÇhostplayer + if (idMaster == m_PlayerInfo.cid) + return 0; + + //// Follow pet cannot be attacked + //if (pNPC.IsPetNPC() && ((CECPet)pNPC).IsFollowPet()) + // return 0; + + idTarget = idMaster; + pObject = EC_ManMessageMono.Instance.GetObject(idTarget, 1); + if (!pObject) + return -1; + } + } + + int iRet = 0; + + if (GPDataTypeHelper.ISNPCID(idTarget)) + { + CECNPC pNPC = (CECNPC)pObject; + + // If this npc is host's pet, cannot be attacked + //if (pNPC.GetMasterID() == m_PlayerInfo.cid) + // return 0; + + // If it's a pet and can not be attacked, pet can be attacked only if it's a fighting pet + //if (pNPC.IsPetNPC() && !((CECPet)pNPC).CanBeAttacked()) + // return 0; + + if (IsInBattle()) // Host is in battle + { + if (InSameBattleCamp(pNPC)) + iRet = 0; + else + { + if (pNPC.IsMonsterNPC()) + iRet = 1; + else if (pNPC.IsServerNPC() && + (IsInFortress() || pNPC.GetRoleInBattle() == 8)) // ¶Ô·þÎñÐÍNPCµÄ¹¥»÷£¬°ïÅÉ»ùµØ»ò³Çսʱ¿ÉÓà + iRet = 1; + else + iRet = 0; + } + } + else if (pNPC.IsServerNPC()) + { + // In sanctuary we cannot attack NPCs + if (!IsPVPOpen() || m_bInSanctuary || !bForceAttack) + iRet = 0; + else + iRet = 1; + } + else // Is monster + { + iRet = 1; + } + + if (iRet == 1 && pNPC.GetOwnerFaction() > 0) + { + // Õë¶Ô°ïÅÉ PVP Õ½ÕùÖнûÖ¹²¿·Ö¹¥»÷ + if (GetFactionID() == pNPC.GetOwnerFaction() || // ²»¹¥»÷ͬ°ï¹Ö + pNPC.IsFactionPVPMineCar() && !CanAttackFactionPVPMineCar() || // ÎÞ·¨ÔÙ¹¥»÷Ëû°ï¿ó³µÇé¿ö + pNPC.IsFactionPVPMineBase() && !CanAttackFactionPVPMineBase()) + { + // ÎÞ·¨ÔÙ¹¥»÷Ëû°ï´æ¿óµãÇé¿ö + iRet = 0; + } + } + } + // TO DO: fix later + //else if (GPDataTypeHelper.ISPLAYERID(idTarget)) + //{ + // // Check duel at first + // if (m_pvp.iDuelState == Duel_state.DUEL_ST_INDUEL && m_pvp.idDuelOpp == idTarget) + // return 1; + // else if (m_pvp.iDuelState == Duel_state.DUEL_ST_STOPPING && m_pvp.idDuelOpp == idTarget) + // return 0; + + // // In sanctuary we cannot attack other players + // if (m_bInSanctuary) + // return 0; + + // //ASSERT(pObject.GetClassID() == CECObject::OCID_ELSEPLAYER); + // EC_ElsePlayer pPlayer = (EC_ElsePlayer)pObject; + // ROLEBASICPROP bp = pPlayer.GetBasicProps(); + // EC_GAME_SETTING gs = g_pGame.GetConfigs().GetGameSettings(); + + // if (m_pvp.bFreePVP) + // { + // if (IsTeamMember(idTarget)) + // return 0; + + // // In free pvp mode, for example, host is in arena. + // if (bForceAttack) + // iRet = 1; + // else if (gs.bAtk_NoMafia && IsFactionMember(pPlayer.GetFactionID())) + // iRet = 0; + // else if (gs.bAtk_NoWhite && !pPlayer.IsInvader() && !pPlayer.IsPariah()) + // iRet = 0; + // else if (gs.bAtk_NoAlliance && g_pGame.GetFactionMan().IsFactionAlliance(pPlayer.GetFactionID())) + // iRet = 0; + // else if (gs.bAtk_NoForce && GetForce() > 0 && GetForce() == pPlayer.GetForce()) + // iRet = 0; + // else + // iRet = 1; + // } + // else if (m_iBattleCamp != GP_BATTLE_CAMP_NONE) + // { + // // Host is in battle + // int iCamp = pPlayer.GetBattleCamp(); + // if (iCamp != GP_BATTLE_CAMP_NONE && iCamp != m_iBattleCamp) + // iRet = 1; + // else + // iRet = 0; + // } + // else // Normal mode + // { + // if (IsTeamMember(idTarget)) + // return 0; + + // if (!IsPVPOpen() || !pPlayer.IsPVPOpen() || m_BasicProps.iLevel < EC_MAXNOPKLEVEL || bp.iLevel < EC_MAXNOPKLEVEL) + // iRet = 0; + // else if (bForceAttack) + // iRet = 1; + // else if (!gs.bAtk_Player) + // iRet = 0; + // else if (gs.bAtk_NoMafia && IsFactionMember(pPlayer.GetFactionID())) + // iRet = 0; + // else if (gs.bAtk_NoWhite && !pPlayer.IsInvader() && !pPlayer.IsPariah()) + // iRet = 0; + // else if (gs.bAtk_NoAlliance && g_pGame.GetFactionMan().IsFactionAlliance(pPlayer.GetFactionID())) + // iRet = 0; + // else if (gs.bAtk_NoForce && GetForce() > 0 && GetForce() == pPlayer.GetForce()) + // iRet = 0; + // else + // iRet = 1; + // } + //} + else + { + return -1; + } + + return iRet; + } + public CECActionSwitcherBase GetActionSwitcher() { return m_pActionSwitcher; } + private float A3d_Magnitude(A3DVECTOR3 v) + { + return Mathf.Sqrt(v.x * v.x + v.y * v.y + v.z * v.z); + } + + // Load configs data (shortcut, etc.) from specified buffer + // Converted from: bool CECHostPlayer::LoadConfigData(const void* pDataBuf) + public bool LoadConfigData(byte[] dataBuf) + { + if (dataBuf == null || dataBuf.Length < sizeof(uint)) + return false; + + int offset = 0; + + // Version number + uint dwVer = BitConverter.ToUInt32(dataBuf, offset); + offset += sizeof(uint); + if (dwVer > HostCfgConstants.HOSTCFG_VERSION) + { + return false; + } + + // Load shortcut configs... + int iHostSCSets1 = (dwVer <= 4) ? 3 : HostCfgConstants.NUM_HOSTSCSETS1; + + for (int i = 0; i < iHostSCSets1; i++) + { + if (offset >= dataBuf.Length) + return false; + + int consumed = ReadShortcutSetSegment(dataBuf, offset, dwVer); + if (consumed <= 0 || offset + consumed > dataBuf.Length) + return false; + + if (m_aSCSets1[i] == null) + { + m_aSCSets1[i] = new CECShortcutSet(); + m_aSCSets1[i].Init(HostCfgConstants.SIZE_HOSTSCSET1); + } + + // Slice the set data and delegate to set loader + byte[] setBytes = new byte[consumed]; + Buffer.BlockCopy(dataBuf, offset, setBytes, 0, consumed); + if (!m_aSCSets1[i].LoadConfigData(setBytes, dwVer)) + return false; + + offset += consumed; + } + + for (int i = 0; i < HostCfgConstants.NUM_HOSTSCSETS2; i++) + { + if (offset >= dataBuf.Length) + break; // No more data; tolerate truncated optional parts + + int consumed = ReadShortcutSetSegment(dataBuf, offset, dwVer); + if (consumed <= 0 || offset + consumed > dataBuf.Length) + break; + + if (m_aSCSets2[i] == null) + { + m_aSCSets2[i] = new CECShortcutSet(); + m_aSCSets2[i].Init(HostCfgConstants.SIZE_HOSTSCSET2); + } + + byte[] setBytes = new byte[consumed]; + Buffer.BlockCopy(dataBuf, offset, setBytes, 0, consumed); + if (!m_aSCSets2[i].LoadConfigData(setBytes, dwVer)) + return false; + + offset += consumed; + } + + // Notes: + // - Auto fashion sets, system module shortcut sets, booth packs, and AutoYinpiao + // sections from native are not loaded here in this Unity port yet. + // The native format appends these after the two shortcut-set groups. + // We intentionally ignore them safely for now. + return true; } - CECObject pTarget = null; - if (GPDataTypeHelper.ISPLAYERID(idTarget)) + // Helper to compute the byte length of one serialized CECShortcutSet segment, + // based on the native serialization format (ends with slot = -1 sentinel). + private static int ReadShortcutSetSegment(byte[] data, int startOffset, uint version) { - EC_ElsePlayer pElsePlayer = - (EC_ManMessageMono.Instance.GetECManPlayer.GetPlayer(idTarget)) as EC_ElsePlayer; - if (pElsePlayer != null) + int offset = startOffset; + int length = data.Length; + + while (offset + sizeof(int) <= length) { - if (CanSafelySelect(pElsePlayer)) + int slot = BitConverter.ToInt32(data, offset); + offset += sizeof(int); + if (slot < 0) + break; // end flag + + if (offset + sizeof(int) > length) return -1; + int type = BitConverter.ToInt32(data, offset); + offset += sizeof(int); + + switch (type) { - pTarget = pElsePlayer; + case (int)CECShortcut.ShortcutType.SCT_COMMAND: + // command id + if (offset + sizeof(int) > length) return -1; + offset += sizeof(int); + // optional param since version >= 2 + if (version >= 2) + { + if (offset + sizeof(int) > length) return -1; + offset += sizeof(int); + } + break; + case (int)CECShortcut.ShortcutType.SCT_SKILL: + if (offset + sizeof(int) > length) return -1; + offset += sizeof(int); + break; + case (int)CECShortcut.ShortcutType.SCT_ITEM: + // iIvtr, iIvtrSlot, idItem + if (offset + sizeof(int) * 3 > length) return -1; + offset += sizeof(int) * 3; + break; + case (int)CECShortcut.ShortcutType.SCT_SKILLGRP: + if (version >= 3) + { + if (offset + sizeof(int) > length) return -1; + offset += sizeof(int); + } + break; + case (int)CECShortcut.ShortcutType.SCT_PET: + if (version >= 4) + { + if (offset + sizeof(int) > length) return -1; + offset += sizeof(int); + } + break; + case (int)CECShortcut.ShortcutType.SCT_AUTOFASHION: + if (version >= 5) + { + if (offset + sizeof(int) > length) return -1; + offset += sizeof(int); + } + break; + case (int)CECShortcut.ShortcutType.SCT_SYSMODULE: + if (version > 10) + { + if (offset + sizeof(int) > length) return -1; + offset += sizeof(int); + } + break; + default: + // Unknown type; abort to avoid infinite loop + return -1; } } + + return offset - startOffset; } - else if (GPDataTypeHelper.ISNPCID(idTarget)) + + public int GetCharacterID() { - CECNPC pNPC = EC_ManMessageMono.Instance._CECNPCMan.GetNPC(idTarget); - if (pNPC != null) + return m_PlayerInfo.cid; + } + + public bool CannotAttack() + { + return (m_dwLIES & (uint)Logic_Influence_Extned_states.LIES_DISABLEFIGHT) != 0; + } + + public bool CanTouchTarget(A3DVECTOR3 vHostPos, A3DVECTOR3 vTargetPos, float fTargetRad, int iReason, + float fMaxCut = 1.0f) + { + float fDist = A3d_Magnitude(vTargetPos - vHostPos); + switch (iReason) { - if (CanSafelySelect(pNPC) && !pNPC.IsDead()) + case 1: // melee + { + float fRange; + if (fMaxCut >= 0.0f) + { + float fCutDist = m_ExtProps.ak.AttackRange * 0.3f; + if (fCutDist > fMaxCut) + fCutDist = fMaxCut; + + fRange = m_ExtProps.ak.AttackRange - fCutDist; + } + else + { + fRange = m_ExtProps.ak.AttackRange * 0.7f; + } + // TO DO: fix later + fRange = 1f; + if (fDist - fTargetRad <= fRange) + return true; + + break; + } + //case 2: // cast magic + //{ + // if (m_pPrepSkill) + // { + // float fRange = m_pPrepSkill.GetCastRange(m_ExtProps.ak.AttackRange, GetPrayDistancePlus()); + // if (fRange > 0.0f) + // { + // if (fDist - fTargetRad <= fRange) + // return true; + // } + // else + // return true; + // } + + // break; + //} + case 3: // talk + { + if (fDist - fTargetRad <= 5.0f) + return true; + + break; + } + default: // no special reason + { + if (fDist < (fTargetRad + m_fTouchRad) * 3.0f) + return true; + + break; + } + } + + return false; + } + + public void RemoveObjectFromTabSels(CECObject pObject) + { + for (int i = 0; i < m_aTabSels.Count; i++) + { + if (m_aTabSels[i] == pObject) { - pTarget = pNPC; + m_aTabSels.RemoveAt(i); + break; } } } - return pTarget ? pTarget.IsSelectable() : false; - } - - - float SafelySelectDistance() - { - // ·þÎñÆ÷¶Ô SelectTarget ÓжîÍâ¾àÀëÏÞÖÆ£¬Èýά¾àÀë 150.0¡¢Ë®Æ½¾àÀë 125.0 ÒÔÉϵ쬶¼»áÎÞ·¨Ñ¡ÖÐ - // »ùÓÚÒÔÉÏÔ­Òò£¬¿Í»§¶ËÑ¡Ôñ¶ÔÏó¡¢»òÕß¶ÔÒѾ­Ñ¡ÔñµÄ¶ÔÏ󣬶¼È·±£ÆäÔÚ´ËÏÞÖÆ·¶Î§ÄÚ£¬¼´Ñ¡ÔñʱʹÓýÏС¾àÀë¼ì²â - return 100.0f; - } - - bool CanSafelySelectWith(float fDistanceToHostPlayer) - { - return fDistanceToHostPlayer <= SafelySelectDistance(); - } - - bool CanSafelySelect(EC_ElsePlayer pElsePlayer) - { - // IsSkeletonReady() Ϊ true ʱ, GetDistToHost() ²ÅΪÓÐЧÊý¾Ý - // !IsSkeletonReady() ʱ£¬Ò²ÔÊÐíʹÓã¬Ä¿µÄÊDZÜÃâδ¿¼Âǵ½µÄÒâÍâÇé¿ö - // ÏÂͬ - return pElsePlayer && ( /*!IsSkeletonReady() || */CanSafelySelectWith(pElsePlayer.GetDistToHost())); - } - - bool CanSafelySelect(CECNPC pNPC) - { - return pNPC && ( /*!IsSkeletonReady() ||*/ CanSafelySelectWith(pNPC.GetDistToHost())); - } - - // Check whether host can do a behavior - bool CanDo(int iThing) - { - bool bRet = true; - - switch (iThing) + public bool CanTouchTarget(A3DVECTOR3 vTargetPos, float fTargetRad, int iReason, float fMaxCut = 1.0f) { - case ActionCanDo.CANDO_SITDOWN: + A3DVECTOR3 vector = new A3DVECTOR3(gameObject.transform.position.x, gameObject.transform.position.y, + gameObject.transform.position.z); + return CanTouchTarget(vector, vTargetPos, fTargetRad, iReason, fMaxCut); + } - if (IsDead() /*|| IsAboutToDie() */ || IsJumping() /*|| IsTrading() || IsUsingTrashBox()*/ || - IsRooting() || /*IsReviving() || IsTalkingWithNPC() || IsChangingFace() ||*/ - !m_GndInfo - .bOnGround /*|| GetBoothState() != 0 || m_iBuddyId || IsOperatingPet() || IsRebuildingPet() || + public bool IsRooting() + { + var mask = (uint)(Logic_Influence_Extned_states.LIES_ROOT + | Logic_Influence_Extned_states.LIES_SLEEP + | Logic_Influence_Extned_states.LIES_STUN); + return (m_dwLIES & mask) != 0; + } + + bool IsInFortress() + { + return m_fortressEnter.role_in_war != 0; + } + + bool IsPVPOpen() + { + return m_pvp.bEnable; + } + + // Get faction ID + int GetFactionID() + { + return m_idFaction; + } + + public bool IsJumping() + { + return m_iJumpCount > 0; + } + + public bool IsPlayingAction(int iAction) + { + if (iAction == (int)PLAYER_ACTION_TYPE.ACT_WALK && _playerStateMachine.State is PlayerMoveState) + { + return true; + } + + if (iAction == (int)PLAYER_ACTION_TYPE.ACT_STAND && _playerStateMachine.State is PlayerIdleState) + { + return true; + } + + return false; + } + + public void ResetJump() + { + m_iJumpCount = 0; + m_bJumpInWater = false; + } + + // Get move speed + public float GetFlySpeed() + { + return m_ExtProps.mv.flight_speed; + } + + public float GetSwimSpeed() + { + return m_ExtProps.mv.swim_speed; + } + public bool ApplySkillShortcut(int idSkill, bool bCombo = false /* false */, + int idSelTarget = 0/* 0 */, int iForceAtk = -1/* -1 */) + { + //StackChecker::ACTrace(4); + + if (m_pActionSwitcher != null) + m_pActionSwitcher.PostMessge((int)EMsgActionSwitcher.MSG_CASTSKILL); + + // Return-town skill is very special, handle it separately + //if (idSkill == ID_RETURNTOWN_SKILL) + // return ReturnToTargetTown(0, bCombo); + + //if (idSkill == ID_SUMMONPLAYER_SKILL) + // return SummonPlayer(idSelTarget, bCombo); + + //if (!CanDo(CANDO_SPELLMAGIC)) + // return false; + + //if (InSlidingState()) + // return false; + + if (!bCombo) + //ClearComboSkill(); + + if (idSelTarget == 0) + idSelTarget = m_idSelTarget; + + CECSkill pSkill = GetPositiveSkillByID(idSkill); + if (pSkill == null) pSkill = GetEquipSkillByID(idSkill); + if (pSkill == null) pSkill = CECComboSkillState.Instance.GetInherentSkillByID((uint)idSkill); + if (pSkill == null) + { + return false; + } + + //// If we press a chargeable skill again when it's being charged, + //// we cast it out at once + //if (IsSpellingMagic() && m_pCurSkill && m_pCurSkill->IsCharging() && + // m_pCurSkill->GetSkillID() == pSkill->GetSkillID()) + //{ + // m_pCurSkill->EndCharging(); + // g_pGame->GetGameSession()->c2s_CmdContinueAction(); + // return true; + //} + + //int iCon = CheckSkillCastCondition(pSkill); + //if (iCon) + //{ + // ProcessSkillCondition(iCon); + // return false; + //} + + //// Get force attack flag + bool bForceAttack = false; + //if (iForceAtk < 0) + // bForceAttack = glb_GetForceAttackFlag(0); + //else + // bForceAttack = iForceAtk > 0 ? true : false; + + //// Check negative effect skill + //if (pSkill->GetType() == CECSkill::TYPE_ATTACK || pSkill->GetType() == CECSkill::TYPE_CURSE) + //{ + // if (idSelTarget == m_PlayerInfo.cid) + // { + // // Host cannot spell negative effect magic to himself. + // g_pGame->GetGameRun()->AddFixedChannelMsg(FIXMSG_TARGETWRONG, GP_CHAT_FIGHT); + // return false; + // } + // else if (idSelTarget) + // { + // if (AttackableJudge(idSelTarget, bForceAttack) != 1) + // return false; + // } + //} + + //// Check whether target type match + int idCastTarget = idSelTarget; + int iTargetType = pSkill.GetTargetType(); + + //if (pSkill->GetType() == CECSkill::TYPE_BLESS || + // pSkill->GetType() == CECSkill::TYPE_NEUTRALBLESS) + //{ + // if (!iTargetType || !ISPLAYERID(idSelTarget)) + // idCastTarget = m_PlayerInfo.cid; + + // // In some case, we shouldn't add bless effect to other players + // if (ISPLAYERID(idCastTarget) && idCastTarget != m_PlayerInfo.cid) + // { + // // If host has set bless skill filter only to himself, bless skill couldn't add to other players + // BYTE byBLSMask = glb_BuildBLSMask(); + + // if (pSkill->GetRangeType() == CECSkill::RANGE_POINT) + // { + // if (!IsTeamMember(idCastTarget)) + // { + // if (byBLSMask & GP_BLSMASK_SELF) + // idCastTarget = m_PlayerInfo.cid; + // else + // { + // CECElsePlayer* pPlayer = (CECElsePlayer*)g_pGame->GetGameRun()->GetWorld()->GetPlayerMan()->GetPlayer(idCastTarget); + // if (!pPlayer) + // { + // // Ä¿±êÏûʧ + // return false; + // } + + // if (pPlayer->IsInvader() || pPlayer->IsPariah()) + // { + // if (byBLSMask & GP_BLSMASK_NORED) + // idCastTarget = m_PlayerInfo.cid; + // } + + // if (!IsFactionMember(pPlayer->GetFactionID())) + // { + // if (byBLSMask & GP_BLSMASK_NOMAFIA) + // idCastTarget = m_PlayerInfo.cid; + // } + + // if (!IsFactionAllianceMember(pPlayer->GetFactionID())) + // { + // if (byBLSMask & GP_BLSMASK_NOALLIANCE) + // idCastTarget = m_PlayerInfo.cid; + // } + // if (GetForce() != pPlayer->GetForce()) + // { + // if (byBLSMask & GP_BLSMASK_NOFORCE) + // idCastTarget = m_PlayerInfo.cid; + // } + // } + // } + // } + + // // If host is in duel, bless skill couldn't add to opponent + // if (IsInDuel() && idSelTarget == m_pvp.idDuelOpp) + // idCastTarget = m_PlayerInfo.cid; + + // // If host is in battle, bless skill couldn't add to enemies + // if (IsInBattle()) + // { + // CECElsePlayer* pPlayer = m_pPlayerMan->GetElsePlayer(idCastTarget); + // if (!InSameBattleCamp(pPlayer)) + // idCastTarget = m_PlayerInfo.cid; + // } + // } + //} + //else if (pSkill->GetType() == CECSkill::TYPE_BLESSPET) + //{ + // CECPet* pPet = g_pGame->GetGameRun()->GetWorld()->GetNPCMan()->GetPetByID(idSelTarget); + // if (!pPet || pPet->GetMasterID() == GetCharacterID()) + // { + // // Spell skill on host's pet + // CECPetData* pPetData = m_pPetCorral->GetActivePet(); + // if (!pPetData || + // pPetData->GetClass() != GP_PET_CLASS_COMBAT && + // pPetData->GetClass() != GP_PET_CLASS_SUMMON && + // pPetData->GetClass() != GP_PET_CLASS_EVOLUTION) + // return false; + + // idCastTarget = m_pPetCorral->GetActivePetNPCID(); + // } + // // Only fighting pet can be blessed. + // if (pPet && !pPet->CanBeAttacked()) + // return false; + //} + //else + //{ + // if (iTargetType != 0 && !idCastTarget) + // return false; + //} + + //// iTargetType == 4 means target must be pet. The problem is that pet will + //// disappear from world after it died, so GetWorld()->GetObject() will return + //// NULL when host spells revive-pet skill on his dead pet. So, the target + //// type of revive-pet skill should be 0 + //if (iTargetType) + //{ + // // Target shoundn't be a corpse ? + // int iAliveFlag = 0; + // if (iTargetType == 1) + // iAliveFlag = 1; + // else if (iTargetType == 2) + // iAliveFlag = 2; + + // CECObject* pObject = g_pGame->GetGameRun()->GetWorld()->GetObject(idCastTarget, iAliveFlag); + // if (!pObject) + // return false; + //} + + //if (!IsMeleeing() && !IsSpellingMagic() && + // (!iTargetType || idCastTarget == m_PlayerInfo.cid)) + //{ + // // Cast this skill need't checking cast distance + // if (!pSkill->ReadyToCast()) + // return false; + + // // Prepare to cast skill, if skill isn't INSTANT and FLASHMOVE, + // // we must stop moving and stand + // if (!pSkill->IsInstant() && pSkill->GetType() != CECSkill::TYPE_FLASHMOVE) + // { + // if (!NaturallyStopMoving()) + // return false; // Couldn't stop naturally, so cancel casting skill + // } + // else if (pSkill->GetType() == CECSkill::TYPE_FLASHMOVE) + // { + // if (!CanDo(CANDO_FLASHMOVE)) + // return false; + // } + + m_pPrepSkill = pSkill; + //CastSkill(m_idSelTarget, bForceAttack); + //} + //else if (IsSpellingMagic() && m_pCurSkill == pSkill) + //{ + // // If we are casting the same skill and it's in cooling time + // return false; + //} + //else // Have to trace selected object before cast skill + //{ + // if (!pSkill->ReadyToCast()) + // return false; + + // if (CECCastSkillWhenMove::Instance().IsSkillSupported(pSkill->GetSkillID(), this) && + // m_pWorkMan->IsMovingToPosition() && + // m_pWorkMan->CanCastSkillImmediately(pSkill->GetSkillID())) + // { + // m_pPrepSkill = pSkill; + // return CastSkill(idCastTarget, bForceAttack); + // } + // else + // { + bool bTraceOK = false; + bool bUseAutoPF = false; + /* CECPlayerWrapper* pWrapper = CECAutoPolicy::GetInstance().GetPlayerWrapper(); + if (CECAutoPolicy::GetInstance().IsAutoPolicyEnabled() && pWrapper->GetAttackError() >= 2) + bUseAutoPF = true;*/ + + if (idCastTarget == 0) + { + idCastTarget = GetCharacterID(); // ±ÜÃâË²ÒÆµÈ¼¼ÄÜʱ idCastTarget Ϊ0µ¼Ö CECWorkTrace::CreateTraceTarget ·µ»Ø¿Õ + } + CECHPWork pWork = m_pWorkMan.GetWork(Host_work_ID.WORK_TRACEOBJECT); + if (pWork != null) + { + CECHPWorkTrace pWorkTrace = (CECHPWorkTrace)(pWork); + if (pWorkTrace.GetTraceReason() == Trace_reason.TRACE_SPELL && + pWorkTrace.GetTarget() == idCastTarget && + pWorkTrace.GetPrepSkill() == pSkill) + return false; // We are just doing the same thing + + pWorkTrace.SetTraceTarget(pWorkTrace.CreatTraceTarget(idCastTarget, Trace_reason.TRACE_SPELL, bForceAttack), bUseAutoPF); + pWorkTrace.SetPrepSkill(pSkill); + bTraceOK = true; + } + else if (m_pWorkMan.CanStartWork(Host_work_ID.WORK_TRACEOBJECT)) + { + CECHPWorkTrace pWork2 = (CECHPWorkTrace)m_pWorkMan.CreateWork(Host_work_ID.WORK_TRACEOBJECT); + pWork2.SetTraceTarget(pWork2.CreatTraceTarget(idCastTarget, Trace_reason.TRACE_SPELL, bForceAttack), bUseAutoPF); + pWork2.SetPrepSkill(pSkill); + m_pWorkMan.StartWork_p1(pWork2); + bTraceOK = true; + } + + if (!bTraceOK) return false; + // } + //} + + return true; + } + + public bool CastSkill(int idTarget, bool bForceAttack, CECObject pTarget = null) + { + byte byPVPMask = glb_BuildPVPMask(bForceAttack); + UnityGameSession.c2s_CmdCastSkill(m_pPrepSkill.GetSkillID(), byPVPMask, 1, idTarget); + return true; + } + public byte glb_BuildPVPMask(bool bForceAttack) + { + byte byMask = 0; + if (bForceAttack) + byMask |= (byte)PVPMask.GP_PVPMASK_FORCE; + else + { + /* CECConfigs pConfigs = EC_Game.GetConfigs(); + + if (pConfigs->GetGameSettings().bAtk_Player) + { + byMask |= GP_PVPMASK_FORCE; + + if (pConfigs->GetGameSettings().bAtk_NoMafia) + byMask |= GP_PVPMASK_NOMAFIA; + + if (pConfigs->GetGameSettings().bAtk_NoWhite) + byMask |= GP_PVPMASK_NOWHITE; + + if (pConfigs->GetGameSettings().bAtk_NoAlliance) + byMask |= GP_PVPMASK_NOALLIANCE; + + if (pConfigs->GetGameSettings().bAtk_NoForce) + byMask |= GP_PVPMASK_NOFORCE; + }*/ + } + + return byMask; + } + public bool SelectTarget(int idTarget) + { + //BMLogger.LogError("HoangDev: HostPlayer SelectTarget"); + bool bRet = false; + bool canDo = CanDo(ActionCanDo.CANDO_CHANGESELECT); + bool canselect = CanSelectTarget(idTarget); + if (canDo && canselect) + { + bRet = true; + if (idTarget == 0) + { + //BMLogger.LogError("HoangDev: HostPlayer Unsetlect npc"); + UnityGameSession.c2s_CmdUnselect(); + } + else + { + //BMLogger.LogError("HoangDev: HostPlayer setlect npc"); + UnityGameSession.c2s_CmdSelectTarget(idTarget); + } + } + + return bRet; + } + public CECSkill GetPositiveSkillByID(int id, bool bSenior = false) + { + CECSkill pSenior = null; + + for (int i = 0; i < m_aPtSkills.Count; i++) + { + if (m_aPtSkills[i].GetSkillID() == id) + return m_aPtSkills[i]; + else if (m_aPtSkills[i].GetJunior().Find((uint)id)) + pSenior = m_aPtSkills[i]; + } + + if (bSenior && pSenior != null) + return pSenior; + + return null; + } + + // C# conversion of CECHostPlayer::GetEquipSkillByID + // Assumes: GetEquipSkillNum() returns the count of equipment skills + // GetEquipSkillByIndex(int) returns a CECSkill at the given index + public CECSkill GetEquipSkillByID(int id) + { + CECSkill pRet = null; + + for (int i = 0; i < GetEquipSkillNum(); i++) + { + CECSkill pSkill = GetEquipSkillByIndex(i); + if (pSkill != null && pSkill.GetSkillID() == id) + { + pRet = pSkill; + break; + } + } + + return pRet; + } + public int GetEquipSkillNum() { return m_aEquipSkills.Count; } + public CECSkill GetEquipSkillByIndex(int n) { return m_aEquipSkills[n]; } + bool CanSelectTarget(int idTarget) + { + if (idTarget == 0 || idTarget == this.GetCharacterID()) + { + // 0 means unselect + return true; + } + + CECObject pTarget = null; + if (GPDataTypeHelper.ISPLAYERID(idTarget)) + { + EC_ElsePlayer pElsePlayer = + (EC_ManMessageMono.Instance.GetECManPlayer.GetPlayer(idTarget)) as EC_ElsePlayer; + if (pElsePlayer != null) + { + if (CanSafelySelect(pElsePlayer)) + { + pTarget = pElsePlayer; + } + } + } + else if (GPDataTypeHelper.ISNPCID(idTarget)) + { + CECNPC pNPC = EC_ManMessageMono.Instance._CECNPCMan.GetNPC(idTarget); + if (pNPC != null) + { + if (CanSafelySelect(pNPC) && !pNPC.IsDead()) + { + pTarget = pNPC; + } + } + } + + return pTarget ? pTarget.IsSelectable() : false; + } + + + float SafelySelectDistance() + { + // ·þÎñÆ÷¶Ô SelectTarget ÓжîÍâ¾àÀëÏÞÖÆ£¬Èýά¾àÀë 150.0¡¢Ë®Æ½¾àÀë 125.0 ÒÔÉϵ쬶¼»áÎÞ·¨Ñ¡ÖÐ + // »ùÓÚÒÔÉÏÔ­Òò£¬¿Í»§¶ËÑ¡Ôñ¶ÔÏó¡¢»òÕß¶ÔÒѾ­Ñ¡ÔñµÄ¶ÔÏ󣬶¼È·±£ÆäÔÚ´ËÏÞÖÆ·¶Î§ÄÚ£¬¼´Ñ¡ÔñʱʹÓýÏС¾àÀë¼ì²â + return 100.0f; + } + + bool CanSafelySelectWith(float fDistanceToHostPlayer) + { + return fDistanceToHostPlayer <= SafelySelectDistance(); + } + + bool CanSafelySelect(EC_ElsePlayer pElsePlayer) + { + // IsSkeletonReady() Ϊ true ʱ, GetDistToHost() ²ÅΪÓÐЧÊý¾Ý + // !IsSkeletonReady() ʱ£¬Ò²ÔÊÐíʹÓã¬Ä¿µÄÊDZÜÃâδ¿¼Âǵ½µÄÒâÍâÇé¿ö + // ÏÂͬ + return pElsePlayer && ( /*!IsSkeletonReady() || */CanSafelySelectWith(pElsePlayer.GetDistToHost())); + } + + bool CanSafelySelect(CECNPC pNPC) + { + return pNPC && ( /*!IsSkeletonReady() ||*/ CanSafelySelectWith(pNPC.GetDistToHost())); + } + + // Check whether host can do a behavior + bool CanDo(int iThing) + { + bool bRet = true; + + switch (iThing) + { + case ActionCanDo.CANDO_SITDOWN: + + if (IsDead() /*|| IsAboutToDie() */ || IsJumping() /*|| IsTrading() || IsUsingTrashBox()*/ || + IsRooting() || /*IsReviving() || IsTalkingWithNPC() || IsChangingFace() ||*/ + !m_GndInfo + .bOnGround /*|| GetBoothState() != 0 || m_iBuddyId || IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || IsRidingOnPet() || GetShapeType() == PLAYERMODEL_DUMMYTYPE2 || IsPassiveMove()*/ - ) - bRet = false; - - break; - - case ActionCanDo.CANDO_MOVETO: - { - if (IsDead() /*|| IsSitting() || IsTrading() || IsUsingTrashBox()*/ || IsRooting() /*|| - IsReviving() || IsTalkingWithNPC() || IsChangingFace() || IsUsingItem() || - GetBoothState() != 0 || m_bHangerOn || IsOperatingPet() || IsRebuildingPet() || IsPassiveMove()*/) + ) bRet = false; break; - } - case ActionCanDo.CANDO_MELEE: - if (IsDead() /*|| IsSitting() */ || m_idSelTarget == 0 || m_idSelTarget == m_PlayerInfo.cid || - IsJumping() || GPDataTypeHelper.ISMATTERID(m_idSelTarget) /*|| IsTrading() || IsReviving() || + case ActionCanDo.CANDO_MOVETO: + { + if (IsDead() /*|| IsSitting() || IsTrading() || IsUsingTrashBox()*/ || IsRooting() /*|| + IsReviving() || IsTalkingWithNPC() || IsChangingFace() || IsUsingItem() || + GetBoothState() != 0 || m_bHangerOn || IsOperatingPet() || IsRebuildingPet() || IsPassiveMove()*/) + bRet = false; + + break; + } + case ActionCanDo.CANDO_MELEE: + + if (IsDead() /*|| IsSitting() */ || m_idSelTarget == 0 || m_idSelTarget == m_PlayerInfo.cid || + IsJumping() || GPDataTypeHelper.ISMATTERID(m_idSelTarget) /*|| IsTrading() || IsReviving() || IsUsingTrashBox() || IsTalkingWithNPC() || IsChangingFace()*/ || CannotAttack() /*|| GetBoothState() != 0 || m_iBuddyId || IsRidingOnPet() || IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || IsPassiveMove()*/) - bRet = false; + bRet = false; - break; + break; - case ActionCanDo.CANDO_ASSISTSEL: + case ActionCanDo.CANDO_ASSISTSEL: - if (IsDead() || !GPDataTypeHelper.ISPLAYERID(m_idSelTarget) || m_idSelTarget == m_PlayerInfo.cid /*|| + if (IsDead() || !GPDataTypeHelper.ISPLAYERID(m_idSelTarget) || m_idSelTarget == m_PlayerInfo.cid /*|| !m_pTeam || !m_pTeam->GetMemberByID(m_idSelTarget) || m_iBuddyId || IsPassiveMove() || m_playerLimits.test(PLAYER_LIMIT_NOCHANGESELECT)*/) - bRet = false; + bRet = false; - break; + break; - case ActionCanDo.CANDO_FLY: + case ActionCanDo.CANDO_FLY: - if (IsDead() || IsRooting() /*|| IsSitting() || IsTrading() || IsReviving() || + if (IsDead() || IsRooting() /*|| IsSitting() || IsTrading() || IsReviving() || IsUsingTrashBox() || IsTalkingWithNPC() || IsChangingFace() || GetBoothState() != 0 || IsFlashMoving() */ || - m_pWorkMan.HasWorkRunningOnPriority(CECHPWorkMan.Work_priority.PRIORITY_2) /*|| + m_pWorkMan.HasWorkRunningOnPriority(CECHPWorkMan.Work_priority.PRIORITY_2) /*|| m_bHangerOn || IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || IsRidingOnPet() || GetShapeType() == PLAYERMODEL_DUMMYTYPE2 || IsPassiveMove() || m_playerLimits.test(PLAYER_LIMIT_NOFLY) || m_BattleInfo.IsChariotWar()*/) - bRet = false; + bRet = false; - break; + break; - case ActionCanDo.CANDO_PICKUP: - case ActionCanDo.CANDO_GATHER: + case ActionCanDo.CANDO_PICKUP: + case ActionCanDo.CANDO_GATHER: - if (IsDead() /*|| IsAboutToDie() || IsSitting() || IsTrading() || IsUsingTrashBox() || + if (IsDead() /*|| IsAboutToDie() || IsSitting() || IsTrading() || IsUsingTrashBox() || IsReviving() || IsTalkingWithNPC() || IsChangingFace() || GetBoothState() != 0 || GetBuddyState() == 1 || IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || IsPassiveMove()*/) - bRet = false; + bRet = false; - break; + break; - case ActionCanDo.CANDO_TRADE: + case ActionCanDo.CANDO_TRADE: - if (IsDead() /*|| IsAboutToDie() || IsSitting() */ || IsJumping() /*|| IsMeleeing() || + if (IsDead() /*|| IsAboutToDie() || IsSitting() */ || IsJumping() /*|| IsMeleeing() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() || IsChangingFace() || IsSpellingMagic() || GetBoothState() != 0 || m_iBuddyId || IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || IsInvisible() || IsPassiveMove()*/) - bRet = false; + bRet = false; - break; + break; - case ActionCanDo.CANDO_PLAYPOSE: + case ActionCanDo.CANDO_PLAYPOSE: - if (IsDead() /*|| IsAboutToDie() || IsSitting()*/ || IsJumping() || /* IsMeleeing() || + if (IsDead() /*|| IsAboutToDie() || IsSitting()*/ || IsJumping() || /* IsMeleeing() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() || IsChangingFace() || IsSpellingMagic() || IsShapeChanged() || IsReviving() ||*/ - m_iMoveEnv != (int)MoveEnvironment.MOVEENV_GROUND /*|| + m_iMoveEnv != (int)MoveEnvironment.MOVEENV_GROUND /*|| GetBoothState() != 0 || m_iBuddyId || IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || IsRidingOnPet() || GetShapeType() == PLAYERMODEL_DUMMYTYPE2 || IsPassiveMove() || m_BattleInfo.IsChariotWar()*/ - ) - bRet = false; + ) + bRet = false; - break; + break; - //case ActionCanDo.CANDO_SPELLMAGIC: - // if (IsDead() || ISMATTERID(m_idSelTarget) || IsAboutToDie() || IsSitting() || - // IsJumping() || IsFlashMoving() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() || - // IsChangingFace() || CannotAttack() || IsReviving() || GetBoothState() != 0 || - // m_iBuddyId || IsRidingOnPet() || IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || IsPassiveMove()) - // bRet = false; + //case ActionCanDo.CANDO_SPELLMAGIC: + // if (IsDead() || ISMATTERID(m_idSelTarget) || IsAboutToDie() || IsSitting() || + // IsJumping() || IsFlashMoving() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() || + // IsChangingFace() || CannotAttack() || IsReviving() || GetBoothState() != 0 || + // m_iBuddyId || IsRidingOnPet() || IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || IsPassiveMove()) + // bRet = false; - // break; + // break; - case ActionCanDo.CANDO_SUMMONPET: + case ActionCanDo.CANDO_SUMMONPET: - if (IsDead() || GPDataTypeHelper.ISMATTERID(m_idSelTarget) || /*IsAboutToDie() || IsSitting() ||*/ - IsJumping() || /*IsFlashMoving() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() || + if (IsDead() || GPDataTypeHelper.ISMATTERID(m_idSelTarget) || /*IsAboutToDie() || IsSitting() ||*/ + IsJumping() || /*IsFlashMoving() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() || IsChangingFace() ||*/ CannotAttack() /*|| IsReviving() || GetBoothState() != 0 || IsInvisible() || IsGMInvisible() || IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || IsPassiveMove() || m_BattleInfo.IsChariotWar()*/) - bRet = false; + bRet = false; - break; - case ActionCanDo.CANDO_REBUILDPET: + break; + case ActionCanDo.CANDO_REBUILDPET: - if (IsDead() || GPDataTypeHelper.ISMATTERID(m_idSelTarget) /*|| IsAboutToDie() || IsSitting() */ || - IsJumping() /*|| IsFlashMoving() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() || + if (IsDead() || GPDataTypeHelper.ISMATTERID(m_idSelTarget) /*|| IsAboutToDie() || IsSitting() */ || + IsJumping() /*|| IsFlashMoving() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() || IsChangingFace()*/ || CannotAttack() /*|| IsReviving() || GetBoothState() != 0 || m_iBuddyId || IsInvisible() || IsGMInvisible() || IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || IsPassiveMove() || IsPlayerMoving() || m_BattleInfo.IsChariotWar()*/) - bRet = false; + bRet = false; - break; + break; - //case ActionCanDo.CANDO_USEITEM: + //case ActionCanDo.CANDO_USEITEM: - // if (IsAboutToDie() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() || - // IsChangingFace() || GetBoothState() != 0 || IsPassiveMove() || m_BattleInfo.IsChariotWar()) - // bRet = false; + // if (IsAboutToDie() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() || + // IsChangingFace() || GetBoothState() != 0 || IsPassiveMove() || m_BattleInfo.IsChariotWar()) + // bRet = false; - // break; + // break; - //case ActionCanDo.CANDO_JUMP: - // { - // if (IsDead() || - // m_iJumpCount >= MAX_JUMP_COUNT || - // // cannot jump more than one time if shape mode is type2 - // (IsJumping() && (GetShapeType() == PLAYERMODEL_DUMMYTYPE2)) || - // IsJumpInWater() || m_iMoveEnv == MOVEENV_AIR || IsSitting() || - // IsMeleeing() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() || - // IsChangingFace() || IsReviving() || IsSpellingMagic() || IsPicking() || - // IsGathering() || IsRooting() || GetBoothState() != 0 || m_bHangerOn || (IsJumping() && IsRidingOnPet()) || - // IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || IsPassiveMove() || m_BattleInfo.IsChariotWar()) - // bRet = false; + //case ActionCanDo.CANDO_JUMP: + // { + // if (IsDead() || + // m_iJumpCount >= MAX_JUMP_COUNT || + // // cannot jump more than one time if shape mode is type2 + // (IsJumping() && (GetShapeType() == PLAYERMODEL_DUMMYTYPE2)) || + // IsJumpInWater() || m_iMoveEnv == MOVEENV_AIR || IsSitting() || + // IsMeleeing() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() || + // IsChangingFace() || IsReviving() || IsSpellingMagic() || IsPicking() || + // IsGathering() || IsRooting() || GetBoothState() != 0 || m_bHangerOn || (IsJumping() && IsRidingOnPet()) || + // IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || IsPassiveMove() || m_BattleInfo.IsChariotWar()) + // bRet = false; - // break; - // } - //case ActionCanDo.CANDO_FOLLOW: - // { - // if (IsDead() || IsAboutToDie() || IsSitting() || IsMeleeing() || IsReviving() || - // IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() || IsChangingFace() || - // IsSpellingMagic() || GetBoothState() != 0 || m_bHangerOn || IsOperatingPet() || IsRebuildingPet() || - // IsUsingItem() || IsPassiveMove()) - // bRet = false; + // break; + // } + //case ActionCanDo.CANDO_FOLLOW: + // { + // if (IsDead() || IsAboutToDie() || IsSitting() || IsMeleeing() || IsReviving() || + // IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() || IsChangingFace() || + // IsSpellingMagic() || GetBoothState() != 0 || m_bHangerOn || IsOperatingPet() || IsRebuildingPet() || + // IsUsingItem() || IsPassiveMove()) + // bRet = false; - // break; - // } - //case ActionCanDo.CANDO_BOOTH: + // break; + // } + //case ActionCanDo.CANDO_BOOTH: - // if (IsDead() || IsAboutToDie() || IsPlayerMoving() || IsSitting() || IsReviving() || - // IsMeleeing() || IsJumping() || IsTrading() || IsUsingTrashBox() || - // IsTalkingWithNPC() || IsChangingFace() || IsSpellingMagic() || IsFlying() || - // IsUnderWater() || m_iBuddyId || IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || IsRidingOnPet() || IsInvisible() || - // IsPassiveMove()) - // bRet = false; + // if (IsDead() || IsAboutToDie() || IsPlayerMoving() || IsSitting() || IsReviving() || + // IsMeleeing() || IsJumping() || IsTrading() || IsUsingTrashBox() || + // IsTalkingWithNPC() || IsChangingFace() || IsSpellingMagic() || IsFlying() || + // IsUnderWater() || m_iBuddyId || IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || IsRidingOnPet() || IsInvisible() || + // IsPassiveMove()) + // bRet = false; - // break; + // break; - //case ActionCanDo.CANDO_FLASHMOVE: + //case ActionCanDo.CANDO_FLASHMOVE: - // if (IsDead() || IsAboutToDie() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() || - // IsJumping() || IsFlashMoving() || IsFalling() || IsChangingFace() || GetBoothState() != 0 || IsTakingOff() || - // m_pWorkMan->HasWorkRunningOnPriority(CECHPWorkMan::PRIORITY_2) || - // m_iBuddyId || IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || IsPassiveMove()) - // bRet = false; + // if (IsDead() || IsAboutToDie() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() || + // IsJumping() || IsFlashMoving() || IsFalling() || IsChangingFace() || GetBoothState() != 0 || IsTakingOff() || + // m_pWorkMan->HasWorkRunningOnPriority(CECHPWorkMan::PRIORITY_2) || + // m_iBuddyId || IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || IsPassiveMove()) + // bRet = false; - // break; + // break; - //case ActionCanDo.CANDO_BINDBUDDY: + //case ActionCanDo.CANDO_BINDBUDDY: - // if (IsDead() || IsAboutToDie() || IsJumping() || IsSitting() || - // IsMeleeing() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() || - // IsChangingFace() || IsReviving() || IsSpellingMagic() || IsPicking() || - // IsGathering() || IsRooting() || GetBoothState() != 0 || - // !m_pWorkMan->IsStanding() || m_iBuddyId || - // IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || GetShapeType() == PLAYERMODEL_DUMMYTYPE2 || IsPassiveMove() || - // m_playerLimits.test(PLAYER_LIMIT_NOBIND)) - // bRet = false; - - // break; - - //case ActionCanDo.CANDO_DUEL: - - // if (IsDead() || IsAboutToDie() || IsSitting() || IsFighting() || IsTrading() || - // IsReviving() || IsUsingTrashBox() || IsTalkingWithNPC() || IsChangingFace() || - // GetBoothState() != 0 || m_iBuddyId || m_pvp.iDuelState != DUEL_ST_NONE || - // IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || IsPassiveMove()) - // bRet = false; - - // break; - - case ActionCanDo.CANDO_CHANGESELECT: - - //if (m_playerLimits.test(PLAYER_LIMIT_NOCHANGESELECT)) - // bRet = false; - - break; - - //case ActionCanDo.CANDO_SWITCH_PARALLEL_WORLD: - // if (IsDead() || IsAboutToDie() || IsJumping() || IsFighting() || + // if (IsDead() || IsAboutToDie() || IsJumping() || IsSitting() || // IsMeleeing() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() || // IsChangingFace() || IsReviving() || IsSpellingMagic() || IsPicking() || // IsGathering() || IsRooting() || GetBoothState() != 0 || - // m_iBuddyId || IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || - // GetShapeType() == PLAYERMODEL_DUMMYTYPE2 || IsPassiveMove()) + // !m_pWorkMan->IsStanding() || m_iBuddyId || + // IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || GetShapeType() == PLAYERMODEL_DUMMYTYPE2 || IsPassiveMove() || + // m_playerLimits.test(PLAYER_LIMIT_NOBIND)) // bRet = false; + // break; + + //case ActionCanDo.CANDO_DUEL: + + // if (IsDead() || IsAboutToDie() || IsSitting() || IsFighting() || IsTrading() || + // IsReviving() || IsUsingTrashBox() || IsTalkingWithNPC() || IsChangingFace() || + // GetBoothState() != 0 || m_iBuddyId || m_pvp.iDuelState != DUEL_ST_NONE || + // IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || IsPassiveMove()) + // bRet = false; + + // break; + + case ActionCanDo.CANDO_CHANGESELECT: + + //if (m_playerLimits.test(PLAYER_LIMIT_NOCHANGESELECT)) + // bRet = false; + + break; + + //case ActionCanDo.CANDO_SWITCH_PARALLEL_WORLD: + // if (IsDead() || IsAboutToDie() || IsJumping() || IsFighting() || + // IsMeleeing() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() || + // IsChangingFace() || IsReviving() || IsSpellingMagic() || IsPicking() || + // IsGathering() || IsRooting() || GetBoothState() != 0 || + // m_iBuddyId || IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || + // GetShapeType() == PLAYERMODEL_DUMMYTYPE2 || IsPassiveMove()) + // bRet = false; + // break; + } + + return bRet; } - - return bRet; - } - public int GetProfession() - { - return m_iProfession; - } - public void SetSelectedTarget(int id) - { - m_idSelTarget = id; - } - public bool glb_GetForceAttackFlag(uint pdwParam) - { - - /*bool bForceAttack = false; - CECInputCtrl* pInputCtrl = g_pGame->GetGameRun()->GetInputCtrl(); - - if (pdwParam) - bForceAttack = pInputCtrl->IsCtrlPressed(*pdwParam); - else - bForceAttack = pInputCtrl->KeyIsBeingPressed(VK_CONTROL); - - return bForceAttack;*/ - return true; - } - //public float GetSwimSpeedSev() - //{ - // float fSpeedSev = GetSwimSpeed(); - // while (true) - // { - // if (!IsUnderWater()) break; - // //CECWorld* pWorld = g_pGame.GetGameRun().GetWorld(); - // //if (!pWorld) break; - - // const A3DVECTOR3 vPos = GetPos(); - // float fTerrainHeight = pWorld.GetTerrainHeight(vPos); - // float fWaterHeight = pWorld.GetWaterHeight(vPos); - // if (fWaterHeight <= fTerrainHeight) break; - - // float fBorderLine = fWaterHeight - 2.0f; - // if (vPos.y <= fBorderLine) break; - - // // ·þÎñÆ÷¶Ë½«Ë®ÃæÒÔÏÂ2Ã×ÒÔÉÏ´¦ÀíΪ run_speed£¨ÓÐÎÊÌ⣩ - // // µ«Î´Ê¹ÓüÓËÙ¼¼ÄÜʱ swim_speed СÓÚ run_speed£¬ - // // ¿ÉÒÔÔÚË®ÃæÒÔÏÂ2Ã×ÒÔÉÏ»ñÈ¡³¬¹ý swim_speed µÄËÙ¶È£¬Òò´Ë£¬´Ë´¦È¡Á½Õß½ÏСֵΪºÏÀí×ö·¨ - // fSpeedSev = min(m_ExtProps.mv.run_speed, fSpeedSev); - // break; - // } - // return fSpeedSev; - //} - - void UpdateGFXs(float dwDeltaTime) - { -// if (m_pLevelUpGFX) -// m_pLevelUpGFX->SetParentTM(GetAbsoluteTM()); - - if (m_pHoverGFX)// && m_idCurHover != m_idSelTarget) + public int GetProfession() { - if (!IsChangingFace() && (GPDataTypeHelper.ISPLAYERID(m_idCurHover) || GPDataTypeHelper.ISNPCID(m_idCurHover))) + return m_iProfession; + } + public void SetSelectedTarget(int id) + { + m_idSelTarget = id; + } + public bool glb_GetForceAttackFlag(uint pdwParam) + { + + /*bool bForceAttack = false; + CECInputCtrl* pInputCtrl = g_pGame->GetGameRun()->GetInputCtrl(); + + if (pdwParam) + bForceAttack = pInputCtrl->IsCtrlPressed(*pdwParam); + else + bForceAttack = pInputCtrl->KeyIsBeingPressed(VK_CONTROL); + + return bForceAttack;*/ + return true; + } + //public float GetSwimSpeedSev() + //{ + // float fSpeedSev = GetSwimSpeed(); + // while (true) + // { + // if (!IsUnderWater()) break; + // //CECWorld* pWorld = g_pGame.GetGameRun().GetWorld(); + // //if (!pWorld) break; + + // const A3DVECTOR3 vPos = GetPos(); + // float fTerrainHeight = pWorld.GetTerrainHeight(vPos); + // float fWaterHeight = pWorld.GetWaterHeight(vPos); + // if (fWaterHeight <= fTerrainHeight) break; + + // float fBorderLine = fWaterHeight - 2.0f; + // if (vPos.y <= fBorderLine) break; + + // // ·þÎñÆ÷¶Ë½«Ë®ÃæÒÔÏÂ2Ã×ÒÔÉÏ´¦ÀíΪ run_speed£¨ÓÐÎÊÌ⣩ + // // µ«Î´Ê¹ÓüÓËÙ¼¼ÄÜʱ swim_speed СÓÚ run_speed£¬ + // // ¿ÉÒÔÔÚË®ÃæÒÔÏÂ2Ã×ÒÔÉÏ»ñÈ¡³¬¹ý swim_speed µÄËÙ¶È£¬Òò´Ë£¬´Ë´¦È¡Á½Õß½ÏСֵΪºÏÀí×ö·¨ + // fSpeedSev = min(m_ExtProps.mv.run_speed, fSpeedSev); + // break; + // } + // return fSpeedSev; + //} + + void UpdateGFXs(float dwDeltaTime) + { + // if (m_pLevelUpGFX) + // m_pLevelUpGFX->SetParentTM(GetAbsoluteTM()); + + if (m_pHoverGFX)// && m_idCurHover != m_idSelTarget) { - CECObject pObject = EC_ManMessageMono.Instance?.GetObject(m_idCurHover, 1); - if (pObject) + if (!IsChangingFace() && (GPDataTypeHelper.ISPLAYERID(m_idCurHover) || GPDataTypeHelper.ISNPCID(m_idCurHover))) { - if (m_pHoverGFX.GetState() == GFX_STATE.ST_STOP) + CECObject pObject = EC_ManMessageMono.Instance?.GetObject(m_idCurHover, 1); + if (pObject) { - m_pHoverGFX.Play(); - m_pHoverGFX.transform.parent = pObject.transform; - m_pHoverGFX.transform.localPosition = Vector3.zero; + if (m_pHoverGFX.GetState() == GFX_STATE.ST_STOP) + { + m_pHoverGFX.Play(); + m_pHoverGFX.transform.parent = pObject.transform; + m_pHoverGFX.transform.localPosition = Vector3.zero; + } } + else + m_pHoverGFX.Stop(true); } else m_pHoverGFX.Stop(true); } - else - m_pHoverGFX.Stop(true); - } - if (m_pSelectedGFX) - { - if (!IsChangingFace() && (GPDataTypeHelper.ISPLAYERID(m_idSelTarget) || GPDataTypeHelper.ISNPCID(m_idSelTarget))) + if (m_pSelectedGFX) { - var pObject = EC_ManMessageMono.Instance?.GetObject(m_idSelTarget, 1); - if (pObject) + if (!IsChangingFace() && (GPDataTypeHelper.ISPLAYERID(m_idSelTarget) || GPDataTypeHelper.ISNPCID(m_idSelTarget))) { - if (m_pSelectedGFX.GetState() == GFX_STATE.ST_STOP) + var pObject = EC_ManMessageMono.Instance?.GetObject(m_idSelTarget, 1); + if (pObject) { - m_pSelectedGFX.Play(); - m_pSelectedGFX.transform.parent = pObject.transform; - m_pSelectedGFX.transform.localPosition = Vector3.zero; + if (m_pSelectedGFX.GetState() == GFX_STATE.ST_STOP) + { + m_pSelectedGFX.Play(); + m_pSelectedGFX.transform.parent = pObject.transform; + m_pSelectedGFX.transform.localPosition = Vector3.zero; + } } + else + m_pSelectedGFX.Stop(true); } else m_pSelectedGFX.Stop(true); } - else - m_pSelectedGFX.Stop(true); + + // if (m_pFloatDust) + // { + // A3DTerrainWater* pWater = g_pGame->GetGameRun()->GetWorld()->GetTerrainWater(); + // + // if (pWater->IsUnderWater(m_CameraCoord.GetPos())) + // { + // if (m_pFloatDust->GetState() == ST_STOP) + // { + // m_pFloatDust->Start(true); + // m_pFloatDust->TickAnimation(2000); + // } + // + // m_pFloatDust->SetParentTM(GetAbsoluteTM()); + // } + // else if (m_pFloatDust->GetState() != ST_STOP) + // m_pFloatDust->Stop(); + // } + // UpdateMonsterSpiritGfx(dwDeltaTime); } - // if (m_pFloatDust) - // { - // A3DTerrainWater* pWater = g_pGame->GetGameRun()->GetWorld()->GetTerrainWater(); - // - // if (pWater->IsUnderWater(m_CameraCoord.GetPos())) - // { - // if (m_pFloatDust->GetState() == ST_STOP) - // { - // m_pFloatDust->Start(true); - // m_pFloatDust->TickAnimation(2000); - // } - // - // m_pFloatDust->SetParentTM(GetAbsoluteTM()); - // } - // else if (m_pFloatDust->GetState() != ST_STOP) - // m_pFloatDust->Stop(); - // } - // UpdateMonsterSpiritGfx(dwDeltaTime); - } - - // Level up - public void LevelUp() - { - // CECGameSession *pSession = g_pGame->GetGameSession(); - // - // m_BasicProps.iLevel++; - // g_pGame->GetGameRun()->AddFixedMessage(FIXMSG_LEVELUP, m_BasicProps.iLevel); - // - // // Get all extend properties - // pSession->c2s_CmdGetExtProps(); + // Level up + public void LevelUp() + { + // CECGameSession *pSession = g_pGame->GetGameSession(); + // + // m_BasicProps.iLevel++; + // g_pGame->GetGameRun()->AddFixedMessage(FIXMSG_LEVELUP, m_BasicProps.iLevel); + // + // // Get all extend properties + // pSession->c2s_CmdGetExtProps(); -// if (m_pLevelUpGFX) -// m_pLevelUpGFX->Start(true); - PlayGfx(EC_Resource.res_GFXFile((int)GfxResourceType.RES_GFX_LEVELUP), null, 1f,1);//PLAYERMODEL_TYPEALL - - // // Popup notify bubble text - // BubbleText(BUBBLE_LEVELUP, 0); - // - // // Notify my friends that my level changed - // ACHAR szInfo[40]; - // a_sprintf(szInfo, _AL("L%d"), m_BasicProps.iLevel); - // - // for (int i=0; i < m_pFriendMan->GetGroupNum(); i++) - // { - // CECFriendMan::GROUP* pGroup = m_pFriendMan->GetGroupByIndex(i); - // for (int j=0; j < pGroup->aFriends.GetSize(); j++) - // { - // CECFriendMan::FRIEND* pFriend = pGroup->aFriends[j]; - // if (pFriend->IsGameOnline()) - // { - // pSession->SendPrivateChatData(pFriend->GetName(), - // szInfo, GNET::CHANNEL_USERINFO, pFriend->id); - // } - // } - // } - // - // if (GetBasicProps().iLevel==30) - // { - // CECGameUIMan* pGameUI = g_pGame->GetGameRun()->GetUIManager()->GetInGameUIMan(); - // pGameUI->AddChatMessage(pGameUI->GetStringFromTable(9638), GP_CHAT_SYSTEM); - // } - // if (GetBasicProps().iLevel>31) - // { - // CECGameUIMan* pGameUI = g_pGame->GetGameRun()->GetUIManager()->GetInGameUIMan(); - // ((CDlgOnlineAward*)pGameUI->GetDialog("Win_AddExp2"))->RestartWhenLevelup(); - // } - } - - // Estimate mouse cursor - private void EstimateCursor() - { - m_cursorUpdateTimer += Time.deltaTime; - if (m_cursorUpdateTimer < CURSOR_UPDATE_INTERVAL) - return; - m_cursorUpdateTimer = 0f; - - // Early exit checks - if (IsChangingFace() || mainCam == null || m_cachedMouse == null) - { - m_idCurHover = 0; - return; + // if (m_pLevelUpGFX) + // m_pLevelUpGFX->Start(true); + PlayGfx(EC_Resource.res_GFXFile((int)GfxResourceType.RES_GFX_LEVELUP), null, 1f, 1);//PLAYERMODEL_TYPEALL + + // // Popup notify bubble text + // BubbleText(BUBBLE_LEVELUP, 0); + // + // // Notify my friends that my level changed + // ACHAR szInfo[40]; + // a_sprintf(szInfo, _AL("L%d"), m_BasicProps.iLevel); + // + // for (int i=0; i < m_pFriendMan->GetGroupNum(); i++) + // { + // CECFriendMan::GROUP* pGroup = m_pFriendMan->GetGroupByIndex(i); + // for (int j=0; j < pGroup->aFriends.GetSize(); j++) + // { + // CECFriendMan::FRIEND* pFriend = pGroup->aFriends[j]; + // if (pFriend->IsGameOnline()) + // { + // pSession->SendPrivateChatData(pFriend->GetName(), + // szInfo, GNET::CHANNEL_USERINFO, pFriend->id); + // } + // } + // } + // + // if (GetBasicProps().iLevel==30) + // { + // CECGameUIMan* pGameUI = g_pGame->GetGameRun()->GetUIManager()->GetInGameUIMan(); + // pGameUI->AddChatMessage(pGameUI->GetStringFromTable(9638), GP_CHAT_SYSTEM); + // } + // if (GetBasicProps().iLevel>31) + // { + // CECGameUIMan* pGameUI = g_pGame->GetGameRun()->GetUIManager()->GetInGameUIMan(); + // ((CDlgOnlineAward*)pGameUI->GetDialog("Win_AddExp2"))->RestartWhenLevelup(); + // } } - - // Get mouse position using cached device - Vector2 mousePosition = m_cachedMouse.position.ReadValue(); - - // Early exit if mouse hasn't moved significantly (2 pixel threshold) - if (Vector2.Distance(mousePosition, m_lastMousePosition) < 2f) - return; - - m_lastMousePosition = mousePosition; - m_idCurHover = 0; - - CursorType cursorType = CursorType.RES_CUR_NORMAL; - - // Check modifier keys using cached keyboard - bool isShiftPressed = m_cachedKeyboard != null && - (m_cachedKeyboard.leftShiftKey.isPressed || m_cachedKeyboard.rightShiftKey.isPressed); - - Ray ray = mainCam.ScreenPointToRay(mousePosition); - RaycastHit hit; - - // You can add a layer mask here to only raycast against specific layers - // LayerMask interactableMask = LayerMask.GetMask("NPC", "Player", "Item"); - // if (Physics.Raycast(ray, out hit, 100f, interactableMask)) - - if (Physics.Raycast(ray, out hit, 1000f)) // Reduced from 1000f to 100f for better performance + + // Estimate mouse cursor + private void EstimateCursor() { - // Try to get CECObject component (cached lookup) - CECObject hitObject = hit.collider.GetComponent(); - - if (hitObject != null) + m_cursorUpdateTimer += Time.deltaTime; + if (m_cursorUpdateTimer < CURSOR_UPDATE_INTERVAL) + return; + m_cursorUpdateTimer = 0f; + + // Early exit checks + if (IsChangingFace() || mainCam == null || m_cachedMouse == null) { - int idHitObject = CECObject.GetObjectID(hitObject); - - if (idHitObject != 0) + m_idCurHover = 0; + return; + } + + // Get mouse position using cached device + Vector2 mousePosition = m_cachedMouse.position.ReadValue(); + + // Early exit if mouse hasn't moved significantly (2 pixel threshold) + if (Vector2.Distance(mousePosition, m_lastMousePosition) < 2f) + return; + + m_lastMousePosition = mousePosition; + m_idCurHover = 0; + + CursorType cursorType = CursorType.RES_CUR_NORMAL; + + // Check modifier keys using cached keyboard + bool isShiftPressed = m_cachedKeyboard != null && + (m_cachedKeyboard.leftShiftKey.isPressed || m_cachedKeyboard.rightShiftKey.isPressed); + + Ray ray = mainCam.ScreenPointToRay(mousePosition); + RaycastHit hit; + + // You can add a layer mask here to only raycast against specific layers + // LayerMask interactableMask = LayerMask.GetMask("NPC", "Player", "Item"); + // if (Physics.Raycast(ray, out hit, 100f, interactableMask)) + + if (Physics.Raycast(ray, out hit, 1000f)) // Reduced from 1000f to 100f for better performance + { + // Try to get CECObject component (cached lookup) + CECObject hitObject = hit.collider.GetComponent(); + + if (hitObject != null) { - bool bForceAttack = isShiftPressed; - - // Check object type and set appropriate cursor - if (GPDataTypeHelper.ISNPCID(idHitObject)) + int idHitObject = CECObject.GetObjectID(hitObject); + + if (idHitObject != 0) { - // NPC handling - CECNPC pNPC = EC_ManMessageMono.Instance?._CECNPCMan?.GetNPC(idHitObject); - if (pNPC != null && !pNPC.IsDead()) + bool bForceAttack = isShiftPressed; + + // Check object type and set appropriate cursor + if (GPDataTypeHelper.ISNPCID(idHitObject)) { - m_idCurHover = idHitObject; - - if (m_idSelTarget == idHitObject && AttackableJudge(idHitObject, bForceAttack) == 1) + // NPC handling + CECNPC pNPC = EC_ManMessageMono.Instance?._CECNPCMan?.GetNPC(idHitObject); + if (pNPC != null && !pNPC.IsDead()) { - cursorType = CursorType.RES_CUR_ATTACK; - } - else if (pNPC.IsServerNPC()) - { - if (!IsInBattle() || InSameBattleCamp(pNPC)) + m_idCurHover = idHitObject; + + if (m_idSelTarget == idHitObject && AttackableJudge(idHitObject, bForceAttack) == 1) { - cursorType = CursorType.RES_CUR_TALK; + cursorType = CursorType.RES_CUR_ATTACK; + } + else if (pNPC.IsServerNPC()) + { + if (!IsInBattle() || InSameBattleCamp(pNPC)) + { + cursorType = CursorType.RES_CUR_TALK; + } } } } - } - else if (GPDataTypeHelper.ISPLAYERID(idHitObject)) - { - // Player handling - EC_ElsePlayer pPlayer = EC_ManMessageMono.Instance?.GetECManPlayer?.GetPlayer(idHitObject) as EC_ElsePlayer; - if (pPlayer != null) + else if (GPDataTypeHelper.ISPLAYERID(idHitObject)) { - m_idCurHover = idHitObject; - - if (m_idSelTarget == idHitObject && AttackableJudge(idHitObject, bForceAttack) == 1) + // Player handling + EC_ElsePlayer pPlayer = EC_ManMessageMono.Instance?.GetECManPlayer?.GetPlayer(idHitObject) as EC_ElsePlayer; + if (pPlayer != null) { - cursorType = CursorType.RES_CUR_ATTACK; + m_idCurHover = idHitObject; + + if (m_idSelTarget == idHitObject && AttackableJudge(idHitObject, bForceAttack) == 1) + { + cursorType = CursorType.RES_CUR_ATTACK; + } } } - } - else if (GPDataTypeHelper.ISMATTERID(idHitObject)) - { - //todo - // BMLogger.LogError($"[EstimateCursor]- GPDataTypeHelper.ISMATTERID: {idHitObject}"); - // Matter/item handling (uncomment when CECMatter is implemented) - // CECMatter pMatter = GetMatterManager()?.GetMatter(idHitObject); - // if (pMatter != null) - // { - // if (!pMatter.IsMine()) - // cursorType = CursorType.Pickup; - // else if (CanGatherMatter(pMatter)) - // cursorType = pMatter.IsMonsterSpiritMine() ? CursorType.Swallow : CursorType.Dig; - // - // if (cursorType != CursorType.Normal) - // m_idCurHover = idHitObject; - // } + else if (GPDataTypeHelper.ISMATTERID(idHitObject)) + { + //todo + // BMLogger.LogError($"[EstimateCursor]- GPDataTypeHelper.ISMATTERID: {idHitObject}"); + // Matter/item handling (uncomment when CECMatter is implemented) + // CECMatter pMatter = GetMatterManager()?.GetMatter(idHitObject); + // if (pMatter != null) + // { + // if (!pMatter.IsMine()) + // cursorType = CursorType.Pickup; + // else if (CanGatherMatter(pMatter)) + // cursorType = pMatter.IsMonsterSpiritMine() ? CursorType.Swallow : CursorType.Dig; + // + // if (cursorType != CursorType.Normal) + // m_idCurHover = idHitObject; + // } + } } } } + + // Apply cursor change + EC_Game.ChangeCursor((int)cursorType); } - - // Apply cursor change - EC_Game.ChangeCursor((int)cursorType); } -} -public enum StateAnim -{ - Idle = 1, - Walk = 2, - Run = 3, - Jump = 4 -} - -// Mask of some special extend states which will influence host game logic. -// Logic Influence Extned states -[Flags] -public enum Logic_Influence_Extned_states -{ - LIES_SLEEP = 0x0001, - LIES_STUN = 0x0002, - LIES_ROOT = 0x0004, - LIES_NOFGIHT = 0x0008, - - LIES_DISABLEFIGHT = 0x000B, -} - -// ½øÈë»ùµØÐÅÏ¢ -public struct FACTION_FORTRESS_ENTER -{ - public int faction_id; - public int role_in_war; // 0 : ÖÐÁ¢»ò²»ÔÚ»ùµØ 1:¹¥·½ 2: ÊØ·½ - public int end_time; - - public FACTION_FORTRESS_ENTER(int faction_id, int role_in_war, int end_time) + public enum StateAnim { - this.faction_id = faction_id; - this.role_in_war = role_in_war; - this.end_time = end_time; + Idle = 1, + Walk = 2, + Run = 3, + Jump = 4 } -} -public struct EXPToUpLevel -{ - public int NeededExp; - public EXPToUpLevel(int neededExp) + // Mask of some special extend states which will influence host game logic. + // Logic Influence Extned states + [Flags] + public enum Logic_Influence_Extned_states { - NeededExp = neededExp; - } -} -public struct NPCINFO -{ - public string Name; // Movement properties - public int CurrentHealth; - public int MaxHealth; // Attacking properties - public int IDNPC; // Attacking properties + LIES_SLEEP = 0x0001, + LIES_STUN = 0x0002, + LIES_ROOT = 0x0004, + LIES_NOFGIHT = 0x0008, - public NPCINFO(string name, int currentHealth, int maxHealth, int idnpc) + LIES_DISABLEFIGHT = 0x000B, + } + + // ½øÈë»ùµØÐÅÏ¢ + public struct FACTION_FORTRESS_ENTER { - Name = name; - CurrentHealth = currentHealth; - MaxHealth = maxHealth; - IDNPC = idnpc; + public int faction_id; + public int role_in_war; // 0 : ÖÐÁ¢»ò²»ÔÚ»ùµØ 1:¹¥·½ 2: ÊØ·½ + public int end_time; + + public FACTION_FORTRESS_ENTER(int faction_id, int role_in_war, int end_time) + { + this.faction_id = faction_id; + this.role_in_war = role_in_war; + this.end_time = end_time; + } } -}; -// PVP infomation -public struct PVPINFO -{ - public bool bEnable; // PVP switch - public uint dwCoolTime; - public uint dwMaxCoolTime; - public bool bFreePVP; // Free PVP flag, ignore bEnable flag - public bool bInPVPCombat; // true, in PVP combat - public int iDuelState; // Duel state - public int idDuelOpp; // Duel opponent - public int iDuelTimeCnt; // Duel time counter - public int iDuelRlt; // Duel result. 0, no defined; 1-win; 2-lose; 3-draw -}; - -// Current ground information -public struct GNDINFO -{ - public float fGndHei; // Ground height - public float fWaterHei; // Water height - public A3DVECTOR3 vGndNormal; // Terrain normal - public bool bOnGround; // On ground flag -}; -public struct InfoHostPlayer -{ - public string NameHostPlayer; - - public InfoHostPlayer(string name) + public struct EXPToUpLevel { - NameHostPlayer = name; + public int NeededExp; + public EXPToUpLevel(int neededExp) + { + NeededExp = neededExp; + } } -} -// Behavior id used by CanDo() -public static class ActionCanDo + public struct NPCINFO + { + public string Name; // Movement properties + public int CurrentHealth; + public int MaxHealth; // Attacking properties + public int IDNPC; // Attacking properties -{ - public const int CANDO_SITDOWN = 0, - CANDO_MOVETO = 1, - CANDO_MELEE = 2, - CANDO_ASSISTSEL = 3, - CANDO_FLY = 4, - CANDO_PICKUP = 5, - CANDO_TRADE = 6, - CANDO_PLAYPOSE = 7, - CANDO_SPELLMAGIC = 8, - CANDO_USEITEM = 9, - CANDO_JUMP = 10, - CANDO_FOLLOW = 11, - CANDO_GATHER = 12, - CANDO_BOOTH = 13, - CANDO_FLASHMOVE = 14, - CANDO_BINDBUDDY = 15, - CANDO_DUEL = 16, - CANDO_SUMMONPET = 17, - CANDO_CHANGESELECT = 18, - CANDO_REBUILDPET = 19, - CANDO_SWITCH_PARALLEL_WORLD = 20; + public NPCINFO(string name, int currentHealth, int maxHealth, int idnpc) + { + Name = name; + CurrentHealth = currentHealth; + MaxHealth = maxHealth; + IDNPC = idnpc; + } + }; + + // PVP infomation + public struct PVPINFO + { + public bool bEnable; // PVP switch + public uint dwCoolTime; + public uint dwMaxCoolTime; + public bool bFreePVP; // Free PVP flag, ignore bEnable flag + public bool bInPVPCombat; // true, in PVP combat + public int iDuelState; // Duel state + public int idDuelOpp; // Duel opponent + public int iDuelTimeCnt; // Duel time counter + public int iDuelRlt; // Duel result. 0, no defined; 1-win; 2-lose; 3-draw + }; + + // Current ground information + public struct GNDINFO + { + public float fGndHei; // Ground height + public float fWaterHei; // Water height + public A3DVECTOR3 vGndNormal; // Terrain normal + public bool bOnGround; // On ground flag + }; + public struct InfoHostPlayer + { + public string NameHostPlayer; + + public InfoHostPlayer(string name) + { + NameHostPlayer = name; + } + } + // Behavior id used by CanDo() + public static class ActionCanDo + + { + public const int CANDO_SITDOWN = 0, + CANDO_MOVETO = 1, + CANDO_MELEE = 2, + CANDO_ASSISTSEL = 3, + CANDO_FLY = 4, + CANDO_PICKUP = 5, + CANDO_TRADE = 6, + CANDO_PLAYPOSE = 7, + CANDO_SPELLMAGIC = 8, + CANDO_USEITEM = 9, + CANDO_JUMP = 10, + CANDO_FOLLOW = 11, + CANDO_GATHER = 12, + CANDO_BOOTH = 13, + CANDO_FLASHMOVE = 14, + CANDO_BINDBUDDY = 15, + CANDO_DUEL = 16, + CANDO_SUMMONPET = 17, + CANDO_CHANGESELECT = 18, + CANDO_REBUILDPET = 19, + CANDO_SWITCH_PARALLEL_WORLD = 20; + } } \ No newline at end of file diff --git a/Assets/Scripts/CECHostPlayer_Inventory.cs b/Assets/Scripts/CECHostPlayer_Inventory.cs index 3b42997524..5da4030300 100644 --- a/Assets/Scripts/CECHostPlayer_Inventory.cs +++ b/Assets/Scripts/CECHostPlayer_Inventory.cs @@ -3,52 +3,55 @@ using BrewMonster.Scripts; using BrewMonster.Scripts.Managers; using ModelRenderer.Scripts.GameData; -public partial class CECHostPlayer +namespace BrewMonster { - public int[] m_aEquips = new int[InventoryConst.IVTRSIZE_EQUIPPACK]; - - public bool UpdateEquipSkins() + public partial class CECHostPlayer { - var equipPack = EC_Inventory.GetPack(EC_Inventory.IVTRTYPE_EQUIPPACK); + public int[] m_aEquips = new int[InventoryConst.IVTRSIZE_EQUIPPACK]; - int[] aNewEquips = new int[InventoryConst.IVTRSIZE_EQUIPPACK]; - EC_IvtrItem pItem = null; - for (int i = 0; i < InventoryConst.IVTRSIZE_EQUIPPACK; i++) + public bool UpdateEquipSkins() { + var equipPack = EC_Inventory.GetPack(EC_Inventory.IVTRTYPE_EQUIPPACK); - if (equipPack.TryGetValue(i, out pItem)) + int[] aNewEquips = new int[InventoryConst.IVTRSIZE_EQUIPPACK]; + EC_IvtrItem pItem = null; + for (int i = 0; i < InventoryConst.IVTRSIZE_EQUIPPACK; i++) { - aNewEquips[i] = pItem.m_tid; + + if (equipPack.TryGetValue(i, out pItem)) + { + aNewEquips[i] = pItem.m_tid; + } } + + ShowEquipments(aNewEquips, true, true); + + return true; } - ShowEquipments(aNewEquips, true, true); - - return true; - } - - public void ShowEquipments(int[] pEquipmentID, bool bLoadAtOnce, bool bForceLoad) - { - var elemendataman = BrewMonster.ElementDataManProvider.GetElementDataMan(); - DATA_TYPE DataType = default; - for (int i = 0; i < InventoryConst.IVTRSIZE_EQUIPPACK; i++) + public void ShowEquipments(int[] pEquipmentID, bool bLoadAtOnce, bool bForceLoad) { - if (pEquipmentID[i] != m_aEquips[i]) + var elemendataman = BrewMonster.ElementDataManProvider.GetElementDataMan(); + DATA_TYPE DataType = default; + for (int i = 0; i < InventoryConst.IVTRSIZE_EQUIPPACK; i++) { - // new equipment. Need to load and equip to host player - var equipData = elemendataman.get_data_ptr((uint)pEquipmentID[i], ID_SPACE.ID_SPACE_ESSENCE, ref DataType); - switch (DataType) + if (pEquipmentID[i] != m_aEquips[i]) { - case DATA_TYPE.DT_WEAPON_ESSENCE: - var weaponData = (WEAPON_ESSENCE)equipData; - BMLogger.Log($"ShowEquipments():: Weapon Essence: {weaponData.FileModelRight} -- {weaponData.FileModelLeft}"); - break; - case DATA_TYPE.DT_ARMOR_ESSENCE: - var armorData = (ARMOR_ESSENCE)equipData; - BMLogger.Log($"ShowEquipments():: Armor Essence: {armorData.RealName}"); - break; - default: - break; + // new equipment. Need to load and equip to host player + var equipData = elemendataman.get_data_ptr((uint)pEquipmentID[i], ID_SPACE.ID_SPACE_ESSENCE, ref DataType); + switch (DataType) + { + case DATA_TYPE.DT_WEAPON_ESSENCE: + var weaponData = (WEAPON_ESSENCE)equipData; + BMLogger.Log($"ShowEquipments():: Weapon Essence: {weaponData.FileModelRight} -- {weaponData.FileModelLeft}"); + break; + case DATA_TYPE.DT_ARMOR_ESSENCE: + var armorData = (ARMOR_ESSENCE)equipData; + BMLogger.Log($"ShowEquipments():: Armor Essence: {armorData.RealName}"); + break; + default: + break; + } } } } diff --git a/Assets/Scripts/EC_Utility.cs b/Assets/Scripts/EC_Utility.cs index 97239ed2bf..aad8b42dde 100644 --- a/Assets/Scripts/EC_Utility.cs +++ b/Assets/Scripts/EC_Utility.cs @@ -2,6 +2,8 @@ using BrewMonster; using CSNetwork.GPDataType; using System; using System.Collections; +using System.IO; +using System.IO.Compression; using System.Runtime.InteropServices; using System.Text; using UnityEngine; @@ -63,6 +65,47 @@ public static class EC_Utility Marshal.FreeHGlobal(ptr); } } + public static byte[] UncompressData(byte[] compressedData, int expectedSize) + { + // Bỏ header zlib 2 byte (0x78 0x9C hoặc tương tự) + int start = 2; + int len = compressedData.Length - 6; // bỏ 4 byte ADLER32 cuối + + using var ms = new MemoryStream(compressedData, start, len); + using var ds = new DeflateStream(ms, CompressionMode.Decompress); + using var outMs = new MemoryStream(expectedSize); + + ds.CopyTo(outMs); + + return outMs.ToArray(); + } + public static int UncompressData( + byte[] compressedBuffer, + int compressedLength, + byte[] outBuffer, + ref uint outLength) + { + try + { + byte[] result = UncompressData(compressedBuffer, (int)outLength); + + if (result.Length > outBuffer.Length) + return -1; // dest buffer quá nhỏ giống C++ + + Buffer.BlockCopy(result, 0, outBuffer, 0, result.Length); + outLength = (uint)result.Length; + + return 0; // OK + } + catch (InvalidDataException) + { + return -2; // inflate failed + } + catch + { + return -2; + } + } public static Vector3 glb_DecompressDirH(byte byDir) { const float fInter = 360.0f / 256.0f; diff --git a/Assets/StarterAssets/ThirdPersonController/Scripts/ThirdPersonController.cs b/Assets/StarterAssets/ThirdPersonController/Scripts/ThirdPersonController.cs index 3068a8777f..3da77b5774 100644 --- a/Assets/StarterAssets/ThirdPersonController/Scripts/ThirdPersonController.cs +++ b/Assets/StarterAssets/ThirdPersonController/Scripts/ThirdPersonController.cs @@ -1,4 +1,5 @@ -using BrewMonster.Scripts.Player; +using BrewMonster; +using BrewMonster.Scripts.Player; using UnityEngine; #if ENABLE_INPUT_SYSTEM using UnityEngine.InputSystem;