Files
2026-06-01 12:46:52 +02:00

505 lines
17 KiB
C++

#include "stdafx.h"
#include "stdafx.h"
#include "SKMoveControler.h"
#include "SGameAvatarEx.h"
#include "KPrimitiveMesh.h"
#include "SGameCamera.h"
#include "SGameSystem.h"
#include "SCommandSystem.h"
#include "SGameMessage.h"
#include "KViewport.h"
#include "SGame.h"
#include "TerrainMapEngine.h"
#include "SGameWorld.h"
#include "ErrorCode/ErrorCode.h"
#include "SGameOption.h"
#include "KUIControlEdit.h"
#include "SGameSystem.h"
#include "Arena\\ArenaSystem.h"
#include "SGameWorldKeymapping.h"
#include "SUIDisplayInfo.h"
#include "SGameLocalPlayer.h"
extern SGameSystem* g_pCurrentGameSystem;
extern bool g_bActiveRender;
//#define UPDATE_TIME_RATE 0.8f // ONE_STEP_KMOVE_LENGTH를 이동했을 때, 걸리는 시간의 비율, 주기적으로 보내는 시간
//#define LAST_MOVE_LEN_RATE 0.3f // 마지막 이동 패킷을 보낼 때, 이동 거리
float st_move_length= 48.0f; // 한번 클릭으로 갈 수 있는 최소 거리, 적당한 거리를 임의로 정했다.
float st_stop_rate = 0.3f;
float st_update_rate= 0.8f;
int st_interval = 30;
SKMoveControler::SKMoveControler()
{
m_commandSystem = NULL;
m_gameSystem = NULL;
m_gameCamera = NULL;
m_arObject = NULL;
m_arTime = 0;
m_automove = FALSE;
m_servermove = 0;
}
SKMoveControler::~SKMoveControler()
{
}
void SKMoveControler::initialize(SCommandSystem* commandSystem, SGameSystem* gameSystem, SGameCamera* gameCamera, SGameWorld* gameWorld, ArcadiaClient* arObject)
{
m_commandSystem = commandSystem;
m_gameSystem = gameSystem;
m_gameCamera = gameCamera;
m_gameWorld = gameWorld;
m_arObject = arObject;
}
// 이동 또는 정지
//if ( cur_state == SObjectState::STATE_SKILL_END)
//{ player->m_pStateVM->StopCurrentState();
//}
//if (cur_state==SObjectState::STATE_SHOOTING)
//{ stop_move(player,false);
// player->ReqCancelAction();
// player->m_pStateVM->StopCurrentState();
// return;
// }
K3DVector SKMoveControler::get_local_pos()
{
K3DVector pos = m_sent_pos;
SGameAvatarEx* player = m_gameSystem->GetLocalPlayer(); if (!player) return pos;
pos = player->getMyPos();
pos.x = floor(pos.x+0.5f);
pos.y = floor(pos.y+0.5f);
return pos;
}
void SKMoveControler::process(int gameRef)
{
if (SGame::STAGE_ING != gameRef) return ;
SGameAvatarEx* player = m_gameSystem->GetLocalPlayer(); if (!player) return;
SGameLocalPlayer* localPlayer = dynamicCast<SGameLocalPlayer*>(g_pCurrentGameSystem->GetLocalPlayer());
if (localPlayer)
{ ArPosition _target;
_target.x = 0;
_target.y = 0;
_target.z = 0;
localPlayer->ReqGameObjectMove( 0, _target, &_target, 1, true );
if (_target.x) return;
}
// 1.키보드 방향키를 구한다.
int base_key_status = MOVE_NONE;
// AziaMafia clavier move
if (GetAsyncKeyState(GetGameKeymapping().GetKeymapping( HOTKEYCODE::HMOVE_UP ).wParam) & 0x8000) base_key_status |= MOVE_UP;
if (GetAsyncKeyState(GetGameKeymapping().GetKeymapping( HOTKEYCODE::HMOVE_DOWN ).wParam) & 0x8000) base_key_status |= MOVE_DOWN;
if (GetAsyncKeyState(GetGameKeymapping().GetKeymapping( HOTKEYCODE::HMOVE_LEFT ).wParam) & 0x8000) base_key_status |= MOVE_LEFT;
if (GetAsyncKeyState(GetGameKeymapping().GetKeymapping( HOTKEYCODE::HMOVE_RIGHT).wParam) & 0x8000) base_key_status |= MOVE_RIGHT;
int curr_key_status = base_key_status;
// 자동이동중일경우 화면방향(UP)키 세팅
int key_by_automove = FALSE;
if (m_automove && curr_key_status==0)
{ curr_key_status = MOVE_UP;
key_by_automove = TRUE;
}
// 이동불가 상태 체크
static const int lock_state = SGameAvatarEx::FLAG_STATE::FLAG_STATE_PETRIFY | SGameAvatarEx::FLAG_STATE::FLAG_STATE_FEAR | SGameAvatarEx::FLAG_STATE::FLAG_STATE_SLEEP | SGameAvatarEx::FLAG_STATE::FLAG_STATE_STUN | SGameAvatarEx::FLAG_STATE::FLAG_STATE_FROZEN | SGameAvatarEx::FLAG_STATE::FLAG_STATE_HOLD;
SObjectState::ID cur_state = player->m_pStateVM->GetCurrentState();
int cur_ani = player->GetCurrAnimationID();
if (g_pCurrentGameSystem == NULL ) return;
if (m_gameWorld->GetGameManager()->IsShowLoadingWnd() ) return;
if (key_by_automove==FALSE && g_bActiveRender==FALSE) return;
if (m_servermove)
{
int moving = player->IsMoving();
if (moving==FALSE)
{ m_servermove = FALSE;
} else
{ return;
}
}
int cur_tick = timeGetTime();
if (KUIControlEdit::IsFocusEdit() ) curr_key_status = MOVE_NONE; else
if ( m_gameWorld->GetGameManager()->IsShow(SIMSG_TOGGLE_UIWINDOW::UIWINDOW_STORE_HOST) ) curr_key_status = MOVE_NONE; else // 노점이 열려있는가??
if (GetGameOption().GetOptData().nEnterChat == false ) curr_key_status = MOVE_NONE; else
if (m_gameWorld->GetGameManager()->GetWndManager()->IsOpenModalWnd() == true ) curr_key_status = MOVE_NONE; else
if (player->GetStateFlag() & lock_state ) curr_key_status = MOVE_NONE; else
if (player->IsDead()) curr_key_status = MOVE_NONE; else
if (cur_state == SObjectState::STATE_FIRE || cur_state == SObjectState::STATE_ATTACK) curr_key_status = MOVE_NONE; else
if (cur_state == SObjectState::STATE_CAST || cur_state == SObjectState::STATE_AIMING) curr_key_status = MOVE_NONE; else
if (cur_state == SObjectState::STATE_SHOOTING && cur_ani != ANI_BOW_ATTACK01_C ) curr_key_status = MOVE_NONE; else
if ( last_skill_request_time> cur_tick-delay_after_skill_request && last_skill_request_time<cur_tick) curr_key_status = MOVE_NONE;
//if (cur_state == SObjectState::STATE_CHASE ) curr_key_status = MOVE_NONE;
if (curr_key_status == MOVE_NONE)
{
if (player->isKMoving())
{ //_oprint( "stop: 3 [%5.0f-%5.0f] [%5.0f-%5.0f] %f-%f \n", m_sent_pos.x,player->getMyPos().x,m_sent_pos.y,player->getMyPos().y,m_sent_move_dir);// sent_pos, sent_dir,curr_pos,curr_dir
stop_move( TRUE);
} else
{ stop_move( FALSE );
}
if (base_key_status == MOVE_NONE)
{ player->setKMoveType( MOVE_NONE );
}
return;
}
// 방향 키가 눌린경우, 자동이동 취소.
if (key_by_automove==0)
{ m_automove = FALSE;
/*
if (cur_state == SObjectState::STATE_CHASE)
{ K3DVector curr_pos = player->getMyPos();
SInputMove input_move( curr_pos );
m_gameSystem->AddGameInput( &input_move );
stop_move( FALSE );
return;
}
*/
}
//if (player->IsChasing()) // 키보드 이동은 추적을 캔슬 시킨다
//{ //player->m_pStateVM->StopCurrentState();
//player->clearAllState();
//player->m_pStateVM->ClearPendingNextState();
//}
AR_TIME prev_time = m_arTime;
AR_TIME curr_time = GetArTime();
AR_TIME elapsed_time = curr_time-prev_time;
m_arTime = curr_time;
int elapsed_sent = curr_time - m_sent_time;
float curr_move_dir = get_key_move_dir(curr_key_status);
float prev_move_dir = player->getKMoveDir();
int prev_key_status = player->getKMoveType() ;
player->setKMoveType(curr_key_status);
int direction_equal = sMathUtil::isEqual(prev_move_dir, curr_move_dir);
int send_client = FALSE;
int send_server = FALSE;
if (prev_key_status != curr_key_status ) // 1.키이동시작 또는 키변경
{
if (elapsed_sent>=st_interval && m_sent_key_status != curr_key_status) // 서버 패킷은 초당 5회
{ send_server = TRUE;
} else
{ send_client = TRUE;
}
} else
if (prev_move_dir != curr_move_dir) // 2.키를 누른생태 또른 자동이동중 마우스로 방향 변경
{
//float minAngle = sMathUtil::degreeToRadian(MIN_CHANGED_CAM_DEGREE); // 30도 이상 회전시 바로 패킷을 날린다동일방향으로 이동하면서 카메라로 방향을 바꾼경우.
//if (fabs( curr_move_dir - m_sent_move_dir) >= minAngle)
if (elapsed_sent>=st_interval && m_sent_move_dir != curr_move_dir) // 회전각보다 시간으로 제어
{ send_server = TRUE;
} else
{ send_client = TRUE;
}
} else // 3.누른 상태 또는 자동이동으로 동일방향 이동.
{ if (!m_moveUpdate.m_active)
{
if (player->IsMoving()==FALSE && player->IsChasing()==FALSE ) send_server = TRUE; // 다른 액션에 의해서 키보드 누르고 있는 상태가 유예. 이상황에서 elapsed 는?
else return;
}
}
// 일정시간이상 경과시 무조건 서버 전송
if (m_moveUpdate.update(elapsed_time)==FALSE) send_server = TRUE;
// 이동
if (send_server || send_client)
{ AR_TIME elapsed;
K3DVector target_pos;
K3DVector curr_pos = get_local_pos();
int collision = get_move_pos( &curr_pos , &curr_move_dir, &target_pos, &elapsed, 1.0f );
if (collision==FALSE)
{
start_move(&curr_pos,curr_move_dir,curr_key_status, &target_pos, elapsed, send_server); // 충돌에의해 변경된 방향도 리턴되어야 하는가?
if (send_server) _oprint( "start: 2 (%5.0f,%5.0f)-(%5.0f,%5.0f) %d %d (%d/%d)\n", curr_pos.x,curr_pos.y,target_pos.x,target_pos.y,elapsed, elapsed_time,send_server,send_client);
} else
{
if (player->isKMoving())
{ stop_move( TRUE );
_oprint( "stop: 2 (%5.0f,%5.0f)-(%5.0f,%5.0f) %d %d\n", curr_pos.x,curr_pos.y,target_pos.x,target_pos.y,elapsed, elapsed_time);
} else
{ stop_move( FALSE );
}
player->setKMoveType( MOVE_NONE );
}
}
}
float SKMoveControler::get_key_move_dir(int key_status)
{
float fdir = m_gameCamera->getAngleZ() - sMathUtil::degree90; // = UP DIR
// AziaMafia Clavier move
if ((MOVE_UP & key_status) && (MOVE_LEFT & key_status) ) fdir += sMathUtil::degree45; else
if ((MOVE_UP & key_status) && (MOVE_RIGHT & key_status) ) fdir -= sMathUtil::degree45; else
if ((MOVE_DOWN & key_status) && (MOVE_RIGHT & key_status) ) fdir -= sMathUtil::degree135; else
if ((MOVE_DOWN & key_status) && (MOVE_LEFT & key_status) ) fdir += sMathUtil::degree135; else
if (MOVE_RIGHT& key_status) fdir -= sMathUtil::degree90; else
if (MOVE_DOWN & key_status) fdir -= sMathUtil::degree180; else
if (MOVE_LEFT & key_status) fdir += sMathUtil::degree90; else
if (MOVE_UP & key_status) fdir += 0;
return fdir;
}
bool SKMoveControler::get_move_pos( K3DVector* pcurr_pos, float* pdir, K3DVector* ptarget_pos, AR_TIME* pelapsed,float rate)
{
SGameAvatarEx* player = m_gameSystem->GetLocalPlayer(); if (!player) return TRUE;
sNextKMoveInfo info;
info.kmoveDir = *pdir;
info.collisionTheta = *pdir;
info.speed = player->getSpeed();
//if (info.speed<=0) info.speed = DEF_SPEED;
if (info.speed<=0 || info.speed>200) info.speed = g_nMoveSpeed/7;
if (player->GetCreatureMountHandle())
info.speed = player->getSpeed();
//if (info.speed<=0 || info.speed>100) info.speed = g_nMoveSpeed / 7;
//info.speed = g_nMoveSpeed / 7; // AziaMafia FIx Speed
info.setCurPos(pcurr_pos->x, pcurr_pos->y, pcurr_pos->z);
info.checkNextCollisionPos = true;
sArenaSystem* arenaSystem = g_pCurrentGameSystem->getArenaSystem();
bool collision = m_arObject->getNextKMovePos(info, st_move_length, arenaSystem->getBlockList(), rate);
float nMovelength = sqrtf( (info.curPos.x - info.nextKMovePos.x) * (info.curPos.x - info.nextKMovePos.x) + (info.curPos.y - info.nextKMovePos.y) * (info.curPos.y - info.nextKMovePos.y) );
if ( nMovelength < (st_move_length/2.f) ) // 이동길이 / 2 보다 이동거리가 작을 땐 충돌로 처리
m_automove = FALSE;
for (int i=0;i<2;i++)
{ if (collision==FALSE) break;
if (i==0) info.collisionTheta = *pdir + 0.1f;
else info.collisionTheta = *pdir - 0.1f;
info.checkNextCollisionPos = true;
info.collisionCount = 0;
collision = m_arObject->getNextKMovePos(info, st_move_length, arenaSystem->getBlockList(), rate);
}
if (!collision)
player->setCameraRoll(info.kmoveDir);
/// 이동 방향과 충돌 후의 방향사이의 각이 90도가 넘으면 충돌로 간주해서 멈춘다.
if (!collision && 0 < info.collisionCount)
{
float a1 = *pdir; sMathUtil::makeAbsTheta(a1);
float a2 = info.kmoveDir; sMathUtil::makeAbsTheta(a2);
float diff = a1 - a2; sMathUtil::makeAbsTheta(diff);
//float t = min(diff, sMathUtil::degree360 - diff);
if ( (diff>sMathUtil::degree90) && (diff <(sMathUtil::degree360-sMathUtil::degree90)))
collision = true;
*pdir = info.kmoveDir;
}
ptarget_pos->x = info.nextKMovePos.x;
ptarget_pos->y = info.nextKMovePos.y;
ptarget_pos->z = info.nextKMovePos.z;
*pelapsed = info.elapsedArTime;
return collision;
}
void SKMoveControler::send_move(K3DVector* ptarget_pos, float move_dir,int key_status, bool send_server)
{
SGameAvatarEx* player = m_gameSystem->GetLocalPlayer(); if (!player) return ;
K3DVector target_pos = *ptarget_pos;
// 서버에 전송
if (send_server)
{ AR_HANDLE ar_id = player->GetArID();
player->reqKMove(ar_id, target_pos);
m_sent_key_status = key_status;
m_sent_move_dir = move_dir;
m_sent_pos = *ptarget_pos;
m_sent_time = m_arTime;
SObjectState::ID cur_state = player->m_pStateVM->GetCurrentState();
if (cur_state == SObjectState::STATE_CHASE)
{ //K3DVector curr_pos = player->getMyPos();
K3DVector target_pos = *ptarget_pos;
SInputMove input_move( target_pos );
m_gameSystem->AddGameInput( &input_move );
stop_move( FALSE );
return;
}
}
// 클라 이동
player->ClearWayPointList();
SMSG_KMOVE msg_move;
msg_move.handle = player->GetArID();
msg_move.start_time = 0;
msg_move.bReqMove = false;
msg_move.pos_target = *ptarget_pos;
msg_move.speed = player->getSpeed();
//if (msg_move.speed<=0) msg_move.speed = DEF_SPEED;
if (msg_move.speed<=0 || msg_move.speed>200) msg_move.speed = g_nMoveSpeed/7;
if (player->GetCreatureMountHandle())
msg_move.speed = player->getSpeed();
//msg_move.speed = g_nMoveSpeed /7; // AziaMafia FIx Speed
ArPosition ar_pos = ArPosition(ptarget_pos->x, ptarget_pos->y, ptarget_pos->z);
msg_move.m_vecMoveInfo.push_back(ar_pos);
m_commandSystem->ProcMsgAtStatic(&msg_move);
player->addKMoveTargetList(target_pos);
}
void SKMoveControler::send_last_move()
{
SGameAvatarEx* player = m_gameSystem->GetLocalPlayer(); if (!player) return ;
K3DVector target_pos;
AR_TIME elapsed;
int key_status = player->getKMoveType();
//else kmoveDir = player->getKMoveDir();
// 이동을 멈출 때, 약간 이동을 더 시켜준다.
K3DVector curr_pos = get_local_pos();
float curr_dir = get_key_move_dir(key_status);
int collision = get_move_pos( &curr_pos, &curr_dir, &target_pos, &elapsed, st_stop_rate); //, ))
if (collision == FALSE)
{ send_move(&target_pos, curr_dir, key_status,TRUE);
_oprint( "stop: 2 (%5.0f,%5.0f)-(%5.0f,%5.0f)\n", curr_pos.x,curr_pos.y,target_pos.x,target_pos.y,elapsed);
} else
{ send_move(&curr_pos, curr_dir, key_status,TRUE);
_oprint( "block: 2 (%5.0f,%5.0f)-(%5.0f,%5.0f)\n", curr_pos.x,curr_pos.y,target_pos.x,target_pos.y,elapsed);
}
}
void SKMoveControler::start_move(K3DVector* curr_pos, float curr_dir, int key_status, K3DVector* ptarget_pos, AR_TIME elapsed ,int send_server)
{
SGameAvatarEx* player = m_gameSystem->GetLocalPlayer(); if (!player) return ;
m_gameWorld->ResetAutoMoveMode();
m_gameWorld->ResetAutoFollowMode();
if (player->IsMountMode())
player->ClearWayPointList();
player->EraseDetour();
send_move(ptarget_pos, curr_dir, key_status, send_server);
AR_TIME updateTime = (AR_TIME)((float) elapsed * st_update_rate); // 0.8f
m_moveUpdate.begin(updateTime);
player->setKMoving(true);
player->setKMoveType(key_status);
}
void SKMoveControler::stop_move(bool send_last)
{ SGameAvatarEx* player = m_gameSystem->GetLocalPlayer(); if (!player) return ;
if (player->isKMoving() && send_last)
send_last_move();
m_moveUpdate.end();
player->setKMoving( FALSE );
}
/////////////////////////////////////////////////////////////////////////////////////////////////////// 이하 메시지 처리.
// ??
void SKMoveControler::procMoveMsg(SGameMessage* msg)
{
SMSG_MOVE* moveMsg = dynamicCast<SMSG_MOVE*>(msg);
if (!moveMsg)return ;
SGameAvatarEx* player = m_commandSystem->GetAvatar(moveMsg->handle);
if (player==NULL) return;
if (player->IsLocalPlayer() && player->GetObjType() == TS_ENTER::GAME_PLAYER)
{
if (player->isKMoving())
{
if (!player->isKMoveTargetList(moveMsg->m_vecMoveInfo))
{
ArPosition p = moveMsg->m_vecMoveInfo.back();
stop_move( FALSE );
player->setKMoveType( MOVE_NONE );
/// 실제 자신의 위치로 이동 시킨다
ArMoveVector const& ar_pos = m_arObject->GetMyPos();
K3DVector pos(ar_pos.x, ar_pos.y, ar_pos.z);
float curr_dir = m_sent_move_dir;
int key_status = m_sent_key_status;
send_move( &pos ,curr_dir, key_status, FALSE );
return ;
}
player->eraseKMoveTargetList( moveMsg->m_vecMoveInfo );
}
}
}
// 마우스 미들버튼을 자동이동으로 사용하고 있다
void SKMoveControler::procMouseMsg(SGameMessage* msg)
{
SIMSG_MBUTTONDOWN* pmsg = dynamicCast<SIMSG_MBUTTONDOWN*>(msg);
if (pmsg==NULL) return ;
if (pmsg->wParam & MK_MBUTTON)
{ m_automove = !m_automove;
}
}
// 이동 서버 불허 판정
void SKMoveControler::procMsgResult(SGameMessage* msg)
{
SMSG_RESULT* pmsg = dynamicCast<SMSG_RESULT*>(msg);
if (pmsg==NULL) return;
if (pmsg->request_msg_id==TM_CS_MOVE_REQUEST)
{
m_servermove = TRUE;
//if (pmsg->result==RESULT_ACCESS_DENIED)
//{ // 최종컨펌받은 위치로 텔포?
m_commandSystem->MoveImpossibleMsg();
//}
// 서버에 의한 위치 중재 메시지로 활용?
//SGameAvatarEx* player = m_commandSystem->GetLocalPlayer();
//if (player->isKMoving())
//{ stop_move( FALSE ); /// 실제 자신의 위치로 이동 시킨다
// player->setKMoveType( MOVE_NONE );
//}
}
}