#define _WIN32_WINNT 0x0501 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(CONF_FAMILY_WINDOWS) #define WIN32_LEAN_AND_MEAN #include #endif #include volatile sig_atomic_t InterruptSignaled = 0; bool IsInterrupted() { return InterruptSignaled; } void HandleSigIntTerm(int Param) { InterruptSignaled = 1; // Exit the next time a signal is received signal(SIGINT, SIG_DFL); signal(SIGTERM, SIG_DFL); } int main(int argc, const char **argv) { CCmdlineFix CmdlineFix(&argc, &argv); bool Silent = false; for(int i = 1; i < argc; i++) { if(str_comp("-s", argv[i]) == 0 || str_comp("--silent", argv[i]) == 0) { Silent = true; #if defined(CONF_FAMILY_WINDOWS) ShowWindow(GetConsoleWindow(), SW_HIDE); #endif break; } } #if defined(CONF_FAMILY_WINDOWS) CWindowsComLifecycle WindowsComLifecycle(false); #endif std::vector> vpLoggers; std::shared_ptr pStdoutLogger; #if defined(CONF_PLATFORM_ANDROID) pStdoutLogger = std::shared_ptr(log_logger_android()); #else if(!Silent) { pStdoutLogger = std::shared_ptr(log_logger_stdout()); } #endif if(pStdoutLogger) { vpLoggers.push_back(pStdoutLogger); } std::shared_ptr pFutureFileLogger = std::make_shared(); vpLoggers.push_back(pFutureFileLogger); std::shared_ptr pFutureConsoleLogger = std::make_shared(); vpLoggers.push_back(pFutureConsoleLogger); std::shared_ptr pFutureAssertionLogger = std::make_shared(); vpLoggers.push_back(pFutureAssertionLogger); log_set_global_logger(log_logger_collection(std::move(vpLoggers)).release()); if(secure_random_init() != 0) { dbg_msg("secure", "could not initialize secure RNG"); return -1; } if(MysqlInit() != 0) { dbg_msg("mysql", "failed to initialize MySQL library"); return -1; } signal(SIGINT, HandleSigIntTerm); signal(SIGTERM, HandleSigIntTerm); #if defined(CONF_EXCEPTION_HANDLING) init_exception_handler(); #endif CServer *pServer = CreateServer(); pServer->SetLoggers(pFutureFileLogger, std::move(pStdoutLogger)); IKernel *pKernel = IKernel::Create(); // create the components IEngine *pEngine = CreateEngine(GAME_NAME, pFutureConsoleLogger, 2); IEngineMap *pEngineMap = CreateEngineMap(); IGameServer *pGameServer = CreateGameServer(); IConsole *pConsole = CreateConsole(CFGFLAG_SERVER | CFGFLAG_ECON).release(); IStorage *pStorage = CreateStorage(IStorage::STORAGETYPE_SERVER, argc, argv); IConfigManager *pConfigManager = CreateConfigManager(); IEngineAntibot *pEngineAntibot = CreateEngineAntibot(); pFutureAssertionLogger->Set(CreateAssertionLogger(pStorage, GAME_NAME)); #if defined(CONF_EXCEPTION_HANDLING) char aBuf[IO_MAX_PATH_LENGTH]; char aBufName[IO_MAX_PATH_LENGTH]; char aDate[64]; str_timestamp(aDate, sizeof(aDate)); str_format(aBufName, sizeof(aBufName), "dumps/" GAME_NAME "-Server_%s_crash_log_%s_%d_%s.RTP", CONF_PLATFORM_STRING, aDate, pid(), GIT_SHORTREV_HASH != nullptr ? GIT_SHORTREV_HASH : ""); pStorage->GetCompletePath(IStorage::TYPE_SAVE, aBufName, aBuf, sizeof(aBuf)); set_exception_handler_log_file(aBuf); #endif { bool RegisterFail = false; RegisterFail = RegisterFail || !pKernel->RegisterInterface(pServer); RegisterFail = RegisterFail || !pKernel->RegisterInterface(pEngine); RegisterFail = RegisterFail || !pKernel->RegisterInterface(pEngineMap); // register as both RegisterFail = RegisterFail || !pKernel->RegisterInterface(static_cast(pEngineMap), false); RegisterFail = RegisterFail || !pKernel->RegisterInterface(pGameServer); RegisterFail = RegisterFail || !pKernel->RegisterInterface(pConsole); RegisterFail = RegisterFail || !pKernel->RegisterInterface(pStorage); RegisterFail = RegisterFail || !pKernel->RegisterInterface(pConfigManager); RegisterFail = RegisterFail || !pKernel->RegisterInterface(pEngineAntibot); RegisterFail = RegisterFail || !pKernel->RegisterInterface(static_cast(pEngineAntibot), false); if(RegisterFail) { delete pKernel; return -1; } } pEngine->Init(); pConfigManager->Init(); pConsole->Init(); // register all console commands pServer->RegisterCommands(); // execute autoexec file if(pStorage->FileExists(AUTOEXEC_SERVER_FILE, IStorage::TYPE_ALL)) { pConsole->ExecuteFile(AUTOEXEC_SERVER_FILE); } else // fallback { pConsole->ExecuteFile(AUTOEXEC_FILE); } // parse the command line arguments if(argc > 1) pConsole->ParseArguments(argc - 1, &argv[1]); pConsole->Register("sv_test_cmds", "", CFGFLAG_SERVER, CServer::ConTestingCommands, pConsole, "Turns testing commands aka cheats on/off (setting only works in initial config)"); pConsole->Register("sv_rescue", "", CFGFLAG_SERVER, CServer::ConRescue, pConsole, "Allow /rescue command so players can teleport themselves out of freeze (setting only works in initial config)"); const int Mode = g_Config.m_Logappend ? IOFLAG_APPEND : IOFLAG_WRITE; if(g_Config.m_Logfile[0]) { IOHANDLE Logfile = pStorage->OpenFile(g_Config.m_Logfile, Mode, IStorage::TYPE_SAVE_OR_ABSOLUTE); if(Logfile) { pFutureFileLogger->Set(log_logger_file(Logfile)); } else { dbg_msg("server", "failed to open '%s' for logging", g_Config.m_Logfile); } } auto pServerLogger = std::make_shared(pServer); pEngine->SetAdditionalLogger(pServerLogger); // run the server dbg_msg("server", "starting..."); int Ret = pServer->Run(); pServerLogger->OnServerDeletion(); // free delete pKernel; MysqlUninit(); secure_random_uninit(); return Ret; }