Files
test/Assets/PerfectWorld/Scripts/Move/CECHostMove.cs

531 lines
18 KiB
C#

using BrewMonster.Network;
using BrewMonster.Scripts;
using CSNetwork.GPDataType;
using System;
using UnityEngine;
using BrewMonster.Scripts.World;
namespace BrewMonster
{
public class CECHostMove
{
ushort m_wMoveStamp;
float m_fMoveTime;
CECHostPlayer m_pHost;
bool m_bStop;
const float MOVECMD_INTERVAL = .5f;
A3DVECTOR3 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 A3DVECTOR3 m_vFlashTPNormal;
// Negative accelerate in water and air
public const float EC_NACCE_AIR = -5.0f;
public const float EC_NACCE_WATER = -5.0f;
// Push accelerate
public const float EC_PUSH_ACCE = 8.0f; // Normal push accelerate in air and water
public const float EC_FLYOFF_ACCE = 10.0f; // Fly off accelerate
public const float EC_SLOPE_Y = 0.5f;
public const float EC_GRAVITY = 9.8f;
// Move length minimum threshold
public const float MIN_MOVELEN_IN_AIR_WATER = 0.5f;
public const float MIN_MOVELEN_ON_GROUND = 0.5f;
public const float MIN_MOVELEN_FOR_DETECT_VIBRATION = 0.05f;
public CECHostMove(CECHostPlayer pHost)
{
m_wMoveStamp = 0;
m_fMoveTime = 0.0f;
m_pHost = pHost;
m_bStop = false;
cmdstopdelayCounter = 500;
m_DelayedStop = new STOPMOVE();
}
public void Tick(ulong dwDeltaTime)
{
cmdstopdelayCounter += dwDeltaTime;
cmdmovedelayCounter += dwDeltaTime;
if (cmdstopdelayCounter >= 500 && m_DelayedStop.bValid)
{
var m = m_DelayedStop;
// a_GetTime() . Environment.TickCount (ms)
ulong dwCurrent = (ulong)Mathf.RoundToInt(Time.time * 1000);
// 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));
// tính tốc độ trung bình (giây = iTime * 0.001f)
float fSpeed = l_CalcAverageSpeed(EC_Utility.ToVector3(m_vLastSevPos), m.vPos, iTime * 0.001f, m.fSpeed);
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 = EC_Utility.ToA3DVECTOR3(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 SetHostLastPos(A3DVECTOR3 vPos) { m_vLastPos = EC_Utility.ToVector3(vPos); }
public void SendStopMoveCmd(in Vector3 vPos, float fSpeed, int iMoveMode)
{
UnityEngine.Debug.LogWarning("HoangDev : SendStopMoveCmd");
iMoveMode |= (int)GPMoveMode.GP_MOVE_DEAD;
if (cmdstopdelayCounter >= 500)
{
Vector3 vDir = m_pHost.transform.forward;
byte byDir = EC_Utility.glb_CompressDirH(vDir.x, vDir.z);
fSpeed = l_CalcAverageSpeed(EC_Utility.ToVector3(m_vLastSevPos), vPos, m_fMoveTime, fSpeed);
int iTime = (int)(m_fMoveTime * 1000);
UnityGameSession.Instance.c2s_SendCmdStopMove(vPos, fSpeed, iMoveMode, byDir, m_wMoveStamp++, iTime);
m_vLastSevPos = EC_Utility.ToA3DVECTOR3(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);
}
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)
{
// m_CmdTimeCnt.Reset();
cmdmovedelayCounter = (ulong)(m_fMoveTime * 1000);
m_bStop = false;
}
if (!bForceSend && cmdmovedelayCounter < 500)
return;
int iTime = (int)(m_fMoveTime * 1000);
if (iTime < 200)
{
if (iTime == 0 || !bForceSend)
{
// if time is too little, wait again
cmdmovedelayCounter = (ulong)(iTime);
return;
}
}
cmdmovedelayCounter = 0;
m_DelayedStop.bValid = false;
fSpeed = l_CalcAverageSpeed(EC_Utility.ToVector3(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 = EC_Utility.ToA3DVECTOR3(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
UnityEngine.Debug.LogWarning("CalcAverageSpeed: invalid input, fallback to default speed.");
return fDefSpeed;
}
return fSpeed;
}
public 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;
}
public void SetLastSevPos(A3DVECTOR3 vPos) { m_vLastSevPos = vPos; }
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 = EC_Game.GetGameRun().GetWorld().GetInstanceID();
CECInstance pInstance = EC_Game.GetGameRun().GetInstance(idInst);
if (pInstance.GetLimitJump())
fGravity *= 4.0f;
Vector3 posStart = EC_Utility.ToVector3(m_pHost.m_aabbServer.Center);
CDR_INFO cdr = m_pHost.m_CDRInfo;
cdr.vCenter = m_pHost.m_aabbServer.Center;
cdr.vXOZVelDir = vRealDirH;
cdr.fSpeed = fSpeedH;
cdr.t = fTime;
cdr.fGravityAccel = fGravity;
cdr.fYVel += fSpeedV;
EC_CDR.OnGroundMove(ref cdr);
m_pHost.m_CDRInfo = cdr;
//if (g_pGame.GetGameRun().GetWorld().GetAssureMove())
// g_pGame.GetGameRun().GetWorld().GetAssureMove().AssureMove(m_pHost.m_aabbServer.Center, cdr.vCenter);
if (cdr.vTPNormal != new A3DVECTOR3(0))
m_pHost.SetGroundNormal(cdr.vTPNormal);
else
m_pHost.SetGroundNormal(GPDataTypeHelper.g_vAxisY);
A3DVECTOR3 vNewPos = cdr.vCenter - 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();
m_fBlockTime += fTime;
//TO DO: in c++ set 1.0f. Convert to c#, this logic is wrong. If set time is 2.0, game run correct
if ((m_fBlockTime) >= 2.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;
//Debug.LogError("speed = " + (Vector3.Distance(posStart, EC_Utility.ToVector3(vNewPos)) / fTime));
return vNewPos;
}
public int MoveBlocked() { return m_iBlockedCnt; }
public void SetSlideLock(bool bLock) { m_bSlideLock = bLock; }
// Is stoping ?
public bool IsStop() { return m_bStop; }
// Flash move
public A3DVECTOR3 FlashMove(A3DVECTOR3 vDir, float fSpeed, float fDist)
{
// Copy cdr data from host
CDR_INFO cdr = m_pHost.m_CDRInfo;
A3DVECTOR3 vStartPos = m_vLastSevPos + EC_Utility.ToA3DVECTOR3(Vector3.up) * cdr.vExtent.y;
if (fDist == 0f || fSpeed == 0f)
return m_vLastSevPos;
// Get horizonal directional
A3DVECTOR3 vRealDirH = vDir;
if (vRealDirH.y != 0f)
{
vRealDirH.y = 0.0f;
vRealDirH.Normalize();
}
const int iNumSeg = 6;
float[] aFactors = { 0.3f, 0.3f, 0.15f, 0.1f, 0.1f, 0.5f };
float fTotalTime = fDist / fSpeed;
A3DVECTOR3 vCurPos = vStartPos;
A3DVECTOR3 vCurTPNormal = cdr.vTPNormal;
cdr.vCenter = vStartPos;
cdr.fYVel = 0.0f;
for (int i = 0; i < iNumSeg; i++)
{
cdr.vXOZVelDir = vRealDirH;
cdr.fSpeed = fSpeed;
cdr.t = fTotalTime * aFactors[i];
cdr.fGravityAccel = 9.8f; // EC_GRAVITY
EC_CDR.OnGroundMove(ref cdr);
//BMLogger.LogError($"HoangDev: FlashMove seg={i} stepTime={cdr.t} center=({cdr.vCenter})");
var world = CECGameRun.Instance?.GetWorld();
if (world?.GetAssureMove() != null)
world.GetAssureMove().NoAssureMove();
if ((cdr.vCenter - vStartPos).Magnitude() >= fDist * 0.98f)
{
// Use the result of last time
cdr.vCenter = vCurPos;
cdr.vTPNormal = vCurTPNormal;
break;
}
if ((cdr.vCenter - vCurPos).Magnitude() < 0.3f)
break;
// Record result of this time
vCurPos = cdr.vCenter;
vCurTPNormal = cdr.vTPNormal;
}
// Calculate new position
vCurPos = cdr.vCenter - GPDataTypeHelper.g_vAxisY * cdr.vExtent.y;
m_vFlashTPNormal = cdr.vTPNormal;
A3DVECTOR3 vCurrentPlayerPos = m_pHost.GetPos();
return vCurPos;
}
// Get host's last position sent to server
public Vector3 GetLastSevPos() { return EC_Utility.ToVector3(m_vLastSevPos); }
public bool GetSlideLock() { return m_bSlideLock; }
// Air/Water move
public A3DVECTOR3 AirWaterMove(A3DVECTOR3 vSpeed, float fTime, bool bInAir, bool bTrace = false)
{
A3DVECTOR3 vDir = vSpeed;
float fSpeed = vDir.Normalize();
return AirWaterMove(vDir, fSpeed, fTime, bInAir, bTrace);
}
// Air/Water move
public A3DVECTOR3 AirWaterMove(A3DVECTOR3 vDir, float fSpeed, float fTime, bool bInAir, bool bTrace/* false */)
{
A3DVECTOR3 vRealDir = vDir;
// OnAirMove only accept positive speed value
if (fSpeed < 0.0f)
{
vRealDir = -vDir;
fSpeed = -fSpeed;
}
float fMaxSpeed = bInAir ? m_pHost.GetFlySpeed() : m_pHost.GetSwimSpeedSev();
if (fSpeed > fMaxSpeed)
fSpeed = fMaxSpeed;
ON_AIR_CDR_INFO cdr = m_pHost.m_AirCDRInfo;
cdr.vCenter = m_pHost.m_aabbServer.Center;
cdr.vVelDir = vRealDir;
cdr.fSpeed = fSpeed;
cdr.fHeightThresh = bInAir ? m_pHost.m_MoveConst.fMinAirHei : m_pHost.m_MoveConst.fMinWaterHei;
cdr.t = fTime;
cdr.bOnAir = bInAir;
// If player is tracing something, let he fly/swim low enough
// if (bTrace)
// cdr.fHeightThresh = 0.2f;
EC_CDR.OnAirMove(ref cdr);
m_pHost.m_AirCDRInfo = cdr;
// TO DO: fix later
//if(EC_Game.GetGameRun().GetWorld().GetAssureMove() )
// EC_Game.GetGameRun().GetWorld().GetAssureMove().NoAssureMove();
m_pHost.SetGroundNormal(GPDataTypeHelper.g_vAxisY);
A3DVECTOR3 vNewPos = cdr.vCenter - 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 < MIN_MOVELEN_IN_AIR_WATER || m_vBlockMove.Magnitude() < MIN_MOVELEN_FOR_DETECT_VIBRATION)
{
m_iBlockedCnt = 5;
}
m_fBlockTime = 0.0f;
m_fBlockMove = 0.0f;
m_vBlockMove.Clear();
}
m_fMoveTime += fTime;
return vNewPos;
}
// Set / Get move stamp
public void SetMoveStamp(ushort wStamp) { m_wMoveStamp = wStamp; }
}
public struct CDR_INFO
{
//the aabb
public A3DVECTOR3 vCenter;
//@note : the caller should make sure ext(.x, .y, .z) > 0. By Kuiwu[22/9/2005]
public A3DVECTOR3 vExtent;
public float fStepHeight;
// Velocity Info
public A3DVECTOR3 vXOZVelDir;
public float fYVel;
public float fSpeed;
// time span ( sec )
public float t;
// Gravity acceleration
public float fGravityAccel;
// the Climb Slope Thresh
public float fSlopeThresh;
// Tangent plane Info
public A3DVECTOR3 vTPNormal;
// Absolute Velocity: output for forcast!
public A3DVECTOR3 vAbsVelocity;
//the moving dist
public float fMoveDist;
};
}