Compare commits

..

18 Commits

Author SHA1 Message Date
Tixx da677a473d Revert "Lua version change to 5.3.5 (#458)"
This reverts commit 9fa9974159, reversing
changes made to 6ec4106ec7.
2026-01-16 23:55:45 +01:00
Tixx 99476a2c77 Revert "Add stack trace to server lua engine (#350)" 2026-01-15 14:44:13 +01:00
Tixx 9fa9974159 Lua version change to 5.3.5 (#458)
Update Lua version to make plugin development easier across platforms
and simplify Windows builds by using vcpkg.

---

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.
2026-01-10 21:39:52 +01:00
boubouleuh 3ef816845d Lua version change to 5.3.5 2026-01-10 21:09:05 +01:00
Tixx 6ec4106ec7 refactor: optimize string operations and improve code clarity (#451)
- Avoid redundant substr() calls in packet parsing hot-path
(TServer.cpp)
  The previous code called substr(3) twice per packet, creating
  unnecessary temporary strings. Now stores the result once.

- Replace .size() == 0 with .empty() for idiomatic C++
  (TConsole.cpp, TLuaEngine.cpp)
2026-01-02 00:42:03 +01:00
Tixx b094e35f8c Skip invalid socket when accept() fails (#457)
When Acceptor.accept() returns an error (e.g., "Too many open files"),
the server was continuing to process an invalid socket, causing resource
leaks and potential infinite error loops.
Add continue statement to skip processing when accept() fails, allowing
the server to retry on the next iteration instead of crashing.
Fixes resource exhaustion DoS vulnerability where server would enter
error loop instead of handling gracefully.
<img width="1233" height="199" alt="image"
src="https://github.com/user-attachments/assets/bad8f559-6ef2-47ee-b1c1-3e6020cdfb77"
/>

---

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-12-29 17:38:53 +01:00
wadyankaw 83afafc0c3 Skip invalid socket when accept() fails
When Acceptor.accept() returns an error (e.g., "Too many open files"),
the server was continuing to process an invalid socket, causing resource
leaks and potential infinite error loops.

Add continue statement to skip processing when accept() fails, allowing
the server to retry on the next iteration instead of crashing.

Fixes resource exhaustion DoS vulnerability where server would enter
error loop instead of handling gracefully.
2025-12-28 03:54:55 +03:00
Kipstz 31122abe10 Merge branch 'BeamMP:minor' into refactor-string-optimizations 2025-12-28 00:56:24 +01:00
Tixx 0615b57a37 Add message length validation for chat messages (#456)
Right now server only checks if chat message is empty but doesnt check
the max length. Client limits to 500 chars but if someone modifies the
client they can send huge messages. I added a check on server side to
reject messages longer than 500 characters, same as client limit. I used
translator because I don't know English well

---

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-12-28 00:35:43 +01:00
wadyankaw 4a8378427a Add message length validation for chat messages
Right now server only checks if chat message is empty but doesnt check the max length. Client limits to 500 chars but if someone modifies the client they can send huge messages.
I added a check on server side to reject messages longer than 500 characters, same as client limit.
I used translator because I don't know English well
2025-12-28 02:24:08 +03:00
Kipstz b74f0c7ca8 refactor: optimize string operations and improve code clarity
- Avoid redundant substr() calls in packet parsing hot-path (TServer.cpp)
  The previous code called substr(3) twice per packet, creating
  unnecessary temporary strings. Now stores the result once.

- Replace .size() == 0 with .empty() for idiomatic C++
  (TConsole.cpp, TLuaEngine.cpp)
2025-12-27 23:46:45 +01:00
Tixx 420c64f6cf Fix build (#444)
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-12-20 20:13:15 +01:00
Tixx add45c085b Remove debian 11 2025-12-13 00:10:30 +01:00
Tixx 372076a4ef Set fetch-depth to 0 2025-11-30 00:12:55 +01:00
Tixx eb2deb73c1 Update vcpkg 2025-11-29 23:23:36 +01:00
Tixx 21874afb87 Downgrade sol2 and force windows ver to 10 2025-11-29 23:20:27 +01:00
Tixx 184d50bf8c Update vcpkg submodule 2025-10-21 22:11:46 +02:00
Tixx c4c894c1f7 Bump version v3.9.0 2025-10-20 22:41:29 +02:00
14 changed files with 102 additions and 64 deletions
+2 -4
View File
@@ -19,8 +19,6 @@ jobs:
strategy: strategy:
matrix: matrix:
include: include:
- distro: debian
version: 11
- distro: debian - distro: debian
version: 12 version: 12
- distro: ubuntu - distro: ubuntu
@@ -48,6 +46,7 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with: with:
submodules: 'recursive' submodules: 'recursive'
fetch-depth: 0
- name: Git config safe directory - name: Git config safe directory
shell: bash shell: bash
@@ -90,8 +89,6 @@ jobs:
strategy: strategy:
matrix: matrix:
include: include:
- distro: debian
version: 11
- distro: debian - distro: debian
version: 12 version: 12
- distro: ubuntu - distro: ubuntu
@@ -119,6 +116,7 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with: with:
submodules: 'recursive' submodules: 'recursive'
fetch-depth: 0
- name: Git config safe directory - name: Git config safe directory
shell: bash shell: bash
+3 -4
View File
@@ -38,8 +38,6 @@ jobs:
strategy: strategy:
matrix: matrix:
include: include:
- distro: debian
version: 11
- distro: debian - distro: debian
version: 12 version: 12
- distro: ubuntu - distro: ubuntu
@@ -67,6 +65,7 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with: with:
submodules: 'recursive' submodules: 'recursive'
fetch-depth: 0
- name: Git config safe directory - name: Git config safe directory
shell: bash shell: bash
@@ -109,8 +108,6 @@ jobs:
strategy: strategy:
matrix: matrix:
include: include:
- distro: debian
version: 11
- distro: debian - distro: debian
version: 12 version: 12
- distro: ubuntu - distro: ubuntu
@@ -141,6 +138,7 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with: with:
submodules: 'recursive' submodules: 'recursive'
fetch-depth: 0
- name: Git config safe directory - name: Git config safe directory
shell: bash shell: bash
@@ -194,6 +192,7 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with: with:
submodules: 'recursive' submodules: 'recursive'
fetch-depth: 0
- name: Create Build Environment - name: Create Build Environment
shell: bash shell: bash
+1
View File
@@ -26,6 +26,7 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with: with:
submodules: 'recursive' submodules: 'recursive'
fetch-depth: 0
- name: Setup vcpkg - name: Setup vcpkg
uses: lukka/run-vcpkg@v11 uses: lukka/run-vcpkg@v11
+2 -1
View File
@@ -148,7 +148,8 @@ if(UNIX)
endif(UNIX) endif(UNIX)
if (WIN32) if (WIN32)
add_compile_options("-D_WIN32_WINNT=0x0601") add_compile_definitions(_WIN32_WINNT=0x0A00)
add_compile_options("/bigobj") add_compile_options("/bigobj")
endif(WIN32) endif(WIN32)
+4
View File
@@ -24,6 +24,7 @@
#include <queue> #include <queue>
#include <string> #include <string>
#include <unordered_set> #include <unordered_set>
#include <utility>
#include "BoostAliases.h" #include "BoostAliases.h"
#include "Common.h" #include "Common.h"
@@ -101,6 +102,8 @@ public:
[[nodiscard]] TServer& Server() const; [[nodiscard]] TServer& Server() const;
void UpdatePingTime(); void UpdatePingTime();
int SecondsSinceLastPing(); int SecondsSinceLastPing();
void SetMagic(std::vector<uint8_t> magic) { mMagic = std::move(magic); }
[[nodiscard]] const std::vector<uint8_t>& GetMagic() const { return mMagic; }
private: private:
void InsertVehicle(int ID, const std::string& Data); void InsertVehicle(int ID, const std::string& Data);
@@ -125,6 +128,7 @@ private:
std::string mDID; std::string mDID;
int mID = -1; int mID = -1;
std::chrono::time_point<std::chrono::high_resolution_clock> mLastPingTime = std::chrono::high_resolution_clock::now(); std::chrono::time_point<std::chrono::high_resolution_clock> mLastPingTime = std::chrono::high_resolution_clock::now();
std::vector<uint8_t> mMagic;
}; };
std::optional<std::weak_ptr<TClient>> GetClient(class TServer& Server, int ID); std::optional<std::weak_ptr<TClient>> GetClient(class TServer& Server, int ID);
+2 -2
View File
@@ -74,7 +74,7 @@ public:
static TConsole& Console() { return mConsole; } static TConsole& Console() { return mConsole; }
static std::string ServerVersionString(); static std::string ServerVersionString();
static const Version& ServerVersion() { return mVersion; } static const Version& ServerVersion() { return mVersion; }
static Version ClientMinimumVersion() { return Version { 2, 2, 0 }; } static Version ClientMinimumVersion() { return Version { 2, 7, 0 }; }
static std::string PPS() { return mPPS; } static std::string PPS() { return mPPS; }
static void SetPPS(const std::string& NewPPS) { mPPS = NewPPS; } static void SetPPS(const std::string& NewPPS) { mPPS = NewPPS; }
@@ -129,7 +129,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, 8, 5 }; static inline Version mVersion { 3, 9, 0 };
}; };
void SplitString(std::string const& str, const char delim, std::vector<std::string>& out); void SplitString(std::string const& str, const char delim, std::vector<std::string>& out);
+1 -3
View File
@@ -192,9 +192,7 @@ public:
for (const auto& Event : mLuaEvents.at(EventName)) { for (const auto& Event : mLuaEvents.at(EventName)) {
for (const auto& Function : Event.second) { for (const auto& Function : Event.second) {
if (Event.first != IgnoreId) { if (Event.first != IgnoreId) {
auto Result = EnqueueFunctionCall(Event.first, Function, Arguments, EventName); Results.push_back(EnqueueFunctionCall(Event.first, Function, Arguments, EventName));
Results.push_back(Result);
AddResultToCheck(Result);
} }
} }
} }
+1 -1
View File
@@ -44,7 +44,7 @@ public:
void ForEachClient(const std::function<bool(std::weak_ptr<TClient>)>& Fn); void ForEachClient(const std::function<bool(std::weak_ptr<TClient>)>& Fn);
size_t ClientCount() const; size_t ClientCount() const;
void GlobalParser(const std::weak_ptr<TClient>& Client, std::vector<uint8_t>&& Packet, TPPSMonitor& PPSMonitor, TNetwork& Network); void GlobalParser(const std::weak_ptr<TClient>& Client, std::vector<uint8_t>&& Packet, TPPSMonitor& PPSMonitor, TNetwork& Network, bool udp);
static void HandleEvent(TClient& c, const std::string& Data); static void HandleEvent(TClient& c, const std::string& Data);
RWMutex& GetClientMutex() const { return mClientsMutex; } RWMutex& GetClientMutex() const { return mClientsMutex; }
+4 -4
View File
@@ -160,7 +160,7 @@ void TConsole::ChangeToRegularConsole() {
} }
bool TConsole::EnsureArgsCount(const std::vector<std::string>& args, size_t n) { bool TConsole::EnsureArgsCount(const std::vector<std::string>& args, size_t n) {
if (n == 0 && args.size() != 0) { if (n == 0 && !args.empty()) {
Application::Console().WriteRaw("This command expects no arguments."); Application::Console().WriteRaw("This command expects no arguments.");
return false; return false;
} else if (args.size() != n) { } else if (args.size() != n) {
@@ -198,7 +198,7 @@ void TConsole::Command_Lua(const std::string&, const std::vector<std::string>& a
} else { } else {
Application::Console().WriteRaw("Lua state '" + NewStateId + "' is not a known state. Didn't switch to Lua."); Application::Console().WriteRaw("Lua state '" + NewStateId + "' is not a known state. Didn't switch to Lua.");
} }
} else if (args.size() == 0) { } else if (args.empty()) {
ChangeToLuaConsole(mDefaultStateId); ChangeToLuaConsole(mDefaultStateId);
} }
} }
@@ -423,7 +423,7 @@ void TConsole::Command_Settings(const std::string&, const std::vector<std::strin
settings set <category> <setting> <value> sets specified setting to value settings set <category> <setting> <value> sets specified setting to value
)"; )";
if (args.size() == 0) { if (args.empty()) {
beammp_errorf("No arguments specified for command 'settings'!"); beammp_errorf("No arguments specified for command 'settings'!");
Application::Console().WriteRaw("BeamMP-Server Console: " + std::string(sHelpString)); Application::Console().WriteRaw("BeamMP-Server Console: " + std::string(sHelpString));
return; return;
@@ -705,7 +705,7 @@ void TConsole::RunAsCommand(const std::string& cmd, bool IgnoreNotACommand) {
} }
} }
} }
if (NonNilFutures.size() == 0) { if (NonNilFutures.empty()) {
if (!IgnoreNotACommand) { if (!IgnoreNotACommand) {
Application::Console().WriteRaw("Error: Unknown command: '" + cmd + "'. Type 'help' to see a list of valid commands."); Application::Console().WriteRaw("Error: Unknown command: '" + cmd + "'. Type 'help' to see a list of valid commands.");
} }
+4 -27
View File
@@ -30,16 +30,12 @@
#include <condition_variable> #include <condition_variable>
#include <fmt/core.h> #include <fmt/core.h>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <optional>
#include <random> #include <random>
#include <sol/stack_core.hpp>
#include <thread> #include <thread>
#include <tuple> #include <tuple>
TLuaEngine* LuaAPI::MP::Engine; TLuaEngine* LuaAPI::MP::Engine;
static sol::protected_function AddTraceback(sol::state_view StateView, sol::protected_function RawFn);
TLuaEngine::TLuaEngine() TLuaEngine::TLuaEngine()
: mResourceServerPath(fs::path(Application::Settings.getAsString(Settings::Key::General_ResourceFolder)) / "Server") { : mResourceServerPath(fs::path(Application::Settings.getAsString(Settings::Key::General_ResourceFolder)) / "Server") {
Application::SetSubsystemStatus("LuaEngine", Application::Status::Starting); Application::SetSubsystemStatus("LuaEngine", Application::Status::Starting);
@@ -131,7 +127,7 @@ void TLuaEngine::operator()() {
} }
} }
} }
if (mLuaStates.size() == 0) { if (mLuaStates.empty()) {
beammp_trace("No Lua states, event loop running extremely sparsely"); beammp_trace("No Lua states, event loop running extremely sparsely");
Application::SleepSafeSeconds(10); Application::SleepSafeSeconds(10);
} else { } else {
@@ -496,7 +492,6 @@ sol::table TLuaEngine::StateThreadData::Lua_TriggerGlobalEvent(const std::string
sol::variadic_results LocalArgs = JsonStringToArray(Str); sol::variadic_results LocalArgs = JsonStringToArray(Str);
for (const auto& Handler : MyHandlers) { for (const auto& Handler : MyHandlers) {
auto Fn = mStateView[Handler]; auto Fn = mStateView[Handler];
Fn = AddTraceback(mStateView, Fn);
if (Fn.valid()) { if (Fn.valid()) {
auto LuaResult = Fn(LocalArgs); auto LuaResult = Fn(LocalArgs);
auto Result = std::make_shared<TLuaResult>(); auto Result = std::make_shared<TLuaResult>();
@@ -505,9 +500,7 @@ sol::table TLuaEngine::StateThreadData::Lua_TriggerGlobalEvent(const std::string
Result->Result = LuaResult; Result->Result = LuaResult;
} else { } else {
Result->Error = true; Result->Error = true;
sol::error Err = LuaResult; Result->ErrorMessage = "Function result in TriggerGlobalEvent was invalid";
Result->ErrorMessage = Err.what();
beammp_errorf("An error occured while executing local event handler \"{}\" for event \"{}\": {}", Handler, EventName, Result->ErrorMessage);
} }
Result->MarkAsReady(); Result->MarkAsReady();
Return.push_back(Result); Return.push_back(Result);
@@ -1089,21 +1082,6 @@ void TLuaEngine::StateThreadData::RegisterEvent(const std::string& EventName, co
mEngine->RegisterEvent(EventName, mStateId, FunctionName); mEngine->RegisterEvent(EventName, mStateId, FunctionName);
} }
static sol::protected_function AddTraceback(sol::state_view StateView, sol::protected_function RawFn) {
StateView["INTERNAL_ERROR_HANDLER"] = [](lua_State *L) {
auto Error = sol::stack::get<std::optional<std::string>>(L);
std::string ErrorString = "<Unknown error>";
if (Error.has_value()) {
ErrorString = Error.value();
}
auto DebugTracebackFn = sol::state_view(L).globals().get<sol::table>("debug").get<sol::protected_function>("traceback");
// 2 = start collecting the trace one above the current function (1=current function)
std::string Traceback = DebugTracebackFn(ErrorString, 2);
return sol::stack::push(L, Traceback);
};
return sol::protected_function(RawFn, StateView["INTERNAL_ERROR_HANDLER"]);
}
void TLuaEngine::StateThreadData::operator()() { void TLuaEngine::StateThreadData::operator()() {
RegisterThread("Lua:" + mStateId); RegisterThread("Lua:" + mStateId);
while (!Application::IsShuttingDown()) { while (!Application::IsShuttingDown()) {
@@ -1168,8 +1146,8 @@ void TLuaEngine::StateThreadData::operator()() {
// TODO: Use TheQueuedFunction.EventName for errors, warnings, etc // TODO: Use TheQueuedFunction.EventName for errors, warnings, etc
Result->StateId = mStateId; Result->StateId = mStateId;
sol::state_view StateView(mState); sol::state_view StateView(mState);
auto RawFn = StateView[FnName]; auto Fn = StateView[FnName];
if (RawFn.valid() && RawFn.get_type() == sol::type::function) { if (Fn.valid() && Fn.get_type() == sol::type::function) {
std::vector<sol::object> LuaArgs; std::vector<sol::object> LuaArgs;
for (const auto& Arg : Args) { for (const auto& Arg : Args) {
if (Arg.valueless_by_exception()) { if (Arg.valueless_by_exception()) {
@@ -1204,7 +1182,6 @@ void TLuaEngine::StateThreadData::operator()() {
break; break;
} }
} }
auto Fn = AddTraceback(StateView, RawFn);
auto Res = Fn(sol::as_args(LuaArgs)); auto Res = Fn(sol::as_args(LuaArgs));
if (Res.valid()) { if (Res.valid()) {
Result->Error = false; Result->Error = false;
+35 -13
View File
@@ -32,6 +32,8 @@
#include <boost/asio/ip/address_v6.hpp> #include <boost/asio/ip/address_v6.hpp>
#include <boost/asio/ip/v6_only.hpp> #include <boost/asio/ip/v6_only.hpp>
#include <cstring> #include <cstring>
#include <openssl/err.h>
#include <openssl/rand.h>
#include <zlib.h> #include <zlib.h>
typedef boost::asio::detail::socket_option::integer<SOL_SOCKET, SO_RCVTIMEO> rcv_timeout_option; typedef boost::asio::detail::socket_option::integer<SOL_SOCKET, SO_RCVTIMEO> rcv_timeout_option;
@@ -146,23 +148,30 @@ void TNetwork::UDPServerMain() {
} }
if (Client->GetID() == ID) { if (Client->GetID() == ID) {
// not initialized yet if (Client->GetUDPAddr() == ip::udp::endpoint {} && !Client->IsUDPConnected() && !Client->GetMagic().empty()) {
if (Client->GetUDPAddr() == ip::udp::endpoint {} || !Client->IsUDPConnected()) { if (Data.size() != 66) {
// same IP (just a sanity check) beammp_debugf("Invalid size for UDP value. IP: {} ID: {}", remote_client_ep.address().to_string(), ID);
if (remote_client_ep.address() == Client->GetTCPSock().remote_endpoint().address()) {
Client->SetUDPAddr(remote_client_ep);
Client->SetIsUDPConnected(true);
beammp_debugf("UDP connected for client {}", ID);
} else {
beammp_debugf("Denied initial UDP packet due to IP mismatch");
return false; return false;
} }
const std::vector Magic(Data.begin() + 2, Data.end());
if (Magic != Client->GetMagic()) {
beammp_debugf("Invalid value for UDP IP: {} ID: {}", remote_client_ep.address().to_string(), ID);
return false;
}
Client->SetMagic({});
Client->SetUDPAddr(remote_client_ep);
Client->SetIsUDPConnected(true);
return false;
} }
if (Client->GetUDPAddr() == remote_client_ep) { if (Client->GetUDPAddr() == remote_client_ep) {
Data.erase(Data.begin(), Data.begin() + 2); Data.erase(Data.begin(), Data.begin() + 2);
mServer.GlobalParser(ClientPtr, std::move(Data), mPPSMonitor, *this); mServer.GlobalParser(ClientPtr, std::move(Data), mPPSMonitor, *this, true);
} else { } else {
beammp_debugf("Ignored UDP packet due to remote address mismatch"); beammp_debugf("Ignored UDP packet for Client {} due to remote address mismatch. Source: {}, Client: {}", ID, remote_client_ep.address().to_string(), Client->GetUDPAddr().address().to_string());
return false; return false;
} }
} }
@@ -234,10 +243,11 @@ void TNetwork::TCPServerMain() {
ip::tcp::socket ClientSocket = Acceptor.accept(ClientEp, ec); ip::tcp::socket ClientSocket = Acceptor.accept(ClientEp, ec);
if (ec) { if (ec) {
beammp_errorf("Failed to accept() new client: {}", ec.message()); beammp_errorf("Failed to accept() new client: {}", ec.message());
continue;
} }
TConnection Conn { std::move(ClientSocket), ClientEp }; TConnection Conn { std::move(ClientSocket), ClientEp };
std::thread ID(&TNetwork::Identify, this, std::move(Conn)); std::thread ID(&TNetwork::Identify, this, std::move(Conn));
ID.detach(); // TODO: Add to a queue and attempt to join periodically ID.detach();
} catch (const std::exception& e) { } catch (const std::exception& e) {
beammp_errorf("Exception in accept routine: {}", e.what()); beammp_errorf("Exception in accept routine: {}", e.what());
} }
@@ -660,7 +670,7 @@ void TNetwork::TCPClient(const std::weak_ptr<TClient>& c) {
Client->Disconnect("TCPRcv failed"); Client->Disconnect("TCPRcv failed");
break; break;
} }
mServer.GlobalParser(c, std::move(res), mPPSMonitor, *this); mServer.GlobalParser(c, std::move(res), mPPSMonitor, *this, false);
} }
if (QueueSync.joinable()) if (QueueSync.joinable())
@@ -751,6 +761,18 @@ void TNetwork::OnConnect(const std::weak_ptr<TClient>& c) {
SyncResources(*LockedClient); SyncResources(*LockedClient);
if (LockedClient->IsDisconnected()) if (LockedClient->IsDisconnected())
return; return;
std::vector<unsigned char> buf(64);
int ret = RAND_bytes(buf.data(), buf.size());
if (ret != 1) {
unsigned long error = ERR_get_error();
beammp_errorf("RAND_bytes failed with error code {}", error);
beammp_assert(ret != 1);
return;
}
LockedClient->SetMagic(buf);
buf.insert(buf.begin(), 'U');
(void)Respond(*LockedClient, buf, true);
(void)Respond(*LockedClient, StringToVector("M" + Application::Settings.getAsString(Settings::Key::General_Map)), true); // Send the Map on connect (void)Respond(*LockedClient, StringToVector("M" + Application::Settings.getAsString(Settings::Key::General_Map)), true); // Send the Map on connect
beammp_info(LockedClient->GetName() + " : Connected"); beammp_info(LockedClient->GetName() + " : Connected");
LuaAPI::MP::Engine->ReportErrors(LuaAPI::MP::Engine->TriggerEvent("onPlayerJoining", "", LockedClient->GetID())); LuaAPI::MP::Engine->ReportErrors(LuaAPI::MP::Engine->TriggerEvent("onPlayerJoining", "", LockedClient->GetID()));
+34 -3
View File
@@ -161,7 +161,7 @@ size_t TServer::ClientCount() const {
return mClients.size(); return mClients.size();
} }
void TServer::GlobalParser(const std::weak_ptr<TClient>& Client, std::vector<uint8_t>&& Packet, TPPSMonitor& PPSMonitor, TNetwork& Network) { void TServer::GlobalParser(const std::weak_ptr<TClient>& Client, std::vector<uint8_t>&& Packet, TPPSMonitor& PPSMonitor, TNetwork& Network, bool udp) {
constexpr std::string_view ABG = "ABG:"; constexpr std::string_view ABG = "ABG:";
if (Packet.size() >= ABG.size() && std::equal(Packet.begin(), Packet.begin() + ABG.size(), ABG.begin(), ABG.end())) { if (Packet.size() >= ABG.size() && std::equal(Packet.begin(), Packet.begin() + ABG.size(), ABG.begin(), ABG.end())) {
Packet.erase(Packet.begin(), Packet.begin() + ABG.size()); Packet.erase(Packet.begin(), Packet.begin() + ABG.size());
@@ -198,7 +198,8 @@ void TServer::GlobalParser(const std::weak_ptr<TClient>& Client, std::vector<uin
int PID = -1; int PID = -1;
int VID = -1; int VID = -1;
auto MaybePidVid = GetPidVid(StringPacket.substr(3).substr(0, StringPacket.substr(3).find(':', 1))); auto pidVidPart = StringPacket.substr(3);
auto MaybePidVid = GetPidVid(pidVidPart.substr(0, pidVidPart.find(':')));
if (MaybePidVid) { if (MaybePidVid) {
std::tie(PID, VID) = MaybePidVid.value(); std::tie(PID, VID) = MaybePidVid.value();
} }
@@ -213,6 +214,10 @@ void TServer::GlobalParser(const std::weak_ptr<TClient>& Client, std::vector<uin
} }
switch (Code) { switch (Code) {
case 'H': // initial connection case 'H': // initial connection
if (udp) {
beammp_debugf("Received 'H' packet over UDP from client '{}' ({}), ignoring it", LockedClient->GetName(), LockedClient->GetID());
return;
}
if (!Network.SyncClient(Client)) { if (!Network.SyncClient(Client)) {
// TODO handle // TODO handle
} }
@@ -226,12 +231,20 @@ void TServer::GlobalParser(const std::weak_ptr<TClient>& Client, std::vector<uin
} }
return; return;
case 'O': case 'O':
if (udp) {
beammp_debugf("Received 'O' packet over UDP from client '{}' ({}), ignoring it", LockedClient->GetName(), LockedClient->GetID());
return;
}
if (Packet.size() > 1000) { if (Packet.size() > 1000) {
beammp_debug(("Received data from: ") + LockedClient->GetName() + (" Size: ") + std::to_string(Packet.size())); beammp_debug(("Received data from: ") + LockedClient->GetName() + (" Size: ") + std::to_string(Packet.size()));
} }
ParseVehicle(*LockedClient, StringPacket, Network); ParseVehicle(*LockedClient, StringPacket, Network);
return; return;
case 'C': { case 'C': {
if (udp) {
beammp_debugf("Received 'C' packet over UDP from client '{}' ({}), ignoring it", LockedClient->GetName(), LockedClient->GetID());
return;
}
if (Packet.size() < 4 || std::find(Packet.begin() + 3, Packet.end(), ':') == Packet.end()) if (Packet.size() < 4 || std::find(Packet.begin() + 3, Packet.end(), ':') == Packet.end())
break; break;
const auto PacketAsString = std::string(reinterpret_cast<const char*>(Packet.data()), Packet.size()); const auto PacketAsString = std::string(reinterpret_cast<const char*>(Packet.data()), Packet.size());
@@ -244,6 +257,10 @@ void TServer::GlobalParser(const std::weak_ptr<TClient>& Client, std::vector<uin
beammp_debugf("Empty chat message received from '{}' ({}), ignoring it", LockedClient->GetName(), LockedClient->GetID()); beammp_debugf("Empty chat message received from '{}' ({}), ignoring it", LockedClient->GetName(), LockedClient->GetID());
return; return;
} }
if (Message.size() > 500) {
beammp_debugf("Chat message too long from '{}' ({}), ignoring it", LockedClient->GetName(), LockedClient->GetID());
return;
}
auto Futures = LuaAPI::MP::Engine->TriggerEvent("onChatMessage", "", LockedClient->GetID(), LockedClient->GetName(), Message); auto Futures = LuaAPI::MP::Engine->TriggerEvent("onChatMessage", "", LockedClient->GetID(), LockedClient->GetName(), Message);
TLuaEngine::WaitForAll(Futures); TLuaEngine::WaitForAll(Futures);
LogChatMessage(LockedClient->GetName(), LockedClient->GetID(), PacketAsString.substr(PacketAsString.find(':', 3) + 1)); LogChatMessage(LockedClient->GetName(), LockedClient->GetID(), PacketAsString.substr(PacketAsString.find(':', 3) + 1));
@@ -262,6 +279,10 @@ void TServer::GlobalParser(const std::weak_ptr<TClient>& Client, std::vector<uin
return; return;
} }
case 'E': case 'E':
if (udp) {
beammp_debugf("Received 'E' packet over UDP from client '{}' ({}), ignoring it", LockedClient->GetName(), LockedClient->GetID());
return;
}
HandleEvent(*LockedClient, StringPacket); HandleEvent(*LockedClient, StringPacket);
return; return;
case 'N': case 'N':
@@ -273,7 +294,8 @@ void TServer::GlobalParser(const std::weak_ptr<TClient>& Client, std::vector<uin
int PID = -1; int PID = -1;
int VID = -1; int VID = -1;
auto MaybePidVid = GetPidVid(StringPacket.substr(3).substr(0, StringPacket.substr(3).find(':', 1))); auto pidVidPart = StringPacket.substr(3);
auto MaybePidVid = GetPidVid(pidVidPart.substr(0, pidVidPart.find(':')));
if (MaybePidVid) { if (MaybePidVid) {
std::tie(PID, VID) = MaybePidVid.value(); std::tie(PID, VID) = MaybePidVid.value();
} }
@@ -304,6 +326,15 @@ void TServer::HandleEvent(TClient& c, const std::string& RawData) {
} }
std::string Name = RawData.substr(2, NameDataSep - 2); std::string Name = RawData.substr(2, NameDataSep - 2);
std::string Data = RawData.substr(NameDataSep + 1); std::string Data = RawData.substr(NameDataSep + 1);
std::vector<std::string> exclude = {"onInit", "onFileChanged","onVehicleDeleted","onConsoleInput","onPlayerAuth","postPlayerAuth", "onPlayerDisconnect",
"onPlayerConnecting","onPlayerJoining","onPlayerJoin","onChatMessage","postChatMessage","onVehicleSpawn","postVehicleSpawn","onVehicleEdited", "postVehicleEdited",
"onVehicleReset","onVehiclePaintChanged","onShutdown"};
if (std::ranges::find(exclude, Name) != exclude.end()) {
beammp_debugf("Excluded event triggered by client '{}' ({}): '{}', ignoring.", c.GetName(), c.GetID(), Name);
return;
}
LuaAPI::MP::Engine->ReportErrors(LuaAPI::MP::Engine->TriggerEvent(Name, "", c.GetID(), Data)); LuaAPI::MP::Engine->ReportErrors(LuaAPI::MP::Engine->TriggerEvent(Name, "", c.GetID(), Data));
} }
+1 -1
Submodule vcpkg updated: 6978381401...5bf0c55239
+8 -1
View File
@@ -15,5 +15,12 @@
"rapidjson", "rapidjson",
"sol2", "sol2",
"curl" "curl"
] ],
"overrides": [
{
"name": "sol2",
"version": "3.3.1"
}
],
"builtin-baseline": "5bf0c55239da398b8c6f450818c9e28d36bf9966"
} }