mirror of
https://github.com/BeamMP/BeamMP-Server.git
synced 2026-05-19 16:10:41 +00:00
@@ -8,6 +8,8 @@ project(BeamMP-Server
|
|||||||
HOMEPAGE_URL https://beammp.com
|
HOMEPAGE_URL https://beammp.com
|
||||||
LANGUAGES CXX C)
|
LANGUAGES CXX C)
|
||||||
|
|
||||||
|
set(HTTPLIB_REQUIRE_OPENSSL ON)
|
||||||
|
|
||||||
include_directories("${PROJECT_SOURCE_DIR}/deps/asio/asio/include")
|
include_directories("${PROJECT_SOURCE_DIR}/deps/asio/asio/include")
|
||||||
include_directories("${PROJECT_SOURCE_DIR}/deps/rapidjson/include")
|
include_directories("${PROJECT_SOURCE_DIR}/deps/rapidjson/include")
|
||||||
include_directories("${PROJECT_SOURCE_DIR}/deps/websocketpp")
|
include_directories("${PROJECT_SOURCE_DIR}/deps/websocketpp")
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
# v3.0.1
|
||||||
|
|
||||||
|
- ADDED Backup URLs to UpdateCheck (will fail less often now)
|
||||||
|
- FIXED a bug where, when run with --working-directory, the Server.log would still be in the original directory
|
||||||
|
- FIXED a bug which could cause the plugin reload thread to spin at 100% if the reloaded plugin's didn't terminate
|
||||||
|
|
||||||
# v3.0.0
|
# v3.0.0
|
||||||
|
|
||||||
- CHANGED entire plugin Lua implementation (rewrite)
|
- CHANGED entire plugin Lua implementation (rewrite)
|
||||||
|
|||||||
Vendored
+1
-1
Submodule deps/commandline updated: 3d11606d02...0d3e1073c1
Vendored
+1
-1
Submodule deps/cpp-httplib updated: 301faa074c...b324921c1a
+9
-4
@@ -74,10 +74,15 @@ public:
|
|||||||
|
|
||||||
static TSettings Settings;
|
static TSettings Settings;
|
||||||
|
|
||||||
|
static std::vector<std::string> GetBackendUrlsInOrder() {
|
||||||
|
return {
|
||||||
|
"backend.beammp.com",
|
||||||
|
"backup1.beammp.com",
|
||||||
|
"backup2.beammp.com"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
static std::string GetBackendUrlForAuth() { return "auth.beammp.com"; }
|
static std::string GetBackendUrlForAuth() { return "auth.beammp.com"; }
|
||||||
static std::string GetBackendHostname() { return "backend.beammp.com"; }
|
|
||||||
static std::string GetBackup1Hostname() { return "backup1.beammp.com"; }
|
|
||||||
static std::string GetBackup2Hostname() { return "backup2.beammp.com"; }
|
|
||||||
static std::string GetBackendUrlForSocketIO() { return "https://backend.beammp.com"; }
|
static std::string GetBackendUrlForSocketIO() { return "https://backend.beammp.com"; }
|
||||||
static void CheckForUpdates();
|
static void CheckForUpdates();
|
||||||
static std::array<uint8_t, 3> VersionStrToInts(const std::string& str);
|
static std::array<uint8_t, 3> VersionStrToInts(const std::string& str);
|
||||||
@@ -114,7 +119,7 @@ private:
|
|||||||
static inline std::mutex mShutdownHandlersMutex {};
|
static inline std::mutex mShutdownHandlersMutex {};
|
||||||
static inline std::deque<TShutdownHandler> mShutdownHandlers {};
|
static inline std::deque<TShutdownHandler> mShutdownHandlers {};
|
||||||
|
|
||||||
static inline Version mVersion { 3, 0, 0 };
|
static inline Version mVersion { 3, 0, 1 };
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string ThreadName(bool DebugModeOverride = false);
|
std::string ThreadName(bool DebugModeOverride = false);
|
||||||
|
|||||||
+1
-1
@@ -25,7 +25,7 @@ constexpr size_t RSA_DEFAULT_KEYLENGTH { 2048 };
|
|||||||
|
|
||||||
namespace Http {
|
namespace Http {
|
||||||
std::string GET(const std::string& host, int port, const std::string& target, unsigned int* status = nullptr);
|
std::string GET(const std::string& host, int port, const std::string& target, unsigned int* status = nullptr);
|
||||||
std::string POST(const std::string& host, int port, const std::string& target, const std::string& body, const std::string& ContentType, unsigned int* status = nullptr);
|
std::string POST(const std::string& host, int port, const std::string& target, const std::string& body, const std::string& ContentType, unsigned int* status = nullptr, const httplib::Headers& headers = {});
|
||||||
namespace Status {
|
namespace Status {
|
||||||
std::string ToString(int code);
|
std::string ToString(int code);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -149,6 +149,7 @@ public:
|
|||||||
void CancelEventTimers(const std::string& EventName, TLuaStateId StateId);
|
void CancelEventTimers(const std::string& EventName, TLuaStateId StateId);
|
||||||
sol::state_view GetStateForPlugin(const fs::path& PluginPath);
|
sol::state_view GetStateForPlugin(const fs::path& PluginPath);
|
||||||
TLuaStateId GetStateIDForPlugin(const fs::path& PluginPath);
|
TLuaStateId GetStateIDForPlugin(const fs::path& PluginPath);
|
||||||
|
void AddResultToCheck(const std::shared_ptr<TLuaResult>& Result);
|
||||||
|
|
||||||
static constexpr const char* BeamMPFnNotFoundError = "BEAMMP_FN_NOT_FOUND";
|
static constexpr const char* BeamMPFnNotFoundError = "BEAMMP_FN_NOT_FOUND";
|
||||||
|
|
||||||
|
|||||||
+8
-2
@@ -99,7 +99,8 @@ void Application::CheckForUpdates() {
|
|||||||
Application::SetSubsystemStatus("UpdateCheck", Application::Status::Starting);
|
Application::SetSubsystemStatus("UpdateCheck", Application::Status::Starting);
|
||||||
// checks current version against latest version
|
// checks current version against latest version
|
||||||
std::regex VersionRegex { R"(\d+\.\d+\.\d+\n*)" };
|
std::regex VersionRegex { R"(\d+\.\d+\.\d+\n*)" };
|
||||||
auto Response = Http::GET(GetBackendHostname(), 443, "/v/s");
|
for (const auto& url : GetBackendUrlsInOrder()) {
|
||||||
|
auto Response = Http::GET(GetBackendUrlsInOrder().at(0), 443, "/v/s");
|
||||||
bool Matches = std::regex_match(Response, VersionRegex);
|
bool Matches = std::regex_match(Response, VersionRegex);
|
||||||
if (Matches) {
|
if (Matches) {
|
||||||
auto MyVersion = ServerVersion();
|
auto MyVersion = ServerVersion();
|
||||||
@@ -111,14 +112,19 @@ void Application::CheckForUpdates() {
|
|||||||
beammp_info("Server up-to-date!");
|
beammp_info("Server up-to-date!");
|
||||||
}
|
}
|
||||||
Application::SetSubsystemStatus("UpdateCheck", Application::Status::Good);
|
Application::SetSubsystemStatus("UpdateCheck", Application::Status::Good);
|
||||||
|
break;
|
||||||
} else {
|
} else {
|
||||||
beammp_warn("Unable to fetch version from backend.");
|
beammp_debug("Failed to fetch version from: " + url);
|
||||||
beammp_trace("got " + Response);
|
beammp_trace("got " + Response);
|
||||||
auto Lock = Sentry.CreateExclusiveContext();
|
auto Lock = Sentry.CreateExclusiveContext();
|
||||||
Sentry.SetContext("get-response", { { "response", Response } });
|
Sentry.SetContext("get-response", { { "response", Response } });
|
||||||
Sentry.LogError("failed to get server version", _file_basename, _line);
|
Sentry.LogError("failed to get server version", _file_basename, _line);
|
||||||
Application::SetSubsystemStatus("UpdateCheck", Application::Status::Bad);
|
Application::SetSubsystemStatus("UpdateCheck", Application::Status::Bad);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (Application::GetSubsystemStatuses().at("UpdateCheck") == Application::Status::Bad) {
|
||||||
|
beammp_warn("Unable to fetch version info from backend.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// thread name stuff
|
// thread name stuff
|
||||||
|
|||||||
+6
-2
@@ -4,6 +4,7 @@
|
|||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "CustomAssert.h"
|
#include "CustomAssert.h"
|
||||||
#include "LuaAPI.h"
|
#include "LuaAPI.h"
|
||||||
|
#include "httplib.h"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <random>
|
#include <random>
|
||||||
@@ -33,17 +34,20 @@ std::string Http::GET(const std::string& host, int port, const std::string& targ
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Http::POST(const std::string& host, int port, const std::string& target, const std::string& body, const std::string& ContentType, unsigned int* status) {
|
std::string Http::POST(const std::string& host, int port, const std::string& target, const std::string& body, const std::string& ContentType, unsigned int* status, const httplib::Headers& headers) {
|
||||||
httplib::SSLClient client(host, port);
|
httplib::SSLClient client(host, port);
|
||||||
|
client.set_read_timeout(std::chrono::seconds(10));
|
||||||
|
beammp_assert(client.is_valid());
|
||||||
client.enable_server_certificate_verification(false);
|
client.enable_server_certificate_verification(false);
|
||||||
client.set_address_family(AF_INET);
|
client.set_address_family(AF_INET);
|
||||||
auto res = client.Post(target.c_str(), body.c_str(), body.size(), ContentType.c_str());
|
auto res = client.Post(target.c_str(), headers, body.c_str(), body.size(), ContentType.c_str());
|
||||||
if (res) {
|
if (res) {
|
||||||
if (status) {
|
if (status) {
|
||||||
*status = res->status;
|
*status = res->status;
|
||||||
}
|
}
|
||||||
return res->body;
|
return res->body;
|
||||||
} else {
|
} else {
|
||||||
|
beammp_debug("POST failed: " + httplib::to_string(res.error()));
|
||||||
return Http::ErrorString;
|
return Http::ErrorString;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -386,7 +386,7 @@ TConsole::TConsole() {
|
|||||||
} else {
|
} else {
|
||||||
auto Future = mLuaEngine->EnqueueScript(mStateId, { std::make_shared<std::string>(cmd), "", "" });
|
auto Future = mLuaEngine->EnqueueScript(mStateId, { std::make_shared<std::string>(cmd), "", "" });
|
||||||
while (!Future->Ready) {
|
while (!Future->Ready) {
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // TODO: Add a timeout
|
std::this_thread::yield(); // TODO: Add a timeout
|
||||||
}
|
}
|
||||||
if (Future->Error) {
|
if (Future->Error) {
|
||||||
beammp_lua_error(Future->ErrorMessage);
|
beammp_lua_error(Future->ErrorMessage);
|
||||||
|
|||||||
+54
-24
@@ -54,41 +54,71 @@ void THeartbeatThread::operator()() {
|
|||||||
|
|
||||||
auto Target = "/heartbeat";
|
auto Target = "/heartbeat";
|
||||||
unsigned int ResponseCode = 0;
|
unsigned int ResponseCode = 0;
|
||||||
T = Http::POST(Application::GetBackendHostname(), 443, Target, Body, "application/x-www-form-urlencoded", &ResponseCode);
|
|
||||||
|
|
||||||
if ((T.substr(0, 2) != "20" && ResponseCode != 200) || ResponseCode != 200) {
|
json::Document Doc;
|
||||||
beammp_trace("got " + T + " from backend");
|
bool Ok = false;
|
||||||
Application::SetSubsystemStatus("Heartbeat", Application::Status::Bad);
|
for (const auto& Url : Application::GetBackendUrlsInOrder()) {
|
||||||
SentryReportError(Application::GetBackendHostname() + Target, ResponseCode);
|
T = Http::POST(Url, 443, Target, Body, "application/x-www-form-urlencoded", &ResponseCode, { { "api-v", "2" } });
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
beammp_trace(T);
|
||||||
T = Http::POST(Application::GetBackup1Hostname(), 443, Target, Body, "application/x-www-form-urlencoded", &ResponseCode);
|
Doc.Parse(T.data(), T.size());
|
||||||
if ((T.substr(0, 2) != "20" && ResponseCode != 200) || ResponseCode != 200) {
|
if (Doc.HasParseError() || !Doc.IsObject()) {
|
||||||
SentryReportError(Application::GetBackup1Hostname() + Target, ResponseCode);
|
beammp_error("Backend response failed to parse as valid json");
|
||||||
Application::SetSubsystemStatus("Heartbeat", Application::Status::Bad);
|
beammp_debug("Response was: `" + T + "`");
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
Sentry.SetContext("JSON Response", { { "reponse", T } });
|
||||||
T = Http::POST(Application::GetBackup2Hostname(), 443, Target, Body, "application/x-www-form-urlencoded", &ResponseCode);
|
SentryReportError(Url + Target, ResponseCode);
|
||||||
if ((T.substr(0, 2) != "20" && ResponseCode != 200) || ResponseCode != 200) {
|
} else if (ResponseCode != 200) {
|
||||||
beammp_warn("Backend system refused server! Server will not show in the public server list.");
|
SentryReportError(Url + Target, ResponseCode);
|
||||||
Application::SetSubsystemStatus("Heartbeat", Application::Status::Bad);
|
|
||||||
isAuth = false;
|
|
||||||
SentryReportError(Application::GetBackup2Hostname() + Target, ResponseCode);
|
|
||||||
} else {
|
} else {
|
||||||
Application::SetSubsystemStatus("Heartbeat", Application::Status::Good);
|
// all ok
|
||||||
|
Ok = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||||
Application::SetSubsystemStatus("Heartbeat", Application::Status::Good);
|
|
||||||
}
|
}
|
||||||
|
std::string Status {};
|
||||||
|
std::string Code {};
|
||||||
|
std::string Message {};
|
||||||
|
const auto StatusKey = "status";
|
||||||
|
const auto CodeKey = "code";
|
||||||
|
const auto MessageKey = "msg";
|
||||||
|
|
||||||
|
if (Ok) {
|
||||||
|
if (Doc.HasMember(StatusKey) && Doc[StatusKey].IsString()) {
|
||||||
|
Status = Doc[StatusKey].GetString();
|
||||||
} else {
|
} else {
|
||||||
Application::SetSubsystemStatus("Heartbeat", Application::Status::Good);
|
Sentry.SetContext("JSON Response", { { StatusKey, "invalid string / missing" } });
|
||||||
|
Ok = false;
|
||||||
|
}
|
||||||
|
if (Doc.HasMember(CodeKey) && Doc[CodeKey].IsString()) {
|
||||||
|
Code = Doc[CodeKey].GetString();
|
||||||
|
} else {
|
||||||
|
Sentry.SetContext("JSON Response", { { CodeKey, "invalid string / missing" } });
|
||||||
|
Ok = false;
|
||||||
|
}
|
||||||
|
if (Doc.HasMember(MessageKey) && Doc[MessageKey].IsString()) {
|
||||||
|
Message = Doc[MessageKey].GetString();
|
||||||
|
} else {
|
||||||
|
Sentry.SetContext("JSON Response", { { MessageKey, "invalid string / missing" } });
|
||||||
|
Ok = false;
|
||||||
|
}
|
||||||
|
if (!Ok) {
|
||||||
|
beammp_error("Missing/invalid json members in backend response");
|
||||||
|
Sentry.LogError("Missing/invalid json members in backend response", __FILE__, std::to_string(__LINE__));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isAuth) {
|
if (Ok && !isAuth) {
|
||||||
if (T == "2000") {
|
if (Status == "2000") {
|
||||||
beammp_info(("Authenticated!"));
|
beammp_info(("Authenticated!"));
|
||||||
isAuth = true;
|
isAuth = true;
|
||||||
} else if (T == "200") {
|
} else if (Status == "200") {
|
||||||
beammp_info(("Resumed authenticated session!"));
|
beammp_info(("Resumed authenticated session!"));
|
||||||
isAuth = true;
|
isAuth = true;
|
||||||
|
} else {
|
||||||
|
if (Message.empty()) {
|
||||||
|
Message = "Backend didn't provide a reason";
|
||||||
|
}
|
||||||
|
beammp_error("Backend REFUSED the auth key. " + Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-17
@@ -54,25 +54,17 @@ void TLuaEngine::operator()() {
|
|||||||
auto ResultCheckThread = std::thread([&] {
|
auto ResultCheckThread = std::thread([&] {
|
||||||
RegisterThread("ResultCheckThread");
|
RegisterThread("ResultCheckThread");
|
||||||
while (!mShutdown) {
|
while (!mShutdown) {
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
std::unique_lock Lock(mResultsToCheckMutex);
|
std::unique_lock Lock(mResultsToCheckMutex);
|
||||||
if (!mResultsToCheck.empty()) {
|
if (!mResultsToCheck.empty()) {
|
||||||
auto Res = mResultsToCheck.front();
|
auto Res = mResultsToCheck.front();
|
||||||
mResultsToCheck.pop();
|
mResultsToCheck.pop();
|
||||||
Lock.unlock();
|
Lock.unlock();
|
||||||
|
|
||||||
size_t Waited = 0;
|
if (!Res->Ready) {
|
||||||
while (!Res->Ready) {
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
|
||||||
Waited++;
|
|
||||||
if (Waited > 250) {
|
|
||||||
// FIXME: This should *eventually* timeout.
|
|
||||||
// beammp_lua_error(Res->Function + " in " + Res->StateId + " took >1s to respond, not printing possible errors");
|
|
||||||
Lock.lock();
|
Lock.lock();
|
||||||
mResultsToCheck.push(Res);
|
mResultsToCheck.push(Res);
|
||||||
Lock.unlock();
|
Lock.unlock();
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (Res->Error) {
|
if (Res->Error) {
|
||||||
if (Res->ErrorMessage != BeamMPFnNotFoundError) {
|
if (Res->ErrorMessage != BeamMPFnNotFoundError) {
|
||||||
@@ -80,13 +72,14 @@ void TLuaEngine::operator()() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
std::this_thread::yield();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// event loop
|
// event loop
|
||||||
auto Before = std::chrono::high_resolution_clock::now();
|
auto Before = std::chrono::high_resolution_clock::now();
|
||||||
while (!mShutdown) {
|
while (!mShutdown) {
|
||||||
if (mLuaStates.size() == 0) {
|
if (mLuaStates.size() == 0) {
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(500));
|
std::this_thread::sleep_for(std::chrono::seconds(100));
|
||||||
}
|
}
|
||||||
{ // Timed Events Scope
|
{ // Timed Events Scope
|
||||||
std::unique_lock Lock(mTimedEventsMutex);
|
std::unique_lock Lock(mTimedEventsMutex);
|
||||||
@@ -149,6 +142,11 @@ TLuaStateId TLuaEngine::GetStateIDForPlugin(const fs::path& PluginPath) {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TLuaEngine::AddResultToCheck(const std::shared_ptr<TLuaResult>& Result) {
|
||||||
|
std::unique_lock Lock(mResultsToCheckMutex);
|
||||||
|
mResultsToCheck.push(Result);
|
||||||
|
}
|
||||||
|
|
||||||
void TLuaEngine::WaitForAll(std::vector<std::shared_ptr<TLuaResult>>& Results, const std::optional<std::chrono::high_resolution_clock::duration>& Max) {
|
void TLuaEngine::WaitForAll(std::vector<std::shared_ptr<TLuaResult>>& Results, const std::optional<std::chrono::high_resolution_clock::duration>& Max) {
|
||||||
for (const auto& Result : Results) {
|
for (const auto& Result : Results) {
|
||||||
bool Cancelled = false;
|
bool Cancelled = false;
|
||||||
@@ -705,6 +703,7 @@ void TLuaEngine::StateThreadData::AddPath(const fs::path& Path) {
|
|||||||
|
|
||||||
void TLuaResult::WaitUntilReady() {
|
void TLuaResult::WaitUntilReady() {
|
||||||
while (!Ready) {
|
while (!Ready) {
|
||||||
|
std::this_thread::yield();
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -762,12 +761,7 @@ void TPluginMonitor::operator()() {
|
|||||||
auto StateID = mEngine.GetStateIDForPlugin(fs::path(Pair.first).parent_path());
|
auto StateID = mEngine.GetStateIDForPlugin(fs::path(Pair.first).parent_path());
|
||||||
auto Res = mEngine.EnqueueScript(StateID, Chunk);
|
auto Res = mEngine.EnqueueScript(StateID, Chunk);
|
||||||
// TODO: call onInit
|
// TODO: call onInit
|
||||||
while (!Res->Ready) {
|
mEngine.AddResultToCheck(Res);
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
|
||||||
}
|
|
||||||
if (Res->Error) {
|
|
||||||
beammp_lua_error(Res->ErrorMessage);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// TODO: trigger onFileChanged event
|
// TODO: trigger onFileChanged event
|
||||||
beammp_trace("Change detected in file \"" + Pair.first + "\", event trigger not implemented yet");
|
beammp_trace("Change detected in file \"" + Pair.first + "\", event trigger not implemented yet");
|
||||||
|
|||||||
+2
-2
@@ -21,8 +21,8 @@ TPPSMonitor::TPPSMonitor(TServer& Server)
|
|||||||
void TPPSMonitor::operator()() {
|
void TPPSMonitor::operator()() {
|
||||||
RegisterThread("PPSMonitor");
|
RegisterThread("PPSMonitor");
|
||||||
while (!mNetwork) {
|
while (!mNetwork) {
|
||||||
// hard spi
|
// hard(-ish) spin
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
std::this_thread::yield();
|
||||||
}
|
}
|
||||||
beammp_debug("PPSMonitor starting");
|
beammp_debug("PPSMonitor starting");
|
||||||
Application::SetSubsystemStatus("PPSMonitor", Application::Status::Good);
|
Application::SetSubsystemStatus("PPSMonitor", Application::Status::Good);
|
||||||
|
|||||||
+5
-5
@@ -77,11 +77,6 @@ int main(int argc, char** argv) {
|
|||||||
|
|
||||||
int BeamMPServerMain(MainArguments Arguments) {
|
int BeamMPServerMain(MainArguments Arguments) {
|
||||||
setlocale(LC_ALL, "C");
|
setlocale(LC_ALL, "C");
|
||||||
Application::InitializeConsole();
|
|
||||||
Application::SetSubsystemStatus("Main", Application::Status::Starting);
|
|
||||||
|
|
||||||
SetupSignalHandlers();
|
|
||||||
|
|
||||||
ArgsParser Parser;
|
ArgsParser Parser;
|
||||||
Parser.RegisterArgument({ "help" }, ArgsParser::NONE);
|
Parser.RegisterArgument({ "help" }, ArgsParser::NONE);
|
||||||
Parser.RegisterArgument({ "version" }, ArgsParser::NONE);
|
Parser.RegisterArgument({ "version" }, ArgsParser::NONE);
|
||||||
@@ -122,6 +117,11 @@ int BeamMPServerMain(MainArguments Arguments) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Application::InitializeConsole();
|
||||||
|
Application::SetSubsystemStatus("Main", Application::Status::Starting);
|
||||||
|
|
||||||
|
SetupSignalHandlers();
|
||||||
|
|
||||||
bool Shutdown = false;
|
bool Shutdown = false;
|
||||||
Application::RegisterShutdownHandler([&Shutdown] {
|
Application::RegisterShutdownHandler([&Shutdown] {
|
||||||
Application::SetSubsystemStatus("Main", Application::Status::ShuttingDown);
|
Application::SetSubsystemStatus("Main", Application::Status::ShuttingDown);
|
||||||
|
|||||||
Reference in New Issue
Block a user