Compare commits

..

63 Commits

Author SHA1 Message Date
Tixx bd9b6212e2 Bump version 2025-01-19 13:41:14 +01:00
Tixx b112ee20d8 Force IPv4 for backend requests (#417)
Force the use of ipv4 for backend requests because the launcher doesn't
support ipv6 yet

---

By creating this pull request, I understand that code that is AI
generated or otherwise automatically generated may be rejected without
further discussion.
I declare that I fully understand all code I pushed into this PR, and
wrote all this code myself and own the rights to this code.
2025-01-19 13:38:36 +01:00
Tixx 8593aeb21d Force IPv4 2025-01-19 11:53:42 +01:00
Tixx ec21cbbe86 Bump version 2025-01-18 21:40:07 +01:00
Tixx e90f1af109 Fix crash (#413)
This PR fixes the segfault caused by rapidjson on the first heartbeat,
and the memory leak that happens during mod hashing.

---

By creating this pull request, I understand that code that is AI
generated or otherwise automatically generated may be rejected without
further discussion.
I declare that I fully understand all code I pushed into this PR, and
wrote all this code myself and own the rights to this code.
2025-01-18 21:36:54 +01:00
Tixx c78775bfd8 Add size header to information packet (#409)
By creating this pull request, I understand that code that is AI
generated or otherwise automatically generated may be rejected without
further discussion.
I declare that I fully understand all code I pushed into this PR, and
wrote all this code myself and own the rights to this code.
2025-01-18 20:52:20 +01:00
Tixx 4f2ef3c3a7 Fix hashing memory leak 2025-01-17 14:40:27 +01:00
Tixx 6a2ee052ba Fix curl post headers 2025-01-16 14:22:47 +01:00
Tixx 2658d0f785 Fix segfault by switching from rapidjson to nlohmann::json 2025-01-16 14:21:43 +01:00
Tixx a7eeda0569 Add size header to information packet 2025-01-12 16:55:38 +01:00
Tixx cd29f25435 Switch to curl (#405)
This PR converts all the http client code to use curl instead of
httplib. This will hopefully do something about the connectivity issues
with the backend and auth.

---

By creating this pull request, I understand that code that is AI
generated or otherwise automatically generated may be rejected without
further discussion.
I declare that I fully understand all code I pushed into this PR, and
wrote all this code myself and own the rights to this code.
2025-01-12 13:00:44 +01:00
Tixx 7c864d94b3 Fix heartbeat request 2025-01-11 22:27:42 +01:00
Tixx 26f1be0a51 Switch to curl 2025-01-11 22:18:50 +01:00
Tixx d7e75ae0c7 Fix windows build 2025-01-11 22:18:19 +01:00
Tixx 1d90f53527 Add curl 2025-01-11 22:18:19 +01:00
Tixx 7dd6b41642 Debug log responses from auth and backend (#403)
Logs the reponses from authentication and backend.

---

By creating this pull request, I understand that code that is AI
generated or otherwise automatically generated may be rejected without
further discussion.
I declare that I fully understand all code I pushed into this PR, and
wrote all this code myself and own the rights to this code.
2025-01-11 22:14:42 +01:00
Tixx d7f3bc8b9f Debug log responses from auth and backend 2024-12-23 18:18:42 +01:00
Tixx 687a988701 Fix build failure with Boost >= v1.87.0 (#402)
Closes #401

Replace deprecated `ip::address::from_string` with `ip::make_address` to
avoid build errors with Boost versions >= 1.87.0

---

By creating this pull request, I understand that code that is AI
generated or otherwise automatically generated may be rejected without
further discussion.
I declare that I fully understand all code I pushed into this PR, and
wrote all this code myself and own the rights to this code.
2024-12-21 20:30:02 +01:00
Mathijs 9046b5a4d3 Fix build failure with Boost >= v1.87.0
Closes #401
2024-12-18 14:12:38 +01:00
Tixx b4d4967529 Bump version 2024-12-09 09:52:58 +01:00
Tixx 51c24b82fe remove sentry leftovers (#392)
Just cleaning up some sentry related code, mentions, etc.

---

By creating this pull request, I understand that code that is AI
generated or otherwise automatically generated may be rejected without
further discussion.
I declare that I fully understand all code I pushed into this PR, and
wrote all this code myself and own the rights to this code.
2024-11-30 21:19:48 +01:00
Tixx 5e13f9dd2d fix crash when double closing (#383) 2024-11-30 21:14:09 +01:00
Tixx f8d66c4336 Re-Add BEAMMP_PROVIDER_PORT_ENV (#399)
#398

---

By creating this pull request, I understand that code that is AI
generated or otherwise automatically generated may be rejected without
further discussion.
I declare that I fully understand all code I pushed into this PR, and
wrote all this code myself and own the rights to this code.
2024-11-30 20:23:31 +01:00
Tixx 9875defe86 Re-Add BEAMMP_PROVIDER_PORT_ENV 2024-11-30 18:04:23 +01:00
Lion fc208770dd Fix postPlayerAuth and add reason value (#395)
Closes #393 and #394
This PR cleans up and fixes the code in TNetwork::Authentication and
sends the kick reason to lua.
The event is now `function postPlayerAuth(Kicked: bool, Reason: string,
Name: string, Role: string, Guest: bool, Identifiers: table)`

---

By creating this pull request, I understand that code that is AI
generated or otherwise automatically generated may be rejected without
further discussion.
I declare that I fully understand all code I pushed into this PR, and
wrote all this code myself and own the rights to this code.
2024-11-25 10:15:20 +01:00
Tixx 99a51808a0 Fix postPlayerAuth not running until after leaving 2024-11-25 00:33:10 +01:00
Tixx 1c07cf83b2 Fix postPlayerAuth and add reason value 2024-11-24 22:28:32 +01:00
0R3Z 99136f133a remove sentry leftovers 2024-11-16 19:02:50 +01:00
Tixx 6c9d58582b Swap build instruction sequence (#391)
Swap the sequence of the build instruction steps 2 and 3 so it actually
works

No AI involved, i used my own brain to mess it up and to fix it 😉

---

By creating this pull request, I understand that code that is AI
generated or otherwise automatically generated may be rejected without
further discussion.
I declare that I fully understand all code I pushed into this PR, and
wrote all this code myself and own the rights to this code.
2024-11-14 22:40:26 +01:00
O1LER 4edae00998 Swap build instruction sequence 2024-11-14 18:29:30 +01:00
Lion 17e9c05f46 add PR template 2024-11-13 16:21:49 +01:00
Lion 71e3cb83ae Allow for empty icon param in MP.SendNotification (#389)
This PR allows you to call MP.SendNotification with only a player ID and
a message, removing the requirement for an icon.
2024-11-12 13:32:58 +01:00
Tixx fb2e26bd28 Allow for empty icon param in MP.SendNotification 2024-11-12 12:35:12 +01:00
Tixx 976ab68ca3 Bump version 2024-11-05 23:13:46 +01:00
Tixx 58a76e1df2 Add some information about tags in the build instructions (#386) 2024-11-05 10:30:05 +01:00
O1LER c696276fc3 Update README.md
Co-authored-by: Tixx <83774803+WiserTixx@users.noreply.github.com>
2024-11-02 23:30:22 +01:00
O1LER 6ce0608bb3 Third times the charm 2024-11-02 14:35:17 +01:00
O1LER 52ad237419 Fix bracket skill issue 2024-11-02 14:33:52 +01:00
O1LER 71038dc617 Hide links 2024-11-02 14:32:47 +01:00
O1LER dc3bb517a3 Update README.md
Co-authored-by: Tixx <83774803+WiserTixx@users.noreply.github.com>
2024-11-02 14:29:48 +01:00
O1LER 7b2c48c8d4 Add some information about tags in the build instructions 2024-11-02 14:04:09 +01:00
Lion ef557ebfc4 Fix backend heartbeat (#385) 2024-11-01 17:40:33 +01:00
Tixx b2e953b92a Fix JSON heartbeat request 2024-11-01 17:30:17 +01:00
Lion Kortlepel 576d765557 fix crash when double closing 2024-11-01 15:07:54 +01:00
Lion Kortlepel e3416804e4 bump version 2024-11-01 12:50:11 +01:00
Lion 9ad4f61209 Information packet (#382)
This PR adds an "I" packet which returns the server information. This
can be used by external programs and the launcher to get information
about a server without having to connect it to. It can be toggled in the
config and in lua.
2024-11-01 12:27:31 +01:00
Tixx aed6311146 Run clang-format on THeartbeatThread.cpp 2024-11-01 12:22:56 +01:00
Lion 5e41cefa87 Paint packet (#381)
Adds a packet for live color updating `vid:[{}]`
2024-11-01 12:18:06 +01:00
Tixx b1710ee826 Add explanation for why uuid is added later 2024-10-20 18:33:49 +02:00
Lion 03b0bd4d2c Add 'P' packet on UDP (#379)
This can be used to check if UDP works :)

I've tested this a bit with snep ingame, even spamming this on localhost
with a large number of connections seems to not impact gameplay at all.
2024-10-20 18:29:12 +02:00
Tixx 5179ac1fdc Paint packet 2024-10-20 15:38:07 +02:00
Tixx 54e31ce2ec Move backend heartbeat to json 2024-10-14 00:42:14 +02:00
Tixx 4abe9b8636 Add informationpacket setting to the config 2024-10-14 00:39:12 +02:00
Tixx 956d6f50e1 Add setting for the information packet 2024-10-14 00:39:12 +02:00
Tixx 6aeb2eb736 Add server identification packet 2024-10-14 00:39:12 +02:00
Lion Kortlepel f40d4c1ddd add 'P' packet on UDP
this can be used to check if UDP works :)
2024-10-13 22:13:05 +02:00
Lion 4f052a3e0a Make modlist an empty array by default instead of null (#377)
Related launcher PR: https://github.com/BeamMP/BeamMP-Launcher/pull/136
2024-10-12 21:06:41 +02:00
Tixx 2bf9e7d916 Make modlist [] by default instead of null 2024-10-09 19:42:47 +02:00
Lion 89c906232d Report correct client minimum version to the backend (#376) 2024-10-09 18:06:03 +02:00
Lion c39beb5b72 reuse minclientversion where possible
Co-authored-by: Tixx <83774803+WiserTixx@users.noreply.github.com>
2024-10-09 18:03:01 +02:00
Lion Kortlepel 7dd2d89ad9 clarify auth version reject message 2024-10-09 16:48:40 +02:00
Lion Kortlepel 3403c8acba fix version check on auth 2024-10-09 16:44:38 +02:00
Lion Kortlepel 0a6eecee69 report correct client minimum version to the backend 2024-10-09 16:37:16 +02:00
23 changed files with 247 additions and 158 deletions
+6
View File
@@ -0,0 +1,6 @@
Please replace this text <-> with your PR description and leave the below declarations intact.
---
By creating this pull request, I understand that code that is AI generated or otherwise automatically generated may be rejected without further discussion.
I declare that I fully understand all code I pushed into this PR, and wrote all this code myself and own the rights to this code.
-1
View File
@@ -1,5 +1,4 @@
.idea/
.sentry-native/
*.orig
*.toml
boost_*
+2
View File
@@ -104,6 +104,7 @@ set(PRJ_LIBRARIES
httplib::httplib
libzip::zip
OpenSSL::SSL OpenSSL::Crypto
CURL::libcurl
${LUA_LIBRARIES}
)
@@ -116,6 +117,7 @@ find_package(httplib CONFIG REQUIRED)
find_package(libzip CONFIG REQUIRED)
find_package(RapidJSON CONFIG REQUIRED)
find_package(sol2 CONFIG REQUIRED)
find_package(CURL CONFIG REQUIRED)
add_subdirectory("deps/toml11")
include_directories(include)
+2 -2
View File
@@ -108,8 +108,8 @@ A BeamMP-Developer must review your code in detail, and leave a review. If this
5. Run `git submodule update --init --recursive`.
6. Make a new branch for your feature or fix from the branch you are on. You can do this via `git checkout -b <branch name>`. See [this section on branches](#branches) for more info on branch naming.
7. Install all dependencies. Those are usually listed in the `README.md` in the branch you're in, or, more reliably, in one of the files in `.github/workflows` (if you can read `yaml`).
8. Run CMake to configure the project. You can find tutorials on this online. You will want to tell CMake to build with `CMAKE_BUILD_TYPE=Debug`, for example by passing it to CMake via the commandline switch `-DCMAKE_BUILD_TYPE=Debug`. You may also want to turn off sentry by setting `SENTRY_BACKEND=none` (for example via commandline switch `-DSENTRY_BACKEND=none`). An example invocation on Linux with GNU make would be
`cmake . -DCMAKE_BUILD_TYPE=Debug -DSENTRY_BACKEND=none` .
8. Run CMake to configure the project. You can find tutorials on this online. You will want to tell CMake to build with `CMAKE_BUILD_TYPE=Debug`, for example by passing it to CMake via the commandline switch `-DCMAKE_BUILD_TYPE=Debug`. An example invocation on Linux with GNU make would be
`cmake . -DCMAKE_BUILD_TYPE=Debug` .
9. Build the `BeamMP-Server` target to build the BeamMP-Server, or the `BeamMP-Server-tests` target to build the unit-tests (does not include a working server). In the example from 8. (on Linux), you could build with `make BeamMP-Server`, `make -j BeamMP-Server` or `cmake --build . --parallel --target BeamMP-Server` . Or, on Windows, (in Visual Studio), you would just press some big green "run" or "debug" button.
10. When making changes, refer to [this section on how to commit properly](#how-to-commit). Not following those guidelines will result in your changes being rejected, so please take a look.
11. Make sure to add Unit-tests with `doctest` if you build new stuff. You can find examples all over the latest version of the codebase (search for `TEST_CASE`).
+5 -4
View File
@@ -38,7 +38,7 @@ If you need support with understanding the codebase, please write us in the Disc
## About Building from Source
We only allow building unmodified (original) source code for public use. `master` is considered **unstable** and we will not provide technical support if such a build doesn't work, so always build from a tag. You can checkout a tag with `git checkout tags/TAGNAME`, where `TAGNAME` is the tag, for example `v3.1.0`.
We only allow building unmodified (original) source code for public use. `master` is considered **unstable** and we will not provide technical support if such a build doesn't work, so always build from a tag. You can checkout a tag with `git checkout tags/TAGNAME`, where `TAGNAME` is the tag, for example `v3.4.1`. See [the tags](https://github.com/BeamMP/BeamMP-Server/tags) for possible versions/tags, as well as [the releases](https://github.com/BeamMP/BeamMP-Server/releases) to check which version is marked as a release/prerelease. We recommend using the [latest release](https://github.com/BeamMP/BeamMP-Server/releases/latest).
## Supported Operating Systems
@@ -66,9 +66,10 @@ You can build on **Windows, Linux** or other platforms by following these steps:
1. Check out the repository with git: `git clone --recursive https://github.com/BeamMP/BeamMP-Server`.
2. Go into the directory `cd BeamMP-Server`.
3. Run CMake `cmake -S . -B bin -DCMAKE_BUILD_TYPE=Release` - this can take a few minutes and may take a lot of disk space and bandwidth.
4. Build via `cmake --build bin --parallel --config Release -t BeamMP-Server`.
5. Your executable can be found in `bin/`.
3. Specify the server version to build by checking out a tag: `git checkout tags/v3.4.1` - [Possible versions/tags](https://github.com/BeamMP/BeamMP-Server/tags)
4. Run CMake `cmake -S . -B bin -DCMAKE_BUILD_TYPE=Release` - this can take a few minutes and may take a lot of disk space and bandwidth.
5. Build via `cmake --build bin --parallel --config Release -t BeamMP-Server`.
6. Your executable can be found in `bin/`.
When you make changes to the code, you only have to run step 4 again.
### Building for FreeBSD
+9 -10
View File
@@ -74,7 +74,7 @@ public:
static TConsole& Console() { return mConsole; }
static std::string ServerVersionString();
static const Version& ServerVersion() { return mVersion; }
static uint8_t ClientMajorVersion() { return 2; }
static Version ClientMinimumVersion() { return Version { 2, 2, 0 }; }
static std::string PPS() { return mPPS; }
static void SetPPS(const std::string& NewPPS) { mPPS = NewPPS; }
@@ -82,11 +82,11 @@ public:
static std::vector<std::string> GetBackendUrlsInOrder() {
return {
"backend.beammp.com",
"https://backend.beammp.com",
};
}
static std::string GetBackendUrlForAuth() { return "auth.beammp.com"; }
static std::string GetBackendUrlForAuth() { return "https://auth.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);
@@ -127,7 +127,7 @@ private:
static inline std::mutex mShutdownHandlersMutex {};
static inline std::deque<TShutdownHandler> mShutdownHandlers {};
static inline Version mVersion { 3, 6, 0 };
static inline Version mVersion { 3, 8, 1 };
};
void SplitString(std::string const& str, const char delim, std::vector<std::string>& out);
@@ -139,7 +139,6 @@ void RegisterThread(const std::string& str);
#define KB 1024llu
#define MB (KB * 1024llu)
#define GB (MB * 1024llu)
#define SSU_UNRAW SECRET_SENTRY_URL
#define _file_basename std::filesystem::path(__FILE__).filename().string()
#define _line std::to_string(__LINE__)
@@ -162,13 +161,13 @@ void RegisterThread(const std::string& str);
#else
#define _function_name std::string(__func__)
#endif
#ifndef NDEBUG
#define DEBUG
#endif
#if defined(DEBUG)
// if this is defined, we will show the full function signature infront of
// each info/debug/warn... call instead of the 'filename:line' format.
#if defined(BMP_FULL_FUNCTION_NAMES)
@@ -178,7 +177,7 @@ void RegisterThread(const std::string& str);
#endif
#endif // defined(DEBUG)
#define beammp_warn(x) Application::Console().Write(_this_location + std::string("[WARN] ") + (x))
#define beammp_info(x) Application::Console().Write(_this_location + std::string("[INFO] ") + (x))
#define beammp_error(x) \
@@ -221,7 +220,7 @@ void RegisterThread(const std::string& str);
#else
#define beammp_trace(x)
#endif // defined(DEBUG)
#define beammp_errorf(...) beammp_error(fmt::format(__VA_ARGS__))
#define beammp_infof(...) beammp_info(fmt::format(__VA_ARGS__))
#define beammp_debugf(...) beammp_debug(fmt::format(__VA_ARGS__))
+3 -2
View File
@@ -23,6 +23,7 @@
#include <filesystem>
#include <string>
#include <unordered_map>
#include <curl/curl.h>
#if defined(BEAMMP_LINUX)
#pragma GCC diagnostic push
@@ -38,8 +39,8 @@
namespace fs = std::filesystem;
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, const httplib::Headers& headers = {});
std::string GET(const std::string& url, unsigned int* status = nullptr);
std::string POST(const std::string& url, const std::string& body, const std::string& ContentType, unsigned int* status = nullptr, const std::map<std::string, std::string>& headers = {});
namespace Status {
std::string ToString(int code);
}
+3
View File
@@ -6,6 +6,9 @@
#include <limits>
#include <unordered_map>
#undef max
#undef min
namespace prof {
using Duration = std::chrono::duration<double, std::milli>;
+2 -3
View File
@@ -68,8 +68,6 @@ struct Settings {
// Keys have their TOML section name as prefix
// [Misc]
Misc_SendErrorsShowMessage,
Misc_SendErrors,
Misc_ImScaredOfUpdates,
Misc_UpdateReminderTime,
@@ -86,7 +84,8 @@ struct Settings {
General_LogChat,
General_ResourceFolder,
General_Debug,
General_AllowGuests
General_AllowGuests,
General_InformationPacket,
};
Sync<std::unordered_map<Key, SettingsTypeVariant>> SettingsMap;
+1
View File
@@ -29,6 +29,7 @@ public:
//~THeartbeatThread();
void operator()() override;
static inline std::string lastCall = "";
private:
std::string GenerateCall();
std::string GetPlayers();
+1 -1
View File
@@ -43,5 +43,5 @@ private:
int mModsLoaded = 0;
std::mutex mModsMutex;
nlohmann::json mMods;
nlohmann::json mMods = nlohmann::json::array();
};
+11 -7
View File
@@ -79,13 +79,17 @@ std::string TClient::GetCarPositionRaw(int Ident) {
void TClient::Disconnect(std::string_view Reason) {
beammp_debugf("Disconnecting client {} for reason: {}", GetID(), Reason);
boost::system::error_code ec;
mSocket.shutdown(socket_base::shutdown_both, ec);
if (ec) {
beammp_debugf("Failed to shutdown client socket: {}", ec.message());
}
mSocket.close(ec);
if (ec) {
beammp_debugf("Failed to close client socket: {}", ec.message());
if (mSocket.is_open()) {
mSocket.shutdown(socket_base::shutdown_both, ec);
if (ec) {
beammp_debugf("Failed to shutdown client socket: {}", ec.message());
}
mSocket.close(ec);
if (ec) {
beammp_debugf("Failed to close client socket: {}", ec.message());
}
} else {
beammp_debug("Socket is already closed.");
}
}
+1 -1
View File
@@ -215,7 +215,7 @@ void Application::CheckForUpdates() {
// checks current version against latest version
std::regex VersionRegex { R"(\d+\.\d+\.\d+\n*)" };
for (const auto& url : GetBackendUrlsInOrder()) {
auto Response = Http::GET(url, 443, "/v/s");
auto Response = Http::GET(url + "/v/s");
bool Matches = std::regex_match(Response, VersionRegex);
if (Matches) {
auto MyVersion = ServerVersion();
+69 -48
View File
@@ -29,67 +29,88 @@
#include <stdexcept>
using json = nlohmann::json;
struct Connection {
std::string host {};
int port {};
Connection() = default;
Connection(std::string host, int port)
: host(host)
, port(port) {};
};
constexpr uint8_t CONNECTION_AMOUNT = 10;
static thread_local uint8_t write_index = 0;
static thread_local std::array<Connection, CONNECTION_AMOUNT> connections;
static thread_local std::array<std::shared_ptr<httplib::SSLClient>, CONNECTION_AMOUNT> clients;
[[nodiscard]] static std::shared_ptr<httplib::SSLClient> getClient(Connection connectionInfo) {
for (uint8_t i = 0; i < CONNECTION_AMOUNT; i++) {
if (connectionInfo.host == connections[i].host
&& connectionInfo.port == connections[i].port) {
beammp_tracef("Old client reconnected, with ip {} and port {}", connectionInfo.host, connectionInfo.port);
return clients[i];
}
}
uint8_t i = write_index;
write_index++;
write_index %= CONNECTION_AMOUNT;
clients[i] = std::make_shared<httplib::SSLClient>(connectionInfo.host, connectionInfo.port);
connections[i] = { connectionInfo.host, connectionInfo.port };
beammp_tracef("New client connected, with ip {} and port {}", connectionInfo.host, connectionInfo.port);
return clients[i];
static size_t CurlWriteCallback(void* contents, size_t size, size_t nmemb, void* userp) {
std::string* Result = reinterpret_cast<std::string*>(userp);
std::string NewContents(reinterpret_cast<char*>(contents), size * nmemb);
*Result += NewContents;
return size * nmemb;
}
std::string Http::GET(const std::string& host, int port, const std::string& target, unsigned int* status) {
std::shared_ptr<httplib::SSLClient> client = getClient({ host, port });
client->enable_server_certificate_verification(false);
client->set_address_family(AF_INET);
auto res = client->Get(target.c_str());
if (res) {
if (status) {
*status = res->status;
std::string Http::GET(const std::string& url, unsigned int* status) {
std::string Ret;
static thread_local CURL* curl = curl_easy_init();
if (curl) {
CURLcode res;
char errbuf[CURL_ERROR_SIZE];
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&Ret);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10); // seconds
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf);
errbuf[0] = 0;
res = curl_easy_perform(curl);
if (res != CURLE_OK) {
beammp_error("GET to " + url + " failed: " + std::string(curl_easy_strerror(res)));
beammp_error("Curl error: " + std::string(errbuf));
return Http::ErrorString;
}
return res->body;
if (status) {
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, status);
}
} else {
beammp_error("Curl easy init failed");
return Http::ErrorString;
}
return Ret;
}
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) {
std::shared_ptr<httplib::SSLClient> client = getClient({ 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(), headers, body.c_str(), body.size(), ContentType.c_str());
if (res) {
if (status) {
*status = res->status;
std::string Http::POST(const std::string& url, const std::string& body, const std::string& ContentType, unsigned int* status, const std::map<std::string, std::string>& headers) {
std::string Ret;
static thread_local CURL* curl = curl_easy_init();
if (curl) {
CURLcode res;
char errbuf[CURL_ERROR_SIZE];
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&Ret);
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body.c_str());
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, body.size());
struct curl_slist* list = nullptr;
list = curl_slist_append(list, ("Content-Type: " + ContentType).c_str());
for (auto [header, value] : headers) {
list = curl_slist_append(list, (header + ": " + value).c_str());
}
return res->body;
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10); // seconds
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf);
errbuf[0] = 0;
res = curl_easy_perform(curl);
curl_slist_free_all(list);
if (res != CURLE_OK) {
beammp_error("POST to " + url + " failed: " + std::string(curl_easy_strerror(res)));
beammp_error("Curl error: " + std::string(errbuf));
return Http::ErrorString;
}
if (status) {
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, status);
}
} else {
beammp_debug("POST failed: " + httplib::to_string(res.error()));
beammp_error("Curl easy init failed");
return Http::ErrorString;
}
return Ret;
}
// RFC 2616, RFC 7231
+11 -1
View File
@@ -207,7 +207,7 @@ std::pair<bool, std::string> LuaAPI::MP::SendChatMessage(int ID, const std::stri
std::pair<bool, std::string> LuaAPI::MP::SendNotification(int ID, const std::string& Message, const std::string& Icon, const std::string& Category) {
std::pair<bool, std::string> Result;
std::string Packet = "N" + Category + ":" + Icon + ":" + Message;
std::string Packet = "n" + Category + ":" + Icon + ":" + Message;
if (ID == -1) {
Engine->Network().SendToAll(nullptr, StringToVector(Packet), true, true);
Result.first = true;
@@ -317,6 +317,14 @@ void LuaAPI::MP::Set(int ConfigID, sol::object NewValue) {
beammp_lua_error("set invalid argument [2] expected string");
}
break;
case 7: // Information packet
if (NewValue.is<bool>()) {
Application::Settings.set(Settings::Key::General_InformationPacket, NewValue.as<bool>());
beammp_info(std::string("Set `InformationPacket` to ") + (Application::Settings.getAsBool(Settings::Key::General_InformationPacket) ? "true" : "false"));
} else {
beammp_lua_error("set invalid argument [2] expected boolean");
}
break;
default:
beammp_warn("Invalid config ID \"" + std::to_string(ConfigID) + "\". Use `MP.Settings.*` enum for this.");
break;
@@ -339,6 +347,8 @@ TLuaValue LuaAPI::MP::Get(int ConfigID) {
return Application::Settings.getAsString(Settings::Key::General_Name);
case 6: // Desc
return Application::Settings.getAsString(Settings::Key::General_Description);
case 7: // Information packet
return Application::Settings.getAsBool(Settings::Key::General_InformationPacket);
default:
beammp_warn("Invalid config ID \"" + std::to_string(ConfigID) + "\". Use `MP.Settings.*` enum for this.");
return 0;
+2 -4
View File
@@ -34,8 +34,7 @@ Settings::Settings() {
{ General_ResourceFolder, std::string("Resources") },
{ General_Debug, false },
{ General_AllowGuests, true },
{ Misc_SendErrorsShowMessage, true },
{ Misc_SendErrors, true },
{ General_InformationPacket, true },
{ Misc_ImScaredOfUpdates, true },
{ Misc_UpdateReminderTime, "30s" }
};
@@ -54,8 +53,7 @@ Settings::Settings() {
{ { "General", "ResourceFolder" }, { General_ResourceFolder, READ_ONLY } },
{ { "General", "Debug" }, { General_Debug, READ_WRITE } },
{ { "General", "AllowGuests" }, { General_AllowGuests, READ_WRITE } },
{ { "Misc", "SendErrorsShowMessage" }, { Misc_SendErrorsShowMessage, READ_WRITE } },
{ { "Misc", "SendErrors" }, { Misc_SendErrors, READ_WRITE } },
{ { "General", "InformationPacket" }, { General_InformationPacket, READ_WRITE } },
{ { "Misc", "ImScaredOfUpdates" }, { Misc_ImScaredOfUpdates, READ_WRITE } },
{ { "Misc", "UpdateReminderTime" }, { Misc_UpdateReminderTime, READ_WRITE } }
};
+11 -9
View File
@@ -56,11 +56,11 @@ static constexpr std::string_view StrLogChat = "LogChat";
static constexpr std::string_view EnvStrLogChat = "BEAMMP_LOG_CHAT";
static constexpr std::string_view StrAllowGuests = "AllowGuests";
static constexpr std::string_view EnvStrAllowGuests = "BEAMMP_ALLOW_GUESTS";
static constexpr std::string_view StrInformationPacket = "InformationPacket";
static constexpr std::string_view EnvStrInformationPacket = "BEAMMP_INFORMATION_PACKET";
static constexpr std::string_view StrPassword = "Password";
// Misc
static constexpr std::string_view StrSendErrors = "SendErrors";
static constexpr std::string_view StrSendErrorsMessageEnabled = "SendErrorsShowMessage";
static constexpr std::string_view StrHideUpdateMessages = "ImScaredOfUpdates";
static constexpr std::string_view StrUpdateReminderTime = "UpdateReminderTime";
@@ -132,6 +132,8 @@ void TConfig::FlushToFile() {
SetComment(data["General"][StrLogChat.data()].comments(), " Whether to log chat messages in the console / log");
data["General"][StrDebug.data()] = Application::Settings.getAsBool(Settings::Key::General_Debug);
data["General"][StrPrivate.data()] = Application::Settings.getAsBool(Settings::Key::General_Private);
SetComment(data["General"][StrInformationPacket.data()].comments(), " Whether to allow unconnected clients to get the public server information without joining");
data["General"][StrInformationPacket.data()] = Application::Settings.getAsBool(Settings::Key::General_InformationPacket);
data["General"][StrAllowGuests.data()] = Application::Settings.getAsBool(Settings::Key::General_AllowGuests);
SetComment(data["General"][StrAllowGuests.data()].comments(), " Whether to allow guests");
data["General"][StrPort.data()] = Application::Settings.getAsInt(Settings::Key::General_Port);
@@ -148,12 +150,8 @@ void TConfig::FlushToFile() {
// Misc
data["Misc"][StrHideUpdateMessages.data()] = Application::Settings.getAsBool(Settings::Key::Misc_ImScaredOfUpdates);
SetComment(data["Misc"][StrHideUpdateMessages.data()].comments(), " Hides the periodic update message which notifies you of a new server version. You should really keep this on and always update as soon as possible. For more information visit https://wiki.beammp.com/en/home/server-maintenance#updating-the-server. An update message will always appear at startup regardless.");
data["Misc"][StrSendErrors.data()] = Application::Settings.getAsBool(Settings::Key::Misc_SendErrors);
data["Misc"][StrUpdateReminderTime.data()] = Application::Settings.getAsString(Settings::Key::Misc_UpdateReminderTime);
SetComment(data["Misc"][StrUpdateReminderTime.data()].comments(), " Specifies the time between update reminders. You can use any of \"s, min, h, d\" at the end to specify the units seconds, minutes, hours or days. So 30d or 0.5min will print the update message every 30 days or half a minute.");
SetComment(data["Misc"][StrSendErrors.data()].comments(), " If SendErrors is `true`, the server will send helpful info about crashes and other issues back to the BeamMP developers. This info may include your config, who is on your server at the time of the error, and similar general information. This kind of data is vital in helping us diagnose and fix issues faster. This has no impact on server performance. You can opt-out of this system by setting this to `false`");
data["Misc"][StrSendErrorsMessageEnabled.data()] = Application::Settings.getAsBool(Settings::Key::Misc_SendErrorsShowMessage);
SetComment(data["Misc"][StrSendErrorsMessageEnabled.data()].comments(), " You can turn on/off the SendErrors message you get on startup here");
std::stringstream Ss;
Ss << "# This is the BeamMP-Server config file.\n"
"# Help & Documentation: `https://docs.beammp.com/server/server-maintenance/`\n"
@@ -248,7 +246,12 @@ void TConfig::ParseFromFile(std::string_view name) {
// Read into new Settings Singleton
TryReadValue(data, "General", StrDebug, EnvStrDebug, Settings::Key::General_Debug);
TryReadValue(data, "General", StrPrivate, EnvStrPrivate, Settings::Key::General_Private);
TryReadValue(data, "General", StrPort, EnvStrPort, Settings::Key::General_Port);
TryReadValue(data, "General", StrInformationPacket, EnvStrInformationPacket, Settings::Key::General_InformationPacket);
if (Env::Get(Env::Key::PROVIDER_PORT_ENV).has_value()) {
TryReadValue(data, "General", StrPort, Env::Get(Env::Key::PROVIDER_PORT_ENV).value(), Settings::Key::General_Port);
} else {
TryReadValue(data, "General", StrPort, EnvStrPort, Settings::Key::General_Port);
}
TryReadValue(data, "General", StrMaxCars, EnvStrMaxCars, Settings::Key::General_MaxCars);
TryReadValue(data, "General", StrMaxPlayers, EnvStrMaxPlayers, Settings::Key::General_MaxPlayers);
TryReadValue(data, "General", StrMap, EnvStrMap, Settings::Key::General_Map);
@@ -260,9 +263,7 @@ void TConfig::ParseFromFile(std::string_view name) {
TryReadValue(data, "General", StrLogChat, EnvStrLogChat, Settings::Key::General_LogChat);
TryReadValue(data, "General", StrAllowGuests, EnvStrAllowGuests, Settings::Key::General_AllowGuests);
// Misc
TryReadValue(data, "Misc", StrSendErrors, "", Settings::Key::Misc_SendErrors);
TryReadValue(data, "Misc", StrHideUpdateMessages, "", Settings::Key::Misc_ImScaredOfUpdates);
TryReadValue(data, "Misc", StrSendErrorsMessageEnabled, "", Settings::Key::Misc_SendErrorsShowMessage);
TryReadValue(data, "Misc", StrUpdateReminderTime, "", Settings::Key::Misc_UpdateReminderTime);
} catch (const std::exception& err) {
@@ -299,6 +300,7 @@ void TConfig::PrintDebug() {
}
beammp_debug(std::string(StrDebug) + ": " + std::string(Application::Settings.getAsBool(Settings::Key::General_Debug) ? "true" : "false"));
beammp_debug(std::string(StrPrivate) + ": " + std::string(Application::Settings.getAsBool(Settings::Key::General_Private) ? "true" : "false"));
beammp_debug(std::string(StrInformationPacket) + ": " + std::string(Application::Settings.getAsBool(Settings::Key::General_InformationPacket) ? "true" : "false"));
beammp_debug(std::string(StrPort) + ": " + std::to_string(Application::Settings.getAsInt(Settings::Key::General_Port)));
beammp_debug(std::string(StrMaxCars) + ": " + std::to_string(Application::Settings.getAsInt(Settings::Key::General_MaxCars)));
beammp_debug(std::string(StrMaxPlayers) + ": " + std::to_string(Application::Settings.getAsInt(Settings::Key::General_MaxPlayers)));
+40 -33
View File
@@ -20,14 +20,12 @@
#include "ChronoWrapper.h"
#include "Client.h"
#include "Common.h"
#include "Http.h"
// #include "SocketIO.h"
#include <rapidjson/document.h>
#include <rapidjson/rapidjson.h>
#include <nlohmann/json.hpp>
#include <sstream>
namespace json = rapidjson;
void THeartbeatThread::operator()() {
RegisterThread("Heartbeat");
std::string Body;
@@ -61,15 +59,19 @@ void THeartbeatThread::operator()() {
auto Target = "/heartbeat";
unsigned int ResponseCode = 0;
json::Document Doc;
nlohmann::json 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" } });
Doc.Parse(T.data(), T.size());
if (Doc.HasParseError() || !Doc.IsObject()) {
T = Http::POST(Url + Target, Body, "application/json", &ResponseCode, { { "api-v", "2" } });
if (!Application::Settings.getAsBool(Settings::Key::General_Private)) {
beammp_debug("Backend response was: `" + T + "`");
}
Doc = nlohmann::json::parse(T, nullptr, false);
if (Doc.is_discarded() || !Doc.is_object()) {
if (!Application::Settings.getAsBool(Settings::Key::General_Private)) {
beammp_trace("Backend response failed to parse as valid json");
beammp_trace("Response was: `" + T + "`");
}
} else if (ResponseCode != 200) {
beammp_errorf("Response code from the heartbeat: {}", ResponseCode);
@@ -88,18 +90,18 @@ void THeartbeatThread::operator()() {
const auto MessageKey = "msg";
if (Ok) {
if (Doc.HasMember(StatusKey) && Doc[StatusKey].IsString()) {
Status = Doc[StatusKey].GetString();
if (Doc.contains(StatusKey) && Doc[StatusKey].is_string()) {
Status = Doc[StatusKey];
} else {
Ok = false;
}
if (Doc.HasMember(CodeKey) && Doc[CodeKey].IsString()) {
Code = Doc[CodeKey].GetString();
if (Doc.contains(CodeKey) && Doc[CodeKey].is_string()) {
Code = Doc[CodeKey];
} else {
Ok = false;
}
if (Doc.HasMember(MessageKey) && Doc[MessageKey].IsString()) {
Message = Doc[MessageKey].GetString();
if (Doc.contains(MessageKey) && Doc[MessageKey].is_string()) {
Message = Doc[MessageKey];
} else {
Ok = false;
}
@@ -137,25 +139,30 @@ void THeartbeatThread::operator()() {
}
std::string THeartbeatThread::GenerateCall() {
std::stringstream Ret;
nlohmann::json Ret = {
{ "players", std::to_string(mServer.ClientCount()) },
{ "maxplayers", std::to_string(Application::Settings.getAsInt(Settings::Key::General_MaxPlayers)) },
{ "port", std::to_string(Application::Settings.getAsInt(Settings::Key::General_Port)) },
{ "map", Application::Settings.getAsString(Settings::Key::General_Map) },
{ "private", Application::Settings.getAsBool(Settings::Key::General_Private) ? "true" : "false" },
{ "version", Application::ServerVersionString() },
{ "clientversion", Application::ClientMinimumVersion().AsString() },
{ "name", Application::Settings.getAsString(Settings::Key::General_Name) },
{ "tags", Application::Settings.getAsString(Settings::Key::General_Tags) },
{ "guests", Application::Settings.getAsBool(Settings::Key::General_AllowGuests) ? "true" : "false" },
{ "modlist", mResourceManager.TrimmedList() },
{ "modstotalsize", std::to_string(mResourceManager.MaxModSize()) },
{ "modstotal", std::to_string(mResourceManager.ModsLoaded()) },
{ "playerslist", GetPlayers() },
{ "desc", Application::Settings.getAsString(Settings::Key::General_Description) }
};
Ret << "uuid=" << Application::Settings.getAsString(Settings::Key::General_AuthKey)
<< "&players=" << mServer.ClientCount()
<< "&maxplayers=" << Application::Settings.getAsInt(Settings::Key::General_MaxPlayers)
<< "&port=" << Application::Settings.getAsInt(Settings::Key::General_Port)
<< "&map=" << Application::Settings.getAsString(Settings::Key::General_Map)
<< "&private=" << (Application::Settings.getAsBool(Settings::Key::General_Private) ? "true" : "false")
<< "&version=" << Application::ServerVersionString()
<< "&clientversion=" << std::to_string(Application::ClientMajorVersion()) + ".0" // FIXME: Wtf.
<< "&name=" << Application::Settings.getAsString(Settings::Key::General_Name)
<< "&tags=" << Application::Settings.getAsString(Settings::Key::General_Tags)
<< "&guests=" << (Application::Settings.getAsBool(Settings::Key::General_AllowGuests) ? "true" : "false")
<< "&modlist=" << mResourceManager.TrimmedList()
<< "&modstotalsize=" << mResourceManager.MaxModSize()
<< "&modstotal=" << mResourceManager.ModsLoaded()
<< "&playerslist=" << GetPlayers()
<< "&desc=" << Application::Settings.getAsString(Settings::Key::General_Description);
return Ret.str();
lastCall = Ret.dump();
// Add sensitive information here because value of lastCall is used for the information packet.
Ret["uuid"] = Application::Settings.getAsString(Settings::Key::General_AuthKey);
return Ret.dump();
}
THeartbeatThread::THeartbeatThread(TResourceManager& ResourceManager, TServer& Server)
: mResourceManager(ResourceManager)
+6 -3
View File
@@ -880,12 +880,14 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, TLuaStateI
});
MPTable.set_function("SendChatMessage", &LuaAPI::MP::SendChatMessage);
MPTable.set_function("SendNotification", [&](sol::variadic_args Args) {
if (Args.size() == 3) {
if (Args.size() == 2) {
LuaAPI::MP::SendNotification(Args.get<int>(0), Args.get<std::string>(1), "", Args.get<std::string>(1));
} else if (Args.size() == 3) {
LuaAPI::MP::SendNotification(Args.get<int>(0), Args.get<std::string>(1), Args.get<std::string>(2), Args.get<std::string>(1));
} else if (Args.size() == 4) {
LuaAPI::MP::SendNotification(Args.get<int>(0), Args.get<std::string>(1), Args.get<std::string>(2), Args.get<std::string>(3));
} else {
beammp_lua_error("SendNotification expects 2 or 3 arguments.");
beammp_lua_error("SendNotification expects 2, 3 or 4 arguments.");
}
});
MPTable.set_function("GetPlayers", [&]() -> sol::table {
@@ -1024,7 +1026,8 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, TLuaStateI
"MaxPlayers", 3,
"Map", 4,
"Name", 5,
"Description", 6);
"Description", 6,
"InformationPacket", 7);
MPTable.create_named("CallStrategy",
"BestEffort", CallStrategy::BestEffort,
+44 -27
View File
@@ -20,6 +20,7 @@
#include "Client.h"
#include "Common.h"
#include "LuaAPI.h"
#include "THeartbeatThread.h"
#include "TLuaEngine.h"
#include "TScopedTimer.h"
#include "nlohmann/json.hpp"
@@ -85,7 +86,7 @@ TNetwork::TNetwork(TServer& Server, TPPSMonitor& PPSMonitor, TResourceManager& R
void TNetwork::UDPServerMain() {
RegisterThread("UDPServer");
// listen on all ipv6 addresses
ip::udp::endpoint UdpListenEndpoint(ip::address::from_string("::"), Application::Settings.getAsInt(Settings::Key::General_Port));
ip::udp::endpoint UdpListenEndpoint(ip::make_address("::"), Application::Settings.getAsInt(Settings::Key::General_Port));
boost::system::error_code ec;
mUDPSock.open(UdpListenEndpoint.protocol(), ec);
if (ec) {
@@ -112,9 +113,19 @@ void TNetwork::UDPServerMain() {
try {
ip::udp::endpoint remote_client_ep {};
std::vector<uint8_t> Data = UDPRcvFromClient(remote_client_ep);
auto Pos = std::find(Data.begin(), Data.end(), ':');
if (Data.empty() || Pos > Data.begin() + 2)
if (Data.empty()) {
continue;
}
if (Data.size() == 1 && Data.at(0) == 'P') {
mUDPSock.send_to(const_buffer("P", 1), remote_client_ep, {}, ec);
// ignore errors
(void)ec;
continue;
}
auto Pos = std::find(Data.begin(), Data.end(), ':');
if (Pos > Data.begin() + 2) {
continue;
}
uint8_t ID = uint8_t(Data.at(0)) - 1;
mServer.ForEachClient([&](std::weak_ptr<TClient> ClientPtr) -> bool {
std::shared_ptr<TClient> Client;
@@ -161,7 +172,7 @@ void TNetwork::TCPServerMain() {
// listen on all ipv6 addresses
auto port = uint16_t(Application::Settings.getAsInt(Settings::Key::General_Port));
ip::tcp::endpoint ListenEp(ip::address::from_string("::"), port);
ip::tcp::endpoint ListenEp(ip::make_address("::"), port);
beammp_infof("Listening on 0.0.0.0:{0} and [::]:{0}", port);
ip::tcp::socket Listener(mServer.IoCtx());
boost::system::error_code ec;
@@ -246,6 +257,17 @@ void TNetwork::Identify(TConnection&& RawConnection) {
boost::system::error_code ec;
write(RawConnection.Socket, buffer("P"), ec);
return;
} else if (Code == 'I') {
const std::string Data = Application::Settings.getAsBool(Settings::Key::General_InformationPacket) ? THeartbeatThread::lastCall : "";
const auto Size = static_cast<int32_t>(Data.size());
std::vector<uint8_t> ToSend;
ToSend.resize(Data.size() + sizeof(Size));
std::memcpy(ToSend.data(), &Size, sizeof(Size));
std::memcpy(ToSend.data() + sizeof(Size), Data.data(), Data.size());
boost::system::error_code ec;
write(RawConnection.Socket, buffer(ToSend), ec);
} else {
beammp_errorf("Invalid code got in Identify: '{}'", Code);
}
@@ -293,10 +315,11 @@ std::shared_ptr<TClient> TNetwork::Authentication(TConnection&& RawConnection) {
if (Data.size() > 3 && std::equal(Data.begin(), Data.begin() + VC.size(), VC.begin(), VC.end())) {
std::string ClientVersionStr(reinterpret_cast<const char*>(Data.data() + 2), Data.size() - 2);
Version ClientVersion = Application::VersionStrToInts(ClientVersionStr + ".0");
if (ClientVersion.major != Application::ClientMajorVersion()) {
beammp_errorf("Client tried to connect with version '{}', but only versions '{}.x.x' is allowed",
ClientVersion.AsString(), Application::ClientMajorVersion());
ClientKick(*Client, "Outdated Version!");
Version MinClientVersion = Application::ClientMinimumVersion();
if (Application::IsOutdated(ClientVersion, MinClientVersion)) {
beammp_errorf("Client tried to connect with version '{}', but only versions >= {} are allowed",
ClientVersion.AsString(), MinClientVersion.AsString());
ClientKick(*Client, fmt::format("Outdated version, launcher version >={} required to join!", MinClientVersion.AsString()));
return nullptr;
}
} else {
@@ -331,7 +354,7 @@ std::shared_ptr<TClient> TNetwork::Authentication(TConnection&& RawConnection) {
auto Target = "/pkToUser";
unsigned int ResponseCode = 0;
AuthResStr = Http::POST(Application::GetBackendUrlForAuth(), 443, Target, AuthReq.dump(), "application/json", &ResponseCode);
AuthResStr = Http::POST(Application::GetBackendUrlForAuth() + Target, AuthReq.dump(), "application/json", &ResponseCode);
} catch (const std::exception& e) {
beammp_debugf("Invalid json sent by client, kicking: {}", e.what());
@@ -339,6 +362,8 @@ std::shared_ptr<TClient> TNetwork::Authentication(TConnection&& RawConnection) {
return nullptr;
}
beammp_debug("Response from authentication backend: " + AuthResStr);
try {
nlohmann::json AuthRes = nlohmann::json::parse(AuthResStr);
@@ -415,35 +440,27 @@ std::shared_ptr<TClient> TNetwork::Authentication(TConnection&& RawConnection) {
Reason = "No guests are allowed on this server! To join, sign up at: forum.beammp.com.";
}
bool Allowed = true;
if (NotAllowed) {
Allowed = false;
if (!NotAllowed && !NotAllowedWithReason && mServer.ClientCount() >= size_t(Application::Settings.getAsInt(Settings::Key::General_MaxPlayers)) && !BypassLimit) {
NotAllowedWithReason = true;
Reason = "Server full!";
}
if (NotAllowedWithReason) {
Allowed = false;
}
if (NotAllowed) {
ClientKick(*Client, "you are not allowed on the server!");
} else if (NotAllowedWithReason) {
ClientKick(*Client, Reason);
} else if (NotAllowed) {
ClientKick(*Client, "you are not allowed on the server!");
}
auto PostFutures = LuaAPI::MP::Engine->TriggerEvent("postPlayerAuth", "", NotAllowed || NotAllowedWithReason, Reason, Client->GetName(), Client->GetRoles(), Client->IsGuest(), Client->GetIdentifiers());
// the post event is not cancellable so we dont wait for it
LuaAPI::MP::Engine->ReportErrors(PostFutures);
if (!Allowed) {
return {};
} else if (mServer.ClientCount() < size_t(Application::Settings.getAsInt(Settings::Key::General_MaxPlayers)) || BypassLimit) {
if (!NotAllowed && !NotAllowedWithReason) {
beammp_info("Identification success");
mServer.InsertClient(Client);
TCPClient(Client);
} else {
ClientKick(*Client, "Server full!");
}
auto PostFutures = LuaAPI::MP::Engine->TriggerEvent("postPlayerAuth", "", Allowed, Client->GetName(), Client->GetRoles(), Client->IsGuest(), Client->GetIdentifiers());
// the post event is not cancellable so we dont wait for it
LuaAPI::MP::Engine->ReportErrors(PostFutures);
return Client;
}
+2
View File
@@ -121,6 +121,8 @@ void TResourceManager::RefreshFiles() {
}
EVP_MD_CTX_free(mdctx);
stream.close();
std::string result;
for (size_t i = 0; i < sha256_len; i++) {
result += fmt::format("{:02x}", sha256_value[i]);
+14 -1
View File
@@ -253,7 +253,6 @@ void TServer::GlobalParser(const std::weak_ptr<TClient>& Client, std::vector<uin
HandleEvent(*LockedClient, StringPacket);
return;
case 'N':
beammp_trace("got 'N' packet (" + std::to_string(Packet.size()) + ")");
Network.SendToAll(LockedClient.get(), Packet, false, true);
return;
case 'Z': // position packet
@@ -436,6 +435,20 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ
Network.SendToAll(&c, StringToVector(Packet), false, true);
return;
}
case 'p': {
beammp_trace(std::string(("got 'Op' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")"));
auto MaybePidVid = GetPidVid(Data.substr(0, Data.find(':', 1)));
if (MaybePidVid) {
std::tie(PID, VID) = MaybePidVid.value();
}
if (PID != -1 && VID != -1 && PID == c.GetID()) {
Data = Data.substr(Data.find('['));
LuaAPI::MP::Engine->ReportErrors(LuaAPI::MP::Engine->TriggerEvent("onVehiclePaintChanged", "", c.GetID(), VID, Data));
Network.SendToAll(&c, StringToVector(Packet), false, true);
}
return;
}
default:
beammp_trace(std::string(("possibly not implemented: '") + Packet + ("' (") + std::to_string(Packet.size()) + (")")));
return;
+2 -1
View File
@@ -13,6 +13,7 @@
"nlohmann-json",
"openssl",
"rapidjson",
"sol2"
"sol2",
"curl"
]
}