Compare commits

...

26 Commits

Author SHA1 Message Date
Lion Kortlepel
daa674f448 add infinite snowmen bug to changelog 2022-03-10 12:31:02 +01:00
Lion Kortlepel
a85fef15c2 only use sentry if URL is specified, possibly fix stupid microsoft compiler error
hey @microsoft, maybe don't have a limit on the size of obj files.
2022-03-10 12:23:24 +01:00
Lion Kortlepel
359faee696 Fix Unicycle "infinite spawning" bug 2022-03-10 12:22:11 +01:00
Lion Kortlepel
299004b14e fix msvc /bigobj issue 2022-03-10 12:21:08 +01:00
Lion Kortlepel
b09f5a401d update lionkor/commandline to 1.0.0 (adds cursor left- and right
movement)
2022-03-10 12:19:01 +01:00
Lion Kortlepel
8ce3be03a3 make bigobj a linker flag? 2022-02-17 12:00:03 +01:00
Lion Kortlepel
687b4e4235 add bigobj flag 2022-02-17 11:47:28 +01:00
Lion Kortlepel
86ad28abdc Microsoft (R) Windows (TM) needs deprecation 2022-02-17 11:29:51 +01:00
Lion Kortlepel
a982d54202 add debug build to windows github actions 2022-02-17 11:13:07 +01:00
Lion Kortlepel
5553aca0bb set heartbeat status properly 2022-02-12 22:08:49 +01:00
Lion Kortlepel
beaea4f624 Fix crash when giving commandline arguments with no console initialized 2022-02-11 11:57:01 +01:00
Lion
a4f07c9a4d Merge pull request #86 from BeamMP/rc-v3.0.1
Release Candidate v3.0.1
2022-02-11 11:07:39 +01:00
Lion Kortlepel
dada8fe6bf update changelog 2022-02-11 11:01:39 +01:00
Lion Kortlepel
36853ca683 add MSG_NOSIGNAL to all calls to send() to get rid of useless SIGPIPE signals 2022-02-11 10:59:17 +01:00
Lion Kortlepel
d969c4a2c2 Use nlohmann/json for IsUnicycle 2022-02-11 10:36:10 +01:00
Lion Kortlepel
f26ca6b40d add nlohmann/json
this will conflict with a change in the http branch, but i dont care
right now
2022-02-11 10:19:10 +01:00
Lion
b72de4bd0a Merge pull request #82 from BeamMP/rc-v3.0.1
Release Candidate v3.0.1
2022-02-04 04:37:09 +01:00
Lion Kortlepel
9494bc70fb fix changelog 2022-02-03 19:46:31 +01:00
Lion Kortlepel
5c44a307bc update changelog 2022-02-03 19:03:21 +01:00
Lion Kortlepel
754053e73f Use yield() where possible
Replaced calls of this_thread::sleep_* with this_thread::yield(), which
yields the thread to the OS' scheduler.
2022-02-03 18:57:52 +01:00
Lion Kortlepel
29f8d29e33 Move commandline initialization after cwd setting
This fixes an issue where the log file is written to the original
directory, even if --working-directory=path was used. This can obviously
be pretty bad.
2022-02-03 18:31:18 +01:00
Lion Kortlepel
e043361abb update libraries 2022-02-03 18:30:00 +01:00
Lion Kortlepel
fca5bbcec9 UpdateCheck: Try all URLs 2022-01-21 14:26:42 +01:00
Lion Kortlepel
2a588954be advance to 3.0.1 2022-01-20 21:31:00 +01:00
Lion Kortlepel
cd4129e05d add api-v header to heartbeat post 2022-01-20 16:09:08 +01:00
Lion Kortlepel
c42c748b37 start fixing backend heartbeat 2022-01-20 15:46:13 +01:00
19 changed files with 194 additions and 112 deletions

View File

@@ -44,4 +44,15 @@ jobs:
name: BeamMP-Server.exe
path: ${{github.workspace}}/build-windows/Release/BeamMP-Server.exe
- name: Build debug
working-directory: ${{github.workspace}}/build-windows
shell: bash
run: |
cmake --build . --config Debug
- name: Archive debug artifacts
uses: actions/upload-artifact@v2
with:
name: BeamMP-Server-debug.exe
path: ${{github.workspace}}/build-windows/Debug/BeamMP-Server.exe

5
.gitmodules vendored
View File

@@ -21,4 +21,7 @@
url = https://github.com/nih-at/libzip
[submodule "deps/cpp-httplib"]
path = deps/cpp-httplib
url = https://github.com/yhirose/cpp-httplib
url = https://github.com/yhirose/cpp-httplib
[submodule "deps/json"]
path = deps/json
url = https://github.com/nlohmann/json

View File

@@ -8,12 +8,15 @@ project(BeamMP-Server
HOMEPAGE_URL https://beammp.com
LANGUAGES CXX C)
set(HTTPLIB_REQUIRE_OPENSSL ON)
include_directories("${PROJECT_SOURCE_DIR}/deps/asio/asio/include")
include_directories("${PROJECT_SOURCE_DIR}/deps/rapidjson/include")
include_directories("${PROJECT_SOURCE_DIR}/deps/websocketpp")
include_directories("${PROJECT_SOURCE_DIR}/deps/commandline")
include_directories("${PROJECT_SOURCE_DIR}/deps/sol2/include")
include_directories("${PROJECT_SOURCE_DIR}/deps/cpp-httplib")
include_directories("${PROJECT_SOURCE_DIR}/deps/json/single_include")
include_directories("${PROJECT_SOURCE_DIR}/deps")
add_compile_definitions(CPPHTTPLIB_OPENSSL_SUPPORT)
@@ -38,9 +41,25 @@ set(SENTRY_BUILD_SHARED_LIBS OFF)
if (MSVC)
set(SENTRY_BUILD_RUNTIMESTATIC ON)
endif()
set(SENTRY_BACKEND breakpad)
message(STATUS "Checking for Sentry URL")
# this is set by the build system.
# IMPORTANT: if you're building from source, just leave this empty
if (NOT DEFINED BEAMMP_SECRET_SENTRY_URL)
message(WARNING "No sentry URL configured. Sentry logging is disabled for this build. \
This is not an error, and if you're building the BeamMP-Server yourself, this is expected and can be ignored.")
set(BEAMMP_SECRET_SENTRY_URL "")
set(SENTRY_BACKEND none)
else()
string(LENGTH ${BEAMMP_SECRET_SENTRY_URL} URL_LEN)
message(STATUS "Sentry URL is length ${URL_LEN}")
set(SENTRY_BACKEND breakpad)
endif()
add_subdirectory("deps/sentry-native")
if (MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj")
endif ()
message(STATUS "Setting compiler flags")
if (WIN32)
@@ -58,17 +77,6 @@ elseif (UNIX)
endif (SANITIZE)
endif ()
message(STATUS "Checking for Sentry URL")
# this is set by the build system.
# IMPORTANT: if you're building from source, just leave this empty
if (NOT DEFINED BEAMMP_SECRET_SENTRY_URL)
message(WARNING "No sentry URL configured. Sentry logging is disabled for this build. \
This is not an error, and if you're building the BeamMP-Server yourself, this is expected and can be ignored.")
set(BEAMMP_SECRET_SENTRY_URL "")
else()
string(LENGTH ${BEAMMP_SECRET_SENTRY_URL} URL_LEN)
message(STATUS "Sentry URL is length ${URL_LEN}")
endif()
message(STATUS "Adding local source dependencies")
# this has to happen before -DDEBUG since it wont compile properly with -DDEBUG

View File

@@ -1,3 +1,13 @@
# v3.0.1
- ADDED Backup URLs to UpdateCheck (will fail less often now)
- ADDED console cursor left and right movement (with arrow keys) and working HOME and END key (via github.com/lionkor/commandline)
- FIXED infinite snowmen / infinite unicycle spawning bug
- 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
- FIXED an issue which would cause servers to crash on mod download via SIGPIPE on POSIX
- FIXED an issue which would cause servers to crash when checking if a vehicle is a unicycle
# v3.0.0
- CHANGED entire plugin Lua implementation (rewrite)

1
deps/json vendored Submodule

Submodule deps/json added at eb21824147

View File

@@ -74,10 +74,15 @@ public:
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 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 void CheckForUpdates();
static std::array<uint8_t, 3> VersionStrToInts(const std::string& str);
@@ -114,7 +119,7 @@ private:
static inline std::mutex mShutdownHandlersMutex {};
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);

View File

@@ -25,7 +25,7 @@ constexpr size_t RSA_DEFAULT_KEYLENGTH { 2048 };
namespace Http {
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 {
std::string ToString(int code);
}

View File

@@ -149,6 +149,7 @@ public:
void CancelEventTimers(const std::string& EventName, TLuaStateId StateId);
sol::state_view GetStateForPlugin(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";

View File

@@ -99,25 +99,31 @@ void Application::CheckForUpdates() {
Application::SetSubsystemStatus("UpdateCheck", Application::Status::Starting);
// checks current version against latest version
std::regex VersionRegex { R"(\d+\.\d+\.\d+\n*)" };
auto Response = Http::GET(GetBackendHostname(), 443, "/v/s");
bool Matches = std::regex_match(Response, VersionRegex);
if (Matches) {
auto MyVersion = ServerVersion();
auto RemoteVersion = Version(VersionStrToInts(Response));
if (IsOutdated(MyVersion, RemoteVersion)) {
std::string RealVersionString = RemoteVersion.AsString();
beammp_warn(std::string(ANSI_YELLOW_BOLD) + "NEW VERSION OUT! There's a new version (v" + RealVersionString + ") of the BeamMP-Server available! For more info visit https://wiki.beammp.com/en/home/server-maintenance#updating-the-server." + std::string(ANSI_RESET));
for (const auto& url : GetBackendUrlsInOrder()) {
auto Response = Http::GET(GetBackendUrlsInOrder().at(0), 443, "/v/s");
bool Matches = std::regex_match(Response, VersionRegex);
if (Matches) {
auto MyVersion = ServerVersion();
auto RemoteVersion = Version(VersionStrToInts(Response));
if (IsOutdated(MyVersion, RemoteVersion)) {
std::string RealVersionString = RemoteVersion.AsString();
beammp_warn(std::string(ANSI_YELLOW_BOLD) + "NEW VERSION OUT! There's a new version (v" + RealVersionString + ") of the BeamMP-Server available! For more info visit https://wiki.beammp.com/en/home/server-maintenance#updating-the-server." + std::string(ANSI_RESET));
} else {
beammp_info("Server up-to-date!");
}
Application::SetSubsystemStatus("UpdateCheck", Application::Status::Good);
break;
} else {
beammp_info("Server up-to-date!");
beammp_debug("Failed to fetch version from: " + url);
beammp_trace("got " + Response);
auto Lock = Sentry.CreateExclusiveContext();
Sentry.SetContext("get-response", { { "response", Response } });
Sentry.LogError("failed to get server version", _file_basename, _line);
Application::SetSubsystemStatus("UpdateCheck", Application::Status::Bad);
}
Application::SetSubsystemStatus("UpdateCheck", Application::Status::Good);
} else {
beammp_warn("Unable to fetch version from backend.");
beammp_trace("got " + Response);
auto Lock = Sentry.CreateExclusiveContext();
Sentry.SetContext("get-response", { { "response", Response } });
Sentry.LogError("failed to get server version", _file_basename, _line);
Application::SetSubsystemStatus("UpdateCheck", Application::Status::Bad);
}
if (Application::GetSubsystemStatuses().at("UpdateCheck") == Application::Status::Bad) {
beammp_warn("Unable to fetch version info from backend.");
}
}

View File

@@ -4,6 +4,7 @@
#include "Common.h"
#include "CustomAssert.h"
#include "LuaAPI.h"
#include "httplib.h"
#include <map>
#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);
client.set_read_timeout(std::chrono::seconds(10));
beammp_assert(client.is_valid());
client.enable_server_certificate_verification(false);
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 (status) {
*status = res->status;
}
return res->body;
} else {
beammp_debug("POST failed: " + httplib::to_string(res.error()));
return Http::ErrorString;
}
}

View File

@@ -369,10 +369,6 @@ TConsole::TConsole() {
mCommandline.set_history_limit(20);
mCommandline.set_prompt("> ");
BackupOldLog();
bool success = mCommandline.enable_write_to_file("Server.log");
if (!success) {
beammp_error("unable to open file for writing: \"Server.log\"");
}
mCommandline.on_command = [this](Commandline& c) {
try {
auto cmd = c.get_command();
@@ -386,7 +382,7 @@ TConsole::TConsole() {
} else {
auto Future = mLuaEngine->EnqueueScript(mStateId, { std::make_shared<std::string>(cmd), "", "" });
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) {
beammp_lua_error(Future->ErrorMessage);

View File

@@ -54,43 +54,76 @@ void THeartbeatThread::operator()() {
auto Target = "/heartbeat";
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) {
beammp_trace("got " + T + " from backend");
Application::SetSubsystemStatus("Heartbeat", Application::Status::Bad);
SentryReportError(Application::GetBackendHostname() + Target, ResponseCode);
std::this_thread::sleep_for(std::chrono::milliseconds(500));
T = Http::POST(Application::GetBackup1Hostname(), 443, Target, Body, "application/x-www-form-urlencoded", &ResponseCode);
if ((T.substr(0, 2) != "20" && ResponseCode != 200) || ResponseCode != 200) {
SentryReportError(Application::GetBackup1Hostname() + Target, ResponseCode);
Application::SetSubsystemStatus("Heartbeat", Application::Status::Bad);
std::this_thread::sleep_for(std::chrono::milliseconds(500));
T = Http::POST(Application::GetBackup2Hostname(), 443, Target, Body, "application/x-www-form-urlencoded", &ResponseCode);
if ((T.substr(0, 2) != "20" && ResponseCode != 200) || ResponseCode != 200) {
beammp_warn("Backend system refused server! Server will not show in the public server list.");
Application::SetSubsystemStatus("Heartbeat", Application::Status::Bad);
isAuth = false;
SentryReportError(Application::GetBackup2Hostname() + Target, ResponseCode);
} else {
Application::SetSubsystemStatus("Heartbeat", Application::Status::Good);
}
json::Document Doc;
bool Ok = false;
for (const auto& Url : Application::GetBackendUrlsInOrder()) {
T = Http::POST(Url, 443, Target, Body, "application/x-www-form-urlencoded", &ResponseCode, { { "api-v", "2" } });
beammp_trace(T);
Doc.Parse(T.data(), T.size());
if (Doc.HasParseError() || !Doc.IsObject()) {
beammp_error("Backend response failed to parse as valid json");
beammp_debug("Response was: `" + T + "`");
Sentry.SetContext("JSON Response", { { "reponse", T } });
SentryReportError(Url + Target, ResponseCode);
} else if (ResponseCode != 200) {
SentryReportError(Url + Target, ResponseCode);
} else {
Application::SetSubsystemStatus("Heartbeat", Application::Status::Good);
// all ok
Ok = true;
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
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 {
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__));
}
} else {
Application::SetSubsystemStatus("Heartbeat", Application::Status::Good);
}
if (!isAuth) {
if (T == "2000") {
if (Ok && !isAuth) {
if (Status == "2000") {
beammp_info(("Authenticated!"));
isAuth = true;
} else if (T == "200") {
} else if (Status == "200") {
beammp_info(("Resumed authenticated session!"));
isAuth = true;
} else {
if (Message.empty()) {
Message = "Backend didn't provide a reason";
}
beammp_error("Backend REFUSED the auth key. " + Message);
}
}
if (isAuth) {
Application::SetSubsystemStatus("Heartbeat", Application::Status::Good);
}
}
}

View File

@@ -54,25 +54,17 @@ void TLuaEngine::operator()() {
auto ResultCheckThread = std::thread([&] {
RegisterThread("ResultCheckThread");
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);
if (!mResultsToCheck.empty()) {
auto Res = mResultsToCheck.front();
mResultsToCheck.pop();
Lock.unlock();
size_t Waited = 0;
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();
mResultsToCheck.push(Res);
Lock.unlock();
break;
}
if (!Res->Ready) {
Lock.lock();
mResultsToCheck.push(Res);
Lock.unlock();
}
if (Res->Error) {
if (Res->ErrorMessage != BeamMPFnNotFoundError) {
@@ -80,13 +72,14 @@ void TLuaEngine::operator()() {
}
}
}
std::this_thread::yield();
}
});
// event loop
auto Before = std::chrono::high_resolution_clock::now();
while (!mShutdown) {
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
std::unique_lock Lock(mTimedEventsMutex);
@@ -149,6 +142,11 @@ TLuaStateId TLuaEngine::GetStateIDForPlugin(const fs::path& PluginPath) {
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) {
for (const auto& Result : Results) {
bool Cancelled = false;
@@ -705,6 +703,7 @@ void TLuaEngine::StateThreadData::AddPath(const fs::path& Path) {
void TLuaResult::WaitUntilReady() {
while (!Ready) {
std::this_thread::yield();
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 Res = mEngine.EnqueueScript(StateID, Chunk);
// TODO: call onInit
while (!Res->Ready) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
if (Res->Error) {
beammp_lua_error(Res->ErrorMessage);
}
mEngine.AddResultToCheck(Res);
} else {
// TODO: trigger onFileChanged event
beammp_trace("Change detected in file \"" + Pair.first + "\", event trigger not implemented yet");

View File

@@ -187,7 +187,11 @@ void TNetwork::Identify(const TConnection& client) {
} else if (Code == 'D') {
HandleDownload(client.Socket);
} else if (Code == 'P') {
#if defined(BEAMMP_LINUX) || defined(BEAMMP_APPLE)
send(client.Socket, "P", 1, MSG_NOSIGNAL);
#else
send(client.Socket, "P", 1, 0);
#endif
CloseSocketProper(client.Socket);
return;
} else {
@@ -778,7 +782,11 @@ void TNetwork::SplitLoad(TClient& c, size_t Sent, size_t Size, bool D, const std
bool TNetwork::TCPSendRaw(TClient& C, SOCKET socket, char* Data, int32_t Size) {
intmax_t Sent = 0;
do {
#if defined(BEAMMP_LINUX) || defined(BEAMMP_APPLE)
intmax_t Temp = send(socket, &Data[Sent], int(Size - Sent), MSG_NOSIGNAL);
#else
intmax_t Temp = send(socket, &Data[Sent], int(Size - Sent), 0);
#endif
if (Temp < 1) {
beammp_info("Socket Closed! " + std::to_string(socket));
CloseSocketProper(socket);

View File

@@ -21,8 +21,8 @@ TPPSMonitor::TPPSMonitor(TServer& Server)
void TPPSMonitor::operator()() {
RegisterThread("PPSMonitor");
while (!mNetwork) {
// hard spi
std::this_thread::sleep_for(std::chrono::milliseconds(1));
// hard(-ish) spin
std::this_thread::yield();
}
beammp_debug("PPSMonitor starting");
Application::SetSubsystemStatus("PPSMonitor", Application::Status::Good);

View File

@@ -7,14 +7,14 @@
#include <any>
#include <sstream>
#include <nlohmann/json.hpp>
#include "LuaAPI.h"
#undef GetObject // Fixes Windows
#include "Json.h"
namespace json = rapidjson;
TServer::TServer(const std::vector<std::string_view>& Arguments) {
beammp_info("BeamMP Server v" + Application::ServerVersionString());
Application::SetSubsystemStatus("Server", Application::Status::Starting);
@@ -171,27 +171,25 @@ void TServer::HandleEvent(TClient& c, const std::string& Data) {
}
}
bool TServer::IsUnicycle(TClient& c, const std::string& CarJson) {
rapidjson::Document Car;
Car.Parse(CarJson.c_str(), CarJson.size());
if (Car.HasParseError()) {
beammp_error("Failed to parse vehicle data -> " + CarJson);
} else if (Car["jbm"].IsString() && std::string(Car["jbm"].GetString()) == "unicycle") {
return true;
try {
auto Car = nlohmann::json::parse(CarJson);
const std::string jbm = "jbm";
if (Car.contains(jbm) && Car[jbm].is_string() && Car[jbm] == "unicycle") {
return true;
}
} catch (const std::exception& e) {
beammp_error("Failed to parse vehicle data as json for client " + std::to_string(c.GetID()) + ": '" + CarJson + "'");
}
return false;
}
bool TServer::ShouldSpawn(TClient& c, const std::string& CarJson, int ID) {
if (c.GetUnicycleID() > -1 && (c.GetCarCount() - 1) < Application::Settings.MaxCars) {
return true;
}
if (IsUnicycle(c, CarJson)) {
if (IsUnicycle(c, CarJson) && c.GetUnicycleID() < 0) {
c.SetUnicycleID(ID);
return true;
} else {
return c.GetCarCount() < Application::Settings.MaxCars;
}
return Application::Settings.MaxCars > c.GetCarCount();
}
void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Network) {

View File

@@ -78,10 +78,6 @@ int main(int argc, char** argv) {
int BeamMPServerMain(MainArguments Arguments) {
setlocale(LC_ALL, "C");
Application::InitializeConsole();
Application::SetSubsystemStatus("Main", Application::Status::Starting);
SetupSignalHandlers();
ArgsParser Parser;
Parser.RegisterArgument({ "help" }, ArgsParser::NONE);
Parser.RegisterArgument({ "version" }, ArgsParser::NONE);
@@ -122,6 +118,14 @@ int BeamMPServerMain(MainArguments Arguments) {
}
}
Application::SetSubsystemStatus("Main", Application::Status::Starting);
bool Success = Application::Console().Internal().enable_write_to_file("Server.log");
if (!Success) {
beammp_error("unable to open file for writing: \"Server.log\"");
}
SetupSignalHandlers();
bool Shutdown = false;
Application::RegisterShutdownHandler([&Shutdown] {
Application::SetSubsystemStatus("Main", Application::Status::ShuttingDown);