215 lines
9.0 KiB
C++
215 lines
9.0 KiB
C++
#pragma once
|
|
|
|
#include <vector>
|
|
|
|
#include "ArObject.h"
|
|
#include "ArOption.h"
|
|
|
|
#include "../toolkit/XConsole.h"
|
|
#include "../toolkit/SafeTickCount.h"
|
|
|
|
|
|
/*
|
|
|
|
ArcadiaServer 의 주요 기능은 다음과 같다.
|
|
|
|
. 맵상의 object 들의 이동처리
|
|
. 임의의 지역에 대한 lock (SMP 관련)
|
|
|
|
Arcadia 엔진은 기본적으로 Network I/O 에 사용되는 메세지 프로토콜을 정의하지 않는다.
|
|
Arcadia 는 메세지가 포함해야할 기본적인 정보들만을 노출시키고 있으며 그것의 실제적인
|
|
구현은 전적으로 사용자에게 달려 있다.
|
|
이를테면 "플레이어가 x,y 좌표로 이동한다" 를 다루기 위해 필요한 것은
|
|
"ARCADIA_MOVE_MESSAGE" 같은 메세지 스트럭쳐가 아니라 단지 x, y 좌표일 뿐이다.
|
|
|
|
*/
|
|
|
|
|
|
struct ArcadiaIntf
|
|
{
|
|
virtual void SendEnterMessage( const ArObject * pClient, const ArObject * pObj ) = 0;
|
|
virtual void SendLeaveMessage( const ArObject * pClient, const ArObject * pObj ) = 0;
|
|
virtual void SendForceMoveMessage( const ArObject * pClient, const ArObject * pObj ) = 0;
|
|
virtual void SendMoveMessage( const ArObject * pClient, const ArObject * pObj ) = 0;
|
|
virtual void SendMoveAckMessage( const ArObject * pClient, AR_TIME tm, unsigned char speed ) = 0;
|
|
virtual void SendRegionAckMessage( const ArObject * pClient, unsigned rx, unsigned ry ) = 0;
|
|
|
|
virtual void SendGameMessage( const ArObject * pClient, const void *Message ) = 0;
|
|
|
|
virtual bool onSetMove( ArObject * pObj, const ArPosition & oldPos, const ArPosition & newPos ) { return true; }
|
|
|
|
virtual void onNearRegion( ArObject * pClient, ArObject * pObj ) {}
|
|
};
|
|
|
|
struct ArcadiaLock
|
|
{
|
|
int handle;
|
|
|
|
ArcadiaLock( int _handle ) : handle( _handle )
|
|
{
|
|
}
|
|
};
|
|
|
|
class ArcadiaServer
|
|
{
|
|
public:
|
|
|
|
virtual ~ArcadiaServer();
|
|
|
|
bool Init( ArcadiaIntf * pIntf, AR_UNIT map_width, AR_UNIT map_height, void (*scheduler_thread_init_func)( int ), bool bMonitoringThread = false );
|
|
bool DeInit();
|
|
|
|
// priority 를 변경할 필요가 없을경우, call instruction 을 피해가기 위해 인라인으로 뽑았음.
|
|
inline void SetObjectPriority( ArSchedulerObject * obj, ArSchedulerObject::AR_OBJECT_PRIORITY priority )
|
|
{
|
|
// 이미 등록되어 있으면 무시~
|
|
if( obj->GetPriority() == priority &&
|
|
obj->GetPendingPriority() == -1 ) return;
|
|
|
|
if( obj->GetPendingPriority() == priority ) return;
|
|
|
|
setObjectPriority( obj, priority );
|
|
}
|
|
|
|
// DeleteObject 호출시 자동으로 스케쥴러에서 제거되고, 이후 적절한 때에 ProcDelete() 가 호출 된다.
|
|
void DeleteObject( ArSchedulerObject* pObject );
|
|
|
|
void onRegionChange( ArObject* pObject, AR_TIME update_time, bool bIsStopMessage );
|
|
|
|
// 이하 함수들에서 layer 관련 변수가 short 타입인 이유는 unsigned char 타입에서 -1과 255가 같은 값으로 취급되는 문제를 피하기 위함
|
|
ArcadiaLock _LockWorld( const char * filename, int linenumber );
|
|
ArcadiaLock _LockWithVisibleRange( const char * filename, int linenumber, unsigned rx, unsigned ry, short layer = -1 );
|
|
ArcadiaLock _LockObjectWithVisibleRange( const char * filename, int linenumber, const ArObject * pObject );
|
|
ArcadiaLock _LockObjectWithSpecificRegion( const char * filename, int linenumber, const ArObject * pObject, unsigned rx, unsigned ry, short layer = -2 );
|
|
ArcadiaLock _LockObject( const char * filename, int linenumber, const ArObject * pObject );
|
|
ArcadiaLock _LockObjects( const char * filename, int linenumber, const ArObject * pObject1, const ArObject * pObject2 );
|
|
ArcadiaLock _LockArea( const char * filename, int linenumber, unsigned rx1, unsigned ry1, unsigned rx2, unsigned ry2, short layer = -1 ); // region_update 로만 사용해야함
|
|
ArcadiaLock _LockObjectWithSpecificRange( const char * filename, int linenumber, const ArObject *pObject, unsigned range );
|
|
|
|
void UnLock( ArcadiaLock * pLockHandle );
|
|
|
|
const bool IsLocked( const unsigned int rx, const unsigned int ry, const short layer = -1, const bool bPartial = false );
|
|
const bool IsLocked( unsigned rx1, unsigned ry1, unsigned rx2, unsigned ry2, const short layer = -1, const bool bPartial = false );
|
|
const bool IsLocked( const ArObject *pObject, const bool bPartial = false );
|
|
|
|
unsigned Broadcast( unsigned rx, unsigned ry, unsigned char layer, const void * msg );
|
|
unsigned Broadcast( unsigned rx1, unsigned ry1, unsigned rx2, unsigned ry2, unsigned char layer, const void * msg );
|
|
unsigned BroadcastToSpecificRegion( unsigned rx, unsigned ry, unsigned range, unsigned char layer, const void * msg );
|
|
|
|
// Lock 을 해야함.
|
|
void AddObject( ArObject* pObject );
|
|
void RemoveObject( ArObject* pObject );
|
|
void EnumMovableObject( const ArPosition & pos, unsigned char layer, AR_UNIT range, std::vector< AR_HANDLE > * pvResult, bool bIncludeClient = true, bool bIncludeNPC = true );
|
|
void EnumMovableObject( int rx1, int ry1, int rx2, int ry2, unsigned char layer, std::vector< AR_HANDLE > * pvResult, bool bIncludeClient = true, bool bIncludeNPC = true );
|
|
void EnumMovableObjectInEveryRegion( int rx1, int ry1, int rx2, int ry2, unsigned char layer, std::vector< AR_HANDLE > * pvResult, bool bIncludeClient = true, bool bIncludeNPC = true );
|
|
void DoEachVisibleRegion( int rx, int ry, unsigned char layer, struct ArRegionFunctor & _fo );
|
|
void DoEachVisibleRegion( int rx1, int ry1, int rx2, int ry2, unsigned char layer, ArRegionFunctor & _fo );
|
|
void DoEachRegion( int rx1, int ry1, int rx2, int ry2, unsigned char layer, ArRegionFunctor & _fo );
|
|
|
|
bool SetMultipleMove( ArObject* pObject, const ArPosition & curPos, const std::vector< ArPosition > & newPos, unsigned char speed, bool bAbsoluteMove, AR_TIME t, bool bBroadcastMove = true );
|
|
bool SetMove( ArObject* pObject, const ArPosition & curPos, const ArPosition & newPos, unsigned char speed, bool bAbsoluteMove, AR_TIME t, bool bBroadcastMove = true );
|
|
void MoveObject( ArObject* pObject, const ArPosition & newPos, const float face );
|
|
|
|
static struct ArcadiaIntf* GetIntf() { return m_pIntf; }
|
|
|
|
LONG GetLockedThreadCount();
|
|
LONG GetWaitingThreadCount();
|
|
|
|
const LONG & GetUserCount() { return m_nUserCount; }
|
|
const LONG & GetNPCCount() { return m_nNPCCount; }
|
|
const LONG & GetItemCount() { return m_nItemCount; }
|
|
|
|
static ArcadiaServer & Instance();
|
|
|
|
protected:
|
|
|
|
private:
|
|
|
|
int arcadia_lock( struct ArBoxCollision * pLockInfo, const char * filename, int linenumber );
|
|
|
|
void setObjectPriority( ArSchedulerObject * pObj, ArSchedulerObject::AR_OBJECT_PRIORITY priority );
|
|
|
|
ArcadiaServer();
|
|
|
|
void step( ArObject* pObject, AR_TIME tm );
|
|
void onMoveObject( ArObject* pObject, const ArPosition & oldPos, const ArPosition & newPos );
|
|
void enterProc( ArObject* pObject, unsigned prx, unsigned pry );
|
|
|
|
static struct ArcadiaIntf* m_pIntf;
|
|
static struct ArcadiaData* m_pData;
|
|
|
|
AR_UNIT m_nMapWidth, m_nMapHeight;
|
|
|
|
LONG m_nUserCount;
|
|
LONG m_nNPCCount;
|
|
LONG m_nItemCount;
|
|
};
|
|
|
|
|
|
struct ArcadiaAutoLock
|
|
{
|
|
ArcadiaAutoLock()
|
|
: plockhandle(NULL)
|
|
, lockHandle(0)
|
|
, tLockStartTick( GetSafeTickCount() )
|
|
, szFileName( "??" )
|
|
, nLineNumber( 0 )
|
|
{
|
|
}
|
|
ArcadiaAutoLock( ArcadiaLock & lock, const char *fn = "??", int ln = 0 )
|
|
: lockHandle( lock.handle )
|
|
, szFileName( fn )
|
|
, nLineNumber( ln )
|
|
, tLockStartTick( GetSafeTickCount() )
|
|
{
|
|
plockhandle = &lockHandle;
|
|
}
|
|
|
|
~ArcadiaAutoLock()
|
|
{
|
|
unsigned int lock_time = GetSafeTickCount() - tLockStartTick;
|
|
|
|
if( plockhandle ) ArcadiaServer::Instance().UnLock( plockhandle );
|
|
extern volatile int g_bUseLockDelayLogging;
|
|
if( !g_bUseLockDelayLogging )
|
|
return;
|
|
|
|
if( lock_time > 1000 )
|
|
{
|
|
// 로그를 남기자..
|
|
_lprint( "LockPerfLog.txt", "%s : %d [%d]\n", szFileName, nLineNumber, lock_time );
|
|
}
|
|
}
|
|
|
|
void set( ArcadiaLock & lock, const char *fn = "??", int ln = 0 )
|
|
{
|
|
szFileName = fn;
|
|
nLineNumber = ln;
|
|
tLockStartTick = GetSafeTickCount();
|
|
lockHandle.handle = lock.handle;
|
|
plockhandle = &lockHandle;
|
|
}
|
|
|
|
const char* szFileName;
|
|
int nLineNumber;
|
|
unsigned int tLockStartTick;
|
|
ArcadiaLock* plockhandle;
|
|
ArcadiaLock lockHandle;
|
|
};
|
|
|
|
|
|
// For information on __VA_ARGS__, see http://msdn.microsoft.com/en-us/library/ms177415(VS.80).aspx (variable-parameter macro definitions)
|
|
#define LockWorld() _LockWorld( __FILE__, __LINE__ )
|
|
// Syntax: Lock( rx, ry[, layer] )
|
|
#define LockWithVisibleRange( rx, ry, ... ) _LockWithVisibleRange( __FILE__, __LINE__, rx, ry, __VA_ARGS__ )
|
|
// Syntax: LockArea( rx1, ry1, rx2, ry2[, layer] )
|
|
#define LockArea( rx1, ry1, rx2, ry2, ... ) _LockArea( __FILE__, __LINE__, rx1, ry1, rx2, ry2, __VA_ARGS__ )
|
|
// Syntax: LockObjectWithSpecificRegion( pObject, rx, ry[, layer] )
|
|
#define LockObjectWithSpecificRegion( pObject, rx, ry, ... ) _LockObjectWithSpecificRegion( __FILE__, __LINE__, pObject, rx, ry, __VA_ARGS__ )
|
|
#define LockObjectWithVisibleRange( pObject ) _LockObjectWithVisibleRange( __FILE__, __LINE__, pObject )
|
|
#define LockObject( pObject ) _LockObject( __FILE__, __LINE__, pObject )
|
|
#define LockObjects( pObject1, pObject2 ) _LockObjects( __FILE__, __LINE__, pObject1, pObject2 )
|
|
#define LockObjectWithSpecificRange( pObject, range ) _LockObjectWithSpecificRange( __FILE__, __LINE__, pObject, range )
|
|
|
|
#define ARCADIA_LOCK(x) ArcadiaAutoLock _lock( x, __FILE__, __LINE__ )
|