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 | |
28 | volatile sig_atomic_t InterruptSignaled = 0; |
29 | |
30 | bool IsInterrupted() |
31 | { |
32 | return InterruptSignaled; |
33 | } |
34 | |
35 | void 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 | |
44 | int 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 | |