Compare commits

..

1 Commits

41 changed files with 254 additions and 792 deletions
+10 -11
View File
@@ -3,8 +3,8 @@ name: Linux
on: on:
push: push:
branches: branches:
- "develop" - 'develop'
- "minor" - 'minor'
pull_request: pull_request:
env: env:
@@ -20,9 +20,9 @@ jobs:
matrix: matrix:
include: include:
- distro: debian - distro: debian
version: 12 version: 11
- distro: debian - distro: debian
version: 13 version: 12
- distro: ubuntu - distro: ubuntu
version: 22.04 version: 22.04
- distro: ubuntu - distro: ubuntu
@@ -47,8 +47,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
@@ -85,16 +84,16 @@ jobs:
run: ./bin/BeamMP-Server-tests run: ./bin/BeamMP-Server-tests
arm64-matrix: arm64-matrix:
runs-on: ubuntu-22.04-arm runs-on: [Linux, ARM64]
env: env:
VCPKG_DEFAULT_TRIPLET: "arm64-linux" VCPKG_DEFAULT_TRIPLET: "arm64-linux"
strategy: strategy:
matrix: matrix:
include: include:
- distro: debian - distro: debian
version: 12 version: 11
- distro: debian - distro: debian
version: 13 version: 12
- distro: ubuntu - distro: ubuntu
version: 22.04 version: 22.04
- distro: ubuntu - distro: ubuntu
@@ -119,8 +118,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
@@ -155,3 +153,4 @@ jobs:
- name: Test - name: Test
run: ./bin/BeamMP-Server-tests run: ./bin/BeamMP-Server-tests
+9 -12
View File
@@ -3,7 +3,7 @@ on:
push: push:
# Sequence of patterns matched against refs/tags # Sequence of patterns matched against refs/tags
tags: tags:
- "v*" # Push events to matching v*, i.e. v1.0, v20.15.10 - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10
env: env:
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite" VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
@@ -39,9 +39,9 @@ jobs:
matrix: matrix:
include: include:
- distro: debian - distro: debian
version: 12 version: 11
- distro: debian - distro: debian
version: 13 version: 12
- distro: ubuntu - distro: ubuntu
version: 22.04 version: 22.04
- distro: ubuntu - distro: ubuntu
@@ -66,8 +66,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
@@ -105,15 +104,15 @@ jobs:
asset_content_type: application/x-elf asset_content_type: application/x-elf
arm64-matrix: arm64-matrix:
runs-on: ubuntu-22.04-arm runs-on: [Linux, ARM64]
needs: create-release needs: create-release
strategy: strategy:
matrix: matrix:
include: include:
- distro: debian - distro: debian
version: 12 version: 11
- distro: debian - distro: debian
version: 13 version: 12
- distro: ubuntu - distro: ubuntu
version: 22.04 version: 22.04
- distro: ubuntu - distro: ubuntu
@@ -141,8 +140,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
@@ -195,8 +193,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,7 +26,6 @@ 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
+1 -2
View File
@@ -148,8 +148,7 @@ if(UNIX)
endif(UNIX) endif(UNIX)
if (WIN32) if (WIN32)
add_compile_definitions(_WIN32_WINNT=0x0A00) add_compile_options("-D_WIN32_WINNT=0x0601")
add_compile_options("/bigobj") add_compile_options("/bigobj")
endif(WIN32) endif(WIN32)
+3 -7
View File
@@ -24,7 +24,6 @@
#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"
@@ -57,14 +56,14 @@ public:
~TClient(); ~TClient();
TClient& operator=(const TClient&) = delete; TClient& operator=(const TClient&) = delete;
void AddNewCar(int Ident, const nlohmann::json& Data); void AddNewCar(int Ident, const std::string& Data);
void SetCarData(int Ident, const nlohmann::json& Data); void SetCarData(int Ident, const std::string& Data);
void SetCarPosition(int Ident, const std::string& Data); void SetCarPosition(int Ident, const std::string& Data);
TVehicleDataLockPair GetAllCars(); TVehicleDataLockPair GetAllCars();
void SetName(const std::string& Name) { mName = Name; } void SetName(const std::string& Name) { mName = Name; }
void SetRoles(const std::string& Role) { mRole = Role; } void SetRoles(const std::string& Role) { mRole = Role; }
void SetIdentifier(const std::string& key, const std::string& value) { mIdentifiers[key] = value; } void SetIdentifier(const std::string& key, const std::string& value) { mIdentifiers[key] = value; }
nlohmann::json GetCarData(int Ident); std::string GetCarData(int Ident);
std::string GetCarPositionRaw(int Ident); std::string GetCarPositionRaw(int Ident);
void SetUDPAddr(const ip::udp::endpoint& Addr) { mUDPAddress = Addr; } void SetUDPAddr(const ip::udp::endpoint& Addr) { mUDPAddress = Addr; }
void SetTCPSock(ip::tcp::socket&& CSock) { mSocket = std::move(CSock); } void SetTCPSock(ip::tcp::socket&& CSock) { mSocket = std::move(CSock); }
@@ -102,8 +101,6 @@ 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);
@@ -128,7 +125,6 @@ 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 -5
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, 7, 0 }; } static Version ClientMinimumVersion() { return Version { 2, 2, 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; }
@@ -86,8 +86,6 @@ public:
}; };
} }
static std::string GetServerCheckUrl() { return "https://check.beammp.com"; }
static std::string GetBackendUrlForAuth() { return "https://auth.beammp.com"; } static std::string GetBackendUrlForAuth() { return "https://auth.beammp.com"; }
static std::string GetBackendUrlForSocketIO() { return "https://backend.beammp.com"; } static std::string GetBackendUrlForSocketIO() { return "https://backend.beammp.com"; }
static void CheckForUpdates(); static void CheckForUpdates();
@@ -129,11 +127,10 @@ 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, 9, 2 }; static inline Version mVersion { 3, 8, 1 };
}; };
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);
std::string LowerString(std::string str);
std::string ThreadName(bool DebugModeOverride = false); std::string ThreadName(bool DebugModeOverride = false);
void RegisterThread(const std::string& str); void RegisterThread(const std::string& str);
-2
View File
@@ -26,9 +26,7 @@ enum class Key {
// provider settings // provider settings
PROVIDER_UPDATE_MESSAGE, PROVIDER_UPDATE_MESSAGE,
PROVIDER_DISABLE_CONFIG, PROVIDER_DISABLE_CONFIG,
PROVIDER_DISABLE_MP_SET,
PROVIDER_PORT_ENV, PROVIDER_PORT_ENV,
PROVIDER_IP_ENV
}; };
std::optional<std::string> Get(Key key); std::optional<std::string> Get(Key key);
+1 -2
View File
@@ -34,9 +34,8 @@ namespace MP {
std::pair<bool, std::string> TriggerClientEventJson(int PlayerID, const std::string& EventName, const sol::table& Data); std::pair<bool, std::string> TriggerClientEventJson(int PlayerID, const std::string& EventName, const sol::table& Data);
inline size_t GetPlayerCount() { return Engine->Server().ClientCount(); } inline size_t GetPlayerCount() { return Engine->Server().ClientCount(); }
std::pair<bool, std::string> DropPlayer(int ID, std::optional<std::string> MaybeReason); std::pair<bool, std::string> DropPlayer(int ID, std::optional<std::string> MaybeReason);
std::pair<bool, std::string> SendChatMessage(int ID, const std::string& Message, const bool& LogChat = true); std::pair<bool, std::string> SendChatMessage(int ID, const std::string& Message);
std::pair<bool, std::string> SendNotification(int ID, const std::string& Message, const std::string& Icon, const std::string& Category); std::pair<bool, std::string> SendNotification(int ID, const std::string& Message, const std::string& Icon, const std::string& Category);
std::pair<bool, std::string> ConfirmationDialog(int ID, const std::string& Title, const std::string& Body, const sol::table& buttons, const std::string& InteractionID, const bool& warning = false, const bool& reportToServer = true, const bool& reportToExtensions = true);
std::pair<bool, std::string> RemoveVehicle(int PlayerID, int VehicleID); std::pair<bool, std::string> RemoveVehicle(int PlayerID, int VehicleID);
void Set(int ConfigID, sol::object NewValue); void Set(int ConfigID, sol::object NewValue);
TLuaValue Get(int ConfigID); TLuaValue Get(int ConfigID);
-1
View File
@@ -79,7 +79,6 @@ struct Settings {
General_Map, General_Map,
General_AuthKey, General_AuthKey,
General_Private, General_Private,
General_IP,
General_Port, General_Port,
General_MaxCars, General_MaxCars,
General_LogChat, General_LogChat,
-6
View File
@@ -59,9 +59,6 @@ private:
void Command_Settings(const std::string& cmd, const std::vector<std::string>& args); void Command_Settings(const std::string& cmd, const std::vector<std::string>& args);
void Command_Clear(const std::string&, const std::vector<std::string>& args); void Command_Clear(const std::string&, const std::vector<std::string>& args);
void Command_Version(const std::string& cmd, const std::vector<std::string>& args); void Command_Version(const std::string& cmd, const std::vector<std::string>& args);
void Command_ProtectMod(const std::string& cmd, const std::vector<std::string>& args);
void Command_ReloadMods(const std::string& cmd, const std::vector<std::string>& args);
void Command_NetTest(const std::string& cmd, const std::vector<std::string>& args);
void Command_Say(const std::string& FullCommand); void Command_Say(const std::string& FullCommand);
bool EnsureArgsCount(const std::vector<std::string>& args, size_t n); bool EnsureArgsCount(const std::vector<std::string>& args, size_t n);
@@ -80,9 +77,6 @@ private:
{ "clear", [this](const auto& a, const auto& b) { Command_Clear(a, b); } }, { "clear", [this](const auto& a, const auto& b) { Command_Clear(a, b); } },
{ "say", [this](const auto&, const auto&) { Command_Say(""); } }, // shouldn't actually be called { "say", [this](const auto&, const auto&) { Command_Say(""); } }, // shouldn't actually be called
{ "version", [this](const auto& a, const auto& b) { Command_Version(a, b); } }, { "version", [this](const auto& a, const auto& b) { Command_Version(a, b); } },
{ "protectmod", [this](const auto& a, const auto& b) { Command_ProtectMod(a, b); } },
{ "reloadmods", [this](const auto& a, const auto& b) { Command_ReloadMods(a, b); } },
{ "nettest", [this](const auto& a, const auto& b) { Command_NetTest(a, b); } },
}; };
std::unique_ptr<Commandline> mCommandline { nullptr }; std::unique_ptr<Commandline> mCommandline { nullptr };
+3 -1
View File
@@ -192,7 +192,9 @@ 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) {
Results.push_back(EnqueueFunctionCall(Event.first, Function, Arguments, EventName)); auto Result = EnqueueFunctionCall(Event.first, Function, Arguments, EventName);
Results.push_back(Result);
AddResultToCheck(Result);
} }
} }
} }
+6 -13
View File
@@ -34,11 +34,9 @@ public:
[[nodiscard]] bool TCPSend(TClient& c, const std::vector<uint8_t>& Data, bool IsSync = false); [[nodiscard]] bool TCPSend(TClient& c, const std::vector<uint8_t>& Data, bool IsSync = false);
[[nodiscard]] bool SendLarge(TClient& c, std::vector<uint8_t> Data, bool isSync = false); [[nodiscard]] bool SendLarge(TClient& c, std::vector<uint8_t> Data, bool isSync = false);
[[nodiscard]] bool Respond(TClient& c, const std::vector<uint8_t>& MSG, bool Rel, bool isSync = false); [[nodiscard]] bool Respond(TClient& c, const std::vector<uint8_t>& MSG, bool Rel, bool isSync = false);
std::shared_ptr<TClient> CreateClient(boost::asio::ip::tcp::socket&& TCPSock); std::shared_ptr<TClient> CreateClient(ip::tcp::socket&& TCPSock);
std::vector<uint8_t> TCPRcv(TClient& c); std::vector<uint8_t> TCPRcv(TClient& c);
void ClientKick(TClient& c, const std::string& R); void ClientKick(TClient& c, const std::string& R);
void DisconnectClient(const std::weak_ptr<TClient>& c, const std::string& R);
void DisconnectClient(TClient& c, const std::string& R);
[[nodiscard]] bool SyncClient(const std::weak_ptr<TClient>& c); [[nodiscard]] bool SyncClient(const std::weak_ptr<TClient>& c);
void Identify(TConnection&& client); void Identify(TConnection&& client);
std::shared_ptr<TClient> Authentication(TConnection&& ClientConnection); std::shared_ptr<TClient> Authentication(TConnection&& ClientConnection);
@@ -46,9 +44,6 @@ public:
[[nodiscard]] bool UDPSend(TClient& Client, std::vector<uint8_t> Data); [[nodiscard]] bool UDPSend(TClient& Client, std::vector<uint8_t> Data);
void SendToAll(TClient* c, const std::vector<uint8_t>& Data, bool Self, bool Rel); void SendToAll(TClient* c, const std::vector<uint8_t>& Data, bool Self, bool Rel);
void UpdatePlayer(TClient& Client); void UpdatePlayer(TClient& Client);
boost::system::error_code ReadWithTimeout(TConnection& Connection, void* Buf, size_t Len, std::chrono::steady_clock::duration Timeout);
TResourceManager& ResourceManager() const { return mResourceManager; }
private: private:
void UDPServerMain(); void UDPServerMain();
@@ -56,15 +51,13 @@ private:
TServer& mServer; TServer& mServer;
TPPSMonitor& mPPSMonitor; TPPSMonitor& mPPSMonitor;
boost::asio::ip::udp::socket mUDPSock; ip::udp::socket mUDPSock;
TResourceManager& mResourceManager; TResourceManager& mResourceManager;
std::thread mUDPThread; std::thread mUDPThread;
std::thread mTCPThread; std::thread mTCPThread;
std::mutex mOpenIDMutex; std::mutex mOpenIDMutex;
std::map<std::string, uint16_t> mClientMap;
std::mutex mClientMapMutex;
std::vector<uint8_t> UDPRcvFromClient(boost::asio::ip::udp::endpoint& ClientEndpoint); std::vector<uint8_t> UDPRcvFromClient(ip::udp::endpoint& ClientEndpoint);
void OnConnect(const std::weak_ptr<TClient>& c); void OnConnect(const std::weak_ptr<TClient>& c);
void TCPClient(const std::weak_ptr<TClient>& c); void TCPClient(const std::weak_ptr<TClient>& c);
void Looper(const std::weak_ptr<TClient>& c); void Looper(const std::weak_ptr<TClient>& c);
@@ -72,9 +65,9 @@ private:
void OnDisconnect(const std::weak_ptr<TClient>& ClientPtr); void OnDisconnect(const std::weak_ptr<TClient>& ClientPtr);
void Parse(TClient& c, const std::vector<uint8_t>& Packet); void Parse(TClient& c, const std::vector<uint8_t>& Packet);
void SendFile(TClient& c, const std::string& Name); void SendFile(TClient& c, const std::string& Name);
static bool TCPSendRaw(TClient& C, boost::asio::ip::tcp::socket& socket, const uint8_t* Data, size_t Size); static bool TCPSendRaw(TClient& C, ip::tcp::socket& socket, const uint8_t* Data, size_t Size);
void SendFileToClient(TClient& c, size_t Size, const std::string& Name); static void SendFileToClient(TClient& c, size_t Size, const std::string& Name);
static const uint8_t* SendSplit(TClient& c, boost::asio::ip::tcp::socket& Socket, const uint8_t* DataPtr, size_t Size); static const uint8_t* SendSplit(TClient& c, ip::tcp::socket& Socket, const uint8_t* DataPtr, size_t Size);
}; };
std::string HashPassword(const std::string& str); std::string HashPassword(const std::string& str);
+2 -2
View File
@@ -30,10 +30,10 @@ public:
[[nodiscard]] std::string TrimmedList() const { return mTrimmedList; } [[nodiscard]] std::string TrimmedList() const { return mTrimmedList; }
[[nodiscard]] std::string FileSizes() const { return mFileSizes; } [[nodiscard]] std::string FileSizes() const { return mFileSizes; }
[[nodiscard]] int ModsLoaded() const { return mModsLoaded; } [[nodiscard]] int ModsLoaded() const { return mModsLoaded; }
[[nodiscard]] nlohmann::json GetMods() const { return mMods; }
[[nodiscard]] std::string NewFileList() const;
void RefreshFiles(); void RefreshFiles();
void SetProtected(const std::string& ModName, bool Protected);
private: private:
size_t mMaxModSize = 0; size_t mMaxModSize = 0;
+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, bool udp); void GlobalParser(const std::weak_ptr<TClient>& Client, std::vector<uint8_t>&& Packet, TPPSMonitor& PPSMonitor, TNetwork& Network);
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 -7
View File
@@ -18,12 +18,11 @@
#pragma once #pragma once
#include <nlohmann/json.hpp>
#include <string> #include <string>
class TVehicleData final { class TVehicleData final {
public: public:
TVehicleData(int ID, nlohmann::json Data); TVehicleData(int ID, std::string Data);
~TVehicleData(); ~TVehicleData();
// We cannot delete this, since vector needs to be able to copy when it resizes. // We cannot delete this, since vector needs to be able to copy when it resizes.
// Deleting this causes some wacky template errors which are hard to decipher, // Deleting this causes some wacky template errors which are hard to decipher,
@@ -33,16 +32,14 @@ public:
[[nodiscard]] bool IsInvalid() const { return mID == -1; } [[nodiscard]] bool IsInvalid() const { return mID == -1; }
[[nodiscard]] int ID() const { return mID; } [[nodiscard]] int ID() const { return mID; }
[[nodiscard]] nlohmann::json Data() const { return mData; } [[nodiscard]] std::string Data() const { return mData; }
[[nodiscard]] std::string DataAsPacket(const std::string& Role, const std::string& Name, int ID) const; void SetData(const std::string& Data) { mData = Data; }
void SetData(const nlohmann::json& Data) { mData = Data; }
bool operator==(const TVehicleData& v) const { return mID == v.mID; } bool operator==(const TVehicleData& v) const { return mID == v.mID; }
private: private:
int mID { -1 }; int mID { -1 };
nlohmann::json mData; std::string mData;
}; };
// TODO: unused now, remove? // TODO: unused now, remove?
+1 -1
View File
@@ -4,4 +4,4 @@ set -ex
./vcpkg/bootstrap-vcpkg.sh ./vcpkg/bootstrap-vcpkg.sh
cmake . -B bin $1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-O3 -g -Wl,-z,norelro -Wl,--hash-style=gnu -Wl,-z,noseparate-code -ffunction-sections -fdata-sections -Wl,--gc-sections -Wl,--export-dynamic" -DBeamMP-Server_ENABLE_LTO=ON cmake . -B bin $1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-O3 -g -Wl,-z,norelro -Wl,--hash-style=gnu -Wl,-z,noseparate-code -ffunction-sections -fdata-sections -Wl,--gc-sections" -DBeamMP-Server_ENABLE_LTO=ON
+1 -1
View File
@@ -4,4 +4,4 @@ set -ex
./vcpkg/bootstrap-vcpkg.sh ./vcpkg/bootstrap-vcpkg.sh
cmake . -B bin $1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-O3 -g -Wl,-z,norelro -Wl,--hash-style=gnu -Wl,-z,noseparate-code -ffunction-sections -fdata-sections -Wl,--gc-sections -Wl,--export-dynamic" -DBeamMP-Server_ENABLE_LTO=ON cmake . -B bin $1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-O3 -g -Wl,-z,norelro -Wl,--hash-style=gnu -Wl,-z,noseparate-code -ffunction-sections -fdata-sections -Wl,--gc-sections" -DBeamMP-Server_ENABLE_LTO=ON
-7
View File
@@ -1,7 +0,0 @@
#!/bin/bash
set -ex
apt-get update -y
apt-get install -y liblua5.3-0 liblua5.3-dev curl zip unzip tar cmake make git g++ ninja-build
-7
View File
@@ -1,7 +0,0 @@
#!/bin/bash
set -ex
git config --global --add safe.directory $(pwd)
git config --global --add safe.directory $(pwd)/vcpkg
git config --global --add safe.directory $(pwd)/deps/commandline
-7
View File
@@ -1,7 +0,0 @@
#!/bin/bash
set -ex
./vcpkg/bootstrap-vcpkg.sh
cmake . -B bin $1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-O3 -g -Wl,-z,norelro -Wl,--hash-style=gnu -Wl,-z,noseparate-code -ffunction-sections -fdata-sections -Wl,--gc-sections -Wl,--export-dynamic" -DBeamMP-Server_ENABLE_LTO=ON
-5
View File
@@ -1,5 +0,0 @@
#!/bin/bash
set -ex
cmake --build bin --parallel -t BeamMP-Server-tests
-10
View File
@@ -1,10 +0,0 @@
#!/bin/bash
set -ex
cmake --build bin --parallel -t BeamMP-Server
objcopy --only-keep-debug bin/BeamMP-Server bin/BeamMP-Server.debug
objcopy --add-gnu-debuglink bin/BeamMP-Server bin/BeamMP-Server.debug
strip -s bin/BeamMP-Server
@@ -1,8 +0,0 @@
#!/bin/bash
set -ex
apt-get update -y
apt-get install -y liblua5.3-0 curl
+1 -1
View File
@@ -4,4 +4,4 @@ set -ex
./vcpkg/bootstrap-vcpkg.sh ./vcpkg/bootstrap-vcpkg.sh
cmake . -B bin $1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-O3 -g -Wl,-z,norelro -Wl,--hash-style=gnu -Wl,-z,noseparate-code -ffunction-sections -fdata-sections -Wl,--gc-sections -Wl,--export-dynamic" -DBeamMP-Server_ENABLE_LTO=ON cmake . -B bin $1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-O3 -g -Wl,-z,norelro -Wl,--hash-style=gnu -Wl,-z,noseparate-code -ffunction-sections -fdata-sections -Wl,--gc-sections" -DBeamMP-Server_ENABLE_LTO=ON
+1 -1
View File
@@ -4,4 +4,4 @@ set -ex
./vcpkg/bootstrap-vcpkg.sh ./vcpkg/bootstrap-vcpkg.sh
cmake . -B bin $1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-O3 -g -Wl,-z,norelro -Wl,--hash-style=gnu -Wl,-z,noseparate-code -ffunction-sections -fdata-sections -Wl,--gc-sections -Wl,--export-dynamic" -DBeamMP-Server_ENABLE_LTO=ON cmake . -B bin $1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-O3 -g -Wl,-z,norelro -Wl,--hash-style=gnu -Wl,-z,noseparate-code -ffunction-sections -fdata-sections -Wl,--gc-sections" -DBeamMP-Server_ENABLE_LTO=ON
+5 -4
View File
@@ -57,7 +57,7 @@ int TClient::GetOpenCarID() const {
return OpenID; return OpenID;
} }
void TClient::AddNewCar(int Ident, const nlohmann::json& Data) { void TClient::AddNewCar(int Ident, const std::string& Data) {
std::unique_lock lock(mVehicleDataMutex); std::unique_lock lock(mVehicleDataMutex);
mVehicleData.emplace_back(Ident, Data); mVehicleData.emplace_back(Ident, Data);
} }
@@ -84,6 +84,7 @@ void TClient::Disconnect(std::string_view Reason) {
if (ec) { if (ec) {
beammp_debugf("Failed to shutdown client socket: {}", ec.message()); beammp_debugf("Failed to shutdown client socket: {}", ec.message());
} }
mSocket.cancel();
mSocket.close(ec); mSocket.close(ec);
if (ec) { if (ec) {
beammp_debugf("Failed to close client socket: {}", ec.message()); beammp_debugf("Failed to close client socket: {}", ec.message());
@@ -98,7 +99,7 @@ void TClient::SetCarPosition(int Ident, const std::string& Data) {
mVehiclePosition[size_t(Ident)] = Data; mVehiclePosition[size_t(Ident)] = Data;
} }
nlohmann::json TClient::GetCarData(int Ident) { std::string TClient::GetCarData(int Ident) {
{ // lock { // lock
std::unique_lock lock(mVehicleDataMutex); std::unique_lock lock(mVehicleDataMutex);
for (auto& v : mVehicleData) { for (auto& v : mVehicleData) {
@@ -108,10 +109,10 @@ nlohmann::json TClient::GetCarData(int Ident) {
} }
} // unlock } // unlock
DeleteCar(Ident); DeleteCar(Ident);
return nlohmann::detail::value_t::null; return "";
} }
void TClient::SetCarData(int Ident, const nlohmann::json& Data) { void TClient::SetCarData(int Ident, const std::string& Data) {
{ // lock { // lock
std::unique_lock lock(mVehicleDataMutex); std::unique_lock lock(mVehicleDataMutex);
for (auto& v : mVehicleData) { for (auto& v : mVehicleData) {
-7
View File
@@ -384,13 +384,6 @@ void SplitString(const std::string& str, const char delim, std::vector<std::stri
out.push_back(str.substr(start, end - start)); out.push_back(str.substr(start, end - start));
} }
} }
std::string LowerString(std::string str) {
std::ranges::transform(str, str.begin(), ::tolower);
return str;
}
static constexpr size_t STARTING_MAX_DECOMPRESSION_BUFFER_SIZE = 15 * 1024 * 1024; static constexpr size_t STARTING_MAX_DECOMPRESSION_BUFFER_SIZE = 15 * 1024 * 1024;
static constexpr size_t MAX_DECOMPRESSION_BUFFER_SIZE = 30 * 1024 * 1024; static constexpr size_t MAX_DECOMPRESSION_BUFFER_SIZE = 30 * 1024 * 1024;
-6
View File
@@ -36,15 +36,9 @@ std::string_view Env::ToString(Env::Key key) {
case Key::PROVIDER_DISABLE_CONFIG: case Key::PROVIDER_DISABLE_CONFIG:
return "BEAMMP_PROVIDER_DISABLE_CONFIG"; return "BEAMMP_PROVIDER_DISABLE_CONFIG";
break; break;
case Key::PROVIDER_DISABLE_MP_SET:
return "BEAMMP_PROVIDER_DISABLE_MP_SET";
break;
case Key::PROVIDER_PORT_ENV: case Key::PROVIDER_PORT_ENV:
return "BEAMMP_PROVIDER_PORT_ENV"; return "BEAMMP_PROVIDER_PORT_ENV";
break; break;
case Key::PROVIDER_IP_ENV:
return "BEAMMP_PROVIDER_IP_ENV";
break;
} }
return ""; return "";
} }
+4 -55
View File
@@ -148,11 +148,6 @@ static inline std::pair<bool, std::string> InternalTriggerClientEvent(int Player
return { false, "Invalid Player ID" }; return { false, "Invalid Player ID" };
} }
auto c = MaybeClient.value().lock(); auto c = MaybeClient.value().lock();
if (!c->IsSyncing() && !c->IsSynced()) {
return { false, "Player hasn't joined yet" };
}
if (!LuaAPI::MP::Engine->Network().Respond(*c, StringToVector(Packet), true)) { if (!LuaAPI::MP::Engine->Network().Respond(*c, StringToVector(Packet), true)) {
beammp_lua_errorf("Respond failed, dropping client {}", PlayerID); beammp_lua_errorf("Respond failed, dropping client {}", PlayerID);
LuaAPI::MP::Engine->Network().ClientKick(*c, "Disconnected after failing to receive packets"); LuaAPI::MP::Engine->Network().ClientKick(*c, "Disconnected after failing to receive packets");
@@ -178,13 +173,11 @@ std::pair<bool, std::string> LuaAPI::MP::DropPlayer(int ID, std::optional<std::s
return { true, "" }; return { true, "" };
} }
std::pair<bool, std::string> LuaAPI::MP::SendChatMessage(int ID, const std::string& Message, const bool& LogChat) { std::pair<bool, std::string> LuaAPI::MP::SendChatMessage(int ID, const std::string& Message) {
std::pair<bool, std::string> Result; std::pair<bool, std::string> Result;
std::string Packet = "C:Server: " + Message; std::string Packet = "C:Server: " + Message;
if (ID == -1) { if (ID == -1) {
if (LogChat) { LogChatMessage("<Server> (to everyone) ", -1, Message);
LogChatMessage("<Server> (to everyone) ", -1, Message);
}
Engine->Network().SendToAll(nullptr, StringToVector(Packet), true, true); Engine->Network().SendToAll(nullptr, StringToVector(Packet), true, true);
Result.first = true; Result.first = true;
} else { } else {
@@ -196,9 +189,7 @@ std::pair<bool, std::string> LuaAPI::MP::SendChatMessage(int ID, const std::stri
Result.second = "Player still syncing data"; Result.second = "Player still syncing data";
return Result; return Result;
} }
if (LogChat) { LogChatMessage("<Server> (to \"" + c->GetName() + "\")", -1, Message);
LogChatMessage("<Server> (to \"" + c->GetName() + "\")", -1, Message);
}
if (!Engine->Network().Respond(*c, StringToVector(Packet), true)) { if (!Engine->Network().Respond(*c, StringToVector(Packet), true)) {
beammp_errorf("Failed to send chat message back to sender (id {}) - did the sender disconnect?", ID); beammp_errorf("Failed to send chat message back to sender (id {}) - did the sender disconnect?", ID);
// TODO: should we return an error here? // TODO: should we return an error here?
@@ -245,48 +236,6 @@ std::pair<bool, std::string> LuaAPI::MP::SendNotification(int ID, const std::str
return Result; return Result;
} }
std::pair<bool, std::string> LuaAPI::MP::ConfirmationDialog(int ID, const std::string& Title, const std::string& Body, const sol::table& buttons, const std::string& InteractionID, const bool& warning, const bool& reportToServer, const bool& reportToExtensions) {
std::pair<bool, std::string> Result;
const nlohmann::json PacketBody = {
{ "title", Title },
{ "body", Body },
{ "buttons", nlohmann::json::parse(JsonEncode(buttons), nullptr, false) },
{ "interactionID", InteractionID },
{ "class", warning ? "experimental" : "" },
{ "reportToServer", reportToServer },
{ "reportToExtensions", reportToExtensions }
};
std::string Packet = "D" + PacketBody.dump();
if (ID == -1) {
Engine->Network().SendToAll(nullptr, StringToVector(Packet), true, true);
Result.first = true;
} else {
auto MaybeClient = GetClient(Engine->Server(), ID);
if (MaybeClient) {
auto c = MaybeClient.value().lock();
if (!c->IsSynced()) {
Result.first = false;
Result.second = "Player is not synced yet";
return Result;
}
if (!Engine->Network().Respond(*c, StringToVector(Packet), true)) {
beammp_errorf("Failed to send confirmation dialog to player (id {}) - did the player disconnect?", ID);
Result.first = false;
Result.second = "Failed to send packet";
}
Result.first = true;
} else {
beammp_lua_error("ConfirmationDialog invalid argument [1] invalid ID");
Result.first = false;
Result.second = "Invalid Player ID";
}
return Result;
}
return Result;
}
std::pair<bool, std::string> LuaAPI::MP::RemoveVehicle(int PID, int VID) { std::pair<bool, std::string> LuaAPI::MP::RemoveVehicle(int PID, int VID) {
std::pair<bool, std::string> Result; std::pair<bool, std::string> Result;
auto MaybeClient = GetClient(Engine->Server(), PID); auto MaybeClient = GetClient(Engine->Server(), PID);
@@ -297,7 +246,7 @@ std::pair<bool, std::string> LuaAPI::MP::RemoveVehicle(int PID, int VID) {
return Result; return Result;
} }
auto c = MaybeClient.value().lock(); auto c = MaybeClient.value().lock();
if (c->GetCarData(VID) != nlohmann::detail::value_t::null) { if (!c->GetCarData(VID).empty()) {
std::string Destroy = "Od:" + std::to_string(PID) + "-" + std::to_string(VID); std::string Destroy = "Od:" + std::to_string(PID) + "-" + std::to_string(VID);
LuaAPI::MP::Engine->ReportErrors(LuaAPI::MP::Engine->TriggerEvent("onVehicleDeleted", "", PID, VID)); LuaAPI::MP::Engine->ReportErrors(LuaAPI::MP::Engine->TriggerEvent("onVehicleDeleted", "", PID, VID));
Engine->Network().SendToAll(nullptr, StringToVector(Destroy), true, true); Engine->Network().SendToAll(nullptr, StringToVector(Destroy), true, true);
-2
View File
@@ -28,7 +28,6 @@ Settings::Settings() {
{ General_Map, std::string("/levels/gridmap_v2/info.json") }, { General_Map, std::string("/levels/gridmap_v2/info.json") },
{ General_AuthKey, std::string("") }, { General_AuthKey, std::string("") },
{ General_Private, true }, { General_Private, true },
{ General_IP, "::"},
{ General_Port, 30814 }, { General_Port, 30814 },
{ General_MaxCars, 1 }, { General_MaxCars, 1 },
{ General_LogChat, true }, { General_LogChat, true },
@@ -48,7 +47,6 @@ Settings::Settings() {
{ { "General", "Map" }, { General_Map, READ_WRITE } }, { { "General", "Map" }, { General_Map, READ_WRITE } },
{ { "General", "AuthKey" }, { General_AuthKey, NO_ACCESS } }, { { "General", "AuthKey" }, { General_AuthKey, NO_ACCESS } },
{ { "General", "Private" }, { General_Private, READ_ONLY } }, { { "General", "Private" }, { General_Private, READ_ONLY } },
{ { "General", "IP" }, { General_IP, READ_ONLY } },
{ { "General", "Port" }, { General_Port, READ_ONLY } }, { { "General", "Port" }, { General_Port, READ_ONLY } },
{ { "General", "MaxCars" }, { General_MaxCars, READ_WRITE } }, { { "General", "MaxCars" }, { General_MaxCars, READ_WRITE } },
{ { "General", "LogChat" }, { General_LogChat, READ_ONLY } }, { { "General", "LogChat" }, { General_LogChat, READ_ONLY } },
-10
View File
@@ -34,8 +34,6 @@ static constexpr std::string_view StrDebug = "Debug";
static constexpr std::string_view EnvStrDebug = "BEAMMP_DEBUG"; static constexpr std::string_view EnvStrDebug = "BEAMMP_DEBUG";
static constexpr std::string_view StrPrivate = "Private"; static constexpr std::string_view StrPrivate = "Private";
static constexpr std::string_view EnvStrPrivate = "BEAMMP_PRIVATE"; static constexpr std::string_view EnvStrPrivate = "BEAMMP_PRIVATE";
static constexpr std::string_view StrIP = "IP";
static constexpr std::string_view EnvStrIP = "BEAMMP_IP";
static constexpr std::string_view StrPort = "Port"; static constexpr std::string_view StrPort = "Port";
static constexpr std::string_view EnvStrPort = "BEAMMP_PORT"; static constexpr std::string_view EnvStrPort = "BEAMMP_PORT";
static constexpr std::string_view StrMaxCars = "MaxCars"; static constexpr std::string_view StrMaxCars = "MaxCars";
@@ -140,8 +138,6 @@ void TConfig::FlushToFile() {
data["General"][StrInformationPacket.data()] = Application::Settings.getAsBool(Settings::Key::General_InformationPacket); data["General"][StrInformationPacket.data()] = Application::Settings.getAsBool(Settings::Key::General_InformationPacket);
data["General"][StrAllowGuests.data()] = Application::Settings.getAsBool(Settings::Key::General_AllowGuests); data["General"][StrAllowGuests.data()] = Application::Settings.getAsBool(Settings::Key::General_AllowGuests);
SetComment(data["General"][StrAllowGuests.data()].comments(), " Whether to allow guests"); SetComment(data["General"][StrAllowGuests.data()].comments(), " Whether to allow guests");
data["General"][StrIP.data()] = Application::Settings.getAsString(Settings::Key::General_IP);
SetComment(data["General"][StrIP.data()].comments(), " The IP address to bind the server to, this is NOT related to your public IP. Can be used if your machine has multiple network interfaces");
data["General"][StrPort.data()] = Application::Settings.getAsInt(Settings::Key::General_Port); data["General"][StrPort.data()] = Application::Settings.getAsInt(Settings::Key::General_Port);
data["General"][StrName.data()] = Application::Settings.getAsString(Settings::Key::General_Name); data["General"][StrName.data()] = Application::Settings.getAsString(Settings::Key::General_Name);
SetComment(data["General"][StrTags.data()].comments(), " Add custom identifying tags to your server to make it easier to find. Format should be TagA,TagB,TagC. Note the comma seperation."); SetComment(data["General"][StrTags.data()].comments(), " Add custom identifying tags to your server to make it easier to find. Format should be TagA,TagB,TagC. Note the comma seperation.");
@@ -258,11 +254,6 @@ void TConfig::ParseFromFile(std::string_view name) {
} else { } else {
TryReadValue(data, "General", StrPort, EnvStrPort, Settings::Key::General_Port); TryReadValue(data, "General", StrPort, EnvStrPort, Settings::Key::General_Port);
} }
if (Env::Get(Env::Key::PROVIDER_IP_ENV).has_value()) {
TryReadValue(data, "General", StrIP, Env::Get(Env::Key::PROVIDER_IP_ENV).value(), Settings::Key::General_IP);
} else {
TryReadValue(data, "General", StrIP, EnvStrIP, Settings::Key::General_IP);
}
TryReadValue(data, "General", StrMaxCars, EnvStrMaxCars, Settings::Key::General_MaxCars); TryReadValue(data, "General", StrMaxCars, EnvStrMaxCars, Settings::Key::General_MaxCars);
TryReadValue(data, "General", StrMaxPlayers, EnvStrMaxPlayers, Settings::Key::General_MaxPlayers); TryReadValue(data, "General", StrMaxPlayers, EnvStrMaxPlayers, Settings::Key::General_MaxPlayers);
TryReadValue(data, "General", StrMap, EnvStrMap, Settings::Key::General_Map); TryReadValue(data, "General", StrMap, EnvStrMap, Settings::Key::General_Map);
@@ -313,7 +304,6 @@ void TConfig::PrintDebug() {
beammp_debug(std::string(StrPrivate) + ": " + std::string(Application::Settings.getAsBool(Settings::Key::General_Private) ? "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(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(StrPort) + ": " + std::to_string(Application::Settings.getAsInt(Settings::Key::General_Port)));
beammp_debug(std::string(StrIP) + ": \"" + Application::Settings.getAsString(Settings::Key::General_IP) + "\"");
beammp_debug(std::string(StrMaxCars) + ": " + std::to_string(Application::Settings.getAsInt(Settings::Key::General_MaxCars))); 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))); beammp_debug(std::string(StrMaxPlayers) + ": " + std::to_string(Application::Settings.getAsInt(Settings::Key::General_MaxPlayers)));
beammp_debug(std::string(StrMap) + ": \"" + Application::Settings.getAsString(Settings::Key::General_Map) + "\""); beammp_debug(std::string(StrMap) + ": \"" + Application::Settings.getAsString(Settings::Key::General_Map) + "\"");
+14 -67
View File
@@ -24,7 +24,6 @@
#include "CustomAssert.h" #include "CustomAssert.h"
#include "LuaAPI.h" #include "LuaAPI.h"
#include "TLuaEngine.h" #include "TLuaEngine.h"
#include "Http.h"
#include <ctime> #include <ctime>
#include <lua.hpp> #include <lua.hpp>
@@ -160,7 +159,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.empty()) { if (n == 0 && args.size() != 0) {
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 +197,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.empty()) { } else if (args.size() == 0) {
ChangeToLuaConsole(mDefaultStateId); ChangeToLuaConsole(mDefaultStateId);
} }
} }
@@ -209,18 +208,16 @@ void TConsole::Command_Help(const std::string&, const std::vector<std::string>&
} }
static constexpr const char* sHelpString = R"( static constexpr const char* sHelpString = R"(
Commands: Commands:
help displays this help help displays this help
exit shuts down the server exit shuts down the server
kick <name> [reason] kicks specified player with an optional reason kick <name> [reason] kicks specified player with an optional reason
list lists all players and info about them list lists all players and info about them
say <message> sends the message to all players in chat say <message> sends the message to all players in chat
lua [state id] switches to lua, optionally into a specific state id's lua lua [state id] switches to lua, optionally into a specific state id's lua
settings [command] sets or gets settings for the server, run `settings help` for more info settings [command] sets or gets settings for the server, run `settings help` for more info
status how the server is doing and what it's up to status how the server is doing and what it's up to
clear clears the console window clear clears the console window
version displays the server version version displays the server version)";
protectmod <name> <value> sets whether a mod is protected, value can be true or false
reloadmods reloads all mods from the Resources Client folder)";
Application::Console().WriteRaw("BeamMP-Server Console: " + std::string(sHelpString)); Application::Console().WriteRaw("BeamMP-Server Console: " + std::string(sHelpString));
} }
@@ -265,56 +262,6 @@ void TConsole::Command_Version(const std::string& cmd, const std::vector<std::st
std::string openssl_version = fmt::format("OpenSSL: v{}.{}.{}", OPENSSL_VERSION_MAJOR, OPENSSL_VERSION_MINOR, OPENSSL_VERSION_PATCH); std::string openssl_version = fmt::format("OpenSSL: v{}.{}.{}", OPENSSL_VERSION_MAJOR, OPENSSL_VERSION_MINOR, OPENSSL_VERSION_PATCH);
Application::Console().WriteRaw(openssl_version); Application::Console().WriteRaw(openssl_version);
} }
void TConsole::Command_ProtectMod(const std::string& cmd, const std::vector<std::string>& args) {
if (!EnsureArgsCount(args, 2)) {
return;
}
const auto& ModName = args.at(0);
const auto& Protect = args.at(1);
for (auto mod : mLuaEngine->Network().ResourceManager().GetMods()) {
if (mod["file_name"].get<std::string>() == ModName) {
mLuaEngine->Network().ResourceManager().SetProtected(ModName, Protect == "true");
Application::Console().WriteRaw("Mod " + ModName + " is now " + (Protect == "true" ? "protected" : "unprotected"));
return;
}
}
Application::Console().WriteRaw("Mod " + ModName + " not found.");
}
void TConsole::Command_ReloadMods(const std::string& cmd, const std::vector<std::string>& args) {
if (!EnsureArgsCount(args, 0)) {
return;
}
mLuaEngine->Network().ResourceManager().RefreshFiles();
Application::Console().WriteRaw("Mods reloaded.");
}
void TConsole::Command_NetTest(const std::string& cmd, const std::vector<std::string>& args) {
unsigned int status = 0;
std::string T = Http::GET(
Application::GetServerCheckUrl() + "/api/v2/beammp/" + std::to_string(Application::Settings.getAsInt(Settings::Key::General_Port)), &status
);
beammp_debugf("Status and response from Server Check API: {0}, {1}", status, T);
auto Doc = nlohmann::json::parse(T, nullptr, false);
if (Doc.is_discarded() || !Doc.is_object()) {
beammp_warn("Failed to parse Server Check API response, however the server will most likely still work correctly.");
} else {
std::string status = Doc["status"];
std::string details = "Response from Server Check API: " + std::string(Doc["details"]);
if (status == "ok") {
beammp_info(details);
} else {
beammp_warn(details);
}
}
}
void TConsole::Command_Kick(const std::string&, const std::vector<std::string>& args) { void TConsole::Command_Kick(const std::string&, const std::vector<std::string>& args) {
if (!EnsureArgsCount(args, 1, size_t(-1))) { if (!EnsureArgsCount(args, 1, size_t(-1))) {
@@ -423,7 +370,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.empty()) { if (args.size() == 0) {
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 +652,7 @@ void TConsole::RunAsCommand(const std::string& cmd, bool IgnoreNotACommand) {
} }
} }
} }
if (NonNilFutures.empty()) { if (NonNilFutures.size() == 0) {
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.");
} }
+54 -53
View File
@@ -22,7 +22,6 @@
#include "CustomAssert.h" #include "CustomAssert.h"
#include "Http.h" #include "Http.h"
#include "LuaAPI.h" #include "LuaAPI.h"
#include "Env.h"
#include "Profiling.h" #include "Profiling.h"
#include "TLuaPlugin.h" #include "TLuaPlugin.h"
#include "sol/object.hpp" #include "sol/object.hpp"
@@ -31,12 +30,30 @@
#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);
static std::optional<sol::function> GetLuaHandler(sol::state_view StateView, const std::string Handler, const std::string EventName);
static std::optional<sol::function> GetLuaHandler(sol::state_view StateView, const std::string Handler, const std::string EventName) {
if (!StateView)
return std::nullopt;
auto Res = StateView.safe_script("return " + Handler, sol::script_pass_on_error);
if (!Res.valid()) {
beammp_errorf("invalid handler for event \"{}\". handler: \"{}\"", EventName, Handler);
} else if (Res.get_type() == sol::type::function) {
return Res.get<sol::function>();
}
return std::nullopt;
}
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);
@@ -65,11 +82,10 @@ TEST_CASE("TLuaEngine ctor & dtor") {
void TLuaEngine::operator()() { void TLuaEngine::operator()() {
RegisterThread("LuaEngine"); RegisterThread("LuaEngine");
Application::SetSubsystemStatus("LuaEngine", Application::Status::Good);
// lua engine main thread // lua engine main thread
beammp_infof("Lua v{}.{}.{}", LUA_VERSION_MAJOR, LUA_VERSION_MINOR, LUA_VERSION_RELEASE); beammp_infof("Lua v{}.{}.{}", LUA_VERSION_MAJOR, LUA_VERSION_MINOR, LUA_VERSION_RELEASE);
CollectAndInitPlugins(); CollectAndInitPlugins();
Application::SetSubsystemStatus("LuaEngine", Application::Status::Good);
// now call all onInit's // now call all onInit's
auto Futures = TriggerEvent("onInit", ""); auto Futures = TriggerEvent("onInit", "");
WaitForAll(Futures, std::chrono::seconds(5)); WaitForAll(Futures, std::chrono::seconds(5));
@@ -128,7 +144,7 @@ void TLuaEngine::operator()() {
} }
} }
} }
if (mLuaStates.empty()) { if (mLuaStates.size() == 0) {
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 {
@@ -492,8 +508,11 @@ 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 Res = GetLuaHandler(mStateView, Handler, EventName);
if (Fn.valid()) { if (Res.has_value()) {
sol::function Fn = Res.value();
Fn = AddTraceback(mStateView, Fn);
auto LuaResult = Fn(LocalArgs); auto LuaResult = Fn(LocalArgs);
auto Result = std::make_shared<TLuaResult>(); auto Result = std::make_shared<TLuaResult>();
if (LuaResult.valid()) { if (LuaResult.valid()) {
@@ -501,7 +520,9 @@ sol::table TLuaEngine::StateThreadData::Lua_TriggerGlobalEvent(const std::string
Result->Result = LuaResult; Result->Result = LuaResult;
} else { } else {
Result->Error = true; Result->Error = true;
Result->ErrorMessage = "Function result in TriggerGlobalEvent was invalid"; sol::error Err = LuaResult;
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);
@@ -543,8 +564,9 @@ sol::table TLuaEngine::StateThreadData::Lua_TriggerLocalEvent(const std::string&
sol::table Result = mStateView.create_table(); sol::table Result = mStateView.create_table();
int i = 1; int i = 1;
for (const auto& Handler : mEngine->GetEventHandlersForState(EventName, mStateId)) { for (const auto& Handler : mEngine->GetEventHandlersForState(EventName, mStateId)) {
auto Fn = mStateView[Handler]; auto Res = GetLuaHandler(mStateView, Handler, EventName);
if (Fn.valid() && Fn.get_type() == sol::type::function) { if (Res.has_value()) {
sol::function Fn = Res.value();
auto FnRet = Fn(EventArgs); auto FnRet = Fn(EventArgs);
if (FnRet.valid()) { if (FnRet.valid()) {
Result.set(i, FnRet); Result.set(i, FnRet);
@@ -662,7 +684,7 @@ sol::table TLuaEngine::StateThreadData::Lua_GetPlayerVehicles(int ID) {
sol::state_view StateView(mState); sol::state_view StateView(mState);
sol::table Result = StateView.create_table(); sol::table Result = StateView.create_table();
for (const auto& v : VehicleData) { for (const auto& v : VehicleData) {
Result[v.ID()] = v.DataAsPacket(Client->GetRoles(), Client->GetName(), Client->GetID()).substr(3); Result[v.ID()] = v.Data().substr(3);
} }
return Result; return Result;
} else } else
@@ -727,25 +749,6 @@ static void AddToTable(sol::table& table, const std::string& left, const T& valu
} }
} }
static bool mDisableMPSet = [] {
auto DisableMPSet = Env::Get(Env::Key::PROVIDER_DISABLE_MP_SET).value_or("false");
return DisableMPSet == "true" || DisableMPSet == "1";
}();
static auto GetSettingName = [](int id) -> const char* {
switch (id) {
case 0: return "Debug";
case 1: return "Private";
case 2: return "MaxCars";
case 3: return "MaxPlayers";
case 4: return "Map";
case 5: return "Name";
case 6: return "Description";
case 7: return "InformationPacket";
default: return "Unknown";
}
};
static void JsonDecodeRecursive(sol::state_view& StateView, sol::table& table, const std::string& left, const nlohmann::json& right) { static void JsonDecodeRecursive(sol::state_view& StateView, sol::table& table, const std::string& left, const nlohmann::json& right) {
switch (right.type()) { switch (right.type()) {
case nlohmann::detail::value_t::null: case nlohmann::detail::value_t::null:
@@ -877,15 +880,7 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, TLuaStateI
MPTable.set_function("GetPositionRaw", [&](int PID, int VID) -> std::pair<sol::table, std::string> { MPTable.set_function("GetPositionRaw", [&](int PID, int VID) -> std::pair<sol::table, std::string> {
return Lua_GetPositionRaw(PID, VID); return Lua_GetPositionRaw(PID, VID);
}); });
MPTable.set_function("SendChatMessage", [&](sol::variadic_args Args) { MPTable.set_function("SendChatMessage", &LuaAPI::MP::SendChatMessage);
if (Args.size() == 2) {
LuaAPI::MP::SendChatMessage(Args.get<int>(0), Args.get<std::string>(1));
} else if (Args.size() == 3) {
LuaAPI::MP::SendChatMessage(Args.get<int>(0), Args.get<std::string>(1), Args.get<bool>(2));
} else {
beammp_lua_error("SendChatMessage expects 2 or 3 arguments.");
}
});
MPTable.set_function("SendNotification", [&](sol::variadic_args Args) { MPTable.set_function("SendNotification", [&](sol::variadic_args Args) {
if (Args.size() == 2) { if (Args.size() == 2) {
LuaAPI::MP::SendNotification(Args.get<int>(0), Args.get<std::string>(1), "", Args.get<std::string>(1)); LuaAPI::MP::SendNotification(Args.get<int>(0), Args.get<std::string>(1), "", Args.get<std::string>(1));
@@ -897,12 +892,6 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, TLuaStateI
beammp_lua_error("SendNotification expects 2, 3 or 4 arguments."); beammp_lua_error("SendNotification expects 2, 3 or 4 arguments.");
} }
}); });
MPTable.set_function("ConfirmationDialog", sol::overload(
&LuaAPI::MP::ConfirmationDialog,
[&](const int& ID, const std::string& Title, const std::string& Body, const sol::table& Buttons, const std::string& InteractionID) {
LuaAPI::MP::ConfirmationDialog(ID, Title, Body, Buttons, InteractionID);
}
));
MPTable.set_function("GetPlayers", [&]() -> sol::table { MPTable.set_function("GetPlayers", [&]() -> sol::table {
return Lua_GetPlayers(); return Lua_GetPlayers();
}); });
@@ -946,13 +935,7 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, TLuaStateI
MPTable.set_function("CancelEventTimer", [&](const std::string& EventName) { MPTable.set_function("CancelEventTimer", [&](const std::string& EventName) {
mEngine->CancelEventTimers(EventName, mStateId); mEngine->CancelEventTimers(EventName, mStateId);
}); });
if (mDisableMPSet) { MPTable.set_function("Set", &LuaAPI::MP::Set);
MPTable.set_function("Set", [this](int ConfigID, sol::object NewValue) {
beammp_lua_errorf("A script ({}) tried to call MP.Set to change setting '{}' but this was blocked by your server provider.", mStateId, GetSettingName(ConfigID));
});
} else {
MPTable.set_function("Set", &LuaAPI::MP::Set);
}
MPTable.set_function("Get", &LuaAPI::MP::Get); MPTable.set_function("Get", &LuaAPI::MP::Get);
auto UtilTable = StateView.create_named_table("Util"); auto UtilTable = StateView.create_named_table("Util");
@@ -1116,6 +1099,21 @@ 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()) {
@@ -1180,8 +1178,10 @@ 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 Fn = StateView[FnName];
if (Fn.valid() && Fn.get_type() == sol::type::function) { auto Res = GetLuaHandler(StateView, FnName, TheQueuedFunction.EventName);
if (Res.has_value()) {
sol::function Fn = Res.value();
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()) {
@@ -1216,6 +1216,7 @@ void TLuaEngine::StateThreadData::operator()() {
break; break;
} }
} }
Fn = AddTraceback(StateView, Fn);
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;
+59 -208
View File
@@ -32,16 +32,10 @@
#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;
static constexpr uint8_t MAX_CONCURRENT_CONNECTIONS = 10;
static constexpr uint8_t MAX_GLOBAL_CONNECTIONS = 128;
static constexpr uint8_t READ_TIMEOUT_S = 10; //seconds
std::vector<uint8_t> StringToVector(const std::string& Str) { std::vector<uint8_t> StringToVector(const std::string& Str) {
return std::vector<uint8_t>(Str.data(), Str.data() + Str.size()); return std::vector<uint8_t>(Str.data(), Str.data() + Str.size());
} }
@@ -91,17 +85,9 @@ TNetwork::TNetwork(TServer& Server, TPPSMonitor& PPSMonitor, TResourceManager& R
void TNetwork::UDPServerMain() { void TNetwork::UDPServerMain() {
RegisterThread("UDPServer"); RegisterThread("UDPServer");
// listen on all ipv6 addresses
ip::udp::endpoint UdpListenEndpoint(ip::make_address("::"), Application::Settings.getAsInt(Settings::Key::General_Port));
boost::system::error_code ec; boost::system::error_code ec;
auto address = boost::asio::ip::make_address(Application::Settings.getAsString(Settings::Key::General_IP), ec);
if (ec) {
beammp_errorf("Failed to parse IP: {}", ec.message());
Application::GracefullyShutdown();
}
boost::asio::ip::udp::endpoint UdpListenEndpoint(address, Application::Settings.getAsInt(Settings::Key::General_Port));
mUDPSock.open(UdpListenEndpoint.protocol(), ec); mUDPSock.open(UdpListenEndpoint.protocol(), ec);
if (ec) { if (ec) {
beammp_error("open() failed: " + ec.message()); beammp_error("open() failed: " + ec.message());
@@ -121,17 +107,17 @@ void TNetwork::UDPServerMain() {
Application::GracefullyShutdown(); Application::GracefullyShutdown();
} }
Application::SetSubsystemStatus("UDPNetwork", Application::Status::Good); Application::SetSubsystemStatus("UDPNetwork", Application::Status::Good);
beammp_info(("Vehicle data network online on port ") + std::to_string(UdpListenEndpoint.port()) + (" with a Max of ") beammp_info(("Vehicle data network online on port ") + std::to_string(Application::Settings.getAsInt(Settings::Key::General_Port)) + (" with a Max of ")
+ std::to_string(Application::Settings.getAsInt(Settings::Key::General_MaxPlayers)) + (" Clients")); + std::to_string(Application::Settings.getAsInt(Settings::Key::General_MaxPlayers)) + (" Clients"));
while (!Application::IsShuttingDown()) { while (!Application::IsShuttingDown()) {
try { try {
boost::asio::ip::udp::endpoint remote_client_ep {}; ip::udp::endpoint remote_client_ep {};
std::vector<uint8_t> Data = UDPRcvFromClient(remote_client_ep); std::vector<uint8_t> Data = UDPRcvFromClient(remote_client_ep);
if (Data.empty()) { if (Data.empty()) {
continue; continue;
} }
if (Data.size() == 1 && Data.at(0) == 'P') { if (Data.size() == 1 && Data.at(0) == 'P') {
mUDPSock.send_to(boost::asio::const_buffer("P", 1), remote_client_ep, {}, ec); mUDPSock.send_to(const_buffer("P", 1), remote_client_ep, {}, ec);
// ignore errors // ignore errors
(void)ec; (void)ec;
continue; continue;
@@ -152,30 +138,23 @@ void TNetwork::UDPServerMain() {
} }
if (Client->GetID() == ID) { if (Client->GetID() == ID) {
if (Client->GetUDPAddr() == boost::asio::ip::udp::endpoint {} && !Client->IsUDPConnected() && !Client->GetMagic().empty()) { // not initialized yet
if (Data.size() != 66) { if (Client->GetUDPAddr() == ip::udp::endpoint {} || !Client->IsUDPConnected()) {
beammp_debugf("Invalid size for UDP value. IP: {} ID: {}", remote_client_ep.address().to_string(), ID); // same IP (just a sanity check)
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, true); mServer.GlobalParser(ClientPtr, std::move(Data), mPPSMonitor, *this);
} else { } else {
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()); beammp_debugf("Ignored UDP packet due to remote address mismatch");
return false; return false;
} }
} }
@@ -191,17 +170,12 @@ void TNetwork::UDPServerMain() {
void TNetwork::TCPServerMain() { void TNetwork::TCPServerMain() {
RegisterThread("TCPServer"); RegisterThread("TCPServer");
// listen on all ipv6 addresses
auto port = uint16_t(Application::Settings.getAsInt(Settings::Key::General_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; boost::system::error_code ec;
auto address = boost::asio::ip::make_address(Application::Settings.getAsString(Settings::Key::General_IP), ec);
if (ec) {
beammp_errorf("Failed to parse IP: {}", ec.message());
return;
}
boost::asio::ip::tcp::endpoint ListenEp(address,
uint16_t(Application::Settings.getAsInt(Settings::Key::General_Port)));
boost::asio::ip::tcp::socket Listener(mServer.IoCtx());
Listener.open(ListenEp.protocol(), ec); Listener.open(ListenEp.protocol(), ec);
if (ec) { if (ec) {
beammp_errorf("Failed to open socket: {}", ec.message()); beammp_errorf("Failed to open socket: {}", ec.message());
@@ -226,7 +200,7 @@ void TNetwork::TCPServerMain() {
ec.message()); ec.message());
} }
boost::asio::ip::tcp::acceptor Acceptor(mServer.IoCtx(), ListenEp); ip::tcp::acceptor Acceptor(mServer.IoCtx(), ListenEp);
Acceptor.listen(socket_base::max_listen_connections, ec); Acceptor.listen(socket_base::max_listen_connections, ec);
if (ec) { if (ec) {
beammp_errorf("listen() failed, which is needed for the server to operate. " beammp_errorf("listen() failed, which is needed for the server to operate. "
@@ -235,7 +209,6 @@ void TNetwork::TCPServerMain() {
Application::GracefullyShutdown(); Application::GracefullyShutdown();
} }
Application::SetSubsystemStatus("TCPNetwork", Application::Status::Good); Application::SetSubsystemStatus("TCPNetwork", Application::Status::Good);
beammp_infof("Listening on {0} port {1}", ListenEp.address().to_string(), static_cast<uint16_t>(ListenEp.port()));
beammp_info("Vehicle event network online"); beammp_info("Vehicle event network online");
do { do {
try { try {
@@ -243,28 +216,14 @@ void TNetwork::TCPServerMain() {
beammp_debug("shutdown during TCP wait for accept loop"); beammp_debug("shutdown during TCP wait for accept loop");
break; break;
} }
boost::asio::ip::tcp::endpoint ClientEp; ip::tcp::endpoint ClientEp;
boost::asio::ip::tcp::socket ClientSocket = Acceptor.accept(ClientEp, ec); ip::tcp::socket ClientSocket = Acceptor.accept(ClientEp, ec);
std::string ClientIP = ClientEp.address().to_string(); if (ec) {
if (!ec) {
mClientMapMutex.lock();
if (mClientMap[ClientIP] >= MAX_CONCURRENT_CONNECTIONS) {
beammp_debugf("The connection was rejected for {}, as it had {} concurrent connections.", ClientIP, mClientMap[ClientIP]);
}
else if (mClientMap.size() >= MAX_GLOBAL_CONNECTIONS) {
beammp_debugf("The connection was rejected for {}, as there are {} global connections.", ClientIP, mClientMap.size());
}
else {
TConnection Conn { std::move(ClientSocket), ClientEp };
std::thread ID(&TNetwork::Identify, this, std::move(Conn));
ID.detach(); // TODO: Add to a queue and attempt to join periodically
mClientMap[ClientIP]++;
}
mClientMapMutex.unlock();
}
else {
beammp_errorf("Failed to accept() new client: {}", ec.message()); beammp_errorf("Failed to accept() new client: {}", ec.message());
} }
TConnection Conn { std::move(ClientSocket), ClientEp };
std::thread ID(&TNetwork::Identify, this, std::move(Conn));
ID.detach(); // TODO: Add to a queue and attempt to join periodically
} 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());
} }
@@ -280,22 +239,11 @@ void TNetwork::Identify(TConnection&& RawConnection) {
RegisterThreadAuto(); RegisterThreadAuto();
char Code; char Code;
boost::system::error_code ec = ReadWithTimeout(RawConnection, &Code, 1, std::chrono::seconds(READ_TIMEOUT_S)); boost::system::error_code ec;
read(RawConnection.Socket, buffer(&Code, 1), ec);
if (ec) { if (ec) {
// TODO: is this right?! // TODO: is this right?!
beammp_debug("Error occured reading code");
RawConnection.Socket.shutdown(socket_base::shutdown_both, ec); RawConnection.Socket.shutdown(socket_base::shutdown_both, ec);
mClientMapMutex.lock();
{
std::string ClientIP = RawConnection.SockAddr.address().to_string();
if (mClientMap[ClientIP] > 0) {
mClientMap[ClientIP]--;
}
if (mClientMap[ClientIP] == 0) {
mClientMap.erase(ClientIP);
}
}
mClientMapMutex.unlock();
return; return;
} }
std::shared_ptr<TClient> Client { nullptr }; std::shared_ptr<TClient> Client { nullptr };
@@ -306,7 +254,8 @@ void TNetwork::Identify(TConnection&& RawConnection) {
beammp_errorf("Old download packet detected - the client is wildly out of date, this will be ignored"); beammp_errorf("Old download packet detected - the client is wildly out of date, this will be ignored");
return; return;
} else if (Code == 'P') { } else if (Code == 'P') {
boost::asio::write(RawConnection.Socket, boost::asio::buffer("P"), ec); boost::system::error_code ec;
write(RawConnection.Socket, buffer("P"), ec);
return; return;
} else if (Code == 'I') { } else if (Code == 'I') {
const std::string Data = Application::Settings.getAsBool(Settings::Key::General_InformationPacket) ? THeartbeatThread::lastCall : ""; const std::string Data = Application::Settings.getAsBool(Settings::Key::General_InformationPacket) ? THeartbeatThread::lastCall : "";
@@ -318,25 +267,14 @@ void TNetwork::Identify(TConnection&& RawConnection) {
std::memcpy(ToSend.data() + sizeof(Size), Data.data(), Data.size()); std::memcpy(ToSend.data() + sizeof(Size), Data.data(), Data.size());
boost::system::error_code ec; boost::system::error_code ec;
boost::asio::write(RawConnection.Socket, boost::asio::buffer(ToSend), ec); write(RawConnection.Socket, buffer(ToSend), ec);
} else { } else {
beammp_errorf("Invalid code got in Identify: '{}'", Code); beammp_errorf("Invalid code got in Identify: '{}'", Code);
} }
} catch (const std::exception& e) { } catch (const std::exception& e) {
beammp_errorf("Error during handling of code {} - client left in invalid state, closing socket: {}", Code, e.what()); beammp_errorf("Error during handling of code {} - client left in invalid state, closing socket: {}", Code, e.what());
boost::system::error_code ec; boost::system::error_code ec;
RawConnection.Socket.shutdown(boost::asio::socket_base::shutdown_both, ec); RawConnection.Socket.shutdown(socket_base::shutdown_both, ec);
mClientMapMutex.lock();
{
std::string ClientIP = RawConnection.SockAddr.address().to_string();
if (mClientMap[ClientIP] > 0) {
mClientMap[ClientIP]--;
}
if (mClientMap[ClientIP] == 0) {
mClientMap.erase(ClientIP);
}
}
mClientMapMutex.unlock();
if (ec) { if (ec) {
beammp_debugf("Failed to shutdown client socket: {}", ec.message()); beammp_debugf("Failed to shutdown client socket: {}", ec.message());
} }
@@ -369,11 +307,6 @@ std::shared_ptr<TClient> TNetwork::Authentication(TConnection&& RawConnection) {
Client->SetIdentifier("ip", ip); Client->SetIdentifier("ip", ip);
beammp_tracef("This thread is ip {} ({})", ip, RawConnection.SockAddr.address().to_v6().is_v4_mapped() ? "IPv4 mapped IPv6" : "IPv6"); beammp_tracef("This thread is ip {} ({})", ip, RawConnection.SockAddr.address().to_v6().is_v4_mapped() ? "IPv4 mapped IPv6" : "IPv6");
if (Application::GetSubsystemStatuses().at("Main") == Application::Status::Starting) {
ClientKick(*Client, "The server is still starting, please try joining again later.");
return nullptr;
}
beammp_info("Identifying new ClientConnection..."); beammp_info("Identifying new ClientConnection...");
auto Data = TCPRcv(*Client); auto Data = TCPRcv(*Client);
@@ -434,7 +367,7 @@ std::shared_ptr<TClient> TNetwork::Authentication(TConnection&& RawConnection) {
try { try {
nlohmann::json AuthRes = nlohmann::json::parse(AuthResStr); nlohmann::json AuthRes = nlohmann::json::parse(AuthResStr);
if (AuthRes["username"].is_string() && AuthRes["username"].size() > 0 && AuthRes["roles"].is_string() if (AuthRes["username"].is_string() && AuthRes["roles"].is_string()
&& AuthRes["guest"].is_boolean() && AuthRes["identifiers"].is_array()) { && AuthRes["guest"].is_boolean() && AuthRes["identifiers"].is_array()) {
Client->SetName(AuthRes["username"]); Client->SetName(AuthRes["username"]);
@@ -468,7 +401,7 @@ std::shared_ptr<TClient> TNetwork::Authentication(TConnection&& RawConnection) {
return true; return true;
} }
if (Cl->GetName() == Client->GetName() && Cl->IsGuest() == Client->IsGuest()) { if (Cl->GetName() == Client->GetName() && Cl->IsGuest() == Client->IsGuest()) {
DisconnectClient(Cl, "Stale Client (not a real player)"); Cl->Disconnect("Stale Client (not a real player)");
return false; return false;
} }
@@ -531,7 +464,7 @@ std::shared_ptr<TClient> TNetwork::Authentication(TConnection&& RawConnection) {
return Client; return Client;
} }
std::shared_ptr<TClient> TNetwork::CreateClient(boost::asio::ip::tcp::socket&& TCPSock) { std::shared_ptr<TClient> TNetwork::CreateClient(ip::tcp::socket&& TCPSock) {
auto c = std::make_shared<TClient>(mServer, std::move(TCPSock)); auto c = std::make_shared<TClient>(mServer, std::move(TCPSock));
return c; return c;
} }
@@ -564,10 +497,10 @@ bool TNetwork::TCPSend(TClient& c, const std::vector<uint8_t>& Data, bool IsSync
std::memcpy(ToSend.data(), &Size, sizeof(Size)); std::memcpy(ToSend.data(), &Size, sizeof(Size));
std::memcpy(ToSend.data() + sizeof(Size), Data.data(), Data.size()); std::memcpy(ToSend.data() + sizeof(Size), Data.data(), Data.size());
boost::system::error_code ec; boost::system::error_code ec;
boost::asio::write(Sock, boost::asio::buffer(ToSend), ec); write(Sock, buffer(ToSend), ec);
if (ec) { if (ec) {
beammp_debugf("write(): {}", ec.message()); beammp_debugf("write(): {}", ec.message());
DisconnectClient(c, "write() failed"); c.Disconnect("write() failed");
return false; return false;
} }
c.UpdatePingTime(); c.UpdatePingTime();
@@ -585,7 +518,7 @@ std::vector<uint8_t> TNetwork::TCPRcv(TClient& c) {
boost::system::error_code ec; boost::system::error_code ec;
std::array<uint8_t, sizeof(Header)> HeaderData; std::array<uint8_t, sizeof(Header)> HeaderData;
boost::asio::read(Sock, boost::asio::buffer(HeaderData), ec); read(Sock, buffer(HeaderData), ec);
if (ec) { if (ec) {
// TODO: handle this case (read failed) // TODO: handle this case (read failed)
beammp_debugf("TCPRcv: Reading header failed: {}", ec.message()); beammp_debugf("TCPRcv: Reading header failed: {}", ec.message());
@@ -601,16 +534,14 @@ std::vector<uint8_t> TNetwork::TCPRcv(TClient& c) {
std::vector<uint8_t> Data; std::vector<uint8_t> Data;
// TODO: This is arbitrary, this needs to be handled another way // TODO: This is arbitrary, this needs to be handled another way
bool isUnauthenticated = c.GetName().empty(); if (Header < int32_t(100 * MB)) {
int32_t maxHeaderSize = isUnauthenticated ? 4096 : int32_t(100 * MB);
if (Header < maxHeaderSize) {
Data.resize(Header); Data.resize(Header);
} else { } else {
ClientKick(c, "Header size limit exceeded"); ClientKick(c, "Header size limit exceeded");
beammp_warn("Client " + c.GetName() + " (" + std::to_string(c.GetID()) + ") sent header larger than expected - assuming malicious intent and disconnecting the client."); beammp_warn("Client " + c.GetName() + " (" + std::to_string(c.GetID()) + ") sent header of >100MB - assuming malicious intent and disconnecting the client.");
return {}; return {};
} }
auto N = boost::asio::read(Sock, boost::asio::buffer(Data), ec); auto N = read(Sock, buffer(Data), ec);
if (ec) { if (ec) {
// TODO: handle this case properly // TODO: handle this case properly
beammp_debugf("TCPRcv: Reading data failed: {}", ec.message()); beammp_debugf("TCPRcv: Reading data failed: {}", ec.message());
@@ -645,32 +576,7 @@ void TNetwork::ClientKick(TClient& c, const std::string& R) {
if (!TCPSend(c, StringToVector("K" + R))) { if (!TCPSend(c, StringToVector("K" + R))) {
beammp_debugf("tried to kick player '{}' (id {}), but was already disconnected", c.GetName(), c.GetID()); beammp_debugf("tried to kick player '{}' (id {}), but was already disconnected", c.GetName(), c.GetID());
} }
DisconnectClient(c, "Kicked"); c.Disconnect("Kicked");
}
void TNetwork::DisconnectClient(const std::weak_ptr<TClient> &c, const std::string &R)
{
if (auto locked = c.lock()) {
DisconnectClient(*locked, R);
}
else {
beammp_debugf("Tried to disconnect a non existant client with reason: {}", R);
}
}
void TNetwork::DisconnectClient(TClient &c, const std::string &R)
{
if (c.IsDisconnected()) return;
std::string ClientIP = c.GetIdentifiers().at("ip");
mClientMapMutex.lock();
if (mClientMap[ClientIP] > 0) {
mClientMap[ClientIP]--;
}
if (mClientMap[ClientIP] == 0) {
mClientMap.erase(ClientIP);
}
mClientMapMutex.unlock();
c.Disconnect(R);
} }
void TNetwork::Looper(const std::weak_ptr<TClient>& c) { void TNetwork::Looper(const std::weak_ptr<TClient>& c) {
@@ -695,7 +601,7 @@ void TNetwork::Looper(const std::weak_ptr<TClient>& c) {
} // end locked context } // end locked context
// beammp_debug("sending a missed packet: " + QData); // beammp_debug("sending a missed packet: " + QData);
if (!TCPSend(*Client, QData, true)) { if (!TCPSend(*Client, QData, true)) {
DisconnectClient(Client, "Failed to TCPSend while clearing the missed packet queue"); Client->Disconnect("Failed to TCPSend while clearing the missed packet queue");
std::unique_lock lock(Client->MissedPacketQueueMutex()); std::unique_lock lock(Client->MissedPacketQueueMutex());
while (!Client->MissedPacketQueue().empty()) { while (!Client->MissedPacketQueue().empty()) {
Client->MissedPacketQueue().pop(); Client->MissedPacketQueue().pop();
@@ -732,16 +638,10 @@ void TNetwork::TCPClient(const std::weak_ptr<TClient>& c) {
auto res = TCPRcv(*Client); auto res = TCPRcv(*Client);
if (res.empty()) { if (res.empty()) {
beammp_debug("TCPRcv empty"); beammp_debug("TCPRcv empty");
DisconnectClient(Client, "TCPRcv failed"); Client->Disconnect("TCPRcv failed");
break;
}
try {
mServer.GlobalParser(c, std::move(res), mPPSMonitor, *this, false);
} catch (const std::exception& e) {
beammp_warnf("Failed to receive/parse packet via TCP from client {}: {}", Client->GetID(), e.what());
DisconnectClient(Client, "Failed to parse packet");
break; break;
} }
mServer.GlobalParser(c, std::move(res), mPPSMonitor, *this);
} }
if (QueueSync.joinable()) if (QueueSync.joinable())
@@ -770,34 +670,6 @@ void TNetwork::UpdatePlayer(TClient& Client) {
//(void)Respond(Client, Packet, true); //(void)Respond(Client, Packet, true);
} }
boost::system::error_code TNetwork::ReadWithTimeout(TConnection& Connection, void *Buf, size_t Len, std::chrono::steady_clock::duration Timeout)
{
io_context TimerIO;
steady_timer Timer(TimerIO);
Timer.expires_after(Timeout);
std::atomic<bool> TimedOut = false;
Timer.async_wait([&](const boost::system::error_code& ec) {
if (!ec) {
TimedOut = true;
Connection.Socket.cancel();
}
});
std::thread TimerThread([&]() { TimerIO.run(); });
boost::system::error_code ReadEc;
boost::asio::read(Connection.Socket, boost::asio::buffer(Buf, Len), ReadEc);
TimerIO.stop();
TimerThread.join();
if (TimedOut.load()) {
return error::timed_out; // synthesize a clean timeout error
}
return ReadEc; //Succes!
}
void TNetwork::OnDisconnect(const std::weak_ptr<TClient>& ClientPtr) { void TNetwork::OnDisconnect(const std::weak_ptr<TClient>& ClientPtr) {
std::shared_ptr<TClient> LockedClientPtr { nullptr }; std::shared_ptr<TClient> LockedClientPtr { nullptr };
try { try {
@@ -825,7 +697,7 @@ void TNetwork::OnDisconnect(const std::weak_ptr<TClient>& ClientPtr) {
Packet.clear(); Packet.clear();
auto Futures = LuaAPI::MP::Engine->TriggerEvent("onPlayerDisconnect", "", c.GetID()); auto Futures = LuaAPI::MP::Engine->TriggerEvent("onPlayerDisconnect", "", c.GetID());
LuaAPI::MP::Engine->WaitForAll(Futures); LuaAPI::MP::Engine->WaitForAll(Futures);
DisconnectClient(c, "Already Disconnected (OnDisconnect)"); c.Disconnect("Already Disconnected (OnDisconnect)");
mServer.RemoveClient(ClientPtr); mServer.RemoveClient(ClientPtr);
} }
@@ -860,18 +732,6 @@ 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()));
@@ -907,7 +767,7 @@ void TNetwork::Parse(TClient& c, const std::vector<uint8_t>& Packet) {
case 'S': case 'S':
if (SubCode == 'R') { if (SubCode == 'R') {
beammp_debug("Sending Mod Info"); beammp_debug("Sending Mod Info");
std::string ToSend = mResourceManager.GetMods().dump(); std::string ToSend = mResourceManager.NewFileList();
beammp_debugf("Mod Info: {}", ToSend); beammp_debugf("Mod Info: {}", ToSend);
if (!TCPSend(c, StringToVector(ToSend))) { if (!TCPSend(c, StringToVector(ToSend))) {
ClientKick(c, "TCP Send 'SY' failed"); ClientKick(c, "TCP Send 'SY' failed");
@@ -929,15 +789,6 @@ void TNetwork::SendFile(TClient& c, const std::string& UnsafeName) {
return; return;
} }
auto FileName = fs::path(UnsafeName).filename().string(); auto FileName = fs::path(UnsafeName).filename().string();
for (auto mod : mResourceManager.GetMods()) {
if (mod["file_name"].get<std::string>() == FileName && mod["protected"] == true) {
beammp_warn("Client tried to access protected file " + UnsafeName);
DisconnectClient(c, "Mod is protected thus cannot be downloaded");
return;
}
}
FileName = Application::Settings.getAsString(Settings::Key::General_ResourceFolder) + "/Client/" + FileName; FileName = Application::Settings.getAsString(Settings::Key::General_ResourceFolder) + "/Client/" + FileName;
if (!std::filesystem::exists(FileName)) { if (!std::filesystem::exists(FileName)) {
@@ -997,7 +848,7 @@ void TNetwork::SendFileToClient(TClient& c, size_t Size, const std::string& Name
Data.resize(Split); Data.resize(Split);
else else
Data.resize(Size); Data.resize(Size);
boost::asio::ip::tcp::socket* TCPSock = &c.GetTCPSock(); ip::tcp::socket* TCPSock = &c.GetTCPSock();
std::streamsize Sent = 0; std::streamsize Sent = 0;
while (!c.IsDisconnected() && Sent < Size) { while (!c.IsDisconnected() && Sent < Size) {
size_t Diff = Size - Sent; size_t Diff = Size - Sent;
@@ -1006,7 +857,7 @@ void TNetwork::SendFileToClient(TClient& c, size_t Size, const std::string& Name
f.read(reinterpret_cast<char*>(Data.data()), Split); f.read(reinterpret_cast<char*>(Data.data()), Split);
if (!TCPSendRaw(c, *TCPSock, Data.data(), Split)) { if (!TCPSendRaw(c, *TCPSock, Data.data(), Split)) {
if (!c.IsDisconnected()) if (!c.IsDisconnected())
DisconnectClient(c, "TCPSendRaw failed in mod download (1)"); c.Disconnect("TCPSendRaw failed in mod download (1)");
break; break;
} }
Sent += Split; Sent += Split;
@@ -1015,7 +866,7 @@ void TNetwork::SendFileToClient(TClient& c, size_t Size, const std::string& Name
f.read(reinterpret_cast<char*>(Data.data()), Diff); f.read(reinterpret_cast<char*>(Data.data()), Diff);
if (!TCPSendRaw(c, *TCPSock, Data.data(), int32_t(Diff))) { if (!TCPSendRaw(c, *TCPSock, Data.data(), int32_t(Diff))) {
if (!c.IsDisconnected()) if (!c.IsDisconnected())
DisconnectClient(c, "TCPSendRaw failed in mod download (2)"); c.Disconnect("TCPSendRaw failed in mod download (2)");
break; break;
} }
Sent += Diff; Sent += Diff;
@@ -1024,9 +875,9 @@ void TNetwork::SendFileToClient(TClient& c, size_t Size, const std::string& Name
#endif #endif
} }
bool TNetwork::TCPSendRaw(TClient& C, boost::asio::ip::tcp::socket& socket, const uint8_t* Data, size_t Size) { bool TNetwork::TCPSendRaw(TClient& C, ip::tcp::socket& socket, const uint8_t* Data, size_t Size) {
boost::system::error_code ec; boost::system::error_code ec;
boost::asio::write(socket, boost::asio::buffer(Data, Size), ec); write(socket, buffer(Data, Size), ec);
if (ec) { if (ec) {
beammp_errorf("Failed to send raw data to client: {}", ec.message()); beammp_errorf("Failed to send raw data to client: {}", ec.message());
return false; return false;
@@ -1095,7 +946,7 @@ bool TNetwork::SyncClient(const std::weak_ptr<TClient>& c) {
res = false; res = false;
return false; return false;
} }
res = Respond(*LockedClient, StringToVector(v.DataAsPacket(client->GetRoles(), client->GetName(), client->GetID())), true, true); res = Respond(*LockedClient, StringToVector(v.Data()), true, true);
} }
} }
@@ -1167,20 +1018,20 @@ bool TNetwork::UDPSend(TClient& Client, std::vector<uint8_t> Data) {
CompressProperly(Data); CompressProperly(Data);
} }
boost::system::error_code ec; boost::system::error_code ec;
mUDPSock.send_to(boost::asio::buffer(Data), Addr, 0, ec); mUDPSock.send_to(buffer(Data), Addr, 0, ec);
if (ec) { if (ec) {
beammp_debugf("UDP sendto() failed: {}", ec.message()); beammp_debugf("UDP sendto() failed: {}", ec.message());
if (!Client.IsDisconnected()) if (!Client.IsDisconnected())
DisconnectClient(Client, "UDP send failed"); Client.Disconnect("UDP send failed");
return false; return false;
} }
return true; return true;
} }
std::vector<uint8_t> TNetwork::UDPRcvFromClient(boost::asio::ip::udp::endpoint& ClientEndpoint) { std::vector<uint8_t> TNetwork::UDPRcvFromClient(ip::udp::endpoint& ClientEndpoint) {
std::array<char, 1024> Ret {}; std::array<char, 1024> Ret {};
boost::system::error_code ec; boost::system::error_code ec;
const auto Rcv = mUDPSock.receive_from(boost::asio::mutable_buffer(Ret.data(), Ret.size()), ClientEndpoint, 0, ec); const auto Rcv = mUDPSock.receive_from(mutable_buffer(Ret.data(), Ret.size()), ClientEndpoint, 0, ec);
if (ec) { if (ec) {
beammp_errorf("UDP recvfrom() failed: {}", ec.message()); beammp_errorf("UDP recvfrom() failed: {}", ec.message());
return {}; return {};
+14 -19
View File
@@ -57,26 +57,21 @@ void TPluginMonitor::operator()() {
mFileTimes[Pair.first] = CurrentTime; mFileTimes[Pair.first] = CurrentTime;
// grandparent of the path should be Resources/Server // grandparent of the path should be Resources/Server
if (fs::equivalent(fs::path(Pair.first).parent_path().parent_path(), mPath)) { if (fs::equivalent(fs::path(Pair.first).parent_path().parent_path(), mPath)) {
if (LowerString(fs::path(Pair.first).extension().string()) == ".lua") { beammp_infof("File \"{}\" changed, reloading", Pair.first);
beammp_infof("File \"{}\" changed, reloading", Pair.first); // is in root folder, so reload
// is in root folder, so reload std::ifstream FileStream(Pair.first, std::ios::in | std::ios::binary);
std::ifstream FileStream(Pair.first, std::ios::in | std::ios::binary); auto Size = std::filesystem::file_size(Pair.first);
auto Size = std::filesystem::file_size(Pair.first); auto Contents = std::make_shared<std::string>();
auto Contents = std::make_shared<std::string>(); Contents->resize(Size);
Contents->resize(Size); FileStream.read(Contents->data(), Contents->size());
FileStream.read(Contents->data(), Contents->size()); TLuaChunk Chunk(Contents, Pair.first, fs::path(Pair.first).parent_path().string());
TLuaChunk Chunk(Contents, Pair.first, fs::path(Pair.first).parent_path().string()); auto StateID = mEngine->GetStateIDForPlugin(fs::path(Pair.first).parent_path());
auto StateID = mEngine->GetStateIDForPlugin(fs::path(Pair.first).parent_path()); auto Res = mEngine->EnqueueScript(StateID, Chunk);
auto Res = mEngine->EnqueueScript(StateID, Chunk); Res->WaitUntilReady();
Res->WaitUntilReady(); if (Res->Error) {
if (Res->Error) { beammp_lua_errorf("Error while hot-reloading \"{}\": {}", Pair.first, Res->ErrorMessage);
beammp_lua_errorf("Error while hot-reloading \"{}\": {}", Pair.first, Res->ErrorMessage);
} else {
mEngine->ReportErrors(mEngine->TriggerLocalEvent(StateID, "onInit"));
mEngine->ReportErrors(mEngine->TriggerEvent("onFileChanged", "", Pair.first));
}
} else { } else {
beammp_debugf("File \"{}\" changed, not reloading because it's not a lua file. Triggering 'onFileChanged' event instead", Pair.first); mEngine->ReportErrors(mEngine->TriggerLocalEvent(StateID, "onInit"));
mEngine->ReportErrors(mEngine->TriggerEvent("onFileChanged", "", Pair.first)); mEngine->ReportErrors(mEngine->TriggerEvent("onFileChanged", "", Pair.first));
} }
} else { } else {
+4 -104
View File
@@ -58,58 +58,22 @@ TResourceManager::TResourceManager() {
Application::SetSubsystemStatus("ResourceManager", Application::Status::Good); Application::SetSubsystemStatus("ResourceManager", Application::Status::Good);
} }
std::string TResourceManager::NewFileList() const {
return mMods.dump();
}
void TResourceManager::RefreshFiles() { void TResourceManager::RefreshFiles() {
mMods.clear(); mMods.clear();
std::unique_lock Lock(mModsMutex); std::unique_lock Lock(mModsMutex);
std::string Path = Application::Settings.getAsString(Settings::Key::General_ResourceFolder) + "/Client"; std::string Path = Application::Settings.getAsString(Settings::Key::General_ResourceFolder) + "/Client";
nlohmann::json modsDB;
if (std::filesystem::exists(Path + "/mods.json")) {
try {
std::ifstream stream(Path + "/mods.json");
stream >> modsDB;
stream.close();
} catch (const std::exception& e) {
beammp_errorf("Failed to load mods.json: {}", e.what());
}
}
for (const auto& entry : fs::directory_iterator(Path)) { for (const auto& entry : fs::directory_iterator(Path)) {
std::string File(entry.path().string()); std::string File(entry.path().string());
if (entry.path().filename().string() == "mods.json") {
continue;
}
if (entry.path().extension() != ".zip" || std::filesystem::is_directory(entry.path())) { if (entry.path().extension() != ".zip" || std::filesystem::is_directory(entry.path())) {
beammp_warnf("'{}' is not a ZIP file and will be ignored", File); beammp_warnf("'{}' is not a ZIP file and will be ignored", File);
continue; continue;
} }
if (modsDB.contains(entry.path().filename().string())) {
auto& dbEntry = modsDB[entry.path().filename().string()];
if (entry.last_write_time().time_since_epoch().count() > dbEntry["lastwrite"] || std::filesystem::file_size(File) != dbEntry["filesize"].get<size_t>()) {
beammp_infof("File '{}' has been modified, rehashing", File);
} else {
dbEntry["exists"] = true;
mMods.push_back(nlohmann::json {
{ "file_name", std::filesystem::path(File).filename() },
{ "file_size", std::filesystem::file_size(File) },
{ "hash_algorithm", "sha256" },
{ "hash", dbEntry["hash"] },
{ "protected", dbEntry["protected"] } });
beammp_debugf("Mod '{}' loaded from cache", File);
continue;
}
}
try { try {
EVP_MD_CTX* mdctx; EVP_MD_CTX* mdctx;
const EVP_MD* md; const EVP_MD* md;
@@ -169,73 +133,9 @@ void TResourceManager::RefreshFiles() {
{ "file_size", std::filesystem::file_size(File) }, { "file_size", std::filesystem::file_size(File) },
{ "hash_algorithm", "sha256" }, { "hash_algorithm", "sha256" },
{ "hash", result }, { "hash", result },
{ "protected", false } }); });
modsDB[std::filesystem::path(File).filename().string()] = {
{ "lastwrite", entry.last_write_time().time_since_epoch().count() },
{ "hash", result },
{ "filesize", std::filesystem::file_size(File) },
{ "protected", false },
{ "exists", true }
};
} catch (const std::exception& e) { } catch (const std::exception& e) {
beammp_errorf("Sha256 hashing of '{}' failed: {}", File, e.what()); beammp_errorf("Sha256 hashing of '{}' failed: {}", File, e.what());
} }
} }
for (auto it = modsDB.begin(); it != modsDB.end();) {
if (!it.value().contains("exists")) {
it = modsDB.erase(it);
} else {
it.value().erase("exists");
++it;
}
}
try {
std::ofstream stream(Path + "/mods.json");
stream << modsDB.dump(4);
stream.close();
} catch (std::exception& e) {
beammp_error("Failed to update mod DB: " + std::string(e.what()));
}
}
void TResourceManager::SetProtected(const std::string& ModName, bool Protected) {
std::unique_lock Lock(mModsMutex);
for (auto& mod : mMods) {
if (mod["file_name"].get<std::string>() == ModName) {
mod["protected"] = Protected;
break;
}
}
auto modsDBPath = Application::Settings.getAsString(Settings::Key::General_ResourceFolder) + "/Client/mods.json";
if (std::filesystem::exists(modsDBPath)) {
try {
nlohmann::json modsDB;
std::fstream stream(modsDBPath);
stream >> modsDB;
if (modsDB.contains(ModName)) {
modsDB[ModName]["protected"] = Protected;
}
stream.clear();
stream.seekp(0, std::ios::beg);
stream << modsDB.dump(4);
stream.close();
} catch (const std::exception& e) {
beammp_errorf("Failed to update mods.json: {}", e.what());
}
}
} }
+35 -96
View File
@@ -28,7 +28,6 @@
#include <any> #include <any>
#include <optional> #include <optional>
#include <sstream> #include <sstream>
#include <utility>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
@@ -54,6 +53,7 @@ static std::optional<std::pair<int, int>> GetPidVid(const std::string& str) {
} }
return std::nullopt; return std::nullopt;
} }
TEST_CASE("GetPidVid") { TEST_CASE("GetPidVid") {
SUBCASE("Valid singledigit") { SUBCASE("Valid singledigit") {
const auto MaybePidVid = GetPidVid("0-1"); const auto MaybePidVid = GetPidVid("0-1");
@@ -120,6 +120,7 @@ TEST_CASE("GetPidVid") {
CHECK(!MaybePidVid); CHECK(!MaybePidVid);
} }
} }
TServer::TServer(const std::vector<std::string_view>& Arguments) { TServer::TServer(const std::vector<std::string_view>& Arguments) {
beammp_info("BeamMP Server v" + Application::ServerVersionString()); beammp_info("BeamMP Server v" + Application::ServerVersionString());
Application::SetSubsystemStatus("Server", Application::Status::Starting); Application::SetSubsystemStatus("Server", Application::Status::Starting);
@@ -160,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, bool udp) { void TServer::GlobalParser(const std::weak_ptr<TClient>& Client, std::vector<uint8_t>&& Packet, TPPSMonitor& PPSMonitor, TNetwork& Network) {
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());
@@ -194,29 +195,12 @@ void TServer::GlobalParser(const std::weak_ptr<TClient>& Client, std::vector<uin
// V to Y // V to Y
if (Code <= 89 && Code >= 86) { if (Code <= 89 && Code >= 86) {
int PID = -1;
int VID = -1;
auto pidVidPart = StringPacket.substr(3);
auto MaybePidVid = GetPidVid(pidVidPart.substr(0, pidVidPart.find(':')));
if (MaybePidVid) {
std::tie(PID, VID) = MaybePidVid.value();
}
if (PID == -1 || VID == -1 || PID != LockedClient->GetID()) {
return;
}
PPSMonitor.IncrementInternalPPS(); PPSMonitor.IncrementInternalPPS();
Network.SendToAll(LockedClient.get(), Packet, false, false); Network.SendToAll(LockedClient.get(), Packet, false, false);
return; return;
} }
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
} }
@@ -230,20 +214,12 @@ 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());
@@ -256,10 +232,6 @@ 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));
@@ -278,35 +250,16 @@ 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':
Network.SendToAll(LockedClient.get(), Packet, false, true); Network.SendToAll(LockedClient.get(), Packet, false, true);
return; return;
case 'Z': { // position packet case 'Z': // position packet
PPSMonitor.IncrementInternalPPS(); PPSMonitor.IncrementInternalPPS();
int PID = -1;
int VID = -1;
auto pidVidPart = StringPacket.substr(3);
auto MaybePidVid = GetPidVid(pidVidPart.substr(0, pidVidPart.find(':')));
if (MaybePidVid) {
std::tie(PID, VID) = MaybePidVid.value();
}
if (PID == -1 || VID == -1 || PID != LockedClient->GetID()) {
return;
}
Network.SendToAll(LockedClient.get(), Packet, false, false); Network.SendToAll(LockedClient.get(), Packet, false, false);
HandlePosition(*LockedClient, StringPacket); HandlePosition(*LockedClient, StringPacket);
return; return;
}
default: default:
return; return;
} }
@@ -325,15 +278,6 @@ 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));
} }
@@ -384,9 +328,8 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ
}); });
bool SpawnConfirmed = false; bool SpawnConfirmed = false;
auto CarJsonDoc = nlohmann::json::parse(CarJson, nullptr, false); if (ShouldSpawn(c, CarJson, CarID) && !ShouldntSpawn) {
if (ShouldSpawn(c, CarJson, CarID) && !ShouldntSpawn && !CarJsonDoc.is_discarded()) { c.AddNewCar(CarID, Packet);
c.AddNewCar(CarID, CarJsonDoc);
Network.SendToAll(nullptr, StringToVector(Packet), true, true); Network.SendToAll(nullptr, StringToVector(Packet), true, true);
SpawnConfirmed = true; SpawnConfirmed = true;
} else { } else {
@@ -471,13 +414,7 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ
} }
if (PID != -1 && VID != -1 && PID == c.GetID()) { if (PID != -1 && VID != -1 && PID == c.GetID()) {
auto BracketPos = Data.find('{'); Data = Data.substr(Data.find('{'));
if (BracketPos == std::string::npos) {
beammp_debugf("Invalid 'Or' packet body from client {}", c.GetID());
return;
}
Data = Data.substr(BracketPos);
LuaAPI::MP::Engine->ReportErrors(LuaAPI::MP::Engine->TriggerEvent("onVehicleReset", "", c.GetID(), VID, Data)); LuaAPI::MP::Engine->ReportErrors(LuaAPI::MP::Engine->TriggerEvent("onVehicleReset", "", c.GetID(), VID, Data));
Network.SendToAll(&c, StringToVector(Packet), false, true); Network.SendToAll(&c, StringToVector(Packet), false, true);
} }
@@ -506,27 +443,9 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ
} }
if (PID != -1 && VID != -1 && PID == c.GetID()) { if (PID != -1 && VID != -1 && PID == c.GetID()) {
auto BracketPos = Data.find('['); Data = Data.substr(Data.find('['));
if (BracketPos == std::string::npos) {
beammp_debugf("Invalid 'Op' packet body from client {}", c.GetID());
return;
}
Data = Data.substr(BracketPos);
LuaAPI::MP::Engine->ReportErrors(LuaAPI::MP::Engine->TriggerEvent("onVehiclePaintChanged", "", c.GetID(), VID, Data)); LuaAPI::MP::Engine->ReportErrors(LuaAPI::MP::Engine->TriggerEvent("onVehiclePaintChanged", "", c.GetID(), VID, Data));
Network.SendToAll(&c, StringToVector(Packet), false, true); Network.SendToAll(&c, StringToVector(Packet), false, true);
auto CarData = c.GetCarData(VID);
if (CarData == nlohmann::detail::value_t::null)
return;
if (CarData.contains("vcf") && CarData.at("vcf").is_object())
if (CarData.at("vcf").contains("paints") && CarData.at("vcf").at("paints").is_array()) {
CarData.at("vcf")["paints"] = nlohmann::json::parse(Data);
c.SetCarData(VID, CarData);
}
} }
return; return;
} }
@@ -542,22 +461,42 @@ void TServer::Apply(TClient& c, int VID, const std::string& pckt) {
beammp_error("Malformed packet received, no '{' found"); beammp_error("Malformed packet received, no '{' found");
return; return;
} }
std::string Packet = pckt.substr(FoundPos); std::string Packet = pckt.substr(FoundPos);
nlohmann::json VD = c.GetCarData(VID); std::string VD = c.GetCarData(VID);
if (VD == nlohmann::detail::value_t::null) { if (VD.empty()) {
beammp_error("Tried to apply change to vehicle that does not exist"); beammp_error("Tried to apply change to vehicle that does not exist");
return; return;
} }
std::string Header = VD.substr(0, VD.find('{'));
nlohmann::json Pack = nlohmann::json::parse(Packet, nullptr, false); FoundPos = VD.find('{');
if (FoundPos == std::string::npos) {
if (Pack.is_discarded()) { return;
}
VD = VD.substr(FoundPos);
rapidjson::Document Veh, Pack;
Veh.Parse(VD.c_str());
if (Veh.HasParseError()) {
beammp_error("Could not get vehicle config!");
return;
}
Pack.Parse(Packet.c_str());
if (Pack.HasParseError() || Pack.IsNull()) {
beammp_error("Could not get active vehicle config!"); beammp_error("Could not get active vehicle config!");
return; return;
} }
c.SetCarData(VID, Pack); for (auto& M : Pack.GetObject()) {
if (Veh[M.name].IsNull()) {
Veh.AddMember(M.name, M.value, Veh.GetAllocator());
} else {
Veh[M.name] = Pack[M.name];
}
}
rapidjson::StringBuffer Buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(Buffer);
Veh.Accept(writer);
c.SetCarData(VID, Header + Buffer.GetString());
} }
void TServer::InsertClient(const std::shared_ptr<TClient>& NewClient) { void TServer::InsertClient(const std::shared_ptr<TClient>& NewClient) {
+1 -5
View File
@@ -21,7 +21,7 @@
#include "Common.h" #include "Common.h"
#include <utility> #include <utility>
TVehicleData::TVehicleData(int ID, nlohmann::json Data) TVehicleData::TVehicleData(int ID, std::string Data)
: mID(ID) : mID(ID)
, mData(std::move(Data)) { , mData(std::move(Data)) {
beammp_trace("vehicle " + std::to_string(mID) + " constructed"); beammp_trace("vehicle " + std::to_string(mID) + " constructed");
@@ -30,7 +30,3 @@ TVehicleData::TVehicleData(int ID, nlohmann::json Data)
TVehicleData::~TVehicleData() { TVehicleData::~TVehicleData() {
beammp_trace("vehicle " + std::to_string(mID) + " destroyed"); beammp_trace("vehicle " + std::to_string(mID) + " destroyed");
} }
std::string TVehicleData::DataAsPacket(const std::string& Role, const std::string& Name, const int ID) const {
return "Os:" + Role + ":" + Name + ":" + std::to_string(ID) + "-" + std::to_string(this->mID) + ":" + this->mData.dump();
}
+5 -10
View File
@@ -182,6 +182,10 @@ int BeamMPServerMain(MainArguments Arguments) {
TServer Server(Arguments.List); TServer Server(Arguments.List);
auto LuaEngine = std::make_shared<TLuaEngine>();
LuaEngine->SetServer(&Server);
Application::Console().InitializeLuaConsole(*LuaEngine);
RegisterThread("Main"); RegisterThread("Main");
beammp_trace("Running in debug mode on a debug build"); beammp_trace("Running in debug mode on a debug build");
@@ -190,16 +194,13 @@ int BeamMPServerMain(MainArguments Arguments) {
TPPSMonitor PPSMonitor(Server); TPPSMonitor PPSMonitor(Server);
THeartbeatThread Heartbeat(ResourceManager, Server); THeartbeatThread Heartbeat(ResourceManager, Server);
TNetwork Network(Server, PPSMonitor, ResourceManager); TNetwork Network(Server, PPSMonitor, ResourceManager);
auto LuaEngine = std::make_shared<TLuaEngine>();
LuaEngine->SetServer(&Server);
Application::Console().InitializeLuaConsole(*LuaEngine);
LuaEngine->SetNetwork(&Network); LuaEngine->SetNetwork(&Network);
PPSMonitor.SetNetwork(Network); PPSMonitor.SetNetwork(Network);
Application::CheckForUpdates(); Application::CheckForUpdates();
TPluginMonitor PluginMonitor(fs::path(Application::Settings.getAsString(Settings::Key::General_ResourceFolder)) / "Server", LuaEngine); TPluginMonitor PluginMonitor(fs::path(Application::Settings.getAsString(Settings::Key::General_ResourceFolder)) / "Server", LuaEngine);
Application::SetSubsystemStatus("Main", Application::Status::Good);
RegisterThread("Main(Waiting)"); RegisterThread("Main(Waiting)");
std::set<std::string> IgnoreSubsystems { std::set<std::string> IgnoreSubsystems {
@@ -214,10 +215,6 @@ int BeamMPServerMain(MainArguments Arguments) {
std::string SystemsBadList {}; std::string SystemsBadList {};
auto Statuses = Application::GetSubsystemStatuses(); auto Statuses = Application::GetSubsystemStatuses();
for (const auto& NameStatusPair : Statuses) { for (const auto& NameStatusPair : Statuses) {
if (NameStatusPair.first == "Main") {
continue;
}
if (IgnoreSubsystems.count(NameStatusPair.first) > 0) { if (IgnoreSubsystems.count(NameStatusPair.first) > 0) {
continue; // ignore continue; // ignore
} }
@@ -231,8 +228,6 @@ int BeamMPServerMain(MainArguments Arguments) {
// remove ", " // remove ", "
SystemsBadList = SystemsBadList.substr(0, SystemsBadList.size() - 2); SystemsBadList = SystemsBadList.substr(0, SystemsBadList.size() - 2);
if (FullyStarted) { if (FullyStarted) {
Application::SetSubsystemStatus("Main", Application::Status::Good);
if (!WithErrors) { if (!WithErrors) {
beammp_info("ALL SYSTEMS STARTED SUCCESSFULLY, EVERYTHING IS OKAY"); beammp_info("ALL SYSTEMS STARTED SUCCESSFULLY, EVERYTHING IS OKAY");
} else { } else {
+1 -1
Submodule vcpkg updated: 5bf0c55239...6978381401
+2 -14
View File
@@ -14,18 +14,6 @@
"openssl", "openssl",
"rapidjson", "rapidjson",
"sol2", "sol2",
"curl", "curl"
"lua" ]
],
"overrides": [
{
"name": "sol2",
"version": "3.3.1"
},
{
"name": "lua",
"version": "5.3.5#6"
}
],
"builtin-baseline": "5bf0c55239da398b8c6f450818c9e28d36bf9966"
} }