diff --git a/Assets/NetworkLib/Debug/netstandard2.1/CSNetwork.dll b/Assets/NetworkLib/Debug/netstandard2.1/CSNetwork.dll index 372deb8d5a..6976f49050 100644 Binary files a/Assets/NetworkLib/Debug/netstandard2.1/CSNetwork.dll and b/Assets/NetworkLib/Debug/netstandard2.1/CSNetwork.dll differ diff --git a/Assets/PerfectWorld/Scripts/Managers/A3DFuncs.cs b/Assets/PerfectWorld/Scripts/Managers/A3DFuncs.cs index d06611f62a..e5d905547c 100644 --- a/Assets/PerfectWorld/Scripts/Managers/A3DFuncs.cs +++ b/Assets/PerfectWorld/Scripts/Managers/A3DFuncs.cs @@ -4,7 +4,7 @@ using UnityEngine; public class A3DFuncs { // Returns vector with same direction and unit length - static A3DVECTOR3 a3d_Normalize(A3DVECTOR3 v) + public static A3DVECTOR3 a3d_Normalize(A3DVECTOR3 v) { float mag = v.Magnitude(); if (mag< 1e-12 && mag> -1e-12) diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_HPWorkMelee.cs b/Assets/PerfectWorld/Scripts/Managers/EC_HPWorkMelee.cs index 4fdb32e93b..f2a1b50c1f 100644 --- a/Assets/PerfectWorld/Scripts/Managers/EC_HPWorkMelee.cs +++ b/Assets/PerfectWorld/Scripts/Managers/EC_HPWorkMelee.cs @@ -54,7 +54,7 @@ class CECHPWorkMelee : CECHPWork // If target turn to be un-attackable, cancel action if (m_pHost.AttackableJudge(m_idTarget, true) == 0) { - //g_pGame.GetGameSession().c2s_CmdCancelAction(); + g_pGame.GetGameSession().c2s_CmdCancelAction(); m_bFinished = true; return true; } diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_HPWorkTrace.cs b/Assets/PerfectWorld/Scripts/Managers/EC_HPWorkTrace.cs index 5743504dc5..b10f74e553 100644 --- a/Assets/PerfectWorld/Scripts/Managers/EC_HPWorkTrace.cs +++ b/Assets/PerfectWorld/Scripts/Managers/EC_HPWorkTrace.cs @@ -1,4 +1,10 @@ +using BrewMonster; +using BrewMonster.Network; using CSNetwork.GPDataType; +using PerfectWorld.Scripts.Player; +using System; +using System.Runtime.ConstrainedExecution; +using UnityEngine; /////////////////////////////////////////////////////////////////////////// // @@ -6,16 +12,16 @@ using CSNetwork.GPDataType; // /////////////////////////////////////////////////////////////////////////// -enum TraceObjectType +public static class TraceObjectType { - TRACE_NONE = 0, - TRACE_PLAYER, - TRACE_MATTER, - TRACE_NPC, - TRACE_TASKNPC -}; + public const int TRACE_NONE = 0, + TRACE_PLAYER = 1, + TRACE_MATTER = 2, + TRACE_NPC = 3, + TRACE_TASKNPC = 4; +} -abstract class CECTracedObject +public abstract class CECTracedObject { //friend CECHPWorkTrace; protected int m_iTraceType; @@ -46,22 +52,48 @@ abstract class CECTracedObject public abstract bool OnTouched(); public abstract CECTracedObject Clone(); - // TO DO: fix later public virtual bool IsTargetMissing() { - //if (m_iObjectId != 0) - //{ - // CECObject pObj = g_pGame->GetGameRun()->GetWorld()->GetObject(m_iObjectId, 0); - // if (pObj) - // { - // return false; - // } - //} - //return true; - return false; + if (m_iObjectId != 0) + { + CECObject pObj = EC_ManMessageMono.Instance.GetObject(m_iObjectId, 0); + if (pObj) + { + return false; + } + } + return true; + } + + public A3DVECTOR3? GetMovePos() + { + A3DVECTOR3 vMovePos; + CECObject pObject = EC_ManMessageMono.Instance.GetObject(m_iObjectId, 0); + if (pObject) + { + if (GPDataTypeHelper.ISPLAYERID(m_iObjectId)) + { + if (m_iObjectId == m_pHost.GetCharacterID()) + { + vMovePos = m_pHost.GetPos(); + } + else + { + vMovePos = (pObject as EC_ElsePlayer).GetServerPos(); + } + } + else if (GPDataTypeHelper.ISNPCID(m_iObjectId)) + { + vMovePos = (pObject as CECNPC).GetServerPos(); + } + else + { + vMovePos = pObject.GetPos(); + } + return vMovePos; + } + return null; } - // TO DO: fix later - //public virtual A3DVECTOR3 GetMovePos(); public int GetObjectID() { @@ -96,7 +128,7 @@ abstract class CECTracedObject float fMaxCut = m_bMoreClose ? -1.0f : 1.0f; - CECObject pObject = g_pGame->GetGameRun()->GetWorld()->GetObject(m_iObjectId, 0); + CECObject pObject = EC_ManMessageMono.Instance.GetObject(m_iObjectId, 0); float fTouchRadius = 0.0f; if (GPDataTypeHelper.ISPLAYERID(m_iObjectId)) @@ -107,7 +139,7 @@ abstract class CECTracedObject } else { - CECPlayer pPlayer = pObject as CECPlayer; + EC_Player pPlayer = pObject.GetComponent(); fTouchRadius = pPlayer.GetTouchRadius(); } return m_pHost.CanTouchTarget(vHostPos, vTargetPos, fTouchRadius, iTouchReason, fMaxCut); @@ -118,21 +150,358 @@ abstract class CECTracedObject fTouchRadius = pNPC.GetTouchRadius(); return m_pHost.CanTouchTarget(vHostPos, vTargetPos, fTouchRadius, iTouchReason, fMaxCut); } - else if (GPDataTypeHelper.ISMATTERID(m_iObjectId)) - { - CECMatter pMatter = (pObject) as CECMatter; - return pMatter.CalcDist(vHostPos, true) < pMatter.GetGatherDist(); - } + //else if (GPDataTypeHelper.ISMATTERID(m_iObjectId)) + //{ + // CECMatter pMatter = (pObject) as CECMatter; + // return pMatter.CalcDist(vHostPos, true) < pMatter.GetGatherDist(); + //} break; } return false; } - public int GetTraceType(); - public CECObject GetTargetObject(); + public int GetTraceType() + { + return m_iTraceType; + } + public CECObject GetTargetObject() + { + return EC_ManMessageMono.Instance.GetObject(m_iObjectId, 0); + } }; +public class CECTracedNPC : CECTracedObject +{ + protected bool m_bForceAttack; -class CECHPWorkTrace : CECHPWork + public CECTracedNPC(int type, int id, CECHostPlayer pHost, int ireason, bool bForceAttack = false) : base (type, id, pHost, ireason) + { + m_bForceAttack = bForceAttack; + } + public CECTracedNPC(CECTracedNPC rhs) : base(rhs) + { + m_bForceAttack = rhs.m_bForceAttack; + } + + public override bool OnTargetMissing() + { + bool bRet = false; + + if (m_iReason == CECHPWorkTrace.Trace_reason.TRACE_ATTACK) + { + bRet = true; + } + //else if (m_iReason == CECHPWorkTrace.Trace_reason.TRACE_SPELL) + //{ + // CECSkill pSkill = m_pHost.m_pPrepSkill; + // if (pSkill == null || pSkill.GetTargetType() != 2) + // { + // bRet = true; + // m_pHost.m_pPrepSkill = null; + // } + //} + return bRet; + } + + public override A3DVECTOR3 GetTargetPos() + { + return (GetTargetObject() as CECNPC).GetServerPos(); + } + + public override bool OnTouched() + { + bool bActionDone = false; + + if (GPDataTypeHelper.ISNPCID(m_iObjectId)) + { + CECNPC pNPC = (CECNPC)GetTargetObject(); + + if (m_iReason == CECHPWorkTrace.Trace_reason.TRACE_TALK) + { + if ((!m_pHost.IsInBattle() || m_pHost.InSameBattleCamp(pNPC)) /*&& + !g_pGame.GetGameRun().GetUIManager().GetInGameUIMan().GetDialog("Win_SkillAction").IsShow()*/) + { + UnityGameSession.c2s_CmdNPCSevHello(m_iObjectId); + bActionDone = true; + //a_LogOutput(1, "[NormalATK]- CECTracedNPC- OnTouched- TRACE_TALK"); + } + } + else if (m_iReason == CECHPWorkTrace.Trace_reason.TRACE_ATTACK) + { + if (m_iObjectId == m_pHost.m_idSelTarget && + m_pHost.AttackableJudge(m_iObjectId, m_bForceAttack) == 1) + { + byte byPVPMask = EC_Utility.glb_BuildPVPMask(m_bForceAttack); + UnityGameSession.c2s_CmdNormalAttack(byPVPMask); + m_pHost.m_bPrepareFight = true; + bActionDone = true; + //a_LogOutput(1, "[NormalATK]- CECTracedNPC- OnTouched- TRACE_ATTACK"); + } + } + //else if (m_iReason == CECHPWorkTrace.Trace_reason.TRACE_SPELL) + //{ + // //a_LogOutput(1, "[NormalATK]- CECTracedNPC- OnTouched- TRACE_SPELL"); + // if (!m_pHost.CannotAttack()) + // { + // if (m_pHost.CastSkill(m_iObjectId, m_bForceAttack)) + // bActionDone = true; + // } + // else + // m_pHost.m_pPrepSkill = null; + //} + } + return bActionDone; + } + + public override CECTracedObject Clone() + { + return new CECTracedNPC(this); + } + + public override bool IsTargetMissing() + { + if (base.IsTargetMissing()) + { + return true; + } + CECNPC pNPC = GetTargetObject() as CECNPC; + if (pNPC.IsDead()) + { + return true; + } + return false; + } +} + +public class CECTracedPlayer : CECTracedObject +{ + protected bool m_bForceAttack; + public CECTracedPlayer(int type, int id, CECHostPlayer pHost, int ireason, bool bForceAttack = false) : base(type, id, pHost, ireason) + { + m_bForceAttack = bForceAttack; + } + public CECTracedPlayer(CECTracedPlayer rhs) : base(rhs) + { + m_bForceAttack = rhs.m_bForceAttack; + } + + public override bool OnTargetMissing() + { + bool bRet = false; + + if (m_iReason == CECHPWorkTrace.Trace_reason.TRACE_ATTACK) + { + bRet = true; + } + //else if (m_iReason == CECHPWorkTrace.Trace_reason.TRACE_SPELL) + //{ + // CECSkill pSkill = m_pHost.m_pPrepSkill; + // if (pSkill == null || pSkill.GetTargetType() != 2) + // { + // bRet = true; + // m_pHost.m_pPrepSkill = null; + // } + //} + return bRet; + } + + public override A3DVECTOR3 GetTargetPos() + { + CECObject pObject = EC_ManMessageMono.Instance.GetObject(m_iObjectId, 0); + if (m_iObjectId == m_pHost.GetCharacterID()) + { + return m_pHost.GetPos(); + } + else + { + return (pObject as EC_ElsePlayer).GetServerPos(); + } + } + + public override bool OnTouched() + { + bool bActionDone =false; + if (GPDataTypeHelper.ISPLAYERID(m_iObjectId)) + { + if (m_iObjectId == 0 || m_iObjectId == m_pHost.GetCharacterID()) + { + // Handle special case + //ASSERT(m_iReason == CECHPWorkTrace::TRACE_SPELL); + //if (!m_pHost.CannotAttack()) + //{ + // if (m_pHost.CastSkill(m_iObjectId, m_bForceAttack, null)) + // bActionDone = true; + //} + //else + //{ + // m_pHost.m_pPrepSkill = null; + //} + //a_LogOutput(1, "[NormalATK]- CECTracedPlayer- OnTouched- special case- TRACE_SPELL"); + return bActionDone; + } + if (m_iReason == CECHPWorkTrace.Trace_reason.TRACE_ATTACK) + { + if (m_iObjectId == m_pHost.m_idSelTarget && + m_pHost.AttackableJudge(m_iObjectId, m_bForceAttack) == 1) + { + byte byPVPMask = EC_Utility.glb_BuildPVPMask(m_bForceAttack); + UnityGameSession.c2s_CmdNormalAttack(byPVPMask); + m_pHost.m_bPrepareFight = true; + bActionDone = true; + //a_LogOutput(1, "[NormalATK]- CECTracedPlayer- OnTouched- TRACE_ATTACK"); + } + } + //else if (m_iReason == CECHPWorkTrace.Trace_reason.TRACE_SPELL) + //{ + // //a_LogOutput(1, "[NormalATK]- CECTracedPlayer- OnTouched- TRACE_SPELL"); + // if (!m_pHost.CastSkill(m_iObjectId, m_bForceAttack, GetTargetObject())) + // { + // m_pHost.m_pPrepSkill = null; + // } + // else + // { + // bActionDone = true; + // } + //} + else if (m_iReason == CECHPWorkTrace.Trace_reason.TRACE_TALK) + { + // Visite other's booth, send hello message to him + //a_LogOutput(1, "[NormalATK]- CECTracedPlayer- OnTouched- TRACE_TALK"); + UnityGameSession.c2s_CmdNPCSevHello(m_iObjectId); + bActionDone = true; + } + } + return bActionDone; + } + + public override CECTracedObject Clone() + { + return new CECTracedPlayer(this); + } + + public override bool IsTargetMissing() + { + if (base.IsTargetMissing()) + { + return true; + } + EC_Player pPlayer = GetTargetObject() as EC_Player; + if (pPlayer.IsElsePlayer()) + { + if (pPlayer.IsDead()) + { + //if (m_iReason == CECHPWorkTrace.Trace_reason.TRACE_SPELL) + //{ + // CECSkill pSkill = m_pHost.m_pPrepSkill; + // if (pSkill && pSkill.GetTargetType() == 2) + // { + // return false; + // } + //} + return true; + } + } + return false; + } +}; + +public class CECTracedMatter : CECTracedObject +{ + + public CECTracedMatter(int type, int id, CECHostPlayer pHost, int ireason) : base(type, id, pHost, ireason) + { + + } + public CECTracedMatter(CECTracedMatter rhs) : base(rhs) + { + + } + + public override bool OnTargetMissing() + { + return false; + } + + public override A3DVECTOR3 GetTargetPos() + { + return GetTargetObject().GetPos(); + } + + public override bool OnTouched() + { + bool bActionDone = false; + //if (GPDataTypeHelper.ISMATTERID(m_iObjectId)) + //{ + // if (m_pHost.GetProfession() == PROF_GHOST && m_pHost.IsInvisible()) + // { + // g_pGame.GetGameRun().AddFixedMessage(FIXMSG_CANNOT_USE_WHEN_INVISIBLE); + // return bActionDone; + // } + // CECMatter* pMatter = (CECMatter*)GetTargetObject(); + + // if (m_iReason == CECHPWorkTrace::TRACE_PICKUP) + // { + // // Check whether we have enougth place to hold this item or money + // a_LogOutput(1, "[NormalATK]- CECTracedMatter- OnTouched- TRACE_PICKUP"); + // if (m_pHost.CanTakeItem(pMatter.GetTemplateID(), 1)) + // { + // // Send pickup asking and wait response command + // g_pGame.GetGameSession().c2s_CmdPickup(m_iObjectId, pMatter.GetTemplateID()); + // bActionDone = true; + // } + // else + // { + // // Print a notify message + // g_pGame.GetGameRun().AddFixedMessage(FIXMSG_PACKISFULL); + // } + // } + // else + // { // m_iReason == TRACE_GATHER + // int tidMatter = pMatter.GetTemplateID(); + // a_LogOutput(1, "[NormalATK]- CECTracedMatter- OnTouched- TRACE_GATHER"); + // // Check mine level requirement + // if (m_pHost.GetBasicProps().iLevel < pMatter.GetLevelReq()) + // { + // g_pGame.GetGameRun().AddFixedMessage(FIXMSG_LEVELTOOLOW); + // return bActionDone; + // } + + // // Check whether we have a mine tool + // int iPack, iIndex, idTool; + // if (m_pHost.FindMineTool(tidMatter, &iPack, &iIndex, &idTool)) + // { + // DATA_TYPE DataType; + // const MINE_ESSENCE* pData = (const MINE_ESSENCE*)g_pGame.GetElementDataMan().get_data_ptr(pMatter.GetTemplateID(), ID_SPACE_ESSENCE, DataType); + // if (DataType != DT_MINE_ESSENCE) + // { + // ASSERT(DataType == DT_MINE_ESSENCE); + // return bActionDone; + // } + + // if (m_pHost.GetCoolTime(GP_CT_PLAYER_GATHER)) + // { + // g_pGame.GetGameRun().AddFixedMessage(FIXMSG_CMD_INCOOLTIME); + // } + // else + // { + // // Send gather asking and wait response command + // g_pGame.GetGameSession().c2s_CmdGatherMaterial(m_iObjectId, iPack, iIndex, idTool, pData.task_in); + // } + // } + // else + // { + // g_pGame.GetGameRun().AddFixedMessage(FIXMSG_NEEDTOOL); + // } + // } + //} + return bActionDone; + } + + public override CECTracedObject Clone() + { + return new CECTracedMatter(this); + } +}; +public class CECHPWorkTrace : CECHPWork { // Trace reason public static class Trace_reason @@ -145,90 +514,417 @@ class CECHPWorkTrace : CECHPWork TRACE_GATHER = 4; // Gather object } // Constructor and Destructor - public CECHPWorkTrace(CECHPWorkMan pWorkMan) + public CECHPWorkTrace(CECHPWorkMan pWorkMan) : base(Host_work_ID.WORK_TRACEOBJECT, pWorkMan) { + m_dwMask = Work_mask.MASK_TRACEOBJECT; + m_dwTransMask = Work_mask.MASK_STAND | Work_mask.MASK_MOVETOPOS | Work_mask.MASK_FLYOFF | Work_mask.MASK_FREEFALL | + Work_mask.MASK_FOLLOW | Work_mask.MASK_USEITEM; - } + Reset(); + } // Change trace target //void ChangeTarget(int idTarget, int iReason, bool bUseAutoPF=false); // 设定traceobject public void SetTraceTarget(CECTracedObject pTraceObj, bool bUseAutoPF = false) { + ResetUseAutoPF(bUseAutoPF); + if (!pTraceObj.GetTargetObject() || pTraceObj.GetObjectID() == m_pHost.GetCharacterID()) + { + // This is special case + ReplaceTarget(pTraceObj); + return; + } + int idTarget = pTraceObj.GetObjectID(); + if (!GPDataTypeHelper.ISPLAYERID(idTarget) && !GPDataTypeHelper.ISNPCID(idTarget) && !GPDataTypeHelper.ISMATTERID(idTarget)) + { + return; + } + CECObject pObject = pTraceObj.GetTargetObject(); + if (!pObject) + { + //delete pTraceObj; + return; + } + ReplaceTarget(pTraceObj); + if (m_pTraceObject.GetTargetObject()) + { + A3DVECTOR3 vDirH = pTraceObj.GetTargetPos() - m_pHost.GetPos(); + vDirH.y = 0.0f; + vDirH.Normalize(); + m_vCurDirH = !vDirH.IsZero() ? vDirH : m_vCurDirH = GPDataTypeHelper.g_vAxisZ; + } + } - } - -CECTracedObject CreatTraceTarget(int iTraceObjId, int iReason, bool bForceAttack = false); + public CECTracedObject CreatTraceTarget(int iTraceObjId, int iReason, bool bForceAttack = false) + { + if (GPDataTypeHelper.ISPLAYERID(iTraceObjId)) + { + return new CECTracedPlayer(TraceObjectType.TRACE_PLAYER, iTraceObjId, m_pHost, iReason, bForceAttack); + } + else if (GPDataTypeHelper.ISNPCID(iTraceObjId)) + { + return new CECTracedNPC(TraceObjectType.TRACE_NPC, iTraceObjId, m_pHost, iReason, bForceAttack); + } + //else if (GPDataTypeHelper.ISMATTERID(iTraceObjId)) + //{ + // return new CECTracedMatter(TraceObjectType.TRACE_MATTER, iTraceObjId, m_pHost, iReason); + //} + return null; + } // Tick routine -virtual bool Tick(DWORD dwDeltaTime); +public virtual bool Tick(float dwDeltaTime) + { + base.Tick(dwDeltaTime); + + CheckPrepSkill(); + + UpdateResetUseAutoPF(); + UpdateUseAutoPF(); + + // m_bFinished flag may be set both in OnFirstTick() and CheckPrepSkill(), + // so check it here ! + if (m_bFinished) + { + return true; + } + if (m_pTraceObject.IsTargetMissing()) + { + OnTargetMissing(); + return true; + } + + if (m_bCheckTouch) + { + if (IsGoodTimeToTouch()) + { + if (m_pTraceObject.CanTouchFrom(m_pHost.GetPos())) + { + OnTouchTarget(); + return true; + } + } + } + m_bCheckTouch = true; + + if (!m_pHost.IsRooting()) + { + // Continue tracing object + float fDeltaTime = dwDeltaTime /** 0.001f*/; + if (m_pHost.m_iMoveEnv == EC_Player.Move_environment.MOVEENV_GROUND) + { + // Play appropriate actions + if (!m_pHost.IsJumping() && !m_pHost.IsPlayingAction((int)EC_Player.PLAYER_ACTION_TYPE.ACT_TRICK_RUN) && + m_pHost.m_iMoveMode != (int)MoveMode.MOVE_SLIDE) + { + int iAction = m_pHost.GetMoveStandAction(true); + m_pHost.PlayAction(iAction, false, 200, false); + } + + Trace_Walk(fDeltaTime); + } + else // (m_pHost.m_iMoveEnv == CECPlayer::MOVEENV_AIR || m_pHost.m_iMoveEnv == CECPlayer::MOVEENV_WATER) + { + m_pHost.ResetJump(); + + // Play appropriate actions + int iAction = m_pHost.GetMoveStandAction(true); + m_pHost.PlayAction(iAction, false, 200, false); + + Trace_FlySwim(fDeltaTime); + } + + m_bHaveMoved = true; + } + + return true; + } // Reset work -virtual void Reset(); +public override void Reset() + { + base.Reset(); + + m_bHaveMoved = false; + m_bMeetSlide = false; + m_bCheckTouch = true; + m_bReadyCancel = false; + m_bMoreClose = false; + //m_pPrepSkill = null; + m_bForceAttack = false; + m_bActionDone = false; + ClearResetUseAutoPF(); + m_bUseAutoPF = false; + m_dwAutoPFNextCheckTime = 0; + m_pTraceObject = null; + } // Work is cancel -virtual void Cancel(); +public override void Cancel() + { + //if (m_pHost.m_pPrepSkill && m_pTraceObject.GetTraceReason() == Trace_reason.TRACE_SPELL) + // m_pHost.m_pPrepSkill = null; + + ClearResetUseAutoPF(); + if (GetUseAutoPF()) + { + SetUseAutoPF(false); + } + //m_pHost.StopModelMove(); + base.Cancel(); + + //AP_ActionEvent(m_bActionDone ? AP_EVENT_TRACEOK : AP_EVENT_MOVEFINISHED, m_pTraceObject.GetTraceReason()); + } // This work is do player moving ? -virtual bool IsMoving() { return true; } +public override bool IsMoving() { return true; } // Copy work data -virtual bool CopyData(CECHPWork* pWork); +public override bool CopyData(CECHPWork pWork) + { + if (!base.CopyData(pWork)) + return false; + + CECHPWorkTrace pSrc = (CECHPWorkTrace)pWork; + + m_bHaveMoved = pSrc.m_bHaveMoved; + m_bMeetSlide = pSrc.m_bMeetSlide; + m_bCheckTouch = pSrc.m_bCheckTouch; + m_bReadyCancel = pSrc.m_bReadyCancel; + m_bMoreClose = pSrc.m_bMoreClose; + m_vCurDirH = pSrc.m_vCurDirH; + //m_pPrepSkill = pSrc.m_pPrepSkill; + m_bForceAttack = pSrc.m_bForceAttack; + m_bActionDone = pSrc.m_bActionDone; + m_bShouldResetUseAutoPF = pSrc.m_bShouldResetUseAutoPF; + m_bUseAutoPFResetValue = pSrc.m_bUseAutoPFResetValue; + m_bUseAutoPF = pSrc.m_bUseAutoPF; + m_dwAutoPFNextCheckTime = pSrc.m_dwAutoPFNextCheckTime; + + //delete m_pTraceObject; + m_pTraceObject = pSrc.m_pTraceObject.Clone(); + + return true; + } // User press cancel button -void PressCancel(); +public void PressCancel() + { + m_bReadyCancel = true; + //if (m_pTraceObject.GetTraceReason() == TRACE_SPELL) + // m_pHost.m_pPrepSkill = NULL; + } // Set move close flag -void SetMoveCloseFlag(bool bMoveClose) { m_pTraceObject->SetMoveCloseFlag(bMoveClose); } +public void SetMoveCloseFlag(bool bMoveClose) { m_pTraceObject.SetMoveCloseFlag(bMoveClose); } -// Set / Get force attack flag -void SetForceAttack(bool bTrue) { m_bForceAttack = bTrue; } -bool GetForceAttack() { return m_bForceAttack; } -// Set / Get prepared skill -void SetPrepSkill(CECSkill* pSkill) { m_pPrepSkill = pSkill; } -CECSkill* GetPrepSkill() { return m_pPrepSkill; } -// Get target ID -int GetTarget() { return m_pTraceObject->GetObjectID(); } -// Get trace reason -int GetTraceReason() { return m_pTraceObject->GetTraceReason(); } -// AutoPF -void SetUseAutoPF(bool bUse); -bool GetUseAutoPF()const; -bool IsAutoPF()const; + // Set / Get force attack flag + public void SetForceAttack(bool bTrue) { m_bForceAttack = bTrue; } + public bool GetForceAttack() { return m_bForceAttack; } + // Set / Get prepared skill + public void SetPrepSkill(CECSkill pSkill) { /*m_pPrepSkill = pSkill;*/ } +public CECSkill GetPrepSkill() { /*return m_pPrepSkill;*/ return null; } + // Get target ID + public int GetTarget() { return m_pTraceObject.GetObjectID(); } + // Get trace reason + public int GetTraceReason() { return m_pTraceObject.GetTraceReason(); } + // AutoPF + public void SetUseAutoPF(bool bUse) + { + m_bUseAutoPF = bUse; + //if (!m_bUseAutoPF && CECIntelligentRoute.Instance().IsUsageTrace()) + //{ + // CECIntelligentRoute.Instance().ResetSearch(); + //} + } +public bool GetUseAutoPF() + { + return m_bUseAutoPF; + } +public bool IsAutoPF() + { + return false; + } -void SetActionDone(bool bActionDone) { m_bActionDone = bActionDone; } +public void SetActionDone(bool bActionDone) { m_bActionDone = bActionDone; } -void OnTargetMissing(); +public void OnTargetMissing() + { + StopMove(true); + if ((m_pTraceObject.GetTraceType() == TraceObjectType.TRACE_NPC) || (m_pTraceObject.GetTraceType() == TraceObjectType.TRACE_PLAYER)) + { + m_pTraceObject.OnTargetMissing(); + } + //else if (m_pTraceObject.GetTraceReason() == Trace_reason.TRACE_SPELL) + //{ + // m_pHost.m_pPrepSkill = null; + //} + } -void OnTouchTarget(); -bool CanTouch(); +public void OnTouchTarget() + { + StopMove(true); + m_bActionDone = m_pTraceObject.OnTouched(); + } +public bool CanTouch() + { + //CECSkill pPrepSkill = m_pHost.m_pPrepSkill; + CheckPrepSkill(); + bool result = m_pTraceObject.CanTouchFrom(m_pHost.GetPos()); + //m_pHost.m_pPrepSkill = pPrepSkill; + return result; + } + // Attributes -protected: // Attributes + protected bool m_bHaveMoved; // Have moved flag + protected bool m_bMeetSlide; // true, meet slide + protected bool m_bCheckTouch; // Check whether touch target in this frame + protected A3DVECTOR3 m_vCurDirH; // Current move direction + protected bool m_bReadyCancel; // true, ready to cancel + protected bool m_bMoreClose; // Move close flag + protected bool m_bForceAttack; // Force attack flag + protected CECSkill m_pPrepSkill; // Skill prepared to be casted + protected bool m_bActionDone; // 目标行为成功发出 + protected bool m_bShouldResetUseAutoPF; + protected bool m_bUseAutoPFResetValue; + protected bool m_bUseAutoPF; // Use CECIntelligentRoute::Search + protected uint m_dwAutoPFNextCheckTime; // 下次检查时间 - bool m_bHaveMoved; // Have moved flag -bool m_bMeetSlide; // true, meet slide -bool m_bCheckTouch; // Check whether touch target in this frame -A3DVECTOR3 m_vCurDirH; // Current move direction -bool m_bReadyCancel; // true, ready to cancel -bool m_bMoreClose; // Move close flag -bool m_bForceAttack; // Force attack flag -CECSkill* m_pPrepSkill; // Skill prepared to be casted -bool m_bActionDone; // 目标行为成功发出 -bool m_bShouldResetUseAutoPF; -bool m_bUseAutoPFResetValue; -bool m_bUseAutoPF; // Use CECIntelligentRoute::Search -DWORD m_dwAutoPFNextCheckTime; // 下次检查时间 + protected CECTracedObject m_pTraceObject; // 定义trace目标对象 -CECTracedObject* m_pTraceObject; // 定义trace目标对象 + // Operations -protected: // Operations + // On first tick + protected virtual void OnFirstTick() + { + m_pHost.m_iMoveMode = (int)MoveMode.MOVE_MOVE; + m_bHaveMoved = false; + } - // On first tick - virtual void OnFirstTick(); + // Trace on ground + protected bool Trace_Walk(float fDeltaTime) + { + A3DVECTOR3 vCurPos = m_pHost.GetPos(); + A3DVECTOR3 vTargetPos = GetCurMovingDest(); + CDR_INFO cdr = m_pHost.m_CDRInfo; -// Trace on ground -bool Trace_Walk(float fDeltaTime); + if (m_pHost.m_iMoveMode == (int)MoveMode.MOVE_SLIDE) + { + m_pHost.PlayAction((int)EC_Player.PLAYER_ACTION_TYPE.ACT_JUMP_LOOP, false, 200, false); + + // This will cause stop moming after we slide down. + A3DVECTOR3 vDir = vTargetPos - vCurPos; + vDir.y = 0; + vDir.Normalize(); + + float fMaxSpeedV = 0f; + m_bMeetSlide = m_pHost.m_MoveCtrl.MeetSlope(vDir, fMaxSpeedV); + EC_Utility.a_ClampFloor(cdr.fYVel, -fMaxSpeedV); + + if (!vDir.IsZero()) + m_vCurDirH = vDir; + + vCurPos = m_pHost.m_MoveCtrl.GroundMove(m_vCurDirH, m_pHost.GetGroundSpeed(), fDeltaTime); + if (m_pHost.m_MoveCtrl.MoveBlocked() >= 3) + { + m_pHost.m_MoveCtrl.SetSlideLock(true); + m_pHost.m_MoveCtrl.SendStopMoveCmd(EC_Utility.ToVector3(vCurPos), m_pHost.GetGroundSpeed(), (int)GPMoveMode.GP_MOVE_SLIDE); + m_bFinished = true; + } + else + { + m_pHost.SetPos(EC_Utility.ToVector3(vCurPos)); + //if (GetUseAutoPF() && CECIntelligentRoute::Instance().IsMoveOn()) + //{ + // CECIntelligentRoute::Instance().OnPlayerPosChange(vCurPos); + //} + m_pHost.m_MoveCtrl.SendMoveCmd(vCurPos, 2, GPDataTypeHelper.g_vOrigin, EC_Utility.ToA3DVECTOR3(cdr.vAbsVelocity), (int)GPMoveMode.GP_MOVE_SLIDE); + } + } + else if (!m_bMeetSlide) + { + int iMoveMode = m_pHost.m_bWalkRun ? (int)GPMoveMode.GP_MOVE_RUN : (int)GPMoveMode.GP_MOVE_WALK; + if (m_pHost.IsJumping()) + iMoveMode = (int)GPMoveMode.GP_MOVE_JUMP; + else if (!m_pHost.m_GndInfo.bOnGround) + iMoveMode = (int)GPMoveMode.GP_MOVE_FALL; + + if (m_pHost.m_GndInfo.bOnGround) + { + if (m_bReadyCancel) + { + StopMove(true); + return true; + } + + // Ajust direction only when player on ground + A3DVECTOR3 vDirH = vTargetPos - vCurPos; + A3DVECTOR3 v = A3DFuncs.a3d_Normalize(vDirH); + if (Math.Abs(v.y) > 0.9848f) + { + PressCancel(); + return true; + } + + vDirH.y = 0.0f; + vDirH.Normalize(); + if (!vDirH.IsZero()) + m_vCurDirH = vDirH; + } + + vCurPos = m_pHost.m_MoveCtrl.GroundMove(m_vCurDirH, m_pHost.GetGroundSpeed(), fDeltaTime, m_pHost.m_fVertSpeed); + m_pHost.SetPos(EC_Utility.ToVector3(vCurPos)); + //if (GetUseAutoPF() && CECIntelligentRoute::Instance().IsMoveOn()) + //{ + // CECIntelligentRoute::Instance().OnPlayerPosChange(vCurPos); + //} + + if (cdr.vTPNormal == Vector3.zero) + m_bCheckTouch = false; + + //if (!m_vCurDirH.IsZero()) + //{ + // m_pHost.StartModelMove(m_vCurDirH, g_vAxisY, 0); + //} + + if (m_pHost.m_MoveCtrl.MoveBlocked() >= 3) + { + // m_pHost.m_MoveCtrl.SendStopMoveCmd(vCurPos, m_pHost.GetGroundSpeed(), iMoveMode); + PressCancel(); + } + else + m_pHost.m_MoveCtrl.SendMoveCmd(vCurPos, 0, vTargetPos, EC_Utility.ToA3DVECTOR3(cdr.vAbsVelocity), iMoveMode); + } + else // m_bMeetSlide == true + { + if (m_bHaveMoved) + m_pHost.m_MoveCtrl.SendStopMoveCmd(EC_Utility.ToVector3(vCurPos), m_pHost.GetGroundSpeed(), (int)GPMoveMode.GP_MOVE_SLIDE); + + m_bFinished = true; + } + return true; + } // Trace in air and water -bool Trace_FlySwim(float fDeltaTime); +public bool Trace_FlySwim(float fDeltaTime) + { + return true; + } -// Stop move when touch target -void StopMove(bool bFinish); + // Stop move when touch target + public void StopMove(bool bFinish) + { + // If 'trace' work was transfered from a work which + // needs moving (such as 'move to' work) and we touch the target + // immediately (m_bHaveMoved = false), we must need to send 'stop move' + // command + if (m_bHaveMoved || !m_pHost.m_MoveCtrl.IsStop()) + m_pHost.m_MoveCtrl.SendStopMoveCmd(); + + m_pHost.m_vVelocity.Clear(); + //m_pHost.StopModelMove(); + + if (bFinish) + { + m_bFinished = true; + } + } // Handle the case that target died when host is tracing it bool OnTargetDied(CECObject* pTarget); // Is valid time to touch target ? @@ -239,7 +935,7 @@ bool GetTargetCurPos(A3DVECTOR3 &pos); A3DVECTOR3 GetCurMovingDest(); void UpdateUseAutoPF(); -void ReplaceTarget(CECTracedObject* ptraceobj); +void ReplaceTarget(CECTracedObject ptraceobj); void ResetUseAutoPF(bool bUseAutoPF); void UpdateResetUseAutoPF(); diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_ManPlayer.cs b/Assets/PerfectWorld/Scripts/Managers/EC_ManPlayer.cs index 825d93d228..0db2223156 100644 --- a/Assets/PerfectWorld/Scripts/Managers/EC_ManPlayer.cs +++ b/Assets/PerfectWorld/Scripts/Managers/EC_ManPlayer.cs @@ -23,6 +23,7 @@ namespace PerfectWorld.Scripts.Managers Dictionary m_UkPlayerTab = new Dictionary(); Dictionary m_PlayerTab = new Dictionary(); private readonly object m_csPlayerTab = new object(); + CECHostPlayer m_pHostPlayer; public int HandlerId => (int)MANAGER_INDEX.MAN_PLAYER; public bool ProcessMessage(ECMSG Msg) { @@ -468,6 +469,20 @@ namespace PerfectWorld.Scripts.Managers return true; } + // Get a player (may be host or else player) by id + public EC_Player GetPlayer(int cid, uint dwBornStamp = 0) + { + CECHostPlayer pHost = GetHostPlayer(); + if (pHost && pHost.GetCharacterID() == cid) + return pHost; + else + return GetElsePlayer(cid, dwBornStamp); + } + + public CECHostPlayer GetHostPlayer() + { + return GameController.Instance.GetHostPlayer(); + } } } } \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_Object.cs b/Assets/PerfectWorld/Scripts/Managers/EC_Object.cs index a9a950fc37..b58014c11a 100644 --- a/Assets/PerfectWorld/Scripts/Managers/EC_Object.cs +++ b/Assets/PerfectWorld/Scripts/Managers/EC_Object.cs @@ -186,8 +186,8 @@ public class CECObject : MonoBehaviour protected int m_iCID; // Class ID protected bool m_bAdjustOrient; // Is adjusting orientation - protected A3DQUATERNION m_quOrientStart; // Orientation start - protected A3DQUATERNION m_quOrientEnd; // Orientation end + //protected A3DQUATERNION m_quOrientStart; // Orientation start + //protected A3DQUATERNION m_quOrientEnd; // Orientation end protected float m_dwOrientTime; // Orientation adjusting time counter protected uint m_dwOrientTimeCnt; // Orientation adjusting time counter @@ -201,16 +201,31 @@ public class CECObject : MonoBehaviour protected bool m_bSelectable; // whether the object can be selected - public inline const A3DVECTOR3& GetGroundNormal()const { return m_vecGroundNormal; } - public inline bool GetUseGroundNormal()const { return m_bUseGroundNormal; } + public A3DVECTOR3 GetGroundNormal(){ return m_vecGroundNormal; } + public bool GetUseGroundNormal(){ return m_bUseGroundNormal; } public void SetUseGroundNormal(bool bFlag) { + //if (m_bUseGroundNormal == bFlag) + // return; + //m_bUseGroundNormal = bFlag; + //if (m_bUseGroundNormal) + //{ + // // now reset dir and up to make the object show correct pose + // SetDirAndUp(GetDir(), GetUp()); + //} + //else + //{ + // // now reset dir and up to make the player show correct pose + // A3DVECTOR3 vLeft = CrossProduct(GetDir(), g_vAxisY); + // A3DVECTOR3 vDir = Normalize(CrossProduct(g_vAxisY, vLeft)); + // SetDirAndUp(vDir, g_vAxisY); + //} } public void SetGroundNormal(A3DVECTOR3 vecNormal) { - + m_vecGroundNormalSet = vecNormal; } protected void AdjustOrientation(float dwDeltaTime) diff --git a/Assets/PerfectWorld/Scripts/NPC/CECNPC.cs b/Assets/PerfectWorld/Scripts/NPC/CECNPC.cs index 7566393375..9ccf79e1cc 100644 --- a/Assets/PerfectWorld/Scripts/NPC/CECNPC.cs +++ b/Assets/PerfectWorld/Scripts/NPC/CECNPC.cs @@ -43,6 +43,7 @@ public class CECNPC : CECObject protected static CECStringTab m_ActionNames; + public virtual void SetUpCECNPC(CECNPCMan pNPCMan) { base.SetUpCECObject(); @@ -866,6 +867,38 @@ public class CECNPC : CECObject public int vis_tid;// template id for shape }; public const float MAX_LAGDIST = 25.0f; + + // Get NPC's real position on server + public A3DVECTOR3 GetServerPos() + { + return EC_Utility.ToA3DVECTOR3(m_vServerPos); + } + + // Get master id + public int GetMasterID() { return m_idMaster; } + // Is monster in invader camp in battle ? + public virtual bool IsInBattleInvaderCamp() { return false; } + // Is monster in defender camp in battle ? + public virtual bool IsInBattleDefenderCamp() { return false; } + // Get role in battle + public virtual int GetRoleInBattle() { return 0; } + public int GetOwnerFaction(){ return m_idOwnerFaction; } + + public bool IsFactionPVPMineCar() + { + //if (const MONSTER_ESSENCE* pMonsterEssence = GetMonsterEssence()){ + // return (pMonsterEssence.faction & (1 << 19)) != 0; + //} + return false; + } + + public bool IsFactionPVPMineBase() + { + //if (const MONSTER_ESSENCE *pMonsterEssence = GetMonsterEssence()){ + // return (pMonsterEssence->faction & (1 << 20)) != 0; + //} + return false; + } } public enum WorkType { diff --git a/Assets/PerfectWorld/Scripts/Network/EC_ManMessageMono.cs b/Assets/PerfectWorld/Scripts/Network/EC_ManMessageMono.cs index d2f4925ad3..ac42fabb86 100644 --- a/Assets/PerfectWorld/Scripts/Network/EC_ManMessageMono.cs +++ b/Assets/PerfectWorld/Scripts/Network/EC_ManMessageMono.cs @@ -4,6 +4,7 @@ using CSNetwork; using PerfectWorld.Scripts.Managers.BrewMonster.Managers; using BrewMonster.Network; using UnityEngine.SceneManagement; +using CSNetwork.GPDataType; namespace BrewMonster { @@ -48,5 +49,35 @@ namespace BrewMonster { EC_ManMessage.Tick(); } + + // Get object by specified ID + // iAliveFlag: 0, both alive and dead; 1, must be alive; 2, must be dead + public CECObject GetObject(int idObject, int iAliveFlag) + { + CECObject pObject = null; + + if (GPDataTypeHelper.ISNPCID(idObject)) + { + if (!(pObject = _CECNPCMan.GetNPC(idObject))) + return null; + + if ((iAliveFlag == 1 && (pObject as CECNPC).IsDead()) || + (iAliveFlag == 2 && !(pObject as CECNPC).IsDead())) + return null; + } + else if (GPDataTypeHelper.ISPLAYERID(idObject)) + { + if (!(pObject = EC_ManPlayer.GetPlayer(idObject))) + return null; + + if ((iAliveFlag == 1 && (pObject as EC_Player).IsDead()) || + (iAliveFlag == 2 && !(pObject as EC_Player).IsDead())) + return null; + } + //else if (GPDataTypeHelper.ISMATTERID(idObject)) + // pObject = GetMatterMan()->GetMatter(idObject); + + return pObject; + } } } \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/Network/UnityGameSession.cs b/Assets/PerfectWorld/Scripts/Network/UnityGameSession.cs index 6763df0fb4..e91e6c1c1a 100644 --- a/Assets/PerfectWorld/Scripts/Network/UnityGameSession.cs +++ b/Assets/PerfectWorld/Scripts/Network/UnityGameSession.cs @@ -166,6 +166,16 @@ namespace BrewMonster.Network } } + public static void c2s_CmdNPCSevHello(int nid) + { + Instance._gameSession.c2s_SendCmdNPCSevHello(nid); + } + + public static void c2s_CmdNormalAttack(byte byPVPMask) + { + Instance._gameSession.c2s_CmdNormalAttack(byPVPMask); + } + #region Task public static void c2s_CmdGetAllData(bool byPack, bool byEquip, bool byTask) { diff --git a/Assets/PerfectWorld/Scripts/Players/EC_ElsePlayer.cs b/Assets/PerfectWorld/Scripts/Players/EC_ElsePlayer.cs index ce0212975c..58c64ecb0d 100644 --- a/Assets/PerfectWorld/Scripts/Players/EC_ElsePlayer.cs +++ b/Assets/PerfectWorld/Scripts/Players/EC_ElsePlayer.cs @@ -30,9 +30,9 @@ namespace PerfectWorld.Scripts.Player int m_iGender; // Gender float m_fScaleBySkill = 1f; MOVECONST m_MoveConst; // Const used when moving control - int m_iMoveEnv; // Move environment - bool m_bWalkRun; // Walk-run switch, 0-walk, 1-run - int m_iMoveMode; // Player's move mode + //int m_iMoveEnv; // Move environment + //bool m_bWalkRun; // Walk-run switch, 0-walk, 1-run + //int m_iMoveMode; // Player's move mode public MOVECONST[] aMoveConsts = new MOVECONST[PROFESSION.NUM_PROFESSION * GENDER.NUM_GENDER] { @@ -454,70 +454,8 @@ namespace PerfectWorld.Scripts.Player return result; } - private int GetMoveStandAction(bool bMove, bool bFight = false) - { - int iMoveEnv = m_iMoveEnv; - //if (m_AttachMode != enumAttachNone) - //{ - // bFight = false; - // if (m_bHangerOn) - // iMoveEnv = MOVEENV_GROUND; - //} - - int iAction = (int)PLAYER_ACTION_TYPE.ACT_STAND; - - if (bMove) - { - // Play appropriate actions - if (iMoveEnv == (int)MoveEnvironment.MOVEENV_GROUND) - { - if (m_bWalkRun) - iAction = (int)PLAYER_ACTION_TYPE.ACT_RUN; - else - iAction = (int)PLAYER_ACTION_TYPE.ACT_WALK; - } - //else if (iMoveEnv == MOVEENV_AIR) - //{ - // //if (/*UsingWing()*/ m_wingType == WINGTYPE_WING) - // // iAction = ACT_FLY; - // //else - // // iAction = ACT_FLY_SWORD; - //} - //else if (iMoveEnv == MOVEENV_WATER) - //{ - // //if (CanCombineWithMoveForSkill()) - // //{ - // // iAction = ACT_SWIM_FOR_MOVESKILL; - // //} - // //else - // //{ - // // iAction = ACT_SWIM; - // //} - //} - } - else - { - // Play appropriate actions - if (iMoveEnv == (int)MoveEnvironment.MOVEENV_GROUND) - { - if (bFight) - iAction = (int)PLAYER_ACTION_TYPE.ACT_FIGHTSTAND; - else - iAction = (int)PLAYER_ACTION_TYPE.ACT_STAND; - } - //else if (iMoveEnv == MOVEENV_AIR) - //{ - // if (/*UsingWing()*/ m_wingType == WINGTYPE_WING) - // iAction = ACT_HANGINAIR; - // else - // iAction = ACT_HANGINAIR_SWORD; - //} - //else if (iMoveEnv == MOVEENV_WATER) - // iAction = ACT_HANGINWATER; - } - - return iAction; - } + // Get player's real position on server + public A3DVECTOR3 GetServerPos() { return m_vServerPos; } //public A3DVECTOR3 GetPos() //{ diff --git a/Assets/Scripts/CECHostPlayer.cs b/Assets/Scripts/CECHostPlayer.cs index c31584807e..ababbb8d9a 100644 --- a/Assets/Scripts/CECHostPlayer.cs +++ b/Assets/Scripts/CECHostPlayer.cs @@ -1,4 +1,5 @@ -锘縰sing BrewMonster.Network; +锘縰sing BrewMonster; +using BrewMonster.Network; using CSNetwork; using CSNetwork.GPDataType; using CSNetwork.Protocols; @@ -30,10 +31,17 @@ public class CECHostPlayer : EC_Player PlayerStateMachine _playerStateMachine; PlayerMoveState _moveState; PlayerIdleState _idleState; - CECHostMove m_MoveCtrl; + public CECHostMove m_MoveCtrl; CECHPWorkMan m_pWorkMan; // Host work manager uint m_dwLIES; // Logic-influence extend states + FACTION_FORTRESS_ENTER m_fortressEnter; // 陆酶脠毛禄霉碌脴脨脜脧垄 + PVPINFO m_pvp; // pvp information + bool m_bInSanctuary = false; // true, player is in sanctuary + int m_idFaction = 0; // ID of player's faction + public bool m_bPrepareFight = false; // true, prepare to fight + int m_iJumpCount = 0; + bool m_bJumpInWater = false; float playerSpeed = 5.0f; float jumpHeight = 1.5f; @@ -43,6 +51,9 @@ public class CECHostPlayer : EC_Player bool isGrounded = false; bool isRun = false; Vector3 m_vLastSevPos; + public CDR_INFO m_CDRInfo; + public GNDINFO m_GndInfo; + public float m_fVertSpeed = 0f; // ====== Ground cast config ====== [Header("Ground Cast")] @@ -330,7 +341,7 @@ public class CECHostPlayer : EC_Player } - private void SetPos(Vector3 pos) + public void SetPos(Vector3 pos) { transform.position = pos; } @@ -532,7 +543,7 @@ public class CECHostPlayer : EC_Player if (idTarget == 0 || idTarget == m_PlayerInfo.cid) return -1; - CECObject pObject = g_pGame.GetGameRun().GetWorld().GetObject(idTarget, 1); + CECObject pObject = EC_ManMessageMono.Instance.GetObject(idTarget, 1); if (!pObject) return -1; @@ -541,18 +552,18 @@ public class CECHostPlayer : EC_Player { CECNPC pNPC = (CECNPC)pObject; int idMaster = pNPC.GetMasterID(); - if (idMaster) + 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; + //// Follow pet cannot be attacked + //if (pNPC.IsPetNPC() && ((CECPet)pNPC).IsFollowPet()) + // return 0; idTarget = idMaster; - pObject = g_pGame.GetGameRun().GetWorld().GetObject(idTarget, 1); + pObject = EC_ManMessageMono.Instance.GetObject(idTarget, 1); if (!pObject) return -1; } @@ -565,12 +576,12 @@ public class CECHostPlayer : EC_Player CECNPC pNPC = (CECNPC)pObject; // If this npc is host's pet, cannot be attacked - if (pNPC.GetMasterID() == m_PlayerInfo.cid) - return 0; + //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 (pNPC.IsPetNPC() && !((CECPet)pNPC).CanBeAttacked()) + // return 0; if (IsInBattle()) // Host is in battle { @@ -613,9 +624,9 @@ public class CECHostPlayer : EC_Player //else if (GPDataTypeHelper.ISPLAYERID(idTarget)) //{ // // Check duel at first - // if (m_pvp.iDuelState == DUEL_ST_INDUEL && m_pvp.idDuelOpp == idTarget) + // if (m_pvp.iDuelState == Duel_state.DUEL_ST_INDUEL && m_pvp.idDuelOpp == idTarget) // return 1; - // else if (m_pvp.iDuelState == DUEL_ST_STOPPING && m_pvp.idDuelOpp == idTarget) + // else if (m_pvp.iDuelState == Duel_state.DUEL_ST_STOPPING && m_pvp.idDuelOpp == idTarget) // return 0; // // In sanctuary we cannot attack other players @@ -691,6 +702,8 @@ public class CECHostPlayer : EC_Player 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) @@ -758,11 +771,63 @@ public class CECHostPlayer : EC_Player A3DVECTOR3 vector = new A3DVECTOR3(gameObject.transform.position.x, gameObject.transform.position.y, gameObject.transform.position.z); return CanTouchTarget(vector, vTargetPos, fTargetRad, iReason, fMaxCut); } - bool IsRooting() { + 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 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; + //} } public enum StateAnim @@ -785,3 +850,41 @@ public enum Logic_Influence_Extned_states 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) + { + 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 +}; \ No newline at end of file diff --git a/Assets/Scripts/EC_Utility.cs b/Assets/Scripts/EC_Utility.cs index f238ff39ab..d1ef9f4cfb 100644 --- a/Assets/Scripts/EC_Utility.cs +++ b/Assets/Scripts/EC_Utility.cs @@ -86,4 +86,45 @@ public static class EC_Utility return $"{prefix}_{suffix}"; } + + // Build pvp mask + public static byte glb_BuildPVPMask(bool bForceAttack) + { + byte byMask = 0; + if (bForceAttack) + byMask |= (byte)PVP_mask.GP_PVPMASK_FORCE; + //else + //{ + // CECConfigs* pConfigs = g_pGame->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 static T a_ClampFloor(T x, T min) where T : IComparable + { + return (x.CompareTo(min) < 0) ? min : x; + } + + public static T a_Min(T x, T y) where T : IComparable + { + return (y.CompareTo(x) < 0) ? y : x; + } } diff --git a/Assets/Scripts/Move/CECHostMove.cs b/Assets/Scripts/Move/CECHostMove.cs index 68b8bf4c77..866f0a90fb 100644 --- a/Assets/Scripts/Move/CECHostMove.cs +++ b/Assets/Scripts/Move/CECHostMove.cs @@ -1,13 +1,14 @@ 锘縰sing BrewMonster.Network; +using CSNetwork; using CSNetwork.C2SCommand; using CSNetwork.GPDataType; +using CSNetwork.Protocols; using System; using System.Collections.Generic; using System.Runtime.ConstrainedExecution; +using System.Security.Cryptography; using System.Text; using UnityEngine; -using CSNetwork.Protocols; -using CSNetwork; public class CECHostMove { @@ -23,7 +24,12 @@ public class CECHostMove 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) { @@ -41,8 +47,8 @@ public class CECHostMove { var m = m_DelayedStop; - // a_GetTime() -> Environment.TickCount (ms) - ulong dwCurrent = (ulong)Mathf.RoundToInt( Time.time * 1000); + // a_GetTime() . Environment.TickCount (ms) + ulong dwCurrent = (ulong)Mathf.RoundToInt(Time.time * 1000); // iTime: th峄漣 gian t铆ch l农y (ms) + delta t峄 timestamp 膽岷縩 hi峄噉 t岷 int iTime = (int)((m.fTime * 1000f) @@ -56,9 +62,9 @@ public class CECHostMove // 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 - ); + UnityGameSession.Instance.c2s_SendCmdStopMove( + m.vPos, fSpeed, iMoveMode, m.byDir, m_wMoveStamp++, iTime + ); // Record this position m_vLastSevPos = m.vPos; @@ -72,6 +78,33 @@ public class CECHostMove 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 EC_Player.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"); @@ -86,7 +119,7 @@ public class CECHostMove UnityGameSession.Instance.c2s_SendCmdStopMove(vPos, fSpeed, iMoveMode, byDir, m_wMoveStamp++, iTime); - m_vLastSevPos = vPos; + m_vLastSevPos = vPos; Reset(); } else @@ -114,14 +147,31 @@ public class CECHostMove 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) + float fSpeed, int iMoveMode, bool bForceSend) { if (m_bStop) { // m_CmdTimeCnt.Reset(); - cmdmovedelayCounter = (ulong)( m_fMoveTime * 1000); + cmdmovedelayCounter = (ulong)(m_fMoveTime * 1000); m_bStop = false; } if (!bForceSend && cmdmovedelayCounter < 500) @@ -150,7 +200,7 @@ public class CECHostMove m_vLastSevPos = vCurPos; } - + float l_CalcAverageSpeed(in Vector3 p1, in Vector3 p2, float fTime, float fDefSpeed) { if (Mathf.Approximately(fTime, 0f)) @@ -182,14 +232,105 @@ public class CECHostMove 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; + 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; + + return vNewPos; + } + + public int MoveBlocked() { return m_iBlockedCnt; } + public void SetSlideLock(bool bLock) { m_bSlideLock = bLock; } } public struct CDR_INFO { diff --git a/Assets/Scripts/Move/EC_Player.cs b/Assets/Scripts/Move/EC_Player.cs index b1c5ad744e..70b5284900 100644 --- a/Assets/Scripts/Move/EC_Player.cs +++ b/Assets/Scripts/Move/EC_Player.cs @@ -1,11 +1,12 @@ 锘縰sing BrewMonster; using CSNetwork.GPDataType; using ModelRenderer.Scripts.GameData; +using PerfectWorld.Scripts.Player; using System; using System.Collections.Generic; using UnityEngine; -public abstract class EC_Player : MonoBehaviour +public abstract class EC_Player : CECObject { private static PLAYER_ACTION[] _default_actions; private static PLAYER_ACTION[] _turning_actions; @@ -18,7 +19,12 @@ public abstract class EC_Player : MonoBehaviour uint m_dwStates; // Player's basic states protected ROLEEXTPROP m_ExtProps; // Extend properties protected float m_fTouchRad = 0.3f; // Touch radius - + protected int m_iBattleCamp = Player_camp_in_battle.GP_BATTLE_CAMP_NONE; // Battle this player belongs to + byte m_factionPVPMask; // pvp mask + protected ROLEBASICPROP m_BasicProps; + public int m_iMoveEnv = Move_environment.MOVEENV_GROUND; // Move environment + public bool m_bWalkRun; + public A3DAABB m_aabbServer; // 脫毛路镁脦帽脝梅卤拢鲁脰脪禄脰脗碌脛aabb拢卢 虏禄脢脺脣玫路脜脫掳脧矛 protected void Awake() { m_PlayerActions = _default_actions; @@ -280,6 +286,99 @@ public abstract class EC_Player : MonoBehaviour } public float GetTouchRadius(){ return m_fTouchRad; } + // Is player in battle + public bool IsInBattle() { return m_iBattleCamp != Player_camp_in_battle.GP_BATTLE_CAMP_NONE; } + + // Check whether specified npc in a same battle camp + public bool InSameBattleCamp(CECNPC pNPC) + { + if (!pNPC || m_iBattleCamp == Player_camp_in_battle.GP_BATTLE_CAMP_NONE || + (m_iBattleCamp == Player_camp_in_battle.GP_BATTLE_CAMP_INVADER && !pNPC.IsInBattleInvaderCamp()) || + (m_iBattleCamp == Player_camp_in_battle.GP_BATTLE_CAMP_DEFENDER && !pNPC.IsInBattleDefenderCamp())) + return false; + + return true; + } + public bool IsInFactionPVP() => (m_factionPVPMask & 0x01) != 0; + public bool CanAttackFactionPVPMineCar() => (m_factionPVPMask & 0x02) != 0; + public bool CanAttackFactionPVPMineBase() => (m_factionPVPMask & 0x04) != 0; + + // Get basic properties + public ROLEBASICPROP GetBasicProps() { return m_BasicProps; } + + public int GetMoveStandAction(bool bMove, bool bFight = false) + { + int iMoveEnv = m_iMoveEnv; + //if (m_AttachMode != enumAttachNone) + //{ + // bFight = false; + // if (m_bHangerOn) + // iMoveEnv = MOVEENV_GROUND; + //} + + int iAction = (int)PLAYER_ACTION_TYPE.ACT_STAND; + + if (bMove) + { + // Play appropriate actions + if (iMoveEnv == (int)MoveEnvironment.MOVEENV_GROUND) + { + if (m_bWalkRun) + iAction = (int)PLAYER_ACTION_TYPE.ACT_RUN; + else + iAction = (int)PLAYER_ACTION_TYPE.ACT_WALK; + } + //else if (iMoveEnv == MOVEENV_AIR) + //{ + // //if (/*UsingWing()*/ m_wingType == WINGTYPE_WING) + // // iAction = ACT_FLY; + // //else + // // iAction = ACT_FLY_SWORD; + //} + //else if (iMoveEnv == MOVEENV_WATER) + //{ + // //if (CanCombineWithMoveForSkill()) + // //{ + // // iAction = ACT_SWIM_FOR_MOVESKILL; + // //} + // //else + // //{ + // // iAction = ACT_SWIM; + // //} + //} + } + else + { + // Play appropriate actions + if (iMoveEnv == (int)MoveEnvironment.MOVEENV_GROUND) + { + if (bFight) + iAction = (int)PLAYER_ACTION_TYPE.ACT_FIGHTSTAND; + else + iAction = (int)PLAYER_ACTION_TYPE.ACT_STAND; + } + //else if (iMoveEnv == MOVEENV_AIR) + //{ + // if (/*UsingWing()*/ m_wingType == WINGTYPE_WING) + // iAction = ACT_HANGINAIR; + // else + // iAction = ACT_HANGINAIR_SWORD; + //} + //else if (iMoveEnv == MOVEENV_WATER) + // iAction = ACT_HANGINWATER; + } + + return iAction; + } + + public float GetGroundSpeed() + { + // return m_bWalkRun ? g_pGame->GetConfigs()->GetHostRunSpeed() : m_ExtProps.mv.walk_speed; + return m_bWalkRun ? m_ExtProps.mv.run_speed : m_ExtProps.mv.walk_speed; + } + + // Get move environment + public int GetMoveEnv(){ return m_iMoveEnv; } } public struct PlayActionEvent { @@ -301,4 +400,22 @@ public struct INFO this.crc_c = crc_c; this.crc_e = crc_; } -}; \ No newline at end of file +} + +public static class Duel_state // Duel state +{ + public const int DUEL_ST_NONE = 0, + DUEL_ST_PREPARE = 1, + DUEL_ST_INDUEL = 2, + DUEL_ST_STOPPING = 3; +} + +//// Move mode +//public static class Move_Mode +//{ +// public const int MOVE_STAND = 0, +// MOVE_MOVE = 1, // Normal move, walk, run, swim or fly +// MOVE_JUMP = 2, +// MOVE_FREEFALL = 3, +// MOVE_SLIDE = 4; +//} \ No newline at end of file diff --git a/Assets/Scripts/PlayerStateMachine.cs b/Assets/Scripts/PlayerStateMachine.cs index 787af10b2d..da9131e4e7 100644 --- a/Assets/Scripts/PlayerStateMachine.cs +++ b/Assets/Scripts/PlayerStateMachine.cs @@ -5,6 +5,8 @@ public class PlayerStateMachine PlayerState _state; CECHostPlayer _characterCtrl; + public PlayerState State { get => _state; } + public void InitState(PlayerState state) { if (_state != null)