572 lines
19 KiB
C++
572 lines
19 KiB
C++
#include "WorldServerPch.hxx"
|
|
#include "./WorldServer.h"
|
|
|
|
#include <io.h>
|
|
|
|
#include <PacketStruct_MW.h>
|
|
|
|
#include "Functions/WorldScriptParserManager.h"
|
|
#include "PacketHandler/PacketHandler.h"
|
|
|
|
#include "Channel/WorldChannelManager.h"
|
|
#include "Objects/WorldUserManager.h"
|
|
#include "Services/Friends/FriendInvitation.h"
|
|
#include "Services/Lotto/Lotto.h"
|
|
#include "Services/Guild/WorldGuildManager.h"
|
|
|
|
//==================================================================================================
|
|
|
|
namespace ns_world {
|
|
;
|
|
}; //end of namespace
|
|
|
|
//==================================================================================================
|
|
|
|
ns_world::WorldServer* ns_world::WorldServer::instance_static_ = NULL;
|
|
|
|
ns_world::WorldServer* ns_world::WorldServer::CreateInstance()
|
|
{
|
|
// if the old util::Singleton support interface don't exist, the below code need implements
|
|
static struct AutoClosure {
|
|
AutoClosure(WorldServer** static_table) : static_table_(static_table) {
|
|
}
|
|
~AutoClosure() {
|
|
SAFE_DELETE(*static_table_);
|
|
}
|
|
WorldServer** static_table_;
|
|
} auto_closure(&instance_static_);
|
|
//
|
|
if (instance_static_ != NULL) {
|
|
return instance_static_;
|
|
}
|
|
//
|
|
WorldServer* provider = new WorldServer;
|
|
// initialization...
|
|
instance_static_ = provider;
|
|
//
|
|
return instance_static_;
|
|
}
|
|
|
|
//==================================================================================================
|
|
|
|
ns_world::WorldServer::WorldServer()
|
|
{
|
|
ZeroMemory(fields_start_, static_cast<size_t>(fields_end_ - fields_start_));
|
|
if (ServerSessionPool* const pool = new ServerSessionPool)
|
|
{
|
|
pool->Initialize(5, 5);
|
|
this->server_session_pool_ = pool;
|
|
};
|
|
if (TempServerSessionPool* const pool = new TempServerSessionPool)
|
|
{
|
|
pool->Initialize(5, 5);
|
|
this->temp_session_pool_ = pool;
|
|
};
|
|
this->InitializeDataFields();
|
|
}
|
|
|
|
ns_world::WorldServer::~WorldServer()
|
|
{
|
|
SAFE_DELETE(server_session_pool_);
|
|
SAFE_DELETE(temp_session_pool_);
|
|
}
|
|
|
|
NetworkObject* ns_world::WorldServer::CreateServerSideAcceptedObject()
|
|
{
|
|
ns_world::WorldServer* world_server = ns_world::WorldServer::Instance();
|
|
return world_server->AllocServerSession(TEMP_SERVER);
|
|
}
|
|
|
|
void ns_world::WorldServer::DestroyServerSideAcceptedObject(NetworkObject* network_object)
|
|
{
|
|
ns_world::WorldServer* world_server = ns_world::WorldServer::Instance();
|
|
world_server->FreeServerSession(static_cast<ServerSession*>(network_object));
|
|
}
|
|
|
|
void ns_world::WorldServer::DestroyServerSideConnectedObject(NetworkObject* network_object)
|
|
{
|
|
ns_world::WorldServer* world_server = ns_world::WorldServer::Instance();
|
|
world_server->FreeServerSession(static_cast<ServerSession*>(network_object));
|
|
}
|
|
|
|
ServerSession* ns_world::WorldServer::AllocServerSession(eSERVER_TYPE server_type)
|
|
{
|
|
if (server_type == TEMP_SERVER)
|
|
{
|
|
TempServerSession* temp_session = \
|
|
reinterpret_cast<TempServerSession*>(this->temp_session_pool_->Alloc());
|
|
static_cast<ServerSession*>(temp_session)->Init(this);
|
|
return temp_session;
|
|
}
|
|
else if (kAcceptSessions & (1 << server_type))
|
|
{
|
|
ServerSessionInWorld* server_session = \
|
|
reinterpret_cast<ServerSessionInWorld*>(this->server_session_pool_->Alloc());
|
|
static_cast<ServerSession*>(server_session)->Init(this);
|
|
server_session->ChangeServerType(server_type);
|
|
return server_session;
|
|
}
|
|
else if (kConnectSessions & (1 << server_type))
|
|
{
|
|
ServerSessionInWorld* server_session = \
|
|
reinterpret_cast<ServerSessionInWorld*>(this->server_session_pool_->Alloc());
|
|
static_cast<ServerSession*>(server_session)->Init(this);
|
|
server_session->ChangeServerType(server_type);
|
|
if (server_type == GAME_DBPROXY) {
|
|
this->connect_sessions_.dbproxy_server = server_session;
|
|
this->connect_sessions_.dbproxy_enabled = false;
|
|
}
|
|
else if (server_type == MASTER_SERVER) {
|
|
this->connect_sessions_.master_server = server_session;
|
|
this->connect_sessions_.master_enabled = false;
|
|
};
|
|
|
|
return server_session;
|
|
};
|
|
//
|
|
SUNLOG(eCRITICAL_LOG, _T("|["__FUNCTION__"]|Msg=unexpected server type %d"), server_type);
|
|
return NULL;
|
|
}
|
|
|
|
void ns_world::WorldServer::FreeServerSession(ServerSession* server_session)
|
|
{
|
|
const eSERVER_TYPE server_type = server_session->GetServerType();
|
|
if (server_type == TEMP_SERVER)
|
|
{
|
|
this->temp_session_pool_->Free(static_cast<TempServerSession*>(server_session));
|
|
return;
|
|
}
|
|
else if (kAcceptSessions & (1 << server_type))
|
|
{
|
|
ServerSessionInWorld* server_session_in_world =
|
|
static_cast<ServerSessionInWorld*>(server_session);
|
|
this->server_session_pool_->Free(server_session_in_world);
|
|
return;
|
|
}
|
|
else if (kConnectSessions & (1 << server_type))
|
|
{
|
|
ServerSessionInWorld* server_session_in_world =
|
|
static_cast<ServerSessionInWorld*>(server_session);
|
|
this->server_session_pool_->Free(server_session_in_world);
|
|
|
|
if (server_type == GAME_DBPROXY) {
|
|
this->connect_sessions_.dbproxy_server = NULL;
|
|
this->connect_sessions_.dbproxy_enabled = false;
|
|
}
|
|
else if (server_type == MASTER_SERVER) {
|
|
this->connect_sessions_.master_server = NULL;
|
|
this->connect_sessions_.master_enabled = false;
|
|
};
|
|
|
|
return;
|
|
};
|
|
}
|
|
|
|
void ns_world::WorldServer::EnableSessionService(
|
|
ns_world::ServerSessionInWorld* server_session, bool enabled)
|
|
{
|
|
eSERVER_TYPE server_type = server_session->GetServerType();
|
|
if (kConnectSessions & (1 << server_type))
|
|
{
|
|
ServerSessionInWorld* server_session_in_world =
|
|
static_cast<ServerSessionInWorld*>(server_session);
|
|
|
|
if (server_type == GAME_DBPROXY)
|
|
{
|
|
if (enabled && !FlowControl::FCAssert(connect_sessions_.dbproxy_server != NULL)) {
|
|
return;
|
|
};
|
|
connect_sessions_.dbproxy_enabled = enabled;
|
|
}
|
|
else if (server_type == MASTER_SERVER)
|
|
{
|
|
if (enabled && !FlowControl::FCAssert(connect_sessions_.master_server != NULL)) {
|
|
return;
|
|
};
|
|
connect_sessions_.master_enabled = enabled;
|
|
};
|
|
|
|
return;
|
|
};
|
|
}
|
|
|
|
void ns_world::WorldServer::InitializeDataFields()
|
|
{
|
|
phase_shift_ = PHASE_UNKNOWN;
|
|
}
|
|
|
|
BOOL ns_world::WorldServer::Init()
|
|
{
|
|
WorkLoadManager::CreateInstance();
|
|
this->InitializeDataFields();
|
|
if (this->InitializeLogger() == false) {
|
|
CONSOLELOG(eCRITICAL_LOG, _T("|[%s]|Msg=can't create logger|"), __FUNCTION__);
|
|
return false;
|
|
};
|
|
sequential_shutdown_service_ = ns_world::SequentialShutdownService::Register();
|
|
//;{
|
|
// int service_mode = 0;
|
|
// __READ_CONFIG_NUMBER(service_mode, "ATTRIBUTES", "SERVICE_MODE",
|
|
// eSERVER_LIVE, WORLD_SERVER_INFO_FILE_NAME);
|
|
// if (service_mode < 0 || service_mode >= eSERVER_UPPERBOUND) {
|
|
// SUNLOG(eCRITICAL_LOG, _T("|[%s]|Msg=unexpected service mode = %d|"),
|
|
// __FUNCTION__, service_mode);
|
|
// return false;
|
|
// };
|
|
//};
|
|
if (this->IsServerInfoFromFile())
|
|
{
|
|
int world_id = 0;
|
|
__READ_CONFIG_NUMBER(world_id, "ATTRIBUTES", "WORLD_ID",
|
|
-1, WORLD_SERVER_INFO_FILE_NAME);
|
|
if (world_id < 0) {
|
|
SUNLOG(eCRITICAL_LOG, _T("|[%s]|Msg=unexpected world id, check [ATTRIBUTES] WORLD_ID|"),
|
|
__FUNCTION__, world_id);
|
|
return false;
|
|
};
|
|
server_key_.Set(BYTE(world_id), 0, 0, 1);
|
|
};
|
|
if (this->ReloadAdditionalConfig() == false)
|
|
{
|
|
SUNLOG(eCRITICAL_LOG, _T("|[%s]|Msg=additional configuration load failed|"), __FUNCTION__);
|
|
};
|
|
#ifdef _DEBUG
|
|
if (const char* dll_file = "3DTerrain_sd.dll")
|
|
#else
|
|
if (const char* dll_file = "3DTerrain_s.dll")
|
|
#endif
|
|
{
|
|
engine_.module_instance = ::Load3DTerrainLibrary(dll_file, &engine_.instance);
|
|
if (engine_.module_instance == NULL) {
|
|
SUNLOG(eCRITICAL_LOG, _T("|[%s]|Msg=%s file loading fails|"), dll_file);
|
|
return false;
|
|
};
|
|
engine_.load_helper = (CLoadHelper*)engine_.instance(CT_NEW_MAPLOADER, 0);
|
|
};
|
|
//
|
|
ns_world::PacketHandler::Instance();
|
|
//
|
|
parser_manager_ = new ns_world::WorldScriptParserManager;
|
|
parser_manager_->RegisterParser();
|
|
parser_manager_->InitParserPool(NULL);
|
|
#if !defined(__WAVERIX_SOLAR_AUTH_SERVER_IMPLEMENTATION__)
|
|
parser_manager_->Load();
|
|
//
|
|
this->StartServer();
|
|
#endif
|
|
|
|
SUNLOG(eCRITICAL_LOG, _T("*** WorldServer Start ***"));
|
|
SUNLOG(eCRITICAL_LOG, _T("*** WorldServer Server Version = %d ***"), SERVER_RELEASE_BUILD_NO);
|
|
|
|
return true;
|
|
}
|
|
|
|
BOOL ns_world::WorldServer::Update(DWORD delta_tick)
|
|
{
|
|
__UNUSED(delta_tick);
|
|
const util::ServerTimeInfoPerFrame& time_info = this->GetTimeInfoPerFrame();
|
|
//
|
|
WorkLoadManager::Update();
|
|
//
|
|
this->UpdateServices(time_info);
|
|
//
|
|
if (g_pSunLog) {
|
|
g_pSunLog->Update();
|
|
};
|
|
if (ns_world::count_log_global) {
|
|
ns_world::count_log_global->Update();
|
|
};
|
|
//
|
|
return true;
|
|
}
|
|
|
|
bool ns_world::WorldServer::UpdateServices(const util::ServerTimeInfoPerFrame& time_info)
|
|
{
|
|
if (ns_world::WorldUserManager* const user_manager = ns_world::WorldUserManager::Instance()) {
|
|
user_manager->UpdateServices(time_info, this->GetGameDBProxy());
|
|
};
|
|
//__NA_001359_20090619_HEIM_LOTTO_SYSTEM
|
|
if (connect_sessions_.dbproxy_enabled) {
|
|
Lotto::GetInstance().Update();
|
|
};
|
|
return true;
|
|
}
|
|
|
|
void ns_world::WorldServer::Release()
|
|
{
|
|
SUNLOG(eCRITICAL_LOG, _T("World Server Closing..."));
|
|
WorkLoadManager::DestroyInstance();
|
|
if (sequential_shutdown_service_)
|
|
{
|
|
sequential_shutdown_service_->Shutdown(sequential_shutdown_service_);
|
|
sequential_shutdown_service_ = NULL;
|
|
};
|
|
//
|
|
if (engine_.instance) {
|
|
engine_.instance(CT_DELETE_MAPLOADER, engine_.load_helper);
|
|
engine_.load_helper = NULL;
|
|
engine_.instance = NULL;
|
|
};
|
|
if (engine_.module_instance) {
|
|
::FreeLibrary(engine_.module_instance);
|
|
engine_.module_instance = NULL;
|
|
};
|
|
Lotto::GetInstance().Shutdown();
|
|
ns_world::WorldGuildManager::DestroyInstance();
|
|
//
|
|
if (parser_manager_)
|
|
{
|
|
parser_manager_->Release();
|
|
parser_manager_->DestroyInstanceEx();
|
|
delete parser_manager_;
|
|
};
|
|
//
|
|
SAFE_DELETE(ns_world::world_log);
|
|
SAFE_DELETE(g_pSunLog);
|
|
SAFE_DELETE(ns_world::count_log_global);
|
|
}
|
|
|
|
void ns_world::WorldServer::BroadcastNoticeFromFile()
|
|
{
|
|
// NOTE: f110823.1L, migrated from the original WorldServer.cpp
|
|
const char* const kNoticeFile = "Notice.txt";
|
|
// 파일에서 공지 읽기
|
|
FILE* file_handle = ::fopen(kNoticeFile, "rt");
|
|
if (file_handle == NULL)
|
|
{
|
|
SUNLOG(eCRITICAL_LOG, _T("Can't Open File %s"), kNoticeFile);
|
|
return;
|
|
};
|
|
//
|
|
MSG_CW_NOTICE_BRD msg_brd;
|
|
ZeroMemory(msg_brd.szMsg, sizeof(msg_brd.szMsg));
|
|
|
|
::fread(msg_brd.szMsg, sizeof(msg_brd.szMsg[0]), _countof(msg_brd.szMsg), file_handle);
|
|
::fclose(file_handle);
|
|
|
|
;{ // setup bradcasting message
|
|
msg_brd.m_byRed = 0xFF;
|
|
msg_brd.m_byGreen = 0xFF;
|
|
msg_brd.m_byBlue = 0xFF;
|
|
msg_brd.szMsg[_countof(msg_brd.szMsg) - 1] = '\0';
|
|
msg_brd.wLen = static_cast<WORD>(::strlen(msg_brd.szMsg) + 1);
|
|
};
|
|
// 전체 공지
|
|
if (ns_world::WorldUserManager* user_manager = ns_world::WorldUserManager::Instance()) {
|
|
user_manager->SendToAll(&msg_brd, msg_brd.GetSize());
|
|
};
|
|
SUNLOG(eCRITICAL_LOG, ">> WorldNotice(File): %s", msg_brd.szMsg);
|
|
}
|
|
|
|
//==================================================================================================
|
|
|
|
namespace ns_world { namespace internal {
|
|
;
|
|
static ulong LoadStatisticInterval();
|
|
static ulong LoadShoutInterval();
|
|
static bool LoadUseFileNoticeFunction();
|
|
|
|
}}; //end of namespace
|
|
|
|
static ulong ns_world::internal::LoadStatisticInterval()
|
|
{
|
|
int statistics_interval = 0;
|
|
__READ_CONFIG_NUMBER(statistics_interval, "INTERVAL", "STATISTICS",
|
|
10000, WORLD_SERVER_INFO_FILE_NAME);
|
|
return statistics_interval;
|
|
}
|
|
|
|
static ulong ns_world::internal::LoadShoutInterval()
|
|
{
|
|
int shout_interval = 0;
|
|
__READ_CONFIG_NUMBER(shout_interval, "INTERVAL", "SHOUT",
|
|
30000, WORLD_SERVER_INFO_FILE_NAME);
|
|
return shout_interval;
|
|
}
|
|
|
|
static bool ns_world::internal::LoadUseFileNoticeFunction()
|
|
{
|
|
int use_file_notice_function = 0;
|
|
__READ_CONFIG_NUMBER(use_file_notice_function, "COMMON", "NOTICEFROMFILE",
|
|
0, WORLD_SERVER_INFO_FILE_NAME);
|
|
return (use_file_notice_function != 0);
|
|
}
|
|
|
|
//==================================================================================================
|
|
|
|
bool ns_world::WorldServer::ReloadAdditionalConfig()
|
|
{
|
|
options_.statistics_interval = ns_world::internal::LoadStatisticInterval();
|
|
options_.shout_interval = ns_world::internal::LoadShoutInterval();
|
|
options_.use_file_notice_function = ns_world::internal::LoadUseFileNoticeFunction();
|
|
|
|
return true;
|
|
};
|
|
|
|
bool ns_world::WorldServer::InitializeLogger()
|
|
{
|
|
int log_option = 0;
|
|
int log_level = 0;
|
|
char log_file_path[256];
|
|
;{
|
|
__READ_CONFIG_NUMBER(log_option, "LOGFILE", "SUN_LOGFILE_OPTION",
|
|
OUTPUT_BOTH, WORLD_SERVER_INFO_FILE_NAME);
|
|
__READ_CONFIG_NUMBER(log_level, "LOGFILE", "SUN_LOGFILE_LEVEL",
|
|
eCRITICAL_LOG, WORLD_SERVER_INFO_FILE_NAME);
|
|
__READ_CONFIG_STRING(log_file_path, "LOGFILE", "SUN_LOGFILE_PATH",
|
|
NULL, WORLD_SERVER_INFO_FILE_NAME);
|
|
};
|
|
//
|
|
CONSOLELOG(eCRITICAL_LOG, _T("create server log"));
|
|
ASSERT(g_pSunLog == NULL);
|
|
g_pSunLog = new CSunLog;
|
|
if (g_pSunLog->Init(BYTE(log_option), BYTE(log_level),
|
|
log_file_path, "World") == false)
|
|
{
|
|
CONSOLELOG(eCRITICAL_LOG, _T("|["__FUNCTION__"]|Msg=can't create server log|"));
|
|
SAFE_DELETE(g_pSunLog);
|
|
return false;
|
|
};
|
|
//
|
|
CONSOLELOG(eCRITICAL_LOG, _T("create count log"));
|
|
ASSERT(count_log_global == NULL);
|
|
count_log_global = new CSunLog;
|
|
if (count_log_global->Init(BYTE(log_option), BYTE(log_level),
|
|
log_file_path, "WorldCount") == false)
|
|
{
|
|
SUNLOG(eCRITICAL_LOG, _T("|["__FUNCTION__"]|Msg=can't create count log|"));
|
|
SAFE_DELETE(count_log_global);
|
|
return false;
|
|
};
|
|
//
|
|
CONSOLELOG(eCRITICAL_LOG, _T("create game log"));
|
|
;{
|
|
__READ_CONFIG_NUMBER(log_option, "LOGFILE", "WOPS_LOGFILE_OPTION",
|
|
0, WORLD_SERVER_INFO_FILE_NAME);
|
|
__READ_CONFIG_STRING(log_file_path, "LOGFILE", "WOPS_LOGFILE_PATH",
|
|
"..\\Log", WORLD_SERVER_INFO_FILE_NAME);
|
|
};
|
|
if (log_option == 0)
|
|
{
|
|
CONSOLELOG(eCRITICAL_LOG, _T(" log option = 'don't write game log'"));
|
|
return true;
|
|
};
|
|
|
|
if (_access(log_file_path, 0) == -1)
|
|
{
|
|
if (::CreateDirectory(log_file_path, NULL) == false)
|
|
{
|
|
SUNLOG(eCRITICAL_LOG,
|
|
_T("|["__FUNCTION__"]|Msg=can't create gamelog directory = '%s'|"), log_file_path);
|
|
return false;
|
|
};
|
|
};
|
|
|
|
char full_bin_path[1024];
|
|
char full_text_path[1024];
|
|
_snprintf(full_bin_path, _countof(full_bin_path), "%s\\\\WORLD", log_file_path);
|
|
_snprintf(full_text_path, _countof(full_text_path), "%s\\\\WORLD_TEXT", log_file_path);
|
|
|
|
ns_world::world_log = new ns_world::WorldLog;
|
|
#ifdef __NA_0_ADD_VERSION_TO_LOG_FILE_NAME
|
|
char file_name[MAX_PATH];
|
|
_sntprintf(file_name, _countof(file_name), "%d_SUN_WORLD", NATION_BUILD_VERSION);
|
|
#else
|
|
char* file_name = "SUN_WORLD";
|
|
#endif
|
|
if (ns_world::world_log->Init(log_option, file_name, full_bin_path, full_text_path) == false)
|
|
{
|
|
SUNLOG(eCRITICAL_LOG, _T("|["__FUNCTION__"]|Msg=can't create game_log, ")
|
|
_T("path='%s', file_name='%s'|"), full_bin_path, file_name);
|
|
SAFE_DELETE(ns_world::world_log);
|
|
return false;
|
|
};
|
|
return true;
|
|
}
|
|
|
|
//==================================================================================================
|
|
|
|
void ns_world::WorldServer::StartServer()
|
|
{
|
|
static bool initialized_s = false;
|
|
ns_world::WorldServer* const this_ = ns_world::WorldServer::Instance();
|
|
__TOUCHED(this_);
|
|
if (initialized_s == false)
|
|
{
|
|
ns_world::WorldChannelManager* channel_manager = ns_world::WorldChannelManager::Instance();
|
|
if (FlowControl::FCAssert(channel_manager->LoadFieldInfo() != false) == false) {
|
|
SUNLOG(eCRITICAL_LOG, _T("|["__FUNCTION__"]|Msg=can't load field info|"));
|
|
};
|
|
#if WORLD_CONTENTS_BLOCK
|
|
#ifdef _APPLY_NHN_FILTERFING
|
|
int result = IAF::LoadAbuseDB();
|
|
// error handling?
|
|
if (result != 0)
|
|
{
|
|
SUNLOG(eCRITICAL_LOG, "Fail to load IAF LoadAbuseDB %d", result);
|
|
};
|
|
#endif
|
|
#endif
|
|
ns_world::FriendInvitationInWorld::Instance()->StartService();
|
|
initialized_s = true;
|
|
};
|
|
|
|
#ifdef __WAVERIX_SOLAR_AUTH_SERVER_IMPLEMENTATION__
|
|
;{
|
|
MSG_SERVERCOMMON_DATA_TRANSFER_SENDDATA_NTF msg_ntf;
|
|
if (ns_world::ServerSessionInWorld* session = this_->GetMasterServer())
|
|
{
|
|
session->SendPacket(&msg_ntf, sizeof(msg_ntf));
|
|
};
|
|
};
|
|
#endif
|
|
}
|
|
|
|
|
|
void ns_world::WorldServer::UpdateConnectSessionInfo(const MSG_MW_SERVER_INFO_CMD& msg_cmd)
|
|
{
|
|
server_key_ = msg_cmd.ServerKey;
|
|
this->UpdateAppTitle();
|
|
//
|
|
strncpy(connect_data_.dbproxy_ip_address, msg_cmd.m_szGameDBProxyServerIP,
|
|
_countof(connect_data_.dbproxy_ip_address));
|
|
connect_data_.dbproxy_ip_address[_countof(connect_data_.dbproxy_ip_address) - 1] = '\0';
|
|
connect_data_.dbproxy_port = msg_cmd.m_wGameDBProxyServerPort;
|
|
|
|
this->SetListenIP_s(msg_cmd.m_szWorldServerInnerIP);
|
|
this->SetListenPort_s(msg_cmd.m_wWorldServerInnerPort);
|
|
//
|
|
if (connect_sessions_.dbproxy_server == NULL)
|
|
{ // base interface
|
|
this->InitConnectSession(GAME_DBPROXY,
|
|
connect_data_.dbproxy_ip_address, connect_data_.dbproxy_port);
|
|
};
|
|
#ifdef __WAVERIX_SOLAR_AUTH_SERVER_IMPLEMENTATION__
|
|
#else
|
|
if (this->IsServerInfoFromFile() == false) {
|
|
this->Listen(SERVER_IOHANDLER);
|
|
};
|
|
#endif
|
|
}
|
|
|
|
//==================================================================================================
|
|
// ServerFrame interface
|
|
BOOL ns_world::WorldServer::KeyEvent(char ch)
|
|
{
|
|
switch (ch)
|
|
{
|
|
case 'N':
|
|
options_.use_file_notice_function = ns_world::internal::LoadUseFileNoticeFunction();
|
|
break;
|
|
case 0x1B:
|
|
if (sequential_shutdown_service_)
|
|
{
|
|
sequential_shutdown_service_->Shutdown(sequential_shutdown_service_);
|
|
sequential_shutdown_service_ = NULL;
|
|
};
|
|
return true;
|
|
};
|
|
|
|
return true;
|
|
}
|