1#include <base/logger.h>
2#include <base/system.h>
3
4#include <engine/console.h>
5#include <engine/engine.h>
6#include <engine/map.h>
7#include <engine/server.h>
8#include <engine/storage.h>
9
10#include <engine/server/antibot.h>
11#include <engine/server/databases/connection.h>
12#include <engine/server/server.h>
13#include <engine/server/server_logger.h>
14
15#include <engine/shared/assertion_logger.h>
16#include <engine/shared/config.h>
17
18#include <game/version.h>
19
20#include <vector>
21
22#if defined(CONF_FAMILY_WINDOWS)
23#include <windows.h>
24#endif
25
26#include <csignal>
27
28volatile sig_atomic_t InterruptSignaled = 0;
29
30bool IsInterrupted()
31{
32 return InterruptSignaled;
33}
34
35void HandleSigIntTerm(int Param)
36{
37 InterruptSignaled = 1;
38
39 // Exit the next time a signal is received
40 signal(SIGINT, SIG_DFL);
41 signal(SIGTERM, SIG_DFL);
42}
43
44int main(int argc, const char **argv)
45{
46 const int64_t MainStart = time_get();
47
48 CCmdlineFix CmdlineFix(&argc, &argv);
49 bool Silent = false;
50
51 for(int i = 1; i < argc; i++)
52 {
53 if(str_comp(a: "-s", b: argv[i]) == 0 || str_comp(a: "--silent", b: argv[i]) == 0)
54 {
55 Silent = true;
56#if defined(CONF_FAMILY_WINDOWS)
57 ShowWindow(GetConsoleWindow(), SW_HIDE);
58#endif
59 break;
60 }
61 }
62
63#if defined(CONF_FAMILY_WINDOWS)
64 CWindowsComLifecycle WindowsComLifecycle(false);
65#endif
66
67 std::vector<std::shared_ptr<ILogger>> vpLoggers;
68 std::shared_ptr<ILogger> pStdoutLogger;
69#if defined(CONF_PLATFORM_ANDROID)
70 pStdoutLogger = std::shared_ptr<ILogger>(log_logger_android());
71#else
72 if(!Silent)
73 {
74 pStdoutLogger = std::shared_ptr<ILogger>(log_logger_stdout());
75 }
76#endif
77 if(pStdoutLogger)
78 {
79 vpLoggers.push_back(x: pStdoutLogger);
80 }
81 std::shared_ptr<CFutureLogger> pFutureFileLogger = std::make_shared<CFutureLogger>();
82 vpLoggers.push_back(x: pFutureFileLogger);
83 std::shared_ptr<CFutureLogger> pFutureConsoleLogger = std::make_shared<CFutureLogger>();
84 vpLoggers.push_back(x: pFutureConsoleLogger);
85 std::shared_ptr<CFutureLogger> pFutureAssertionLogger = std::make_shared<CFutureLogger>();
86 vpLoggers.push_back(x: pFutureAssertionLogger);
87 log_set_global_logger(logger: log_logger_collection(vpLoggers: std::move(vpLoggers)).release());
88
89 if(secure_random_init() != 0)
90 {
91 log_error("secure", "could not initialize secure RNG");
92 return -1;
93 }
94 if(MysqlInit() != 0)
95 {
96 log_error("mysql", "failed to initialize MySQL library");
97 return -1;
98 }
99
100 signal(SIGINT, handler: HandleSigIntTerm);
101 signal(SIGTERM, handler: HandleSigIntTerm);
102
103#if defined(CONF_EXCEPTION_HANDLING)
104 init_exception_handler();
105#endif
106
107 CServer *pServer = CreateServer();
108 pServer->SetLoggers(pFileLogger: pFutureFileLogger, pStdoutLogger: std::move(pStdoutLogger));
109
110 IKernel *pKernel = IKernel::Create();
111 pKernel->RegisterInterface(pInterface: pServer);
112
113 // create the components
114 IEngine *pEngine = CreateEngine(GAME_NAME, pFutureLogger: pFutureConsoleLogger, Jobs: 2 * std::thread::hardware_concurrency() + 2);
115 pKernel->RegisterInterface(pInterface: pEngine);
116
117 IStorage *pStorage = CreateStorage(StorageType: IStorage::STORAGETYPE_SERVER, NumArgs: argc, ppArguments: argv);
118 pKernel->RegisterInterface(pInterface: pStorage);
119
120 pFutureAssertionLogger->Set(CreateAssertionLogger(pStorage, GAME_NAME));
121
122#if defined(CONF_EXCEPTION_HANDLING)
123 char aBuf[IO_MAX_PATH_LENGTH];
124 char aBufName[IO_MAX_PATH_LENGTH];
125 char aDate[64];
126 str_timestamp(aDate, sizeof(aDate));
127 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 : "");
128 pStorage->GetCompletePath(IStorage::TYPE_SAVE, aBufName, aBuf, sizeof(aBuf));
129 set_exception_handler_log_file(aBuf);
130#endif
131
132 IConsole *pConsole = CreateConsole(FlagMask: CFGFLAG_SERVER | CFGFLAG_ECON).release();
133 pKernel->RegisterInterface(pInterface: pConsole);
134
135 IConfigManager *pConfigManager = CreateConfigManager();
136 pKernel->RegisterInterface(pInterface: pConfigManager);
137
138 IEngineMap *pEngineMap = CreateEngineMap();
139 pKernel->RegisterInterface(pInterface: pEngineMap); // IEngineMap
140 pKernel->RegisterInterface(pInterface: static_cast<IMap *>(pEngineMap), Destroy: false);
141
142 IEngineAntibot *pEngineAntibot = CreateEngineAntibot();
143 pKernel->RegisterInterface(pInterface: pEngineAntibot); // IEngineAntibot
144 pKernel->RegisterInterface(pInterface: static_cast<IAntibot *>(pEngineAntibot), Destroy: false);
145
146 IGameServer *pGameServer = CreateGameServer();
147 pKernel->RegisterInterface(pInterface: pGameServer);
148
149 pEngine->Init();
150 pConsole->Init();
151 pConfigManager->Init();
152
153 // register all console commands
154 pServer->RegisterCommands();
155
156 // execute autoexec file
157 if(pStorage->FileExists(AUTOEXEC_SERVER_FILE, Type: IStorage::TYPE_ALL))
158 {
159 pConsole->ExecuteFile(AUTOEXEC_SERVER_FILE);
160 }
161 else // fallback
162 {
163 pConsole->ExecuteFile(AUTOEXEC_FILE);
164 }
165
166 // parse the command line arguments
167 if(argc > 1)
168 pConsole->ParseArguments(NumArgs: argc - 1, ppArguments: &argv[1]);
169
170 pConfigManager->SetReadOnly(pScriptName: "sv_test_cmds", ReadOnly: true);
171 pConfigManager->SetReadOnly(pScriptName: "sv_rescue", ReadOnly: true);
172
173 if(g_Config.m_Logfile[0])
174 {
175 const int Mode = g_Config.m_Logappend ? IOFLAG_APPEND : IOFLAG_WRITE;
176 IOHANDLE Logfile = pStorage->OpenFile(pFilename: g_Config.m_Logfile, Flags: Mode, Type: IStorage::TYPE_SAVE_OR_ABSOLUTE);
177 if(Logfile)
178 {
179 pFutureFileLogger->Set(log_logger_file(file: Logfile));
180 }
181 else
182 {
183 log_error("server", "failed to open '%s' for logging", g_Config.m_Logfile);
184 pFutureFileLogger->Set(log_logger_noop());
185 }
186 }
187 else
188 {
189 pFutureFileLogger->Set(log_logger_noop());
190 }
191
192 auto pServerLogger = std::make_shared<CServerLogger>(args&: pServer);
193 pEngine->SetAdditionalLogger(pServerLogger);
194
195 // run the server
196 log_trace("server", "initialization finished after %.2fms, starting...", (time_get() - MainStart) * 1000.0f / (float)time_freq());
197 int Ret = pServer->Run();
198
199 pServerLogger->OnServerDeletion();
200 // free
201 delete pKernel;
202
203 MysqlUninit();
204 secure_random_uninit();
205
206 return Ret;
207}
208