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

502 lines
11 KiB
C++

#include "stdafx.h"
#include "ArcadiaClient.h"
#include <mmo/ArOption.h>
#include <toolkit/XConsole.h>
#include "TerrainMapEngine.h"
bool ArcadiaClient::FinishedReqRegionUpdate()
{
bool bIsFinished = m_myPos.Step( m_lastProcTime );
if( m_myPos.IsMoving() )
return false;
m_intf->ReqRegionUpdate( m_lastProcTime - m_lastPendingTime[0] );
return true;
}
void ArcadiaClient::proc( ArMoveVector & pos )
{
unsigned prev_x = GetRegionX( pos.GetX() );
unsigned prev_y = GetRegionY( pos.GetY() );
bool bIsFinished = m_myPos.Step( m_lastProcTime );
unsigned rx = GetRegionX( pos.GetX() );
unsigned ry = GetRegionY( pos.GetY() );
if( bIsFinished || prev_x != rx || prev_y != ry )
{
// { 살짝 스쳐가는 region 은 무시하자
ArMoveVector mv;
mv = pos;
mv.Step( m_lastProcTime + IGNOREABLE_VISIT_TIME );
if( bIsFinished ||
( mv.GetRX() == rx && mv.GetRY() == ry && mv.IsMoving() )
)
{
m_intf->ReqRegionUpdate( m_lastProcTime - m_lastPendingTime[0] );
m_lastPendingTime[0] = m_lastProcTime;
if( prev_x != rx || prev_y != ry )
{
m_px = m_pnx;
m_py = m_pny;
m_pnx = rx;
m_pny = ry;
}
}
// }
}
}
void ArcadiaClient::Proc( bool bPendingLeave )
{
m_lastProcTime = GetArTime();
/*
unsigned fprx = GetRegionX( GetMyPos().GetX() );
unsigned fpry = GetRegionY( GetMyPos().GetY() );
unsigned rx = GetRegionX( GetMyPos().GetX() );
unsigned ry = GetRegionY( GetMyPos().GetY() );
*/
// update client pos
if( m_myPos.IsMoving() ) proc( m_myPos );
_Object* client = NULL;
bool res;
if( bPendingLeave )
{
_Object* client = NULL;
res = m_clientList.get_first_value(client);
while ( res )
{
if (client->mv.IsMoving())
client->mv.Step(m_lastProcTime);
res = m_clientList.get_next_value(client);
}
}
else
{
res = m_clientList.get_first_value(client);
while ( res )
{
procClient(client);
res = m_clientList.get_next_value(client);
}
}
vector<AR_HANDLE> eraseList;
res = m_clientList.get_first_value(client);
while ( res )
{
if (client->bIsLeaved && client->bIsActivate )
{
if( client->bIsActivate = m_intf->onLeave( client ) )
{
eraseList.push_back(client->handle);
}
}
res = m_clientList.get_next_value(client);
}
size_t eraseCount = eraseList.size();
for (size_t i = 0; i < eraseCount; ++i)
{
m_clientList.erase(eraseList[i]);
}
eraseList.clear();
}
void ArcadiaClient::ReqMove( AR_HANDLE handle, const ArPosition & target, const ArPosition * targetposdata, int count, bool bSpeedSync )
{
if( m_myHandle == handle )
{
ReqMove( target, targetposdata, count, bSpeedSync );
return;
}
AR_TIME gap = m_lastProcTime - m_lastPendingTime[handle];
m_intf->ReqMove( handle, GetPosition( handle ), target, m_lastProcTime, targetposdata, count, bSpeedSync ); // 15 는 메세지 전송 왔다갔다 하는 시간 갭..
m_lastPendingTime[handle] = m_lastProcTime;
}
void ArcadiaClient::ReqMove( const ArPosition & target, const ArPosition * targetposdata, int count, bool bSpeedSync )
{
//if( bIsPendingMove ) return;
bIsPendingMove = true;
AR_TIME gap = m_lastProcTime - m_lastPendingTime[0];
m_targetPos = target;
m_intf->ReqMove( m_myHandle, GetMyPos(), m_targetPos, m_lastProcTime, targetposdata, count ); // 15 는 메세지 전송 왔다갔다 하는 시간 갭..
m_lastPendingTime[0] = m_lastProcTime;
}
void ArcadiaClient::onLogin( const ArPosition & pPos, AR_HANDLE my_handle )
{
m_myHandle = my_handle;
m_myPos.SetCurrentPos( pPos );
m_pnx = m_px = GetRegionX( pPos.x );
m_pny = m_py = GetRegionY( pPos.y );
}
void ArcadiaClient::ReSet()
{
m_myHandle = 0;
m_myPos.StopMove();
m_myPos = ArMoveVector();
}
void ArcadiaClient::StopMove()
{
// 이동정지
m_myPos.StopMove();
}
void ArcadiaClient::ClerAll()
{
m_clientList.clear();
}
void ArcadiaClient::onMoveAck( AR_TIME start_time,unsigned char speed )
{
}
void ArcadiaClient::onEnter( _Object * pPtr )
{
if (m_clientList.lookup(pPtr->handle))
return ;
m_clientList.add(pPtr->handle, pPtr);
}
//활성화 or 비활성화
void ArcadiaClient::SetActivate( AR_HANDLE handle )
{
_Object* client;
if (m_clientList.lookup(handle, client))
{
client->bIsActivate = true;
client->bIsLeaved = false;
}
}
_Object * ArcadiaClient::onLeave( AR_HANDLE handle )
{
_Object* client;
if (m_clientList.lookup(handle, client))
{
m_clientList.erase(handle);
return client;
}
return NULL;
}
void ArcadiaClient::onMove( AR_HANDLE id, const ArPosition & pos, unsigned char speed, AR_TIME start_time )
{
if( id == m_myHandle )
{
m_myPos.SetMove( pos, speed, m_lastProcTime, GetArTime() );
bIsPendingMove = false;
return;
}
_Object* client;
if (m_clientList.lookup(id, client))
{
client->mv.SetMove( pos, speed, start_time, GetArTime() );
}
}
void ArcadiaClient::onMultiMove( AR_HANDLE id, const ArPosition & pos, const std::vector< ArPosition > & _to, unsigned char speed, AR_TIME start_time )
{
if( id == m_myHandle )
{
m_myPos.SetMultipleMove( _to, speed, m_lastProcTime, GetArTime() );
bIsPendingMove = false;
return;
}
_Object* client;
if (m_clientList.lookup(id, client))
{
client->mv.SetMultipleMove( _to, speed, m_lastProcTime, GetArTime() );
}
}
void ArcadiaClient::onKnockBack( AR_HANDLE id, const ArPosition & pos, unsigned char speed )
{
if( id == m_myHandle )
{
m_myPos.SetKnockBack( pos, speed, m_lastProcTime, GetArTime() );
bIsPendingMove = false;
return;
}
_Object* client;
if (m_clientList.lookup(id, client))
{
client->mv.SetKnockBack( pos, speed, m_lastProcTime, GetArTime() );
}
}
void ArcadiaClient::onRegionAck( unsigned rx, unsigned ry )
{
_Object* client = NULL;
bool res = m_clientList.get_first_value(client);
while ( res )
{
if( client->mv.IsMoving() )
{
client->mv.Step( m_lastProcTime );
}
// { leave 해야할 녀석을 세팅 & 인터페이스로 알려주자
int crx = client->mv.GetRX();
int cry = client->mv.GetRY();
if( !IsVisibleRegion( crx, cry, rx, ry ) && !IsVisibleRegion( crx, cry, m_myPos.GetRX(), m_myPos.GetRY() ) )
{
if( !client->leaveTime ) client->leaveTime = m_lastProcTime;
else
{
if( client->leaveTime + 50 < m_lastProcTime )
{
client->bIsLeaved = true;
}
}
}
res = m_clientList.get_next_value(client);
}
vector<AR_HANDLE> eraseList;
res = m_clientList.get_first_value(client);
while ( res )
{
//활성화 돼있나? true( 화면에 보여지고 있다 ) Creature에만 해당
if( client->bIsLeaved && client->bIsActivate )
{
if( client->bIsActivate = m_intf->onLeave( client ) )
{
eraseList.push_back(client->handle);
}
}
res = m_clientList.get_next_value(client);
}
size_t eraseCount = eraseList.size();
for (size_t i = 0; i < eraseCount; ++i)
{
m_clientList.erase(eraseList[i]);
}
eraseList.clear();
}
void ArcadiaClient::onWarp( AR_UNIT x, AR_UNIT y, AR_UNIT z )
{
// 이동정지
m_myPos.Step( 0xffffffff );
// 다 날리고
vector<AR_HANDLE> eraseList;
_Object* client = NULL;
bool res = m_clientList.get_first_value(client);
while ( res )
{
client->mv.StopMove();
if( m_intf->onLeave( client ) )
{
eraseList.push_back(client->handle);
}
res = m_clientList.get_next_value(client);
}
size_t eraseCount = eraseList.size();
for (size_t i = 0; i < eraseCount; ++i)
{
m_clientList.erase(eraseList[i]);
}
eraseList.clear();
m_myPos.StopMove();
m_myPos.SetCurrentXY( x, y );
m_myPos.SetCurrentZ( z );
}
void ArcadiaClient::setTerrainMapEngine(CTerrainMapEngine* terrainMapEngine)
{
m_terrainMapEngine = terrainMapEngine;
}
void ArcadiaClient::calcNextKMovePos(sNextKMoveInfo& info, float oneStepMoveLen, float rateLen)
{
float len = oneStepMoveLen * rateLen;
ArPosition offset;
offset.x = ::cosf(info.kmoveDir) * len;
offset.y = ::sinf(info.kmoveDir) * len;
offset.z = 0.0f;
info.nextKMovePos.x = info.curPos.x + offset.x;
info.nextKMovePos.y = info.curPos.y + offset.y;
info.nextKMovePos.z = info.curPos.z + offset.z;
}
bool ArcadiaClient::getNextKMovePos(sNextKMoveInfo& info, float oneStepMoveLen, std::vector<K3DVector2> const& blockList, float rateLen)
{
calcNextKMovePos(info, rateLen, oneStepMoveLen);
bool collision;
if (!blockList.empty())
{
collision = m_terrainMapEngine->collisionCustomBlock(info.curPos.x, info.curPos.y, info.nextKMovePos.x, info.nextKMovePos.y, blockList);
if (collision)
{
info.elapsedArTime = calcElapsedMoveTime(oneStepMoveLen, info.speed);
AR_UNIT len = info.curPos.GetDistance(info.nextKMovePos);
if (2 >= len)
return true;
/// 타겟 까지 이동은 해야 되기 때문에 false를 리턴한다.
return false;
}
}
collision = m_terrainMapEngine->collisionAttrQuad(info.curPos.x, info.curPos.y, info.nextKMovePos.x, info.nextKMovePos.y, info.collisionTheta);
if (collision)
{
++info.collisionCount;
if (info.checkNextCollisionPos)
{
info.kmoveDir = info.collisionTheta;
info.checkNextCollisionPos = false;
return getNextKMovePos(info, oneStepMoveLen, blockList, rateLen);
}
}
else
{
info.elapsedArTime = calcElapsedMoveTime(oneStepMoveLen, info.speed);
}
return collision;
}
AR_TIME ArcadiaClient::calcElapsedMoveTime(float len, int speed) const
{
return len / ((float)speed/SPEED_UNIT);;
}
void ArcadiaClient::onClientMultiMove( AR_HANDLE id, const ArPosition & pos, const std::vector< ArPosition > & _to, unsigned char speed, AR_TIME start_time )
{
_Object* client = NULL;
if (m_clientList.lookup(id, client))
{
client->mv.SetMultipleMove( _to, speed, m_lastProcTime, GetArTime() );
#ifdef KMOVE_DEBUG
addKMovePrimitive(_to, client->mv.GetPos(), 0);
#endif
}
}
#ifdef KMOVE_DEBUG
void ArcadiaClient::addKMovePrimitive(std::vector<ArPosition> const& _to, ArPosition const& curPos, int type)
{
if (_to.empty())
return ;
if (m_kmovePrimitive->GetWireVertexCnt() > 100)
m_kmovePrimitive->Clear();
K3DVector v1, v2;
std::vector<ArPosition>::const_iterator it = _to.end() - 1;
ArPosition toPos = (*it);
KColor color(0, 255, 0, 255);
float offset = 3.0f;
if (0 != type)
{
offset = 5.0f;
color = KColor(0, 255, 255, 255);
}
/// 현재 위치
v1.Set(curPos.x, curPos.y, curPos.z + offset);
v2.Set(toPos.x, toPos.y, toPos.z+offset+2.0f);
m_kmovePrimitive->AddLine(v1, v2, color);
}
KWireUtilPrimitive* ArcadiaClient::getKMovePrimitive() const
{
return m_kmovePrimitive;
}
#endif
void ArcadiaClient::procClient(_Object* client)
{
if( client->mv.IsMoving() )
{
client->mv.Step( m_lastProcTime);
}
// { leave 해야할 녀석을 세팅 & 인터페이스로 알려주자
int crx = client->mv.GetRX();
int cry = client->mv.GetRY();
if( !IsVisibleRegion( crx, cry, m_myPos.GetRX(), m_myPos.GetRY() ) )
{
if( !client->leaveTime )
{
client->leaveTime = m_lastProcTime;
}
else
{
if( m_myPos.IsMoving() )
{
ArMoveVector afterPos = m_myPos;
afterPos.Step( 100 );
if( m_myPos.GetDistance( client->mv.GetPos() ) < afterPos.GetDistance( client->mv.GetPos() ) )
{
client->bIsLeaved = true;
}
}
else
{
if( client->leaveTime + 100 < m_lastProcTime )
{
client->bIsLeaved = true;
}
}
}
}
}
void ArcadiaClient::setSpeed(AR_HANDLE id, unsigned char speed)
{
if (m_myHandle == id)
{
m_myPos.setSpeed(speed);
}
}