Files
git 9cb257e7ae Add GameClients drops and keep current 1602 source work.
CN1602 is the local client. KR is the official tree with unpacked Data, System, and Sound. Packed .wpk files stay off git.
2026-08-30 23:24:31 +03:00

508 lines
13 KiB
C++

#include "stdafx.h"
#include <io.h>
#include <IOCPServer.h>
#include <NetworkObject.h>
//=========================================================================================================
// GuildServer Include Files
//
#include "GuildServer.h"
#include "PacketHandler/PacketHandler.h"
#include <TempServerSession.h>
#include <Sessions/DBProxyServerSession.h>
#include <Sessions/MasterServerSession.h>
#include <Sessions/GameServerSession.h>
// Internal Function Headers
#include "Guild/GuildManager.h"
#include "GuildScriptParserManager.h"
#include <GuildRankInfoParser.h>
#include <ServerBuildVersion.h>
#include "DominationManager.h"
//#define temp_for_test
#define CHECK_PARAM_NUMBER( variable_type, variable, szSectionName, keyName, defValue ) \
variable_type variable = 0; \
__READ_CONFIG_NUMBER( variable, szSectionName, keyName, defValue, GetDescFileName() ); \
if( variable == defValue ) return FALSE
#define CHECK_PARAM_STRING( variable, szSectionName, keyName, defValue ) \
char variable [128] = {0,}; \
__READ_CONFIG_STRING( variable, szSectionName, keyName, defValue, GetDescFileName() ); \
if( variable == defValue ) return FALSE
#include <boost/shared_array.hpp>
/// @brief 환경 설정 파일에서 문자열 값을 안전하게 읽어온다.
/// @param section_name 섹션 이름
/// @param key_name 키값 이름
/// @param default_value 기본값
/// @param ini_file_name 환경설정 파일 이름
/// @param min_read_count 읽어올 문자열의 최소 개수
/// @param max_read_count 읽어올 문자열의 최대 개수
/// @return 정상적으로 읽어 왔으면 읽어온 문자열, 아니면 NULL값을 반환한다.
boost::shared_array<TCHAR> ReadConfigStringFromIni(
const TCHAR* section_name,
const TCHAR* key_name,
const TCHAR* default_value,
const TCHAR* ini_file_name,
int min_read_count = 0,
int max_read_count = 1000
)
{
boost::shared_array<TCHAR> read_string_ptr;
// 입력값을 검사한다.
if (NULL == section_name || NULL == key_name || NULL == ini_file_name || min_read_count < 0 ||
min_read_count > max_read_count)
{
return read_string_ptr;
}
read_string_ptr.reset(new TCHAR[MAX_PATH]);
// 먼저 읽어올 문자열 길이를 검사한다.
int read_character_count = ::GetPrivateProfileString(section_name, key_name, default_value,
read_string_ptr.get(), MAX_PATH, ini_file_name);
if (read_character_count < min_read_count || read_character_count > max_read_count)
{
read_string_ptr.reset();
return read_string_ptr;
}
read_string_ptr.reset(new TCHAR[read_character_count+1]);
// 읽어온다.
DWORD new_read_character_count = ::GetPrivateProfileString(section_name, key_name, default_value,
read_string_ptr.get(), MAX_PATH, ini_file_name);
// 성공적으로 읽어 왔는지 검사한다.
if (new_read_character_count != read_character_count)
{
read_string_ptr.reset();
return read_string_ptr;
}
return read_string_ptr;
} // ReadConfigStringFromIni
GuildServer::GuildServer()
{
SetPhaseStatus( PHASE_UNKNOWN );
ConnectSessions.Init();
m_pPoolRouter = new SERVER_SESSION_ROUTER;
SERVER_SESSION_ROUTER& rRouter = GetPoolRouter();
rRouter.Register<AgentServerSession>(AGENT_SERVER);
rRouter.Register<DBProxyServerSession>(GAME_DBPROXY);
rRouter.Register<WorldServerSession>(WORLD_SERVER);
rRouter.Register<MasterServerSession>(MASTER_SERVER);
rRouter.Register<GameServerSession>(GAME_SERVER);
//rRouter.Register<TempServerSessionEx>(TEMP_SERVER);
rRouter.Initialize( AGENT_SERVER, 5, 1 );
rRouter.Initialize( GAME_DBPROXY, 1, 1 );
rRouter.Initialize( WORLD_SERVER, 1, 1 );
rRouter.Initialize( MASTER_SERVER, 1, 1 );
//rRouter.Initialize( TEMP_SERVER, 10, 5 );
rRouter.Initialize( GAME_SERVER, 15, 5 );
m_TempServerSessionPool.Initialize( 10, 5 );
TempServerSession::SetPool( &m_TempServerSessionPool );
// Register Object Code
}
GuildServer::~GuildServer()
{
SetPhaseStatus(PHASE_UNKNOWN);
ConnectSessions.Init();
SAFE_DELETE( m_pPoolRouter );
}
BOOL GuildServer::Init()
{
InitializeLogger();
MessageOut( eCRITICAL_LOG, "*** GuildServer Start *** " );
MessageOut( eCRITICAL_LOG, "*** GuildServer Server Version = %d ***", SERVER_RELEASE_BUILD_NO );
// (서비스/콘솔)모드 제어 확인할 것.
__READ_CONFIG_NUMBER( m_bServiceMode, "COMMON", "SERVICE_MODE", 0, GUILD_SERVER_INFO_FILE_NAME );
WorkLoadManager::CreateInstance();
PacketHandler::RegisterHandler();
if( !Init_ScriptData( this->IsServerInfoFromFile() ) )
{
P_FAILED;
return FALSE;
}
P_SUCCESS;
DISPMSG( "Creating GuildLog File..." );
g_pLOG = new GuildLog();
CHECK_PARAM_STRING( pszGameLogfilePath, "LOGFILE", "WOPS_LOGFILE_PATH", NULL );
if( _access( pszGameLogfilePath, 0 ) == -1 ) //폴더가 존재하지 않으면..
{
if( !CreateDirectory( pszGameLogfilePath, NULL) )
printf( "CreateDirectory Fail, path = %s \n", pszGameLogfilePath );
}
TCHAR szBinPath[MAX_PATH], szTextPath[MAX_PATH];
_sntprintf( szBinPath, MAX_PATH, "%s\\\\GUILD", pszGameLogfilePath );
_sntprintf( szTextPath, MAX_PATH, "%s\\\\GUILD_TEXT", pszGameLogfilePath );
CHECK_PARAM_NUMBER( BYTE, byWopsLogOption, "LOGFILE", "WOPS_LOGFILE_OPTION", 0xFF );
#ifdef __NA_0_ADD_VERSION_TO_LOG_FILE_NAME
TCHAR szFileName[MAX_PATH];
_sntprintf( szFileName, MAX_PATH, "%d_SUN_GUILD", NATION_BUILD_VERSION );
if( !g_pLOG->Init( byWopsLogOption, szFileName, _T(szBinPath), _T(szTextPath) ) )
#else
if( !g_pLOG->Init( byWopsLogOption, _T("SUN_GUILD"), _T(szBinPath), _T(szTextPath) ) )
#endif
{ P_FAILED; }
else
{ P_SUCCESS; }
#if !defined(__WAVERIX_SOLAR_AUTH_SERVER_IMPLEMENTATION__)
StartServer();
#endif
return TRUE;
}
VOID GuildServer::Release()
{
WorkLoadManager::DestroyInstance();
PacketHandler::ReleaseHandler();
MessageOut( eCRITICAL_LOG, "*** GuildServer Close *** " );
if( m_pGuildScriptParserManager )
{
m_pGuildScriptParserManager->Release();
m_pGuildScriptParserManager->DestroyInstanceEx();
SAFE_DELETE( m_pGuildScriptParserManager );
}
DominationManager::DestroyInstance();
SAFE_DELETE(g_pSunLog);
SAFE_DELETE(g_pLOG);
}
BOOL GuildServer::Update( DWORD tick )
{
// <2> Server Session 관리
WorkLoadManager::Update();
// SunLog Update 위치나 종료시점의 로그 쓰기 등을 고려해서 재설정할 것.
g_pSunLog->Update();
if(m_GuildDestroyTimer.IsExpired())
g_GuildManager.UpdateForGuildDestroy();
DominationManager::Instance()->LoadDominationInfo();
return TRUE;
}
// <IMPLEMENTATION><SERVERFRAME><INTERFACE>
ServerSession* GuildServer::AllocServerSession( eSERVER_TYPE serverType )
{
ServerSession* pServerSession = NULL;
if( TEMP_SERVER != serverType )
{
SERVER_SESSION_ROUTER& rRouter = GetPoolRouter();
if( BATTLE_SERVER == serverType || FIELD_SERVER == serverType )
serverType = GAME_SERVER;
pServerSession = (ServerSession*)rRouter.Alloc( serverType );
switch( serverType )
{
case GAME_DBPROXY:
ConnectSessions.SessionDBProxy() = (DBProxyServerSession*)pServerSession;
break;
case MASTER_SERVER:
ConnectSessions.SessionMaster() = (MasterServerSession*)pServerSession;
break;
case WORLD_SERVER:
ConnectSessions.SessionWorld() = (WorldServerSession*)pServerSession;
break;
}
}
else
{
pServerSession = (ServerSession*)TempServerSession::ALLOC();
}
if( !pServerSession )
{
ASSERT(!"존재하지 않는 서버타입입니다."); return NULL;
}
pServerSession->Init( this );
return pServerSession;
}
// <IMPLEMENTATION><SERVERFRAME><INTERFACE>
VOID GuildServer::FreeServerSession( ServerSession* pServerSession )
{
if( !pServerSession )
return;
eSERVER_TYPE serverType = pServerSession->GetServerType();
pServerSession->Release();
if( TEMP_SERVER != serverType )
{
SERVER_SESSION_ROUTER& rRouter = GetPoolRouter();
eSERVER_TYPE serverType = pServerSession->GetServerType();
if( BATTLE_SERVER == serverType || FIELD_SERVER == serverType )
serverType = GAME_SERVER;
rRouter.Free( (DWORD)serverType, pServerSession );
}
else
{
TempServerSession::FREE( (TempServerSession*)pServerSession );
}
}
VOID GuildServer::SendToAllGameServers( MSG_BASE* pMsg, WORD wSize )
{
const DWORD cdwBitMask = (DWORD)( (1<<GAME_SERVER) | (1<<FIELD_SERVER) | (1<<BATTLE_SERVER) );
ServerFrame::SERVER_MAP& rSERVERMAP = GetSessionList();
ServerFrame::SERVER_MAP::iterator it = rSERVERMAP.begin();
ServerFrame::SERVER_MAP::iterator end = rSERVERMAP.end();
for( ; it != end ; ++it )
{
ServerSession* pSession = it->second;
if( ((DWORD)(1<<pSession->GetServerType())) & cdwBitMask )
{
pSession->SendPacket( pMsg, wSize );
}
}
}
BOOL GuildServer::ConnectTo( eSERVER_TYPE serverType )
{
ServerSession* pSession = NULL;
switch( serverType )
{
case GAME_DBPROXY:
pSession = ConnectSessions.SessionDBProxy(); break;
case WORLD_SERVER:
pSession = ConnectSessions.SessionWorld(); break;
}
if( !pSession ) return FALSE;
#ifndef __WAVERIX_SOLAR_AUTH_SERVER_IMPLEMENTATION__
if( pSession->IsConnecting() || pSession->IsConnected() )
{
ASSERT( !"중복 Connect 시도" );
return FALSE;
}
Connect(pSession);
return TRUE;
#else //__WAVERIX_SOLAR_AUTH_SERVER_IMPLEMENTATION__
if( ! IsServerInfoFromFile() )
{
if( (MASTER_SERVER != serverType)
&& (GetPhaseStatus() != PHASE_SERVICE) )
return FALSE;
}
if( !( pSession->IsConnecting() || pSession->IsConnected() ) )
{
if( (MASTER_SERVER != serverType)
&& (! IsServerInfoFromFile() )
&& (GetPhaseStatus() != PHASE_SERVICE) )
return FALSE;
Connect( pSession );
return TRUE;
}
ASSERT( !"중복 Connect 시도" );
return FALSE;
#endif //__WAVERIX_SOLAR_AUTH_SERVER_IMPLEMENTATION__
}
//
//
//
//
//
#include <PacketStruct_ServerCommon.h>
VOID GuildServer::StartServer()
{
// <해야 할 일>
//
// <NOTICE>
// 이것이 호출되었다는 의미는 필요한 모든 데이터를 받았다는 의미다.
// <THINKING>
GuildServer* pGuildServer = GuildServer::GetMainFrame();
#ifdef __WAVERIX_SOLAR_AUTH_SERVER_IMPLEMENTATION__
// 현 시점 PHASE_EXCHANGE일 것이다.
MSG_SERVERCOMMON_DATA_TRANSFER_SENDDATA_NTF msgNTF;
pGuildServer->ConnectSessions.SendToMaster( &msgNTF, sizeof(msgNTF) );
#else
if (pGuildServer->IsServerInfoFromFile())
#endif //
{
pGuildServer->Listen(SERVER_IOHANDLER);
};
}
BOOL GuildServer::InitializeLogger()
{
// 로그 파일 옵션을 읽는다.
BYTE sun_log_option = 0;
__READ_CONFIG_NUMBER(sun_log_option, TEXT("LOGFILE"), TEXT("SUN_LOGFILE_OPTION"), 0,
TEXT(GUILD_SERVER_INFO_FILE_NAME));
// 로그 파일 레벨을 읽는다.
BYTE sun_log_file_level = 0;
__READ_CONFIG_NUMBER(sun_log_file_level, TEXT("LOGFILE"), TEXT("SUN_LOGFILE_LEVEL"), 0,
TEXT(GUILD_SERVER_INFO_FILE_NAME));
// 로그 파일 경로를 읽는다.
typedef boost::shared_array<TCHAR> CharSmartPtr;
const CharSmartPtr& sun_log_file_path_ptr = ReadConfigStringFromIni(TEXT("LOGFILE"),
TEXT("SUN_LOGFILE_PATH"), NULL, GUILD_SERVER_INFO_FILE_NAME, 3);
if (!sun_log_file_path_ptr)
{
DISPMSG(TEXT("Fail to loading 'SUN_LOGFILE_PATH' from ini file.\n"));
return FALSE;
}
// 로그를 초기화 한다.
DISPMSG( "SUNLOG.Guild Initializing...\t" );
g_pSunLog = new CSunLog;
BOOL is_success = g_pSunLog->Init(sun_log_option, sun_log_file_level, sun_log_file_path_ptr.get(),
TEXT("Guild"));
if (is_success)
{
P_SUCCESS;
}
else
{
P_FAILED;
}
return is_success;
}
BOOL GuildServer::Init_ScriptData( BOOL bReadFromFile )
{
m_pGuildScriptParserManager = new GuildScriptParserManager;
m_pGuildScriptParserManager->InitParserPool( NULL );
m_pGuildScriptParserManager->RegisterParser();
#ifdef __WAVERIX_SOLAR_AUTH_SERVER_IMPLEMENTATION__
return TRUE;
#else
return m_pGuildScriptParserManager->Load();
#endif
}
//
//=======================================================================================================
BOOL GuildServer::sConnectSession::SendToMaster( MSG_BASE* pMsg, WORD wSize )
{
if( m_pMasterServerSession && m_pMasterServerSession->IsConnected() )
{
return m_pMasterServerSession->SendPacket( pMsg, wSize );
}
return FALSE;
}
BOOL GuildServer::sConnectSession::SendToDBProxy( MSG_BASE* pMsg, WORD wSize )
{
if( m_pDBProxyServerSession && m_pDBProxyServerSession->IsConnected() )
{
return m_pDBProxyServerSession->SendPacket( pMsg, wSize );
}
return FALSE;
}
BOOL GuildServer::sConnectSession::SendToWorld( MSG_BASE* pMsg, WORD wSize )
{
if( m_pWorldServerSession && m_pWorldServerSession->IsConnected() )
{
return m_pWorldServerSession->SendPacket( pMsg, wSize );
}
return FALSE;
}
//=======================================================================================================
//
//
// Callback Handlers
NetworkObject* GuildServer::CreateServerSideAcceptedObject()
{
return GuildServer::GetMainFrame()->AllocServerSession( TEMP_SERVER );
}
VOID GuildServer::DestroyServerSideAcceptedObject( NetworkObject* pNetworkObject )
{
GuildServer::GetMainFrame()->FreeServerSession( (ServerSession*)pNetworkObject );
}
VOID GuildServer::DestroyServerSideConnectedObject( NetworkObject* pNetworkObject )
{
}
BOOL GuildServer::KeyEvent( CHAR ch )
{
switch(ch)
{
case ' ':
DisplayServerInfo();
break;
}
return TRUE;
}
VOID GuildServer::DisplayServerInfo()
{
g_GuildManager.DisplayGuildInfo();
}
//==================================================================================================
//==================================================================================================
//==================================================================================================