From a865c95e2a2161f02a1697481b9e511ee7572ec6 Mon Sep 17 00:00:00 2001 From: Anonymous-275 Date: Fri, 25 Jun 2021 01:10:34 +0300 Subject: [PATCH 001/255] lua Register --- src/TLuaFile.cpp | 107 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 87 insertions(+), 20 deletions(-) diff --git a/src/TLuaFile.cpp b/src/TLuaFile.cpp index d6b1f33..ba1d7f1 100644 --- a/src/TLuaFile.cpp +++ b/src/TLuaFile.cpp @@ -5,7 +5,7 @@ #include "TLuaEngine.h" #include "TNetwork.h" #include "TServer.h" - +#include #include #include @@ -601,7 +601,91 @@ int lua_Print(lua_State* L) { } } -int lua_TempFix(lua_State* L); +int lua_TempFix(lua_State* L) { + if (lua_isnumber(L, 1)) { + int ID = int(lua_tonumber(L, 1)); + auto MaybeClient = GetClient(Engine().Server(), ID); + if (!MaybeClient || MaybeClient.value().expired()) + return 0; + std::string Ret; + auto c = MaybeClient.value().lock(); + if (c->IsGuest()) { + Ret = "Guest-" + c->GetName(); + } else + Ret = c->GetName(); + lua_pushstring(L, Ret.c_str()); + } else + SendError(Engine(), L, "GetDID not enough arguments"); + return 1; +} + +template +struct fun_ptr_helper +{ +public: + typedef std::function function_type; + + static void bind(function_type&& f) + { instance().fn_.swap(f); } + + static void bind(const function_type& f) + { instance().fn_=f; } + + static Res invoke(ArgTypes... args) + { return instance().fn_(args...); } + + typedef decltype(&fun_ptr_helper::invoke) pointer_type; + static pointer_type ptr() + { return &invoke; } + +private: + static fun_ptr_helper& instance() + { + static fun_ptr_helper inst_; + return inst_; + } + + fun_ptr_helper() {} + + function_type fn_; +}; + +template +typename fun_ptr_helper<_UniqueId, _Res, _ArgTypes...>::pointer_type +get_fn_ptr(const std::function<_Res(_ArgTypes...)>& f) +{ + fun_ptr_helper<_UniqueId, _Res, _ArgTypes...>::bind(f); + return fun_ptr_helper<_UniqueId, _Res, _ArgTypes...>::ptr(); +} + + +int lua_Register(lua_State* L) { + if(lua_isstring(L, 1)){ + std::string Name(lua_tolstring(L, 1, nullptr)); + lua_getglobal(L, Name.c_str()); + if (lua_isfunction(L, -1)) { + for (auto& Script : Engine().LuaFiles()) { + if(Script->GetState() != L){ + lua_CFunction Func = get_fn_ptr<0>(std::function([=](lua_State* A) { + lua_getglobal(L, Name.c_str()); + if (lua_isfunction(L, -1)) { + lua_pcall(L, 0, 0, 0); + } + return 0; + })); + lua_register(Script->GetState(), Name.c_str(), Func); + } + } + + } else { + SendError(Engine(), L, Name + " is not a global function!"); + ClearStack(L); + } + } else { + SendError(Engine(), L, "Register wrong arguments expected string"); + } + return 0; +} void TLuaFile::Init(const std::string& PluginName, const std::string& FileName, fs::file_time_type LastWrote) { // set global engine for lua_* functions @@ -700,6 +784,7 @@ void TLuaFile::Load() { lua_register(mLuaState, "StopThread", lua_StopThread); lua_register(mLuaState, "DropPlayer", lua_dropPlayer); lua_register(mLuaState, "GetPlayerHWID", lua_HWID); + lua_register(mLuaState, "Register", lua_Register); lua_register(mLuaState, "exit", lua_ServerExit); lua_register(mLuaState, "Sleep", lua_Sleep); lua_register(mLuaState, "print", lua_Print); @@ -778,24 +863,6 @@ void SendError(TLuaEngine& Engine, lua_State* L, const std::string& msg) { warn(a + (" | Incorrect Call of ") + msg); } -int lua_TempFix(lua_State* L) { - if (lua_isnumber(L, 1)) { - int ID = int(lua_tonumber(L, 1)); - auto MaybeClient = GetClient(Engine().Server(), ID); - if (!MaybeClient || MaybeClient.value().expired()) - return 0; - std::string Ret; - auto c = MaybeClient.value().lock(); - if (c->IsGuest()) { - Ret = "Guest-" + c->GetName(); - } else - Ret = c->GetName(); - lua_pushstring(L, Ret.c_str()); - } else - SendError(Engine(), L, "GetDID not enough arguments"); - return 1; -} - void TLuaArg::PushArgs(lua_State* State) { for (std::any arg : args) { if (!arg.has_value()) { From cc88734279894d4eefbf230f620d74c94818af08 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 25 Jun 2021 00:42:45 +0200 Subject: [PATCH 002/255] implement GetOSName, start working on HttpsPOST --- include/Http.h | 4 +- src/Http.cpp | 10 +--- src/THeartbeatThread.cpp | 4 +- src/TLuaEngine.cpp | 4 ++ src/TLuaFile.cpp | 124 +++++++++++++++++++++++++++++++-------- src/TNetwork.cpp | 2 +- 6 files changed, 113 insertions(+), 35 deletions(-) diff --git a/include/Http.h b/include/Http.h index e0eb564..375aba3 100644 --- a/include/Http.h +++ b/include/Http.h @@ -5,5 +5,5 @@ namespace Http { std::string GET(const std::string& host, int port, const std::string& target); -std::string POST(const std::string& host, const std::string& target, const std::unordered_map& fields, const std::string& body, bool json); -} \ No newline at end of file +std::string POST(const std::string& host, const std::string& target, const std::unordered_map& fields, const std::string& body, const std::string& ContentType); +} diff --git a/src/Http.cpp b/src/Http.cpp index d6ce399..32f8745 100644 --- a/src/Http.cpp +++ b/src/Http.cpp @@ -54,7 +54,7 @@ std::string Http::GET(const std::string& host, int port, const std::string& targ } } -std::string Http::POST(const std::string& host, const std::string& target, const std::unordered_map& fields, const std::string& body, bool json) { +std::string Http::POST(const std::string& host, const std::string& target, const std::unordered_map& fields, const std::string& body, const std::string& ContentType) { try { net::io_context io; @@ -96,12 +96,8 @@ std::string Http::POST(const std::string& host, const std::string& target, const req.set(http::field::host, host); if (!body.empty()) { - if (json) { - // FIXME: json is untested. - req.set(http::field::content_type, "application/json"); - } else { - req.set(http::field::content_type, "application/x-www-form-urlencoded"); - } + req.set(http::field::content_type, ContentType); // "application/json" + // "application/x-www-form-urlencoded" req.set(http::field::content_length, std::to_string(body.size())); req.body() = body; // info("body is " + body + " (" + req.body() + ")"); diff --git a/src/THeartbeatThread.cpp b/src/THeartbeatThread.cpp index ca22780..0d4f4b3 100644 --- a/src/THeartbeatThread.cpp +++ b/src/THeartbeatThread.cpp @@ -35,12 +35,12 @@ void THeartbeatThread::operator()() { Body += "&pps=" + Application::PPS(); - T = Http::POST(Application::GetBackendHostname(), "/heartbeat", {}, Body, false); + T = Http::POST(Application::GetBackendHostname(), "/heartbeat", {}, Body, "application/x-www-form-urlencoded"); if (T.substr(0, 2) != "20") { //Backend system refused server startup! std::this_thread::sleep_for(std::chrono::milliseconds(500)); - T = Http::POST(Application::GetBackendHostname(), "/heartbeat", {}, Body, false); + T = Http::POST(Application::GetBackendHostname(), "/heartbeat", {}, Body, "application/x-www-form-urlencoded"); // TODO backup2 + HTTP flag (no TSL) if (T.substr(0, 2) != "20") { warn("Backend system refused server! Server might not show in the public list"); diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 6db855a..87a1f7c 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -75,7 +75,11 @@ void TLuaEngine::FolderList(const std::string& Path, bool HotSwap) { } void TLuaEngine::RegisterFiles(const std::string& Path, bool HotSwap) { +#if defined(__linux) || defined(__linux__) + std::string Name = Path.substr(Path.find_last_of('/') + 1); +#else std::string Name = Path.substr(Path.find_last_of('\\') + 1); +#endif if (!HotSwap) info(("Loading plugin : ") + Name); for (const auto& entry : fs::directory_iterator(Path)) { diff --git a/src/TLuaFile.cpp b/src/TLuaFile.cpp index ba1d7f1..b9322a0 100644 --- a/src/TLuaFile.cpp +++ b/src/TLuaFile.cpp @@ -2,6 +2,7 @@ #include "Client.h" #include "Common.h" #include "CustomAssert.h" +#include "Http.h" #include "TLuaEngine.h" #include "TNetwork.h" #include "TServer.h" @@ -9,7 +10,30 @@ #include #include -// TODO: REWRITE +namespace LuaTable { +void Begin(lua_State* L) { + lua_newtable(L); +} + +void End(lua_State* L, const std::string& name) { + lua_setglobal(L, name.c_str()); +} + +void BeginEntry(lua_State* L, const std::string& name) { + lua_pushstring(L, name.c_str()); +} + +void EndEntry(lua_State* L) { + lua_settable(L, -3); +} + +void InsertFunction(lua_State* L, const std::string& name, lua_CFunction func) { + BeginEntry(L, name); + lua_pushcfunction(L, func); + EndEntry(L); +} + +} void SendError(TLuaEngine& Engine, lua_State* L, const std::string& msg); std::any CallFunction(TLuaFile* lua, const std::string& FuncName, std::shared_ptr Arg); @@ -39,6 +63,7 @@ std::shared_ptr CreateArg(lua_State* L, int T, int S) { } return temp; } + void ClearStack(lua_State* L) { lua_settop(L, 0); } @@ -561,6 +586,42 @@ int lua_Set(lua_State* L) { return 0; } +/* +// CallInPlugin(PluginName, FunctionName) +int lua_CallInPlugin(lua_State* L) { + if (!lua_isstring(L, 1)) { + SendError(Engine(), L, "CallInPlugin expects a string as 1. argument."); + return 1; + } + if (!lua_isstring(L, 2)) { + SendError(Engine(), L, "CallInPlugin expects a string as 2. argument."); + return 1; + } + const char* PluginName = lua_tostring(L, 1); + const char* FunctionName = lua_tostring(L, 2); + + bool FoundPlugin = false; + for (const auto& File : Engine().LuaFiles()) { + if (File->GetPluginName() == PluginName) { + FoundPlugin = true; + auto State = File->GetState(); + lua_getglobal(State, FunctionName); + if (!lua_isfunction(State, -1)) { + SendError(Engine(), L, "CallInPlugin: \"" + std::string(FunctionName) + "\" in plugin \"" + std::string(PluginName) + "\" is not a function."); + return 1; + } + ClearStack(State); + CallFunction(File.get(), FunctionName, nullptr); + } + } + if (!FoundPlugin) { + SendError(Engine(), L, "CallInPlugin: Could not find plugin called \"" + std::string(PluginName) + "\""); + return 1; + } + + return 0; +} +*/ extern "C" { int lua_Print(lua_State* L) { @@ -763,32 +824,48 @@ void TLuaFile::SetFileName(const std::string& Name) { mFileName = Name; } +// GetOSName() -> Linux || Windows || Other +int lua_GetOSName(lua_State* L) { +#if defined(__linux) || defined(__linux__) + lua_pushstring(L, "Linux"); +#elif defined(WIN32) + lua_pushstring(L, "Windows"); +#else + lua_pushstring(L, "Unknown"); +#endif +} + void TLuaFile::Load() { Assert(mLuaState); luaL_openlibs(mLuaState); - lua_register(mLuaState, "GetPlayerIdentifiers", lua_GetIdentifiers); - lua_register(mLuaState, "TriggerGlobalEvent", lua_TriggerEventG); - lua_register(mLuaState, "TriggerLocalEvent", lua_TriggerEventL); - lua_register(mLuaState, "TriggerClientEvent", lua_RemoteEvent); - lua_register(mLuaState, "GetPlayerCount", lua_GetPlayerCount); - lua_register(mLuaState, "isPlayerConnected", lua_isConnected); - lua_register(mLuaState, "RegisterEvent", lua_RegisterEvent); - lua_register(mLuaState, "GetPlayerName", lua_GetPlayerName); - lua_register(mLuaState, "RemoveVehicle", lua_RemoveVehicle); - lua_register(mLuaState, "GetPlayerDiscordID", lua_TempFix); - lua_register(mLuaState, "CreateThread", lua_CreateThread); - lua_register(mLuaState, "GetPlayerVehicles", lua_GetCars); - lua_register(mLuaState, "SendChatMessage", lua_sendChat); - lua_register(mLuaState, "GetPlayers", lua_GetAllPlayers); - lua_register(mLuaState, "GetPlayerGuest", lua_GetGuest); - lua_register(mLuaState, "StopThread", lua_StopThread); - lua_register(mLuaState, "DropPlayer", lua_dropPlayer); - lua_register(mLuaState, "GetPlayerHWID", lua_HWID); + + LuaTable::Begin(mLuaState); + LuaTable::InsertFunction(mLuaState, "GetPlayerIdentifiers", lua_GetIdentifiers); + LuaTable::InsertFunction(mLuaState, "TriggerGlobalEvent", lua_TriggerEventG); + LuaTable::InsertFunction(mLuaState, "TriggerLocalEvent", lua_TriggerEventL); + LuaTable::InsertFunction(mLuaState, "TriggerClientEvent", lua_RemoteEvent); + LuaTable::InsertFunction(mLuaState, "GetPlayerCount", lua_GetPlayerCount); + LuaTable::InsertFunction(mLuaState, "IsPlayerConnected", lua_isConnected); + LuaTable::InsertFunction(mLuaState, "RegisterEvent", lua_RegisterEvent); + LuaTable::InsertFunction(mLuaState, "GetPlayerName", lua_GetPlayerName); + LuaTable::InsertFunction(mLuaState, "RemoveVehicle", lua_RemoveVehicle); + LuaTable::InsertFunction(mLuaState, "GetPlayerDiscordID", lua_TempFix); + LuaTable::InsertFunction(mLuaState, "CreateThread", lua_CreateThread); + LuaTable::InsertFunction(mLuaState, "GetPlayerVehicles", lua_GetCars); + LuaTable::InsertFunction(mLuaState, "SendChatMessage", lua_sendChat); + LuaTable::InsertFunction(mLuaState, "GetPlayers", lua_GetAllPlayers); + LuaTable::InsertFunction(mLuaState, "GetPlayerGuest", lua_GetGuest); + LuaTable::InsertFunction(mLuaState, "StopThread", lua_StopThread); + LuaTable::InsertFunction(mLuaState, "DropPlayer", lua_dropPlayer); lua_register(mLuaState, "Register", lua_Register); - lua_register(mLuaState, "exit", lua_ServerExit); - lua_register(mLuaState, "Sleep", lua_Sleep); + LuaTable::InsertFunction(mLuaState, "GetPlayerHWID", lua_HWID); + LuaTable::InsertFunction(mLuaState, "Sleep", lua_Sleep); + LuaTable::InsertFunction(mLuaState, "Set", lua_Set); + LuaTable::InsertFunction(mLuaState, "GetOSName", lua_GetOSName); + LuaTable::End(mLuaState, "MP"); + lua_register(mLuaState, "print", lua_Print); - lua_register(mLuaState, "Set", lua_Set); + lua_register(mLuaState, "exit", lua_ServerExit); if (!mConsole) Reload(); } @@ -863,6 +940,7 @@ void SendError(TLuaEngine& Engine, lua_State* L, const std::string& msg) { warn(a + (" | Incorrect Call of ") + msg); } + void TLuaArg::PushArgs(lua_State* State) { for (std::any arg : args) { if (!arg.has_value()) { @@ -887,4 +965,4 @@ void TLuaArg::PushArgs(lua_State* State) { error("what in the hell is " + std::string(arg.type().name())); } } -} +} \ No newline at end of file diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index 5dbb640..eeb451c 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -281,7 +281,7 @@ void TNetwork::Authentication(SOCKET TCPSock) { } if (!Rc.empty()) { - Rc = Http::POST(Application::GetBackendUrlForAuth(), "/pkToUser", {}, R"({"key":")" + Rc + "\"}", true); + Rc = Http::POST(Application::GetBackendUrlForAuth(), "/pkToUser", {}, R"({"key":")" + Rc + "\"}", "application/json"); } json::Document AuthResponse; From 4cd00936871a6c71e26367163ac95e4a834f2a61 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 25 Jun 2021 00:48:52 +0200 Subject: [PATCH 003/255] rebase --- src/TLuaFile.cpp | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/src/TLuaFile.cpp b/src/TLuaFile.cpp index b9322a0..4e19e59 100644 --- a/src/TLuaFile.cpp +++ b/src/TLuaFile.cpp @@ -681,52 +681,44 @@ int lua_TempFix(lua_State* L) { } template -struct fun_ptr_helper -{ +struct fun_ptr_helper { public: typedef std::function function_type; - static void bind(function_type&& f) - { instance().fn_.swap(f); } + static void bind(function_type&& f) { instance().fn_.swap(f); } - static void bind(const function_type& f) - { instance().fn_=f; } + static void bind(const function_type& f) { instance().fn_ = f; } - static Res invoke(ArgTypes... args) - { return instance().fn_(args...); } + static Res invoke(ArgTypes... args) { return instance().fn_(args...); } typedef decltype(&fun_ptr_helper::invoke) pointer_type; - static pointer_type ptr() - { return &invoke; } + static pointer_type ptr() { return &invoke; } private: - static fun_ptr_helper& instance() - { + static fun_ptr_helper& instance() { static fun_ptr_helper inst_; return inst_; } - fun_ptr_helper() {} + fun_ptr_helper() { } function_type fn_; }; template typename fun_ptr_helper<_UniqueId, _Res, _ArgTypes...>::pointer_type -get_fn_ptr(const std::function<_Res(_ArgTypes...)>& f) -{ +get_fn_ptr(const std::function<_Res(_ArgTypes...)>& f) { fun_ptr_helper<_UniqueId, _Res, _ArgTypes...>::bind(f); return fun_ptr_helper<_UniqueId, _Res, _ArgTypes...>::ptr(); } - int lua_Register(lua_State* L) { - if(lua_isstring(L, 1)){ + if (lua_isstring(L, 1)) { std::string Name(lua_tolstring(L, 1, nullptr)); lua_getglobal(L, Name.c_str()); if (lua_isfunction(L, -1)) { for (auto& Script : Engine().LuaFiles()) { - if(Script->GetState() != L){ + if (Script->GetState() != L) { lua_CFunction Func = get_fn_ptr<0>(std::function([=](lua_State* A) { lua_getglobal(L, Name.c_str()); if (lua_isfunction(L, -1)) { @@ -833,6 +825,7 @@ int lua_GetOSName(lua_State* L) { #else lua_pushstring(L, "Unknown"); #endif + return 1; } void TLuaFile::Load() { @@ -857,7 +850,7 @@ void TLuaFile::Load() { LuaTable::InsertFunction(mLuaState, "GetPlayerGuest", lua_GetGuest); LuaTable::InsertFunction(mLuaState, "StopThread", lua_StopThread); LuaTable::InsertFunction(mLuaState, "DropPlayer", lua_dropPlayer); - lua_register(mLuaState, "Register", lua_Register); + LuaTable::InsertFunction(mLuaState, "Register", lua_Register); LuaTable::InsertFunction(mLuaState, "GetPlayerHWID", lua_HWID); LuaTable::InsertFunction(mLuaState, "Sleep", lua_Sleep); LuaTable::InsertFunction(mLuaState, "Set", lua_Set); @@ -940,7 +933,6 @@ void SendError(TLuaEngine& Engine, lua_State* L, const std::string& msg) { warn(a + (" | Incorrect Call of ") + msg); } - void TLuaArg::PushArgs(lua_State* State) { for (std::any arg : args) { if (!arg.has_value()) { @@ -965,4 +957,4 @@ void TLuaArg::PushArgs(lua_State* State) { error("what in the hell is " + std::string(arg.type().name())); } } -} \ No newline at end of file +} From 55ee1d3747952134dbb54f1b1d73770fe6a344dc Mon Sep 17 00:00:00 2001 From: Anonymous-275 Date: Fri, 25 Jun 2021 02:12:21 +0300 Subject: [PATCH 004/255] simpler lua_Register --- src/TLuaFile.cpp | 49 +++++++++++++++++------------------------------- 1 file changed, 17 insertions(+), 32 deletions(-) diff --git a/src/TLuaFile.cpp b/src/TLuaFile.cpp index 4e19e59..977535d 100644 --- a/src/TLuaFile.cpp +++ b/src/TLuaFile.cpp @@ -680,53 +680,38 @@ int lua_TempFix(lua_State* L) { return 1; } -template -struct fun_ptr_helper { -public: - typedef std::function function_type; +template +struct CFunctionPointer { + std::function func; - static void bind(function_type&& f) { instance().fn_.swap(f); } - - static void bind(const function_type& f) { instance().fn_ = f; } - - static Res invoke(ArgTypes... args) { return instance().fn_(args...); } - - typedef decltype(&fun_ptr_helper::invoke) pointer_type; - static pointer_type ptr() { return &invoke; } - -private: - static fun_ptr_helper& instance() { - static fun_ptr_helper inst_; - return inst_; + static int callback(lua_State* s) { + return instance().func(s); } - fun_ptr_helper() { } - - function_type fn_; + static CFunctionPointer& instance() { + static CFunctionPointer inst_; + return inst_; + } }; -template -typename fun_ptr_helper<_UniqueId, _Res, _ArgTypes...>::pointer_type -get_fn_ptr(const std::function<_Res(_ArgTypes...)>& f) { - fun_ptr_helper<_UniqueId, _Res, _ArgTypes...>::bind(f); - return fun_ptr_helper<_UniqueId, _Res, _ArgTypes...>::ptr(); -} - int lua_Register(lua_State* L) { - if (lua_isstring(L, 1)) { + if(lua_isstring(L, 1)){ std::string Name(lua_tolstring(L, 1, nullptr)); lua_getglobal(L, Name.c_str()); if (lua_isfunction(L, -1)) { for (auto& Script : Engine().LuaFiles()) { - if (Script->GetState() != L) { - lua_CFunction Func = get_fn_ptr<0>(std::function([=](lua_State* A) { + if(Script->GetState() != L){ + + CFunctionPointer<0> F; //How do we pass a value instead of a const + F.instance().func = [=](lua_State* A) { lua_getglobal(L, Name.c_str()); if (lua_isfunction(L, -1)) { lua_pcall(L, 0, 0, 0); } return 0; - })); - lua_register(Script->GetState(), Name.c_str(), Func); + }; + + lua_register(Script->GetState(), Name.c_str(), F.callback); } } From a23946dddf6d8ec3725ed162910cdfa90ae71193 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 25 Jun 2021 01:59:38 +0200 Subject: [PATCH 005/255] switch to toml11 it's better, believe me --- .gitmodules | 6 +-- CMakeLists.txt | 2 +- include/TConfig.h | 2 + include/toml11 | 1 + include/tomlplusplus | 1 - src/TConfig.cpp | 117 +++++++++++++++++-------------------------- src/TLuaFile.cpp | 36 ------------- 7 files changed, 54 insertions(+), 111 deletions(-) create mode 160000 include/toml11 delete mode 160000 include/tomlplusplus diff --git a/.gitmodules b/.gitmodules index 71828b9..0d23bc7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,6 +10,6 @@ [submodule "rapidjson"] path = rapidjson url = https://github.com/Tencent/rapidjson -[submodule "include/tomlplusplus"] - path = include/tomlplusplus - url = https://github.com/marzer/tomlplusplus +[submodule "include/toml11"] + path = include/toml11 + url = https://github.com/ToruNiina/toml11 diff --git a/CMakeLists.txt b/CMakeLists.txt index 182749c..2a5a9f2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,7 +53,7 @@ add_executable(BeamMP-Server target_include_directories(BeamMP-Server PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_SOURCE_DIR}/commandline") find_package(Lua REQUIRED) -target_include_directories(BeamMP-Server PUBLIC ${Boost_INCLUDE_DIRS} ${LUA_INCLUDE_DIR} "socket.io-client-cpp/src" "include/tomlplusplus") +target_include_directories(BeamMP-Server PUBLIC ${Boost_INCLUDE_DIRS} ${LUA_INCLUDE_DIR} "socket.io-client-cpp/src") find_package(OpenSSL REQUIRED) diff --git a/include/TConfig.h b/include/TConfig.h index ffb2b53..60001bd 100644 --- a/include/TConfig.h +++ b/include/TConfig.h @@ -10,6 +10,8 @@ public: [[nodiscard]] bool Failed() const { return mFailed; } + void FlushToFile(); + private: void CreateConfigFile(std::string_view name); void ParseFromFile(std::string_view name); diff --git a/include/toml11 b/include/toml11 new file mode 160000 index 0000000..6473810 --- /dev/null +++ b/include/toml11 @@ -0,0 +1 @@ +Subproject commit 647381020ef04b5d41d540ec489eba45e82d90a7 diff --git a/include/tomlplusplus b/include/tomlplusplus deleted file mode 160000 index bc6891e..0000000 --- a/include/tomlplusplus +++ /dev/null @@ -1 +0,0 @@ -Subproject commit bc6891e1fbec0b137ac5795542d728a1ad124c11 diff --git a/src/TConfig.cpp b/src/TConfig.cpp index d2a0696..8a2d9f4 100644 --- a/src/TConfig.cpp +++ b/src/TConfig.cpp @@ -1,4 +1,6 @@ -#include // header-only version of TOML++ +#define TOML11_PRESERVE_COMMENTS_BY_DEFAULT + +#include // header-only version of TOML++ #include "TConfig.h" #include @@ -32,6 +34,23 @@ TConfig::TConfig() { } } +void TConfig::FlushToFile() { + auto data = toml::parse(ConfigFileName); + data["General"] = toml::table(); + data["General"][StrAuthKey.data()] = Application::Settings.Key; + data["General"][StrDebug.data()] = Application::Settings.DebugModeEnabled; + data["General"][StrPrivate.data()] = Application::Settings.Private; + data["General"][StrPort.data()] = Application::Settings.Port; + data["General"][StrName.data()] = Application::Settings.ServerName; + data["General"][StrMaxCars.data()] = Application::Settings.MaxCars; + data["General"][StrMaxPlayers.data()] = Application::Settings.MaxPlayers; + data["General"][StrMap.data()] = Application::Settings.MapName; + data["General"][StrDescription.data()] = Application::Settings.ServerDesc; + data["General"][StrResourceFolder.data()] = Application::Settings.Resource; + std::ofstream Stream(ConfigFileName); + Stream << data << std::flush; +} + void TConfig::CreateConfigFile(std::string_view name) { // build from old config Server.cfg @@ -44,32 +63,31 @@ void TConfig::CreateConfigFile(std::string_view name) { error("an error occurred and was ignored during config transfer: " + std::string(e.what())); } - toml::table tbl { { + { // create file context + std::ofstream ofs(name.data()); + } - { "General", - toml::table { { + auto data = toml::parse(name.data()); - { StrDebug, Application::Settings.DebugModeEnabled }, - { StrPrivate, Application::Settings.Private }, - { StrPort, Application::Settings.Port }, - { StrMaxCars, Application::Settings.MaxCars }, - { StrMaxPlayers, Application::Settings.MaxPlayers }, - { StrMap, Application::Settings.MapName }, - { StrName, Application::Settings.ServerName }, - { StrDescription, Application::Settings.ServerDesc }, - { StrResourceFolder, Application::Settings.Resource }, - { StrAuthKey, Application::Settings.Key }, + data["General"] = toml::table(); + data["General"][StrAuthKey.data()] = Application::Settings.Key; + data["General"][StrDebug.data()] = Application::Settings.DebugModeEnabled; + data["General"][StrPrivate.data()] = Application::Settings.Private; + data["General"][StrPort.data()] = Application::Settings.Port; + data["General"][StrName.data()] = Application::Settings.ServerName; + data["General"][StrMaxCars.data()] = Application::Settings.MaxCars; + data["General"][StrMaxPlayers.data()] = Application::Settings.MaxPlayers; + data["General"][StrMap.data()] = Application::Settings.MapName; + data["General"][StrDescription.data()] = Application::Settings.ServerDesc; + data["General"][StrResourceFolder.data()] = Application::Settings.Resource; - } } }, - - } }; std::ofstream ofs { std::string(name) }; if (ofs.good()) { ofs << "# This is the BeamMP-Server config file.\n" "# Help & Documentation: `https://wiki.beammp.com/en/home/server-maintenance`\n" "# IMPORTANT: Fill in the AuthKey with the key you got from `https://beammp.com/k/dashboard` on the left under \"Keys\"\n" << '\n'; - ofs << tbl << '\n'; + ofs << data << '\n'; error("There was no \"" + std::string(ConfigFileName) + "\" file (this is normal for the first time running the server), so one was generated for you. It was automatically filled with the settings from your Server.cfg, if you have one. Please open ServerConfig.toml and ensure your AuthKey and other settings are filled in and correct, then restart the server. The old Server.cfg file will no longer be used and causes a warning if it exists from now on."); mFailed = true; } else { @@ -80,58 +98,17 @@ void TConfig::CreateConfigFile(std::string_view name) { void TConfig::ParseFromFile(std::string_view name) { try { - toml::table FullTable = toml::parse_file(name); - toml::table GeneralTable = *FullTable["General"].as_table(); - if (auto val = GeneralTable[StrDebug].value(); val.has_value()) { - Application::Settings.DebugModeEnabled = val.value(); - } else { - throw std::runtime_error(std::string(StrDebug)); - } - if (auto val = GeneralTable[StrPrivate].value(); val.has_value()) { - Application::Settings.Private = val.value(); - } else { - throw std::runtime_error(std::string(StrPrivate)); - } - if (auto val = GeneralTable[StrPort].value(); val.has_value()) { - Application::Settings.Port = val.value(); - } else { - throw std::runtime_error(std::string(StrPort)); - } - if (auto val = GeneralTable[StrMaxCars].value(); val.has_value()) { - Application::Settings.MaxCars = val.value(); - } else { - throw std::runtime_error(std::string(StrMaxCars)); - } - if (auto val = GeneralTable[StrMaxPlayers].value(); val.has_value()) { - Application::Settings.MaxPlayers = val.value(); - } else { - throw std::runtime_error(std::string(StrMaxPlayers)); - } - if (auto val = GeneralTable[StrMap].value(); val.has_value()) { - Application::Settings.MapName = val.value(); - } else { - throw std::runtime_error(std::string(StrMap)); - } - if (auto val = GeneralTable[StrName].value(); val.has_value()) { - Application::Settings.ServerName = val.value(); - } else { - throw std::runtime_error(std::string(StrName)); - } - if (auto val = GeneralTable[StrDescription].value(); val.has_value()) { - Application::Settings.ServerDesc = val.value(); - } else { - throw std::runtime_error(std::string(StrDescription)); - } - if (auto val = GeneralTable[StrResourceFolder].value(); val.has_value()) { - Application::Settings.Resource = val.value(); - } else { - throw std::runtime_error(std::string(StrResourceFolder)); - } - if (auto val = GeneralTable[StrAuthKey].value(); val.has_value()) { - Application::Settings.Key = val.value(); - } else { - throw std::runtime_error(std::string(StrAuthKey)); - } + toml::value data = toml::parse(name.data()); + Application::Settings.DebugModeEnabled = data["General"][StrDebug.data()].as_boolean(); + Application::Settings.Private = data["General"][StrPrivate.data()].as_boolean(); + Application::Settings.Port = data["General"][StrPort.data()].as_integer(); + Application::Settings.MaxCars = data["General"][StrMaxCars.data()].as_integer(); + Application::Settings.MaxPlayers = data["General"][StrMaxPlayers.data()].as_integer(); + Application::Settings.MapName = data["General"][StrMap.data()].as_string(); + Application::Settings.ServerName = data["General"][StrName.data()].as_string(); + Application::Settings.ServerDesc = data["General"][StrDescription.data()].as_string(); + Application::Settings.Resource = data["General"][StrResourceFolder.data()].as_string(); + Application::Settings.Key = data["General"][StrAuthKey.data()].as_string(); } catch (const std::exception& err) { error("Error parsing config file value: " + std::string(err.what())); mFailed = true; diff --git a/src/TLuaFile.cpp b/src/TLuaFile.cpp index 977535d..71f1198 100644 --- a/src/TLuaFile.cpp +++ b/src/TLuaFile.cpp @@ -586,42 +586,6 @@ int lua_Set(lua_State* L) { return 0; } -/* -// CallInPlugin(PluginName, FunctionName) -int lua_CallInPlugin(lua_State* L) { - if (!lua_isstring(L, 1)) { - SendError(Engine(), L, "CallInPlugin expects a string as 1. argument."); - return 1; - } - if (!lua_isstring(L, 2)) { - SendError(Engine(), L, "CallInPlugin expects a string as 2. argument."); - return 1; - } - const char* PluginName = lua_tostring(L, 1); - const char* FunctionName = lua_tostring(L, 2); - - bool FoundPlugin = false; - for (const auto& File : Engine().LuaFiles()) { - if (File->GetPluginName() == PluginName) { - FoundPlugin = true; - auto State = File->GetState(); - lua_getglobal(State, FunctionName); - if (!lua_isfunction(State, -1)) { - SendError(Engine(), L, "CallInPlugin: \"" + std::string(FunctionName) + "\" in plugin \"" + std::string(PluginName) + "\" is not a function."); - return 1; - } - ClearStack(State); - CallFunction(File.get(), FunctionName, nullptr); - } - } - if (!FoundPlugin) { - SendError(Engine(), L, "CallInPlugin: Could not find plugin called \"" + std::string(PluginName) + "\""); - return 1; - } - - return 0; -} -*/ extern "C" { int lua_Print(lua_State* L) { From fb76b8309a4a1c99b2ad79711cb991394ccd1765 Mon Sep 17 00:00:00 2001 From: Anonymous-275 Date: Sun, 27 Jun 2021 14:28:16 +0300 Subject: [PATCH 006/255] Fully working lua_Register --- include/TLuaEngine.h | 4 +++- src/TLuaEngine.cpp | 2 ++ src/TLuaFile.cpp | 37 ++++++++++++++++--------------------- 3 files changed, 21 insertions(+), 22 deletions(-) diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index 9e59964..94e3189 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -4,10 +4,11 @@ #include "IThreaded.h" #include "TLuaFile.h" #include "TServer.h" +#include #include #include -#include #include +#include class TLuaEngine : public IThreaded { public: @@ -25,6 +26,7 @@ public: std::optional> GetScript(lua_State* L); + static std::unordered_map mGlobals; private: void FolderList(const std::string& Path, bool HotSwap); void RegisterFiles(const std::string& Path, bool HotSwap); diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 87a1f7c..cd535a9 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -6,6 +6,8 @@ namespace fs = std::filesystem; +std::unordered_map TLuaEngine::mGlobals; + // necessary as lua relies on global state TLuaEngine* TheEngine; diff --git a/src/TLuaFile.cpp b/src/TLuaFile.cpp index 71f1198..49129c0 100644 --- a/src/TLuaFile.cpp +++ b/src/TLuaFile.cpp @@ -644,38 +644,33 @@ int lua_TempFix(lua_State* L) { return 1; } -template -struct CFunctionPointer { - std::function func; +int lua_Registered(lua_State* L) { - static int callback(lua_State* s) { - return instance().func(s); + lua_Debug info; + lua_getstack(L, 0, &info); + lua_getinfo(L, "n", &info); + + if(auto it = TLuaEngine::mGlobals.find(info.name); it != TLuaEngine::mGlobals.end()){ + lua_getglobal(it->second, info.name); + if (lua_isfunction(it->second, -1)) { + lua_pcall(it->second, 0, 0, 0); //TODO revisit to allow arguments and return + } + return 0; } - static CFunctionPointer& instance() { - static CFunctionPointer inst_; - return inst_; - } -}; + SendError(Engine(), L, "Cannot find global '" + std::string(info.name) + "\'"); + return 0; +} int lua_Register(lua_State* L) { if(lua_isstring(L, 1)){ std::string Name(lua_tolstring(L, 1, nullptr)); lua_getglobal(L, Name.c_str()); if (lua_isfunction(L, -1)) { + TLuaEngine::mGlobals.emplace(Name, L); for (auto& Script : Engine().LuaFiles()) { if(Script->GetState() != L){ - - CFunctionPointer<0> F; //How do we pass a value instead of a const - F.instance().func = [=](lua_State* A) { - lua_getglobal(L, Name.c_str()); - if (lua_isfunction(L, -1)) { - lua_pcall(L, 0, 0, 0); - } - return 0; - }; - - lua_register(Script->GetState(), Name.c_str(), F.callback); + lua_register(Script->GetState(), Name.c_str(), lua_Registered); } } From 8853cef809dfff773090e64dc6734a8e7c954ad9 Mon Sep 17 00:00:00 2001 From: Anonymous-275 Date: Sun, 27 Jun 2021 14:29:55 +0300 Subject: [PATCH 007/255] TODO edit --- src/TLuaFile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TLuaFile.cpp b/src/TLuaFile.cpp index 49129c0..6c058b1 100644 --- a/src/TLuaFile.cpp +++ b/src/TLuaFile.cpp @@ -653,7 +653,7 @@ int lua_Registered(lua_State* L) { if(auto it = TLuaEngine::mGlobals.find(info.name); it != TLuaEngine::mGlobals.end()){ lua_getglobal(it->second, info.name); if (lua_isfunction(it->second, -1)) { - lua_pcall(it->second, 0, 0, 0); //TODO revisit to allow arguments and return + lua_pcall(it->second, 0, 0, 0); //TODO revisit to allow arguments and return also we need to mutex this } return 0; } From 44e0f3aa21411781cd487c58ec0da728428062d4 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 1 Jul 2021 00:33:28 +0200 Subject: [PATCH 008/255] add MP.HttpsGET, MP.HttpsPOST --- include/Http.h | 5 +- src/Http.cpp | 105 +++++++++++++++++++++++++----------- src/THeartbeatThread.cpp | 4 +- src/TLuaFile.cpp | 112 +++++++++++++++++++++++++++++++++++++-- src/TNetwork.cpp | 4 +- 5 files changed, 188 insertions(+), 42 deletions(-) diff --git a/include/Http.h b/include/Http.h index 375aba3..7efba8f 100644 --- a/include/Http.h +++ b/include/Http.h @@ -4,6 +4,7 @@ #include namespace Http { -std::string GET(const std::string& host, int port, const std::string& target); -std::string POST(const std::string& host, const std::string& target, const std::unordered_map& fields, const std::string& body, const std::string& ContentType); +std::string GET(const std::string& host, int port, const std::string& target, unsigned int* status = nullptr); +std::string POST(const std::string& host, int port, const std::string& target, const std::unordered_map& fields, const std::string& body, const std::string& ContentType, unsigned int* status = nullptr); +static inline const char* ErrorString = "!BeamMPHttpsError!"; } diff --git a/src/Http.cpp b/src/Http.cpp index 32f8745..00c557b 100644 --- a/src/Http.cpp +++ b/src/Http.cpp @@ -14,47 +14,85 @@ namespace net = boost::asio; // from namespace ssl = net::ssl; // from using tcp = net::ip::tcp; // from -std::string Http::GET(const std::string& host, int port, const std::string& target) { - // FIXME: doesn't support https - // if it causes issues, yell at me and I'll fix it asap. - Lion +std::string Http::GET(const std::string& host, int port, const std::string& target, unsigned int* status) { try { - net::io_context io; - tcp::resolver resolver(io); - beast::tcp_stream stream(io); - auto const results = resolver.resolve(host, std::to_string(port)); - stream.connect(results); + // Check command line arguments. + int version = 11; - http::request req { http::verb::get, target, 11 /* http 1.1 */ }; + // The io_context is required for all I/O + net::io_context ioc; - req.set(http::field::host, host); - // tell the server what we are (boost beast) - req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING); + // The SSL context is required, and holds certificates + ssl::context ctx(ssl::context::tlsv12_client); - http::write(stream, req); + // This holds the root certificate used for verification + // we don't do / have this + // load_root_certificates(ctx); - // used for reading - beast::flat_buffer buffer; - http::response response; + // Verify the remote server's certificate + ctx.set_verify_mode(ssl::verify_none); - http::read(stream, buffer, response); + // These objects perform our I/O + tcp::resolver resolver(ioc); + beast::ssl_stream stream(ioc, ctx); - std::string result(response.body()); - - beast::error_code ec; - stream.socket().shutdown(tcp::socket::shutdown_both, ec); - if (ec && ec != beast::errc::not_connected) { - throw beast::system_error { ec }; // goes down to `return "-1"` anyways + // Set SNI Hostname (many hosts need this to handshake successfully) + if (!SSL_set_tlsext_host_name(stream.native_handle(), host.c_str())) { + beast::error_code ec { static_cast(::ERR_get_error()), net::error::get_ssl_category() }; + throw beast::system_error { ec }; } - return result; + // Look up the domain name + auto const results = resolver.resolve(host.c_str(), std::to_string(port)); - } catch (const std::exception& e) { - Application::Console().Write(e.what()); - return "-1"; + // Make the connection on the IP address we get from a lookup + beast::get_lowest_layer(stream).connect(results); + + // Perform the SSL handshake + stream.handshake(ssl::stream_base::client); + + // Set up an HTTP GET request message + http::request req { http::verb::get, target, version }; + req.set(http::field::host, host); + req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING); + + // Send the HTTP request to the remote host + http::write(stream, req); + + // This buffer is used for reading and must be persisted + beast::flat_buffer buffer; + + // Declare a container to hold the response + http::response res; + + // Receive the HTTP response + http::read(stream, buffer, res); + + // Gracefully close the stream + beast::error_code ec; + stream.shutdown(ec); + if (ec == net::error::eof) { + // Rationale: + // http://stackoverflow.com/questions/25587403/boost-asio-ssl-async-shutdown-always-finishes-with-an-error + ec = {}; + } + + if (status) { + *status = res.base().result_int(); + } + + if (ec) + throw beast::system_error { ec }; + + // If we get here then the connection is closed gracefully + return std::string(res.body()); + } catch (std::exception const& e) { + Application::Console().Write(__func__ + std::string(": ") + e.what()); + return ErrorString; } } -std::string Http::POST(const std::string& host, const std::string& target, const std::unordered_map& fields, const std::string& body, const std::string& ContentType) { +std::string Http::POST(const std::string& host, int port, const std::string& target, const std::unordered_map& fields, const std::string& body, const std::string& ContentType, unsigned int* status) { try { net::io_context io; @@ -68,7 +106,7 @@ std::string Http::POST(const std::string& host, const std::string& target, const decltype(resolver)::results_type results; auto try_connect_with_protocol = [&](tcp protocol) { try { - results = resolver.resolve(protocol, host, std::to_string(443)); + results = resolver.resolve(protocol, host, std::to_string(port)); if (!SSL_set_tlsext_host_name(stream.native_handle(), host.c_str())) { boost::system::error_code ec { static_cast(::ERR_get_error()), boost::asio::error::get_ssl_category() }; // FIXME: we could throw and crash, if we like @@ -121,6 +159,10 @@ std::string Http::POST(const std::string& host, const std::string& target, const http::read(stream, buffer, response); + if (status) { + *status = response.base().result_int(); + } + std::stringstream result; result << response; @@ -131,11 +173,12 @@ std::string Http::POST(const std::string& host, const std::string& target, const // info(result.str()); std::string debug_response_str; std::getline(result, debug_response_str); + //debug("POST " + host + target + ": " + debug_response_str); return std::string(response.body()); } catch (const std::exception& e) { - Application::Console().Write(e.what()); - return "-1"; + Application::Console().Write(__func__ + std::string(": ") + e.what()); + return ErrorString; } } diff --git a/src/THeartbeatThread.cpp b/src/THeartbeatThread.cpp index 0d4f4b3..bacb235 100644 --- a/src/THeartbeatThread.cpp +++ b/src/THeartbeatThread.cpp @@ -35,12 +35,12 @@ void THeartbeatThread::operator()() { Body += "&pps=" + Application::PPS(); - T = Http::POST(Application::GetBackendHostname(), "/heartbeat", {}, Body, "application/x-www-form-urlencoded"); + T = Http::POST(Application::GetBackendHostname(), 443, "/heartbeat", {}, Body, "application/x-www-form-urlencoded"); if (T.substr(0, 2) != "20") { //Backend system refused server startup! std::this_thread::sleep_for(std::chrono::milliseconds(500)); - T = Http::POST(Application::GetBackendHostname(), "/heartbeat", {}, Body, "application/x-www-form-urlencoded"); + T = Http::POST(Application::GetBackendHostname(), 443, "/heartbeat", {}, Body, "application/x-www-form-urlencoded"); // TODO backup2 + HTTP flag (no TSL) if (T.substr(0, 2) != "20") { warn("Backend system refused server! Server might not show in the public list"); diff --git a/src/TLuaFile.cpp b/src/TLuaFile.cpp index 6c058b1..26a7bf9 100644 --- a/src/TLuaFile.cpp +++ b/src/TLuaFile.cpp @@ -650,7 +650,7 @@ int lua_Registered(lua_State* L) { lua_getstack(L, 0, &info); lua_getinfo(L, "n", &info); - if(auto it = TLuaEngine::mGlobals.find(info.name); it != TLuaEngine::mGlobals.end()){ + if (auto it = TLuaEngine::mGlobals.find(info.name); it != TLuaEngine::mGlobals.end()) { lua_getglobal(it->second, info.name); if (lua_isfunction(it->second, -1)) { lua_pcall(it->second, 0, 0, 0); //TODO revisit to allow arguments and return also we need to mutex this @@ -663,13 +663,13 @@ int lua_Registered(lua_State* L) { } int lua_Register(lua_State* L) { - if(lua_isstring(L, 1)){ + if (lua_isstring(L, 1)) { std::string Name(lua_tolstring(L, 1, nullptr)); lua_getglobal(L, Name.c_str()); if (lua_isfunction(L, -1)) { TLuaEngine::mGlobals.emplace(Name, L); for (auto& Script : Engine().LuaFiles()) { - if(Script->GetState() != L){ + if (Script->GetState() != L) { lua_register(Script->GetState(), Name.c_str(), lua_Registered); } } @@ -679,7 +679,7 @@ int lua_Register(lua_State* L) { ClearStack(L); } } else { - SendError(Engine(), L, "Register wrong arguments expected string"); + SendError(Engine(), L, "Wrong arguments to `Register`, expected string"); } return 0; } @@ -772,6 +772,106 @@ int lua_GetOSName(lua_State* L) { return 1; } +// status, body = HttpGET(host, port, target) +// example usage: +// send a GET https://example.com:443/index.html: +// status, body = MP.HttpGET("example.com", 443, "/index.html") +int lua_HttpsGET(lua_State* L) { + if (!lua_isstring(L, 1)) { + SendError(Engine(), L, "`HttpsGET` expects host (type string) as first argument."); + ClearStack(L); + return 0; + } + if (!lua_isnumber(L, 2)) { + SendError(Engine(), L, "`HttpsGET` expects port (type number) as second argument."); + ClearStack(L); + return 0; + } + if (!lua_isstring(L, 3)) { + SendError(Engine(), L, "`HttpsGET` expects target (type string) as third argument."); + ClearStack(L); + return 0; + } + + auto Host = lua_tostring(L, 1); + auto Port = int(lua_tointeger(L, 2)); + auto Target = lua_tostring(L, 3); + + ClearStack(L); + + unsigned int Status; + auto Body = Http::GET(Host, Port, Target, &Status); + lua_pushinteger(L, Status); + + auto PrettyRemote = "https://" + std::string(Host) + ":" + std::to_string(Port) + std::string(Target); + if (Body == Http::ErrorString) { + SendError(Engine(), L, "HTTPS GET " + PrettyRemote + " failed status " + std::to_string(Status) + ". Check the console or log for more info."); + return 1; + } else { + debug("GET " + PrettyRemote + " completed status " + std::to_string(Status)); + } + + lua_pushstring(L, Body.c_str()); + + return 2; +} + +// status, body = HttpsPOST(host, port, target, body, content_type) +int lua_HttpsPOST(lua_State* L) { + if (!lua_isstring(L, 1)) { + SendError(Engine(), L, "`HttpsPOST` expects host (type string) as 1. argument."); + ClearStack(L); + return 0; + } + if (!lua_isnumber(L, 2)) { + SendError(Engine(), L, "`HttpsPOST` expects port (type number) as 2. argument."); + ClearStack(L); + return 0; + } + if (!lua_isstring(L, 3)) { + SendError(Engine(), L, "`HttpsPOST` expects target (type string) as 3. argument."); + ClearStack(L); + return 0; + } + if (!lua_isstring(L, 4)) { + SendError(Engine(), L, "`HttpsPOST` expects body (type string) as 4. argument."); + ClearStack(L); + return 0; + } + if (!lua_isstring(L, 5)) { + SendError(Engine(), L, "`HttpsPOST` expects content_type (type string) as 5. argument."); + ClearStack(L); + return 0; + } + + auto Host = lua_tostring(L, 1); + auto Port = int(lua_tointeger(L, 2)); + auto Target = lua_tostring(L, 3); + auto RequestBody = lua_tostring(L, 4); + auto ContentType = lua_tostring(L, 5); + + ClearStack(L); + + // build fields + std::unordered_map Fields; + + unsigned int Status; + auto ResponseBody = Http::POST(Host, Port, Target, {}, RequestBody, ContentType, &Status); + + lua_pushinteger(L, Status); + + auto PrettyRemote = "https://" + std::string(Host) + ":" + std::to_string(Port) + std::string(Target); + if (ResponseBody == Http::ErrorString) { + SendError(Engine(), L, "HTTPS POST " + PrettyRemote + " failed status " + std::to_string(Status) + ". Check the console or log for more info."); + return 1; + } else { + debug("POST " + PrettyRemote + " completed status " + std::to_string(Status)); + } + + lua_pushstring(L, ResponseBody.c_str()); + return 2; +} + void TLuaFile::Load() { Assert(mLuaState); luaL_openlibs(mLuaState); @@ -799,6 +899,8 @@ void TLuaFile::Load() { LuaTable::InsertFunction(mLuaState, "Sleep", lua_Sleep); LuaTable::InsertFunction(mLuaState, "Set", lua_Set); LuaTable::InsertFunction(mLuaState, "GetOSName", lua_GetOSName); + LuaTable::InsertFunction(mLuaState, "HttpsGET", lua_HttpsGET); + LuaTable::InsertFunction(mLuaState, "HttpsPOST", lua_HttpsPOST); LuaTable::End(mLuaState, "MP"); lua_register(mLuaState, "print", lua_Print); @@ -874,7 +976,7 @@ void SendError(TLuaEngine& Engine, lua_State* L, const std::string& msg) { TLuaFile& S = MaybeS.value(); a = fs::path(S.GetFileName()).filename().string(); } - warn(a + (" | Incorrect Call of ") + msg); + warn(a + (" | Error in MP Lua call: ") + msg); } void TLuaArg::PushArgs(lua_State* State) { diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index eeb451c..279a236 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -281,12 +281,12 @@ void TNetwork::Authentication(SOCKET TCPSock) { } if (!Rc.empty()) { - Rc = Http::POST(Application::GetBackendUrlForAuth(), "/pkToUser", {}, R"({"key":")" + Rc + "\"}", "application/json"); + Rc = Http::POST(Application::GetBackendUrlForAuth(), 443, "/pkToUser", {}, R"({"key":")" + Rc + "\"}", "application/json"); } json::Document AuthResponse; AuthResponse.Parse(Rc.c_str()); - if (Rc == "-1" || AuthResponse.HasParseError()) { + if (Rc == Http::ErrorString || AuthResponse.HasParseError()) { ClientKick(*Client, "Invalid key! Please restart your game."); return; } From e994cdd8a2a905b5e5de387b4995c27c5500b0c7 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 1 Jul 2021 00:44:53 +0200 Subject: [PATCH 009/255] Add printRaw Same as print() but does not prefix with time, date, filename, etc. Use with care. --- src/TLuaFile.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/TLuaFile.cpp b/src/TLuaFile.cpp index 26a7bf9..bb18360 100644 --- a/src/TLuaFile.cpp +++ b/src/TLuaFile.cpp @@ -588,7 +588,7 @@ int lua_Set(lua_State* L) { } extern "C" { -int lua_Print(lua_State* L) { +int InternalLuaPrint(lua_State* L, bool pretty) { int Arg = lua_gettop(L); std::string to_print; for (int i = 1; i <= Arg; i++) { @@ -621,9 +621,19 @@ int lua_Print(lua_State* L) { to_print += "\t"; } } - luaprint(to_print); + if (pretty) { + luaprint(to_print); + } else { + Application::Console().WriteRaw(to_print); + } return 0; } +int lua_Print(lua_State* L) { + return InternalLuaPrint(L, true); +} +int lua_PrintRaw(lua_State* L) { + return InternalLuaPrint(L, false); +} } int lua_TempFix(lua_State* L) { @@ -904,6 +914,7 @@ void TLuaFile::Load() { LuaTable::End(mLuaState, "MP"); lua_register(mLuaState, "print", lua_Print); + lua_register(mLuaState, "printRaw", lua_PrintRaw); lua_register(mLuaState, "exit", lua_ServerExit); if (!mConsole) Reload(); From 261aa8f3208d179b2ca7d181e0069dc2bc9444dc Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 2 Jul 2021 00:01:38 +0200 Subject: [PATCH 010/255] fix comment --- src/TLuaFile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TLuaFile.cpp b/src/TLuaFile.cpp index bb18360..278159b 100644 --- a/src/TLuaFile.cpp +++ b/src/TLuaFile.cpp @@ -782,7 +782,7 @@ int lua_GetOSName(lua_State* L) { return 1; } -// status, body = HttpGET(host, port, target) +// status, body = HttpsGET(host, port, target) // example usage: // send a GET https://example.com:443/index.html: // status, body = MP.HttpGET("example.com", 443, "/index.html") From 7a3848e6409d85b7d42fb49513003d5380c0fd23 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sat, 3 Jul 2021 00:58:19 +0200 Subject: [PATCH 011/255] fix luatable in GetPlayerIdentifiers --- src/TLuaFile.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/TLuaFile.cpp b/src/TLuaFile.cpp index 278159b..17f4ffe 100644 --- a/src/TLuaFile.cpp +++ b/src/TLuaFile.cpp @@ -353,12 +353,13 @@ int lua_GetIdentifiers(lua_State* L) { auto IDs = MaybeClient.value().lock()->GetIdentifiers(); if (IDs.empty()) return 0; - lua_newtable(L); + LuaTable::Begin(L); for (const std::string& ID : IDs) { - lua_pushstring(L, ID.substr(0, ID.find(':')).c_str()); + LuaTable::BeginEntry(L, ID.substr(0, ID.find(':')).c_str()); lua_pushstring(L, ID.c_str()); - lua_settable(L, -3); + LuaTable::EndEntry(L); } + // LuaTable::End(L, ""); } else return 0; } else { From 0acbb70d10eaeb1ce2c5767bf66edab364ad2a58 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sat, 3 Jul 2021 01:43:29 +0200 Subject: [PATCH 012/255] add ip to identifiers, changed value format --- include/Client.h | 12 +++++++++--- include/TNetwork.h | 6 ++++-- src/TLuaFile.cpp | 7 +++---- src/TNetwork.cpp | 38 +++++++++++++++++++++----------------- 4 files changed, 37 insertions(+), 26 deletions(-) diff --git a/include/Client.h b/include/Client.h index 385d2ec..8ac7035 100644 --- a/include/Client.h +++ b/include/Client.h @@ -12,6 +12,12 @@ class TServer; +struct TConnection final { + SOCKET Socket; + struct sockaddr SockAddr; + socklen_t SockAddrLen; +}; + class TClient final { public: using TSetOfVehicleData = std::vector; @@ -30,7 +36,7 @@ public: TVehicleDataLockPair GetAllCars(); void SetName(const std::string& Name) { mName = Name; } void SetRoles(const std::string& Role) { mRole = Role; } - void AddIdentifier(const std::string& ID) { mIdentifiers.insert(ID); }; + void SetIdentifier(const std::string& key, const std::string& value) { mIdentifiers[key] = value; } std::string GetCarData(int Ident); void SetUDPAddr(sockaddr_in Addr) { mUDPAddress = Addr; } void SetDownSock(SOCKET CSock) { mSocket[1] = CSock; } @@ -38,7 +44,7 @@ public: void SetStatus(int Status) { mStatus = Status; } // locks void DeleteCar(int Ident); - [[nodiscard]] std::set GetIdentifiers() const { return mIdentifiers; } + [[nodiscard]] const std::unordered_map& GetIdentifiers() const { return mIdentifiers; } [[nodiscard]] sockaddr_in GetUDPAddr() const { return mUDPAddress; } [[nodiscard]] SOCKET GetDownSock() const { return mSocket[1]; } [[nodiscard]] SOCKET GetTCPSock() const { return mSocket[0]; } @@ -78,7 +84,7 @@ private: bool mIsSyncing = false; mutable std::mutex mMissedPacketsMutex; std::queue mPacketsSync; - std::set mIdentifiers; + std::unordered_map mIdentifiers; bool mIsGuest = false; std::mutex mVehicleDataMutex; TSetOfVehicleData mVehicleData; diff --git a/include/TNetwork.h b/include/TNetwork.h index a4d28c5..528aef4 100644 --- a/include/TNetwork.h +++ b/include/TNetwork.h @@ -4,6 +4,8 @@ #include "TResourceManager.h" #include "TServer.h" +struct TConnection; + class TNetwork { public: TNetwork(TServer& Server, TPPSMonitor& PPSMonitor, TResourceManager& ResourceManager); @@ -15,8 +17,8 @@ public: std::string TCPRcv(TClient& c); void ClientKick(TClient& c, const std::string& R); [[nodiscard]] bool SyncClient(const std::weak_ptr& c); - void Identify(SOCKET TCPSock); - void Authentication(SOCKET TCPSock); + void Identify(const TConnection& client); + void Authentication(const TConnection& ClientConnection); [[nodiscard]] bool CheckBytes(TClient& c, int32_t BytesRcv); void SyncResources(TClient& c); [[nodiscard]] bool UDPSend(TClient& Client, std::string Data) const; diff --git a/src/TLuaFile.cpp b/src/TLuaFile.cpp index 17f4ffe..a9af4c2 100644 --- a/src/TLuaFile.cpp +++ b/src/TLuaFile.cpp @@ -354,12 +354,11 @@ int lua_GetIdentifiers(lua_State* L) { if (IDs.empty()) return 0; LuaTable::Begin(L); - for (const std::string& ID : IDs) { - LuaTable::BeginEntry(L, ID.substr(0, ID.find(':')).c_str()); - lua_pushstring(L, ID.c_str()); + for (const auto& Pair : IDs) { + LuaTable::BeginEntry(L, Pair.first); + lua_pushstring(L, Pair.second.c_str()); LuaTable::EndEntry(L); } - // LuaTable::End(L, ""); } else return 0; } else { diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index 279a236..a5d4624 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -163,7 +163,7 @@ void TNetwork::TCPServerMain() { #else // unix // wondering why we need slightly different implementations of this? // ask ms. - SOCKET client = -1; + TConnection client {}; SOCKET Listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); int optval = 1; setsockopt(Listener, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval)); @@ -193,8 +193,9 @@ void TNetwork::TCPServerMain() { debug("shutdown during TCP wait for accept loop"); break; } - client = accept(Listener, nullptr, nullptr); - if (client == -1) { + client.SockAddrLen = sizeof(client.SockAddr); + client.Socket = accept(Listener, &client.SockAddr, &client.SockAddrLen); + if (client.Socket == -1) { warn(("Got an invalid client socket on connect! Skipping...")); continue; } @@ -203,11 +204,11 @@ void TNetwork::TCPServerMain() { } catch (const std::exception& e) { error(("fatal: ") + std::string(e.what())); } - } while (client); + } while (client.Socket); debug("all ok, arrived at " + std::string(__func__) + ":" + std::to_string(__LINE__)); - CloseSocketProper(client); + CloseSocketProper(client.Socket); #endif } @@ -216,19 +217,19 @@ void TNetwork::TCPServerMain() { #include "Json.h" namespace json = rapidjson; -void TNetwork::Identify(SOCKET TCPSock) { +void TNetwork::Identify(const TConnection& client) { RegisterThreadAuto(); char Code; - if (recv(TCPSock, &Code, 1, 0) != 1) { - CloseSocketProper(TCPSock); + if (recv(client.Socket, &Code, 1, 0) != 1) { + CloseSocketProper(client.Socket); return; } if (Code == 'C') { - Authentication(TCPSock); + Authentication(client); } else if (Code == 'D') { - HandleDownload(TCPSock); + HandleDownload(client.Socket); } else { - CloseSocketProper(TCPSock); + CloseSocketProper(client.Socket); } } @@ -251,11 +252,12 @@ void TNetwork::HandleDownload(SOCKET TCPSock) { }); } -void TNetwork::Authentication(SOCKET TCPSock) { - auto Client = CreateClient(TCPSock); +void TNetwork::Authentication(const TConnection& ClientConnection) { + auto Client = CreateClient(ClientConnection.Socket); + Client->SetIdentifier("ip", inet_ntoa(reinterpret_cast(&ClientConnection.SockAddr)->sin_addr)); std::string Rc; - info("Identifying new client..."); + info("Identifying new ClientConnection..."); Rc = TCPRcv(*Client); @@ -304,7 +306,9 @@ void TNetwork::Authentication(SOCKET TCPSock) { Client->SetRoles(AuthResponse["roles"].GetString()); Client->SetIsGuest(AuthResponse["guest"].GetBool()); for (const auto& ID : AuthResponse["identifiers"].GetArray()) { - Client->AddIdentifier(ID.GetString()); + auto Raw = std::string(ID.GetString()); + auto SepIndex = Raw.find(':'); + Client->SetIdentifier(Raw.substr(0, SepIndex), Raw.substr(SepIndex + 1)); } } else { ClientKick(*Client, "Invalid authentication data!"); @@ -324,8 +328,8 @@ void TNetwork::Authentication(SOCKET TCPSock) { } info("Client Iteration: Name -> " + Cl->GetName() + ", Guest -> " + std::to_string(Cl->IsGuest()) + ", Roles -> " + Cl->GetRoles()); if (Cl->GetName() == Client->GetName() && Cl->IsGuest() == Client->IsGuest()) { - info("New client matched with current iteration"); - info("Old client (" + Cl->GetName() + ") kicked: Reconnecting"); + info("New ClientConnection matched with current iteration"); + info("Old ClientConnection (" + Cl->GetName() + ") kicked: Reconnecting"); CloseSocketProper(Cl->GetTCPSock()); Cl->SetStatus(-2); return false; From d18afdf84b070ed1d09e4ea1bb4cfc3b4cf634fe Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sun, 11 Jul 2021 20:34:18 +0200 Subject: [PATCH 013/255] Lua: add onShutdown --- src/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main.cpp b/src/main.cpp index b78446f..c56d1ce 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -48,6 +48,7 @@ int main(int argc, char** argv) { bool Shutdown = false; Application::RegisterShutdownHandler([&Shutdown] { Shutdown = true; }); + Application::RegisterShutdownHandler([] { TriggerLuaEvent("onShutdown", false, nullptr, {}, true); }); TServer Server(argc, argv); TConfig Config; From 9595ef164e2e37f10f4c50254cc4d7f9bc16b38a Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sun, 11 Jul 2021 20:41:23 +0200 Subject: [PATCH 014/255] use fake version for lua update for now --- include/Common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/Common.h b/include/Common.h index 76d5012..5feccc0 100644 --- a/include/Common.h +++ b/include/Common.h @@ -51,6 +51,7 @@ public: static void GracefullyShutdown(); static TConsole& Console() { return *mConsole; } static std::string ServerVersion() { return "2.2.0"; } +#warning "change version from 2.2.0 to real version" static std::string ClientVersion() { return "2.0"; } static std::string PPS() { return mPPS; } static void SetPPS(std::string NewPPS) { mPPS = NewPPS; } @@ -120,4 +121,3 @@ void RegisterThread(const std::string str); #define Biggest 30000 std::string Comp(std::string Data); std::string DeComp(std::string Compressed); - From e11211f20145c0cf7ea06d88b8fe550fc0474b90 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 15 Jul 2021 00:04:44 +0200 Subject: [PATCH 015/255] add GetServerVersion --- include/Common.h | 17 ++++++++++++++--- src/Common.cpp | 15 +++++++++++++++ src/THeartbeatThread.cpp | 4 ++-- src/TLuaFile.cpp | 9 +++++++++ src/TNetwork.cpp | 2 +- src/TServer.cpp | 2 +- 6 files changed, 42 insertions(+), 7 deletions(-) diff --git a/include/Common.h b/include/Common.h index 5feccc0..40ccb99 100644 --- a/include/Common.h +++ b/include/Common.h @@ -8,6 +8,14 @@ #include "TConsole.h" +struct Version { + uint8_t major; + uint8_t minor; + uint8_t patch; + Version(uint8_t major, uint8_t minor, uint8_t patch); + std::string AsString(); +}; + // static class handling application start, shutdown, etc. // yes, static classes, singletons, globals are all pretty // bad idioms. In this case we need a central way to access @@ -40,6 +48,7 @@ public: std::string CustomIP; [[nodiscard]] bool HasCustomIP() const { return !CustomIP.empty(); } }; + using TShutdownHandler = std::function; // methods @@ -50,9 +59,9 @@ public: // Causes all threads to finish up and exit gracefull gracefully static void GracefullyShutdown(); static TConsole& Console() { return *mConsole; } - static std::string ServerVersion() { return "2.2.0"; } -#warning "change version from 2.2.0 to real version" - static std::string ClientVersion() { return "2.0"; } + static std::string ServerVersionString(); + static const Version& ServerVersion() { return mVersion; } + static std::string ClientVersionString() { return "2.0"; } static std::string PPS() { return mPPS; } static void SetPPS(std::string NewPPS) { mPPS = NewPPS; } @@ -67,6 +76,8 @@ private: static std::unique_ptr mConsole; static inline std::mutex mShutdownHandlersMutex {}; static inline std::deque mShutdownHandlers {}; + + static inline Version mVersion { 2, 2, 0 }; }; std::string ThreadName(); diff --git a/src/Common.cpp b/src/Common.cpp index 32b5905..0b7e336 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -24,6 +24,10 @@ void Application::GracefullyShutdown() { } } +std::string Application::ServerVersionString() { + return mVersion.AsString(); +} + std::string Comp(std::string Data) { std::array C {}; // obsolete @@ -86,3 +90,14 @@ std::string ThreadName() { void RegisterThread(const std::string str) { threadNameMap[std::this_thread::get_id()] = str; } + +Version::Version(uint8_t major, uint8_t minor, uint8_t patch) + : major(major) + , minor(minor) + , patch(patch) { } + +std::string Version::AsString() { + std::stringstream ss {}; + ss << major << "." << minor << "." << patch; + return ss.str(); +} diff --git a/src/THeartbeatThread.cpp b/src/THeartbeatThread.cpp index bacb235..607fd94 100644 --- a/src/THeartbeatThread.cpp +++ b/src/THeartbeatThread.cpp @@ -71,8 +71,8 @@ std::string THeartbeatThread::GenerateCall() { << "&port=" << Application::Settings.Port << "&map=" << Application::Settings.MapName << "&private=" << (Application::Settings.Private ? "true" : "false") - << "&version=" << Application::ServerVersion() - << "&clientversion=" << Application::ClientVersion() + << "&version=" << Application::ServerVersionString() + << "&clientversion=" << Application::ClientVersionString() << "&name=" << Application::Settings.ServerName << "&modlist=" << mResourceManager.TrimmedList() << "&modstotalsize=" << mResourceManager.MaxModSize() diff --git a/src/TLuaFile.cpp b/src/TLuaFile.cpp index a9af4c2..bfbfc09 100644 --- a/src/TLuaFile.cpp +++ b/src/TLuaFile.cpp @@ -782,6 +782,14 @@ int lua_GetOSName(lua_State* L) { return 1; } +int lua_GetServerVersion(lua_State* L) { + const auto& ver = Application::ServerVersion(); + lua_pushinteger(L, ver.major); + lua_pushinteger(L, ver.minor); + lua_pushinteger(L, ver.patch); + return 3; +} + // status, body = HttpsGET(host, port, target) // example usage: // send a GET https://example.com:443/index.html: @@ -911,6 +919,7 @@ void TLuaFile::Load() { LuaTable::InsertFunction(mLuaState, "GetOSName", lua_GetOSName); LuaTable::InsertFunction(mLuaState, "HttpsGET", lua_HttpsGET); LuaTable::InsertFunction(mLuaState, "HttpsPOST", lua_HttpsPOST); + LuaTable::InsertFunction(mLuaState, "GetServerVersion", lua_GetServerVersion); LuaTable::End(mLuaState, "MP"); lua_register(mLuaState, "print", lua_Print); diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index a5d4624..d24cf6e 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -263,7 +263,7 @@ void TNetwork::Authentication(const TConnection& ClientConnection) { if (Rc.size() > 3 && Rc.substr(0, 2) == "VC") { Rc = Rc.substr(2); - if (Rc.length() > 4 || Rc != Application::ClientVersion()) { + if (Rc.length() > 4 || Rc != Application::ClientVersionString()) { ClientKick(*Client, "Outdated Version!"); return; } diff --git a/src/TServer.cpp b/src/TServer.cpp index 7be220e..5492b66 100644 --- a/src/TServer.cpp +++ b/src/TServer.cpp @@ -14,7 +14,7 @@ namespace json = rapidjson; TServer::TServer(int argc, char** argv) { - info("BeamMP Server v" + Application::ServerVersion()); + info("BeamMP Server v" + Application::ServerVersionString()); if (argc > 1) { Application::Settings.CustomIP = argv[1]; size_t n = std::count(Application::Settings.CustomIP.begin(), Application::Settings.CustomIP.end(), '.'); From 8420cdb5bf32b0722f9e1f33a268c764b50ebbe1 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 15 Jul 2021 01:49:30 +0200 Subject: [PATCH 016/255] Add Settings enum, better print --- include/THeartbeatThread.h | 2 +- src/TLuaFile.cpp | 35 +++++++++++++++++++++++++++-------- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/include/THeartbeatThread.h b/include/THeartbeatThread.h index 1442e08..1f0ab14 100644 --- a/include/THeartbeatThread.h +++ b/include/THeartbeatThread.h @@ -18,4 +18,4 @@ private: bool mShutdown = false; TResourceManager& mResourceManager; TServer& mServer; -}; \ No newline at end of file +}; diff --git a/src/TLuaFile.cpp b/src/TLuaFile.cpp index bfbfc09..5319eb8 100644 --- a/src/TLuaFile.cpp +++ b/src/TLuaFile.cpp @@ -33,6 +33,12 @@ void InsertFunction(lua_State* L, const std::string& name, lua_CFunction func) { EndEntry(L); } +void InsertInteger(lua_State* L, const std::string& name, lua_Integer i) { + BeginEntry(L, name); + lua_pushinteger(L, i); + EndEntry(L); +} + } void SendError(TLuaEngine& Engine, lua_State* L, const std::string& msg); @@ -533,49 +539,49 @@ int lua_Set(lua_State* L) { case 0: //debug if (lua_isboolean(L, 2)) { Application::Settings.DebugModeEnabled = lua_toboolean(L, 2); - info(Name + (" | Debug -> ") + (Application::Settings.DebugModeEnabled ? "true" : "false")); + info(Name + (" | Set `Debug` to ") + (Application::Settings.DebugModeEnabled ? "true" : "false")); } else SendError(Engine(), L, ("set invalid argument [2] expected boolean for ID : 0")); break; case 1: //private if (lua_isboolean(L, 2)) { Application::Settings.Private = lua_toboolean(L, 2); - info(Name + (" | Private -> ") + (Application::Settings.Private ? "true" : "false")); + info(Name + (" | Set `Private` to ") + (Application::Settings.Private ? "true" : "false")); } else SendError(Engine(), L, ("set invalid argument [2] expected boolean for ID : 1")); break; case 2: //max cars if (lua_isnumber(L, 2)) { Application::Settings.MaxCars = int(lua_tointeger(L, 2)); - info(Name + (" | MaxCars -> ") + std::to_string(Application::Settings.MaxCars)); + info(Name + (" | Set `MaxCars` to ") + std::to_string(Application::Settings.MaxCars)); } else SendError(Engine(), L, ("set invalid argument [2] expected number for ID : 2")); break; case 3: //max players if (lua_isnumber(L, 2)) { Application::Settings.MaxPlayers = int(lua_tointeger(L, 2)); - info(Name + (" | MaxPlayers -> ") + std::to_string(Application::Settings.MaxPlayers)); + info(Name + (" | Set `MaxPlayers` to ") + std::to_string(Application::Settings.MaxPlayers)); } else SendError(Engine(), L, ("set invalid argument [2] expected number for ID : 3")); break; case 4: //Map if (lua_isstring(L, 2)) { Application::Settings.MapName = lua_tostring(L, 2); - info(Name + (" | MapName -> ") + Application::Settings.MapName); + info(Name + (" | Set `Map` to ") + Application::Settings.MapName); } else SendError(Engine(), L, ("set invalid argument [2] expected string for ID : 4")); break; case 5: //Name if (lua_isstring(L, 2)) { Application::Settings.ServerName = lua_tostring(L, 2); - info(Name + (" | ServerName -> ") + Application::Settings.ServerName); + info(Name + (" | Set `Name` to ") + Application::Settings.ServerName); } else SendError(Engine(), L, ("set invalid argument [2] expected string for ID : 5")); break; case 6: //Desc if (lua_isstring(L, 2)) { Application::Settings.ServerDesc = lua_tostring(L, 2); - info(Name + (" | ServerDesc -> ") + Application::Settings.ServerDesc); + info(Name + (" | Set `Description` to ") + Application::Settings.ServerDesc); } else SendError(Engine(), L, ("set invalid argument [2] expected string for ID : 6")); break; @@ -583,7 +589,6 @@ int lua_Set(lua_State* L) { warn(("Invalid config ID : ") + std::to_string(C)); break; } - return 0; } @@ -895,6 +900,19 @@ void TLuaFile::Load() { luaL_openlibs(mLuaState); LuaTable::Begin(mLuaState); + + LuaTable::BeginEntry(mLuaState, "Settings"); + LuaTable::Begin(mLuaState); + // put Settings enums here + LuaTable::InsertInteger(mLuaState, "Debug", 0); + LuaTable::InsertInteger(mLuaState, "Private", 1); + LuaTable::InsertInteger(mLuaState, "MaxCars", 2); + LuaTable::InsertInteger(mLuaState, "MaxPlayers", 3); + LuaTable::InsertInteger(mLuaState, "Map", 4); + LuaTable::InsertInteger(mLuaState, "Name", 5); + LuaTable::InsertInteger(mLuaState, "Description", 6); + LuaTable::EndEntry(mLuaState); + LuaTable::InsertFunction(mLuaState, "GetPlayerIdentifiers", lua_GetIdentifiers); LuaTable::InsertFunction(mLuaState, "TriggerGlobalEvent", lua_TriggerEventG); LuaTable::InsertFunction(mLuaState, "TriggerLocalEvent", lua_TriggerEventL); @@ -920,6 +938,7 @@ void TLuaFile::Load() { LuaTable::InsertFunction(mLuaState, "HttpsGET", lua_HttpsGET); LuaTable::InsertFunction(mLuaState, "HttpsPOST", lua_HttpsPOST); LuaTable::InsertFunction(mLuaState, "GetServerVersion", lua_GetServerVersion); + LuaTable::End(mLuaState, "MP"); lua_register(mLuaState, "print", lua_Print); From b071906db5b8e30d260617ca4d6ba38890443a42 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 15 Jul 2021 02:23:53 +0200 Subject: [PATCH 017/255] clarify installation --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 4e1218c..cf90c3e 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,12 @@ These package names are in the debian / ubuntu style. Feel free to PR your own g **If** you're building it from source, you'll need `libboost1.70-all-dev` or `libboost1.71-all-dev` or higher as well. +In the end you should end up with a command something like this: + +```sh +sudo apt install git make cmake g++-10 liblua5.3 libz-dev rapidjson-dev libopenssl-dev libboost1.71-all-dev +``` + ### How to build On windows. use git-bash for these commands. On linux, these should work in your shell. From d39b5d7c7724e58ae5fbc31375a8fe43a3533a40 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 15 Jul 2021 16:34:44 +0200 Subject: [PATCH 018/255] use inet_ntop instead of inet_ntoa (STILL BROKEN THOUGH) --- src/TNetwork.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index d24cf6e..39a816d 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -254,7 +254,10 @@ void TNetwork::HandleDownload(SOCKET TCPSock) { void TNetwork::Authentication(const TConnection& ClientConnection) { auto Client = CreateClient(ClientConnection.Socket); - Client->SetIdentifier("ip", inet_ntoa(reinterpret_cast(&ClientConnection.SockAddr)->sin_addr)); + char AddrBuf[30]; + inet_ntoa(reinterpret_cast(&ClientConnection.SockAddr)->sin_addr); + auto str = inet_ntop(AF_INET, static_cast(reinterpret_cast(&ClientConnection.SockAddr)), AddrBuf, sizeof(struct sockaddr_in)); + Client->SetIdentifier("ip", str); std::string Rc; info("Identifying new ClientConnection..."); From 9d4c6e880b7d7c61ee2c17dd35b55c9a73f7af57 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Wed, 21 Jul 2021 01:59:36 +0200 Subject: [PATCH 019/255] fix version printing --- src/Common.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Common.cpp b/src/Common.cpp index 0b7e336..41d35d3 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -98,6 +98,6 @@ Version::Version(uint8_t major, uint8_t minor, uint8_t patch) std::string Version::AsString() { std::stringstream ss {}; - ss << major << "." << minor << "." << patch; + ss << int(major) << "." << int(minor) << "." << int(patch); return ss.str(); } From ed3d0834e6e96af782e0d3e5611ae964f5147ce1 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 29 Jul 2021 12:02:49 +0200 Subject: [PATCH 020/255] add ws2tcpip.h --- include/Compat.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/Compat.h b/include/Compat.h index 18d2b90..60ff13a 100644 --- a/include/Compat.h +++ b/include/Compat.h @@ -23,6 +23,7 @@ inline void CloseSocketProper(int socket) { #ifdef WIN32 #include #include +#include inline void CloseSocketProper(SOCKET socket) { shutdown(socket, SD_BOTH); closesocket(socket); From c46c36bf095713dc79631d9fb71af795eb981953 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 29 Jul 2021 12:04:11 +0200 Subject: [PATCH 021/255] add luasocket submodule --- .gitmodules | 3 +++ lib/luasocket | 1 + 2 files changed, 4 insertions(+) create mode 160000 lib/luasocket diff --git a/.gitmodules b/.gitmodules index 0d23bc7..08ba65a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,3 +13,6 @@ [submodule "include/toml11"] path = include/toml11 url = https://github.com/ToruNiina/toml11 +[submodule "lib/luasocket"] + path = lib/luasocket + url = https://github.com/diegonehab/luasocket diff --git a/lib/luasocket b/lib/luasocket new file mode 160000 index 0000000..5b18e47 --- /dev/null +++ b/lib/luasocket @@ -0,0 +1 @@ +Subproject commit 5b18e475f38fcf28429b1cc4b17baee3b9793a62 From dae52a71fdf90188d6ad70bf79a58d3e94880d70 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 29 Jul 2021 12:04:38 +0200 Subject: [PATCH 022/255] add CMakeLists for lib/ --- lib/CMakeLists.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 lib/CMakeLists.txt diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt new file mode 100644 index 0000000..e69de29 From 0faa46d48cd889a9a91d57b1b857de349fb4cd71 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 29 Jul 2021 12:11:43 +0200 Subject: [PATCH 023/255] remove luasocket again --- .gitmodules | 3 --- CMakeLists.txt | 7 ++++--- lib/CMakeLists.txt | 5 +++++ lib/luasocket | 1 - 4 files changed, 9 insertions(+), 7 deletions(-) delete mode 160000 lib/luasocket diff --git a/.gitmodules b/.gitmodules index 08ba65a..0d23bc7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,6 +13,3 @@ [submodule "include/toml11"] path = include/toml11 url = https://github.com/ToruNiina/toml11 -[submodule "lib/luasocket"] - path = lib/luasocket - url = https://github.com/diegonehab/luasocket diff --git a/CMakeLists.txt b/CMakeLists.txt index 2a5a9f2..9c437fb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,8 @@ include_directories("rapidjson/include") include_directories("websocketpp") add_subdirectory("socket.io-client-cpp") add_subdirectory("include/commandline") +# builds all libraries that don't have cmakelists +add_subdirectory("lib") set(CMAKE_CXX_STANDARD 17) @@ -46,7 +48,6 @@ add_executable(BeamMP-Server include/TResourceManager.h src/TResourceManager.cpp include/THeartbeatThread.h src/THeartbeatThread.cpp include/Http.h src/Http.cpp - #include/SocketIO.h src/SocketIO.cpp include/TPPSMonitor.h src/TPPSMonitor.cpp include/TNetwork.h src/TNetwork.cpp) @@ -58,11 +59,11 @@ target_include_directories(BeamMP-Server PUBLIC ${Boost_INCLUDE_DIRS} ${LUA_INCL find_package(OpenSSL REQUIRED) if (UNIX) - target_link_libraries(BeamMP-Server z pthread stdc++fs ${LUA_LIBRARIES} crypto ${OPENSSL_LIBRARIES} commandline sioclient_tls) + target_link_libraries(BeamMP-Server z pthread stdc++fs ${LUA_LIBRARIES} crypto ${OPENSSL_LIBRARIES} commandline sioclient_tls luasocket) elseif (WIN32) include(FindLua) find_package(ZLIB REQUIRED) find_package(RapidJSON CONFIG REQUIRED) target_include_directories(BeamMP-Server PRIVATE ${RAPIDJSON_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}) - target_link_libraries(BeamMP-Server PRIVATE ws2_32 ZLIB::ZLIB ${LUA_LIBRARIES} ${OPENSSL_LIBRARIES} commandline sioclient_tls) + target_link_libraries(BeamMP-Server PRIVATE ws2_32 ZLIB::ZLIB ${LUA_LIBRARIES} ${OPENSSL_LIBRARIES} commandline sioclient_tls luasocket) endif () diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index e69de29..ab2d18a 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -0,0 +1,5 @@ + + +############# luasocket ############# + +##################################### \ No newline at end of file diff --git a/lib/luasocket b/lib/luasocket deleted file mode 160000 index 5b18e47..0000000 --- a/lib/luasocket +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 5b18e475f38fcf28429b1cc4b17baee3b9793a62 From 2a3bb1bef8af536763c102bbfce55d17503d058c Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 29 Jul 2021 12:18:01 +0200 Subject: [PATCH 024/255] add luasocket --- .gitmodules | 3 +++ CMakeLists.txt | 9 +++++---- lib/CMakeLists.txt | 5 ----- lib/luasocket-cmake | 1 + 4 files changed, 9 insertions(+), 9 deletions(-) delete mode 100644 lib/CMakeLists.txt create mode 160000 lib/luasocket-cmake diff --git a/.gitmodules b/.gitmodules index 0d23bc7..d4058b3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,3 +13,6 @@ [submodule "include/toml11"] path = include/toml11 url = https://github.com/ToruNiina/toml11 +[submodule "lib/luasocket-cmake"] + path = lib/luasocket-cmake + url = https://github.com/trevex/luasocket diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c437fb..13da1e5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,8 +25,9 @@ include_directories("rapidjson/include") include_directories("websocketpp") add_subdirectory("socket.io-client-cpp") add_subdirectory("include/commandline") -# builds all libraries that don't have cmakelists -add_subdirectory("lib") +# luasocket +set(WANTS_BUILD_STATIC_LIBRARY ON) +add_subdirectory("lib/luasocket-cmake") set(CMAKE_CXX_STANDARD 17) @@ -59,11 +60,11 @@ target_include_directories(BeamMP-Server PUBLIC ${Boost_INCLUDE_DIRS} ${LUA_INCL find_package(OpenSSL REQUIRED) if (UNIX) - target_link_libraries(BeamMP-Server z pthread stdc++fs ${LUA_LIBRARIES} crypto ${OPENSSL_LIBRARIES} commandline sioclient_tls luasocket) + target_link_libraries(BeamMP-Server z pthread stdc++fs ${LUA_LIBRARIES} crypto ${OPENSSL_LIBRARIES} commandline sioclient_tls luasocket_library_static) elseif (WIN32) include(FindLua) find_package(ZLIB REQUIRED) find_package(RapidJSON CONFIG REQUIRED) target_include_directories(BeamMP-Server PRIVATE ${RAPIDJSON_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}) - target_link_libraries(BeamMP-Server PRIVATE ws2_32 ZLIB::ZLIB ${LUA_LIBRARIES} ${OPENSSL_LIBRARIES} commandline sioclient_tls luasocket) + target_link_libraries(BeamMP-Server PRIVATE ws2_32 ZLIB::ZLIB ${LUA_LIBRARIES} ${OPENSSL_LIBRARIES} commandline sioclient_tls luasocket_library_static) endif () diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt deleted file mode 100644 index ab2d18a..0000000 --- a/lib/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ - - -############# luasocket ############# - -##################################### \ No newline at end of file diff --git a/lib/luasocket-cmake b/lib/luasocket-cmake new file mode 160000 index 0000000..2cb3208 --- /dev/null +++ b/lib/luasocket-cmake @@ -0,0 +1 @@ +Subproject commit 2cb3208cf32d8349c04af2884e50db008ff27ef8 From 206120dcefe97df23199a4cc3e12ee527596c809 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 29 Jul 2021 12:21:29 +0200 Subject: [PATCH 025/255] CMake: include luasocket after finding lua --- CMakeLists.txt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 13da1e5..6f66237 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,9 +25,7 @@ include_directories("rapidjson/include") include_directories("websocketpp") add_subdirectory("socket.io-client-cpp") add_subdirectory("include/commandline") -# luasocket -set(WANTS_BUILD_STATIC_LIBRARY ON) -add_subdirectory("lib/luasocket-cmake") + set(CMAKE_CXX_STANDARD 17) @@ -55,6 +53,11 @@ add_executable(BeamMP-Server target_include_directories(BeamMP-Server PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_SOURCE_DIR}/commandline") find_package(Lua REQUIRED) + +# luasocket +set(WANTS_BUILD_STATIC_LIBRARY ON) +add_subdirectory("lib/luasocket-cmake") + target_include_directories(BeamMP-Server PUBLIC ${Boost_INCLUDE_DIRS} ${LUA_INCLUDE_DIR} "socket.io-client-cpp/src") find_package(OpenSSL REQUIRED) From cfe348770c7e62313f4d534cf9098ba88e8174df Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 2 Aug 2021 13:28:41 +0200 Subject: [PATCH 026/255] Common: Add sstream include for std::stringstream --- include/Common.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/Common.h b/include/Common.h index 40ccb99..1c156b9 100644 --- a/include/Common.h +++ b/include/Common.h @@ -5,6 +5,7 @@ #include #include #include +#include #include "TConsole.h" From 5d5f155f0c011dfc809e116e56bbd8f3b8668b83 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 2 Aug 2021 13:31:49 +0200 Subject: [PATCH 027/255] remove luasocket-cmake --- .gitmodules | 3 --- lib/luasocket-cmake | 1 - 2 files changed, 4 deletions(-) delete mode 160000 lib/luasocket-cmake diff --git a/.gitmodules b/.gitmodules index d4058b3..0d23bc7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,6 +13,3 @@ [submodule "include/toml11"] path = include/toml11 url = https://github.com/ToruNiina/toml11 -[submodule "lib/luasocket-cmake"] - path = lib/luasocket-cmake - url = https://github.com/trevex/luasocket diff --git a/lib/luasocket-cmake b/lib/luasocket-cmake deleted file mode 160000 index 2cb3208..0000000 --- a/lib/luasocket-cmake +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 2cb3208cf32d8349c04af2884e50db008ff27ef8 From 9666fff6225735fe32cc7f0ecd518d9bc325e262 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 2 Aug 2021 13:32:14 +0200 Subject: [PATCH 028/255] CMake: remove mentions of luasocket again --- CMakeLists.txt | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6f66237..cd35ed1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,20 +54,16 @@ target_include_directories(BeamMP-Server PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/inc find_package(Lua REQUIRED) -# luasocket -set(WANTS_BUILD_STATIC_LIBRARY ON) -add_subdirectory("lib/luasocket-cmake") - target_include_directories(BeamMP-Server PUBLIC ${Boost_INCLUDE_DIRS} ${LUA_INCLUDE_DIR} "socket.io-client-cpp/src") find_package(OpenSSL REQUIRED) if (UNIX) - target_link_libraries(BeamMP-Server z pthread stdc++fs ${LUA_LIBRARIES} crypto ${OPENSSL_LIBRARIES} commandline sioclient_tls luasocket_library_static) + target_link_libraries(BeamMP-Server z pthread stdc++fs ${LUA_LIBRARIES} crypto ${OPENSSL_LIBRARIES} commandline sioclient_tls) elseif (WIN32) include(FindLua) find_package(ZLIB REQUIRED) find_package(RapidJSON CONFIG REQUIRED) target_include_directories(BeamMP-Server PRIVATE ${RAPIDJSON_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}) - target_link_libraries(BeamMP-Server PRIVATE ws2_32 ZLIB::ZLIB ${LUA_LIBRARIES} ${OPENSSL_LIBRARIES} commandline sioclient_tls luasocket_library_static) + target_link_libraries(BeamMP-Server PRIVATE ws2_32 ZLIB::ZLIB ${LUA_LIBRARIES} ${OPENSSL_LIBRARIES} commandline sioclient_tls) endif () From 1fb7cb6bc1731303fccbe8b3350a8936e28b3e85 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 2 Aug 2021 13:54:36 +0200 Subject: [PATCH 029/255] improve error reporting, remove duplicate code --- include/Common.h | 5 +++ include/Compat.h | 1 + src/Common.cpp | 27 ++++++++++++ src/TNetwork.cpp | 105 ++++++++--------------------------------------- 4 files changed, 49 insertions(+), 89 deletions(-) diff --git a/include/Common.h b/include/Common.h index 1c156b9..3b572c5 100644 --- a/include/Common.h +++ b/include/Common.h @@ -1,12 +1,15 @@ #pragma once #include +#include #include #include #include #include #include +#include "Compat.h" + #include "TConsole.h" struct Version { @@ -133,3 +136,5 @@ void RegisterThread(const std::string str); #define Biggest 30000 std::string Comp(std::string Data); std::string DeComp(std::string Compressed); + +std::string GetPlatformAgnosticErrorString(); diff --git a/include/Compat.h b/include/Compat.h index 60ff13a..c7b5e21 100644 --- a/include/Compat.h +++ b/include/Compat.h @@ -7,6 +7,7 @@ #include #include #include +#include using SOCKET = int; using DWORD = unsigned long; using PDWORD = unsigned long*; diff --git a/src/Common.cpp b/src/Common.cpp index 41d35d3..20477b7 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -101,3 +101,30 @@ std::string Version::AsString() { ss << int(major) << "." << int(minor) << "." << int(patch); return ss.str(); } + +std::string GetPlatformAgnosticErrorString() { +#ifdef WIN32 + // This will provide us with the error code and an error message, all in one. + int err; + char msgbuf[256]; + msgbuf[0] = '\0'; + + err = GetLastError(); + + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, + err, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + msgbuf, + sizeof(msgbuf), + nullptr); + + if (*msgbuf) { + return std::to_string(GetLastError()) + " - " + std::string(msgbuf); + } else { + return std::to_string(GetLastError()) + } +#else // posix + return std::strerror(errno); +#endif +} diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index 39a816d..04d965c 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -46,22 +46,7 @@ void TNetwork::UDPServerMain() { error(("Can't start Winsock!")); //return; } - - mUDPSock = socket(AF_INET, SOCK_DGRAM, 0); - // Create a server hint structure for the server - sockaddr_in serverAddr {}; - serverAddr.sin_addr.S_un.S_addr = ADDR_ANY; //Any Local - serverAddr.sin_family = AF_INET; // Address format is IPv4 - serverAddr.sin_port = htons(Application::Settings.Port); // Convert from little to big endian - - // Try and bind the socket to the IP and port - if (bind(mUDPSock, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) { - error(("Can't bind socket!") + std::to_string(WSAGetLastError())); - std::this_thread::sleep_for(std::chrono::seconds(5)); - exit(-1); - //return; - } -#else // unix +#endif // WIN32 mUDPSock = socket(AF_INET, SOCK_DGRAM, 0); // Create a server hint structure for the server sockaddr_in serverAddr {}; @@ -71,12 +56,12 @@ void TNetwork::UDPServerMain() { // Try and bind the socket to the IP and port if (bind(mUDPSock, (sockaddr*)&serverAddr, sizeof(serverAddr)) != 0) { - error(("Can't bind socket!") + std::string(strerror(errno))); + error("bind() failed: " + GetPlatformAgnosticErrorString()); std::this_thread::sleep_for(std::chrono::seconds(5)); exit(-1); //return; } -#endif + info(("Vehicle data network online on port ") + std::to_string(Application::Settings.Port) + (" with a Max of ") + std::to_string(Application::Settings.MaxPlayers) + (" Clients")); @@ -123,46 +108,7 @@ void TNetwork::TCPServerMain() { error("Can't start Winsock!"); return; } - SOCKET client, Listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - sockaddr_in addr {}; - addr.sin_addr.S_un.S_addr = ADDR_ANY; - addr.sin_family = AF_INET; - addr.sin_port = htons(Application::Settings.Port); - if (bind(Listener, (sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) { - error("Can't bind socket! " + std::to_string(WSAGetLastError())); - std::this_thread::sleep_for(std::chrono::seconds(5)); - exit(-1); - } - if (Listener == -1) { - error("Invalid listening socket"); - return; - } - - if (listen(Listener, SOMAXCONN)) { - error("listener failed " + std::to_string(GetLastError())); - //TODO Fix me leak for Listener socket - return; - } - info("Vehicle event network online"); - do { - try { - client = accept(Listener, nullptr, nullptr); - if (client == -1) { - warn("Got an invalid client socket on connect! Skipping..."); - continue; - } - std::thread ID(&TNetwork::Identify, this, client); - ID.detach(); - } catch (const std::exception& e) { - error("fatal: " + std::string(e.what())); - } - } while (client); - - CloseSocketProper(client); - WSACleanup(); -#else // unix - // wondering why we need slightly different implementations of this? - // ask ms. +#endif // WIN32 TConnection client {}; SOCKET Listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); int optval = 1; @@ -173,7 +119,7 @@ void TNetwork::TCPServerMain() { addr.sin_family = AF_INET; addr.sin_port = htons(uint16_t(Application::Settings.Port)); if (bind(Listener, (sockaddr*)&addr, sizeof(addr)) != 0) { - error(("Can't bind socket! ") + std::string(strerror(errno))); + error(("Can't bind socket! ") + GetPlatformAgnosticErrorString()); std::this_thread::sleep_for(std::chrono::seconds(5)); exit(-1); } @@ -182,7 +128,7 @@ void TNetwork::TCPServerMain() { return; } if (listen(Listener, SOMAXCONN)) { - error(("listener failed ") + std::string(strerror(errno))); + error(("listener failed ") + GetPlatformAgnosticErrorString()); //TODO fix me leak Listener return; } @@ -209,7 +155,10 @@ void TNetwork::TCPServerMain() { debug("all ok, arrived at " + std::string(__func__) + ":" + std::to_string(__LINE__)); CloseSocketProper(client.Socket); -#endif +#ifdef WIN32 + CloseSocketProper(client); + WSACleanup(); +#endif // WIN32 } #undef GetObject //Fixes Windows @@ -391,12 +340,12 @@ bool TNetwork::TCPSend(TClient& c, const std::string& Data, bool IsSync) { int32_t Temp = send(c.GetTCPSock(), &Send[Sent], Size - Sent, MSG_NOSIGNAL); #endif //WIN32 if (Temp == 0) { - debug("send() == 0: " + std::string(std::strerror(errno))); + debug("send() == 0: " + GetPlatformAgnosticErrorString()); if (c.GetStatus() > -1) c.SetStatus(-1); return false; } else if (Temp < 0) { - debug("send() < 0: " + std::string(std::strerror(errno))); //TODO fix it was spamming yet everyone stayed on the server + debug("send() < 0: " + GetPlatformAgnosticErrorString()); //TODO fix it was spamming yet everyone stayed on the server if (c.GetStatus() > -1) c.SetStatus(-1); CloseSocketProper(c.GetTCPSock()); @@ -415,11 +364,7 @@ bool TNetwork::CheckBytes(TClient& c, int32_t BytesRcv) { c.SetStatus(-1); return false; } else if (BytesRcv < 0) { -#ifdef WIN32 - debug(("(TCP) recv failed with error: ") + std::to_string(WSAGetLastError())); -#else // unix - debug(("(TCP) recv failed with error: ") + std::string(strerror(errno))); -#endif // WIN32 + debug("(TCP) recv() failed: " + GetPlatformAgnosticErrorString()); if (c.GetStatus() > -1) c.SetStatus(-1); info(("Closing socket in CheckBytes, BytesRcv < 0")); @@ -962,31 +907,17 @@ bool TNetwork::UDPSend(TClient& Client, std::string Data) const { #endif // WIN32 sendOk = sendto(mUDPSock, Data.c_str(), len, 0, (sockaddr*)&Addr, int(AddrSize)); -#ifdef WIN32 if (sendOk == -1) { - debug(("(UDP) Send Failed Code : ") + std::to_string(WSAGetLastError())); + debug("(UDP) sendto() failed: " + GetPlatformAgnosticErrorString()); if (Client.GetStatus() > -1) Client.SetStatus(-1); return false; } else if (sendOk == 0) { - debug(("(UDP) sendto returned 0")); + debug(("(UDP) sendto() returned 0")); if (Client.GetStatus() > -1) Client.SetStatus(-1); return false; } -#else // unix - if (sendOk == -1) { - debug(("(UDP) Send Failed Code : ") + std::string(strerror(errno))); - if (Client.GetStatus() > -1) - Client.SetStatus(-1); - return false; - } else if (sendOk == 0) { - debug(("(UDP) sendto returned 0")); - if (Client.GetStatus() > -1) - Client.SetStatus(-1); - return false; - } -#endif // WIN32 return true; } @@ -1000,11 +931,7 @@ std::string TNetwork::UDPRcvFromClient(sockaddr_in& client) const { #endif // WIN32 if (Rcv == -1) { -#ifdef WIN32 - error(("(UDP) Error receiving from Client! Code : ") + std::to_string(WSAGetLastError())); -#else // unix - error(("(UDP) Error receiving from Client! Code : ") + std::string(strerror(errno))); -#endif // WIN32 + error("(UDP) Error receiving from client! recvfrom() failed: " + GetPlatformAgnosticErrorString()); return ""; } return std::string(Ret.begin(), Ret.begin() + Rcv); From 106d8e58637fb264f465295796e519a8b2531287 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 2 Aug 2021 14:06:00 +0200 Subject: [PATCH 030/255] Common: missed semicolon --- include/Common.h | 2 +- src/Common.cpp | 2 +- src/TNetwork.cpp | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/include/Common.h b/include/Common.h index 3b572c5..e991c5f 100644 --- a/include/Common.h +++ b/include/Common.h @@ -81,7 +81,7 @@ private: static inline std::mutex mShutdownHandlersMutex {}; static inline std::deque mShutdownHandlers {}; - static inline Version mVersion { 2, 2, 0 }; + static inline Version mVersion { 2, 3, 0 }; }; std::string ThreadName(); diff --git a/src/Common.cpp b/src/Common.cpp index 20477b7..1cfcdb6 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -122,7 +122,7 @@ std::string GetPlatformAgnosticErrorString() { if (*msgbuf) { return std::to_string(GetLastError()) + " - " + std::string(msgbuf); } else { - return std::to_string(GetLastError()) + return std::to_string(GetLastError()); } #else // posix return std::strerror(errno); diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index 04d965c..d803da5 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -62,7 +62,6 @@ void TNetwork::UDPServerMain() { //return; } - info(("Vehicle data network online on port ") + std::to_string(Application::Settings.Port) + (" with a Max of ") + std::to_string(Application::Settings.MaxPlayers) + (" Clients")); while (!mShutdown) { From 2c2f76b3402adccb3c9171ac70935976ab18eb8f Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 2 Aug 2021 14:15:30 +0200 Subject: [PATCH 031/255] TNetwork: reuseaddr instead of reuseport --- src/TNetwork.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index d803da5..d0784ee 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -111,7 +111,7 @@ void TNetwork::TCPServerMain() { TConnection client {}; SOCKET Listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); int optval = 1; - setsockopt(Listener, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval)); + setsockopt(Listener, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); // TODO: check optval or return value idk sockaddr_in addr {}; addr.sin_addr.s_addr = INADDR_ANY; From 131ade02cd0c2cf29178ee2244a95e4b5d5c4e02 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 2 Aug 2021 14:23:20 +0200 Subject: [PATCH 032/255] TNetwork: setsockopt: cast optval to void* --- src/TNetwork.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index d0784ee..004f4ee 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -111,7 +111,7 @@ void TNetwork::TCPServerMain() { TConnection client {}; SOCKET Listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); int optval = 1; - setsockopt(Listener, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); + setsockopt(Listener, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&optval), sizeof(optval)); // TODO: check optval or return value idk sockaddr_in addr {}; addr.sin_addr.s_addr = INADDR_ANY; From 35a3dab1cecd4537c6b946d3777671e7a3706ebc Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sat, 7 Aug 2021 23:51:56 +0200 Subject: [PATCH 033/255] TNetwork: clarify error messages --- src/TNetwork.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index 004f4ee..99e5395 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -118,17 +118,17 @@ void TNetwork::TCPServerMain() { addr.sin_family = AF_INET; addr.sin_port = htons(uint16_t(Application::Settings.Port)); if (bind(Listener, (sockaddr*)&addr, sizeof(addr)) != 0) { - error(("Can't bind socket! ") + GetPlatformAgnosticErrorString()); + error("bind() failed: " + GetPlatformAgnosticErrorString()); std::this_thread::sleep_for(std::chrono::seconds(5)); exit(-1); } if (Listener == -1) { - error(("Invalid listening socket")); + error("Invalid listening socket"); return; } if (listen(Listener, SOMAXCONN)) { - error(("listener failed ") + GetPlatformAgnosticErrorString()); - //TODO fix me leak Listener + error("listen() failed: " + GetPlatformAgnosticErrorString()); + // FIXME leak Listener return; } info(("Vehicle event network online")); From 046097579ee11ce4cdb641301feb1bad8dac765c Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 9 Aug 2021 12:08:04 +0200 Subject: [PATCH 034/255] README: ensure that submodules are initialized recursively --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 22464eb..52d4f59 100644 --- a/README.md +++ b/README.md @@ -80,8 +80,8 @@ If you can't find this version of boost (only 1.6x, for example), you can either On windows, use git-bash for these commands. On Linux, these should work in your shell. 1. Make sure you have all [prerequisites](#prerequisites) installed -2. Clone the repository in a location of your choice with **`git clone --recurse-submodules https://github.com/BeamMP/BeamMP-Server`**. Now change into the cloned directory by running `cd BeamMP-Server`. -3. Ensure that all submodules are initialized by running `git submodule update --init --recursive`. Then change into the cloned directory by running `cd BeamMP-Server`. +2. Clone the repository in a location of your choice with `git clone --recurse-submodules https://github.com/BeamMP/BeamMP-Server`. +3. Ensure that all submodules are initialized by running `git submodule init --update --recursive`. Then change into the cloned directory by running `cd BeamMP-Server`. 4. Checkout the branch of the release you want to compile (`master` is often unstable), for example `git checkout tags/v1.20` for version 1.20. You can find the latest version [here](https://github.com/BeamMP/BeamMP-Server/tags). 5. Run `cmake .` (with `.`) 6. Run `make` From 950cee9fd0e5e8645acbf63ab7394e3ed37be62b Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 9 Aug 2021 12:18:55 +0200 Subject: [PATCH 035/255] README: fix git submodule update command --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 52d4f59..c69efcd 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,7 @@ On windows, use git-bash for these commands. On Linux, these should work in your 1. Make sure you have all [prerequisites](#prerequisites) installed 2. Clone the repository in a location of your choice with `git clone --recurse-submodules https://github.com/BeamMP/BeamMP-Server`. -3. Ensure that all submodules are initialized by running `git submodule init --update --recursive`. Then change into the cloned directory by running `cd BeamMP-Server`. +3. Ensure that all submodules are initialized by running `git submodule update --init --recursive`. Then change into the cloned directory by running `cd BeamMP-Server`. 4. Checkout the branch of the release you want to compile (`master` is often unstable), for example `git checkout tags/v1.20` for version 1.20. You can find the latest version [here](https://github.com/BeamMP/BeamMP-Server/tags). 5. Run `cmake .` (with `.`) 6. Run `make` From b1caf5c29a29227225e7ea24ed8b006b19c36f9e Mon Sep 17 00:00:00 2001 From: Anonymous-275 Date: Fri, 25 Jun 2021 01:10:34 +0300 Subject: [PATCH 036/255] lua Register --- src/TLuaFile.cpp | 107 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 87 insertions(+), 20 deletions(-) diff --git a/src/TLuaFile.cpp b/src/TLuaFile.cpp index a54eed1..5faacc2 100644 --- a/src/TLuaFile.cpp +++ b/src/TLuaFile.cpp @@ -6,7 +6,7 @@ #include "TLuaEngine.h" #include "TNetwork.h" #include "TServer.h" - +#include #include #include @@ -625,7 +625,91 @@ int lua_Print(lua_State* L) { } } -int lua_TempFix(lua_State* L); +int lua_TempFix(lua_State* L) { + if (lua_isnumber(L, 1)) { + int ID = int(lua_tonumber(L, 1)); + auto MaybeClient = GetClient(Engine().Server(), ID); + if (!MaybeClient || MaybeClient.value().expired()) + return 0; + std::string Ret; + auto c = MaybeClient.value().lock(); + if (c->IsGuest()) { + Ret = "Guest-" + c->GetName(); + } else + Ret = c->GetName(); + lua_pushstring(L, Ret.c_str()); + } else + SendError(Engine(), L, "GetDID not enough arguments"); + return 1; +} + +template +struct fun_ptr_helper +{ +public: + typedef std::function function_type; + + static void bind(function_type&& f) + { instance().fn_.swap(f); } + + static void bind(const function_type& f) + { instance().fn_=f; } + + static Res invoke(ArgTypes... args) + { return instance().fn_(args...); } + + typedef decltype(&fun_ptr_helper::invoke) pointer_type; + static pointer_type ptr() + { return &invoke; } + +private: + static fun_ptr_helper& instance() + { + static fun_ptr_helper inst_; + return inst_; + } + + fun_ptr_helper() {} + + function_type fn_; +}; + +template +typename fun_ptr_helper<_UniqueId, _Res, _ArgTypes...>::pointer_type +get_fn_ptr(const std::function<_Res(_ArgTypes...)>& f) +{ + fun_ptr_helper<_UniqueId, _Res, _ArgTypes...>::bind(f); + return fun_ptr_helper<_UniqueId, _Res, _ArgTypes...>::ptr(); +} + + +int lua_Register(lua_State* L) { + if(lua_isstring(L, 1)){ + std::string Name(lua_tolstring(L, 1, nullptr)); + lua_getglobal(L, Name.c_str()); + if (lua_isfunction(L, -1)) { + for (auto& Script : Engine().LuaFiles()) { + if(Script->GetState() != L){ + lua_CFunction Func = get_fn_ptr<0>(std::function([=](lua_State* A) { + lua_getglobal(L, Name.c_str()); + if (lua_isfunction(L, -1)) { + lua_pcall(L, 0, 0, 0); + } + return 0; + })); + lua_register(Script->GetState(), Name.c_str(), Func); + } + } + + } else { + SendError(Engine(), L, Name + " is not a global function!"); + ClearStack(L); + } + } else { + SendError(Engine(), L, "Register wrong arguments expected string"); + } + return 0; +} void TLuaFile::Init(const std::string& PluginName, const std::string& FileName, fs::file_time_type LastWrote) { auto Lock = std::unique_lock(mInitMutex); @@ -724,6 +808,7 @@ void TLuaFile::Load() { lua_register(mLuaState, "StopThread", lua_StopThread); lua_register(mLuaState, "DropPlayer", lua_dropPlayer); lua_register(mLuaState, "GetPlayerHWID", lua_HWID); + lua_register(mLuaState, "Register", lua_Register); lua_register(mLuaState, "exit", lua_ServerExit); lua_register(mLuaState, "Sleep", lua_Sleep); lua_register(mLuaState, "print", lua_Print); @@ -802,24 +887,6 @@ void SendError(TLuaEngine& Engine, lua_State* L, const std::string& msg) { warn(a + (" | Incorrect Call of ") + msg); } -int lua_TempFix(lua_State* L) { - if (lua_isnumber(L, 1)) { - int ID = int(lua_tonumber(L, 1)); - auto MaybeClient = GetClient(Engine().Server(), ID); - if (!MaybeClient || MaybeClient.value().expired()) - return 0; - std::string Ret; - auto c = MaybeClient.value().lock(); - if (c->IsGuest()) { - Ret = "Guest-" + c->GetName(); - } else - Ret = c->GetName(); - lua_pushstring(L, Ret.c_str()); - } else - SendError(Engine(), L, "GetDID not enough arguments"); - return 1; -} - void TLuaArg::PushArgs(lua_State* State) { for (std::any arg : args) { if (!arg.has_value()) { From 80432eb718eddb3bfcbd49f20182e103bd6e59ef Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 25 Jun 2021 00:42:45 +0200 Subject: [PATCH 037/255] implement GetOSName, start working on HttpsPOST --- include/Http.h | 2 +- src/Http.cpp | 14 +++-- src/THeartbeatThread.cpp | 5 +- src/TLuaEngine.cpp | 8 ++- src/TLuaFile.cpp | 127 ++++++++++++++++++++++++++++++++------- src/TNetwork.cpp | 2 +- 6 files changed, 125 insertions(+), 33 deletions(-) diff --git a/include/Http.h b/include/Http.h index 6c3cec3..48bae69 100644 --- a/include/Http.h +++ b/include/Http.h @@ -9,4 +9,4 @@ std::string POST(const std::string& host, const std::string& target, const std:: namespace Status { std::string ToString(int code); } -} +} \ No newline at end of file diff --git a/src/Http.cpp b/src/Http.cpp index 3ac754c..a02e323 100644 --- a/src/Http.cpp +++ b/src/Http.cpp @@ -16,10 +16,12 @@ namespace ssl = net::ssl; // from using tcp = net::ip::tcp; // from std::string Http::GET(const std::string& host, int port, const std::string& target, unsigned int* status) { + try { // Check command line arguments. int version = 11; + // The io_context is required for all I/O net::io_context ioc; @@ -64,6 +66,7 @@ std::string Http::GET(const std::string& host, int port, const std::string& targ // This buffer is used for reading and must be persisted beast::flat_buffer buffer; + // Declare a container to hold the response http::response res; @@ -135,11 +138,10 @@ std::string Http::POST(const std::string& host, const std::string& target, const req.set(http::field::host, host); if (!body.empty()) { - if (json) { - req.set(http::field::content_type, "application/json"); - } else { - req.set(http::field::content_type, "application/x-www-form-urlencoded"); - } + req.set(http::field::content_type, ContentType); // "application/json" + // "application/x-www-form-urlencoded" + + req.set(http::field::content_length, std::to_string(body.size())); req.body() = body; // info("body is " + body + " (" + req.body() + ")"); @@ -278,4 +280,4 @@ std::string Http::Status::ToString(int code) { } else { return "Unassigned"; } -} +} \ No newline at end of file diff --git a/src/THeartbeatThread.cpp b/src/THeartbeatThread.cpp index d650966..6a72004 100644 --- a/src/THeartbeatThread.cpp +++ b/src/THeartbeatThread.cpp @@ -39,6 +39,7 @@ void THeartbeatThread::operator()() { if (status < 0) { status = 0; } + auto Lock = Sentry.CreateExclusiveContext(); Sentry.SetContext("heartbeat", { { "response-body", T }, @@ -48,6 +49,7 @@ void THeartbeatThread::operator()() { Sentry.Log(SentryLevel::Error, "default", Http::Status::ToString(status) + " (" + std::to_string(status) + ")"); }; + auto Target = "/heartbeat"; int ResponseCode = -1; T = Http::POST(Application::GetBackendHostname(), Target, {}, Body, false, &ResponseCode); @@ -63,6 +65,7 @@ void THeartbeatThread::operator()() { T = Http::POST(Application::GetBackup2Hostname(), Target, {}, Body, false, &ResponseCode); if (T.substr(0, 2) != "20" || ResponseCode != 200) { warn("Backend system refused server! Server will not show in the public server list."); + isAuth = false; SentryReportError(Application::GetBackup2Hostname() + Target, ResponseCode); } @@ -127,4 +130,4 @@ std::string THeartbeatThread::GetPlayers() { return Return; } /*THeartbeatThread::~THeartbeatThread() { -}*/ +}*/ \ No newline at end of file diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 0ec1b07..086355a 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -70,12 +70,17 @@ void TLuaEngine::FolderList(const std::string& Path, bool HotSwap) { for (const auto& entry : fs::directory_iterator(Path)) { if (fs::is_directory(entry)) { RegisterFiles(entry.path(), HotSwap); + } } } void TLuaEngine::RegisterFiles(const fs::path& Path, bool HotSwap) { std::string Name = Path.filename().string(); + std::string Name = Path.substr(Path.find_last_of('/') + 1); +#else + +#endif if (!HotSwap) info(("Loading plugin : ") + Name); std::vector Entries; @@ -104,10 +109,11 @@ void TLuaEngine::RegisterFiles(const fs::path& Path, bool HotSwap) { } } + bool TLuaEngine::IsNewFile(const std::string& Path) { for (auto& Script : mLuaFiles) { if (fs::absolute(Path) == fs::absolute(Script->GetFileName())) return false; } return true; -} +} \ No newline at end of file diff --git a/src/TLuaFile.cpp b/src/TLuaFile.cpp index 5faacc2..dbfe81b 100644 --- a/src/TLuaFile.cpp +++ b/src/TLuaFile.cpp @@ -3,6 +3,7 @@ #include "Common.h" #include "CustomAssert.h" #include "Defer.h" +#include "Http.h" #include "TLuaEngine.h" #include "TNetwork.h" #include "TServer.h" @@ -10,7 +11,30 @@ #include #include -// TODO: REWRITE +namespace LuaTable { +void Begin(lua_State* L) { + lua_newtable(L); +} + +void End(lua_State* L, const std::string& name) { + lua_setglobal(L, name.c_str()); +} + +void BeginEntry(lua_State* L, const std::string& name) { + lua_pushstring(L, name.c_str()); +} + +void EndEntry(lua_State* L) { + lua_settable(L, -3); +} + +void InsertFunction(lua_State* L, const std::string& name, lua_CFunction func) { + BeginEntry(L, name); + lua_pushcfunction(L, func); + EndEntry(L); +} + +} void SendError(TLuaEngine& Engine, lua_State* L, const std::string& msg); std::any CallFunction(TLuaFile* lua, const std::string& FuncName, std::shared_ptr Arg); @@ -40,11 +64,13 @@ std::shared_ptr CreateArg(lua_State* L, int T, int S) { } return temp; } + void ClearStack(lua_State* L) { lua_settop(L, 0); } std::any Trigger(TLuaFile* lua, const std::string& R, std::shared_ptr arg) { + std::lock_guard lockGuard(lua->Lock); std::packaged_task)> task([lua, R](std::shared_ptr arg) { return CallFunction(lua, R, arg); }); std::future f1 = task.get_future(); @@ -198,6 +224,7 @@ void ExecuteAsync(TLuaFile* lua, const std::string& FuncName) { } void CallAsync(TLuaFile* lua, const std::string& Func, int U) { + lua->SetStopThread(false); int D = 1000 / U; while (!lua->GetStopThread()) { @@ -585,6 +612,42 @@ int lua_Set(lua_State* L) { return 0; } +/* +// CallInPlugin(PluginName, FunctionName) +int lua_CallInPlugin(lua_State* L) { + if (!lua_isstring(L, 1)) { + SendError(Engine(), L, "CallInPlugin expects a string as 1. argument."); + return 1; + } + if (!lua_isstring(L, 2)) { + SendError(Engine(), L, "CallInPlugin expects a string as 2. argument."); + return 1; + } + const char* PluginName = lua_tostring(L, 1); + const char* FunctionName = lua_tostring(L, 2); + + bool FoundPlugin = false; + for (const auto& File : Engine().LuaFiles()) { + if (File->GetPluginName() == PluginName) { + FoundPlugin = true; + auto State = File->GetState(); + lua_getglobal(State, FunctionName); + if (!lua_isfunction(State, -1)) { + SendError(Engine(), L, "CallInPlugin: \"" + std::string(FunctionName) + "\" in plugin \"" + std::string(PluginName) + "\" is not a function."); + return 1; + } + ClearStack(State); + CallFunction(File.get(), FunctionName, nullptr); + } + } + if (!FoundPlugin) { + SendError(Engine(), L, "CallInPlugin: Could not find plugin called \"" + std::string(PluginName) + "\""); + return 1; + } + + return 0; +} +*/ extern "C" { int lua_Print(lua_State* L) { @@ -754,6 +817,7 @@ std::string TLuaFile::GetOrigin() { } std::any CallFunction(TLuaFile* lua, const std::string& FuncName, std::shared_ptr Arg) { + lua_State* luaState = lua->GetState(); lua_getglobal(luaState, FuncName.c_str()); if (lua_isfunction(luaState, -1)) { @@ -787,32 +851,48 @@ void TLuaFile::SetFileName(const std::string& Name) { mFileName = Name; } +// GetOSName() -> Linux || Windows || Other +int lua_GetOSName(lua_State* L) { +#if defined(__linux) || defined(__linux__) + lua_pushstring(L, "Linux"); +#elif defined(WIN32) + lua_pushstring(L, "Windows"); +#else + lua_pushstring(L, "Unknown"); +#endif +} + void TLuaFile::Load() { Assert(mLuaState); luaL_openlibs(mLuaState); - lua_register(mLuaState, "GetPlayerIdentifiers", lua_GetIdentifiers); - lua_register(mLuaState, "TriggerGlobalEvent", lua_TriggerEventG); - lua_register(mLuaState, "TriggerLocalEvent", lua_TriggerEventL); - lua_register(mLuaState, "TriggerClientEvent", lua_RemoteEvent); - lua_register(mLuaState, "GetPlayerCount", lua_GetPlayerCount); - lua_register(mLuaState, "isPlayerConnected", lua_isConnected); - lua_register(mLuaState, "RegisterEvent", lua_RegisterEvent); - lua_register(mLuaState, "GetPlayerName", lua_GetPlayerName); - lua_register(mLuaState, "RemoveVehicle", lua_RemoveVehicle); - lua_register(mLuaState, "GetPlayerDiscordID", lua_TempFix); - lua_register(mLuaState, "CreateThread", lua_CreateThread); - lua_register(mLuaState, "GetPlayerVehicles", lua_GetCars); - lua_register(mLuaState, "SendChatMessage", lua_sendChat); - lua_register(mLuaState, "GetPlayers", lua_GetAllPlayers); - lua_register(mLuaState, "GetPlayerGuest", lua_GetGuest); - lua_register(mLuaState, "StopThread", lua_StopThread); - lua_register(mLuaState, "DropPlayer", lua_dropPlayer); - lua_register(mLuaState, "GetPlayerHWID", lua_HWID); + + LuaTable::Begin(mLuaState); + LuaTable::InsertFunction(mLuaState, "GetPlayerIdentifiers", lua_GetIdentifiers); + LuaTable::InsertFunction(mLuaState, "TriggerGlobalEvent", lua_TriggerEventG); + LuaTable::InsertFunction(mLuaState, "TriggerLocalEvent", lua_TriggerEventL); + LuaTable::InsertFunction(mLuaState, "TriggerClientEvent", lua_RemoteEvent); + LuaTable::InsertFunction(mLuaState, "GetPlayerCount", lua_GetPlayerCount); + LuaTable::InsertFunction(mLuaState, "IsPlayerConnected", lua_isConnected); + LuaTable::InsertFunction(mLuaState, "RegisterEvent", lua_RegisterEvent); + LuaTable::InsertFunction(mLuaState, "GetPlayerName", lua_GetPlayerName); + LuaTable::InsertFunction(mLuaState, "RemoveVehicle", lua_RemoveVehicle); + LuaTable::InsertFunction(mLuaState, "GetPlayerDiscordID", lua_TempFix); + LuaTable::InsertFunction(mLuaState, "CreateThread", lua_CreateThread); + LuaTable::InsertFunction(mLuaState, "GetPlayerVehicles", lua_GetCars); + LuaTable::InsertFunction(mLuaState, "SendChatMessage", lua_sendChat); + LuaTable::InsertFunction(mLuaState, "GetPlayers", lua_GetAllPlayers); + LuaTable::InsertFunction(mLuaState, "GetPlayerGuest", lua_GetGuest); + LuaTable::InsertFunction(mLuaState, "StopThread", lua_StopThread); + LuaTable::InsertFunction(mLuaState, "DropPlayer", lua_dropPlayer); lua_register(mLuaState, "Register", lua_Register); - lua_register(mLuaState, "exit", lua_ServerExit); - lua_register(mLuaState, "Sleep", lua_Sleep); + LuaTable::InsertFunction(mLuaState, "GetPlayerHWID", lua_HWID); + LuaTable::InsertFunction(mLuaState, "Sleep", lua_Sleep); + LuaTable::InsertFunction(mLuaState, "Set", lua_Set); + LuaTable::InsertFunction(mLuaState, "GetOSName", lua_GetOSName); + LuaTable::End(mLuaState, "MP"); + lua_register(mLuaState, "print", lua_Print); - lua_register(mLuaState, "Set", lua_Set); + lua_register(mLuaState, "exit", lua_ServerExit); if (!mConsole) Reload(); } @@ -887,6 +967,7 @@ void SendError(TLuaEngine& Engine, lua_State* L, const std::string& msg) { warn(a + (" | Incorrect Call of ") + msg); } + void TLuaArg::PushArgs(lua_State* State) { for (std::any arg : args) { if (!arg.has_value()) { @@ -911,4 +992,4 @@ void TLuaArg::PushArgs(lua_State* State) { error("what in the hell is " + std::string(arg.type().name())); } } -} +} \ No newline at end of file diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index d0972f3..f8722fc 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -992,4 +992,4 @@ std::string TNetwork::UDPRcvFromClient(sockaddr_in& client) const { return ""; } return std::string(Ret.begin(), Ret.begin() + Rcv); -} +} \ No newline at end of file From 518cb0664ec7aeef12dc9101beb86a731e100d71 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 25 Jun 2021 00:48:52 +0200 Subject: [PATCH 038/255] rebase --- src/TLuaFile.cpp | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/src/TLuaFile.cpp b/src/TLuaFile.cpp index dbfe81b..4328bea 100644 --- a/src/TLuaFile.cpp +++ b/src/TLuaFile.cpp @@ -707,52 +707,44 @@ int lua_TempFix(lua_State* L) { } template -struct fun_ptr_helper -{ +struct fun_ptr_helper { public: typedef std::function function_type; - static void bind(function_type&& f) - { instance().fn_.swap(f); } + static void bind(function_type&& f) { instance().fn_.swap(f); } - static void bind(const function_type& f) - { instance().fn_=f; } + static void bind(const function_type& f) { instance().fn_ = f; } - static Res invoke(ArgTypes... args) - { return instance().fn_(args...); } + static Res invoke(ArgTypes... args) { return instance().fn_(args...); } typedef decltype(&fun_ptr_helper::invoke) pointer_type; - static pointer_type ptr() - { return &invoke; } + static pointer_type ptr() { return &invoke; } private: - static fun_ptr_helper& instance() - { + static fun_ptr_helper& instance() { static fun_ptr_helper inst_; return inst_; } - fun_ptr_helper() {} + fun_ptr_helper() { } function_type fn_; }; template typename fun_ptr_helper<_UniqueId, _Res, _ArgTypes...>::pointer_type -get_fn_ptr(const std::function<_Res(_ArgTypes...)>& f) -{ +get_fn_ptr(const std::function<_Res(_ArgTypes...)>& f) { fun_ptr_helper<_UniqueId, _Res, _ArgTypes...>::bind(f); return fun_ptr_helper<_UniqueId, _Res, _ArgTypes...>::ptr(); } - int lua_Register(lua_State* L) { - if(lua_isstring(L, 1)){ + if (lua_isstring(L, 1)) { std::string Name(lua_tolstring(L, 1, nullptr)); lua_getglobal(L, Name.c_str()); if (lua_isfunction(L, -1)) { for (auto& Script : Engine().LuaFiles()) { - if(Script->GetState() != L){ + if (Script->GetState() != L) { lua_CFunction Func = get_fn_ptr<0>(std::function([=](lua_State* A) { lua_getglobal(L, Name.c_str()); if (lua_isfunction(L, -1)) { @@ -860,6 +852,7 @@ int lua_GetOSName(lua_State* L) { #else lua_pushstring(L, "Unknown"); #endif + return 1; } void TLuaFile::Load() { @@ -884,7 +877,7 @@ void TLuaFile::Load() { LuaTable::InsertFunction(mLuaState, "GetPlayerGuest", lua_GetGuest); LuaTable::InsertFunction(mLuaState, "StopThread", lua_StopThread); LuaTable::InsertFunction(mLuaState, "DropPlayer", lua_dropPlayer); - lua_register(mLuaState, "Register", lua_Register); + LuaTable::InsertFunction(mLuaState, "Register", lua_Register); LuaTable::InsertFunction(mLuaState, "GetPlayerHWID", lua_HWID); LuaTable::InsertFunction(mLuaState, "Sleep", lua_Sleep); LuaTable::InsertFunction(mLuaState, "Set", lua_Set); @@ -967,7 +960,6 @@ void SendError(TLuaEngine& Engine, lua_State* L, const std::string& msg) { warn(a + (" | Incorrect Call of ") + msg); } - void TLuaArg::PushArgs(lua_State* State) { for (std::any arg : args) { if (!arg.has_value()) { @@ -992,4 +984,4 @@ void TLuaArg::PushArgs(lua_State* State) { error("what in the hell is " + std::string(arg.type().name())); } } -} \ No newline at end of file +} From 1ff12cb2bf69b9442603e01e169ea2754d443644 Mon Sep 17 00:00:00 2001 From: Anonymous-275 Date: Fri, 25 Jun 2021 02:12:21 +0300 Subject: [PATCH 039/255] simpler lua_Register --- src/TLuaFile.cpp | 49 +++++++++++++++++------------------------------- 1 file changed, 17 insertions(+), 32 deletions(-) diff --git a/src/TLuaFile.cpp b/src/TLuaFile.cpp index 4328bea..0eb7e7c 100644 --- a/src/TLuaFile.cpp +++ b/src/TLuaFile.cpp @@ -706,53 +706,38 @@ int lua_TempFix(lua_State* L) { return 1; } -template -struct fun_ptr_helper { -public: - typedef std::function function_type; +template +struct CFunctionPointer { + std::function func; - static void bind(function_type&& f) { instance().fn_.swap(f); } - - static void bind(const function_type& f) { instance().fn_ = f; } - - static Res invoke(ArgTypes... args) { return instance().fn_(args...); } - - typedef decltype(&fun_ptr_helper::invoke) pointer_type; - static pointer_type ptr() { return &invoke; } - -private: - static fun_ptr_helper& instance() { - static fun_ptr_helper inst_; - return inst_; + static int callback(lua_State* s) { + return instance().func(s); } - fun_ptr_helper() { } - - function_type fn_; + static CFunctionPointer& instance() { + static CFunctionPointer inst_; + return inst_; + } }; -template -typename fun_ptr_helper<_UniqueId, _Res, _ArgTypes...>::pointer_type -get_fn_ptr(const std::function<_Res(_ArgTypes...)>& f) { - fun_ptr_helper<_UniqueId, _Res, _ArgTypes...>::bind(f); - return fun_ptr_helper<_UniqueId, _Res, _ArgTypes...>::ptr(); -} - int lua_Register(lua_State* L) { - if (lua_isstring(L, 1)) { + if(lua_isstring(L, 1)){ std::string Name(lua_tolstring(L, 1, nullptr)); lua_getglobal(L, Name.c_str()); if (lua_isfunction(L, -1)) { for (auto& Script : Engine().LuaFiles()) { - if (Script->GetState() != L) { - lua_CFunction Func = get_fn_ptr<0>(std::function([=](lua_State* A) { + if(Script->GetState() != L){ + + CFunctionPointer<0> F; //How do we pass a value instead of a const + F.instance().func = [=](lua_State* A) { lua_getglobal(L, Name.c_str()); if (lua_isfunction(L, -1)) { lua_pcall(L, 0, 0, 0); } return 0; - })); - lua_register(Script->GetState(), Name.c_str(), Func); + }; + + lua_register(Script->GetState(), Name.c_str(), F.callback); } } From 2cfb27820a1407e0a425be35b578a87ae1e1308e Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 25 Jun 2021 01:59:38 +0200 Subject: [PATCH 040/255] switch to toml11 it's better, believe me --- .gitmodules | 8 +-- CMakeLists.txt | 5 +- include/TConfig.h | 2 + include/toml11 | 1 + include/tomlplusplus | 1 - src/TConfig.cpp | 117 +++++++++++++++++-------------------------- src/TLuaFile.cpp | 36 ------------- 7 files changed, 58 insertions(+), 112 deletions(-) create mode 160000 include/toml11 delete mode 160000 include/tomlplusplus diff --git a/.gitmodules b/.gitmodules index e0dfe36..a9df475 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,9 +10,9 @@ [submodule "rapidjson"] path = rapidjson url = https://github.com/Tencent/rapidjson -[submodule "include/tomlplusplus"] - path = include/tomlplusplus - url = https://github.com/marzer/tomlplusplus +[submodule "include/toml11"] + path = include/toml11 + url = https://github.com/ToruNiina/toml11 [submodule "include/sentry-native"] path = include/sentry-native - url = https://github.com/getsentry/sentry-native + url = https://github.com/getsentry/sentry-native \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f9f672..cd6a6ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,6 @@ cmake_minimum_required(VERSION 3.0) + message(STATUS "You can find build instructions and a list of dependencies in the README at \ https://github.com/BeamMP/BeamMP-Server") @@ -25,6 +26,7 @@ add_subdirectory("include/sentry-native") message(STATUS "Setting compiler flags") if (WIN32) + #-DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x64-windows-static set(VcpkgRoot ${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}) include_directories(${VcpkgRoot}/include) @@ -60,6 +62,7 @@ add_subdirectory("socket.io-client-cpp") add_subdirectory("include/commandline") set(CMAKE_CXX_STANDARD 17) + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG") message(STATUS "Looking for Boost") @@ -131,4 +134,4 @@ elseif (WIN32) commandline sioclient_tls sentry) -endif () +endif () \ No newline at end of file diff --git a/include/TConfig.h b/include/TConfig.h index ffb2b53..60001bd 100644 --- a/include/TConfig.h +++ b/include/TConfig.h @@ -10,6 +10,8 @@ public: [[nodiscard]] bool Failed() const { return mFailed; } + void FlushToFile(); + private: void CreateConfigFile(std::string_view name); void ParseFromFile(std::string_view name); diff --git a/include/toml11 b/include/toml11 new file mode 160000 index 0000000..6473810 --- /dev/null +++ b/include/toml11 @@ -0,0 +1 @@ +Subproject commit 647381020ef04b5d41d540ec489eba45e82d90a7 diff --git a/include/tomlplusplus b/include/tomlplusplus deleted file mode 160000 index bc6891e..0000000 --- a/include/tomlplusplus +++ /dev/null @@ -1 +0,0 @@ -Subproject commit bc6891e1fbec0b137ac5795542d728a1ad124c11 diff --git a/src/TConfig.cpp b/src/TConfig.cpp index d2a0696..8a2d9f4 100644 --- a/src/TConfig.cpp +++ b/src/TConfig.cpp @@ -1,4 +1,6 @@ -#include // header-only version of TOML++ +#define TOML11_PRESERVE_COMMENTS_BY_DEFAULT + +#include // header-only version of TOML++ #include "TConfig.h" #include @@ -32,6 +34,23 @@ TConfig::TConfig() { } } +void TConfig::FlushToFile() { + auto data = toml::parse(ConfigFileName); + data["General"] = toml::table(); + data["General"][StrAuthKey.data()] = Application::Settings.Key; + data["General"][StrDebug.data()] = Application::Settings.DebugModeEnabled; + data["General"][StrPrivate.data()] = Application::Settings.Private; + data["General"][StrPort.data()] = Application::Settings.Port; + data["General"][StrName.data()] = Application::Settings.ServerName; + data["General"][StrMaxCars.data()] = Application::Settings.MaxCars; + data["General"][StrMaxPlayers.data()] = Application::Settings.MaxPlayers; + data["General"][StrMap.data()] = Application::Settings.MapName; + data["General"][StrDescription.data()] = Application::Settings.ServerDesc; + data["General"][StrResourceFolder.data()] = Application::Settings.Resource; + std::ofstream Stream(ConfigFileName); + Stream << data << std::flush; +} + void TConfig::CreateConfigFile(std::string_view name) { // build from old config Server.cfg @@ -44,32 +63,31 @@ void TConfig::CreateConfigFile(std::string_view name) { error("an error occurred and was ignored during config transfer: " + std::string(e.what())); } - toml::table tbl { { + { // create file context + std::ofstream ofs(name.data()); + } - { "General", - toml::table { { + auto data = toml::parse(name.data()); - { StrDebug, Application::Settings.DebugModeEnabled }, - { StrPrivate, Application::Settings.Private }, - { StrPort, Application::Settings.Port }, - { StrMaxCars, Application::Settings.MaxCars }, - { StrMaxPlayers, Application::Settings.MaxPlayers }, - { StrMap, Application::Settings.MapName }, - { StrName, Application::Settings.ServerName }, - { StrDescription, Application::Settings.ServerDesc }, - { StrResourceFolder, Application::Settings.Resource }, - { StrAuthKey, Application::Settings.Key }, + data["General"] = toml::table(); + data["General"][StrAuthKey.data()] = Application::Settings.Key; + data["General"][StrDebug.data()] = Application::Settings.DebugModeEnabled; + data["General"][StrPrivate.data()] = Application::Settings.Private; + data["General"][StrPort.data()] = Application::Settings.Port; + data["General"][StrName.data()] = Application::Settings.ServerName; + data["General"][StrMaxCars.data()] = Application::Settings.MaxCars; + data["General"][StrMaxPlayers.data()] = Application::Settings.MaxPlayers; + data["General"][StrMap.data()] = Application::Settings.MapName; + data["General"][StrDescription.data()] = Application::Settings.ServerDesc; + data["General"][StrResourceFolder.data()] = Application::Settings.Resource; - } } }, - - } }; std::ofstream ofs { std::string(name) }; if (ofs.good()) { ofs << "# This is the BeamMP-Server config file.\n" "# Help & Documentation: `https://wiki.beammp.com/en/home/server-maintenance`\n" "# IMPORTANT: Fill in the AuthKey with the key you got from `https://beammp.com/k/dashboard` on the left under \"Keys\"\n" << '\n'; - ofs << tbl << '\n'; + ofs << data << '\n'; error("There was no \"" + std::string(ConfigFileName) + "\" file (this is normal for the first time running the server), so one was generated for you. It was automatically filled with the settings from your Server.cfg, if you have one. Please open ServerConfig.toml and ensure your AuthKey and other settings are filled in and correct, then restart the server. The old Server.cfg file will no longer be used and causes a warning if it exists from now on."); mFailed = true; } else { @@ -80,58 +98,17 @@ void TConfig::CreateConfigFile(std::string_view name) { void TConfig::ParseFromFile(std::string_view name) { try { - toml::table FullTable = toml::parse_file(name); - toml::table GeneralTable = *FullTable["General"].as_table(); - if (auto val = GeneralTable[StrDebug].value(); val.has_value()) { - Application::Settings.DebugModeEnabled = val.value(); - } else { - throw std::runtime_error(std::string(StrDebug)); - } - if (auto val = GeneralTable[StrPrivate].value(); val.has_value()) { - Application::Settings.Private = val.value(); - } else { - throw std::runtime_error(std::string(StrPrivate)); - } - if (auto val = GeneralTable[StrPort].value(); val.has_value()) { - Application::Settings.Port = val.value(); - } else { - throw std::runtime_error(std::string(StrPort)); - } - if (auto val = GeneralTable[StrMaxCars].value(); val.has_value()) { - Application::Settings.MaxCars = val.value(); - } else { - throw std::runtime_error(std::string(StrMaxCars)); - } - if (auto val = GeneralTable[StrMaxPlayers].value(); val.has_value()) { - Application::Settings.MaxPlayers = val.value(); - } else { - throw std::runtime_error(std::string(StrMaxPlayers)); - } - if (auto val = GeneralTable[StrMap].value(); val.has_value()) { - Application::Settings.MapName = val.value(); - } else { - throw std::runtime_error(std::string(StrMap)); - } - if (auto val = GeneralTable[StrName].value(); val.has_value()) { - Application::Settings.ServerName = val.value(); - } else { - throw std::runtime_error(std::string(StrName)); - } - if (auto val = GeneralTable[StrDescription].value(); val.has_value()) { - Application::Settings.ServerDesc = val.value(); - } else { - throw std::runtime_error(std::string(StrDescription)); - } - if (auto val = GeneralTable[StrResourceFolder].value(); val.has_value()) { - Application::Settings.Resource = val.value(); - } else { - throw std::runtime_error(std::string(StrResourceFolder)); - } - if (auto val = GeneralTable[StrAuthKey].value(); val.has_value()) { - Application::Settings.Key = val.value(); - } else { - throw std::runtime_error(std::string(StrAuthKey)); - } + toml::value data = toml::parse(name.data()); + Application::Settings.DebugModeEnabled = data["General"][StrDebug.data()].as_boolean(); + Application::Settings.Private = data["General"][StrPrivate.data()].as_boolean(); + Application::Settings.Port = data["General"][StrPort.data()].as_integer(); + Application::Settings.MaxCars = data["General"][StrMaxCars.data()].as_integer(); + Application::Settings.MaxPlayers = data["General"][StrMaxPlayers.data()].as_integer(); + Application::Settings.MapName = data["General"][StrMap.data()].as_string(); + Application::Settings.ServerName = data["General"][StrName.data()].as_string(); + Application::Settings.ServerDesc = data["General"][StrDescription.data()].as_string(); + Application::Settings.Resource = data["General"][StrResourceFolder.data()].as_string(); + Application::Settings.Key = data["General"][StrAuthKey.data()].as_string(); } catch (const std::exception& err) { error("Error parsing config file value: " + std::string(err.what())); mFailed = true; diff --git a/src/TLuaFile.cpp b/src/TLuaFile.cpp index 0eb7e7c..ab2960c 100644 --- a/src/TLuaFile.cpp +++ b/src/TLuaFile.cpp @@ -612,42 +612,6 @@ int lua_Set(lua_State* L) { return 0; } -/* -// CallInPlugin(PluginName, FunctionName) -int lua_CallInPlugin(lua_State* L) { - if (!lua_isstring(L, 1)) { - SendError(Engine(), L, "CallInPlugin expects a string as 1. argument."); - return 1; - } - if (!lua_isstring(L, 2)) { - SendError(Engine(), L, "CallInPlugin expects a string as 2. argument."); - return 1; - } - const char* PluginName = lua_tostring(L, 1); - const char* FunctionName = lua_tostring(L, 2); - - bool FoundPlugin = false; - for (const auto& File : Engine().LuaFiles()) { - if (File->GetPluginName() == PluginName) { - FoundPlugin = true; - auto State = File->GetState(); - lua_getglobal(State, FunctionName); - if (!lua_isfunction(State, -1)) { - SendError(Engine(), L, "CallInPlugin: \"" + std::string(FunctionName) + "\" in plugin \"" + std::string(PluginName) + "\" is not a function."); - return 1; - } - ClearStack(State); - CallFunction(File.get(), FunctionName, nullptr); - } - } - if (!FoundPlugin) { - SendError(Engine(), L, "CallInPlugin: Could not find plugin called \"" + std::string(PluginName) + "\""); - return 1; - } - - return 0; -} -*/ extern "C" { int lua_Print(lua_State* L) { From 2be4b8fd91a94fcc546cf6960d06eb47bfca801a Mon Sep 17 00:00:00 2001 From: Anonymous-275 Date: Sun, 27 Jun 2021 14:28:16 +0300 Subject: [PATCH 041/255] Fully working lua_Register --- include/TLuaEngine.h | 4 +++- src/TLuaEngine.cpp | 2 ++ src/TLuaFile.cpp | 37 ++++++++++++++++--------------------- 3 files changed, 21 insertions(+), 22 deletions(-) diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index 1798f3e..29ad668 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -4,10 +4,11 @@ #include "IThreaded.h" #include "TLuaFile.h" #include "TServer.h" +#include #include #include -#include #include +#include class TLuaEngine : public IThreaded { public: @@ -25,6 +26,7 @@ public: std::optional> GetScript(lua_State* L); + static std::unordered_map mGlobals; private: void FolderList(const std::string& Path, bool HotSwap); void RegisterFiles(const fs::path& Path, bool HotSwap); diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 086355a..7bbd874 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -6,6 +6,8 @@ namespace fs = std::filesystem; +std::unordered_map TLuaEngine::mGlobals; + // necessary as lua relies on global state TLuaEngine* TheEngine; diff --git a/src/TLuaFile.cpp b/src/TLuaFile.cpp index ab2960c..d9bad52 100644 --- a/src/TLuaFile.cpp +++ b/src/TLuaFile.cpp @@ -670,38 +670,33 @@ int lua_TempFix(lua_State* L) { return 1; } -template -struct CFunctionPointer { - std::function func; +int lua_Registered(lua_State* L) { - static int callback(lua_State* s) { - return instance().func(s); + lua_Debug info; + lua_getstack(L, 0, &info); + lua_getinfo(L, "n", &info); + + if(auto it = TLuaEngine::mGlobals.find(info.name); it != TLuaEngine::mGlobals.end()){ + lua_getglobal(it->second, info.name); + if (lua_isfunction(it->second, -1)) { + lua_pcall(it->second, 0, 0, 0); //TODO revisit to allow arguments and return + } + return 0; } - static CFunctionPointer& instance() { - static CFunctionPointer inst_; - return inst_; - } -}; + SendError(Engine(), L, "Cannot find global '" + std::string(info.name) + "\'"); + return 0; +} int lua_Register(lua_State* L) { if(lua_isstring(L, 1)){ std::string Name(lua_tolstring(L, 1, nullptr)); lua_getglobal(L, Name.c_str()); if (lua_isfunction(L, -1)) { + TLuaEngine::mGlobals.emplace(Name, L); for (auto& Script : Engine().LuaFiles()) { if(Script->GetState() != L){ - - CFunctionPointer<0> F; //How do we pass a value instead of a const - F.instance().func = [=](lua_State* A) { - lua_getglobal(L, Name.c_str()); - if (lua_isfunction(L, -1)) { - lua_pcall(L, 0, 0, 0); - } - return 0; - }; - - lua_register(Script->GetState(), Name.c_str(), F.callback); + lua_register(Script->GetState(), Name.c_str(), lua_Registered); } } From 549517c518ba6d0a11dfbec196f03d19c065e594 Mon Sep 17 00:00:00 2001 From: Anonymous-275 Date: Sun, 27 Jun 2021 14:29:55 +0300 Subject: [PATCH 042/255] TODO edit --- src/TLuaFile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TLuaFile.cpp b/src/TLuaFile.cpp index d9bad52..c5bad80 100644 --- a/src/TLuaFile.cpp +++ b/src/TLuaFile.cpp @@ -679,7 +679,7 @@ int lua_Registered(lua_State* L) { if(auto it = TLuaEngine::mGlobals.find(info.name); it != TLuaEngine::mGlobals.end()){ lua_getglobal(it->second, info.name); if (lua_isfunction(it->second, -1)) { - lua_pcall(it->second, 0, 0, 0); //TODO revisit to allow arguments and return + lua_pcall(it->second, 0, 0, 0); //TODO revisit to allow arguments and return also we need to mutex this } return 0; } From 853b078124cbe1e4c2926c59b40d3183c89fbbf5 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 1 Jul 2021 00:33:28 +0200 Subject: [PATCH 043/255] add MP.HttpsGET, MP.HttpsPOST --- src/Http.cpp | 23 +++++++--- src/TLuaFile.cpp | 112 ++++++++++++++++++++++++++++++++++++++++++++--- src/TNetwork.cpp | 2 +- 3 files changed, 125 insertions(+), 12 deletions(-) diff --git a/src/Http.cpp b/src/Http.cpp index a02e323..f69ff5a 100644 --- a/src/Http.cpp +++ b/src/Http.cpp @@ -17,11 +17,14 @@ using tcp = net::ip::tcp; // from std::string Http::GET(const std::string& host, int port, const std::string& target, unsigned int* status) { + try { // Check command line arguments. int version = 11; + + // The io_context is required for all I/O net::io_context ioc; @@ -67,6 +70,8 @@ std::string Http::GET(const std::string& host, int port, const std::string& targ beast::flat_buffer buffer; + + // Declare a container to hold the response http::response res; @@ -86,17 +91,18 @@ std::string Http::GET(const std::string& host, int port, const std::string& targ *status = res.base().result_int(); } - // ignore ec + if (ec) + throw beast::system_error { ec }; // If we get here then the connection is closed gracefully return std::string(res.body()); } catch (std::exception const& e) { Application::Console().Write(__func__ + std::string(": ") + e.what()); - return "-1"; + return ErrorString; } } -std::string Http::POST(const std::string& host, const std::string& target, const std::unordered_map& fields, const std::string& body, bool json, int* status) { +std::string Http::POST(const std::string& host, int port, const std::string& target, const std::unordered_map& fields, const std::string& body, const std::string& ContentType, unsigned int* status) { try { net::io_context io; @@ -110,7 +116,7 @@ std::string Http::POST(const std::string& host, const std::string& target, const decltype(resolver)::results_type results; auto try_connect_with_protocol = [&](tcp protocol) { try { - results = resolver.resolve(protocol, host, std::to_string(443)); + results = resolver.resolve(protocol, host, std::to_string(port)); if (!SSL_set_tlsext_host_name(stream.native_handle(), host.c_str())) { boost::system::error_code ec { static_cast(::ERR_get_error()), boost::asio::error::get_ssl_category() }; // FIXME: we could throw and crash, if we like @@ -189,6 +195,10 @@ std::string Http::POST(const std::string& host, const std::string& target, const } Sentry.SetContext("https-post-response-data", response_data); + if (status) { + *status = response.base().result_int(); + } + std::stringstream result; result << response; @@ -199,12 +209,13 @@ std::string Http::POST(const std::string& host, const std::string& target, const // info(result.str()); std::string debug_response_str; std::getline(result, debug_response_str); + //debug("POST " + host + target + ": " + debug_response_str); return std::string(response.body()); } catch (const std::exception& e) { - Application::Console().Write(e.what()); - return "-1"; + Application::Console().Write(__func__ + std::string(": ") + e.what()); + return ErrorString; } } diff --git a/src/TLuaFile.cpp b/src/TLuaFile.cpp index c5bad80..403a671 100644 --- a/src/TLuaFile.cpp +++ b/src/TLuaFile.cpp @@ -676,7 +676,7 @@ int lua_Registered(lua_State* L) { lua_getstack(L, 0, &info); lua_getinfo(L, "n", &info); - if(auto it = TLuaEngine::mGlobals.find(info.name); it != TLuaEngine::mGlobals.end()){ + if (auto it = TLuaEngine::mGlobals.find(info.name); it != TLuaEngine::mGlobals.end()) { lua_getglobal(it->second, info.name); if (lua_isfunction(it->second, -1)) { lua_pcall(it->second, 0, 0, 0); //TODO revisit to allow arguments and return also we need to mutex this @@ -689,13 +689,13 @@ int lua_Registered(lua_State* L) { } int lua_Register(lua_State* L) { - if(lua_isstring(L, 1)){ + if (lua_isstring(L, 1)) { std::string Name(lua_tolstring(L, 1, nullptr)); lua_getglobal(L, Name.c_str()); if (lua_isfunction(L, -1)) { TLuaEngine::mGlobals.emplace(Name, L); for (auto& Script : Engine().LuaFiles()) { - if(Script->GetState() != L){ + if (Script->GetState() != L) { lua_register(Script->GetState(), Name.c_str(), lua_Registered); } } @@ -705,7 +705,7 @@ int lua_Register(lua_State* L) { ClearStack(L); } } else { - SendError(Engine(), L, "Register wrong arguments expected string"); + SendError(Engine(), L, "Wrong arguments to `Register`, expected string"); } return 0; } @@ -799,6 +799,106 @@ int lua_GetOSName(lua_State* L) { return 1; } +// status, body = HttpGET(host, port, target) +// example usage: +// send a GET https://example.com:443/index.html: +// status, body = MP.HttpGET("example.com", 443, "/index.html") +int lua_HttpsGET(lua_State* L) { + if (!lua_isstring(L, 1)) { + SendError(Engine(), L, "`HttpsGET` expects host (type string) as first argument."); + ClearStack(L); + return 0; + } + if (!lua_isnumber(L, 2)) { + SendError(Engine(), L, "`HttpsGET` expects port (type number) as second argument."); + ClearStack(L); + return 0; + } + if (!lua_isstring(L, 3)) { + SendError(Engine(), L, "`HttpsGET` expects target (type string) as third argument."); + ClearStack(L); + return 0; + } + + auto Host = lua_tostring(L, 1); + auto Port = int(lua_tointeger(L, 2)); + auto Target = lua_tostring(L, 3); + + ClearStack(L); + + unsigned int Status; + auto Body = Http::GET(Host, Port, Target, &Status); + lua_pushinteger(L, Status); + + auto PrettyRemote = "https://" + std::string(Host) + ":" + std::to_string(Port) + std::string(Target); + if (Body == Http::ErrorString) { + SendError(Engine(), L, "HTTPS GET " + PrettyRemote + " failed status " + std::to_string(Status) + ". Check the console or log for more info."); + return 1; + } else { + debug("GET " + PrettyRemote + " completed status " + std::to_string(Status)); + } + + lua_pushstring(L, Body.c_str()); + + return 2; +} + +// status, body = HttpsPOST(host, port, target, body, content_type) +int lua_HttpsPOST(lua_State* L) { + if (!lua_isstring(L, 1)) { + SendError(Engine(), L, "`HttpsPOST` expects host (type string) as 1. argument."); + ClearStack(L); + return 0; + } + if (!lua_isnumber(L, 2)) { + SendError(Engine(), L, "`HttpsPOST` expects port (type number) as 2. argument."); + ClearStack(L); + return 0; + } + if (!lua_isstring(L, 3)) { + SendError(Engine(), L, "`HttpsPOST` expects target (type string) as 3. argument."); + ClearStack(L); + return 0; + } + if (!lua_isstring(L, 4)) { + SendError(Engine(), L, "`HttpsPOST` expects body (type string) as 4. argument."); + ClearStack(L); + return 0; + } + if (!lua_isstring(L, 5)) { + SendError(Engine(), L, "`HttpsPOST` expects content_type (type string) as 5. argument."); + ClearStack(L); + return 0; + } + + auto Host = lua_tostring(L, 1); + auto Port = int(lua_tointeger(L, 2)); + auto Target = lua_tostring(L, 3); + auto RequestBody = lua_tostring(L, 4); + auto ContentType = lua_tostring(L, 5); + + ClearStack(L); + + // build fields + std::unordered_map Fields; + + unsigned int Status; + auto ResponseBody = Http::POST(Host, Port, Target, {}, RequestBody, ContentType, &Status); + + lua_pushinteger(L, Status); + + auto PrettyRemote = "https://" + std::string(Host) + ":" + std::to_string(Port) + std::string(Target); + if (ResponseBody == Http::ErrorString) { + SendError(Engine(), L, "HTTPS POST " + PrettyRemote + " failed status " + std::to_string(Status) + ". Check the console or log for more info."); + return 1; + } else { + debug("POST " + PrettyRemote + " completed status " + std::to_string(Status)); + } + + lua_pushstring(L, ResponseBody.c_str()); + return 2; +} + void TLuaFile::Load() { Assert(mLuaState); luaL_openlibs(mLuaState); @@ -826,6 +926,8 @@ void TLuaFile::Load() { LuaTable::InsertFunction(mLuaState, "Sleep", lua_Sleep); LuaTable::InsertFunction(mLuaState, "Set", lua_Set); LuaTable::InsertFunction(mLuaState, "GetOSName", lua_GetOSName); + LuaTable::InsertFunction(mLuaState, "HttpsGET", lua_HttpsGET); + LuaTable::InsertFunction(mLuaState, "HttpsPOST", lua_HttpsPOST); LuaTable::End(mLuaState, "MP"); lua_register(mLuaState, "print", lua_Print); @@ -901,7 +1003,7 @@ void SendError(TLuaEngine& Engine, lua_State* L, const std::string& msg) { TLuaFile& S = MaybeS.value(); a = fs::path(S.GetFileName()).filename().string(); } - warn(a + (" | Incorrect Call of ") + msg); + warn(a + (" | Error in MP Lua call: ") + msg); } void TLuaArg::PushArgs(lua_State* State) { diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index f8722fc..3f6511f 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -290,7 +290,7 @@ void TNetwork::Authentication(SOCKET TCPSock) { json::Document AuthResponse; AuthResponse.Parse(Rc.c_str()); - if (Rc == "-1" || AuthResponse.HasParseError()) { + if (Rc == Http::ErrorString || AuthResponse.HasParseError()) { ClientKick(*Client, "Invalid key! Please restart your game."); return; } From 53617abae42ced4d5fbdf2161ec5a48a42930255 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 1 Jul 2021 00:44:53 +0200 Subject: [PATCH 044/255] Add printRaw Same as print() but does not prefix with time, date, filename, etc. Use with care. --- src/TLuaFile.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/TLuaFile.cpp b/src/TLuaFile.cpp index 403a671..1f2f233 100644 --- a/src/TLuaFile.cpp +++ b/src/TLuaFile.cpp @@ -614,7 +614,7 @@ int lua_Set(lua_State* L) { } extern "C" { -int lua_Print(lua_State* L) { +int InternalLuaPrint(lua_State* L, bool pretty) { int Arg = lua_gettop(L); std::string to_print; for (int i = 1; i <= Arg; i++) { @@ -647,9 +647,19 @@ int lua_Print(lua_State* L) { to_print += "\t"; } } - luaprint(to_print); + if (pretty) { + luaprint(to_print); + } else { + Application::Console().WriteRaw(to_print); + } return 0; } +int lua_Print(lua_State* L) { + return InternalLuaPrint(L, true); +} +int lua_PrintRaw(lua_State* L) { + return InternalLuaPrint(L, false); +} } int lua_TempFix(lua_State* L) { @@ -931,6 +941,7 @@ void TLuaFile::Load() { LuaTable::End(mLuaState, "MP"); lua_register(mLuaState, "print", lua_Print); + lua_register(mLuaState, "printRaw", lua_PrintRaw); lua_register(mLuaState, "exit", lua_ServerExit); if (!mConsole) Reload(); From a0a7b8ecce844b30a22f6f894646c67a3d2f5696 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 2 Jul 2021 00:01:38 +0200 Subject: [PATCH 045/255] fix comment --- src/TLuaFile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TLuaFile.cpp b/src/TLuaFile.cpp index 1f2f233..a93b2ee 100644 --- a/src/TLuaFile.cpp +++ b/src/TLuaFile.cpp @@ -809,7 +809,7 @@ int lua_GetOSName(lua_State* L) { return 1; } -// status, body = HttpGET(host, port, target) +// status, body = HttpsGET(host, port, target) // example usage: // send a GET https://example.com:443/index.html: // status, body = MP.HttpGET("example.com", 443, "/index.html") From 95188042c58429ffa0d3c610b0e758b6b381e0da Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sat, 3 Jul 2021 00:58:19 +0200 Subject: [PATCH 046/255] fix luatable in GetPlayerIdentifiers --- src/TLuaFile.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/TLuaFile.cpp b/src/TLuaFile.cpp index a93b2ee..4b5b547 100644 --- a/src/TLuaFile.cpp +++ b/src/TLuaFile.cpp @@ -375,12 +375,13 @@ int lua_GetIdentifiers(lua_State* L) { auto IDs = MaybeClient.value().lock()->GetIdentifiers(); if (IDs.empty()) return 0; - lua_newtable(L); + LuaTable::Begin(L); for (const std::string& ID : IDs) { - lua_pushstring(L, ID.substr(0, ID.find(':')).c_str()); + LuaTable::BeginEntry(L, ID.substr(0, ID.find(':')).c_str()); lua_pushstring(L, ID.c_str()); - lua_settable(L, -3); + LuaTable::EndEntry(L); } + // LuaTable::End(L, ""); } else return 0; } else { From 9423831937117c1ca16f2345036793929a237ca2 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sat, 3 Jul 2021 01:43:29 +0200 Subject: [PATCH 047/255] add ip to identifiers, changed value format --- include/Client.h | 12 +++++++++--- include/TNetwork.h | 6 ++++-- src/TLuaFile.cpp | 7 +++---- src/TNetwork.cpp | 34 +++++++++++++++++++--------------- 4 files changed, 35 insertions(+), 24 deletions(-) diff --git a/include/Client.h b/include/Client.h index 385d2ec..8ac7035 100644 --- a/include/Client.h +++ b/include/Client.h @@ -12,6 +12,12 @@ class TServer; +struct TConnection final { + SOCKET Socket; + struct sockaddr SockAddr; + socklen_t SockAddrLen; +}; + class TClient final { public: using TSetOfVehicleData = std::vector; @@ -30,7 +36,7 @@ public: TVehicleDataLockPair GetAllCars(); void SetName(const std::string& Name) { mName = Name; } void SetRoles(const std::string& Role) { mRole = Role; } - void AddIdentifier(const std::string& ID) { mIdentifiers.insert(ID); }; + void SetIdentifier(const std::string& key, const std::string& value) { mIdentifiers[key] = value; } std::string GetCarData(int Ident); void SetUDPAddr(sockaddr_in Addr) { mUDPAddress = Addr; } void SetDownSock(SOCKET CSock) { mSocket[1] = CSock; } @@ -38,7 +44,7 @@ public: void SetStatus(int Status) { mStatus = Status; } // locks void DeleteCar(int Ident); - [[nodiscard]] std::set GetIdentifiers() const { return mIdentifiers; } + [[nodiscard]] const std::unordered_map& GetIdentifiers() const { return mIdentifiers; } [[nodiscard]] sockaddr_in GetUDPAddr() const { return mUDPAddress; } [[nodiscard]] SOCKET GetDownSock() const { return mSocket[1]; } [[nodiscard]] SOCKET GetTCPSock() const { return mSocket[0]; } @@ -78,7 +84,7 @@ private: bool mIsSyncing = false; mutable std::mutex mMissedPacketsMutex; std::queue mPacketsSync; - std::set mIdentifiers; + std::unordered_map mIdentifiers; bool mIsGuest = false; std::mutex mVehicleDataMutex; TSetOfVehicleData mVehicleData; diff --git a/include/TNetwork.h b/include/TNetwork.h index a4d28c5..528aef4 100644 --- a/include/TNetwork.h +++ b/include/TNetwork.h @@ -4,6 +4,8 @@ #include "TResourceManager.h" #include "TServer.h" +struct TConnection; + class TNetwork { public: TNetwork(TServer& Server, TPPSMonitor& PPSMonitor, TResourceManager& ResourceManager); @@ -15,8 +17,8 @@ public: std::string TCPRcv(TClient& c); void ClientKick(TClient& c, const std::string& R); [[nodiscard]] bool SyncClient(const std::weak_ptr& c); - void Identify(SOCKET TCPSock); - void Authentication(SOCKET TCPSock); + void Identify(const TConnection& client); + void Authentication(const TConnection& ClientConnection); [[nodiscard]] bool CheckBytes(TClient& c, int32_t BytesRcv); void SyncResources(TClient& c); [[nodiscard]] bool UDPSend(TClient& Client, std::string Data) const; diff --git a/src/TLuaFile.cpp b/src/TLuaFile.cpp index 4b5b547..b16b9de 100644 --- a/src/TLuaFile.cpp +++ b/src/TLuaFile.cpp @@ -376,12 +376,11 @@ int lua_GetIdentifiers(lua_State* L) { if (IDs.empty()) return 0; LuaTable::Begin(L); - for (const std::string& ID : IDs) { - LuaTable::BeginEntry(L, ID.substr(0, ID.find(':')).c_str()); - lua_pushstring(L, ID.c_str()); + for (const auto& Pair : IDs) { + LuaTable::BeginEntry(L, Pair.first); + lua_pushstring(L, Pair.second.c_str()); LuaTable::EndEntry(L); } - // LuaTable::End(L, ""); } else return 0; } else { diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index 3f6511f..0935e7b 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -163,7 +163,7 @@ void TNetwork::TCPServerMain() { #else // unix // wondering why we need slightly different implementations of this? // ask ms. - SOCKET client = -1; + TConnection client {}; SOCKET Listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); int optval = 1; setsockopt(Listener, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval)); @@ -193,8 +193,9 @@ void TNetwork::TCPServerMain() { debug("shutdown during TCP wait for accept loop"); break; } - client = accept(Listener, nullptr, nullptr); - if (client == -1) { + client.SockAddrLen = sizeof(client.SockAddr); + client.Socket = accept(Listener, &client.SockAddr, &client.SockAddrLen); + if (client.Socket == -1) { warn(("Got an invalid client socket on connect! Skipping...")); continue; } @@ -203,11 +204,11 @@ void TNetwork::TCPServerMain() { } catch (const std::exception& e) { error(("fatal: ") + std::string(e.what())); } - } while (client); + } while (client.Socket); debug("all ok, arrived at " + std::string(__func__) + ":" + std::to_string(__LINE__)); - CloseSocketProper(client); + CloseSocketProper(client.Socket); #endif } @@ -216,19 +217,19 @@ void TNetwork::TCPServerMain() { #include "Json.h" namespace json = rapidjson; -void TNetwork::Identify(SOCKET TCPSock) { +void TNetwork::Identify(const TConnection& client) { RegisterThreadAuto(); char Code; - if (recv(TCPSock, &Code, 1, 0) != 1) { - CloseSocketProper(TCPSock); + if (recv(client.Socket, &Code, 1, 0) != 1) { + CloseSocketProper(client.Socket); return; } if (Code == 'C') { - Authentication(TCPSock); + Authentication(client); } else if (Code == 'D') { - HandleDownload(TCPSock); + HandleDownload(client.Socket); } else { - CloseSocketProper(TCPSock); + CloseSocketProper(client.Socket); } } @@ -251,11 +252,12 @@ void TNetwork::HandleDownload(SOCKET TCPSock) { }); } -void TNetwork::Authentication(SOCKET TCPSock) { - auto Client = CreateClient(TCPSock); +void TNetwork::Authentication(const TConnection& ClientConnection) { + auto Client = CreateClient(ClientConnection.Socket); + Client->SetIdentifier("ip", inet_ntoa(reinterpret_cast(&ClientConnection.SockAddr)->sin_addr)); std::string Rc; - info("Identifying new client..."); + info("Identifying new ClientConnection..."); Rc = TCPRcv(*Client); @@ -323,7 +325,9 @@ void TNetwork::Authentication(SOCKET TCPSock) { Client->SetRoles(AuthResponse["roles"].GetString()); Client->SetIsGuest(AuthResponse["guest"].GetBool()); for (const auto& ID : AuthResponse["identifiers"].GetArray()) { - Client->AddIdentifier(ID.GetString()); + auto Raw = std::string(ID.GetString()); + auto SepIndex = Raw.find(':'); + Client->SetIdentifier(Raw.substr(0, SepIndex), Raw.substr(SepIndex + 1)); } } else { ClientKick(*Client, "Invalid authentication data!"); From 943159cd40902a657671770f07d9136e695ef1bf Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sun, 11 Jul 2021 20:34:18 +0200 Subject: [PATCH 048/255] Lua: add onShutdown --- src/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main.cpp b/src/main.cpp index 5e0aeaa..fd324be 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -55,6 +55,7 @@ int main(int argc, char** argv) try { bool Shutdown = false; Application::RegisterShutdownHandler([&Shutdown] { Shutdown = true; }); + Application::RegisterShutdownHandler([] { TriggerLuaEvent("onShutdown", false, nullptr, {}, true); }); TServer Server(argc, argv); TConfig Config; From e3b6fd7998de1a0fb70a9c4862f8e01b887af630 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sun, 11 Jul 2021 20:41:23 +0200 Subject: [PATCH 049/255] use fake version for lua update for now --- include/Common.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/Common.h b/include/Common.h index 6b6466a..c95bd2d 100644 --- a/include/Common.h +++ b/include/Common.h @@ -55,6 +55,7 @@ public: static void GracefullyShutdown(); static TConsole& Console() { return *mConsole; } static std::string ServerVersion() { return "2.3.1"; } +#warning "change version from 2.2.0 to real version" static std::string ClientVersion() { return "2.0"; } static std::string PPS() { return mPPS; } static void SetPPS(const std::string& NewPPS) { mPPS = NewPPS; } From ba3fd0e1446ee5ba0efc7fa2c6bdf53435e1a518 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 15 Jul 2021 00:04:44 +0200 Subject: [PATCH 050/255] add GetServerVersion --- include/Common.h | 19 +++++++++++++++---- src/Common.cpp | 13 +++++++++++-- src/THeartbeatThread.cpp | 4 ++-- src/TLuaFile.cpp | 9 +++++++++ src/TNetwork.cpp | 2 +- src/TServer.cpp | 2 +- 6 files changed, 39 insertions(+), 10 deletions(-) diff --git a/include/Common.h b/include/Common.h index c95bd2d..f832b1b 100644 --- a/include/Common.h +++ b/include/Common.h @@ -12,6 +12,14 @@ extern TSentry Sentry; #include "TConsole.h" +struct Version { + uint8_t major; + uint8_t minor; + uint8_t patch; + Version(uint8_t major, uint8_t minor, uint8_t patch); + std::string AsString(); +}; + // static class handling application start, shutdown, etc. // yes, static classes, singletons, globals are all pretty // bad idioms. In this case we need a central way to access @@ -44,6 +52,7 @@ public: std::string CustomIP; [[nodiscard]] bool HasCustomIP() const { return !CustomIP.empty(); } }; + using TShutdownHandler = std::function; // methods @@ -54,9 +63,9 @@ public: // Causes all threads to finish up and exit gracefull gracefully static void GracefullyShutdown(); static TConsole& Console() { return *mConsole; } - static std::string ServerVersion() { return "2.3.1"; } -#warning "change version from 2.2.0 to real version" - static std::string ClientVersion() { return "2.0"; } + static std::string ServerVersionString(); + static const Version& ServerVersion() { return mVersion; } + static std::string ClientVersionString() { return "2.0"; } static std::string PPS() { return mPPS; } static void SetPPS(const std::string& NewPPS) { mPPS = NewPPS; } @@ -76,6 +85,8 @@ private: static std::unique_ptr mConsole; static inline std::mutex mShutdownHandlersMutex {}; static inline std::deque mShutdownHandlers {}; + + static inline Version mVersion { 2, 2, 0 }; }; std::string ThreadName(bool DebugModeOverride = false); @@ -146,4 +157,4 @@ void LogChatMessage(const std::string& name, int id, const std::string& msg); #define Biggest 30000 std::string Comp(std::string Data); -std::string DeComp(std::string Compressed); +std::string DeComp(std::string Compressed); \ No newline at end of file diff --git a/src/Common.cpp b/src/Common.cpp index 3fe52bf..0e52b2c 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -144,6 +144,15 @@ void RegisterThread(const std::string& str) { threadNameMap[std::this_thread::get_id()] = str; } +Version::Version(uint8_t major, uint8_t minor, uint8_t patch) + : major(major) + , minor(minor) + , patch(patch) { } + +std::string Version::AsString() { + std::stringstream ss {}; + ss << major << "." << minor << "." << patch; + return ss.str(); void LogChatMessage(const std::string& name, int id, const std::string& msg) { std::stringstream ss; ss << "[CHAT] "; @@ -153,5 +162,5 @@ void LogChatMessage(const std::string& name, int id, const std::string& msg) { ss << name << ""; } ss << msg; - Application::Console().Write(ss.str()); -} + +} \ No newline at end of file diff --git a/src/THeartbeatThread.cpp b/src/THeartbeatThread.cpp index 6a72004..826e0b1 100644 --- a/src/THeartbeatThread.cpp +++ b/src/THeartbeatThread.cpp @@ -95,8 +95,8 @@ std::string THeartbeatThread::GenerateCall() { << "&port=" << Application::Settings.Port << "&map=" << Application::Settings.MapName << "&private=" << (Application::Settings.Private ? "true" : "false") - << "&version=" << Application::ServerVersion() - << "&clientversion=" << Application::ClientVersion() + << "&version=" << Application::ServerVersionString() + << "&clientversion=" << Application::ClientVersionString() << "&name=" << Application::Settings.ServerName << "&modlist=" << mResourceManager.TrimmedList() << "&modstotalsize=" << mResourceManager.MaxModSize() diff --git a/src/TLuaFile.cpp b/src/TLuaFile.cpp index b16b9de..4de5d47 100644 --- a/src/TLuaFile.cpp +++ b/src/TLuaFile.cpp @@ -809,6 +809,14 @@ int lua_GetOSName(lua_State* L) { return 1; } +int lua_GetServerVersion(lua_State* L) { + const auto& ver = Application::ServerVersion(); + lua_pushinteger(L, ver.major); + lua_pushinteger(L, ver.minor); + lua_pushinteger(L, ver.patch); + return 3; +} + // status, body = HttpsGET(host, port, target) // example usage: // send a GET https://example.com:443/index.html: @@ -938,6 +946,7 @@ void TLuaFile::Load() { LuaTable::InsertFunction(mLuaState, "GetOSName", lua_GetOSName); LuaTable::InsertFunction(mLuaState, "HttpsGET", lua_HttpsGET); LuaTable::InsertFunction(mLuaState, "HttpsPOST", lua_HttpsPOST); + LuaTable::InsertFunction(mLuaState, "GetServerVersion", lua_GetServerVersion); LuaTable::End(mLuaState, "MP"); lua_register(mLuaState, "print", lua_Print); diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index 0935e7b..30c8ad6 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -263,7 +263,7 @@ void TNetwork::Authentication(const TConnection& ClientConnection) { if (Rc.size() > 3 && Rc.substr(0, 2) == "VC") { Rc = Rc.substr(2); - if (Rc.length() > 4 || Rc != Application::ClientVersion()) { + if (Rc.length() > 4 || Rc != Application::ClientVersionString()) { ClientKick(*Client, "Outdated Version!"); return; } diff --git a/src/TServer.cpp b/src/TServer.cpp index 9c294a1..2bb8fc5 100644 --- a/src/TServer.cpp +++ b/src/TServer.cpp @@ -14,7 +14,7 @@ namespace json = rapidjson; TServer::TServer(int argc, char** argv) { - info("BeamMP Server v" + Application::ServerVersion()); + info("BeamMP Server v" + Application::ServerVersionString()); if (argc > 1) { Application::Settings.CustomIP = argv[1]; size_t n = std::count(Application::Settings.CustomIP.begin(), Application::Settings.CustomIP.end(), '.'); From c6457f7df47100714df3a52e2f7bec574282c77f Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 15 Jul 2021 01:49:30 +0200 Subject: [PATCH 051/255] Add Settings enum, better print --- include/THeartbeatThread.h | 2 +- src/TLuaFile.cpp | 35 +++++++++++++++++++++++++++-------- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/include/THeartbeatThread.h b/include/THeartbeatThread.h index 1442e08..1f0ab14 100644 --- a/include/THeartbeatThread.h +++ b/include/THeartbeatThread.h @@ -18,4 +18,4 @@ private: bool mShutdown = false; TResourceManager& mResourceManager; TServer& mServer; -}; \ No newline at end of file +}; diff --git a/src/TLuaFile.cpp b/src/TLuaFile.cpp index 4de5d47..4e7e39d 100644 --- a/src/TLuaFile.cpp +++ b/src/TLuaFile.cpp @@ -34,6 +34,12 @@ void InsertFunction(lua_State* L, const std::string& name, lua_CFunction func) { EndEntry(L); } +void InsertInteger(lua_State* L, const std::string& name, lua_Integer i) { + BeginEntry(L, name); + lua_pushinteger(L, i); + EndEntry(L); +} + } void SendError(TLuaEngine& Engine, lua_State* L, const std::string& msg); @@ -559,49 +565,49 @@ int lua_Set(lua_State* L) { case 0: //debug if (lua_isboolean(L, 2)) { Application::Settings.DebugModeEnabled = lua_toboolean(L, 2); - info(Name + (" | Debug -> ") + (Application::Settings.DebugModeEnabled ? "true" : "false")); + info(Name + (" | Set `Debug` to ") + (Application::Settings.DebugModeEnabled ? "true" : "false")); } else SendError(Engine(), L, ("set invalid argument [2] expected boolean for ID : 0")); break; case 1: //private if (lua_isboolean(L, 2)) { Application::Settings.Private = lua_toboolean(L, 2); - info(Name + (" | Private -> ") + (Application::Settings.Private ? "true" : "false")); + info(Name + (" | Set `Private` to ") + (Application::Settings.Private ? "true" : "false")); } else SendError(Engine(), L, ("set invalid argument [2] expected boolean for ID : 1")); break; case 2: //max cars if (lua_isnumber(L, 2)) { Application::Settings.MaxCars = int(lua_tointeger(L, 2)); - info(Name + (" | MaxCars -> ") + std::to_string(Application::Settings.MaxCars)); + info(Name + (" | Set `MaxCars` to ") + std::to_string(Application::Settings.MaxCars)); } else SendError(Engine(), L, ("set invalid argument [2] expected number for ID : 2")); break; case 3: //max players if (lua_isnumber(L, 2)) { Application::Settings.MaxPlayers = int(lua_tointeger(L, 2)); - info(Name + (" | MaxPlayers -> ") + std::to_string(Application::Settings.MaxPlayers)); + info(Name + (" | Set `MaxPlayers` to ") + std::to_string(Application::Settings.MaxPlayers)); } else SendError(Engine(), L, ("set invalid argument [2] expected number for ID : 3")); break; case 4: //Map if (lua_isstring(L, 2)) { Application::Settings.MapName = lua_tostring(L, 2); - info(Name + (" | MapName -> ") + Application::Settings.MapName); + info(Name + (" | Set `Map` to ") + Application::Settings.MapName); } else SendError(Engine(), L, ("set invalid argument [2] expected string for ID : 4")); break; case 5: //Name if (lua_isstring(L, 2)) { Application::Settings.ServerName = lua_tostring(L, 2); - info(Name + (" | ServerName -> ") + Application::Settings.ServerName); + info(Name + (" | Set `Name` to ") + Application::Settings.ServerName); } else SendError(Engine(), L, ("set invalid argument [2] expected string for ID : 5")); break; case 6: //Desc if (lua_isstring(L, 2)) { Application::Settings.ServerDesc = lua_tostring(L, 2); - info(Name + (" | ServerDesc -> ") + Application::Settings.ServerDesc); + info(Name + (" | Set `Description` to ") + Application::Settings.ServerDesc); } else SendError(Engine(), L, ("set invalid argument [2] expected string for ID : 6")); break; @@ -609,7 +615,6 @@ int lua_Set(lua_State* L) { warn(("Invalid config ID : ") + std::to_string(C)); break; } - return 0; } @@ -922,6 +927,19 @@ void TLuaFile::Load() { luaL_openlibs(mLuaState); LuaTable::Begin(mLuaState); + + LuaTable::BeginEntry(mLuaState, "Settings"); + LuaTable::Begin(mLuaState); + // put Settings enums here + LuaTable::InsertInteger(mLuaState, "Debug", 0); + LuaTable::InsertInteger(mLuaState, "Private", 1); + LuaTable::InsertInteger(mLuaState, "MaxCars", 2); + LuaTable::InsertInteger(mLuaState, "MaxPlayers", 3); + LuaTable::InsertInteger(mLuaState, "Map", 4); + LuaTable::InsertInteger(mLuaState, "Name", 5); + LuaTable::InsertInteger(mLuaState, "Description", 6); + LuaTable::EndEntry(mLuaState); + LuaTable::InsertFunction(mLuaState, "GetPlayerIdentifiers", lua_GetIdentifiers); LuaTable::InsertFunction(mLuaState, "TriggerGlobalEvent", lua_TriggerEventG); LuaTable::InsertFunction(mLuaState, "TriggerLocalEvent", lua_TriggerEventL); @@ -947,6 +965,7 @@ void TLuaFile::Load() { LuaTable::InsertFunction(mLuaState, "HttpsGET", lua_HttpsGET); LuaTable::InsertFunction(mLuaState, "HttpsPOST", lua_HttpsPOST); LuaTable::InsertFunction(mLuaState, "GetServerVersion", lua_GetServerVersion); + LuaTable::End(mLuaState, "MP"); lua_register(mLuaState, "print", lua_Print); From 88684bd9aff4e4dfd673b24744e442d4f677790f Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 15 Jul 2021 02:23:53 +0200 Subject: [PATCH 052/255] clarify installation --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index c69efcd..8b02566 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,12 @@ These package names are in the debian / ubuntu style. Feel free to PR your own g **If** you're building it from source, you'll need `libboost1.70-all-dev` or `libboost1.71-all-dev` or higher as well. If you can't find this version of boost (only 1.6x, for example), you can either update to a newer version of your distro, build boost yourself, or use an unstable rolling release (like Debian `sid` aka `unstable`). +In the end you should end up with a command something like this: + +```sh +sudo apt install git make cmake g++-10 liblua5.3 libz-dev rapidjson-dev libopenssl-dev libboost1.71-all-dev +``` + ### How to build On windows, use git-bash for these commands. On Linux, these should work in your shell. From 42c5aaad5a18d1564d616eac5379011a4340a1f0 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 15 Jul 2021 16:34:44 +0200 Subject: [PATCH 053/255] use inet_ntop instead of inet_ntoa (STILL BROKEN THOUGH) --- src/TNetwork.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index 30c8ad6..2e0064f 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -254,7 +254,10 @@ void TNetwork::HandleDownload(SOCKET TCPSock) { void TNetwork::Authentication(const TConnection& ClientConnection) { auto Client = CreateClient(ClientConnection.Socket); - Client->SetIdentifier("ip", inet_ntoa(reinterpret_cast(&ClientConnection.SockAddr)->sin_addr)); + char AddrBuf[30]; + inet_ntoa(reinterpret_cast(&ClientConnection.SockAddr)->sin_addr); + auto str = inet_ntop(AF_INET, static_cast(reinterpret_cast(&ClientConnection.SockAddr)), AddrBuf, sizeof(struct sockaddr_in)); + Client->SetIdentifier("ip", str); std::string Rc; info("Identifying new ClientConnection..."); From a7f2f85e45f44ac496d02f70ab651a8431831ec6 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Wed, 21 Jul 2021 01:59:36 +0200 Subject: [PATCH 054/255] fix version printing --- src/Common.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Common.cpp b/src/Common.cpp index 0e52b2c..da16d9b 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -151,7 +151,7 @@ Version::Version(uint8_t major, uint8_t minor, uint8_t patch) std::string Version::AsString() { std::stringstream ss {}; - ss << major << "." << minor << "." << patch; + ss << int(major) << "." << int(minor) << "." << int(patch); return ss.str(); void LogChatMessage(const std::string& name, int id, const std::string& msg) { std::stringstream ss; From 95c036836e174f5aadfeca00df9d17ab0242b41e Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 29 Jul 2021 12:02:49 +0200 Subject: [PATCH 055/255] add ws2tcpip.h --- include/Compat.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/Compat.h b/include/Compat.h index 89d625c..e8052d9 100644 --- a/include/Compat.h +++ b/include/Compat.h @@ -26,6 +26,7 @@ inline void CloseSocketProper(int TheSocket) { inline void CloseSocketProper(SOCKET TheSocket) { shutdown(TheSocket, 2); // 2 == SD_BOTH closesocket(TheSocket); + } #endif // WIN32 @@ -33,4 +34,4 @@ inline void CloseSocketProper(SOCKET TheSocket) { #if !defined(WIN32) && !defined(__unix) #error "OS not supported" -#endif +#endif \ No newline at end of file From 2af9491fd61a3d738e24a4381d6848f35f35f45f Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 29 Jul 2021 12:04:11 +0200 Subject: [PATCH 056/255] add luasocket submodule --- lib/luasocket | 1 + 1 file changed, 1 insertion(+) create mode 160000 lib/luasocket diff --git a/lib/luasocket b/lib/luasocket new file mode 160000 index 0000000..5b18e47 --- /dev/null +++ b/lib/luasocket @@ -0,0 +1 @@ +Subproject commit 5b18e475f38fcf28429b1cc4b17baee3b9793a62 From 51d6c4fb0aa532efdd066dccc45d9a31dbb4104e Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 29 Jul 2021 12:04:38 +0200 Subject: [PATCH 057/255] add CMakeLists for lib/ --- lib/CMakeLists.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 lib/CMakeLists.txt diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt new file mode 100644 index 0000000..e69de29 From aca3c52c20b09ab4a2d744b0a30a0770b68215b7 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 29 Jul 2021 12:11:43 +0200 Subject: [PATCH 058/255] remove luasocket again --- CMakeLists.txt | 3 +++ lib/CMakeLists.txt | 5 +++++ lib/luasocket | 1 - 3 files changed, 8 insertions(+), 1 deletion(-) delete mode 160000 lib/luasocket diff --git a/CMakeLists.txt b/CMakeLists.txt index cd6a6ec..87f888b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,7 @@ cmake_minimum_required(VERSION 3.0) + message(STATUS "You can find build instructions and a list of dependencies in the README at \ https://github.com/BeamMP/BeamMP-Server") @@ -60,6 +61,8 @@ include_directories("rapidjson/include") include_directories("websocketpp") add_subdirectory("socket.io-client-cpp") add_subdirectory("include/commandline") +# builds all libraries that don't have cmakelists +add_subdirectory("lib") set(CMAKE_CXX_STANDARD 17) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index e69de29..ab2d18a 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -0,0 +1,5 @@ + + +############# luasocket ############# + +##################################### \ No newline at end of file diff --git a/lib/luasocket b/lib/luasocket deleted file mode 160000 index 5b18e47..0000000 --- a/lib/luasocket +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 5b18e475f38fcf28429b1cc4b17baee3b9793a62 From 4c23b78f8469d35304c78f7a26c03c3cc1b28332 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 29 Jul 2021 12:18:01 +0200 Subject: [PATCH 059/255] add luasocket --- CMakeLists.txt | 6 ++++-- lib/CMakeLists.txt | 5 ----- lib/luasocket-cmake | 1 + 3 files changed, 5 insertions(+), 7 deletions(-) delete mode 100644 lib/CMakeLists.txt create mode 160000 lib/luasocket-cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 87f888b..8449263 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.0) + message(STATUS "You can find build instructions and a list of dependencies in the README at \ https://github.com/BeamMP/BeamMP-Server") @@ -61,8 +62,9 @@ include_directories("rapidjson/include") include_directories("websocketpp") add_subdirectory("socket.io-client-cpp") add_subdirectory("include/commandline") -# builds all libraries that don't have cmakelists -add_subdirectory("lib") +# luasocket +set(WANTS_BUILD_STATIC_LIBRARY ON) +add_subdirectory("lib/luasocket-cmake") set(CMAKE_CXX_STANDARD 17) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt deleted file mode 100644 index ab2d18a..0000000 --- a/lib/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ - - -############# luasocket ############# - -##################################### \ No newline at end of file diff --git a/lib/luasocket-cmake b/lib/luasocket-cmake new file mode 160000 index 0000000..2cb3208 --- /dev/null +++ b/lib/luasocket-cmake @@ -0,0 +1 @@ +Subproject commit 2cb3208cf32d8349c04af2884e50db008ff27ef8 From ff80b4cf63d2a80eb4ab0dfc76f0f47bb61460af Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 29 Jul 2021 12:21:29 +0200 Subject: [PATCH 060/255] CMake: include luasocket after finding lua --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8449263..54c2bb8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 3.0) + message(STATUS "You can find build instructions and a list of dependencies in the README at \ https://github.com/BeamMP/BeamMP-Server") @@ -62,9 +63,8 @@ include_directories("rapidjson/include") include_directories("websocketpp") add_subdirectory("socket.io-client-cpp") add_subdirectory("include/commandline") -# luasocket -set(WANTS_BUILD_STATIC_LIBRARY ON) -add_subdirectory("lib/luasocket-cmake") + + set(CMAKE_CXX_STANDARD 17) From b49782e8a343b0a2719072f9be64285ea34e876f Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 2 Aug 2021 13:28:41 +0200 Subject: [PATCH 061/255] Common: Add sstream include for std::stringstream --- include/Common.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/Common.h b/include/Common.h index f832b1b..e7b534b 100644 --- a/include/Common.h +++ b/include/Common.h @@ -9,6 +9,7 @@ extern TSentry Sentry; #include #include #include +#include #include "TConsole.h" From de576133266816b89be1fe2fc0d146b601a0aaf1 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 2 Aug 2021 13:31:49 +0200 Subject: [PATCH 062/255] remove luasocket-cmake --- lib/luasocket-cmake | 1 - 1 file changed, 1 deletion(-) delete mode 160000 lib/luasocket-cmake diff --git a/lib/luasocket-cmake b/lib/luasocket-cmake deleted file mode 160000 index 2cb3208..0000000 --- a/lib/luasocket-cmake +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 2cb3208cf32d8349c04af2884e50db008ff27ef8 From fdb5da2ed686526c3dcff5bfb404b0a6dcfb8fcb Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 2 Aug 2021 13:32:14 +0200 Subject: [PATCH 063/255] CMake: remove mentions of luasocket again --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 54c2bb8..b4aa0e3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,7 @@ cmake_minimum_required(VERSION 3.0) + message(STATUS "You can find build instructions and a list of dependencies in the README at \ https://github.com/BeamMP/BeamMP-Server") @@ -109,6 +110,8 @@ target_include_directories(BeamMP-Server PUBLIC "include/curl/include") message(STATUS "Looking for SSL") + + find_package(OpenSSL REQUIRED) message(STATUS "CURL IS ${CURL_LIBRARIES}") From 1e2f06010735bedabd99e7def50a65ba62cad372 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 2 Aug 2021 13:54:36 +0200 Subject: [PATCH 064/255] improve error reporting, remove duplicate code --- include/Common.h | 7 +++- include/Compat.h | 1 + src/Common.cpp | 27 ++++++++++++ src/TNetwork.cpp | 105 ++++++++--------------------------------------- 4 files changed, 50 insertions(+), 90 deletions(-) diff --git a/include/Common.h b/include/Common.h index e7b534b..380af42 100644 --- a/include/Common.h +++ b/include/Common.h @@ -5,12 +5,15 @@ extern TSentry Sentry; #include #include +#include #include #include #include #include #include +#include "Compat.h" + #include "TConsole.h" struct Version { @@ -158,4 +161,6 @@ void LogChatMessage(const std::string& name, int id, const std::string& msg); #define Biggest 30000 std::string Comp(std::string Data); -std::string DeComp(std::string Compressed); \ No newline at end of file +std::string DeComp(std::string Compressed); + +std::string GetPlatformAgnosticErrorString(); \ No newline at end of file diff --git a/include/Compat.h b/include/Compat.h index e8052d9..8c1b662 100644 --- a/include/Compat.h +++ b/include/Compat.h @@ -7,6 +7,7 @@ #include #include #include +#include using SOCKET = int; using DWORD = unsigned long; using PDWORD = unsigned long*; diff --git a/src/Common.cpp b/src/Common.cpp index da16d9b..385d6a7 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -163,4 +163,31 @@ void LogChatMessage(const std::string& name, int id, const std::string& msg) { } ss << msg; +} + +std::string GetPlatformAgnosticErrorString() { +#ifdef WIN32 + // This will provide us with the error code and an error message, all in one. + int err; + char msgbuf[256]; + msgbuf[0] = '\0'; + + err = GetLastError(); + + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, + err, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + msgbuf, + sizeof(msgbuf), + nullptr); + + if (*msgbuf) { + return std::to_string(GetLastError()) + " - " + std::string(msgbuf); + } else { + return std::to_string(GetLastError()) + } +#else // posix + return std::strerror(errno); +#endif } \ No newline at end of file diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index 2e0064f..638e7de 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -46,22 +46,7 @@ void TNetwork::UDPServerMain() { error(("Can't start Winsock!")); //return; } - - mUDPSock = socket(AF_INET, SOCK_DGRAM, 0); - // Create a server hint structure for the server - sockaddr_in serverAddr {}; - serverAddr.sin_addr.S_un.S_addr = ADDR_ANY; //Any Local - serverAddr.sin_family = AF_INET; // Address format is IPv4 - serverAddr.sin_port = htons(Application::Settings.Port); // Convert from little to big endian - - // Try and bind the socket to the IP and port - if (bind(mUDPSock, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) { - error(("Can't bind socket!") + std::to_string(WSAGetLastError())); - std::this_thread::sleep_for(std::chrono::seconds(5)); - exit(-1); - //return; - } -#else // unix +#endif // WIN32 mUDPSock = socket(AF_INET, SOCK_DGRAM, 0); // Create a server hint structure for the server sockaddr_in serverAddr {}; @@ -71,12 +56,12 @@ void TNetwork::UDPServerMain() { // Try and bind the socket to the IP and port if (bind(mUDPSock, (sockaddr*)&serverAddr, sizeof(serverAddr)) != 0) { - error(("Can't bind socket!") + std::string(strerror(errno))); + error("bind() failed: " + GetPlatformAgnosticErrorString()); std::this_thread::sleep_for(std::chrono::seconds(5)); exit(-1); //return; } -#endif + info(("Vehicle data network online on port ") + std::to_string(Application::Settings.Port) + (" with a Max of ") + std::to_string(Application::Settings.MaxPlayers) + (" Clients")); @@ -123,46 +108,7 @@ void TNetwork::TCPServerMain() { error("Can't start Winsock!"); return; } - SOCKET client, Listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - sockaddr_in addr {}; - addr.sin_addr.S_un.S_addr = ADDR_ANY; - addr.sin_family = AF_INET; - addr.sin_port = htons(Application::Settings.Port); - if (bind(Listener, (sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) { - error("Can't bind socket! " + std::to_string(WSAGetLastError())); - std::this_thread::sleep_for(std::chrono::seconds(5)); - exit(-1); - } - if (Listener == -1) { - error("Invalid listening socket"); - return; - } - - if (listen(Listener, SOMAXCONN)) { - error("listener failed " + std::to_string(GetLastError())); - //TODO Fix me leak for Listener socket - return; - } - info("Vehicle event network online"); - do { - try { - client = accept(Listener, nullptr, nullptr); - if (client == -1) { - warn("Got an invalid client socket on connect! Skipping..."); - continue; - } - std::thread ID(&TNetwork::Identify, this, client); - ID.detach(); - } catch (const std::exception& e) { - error("fatal: " + std::string(e.what())); - } - } while (client); - - CloseSocketProper(client); - WSACleanup(); -#else // unix - // wondering why we need slightly different implementations of this? - // ask ms. +#endif // WIN32 TConnection client {}; SOCKET Listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); int optval = 1; @@ -173,7 +119,7 @@ void TNetwork::TCPServerMain() { addr.sin_family = AF_INET; addr.sin_port = htons(uint16_t(Application::Settings.Port)); if (bind(Listener, (sockaddr*)&addr, sizeof(addr)) != 0) { - error(("Can't bind socket! ") + std::string(strerror(errno))); + error(("Can't bind socket! ") + GetPlatformAgnosticErrorString()); std::this_thread::sleep_for(std::chrono::seconds(5)); exit(-1); } @@ -182,7 +128,7 @@ void TNetwork::TCPServerMain() { return; } if (listen(Listener, SOMAXCONN)) { - error(("listener failed ") + std::string(strerror(errno))); + error(("listener failed ") + GetPlatformAgnosticErrorString()); //TODO fix me leak Listener return; } @@ -209,7 +155,10 @@ void TNetwork::TCPServerMain() { debug("all ok, arrived at " + std::string(__func__) + ":" + std::to_string(__LINE__)); CloseSocketProper(client.Socket); -#endif +#ifdef WIN32 + CloseSocketProper(client); + WSACleanup(); +#endif // WIN32 } #undef GetObject //Fixes Windows @@ -406,12 +355,12 @@ bool TNetwork::TCPSend(TClient& c, const std::string& Data, bool IsSync) { int32_t Temp = send(c.GetTCPSock(), &Send[Sent], Size - Sent, MSG_NOSIGNAL); #endif //WIN32 if (Temp == 0) { - debug("send() == 0: " + std::string(std::strerror(errno))); + debug("send() == 0: " + GetPlatformAgnosticErrorString()); if (c.GetStatus() > -1) c.SetStatus(-1); return false; } else if (Temp < 0) { - debug("send() < 0: " + std::string(std::strerror(errno))); //TODO fix it was spamming yet everyone stayed on the server + debug("send() < 0: " + GetPlatformAgnosticErrorString()); //TODO fix it was spamming yet everyone stayed on the server if (c.GetStatus() > -1) c.SetStatus(-1); CloseSocketProper(c.GetTCPSock()); @@ -430,11 +379,7 @@ bool TNetwork::CheckBytes(TClient& c, int32_t BytesRcv) { c.SetStatus(-1); return false; } else if (BytesRcv < 0) { -#ifdef WIN32 - debug(("(TCP) recv failed with error: ") + std::to_string(WSAGetLastError())); -#else // unix - debug(("(TCP) recv failed with error: ") + std::string(strerror(errno))); -#endif // WIN32 + debug("(TCP) recv() failed: " + GetPlatformAgnosticErrorString()); if (c.GetStatus() > -1) c.SetStatus(-1); CloseSocketProper(c.GetTCPSock()); @@ -953,31 +898,17 @@ bool TNetwork::UDPSend(TClient& Client, std::string Data) const { #endif // WIN32 sendOk = sendto(mUDPSock, Data.c_str(), len, 0, (sockaddr*)&Addr, int(AddrSize)); -#ifdef WIN32 if (sendOk == -1) { - debug(("(UDP) Send Failed Code : ") + std::to_string(WSAGetLastError())); + debug("(UDP) sendto() failed: " + GetPlatformAgnosticErrorString()); if (Client.GetStatus() > -1) Client.SetStatus(-1); return false; } else if (sendOk == 0) { - debug(("(UDP) sendto returned 0")); + debug(("(UDP) sendto() returned 0")); if (Client.GetStatus() > -1) Client.SetStatus(-1); return false; } -#else // unix - if (sendOk == -1) { - debug(("(UDP) Send Failed Code : ") + std::string(strerror(errno))); - if (Client.GetStatus() > -1) - Client.SetStatus(-1); - return false; - } else if (sendOk == 0) { - debug(("(UDP) sendto returned 0")); - if (Client.GetStatus() > -1) - Client.SetStatus(-1); - return false; - } -#endif // WIN32 return true; } @@ -991,11 +922,7 @@ std::string TNetwork::UDPRcvFromClient(sockaddr_in& client) const { #endif // WIN32 if (Rcv == -1) { -#ifdef WIN32 - error(("(UDP) Error receiving from Client! Code : ") + std::to_string(WSAGetLastError())); -#else // unix - error(("(UDP) Error receiving from Client! Code : ") + std::string(strerror(errno))); -#endif // WIN32 + error("(UDP) Error receiving from client! recvfrom() failed: " + GetPlatformAgnosticErrorString()); return ""; } return std::string(Ret.begin(), Ret.begin() + Rcv); From 1444d91e7e7becfdce598db1fb02cd1c55f99ee2 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 2 Aug 2021 14:06:00 +0200 Subject: [PATCH 065/255] Common: missed semicolon --- include/Common.h | 2 +- src/Common.cpp | 2 +- src/TNetwork.cpp | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/include/Common.h b/include/Common.h index 380af42..74ec111 100644 --- a/include/Common.h +++ b/include/Common.h @@ -90,7 +90,7 @@ private: static inline std::mutex mShutdownHandlersMutex {}; static inline std::deque mShutdownHandlers {}; - static inline Version mVersion { 2, 2, 0 }; + static inline Version mVersion { 2, 3, 0 }; }; std::string ThreadName(bool DebugModeOverride = false); diff --git a/src/Common.cpp b/src/Common.cpp index 385d6a7..915c216 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -185,7 +185,7 @@ std::string GetPlatformAgnosticErrorString() { if (*msgbuf) { return std::to_string(GetLastError()) + " - " + std::string(msgbuf); } else { - return std::to_string(GetLastError()) + return std::to_string(GetLastError()); } #else // posix return std::strerror(errno); diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index 638e7de..832fc84 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -62,7 +62,6 @@ void TNetwork::UDPServerMain() { //return; } - info(("Vehicle data network online on port ") + std::to_string(Application::Settings.Port) + (" with a Max of ") + std::to_string(Application::Settings.MaxPlayers) + (" Clients")); while (!mShutdown) { From a311d58e1173550bdbdf065f39fcf196cb2029fd Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 2 Aug 2021 14:15:30 +0200 Subject: [PATCH 066/255] TNetwork: reuseaddr instead of reuseport --- src/TNetwork.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index 832fc84..a6c83e1 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -111,7 +111,7 @@ void TNetwork::TCPServerMain() { TConnection client {}; SOCKET Listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); int optval = 1; - setsockopt(Listener, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval)); + setsockopt(Listener, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); // TODO: check optval or return value idk sockaddr_in addr {}; addr.sin_addr.s_addr = INADDR_ANY; From 24516dbfd7b3bc9117f893b30135bb522918bd2e Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 2 Aug 2021 14:23:20 +0200 Subject: [PATCH 067/255] TNetwork: setsockopt: cast optval to void* --- src/TNetwork.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index a6c83e1..1cae744 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -111,7 +111,7 @@ void TNetwork::TCPServerMain() { TConnection client {}; SOCKET Listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); int optval = 1; - setsockopt(Listener, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); + setsockopt(Listener, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&optval), sizeof(optval)); // TODO: check optval or return value idk sockaddr_in addr {}; addr.sin_addr.s_addr = INADDR_ANY; From d16843e45dd88708898f7099a719af4f69202e74 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sat, 7 Aug 2021 23:51:56 +0200 Subject: [PATCH 068/255] TNetwork: clarify error messages --- src/TNetwork.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index 1cae744..5d223ac 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -118,17 +118,17 @@ void TNetwork::TCPServerMain() { addr.sin_family = AF_INET; addr.sin_port = htons(uint16_t(Application::Settings.Port)); if (bind(Listener, (sockaddr*)&addr, sizeof(addr)) != 0) { - error(("Can't bind socket! ") + GetPlatformAgnosticErrorString()); + error("bind() failed: " + GetPlatformAgnosticErrorString()); std::this_thread::sleep_for(std::chrono::seconds(5)); exit(-1); } if (Listener == -1) { - error(("Invalid listening socket")); + error("Invalid listening socket"); return; } if (listen(Listener, SOMAXCONN)) { - error(("listener failed ") + GetPlatformAgnosticErrorString()); - //TODO fix me leak Listener + error("listen() failed: " + GetPlatformAgnosticErrorString()); + // FIXME leak Listener return; } info(("Vehicle event network online")); From 0087205d559144e596bd01b19143253e57c054f9 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Wed, 11 Aug 2021 12:54:44 +0200 Subject: [PATCH 069/255] fix issues caused by rebase --- src/TNetwork.cpp | 1 + src/TSentry.cpp | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index 5d223ac..86ec5b5 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -267,6 +267,7 @@ void TNetwork::Authentication(const TConnection& ClientConnection) { Sentry.Log(SentryLevel::Error, "default", "unexpected backend response (" + std::to_string(ResponseCode) + ")"); } return; + } if (AuthResponse["username"].IsString() && AuthResponse["roles"].IsString() diff --git a/src/TSentry.cpp b/src/TSentry.cpp index fd8069f..3986633 100644 --- a/src/TSentry.cpp +++ b/src/TSentry.cpp @@ -17,9 +17,8 @@ TSentry::TSentry() { mValid = true; sentry_options_t* options = sentry_options_new(); sentry_options_set_dsn(options, SECRET_SENTRY_URL); - sentry_options_set_debug(options, false); // needs to always be false + auto ReleaseString = "BeamMP-Server@" + Application::ServerVersionString(); sentry_options_set_symbolize_stacktraces(options, true); - auto ReleaseString = "BeamMP-Server@" + Application::ServerVersion(); sentry_options_set_release(options, ReleaseString.c_str()); sentry_options_set_max_breadcrumbs(options, 10); sentry_init(options); From 5742ab0dad01da40f29820b5d47c53181280fb39 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Wed, 11 Aug 2021 13:00:46 +0200 Subject: [PATCH 070/255] possible windows compiler fix --- src/TNetwork.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index 86ec5b5..05a226f 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -111,7 +111,12 @@ void TNetwork::TCPServerMain() { TConnection client {}; SOCKET Listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); int optval = 1; - setsockopt(Listener, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&optval), sizeof(optval)); +#ifdef WIN32 + const char* optval_ptr = reinterpret_cast(&optval); +#else + void* optval_ptr = reinterpret_cast(&optval); +#endif + setsockopt(Listener, SOL_SOCKET, SO_REUSEADDR, optval_ptr, sizeof(optval)); // TODO: check optval or return value idk sockaddr_in addr {}; addr.sin_addr.s_addr = INADDR_ANY; From 6462636b295d75145a69208fde30d3545c25898f Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Tue, 17 Aug 2021 14:33:03 +0200 Subject: [PATCH 071/255] Multiple merge fixes, rebase, working Https::GET --- include/Common.h | 7 +-- include/Http.h | 5 +- src/Common.cpp | 36 ++++++++------ src/Http.cpp | 104 +++++---------------------------------- src/THeartbeatThread.cpp | 11 ++--- src/TLuaEngine.cpp | 8 +-- src/TNetwork.cpp | 7 ++- 7 files changed, 50 insertions(+), 128 deletions(-) diff --git a/include/Common.h b/include/Common.h index 74ec111..cc5fb94 100644 --- a/include/Common.h +++ b/include/Common.h @@ -21,6 +21,7 @@ struct Version { uint8_t minor; uint8_t patch; Version(uint8_t major, uint8_t minor, uint8_t patch); + Version(const std::array& v); std::string AsString(); }; @@ -81,8 +82,8 @@ public: static std::string GetBackup2Hostname() { return "backup2.beammp.com"; } static std::string GetBackendUrlForSocketIO() { return "https://backend.beammp.com"; } static void CheckForUpdates(); - static std::array VersionStrToInts(const std::string& str); - static bool IsOutdated(const std::array& Current, const std::array& Newest); + static std::array VersionStrToInts(const std::string& str); + static bool IsOutdated(const Version& Current, const Version& Newest); private: static inline std::string mPPS; @@ -163,4 +164,4 @@ void LogChatMessage(const std::string& name, int id, const std::string& msg); std::string Comp(std::string Data); std::string DeComp(std::string Compressed); -std::string GetPlatformAgnosticErrorString(); \ No newline at end of file +std::string GetPlatformAgnosticErrorString(); diff --git a/include/Http.h b/include/Http.h index 48bae69..daf38da 100644 --- a/include/Http.h +++ b/include/Http.h @@ -5,8 +5,9 @@ namespace Http { std::string GET(const std::string& host, int port, const std::string& target, unsigned int* status = nullptr); -std::string POST(const std::string& host, const std::string& target, const std::unordered_map& fields, const std::string& body, bool json, int* status = nullptr); +std::string POST(const std::string& host, int port, const std::string& target, const std::unordered_map& fields, const std::string& body, const std::string& ContentType, unsigned int* status = nullptr); namespace Status { std::string ToString(int code); } -} \ No newline at end of file +const std::string ErrorString = "-1"; +} diff --git a/src/Common.cpp b/src/Common.cpp index 915c216..26e5f6b 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -30,10 +30,14 @@ void Application::GracefullyShutdown() { } } -std::array Application::VersionStrToInts(const std::string& str) { - std::array Version; +std::string Application::ServerVersionString() { + return mVersion.AsString(); +} + +std::array Application::VersionStrToInts(const std::string& str) { + std::array Version; std::stringstream ss(str); - for (int& i : Version) { + for (uint8_t& i : Version) { std::string Part; std::getline(ss, Part, '.'); std::from_chars(&*Part.begin(), &*Part.begin() + Part.size(), i); @@ -41,12 +45,13 @@ std::array Application::VersionStrToInts(const std::string& str) { return Version; } -bool Application::IsOutdated(const std::array& Current, const std::array& Newest) { - if (Newest[0] > Current[0]) { +// FIXME: This should be used by operator< on Version +bool Application::IsOutdated(const Version& Current, const Version& Newest) { + if (Newest.major > Current.major) { return true; - } else if (Newest[0] == Current[0] && Newest[1] > Current[1]) { + } else if (Newest.major == Current.major && Newest.minor > Current.minor) { return true; - } else if (Newest[0] == Current[0] && Newest[1] == Current[1] && Newest[2] > Current[2]) { + } else if (Newest.major == Current.major && Newest.minor == Current.minor && Newest.patch > Current.patch) { return true; } else { return false; @@ -59,12 +64,10 @@ void Application::CheckForUpdates() { auto Response = Http::GET(GetBackendHostname(), 443, "/v/s"); bool Matches = std::regex_match(Response, VersionRegex); if (Matches) { - auto MyVersion = VersionStrToInts(ServerVersion()); - auto RemoteVersion = VersionStrToInts(Response); + auto MyVersion = ServerVersion(); + auto RemoteVersion = Version(VersionStrToInts(Response)); if (IsOutdated(MyVersion, RemoteVersion)) { - std::string RealVersionString = std::to_string(RemoteVersion[0]) + "."; - RealVersionString += std::to_string(RemoteVersion[1]) + "."; - RealVersionString += std::to_string(RemoteVersion[2]); + std::string RealVersionString = RemoteVersion.AsString(); warn(std::string(ANSI_YELLOW_BOLD) + "NEW VERSION OUT! There's a new version (v" + RealVersionString + ") of the BeamMP-Server available! For info on how to update your server, visit https://wiki.beammp.com/en/home/server-maintenance#updating-the-server." + std::string(ANSI_RESET)); } else { info("Server up-to-date!"); @@ -149,10 +152,16 @@ Version::Version(uint8_t major, uint8_t minor, uint8_t patch) , minor(minor) , patch(patch) { } +Version::Version(const std::array& v) + : Version(v[0], v[1], v[2]) { +} + std::string Version::AsString() { std::stringstream ss {}; ss << int(major) << "." << int(minor) << "." << int(patch); return ss.str(); +} + void LogChatMessage(const std::string& name, int id, const std::string& msg) { std::stringstream ss; ss << "[CHAT] "; @@ -162,7 +171,6 @@ void LogChatMessage(const std::string& name, int id, const std::string& msg) { ss << name << ""; } ss << msg; - } std::string GetPlatformAgnosticErrorString() { @@ -190,4 +198,4 @@ std::string GetPlatformAgnosticErrorString() { #else // posix return std::strerror(errno); #endif -} \ No newline at end of file +} diff --git a/src/Http.cpp b/src/Http.cpp index f69ff5a..d67f18e 100644 --- a/src/Http.cpp +++ b/src/Http.cpp @@ -15,94 +15,7 @@ namespace net = boost::asio; // from namespace ssl = net::ssl; // from using tcp = net::ip::tcp; // from -std::string Http::GET(const std::string& host, int port, const std::string& target, unsigned int* status) { - - - try { - // Check command line arguments. - int version = 11; - - - - - // The io_context is required for all I/O - net::io_context ioc; - - // The SSL context is required, and holds certificates - ssl::context ctx(ssl::context::tlsv12_client); - - // This holds the root certificate used for verification - // we don't do / have this - // load_root_certificates(ctx); - - // Verify the remote server's certificate - ctx.set_verify_mode(ssl::verify_none); - - // These objects perform our I/O - tcp::resolver resolver(ioc); - beast::ssl_stream stream(ioc, ctx); - - // Set SNI Hostname (many hosts need this to handshake successfully) - if (!SSL_set_tlsext_host_name(stream.native_handle(), host.c_str())) { - beast::error_code ec { static_cast(::ERR_get_error()), net::error::get_ssl_category() }; - throw beast::system_error { ec }; - } - - // Look up the domain name - auto const results = resolver.resolve(host.c_str(), std::to_string(port)); - - // Make the connection on the IP address we get from a lookup - beast::get_lowest_layer(stream).connect(results); - - // Perform the SSL handshake - stream.handshake(ssl::stream_base::client); - - // Set up an HTTP GET request message - http::request req { http::verb::get, target, version }; - req.set(http::field::host, host); - - req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING); - - // Send the HTTP request to the remote host - http::write(stream, req); - - // This buffer is used for reading and must be persisted - beast::flat_buffer buffer; - - - - - // Declare a container to hold the response - http::response res; - - // Receive the HTTP response - http::read(stream, buffer, res); - - // Gracefully close the stream - beast::error_code ec; - stream.shutdown(ec); - if (ec == net::error::eof) { - // Rationale: - // http://stackoverflow.com/questions/25587403/boost-asio-ssl-async-shutdown-always-finishes-with-an-error - ec = {}; - } - - if (status) { - *status = res.base().result_int(); - } - - if (ec) - throw beast::system_error { ec }; - - // If we get here then the connection is closed gracefully - return std::string(res.body()); - } catch (std::exception const& e) { - Application::Console().Write(__func__ + std::string(": ") + e.what()); - return ErrorString; - } -} - -std::string Http::POST(const std::string& host, int port, const std::string& target, const std::unordered_map& fields, const std::string& body, const std::string& ContentType, unsigned int* status) { +std::string GenericRequest(http::verb verb, const std::string& host, int port, const std::string& target, const std::unordered_map& fields, const std::string& body, const std::string& ContentType, unsigned int* status) { try { net::io_context io; @@ -140,14 +53,13 @@ std::string Http::POST(const std::string& host, int port, const std::string& tar } //} stream.handshake(ssl::stream_base::client); - http::request req { http::verb::post, target, 11 /* http 1.1 */ }; + http::request req { verb, target, 11 /* http 1.1 */ }; req.set(http::field::host, host); if (!body.empty()) { req.set(http::field::content_type, ContentType); // "application/json" // "application/x-www-form-urlencoded" - req.set(http::field::content_length, std::to_string(body.size())); req.body() = body; // info("body is " + body + " (" + req.body() + ")"); @@ -215,10 +127,18 @@ std::string Http::POST(const std::string& host, int port, const std::string& tar } catch (const std::exception& e) { Application::Console().Write(__func__ + std::string(": ") + e.what()); - return ErrorString; + return Http::ErrorString; } } +std::string Http::GET(const std::string& host, int port, const std::string& target, unsigned int* status) { + return GenericRequest(http::verb::get, host, port, target, {}, {}, {}, status); +} + +std::string Http::POST(const std::string& host, int port, const std::string& target, const std::unordered_map& fields, const std::string& body, const std::string& ContentType, unsigned int* status) { + return GenericRequest(http::verb::post, host, port, target, fields, body, ContentType, status); +} + // RFC 2616, RFC 7231 static std::map Map = { { 100, "Continue" }, @@ -291,4 +211,4 @@ std::string Http::Status::ToString(int code) { } else { return "Unassigned"; } -} \ No newline at end of file +} diff --git a/src/THeartbeatThread.cpp b/src/THeartbeatThread.cpp index 826e0b1..e5d2855 100644 --- a/src/THeartbeatThread.cpp +++ b/src/THeartbeatThread.cpp @@ -49,20 +49,19 @@ void THeartbeatThread::operator()() { Sentry.Log(SentryLevel::Error, "default", Http::Status::ToString(status) + " (" + std::to_string(status) + ")"); }; - auto Target = "/heartbeat"; - int ResponseCode = -1; - T = Http::POST(Application::GetBackendHostname(), Target, {}, Body, false, &ResponseCode); + unsigned int ResponseCode = 0; + T = Http::POST(Application::GetBackendHostname(), 443, Target, {}, Body, "application/x-www-form-urlencoded", &ResponseCode); if (T.substr(0, 2) != "20" || ResponseCode != 200) { trace("got " + T + " from backend"); SentryReportError(Application::GetBackendHostname() + Target, ResponseCode); std::this_thread::sleep_for(std::chrono::milliseconds(500)); - T = Http::POST(Application::GetBackup1Hostname(), Target, {}, Body, false, &ResponseCode); + T = Http::POST(Application::GetBackup1Hostname(), 443, Target, {}, Body, "application/x-www-form-urlencoded", &ResponseCode); if (T.substr(0, 2) != "20" || ResponseCode != 200) { SentryReportError(Application::GetBackup1Hostname() + Target, ResponseCode); std::this_thread::sleep_for(std::chrono::milliseconds(500)); - T = Http::POST(Application::GetBackup2Hostname(), Target, {}, Body, false, &ResponseCode); + T = Http::POST(Application::GetBackup2Hostname(), 443, Target, {}, Body, "application/x-www-form-urlencoded", &ResponseCode); if (T.substr(0, 2) != "20" || ResponseCode != 200) { warn("Backend system refused server! Server will not show in the public server list."); @@ -130,4 +129,4 @@ std::string THeartbeatThread::GetPlayers() { return Return; } /*THeartbeatThread::~THeartbeatThread() { -}*/ \ No newline at end of file +}*/ diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 7bbd874..dca0de8 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -72,17 +72,12 @@ void TLuaEngine::FolderList(const std::string& Path, bool HotSwap) { for (const auto& entry : fs::directory_iterator(Path)) { if (fs::is_directory(entry)) { RegisterFiles(entry.path(), HotSwap); - } } } void TLuaEngine::RegisterFiles(const fs::path& Path, bool HotSwap) { std::string Name = Path.filename().string(); - std::string Name = Path.substr(Path.find_last_of('/') + 1); -#else - -#endif if (!HotSwap) info(("Loading plugin : ") + Name); std::vector Entries; @@ -111,11 +106,10 @@ void TLuaEngine::RegisterFiles(const fs::path& Path, bool HotSwap) { } } - bool TLuaEngine::IsNewFile(const std::string& Path) { for (auto& Script : mLuaFiles) { if (fs::absolute(Path) == fs::absolute(Script->GetFileName())) return false; } return true; -} \ No newline at end of file +} diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index 05a226f..cf0625b 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -241,9 +241,9 @@ void TNetwork::Authentication(const TConnection& ClientConnection) { auto RequestString = R"({"key":")" + Rc + "\"}"; auto Target = "/pkToUser"; - int ResponseCode = -1; + unsigned int ResponseCode = 0; if (!Rc.empty()) { - Rc = Http::POST(Application::GetBackendUrlForAuth(), Target, {}, RequestString, true, &ResponseCode); + Rc = Http::POST(Application::GetBackendUrlForAuth(), 443, Target, {}, RequestString, "application/json", &ResponseCode); } json::Document AuthResponse; @@ -272,7 +272,6 @@ void TNetwork::Authentication(const TConnection& ClientConnection) { Sentry.Log(SentryLevel::Error, "default", "unexpected backend response (" + std::to_string(ResponseCode) + ")"); } return; - } if (AuthResponse["username"].IsString() && AuthResponse["roles"].IsString() @@ -931,4 +930,4 @@ std::string TNetwork::UDPRcvFromClient(sockaddr_in& client) const { return ""; } return std::string(Ret.begin(), Ret.begin() + Rcv); -} \ No newline at end of file +} From 2a96546c8cfca334777cc2a7258f4b693a9c6cb7 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Wed, 18 Aug 2021 09:00:23 +0200 Subject: [PATCH 072/255] Lua: Add GetPluginName, GetPluginPath --- include/TLuaFile.h | 13 +++++++------ src/TLuaFile.cpp | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/include/TLuaFile.h b/include/TLuaFile.h index 43620a9..7693298 100644 --- a/include/TLuaFile.h +++ b/include/TLuaFile.h @@ -37,12 +37,13 @@ public: ~TLuaFile(); void SetStopThread(bool StopThread) { mStopThread = StopThread; } TLuaEngine& Engine() { return mEngine; } - [[nodiscard]] std::string GetPluginName() const; - [[nodiscard]] std::string GetFileName() const; - [[nodiscard]] const lua_State* GetState() const; - [[nodiscard]] bool GetStopThread() const { return mStopThread; } - [[nodiscard]] const TLuaEngine& Engine() const { return mEngine; } - [[nodiscard]] std::string GetRegistered(const std::string& Event) const; + std::string GetPluginPath() const; + std::string GetPluginName() const; + std::string GetFileName() const; + const lua_State* GetState() const; + bool GetStopThread() const { return mStopThread; } + const TLuaEngine& Engine() const { return mEngine; } + std::string GetRegistered(const std::string& Event) const; private: TLuaEngine& mEngine; diff --git a/src/TLuaFile.cpp b/src/TLuaFile.cpp index 4e7e39d..8db27d4 100644 --- a/src/TLuaFile.cpp +++ b/src/TLuaFile.cpp @@ -922,6 +922,31 @@ int lua_HttpsPOST(lua_State* L) { return 2; } +int lua_GetPluginName(lua_State* L) { + auto MaybeFile = Engine().GetScript(L); + if (MaybeFile) { + lua_pushstring(L, MaybeFile.value().get().GetPluginName().c_str()); + return 1; + } else { + warn("no plugin associated with this state"); + return 0; + } +} + +int lua_GetPluginPath(lua_State* L) { + auto MaybeFile = Engine().GetScript(L); + if (MaybeFile) { + lua_pushstring(L, MaybeFile.value().get().GetPluginPath().c_str()); + return 1; + } else { + warn("no plugin associated with this state"); + return 0; + } +} + +int lua_Dump(lua_State* L) { +} + void TLuaFile::Load() { Assert(mLuaState); luaL_openlibs(mLuaState); @@ -965,11 +990,14 @@ void TLuaFile::Load() { LuaTable::InsertFunction(mLuaState, "HttpsGET", lua_HttpsGET); LuaTable::InsertFunction(mLuaState, "HttpsPOST", lua_HttpsPOST); LuaTable::InsertFunction(mLuaState, "GetServerVersion", lua_GetServerVersion); + LuaTable::InsertFunction(mLuaState, "GetPluginName", lua_GetPluginName); + LuaTable::InsertFunction(mLuaState, "GetPluginPath", lua_GetPluginPath); LuaTable::End(mLuaState, "MP"); lua_register(mLuaState, "print", lua_Print); lua_register(mLuaState, "printRaw", lua_PrintRaw); + lua_register(mLuaState, "dump", lua_Dump); lua_register(mLuaState, "exit", lua_ServerExit); if (!mConsole) Reload(); @@ -1032,6 +1060,13 @@ TLuaFile::~TLuaFile() { lua_close(mLuaState); } +std::string TLuaFile::GetPluginPath() const { + auto path = fs::path(Application::Settings.Resource); + path /= "Server"; + path /= mPluginName; + return path.string(); +} + void SendError(TLuaEngine& Engine, lua_State* L, const std::string& msg) { Assert(L); auto MaybeS = Engine.GetScript(L); From 2727f90430fa8ad1cd9f151e06fa013c4e027c36 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 9 Sep 2021 12:25:08 +0300 Subject: [PATCH 073/255] Remove Socket.io for now it is being built every time and we dont need it --- CMakeLists.txt | 4 +- include/Common.h | 2 +- include/SocketIO.h | 69 -------------------------------- src/SocketIO.cpp | 98 ---------------------------------------------- 4 files changed, 2 insertions(+), 171 deletions(-) delete mode 100644 include/SocketIO.h delete mode 100644 src/SocketIO.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b4aa0e3..44d56ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,7 +62,6 @@ message(STATUS "Adding local source dependencies") include_directories("asio/asio/include") include_directories("rapidjson/include") include_directories("websocketpp") -add_subdirectory("socket.io-client-cpp") add_subdirectory("include/commandline") @@ -104,7 +103,6 @@ target_include_directories(BeamMP-Server PUBLIC ${Boost_INCLUDE_DIRS} ${LUA_INCLUDE_DIR} ${CURL_INCLUDE_DIRS} - "socket.io-client-cpp/src" "include/tomlplusplus" "include/sentry-native/include" "include/curl/include") @@ -142,4 +140,4 @@ elseif (WIN32) commandline sioclient_tls sentry) -endif () \ No newline at end of file +endif () diff --git a/include/Common.h b/include/Common.h index cc5fb94..bdcd7ab 100644 --- a/include/Common.h +++ b/include/Common.h @@ -91,7 +91,7 @@ private: static inline std::mutex mShutdownHandlersMutex {}; static inline std::deque mShutdownHandlers {}; - static inline Version mVersion { 2, 3, 0 }; + static inline Version mVersion { 2, 4, 0 }; }; std::string ThreadName(bool DebugModeOverride = false); diff --git a/include/SocketIO.h b/include/SocketIO.h deleted file mode 100644 index 47c090e..0000000 --- a/include/SocketIO.h +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -/* - * We send relevant server events over socket.io to the backend. - * - * We send all events to `backend.beammp.com`, to the room `/key` - * where `key` is the currently active auth-key. - */ - -enum class SocketIOEvent { - ConsoleOut, - CPUUsage, - MemoryUsage, - NetworkUsage, - PlayerList, -}; - -enum class SocketIORoom { - None, - Stats, - Player, - Info, - Console, -}; - -class SocketIO final { -private: - struct Event; - -public: - enum class EventType { - }; - - // Singleton pattern - static SocketIO& Get(); - - void Emit(SocketIOEvent Event, const std::string& Data); - - ~SocketIO(); - - void SetAuthenticated(bool auth) { mAuthenticated = auth; } - -private: - SocketIO() noexcept; - - void ThreadMain(); - - struct Event { - std::string Name; - std::string Data; - }; - - bool mAuthenticated { false }; - sio::client mClient; - std::thread mThread; - std::atomic_bool mCloseThread { false }; - std::mutex mQueueMutex; - std::deque mQueue; - - friend std::unique_ptr std::make_unique(); -}; - diff --git a/src/SocketIO.cpp b/src/SocketIO.cpp deleted file mode 100644 index 2c10f6f..0000000 --- a/src/SocketIO.cpp +++ /dev/null @@ -1,98 +0,0 @@ -#include "SocketIO.h" -#include "Common.h" -#include - - -//TODO Default disabled with config option -static std::unique_ptr SocketIOInstance = std::make_unique(); - -SocketIO& SocketIO::Get() { - return *SocketIOInstance; -} - -SocketIO::SocketIO() noexcept - : mThread([this] { ThreadMain(); }) { - - mClient.socket()->on("network", [&](sio::event&e) { - if(e.get_message()->get_string() == "Welcome"){ - info("SocketIO Authenticated!"); - mAuthenticated = true; - } - }); - - mClient.socket()->on("welcome", [&](sio::event&) { - info("Got welcome from backend! Authenticating SocketIO..."); - mClient.socket()->emit("onInitConnection", Application::Settings.Key); - }); - - mClient.set_logs_quiet(); - mClient.set_reconnect_delay(10000); - mClient.connect(Application::GetBackendUrlForSocketIO()); -} - -SocketIO::~SocketIO() { - mCloseThread.store(true); - mThread.join(); -} - - -static constexpr auto EventNameFromEnum(SocketIOEvent Event) { - switch (Event) { - case SocketIOEvent::CPUUsage: - return "cpu usage"; - case SocketIOEvent::MemoryUsage: - return "memory usage"; - case SocketIOEvent::ConsoleOut: - return "console out"; - case SocketIOEvent::NetworkUsage: - return "network usage"; - case SocketIOEvent::PlayerList: - return "player list"; - default: - error("unreachable code reached (developer error)"); - abort(); - } -} - -void SocketIO::Emit(SocketIOEvent Event, const std::string& Data) { - if (!mAuthenticated) { - debug("trying to emit a socket.io event when not yet authenticated"); - return; - } - std::string EventName = EventNameFromEnum(Event); - debug("emitting event \"" + EventName + "\" with data: \"" + Data); - std::unique_lock Lock(mQueueMutex); - mQueue.push_back({EventName, Data }); - debug("queue now has " + std::to_string(mQueue.size()) + " events"); -} - -void SocketIO::ThreadMain() { - while (!mCloseThread.load()) { - bool empty; - { // queue lock scope - std::unique_lock Lock(mQueueMutex); - empty = mQueue.empty(); - } // end queue lock scope - if (empty || !mClient.opened()) { - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - continue; - } else { - Event TheEvent; - { // queue lock scope - std::unique_lock Lock(mQueueMutex); - TheEvent = mQueue.front(); - mQueue.pop_front(); - } // end queue lock scope - debug("sending \"" + TheEvent.Name + "\" event"); - mClient.socket()->emit(TheEvent.Name, TheEvent.Data); - debug("sent \"" + TheEvent.Name + "\" event"); - } - } - // using std::cout as this happens during static destruction and the logger might be dead already - std::cout << "closing " + std::string(__func__) << std::endl; - - mClient.sync_close(); - mClient.clear_con_listeners(); - - std::cout << "closed" << std::endl; -} From 27103a73a9f3ab0b17607fe29ed61d93fe4e3b74 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 9 Sep 2021 12:26:03 +0300 Subject: [PATCH 074/255] remove socket.io module --- .gitmodules | 3 --- socket.io-client-cpp | 1 - 2 files changed, 4 deletions(-) delete mode 160000 socket.io-client-cpp diff --git a/.gitmodules b/.gitmodules index a9df475..9080a2c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,6 @@ [submodule "include/commandline"] path = include/commandline url = https://github.com/lionkor/commandline -[submodule "socket.io-client-cpp"] - path = socket.io-client-cpp - url = https://github.com/socketio/socket.io-client-cpp [submodule "asio"] path = asio url = https://github.com/chriskohlhoff/asio diff --git a/socket.io-client-cpp b/socket.io-client-cpp deleted file mode 160000 index b196fa7..0000000 --- a/socket.io-client-cpp +++ /dev/null @@ -1 +0,0 @@ -Subproject commit b196fa7537cd3f7bed626ead873a7b71d1293c0d From f4ccf6c17747c67bf580fce1b7487c3f8d8b4a18 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 9 Sep 2021 12:26:26 +0300 Subject: [PATCH 075/255] add sentry native db folder to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 4b06a99..16e5721 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .idea/ +.sentry-native/ *.orig *.toml boost_* From 58da200901ae51d7baff0b46442bdfd6ab054ad6 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 9 Sep 2021 12:32:33 +0300 Subject: [PATCH 076/255] Client: fix socklen_t compile error --- include/Client.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/Client.h b/include/Client.h index 8ac7035..3c605c7 100644 --- a/include/Client.h +++ b/include/Client.h @@ -12,6 +12,11 @@ class TServer; +#ifdef WIN32 +// for socklen_t +#include +#endif // WIN32 + struct TConnection final { SOCKET Socket; struct sockaddr SockAddr; From 588242822c3b92298eaf8183b6fea6a56e55a97d Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 9 Sep 2021 12:33:59 +0300 Subject: [PATCH 077/255] CMake: Remove socketio link, forgot --- CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 44d56ff..3574e10 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -123,7 +123,6 @@ if (UNIX) crypto ${OPENSSL_LIBRARIES} commandline - sioclient_tls sentry) elseif (WIN32) include(FindLua) @@ -138,6 +137,5 @@ elseif (WIN32) ${LUA_LIBRARIES} ${OPENSSL_LIBRARIES} commandline - sioclient_tls sentry) endif () From bb34378b8e0be9055406675072a0c2ae34e7dd7f Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 16 Sep 2021 00:09:39 +0200 Subject: [PATCH 078/255] Move all dependencies to deps/ --- .gitmodules | 10 +++++----- CMakeLists.txt | 16 +++++++--------- asio => deps/asio | 0 {include => deps}/commandline | 0 rapidjson => deps/rapidjson | 0 .../socket.io-client-cpp | 0 {include => deps}/toml11 | 0 7 files changed, 12 insertions(+), 14 deletions(-) rename asio => deps/asio (100%) rename {include => deps}/commandline (100%) rename rapidjson => deps/rapidjson (100%) rename socket.io-client-cpp => deps/socket.io-client-cpp (100%) rename {include => deps}/toml11 (100%) diff --git a/.gitmodules b/.gitmodules index 0d23bc7..5155418 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,15 +1,15 @@ [submodule "include/commandline"] - path = include/commandline + path = deps/commandline url = https://github.com/lionkor/commandline [submodule "socket.io-client-cpp"] - path = socket.io-client-cpp + path = deps/socket.io-client-cpp url = https://github.com/socketio/socket.io-client-cpp [submodule "asio"] - path = asio + path = deps/asio url = https://github.com/chriskohlhoff/asio [submodule "rapidjson"] - path = rapidjson + path = deps/rapidjson url = https://github.com/Tencent/rapidjson [submodule "include/toml11"] - path = include/toml11 + path = deps/toml11 url = https://github.com/ToruNiina/toml11 diff --git a/CMakeLists.txt b/CMakeLists.txt index cd35ed1..9082d61 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,11 +20,11 @@ elseif (UNIX) endif () # this has to happen before -DDEBUG since it wont compile properly with -DDEBUG -include_directories("asio/asio/include") -include_directories("rapidjson/include") -include_directories("websocketpp") -add_subdirectory("socket.io-client-cpp") -add_subdirectory("include/commandline") +include_directories("deps/asio/asio/include") +include_directories("deps/rapidjson/include") +include_directories("deps/websocketpp") +add_subdirectory("deps/socket.io-client-cpp") +add_subdirectory("deps/commandline") set(CMAKE_CXX_STANDARD 17) @@ -50,12 +50,10 @@ add_executable(BeamMP-Server include/TPPSMonitor.h src/TPPSMonitor.cpp include/TNetwork.h src/TNetwork.cpp) -target_include_directories(BeamMP-Server PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_SOURCE_DIR}/commandline") + +target_include_directories(BeamMP-Server PUBLIC ${Boost_INCLUDE_DIRS} ${LUA_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/include) find_package(Lua REQUIRED) - -target_include_directories(BeamMP-Server PUBLIC ${Boost_INCLUDE_DIRS} ${LUA_INCLUDE_DIR} "socket.io-client-cpp/src") - find_package(OpenSSL REQUIRED) if (UNIX) diff --git a/asio b/deps/asio similarity index 100% rename from asio rename to deps/asio diff --git a/include/commandline b/deps/commandline similarity index 100% rename from include/commandline rename to deps/commandline diff --git a/rapidjson b/deps/rapidjson similarity index 100% rename from rapidjson rename to deps/rapidjson diff --git a/socket.io-client-cpp b/deps/socket.io-client-cpp similarity index 100% rename from socket.io-client-cpp rename to deps/socket.io-client-cpp diff --git a/include/toml11 b/deps/toml11 similarity index 100% rename from include/toml11 rename to deps/toml11 From 8b69127cdd944bb2f44e0b27328c2fbf0e99d416 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 16 Sep 2021 00:22:33 +0200 Subject: [PATCH 079/255] Finish moving deps to deps/ --- CMakeLists.txt | 14 +++++++------- deps/CMakeLists.txt | 2 ++ include/TConsole.h | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) create mode 100644 deps/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 9082d61..9618fdd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,12 +20,7 @@ elseif (UNIX) endif () # this has to happen before -DDEBUG since it wont compile properly with -DDEBUG -include_directories("deps/asio/asio/include") -include_directories("deps/rapidjson/include") -include_directories("deps/websocketpp") -add_subdirectory("deps/socket.io-client-cpp") -add_subdirectory("deps/commandline") - +add_subdirectory(deps) set(CMAKE_CXX_STANDARD 17) @@ -50,8 +45,13 @@ add_executable(BeamMP-Server include/TPPSMonitor.h src/TPPSMonitor.cpp include/TNetwork.h src/TNetwork.cpp) +target_include_directories(BeamMP-Server PRIVATE "${PROJECT_SOURCE_DIR}/deps/asio/asio/include") +target_include_directories(BeamMP-Server PRIVATE "${PROJECT_SOURCE_DIR}/deps/rapidjson/include") +target_include_directories(BeamMP-Server PRIVATE "${PROJECT_SOURCE_DIR}/deps/websocketpp") +target_include_directories(BeamMP-Server PRIVATE "${PROJECT_SOURCE_DIR}/deps/commandline") +target_include_directories(BeamMP-Server PRIVATE "${PROJECT_SOURCE_DIR}/deps") -target_include_directories(BeamMP-Server PUBLIC ${Boost_INCLUDE_DIRS} ${LUA_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/include) +include_directories(BeamMP-Server PUBLIC ${Boost_INCLUDE_DIRS} ${LUA_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/include) find_package(Lua REQUIRED) find_package(OpenSSL REQUIRED) diff --git a/deps/CMakeLists.txt b/deps/CMakeLists.txt new file mode 100644 index 0000000..e204f2c --- /dev/null +++ b/deps/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory("${PROJECT_SOURCE_DIR}/deps/socket.io-client-cpp") +add_subdirectory("${PROJECT_SOURCE_DIR}/deps/commandline") diff --git a/include/TConsole.h b/include/TConsole.h index fcaca26..592bfb8 100644 --- a/include/TConsole.h +++ b/include/TConsole.h @@ -1,9 +1,9 @@ #pragma once -#include "commandline/commandline.h" #include "TLuaFile.h" #include #include +#include "commandline.h" class TConsole { public: From be90a8a2c08b282dc1e2cfa36b6ed14945bde684 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 16 Sep 2021 00:33:13 +0200 Subject: [PATCH 080/255] add sol2 --- .gitmodules | 5 +- include/TLuaEngine.h | 40 -- include/TLuaFile.h | 61 --- src/TLuaEngine.cpp | 109 ----- src/TLuaFile.cpp | 1045 ------------------------------------------ 5 files changed, 4 insertions(+), 1256 deletions(-) diff --git a/.gitmodules b/.gitmodules index 5155418..bb41fae 100644 --- a/.gitmodules +++ b/.gitmodules @@ -12,4 +12,7 @@ url = https://github.com/Tencent/rapidjson [submodule "include/toml11"] path = deps/toml11 - url = https://github.com/ToruNiina/toml11 + url = https://github.com/ToruNiina/toml11 +[submodule "include/sol2"] + path = deps/sol2 + url = https://github.com/ThePhD/sol2 diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index 94e3189..e69de29 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -1,40 +0,0 @@ -#pragma once - -#include "Common.h" -#include "IThreaded.h" -#include "TLuaFile.h" -#include "TServer.h" -#include -#include -#include -#include -#include - -class TLuaEngine : public IThreaded { -public: - explicit TLuaEngine(TServer& Server, TNetwork& Network); - - using TSetOfLuaFile = std::set>; - - void operator()() override; - - [[nodiscard]] const TSetOfLuaFile& LuaFiles() const { return mLuaFiles; } - [[nodiscard]] TServer& Server() { return mServer; } - [[nodiscard]] const TServer& Server() const { return mServer; } - [[nodiscard]] TNetwork& Network() { return mNetwork; } - [[nodiscard]] const TNetwork& Network() const { return mNetwork; } - - std::optional> GetScript(lua_State* L); - - static std::unordered_map mGlobals; -private: - void FolderList(const std::string& Path, bool HotSwap); - void RegisterFiles(const std::string& Path, bool HotSwap); - bool NewFile(const std::string& Path); - - TNetwork& mNetwork; - TServer& mServer; - std::string mPath; - bool mShutdown { false }; - TSetOfLuaFile mLuaFiles; -}; diff --git a/include/TLuaFile.h b/include/TLuaFile.h index a94a6b8..e69de29 100644 --- a/include/TLuaFile.h +++ b/include/TLuaFile.h @@ -1,61 +0,0 @@ -#ifndef TLUAFILE_H -#define TLUAFILE_H - -#include -#include -#include -#include -#include -#include -#include - -namespace fs = std::filesystem; - -struct TLuaArg { - std::vector args; - void PushArgs(lua_State* State); -}; - -class TLuaEngine; - -class TLuaFile { -public: - void RegisterEvent(const std::string& Event, const std::string& FunctionName); - void UnRegisterEvent(const std::string& Event); - void SetLastWrite(fs::file_time_type time); - bool IsRegistered(const std::string& Event); - void SetPluginName(const std::string& Name); - void Execute(const std::string& Command); - void SetFileName(const std::string& Name); - fs::file_time_type GetLastWrite(); - lua_State* GetState(); - std::string GetOrigin(); - std::mutex Lock; - void Reload(); - void Init(const std::string& PluginName, const std::string& FileName, fs::file_time_type LastWrote); - explicit TLuaFile(TLuaEngine& Engine, bool Console = false); - ~TLuaFile(); - void SetStopThread(bool StopThread) { mStopThread = StopThread; } - TLuaEngine& Engine() { return mEngine; } - [[nodiscard]] std::string GetPluginName() const; - [[nodiscard]] std::string GetFileName() const; - [[nodiscard]] const lua_State* GetState() const; - [[nodiscard]] bool GetStopThread() const { return mStopThread; } - [[nodiscard]] const TLuaEngine& Engine() const { return mEngine; } - [[nodiscard]] std::string GetRegistered(const std::string& Event) const; - -private: - TLuaEngine& mEngine; - std::set> mRegisteredEvents; - lua_State* mLuaState { nullptr }; - fs::file_time_type mLastWrote; - std::string mPluginName {}; - std::string mFileName {}; - bool mStopThread = false; - bool mConsole = false; - void Load(); -}; - -std::any TriggerLuaEvent(const std::string& Event, bool local, TLuaFile* Caller, std::shared_ptr arg, bool Wait); - -#endif // TLUAFILE_H diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index cd535a9..e69de29 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -1,109 +0,0 @@ -#include "TLuaEngine.h" -#include "TLuaFile.h" - -#include -#include - -namespace fs = std::filesystem; - -std::unordered_map TLuaEngine::mGlobals; - -// necessary as lua relies on global state -TLuaEngine* TheEngine; - -TLuaEngine::TLuaEngine(TServer& Server, TNetwork& Network) - : mNetwork(Network) - , mServer(Server) { - TheEngine = this; - if (!fs::exists(Application::Settings.Resource)) { - fs::create_directory(Application::Settings.Resource); - } - std::string Path = Application::Settings.Resource + ("/Server"); - if (!fs::exists(Path)) { - fs::create_directory(Path); - } - FolderList(Path, false); - mPath = Path; - Application::RegisterShutdownHandler([&] {if (mThread.joinable()) { - debug("shutting down LuaEngine"); - mShutdown = true; - mThread.join(); - debug("shut down LuaEngine"); - } }); - Start(); -} - -void TLuaEngine::operator()() { - RegisterThread("LuaEngine"); - info("Lua system online"); - while (!mShutdown) { - if (!mLuaFiles.empty()) { - for (auto& Script : mLuaFiles) { - struct stat Info { }; - if (stat(Script->GetFileName().c_str(), &Info) != 0) { - Script->SetStopThread(true); - mLuaFiles.erase(Script); - info(("[HOTSWAP] Removed removed script due to delete")); - break; - } - if (Script->GetLastWrite() != fs::last_write_time(Script->GetFileName())) { - Script->SetStopThread(true); - info(("[HOTSWAP] Updated Scripts due to edit")); - Script->SetLastWrite(fs::last_write_time(Script->GetFileName())); - Script->Reload(); - } - } - } - FolderList(mPath, true); - std::this_thread::sleep_for(std::chrono::seconds(2)); - } -} - -std::optional> TLuaEngine::GetScript(lua_State* L) { - for (auto& Script : mLuaFiles) { - if (Script->GetState() == L) - return *Script; - } - return std::nullopt; -} - -void TLuaEngine::FolderList(const std::string& Path, bool HotSwap) { - for (const auto& entry : fs::directory_iterator(Path)) { - auto pos = entry.path().filename().string().find('.'); - if (pos == std::string::npos) { - RegisterFiles(entry.path().string(), HotSwap); - } - } -} - -void TLuaEngine::RegisterFiles(const std::string& Path, bool HotSwap) { -#if defined(__linux) || defined(__linux__) - std::string Name = Path.substr(Path.find_last_of('/') + 1); -#else - std::string Name = Path.substr(Path.find_last_of('\\') + 1); -#endif - if (!HotSwap) - info(("Loading plugin : ") + Name); - for (const auto& entry : fs::directory_iterator(Path)) { - auto pos = entry.path().string().find((".lua")); - if (pos != std::string::npos && entry.path().string().length() - pos == 4) { - if (!HotSwap || NewFile(entry.path().string())) { - auto FileName = entry.path().string(); - std::unique_ptr ScriptToInsert(new TLuaFile(*this)); - auto& Script = *ScriptToInsert; - mLuaFiles.insert(std::move(ScriptToInsert)); - Script.Init(Name, FileName, fs::last_write_time(FileName)); - if (HotSwap) - info(("[HOTSWAP] Added : ") + Script.GetFileName().substr(Script.GetFileName().find('\\'))); - } - } - } -} - -bool TLuaEngine::NewFile(const std::string& Path) { - for (auto& Script : mLuaFiles) { - if (Path == Script->GetFileName()) - return false; - } - return true; -} diff --git a/src/TLuaFile.cpp b/src/TLuaFile.cpp index 5319eb8..e69de29 100644 --- a/src/TLuaFile.cpp +++ b/src/TLuaFile.cpp @@ -1,1045 +0,0 @@ -#include "TLuaFile.h" -#include "Client.h" -#include "Common.h" -#include "CustomAssert.h" -#include "Http.h" -#include "TLuaEngine.h" -#include "TNetwork.h" -#include "TServer.h" -#include -#include -#include - -namespace LuaTable { -void Begin(lua_State* L) { - lua_newtable(L); -} - -void End(lua_State* L, const std::string& name) { - lua_setglobal(L, name.c_str()); -} - -void BeginEntry(lua_State* L, const std::string& name) { - lua_pushstring(L, name.c_str()); -} - -void EndEntry(lua_State* L) { - lua_settable(L, -3); -} - -void InsertFunction(lua_State* L, const std::string& name, lua_CFunction func) { - BeginEntry(L, name); - lua_pushcfunction(L, func); - EndEntry(L); -} - -void InsertInteger(lua_State* L, const std::string& name, lua_Integer i) { - BeginEntry(L, name); - lua_pushinteger(L, i); - EndEntry(L); -} - -} - -void SendError(TLuaEngine& Engine, lua_State* L, const std::string& msg); -std::any CallFunction(TLuaFile* lua, const std::string& FuncName, std::shared_ptr Arg); -std::any TriggerLuaEvent(TLuaEngine& Engine, const std::string& Event, bool local, TLuaFile* Caller, std::shared_ptr arg, bool Wait); - -extern TLuaEngine* TheEngine; - -static TLuaEngine& Engine() { - Assert(TheEngine); - return *TheEngine; -} - -std::shared_ptr CreateArg(lua_State* L, int T, int S) { - if (S > T) - return nullptr; - std::shared_ptr temp(new TLuaArg); - for (int C = S; C <= T; C++) { - if (lua_isstring(L, C)) { - temp->args.emplace_back(std::string(lua_tostring(L, C))); - } else if (lua_isinteger(L, C)) { - temp->args.emplace_back(int(lua_tointeger(L, C))); - } else if (lua_isboolean(L, C)) { - temp->args.emplace_back(bool(lua_toboolean(L, C))); - } else if (lua_isnumber(L, C)) { - temp->args.emplace_back(float(lua_tonumber(L, C))); - } - } - return temp; -} - -void ClearStack(lua_State* L) { - lua_settop(L, 0); -} - -std::any Trigger(TLuaFile* lua, const std::string& R, std::shared_ptr arg) { - RegisterThread(lua->GetFileName()); - std::lock_guard lockGuard(lua->Lock); - std::packaged_task)> task([lua, R](std::shared_ptr arg) { return CallFunction(lua, R, arg); }); - std::future f1 = task.get_future(); - std::thread t(std::move(task), arg); - t.detach(); - auto status = f1.wait_for(std::chrono::seconds(5)); - if (status != std::future_status::timeout) - return f1.get(); - SendError(lua->Engine(), lua->GetState(), R + " took too long to respond"); - return 0; -} - -std::any FutureWait(TLuaFile* lua, const std::string& R, std::shared_ptr arg, bool Wait) { - Assert(lua); - std::packaged_task)> task([lua, R](std::shared_ptr arg) { return Trigger(lua, R, arg); }); - std::future f1 = task.get_future(); - std::thread t(std::move(task), arg); - t.detach(); - int T = 0; - if (Wait) - T = 6; - auto status = f1.wait_for(std::chrono::seconds(T)); - if (status != std::future_status::timeout) - return f1.get(); - return 0; -} - -std::any TriggerLuaEvent(const std::string& Event, bool local, TLuaFile* Caller, std::shared_ptr arg, bool Wait) { - std::any R; - int Ret = 0; - for (auto& Script : Engine().LuaFiles()) { - if (Script->IsRegistered(Event)) { - if (local) { - if (Script->GetPluginName() == Caller->GetPluginName()) { - R = FutureWait(Script.get(), Script->GetRegistered(Event), arg, Wait); - if (R.type() == typeid(int)) { - if (std::any_cast(R)) - Ret++; - } else if (Event == "onPlayerAuth") - return R; - } - } else { - R = FutureWait(Script.get(), Script->GetRegistered(Event), arg, Wait); - if (R.type() == typeid(int)) { - if (std::any_cast(R)) - Ret++; - } else if (Event == "onPlayerAuth") - return R; - } - } - } - return Ret; -} - -bool ConsoleCheck(lua_State* L, int r) { - if (r != LUA_OK) { - std::string msg = lua_tostring(L, -1); - warn(("_Console | ") + msg); - return false; - } - return true; -} - -bool CheckLua(lua_State* L, int r) { - if (r != LUA_OK) { - std::string msg = lua_tostring(L, -1); - auto MaybeS = Engine().GetScript(L); - if (MaybeS.has_value()) { - TLuaFile& S = MaybeS.value(); - std::string a = fs::path(S.GetFileName()).filename().string(); - warn(a + " | " + msg); - return false; - } - // What the fuck, what do we do?! - AssertNotReachable(); - } - return true; -} - -int lua_RegisterEvent(lua_State* L) { - int Args = lua_gettop(L); - auto MaybeScript = Engine().GetScript(L); - Assert(MaybeScript.has_value()); - TLuaFile& Script = MaybeScript.value(); - if (Args == 2 && lua_isstring(L, 1) && lua_isstring(L, 2)) { - Script.RegisterEvent(lua_tostring(L, 1), lua_tostring(L, 2)); - } else - SendError(Engine(), L, "RegisterEvent invalid argument count expected 2 got " + std::to_string(Args)); - return 0; -} - -int lua_TriggerEventL(lua_State* L) { - int Args = lua_gettop(L); - auto MaybeScript = Engine().GetScript(L); - Assert(MaybeScript.has_value()); - TLuaFile& Script = MaybeScript.value(); - if (Args > 0) { - if (lua_isstring(L, 1)) { - TriggerLuaEvent(lua_tostring(L, 1), true, &Script, CreateArg(L, Args, 2), false); - } else - SendError(Engine(), L, ("TriggerLocalEvent wrong argument [1] need string")); - } else { - SendError(Engine(), L, ("TriggerLocalEvent not enough arguments expected 1 got 0")); - } - return 0; -} - -int lua_TriggerEventG(lua_State* L) { - int Args = lua_gettop(L); - auto MaybeScript = Engine().GetScript(L); - Assert(MaybeScript.has_value()); - TLuaFile& Script = MaybeScript.value(); - if (Args > 0) { - if (lua_isstring(L, 1)) { - TriggerLuaEvent(lua_tostring(L, 1), false, &Script, CreateArg(L, Args, 2), false); - } else - SendError(Engine(), L, ("TriggerGlobalEvent wrong argument [1] need string")); - } else - SendError(Engine(), L, ("TriggerGlobalEvent not enough arguments")); - return 0; -} - -void SafeExecution(TLuaFile* lua, const std::string& FuncName) { - lua_State* luaState = lua->GetState(); - lua_getglobal(luaState, FuncName.c_str()); - if (lua_isfunction(luaState, -1)) { - int R = lua_pcall(luaState, 0, 0, 0); - CheckLua(luaState, R); - } - ClearStack(luaState); -} - -void ExecuteAsync(TLuaFile* lua, const std::string& FuncName) { - std::lock_guard lockGuard(lua->Lock); - SafeExecution(lua, FuncName); -} - -void CallAsync(TLuaFile* lua, const std::string& Func, int U) { - RegisterThread(lua->GetFileName()); - lua->SetStopThread(false); - int D = 1000 / U; - while (!lua->GetStopThread()) { - ExecuteAsync(lua, Func); - std::this_thread::sleep_for(std::chrono::milliseconds(D)); - } -} - -int lua_StopThread(lua_State* L) { - auto MaybeScript = Engine().GetScript(L); - Assert(MaybeScript.has_value()); - // ugly, but whatever, this is safe as fuck - MaybeScript.value().get().SetStopThread(true); - return 0; -} - -int lua_CreateThread(lua_State* L) { - int Args = lua_gettop(L); - if (Args > 1) { - if (lua_isstring(L, 1)) { - std::string STR = lua_tostring(L, 1); - if (lua_isinteger(L, 2) || lua_isnumber(L, 2)) { - int U = int(lua_tointeger(L, 2)); - if (U > 0 && U < 501) { - auto MaybeScript = Engine().GetScript(L); - Assert(MaybeScript.has_value()); - TLuaFile& Script = MaybeScript.value(); - std::thread t1(CallAsync, &Script, STR, U); - t1.detach(); - } else - SendError(Engine(), L, ("CreateThread wrong argument [2] number must be between 1 and 500")); - } else - SendError(Engine(), L, ("CreateThread wrong argument [2] need number")); - } else - SendError(Engine(), L, ("CreateThread wrong argument [1] need string")); - } else - SendError(Engine(), L, ("CreateThread not enough arguments")); - return 0; -} - -int lua_Sleep(lua_State* L) { - if (lua_isnumber(L, 1)) { - int t = int(lua_tonumber(L, 1)); - std::this_thread::sleep_for(std::chrono::milliseconds(t)); - } else { - SendError(Engine(), L, ("Sleep not enough arguments")); - return 0; - } - return 1; -} - -std::optional> GetClient(TServer& Server, int ID) { - std::optional> MaybeClient { std::nullopt }; - Server.ForEachClient([&](std::weak_ptr CPtr) -> bool { - ReadLock Lock(Server.GetClientMutex()); - if (!CPtr.expired()) { - auto C = CPtr.lock(); - if (C->GetID() == ID) { - MaybeClient = CPtr; - return false; - } - } - return true; - }); - return MaybeClient; -} - -int lua_isConnected(lua_State* L) { - if (lua_isnumber(L, 1)) { - int ID = int(lua_tonumber(L, 1)); - auto MaybeClient = GetClient(Engine().Server(), ID); - if (MaybeClient && !MaybeClient.value().expired()) - lua_pushboolean(L, MaybeClient.value().lock()->IsConnected()); - else - return 0; - } else { - SendError(Engine(), L, ("isConnected not enough arguments")); - return 0; - } - return 1; -} - -int lua_GetPlayerName(lua_State* L) { - if (lua_isnumber(L, 1)) { - int ID = int(lua_tonumber(L, 1)); - auto MaybeClient = GetClient(Engine().Server(), ID); - if (MaybeClient && !MaybeClient.value().expired()) - lua_pushstring(L, MaybeClient.value().lock()->GetName().c_str()); - else - return 0; - } else { - SendError(Engine(), L, ("GetPlayerName not enough arguments")); - return 0; - } - return 1; -} - -int lua_GetPlayerCount(lua_State* L) { - lua_pushinteger(L, Engine().Server().ClientCount()); - return 1; -} - -int lua_GetGuest(lua_State* L) { - if (lua_isnumber(L, 1)) { - int ID = int(lua_tonumber(L, 1)); - auto MaybeClient = GetClient(Engine().Server(), ID); - if (MaybeClient && !MaybeClient.value().expired()) - lua_pushboolean(L, MaybeClient.value().lock()->IsGuest()); - else - return 0; - } else { - SendError(Engine(), L, "GetGuest not enough arguments"); - return 0; - } - return 1; -} - -int lua_GetAllPlayers(lua_State* L) { - lua_newtable(L); - Engine().Server().ForEachClient([&](const std::weak_ptr& ClientPtr) -> bool { - std::shared_ptr Client; - { - ReadLock Lock(Engine().Server().GetClientMutex()); - if (ClientPtr.expired()) - return true; - Client = ClientPtr.lock(); - } - lua_pushinteger(L, Client->GetID()); - lua_pushstring(L, Client->GetName().c_str()); - lua_settable(L, -3); - return true; - }); - if (Engine().Server().ClientCount() == 0) - return 0; - return 1; -} - -int lua_GetIdentifiers(lua_State* L) { - if (lua_isnumber(L, 1)) { - auto MaybeClient = GetClient(Engine().Server(), int(lua_tonumber(L, 1))); - if (MaybeClient && !MaybeClient.value().expired()) { - auto IDs = MaybeClient.value().lock()->GetIdentifiers(); - if (IDs.empty()) - return 0; - LuaTable::Begin(L); - for (const auto& Pair : IDs) { - LuaTable::BeginEntry(L, Pair.first); - lua_pushstring(L, Pair.second.c_str()); - LuaTable::EndEntry(L); - } - } else - return 0; - } else { - SendError(Engine(), L, "lua_GetIdentifiers wrong arguments"); - return 0; - } - return 1; -} - -int lua_GetCars(lua_State* L) { - if (lua_isnumber(L, 1)) { - int ID = int(lua_tonumber(L, 1)); - auto MaybeClient = GetClient(Engine().Server(), ID); - if (MaybeClient && !MaybeClient.value().expired()) { - auto Client = MaybeClient.value().lock(); - TClient::TSetOfVehicleData VehicleData; - { // Vehicle Data Lock Scope - auto LockedData = Client->GetAllCars(); - VehicleData = *LockedData.VehicleData; - } // End Vehicle Data Lock Scope - if (VehicleData.empty()) - return 0; - lua_newtable(L); - for (const auto& v : VehicleData) { - lua_pushinteger(L, v.ID()); - lua_pushstring(L, v.Data().substr(3).c_str()); - lua_settable(L, -3); - } - } else - return 0; - } else { - SendError(Engine(), L, ("GetPlayerVehicles wrong arguments")); - return 0; - } - return 1; -} - -int lua_dropPlayer(lua_State* L) { - int Args = lua_gettop(L); - if (lua_isnumber(L, 1)) { - int ID = int(lua_tonumber(L, 1)); - auto MaybeClient = GetClient(Engine().Server(), ID); - if (!MaybeClient || MaybeClient.value().expired()) - return 0; - std::string Reason; - if (Args > 1 && lua_isstring(L, 2)) { - Reason = std::string((" Reason : ")) + lua_tostring(L, 2); - } - auto c = MaybeClient.value().lock(); - Engine().Network().Respond(*c, "C:Server:You have been Kicked from the server! " + Reason, true); - c->SetStatus(-2); - info(("Closing socket due to kick")); - CloseSocketProper(c->GetTCPSock()); - } else - SendError(Engine(), L, ("DropPlayer not enough arguments")); - return 0; -} - -int lua_sendChat(lua_State* L) { - if (lua_isinteger(L, 1) || lua_isnumber(L, 1)) { - if (lua_isstring(L, 2)) { - int ID = int(lua_tointeger(L, 1)); - if (ID == -1) { - std::string Packet = "C:Server: " + std::string(lua_tostring(L, 2)); - Engine().Network().SendToAll(nullptr, Packet, true, true); - } else { - auto MaybeClient = GetClient(Engine().Server(), ID); - if (MaybeClient && !MaybeClient.value().expired()) { - auto c = MaybeClient.value().lock(); - if (!c->IsSynced()) - return 0; - std::string Packet = "C:Server: " + std::string(lua_tostring(L, 2)); - Engine().Network().Respond(*c, Packet, true); - } else - SendError(Engine(), L, ("SendChatMessage invalid argument [1] invalid ID")); - } - } else - SendError(Engine(), L, ("SendChatMessage invalid argument [2] expected string")); - } else - SendError(Engine(), L, ("SendChatMessage invalid argument [1] expected number")); - return 0; -} - -int lua_RemoveVehicle(lua_State* L) { - int Args = lua_gettop(L); - if (Args != 2) { - SendError(Engine(), L, ("RemoveVehicle invalid argument count expected 2 got ") + std::to_string(Args)); - return 0; - } - if ((lua_isinteger(L, 1) || lua_isnumber(L, 1)) && (lua_isinteger(L, 2) || lua_isnumber(L, 2))) { - int PID = int(lua_tointeger(L, 1)); - int VID = int(lua_tointeger(L, 2)); - auto MaybeClient = GetClient(Engine().Server(), PID); - if (!MaybeClient || MaybeClient.value().expired()) { - SendError(Engine(), L, ("RemoveVehicle invalid Player ID")); - return 0; - } - auto c = MaybeClient.value().lock(); - if (!c->GetCarData(VID).empty()) { - std::string Destroy = "Od:" + std::to_string(PID) + "-" + std::to_string(VID); - Engine().Network().SendToAll(nullptr, Destroy, true, true); - c->DeleteCar(VID); - } - } else - SendError(Engine(), L, ("RemoveVehicle invalid argument expected number")); - return 0; -} - -int lua_HWID(lua_State* L) { - lua_pushinteger(L, -1); - return 1; -} - -int lua_RemoteEvent(lua_State* L) { - int Args = lua_gettop(L); - if (Args != 3) { - SendError(Engine(), L, ("TriggerClientEvent invalid argument count expected 3 got ") + std::to_string(Args)); - return 0; - } - if (!lua_isnumber(L, 1)) { - SendError(Engine(), L, ("TriggerClientEvent invalid argument [1] expected number")); - return 0; - } - if (!lua_isstring(L, 2)) { - SendError(Engine(), L, ("TriggerClientEvent invalid argument [2] expected string")); - return 0; - } - if (!lua_isstring(L, 3)) { - SendError(Engine(), L, ("TriggerClientEvent invalid argument [3] expected string")); - return 0; - } - int ID = int(lua_tointeger(L, 1)); - std::string Packet = "E:" + std::string(lua_tostring(L, 2)) + ":" + std::string(lua_tostring(L, 3)); - if (ID == -1) - Engine().Network().SendToAll(nullptr, Packet, true, true); - else { - auto MaybeClient = GetClient(Engine().Server(), ID); - if (!MaybeClient || MaybeClient.value().expired()) { - SendError(Engine(), L, ("TriggerClientEvent invalid Player ID")); - return 0; - } - auto c = MaybeClient.value().lock(); - Engine().Network().Respond(*c, Packet, true); - } - return 0; -} - -int lua_ServerExit(lua_State*) { - Application::GracefullyShutdown(); - return 0; -} - -int lua_Set(lua_State* L) { - int Args = lua_gettop(L); - if (Args != 2) { - SendError(Engine(), L, ("set invalid argument count expected 2 got ") + std::to_string(Args)); - return 0; - } - if (!lua_isnumber(L, 1)) { - SendError(Engine(), L, ("set invalid argument [1] expected number")); - return 0; - } - auto MaybeSrc = Engine().GetScript(L); - std::string Name; - if (!MaybeSrc.has_value()) { - Name = ("_Console"); - } else { - Name = MaybeSrc.value().get().GetPluginName(); - } - int C = int(lua_tointeger(L, 1)); - switch (C) { - case 0: //debug - if (lua_isboolean(L, 2)) { - Application::Settings.DebugModeEnabled = lua_toboolean(L, 2); - info(Name + (" | Set `Debug` to ") + (Application::Settings.DebugModeEnabled ? "true" : "false")); - } else - SendError(Engine(), L, ("set invalid argument [2] expected boolean for ID : 0")); - break; - case 1: //private - if (lua_isboolean(L, 2)) { - Application::Settings.Private = lua_toboolean(L, 2); - info(Name + (" | Set `Private` to ") + (Application::Settings.Private ? "true" : "false")); - } else - SendError(Engine(), L, ("set invalid argument [2] expected boolean for ID : 1")); - break; - case 2: //max cars - if (lua_isnumber(L, 2)) { - Application::Settings.MaxCars = int(lua_tointeger(L, 2)); - info(Name + (" | Set `MaxCars` to ") + std::to_string(Application::Settings.MaxCars)); - } else - SendError(Engine(), L, ("set invalid argument [2] expected number for ID : 2")); - break; - case 3: //max players - if (lua_isnumber(L, 2)) { - Application::Settings.MaxPlayers = int(lua_tointeger(L, 2)); - info(Name + (" | Set `MaxPlayers` to ") + std::to_string(Application::Settings.MaxPlayers)); - } else - SendError(Engine(), L, ("set invalid argument [2] expected number for ID : 3")); - break; - case 4: //Map - if (lua_isstring(L, 2)) { - Application::Settings.MapName = lua_tostring(L, 2); - info(Name + (" | Set `Map` to ") + Application::Settings.MapName); - } else - SendError(Engine(), L, ("set invalid argument [2] expected string for ID : 4")); - break; - case 5: //Name - if (lua_isstring(L, 2)) { - Application::Settings.ServerName = lua_tostring(L, 2); - info(Name + (" | Set `Name` to ") + Application::Settings.ServerName); - } else - SendError(Engine(), L, ("set invalid argument [2] expected string for ID : 5")); - break; - case 6: //Desc - if (lua_isstring(L, 2)) { - Application::Settings.ServerDesc = lua_tostring(L, 2); - info(Name + (" | Set `Description` to ") + Application::Settings.ServerDesc); - } else - SendError(Engine(), L, ("set invalid argument [2] expected string for ID : 6")); - break; - default: - warn(("Invalid config ID : ") + std::to_string(C)); - break; - } - return 0; -} - -extern "C" { -int InternalLuaPrint(lua_State* L, bool pretty) { - int Arg = lua_gettop(L); - std::string to_print; - for (int i = 1; i <= Arg; i++) { - if (lua_isstring(L, i)) { - to_print += lua_tostring(L, i); - } else if (lua_isinteger(L, i)) { - to_print += std::to_string(lua_tointeger(L, 1)); - } else if (lua_isnumber(L, i)) { - to_print += std::to_string(lua_tonumber(L, 1)); - } else if (lua_isboolean(L, i)) { - to_print += lua_toboolean(L, i) ? "true" : "false"; - } else if (lua_isfunction(L, i)) { - std::stringstream ss; - ss << std::hex << reinterpret_cast(lua_tocfunction(L, i)); - to_print += "function: " + ss.str(); - } else if (lua_istable(L, i)) { - std::stringstream ss; - ss << std::hex << reinterpret_cast(lua_topointer(L, i)); - to_print += "table: " + ss.str(); - } else if (lua_isnoneornil(L, i)) { - to_print += "nil"; - } else if (lua_isthread(L, i)) { - std::stringstream ss; - ss << std::hex << reinterpret_cast(lua_tothread(L, i)); - to_print += "thread: " + ss.str(); - } else { - to_print += "(unknown)"; - } - if (i + 1 <= Arg) { - to_print += "\t"; - } - } - if (pretty) { - luaprint(to_print); - } else { - Application::Console().WriteRaw(to_print); - } - return 0; -} -int lua_Print(lua_State* L) { - return InternalLuaPrint(L, true); -} -int lua_PrintRaw(lua_State* L) { - return InternalLuaPrint(L, false); -} -} - -int lua_TempFix(lua_State* L) { - if (lua_isnumber(L, 1)) { - int ID = int(lua_tonumber(L, 1)); - auto MaybeClient = GetClient(Engine().Server(), ID); - if (!MaybeClient || MaybeClient.value().expired()) - return 0; - std::string Ret; - auto c = MaybeClient.value().lock(); - if (c->IsGuest()) { - Ret = "Guest-" + c->GetName(); - } else - Ret = c->GetName(); - lua_pushstring(L, Ret.c_str()); - } else - SendError(Engine(), L, "GetDID not enough arguments"); - return 1; -} - -int lua_Registered(lua_State* L) { - - lua_Debug info; - lua_getstack(L, 0, &info); - lua_getinfo(L, "n", &info); - - if (auto it = TLuaEngine::mGlobals.find(info.name); it != TLuaEngine::mGlobals.end()) { - lua_getglobal(it->second, info.name); - if (lua_isfunction(it->second, -1)) { - lua_pcall(it->second, 0, 0, 0); //TODO revisit to allow arguments and return also we need to mutex this - } - return 0; - } - - SendError(Engine(), L, "Cannot find global '" + std::string(info.name) + "\'"); - return 0; -} - -int lua_Register(lua_State* L) { - if (lua_isstring(L, 1)) { - std::string Name(lua_tolstring(L, 1, nullptr)); - lua_getglobal(L, Name.c_str()); - if (lua_isfunction(L, -1)) { - TLuaEngine::mGlobals.emplace(Name, L); - for (auto& Script : Engine().LuaFiles()) { - if (Script->GetState() != L) { - lua_register(Script->GetState(), Name.c_str(), lua_Registered); - } - } - - } else { - SendError(Engine(), L, Name + " is not a global function!"); - ClearStack(L); - } - } else { - SendError(Engine(), L, "Wrong arguments to `Register`, expected string"); - } - return 0; -} - -void TLuaFile::Init(const std::string& PluginName, const std::string& FileName, fs::file_time_type LastWrote) { - // set global engine for lua_* functions - if (!TheEngine) { - TheEngine = &mEngine; - } - Assert(mLuaState); - if (!PluginName.empty()) { - SetPluginName(PluginName); - } - if (!FileName.empty()) { - SetFileName(FileName); - } - SetLastWrite(LastWrote); - Load(); -} - -TLuaFile::TLuaFile(TLuaEngine& Engine, bool Console) - : mEngine(Engine) - , mLuaState(luaL_newstate()) { - if (Console) { - mConsole = Console; - Load(); - } -} - -void TLuaFile::Execute(const std::string& Command) { - if (ConsoleCheck(mLuaState, luaL_dostring(mLuaState, Command.c_str()))) { - lua_settop(mLuaState, 0); - } -} - -void TLuaFile::Reload() { - if (CheckLua(mLuaState, luaL_dofile(mLuaState, mFileName.c_str()))) { - CallFunction(this, ("onInit"), nullptr); - } -} - -std::string TLuaFile::GetOrigin() { - return fs::path(GetFileName()).filename().string(); -} - -std::any CallFunction(TLuaFile* lua, const std::string& FuncName, std::shared_ptr Arg) { - RegisterThread(lua->GetFileName()); - lua_State* luaState = lua->GetState(); - lua_getglobal(luaState, FuncName.c_str()); - if (lua_isfunction(luaState, -1)) { - int Size = 0; - if (Arg != nullptr) { - Size = int(Arg->args.size()); - Arg->PushArgs(luaState); - } - int R = lua_pcall(luaState, Size, 1, 0); - if (CheckLua(luaState, R)) { - if (lua_isnumber(luaState, -1)) { - auto ret = int(lua_tointeger(luaState, -1)); - ClearStack(luaState); - return ret; - } else if (lua_isstring(luaState, -1)) { - auto ret = std::string(lua_tostring(luaState, -1)); - ClearStack(luaState); - return ret; - } - } - } - ClearStack(luaState); - return 0; -} - -void TLuaFile::SetPluginName(const std::string& Name) { - mPluginName = Name; -} - -void TLuaFile::SetFileName(const std::string& Name) { - mFileName = Name; -} - -// GetOSName() -> Linux || Windows || Other -int lua_GetOSName(lua_State* L) { -#if defined(__linux) || defined(__linux__) - lua_pushstring(L, "Linux"); -#elif defined(WIN32) - lua_pushstring(L, "Windows"); -#else - lua_pushstring(L, "Unknown"); -#endif - return 1; -} - -int lua_GetServerVersion(lua_State* L) { - const auto& ver = Application::ServerVersion(); - lua_pushinteger(L, ver.major); - lua_pushinteger(L, ver.minor); - lua_pushinteger(L, ver.patch); - return 3; -} - -// status, body = HttpsGET(host, port, target) -// example usage: -// send a GET https://example.com:443/index.html: -// status, body = MP.HttpGET("example.com", 443, "/index.html") -int lua_HttpsGET(lua_State* L) { - if (!lua_isstring(L, 1)) { - SendError(Engine(), L, "`HttpsGET` expects host (type string) as first argument."); - ClearStack(L); - return 0; - } - if (!lua_isnumber(L, 2)) { - SendError(Engine(), L, "`HttpsGET` expects port (type number) as second argument."); - ClearStack(L); - return 0; - } - if (!lua_isstring(L, 3)) { - SendError(Engine(), L, "`HttpsGET` expects target (type string) as third argument."); - ClearStack(L); - return 0; - } - - auto Host = lua_tostring(L, 1); - auto Port = int(lua_tointeger(L, 2)); - auto Target = lua_tostring(L, 3); - - ClearStack(L); - - unsigned int Status; - auto Body = Http::GET(Host, Port, Target, &Status); - lua_pushinteger(L, Status); - - auto PrettyRemote = "https://" + std::string(Host) + ":" + std::to_string(Port) + std::string(Target); - if (Body == Http::ErrorString) { - SendError(Engine(), L, "HTTPS GET " + PrettyRemote + " failed status " + std::to_string(Status) + ". Check the console or log for more info."); - return 1; - } else { - debug("GET " + PrettyRemote + " completed status " + std::to_string(Status)); - } - - lua_pushstring(L, Body.c_str()); - - return 2; -} - -// status, body = HttpsPOST(host, port, target, body, content_type) -int lua_HttpsPOST(lua_State* L) { - if (!lua_isstring(L, 1)) { - SendError(Engine(), L, "`HttpsPOST` expects host (type string) as 1. argument."); - ClearStack(L); - return 0; - } - if (!lua_isnumber(L, 2)) { - SendError(Engine(), L, "`HttpsPOST` expects port (type number) as 2. argument."); - ClearStack(L); - return 0; - } - if (!lua_isstring(L, 3)) { - SendError(Engine(), L, "`HttpsPOST` expects target (type string) as 3. argument."); - ClearStack(L); - return 0; - } - if (!lua_isstring(L, 4)) { - SendError(Engine(), L, "`HttpsPOST` expects body (type string) as 4. argument."); - ClearStack(L); - return 0; - } - if (!lua_isstring(L, 5)) { - SendError(Engine(), L, "`HttpsPOST` expects content_type (type string) as 5. argument."); - ClearStack(L); - return 0; - } - - auto Host = lua_tostring(L, 1); - auto Port = int(lua_tointeger(L, 2)); - auto Target = lua_tostring(L, 3); - auto RequestBody = lua_tostring(L, 4); - auto ContentType = lua_tostring(L, 5); - - ClearStack(L); - - // build fields - std::unordered_map Fields; - - unsigned int Status; - auto ResponseBody = Http::POST(Host, Port, Target, {}, RequestBody, ContentType, &Status); - - lua_pushinteger(L, Status); - - auto PrettyRemote = "https://" + std::string(Host) + ":" + std::to_string(Port) + std::string(Target); - if (ResponseBody == Http::ErrorString) { - SendError(Engine(), L, "HTTPS POST " + PrettyRemote + " failed status " + std::to_string(Status) + ". Check the console or log for more info."); - return 1; - } else { - debug("POST " + PrettyRemote + " completed status " + std::to_string(Status)); - } - - lua_pushstring(L, ResponseBody.c_str()); - return 2; -} - -void TLuaFile::Load() { - Assert(mLuaState); - luaL_openlibs(mLuaState); - - LuaTable::Begin(mLuaState); - - LuaTable::BeginEntry(mLuaState, "Settings"); - LuaTable::Begin(mLuaState); - // put Settings enums here - LuaTable::InsertInteger(mLuaState, "Debug", 0); - LuaTable::InsertInteger(mLuaState, "Private", 1); - LuaTable::InsertInteger(mLuaState, "MaxCars", 2); - LuaTable::InsertInteger(mLuaState, "MaxPlayers", 3); - LuaTable::InsertInteger(mLuaState, "Map", 4); - LuaTable::InsertInteger(mLuaState, "Name", 5); - LuaTable::InsertInteger(mLuaState, "Description", 6); - LuaTable::EndEntry(mLuaState); - - LuaTable::InsertFunction(mLuaState, "GetPlayerIdentifiers", lua_GetIdentifiers); - LuaTable::InsertFunction(mLuaState, "TriggerGlobalEvent", lua_TriggerEventG); - LuaTable::InsertFunction(mLuaState, "TriggerLocalEvent", lua_TriggerEventL); - LuaTable::InsertFunction(mLuaState, "TriggerClientEvent", lua_RemoteEvent); - LuaTable::InsertFunction(mLuaState, "GetPlayerCount", lua_GetPlayerCount); - LuaTable::InsertFunction(mLuaState, "IsPlayerConnected", lua_isConnected); - LuaTable::InsertFunction(mLuaState, "RegisterEvent", lua_RegisterEvent); - LuaTable::InsertFunction(mLuaState, "GetPlayerName", lua_GetPlayerName); - LuaTable::InsertFunction(mLuaState, "RemoveVehicle", lua_RemoveVehicle); - LuaTable::InsertFunction(mLuaState, "GetPlayerDiscordID", lua_TempFix); - LuaTable::InsertFunction(mLuaState, "CreateThread", lua_CreateThread); - LuaTable::InsertFunction(mLuaState, "GetPlayerVehicles", lua_GetCars); - LuaTable::InsertFunction(mLuaState, "SendChatMessage", lua_sendChat); - LuaTable::InsertFunction(mLuaState, "GetPlayers", lua_GetAllPlayers); - LuaTable::InsertFunction(mLuaState, "GetPlayerGuest", lua_GetGuest); - LuaTable::InsertFunction(mLuaState, "StopThread", lua_StopThread); - LuaTable::InsertFunction(mLuaState, "DropPlayer", lua_dropPlayer); - LuaTable::InsertFunction(mLuaState, "Register", lua_Register); - LuaTable::InsertFunction(mLuaState, "GetPlayerHWID", lua_HWID); - LuaTable::InsertFunction(mLuaState, "Sleep", lua_Sleep); - LuaTable::InsertFunction(mLuaState, "Set", lua_Set); - LuaTable::InsertFunction(mLuaState, "GetOSName", lua_GetOSName); - LuaTable::InsertFunction(mLuaState, "HttpsGET", lua_HttpsGET); - LuaTable::InsertFunction(mLuaState, "HttpsPOST", lua_HttpsPOST); - LuaTable::InsertFunction(mLuaState, "GetServerVersion", lua_GetServerVersion); - - LuaTable::End(mLuaState, "MP"); - - lua_register(mLuaState, "print", lua_Print); - lua_register(mLuaState, "printRaw", lua_PrintRaw); - lua_register(mLuaState, "exit", lua_ServerExit); - if (!mConsole) - Reload(); -} - -void TLuaFile::RegisterEvent(const std::string& Event, const std::string& FunctionName) { - mRegisteredEvents.insert(std::make_pair(Event, FunctionName)); -} - -void TLuaFile::UnRegisterEvent(const std::string& Event) { - for (const std::pair& a : mRegisteredEvents) { - if (a.first == Event) { - mRegisteredEvents.erase(a); - break; - } - } -} - -bool TLuaFile::IsRegistered(const std::string& Event) { - for (const std::pair& a : mRegisteredEvents) { - if (a.first == Event) - return true; - } - return false; -} - -std::string TLuaFile::GetRegistered(const std::string& Event) const { - for (const std::pair& a : mRegisteredEvents) { - if (a.first == Event) - return a.second; - } - return ""; -} - -std::string TLuaFile::GetFileName() const { - return mFileName; -} - -std::string TLuaFile::GetPluginName() const { - return mPluginName; -} - -lua_State* TLuaFile::GetState() { - return mLuaState; -} - -const lua_State* TLuaFile::GetState() const { - return mLuaState; -} - -void TLuaFile::SetLastWrite(fs::file_time_type time) { - mLastWrote = time; -} -fs::file_time_type TLuaFile::GetLastWrite() { - return mLastWrote; -} - -TLuaFile::~TLuaFile() { - info("closing lua state"); - lua_close(mLuaState); -} - -void SendError(TLuaEngine& Engine, lua_State* L, const std::string& msg) { - Assert(L); - auto MaybeS = Engine.GetScript(L); - std::string a; - if (!MaybeS.has_value()) { - a = ("_Console"); - } else { - TLuaFile& S = MaybeS.value(); - a = fs::path(S.GetFileName()).filename().string(); - } - warn(a + (" | Error in MP Lua call: ") + msg); -} - -void TLuaArg::PushArgs(lua_State* State) { - for (std::any arg : args) { - if (!arg.has_value()) { - error("arg didn't have a value, this is not expected, bad"); - return; - } - const auto& Type = arg.type(); - if (Type == typeid(bool)) { - lua_pushboolean(State, std::any_cast(arg)); - } else if (Type == typeid(std::string)) { - lua_pushstring(State, std::any_cast(arg).c_str()); - } else if (Type == typeid(const char*)) { - lua_pushstring(State, std::any_cast(arg)); - } else if (Type == typeid(int)) { - lua_pushinteger(State, std::any_cast(arg)); - } else if (Type == typeid(float)) { - lua_pushnumber(State, std::any_cast(arg)); - } else if (Type == typeid(double)) { - lua_pushnumber(State, std::any_cast(arg)); - } else { - // if this happens, implement a sane behavior for that value - error("what in the hell is " + std::string(arg.type().name())); - } - } -} From d0826205255925eef982221978428979beb75ec5 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 16 Sep 2021 00:34:09 +0200 Subject: [PATCH 081/255] add sol2 --- .gitmodules | 2 +- deps/sol2 | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 160000 deps/sol2 diff --git a/.gitmodules b/.gitmodules index bb41fae..26aa89c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,6 +13,6 @@ [submodule "include/toml11"] path = deps/toml11 url = https://github.com/ToruNiina/toml11 -[submodule "include/sol2"] +[submodule "deps/sol2"] path = deps/sol2 url = https://github.com/ThePhD/sol2 diff --git a/deps/sol2 b/deps/sol2 new file mode 160000 index 0000000..b43cee5 --- /dev/null +++ b/deps/sol2 @@ -0,0 +1 @@ +Subproject commit b43cee5c9db30fc961b9d7210a1db05d60965f40 From dd4e4c44674936664aafd864e887c25465561f96 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 16 Sep 2021 01:04:01 +0200 Subject: [PATCH 082/255] Start rewrite of lua, rename all print functions --- CMakeLists.txt | 8 +- deps/CMakeLists.txt | 1 + include/Common.h | 8 +- include/TConsole.h | 5 +- include/TLuaEngine.h | 32 ++++++++ include/{TLuaFile.h => TLuaPlugin.h} | 0 src/Client.cpp | 2 +- src/Common.cpp | 2 +- src/Http.cpp | 2 +- src/TConfig.cpp | 36 ++++----- src/TConsole.cpp | 11 ++- src/THeartbeatThread.cpp | 14 ++-- src/TLuaEngine.cpp | 44 +++++++++++ src/{TLuaFile.cpp => TLuaPlugin.cpp} | 0 src/TNetwork.cpp | 106 +++++++++++++-------------- src/TPPSMonitor.cpp | 8 +- src/TResourceManager.cpp | 2 +- src/TServer.cpp | 54 +++++++------- src/VehicleData.cpp | 4 +- src/main.cpp | 12 +-- 20 files changed, 215 insertions(+), 136 deletions(-) rename include/{TLuaFile.h => TLuaPlugin.h} (100%) rename src/{TLuaFile.cpp => TLuaPlugin.cpp} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9618fdd..2d3defc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,7 +38,7 @@ add_executable(BeamMP-Server include/VehicleData.h src/VehicleData.cpp include/TConfig.h src/TConfig.cpp include/TLuaEngine.h src/TLuaEngine.cpp - include/TLuaFile.h src/TLuaFile.cpp + include/TLuaPlugin.h src/TLuaPlugin.cpp include/TResourceManager.h src/TResourceManager.cpp include/THeartbeatThread.h src/THeartbeatThread.cpp include/Http.h src/Http.cpp @@ -49,19 +49,19 @@ target_include_directories(BeamMP-Server PRIVATE "${PROJECT_SOURCE_DIR}/deps/asi target_include_directories(BeamMP-Server PRIVATE "${PROJECT_SOURCE_DIR}/deps/rapidjson/include") target_include_directories(BeamMP-Server PRIVATE "${PROJECT_SOURCE_DIR}/deps/websocketpp") target_include_directories(BeamMP-Server PRIVATE "${PROJECT_SOURCE_DIR}/deps/commandline") +target_include_directories(BeamMP-Server PRIVATE "${PROJECT_SOURCE_DIR}/deps/sol2/include") target_include_directories(BeamMP-Server PRIVATE "${PROJECT_SOURCE_DIR}/deps") include_directories(BeamMP-Server PUBLIC ${Boost_INCLUDE_DIRS} ${LUA_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/include) -find_package(Lua REQUIRED) find_package(OpenSSL REQUIRED) if (UNIX) - target_link_libraries(BeamMP-Server z pthread stdc++fs ${LUA_LIBRARIES} crypto ${OPENSSL_LIBRARIES} commandline sioclient_tls) + target_link_libraries(BeamMP-Server z pthread stdc++fs ${SOL2_LIBRARIES} crypto ${OPENSSL_LIBRARIES} commandline sioclient_tls) elseif (WIN32) include(FindLua) find_package(ZLIB REQUIRED) find_package(RapidJSON CONFIG REQUIRED) target_include_directories(BeamMP-Server PRIVATE ${RAPIDJSON_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}) - target_link_libraries(BeamMP-Server PRIVATE ws2_32 ZLIB::ZLIB ${LUA_LIBRARIES} ${OPENSSL_LIBRARIES} commandline sioclient_tls) + target_link_libraries(BeamMP-Server PRIVATE ws2_32 ZLIB::ZLIB ${SOL2_LIBRARIES} ${OPENSSL_LIBRARIES} commandline sioclient_tls) endif () diff --git a/deps/CMakeLists.txt b/deps/CMakeLists.txt index e204f2c..06cef70 100644 --- a/deps/CMakeLists.txt +++ b/deps/CMakeLists.txt @@ -1,2 +1,3 @@ add_subdirectory("${PROJECT_SOURCE_DIR}/deps/socket.io-client-cpp") add_subdirectory("${PROJECT_SOURCE_DIR}/deps/commandline") +add_subdirectory("${PROJECT_SOURCE_DIR}/deps/sol2") diff --git a/include/Common.h b/include/Common.h index e991c5f..52577f9 100644 --- a/include/Common.h +++ b/include/Common.h @@ -122,11 +122,11 @@ void RegisterThread(const std::string str); #endif // defined(DEBUG) -#define warn(x) Application::Console().Write(_this_location + std::string("[WARN] ") + (x)) -#define info(x) Application::Console().Write(_this_location + std::string("[INFO] ") + (x)) -#define error(x) Application::Console().Write(_this_location + std::string("[ERROR] ") + (x)) +#define beammp_warn(x) Application::Console().Write(_this_location + std::string("[WARN] ") + (x)) +#define beammp_info(x) Application::Console().Write(_this_location + std::string("[INFO] ") + (x)) +#define beammp_error(x) Application::Console().Write(_this_location + std::string("[ERROR] ") + (x)) #define luaprint(x) Application::Console().Write(_this_location + std::string("[LUA] ") + (x)) -#define debug(x) \ +#define beammp_debug(x) \ do { \ if (Application::Settings.DebugModeEnabled) { \ Application::Console().Write(_this_location + std::string("[DEBUG] ") + (x)); \ diff --git a/include/TConsole.h b/include/TConsole.h index 592bfb8..7063d5d 100644 --- a/include/TConsole.h +++ b/include/TConsole.h @@ -1,6 +1,5 @@ #pragma once -#include "TLuaFile.h" #include #include #include "commandline.h" @@ -11,9 +10,9 @@ public: void Write(const std::string& str); void WriteRaw(const std::string& str); - void InitializeLuaConsole(TLuaEngine& Engine); + // BROKEN void InitializeLuaConsole(TLuaEngine& Engine); private: - std::unique_ptr mLuaConsole { nullptr }; +// BROKEN std::unique_ptr mLuaConsole { nullptr }; Commandline mCommandline; }; diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index e69de29..770d949 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -0,0 +1,32 @@ +#pragma once + +#include "TNetwork.h" +#include "TServer.h" +#include +#include +#include +#include +#include + +namespace fs = std::filesystem; + +class TLuaPlugin; + +class TLuaEngine : IThreaded { +public: + TLuaEngine(TServer& Server, TNetwork& Network); + + void operator()() override; + +private: + void CollectPlugins(); + void InitializePlugin(const fs::path& folder); + + TNetwork& mNetwork; + TServer& mServer; + sol::state mL; + std::atomic_bool mShutdown { false }; + fs::path mResourceServerPath; + std::vector mLuaPlugins; + std::unordered_map mLuaStates; +}; diff --git a/include/TLuaFile.h b/include/TLuaPlugin.h similarity index 100% rename from include/TLuaFile.h rename to include/TLuaPlugin.h diff --git a/src/Client.cpp b/src/Client.cpp index a57837a..8cf8722 100644 --- a/src/Client.cpp +++ b/src/Client.cpp @@ -13,7 +13,7 @@ void TClient::DeleteCar(int Ident) { if (iter != mVehicleData.end()) { mVehicleData.erase(iter); } else { - debug("tried to erase a vehicle that doesn't exist (not an error)"); + beammp_debug("tried to erase a vehicle that doesn't exist (not an error)"); } } diff --git a/src/Common.cpp b/src/Common.cpp index 1cfcdb6..0c535f7 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -17,7 +17,7 @@ void Application::RegisterShutdownHandler(const TShutdownHandler& Handler) { } void Application::GracefullyShutdown() { - info("please wait while all subsystems are shutting down..."); + beammp_info("please wait while all subsystems are shutting down..."); std::unique_lock Lock(mShutdownHandlersMutex); for (auto& Handler : mShutdownHandlers) { Handler(); diff --git a/src/Http.cpp b/src/Http.cpp index 00c557b..a97b833 100644 --- a/src/Http.cpp +++ b/src/Http.cpp @@ -1,7 +1,7 @@ #include "Http.h" #include "Common.h" -#undef error +#undef beammp_error #include #include diff --git a/src/TConfig.cpp b/src/TConfig.cpp index 8a2d9f4..9102e9e 100644 --- a/src/TConfig.cpp +++ b/src/TConfig.cpp @@ -23,12 +23,12 @@ static constexpr std::string_view StrAuthKey = "AuthKey"; TConfig::TConfig() { if (!fs::exists(ConfigFileName) || !fs::is_regular_file(ConfigFileName)) { - info("No config file found! Generating one..."); + beammp_info("No config file found! Generating one..."); CreateConfigFile(ConfigFileName); } if (!mFailed) { if (fs::exists("Server.cfg")) { - warn("An old \"Server.cfg\" file still exists. Please note that this is no longer used. Instead, \"" + std::string(ConfigFileName) + "\" is used. You can safely delete the \"Server.cfg\"."); + beammp_warn("An old \"Server.cfg\" file still exists. Please note that this is no longer used. Instead, \"" + std::string(ConfigFileName) + "\" is used. You can safely delete the \"Server.cfg\"."); } ParseFromFile(ConfigFileName); } @@ -60,7 +60,7 @@ void TConfig::CreateConfigFile(std::string_view name) { ParseOldFormat(); } } catch (const std::exception& e) { - error("an error occurred and was ignored during config transfer: " + std::string(e.what())); + beammp_error("an error occurred and was ignored during config transfer: " + std::string(e.what())); } { // create file context @@ -88,10 +88,10 @@ void TConfig::CreateConfigFile(std::string_view name) { "# IMPORTANT: Fill in the AuthKey with the key you got from `https://beammp.com/k/dashboard` on the left under \"Keys\"\n" << '\n'; ofs << data << '\n'; - error("There was no \"" + std::string(ConfigFileName) + "\" file (this is normal for the first time running the server), so one was generated for you. It was automatically filled with the settings from your Server.cfg, if you have one. Please open ServerConfig.toml and ensure your AuthKey and other settings are filled in and correct, then restart the server. The old Server.cfg file will no longer be used and causes a warning if it exists from now on."); + beammp_error("There was no \"" + std::string(ConfigFileName) + "\" file (this is normal for the first time running the server), so one was generated for you. It was automatically filled with the settings from your Server.cfg, if you have one. Please open ServerConfig.toml and ensure your AuthKey and other settings are filled in and correct, then restart the server. The old Server.cfg file will no longer be used and causes a warning if it exists from now on."); mFailed = true; } else { - error("Couldn't create " + std::string(name) + ". Check permissions, try again, and contact support if it continues not to work."); + beammp_error("Couldn't create " + std::string(name) + ". Check permissions, try again, and contact support if it continues not to work."); mFailed = true; } } @@ -110,30 +110,30 @@ void TConfig::ParseFromFile(std::string_view name) { Application::Settings.Resource = data["General"][StrResourceFolder.data()].as_string(); Application::Settings.Key = data["General"][StrAuthKey.data()].as_string(); } catch (const std::exception& err) { - error("Error parsing config file value: " + std::string(err.what())); + beammp_error("Error parsing config file value: " + std::string(err.what())); mFailed = true; return; } PrintDebug(); // all good so far, let's check if there's a key if (Application::Settings.Key.empty()) { - error("No AuthKey specified in the \"" + std::string(ConfigFileName) + "\" file. Please get an AuthKey, enter it into the config file, and restart this server."); + beammp_error("No AuthKey specified in the \"" + std::string(ConfigFileName) + "\" file. Please get an AuthKey, enter it into the config file, and restart this server."); mFailed = true; } } void TConfig::PrintDebug() { - debug(std::string(StrDebug) + ": " + std::string(Application::Settings.DebugModeEnabled ? "true" : "false")); - debug(std::string(StrPrivate) + ": " + std::string(Application::Settings.Private ? "true" : "false")); - debug(std::string(StrPort) + ": " + std::to_string(Application::Settings.Port)); - debug(std::string(StrMaxCars) + ": " + std::to_string(Application::Settings.MaxCars)); - debug(std::string(StrMaxPlayers) + ": " + std::to_string(Application::Settings.MaxPlayers)); - debug(std::string(StrMap) + ": \"" + Application::Settings.MapName + "\""); - debug(std::string(StrName) + ": \"" + Application::Settings.ServerName + "\""); - debug(std::string(StrDescription) + ": \"" + Application::Settings.ServerDesc + "\""); - debug(std::string(StrResourceFolder) + ": \"" + Application::Settings.Resource + "\""); + beammp_debug(std::string(StrDebug) + ": " + std::string(Application::Settings.DebugModeEnabled ? "true" : "false")); + beammp_debug(std::string(StrPrivate) + ": " + std::string(Application::Settings.Private ? "true" : "false")); + beammp_debug(std::string(StrPort) + ": " + std::to_string(Application::Settings.Port)); + beammp_debug(std::string(StrMaxCars) + ": " + std::to_string(Application::Settings.MaxCars)); + beammp_debug(std::string(StrMaxPlayers) + ": " + std::to_string(Application::Settings.MaxPlayers)); + beammp_debug(std::string(StrMap) + ": \"" + Application::Settings.MapName + "\""); + beammp_debug(std::string(StrName) + ": \"" + Application::Settings.ServerName + "\""); + beammp_debug(std::string(StrDescription) + ": \"" + Application::Settings.ServerDesc + "\""); + beammp_debug(std::string(StrResourceFolder) + ": \"" + Application::Settings.Resource + "\""); // special! - debug("Key Length: " + std::to_string(Application::Settings.Key.length()) + ""); + beammp_debug("Key Length: " + std::to_string(Application::Settings.Key.length()) + ""); } void TConfig::ParseOldFormat() { @@ -183,7 +183,7 @@ void TConfig::ParseOldFormat() { } else if (Key == "AuthKey") { Application::Settings.Key = Value.substr(1, Value.size() - 3); } else { - warn("unknown key in old auth file (ignored): " + Key); + beammp_warn("unknown key in old auth file (ignored): " + Key); } Str >> std::ws; } diff --git a/src/TConsole.cpp b/src/TConsole.cpp index b3742fd..1f2a80c 100644 --- a/src/TConsole.cpp +++ b/src/TConsole.cpp @@ -45,22 +45,23 @@ TConsole::TConsole() { mCommandline.set_prompt("> "); bool success = mCommandline.enable_write_to_file("Server.log"); if (!success) { - error("unable to open file for writing: \"Server.log\""); + beammp_error("unable to open file for writing: \"Server.log\""); } mCommandline.on_command = [this](Commandline& c) { auto cmd = c.get_command(); mCommandline.write("> " + cmd); if (cmd == "exit") { - info("gracefully shutting down"); + beammp_info("gracefully shutting down"); Application::GracefullyShutdown(); } else if (cmd == "clear" || cmd == "cls") { // TODO: clear screen } else { - if (mLuaConsole) { + /*if (mLuaConsole) { mLuaConsole->Execute(cmd); } else { error("Lua subsystem not yet initialized, please wait a few seconds and try again"); - } + } BROKEN + */ } }; } @@ -70,9 +71,11 @@ void TConsole::Write(const std::string& str) { mCommandline.write(ToWrite); // TODO write to logfile, too } +/* BROKEN void TConsole::InitializeLuaConsole(TLuaEngine& Engine) { mLuaConsole = std::make_unique(Engine, true); } +*/ void TConsole::WriteRaw(const std::string& str) { mCommandline.write(str); } diff --git a/src/THeartbeatThread.cpp b/src/THeartbeatThread.cpp index 607fd94..f049e94 100644 --- a/src/THeartbeatThread.cpp +++ b/src/THeartbeatThread.cpp @@ -26,7 +26,7 @@ void THeartbeatThread::operator()() { std::this_thread::sleep_for(std::chrono::milliseconds(100)); continue; } - debug("heartbeat (after " + std::to_string(std::chrono::duration_cast(TimePassed).count()) + "s)"); + beammp_debug("heartbeat (after " + std::to_string(std::chrono::duration_cast(TimePassed).count()) + "s)"); Last = Body; LastNormalUpdateTime = Now; @@ -43,18 +43,18 @@ void THeartbeatThread::operator()() { T = Http::POST(Application::GetBackendHostname(), 443, "/heartbeat", {}, Body, "application/x-www-form-urlencoded"); // TODO backup2 + HTTP flag (no TSL) if (T.substr(0, 2) != "20") { - warn("Backend system refused server! Server might not show in the public list"); - debug("server returned \"" + T + "\""); + beammp_warn("Backend system refused server! Server might not show in the public list"); + beammp_debug("server returned \"" + T + "\""); isAuth = false; } } if (!isAuth) { if (T == "2000") { - info(("Authenticated!")); + beammp_info(("Authenticated!")); isAuth = true; } else if (T == "200") { - info(("Resumed authenticated session!")); + beammp_info(("Resumed authenticated session!")); isAuth = true; } } @@ -86,10 +86,10 @@ THeartbeatThread::THeartbeatThread(TResourceManager& ResourceManager, TServer& S , mServer(Server) { Application::RegisterShutdownHandler([&] { if (mThread.joinable()) { - debug("shutting down Heartbeat"); + beammp_debug("shutting down Heartbeat"); mShutdown = true; mThread.join(); - debug("shut down Heartbeat"); + beammp_debug("shut down Heartbeat"); } }); Start(); diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index e69de29..990bc08 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -0,0 +1,44 @@ +#include "TLuaEngine.h" +#include "CustomAssert.h" + +TLuaEngine::TLuaEngine(TServer& Server, TNetwork& Network) + : mNetwork(Network) + , mServer(Server) { + if (!fs::exists(Application::Settings.Resource)) { + fs::create_directory(Application::Settings.Resource); + } + fs::path Path = fs::path(Application::Settings.Resource) / "Server"; + if (!fs::exists(Path)) { + fs::create_directory(Path); + } + mResourceServerPath = Path; + Application::RegisterShutdownHandler([&] { + mShutdown = true; + if (mThread.joinable()) { + mThread.join(); + } + }); +} + +void TLuaEngine::operator()() { + RegisterThread("LuaEngine"); + // lua engine main thread + CollectPlugins(); +} + +void TLuaEngine::CollectPlugins() { + for (const auto& dir : fs::directory_iterator(mResourceServerPath)) { + auto path = dir.path(); + path = fs::relative(path); + if (!dir.is_directory()) { + beammp_error("\"" + dir.path().string() + "\" is not a directory, skipping"); + } else { + beammp_debug("found plugin directory: " + path.string()); + } + } +} + +void TLuaEngine::InitializePlugin(const fs::path& folder) { + Assert(fs::exists(folder)); + Assert(fs::is_directory(folder)); +} diff --git a/src/TLuaFile.cpp b/src/TLuaPlugin.cpp similarity index 100% rename from src/TLuaFile.cpp rename to src/TLuaPlugin.cpp diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index 99e5395..66d4299 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -10,7 +10,7 @@ TNetwork::TNetwork(TServer& Server, TPPSMonitor& PPSMonitor, TResourceManager& R , mPPSMonitor(PPSMonitor) , mResourceManager(ResourceManager) { Application::RegisterShutdownHandler([&] { - debug("Kicking all players due to shutdown"); + beammp_debug("Kicking all players due to shutdown"); Server.ForEachClient([&](std::weak_ptr client) -> bool { if (!client.expired()) { ClientKick(*client.lock(), "Server shutdown"); @@ -20,18 +20,18 @@ TNetwork::TNetwork(TServer& Server, TPPSMonitor& PPSMonitor, TResourceManager& R }); Application::RegisterShutdownHandler([&] { if (mUDPThread.joinable()) { - debug("shutting down TCPServer"); + beammp_debug("shutting down TCPServer"); mShutdown = true; mUDPThread.detach(); - debug("shut down TCPServer"); + beammp_debug("shut down TCPServer"); } }); Application::RegisterShutdownHandler([&] { if (mTCPThread.joinable()) { - debug("shutting down TCPServer"); + beammp_debug("shutting down TCPServer"); mShutdown = true; mTCPThread.detach(); - debug("shut down TCPServer"); + beammp_debug("shut down TCPServer"); } }); mTCPThread = std::thread(&TNetwork::TCPServerMain, this); @@ -56,13 +56,13 @@ void TNetwork::UDPServerMain() { // Try and bind the socket to the IP and port if (bind(mUDPSock, (sockaddr*)&serverAddr, sizeof(serverAddr)) != 0) { - error("bind() failed: " + GetPlatformAgnosticErrorString()); + beammp_error("bind() failed: " + GetPlatformAgnosticErrorString()); std::this_thread::sleep_for(std::chrono::seconds(5)); exit(-1); //return; } - info(("Vehicle data network online on port ") + std::to_string(Application::Settings.Port) + (" with a Max of ") + beammp_info(("Vehicle data network online on port ") + std::to_string(Application::Settings.Port) + (" with a Max of ") + std::to_string(Application::Settings.MaxPlayers) + (" Clients")); while (!mShutdown) { try { @@ -94,7 +94,7 @@ void TNetwork::UDPServerMain() { return true; }); } catch (const std::exception& e) { - error(("fatal: ") + std::string(e.what())); + beammp_error(("fatal: ") + std::string(e.what())); } } } @@ -118,40 +118,40 @@ void TNetwork::TCPServerMain() { addr.sin_family = AF_INET; addr.sin_port = htons(uint16_t(Application::Settings.Port)); if (bind(Listener, (sockaddr*)&addr, sizeof(addr)) != 0) { - error("bind() failed: " + GetPlatformAgnosticErrorString()); + beammp_error("bind() failed: " + GetPlatformAgnosticErrorString()); std::this_thread::sleep_for(std::chrono::seconds(5)); exit(-1); } if (Listener == -1) { - error("Invalid listening socket"); + beammp_error("Invalid listening socket"); return; } if (listen(Listener, SOMAXCONN)) { - error("listen() failed: " + GetPlatformAgnosticErrorString()); + beammp_error("listen() failed: " + GetPlatformAgnosticErrorString()); // FIXME leak Listener return; } - info(("Vehicle event network online")); + beammp_info(("Vehicle event network online")); do { try { if (mShutdown) { - debug("shutdown during TCP wait for accept loop"); + beammp_debug("shutdown during TCP wait for accept loop"); break; } client.SockAddrLen = sizeof(client.SockAddr); client.Socket = accept(Listener, &client.SockAddr, &client.SockAddrLen); if (client.Socket == -1) { - warn(("Got an invalid client socket on connect! Skipping...")); + beammp_warn(("Got an invalid client socket on connect! Skipping...")); continue; } std::thread ID(&TNetwork::Identify, this, client); ID.detach(); // TODO: Add to a queue and attempt to join periodically } catch (const std::exception& e) { - error(("fatal: ") + std::string(e.what())); + beammp_error(("fatal: ") + std::string(e.what())); } } while (client.Socket); - debug("all ok, arrived at " + std::string(__func__) + ":" + std::to_string(__LINE__)); + beammp_debug("all ok, arrived at " + std::string(__func__) + ":" + std::to_string(__LINE__)); CloseSocketProper(client.Socket); #ifdef WIN32 @@ -208,7 +208,7 @@ void TNetwork::Authentication(const TConnection& ClientConnection) { Client->SetIdentifier("ip", str); std::string Rc; - info("Identifying new ClientConnection..."); + beammp_info("Identifying new ClientConnection..."); Rc = TCPRcv(*Client); @@ -246,7 +246,7 @@ void TNetwork::Authentication(const TConnection& ClientConnection) { if (!AuthResponse.IsObject()) { ClientKick(*Client, "Backend returned invalid auth response format."); - error("Backend returned invalid auth response format. This should never happen."); + beammp_error("Backend returned invalid auth response format. This should never happen."); return; } @@ -266,8 +266,8 @@ void TNetwork::Authentication(const TConnection& ClientConnection) { return; } - debug("Name -> " + Client->GetName() + ", Guest -> " + std::to_string(Client->IsGuest()) + ", Roles -> " + Client->GetRoles()); - debug("There are " + std::to_string(mServer.ClientCount()) + " known clients"); + beammp_debug("Name -> " + Client->GetName() + ", Guest -> " + std::to_string(Client->IsGuest()) + ", Roles -> " + Client->GetRoles()); + beammp_debug("There are " + std::to_string(mServer.ClientCount()) + " known clients"); mServer.ForEachClient([&](const std::weak_ptr& ClientPtr) -> bool { std::shared_ptr Cl; { @@ -277,10 +277,10 @@ void TNetwork::Authentication(const TConnection& ClientConnection) { } else return true; } - info("Client Iteration: Name -> " + Cl->GetName() + ", Guest -> " + std::to_string(Cl->IsGuest()) + ", Roles -> " + Cl->GetRoles()); + beammp_info("Client Iteration: Name -> " + Cl->GetName() + ", Guest -> " + std::to_string(Cl->IsGuest()) + ", Roles -> " + Cl->GetRoles()); if (Cl->GetName() == Client->GetName() && Cl->IsGuest() == Client->IsGuest()) { - info("New ClientConnection matched with current iteration"); - info("Old ClientConnection (" + Cl->GetName() + ") kicked: Reconnecting"); + beammp_info("New ClientConnection matched with current iteration"); + beammp_info("Old ClientConnection (" + Cl->GetName() + ") kicked: Reconnecting"); CloseSocketProper(Cl->GetTCPSock()); Cl->SetStatus(-2); return false; @@ -300,7 +300,7 @@ void TNetwork::Authentication(const TConnection& ClientConnection) { } if (mServer.ClientCount() < size_t(Application::Settings.MaxPlayers)) { - info("Identification success"); + beammp_info("Identification success"); mServer.InsertClient(Client); TCPClient(Client); } else @@ -339,12 +339,12 @@ bool TNetwork::TCPSend(TClient& c, const std::string& Data, bool IsSync) { int32_t Temp = send(c.GetTCPSock(), &Send[Sent], Size - Sent, MSG_NOSIGNAL); #endif //WIN32 if (Temp == 0) { - debug("send() == 0: " + GetPlatformAgnosticErrorString()); + beammp_debug("send() == 0: " + GetPlatformAgnosticErrorString()); if (c.GetStatus() > -1) c.SetStatus(-1); return false; } else if (Temp < 0) { - debug("send() < 0: " + GetPlatformAgnosticErrorString()); //TODO fix it was spamming yet everyone stayed on the server + beammp_debug("send() < 0: " + GetPlatformAgnosticErrorString()); //TODO fix it was spamming yet everyone stayed on the server if (c.GetStatus() > -1) c.SetStatus(-1); CloseSocketProper(c.GetTCPSock()); @@ -358,15 +358,15 @@ bool TNetwork::TCPSend(TClient& c, const std::string& Data, bool IsSync) { bool TNetwork::CheckBytes(TClient& c, int32_t BytesRcv) { if (BytesRcv == 0) { - debug("(TCP) Connection closing..."); + beammp_debug("(TCP) Connection closing..."); if (c.GetStatus() > -1) c.SetStatus(-1); return false; } else if (BytesRcv < 0) { - debug("(TCP) recv() failed: " + GetPlatformAgnosticErrorString()); + beammp_debug("(TCP) recv() failed: " + GetPlatformAgnosticErrorString()); if (c.GetStatus() > -1) c.SetStatus(-1); - info(("Closing socket in CheckBytes, BytesRcv < 0")); + beammp_info(("Closing socket in CheckBytes, BytesRcv < 0")); CloseSocketProper(c.GetTCPSock()); return false; } @@ -383,7 +383,7 @@ std::string TNetwork::TCPRcv(TClient& c) { Temp = recv(c.GetTCPSock(), &Data[BytesRcv], 4 - BytesRcv, 0); if (!CheckBytes(c, Temp)) { #ifdef DEBUG - error(std::string(__func__) + (": failed on CheckBytes in while(BytesRcv < 4)")); + beammp_error(std::string(__func__) + (": failed on CheckBytes in while(BytesRcv < 4)")); #endif // DEBUG return ""; } @@ -396,7 +396,7 @@ std::string TNetwork::TCPRcv(TClient& c) { #endif // DEBUG if (!CheckBytes(c, BytesRcv)) { #ifdef DEBUG - error(std::string(__func__) + (": failed on CheckBytes")); + beammp_error(std::string(__func__) + (": failed on CheckBytes")); #endif // DEBUG return ""; } @@ -404,7 +404,7 @@ std::string TNetwork::TCPRcv(TClient& c) { Data.resize(Header); } else { ClientKick(c, "Header size limit exceeded"); - warn("Client " + c.GetName() + " (" + std::to_string(c.GetID()) + ") sent header of >100MB - 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 ""; } BytesRcv = 0; @@ -412,7 +412,7 @@ std::string TNetwork::TCPRcv(TClient& c) { Temp = recv(c.GetTCPSock(), &Data[BytesRcv], Header - BytesRcv, 0); if (!CheckBytes(c, Temp)) { #ifdef DEBUG - error(std::string(__func__) + (": failed on CheckBytes in while(BytesRcv < Header)")); + beammp_error(std::string(__func__) + (": failed on CheckBytes in while(BytesRcv < Header)")); #endif // DEBUG return ""; @@ -438,7 +438,7 @@ std::string TNetwork::TCPRcv(TClient& c) { } void TNetwork::ClientKick(TClient& c, const std::string& R) { - info("Client kicked: " + R); + beammp_info("Client kicked: " + R); if (!TCPSend(c, "E" + R)) { // TODO handle } @@ -454,7 +454,7 @@ void TNetwork::Looper(const std::weak_ptr& c) { while (!c.expired()) { auto Client = c.lock(); if (Client->GetStatus() < 0) { - debug("client status < 0, breaking client loop"); + beammp_debug("client status < 0, breaking client loop"); break; } if (!Client->IsSyncing() && Client->IsSynced() && Client->MissedPacketQueueSize() != 0) { @@ -504,13 +504,13 @@ void TNetwork::TCPClient(const std::weak_ptr& c) { break; auto Client = c.lock(); if (Client->GetStatus() < 0) { - debug("client status < 0, breaking client loop"); + beammp_debug("client status < 0, breaking client loop"); break; } auto res = TCPRcv(*Client); if (res == "") { - debug("TCPRcv error, break client loop"); + beammp_debug("TCPRcv error, break client loop"); break; } TServer::GlobalParser(c, res, mPPSMonitor, *this); @@ -522,7 +522,7 @@ void TNetwork::TCPClient(const std::weak_ptr& c) { auto Client = c.lock(); OnDisconnect(c, Client->GetStatus() == -2); } else { - warn("client expired in TCPClient, should never happen"); + beammp_warn("client expired in TCPClient, should never happen"); } } @@ -545,7 +545,7 @@ void TNetwork::OnDisconnect(const std::weak_ptr& ClientPtr, bool kicked Assert(!ClientPtr.expired()); auto LockedClientPtr = ClientPtr.lock(); TClient& c = *LockedClientPtr; - info(c.GetName() + (" Connection Terminated")); + beammp_info(c.GetName() + (" Connection Terminated")); std::string Packet; TClient::TSetOfVehicleData VehicleData; { // Vehicle Data Lock Scope @@ -592,16 +592,16 @@ int TNetwork::OpenID() { void TNetwork::OnConnect(const std::weak_ptr& c) { Assert(!c.expired()); - info("Client connected"); + beammp_info("Client connected"); auto LockedClient = c.lock(); LockedClient->SetID(OpenID()); - info("Assigned ID " + std::to_string(LockedClient->GetID()) + " to " + LockedClient->GetName()); + beammp_info("Assigned ID " + std::to_string(LockedClient->GetID()) + " to " + LockedClient->GetName()); TriggerLuaEvent("onPlayerConnecting", false, nullptr, std::make_unique(TLuaArg { { LockedClient->GetID() } }), false); SyncResources(*LockedClient); if (LockedClient->GetStatus() < 0) return; (void)Respond(*LockedClient, "M" + Application::Settings.MapName, true); //Send the Map on connect - info(LockedClient->GetName() + " : Connected"); + beammp_info(LockedClient->GetName() + " : Connected"); TriggerLuaEvent("onPlayerJoining", false, nullptr, std::make_unique(TLuaArg { { LockedClient->GetID() } }), false); } @@ -639,7 +639,7 @@ void TNetwork::Parse(TClient& c, const std::string& Packet) { return; case 'S': if (SubCode == 'R') { - debug("Sending Mod Info"); + beammp_debug("Sending Mod Info"); std::string ToSend = mResourceManager.FileList() + mResourceManager.FileSizes(); if (ToSend.empty()) ToSend = "-"; @@ -654,13 +654,13 @@ void TNetwork::Parse(TClient& c, const std::string& Packet) { } void TNetwork::SendFile(TClient& c, const std::string& UnsafeName) { - info(c.GetName() + " requesting : " + UnsafeName.substr(UnsafeName.find_last_of('/'))); + beammp_info(c.GetName() + " requesting : " + UnsafeName.substr(UnsafeName.find_last_of('/'))); if (!fs::path(UnsafeName).has_filename()) { if (!TCPSend(c, "CO")) { // TODO: handle } - warn("File " + UnsafeName + " is not a file!"); + beammp_warn("File " + UnsafeName + " is not a file!"); return; } auto FileName = fs::path(UnsafeName).filename().string(); @@ -670,7 +670,7 @@ void TNetwork::SendFile(TClient& c, const std::string& UnsafeName) { if (!TCPSend(c, "CO")) { // TODO: handle } - warn("File " + UnsafeName + " could not be accessed!"); + beammp_warn("File " + UnsafeName + " could not be accessed!"); return; } @@ -686,7 +686,7 @@ void TNetwork::SendFile(TClient& c, const std::string& UnsafeName) { } if (c.GetDownSock() < 1) { - error("Client doesn't have a download socket!"); + beammp_error("Client doesn't have a download socket!"); if (c.GetStatus() > -1) c.SetStatus(-1); return; @@ -723,7 +723,7 @@ void TNetwork::SplitLoad(TClient& c, size_t Sent, size_t Size, bool D, const std TCPSock = c.GetDownSock(); else TCPSock = c.GetTCPSock(); - info("Split load Socket " + std::to_string(TCPSock)); + beammp_info("Split load Socket " + std::to_string(TCPSock)); while (c.GetStatus() > -1 && Sent < Size) { size_t Diff = Size - Sent; if (Diff > Split) { @@ -755,7 +755,7 @@ bool TNetwork::TCPSendRaw(TClient& C, SOCKET socket, char* Data, int32_t Size) { do { intmax_t Temp = send(socket, &Data[Sent], int(Size - Sent), 0); if (Temp < 1) { - info("Socket Closed! " + std::to_string(socket)); + beammp_info("Socket Closed! " + std::to_string(socket)); CloseSocketProper(socket); return false; } @@ -837,7 +837,7 @@ bool TNetwork::SyncClient(const std::weak_ptr& c) { return res; } LockedClient->SetIsSynced(true); - info(LockedClient->GetName() + (" is now synced!")); + beammp_info(LockedClient->GetName() + (" is now synced!")); return true; } @@ -907,12 +907,12 @@ bool TNetwork::UDPSend(TClient& Client, std::string Data) const { sendOk = sendto(mUDPSock, Data.c_str(), len, 0, (sockaddr*)&Addr, int(AddrSize)); if (sendOk == -1) { - debug("(UDP) sendto() failed: " + GetPlatformAgnosticErrorString()); + beammp_debug("(UDP) sendto() failed: " + GetPlatformAgnosticErrorString()); if (Client.GetStatus() > -1) Client.SetStatus(-1); return false; } else if (sendOk == 0) { - debug(("(UDP) sendto() returned 0")); + beammp_debug(("(UDP) sendto() returned 0")); if (Client.GetStatus() > -1) Client.SetStatus(-1); return false; @@ -930,7 +930,7 @@ std::string TNetwork::UDPRcvFromClient(sockaddr_in& client) const { #endif // WIN32 if (Rcv == -1) { - error("(UDP) Error receiving from client! recvfrom() failed: " + GetPlatformAgnosticErrorString()); + beammp_error("(UDP) Error receiving from client! recvfrom() failed: " + GetPlatformAgnosticErrorString()); return ""; } return std::string(Ret.begin(), Ret.begin() + Rcv); diff --git a/src/TPPSMonitor.cpp b/src/TPPSMonitor.cpp index 6f715c4..11eeff3 100644 --- a/src/TPPSMonitor.cpp +++ b/src/TPPSMonitor.cpp @@ -7,10 +7,10 @@ TPPSMonitor::TPPSMonitor(TServer& Server) Application::SetPPS("-"); Application::RegisterShutdownHandler([&] { if (mThread.joinable()) { - debug("shutting down PPSMonitor"); + beammp_debug("shutting down PPSMonitor"); mShutdown = true; mThread.join(); - debug("shut down PPSMonitor"); + beammp_debug("shut down PPSMonitor"); } }); Start(); @@ -21,7 +21,7 @@ void TPPSMonitor::operator()() { // hard spi std::this_thread::sleep_for(std::chrono::milliseconds(1)); } - info("PPSMonitor starting"); + beammp_info("PPSMonitor starting"); std::vector> TimedOutClients; while (!mShutdown) { std::this_thread::sleep_for(std::chrono::seconds(1)); @@ -45,7 +45,7 @@ void TPPSMonitor::operator()() { } // kick on "no ping" if (c->SecondsSinceLastPing() > (5 * 60)) { - debug("client " + std::string("(") + std::to_string(c->GetID()) + ")" + c->GetName() + " timing out: " + std::to_string(c->SecondsSinceLastPing()) + ", pps: " + Application::PPS()); + beammp_debug("client " + std::string("(") + std::to_string(c->GetID()) + ")" + c->GetName() + " timing out: " + std::to_string(c->SecondsSinceLastPing()) + ", pps: " + Application::PPS()); TimedOutClients.push_back(c); } diff --git a/src/TResourceManager.cpp b/src/TResourceManager.cpp index 6966578..96bc42a 100644 --- a/src/TResourceManager.cpp +++ b/src/TResourceManager.cpp @@ -28,5 +28,5 @@ TResourceManager::TResourceManager() { } if (mModsLoaded) - info("Loaded " + std::to_string(mModsLoaded) + " Mods"); + beammp_info("Loaded " + std::to_string(mModsLoaded) + " Mods"); } diff --git a/src/TServer.cpp b/src/TServer.cpp index 5492b66..7264207 100644 --- a/src/TServer.cpp +++ b/src/TServer.cpp @@ -14,16 +14,16 @@ namespace json = rapidjson; TServer::TServer(int argc, char** argv) { - info("BeamMP Server v" + Application::ServerVersionString()); + beammp_info("BeamMP Server v" + Application::ServerVersionString()); if (argc > 1) { Application::Settings.CustomIP = argv[1]; size_t n = std::count(Application::Settings.CustomIP.begin(), Application::Settings.CustomIP.end(), '.'); auto p = Application::Settings.CustomIP.find_first_not_of(".0123456789"); if (p != std::string::npos || n != 3 || Application::Settings.CustomIP.substr(0, 3) == "127") { Application::Settings.CustomIP.clear(); - warn("IP Specified is invalid! Ignoring"); + beammp_warn("IP Specified is invalid! Ignoring"); } else { - info("server started with custom IP"); + beammp_info("server started with custom IP"); } } } @@ -31,7 +31,7 @@ TServer::TServer(int argc, char** argv) { void TServer::RemoveClient(const std::weak_ptr& WeakClientPtr) { if (!WeakClientPtr.expired()) { TClient& Client = *WeakClientPtr.lock(); - debug("removing client " + Client.GetName() + " (" + std::to_string(ClientCount()) + ")"); + beammp_debug("removing client " + Client.GetName() + " (" + std::to_string(ClientCount()) + ")"); Client.ClearCars(); WriteLock Lock(mClientsMutex); mClients.erase(WeakClientPtr.lock()); @@ -39,7 +39,7 @@ void TServer::RemoveClient(const std::weak_ptr& WeakClientPtr) { } std::weak_ptr TServer::InsertNewClient() { - debug("inserting new client (" + std::to_string(ClientCount()) + ")"); + beammp_debug("inserting new client (" + std::to_string(ClientCount()) + ")"); WriteLock Lock(mClientsMutex); auto [Iter, Replaced] = mClients.insert(std::make_shared(*this)); return *Iter; @@ -91,7 +91,7 @@ void TServer::GlobalParser(const std::weak_ptr& Client, std::string Pac switch (Code) { case 'H': // initial connection #ifdef DEBUG - debug(std::string("got 'H' packet: '") + Packet + "' (" + std::to_string(Packet.size()) + ")"); + beammp_debug(std::string("got 'H' packet: '") + Packet + "' (" + std::to_string(Packet.size()) + ")"); #endif if (!Network.SyncClient(Client)) { // TODO handle @@ -109,19 +109,19 @@ void TServer::GlobalParser(const std::weak_ptr& Client, std::string Pac return; case 'O': if (Packet.length() > 1000) { - debug(("Received data from: ") + LockedClient->GetName() + (" Size: ") + std::to_string(Packet.length())); + beammp_debug(("Received data from: ") + LockedClient->GetName() + (" Size: ") + std::to_string(Packet.length())); } ParseVehicle(*LockedClient, Packet, Network); return; case 'J': #ifdef DEBUG - debug(std::string(("got 'J' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); + beammp_debug(std::string(("got 'J' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); #endif Network.SendToAll(LockedClient.get(), Packet, false, true); return; case 'C': #ifdef DEBUG - debug(std::string(("got 'C' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); + beammp_debug(std::string(("got 'C' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); #endif if (Packet.length() < 4 || Packet.find(':', 3) == std::string::npos) break; @@ -132,12 +132,12 @@ void TServer::GlobalParser(const std::weak_ptr& Client, std::string Pac return; case 'E': #ifdef DEBUG - debug(std::string(("got 'E' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); + beammp_debug(std::string(("got 'E' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); #endif HandleEvent(*LockedClient, Packet); return; case 'N': - debug("got 'N' packet (" + std::to_string(Packet.size()) + ")"); + beammp_debug("got 'N' packet (" + std::to_string(Packet.size()) + ")"); Network.SendToAll(LockedClient.get(), Packet, false, true); default: return; @@ -168,7 +168,7 @@ bool TServer::IsUnicycle(TClient& c, const std::string& CarJson) { rapidjson::Document Car; Car.Parse(CarJson.c_str(), CarJson.size()); if (Car.HasParseError()) { - error("Failed to parse vehicle data -> " + CarJson); + beammp_error("Failed to parse vehicle data -> " + CarJson); } else if (Car["jbm"].IsString() && std::string(Car["jbm"].GetString()) == "unicycle") { return true; } @@ -199,11 +199,11 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ switch (Code) { //Spawned Destroyed Switched/Moved NotFound Reset case 's': #ifdef DEBUG - debug(std::string(("got 'Os' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); + beammp_debug(std::string(("got 'Os' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); #endif if (Data.at(0) == '0') { int CarID = c.GetOpenCarID(); - debug(c.GetName() + (" created a car with ID ") + std::to_string(CarID)); + beammp_debug(c.GetName() + (" created a car with ID ") + std::to_string(CarID)); std::string CarJson = Packet.substr(5); Packet = "Os:" + c.GetRoles() + ":" + c.GetName() + ":" + std::to_string(c.GetID()) + "-" + std::to_string(CarID) + ":" + CarJson; @@ -220,13 +220,13 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ if (!Network.Respond(c, Destroy, true)) { // TODO: handle } - debug(c.GetName() + (" (force : car limit/lua) removed ID ") + std::to_string(CarID)); + beammp_debug(c.GetName() + (" (force : car limit/lua) removed ID ") + std::to_string(CarID)); } } return; case 'c': #ifdef DEBUG - debug(std::string(("got 'Oc' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); + beammp_debug(std::string(("got 'Oc' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); #endif pid = Data.substr(0, Data.find('-')); vid = Data.substr(Data.find('-') + 1, Data.find(':', 1) - Data.find('-') - 1); @@ -259,7 +259,7 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ return; case 'd': #ifdef DEBUG - debug(std::string(("got 'Od' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); + beammp_debug(std::string(("got 'Od' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); #endif pid = Data.substr(0, Data.find('-')); vid = Data.substr(Data.find('-') + 1); @@ -275,12 +275,12 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ TriggerLuaEvent(("onVehicleDeleted"), false, nullptr, std::make_unique(TLuaArg { { c.GetID(), VID } }), false); c.DeleteCar(VID); - debug(c.GetName() + (" deleted car with ID ") + std::to_string(VID)); + beammp_debug(c.GetName() + (" deleted car with ID ") + std::to_string(VID)); } return; case 'r': #ifdef DEBUG - debug(std::string(("got 'Or' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); + beammp_debug(std::string(("got 'Or' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); #endif Pos = int(Data.find('-')); pid = Data.substr(0, Pos++); @@ -301,13 +301,13 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ return; case 't': #ifdef DEBUG - debug(std::string(("got 'Ot' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); + beammp_debug(std::string(("got 'Ot' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); #endif Network.SendToAll(&c, Packet, false, true); return; default: #ifdef DEBUG - warn(std::string(("possibly not implemented: '") + Packet + ("' (") + std::to_string(Packet.size()) + (")"))); + beammp_warn(std::string(("possibly not implemented: '") + Packet + ("' (") + std::to_string(Packet.size()) + (")"))); #endif // DEBUG return; } @@ -316,32 +316,32 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ void TServer::Apply(TClient& c, int VID, const std::string& pckt) { auto FoundPos = pckt.find('{'); if (FoundPos == std::string::npos) { - error("Malformed packet received, no '{' found"); + beammp_error("Malformed packet received, no '{' found"); return; } std::string Packet = pckt.substr(FoundPos); std::string VD = c.GetCarData(VID); if (VD.empty()) { - error("Tried to apply change to vehicle that does not exist"); + beammp_error("Tried to apply change to vehicle that does not exist"); return; } std::string Header = VD.substr(0, VD.find('{')); FoundPos = VD.find('{'); if (FoundPos == std::string::npos) { - error("Malformed packet received, no '{' found"); + beammp_error("Malformed packet received, no '{' found"); return; } VD = VD.substr(FoundPos); rapidjson::Document Veh, Pack; Veh.Parse(VD.c_str()); if (Veh.HasParseError()) { - error("Could not get vehicle config!"); + beammp_error("Could not get vehicle config!"); return; } Pack.Parse(Packet.c_str()); if (Pack.HasParseError() || Pack.IsNull()) { - error("Could not get active vehicle config!"); + beammp_error("Could not get active vehicle config!"); return; } @@ -359,7 +359,7 @@ void TServer::Apply(TClient& c, int VID, const std::string& pckt) { } void TServer::InsertClient(const std::shared_ptr& NewClient) { - debug("inserting client (" + std::to_string(ClientCount()) + ")"); + beammp_debug("inserting client (" + std::to_string(ClientCount()) + ")"); WriteLock Lock(mClientsMutex); //TODO why is there 30+ threads locked here (void)mClients.insert(NewClient); } diff --git a/src/VehicleData.cpp b/src/VehicleData.cpp index dd56d1e..fd3deaa 100644 --- a/src/VehicleData.cpp +++ b/src/VehicleData.cpp @@ -7,12 +7,12 @@ TVehicleData::TVehicleData(int ID, std::string Data) : mID(ID) , mData(std::move(Data)) { #ifdef DEBUG - debug("vehicle " + std::to_string(mID) + " constructed"); + beammp_debug("vehicle " + std::to_string(mID) + " constructed"); #endif } TVehicleData::~TVehicleData() { #ifdef DEBUG - debug("vehicle " + std::to_string(mID) + " destroyed"); + beammp_debug("vehicle " + std::to_string(mID) + " destroyed"); #endif } diff --git a/src/main.cpp b/src/main.cpp index c56d1ce..03bbbc0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -15,18 +15,18 @@ void UnixSignalHandler(int sig) { switch (sig) { case SIGPIPE: - warn("ignoring SIGPIPE"); + beammp_warn("ignoring SIGPIPE"); break; case SIGTERM: - info("gracefully shutting down via SIGTERM"); + beammp_info("gracefully shutting down via SIGTERM"); Application::GracefullyShutdown(); break; case SIGINT: - info("gracefully shutting down via SIGINT"); + beammp_info("gracefully shutting down via SIGINT"); Application::GracefullyShutdown(); break; default: - debug("unhandled signal: " + std::to_string(sig)); + beammp_debug("unhandled signal: " + std::to_string(sig)); break; } } @@ -35,7 +35,7 @@ void UnixSignalHandler(int sig) { int main(int argc, char** argv) { #ifdef __unix #if DEBUG - info("registering handlers for SIGINT, SIGTERM, SIGPIPE"); + beammp_info("registering handlers for SIGINT, SIGTERM, SIGPIPE"); #endif // DEBUG signal(SIGPIPE, UnixSignalHandler); signal(SIGTERM, UnixSignalHandler); @@ -54,7 +54,7 @@ int main(int argc, char** argv) { TConfig Config; if (Config.Failed()) { - info("Closing in 10 seconds"); + beammp_info("Closing in 10 seconds"); std::this_thread::sleep_for(std::chrono::seconds(10)); return 1; } From f5b2be0a03556e8ab5246fc75431ed1546c40bb0 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 16 Sep 2021 01:04:38 +0200 Subject: [PATCH 083/255] rename Assert to beammp_assert --- include/CustomAssert.h | 2 +- src/TLuaEngine.cpp | 4 ++-- src/TNetwork.cpp | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/CustomAssert.h b/include/CustomAssert.h index 7bf3622..cf1c496 100644 --- a/include/CustomAssert.h +++ b/include/CustomAssert.h @@ -55,7 +55,7 @@ inline void _assert([[maybe_unused]] const char* file, [[maybe_unused]] const ch } } -#define Assert(cond) _assert(__FILE__, __func__, __LINE__, #cond, (cond)) +#define beammp_assert(cond) _assert(__FILE__, __func__, __LINE__, #cond, (cond)) #define AssertNotReachable() _assert(__FILE__, __func__, __LINE__, "reached unreachable code", false) #else // In release build, these macros turn into NOPs. The compiler will optimize these out. diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 990bc08..f8438b4 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -39,6 +39,6 @@ void TLuaEngine::CollectPlugins() { } void TLuaEngine::InitializePlugin(const fs::path& folder) { - Assert(fs::exists(folder)); - Assert(fs::is_directory(folder)); + beammp_assert(fs::exists(folder)); + beammp_assert(fs::is_directory(folder)); } diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index 66d4299..016deac 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -542,7 +542,7 @@ void TNetwork::UpdatePlayer(TClient& Client) { } void TNetwork::OnDisconnect(const std::weak_ptr& ClientPtr, bool kicked) { - Assert(!ClientPtr.expired()); + beammp_assert(!ClientPtr.expired()); auto LockedClientPtr = ClientPtr.lock(); TClient& c = *LockedClientPtr; beammp_info(c.GetName() + (" Connection Terminated")); @@ -591,7 +591,7 @@ int TNetwork::OpenID() { } void TNetwork::OnConnect(const std::weak_ptr& c) { - Assert(!c.expired()); + beammp_assert(!c.expired()); beammp_info("Client connected"); auto LockedClient = c.lock(); LockedClient->SetID(OpenID()); @@ -843,7 +843,7 @@ bool TNetwork::SyncClient(const std::weak_ptr& c) { void TNetwork::SendToAll(TClient* c, const std::string& Data, bool Self, bool Rel) { if (!Self) - Assert(c); + beammp_assert(c); char C = Data.at(0); bool ret = true; mServer.ForEachClient([&](std::weak_ptr ClientPtr) -> bool { From c309fa28c6cad91fbde4854e25fc492fe77ac48c Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 16 Sep 2021 01:09:24 +0200 Subject: [PATCH 084/255] update sol2 to v3.2.3 --- deps/sol2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/sol2 b/deps/sol2 index b43cee5..c068aef 160000 --- a/deps/sol2 +++ b/deps/sol2 @@ -1 +1 @@ -Subproject commit b43cee5c9db30fc961b9d7210a1db05d60965f40 +Subproject commit c068aefbeddb3dd1f1fd38d42843ecb49a3b4cdb From ba0678dade63c24846bb0e3310b1ef142b6decaf Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 16 Sep 2021 03:21:00 +0200 Subject: [PATCH 085/255] Continue Lua Rewrite --- CMakeLists.txt | 9 ++-- include/CustomAssert.h | 6 +-- include/TConfig.h | 2 + include/TConsole.h | 9 ++-- include/TLuaEngine.h | 57 ++++++++++++++++++-- include/TLuaPlugin.h | 15 ++++++ src/TConsole.cpp | 19 +++---- src/TLuaEngine.cpp | 116 +++++++++++++++++++++++++++++++++++++---- src/TLuaPlugin.cpp | 10 ++++ src/TNetwork.cpp | 7 +-- src/TServer.cpp | 2 +- src/main.cpp | 2 +- 12 files changed, 215 insertions(+), 39 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2d3defc..8523a78 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,16 +52,19 @@ target_include_directories(BeamMP-Server PRIVATE "${PROJECT_SOURCE_DIR}/deps/com target_include_directories(BeamMP-Server PRIVATE "${PROJECT_SOURCE_DIR}/deps/sol2/include") target_include_directories(BeamMP-Server PRIVATE "${PROJECT_SOURCE_DIR}/deps") -include_directories(BeamMP-Server PUBLIC ${Boost_INCLUDE_DIRS} ${LUA_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/include) +include_directories(BeamMP-Server PUBLIC ${Boost_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}/include) +find_package(Lua REQUIRED) find_package(OpenSSL REQUIRED) +target_link_libraries(BeamMP-Server sol2::sol2 ${LUA_LIBRARIES}) + if (UNIX) - target_link_libraries(BeamMP-Server z pthread stdc++fs ${SOL2_LIBRARIES} crypto ${OPENSSL_LIBRARIES} commandline sioclient_tls) + target_link_libraries(BeamMP-Server z pthread stdc++fs crypto ${OPENSSL_LIBRARIES} commandline sioclient_tls) elseif (WIN32) include(FindLua) find_package(ZLIB REQUIRED) find_package(RapidJSON CONFIG REQUIRED) target_include_directories(BeamMP-Server PRIVATE ${RAPIDJSON_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}) - target_link_libraries(BeamMP-Server PRIVATE ws2_32 ZLIB::ZLIB ${SOL2_LIBRARIES} ${OPENSSL_LIBRARIES} commandline sioclient_tls) + target_link_libraries(BeamMP-Server PRIVATE ws2_32 ZLIB::ZLIB ${OPENSSL_LIBRARIES} commandline sioclient_tls) endif () diff --git a/include/CustomAssert.h b/include/CustomAssert.h index cf1c496..78ff850 100644 --- a/include/CustomAssert.h +++ b/include/CustomAssert.h @@ -56,13 +56,13 @@ inline void _assert([[maybe_unused]] const char* file, [[maybe_unused]] const ch } #define beammp_assert(cond) _assert(__FILE__, __func__, __LINE__, #cond, (cond)) -#define AssertNotReachable() _assert(__FILE__, __func__, __LINE__, "reached unreachable code", false) +#define beammp_assert_not_reachable() _assert(__FILE__, __func__, __LINE__, "reached unreachable code", false) #else // In release build, these macros turn into NOPs. The compiler will optimize these out. -#define Assert(x) \ +#define beammp_assert(x) \ do { \ } while (false) -#define AssertNotReachable() \ +#define beammp_assert_not_reachable() \ do { \ } while (false) #endif // DEBUG diff --git a/include/TConfig.h b/include/TConfig.h index 60001bd..1399aa6 100644 --- a/include/TConfig.h +++ b/include/TConfig.h @@ -4,6 +4,8 @@ #include +namespace fs = std::filesystem; + class TConfig { public: explicit TConfig(); diff --git a/include/TConsole.h b/include/TConsole.h index 7063d5d..edbfdc8 100644 --- a/include/TConsole.h +++ b/include/TConsole.h @@ -1,8 +1,10 @@ #pragma once +#include "commandline.h" #include #include -#include "commandline.h" + +class TLuaEngine; class TConsole { public: @@ -10,9 +12,10 @@ public: void Write(const std::string& str); void WriteRaw(const std::string& str); - // BROKEN void InitializeLuaConsole(TLuaEngine& Engine); + void InitializeLuaConsole(TLuaEngine& Engine); private: -// BROKEN std::unique_ptr mLuaConsole { nullptr }; Commandline mCommandline; + TLuaEngine& mLuaEngine; + const std::string mStateId = "BEAMMP_SERVER_CONSOLE"; }; diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index 770d949..82c33de 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -3,30 +3,77 @@ #include "TNetwork.h" #include "TServer.h" #include -#include +#include +#include +#include #include #include #include +#define SOL_ALL_SAFETIES_ON 1 +#include + +using TLuaStateId = std::string; namespace fs = std::filesystem; class TLuaPlugin; +struct TLuaResult { + std::atomic_bool Ready; + // TODO: Add condition_variable + sol::protected_function_result Result; +}; + +struct TLuaPluginConfig { + static inline const std::string FileName = "PluginConfig.toml"; + TLuaStateId StateId; + // TODO: Execute list +}; + class TLuaEngine : IThreaded { public: TLuaEngine(TServer& Server, TNetwork& Network); void operator()() override; + TLuaResult EnqueueScript(TLuaStateId StateID, const std::shared_ptr& Script); + void EnsureStateExists(TLuaStateId StateId, const std::string& Name); + private: void CollectPlugins(); - void InitializePlugin(const fs::path& folder); + void InitializePlugin(const fs::path& Folder, const TLuaPluginConfig& Config); + void FindAndParseConfig(const fs::path& Folder, TLuaPluginConfig& Config); + + class StateThreadData : IThreaded { + public: + StateThreadData(const std::string& Name, std::atomic_bool& Shutdown); + StateThreadData(const StateThreadData&) = delete; + void EnqueueScript(const std::shared_ptr& Script); + void operator()() override; + ~StateThreadData(); + + private: + std::string mName; + std::atomic_bool& mShutdown; + sol::state mState; + std::thread mThread; + std::queue> mStateExecuteQueue; + std::mutex mStateExecuteQueueMutex; + }; TNetwork& mNetwork; TServer& mServer; - sol::state mL; std::atomic_bool mShutdown { false }; fs::path mResourceServerPath; - std::vector mLuaPlugins; - std::unordered_map mLuaStates; + std::vector mLuaPlugins; + std::unordered_map> mLuaStates; + std::mutex mLuaStatesMutex; }; + +#include +// DEAD CODE +struct TLuaArg { + std::vector args; + void PushArgs(lua_State* State); +}; +std::any TriggerLuaEvent(const std::string& Event, bool local, TLuaPlugin* Caller, std::shared_ptr arg, bool Wait); diff --git a/include/TLuaPlugin.h b/include/TLuaPlugin.h index e69de29..c3ffc2f 100644 --- a/include/TLuaPlugin.h +++ b/include/TLuaPlugin.h @@ -0,0 +1,15 @@ +#include "TLuaEngine.h" + +class TLuaPlugin { +public: + TLuaPlugin(TLuaEngine& Engine, const TLuaPluginConfig& Config); + TLuaPlugin(const TLuaPlugin&) = delete; + TLuaPlugin& operator=(const TLuaPlugin&) = delete; + ~TLuaPlugin() noexcept = default; + + const TLuaPluginConfig& GetConfig() const { return mConfig; } + +private: + TLuaPluginConfig mConfig; + TLuaEngine& mEngine; +}; diff --git a/src/TConsole.cpp b/src/TConsole.cpp index 1f2a80c..1d7b0c6 100644 --- a/src/TConsole.cpp +++ b/src/TConsole.cpp @@ -2,6 +2,8 @@ #include "Common.h" #include "Compat.h" +#include "TLuaEngine.h" + #include #include @@ -55,13 +57,8 @@ TConsole::TConsole() { Application::GracefullyShutdown(); } else if (cmd == "clear" || cmd == "cls") { // TODO: clear screen + mLuaEngine.EnqueueScript(mStateId, std::make_shared(cmd)); } else { - /*if (mLuaConsole) { - mLuaConsole->Execute(cmd); - } else { - error("Lua subsystem not yet initialized, please wait a few seconds and try again"); - } BROKEN - */ } }; } @@ -71,11 +68,11 @@ void TConsole::Write(const std::string& str) { mCommandline.write(ToWrite); // TODO write to logfile, too } -/* BROKEN -void TConsole::InitializeLuaConsole(TLuaEngine& Engine) { - mLuaConsole = std::make_unique(Engine, true); -} -*/ + void TConsole::WriteRaw(const std::string& str) { mCommandline.write(str); } + +void TConsole::InitializeLuaConsole(TLuaEngine& Engine) { + Engine.EnsureStateExists(mStateId, "<>"); +} diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index f8438b4..a25cc41 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -1,5 +1,16 @@ #include "TLuaEngine.h" #include "CustomAssert.h" +#include "TLuaPlugin.h" + +#include +#include + +static std::mt19937_64 MTGen64; + +static TLuaStateId GenerateUniqueStateId() { + auto Time = std::chrono::high_resolution_clock::now().time_since_epoch(); + return std::to_string(MTGen64()) + std::to_string(std::chrono::duration_cast(Time).count()); +} TLuaEngine::TLuaEngine(TServer& Server, TNetwork& Network) : mNetwork(Network) @@ -18,27 +29,114 @@ TLuaEngine::TLuaEngine(TServer& Server, TNetwork& Network) mThread.join(); } }); + Start(); } void TLuaEngine::operator()() { RegisterThread("LuaEngine"); // lua engine main thread CollectPlugins(); + while (!mShutdown) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } +} + +void TLuaEngine::EnqueueScript(TLuaStateId StateID, const std::shared_ptr& Script) { + std::unique_lock Lock(mLuaStatesMutex); + mLuaStates.at(StateID)->EnqueueScript(Script); } void TLuaEngine::CollectPlugins() { - for (const auto& dir : fs::directory_iterator(mResourceServerPath)) { - auto path = dir.path(); - path = fs::relative(path); - if (!dir.is_directory()) { - beammp_error("\"" + dir.path().string() + "\" is not a directory, skipping"); + for (const auto& Dir : fs::directory_iterator(mResourceServerPath)) { + auto Path = Dir.path(); + Path = fs::relative(Path); + if (!Dir.is_directory()) { + beammp_error("\"" + Dir.path().string() + "\" is not a directory, skipping"); } else { - beammp_debug("found plugin directory: " + path.string()); + beammp_debug("found plugin directory: " + Path.string()); + TLuaPluginConfig Config { GenerateUniqueStateId() }; + FindAndParseConfig(Path, Config); + InitializePlugin(Path, Config); } } } -void TLuaEngine::InitializePlugin(const fs::path& folder) { - beammp_assert(fs::exists(folder)); - beammp_assert(fs::is_directory(folder)); +void TLuaEngine::InitializePlugin(const fs::path& Folder, const TLuaPluginConfig& Config) { + beammp_assert(fs::exists(Folder)); + beammp_assert(fs::is_directory(Folder)); + TLuaPlugin Plugin(*this, Config); + std::unique_lock Lock(mLuaStatesMutex); + EnsureStateExists(Config.StateId, Folder.stem().string()); +} + +void TLuaEngine::FindAndParseConfig(const fs::path& Folder, TLuaPluginConfig& Config) { + auto ConfigFile = Folder / TLuaPluginConfig::FileName; + if (fs::exists(ConfigFile) && fs::is_regular_file(ConfigFile)) { + beammp_debug("\"" + ConfigFile.string() + "\" found"); + // TODO use toml11 here to parse it + try { + auto Data = toml::parse(ConfigFile); + if (Data.contains("LuaStateID")) { + auto ID = toml::find(Data, "LuaStateID"); + if (!ID.empty()) { + beammp_debug("Plugin \"" + Folder.string() + "\" specified it wants LuaStateID \"" + ID + "\""); + Config.StateId = ID; + } else { + beammp_debug("LuaStateID empty, using randomized state ID"); + } + } + } catch (const std::exception& e) { + beammp_error(Folder.string() + ": " + e.what()); + } + } +} + +void TLuaEngine::EnsureStateExists(TLuaStateId StateId, const std::string& Name) { + if (mLuaStates.find(StateId) == mLuaStates.end()) { + beammp_debug("Creating lua state for state id \"" + StateId + "\""); + auto DataPtr = std::make_unique(Name, mShutdown); + mLuaStates[StateId] = std::move(DataPtr); + } +} + +TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomic_bool& Shutdown) + : mName(Name) + , mShutdown(Shutdown) { + mState.open_libraries(sol::lib::base); + Start(); +} + +void TLuaEngine::StateThreadData::EnqueueScript(const std::shared_ptr& Script) { + beammp_debug("enqueuing script into \"" + mName + "\""); + std::unique_lock Lock(mStateExecuteQueueMutex); + mStateExecuteQueue.push(Script); +} + +void TLuaEngine::StateThreadData::operator()() { + RegisterThreadAuto(); + while (!mShutdown) { + std::unique_lock Lock(mStateExecuteQueueMutex); + if (mStateExecuteQueue.empty()) { + Lock.unlock(); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } else { + auto S = mStateExecuteQueue.front(); + mStateExecuteQueue.pop(); + Lock.unlock(); + mState.do_string(*S); + } + } +} + +TLuaEngine::StateThreadData::~StateThreadData() { + if (mThread.joinable()) { + mThread.join(); + } +} + +// AHHH +std::any TriggerLuaEvent(const std::string& Event, bool local, TLuaPlugin* Caller, std::shared_ptr arg, bool Wait) { +} + +void TLuaArg::PushArgs(lua_State* State) { } diff --git a/src/TLuaPlugin.cpp b/src/TLuaPlugin.cpp index e69de29..5567335 100644 --- a/src/TLuaPlugin.cpp +++ b/src/TLuaPlugin.cpp @@ -0,0 +1,10 @@ +#include "TLuaPlugin.h" +#include +#include +#include +#include + +TLuaPlugin::TLuaPlugin(TLuaEngine& Engine, const TLuaPluginConfig& Config) + : mConfig(Config) + , mEngine(Engine) { +} diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index 016deac..c76ae9c 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -2,6 +2,7 @@ #include "Client.h" #include #include +#include #include #include @@ -43,7 +44,7 @@ void TNetwork::UDPServerMain() { #ifdef WIN32 WSADATA data; if (WSAStartup(514, &data)) { - error(("Can't start Winsock!")); + beammp_error(("Can't start Winsock!")); //return; } #endif // WIN32 @@ -104,7 +105,7 @@ void TNetwork::TCPServerMain() { #ifdef WIN32 WSADATA wsaData; if (WSAStartup(514, &wsaData)) { - error("Can't start Winsock!"); + beammp_error("Can't start Winsock!"); return; } #endif // WIN32 @@ -621,7 +622,7 @@ void TNetwork::SyncResources(TClient& c) { } #ifndef DEBUG } catch (std::exception& e) { - error("Exception! : " + std::string(e.what())); + beammp_error("Exception! : " + std::string(e.what())); c.SetStatus(-1); } #endif diff --git a/src/TServer.cpp b/src/TServer.cpp index 7264207..38b5d9e 100644 --- a/src/TServer.cpp +++ b/src/TServer.cpp @@ -3,7 +3,7 @@ #include "Common.h" #include "TNetwork.h" #include "TPPSMonitor.h" -#include +#include #include #include diff --git a/src/main.cpp b/src/main.cpp index 03bbbc0..c57ec08 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -66,7 +66,7 @@ int main(int argc, char** argv) { TNetwork Network(Server, PPSMonitor, ResourceManager); TLuaEngine LuaEngine(Server, Network); PPSMonitor.SetNetwork(Network); - Application::Console().InitializeLuaConsole(LuaEngine); + // BROKEN Application::Console().InitializeLuaConsole(LuaEngine); // TODO: replace while (!Shutdown) { From 2cf368c2b08fcb13fdf42c1072b259eec37e85c5 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 16 Sep 2021 03:40:24 +0200 Subject: [PATCH 086/255] First working console --- include/TConsole.h | 2 +- include/TLuaEngine.h | 15 +++++++-------- src/TConsole.cpp | 11 ++++++++++- src/TLuaEngine.cpp | 21 ++++++++++++++------- src/main.cpp | 2 +- 5 files changed, 33 insertions(+), 18 deletions(-) diff --git a/include/TConsole.h b/include/TConsole.h index edbfdc8..f83b75b 100644 --- a/include/TConsole.h +++ b/include/TConsole.h @@ -16,6 +16,6 @@ public: private: Commandline mCommandline; - TLuaEngine& mLuaEngine; + TLuaEngine* mLuaEngine { nullptr }; const std::string mStateId = "BEAMMP_SERVER_CONSOLE"; }; diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index 82c33de..72b3d68 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -2,7 +2,9 @@ #include "TNetwork.h" #include "TServer.h" +#include #include +#include #include #include #include @@ -10,9 +12,6 @@ #include #include -#define SOL_ALL_SAFETIES_ON 1 -#include - using TLuaStateId = std::string; namespace fs = std::filesystem; @@ -21,7 +20,7 @@ class TLuaPlugin; struct TLuaResult { std::atomic_bool Ready; // TODO: Add condition_variable - sol::protected_function_result Result; + std::any Result; }; struct TLuaPluginConfig { @@ -36,7 +35,7 @@ public: void operator()() override; - TLuaResult EnqueueScript(TLuaStateId StateID, const std::shared_ptr& Script); + [[nodiscard]] std::shared_ptr EnqueueScript(TLuaStateId StateID, const std::shared_ptr& Script); void EnsureStateExists(TLuaStateId StateId, const std::string& Name); private: @@ -48,16 +47,16 @@ private: public: StateThreadData(const std::string& Name, std::atomic_bool& Shutdown); StateThreadData(const StateThreadData&) = delete; - void EnqueueScript(const std::shared_ptr& Script); + [[nodiscard]] std::shared_ptr EnqueueScript(const std::shared_ptr& Script); void operator()() override; ~StateThreadData(); private: std::string mName; std::atomic_bool& mShutdown; - sol::state mState; + lua_State* mState; std::thread mThread; - std::queue> mStateExecuteQueue; + std::queue, std::shared_ptr>> mStateExecuteQueue; std::mutex mStateExecuteQueueMutex; }; diff --git a/src/TConsole.cpp b/src/TConsole.cpp index 1d7b0c6..1cdc71e 100644 --- a/src/TConsole.cpp +++ b/src/TConsole.cpp @@ -57,8 +57,16 @@ TConsole::TConsole() { Application::GracefullyShutdown(); } else if (cmd == "clear" || cmd == "cls") { // TODO: clear screen - mLuaEngine.EnqueueScript(mStateId, std::make_shared(cmd)); } else { + while (!mLuaEngine) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + auto Future = mLuaEngine->EnqueueScript(mStateId, std::make_shared(cmd)); + // wait for it to finish + while (!Future->Ready) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + mCommandline.write("Result ready."); } }; } @@ -75,4 +83,5 @@ void TConsole::WriteRaw(const std::string& str) { void TConsole::InitializeLuaConsole(TLuaEngine& Engine) { Engine.EnsureStateExists(mStateId, "<>"); + mLuaEngine = &Engine; } diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index a25cc41..5012b61 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -41,9 +41,11 @@ void TLuaEngine::operator()() { } } -void TLuaEngine::EnqueueScript(TLuaStateId StateID, const std::shared_ptr& Script) { +std::shared_ptr TLuaEngine::EnqueueScript(TLuaStateId StateID, const std::shared_ptr& Script) { std::unique_lock Lock(mLuaStatesMutex); - mLuaStates.at(StateID)->EnqueueScript(Script); + TLuaResult Result; + beammp_debug("enqueuing script into \"" + StateID + "\""); + return mLuaStates.at(StateID)->EnqueueScript(Script); } void TLuaEngine::CollectPlugins() { @@ -102,18 +104,21 @@ void TLuaEngine::EnsureStateExists(TLuaStateId StateId, const std::string& Name) TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomic_bool& Shutdown) : mName(Name) , mShutdown(Shutdown) { - mState.open_libraries(sol::lib::base); + mState = luaL_newstate(); + luaL_openlibs(mState); Start(); } -void TLuaEngine::StateThreadData::EnqueueScript(const std::shared_ptr& Script) { +std::shared_ptr TLuaEngine::StateThreadData::EnqueueScript(const std::shared_ptr& Script) { beammp_debug("enqueuing script into \"" + mName + "\""); std::unique_lock Lock(mStateExecuteQueueMutex); - mStateExecuteQueue.push(Script); + auto Result = std::make_shared(); + mStateExecuteQueue.push({ Script, Result }); + return Result; } void TLuaEngine::StateThreadData::operator()() { - RegisterThreadAuto(); + RegisterThread(mName); while (!mShutdown) { std::unique_lock Lock(mStateExecuteQueueMutex); if (mStateExecuteQueue.empty()) { @@ -123,7 +128,9 @@ void TLuaEngine::StateThreadData::operator()() { auto S = mStateExecuteQueue.front(); mStateExecuteQueue.pop(); Lock.unlock(); - mState.do_string(*S); + beammp_debug("Running script"); + luaL_dostring(mState, S.first->data()); + S.second->Ready = true; } } } diff --git a/src/main.cpp b/src/main.cpp index c57ec08..03bbbc0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -66,7 +66,7 @@ int main(int argc, char** argv) { TNetwork Network(Server, PPSMonitor, ResourceManager); TLuaEngine LuaEngine(Server, Network); PPSMonitor.SetNetwork(Network); - // BROKEN Application::Console().InitializeLuaConsole(LuaEngine); + Application::Console().InitializeLuaConsole(LuaEngine); // TODO: replace while (!Shutdown) { From 5978665ad64f7cc86e49cb84b76d6edd8d6b032d Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 16 Sep 2021 10:07:04 +0200 Subject: [PATCH 087/255] Lua: Fix threading related crash --- include/IThreaded.h | 5 +++++ include/TLuaEngine.h | 6 +++--- src/TConsole.cpp | 8 +++++--- src/TLuaEngine.cpp | 22 +++++++++++++++------- 4 files changed, 28 insertions(+), 13 deletions(-) diff --git a/include/IThreaded.h b/include/IThreaded.h index ca5d7cd..d08e428 100644 --- a/include/IThreaded.h +++ b/include/IThreaded.h @@ -8,6 +8,11 @@ public: IThreaded() // invokes operator() on this object : mThread() { } + ~IThreaded() noexcept { + if (mThread.joinable()) { + mThread.join(); + } + } virtual void Start() final { mThread = std::thread([this] { (*this)(); }); diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index 72b3d68..4899817 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -19,14 +19,15 @@ class TLuaPlugin; struct TLuaResult { std::atomic_bool Ready; + std::atomic_bool Error; + std::string ErrorMessage; // TODO: Add condition_variable - std::any Result; }; struct TLuaPluginConfig { static inline const std::string FileName = "PluginConfig.toml"; TLuaStateId StateId; - // TODO: Execute list + // TODO: Add execute list }; class TLuaEngine : IThreaded { @@ -49,7 +50,6 @@ private: StateThreadData(const StateThreadData&) = delete; [[nodiscard]] std::shared_ptr EnqueueScript(const std::shared_ptr& Script); void operator()() override; - ~StateThreadData(); private: std::string mName; diff --git a/src/TConsole.cpp b/src/TConsole.cpp index 1cdc71e..34e858f 100644 --- a/src/TConsole.cpp +++ b/src/TConsole.cpp @@ -64,9 +64,11 @@ TConsole::TConsole() { auto Future = mLuaEngine->EnqueueScript(mStateId, std::make_shared(cmd)); // wait for it to finish while (!Future->Ready) { - std::this_thread::sleep_for(std::chrono::milliseconds(10)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + if (Future->Error) { + beammp_error(Future->ErrorMessage); } - mCommandline.write("Result ready."); } }; } @@ -82,6 +84,6 @@ void TConsole::WriteRaw(const std::string& str) { } void TConsole::InitializeLuaConsole(TLuaEngine& Engine) { - Engine.EnsureStateExists(mStateId, "<>"); + Engine.EnsureStateExists(mStateId, "Console"); mLuaEngine = &Engine; } diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 5012b61..3b0fa1e 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -5,6 +5,9 @@ #include #include +#define SOL_ALL_SAFETIES_ON 1 +#include + static std::mt19937_64 MTGen64; static TLuaStateId GenerateUniqueStateId() { @@ -106,6 +109,9 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi , mShutdown(Shutdown) { mState = luaL_newstate(); luaL_openlibs(mState); + sol::state_view StateView(mState); + auto LuaPrint = [](const std::string& Msg) { luaprint(Msg); }; + StateView.set_function("print", LuaPrint); Start(); } @@ -129,18 +135,20 @@ void TLuaEngine::StateThreadData::operator()() { mStateExecuteQueue.pop(); Lock.unlock(); beammp_debug("Running script"); - luaL_dostring(mState, S.first->data()); + sol::state_view StateView(mState); + auto Res = StateView.safe_script(*S.first, sol::script_pass_on_error); + if (Res.valid()) { + S.second->Error = false; + } else { + S.second->Error = true; + sol::error Err = Res; + S.second->ErrorMessage = Err.what(); + } S.second->Ready = true; } } } -TLuaEngine::StateThreadData::~StateThreadData() { - if (mThread.joinable()) { - mThread.join(); - } -} - // AHHH std::any TriggerLuaEvent(const std::string& Event, bool local, TLuaPlugin* Caller, std::shared_ptr arg, bool Wait) { } From 9b9c18a4c1b9c41cd73dc1324d96f49bf6c7fbef Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 16 Sep 2021 11:54:52 +0200 Subject: [PATCH 088/255] Lua: Add variadic print, LuaAPI --- CMakeLists.txt | 3 +- include/Common.h | 1 + include/LuaAPI.h | 13 ++++ include/TLuaEngine.h | 18 +++++- include/TLuaPlugin.h | 5 +- src/LuaAPI.cpp | 22 +++++++ src/TLuaEngine.cpp | 138 ++++++++++++++++++++++++++++++++----------- src/TLuaPlugin.cpp | 53 ++++++++++++++++- 8 files changed, 213 insertions(+), 40 deletions(-) create mode 100644 include/LuaAPI.h create mode 100644 src/LuaAPI.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8523a78..1e7f1c4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,7 +43,8 @@ add_executable(BeamMP-Server include/THeartbeatThread.h src/THeartbeatThread.cpp include/Http.h src/Http.cpp include/TPPSMonitor.h src/TPPSMonitor.cpp - include/TNetwork.h src/TNetwork.cpp) + include/TNetwork.h src/TNetwork.cpp + include/LuaAPI.h src/LuaAPI.cpp) target_include_directories(BeamMP-Server PRIVATE "${PROJECT_SOURCE_DIR}/deps/asio/asio/include") target_include_directories(BeamMP-Server PRIVATE "${PROJECT_SOURCE_DIR}/deps/rapidjson/include") diff --git a/include/Common.h b/include/Common.h index 52577f9..c74a16e 100644 --- a/include/Common.h +++ b/include/Common.h @@ -125,6 +125,7 @@ void RegisterThread(const std::string str); #define beammp_warn(x) Application::Console().Write(_this_location + std::string("[WARN] ") + (x)) #define beammp_info(x) Application::Console().Write(_this_location + std::string("[INFO] ") + (x)) #define beammp_error(x) Application::Console().Write(_this_location + std::string("[ERROR] ") + (x)) +#define beammp_lua_error(x) Application::Console().Write(_this_location + std::string("[LUA ERROR] ") + (x)) #define luaprint(x) Application::Console().Write(_this_location + std::string("[LUA] ") + (x)) #define beammp_debug(x) \ do { \ diff --git a/include/LuaAPI.h b/include/LuaAPI.h new file mode 100644 index 0000000..43a1722 --- /dev/null +++ b/include/LuaAPI.h @@ -0,0 +1,13 @@ +#pragma once + +#include +#include "TLuaEngine.h" + +namespace LuaAPI { +void Print(sol::variadic_args); +namespace MP { + static inline TLuaEngine* Engine { nullptr }; + void GetOSName(); + std::tuple GetServerVersion(); +} +} diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index 4899817..b80dfc3 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -12,6 +12,9 @@ #include #include +#define SOL_ALL_SAFETIES_ON 1 +#include + using TLuaStateId = std::string; namespace fs = std::filesystem; @@ -21,7 +24,9 @@ struct TLuaResult { std::atomic_bool Ready; std::atomic_bool Error; std::string ErrorMessage; + sol::protected_function_result Result; // TODO: Add condition_variable + void WaitUntilReady(); }; struct TLuaPluginConfig { @@ -37,27 +42,34 @@ public: void operator()() override; [[nodiscard]] std::shared_ptr EnqueueScript(TLuaStateId StateID, const std::shared_ptr& Script); - void EnsureStateExists(TLuaStateId StateId, const std::string& Name); + [[nodiscard]] std::shared_ptr EnqueueFunctionCall(TLuaStateId StateID, const std::string& FunctionName); + void EnsureStateExists(TLuaStateId StateId, const std::string& Name, bool DontCallOnInit = false); + + static constexpr const char* BeamMPFnNotFoundError = "BEAMMP_FN_NOT_FOUND"; private: - void CollectPlugins(); + void CollectAndInitPlugins(); void InitializePlugin(const fs::path& Folder, const TLuaPluginConfig& Config); void FindAndParseConfig(const fs::path& Folder, TLuaPluginConfig& Config); class StateThreadData : IThreaded { public: - StateThreadData(const std::string& Name, std::atomic_bool& Shutdown); + StateThreadData(const std::string& Name, std::atomic_bool& Shutdown, TLuaStateId StateId); StateThreadData(const StateThreadData&) = delete; [[nodiscard]] std::shared_ptr EnqueueScript(const std::shared_ptr& Script); + [[nodiscard]] std::shared_ptr EnqueueFunctionCall(const std::string& FunctionName); void operator()() override; private: std::string mName; std::atomic_bool& mShutdown; + TLuaStateId mStateId; lua_State* mState; std::thread mThread; std::queue, std::shared_ptr>> mStateExecuteQueue; std::mutex mStateExecuteQueueMutex; + std::queue>> mStateFunctionQueue; + std::mutex mStateFunctionQueueMutex; }; TNetwork& mNetwork; diff --git a/include/TLuaPlugin.h b/include/TLuaPlugin.h index c3ffc2f..a4cb5bd 100644 --- a/include/TLuaPlugin.h +++ b/include/TLuaPlugin.h @@ -2,7 +2,7 @@ class TLuaPlugin { public: - TLuaPlugin(TLuaEngine& Engine, const TLuaPluginConfig& Config); + TLuaPlugin(TLuaEngine& Engine, const TLuaPluginConfig& Config, const fs::path& MainFolder); TLuaPlugin(const TLuaPlugin&) = delete; TLuaPlugin& operator=(const TLuaPlugin&) = delete; ~TLuaPlugin() noexcept = default; @@ -12,4 +12,7 @@ public: private: TLuaPluginConfig mConfig; TLuaEngine& mEngine; + fs::path mFolder; + std::string mPluginName; + std::unordered_map> mFileContents; }; diff --git a/src/LuaAPI.cpp b/src/LuaAPI.cpp new file mode 100644 index 0000000..f50a04a --- /dev/null +++ b/src/LuaAPI.cpp @@ -0,0 +1,22 @@ +#include "LuaAPI.h" +#include "TLuaEngine.h" + +void LuaAPI::MP::GetOSName() { +} + +std::tuple LuaAPI::MP::GetServerVersion() { + return { Application::ServerVersion().major, Application::ServerVersion().minor, Application::ServerVersion().patch }; +} + +void LuaAPI::Print(sol::variadic_args Args) { + std::string ToPrint = ""; + for (const auto& Arg : Args) { + if (Arg.get_type() == sol::type::string) { + ToPrint += Arg.as(); + } else { + ToPrint += "((unprintable type))"; + } + ToPrint += " "; + } + luaprint(ToPrint); +} diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 3b0fa1e..94fe614 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -2,12 +2,11 @@ #include "CustomAssert.h" #include "TLuaPlugin.h" +#include "LuaAPI.h" + #include #include -#define SOL_ALL_SAFETIES_ON 1 -#include - static std::mt19937_64 MTGen64; static TLuaStateId GenerateUniqueStateId() { @@ -18,6 +17,7 @@ static TLuaStateId GenerateUniqueStateId() { TLuaEngine::TLuaEngine(TServer& Server, TNetwork& Network) : mNetwork(Network) , mServer(Server) { + LuaAPI::MP::Engine = this; if (!fs::exists(Application::Settings.Resource)) { fs::create_directory(Application::Settings.Resource); } @@ -38,7 +38,16 @@ TLuaEngine::TLuaEngine(TServer& Server, TNetwork& Network) void TLuaEngine::operator()() { RegisterThread("LuaEngine"); // lua engine main thread - CollectPlugins(); + CollectAndInitPlugins(); + // now call all onInit's + for (const auto& Pair : mLuaStates) { + auto Res = EnqueueFunctionCall(Pair.first, "onInit"); + Res->WaitUntilReady(); + if (Res->Error && Res->ErrorMessage != TLuaEngine::BeamMPFnNotFoundError) { + beammp_lua_error("Calling \"onInit\" on \"" + Pair.first + "\" failed: " + Res->ErrorMessage); + } + } + // this thread handles timers while (!mShutdown) { std::this_thread::sleep_for(std::chrono::milliseconds(10)); } @@ -46,12 +55,17 @@ void TLuaEngine::operator()() { std::shared_ptr TLuaEngine::EnqueueScript(TLuaStateId StateID, const std::shared_ptr& Script) { std::unique_lock Lock(mLuaStatesMutex); - TLuaResult Result; beammp_debug("enqueuing script into \"" + StateID + "\""); return mLuaStates.at(StateID)->EnqueueScript(Script); } -void TLuaEngine::CollectPlugins() { +std::shared_ptr TLuaEngine::EnqueueFunctionCall(TLuaStateId StateID, const std::string& FunctionName) { + std::unique_lock Lock(mLuaStatesMutex); + beammp_debug("calling \"" + FunctionName + "\" in \"" + StateID + "\""); + return mLuaStates.at(StateID)->EnqueueFunctionCall(FunctionName); +} + +void TLuaEngine::CollectAndInitPlugins() { for (const auto& Dir : fs::directory_iterator(mResourceServerPath)) { auto Path = Dir.path(); Path = fs::relative(Path); @@ -69,9 +83,10 @@ void TLuaEngine::CollectPlugins() { void TLuaEngine::InitializePlugin(const fs::path& Folder, const TLuaPluginConfig& Config) { beammp_assert(fs::exists(Folder)); beammp_assert(fs::is_directory(Folder)); - TLuaPlugin Plugin(*this, Config); std::unique_lock Lock(mLuaStatesMutex); - EnsureStateExists(Config.StateId, Folder.stem().string()); + EnsureStateExists(Config.StateId, Folder.stem().string(), true); + Lock.unlock(); + TLuaPlugin Plugin(*this, Config, Folder); } void TLuaEngine::FindAndParseConfig(const fs::path& Folder, TLuaPluginConfig& Config) { @@ -96,56 +111,113 @@ void TLuaEngine::FindAndParseConfig(const fs::path& Folder, TLuaPluginConfig& Co } } -void TLuaEngine::EnsureStateExists(TLuaStateId StateId, const std::string& Name) { +void TLuaEngine::EnsureStateExists(TLuaStateId StateId, const std::string& Name, bool DontCallOnInit) { if (mLuaStates.find(StateId) == mLuaStates.end()) { beammp_debug("Creating lua state for state id \"" + StateId + "\""); - auto DataPtr = std::make_unique(Name, mShutdown); + auto DataPtr = std::make_unique(Name, mShutdown, StateId); mLuaStates[StateId] = std::move(DataPtr); + if (!DontCallOnInit) { + auto Res = EnqueueFunctionCall(StateId, "onInit"); + Res->WaitUntilReady(); + if (Res->Error && Res->ErrorMessage != TLuaEngine::BeamMPFnNotFoundError) { + beammp_lua_error("Calling \"onInit\" on \"" + StateId + "\" failed: " + Res->ErrorMessage); + } + } } } -TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomic_bool& Shutdown) +TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomic_bool& Shutdown, TLuaStateId StateId) : mName(Name) - , mShutdown(Shutdown) { + , mShutdown(Shutdown) + , mStateId(StateId) { mState = luaL_newstate(); luaL_openlibs(mState); sol::state_view StateView(mState); - auto LuaPrint = [](const std::string& Msg) { luaprint(Msg); }; - StateView.set_function("print", LuaPrint); + StateView.set_function("print", &LuaAPI::Print); + auto Table = StateView.create_named_table("MP"); + Table.set_function("GetOSName", &LuaAPI::MP::GetOSName); + Table.set_function("GetServerVersion", &LuaAPI::MP::GetServerVersion); Start(); } std::shared_ptr TLuaEngine::StateThreadData::EnqueueScript(const std::shared_ptr& Script) { - beammp_debug("enqueuing script into \"" + mName + "\""); + beammp_debug("enqueuing script into \"" + mStateId + "\""); std::unique_lock Lock(mStateExecuteQueueMutex); auto Result = std::make_shared(); mStateExecuteQueue.push({ Script, Result }); return Result; } +std::shared_ptr TLuaEngine::StateThreadData::EnqueueFunctionCall(const std::string& FunctionName) { + beammp_debug("calling \"" + FunctionName + "\" in \"" + mName + "\""); + std::unique_lock Lock(mStateFunctionQueueMutex); + auto Result = std::make_shared(); + mStateFunctionQueue.push({ FunctionName, Result }); + return Result; +} + void TLuaEngine::StateThreadData::operator()() { - RegisterThread(mName); + RegisterThread("Lua:" + mStateId); while (!mShutdown) { - std::unique_lock Lock(mStateExecuteQueueMutex); - if (mStateExecuteQueue.empty()) { - Lock.unlock(); - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - } else { - auto S = mStateExecuteQueue.front(); - mStateExecuteQueue.pop(); - Lock.unlock(); - beammp_debug("Running script"); - sol::state_view StateView(mState); - auto Res = StateView.safe_script(*S.first, sol::script_pass_on_error); - if (Res.valid()) { - S.second->Error = false; + { // StateExecuteQueue Scope + std::unique_lock Lock(mStateExecuteQueueMutex); + if (mStateExecuteQueue.empty()) { + Lock.unlock(); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); } else { - S.second->Error = true; - sol::error Err = Res; - S.second->ErrorMessage = Err.what(); + auto S = mStateExecuteQueue.front(); + mStateExecuteQueue.pop(); + Lock.unlock(); + beammp_debug("Running script"); + sol::state_view StateView(mState); + auto Res = StateView.safe_script(*S.first, sol::script_pass_on_error); + S.second->Ready = true; + if (Res.valid()) { + S.second->Error = false; + S.second->Result = std::move(Res); + } else { + S.second->Error = true; + sol::error Err = Res; + S.second->ErrorMessage = Err.what(); + } } - S.second->Ready = true; } + { // StateFunctionQueue Scope + std::unique_lock Lock(mStateFunctionQueueMutex); + if (mStateFunctionQueue.empty()) { + Lock.unlock(); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } else { + auto FnNameResultPair = mStateFunctionQueue.front(); + mStateFunctionQueue.pop(); + Lock.unlock(); + beammp_debug("Running function"); + sol::state_view StateView(mState); + auto Fn = StateView[FnNameResultPair.first]; + if (Fn.valid() && Fn.get_type() == sol::type::function) { + auto Res = Fn(); + FnNameResultPair.second->Ready = true; + if (Res.valid()) { + FnNameResultPair.second->Error = false; + FnNameResultPair.second->Result = std::move(Res); + } else { + FnNameResultPair.second->Error = true; + sol::error Err = Res; + FnNameResultPair.second->ErrorMessage = Err.what(); + } + } else { + FnNameResultPair.second->Ready = true; + FnNameResultPair.second->Error = true; + FnNameResultPair.second->ErrorMessage = BeamMPFnNotFoundError; // special error kind that we can ignore later + } + } + } + } +} + +void TLuaResult::WaitUntilReady() { + while (!Ready) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); } } diff --git a/src/TLuaPlugin.cpp b/src/TLuaPlugin.cpp index 5567335..48e7d8a 100644 --- a/src/TLuaPlugin.cpp +++ b/src/TLuaPlugin.cpp @@ -4,7 +4,56 @@ #include #include -TLuaPlugin::TLuaPlugin(TLuaEngine& Engine, const TLuaPluginConfig& Config) +TLuaPlugin::TLuaPlugin(TLuaEngine& Engine, const TLuaPluginConfig& Config, const fs::path& MainFolder) : mConfig(Config) - , mEngine(Engine) { + , mEngine(Engine) + , mFolder(MainFolder) + , mPluginName(MainFolder.stem().string()) + , mFileContents(0) { + beammp_debug("Lua plugin \"" + mPluginName + "\" starting in \"" + mFolder.string() + "\""); + std::vector Entries; + for (const auto& Entry : fs::directory_iterator(mFolder)) { + if (Entry.is_regular_file() && Entry.path().extension() == ".lua") { + beammp_debug("Found script \"" + Entry.path().string() + "\" in \"" + mFolder.string() + "\""); + Entries.push_back(Entry); + } + } + // sort alphabetically (not needed if config is used to determine call order) + // TODO: Use config to figure out what to run in which order + std::sort(Entries.begin(), Entries.end(), [](const fs::path& first, const fs::path& second) { + auto firstStr = first.string(); + auto secondStr = second.string(); + std::transform(firstStr.begin(), firstStr.end(), firstStr.begin(), ::tolower); + std::transform(secondStr.begin(), secondStr.end(), secondStr.begin(), ::tolower); + return firstStr < secondStr; + }); + std::vector>> ResultsToCheck; + for (const auto& Entry : Entries) { + // read in entire file + std::FILE* File = std::fopen(Entry.c_str(), "r"); + if (File) { + auto Size = std::filesystem::file_size(Entry); + auto Contents = std::make_shared(); + Contents->resize(Size); + auto NRead = std::fread(Contents->data(), 1, Contents->size(), File); + if (NRead == Contents->size()) { + beammp_debug("Successfully read \"" + Entry.string() + "\" (" + std::to_string(NRead) + " Bytes)"); + mFileContents[fs::relative(Entry)] = Contents; + // Execute first time + auto Result = mEngine.EnqueueScript(mConfig.StateId, Contents); + ResultsToCheck.emplace_back(Entry, std::move(Result)); + } else { + beammp_error("Error while reading script file \"" + Entry.string() + "\". Did the file change while reading?"); + } + std::fclose(File); + } else { + beammp_error("Could not read script file \"" + Entry.string() + "\": " + std::strerror(errno)); + } + } + for (auto& Result : ResultsToCheck) { + Result.second->WaitUntilReady(); + if (Result.second->Error) { + beammp_lua_error("Failed: \"" + Result.first.string() + "\": " + Result.second->ErrorMessage); + } + } } From 9ef6c32864af8b866e3204c0dce67d986c0b0687 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 16 Sep 2021 11:59:00 +0200 Subject: [PATCH 089/255] CMake: fix include paths --- CMakeLists.txt | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e7f1c4..b72bdb6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,12 +46,13 @@ add_executable(BeamMP-Server include/TNetwork.h src/TNetwork.cpp include/LuaAPI.h src/LuaAPI.cpp) -target_include_directories(BeamMP-Server PRIVATE "${PROJECT_SOURCE_DIR}/deps/asio/asio/include") -target_include_directories(BeamMP-Server PRIVATE "${PROJECT_SOURCE_DIR}/deps/rapidjson/include") -target_include_directories(BeamMP-Server PRIVATE "${PROJECT_SOURCE_DIR}/deps/websocketpp") -target_include_directories(BeamMP-Server PRIVATE "${PROJECT_SOURCE_DIR}/deps/commandline") -target_include_directories(BeamMP-Server PRIVATE "${PROJECT_SOURCE_DIR}/deps/sol2/include") -target_include_directories(BeamMP-Server PRIVATE "${PROJECT_SOURCE_DIR}/deps") +include_directories("${PROJECT_SOURCE_DIR}/deps/asio/asio/include") +include_directories("${PROJECT_SOURCE_DIR}/deps/asio/asio/include") +include_directories("${PROJECT_SOURCE_DIR}/deps/rapidjson/include") +include_directories("${PROJECT_SOURCE_DIR}/deps/websocketpp") +include_directories("${PROJECT_SOURCE_DIR}/deps/commandline") +include_directories("${PROJECT_SOURCE_DIR}/deps/sol2/include") +include_directories("${PROJECT_SOURCE_DIR}/deps") include_directories(BeamMP-Server PUBLIC ${Boost_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}/include) From d7f7a81cb00d94cbe893969b5e727aa03a6689f2 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 16 Sep 2021 12:21:11 +0200 Subject: [PATCH 090/255] LuaAPI: Print: dump tables properly and recursively --- include/LuaAPI.h | 3 ++- src/LuaAPI.cpp | 39 +++++++++++++++++++++++++++++++++------ 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/include/LuaAPI.h b/include/LuaAPI.h index 43a1722..b7b6493 100644 --- a/include/LuaAPI.h +++ b/include/LuaAPI.h @@ -1,12 +1,13 @@ #pragma once -#include #include "TLuaEngine.h" +#include namespace LuaAPI { void Print(sol::variadic_args); namespace MP { static inline TLuaEngine* Engine { nullptr }; + void GetOSName(); std::tuple GetServerVersion(); } diff --git a/src/LuaAPI.cpp b/src/LuaAPI.cpp index f50a04a..084df24 100644 --- a/src/LuaAPI.cpp +++ b/src/LuaAPI.cpp @@ -1,6 +1,37 @@ #include "LuaAPI.h" #include "TLuaEngine.h" +static std::string LuaToString(const sol::object& Value) { + switch (Value.get_type()) { + case sol::type::string: + return Value.as(); + case sol::type::number: + return std::to_string(Value.as()); + case sol::type::boolean: + return Value.as() ? "true" : "false"; + case sol::type::table: { + std::stringstream Result; + auto Table = Value.as(); + Result << "[[table: " << Table.pointer() << "]]: {"; + if (!Table.empty()) { + for (const auto& Entry : Table) { + Result << "\n\t" << LuaToString(Entry.first) << ": " << LuaToString(Entry.second) << ","; + } + Result << "\n"; + } + Result << "}"; + return Result.str(); + } + case sol::type::function: { + std::stringstream ss; + ss << "[[function: " << Value.as().pointer() << "]]"; + return ss.str(); + } + default: + return "((unprintable type))"; + } +} + void LuaAPI::MP::GetOSName() { } @@ -11,12 +42,8 @@ std::tuple LuaAPI::MP::GetServerVersion() { void LuaAPI::Print(sol::variadic_args Args) { std::string ToPrint = ""; for (const auto& Arg : Args) { - if (Arg.get_type() == sol::type::string) { - ToPrint += Arg.as(); - } else { - ToPrint += "((unprintable type))"; - } - ToPrint += " "; + ToPrint += LuaToString(Arg); + ToPrint += "\t"; } luaprint(ToPrint); } From ebe3630ec8bfefe7b77df8f1570ed4387f2f3641 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 16 Sep 2021 12:22:49 +0200 Subject: [PATCH 091/255] LuaAPI: Implement GetOSName --- include/LuaAPI.h | 2 +- src/LuaAPI.cpp | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/include/LuaAPI.h b/include/LuaAPI.h index b7b6493..93ea0ac 100644 --- a/include/LuaAPI.h +++ b/include/LuaAPI.h @@ -8,7 +8,7 @@ void Print(sol::variadic_args); namespace MP { static inline TLuaEngine* Engine { nullptr }; - void GetOSName(); + std::string GetOSName(); std::tuple GetServerVersion(); } } diff --git a/src/LuaAPI.cpp b/src/LuaAPI.cpp index 084df24..03a7bdc 100644 --- a/src/LuaAPI.cpp +++ b/src/LuaAPI.cpp @@ -32,7 +32,14 @@ static std::string LuaToString(const sol::object& Value) { } } -void LuaAPI::MP::GetOSName() { +std::string LuaAPI::MP::GetOSName() { +#if WIN32 + return "Windows"; +#elif __linux + return "Linux"; +#else + return "Other"; +#endif } std::tuple LuaAPI::MP::GetServerVersion() { From 26231c627254e292b20a161bcd502f19f3f43214 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 16 Sep 2021 13:03:00 +0200 Subject: [PATCH 092/255] Fix compile issue with asio, implement Lua events --- CMakeLists.txt | 15 +++++++-------- deps/CMakeLists.txt | 7 +++++++ include/TLuaEngine.h | 15 +++++++++++---- src/LuaAPI.cpp | 11 +++++++++-- src/TLuaEngine.cpp | 43 +++++++++++++++++++++++++++++++++++++++---- 5 files changed, 73 insertions(+), 18 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b72bdb6..6e49c0b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,13 @@ cmake_minimum_required(VERSION 3.0) project(Server) +include_directories("${PROJECT_SOURCE_DIR}/deps/asio/asio/include") +include_directories("${PROJECT_SOURCE_DIR}/deps/rapidjson/include") +include_directories("${PROJECT_SOURCE_DIR}/deps/websocketpp") +include_directories("${PROJECT_SOURCE_DIR}/deps/commandline") +include_directories("${PROJECT_SOURCE_DIR}/deps/sol2/include") +include_directories("${PROJECT_SOURCE_DIR}/deps") + if (WIN32) message(STATUS "MSVC -> forcing use of statically-linked runtime.") STRING(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE}) @@ -46,14 +53,6 @@ add_executable(BeamMP-Server include/TNetwork.h src/TNetwork.cpp include/LuaAPI.h src/LuaAPI.cpp) -include_directories("${PROJECT_SOURCE_DIR}/deps/asio/asio/include") -include_directories("${PROJECT_SOURCE_DIR}/deps/asio/asio/include") -include_directories("${PROJECT_SOURCE_DIR}/deps/rapidjson/include") -include_directories("${PROJECT_SOURCE_DIR}/deps/websocketpp") -include_directories("${PROJECT_SOURCE_DIR}/deps/commandline") -include_directories("${PROJECT_SOURCE_DIR}/deps/sol2/include") -include_directories("${PROJECT_SOURCE_DIR}/deps") - include_directories(BeamMP-Server PUBLIC ${Boost_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}/include) find_package(Lua REQUIRED) diff --git a/deps/CMakeLists.txt b/deps/CMakeLists.txt index 06cef70..5504038 100644 --- a/deps/CMakeLists.txt +++ b/deps/CMakeLists.txt @@ -1,3 +1,10 @@ +include_directories("${PROJECT_SOURCE_DIR}/deps/asio/asio/include") +include_directories("${PROJECT_SOURCE_DIR}/deps/rapidjson/include") +include_directories("${PROJECT_SOURCE_DIR}/deps/websocketpp") +include_directories("${PROJECT_SOURCE_DIR}/deps/commandline") +include_directories("${PROJECT_SOURCE_DIR}/deps/sol2/include") +include_directories("${PROJECT_SOURCE_DIR}/deps") + add_subdirectory("${PROJECT_SOURCE_DIR}/deps/socket.io-client-cpp") add_subdirectory("${PROJECT_SOURCE_DIR}/deps/commandline") add_subdirectory("${PROJECT_SOURCE_DIR}/deps/sol2") diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index b80dfc3..ba66fa4 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -11,6 +11,7 @@ #include #include #include +#include #define SOL_ALL_SAFETIES_ON 1 #include @@ -44,6 +45,8 @@ public: [[nodiscard]] std::shared_ptr EnqueueScript(TLuaStateId StateID, const std::shared_ptr& Script); [[nodiscard]] std::shared_ptr EnqueueFunctionCall(TLuaStateId StateID, const std::string& FunctionName); void EnsureStateExists(TLuaStateId StateId, const std::string& Name, bool DontCallOnInit = false); + void RegisterEvent(const std::string& EventName, TLuaStateId StateId, const std::string& FunctionName); + [[nodiscard]] std::vector> TriggerEvent(const std::string& EventName); static constexpr const char* BeamMPFnNotFoundError = "BEAMMP_FN_NOT_FOUND"; @@ -54,10 +57,11 @@ private: class StateThreadData : IThreaded { public: - StateThreadData(const std::string& Name, std::atomic_bool& Shutdown, TLuaStateId StateId); + StateThreadData(const std::string& Name, std::atomic_bool& Shutdown, TLuaStateId StateId, TLuaEngine& Engine); StateThreadData(const StateThreadData&) = delete; [[nodiscard]] std::shared_ptr EnqueueScript(const std::shared_ptr& Script); [[nodiscard]] std::shared_ptr EnqueueFunctionCall(const std::string& FunctionName); + void RegisterEvent(const std::string& EventName, const std::string& FunctionName); void operator()() override; private: @@ -67,9 +71,10 @@ private: lua_State* mState; std::thread mThread; std::queue, std::shared_ptr>> mStateExecuteQueue; - std::mutex mStateExecuteQueueMutex; + std::recursive_mutex mStateExecuteQueueMutex; std::queue>> mStateFunctionQueue; - std::mutex mStateFunctionQueueMutex; + std::recursive_mutex mStateFunctionQueueMutex; + TLuaEngine* mEngine; }; TNetwork& mNetwork; @@ -78,7 +83,9 @@ private: fs::path mResourceServerPath; std::vector mLuaPlugins; std::unordered_map> mLuaStates; - std::mutex mLuaStatesMutex; + std::recursive_mutex mLuaStatesMutex; + std::unordered_map>> mEvents; + std::recursive_mutex mEventsMutex; }; #include diff --git a/src/LuaAPI.cpp b/src/LuaAPI.cpp index 03a7bdc..5519c2a 100644 --- a/src/LuaAPI.cpp +++ b/src/LuaAPI.cpp @@ -1,7 +1,7 @@ #include "LuaAPI.h" #include "TLuaEngine.h" -static std::string LuaToString(const sol::object& Value) { +static std::string LuaToString(const sol::object& Value, size_t Indent = 1) { switch (Value.get_type()) { case sol::type::string: return Value.as(); @@ -15,10 +15,17 @@ static std::string LuaToString(const sol::object& Value) { Result << "[[table: " << Table.pointer() << "]]: {"; if (!Table.empty()) { for (const auto& Entry : Table) { - Result << "\n\t" << LuaToString(Entry.first) << ": " << LuaToString(Entry.second) << ","; + Result << "\n"; + for (size_t i = 0; i < Indent; ++i) { + Result << "\t"; + } + Result << LuaToString(Entry.first, Indent + 1) << ": " << LuaToString(Entry.second, Indent + 1) << ","; } Result << "\n"; } + for (size_t i = 0; i < Indent - 1; ++i) { + Result << "\t"; + } Result << "}"; return Result.str(); } diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 94fe614..3acc2cd 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -93,7 +93,6 @@ void TLuaEngine::FindAndParseConfig(const fs::path& Folder, TLuaPluginConfig& Co auto ConfigFile = Folder / TLuaPluginConfig::FileName; if (fs::exists(ConfigFile) && fs::is_regular_file(ConfigFile)) { beammp_debug("\"" + ConfigFile.string() + "\" found"); - // TODO use toml11 here to parse it try { auto Data = toml::parse(ConfigFile); if (Data.contains("LuaStateID")) { @@ -112,10 +111,12 @@ void TLuaEngine::FindAndParseConfig(const fs::path& Folder, TLuaPluginConfig& Co } void TLuaEngine::EnsureStateExists(TLuaStateId StateId, const std::string& Name, bool DontCallOnInit) { + std::unique_lock Lock(mLuaStatesMutex); if (mLuaStates.find(StateId) == mLuaStates.end()) { beammp_debug("Creating lua state for state id \"" + StateId + "\""); - auto DataPtr = std::make_unique(Name, mShutdown, StateId); + auto DataPtr = std::make_unique(Name, mShutdown, StateId, *this); mLuaStates[StateId] = std::move(DataPtr); + RegisterEvent("onInit", StateId, "onInit"); if (!DontCallOnInit) { auto Res = EnqueueFunctionCall(StateId, "onInit"); Res->WaitUntilReady(); @@ -126,10 +127,27 @@ void TLuaEngine::EnsureStateExists(TLuaStateId StateId, const std::string& Name, } } -TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomic_bool& Shutdown, TLuaStateId StateId) +void TLuaEngine::RegisterEvent(const std::string& EventName, TLuaStateId StateId, const std::string& FunctionName) { + std::unique_lock Lock(mEventsMutex); + mEvents[EventName][StateId].insert(FunctionName); +} + +std::vector> TLuaEngine::TriggerEvent(const std::string& EventName) { + std::unique_lock Lock(mEventsMutex); + std::vector> Results; + for (const auto& Entry : mEvents[EventName]) { + for (const auto& Function : Entry.second) { + Results.emplace_back(EnqueueFunctionCall(Entry.first, Function)); + } + } + return Results; +} + +TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomic_bool& Shutdown, TLuaStateId StateId, TLuaEngine& Engine) : mName(Name) , mShutdown(Shutdown) - , mStateId(StateId) { + , mStateId(StateId) + , mEngine(&Engine) { mState = luaL_newstate(); luaL_openlibs(mState); sol::state_view StateView(mState); @@ -137,6 +155,19 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi auto Table = StateView.create_named_table("MP"); Table.set_function("GetOSName", &LuaAPI::MP::GetOSName); Table.set_function("GetServerVersion", &LuaAPI::MP::GetServerVersion); + Table.set_function("RegisterEvent", + [this](const std::string& EventName, const std::string& FunctionName) { + RegisterEvent(EventName, FunctionName); + }); + Table.set_function(""); + Table.create_named("Settings", + "Debug", 0, + "Private", 1, + "MaxCars", 2, + "MaxPlayers", 3, + "Map", 4, + "Name", 5, + "Description", 6); Start(); } @@ -156,6 +187,10 @@ std::shared_ptr TLuaEngine::StateThreadData::EnqueueFunctionCall(con return Result; } +void TLuaEngine::StateThreadData::RegisterEvent(const std::string& EventName, const std::string& FunctionName) { + mEngine->RegisterEvent(EventName, mStateId, FunctionName); +} + void TLuaEngine::StateThreadData::operator()() { RegisterThread("Lua:" + mStateId); while (!mShutdown) { From dca573b15c5836b75d016d101fd1c03b5e90d7ef Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 16 Sep 2021 13:06:04 +0200 Subject: [PATCH 093/255] Fix more compile issues with lua, add TriggerGlobalEvent --- CMakeLists.txt | 1 + src/TLuaEngine.cpp | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e49c0b..fcd9ba3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,6 +56,7 @@ add_executable(BeamMP-Server include_directories(BeamMP-Server PUBLIC ${Boost_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}/include) find_package(Lua REQUIRED) +include_directories(${LUA_INCLUDE_DIR}) find_package(OpenSSL REQUIRED) target_link_libraries(BeamMP-Server sol2::sol2 ${LUA_LIBRARIES}) diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 3acc2cd..32293f4 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -159,7 +159,10 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi [this](const std::string& EventName, const std::string& FunctionName) { RegisterEvent(EventName, FunctionName); }); - Table.set_function(""); + Table.set_function("TriggerGlobalEvent", + [&](const std::string& EventName) { + return mEngine->TriggerEvent(EventName); + }); Table.create_named("Settings", "Debug", 0, "Private", 1, From e602decb96edaa0ff5c71cf4bb6eede88150bad6 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 16 Sep 2021 14:58:47 +0200 Subject: [PATCH 094/255] Lua: Fix multiple issues with events --- include/TLuaEngine.h | 2 ++ src/TConsole.cpp | 13 +++++----- src/TLuaEngine.cpp | 59 ++++++++++++++++++++++++++++++++------------ 3 files changed, 52 insertions(+), 22 deletions(-) diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index ba66fa4..69526dd 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -26,6 +26,8 @@ struct TLuaResult { std::atomic_bool Error; std::string ErrorMessage; sol::protected_function_result Result; + TLuaStateId StateId; + std::string Function; // TODO: Add condition_variable void WaitUntilReady(); }; diff --git a/src/TConsole.cpp b/src/TConsole.cpp index 34e858f..3702c35 100644 --- a/src/TConsole.cpp +++ b/src/TConsole.cpp @@ -58,16 +58,17 @@ TConsole::TConsole() { } else if (cmd == "clear" || cmd == "cls") { // TODO: clear screen } else { - while (!mLuaEngine) { - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - } - auto Future = mLuaEngine->EnqueueScript(mStateId, std::make_shared(cmd)); - // wait for it to finish - while (!Future->Ready) { + if (!mLuaEngine) { + beammp_info("Lua not started yet, please try again in a second"); + } else { + auto Future = mLuaEngine->EnqueueScript(mStateId, std::make_shared(cmd)); + // wait for it to finish + /*while (!Future->Ready) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); } if (Future->Error) { beammp_error(Future->ErrorMessage); + }*/ } } }; diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 32293f4..0475ec1 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -111,6 +111,7 @@ void TLuaEngine::FindAndParseConfig(const fs::path& Folder, TLuaPluginConfig& Co } void TLuaEngine::EnsureStateExists(TLuaStateId StateId, const std::string& Name, bool DontCallOnInit) { + beammp_assert(!StateId.empty()); std::unique_lock Lock(mLuaStatesMutex); if (mLuaStates.find(StateId) == mLuaStates.end()) { beammp_debug("Creating lua state for state id \"" + StateId + "\""); @@ -134,10 +135,14 @@ void TLuaEngine::RegisterEvent(const std::string& EventName, TLuaStateId StateId std::vector> TLuaEngine::TriggerEvent(const std::string& EventName) { std::unique_lock Lock(mEventsMutex); + if (mEvents.find(EventName) == mEvents.end()) { + return {}; + } std::vector> Results; - for (const auto& Entry : mEvents[EventName]) { - for (const auto& Function : Entry.second) { - Results.emplace_back(EnqueueFunctionCall(Entry.first, Function)); + for (const auto& Event : mEvents.at(EventName)) { + for (const auto& Function : Event.second) { + beammp_debug("TriggerEvent: triggering \"" + Function + "\" on \"" + Event.first + "\""); + Results.push_back(EnqueueFunctionCall(Event.first, Function)); } } return Results; @@ -151,6 +156,7 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi mState = luaL_newstate(); luaL_openlibs(mState); sol::state_view StateView(mState); + // StateView.globals()["package"].get() StateView.set_function("print", &LuaAPI::Print); auto Table = StateView.create_named_table("MP"); Table.set_function("GetOSName", &LuaAPI::MP::GetOSName); @@ -160,8 +166,32 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi RegisterEvent(EventName, FunctionName); }); Table.set_function("TriggerGlobalEvent", - [&](const std::string& EventName) { - return mEngine->TriggerEvent(EventName); + [&](const std::string& EventName) -> sol::table { + auto Return = mEngine->TriggerEvent(EventName); + beammp_debug("Triggering event \"" + EventName + "\" in \"" + mStateId + "\""); + sol::state_view StateView(mState); + sol::table AsyncEventReturn = StateView.create_table(); + AsyncEventReturn["ReturnValueImpl"] = Return; + AsyncEventReturn.set_function("Wait", + [&](const sol::table& Self) -> sol::table { + sol::state_view StateView(mState); + sol::table Result = StateView.create_table(); + beammp_debug("beginning to loop"); + auto Vector = Self.get>>("ReturnValueImpl"); + for (const auto& Value : Vector) { + beammp_debug("waiting on a value"); + Value->WaitUntilReady(); + if (Value->Error) { + if (Value->ErrorMessage != BeamMPFnNotFoundError) { + beammp_lua_error("\"" + StateId + "\"" + Value->ErrorMessage); + } + } else { + Result.add(Value->Result); + } + } + return Result; + }); + return AsyncEventReturn; }); Table.create_named("Settings", "Debug", 0, @@ -186,6 +216,7 @@ std::shared_ptr TLuaEngine::StateThreadData::EnqueueFunctionCall(con beammp_debug("calling \"" + FunctionName + "\" in \"" + mName + "\""); std::unique_lock Lock(mStateFunctionQueueMutex); auto Result = std::make_shared(); + Result->StateId = mStateId; mStateFunctionQueue.push({ FunctionName, Result }); return Result; } @@ -199,10 +230,7 @@ void TLuaEngine::StateThreadData::operator()() { while (!mShutdown) { { // StateExecuteQueue Scope std::unique_lock Lock(mStateExecuteQueueMutex); - if (mStateExecuteQueue.empty()) { - Lock.unlock(); - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - } else { + if (!mStateExecuteQueue.empty()) { auto S = mStateExecuteQueue.front(); mStateExecuteQueue.pop(); Lock.unlock(); @@ -222,19 +250,17 @@ void TLuaEngine::StateThreadData::operator()() { } { // StateFunctionQueue Scope std::unique_lock Lock(mStateFunctionQueueMutex); - if (mStateFunctionQueue.empty()) { - Lock.unlock(); - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - } else { + if (!mStateFunctionQueue.empty()) { auto FnNameResultPair = mStateFunctionQueue.front(); mStateFunctionQueue.pop(); Lock.unlock(); - beammp_debug("Running function"); + FnNameResultPair.second->StateId = mStateId; + beammp_debug("Running function \"" + FnNameResultPair.first + "\""); sol::state_view StateView(mState); auto Fn = StateView[FnNameResultPair.first]; + beammp_debug("Done running function \"" + FnNameResultPair.first + "\""); if (Fn.valid() && Fn.get_type() == sol::type::function) { auto Res = Fn(); - FnNameResultPair.second->Ready = true; if (Res.valid()) { FnNameResultPair.second->Error = false; FnNameResultPair.second->Result = std::move(Res); @@ -243,10 +269,11 @@ void TLuaEngine::StateThreadData::operator()() { sol::error Err = Res; FnNameResultPair.second->ErrorMessage = Err.what(); } - } else { FnNameResultPair.second->Ready = true; + } else { FnNameResultPair.second->Error = true; FnNameResultPair.second->ErrorMessage = BeamMPFnNotFoundError; // special error kind that we can ignore later + FnNameResultPair.second->Ready = true; } } } From 1c80a4deb729806235578e978c766d3c500f5995 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 16 Sep 2021 18:14:11 +0200 Subject: [PATCH 095/255] Lua: working events, global and local --- include/TLuaEngine.h | 14 ++++++-- src/LuaAPI.cpp | 2 ++ src/TConsole.cpp | 13 ++++--- src/TLuaEngine.cpp | 82 ++++++++++++++++++++++++++++++-------------- 4 files changed, 75 insertions(+), 36 deletions(-) diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index 69526dd..3701f56 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -8,10 +8,10 @@ #include #include #include +#include #include #include #include -#include #define SOL_ALL_SAFETIES_ON 1 #include @@ -25,7 +25,7 @@ struct TLuaResult { std::atomic_bool Ready; std::atomic_bool Error; std::string ErrorMessage; - sol::protected_function_result Result; + sol::object Result { sol::nil }; TLuaStateId StateId; std::string Function; // TODO: Add condition_variable @@ -41,6 +41,9 @@ struct TLuaPluginConfig { class TLuaEngine : IThreaded { public: TLuaEngine(TServer& Server, TNetwork& Network); + ~TLuaEngine() noexcept { + beammp_debug("Lua Engine terminated"); + } void operator()() override; @@ -49,6 +52,7 @@ public: void EnsureStateExists(TLuaStateId StateId, const std::string& Name, bool DontCallOnInit = false); void RegisterEvent(const std::string& EventName, TLuaStateId StateId, const std::string& FunctionName); [[nodiscard]] std::vector> TriggerEvent(const std::string& EventName); + std::set GetEventHandlersForState(const std::string& EventName, TLuaStateId StateId); static constexpr const char* BeamMPFnNotFoundError = "BEAMMP_FN_NOT_FOUND"; @@ -61,12 +65,16 @@ private: public: StateThreadData(const std::string& Name, std::atomic_bool& Shutdown, TLuaStateId StateId, TLuaEngine& Engine); StateThreadData(const StateThreadData&) = delete; + ~StateThreadData() noexcept { beammp_debug("\"" + mStateId + "\" destroyed"); } [[nodiscard]] std::shared_ptr EnqueueScript(const std::shared_ptr& Script); [[nodiscard]] std::shared_ptr EnqueueFunctionCall(const std::string& FunctionName); void RegisterEvent(const std::string& EventName, const std::string& FunctionName); void operator()() override; - + private: + sol::table Lua_TriggerGlobalEvent(const std::string& EventName); + sol::table Lua_TriggerLocalEvent(const std::string& EventName); + std::string mName; std::atomic_bool& mShutdown; TLuaStateId mStateId; diff --git a/src/LuaAPI.cpp b/src/LuaAPI.cpp index 5519c2a..c13f01f 100644 --- a/src/LuaAPI.cpp +++ b/src/LuaAPI.cpp @@ -7,6 +7,8 @@ static std::string LuaToString(const sol::object& Value, size_t Indent = 1) { return Value.as(); case sol::type::number: return std::to_string(Value.as()); + case sol::type::nil: + return ""; case sol::type::boolean: return Value.as() ? "true" : "false"; case sol::type::table: { diff --git a/src/TConsole.cpp b/src/TConsole.cpp index 3702c35..423e132 100644 --- a/src/TConsole.cpp +++ b/src/TConsole.cpp @@ -62,13 +62,12 @@ TConsole::TConsole() { beammp_info("Lua not started yet, please try again in a second"); } else { auto Future = mLuaEngine->EnqueueScript(mStateId, std::make_shared(cmd)); - // wait for it to finish - /*while (!Future->Ready) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - if (Future->Error) { - beammp_error(Future->ErrorMessage); - }*/ + while (!Future->Ready) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + if (Future->Error) { + beammp_lua_error(Future->ErrorMessage); + } } } }; diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 0475ec1..d6752e4 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -148,6 +148,54 @@ std::vector> TLuaEngine::TriggerEvent(const std::str return Results; } +std::set TLuaEngine::GetEventHandlersForState(const std::string& EventName, TLuaStateId StateId) { + return mEvents[EventName][StateId]; +} + +sol::table TLuaEngine::StateThreadData::Lua_TriggerGlobalEvent(const std::string& EventName) { + auto Return = mEngine->TriggerEvent(EventName); + beammp_debug("Triggering event \"" + EventName + "\" in \"" + mStateId + "\""); + sol::state_view StateView(mState); + sol::table AsyncEventReturn = StateView.create_table(); + AsyncEventReturn["ReturnValueImpl"] = Return; + AsyncEventReturn.set_function("IsDone", + [&](const sol::table& Self) -> bool { + auto Vector = Self.get>>("ReturnValueImpl"); + for (const auto& Value : Vector) { + if (!Value->Ready) { + return false; + } + } + return true; + }); + AsyncEventReturn.set_function("GetResults", + [&](const sol::table& Self) -> sol::table { + sol::state_view StateView(mState); + sol::table Result = StateView.create_table(); + auto Vector = Self.get>>("ReturnValueImpl"); + for (const auto& Value : Vector) { + if (!Value->Ready) { + return sol::nil; + } + Result.add(Value->Result); + } + return Result; + }); + return AsyncEventReturn; +} + +sol::table TLuaEngine::StateThreadData::Lua_TriggerLocalEvent(const std::string& EventName) { + sol::state_view StateView(mState); + sol::table Result = StateView.create_table(); + for (const auto& Handler : mEngine->GetEventHandlersForState(EventName, mStateId)) { + auto Fn = StateView[Handler]; + if (Fn.valid() && Fn.get_type() == sol::type::function) { + Result.add(Fn()); + } + } + return Result; +} + TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomic_bool& Shutdown, TLuaStateId StateId, TLuaEngine& Engine) : mName(Name) , mShutdown(Shutdown) @@ -167,31 +215,11 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi }); Table.set_function("TriggerGlobalEvent", [&](const std::string& EventName) -> sol::table { - auto Return = mEngine->TriggerEvent(EventName); - beammp_debug("Triggering event \"" + EventName + "\" in \"" + mStateId + "\""); - sol::state_view StateView(mState); - sol::table AsyncEventReturn = StateView.create_table(); - AsyncEventReturn["ReturnValueImpl"] = Return; - AsyncEventReturn.set_function("Wait", - [&](const sol::table& Self) -> sol::table { - sol::state_view StateView(mState); - sol::table Result = StateView.create_table(); - beammp_debug("beginning to loop"); - auto Vector = Self.get>>("ReturnValueImpl"); - for (const auto& Value : Vector) { - beammp_debug("waiting on a value"); - Value->WaitUntilReady(); - if (Value->Error) { - if (Value->ErrorMessage != BeamMPFnNotFoundError) { - beammp_lua_error("\"" + StateId + "\"" + Value->ErrorMessage); - } - } else { - Result.add(Value->Result); - } - } - return Result; - }); - return AsyncEventReturn; + return Lua_TriggerGlobalEvent(EventName); + }); + Table.set_function("TriggerLocalEvent", + [&](const std::string& EventName) -> sol::table { + return Lua_TriggerLocalEvent(EventName); }); Table.create_named("Settings", "Debug", 0, @@ -214,9 +242,10 @@ std::shared_ptr TLuaEngine::StateThreadData::EnqueueScript(const std std::shared_ptr TLuaEngine::StateThreadData::EnqueueFunctionCall(const std::string& FunctionName) { beammp_debug("calling \"" + FunctionName + "\" in \"" + mName + "\""); - std::unique_lock Lock(mStateFunctionQueueMutex); auto Result = std::make_shared(); Result->StateId = mStateId; + Result->Function = FunctionName; + std::unique_lock Lock(mStateFunctionQueueMutex); mStateFunctionQueue.push({ FunctionName, Result }); return Result; } @@ -277,6 +306,7 @@ void TLuaEngine::StateThreadData::operator()() { } } } + std::this_thread::sleep_for(std::chrono::milliseconds(10)); } } From 968d9ff999730ce09c9a551ad8915817e5b9b466 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 16 Sep 2021 19:00:13 +0200 Subject: [PATCH 096/255] Lua: Implement most API functions --- include/Client.h | 3 ++ include/LuaAPI.h | 9 +++++ include/TLuaEngine.h | 10 ++++-- src/Client.cpp | 18 ++++++++++ src/LuaAPI.cpp | 69 +++++++++++++++++++++++++++++++++++++++ src/TLuaEngine.cpp | 78 ++++++++++++++++++++++++++++++++++---------- 6 files changed, 168 insertions(+), 19 deletions(-) diff --git a/include/Client.h b/include/Client.h index 8ac7035..9ac4296 100644 --- a/include/Client.h +++ b/include/Client.h @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -98,3 +99,5 @@ private: int mID = -1; std::chrono::time_point mLastPingTime; }; + +std::optional> GetClient(class TServer& Server, int ID); diff --git a/include/LuaAPI.h b/include/LuaAPI.h index 93ea0ac..173dfbf 100644 --- a/include/LuaAPI.h +++ b/include/LuaAPI.h @@ -10,5 +10,14 @@ namespace MP { std::string GetOSName(); std::tuple GetServerVersion(); + bool TriggerClientEvent(int PlayerID, const std::string& EventName, const std::string& Data); + size_t GetPlayerCount() { return Engine->Server().ClientCount(); } + void DropPlayer(int ID, std::optional MaybeReason); + void SendChatMessage(int ID, const std::string& Message); + void RemoveVehicle(int PlayerID, int VehicleID); + void Set(int ConfigID, sol::object NewValue); + bool GetPlayerGuest(int ID); + bool IsPlayerConnected(int ID); + void Sleep(size_t Ms); } } diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index 3701f56..cf3c01f 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -47,6 +47,9 @@ public: void operator()() override; + TNetwork& Network() { return mNetwork; } + TServer& Server() { return mServer; } + [[nodiscard]] std::shared_ptr EnqueueScript(TLuaStateId StateID, const std::shared_ptr& Script); [[nodiscard]] std::shared_ptr EnqueueFunctionCall(TLuaStateId StateID, const std::string& FunctionName); void EnsureStateExists(TLuaStateId StateId, const std::string& Name, bool DontCallOnInit = false); @@ -70,11 +73,13 @@ private: [[nodiscard]] std::shared_ptr EnqueueFunctionCall(const std::string& FunctionName); void RegisterEvent(const std::string& EventName, const std::string& FunctionName); void operator()() override; - + private: sol::table Lua_TriggerGlobalEvent(const std::string& EventName); sol::table Lua_TriggerLocalEvent(const std::string& EventName); - + sol::table Lua_GetPlayerIdentifiers(int ID); + sol::table Lua_GetPlayers(); + std::string mName; std::atomic_bool& mShutdown; TLuaStateId mStateId; @@ -85,6 +90,7 @@ private: std::queue>> mStateFunctionQueue; std::recursive_mutex mStateFunctionQueueMutex; TLuaEngine* mEngine; + sol::state_view mStateView { mState }; }; TNetwork& mNetwork; diff --git a/src/Client.cpp b/src/Client.cpp index 8cf8722..36e3255 100644 --- a/src/Client.cpp +++ b/src/Client.cpp @@ -1,7 +1,9 @@ #include "Client.h" #include "CustomAssert.h" +#include "TServer.h" #include +#include // FIXME: add debug prints @@ -100,3 +102,19 @@ int TClient::SecondsSinceLastPing() { .count(); return int(seconds); } + +std::optional> GetClient(TServer& Server, int ID) { + std::optional> MaybeClient { std::nullopt }; + Server.ForEachClient([&](std::weak_ptr CPtr) -> bool { + ReadLock Lock(Server.GetClientMutex()); + if (!CPtr.expired()) { + auto C = CPtr.lock(); + if (C->GetID() == ID) { + MaybeClient = CPtr; + return false; + } + } + return true; + }); + return MaybeClient; +} diff --git a/src/LuaAPI.cpp b/src/LuaAPI.cpp index c13f01f..85f1f50 100644 --- a/src/LuaAPI.cpp +++ b/src/LuaAPI.cpp @@ -1,4 +1,5 @@ #include "LuaAPI.h" +#include "Client.h" #include "TLuaEngine.h" static std::string LuaToString(const sol::object& Value, size_t Indent = 1) { @@ -63,3 +64,71 @@ void LuaAPI::Print(sol::variadic_args Args) { } luaprint(ToPrint); } + +bool LuaAPI::MP::TriggerClientEvent(int PlayerID, const std::string& EventName, const std::string& Data) { + std::string Packet = "E:" + EventName + ":" + Data; + if (PlayerID == -1) + Engine->Network().SendToAll(nullptr, Packet, true, true); + else { + auto MaybeClient = GetClient(Engine->Server(), PlayerID); + if (!MaybeClient || MaybeClient.value().expired()) { + beammp_lua_error("TriggerClientEvent invalid Player ID"); + return false; + } + auto c = MaybeClient.value().lock(); + if (!Engine->Network().Respond(*c, Packet, true)) { + beammp_lua_error("Respond failed"); + return false; + } + } + return true; +} + +void LuaAPI::MP::DropPlayer(int ID, std::optional MaybeReason) { + auto MaybeClient = GetClient(Engine->Server(), ID); + if (!MaybeClient || MaybeClient.value().expired()) { + return; + } + auto c = MaybeClient.value().lock(); + if (!Engine->Network().Respond(*c, "C:Server:You have been Kicked from the server! Reason: " + MaybeReason.value_or("No reason"), true)) { + // Ignore + } + c->SetStatus(-2); + beammp_info("Closing socket due to kick"); + CloseSocketProper(c->GetTCPSock()); +} + +void LuaAPI::MP::SendChatMessage(int ID, const std::string& Message) { + std::string Packet = "C:Server: " + Message; + if (ID == -1) { + //LogChatMessage(" (to everyone) ", -1, Message); + Engine->Network().SendToAll(nullptr, Packet, true, true); + } else { + auto MaybeClient = GetClient(Engine->Server(), ID); + if (MaybeClient && !MaybeClient.value().expired()) { + auto c = MaybeClient.value().lock(); + if (!c->IsSynced()) + return; + //LogChatMessage(" (to \"" + c->GetName() + "\")", -1, msg); + Engine->Network().Respond(*c, Packet, true); + } else { + beammp_lua_error("SendChatMessage invalid argument [1] invalid ID"); + } + } +} + +void LuaAPI::MP::RemoveVehicle(int PlayerID, int VehicleID) { +} + +void LuaAPI::MP::Set(int ConfigID, sol::object NewValue) { +} + +void LuaAPI::MP::Sleep(size_t Ms) { + std::this_thread::sleep_for(std::chrono::milliseconds(Ms)); +} + +bool LuaAPI::MP::IsPlayerConnected(int ID) { +} + +bool LuaAPI::MP::GetPlayerGuest(int ID) { +} diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index d6752e4..b517234 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -1,8 +1,8 @@ #include "TLuaEngine.h" +#include "Client.h" #include "CustomAssert.h" -#include "TLuaPlugin.h" - #include "LuaAPI.h" +#include "TLuaPlugin.h" #include #include @@ -185,10 +185,9 @@ sol::table TLuaEngine::StateThreadData::Lua_TriggerGlobalEvent(const std::string } sol::table TLuaEngine::StateThreadData::Lua_TriggerLocalEvent(const std::string& EventName) { - sol::state_view StateView(mState); - sol::table Result = StateView.create_table(); + sol::table Result = mStateView.create_table(); for (const auto& Handler : mEngine->GetEventHandlersForState(EventName, mStateId)) { - auto Fn = StateView[Handler]; + auto Fn = mStateView[Handler]; if (Fn.valid() && Fn.get_type() == sol::type::function) { Result.add(Fn()); } @@ -196,6 +195,34 @@ sol::table TLuaEngine::StateThreadData::Lua_TriggerLocalEvent(const std::string& return Result; } +sol::table TLuaEngine::StateThreadData::Lua_GetPlayerIdentifiers(int ID) { + auto MaybeClient = GetClient(mEngine->Server(), ID); + if (MaybeClient && !MaybeClient.value().expired()) { + auto IDs = MaybeClient.value().lock()->GetIdentifiers(); + if (IDs.empty()) { + return sol::nil; + } + sol::table Result = mStateView.create_table(); + for (const auto& Pair : IDs) { + Result[Pair.first] = Pair.second; + } + return Result; + } else { + return sol::nil; + } +} +sol::table TLuaEngine::StateThreadData::Lua_GetPlayers() { + sol::table Result = mStateView.create_table(); + mEngine->Server().ForEachClient([&](std::weak_ptr Client) -> bool { + if (!Client.expired()) { + auto locked = Client.lock(); + Result[locked->GetID()] = locked->GetName(); + } + return true; + }); + return Result; +} + TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomic_bool& Shutdown, TLuaStateId StateId, TLuaEngine& Engine) : mName(Name) , mShutdown(Shutdown) @@ -206,21 +233,38 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi sol::state_view StateView(mState); // StateView.globals()["package"].get() StateView.set_function("print", &LuaAPI::Print); + StateView.set_function("exit", &Application::GracefullyShutdown); auto Table = StateView.create_named_table("MP"); Table.set_function("GetOSName", &LuaAPI::MP::GetOSName); Table.set_function("GetServerVersion", &LuaAPI::MP::GetServerVersion); - Table.set_function("RegisterEvent", - [this](const std::string& EventName, const std::string& FunctionName) { - RegisterEvent(EventName, FunctionName); - }); - Table.set_function("TriggerGlobalEvent", - [&](const std::string& EventName) -> sol::table { - return Lua_TriggerGlobalEvent(EventName); - }); - Table.set_function("TriggerLocalEvent", - [&](const std::string& EventName) -> sol::table { - return Lua_TriggerLocalEvent(EventName); - }); + Table.set_function("RegisterEvent", [this](const std::string& EventName, const std::string& FunctionName) { + RegisterEvent(EventName, FunctionName); + }); + Table.set_function("TriggerGlobalEvent", [&](const std::string& EventName) -> sol::table { + return Lua_TriggerGlobalEvent(EventName); + }); + Table.set_function("TriggerLocalEvent", [&](const std::string& EventName) -> sol::table { + return Lua_TriggerLocalEvent(EventName); + }); + Table.set_function("TriggerClientEvent", &LuaAPI::MP::TriggerClientEvent); + Table.set_function("GetPlayerCount", &LuaAPI::MP::GetPlayerCount); + Table.set_function("IsPlayerConnected", &LuaAPI::MP::IsPlayerConnected); + Table.set_function("GetPlayerName", &LuaAPI::MP::GetPlayerName); + Table.set_function("RemoveVehicle", &LuaAPI::MP::RemoveVehicle); + Table.set_function("GetPlayerVehicles", &LuaAPI::MP::GetPlayerVehicles); + Table.set_function("SendChatMessage", &LuaAPI::MP::SendChatMessage); + Table.set_function("GetPlayers", [&]() -> sol::table { + return Lua_GetPlayers(); + }); + Table.set_function("GetPlayerGuest", &LuaAPI::MP::GetPlayerGuest); + Table.set_function("DropPlayer", &LuaAPI::MP::DropPlayer); + Table.set_function("GetPlayerIdentifiers", [&](int ID) -> sol::table { + return Lua_GetPlayerIdentifiers(ID); + }); + Table.set_function("Sleep", &LuaAPI::MP::Sleep); + Table.set_function("Set", &LuaAPI::MP::Set); + //Table.set_function("HttpsGET", &LuaAPI::MP::HttpsGET); + //Table.set_function("HttpsPOST", &LuaAPI::MP::HttpsPOST); Table.create_named("Settings", "Debug", 0, "Private", 1, From be61511bdffb528d32f02593a170cb47dd9bad62 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 16 Sep 2021 19:38:31 +0200 Subject: [PATCH 097/255] Fix CMake, Add more Lua API --- CMakeLists.txt | 2 +- src/LuaAPI.cpp | 21 +++++++++++++++++++-- src/TLuaEngine.cpp | 2 +- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fcd9ba3..14ddc34 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,5 +68,5 @@ elseif (WIN32) find_package(ZLIB REQUIRED) find_package(RapidJSON CONFIG REQUIRED) target_include_directories(BeamMP-Server PRIVATE ${RAPIDJSON_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}) - target_link_libraries(BeamMP-Server PRIVATE ws2_32 ZLIB::ZLIB ${OPENSSL_LIBRARIES} commandline sioclient_tls) + target_link_libraries(BeamMP-Server ws2_32 ZLIB::ZLIB ${OPENSSL_LIBRARIES} commandline sioclient_tls) endif () diff --git a/src/LuaAPI.cpp b/src/LuaAPI.cpp index 85f1f50..f9e0165 100644 --- a/src/LuaAPI.cpp +++ b/src/LuaAPI.cpp @@ -117,7 +117,18 @@ void LuaAPI::MP::SendChatMessage(int ID, const std::string& Message) { } } -void LuaAPI::MP::RemoveVehicle(int PlayerID, int VehicleID) { +void LuaAPI::MP::RemoveVehicle(int PID, int VID) { + auto MaybeClient = GetClient(Engine->Server(), PID); + if (!MaybeClient || MaybeClient.value().expired()) { + beammp_lua_error("RemoveVehicle invalid Player ID"); + return; + } + auto c = MaybeClient.value().lock(); + if (!c->GetCarData(VID).empty()) { + std::string Destroy = "Od:" + std::to_string(PID) + "-" + std::to_string(VID); + Engine->Network().SendToAll(nullptr, Destroy, true, true); + c->DeleteCar(VID); + } } void LuaAPI::MP::Set(int ConfigID, sol::object NewValue) { @@ -128,7 +139,13 @@ void LuaAPI::MP::Sleep(size_t Ms) { } bool LuaAPI::MP::IsPlayerConnected(int ID) { + auto MaybeClient = GetClient(Engine->Server(), ID); + if (MaybeClient && !MaybeClient.value().expired()) { + return MaybeClient.value().lock()->IsConnected(); + } else { + return false; + } } -bool LuaAPI::MP::GetPlayerGuest(int ID) { +bool LuaAPI::MP::IsPlayerGuest(int ID) { } diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index b517234..be32ee3 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -256,7 +256,7 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi Table.set_function("GetPlayers", [&]() -> sol::table { return Lua_GetPlayers(); }); - Table.set_function("GetPlayerGuest", &LuaAPI::MP::GetPlayerGuest); + Table.set_function("IsPlayerGuest", &LuaAPI::MP::IsPlayerGuest); Table.set_function("DropPlayer", &LuaAPI::MP::DropPlayer); Table.set_function("GetPlayerIdentifiers", [&](int ID) -> sol::table { return Lua_GetPlayerIdentifiers(ID); From 4c03a9015721c77e165a121ba24aae9de8fca2e2 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 16 Sep 2021 22:31:09 +0200 Subject: [PATCH 098/255] Lua: Add more old API --- include/LuaAPI.h | 2 +- src/LuaAPI.cpp | 60 ++++++++++++++++++++++++++++++++++++++++++++++ src/TLuaEngine.cpp | 4 ++-- 3 files changed, 63 insertions(+), 3 deletions(-) diff --git a/include/LuaAPI.h b/include/LuaAPI.h index 173dfbf..053e8c2 100644 --- a/include/LuaAPI.h +++ b/include/LuaAPI.h @@ -16,7 +16,7 @@ namespace MP { void SendChatMessage(int ID, const std::string& Message); void RemoveVehicle(int PlayerID, int VehicleID); void Set(int ConfigID, sol::object NewValue); - bool GetPlayerGuest(int ID); + bool IsPlayerGuest(int ID); bool IsPlayerConnected(int ID); void Sleep(size_t Ms); } diff --git a/src/LuaAPI.cpp b/src/LuaAPI.cpp index f9e0165..d3fa197 100644 --- a/src/LuaAPI.cpp +++ b/src/LuaAPI.cpp @@ -132,6 +132,60 @@ void LuaAPI::MP::RemoveVehicle(int PID, int VID) { } void LuaAPI::MP::Set(int ConfigID, sol::object NewValue) { + switch (ConfigID) { + case 0: //debug + if (lua_isboolean(L, 2)) { + Application::Settings.DebugModeEnabled = NewValue.as(); + beammp_info("Set `Debug` to ") + (Application::Settings.DebugModeEnabled ? "true" : "false")); + } else + SendError(Engine(), L, ("set invalid argument [2] expected boolean for ID : 0")); + break; + case 1: //private + if (lua_isboolean(L, 2)) { + Application::Settings.Private = lua_toboolean(L, 2); + beammp_info("Set `Private` to ") + (Application::Settings.Private ? "true" : "false")); + } else + SendError(Engine(), L, ("set invalid argument [2] expected boolean for ID : 1")); + break; + case 2: //max cars + if (lua_isnumber(L, 2)) { + Application::Settings.MaxCars = int(lua_tointeger(L, 2)); + beammp_info("Set `MaxCars` to ") + std::to_string(Application::Settings.MaxCars)); + } else + SendError(Engine(), L, ("set invalid argument [2] expected number for ID : 2")); + break; + case 3: //max players + if (lua_isnumber(L, 2)) { + Application::Settings.MaxPlayers = int(lua_tointeger(L, 2)); + beammp_info("Set `MaxPlayers` to ") + std::to_string(Application::Settings.MaxPlayers)); + } else + SendError(Engine(), L, ("set invalid argument [2] expected number for ID : 3")); + break; + case 4: //Map + if (lua_isstring(L, 2)) { + Application::Settings.MapName = lua_tostring(L, 2); + beammp_info("Set `Map` to ") + Application::Settings.MapName); + } else + SendError(Engine(), L, ("set invalid argument [2] expected string for ID : 4")); + break; + case 5: //Name + if (lua_isstring(L, 2)) { + Application::Settings.ServerName = lua_tostring(L, 2); + beammp_info("Set `Name` to ") + Application::Settings.ServerName); + } else + SendError(Engine(), L, ("set invalid argument [2] expected string for ID : 5")); + break; + case 6: //Desc + if (lua_isstring(L, 2)) { + Application::Settings.ServerDesc = lua_tostring(L, 2); + beammp_info("Set `Description` to ") + Application::Settings.ServerDesc); + } else + SendError(Engine(), L, ("set invalid argument [2] expected string for ID : 6")); + break; + default: + warn(("Invalid config ID : ") + std::to_string(C)); + break; + } } void LuaAPI::MP::Sleep(size_t Ms) { @@ -148,4 +202,10 @@ bool LuaAPI::MP::IsPlayerConnected(int ID) { } bool LuaAPI::MP::IsPlayerGuest(int ID) { + auto MaybeClient = GetClient(Engine->Server(), ID); + if (MaybeClient && !MaybeClient.value().expired()) { + return MaybeClient.value().lock()->IsGuest(); + } else { + return false; + } } diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index be32ee3..5b276bf 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -249,9 +249,9 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi Table.set_function("TriggerClientEvent", &LuaAPI::MP::TriggerClientEvent); Table.set_function("GetPlayerCount", &LuaAPI::MP::GetPlayerCount); Table.set_function("IsPlayerConnected", &LuaAPI::MP::IsPlayerConnected); - Table.set_function("GetPlayerName", &LuaAPI::MP::GetPlayerName); + Table.set_function("GetPlayerName", &Lua_GetPlayerName); Table.set_function("RemoveVehicle", &LuaAPI::MP::RemoveVehicle); - Table.set_function("GetPlayerVehicles", &LuaAPI::MP::GetPlayerVehicles); + Table.set_function("GetPlayerVehicles", &Lua_GetPlayerVehicles); Table.set_function("SendChatMessage", &LuaAPI::MP::SendChatMessage); Table.set_function("GetPlayers", [&]() -> sol::table { return Lua_GetPlayers(); From cb1eb40def879c690b63645a042853f1cd206e10 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 16 Sep 2021 22:31:54 +0200 Subject: [PATCH 099/255] Lua: remove unimplemented --- src/TLuaEngine.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 5b276bf..e09c968 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -249,9 +249,9 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi Table.set_function("TriggerClientEvent", &LuaAPI::MP::TriggerClientEvent); Table.set_function("GetPlayerCount", &LuaAPI::MP::GetPlayerCount); Table.set_function("IsPlayerConnected", &LuaAPI::MP::IsPlayerConnected); - Table.set_function("GetPlayerName", &Lua_GetPlayerName); + //Table.set_function("GetPlayerName", &Lua_GetPlayerName); Table.set_function("RemoveVehicle", &LuaAPI::MP::RemoveVehicle); - Table.set_function("GetPlayerVehicles", &Lua_GetPlayerVehicles); + //Table.set_function("GetPlayerVehicles", &Lua_GetPlayerVehicles); Table.set_function("SendChatMessage", &LuaAPI::MP::SendChatMessage); Table.set_function("GetPlayers", [&]() -> sol::table { return Lua_GetPlayers(); From a44050f0f14b77f4fb6bf4d8371f86d201e822bd Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 17 Sep 2021 00:21:43 +0200 Subject: [PATCH 100/255] Lua: Almost Working events, all triggers working --- include/Common.h | 3 ++ include/LuaAPI.h | 4 +-- include/TLuaEngine.h | 45 +++++++++++++++--------- src/LuaAPI.cpp | 26 ++++++++++++-- src/TConsole.cpp | 2 +- src/TLuaEngine.cpp | 81 +++++++++++++++++++------------------------- src/TNetwork.cpp | 34 ++++++++++++++----- src/TServer.cpp | 45 ++++++++++++++++-------- src/main.cpp | 10 ++++-- 9 files changed, 157 insertions(+), 93 deletions(-) diff --git a/include/Common.h b/include/Common.h index c74a16e..d36cf6f 100644 --- a/include/Common.h +++ b/include/Common.h @@ -133,6 +133,9 @@ void RegisterThread(const std::string str); Application::Console().Write(_this_location + std::string("[DEBUG] ") + (x)); \ } \ } while (false) +// for those times when you just need to ignore something :^) +// explicity disables a [[nodiscard]] warning +#define beammp_ignore(x) (void)x #define Biggest 30000 std::string Comp(std::string Data); diff --git a/include/LuaAPI.h b/include/LuaAPI.h index 053e8c2..091de13 100644 --- a/include/LuaAPI.h +++ b/include/LuaAPI.h @@ -6,12 +6,12 @@ namespace LuaAPI { void Print(sol::variadic_args); namespace MP { - static inline TLuaEngine* Engine { nullptr }; + extern TLuaEngine* Engine; std::string GetOSName(); std::tuple GetServerVersion(); bool TriggerClientEvent(int PlayerID, const std::string& EventName, const std::string& Data); - size_t GetPlayerCount() { return Engine->Server().ClientCount(); } + inline size_t GetPlayerCount() { return Engine->Server().ClientCount(); } void DropPlayer(int ID, std::optional MaybeReason); void SendChatMessage(int ID, const std::string& Message); void RemoveVehicle(int PlayerID, int VehicleID); diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index cf3c01f..5a64a16 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -4,6 +4,7 @@ #include "TServer.h" #include #include +#include #include #include #include @@ -40,21 +41,39 @@ struct TLuaPluginConfig { class TLuaEngine : IThreaded { public: - TLuaEngine(TServer& Server, TNetwork& Network); + TLuaEngine(); ~TLuaEngine() noexcept { beammp_debug("Lua Engine terminated"); } void operator()() override; - TNetwork& Network() { return mNetwork; } - TServer& Server() { return mServer; } + TNetwork& Network() { return *mNetwork; } + TServer& Server() { return *mServer; } + void SetNetwork(TNetwork* Network) { mNetwork = Network; } + void SetServer(TServer* Server) { mServer = Server; } + + static void WaitForAll(std::vector>& Results); [[nodiscard]] std::shared_ptr EnqueueScript(TLuaStateId StateID, const std::shared_ptr& Script); - [[nodiscard]] std::shared_ptr EnqueueFunctionCall(TLuaStateId StateID, const std::string& FunctionName); + [[nodiscard]] std::shared_ptr EnqueueFunctionCall(TLuaStateId StateID, const std::string& FunctionName, const std::initializer_list& Args); void EnsureStateExists(TLuaStateId StateId, const std::string& Name, bool DontCallOnInit = false); void RegisterEvent(const std::string& EventName, TLuaStateId StateId, const std::string& FunctionName); - [[nodiscard]] std::vector> TriggerEvent(const std::string& EventName); + template + [[nodiscard]] std::vector> TriggerEvent(const std::string& EventName, ArgsT&&... Args) { + std::unique_lock Lock(mEventsMutex); + if (mEvents.find(EventName) == mEvents.end()) { + return {}; + } + std::vector> Results; + for (const auto& Event : mEvents.at(EventName)) { + for (const auto& Function : Event.second) { + beammp_debug("TriggerEvent: triggering \"" + Function + "\" on \"" + Event.first + "\""); + Results.push_back(EnqueueFunctionCall(Event.first, Function, { std::forward(Args)... })); + } + } + return Results; + } std::set GetEventHandlersForState(const std::string& EventName, TLuaStateId StateId); static constexpr const char* BeamMPFnNotFoundError = "BEAMMP_FN_NOT_FOUND"; @@ -70,7 +89,7 @@ private: StateThreadData(const StateThreadData&) = delete; ~StateThreadData() noexcept { beammp_debug("\"" + mStateId + "\" destroyed"); } [[nodiscard]] std::shared_ptr EnqueueScript(const std::shared_ptr& Script); - [[nodiscard]] std::shared_ptr EnqueueFunctionCall(const std::string& FunctionName); + [[nodiscard]] std::shared_ptr EnqueueFunctionCall(const std::string& FunctionName, const std::initializer_list& Args); void RegisterEvent(const std::string& EventName, const std::string& FunctionName); void operator()() override; @@ -87,14 +106,14 @@ private: std::thread mThread; std::queue, std::shared_ptr>> mStateExecuteQueue; std::recursive_mutex mStateExecuteQueueMutex; - std::queue>> mStateFunctionQueue; + std::queue, std::initializer_list>> mStateFunctionQueue; std::recursive_mutex mStateFunctionQueueMutex; TLuaEngine* mEngine; sol::state_view mStateView { mState }; }; - TNetwork& mNetwork; - TServer& mServer; + TNetwork* mNetwork; + TServer* mServer; std::atomic_bool mShutdown { false }; fs::path mResourceServerPath; std::vector mLuaPlugins; @@ -104,10 +123,4 @@ private: std::recursive_mutex mEventsMutex; }; -#include -// DEAD CODE -struct TLuaArg { - std::vector args; - void PushArgs(lua_State* State); -}; -std::any TriggerLuaEvent(const std::string& Event, bool local, TLuaPlugin* Caller, std::shared_ptr arg, bool Wait); +//std::any TriggerLuaEvent(const std::string& Event, bool local, TLuaPlugin* Caller, std::shared_ptr arg, bool Wait); diff --git a/src/LuaAPI.cpp b/src/LuaAPI.cpp index d3fa197..6717b19 100644 --- a/src/LuaAPI.cpp +++ b/src/LuaAPI.cpp @@ -4,11 +4,32 @@ static std::string LuaToString(const sol::object& Value, size_t Indent = 1) { switch (Value.get_type()) { + case sol::type::userdata: { + std::stringstream ss; + ss << "[[userdata: " << Value.as().pointer() << "]]"; + return ss.str(); + } + case sol::type::thread: { + std::stringstream ss; + ss << "[[thread: " << Value.as().pointer() << "]] {" + << "\n"; + for (size_t i = 0; i < Indent; ++i) { + ss << "\t"; + } + ss << "status: " << std::to_string(int(Value.as().status())) << "\n}"; + return ss.str(); + } + case sol::type::lightuserdata: { + std::stringstream ss; + ss << "[[lightuserdata: " << Value.as().pointer() << "]]"; + return ss.str(); + } case sol::type::string: return Value.as(); case sol::type::number: return std::to_string(Value.as()); case sol::type::nil: + case sol::type::none: return ""; case sol::type::boolean: return Value.as() ? "true" : "false"; @@ -130,13 +151,13 @@ void LuaAPI::MP::RemoveVehicle(int PID, int VID) { c->DeleteCar(VID); } } - +/* void LuaAPI::MP::Set(int ConfigID, sol::object NewValue) { switch (ConfigID) { case 0: //debug if (lua_isboolean(L, 2)) { Application::Settings.DebugModeEnabled = NewValue.as(); - beammp_info("Set `Debug` to ") + (Application::Settings.DebugModeEnabled ? "true" : "false")); + beammp_info("Set `Debug` to " + (Application::Settings.DebugModeEnabled ? "true" : "false")); } else SendError(Engine(), L, ("set invalid argument [2] expected boolean for ID : 0")); break; @@ -187,6 +208,7 @@ void LuaAPI::MP::Set(int ConfigID, sol::object NewValue) { break; } } +*/ void LuaAPI::MP::Sleep(size_t Ms) { std::this_thread::sleep_for(std::chrono::milliseconds(Ms)); diff --git a/src/TConsole.cpp b/src/TConsole.cpp index 423e132..841a76d 100644 --- a/src/TConsole.cpp +++ b/src/TConsole.cpp @@ -84,6 +84,6 @@ void TConsole::WriteRaw(const std::string& str) { } void TConsole::InitializeLuaConsole(TLuaEngine& Engine) { - Engine.EnsureStateExists(mStateId, "Console"); mLuaEngine = &Engine; + Engine.EnsureStateExists(mStateId, "Console"); } diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index e09c968..a5d40c7 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -14,9 +14,9 @@ static TLuaStateId GenerateUniqueStateId() { return std::to_string(MTGen64()) + std::to_string(std::chrono::duration_cast(Time).count()); } -TLuaEngine::TLuaEngine(TServer& Server, TNetwork& Network) - : mNetwork(Network) - , mServer(Server) { +TLuaEngine* LuaAPI::MP::Engine; + +TLuaEngine::TLuaEngine() { LuaAPI::MP::Engine = this; if (!fs::exists(Application::Settings.Resource)) { fs::create_directory(Application::Settings.Resource); @@ -41,7 +41,7 @@ void TLuaEngine::operator()() { CollectAndInitPlugins(); // now call all onInit's for (const auto& Pair : mLuaStates) { - auto Res = EnqueueFunctionCall(Pair.first, "onInit"); + auto Res = EnqueueFunctionCall(Pair.first, "onInit", {}); Res->WaitUntilReady(); if (Res->Error && Res->ErrorMessage != TLuaEngine::BeamMPFnNotFoundError) { beammp_lua_error("Calling \"onInit\" on \"" + Pair.first + "\" failed: " + Res->ErrorMessage); @@ -53,16 +53,24 @@ void TLuaEngine::operator()() { } } +void TLuaEngine::WaitForAll(std::vector>& Results) { + for (const auto& Result : Results) { + while (!Result->Ready) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + } +} + std::shared_ptr TLuaEngine::EnqueueScript(TLuaStateId StateID, const std::shared_ptr& Script) { std::unique_lock Lock(mLuaStatesMutex); beammp_debug("enqueuing script into \"" + StateID + "\""); return mLuaStates.at(StateID)->EnqueueScript(Script); } -std::shared_ptr TLuaEngine::EnqueueFunctionCall(TLuaStateId StateID, const std::string& FunctionName) { +std::shared_ptr TLuaEngine::EnqueueFunctionCall(TLuaStateId StateID, const std::string& FunctionName, const std::initializer_list& Args) { std::unique_lock Lock(mLuaStatesMutex); beammp_debug("calling \"" + FunctionName + "\" in \"" + StateID + "\""); - return mLuaStates.at(StateID)->EnqueueFunctionCall(FunctionName); + return mLuaStates.at(StateID)->EnqueueFunctionCall(FunctionName, Args); } void TLuaEngine::CollectAndInitPlugins() { @@ -119,7 +127,7 @@ void TLuaEngine::EnsureStateExists(TLuaStateId StateId, const std::string& Name, mLuaStates[StateId] = std::move(DataPtr); RegisterEvent("onInit", StateId, "onInit"); if (!DontCallOnInit) { - auto Res = EnqueueFunctionCall(StateId, "onInit"); + auto Res = EnqueueFunctionCall(StateId, "onInit", {}); Res->WaitUntilReady(); if (Res->Error && Res->ErrorMessage != TLuaEngine::BeamMPFnNotFoundError) { beammp_lua_error("Calling \"onInit\" on \"" + StateId + "\" failed: " + Res->ErrorMessage); @@ -133,21 +141,6 @@ void TLuaEngine::RegisterEvent(const std::string& EventName, TLuaStateId StateId mEvents[EventName][StateId].insert(FunctionName); } -std::vector> TLuaEngine::TriggerEvent(const std::string& EventName) { - std::unique_lock Lock(mEventsMutex); - if (mEvents.find(EventName) == mEvents.end()) { - return {}; - } - std::vector> Results; - for (const auto& Event : mEvents.at(EventName)) { - for (const auto& Function : Event.second) { - beammp_debug("TriggerEvent: triggering \"" + Function + "\" on \"" + Event.first + "\""); - Results.push_back(EnqueueFunctionCall(Event.first, Function)); - } - } - return Results; -} - std::set TLuaEngine::GetEventHandlersForState(const std::string& EventName, TLuaStateId StateId) { return mEvents[EventName][StateId]; } @@ -227,8 +220,8 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi : mName(Name) , mShutdown(Shutdown) , mStateId(StateId) + , mState(luaL_newstate()) , mEngine(&Engine) { - mState = luaL_newstate(); luaL_openlibs(mState); sol::state_view StateView(mState); // StateView.globals()["package"].get() @@ -262,7 +255,7 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi return Lua_GetPlayerIdentifiers(ID); }); Table.set_function("Sleep", &LuaAPI::MP::Sleep); - Table.set_function("Set", &LuaAPI::MP::Set); + //Table.set_function("Set", &LuaAPI::MP::Set); //Table.set_function("HttpsGET", &LuaAPI::MP::HttpsGET); //Table.set_function("HttpsPOST", &LuaAPI::MP::HttpsPOST); Table.create_named("Settings", @@ -284,13 +277,13 @@ std::shared_ptr TLuaEngine::StateThreadData::EnqueueScript(const std return Result; } -std::shared_ptr TLuaEngine::StateThreadData::EnqueueFunctionCall(const std::string& FunctionName) { +std::shared_ptr TLuaEngine::StateThreadData::EnqueueFunctionCall(const std::string& FunctionName, const std::initializer_list& Args) { beammp_debug("calling \"" + FunctionName + "\" in \"" + mName + "\""); auto Result = std::make_shared(); Result->StateId = mStateId; Result->Function = FunctionName; std::unique_lock Lock(mStateFunctionQueueMutex); - mStateFunctionQueue.push({ FunctionName, Result }); + mStateFunctionQueue.push({ FunctionName, Result, Args }); return Result; } @@ -327,26 +320,29 @@ void TLuaEngine::StateThreadData::operator()() { auto FnNameResultPair = mStateFunctionQueue.front(); mStateFunctionQueue.pop(); Lock.unlock(); - FnNameResultPair.second->StateId = mStateId; - beammp_debug("Running function \"" + FnNameResultPair.first + "\""); + auto& StateId = std::get<0>(FnNameResultPair); + auto& Result = std::get<1>(FnNameResultPair); + auto& Args = std::get<1>(FnNameResultPair); + Result->StateId = mStateId; + beammp_debug("Running function \"" + std::get<0>(FnNameResultPair) + "\""); sol::state_view StateView(mState); - auto Fn = StateView[FnNameResultPair.first]; - beammp_debug("Done running function \"" + FnNameResultPair.first + "\""); + auto Fn = StateView[StateId]; + beammp_debug("Done running function \"" + StateId + "\""); if (Fn.valid() && Fn.get_type() == sol::type::function) { - auto Res = Fn(); + auto Res = Fn(Args); if (Res.valid()) { - FnNameResultPair.second->Error = false; - FnNameResultPair.second->Result = std::move(Res); + Result->Error = false; + Result->Result = std::move(Res); } else { - FnNameResultPair.second->Error = true; + Result->Error = true; sol::error Err = Res; - FnNameResultPair.second->ErrorMessage = Err.what(); + Result->ErrorMessage = Err.what(); } - FnNameResultPair.second->Ready = true; + Result->Ready = true; } else { - FnNameResultPair.second->Error = true; - FnNameResultPair.second->ErrorMessage = BeamMPFnNotFoundError; // special error kind that we can ignore later - FnNameResultPair.second->Ready = true; + Result->Error = true; + Result->ErrorMessage = BeamMPFnNotFoundError; // special error kind that we can ignore later + Result->Ready = true; } } } @@ -359,10 +355,3 @@ void TLuaResult::WaitUntilReady() { std::this_thread::sleep_for(std::chrono::milliseconds(10)); } } - -// AHHH -std::any TriggerLuaEvent(const std::string& Event, bool local, TLuaPlugin* Caller, std::shared_ptr arg, bool Wait) { -} - -void TLuaArg::PushArgs(lua_State* State) { -} diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index c76ae9c..c01b287 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -6,6 +6,8 @@ #include #include +#include "LuaAPI.h" + TNetwork::TNetwork(TServer& Server, TPPSMonitor& PPSMonitor, TResourceManager& ResourceManager) : mServer(Server) , mPPSMonitor(PPSMonitor) @@ -289,14 +291,27 @@ void TNetwork::Authentication(const TConnection& ClientConnection) { return true; }); + auto Futures = LuaAPI::MP::Engine->TriggerEvent("onPlayerAuth", Client->GetName(), Client->GetRoles(), Client->IsGuest()); + TLuaEngine::WaitForAll(Futures); + bool NotAllowed = std::any_of(Futures.begin(), Futures.end(), + [](const std::shared_ptr& Result) { + return !Result->Error && Result->Result.is() && bool(Result->Result.as()); + }); + std::string Reason; + bool NotAllowedWithReason = std::any_of(Futures.begin(), Futures.end(), + [&Reason](const std::shared_ptr& Result) -> bool { + if (!Result->Error && Result->Result.is()) { + Reason = Result->Result.as(); + return true; + } + return false; + }); - auto arg = std::make_unique(TLuaArg { { Client->GetName(), Client->GetRoles(), Client->IsGuest() } }); - std::any Res = TriggerLuaEvent("onPlayerAuth", false, nullptr, std::move(arg), true); - if (Res.type() == typeid(int) && std::any_cast(Res)) { + if (NotAllowed) { ClientKick(*Client, "you are not allowed on the server!"); return; - } else if (Res.type() == typeid(std::string)) { - ClientKick(*Client, std::any_cast(Res)); + } else if (NotAllowedWithReason) { + ClientKick(*Client, Reason); return; } @@ -563,7 +578,8 @@ void TNetwork::OnDisconnect(const std::weak_ptr& ClientPtr, bool kicked Packet = ("L") + c.GetName() + (" left the server!"); SendToAll(&c, Packet, false, true); Packet.clear(); - TriggerLuaEvent(("onPlayerDisconnect"), false, nullptr, std::make_unique(TLuaArg { { c.GetID() } }), false); + auto Futures = LuaAPI::MP::Engine->TriggerEvent("onPlayerDisconnect", c.GetID()); + beammp_ignore(Futures); if (c.GetTCPSock()) CloseSocketProper(c.GetTCPSock()); if (c.GetDownSock()) @@ -597,13 +613,13 @@ void TNetwork::OnConnect(const std::weak_ptr& c) { auto LockedClient = c.lock(); LockedClient->SetID(OpenID()); beammp_info("Assigned ID " + std::to_string(LockedClient->GetID()) + " to " + LockedClient->GetName()); - TriggerLuaEvent("onPlayerConnecting", false, nullptr, std::make_unique(TLuaArg { { LockedClient->GetID() } }), false); + beammp_ignore(LuaAPI::MP::Engine->TriggerEvent("onPlayerConnecting", LockedClient->GetID())); SyncResources(*LockedClient); if (LockedClient->GetStatus() < 0) return; (void)Respond(*LockedClient, "M" + Application::Settings.MapName, true); //Send the Map on connect beammp_info(LockedClient->GetName() + " : Connected"); - TriggerLuaEvent("onPlayerJoining", false, nullptr, std::make_unique(TLuaArg { { LockedClient->GetID() } }), false); + beammp_ignore(LuaAPI::MP::Engine->TriggerEvent("onPlayerJoining", LockedClient->GetID())); } void TNetwork::SyncResources(TClient& c) { @@ -802,7 +818,7 @@ bool TNetwork::SyncClient(const std::weak_ptr& c) { // ignore error (void)SendToAll(LockedClient.get(), ("JWelcome ") + LockedClient->GetName() + "!", false, true); - TriggerLuaEvent(("onPlayerJoin"), false, nullptr, std::make_unique(TLuaArg { { LockedClient->GetID() } }), false); + beammp_ignore(LuaAPI::MP::Engine->TriggerEvent("onPlayerJoin", LockedClient->GetID())); LockedClient->SetIsSyncing(true); bool Return = false; bool res = true; diff --git a/src/TServer.cpp b/src/TServer.cpp index 38b5d9e..2eea8c0 100644 --- a/src/TServer.cpp +++ b/src/TServer.cpp @@ -7,6 +7,8 @@ #include #include +#include "LuaAPI.h" + #undef GetObject //Fixes Windows #include "Json.h" @@ -119,17 +121,25 @@ void TServer::GlobalParser(const std::weak_ptr& Client, std::string Pac #endif Network.SendToAll(LockedClient.get(), Packet, false, true); return; - case 'C': + case 'C': { #ifdef DEBUG beammp_debug(std::string(("got 'C' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); #endif if (Packet.length() < 4 || Packet.find(':', 3) == std::string::npos) break; - Res = TriggerLuaEvent("onChatMessage", false, nullptr, std::make_unique(TLuaArg { { LockedClient->GetID(), LockedClient->GetName(), Packet.substr(Packet.find(':', 3) + 1) } }), true); - if (std::any_cast(Res)) + auto Futures = LuaAPI::MP::Engine->TriggerEvent("onChatMessage", LockedClient->GetID(), LockedClient->GetName(), Packet.substr(Packet.find(':', 3) + 1)); + TLuaEngine::WaitForAll(Futures); + if (std::any_of(Futures.begin(), Futures.end(), + [](const std::shared_ptr& Elem) { + return !Elem->Error + && Elem->Result.is() + && bool(Elem->Result.as()); + })) { break; + } Network.SendToAll(nullptr, Packet, true, true); return; + } case 'E': #ifdef DEBUG beammp_debug(std::string(("got 'E' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); @@ -154,7 +164,7 @@ void TServer::HandleEvent(TClient& c, const std::string& Data) { Name = t; break; case 2: - TriggerLuaEvent(Name, false, nullptr, std::make_unique(TLuaArg { { c.GetID(), t } }), false); + beammp_ignore(LuaAPI::MP::Engine->TriggerEvent(Name, c.GetID(), t)); break; default: break; @@ -207,9 +217,14 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ std::string CarJson = Packet.substr(5); Packet = "Os:" + c.GetRoles() + ":" + c.GetName() + ":" + std::to_string(c.GetID()) + "-" + std::to_string(CarID) + ":" + CarJson; - auto Res = TriggerLuaEvent(("onVehicleSpawn"), false, nullptr, std::make_unique(TLuaArg { { c.GetID(), CarID, Packet.substr(3) } }), true); + auto Futures = LuaAPI::MP::Engine->TriggerEvent("onVehicleSpawn", c.GetID(), CarID, Packet.substr(3)); + TLuaEngine::WaitForAll(Futures); + bool ShouldntSpawn = std::any_of(Futures.begin(), Futures.end(), + [](const std::shared_ptr& Result) { + return !Result->Error && Result->Result.is() && Result->Result.as() != 0; + }); - if (ShouldSpawn(c, CarJson, CarID) && std::any_cast(Res) == 0) { + if (ShouldSpawn(c, CarJson, CarID) && !ShouldntSpawn) { c.AddNewCar(CarID, Packet); Network.SendToAll(nullptr, Packet, true, true); } else { @@ -235,14 +250,17 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ VID = stoi(vid); } if (PID != -1 && VID != -1 && PID == c.GetID()) { - auto Res = TriggerLuaEvent(("onVehicleEdited"), false, nullptr, - std::make_unique(TLuaArg { { c.GetID(), VID, Packet.substr(3) } }), - true); + auto Futures = LuaAPI::MP::Engine->TriggerEvent("onVehicleEdited", c.GetID(), VID, Packet.substr(3)); + TLuaEngine::WaitForAll(Futures); + bool ShouldntAllow = std::any_of(Futures.begin(), Futures.end(), + [](const std::shared_ptr& Result) { + return !Result->Error && Result->Result.is() && Result->Result.as() != 0; + }); auto FoundPos = Packet.find('{'); FoundPos = FoundPos == std::string::npos ? 0 : FoundPos; // attempt at sanitizing this if ((c.GetUnicycleID() != VID || IsUnicycle(c, Packet.substr(FoundPos))) - && std::any_cast(Res) == 0) { + && !ShouldntAllow) { Network.SendToAll(&c, Packet, false, true); Apply(c, VID, Packet); } else { @@ -272,8 +290,7 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ c.SetUnicycleID(-1); } Network.SendToAll(nullptr, Packet, true, true); - TriggerLuaEvent(("onVehicleDeleted"), false, nullptr, - std::make_unique(TLuaArg { { c.GetID(), VID } }), false); + beammp_ignore(LuaAPI::MP::Engine->TriggerEvent("onVehicleDeleted", c.GetID(), VID)); c.DeleteCar(VID); beammp_debug(c.GetName() + (" deleted car with ID ") + std::to_string(VID)); } @@ -293,9 +310,7 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ if (PID != -1 && VID != -1 && PID == c.GetID()) { Data = Data.substr(Data.find('{')); - TriggerLuaEvent("onVehicleReset", false, nullptr, - std::make_unique(TLuaArg { { c.GetID(), VID, Data } }), - false); + beammp_ignore(LuaAPI::MP::Engine->TriggerEvent("onVehicleReset", c.GetID(), VID, Data)); Network.SendToAll(&c, Packet, false, true); } return; diff --git a/src/main.cpp b/src/main.cpp index 03bbbc0..fcbead8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,6 @@ #include "Common.h" #include "Http.h" +#include "LuaAPI.h" #include "TConfig.h" #include "THeartbeatThread.h" #include "TLuaEngine.h" @@ -48,10 +49,15 @@ int main(int argc, char** argv) { bool Shutdown = false; Application::RegisterShutdownHandler([&Shutdown] { Shutdown = true; }); - Application::RegisterShutdownHandler([] { TriggerLuaEvent("onShutdown", false, nullptr, {}, true); }); + Application::RegisterShutdownHandler([] { + auto Futures = LuaAPI::MP::Engine->TriggerEvent("onShutdown"); + TLuaEngine::WaitForAll(Futures); + }); TServer Server(argc, argv); TConfig Config; + TLuaEngine LuaEngine; + LuaEngine.SetServer(&Server); if (Config.Failed()) { beammp_info("Closing in 10 seconds"); @@ -64,7 +70,7 @@ int main(int argc, char** argv) { TPPSMonitor PPSMonitor(Server); THeartbeatThread Heartbeat(ResourceManager, Server); TNetwork Network(Server, PPSMonitor, ResourceManager); - TLuaEngine LuaEngine(Server, Network); + LuaEngine.SetNetwork(&Network); PPSMonitor.SetNetwork(Network); Application::Console().InitializeLuaConsole(LuaEngine); From c73d56c143c3de213aabf6c126325125203d8dff Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 17 Sep 2021 00:54:41 +0200 Subject: [PATCH 101/255] Possible compiler fix --- src/TLuaEngine.cpp | 1 + src/TLuaPlugin.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index a5d40c7..9e58abe 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -204,6 +204,7 @@ sol::table TLuaEngine::StateThreadData::Lua_GetPlayerIdentifiers(int ID) { return sol::nil; } } + sol::table TLuaEngine::StateThreadData::Lua_GetPlayers() { sol::table Result = mStateView.create_table(); mEngine->Server().ForEachClient([&](std::weak_ptr Client) -> bool { diff --git a/src/TLuaPlugin.cpp b/src/TLuaPlugin.cpp index 48e7d8a..97e6158 100644 --- a/src/TLuaPlugin.cpp +++ b/src/TLuaPlugin.cpp @@ -30,7 +30,7 @@ TLuaPlugin::TLuaPlugin(TLuaEngine& Engine, const TLuaPluginConfig& Config, const std::vector>> ResultsToCheck; for (const auto& Entry : Entries) { // read in entire file - std::FILE* File = std::fopen(Entry.c_str(), "r"); + std::FILE* File = std::fopen(static_cast(Entry.c_str()), "r"); if (File) { auto Size = std::filesystem::file_size(Entry); auto Contents = std::make_shared(); From 6b17990d4d80d697dfebbd02525ade860f155db5 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 17 Sep 2021 00:57:43 +0200 Subject: [PATCH 102/255] Add GetOSTimeMS --- src/TLuaEngine.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 9e58abe..db11755 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -252,6 +252,9 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi }); Table.set_function("IsPlayerGuest", &LuaAPI::MP::IsPlayerGuest); Table.set_function("DropPlayer", &LuaAPI::MP::DropPlayer); + Table.set_function("GetOSTimeMS", []() -> size_t { + return std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()).count(); + }); Table.set_function("GetPlayerIdentifiers", [&](int ID) -> sol::table { return Lua_GetPlayerIdentifiers(ID); }); From b0c467f97194a479d7408acfb57830d7b0dff5f4 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 17 Sep 2021 01:25:52 +0200 Subject: [PATCH 103/255] Lua: Add timer --- src/TLuaEngine.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index db11755..9efbc15 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -229,6 +229,20 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi StateView.set_function("print", &LuaAPI::Print); StateView.set_function("exit", &Application::GracefullyShutdown); auto Table = StateView.create_named_table("MP"); + Table.set_function("CreateTimer", [&]() -> sol::table { + sol::state_view StateView(mState); + sol::table Result = StateView.create_table(); + Result["__StartTime"] = std::chrono::high_resolution_clock::now(); + Result.set_function("GetCurrent", [&](const sol::table& Table) -> float { + auto End = std::chrono::high_resolution_clock::now(); + auto Start = Table.get("__StartTime"); + return std::chrono::duration_cast(End - Start).count() / 1000000.0f; + }); + Result.set_function("Start", [&](sol::table Table) { + Table["__StartTime"] = std::chrono::high_resolution_clock::now(); + }); + return Result; + }); Table.set_function("GetOSName", &LuaAPI::MP::GetOSName); Table.set_function("GetServerVersion", &LuaAPI::MP::GetServerVersion); Table.set_function("RegisterEvent", [this](const std::string& EventName, const std::string& FunctionName) { @@ -252,9 +266,6 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi }); Table.set_function("IsPlayerGuest", &LuaAPI::MP::IsPlayerGuest); Table.set_function("DropPlayer", &LuaAPI::MP::DropPlayer); - Table.set_function("GetOSTimeMS", []() -> size_t { - return std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()).count(); - }); Table.set_function("GetPlayerIdentifiers", [&](int ID) -> sol::table { return Lua_GetPlayerIdentifiers(ID); }); From e75e65815cbbe00e54f0aef2c0f67e2fdeb0a5bc Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 17 Sep 2021 01:27:45 +0200 Subject: [PATCH 104/255] Lua: change a static_cast to a reinterpret_cast, fun times :^) --- src/TLuaPlugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TLuaPlugin.cpp b/src/TLuaPlugin.cpp index 97e6158..b72abcb 100644 --- a/src/TLuaPlugin.cpp +++ b/src/TLuaPlugin.cpp @@ -30,7 +30,7 @@ TLuaPlugin::TLuaPlugin(TLuaEngine& Engine, const TLuaPluginConfig& Config, const std::vector>> ResultsToCheck; for (const auto& Entry : Entries) { // read in entire file - std::FILE* File = std::fopen(static_cast(Entry.c_str()), "r"); + std::FILE* File = std::fopen(reinterpret_cast(Entry.c_str()), "r"); if (File) { auto Size = std::filesystem::file_size(Entry); auto Contents = std::make_shared(); From bac476ec349f58df33b642130b6468cc18208bf9 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 17 Sep 2021 02:19:45 +0200 Subject: [PATCH 105/255] Lua: Set package.path and package.cpath before onInit is called --- include/TLuaEngine.h | 3 +++ src/TLuaEngine.cpp | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index 5a64a16..7a6b5c2 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -91,6 +91,7 @@ private: [[nodiscard]] std::shared_ptr EnqueueScript(const std::shared_ptr& Script); [[nodiscard]] std::shared_ptr EnqueueFunctionCall(const std::string& FunctionName, const std::initializer_list& Args); void RegisterEvent(const std::string& EventName, const std::string& FunctionName); + void AddPath(const fs::path& Path); // to be added to path and cpath void operator()() override; private: @@ -110,6 +111,8 @@ private: std::recursive_mutex mStateFunctionQueueMutex; TLuaEngine* mEngine; sol::state_view mStateView { mState }; + std::queue mPaths; + std::recursive_mutex mPathsMutex; }; TNetwork* mNetwork; diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 9efbc15..5a45b15 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -42,7 +42,7 @@ void TLuaEngine::operator()() { // now call all onInit's for (const auto& Pair : mLuaStates) { auto Res = EnqueueFunctionCall(Pair.first, "onInit", {}); - Res->WaitUntilReady(); + Res->WaitUntilReady(); // FIXME this dumb, dont do this, this is smelly! if (Res->Error && Res->ErrorMessage != TLuaEngine::BeamMPFnNotFoundError) { beammp_lua_error("Calling \"onInit\" on \"" + Pair.first + "\" failed: " + Res->ErrorMessage); } @@ -93,6 +93,7 @@ void TLuaEngine::InitializePlugin(const fs::path& Folder, const TLuaPluginConfig beammp_assert(fs::is_directory(Folder)); std::unique_lock Lock(mLuaStatesMutex); EnsureStateExists(Config.StateId, Folder.stem().string(), true); + mLuaStates[Config.StateId]->AddPath(Folder); // add to cpath + path Lock.unlock(); TLuaPlugin Plugin(*this, Config, Folder); } @@ -315,6 +316,33 @@ void TLuaEngine::StateThreadData::operator()() { auto S = mStateExecuteQueue.front(); mStateExecuteQueue.pop(); Lock.unlock(); + + { // Paths Scope + std::unique_lock Lock(mPathsMutex); + if (!mPaths.empty()) { + std::stringstream PathAdditions; + std::stringstream CPathAdditions; + while (!mPaths.empty()) { + auto Path = mPaths.front(); + mPaths.pop(); + PathAdditions << ";" << (Path / "?.lua").string(); + PathAdditions << ";" << (Path / "lua/?.lua").string(); +#if WIN32 + CPathAdditions << ";" << (Path / "?.dll").string(); + CPathAdditions << ";" << (Path / "lib/?.dll").string(); +#else // unix + CPathAdditions << ";" << (Path / "?.so").string(); + CPathAdditions << ";" << (Path / "lib/?.so").string(); +#endif + } + sol::state_view StateView(mState); + auto PackageTable = StateView.globals().get("package"); + PackageTable["path"] = PackageTable.get("path") + PathAdditions.str(); + PackageTable["cpath"] = PackageTable.get("cpath") + CPathAdditions.str(); + StateView.globals()["package"] = PackageTable; + } + } + beammp_debug("Running script"); sol::state_view StateView(mState); auto Res = StateView.safe_script(*S.first, sol::script_pass_on_error); @@ -365,6 +393,11 @@ void TLuaEngine::StateThreadData::operator()() { } } +void TLuaEngine::StateThreadData::AddPath(const fs::path& Path) { + std::unique_lock Lock(mPathsMutex); + mPaths.push(Path); +} + void TLuaResult::WaitUntilReady() { while (!Ready) { std::this_thread::sleep_for(std::chrono::milliseconds(10)); From 18805362763168ac81af052aee64319c33f172f9 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 17 Sep 2021 02:26:49 +0200 Subject: [PATCH 106/255] Lua: Call onInit properly --- src/TLuaEngine.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 5a45b15..e4c2d47 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -40,11 +40,11 @@ void TLuaEngine::operator()() { // lua engine main thread CollectAndInitPlugins(); // now call all onInit's - for (const auto& Pair : mLuaStates) { - auto Res = EnqueueFunctionCall(Pair.first, "onInit", {}); - Res->WaitUntilReady(); // FIXME this dumb, dont do this, this is smelly! - if (Res->Error && Res->ErrorMessage != TLuaEngine::BeamMPFnNotFoundError) { - beammp_lua_error("Calling \"onInit\" on \"" + Pair.first + "\" failed: " + Res->ErrorMessage); + auto Futures = TriggerEvent("onInit"); + WaitForAll(Futures); + for (const auto& Future : Futures) { + if (Future->Error) { + beammp_lua_error("Calling \"onInit\" on \"" + Future->StateId + "\" failed: " + Future->ErrorMessage); } } // this thread handles timers From 62fd3696250393e7391bbbdcf194bda81b0913cc Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 17 Sep 2021 02:30:20 +0200 Subject: [PATCH 107/255] Lua: Fix more compile errors for windows --- src/TLuaPlugin.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/TLuaPlugin.cpp b/src/TLuaPlugin.cpp index b72abcb..e156b5a 100644 --- a/src/TLuaPlugin.cpp +++ b/src/TLuaPlugin.cpp @@ -38,10 +38,10 @@ TLuaPlugin::TLuaPlugin(TLuaEngine& Engine, const TLuaPluginConfig& Config, const auto NRead = std::fread(Contents->data(), 1, Contents->size(), File); if (NRead == Contents->size()) { beammp_debug("Successfully read \"" + Entry.string() + "\" (" + std::to_string(NRead) + " Bytes)"); - mFileContents[fs::relative(Entry)] = Contents; + mFileContents[fs::relative(Entry).string()] = Contents; // Execute first time auto Result = mEngine.EnqueueScript(mConfig.StateId, Contents); - ResultsToCheck.emplace_back(Entry, std::move(Result)); + ResultsToCheck.emplace_back(Entry.string(), std::move(Result)); } else { beammp_error("Error while reading script file \"" + Entry.string() + "\". Did the file change while reading?"); } From ed6f5282d93fbd25be4f6e430919b47c516b7ee2 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 17 Sep 2021 02:36:06 +0200 Subject: [PATCH 108/255] Nice fix. --- src/TLuaEngine.cpp | 2 +- src/TNetwork.cpp | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index e4c2d47..19df10b 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -43,7 +43,7 @@ void TLuaEngine::operator()() { auto Futures = TriggerEvent("onInit"); WaitForAll(Futures); for (const auto& Future : Futures) { - if (Future->Error) { + if (Future->Error && Future->ErrorMessage != BeamMPFnNotFoundError) { beammp_lua_error("Calling \"onInit\" on \"" + Future->StateId + "\" failed: " + Future->ErrorMessage); } } diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index c01b287..31c46ae 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -114,7 +114,11 @@ void TNetwork::TCPServerMain() { TConnection client {}; SOCKET Listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); int optval = 1; +#ifdef WIN32 + setsockopt(Listener, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&optval), sizeof(optval)); +#else setsockopt(Listener, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&optval), sizeof(optval)); +#endif // TODO: check optval or return value idk sockaddr_in addr {}; addr.sin_addr.s_addr = INADDR_ANY; From 79531334ddc665537c6416240921c8ab8117da3f Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 17 Sep 2021 02:38:14 +0200 Subject: [PATCH 109/255] another nice fix --- src/LuaAPI.cpp | 2 +- src/TNetwork.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/LuaAPI.cpp b/src/LuaAPI.cpp index 6717b19..f9378b4 100644 --- a/src/LuaAPI.cpp +++ b/src/LuaAPI.cpp @@ -2,7 +2,7 @@ #include "Client.h" #include "TLuaEngine.h" -static std::string LuaToString(const sol::object& Value, size_t Indent = 1) { +static std::string LuaToString(sol::object Value, size_t Indent = 1) { switch (Value.get_type()) { case sol::type::userdata: { std::stringstream ss; diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index 31c46ae..8bc84ed 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -162,7 +162,7 @@ void TNetwork::TCPServerMain() { CloseSocketProper(client.Socket); #ifdef WIN32 - CloseSocketProper(client); + CloseSocketProper(client.Socket); WSACleanup(); #endif // WIN32 } From e64114e4fa34e9073568975c6de8bded6de43846 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 17 Sep 2021 02:44:49 +0200 Subject: [PATCH 110/255] Possible compiler fix --- src/LuaAPI.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/LuaAPI.cpp b/src/LuaAPI.cpp index f9378b4..8056bc7 100644 --- a/src/LuaAPI.cpp +++ b/src/LuaAPI.cpp @@ -2,7 +2,7 @@ #include "Client.h" #include "TLuaEngine.h" -static std::string LuaToString(sol::object Value, size_t Indent = 1) { +static std::string LuaToString(const sol::object Value, size_t Indent = 1) { switch (Value.get_type()) { case sol::type::userdata: { std::stringstream ss; @@ -80,7 +80,7 @@ std::tuple LuaAPI::MP::GetServerVersion() { void LuaAPI::Print(sol::variadic_args Args) { std::string ToPrint = ""; for (const auto& Arg : Args) { - ToPrint += LuaToString(Arg); + ToPrint += LuaToString(static_cast(Arg)); ToPrint += "\t"; } luaprint(ToPrint); From 9a37ed434152568f13c25c49cbc1efee493203f1 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 17 Sep 2021 12:45:34 +0200 Subject: [PATCH 111/255] Lua: Add GetPlayerName --- include/TLuaEngine.h | 1 + src/TLuaEngine.cpp | 13 ++++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index 7a6b5c2..c232629 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -99,6 +99,7 @@ private: sol::table Lua_TriggerLocalEvent(const std::string& EventName); sol::table Lua_GetPlayerIdentifiers(int ID); sol::table Lua_GetPlayers(); + std::string Lua_GetPlayerName(int ID); std::string mName; std::atomic_bool& mShutdown; diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 19df10b..b11c75f 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -218,6 +218,15 @@ sol::table TLuaEngine::StateThreadData::Lua_GetPlayers() { return Result; } +std::string TLuaEngine::StateThreadData::Lua_GetPlayerName(int ID) { + auto MaybeClient = GetClient(mEngine->Server(), ID); + if (MaybeClient && !MaybeClient.value().expired()) { + return MaybeClient.value().lock()->GetName(); + } else { + return ""; + } +} + TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomic_bool& Shutdown, TLuaStateId StateId, TLuaEngine& Engine) : mName(Name) , mShutdown(Shutdown) @@ -258,7 +267,9 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi Table.set_function("TriggerClientEvent", &LuaAPI::MP::TriggerClientEvent); Table.set_function("GetPlayerCount", &LuaAPI::MP::GetPlayerCount); Table.set_function("IsPlayerConnected", &LuaAPI::MP::IsPlayerConnected); - //Table.set_function("GetPlayerName", &Lua_GetPlayerName); + Table.set_function("GetPlayerName", [&](int ID) -> std::string { + return Lua_GetPlayerName(ID); + }); Table.set_function("RemoveVehicle", &LuaAPI::MP::RemoveVehicle); //Table.set_function("GetPlayerVehicles", &Lua_GetPlayerVehicles); Table.set_function("SendChatMessage", &LuaAPI::MP::SendChatMessage); From c2b73d93b559a476e8c629669e88d115c7afda75 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 17 Sep 2021 12:56:08 +0200 Subject: [PATCH 112/255] Lua: Implement more core functions --- include/TLuaEngine.h | 1 + src/LuaAPI.cpp | 59 ++++++++++++++++++++++---------------------- src/TLuaEngine.cpp | 28 +++++++++++++++++++-- 3 files changed, 56 insertions(+), 32 deletions(-) diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index c232629..8251a05 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -100,6 +100,7 @@ private: sol::table Lua_GetPlayerIdentifiers(int ID); sol::table Lua_GetPlayers(); std::string Lua_GetPlayerName(int ID); + sol::table Lua_GetPlayerVehicles(int ID); std::string mName; std::atomic_bool& mShutdown; diff --git a/src/LuaAPI.cpp b/src/LuaAPI.cpp index 8056bc7..89d54db 100644 --- a/src/LuaAPI.cpp +++ b/src/LuaAPI.cpp @@ -151,64 +151,63 @@ void LuaAPI::MP::RemoveVehicle(int PID, int VID) { c->DeleteCar(VID); } } -/* + void LuaAPI::MP::Set(int ConfigID, sol::object NewValue) { switch (ConfigID) { case 0: //debug - if (lua_isboolean(L, 2)) { + if (NewValue.is()) { Application::Settings.DebugModeEnabled = NewValue.as(); - beammp_info("Set `Debug` to " + (Application::Settings.DebugModeEnabled ? "true" : "false")); + beammp_info(std::string("Set `Debug` to ") + (Application::Settings.DebugModeEnabled ? "true" : "false")); } else - SendError(Engine(), L, ("set invalid argument [2] expected boolean for ID : 0")); + beammp_lua_error("set invalid argument [2] expected boolean"); break; case 1: //private - if (lua_isboolean(L, 2)) { - Application::Settings.Private = lua_toboolean(L, 2); - beammp_info("Set `Private` to ") + (Application::Settings.Private ? "true" : "false")); + if (NewValue.is()) { + Application::Settings.Private = NewValue.as(); + beammp_info(std::string("Set `Private` to ") + (Application::Settings.Private ? "true" : "false")); } else - SendError(Engine(), L, ("set invalid argument [2] expected boolean for ID : 1")); + beammp_lua_error("set invalid argument [2] expected boolean"); break; case 2: //max cars - if (lua_isnumber(L, 2)) { - Application::Settings.MaxCars = int(lua_tointeger(L, 2)); - beammp_info("Set `MaxCars` to ") + std::to_string(Application::Settings.MaxCars)); + if (NewValue.is()) { + Application::Settings.MaxCars = NewValue.as(); + beammp_info(std::string("Set `MaxCars` to ") + std::to_string(Application::Settings.MaxCars)); } else - SendError(Engine(), L, ("set invalid argument [2] expected number for ID : 2")); + beammp_lua_error("set invalid argument [2] expected integer"); break; case 3: //max players - if (lua_isnumber(L, 2)) { - Application::Settings.MaxPlayers = int(lua_tointeger(L, 2)); - beammp_info("Set `MaxPlayers` to ") + std::to_string(Application::Settings.MaxPlayers)); + if (NewValue.is()) { + Application::Settings.MaxPlayers = NewValue.as(); + beammp_info(std::string("Set `MaxPlayers` to ") + std::to_string(Application::Settings.MaxPlayers)); } else - SendError(Engine(), L, ("set invalid argument [2] expected number for ID : 3")); + beammp_lua_error("set invalid argument [2] expected integer"); break; case 4: //Map - if (lua_isstring(L, 2)) { - Application::Settings.MapName = lua_tostring(L, 2); - beammp_info("Set `Map` to ") + Application::Settings.MapName); + if (NewValue.is()) { + Application::Settings.MapName = NewValue.as(); + beammp_info(std::string("Set `Map` to ") + Application::Settings.MapName); } else - SendError(Engine(), L, ("set invalid argument [2] expected string for ID : 4")); + beammp_lua_error("set invalid argument [2] expected string"); break; case 5: //Name - if (lua_isstring(L, 2)) { - Application::Settings.ServerName = lua_tostring(L, 2); - beammp_info("Set `Name` to ") + Application::Settings.ServerName); + if (NewValue.is()) { + Application::Settings.ServerName = NewValue.as(); + beammp_info(std::string("Set `Name` to ") + Application::Settings.ServerName); } else - SendError(Engine(), L, ("set invalid argument [2] expected string for ID : 5")); + beammp_lua_error("set invalid argument [2] expected string"); break; case 6: //Desc - if (lua_isstring(L, 2)) { - Application::Settings.ServerDesc = lua_tostring(L, 2); - beammp_info("Set `Description` to ") + Application::Settings.ServerDesc); + if (NewValue.is()) { + Application::Settings.ServerDesc = NewValue.as(); + beammp_info(std::string("Set `Description` to ") + Application::Settings.ServerDesc); } else - SendError(Engine(), L, ("set invalid argument [2] expected string for ID : 6")); + beammp_lua_error("set invalid argument [2] expected string"); break; default: - warn(("Invalid config ID : ") + std::to_string(C)); + beammp_warn("Invalid config ID \"" + std::to_string(ConfigID) + "\". Use `MP.Settings.*` enum for this."); break; } } -*/ void LuaAPI::MP::Sleep(size_t Ms) { std::this_thread::sleep_for(std::chrono::milliseconds(Ms)); diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index b11c75f..2c22951 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -227,6 +227,28 @@ std::string TLuaEngine::StateThreadData::Lua_GetPlayerName(int ID) { } } +sol::table TLuaEngine::StateThreadData::Lua_GetPlayerVehicles(int ID) { + auto MaybeClient = GetClient(mEngine->Server(), ID); + if (MaybeClient && !MaybeClient.value().expired()) { + auto Client = MaybeClient.value().lock(); + TClient::TSetOfVehicleData VehicleData; + { // Vehicle Data Lock Scope + auto LockedData = Client->GetAllCars(); + VehicleData = *LockedData.VehicleData; + } // End Vehicle Data Lock Scope + if (VehicleData.empty()) { + return sol::nil; + } + sol::state_view StateView(mState); + sol::table Result = StateView.create_table(); + for (const auto& v : VehicleData) { + Result[v.ID()] = v.Data().substr(3); + } + return Result; + } else + return sol::nil; +} + TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomic_bool& Shutdown, TLuaStateId StateId, TLuaEngine& Engine) : mName(Name) , mShutdown(Shutdown) @@ -271,7 +293,9 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi return Lua_GetPlayerName(ID); }); Table.set_function("RemoveVehicle", &LuaAPI::MP::RemoveVehicle); - //Table.set_function("GetPlayerVehicles", &Lua_GetPlayerVehicles); + Table.set_function("GetPlayerVehicles", [&](int ID) -> sol::table { + return Lua_GetPlayerVehicles(ID); + })); Table.set_function("SendChatMessage", &LuaAPI::MP::SendChatMessage); Table.set_function("GetPlayers", [&]() -> sol::table { return Lua_GetPlayers(); @@ -282,7 +306,7 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi return Lua_GetPlayerIdentifiers(ID); }); Table.set_function("Sleep", &LuaAPI::MP::Sleep); - //Table.set_function("Set", &LuaAPI::MP::Set); + Table.set_function("Set", &LuaAPI::MP::Set); //Table.set_function("HttpsGET", &LuaAPI::MP::HttpsGET); //Table.set_function("HttpsPOST", &LuaAPI::MP::HttpsPOST); Table.create_named("Settings", From fd3088c78f1675762010cbced48494cc2b96d952 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 17 Sep 2021 12:58:07 +0200 Subject: [PATCH 113/255] Re-add SendChatMessage --- include/Common.h | 2 ++ src/Common.cpp | 12 ++++++++++++ src/LuaAPI.cpp | 5 +++-- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/include/Common.h b/include/Common.h index d36cf6f..a7e8711 100644 --- a/include/Common.h +++ b/include/Common.h @@ -142,3 +142,5 @@ std::string Comp(std::string Data); std::string DeComp(std::string Compressed); std::string GetPlatformAgnosticErrorString(); + +void LogChatMessage(const std::string& name, int id, const std::string& msg); diff --git a/src/Common.cpp b/src/Common.cpp index 0c535f7..770da76 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -128,3 +128,15 @@ std::string GetPlatformAgnosticErrorString() { return std::strerror(errno); #endif } + +void LogChatMessage(const std::string& name, int id, const std::string& msg) { + std::stringstream ss; + ss << "[CHAT] "; + if (id != -1) { + ss << "(" << id << ") <" << name << ">"; + } else { + ss << name << ""; + } + ss << msg; + Application::Console().Write(ss.str()); +} diff --git a/src/LuaAPI.cpp b/src/LuaAPI.cpp index 89d54db..9c71773 100644 --- a/src/LuaAPI.cpp +++ b/src/LuaAPI.cpp @@ -1,5 +1,6 @@ #include "LuaAPI.h" #include "Client.h" +#include "Common.h" #include "TLuaEngine.h" static std::string LuaToString(const sol::object Value, size_t Indent = 1) { @@ -122,7 +123,7 @@ void LuaAPI::MP::DropPlayer(int ID, std::optional MaybeReason) { void LuaAPI::MP::SendChatMessage(int ID, const std::string& Message) { std::string Packet = "C:Server: " + Message; if (ID == -1) { - //LogChatMessage(" (to everyone) ", -1, Message); + LogChatMessage(" (to everyone) ", -1, Message); Engine->Network().SendToAll(nullptr, Packet, true, true); } else { auto MaybeClient = GetClient(Engine->Server(), ID); @@ -130,7 +131,7 @@ void LuaAPI::MP::SendChatMessage(int ID, const std::string& Message) { auto c = MaybeClient.value().lock(); if (!c->IsSynced()) return; - //LogChatMessage(" (to \"" + c->GetName() + "\")", -1, msg); + LogChatMessage(" (to \"" + c->GetName() + "\")", -1, msg); Engine->Network().Respond(*c, Packet, true); } else { beammp_lua_error("SendChatMessage invalid argument [1] invalid ID"); From 7db345cfbcd8a73bdf6c724231fa930240f1a3a8 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 17 Sep 2021 13:36:16 +0200 Subject: [PATCH 114/255] update submodules --- .gitmodules | 27 +++++++++++++-------------- deps/toml11 | 1 - include/toml11 | 1 - 3 files changed, 13 insertions(+), 16 deletions(-) delete mode 160000 deps/toml11 delete mode 160000 include/toml11 diff --git a/.gitmodules b/.gitmodules index f2cf422..489e67d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,19 +1,18 @@ -[submodule "include/commandline"] - path = include/commandline +[submodule "deps/commandline"] + path = deps/commandline url = https://github.com/lionkor/commandline -[submodule "asio"] - path = asio +[submodule "deps/asio"] + path = deps/asio url = https://github.com/chriskohlhoff/asio -[submodule "rapidjson"] - path = rapidjson +[submodule "deps/rapidjson"] + path = deps/rapidjson url = https://github.com/Tencent/rapidjson -[submodule "include/toml11"] - path = include/toml11 - url = https://github.com/ToruNiina/toml11 -[submodule "include/sentry-native"] - path = include/sentry-native +[submodule "deps/toml11"] path = deps/toml11 - url = https://github.com/ToruNiina/toml11 + url = https://github.com/ToruNiina/toml11 +[submodule "deps/sentry-native"] + path = deps/sentry-native + url = https://github.com/getsentry/sentry-native [submodule "deps/sol2"] - path = deps/sol2 - url = https://github.com/getsentry/sentry-native \ No newline at end of file + path = deps/sol2 + url = https://github.com/ThePhD/sol2 diff --git a/deps/toml11 b/deps/toml11 deleted file mode 160000 index 6473810..0000000 --- a/deps/toml11 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 647381020ef04b5d41d540ec489eba45e82d90a7 diff --git a/include/toml11 b/include/toml11 deleted file mode 160000 index 6473810..0000000 --- a/include/toml11 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 647381020ef04b5d41d540ec489eba45e82d90a7 From a0c47d9947c6162bd8edf2f27789654872bd2ab8 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 17 Sep 2021 14:17:27 +0200 Subject: [PATCH 115/255] move sentry-native --- deps/sentry-native | 1 + include/sentry-native | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) create mode 160000 deps/sentry-native delete mode 160000 include/sentry-native diff --git a/deps/sentry-native b/deps/sentry-native new file mode 160000 index 0000000..90966cc --- /dev/null +++ b/deps/sentry-native @@ -0,0 +1 @@ +Subproject commit 90966cc1022b8155681b6899539b35466baccf2c diff --git a/include/sentry-native b/include/sentry-native deleted file mode 160000 index 5218603..0000000 --- a/include/sentry-native +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 521860373df1cc02607546c3474d78b42042b459 From 74597793635808c7391e4ecd630939cb6b60e480 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 17 Sep 2021 14:21:20 +0200 Subject: [PATCH 116/255] update cmakelists --- .gitmodules | 8 ++++---- CMakeLists.txt | 7 +------ 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/.gitmodules b/.gitmodules index 489e67d..fa52218 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,13 +1,13 @@ -[submodule "deps/commandline"] +[submodule "commandline"] path = deps/commandline url = https://github.com/lionkor/commandline -[submodule "deps/asio"] +[submodule "asio"] path = deps/asio url = https://github.com/chriskohlhoff/asio -[submodule "deps/rapidjson"] +[submodule "rapidjson"] path = deps/rapidjson url = https://github.com/Tencent/rapidjson -[submodule "deps/toml11"] +[submodule "include/toml11"] path = deps/toml11 url = https://github.com/ToruNiina/toml11 [submodule "deps/sentry-native"] diff --git a/CMakeLists.txt b/CMakeLists.txt index 0b72c1b..5e9883e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,5 @@ cmake_minimum_required(VERSION 3.0) - - - - - message(STATUS "You can find build instructions and a list of dependencies in the README at \ https://github.com/BeamMP/BeamMP-Server") @@ -33,7 +28,7 @@ if (MSVC) set(SENTRY_BUILD_RUNTIMESTATIC ON) endif() set(SENTRY_BACKEND breakpad) -add_subdirectory("include/sentry-native") +add_subdirectory("deps/sentry-native") message(STATUS "Setting compiler flags") if (WIN32) From fcbb188ee09cccd9eb39e26b547ef03d0e0fa89c Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 17 Sep 2021 14:25:11 +0200 Subject: [PATCH 117/255] update modules, cmakelists --- .gitmodules | 2 +- CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index fa52218..107343f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ -[submodule "commandline"] +[submodule "include/commandline"] path = deps/commandline url = https://github.com/lionkor/commandline [submodule "asio"] diff --git a/CMakeLists.txt b/CMakeLists.txt index 44b4c21..4754864 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -89,7 +89,7 @@ add_executable(BeamMP-Server include/TSentry.h src/TSentry.cpp include/TPPSMonitor.h src/TPPSMonitor.cpp include/TNetwork.h src/TNetwork.cpp - include/LuaAPI.h src/LuaAPI.cpp) + include/LuaAPI.h src/LuaAPI.cpp include/SignalHandling.h src/SignalHandling.cpp) target_compile_definitions(BeamMP-Server PRIVATE SECRET_SENTRY_URL="${BEAMMP_SECRET_SENTRY_URL}") From a07b5062decd2f59da20f564f64b1b9921136347 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 17 Sep 2021 14:28:45 +0200 Subject: [PATCH 118/255] Reintroduce gitmodules --- .gitmodules | 19 +++++++++++-------- deps/asio | 1 + deps/commandline | 1 + deps/rapidjson | 1 + deps/toml11 | 1 + 5 files changed, 15 insertions(+), 8 deletions(-) create mode 160000 deps/asio create mode 160000 deps/commandline create mode 160000 deps/rapidjson create mode 160000 deps/toml11 diff --git a/.gitmodules b/.gitmodules index 107343f..083c21f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,18 +1,21 @@ -[submodule "include/commandline"] - path = deps/commandline - url = https://github.com/lionkor/commandline -[submodule "asio"] +[submodule "deps/https:/github.com/chriskohlhoff/asio"] + path = deps/https:/github.com/chriskohlhoff/asio + url = https://github.com/lionkor/commandline +[submodule "deps/commandline"] + path = deps/commandline + url = https://github.com/lionkor/commandline +[submodule "deps/asio"] path = deps/asio url = https://github.com/chriskohlhoff/asio -[submodule "rapidjson"] +[submodule "deps/rapidjson"] path = deps/rapidjson url = https://github.com/Tencent/rapidjson -[submodule "include/toml11"] +[submodule "deps/toml11"] path = deps/toml11 url = https://github.com/ToruNiina/toml11 [submodule "deps/sentry-native"] path = deps/sentry-native url = https://github.com/getsentry/sentry-native [submodule "deps/sol2"] - path = deps/sol2 - url = https://github.com/ThePhD/sol2 + path = deps/sol2 + url = https://github.com/ThePhD/sol2 diff --git a/deps/asio b/deps/asio new file mode 160000 index 0000000..d038fb3 --- /dev/null +++ b/deps/asio @@ -0,0 +1 @@ +Subproject commit d038fb3c2fb56fb91ff1d17b0715cff7887aa09e diff --git a/deps/commandline b/deps/commandline new file mode 160000 index 0000000..4931aa8 --- /dev/null +++ b/deps/commandline @@ -0,0 +1 @@ +Subproject commit 4931aa89c1b400732394d8b8523974ed09f427dc diff --git a/deps/rapidjson b/deps/rapidjson new file mode 160000 index 0000000..00dbcf2 --- /dev/null +++ b/deps/rapidjson @@ -0,0 +1 @@ +Subproject commit 00dbcf2c6e03c47d6c399338b6de060c71356464 diff --git a/deps/toml11 b/deps/toml11 new file mode 160000 index 0000000..fda0a2b --- /dev/null +++ b/deps/toml11 @@ -0,0 +1 @@ +Subproject commit fda0a2b9abd16e356f777c40a675131821c71b00 From 9dfe9f659a792992938d0f8eecebf06bd4db2cdd Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 17 Sep 2021 14:30:33 +0200 Subject: [PATCH 119/255] Update cmakelists to remove socket.io --- deps/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/deps/CMakeLists.txt b/deps/CMakeLists.txt index 5504038..4e556b0 100644 --- a/deps/CMakeLists.txt +++ b/deps/CMakeLists.txt @@ -5,6 +5,5 @@ include_directories("${PROJECT_SOURCE_DIR}/deps/commandline") include_directories("${PROJECT_SOURCE_DIR}/deps/sol2/include") include_directories("${PROJECT_SOURCE_DIR}/deps") -add_subdirectory("${PROJECT_SOURCE_DIR}/deps/socket.io-client-cpp") add_subdirectory("${PROJECT_SOURCE_DIR}/deps/commandline") add_subdirectory("${PROJECT_SOURCE_DIR}/deps/sol2") From 48caae25fd27d8c2aef1924fd6895e5f7afccdea Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 17 Sep 2021 14:58:40 +0200 Subject: [PATCH 120/255] Finalize master&new-lua-features merge --- include/Common.h | 10 ++- src/Common.cpp | 18 +++--- src/Http.cpp | 8 +-- src/LuaAPI.cpp | 2 +- src/SignalHandling.cpp | 18 +++--- src/TConfig.cpp | 22 +++---- src/THeartbeatThread.cpp | 12 ++-- src/TLuaEngine.cpp | 2 +- src/TNetwork.cpp | 131 ++++++++++++++++++++++----------------- src/TSentry.cpp | 12 ++-- src/TServer.cpp | 22 +++---- src/VehicleData.cpp | 4 +- src/main.cpp | 6 +- 13 files changed, 143 insertions(+), 124 deletions(-) diff --git a/include/Common.h b/include/Common.h index 6fd0e6b..f8436d6 100644 --- a/include/Common.h +++ b/include/Common.h @@ -141,11 +141,15 @@ void RegisterThread(const std::string& str); #define beammp_warn(x) Application::Console().Write(_this_location + std::string("[WARN] ") + (x)) #define beammp_info(x) Application::Console().Write(_this_location + std::string("[INFO] ") + (x)) -#define error(x) \ +#define beammp_error(x) \ do { \ Application::Console().Write(_this_location + std::string("[ERROR] ") + (x)); \ Sentry.AddErrorBreadcrumb((x), _file_basename, _line); \ } while (false) +#define beammp_lua_error(x) \ + do { \ + Application::Console().Write(_this_location + std::string("[LUA_ERROR] ") + (x)); \ + } while (false) #define luaprint(x) Application::Console().Write(_this_location + std::string("[LUA] ") + (x)) #define beammp_debug(x) \ do { \ @@ -158,14 +162,14 @@ void RegisterThread(const std::string& str); #define beammp_ignore(x) (void)x // trace() is a debug-build debug() #if defined(DEBUG) -#define trace(x) \ +#define beammp_trace(x) \ do { \ if (Application::Settings.DebugModeEnabled) { \ Application::Console().Write(_this_location + std::string("[TRACE] ") + (x)); \ } \ } while (false) #else -#define trace(x) +#define beammp_trace(x) #endif // defined(DEBUG) void LogChatMessage(const std::string& name, int id, const std::string& msg); diff --git a/src/Common.cpp b/src/Common.cpp index c26ddd4..d058de5 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -29,19 +29,19 @@ void Application::GracefullyShutdown() { ++ShutdownAttempts; // hard shutdown at 2 additional tries if (ShutdownAttempts == 2) { - info("hard shutdown forced by multiple shutdown requests"); + beammp_info("hard shutdown forced by multiple shutdown requests"); std::exit(0); } - info("already shutting down!"); + beammp_info("already shutting down!"); return; } else { AlreadyShuttingDown = true; } - trace("waiting for lock release"); + beammp_trace("waiting for lock release"); std::unique_lock Lock(mShutdownHandlersMutex); - info("please wait while all subsystems are shutting down..."); + beammp_info("please wait while all subsystems are shutting down..."); for (size_t i = 0; i < mShutdownHandlers.size(); ++i) { - info("Subsystem " + std::to_string(i + 1) + "/" + std::to_string(mShutdownHandlers.size()) + " shutting down"); + beammp_info("Subsystem " + std::to_string(i + 1) + "/" + std::to_string(mShutdownHandlers.size()) + " shutting down"); mShutdownHandlers[i](); } } @@ -84,13 +84,13 @@ void Application::CheckForUpdates() { auto RemoteVersion = Version(VersionStrToInts(Response)); if (IsOutdated(MyVersion, RemoteVersion)) { std::string RealVersionString = RemoteVersion.AsString(); - warn(std::string(ANSI_YELLOW_BOLD) + "NEW VERSION OUT! There's a new version (v" + RealVersionString + ") of the BeamMP-Server available! For more info visit https://wiki.beammp.com/en/home/server-maintenance#updating-the-server." + std::string(ANSI_RESET)); + beammp_warn(std::string(ANSI_YELLOW_BOLD) + "NEW VERSION OUT! There's a new version (v" + RealVersionString + ") of the BeamMP-Server available! For more info visit https://wiki.beammp.com/en/home/server-maintenance#updating-the-server." + std::string(ANSI_RESET)); } else { - info("Server up-to-date!"); + beammp_info("Server up-to-date!"); } } else { - warn("Unable to fetch version from backend."); - trace("got " + Response); + beammp_warn("Unable to fetch version from backend."); + beammp_trace("got " + Response); auto Lock = Sentry.CreateExclusiveContext(); Sentry.SetContext("get-response", { { "response", Response } }); Sentry.LogError("failed to get server version", _file_basename, _line); diff --git a/src/Http.cpp b/src/Http.cpp index 7d08fa4..b58360f 100644 --- a/src/Http.cpp +++ b/src/Http.cpp @@ -63,11 +63,11 @@ std::string GenericRequest(http::verb verb, const std::string& host, int port, c req.set(http::field::content_length, std::to_string(body.size())); req.body() = body; - // info("body is " + body + " (" + req.body() + ")"); - // info("content size is " + std::to_string(body.size()) + " (" + boost::lexical_cast(body.size()) + ")"); + // beammp_info("body is " + body + " (" + req.body() + ")"); + // beammp_info("content size is " + std::to_string(body.size()) + " (" + boost::lexical_cast(body.size()) + ")"); } for (const auto& pair : fields) { - // info("setting " + pair.first + " to " + pair.second); + // beammp_info("setting " + pair.first + " to " + pair.second); req.set(pair.first, pair.second); } @@ -119,7 +119,7 @@ std::string GenericRequest(http::verb verb, const std::string& host, int port, c stream.shutdown(ec); // IGNORING ec - // info(result.str()); + // beammp_info(result.str()); std::string debug_response_str; std::getline(result, debug_response_str); diff --git a/src/LuaAPI.cpp b/src/LuaAPI.cpp index 9c71773..fbf34cc 100644 --- a/src/LuaAPI.cpp +++ b/src/LuaAPI.cpp @@ -131,7 +131,7 @@ void LuaAPI::MP::SendChatMessage(int ID, const std::string& Message) { auto c = MaybeClient.value().lock(); if (!c->IsSynced()) return; - LogChatMessage(" (to \"" + c->GetName() + "\")", -1, msg); + LogChatMessage(" (to \"" + c->GetName() + "\")", -1, Message); Engine->Network().Respond(*c, Packet, true); } else { beammp_lua_error("SendChatMessage invalid argument [1] invalid ID"); diff --git a/src/SignalHandling.cpp b/src/SignalHandling.cpp index 3325871..7a7f971 100644 --- a/src/SignalHandling.cpp +++ b/src/SignalHandling.cpp @@ -6,18 +6,18 @@ static void UnixSignalHandler(int sig) { switch (sig) { case SIGPIPE: - warn("ignoring SIGPIPE"); + beammp_warn("ignoring SIGPIPE"); break; case SIGTERM: - info("gracefully shutting down via SIGTERM"); + beammp_info("gracefully shutting down via SIGTERM"); Application::GracefullyShutdown(); break; case SIGINT: - info("gracefully shutting down via SIGINT"); + beammp_info("gracefully shutting down via SIGINT"); Application::GracefullyShutdown(); break; default: - debug("unhandled signal: " + std::to_string(sig)); + beammp_debug("unhandled signal: " + std::to_string(sig)); break; } } @@ -29,15 +29,15 @@ static void UnixSignalHandler(int sig) { BOOL WINAPI Win32CtrlC_Handler(DWORD CtrlType) { switch (CtrlType) { case CTRL_C_EVENT: - info("gracefully shutting down via CTRL+C"); + beammp_info("gracefully shutting down via CTRL+C"); Application::GracefullyShutdown(); return TRUE; case CTRL_BREAK_EVENT: - info("gracefully shutting down via CTRL+BREAK"); + beammp_info("gracefully shutting down via CTRL+BREAK"); Application::GracefullyShutdown(); return TRUE; case CTRL_CLOSE_EVENT: - info("gracefully shutting down via close"); + beammp_info("gracefully shutting down via close"); Application::GracefullyShutdown(); return TRUE; } @@ -49,7 +49,7 @@ BOOL WINAPI Win32CtrlC_Handler(DWORD CtrlType) { void SetupSignalHandlers() { // signal handlers for unix#include #ifdef __unix - trace("registering handlers for SIGINT, SIGTERM, SIGPIPE"); + beammp_trace("registering handlers for SIGINT, SIGTERM, SIGPIPE"); signal(SIGPIPE, UnixSignalHandler); signal(SIGTERM, UnixSignalHandler); #ifndef DEBUG @@ -59,7 +59,7 @@ void SetupSignalHandlers() { // signal handlers for win32 #ifdef WIN32 - trace("registering handlers for CTRL_*_EVENTs"); + beammp_trace("registering handlers for CTRL_*_EVENTs"); SetConsoleCtrlHandler(Win32CtrlC_Handler, TRUE); #endif // WIN32 } diff --git a/src/TConfig.cpp b/src/TConfig.cpp index be0f7fe..b5313a9 100644 --- a/src/TConfig.cpp +++ b/src/TConfig.cpp @@ -58,6 +58,8 @@ void TConfig::FlushToFile() { data["General"][StrMap.data()] = Application::Settings.MapName; data["General"][StrDescription.data()] = Application::Settings.ServerDesc; data["General"][StrResourceFolder.data()] = Application::Settings.Resource; + data["General"][StrSendErrors.data()] = Application::Settings.SendErrors; + data["General"][StrSendErrorsMessageEnabled.data()] = Application::Settings.SendErrorsMessageEnabled; std::ofstream Stream(ConfigFileName); Stream << data << std::flush; } @@ -79,7 +81,7 @@ void TConfig::CreateConfigFile(std::string_view name) { } auto data = toml::parse(name.data()); - //{ StrSendErrors, Application::Settings.SendErrors }, + //{ StrSendErrors, Application::Settings.SendErrors }, data["General"] = toml::table(); data["General"][StrAuthKey.data()] = Application::Settings.Key; @@ -92,6 +94,8 @@ void TConfig::CreateConfigFile(std::string_view name) { data["General"][StrMap.data()] = Application::Settings.MapName; data["General"][StrDescription.data()] = Application::Settings.ServerDesc; data["General"][StrResourceFolder.data()] = Application::Settings.Resource; + data["General"][StrSendErrors.data()] = Application::Settings.SendErrors; + data["General"][StrSendErrorsMessageEnabled.data()] = Application::Settings.SendErrorsMessageEnabled; std::ofstream ofs { std::string(name) }; if (ofs.good()) { @@ -123,19 +127,13 @@ void TConfig::ParseFromFile(std::string_view name) { Application::Settings.ServerDesc = data["General"][StrDescription.data()].as_string(); Application::Settings.Resource = data["General"][StrResourceFolder.data()].as_string(); Application::Settings.Key = data["General"][StrAuthKey.data()].as_string(); - } - // added later, so behaves differently - if (auto val = GeneralTable[StrSendErrors].value(); val.has_value()) { - Application::Settings.SendErrors = val.value(); - } else { - // dont throw, instead write it into the file and use default + if (!data["General"][StrSendErrors.data()].is_boolean() + || !data["General"][StrSendErrorsMessageEnabled.data()].is_boolean()) { WriteSendErrors(std::string(name)); - } - if (auto val = GeneralTable[StrSendErrorsMessageEnabled].value(); val.has_value()) { - Application::Settings.SendErrorsMessageEnabled = val.value(); } else { - // no idea what to do here, ignore...? - // this entire toml parser sucks and is replaced in the upcoming lua. + Application::Settings.SendErrors = data["General"][StrSendErrors.data()].as_boolean(); + Application::Settings.SendErrorsMessageEnabled = data["General"][StrSendErrorsMessageEnabled.data()].as_boolean(); + } } catch (const std::exception& err) { beammp_error("Error parsing config file value: " + std::string(err.what())); mFailed = true; diff --git a/src/THeartbeatThread.cpp b/src/THeartbeatThread.cpp index af6b827..cd5aa83 100644 --- a/src/THeartbeatThread.cpp +++ b/src/THeartbeatThread.cpp @@ -26,7 +26,7 @@ void THeartbeatThread::operator()() { std::this_thread::sleep_for(std::chrono::milliseconds(100)); continue; } - debug("heartbeat (after " + std::to_string(std::chrono::duration_cast(TimePassed).count()) + "s)"); + beammp_debug("heartbeat (after " + std::to_string(std::chrono::duration_cast(TimePassed).count()) + "s)"); Last = Body; LastNormalUpdateTime = Now; @@ -42,7 +42,7 @@ void THeartbeatThread::operator()() { { { "response-body", T }, { "request-body", Body } }); Sentry.SetTransaction(transaction); - trace("sending log to sentry: " + std::to_string(status) + " for " + transaction); + beammp_trace("sending log to sentry: " + std::to_string(status) + " for " + transaction); Sentry.Log(SentryLevel::Error, "default", Http::Status::ToString(status) + " (" + std::to_string(status) + ")"); }; @@ -51,7 +51,7 @@ void THeartbeatThread::operator()() { T = Http::POST(Application::GetBackendHostname(), 443, Target, {}, Body, "application/x-www-form-urlencoded", &ResponseCode); if ((T.substr(0, 2) != "20" && ResponseCode != 200) || ResponseCode != 200) { - trace("got " + T + " from backend"); + beammp_trace("got " + T + " from backend"); SentryReportError(Application::GetBackendHostname() + Target, ResponseCode); std::this_thread::sleep_for(std::chrono::milliseconds(500)); T = Http::POST(Application::GetBackup1Hostname(), 443, Target, {}, Body, "application/x-www-form-urlencoded", &ResponseCode); @@ -60,7 +60,7 @@ void THeartbeatThread::operator()() { std::this_thread::sleep_for(std::chrono::milliseconds(500)); T = Http::POST(Application::GetBackup2Hostname(), 443, Target, {}, Body, "application/x-www-form-urlencoded", &ResponseCode); if ((T.substr(0, 2) != "20" && ResponseCode != 200) || ResponseCode != 200) { - warn("Backend system refused server! Server will not show in the public server list."); + beammp_warn("Backend system refused server! Server will not show in the public server list."); isAuth = false; SentryReportError(Application::GetBackup2Hostname() + Target, ResponseCode); @@ -70,10 +70,10 @@ void THeartbeatThread::operator()() { if (!isAuth) { if (T == "2000") { - info(("Authenticated!")); + beammp_info(("Authenticated!")); isAuth = true; } else if (T == "200") { - info(("Resumed authenticated session!")); + beammp_info(("Resumed authenticated session!")); isAuth = true; } } diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 2c22951..3421f5d 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -295,7 +295,7 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi Table.set_function("RemoveVehicle", &LuaAPI::MP::RemoveVehicle); Table.set_function("GetPlayerVehicles", [&](int ID) -> sol::table { return Lua_GetPlayerVehicles(ID); - })); + }); Table.set_function("SendChatMessage", &LuaAPI::MP::SendChatMessage); Table.set_function("GetPlayers", [&]() -> sol::table { return Lua_GetPlayers(); diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index 23dc556..a32d4e1 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -1,5 +1,7 @@ #include "TNetwork.h" #include "Client.h" +#include "LuaAPI.h" +#include "TLuaEngine.h" #include #include #include @@ -10,7 +12,7 @@ TNetwork::TNetwork(TServer& Server, TPPSMonitor& PPSMonitor, TResourceManager& R , mPPSMonitor(PPSMonitor) , mResourceManager(ResourceManager) { Application::RegisterShutdownHandler([&] { - debug("Kicking all players due to shutdown"); + beammp_debug("Kicking all players due to shutdown"); Server.ForEachClient([&](std::weak_ptr client) -> bool { if (!client.expired()) { ClientKick(*client.lock(), "Server shutdown"); @@ -39,7 +41,7 @@ void TNetwork::UDPServerMain() { #ifdef WIN32 WSADATA data; if (WSAStartup(514, &data)) { - error(("Can't start Winsock!")); + beammp_error(("Can't start Winsock!")); //return; } #endif // WIN32 @@ -52,13 +54,13 @@ void TNetwork::UDPServerMain() { // Try and bind the socket to the IP and port if (bind(mUDPSock, (sockaddr*)&serverAddr, sizeof(serverAddr)) != 0) { - error("bind() failed: " + GetPlatformAgnosticErrorString()); + beammp_error("bind() failed: " + GetPlatformAgnosticErrorString()); std::this_thread::sleep_for(std::chrono::seconds(5)); exit(-1); //return; } - info(("Vehicle data network online on port ") + std::to_string(Application::Settings.Port) + (" with a Max of ") + beammp_info(("Vehicle data network online on port ") + std::to_string(Application::Settings.Port) + (" with a Max of ") + std::to_string(Application::Settings.MaxPlayers) + (" Clients")); while (!mShutdown) { try { @@ -90,7 +92,7 @@ void TNetwork::UDPServerMain() { return true; }); } catch (const std::exception& e) { - error(("fatal: ") + std::string(e.what())); + beammp_error(("fatal: ") + std::string(e.what())); } } } @@ -100,7 +102,7 @@ void TNetwork::TCPServerMain() { #ifdef WIN32 WSADATA wsaData; if (WSAStartup(514, &wsaData)) { - error("Can't start Winsock!"); + beammp_error("Can't start Winsock!"); return; } #endif // WIN32 @@ -119,40 +121,40 @@ void TNetwork::TCPServerMain() { addr.sin_family = AF_INET; addr.sin_port = htons(uint16_t(Application::Settings.Port)); if (bind(Listener, (sockaddr*)&addr, sizeof(addr)) != 0) { - error("bind() failed: " + GetPlatformAgnosticErrorString()); + beammp_error("bind() failed: " + GetPlatformAgnosticErrorString()); std::this_thread::sleep_for(std::chrono::seconds(5)); exit(-1); } if (Listener == -1) { - error("Invalid listening socket"); + beammp_error("Invalid listening socket"); return; } if (listen(Listener, SOMAXCONN)) { - error("listen() failed: " + GetPlatformAgnosticErrorString()); + beammp_error("listen() failed: " + GetPlatformAgnosticErrorString()); // FIXME leak Listener return; } - info(("Vehicle event network online")); + beammp_info(("Vehicle event network online")); do { try { if (mShutdown) { - debug("shutdown during TCP wait for accept loop"); + beammp_debug("shutdown during TCP wait for accept loop"); break; } client.SockAddrLen = sizeof(client.SockAddr); client.Socket = accept(Listener, &client.SockAddr, &client.SockAddrLen); if (client.Socket == -1) { - warn(("Got an invalid client socket on connect! Skipping...")); + beammp_warn(("Got an invalid client socket on connect! Skipping...")); continue; } std::thread ID(&TNetwork::Identify, this, client); ID.detach(); // TODO: Add to a queue and attempt to join periodically } catch (const std::exception& e) { - error(("fatal: ") + std::string(e.what())); + beammp_error(("fatal: ") + std::string(e.what())); } } while (client.Socket); - debug("all ok, arrived at " + std::string(__func__) + ":" + std::to_string(__LINE__)); + beammp_debug("all ok, arrived at " + std::string(__func__) + ":" + std::to_string(__LINE__)); CloseSocketProper(client.Socket); #ifdef WIN32 @@ -209,7 +211,7 @@ void TNetwork::Authentication(const TConnection& ClientConnection) { Client->SetIdentifier("ip", str); std::string Rc; - info("Identifying new ClientConnection..."); + beammp_info("Identifying new ClientConnection..."); Rc = TCPRcv(*Client); @@ -259,7 +261,7 @@ void TNetwork::Authentication(const TConnection& ClientConnection) { Sentry.Log(SentryLevel::Info, "default", "backend returned 0 instead of json (" + std::to_string(ResponseCode) + ")"); } else { // Rc != "0" ClientKick(*Client, "Backend returned invalid auth response format."); - error("Backend returned invalid auth response format. This should never happen."); + beammp_error("Backend returned invalid auth response format. This should never happen."); auto Lock = Sentry.CreateExclusiveContext(); Sentry.SetContext("auth", { { "response-body", Rc }, @@ -286,7 +288,7 @@ void TNetwork::Authentication(const TConnection& ClientConnection) { return; } - debug("Name -> " + Client->GetName() + ", Guest -> " + std::to_string(Client->IsGuest()) + ", Roles -> " + Client->GetRoles()); + beammp_debug("Name -> " + Client->GetName() + ", Guest -> " + std::to_string(Client->IsGuest()) + ", Roles -> " + Client->GetRoles()); mServer.ForEachClient([&](const std::weak_ptr& ClientPtr) -> bool { std::shared_ptr Cl; { @@ -305,18 +307,32 @@ void TNetwork::Authentication(const TConnection& ClientConnection) { return true; }); - auto arg = std::make_unique(TLuaArg { { Client->GetName(), Client->GetRoles(), Client->IsGuest() } }); - std::any Res = TriggerLuaEvent("onPlayerAuth", false, nullptr, std::move(arg), true); - if (Res.type() == typeid(int) && std::any_cast(Res)) { + auto Futures = LuaAPI::MP::Engine->TriggerEvent("onPlayerAuth", Client->GetName(), Client->GetRoles(), Client->IsGuest()); + TLuaEngine::WaitForAll(Futures); + bool NotAllowed = std::any_of(Futures.begin(), Futures.end(), + [](const std::shared_ptr& Result) { + return !Result->Error && Result->Result.is() && bool(Result->Result.as()); + }); + std::string Reason; + bool NotAllowedWithReason = std::any_of(Futures.begin(), Futures.end(), + [&Reason](const std::shared_ptr& Result) -> bool { + if (!Result->Error && Result->Result.is()) { + Reason = Result->Result.as(); + return true; + } + return false; + }); + + if (NotAllowed) { ClientKick(*Client, "you are not allowed on the server!"); return; - } else if (Res.type() == typeid(std::string)) { - ClientKick(*Client, std::any_cast(Res)); + } else if (NotAllowedWithReason) { + ClientKick(*Client, Reason); return; } if (mServer.ClientCount() < size_t(Application::Settings.MaxPlayers)) { - info("Identification success"); + beammp_info("Identification success"); mServer.InsertClient(Client); TCPClient(Client); } else @@ -355,12 +371,12 @@ bool TNetwork::TCPSend(TClient& c, const std::string& Data, bool IsSync) { int32_t Temp = send(c.GetTCPSock(), &Send[Sent], Size - Sent, MSG_NOSIGNAL); #endif //WIN32 if (Temp == 0) { - debug("send() == 0: " + GetPlatformAgnosticErrorString()); + beammp_debug("send() == 0: " + GetPlatformAgnosticErrorString()); if (c.GetStatus() > -1) c.SetStatus(-1); return false; } else if (Temp < 0) { - debug("send() < 0: " + GetPlatformAgnosticErrorString()); //TODO fix it was spamming yet everyone stayed on the server + beammp_debug("send() < 0: " + GetPlatformAgnosticErrorString()); //TODO fix it was spamming yet everyone stayed on the server if (c.GetStatus() > -1) c.SetStatus(-1); CloseSocketProper(c.GetTCPSock()); @@ -374,12 +390,12 @@ bool TNetwork::TCPSend(TClient& c, const std::string& Data, bool IsSync) { bool TNetwork::CheckBytes(TClient& c, int32_t BytesRcv) { if (BytesRcv == 0) { - trace("(TCP) Connection closing..."); + beammp_trace("(TCP) Connection closing..."); if (c.GetStatus() > -1) c.SetStatus(-1); return false; } else if (BytesRcv < 0) { - debug("(TCP) recv() failed: " + GetPlatformAgnosticErrorString()); + beammp_debug("(TCP) recv() failed: " + GetPlatformAgnosticErrorString()); if (c.GetStatus() > -1) c.SetStatus(-1); CloseSocketProper(c.GetTCPSock()); @@ -410,7 +426,7 @@ std::string TNetwork::TCPRcv(TClient& c) { Data.resize(Header); } else { ClientKick(c, "Header size limit exceeded"); - warn("Client " + c.GetName() + " (" + std::to_string(c.GetID()) + ") sent header of >100MB - 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 ""; } BytesRcv = 0; @@ -430,7 +446,7 @@ std::string TNetwork::TCPRcv(TClient& c) { } void TNetwork::ClientKick(TClient& c, const std::string& R) { - info("Client kicked: " + R); + beammp_info("Client kicked: " + R); if (!TCPSend(c, "E" + R)) { // TODO handle } @@ -446,7 +462,7 @@ void TNetwork::Looper(const std::weak_ptr& c) { while (!c.expired()) { auto Client = c.lock(); if (Client->GetStatus() < 0) { - debug("client status < 0, breaking client loop"); + beammp_debug("client status < 0, breaking client loop"); break; } if (!Client->IsSyncing() && Client->IsSynced() && Client->MissedPacketQueueSize() != 0) { @@ -461,7 +477,7 @@ void TNetwork::Looper(const std::weak_ptr& c) { QData = Client->MissedPacketQueue().front(); Client->MissedPacketQueue().pop(); } // end locked context - // debug("sending a missed packet: " + QData); + // beammp_debug("sending a missed packet: " + QData); if (!TCPSend(*Client, QData, true)) { if (Client->GetStatus() > -1) Client->SetStatus(-1); @@ -496,13 +512,13 @@ void TNetwork::TCPClient(const std::weak_ptr& c) { break; auto Client = c.lock(); if (Client->GetStatus() < 0) { - debug("client status < 0, breaking client loop"); + beammp_debug("client status < 0, breaking client loop"); break; } auto res = TCPRcv(*Client); if (res == "") { - debug("TCPRcv error, break client loop"); + beammp_debug("TCPRcv error, break client loop"); break; } TServer::GlobalParser(c, res, mPPSMonitor, *this); @@ -514,7 +530,7 @@ void TNetwork::TCPClient(const std::weak_ptr& c) { auto Client = c.lock(); OnDisconnect(c, Client->GetStatus() == -2); } else { - warn("client expired in TCPClient, should never happen"); + beammp_warn("client expired in TCPClient, should never happen"); } } @@ -534,10 +550,10 @@ void TNetwork::UpdatePlayer(TClient& Client) { } void TNetwork::OnDisconnect(const std::weak_ptr& ClientPtr, bool kicked) { - Assert(!ClientPtr.expired()); + beammp_assert(!ClientPtr.expired()); auto LockedClientPtr = ClientPtr.lock(); TClient& c = *LockedClientPtr; - info(c.GetName() + (" Connection Terminated")); + beammp_info(c.GetName() + (" Connection Terminated")); std::string Packet; TClient::TSetOfVehicleData VehicleData; { // Vehicle Data Lock Scope @@ -554,7 +570,8 @@ void TNetwork::OnDisconnect(const std::weak_ptr& ClientPtr, bool kicked Packet = ("L") + c.GetName() + (" left the server!"); SendToAll(&c, Packet, false, true); Packet.clear(); - TriggerLuaEvent(("onPlayerDisconnect"), false, nullptr, std::make_unique(TLuaArg { { c.GetID() } }), false); + auto Futures = LuaAPI::MP::Engine->TriggerEvent("onPlayerDisconnect", c.GetID()); + beammp_ignore(Futures); if (c.GetTCPSock()) CloseSocketProper(c.GetTCPSock()); if (c.GetDownSock()) @@ -583,18 +600,18 @@ int TNetwork::OpenID() { } void TNetwork::OnConnect(const std::weak_ptr& c) { - Assert(!c.expired()); - info("Client connected"); + beammp_assert(!c.expired()); + beammp_info("Client connected"); auto LockedClient = c.lock(); LockedClient->SetID(OpenID()); - info("Assigned ID " + std::to_string(LockedClient->GetID()) + " to " + LockedClient->GetName()); - TriggerLuaEvent("onPlayerConnecting", false, nullptr, std::make_unique(TLuaArg { { LockedClient->GetID() } }), false); + beammp_info("Assigned ID " + std::to_string(LockedClient->GetID()) + " to " + LockedClient->GetName()); + beammp_ignore(LuaAPI::MP::Engine->TriggerEvent("onPlayerConnecting", LockedClient->GetID())); SyncResources(*LockedClient); if (LockedClient->GetStatus() < 0) return; (void)Respond(*LockedClient, "M" + Application::Settings.MapName, true); //Send the Map on connect - info(LockedClient->GetName() + " : Connected"); - TriggerLuaEvent("onPlayerJoining", false, nullptr, std::make_unique(TLuaArg { { LockedClient->GetID() } }), false); + beammp_info(LockedClient->GetName() + " : Connected"); + beammp_ignore(LuaAPI::MP::Engine->TriggerEvent("onPlayerJoining", LockedClient->GetID())); } void TNetwork::SyncResources(TClient& c) { @@ -613,7 +630,7 @@ void TNetwork::SyncResources(TClient& c) { } #ifndef DEBUG } catch (std::exception& e) { - error("Exception! : " + std::string(e.what())); + beammp_error("Exception! : " + std::string(e.what())); c.SetStatus(-1); } #endif @@ -631,7 +648,7 @@ void TNetwork::Parse(TClient& c, const std::string& Packet) { return; case 'S': if (SubCode == 'R') { - debug("Sending Mod Info"); + beammp_debug("Sending Mod Info"); std::string ToSend = mResourceManager.FileList() + mResourceManager.FileSizes(); if (ToSend.empty()) ToSend = "-"; @@ -646,13 +663,13 @@ void TNetwork::Parse(TClient& c, const std::string& Packet) { } void TNetwork::SendFile(TClient& c, const std::string& UnsafeName) { - info(c.GetName() + " requesting : " + UnsafeName.substr(UnsafeName.find_last_of('/'))); + beammp_info(c.GetName() + " requesting : " + UnsafeName.substr(UnsafeName.find_last_of('/'))); if (!fs::path(UnsafeName).has_filename()) { if (!TCPSend(c, "CO")) { // TODO: handle } - warn("File " + UnsafeName + " is not a file!"); + beammp_warn("File " + UnsafeName + " is not a file!"); return; } auto FileName = fs::path(UnsafeName).filename().string(); @@ -662,7 +679,7 @@ void TNetwork::SendFile(TClient& c, const std::string& UnsafeName) { if (!TCPSend(c, "CO")) { // TODO: handle } - warn("File " + UnsafeName + " could not be accessed!"); + beammp_warn("File " + UnsafeName + " could not be accessed!"); return; } @@ -678,7 +695,7 @@ void TNetwork::SendFile(TClient& c, const std::string& UnsafeName) { } if (c.GetDownSock() < 1) { - error("Client doesn't have a download socket!"); + beammp_error("Client doesn't have a download socket!"); if (c.GetStatus() > -1) c.SetStatus(-1); return; @@ -715,7 +732,7 @@ void TNetwork::SplitLoad(TClient& c, size_t Sent, size_t Size, bool D, const std TCPSock = c.GetDownSock(); else TCPSock = c.GetTCPSock(); - info("Split load Socket " + std::to_string(TCPSock)); + beammp_info("Split load Socket " + std::to_string(TCPSock)); while (c.GetStatus() > -1 && Sent < Size) { size_t Diff = Size - Sent; if (Diff > Split) { @@ -747,7 +764,7 @@ bool TNetwork::TCPSendRaw(TClient& C, SOCKET socket, char* Data, int32_t Size) { do { intmax_t Temp = send(socket, &Data[Sent], int(Size - Sent), 0); if (Temp < 1) { - info("Socket Closed! " + std::to_string(socket)); + beammp_info("Socket Closed! " + std::to_string(socket)); CloseSocketProper(socket); return false; } @@ -793,7 +810,7 @@ bool TNetwork::SyncClient(const std::weak_ptr& c) { // ignore error (void)SendToAll(LockedClient.get(), ("JWelcome ") + LockedClient->GetName() + "!", false, true); - TriggerLuaEvent(("onPlayerJoin"), false, nullptr, std::make_unique(TLuaArg { { LockedClient->GetID() } }), false); + beammp_ignore(LuaAPI::MP::Engine->TriggerEvent("onPlayerJoin", LockedClient->GetID())); LockedClient->SetIsSyncing(true); bool Return = false; bool res = true; @@ -829,13 +846,13 @@ bool TNetwork::SyncClient(const std::weak_ptr& c) { return res; } LockedClient->SetIsSynced(true); - info(LockedClient->GetName() + (" is now synced!")); + beammp_info(LockedClient->GetName() + (" is now synced!")); return true; } void TNetwork::SendToAll(TClient* c, const std::string& Data, bool Self, bool Rel) { if (!Self) - Assert(c); + beammp_assert(c); char C = Data.at(0); bool ret = true; mServer.ForEachClient([&](std::weak_ptr ClientPtr) -> bool { @@ -899,12 +916,12 @@ bool TNetwork::UDPSend(TClient& Client, std::string Data) const { sendOk = sendto(mUDPSock, Data.c_str(), len, 0, (sockaddr*)&Addr, int(AddrSize)); if (sendOk == -1) { - debug("(UDP) sendto() failed: " + GetPlatformAgnosticErrorString()); + beammp_debug("(UDP) sendto() failed: " + GetPlatformAgnosticErrorString()); if (Client.GetStatus() > -1) Client.SetStatus(-1); return false; } else if (sendOk == 0) { - debug(("(UDP) sendto() returned 0")); + beammp_debug(("(UDP) sendto() returned 0")); if (Client.GetStatus() > -1) Client.SetStatus(-1); return false; @@ -922,7 +939,7 @@ std::string TNetwork::UDPRcvFromClient(sockaddr_in& client) const { #endif // WIN32 if (Rcv == -1) { - error("(UDP) Error receiving from client! recvfrom() failed: " + GetPlatformAgnosticErrorString()); + beammp_error("(UDP) Error receiving from client! recvfrom() failed: " + GetPlatformAgnosticErrorString()); return ""; } return std::string(Ret.begin(), Ret.begin() + Rcv); diff --git a/src/TSentry.cpp b/src/TSentry.cpp index 266c7e8..447392f 100644 --- a/src/TSentry.cpp +++ b/src/TSentry.cpp @@ -31,22 +31,22 @@ void TSentry::PrintWelcome() { if (!Application::Settings.SendErrors) { mValid = false; if (Application::Settings.SendErrorsMessageEnabled) { - info("Opted out of error reporting (SendErrors), Sentry disabled."); + beammp_info("Opted out of error reporting (SendErrors), Sentry disabled."); } else { - info("Sentry disabled"); + beammp_info("Sentry disabled"); } } else { if (Application::Settings.SendErrorsMessageEnabled) { - info("Sentry started! Reporting errors automatically. This sends data to the developers in case of errors and crashes. You can learn more, turn this message off or opt-out of this in the ServerConfig.toml."); + beammp_info("Sentry started! Reporting errors automatically. This sends data to the developers in case of errors and crashes. You can learn more, turn this message off or opt-out of this in the ServerConfig.toml."); } else { - info("Sentry started"); + beammp_info("Sentry started"); } } } else { if (Application::Settings.SendErrorsMessageEnabled) { - info("Sentry disabled in unofficial build. Automatic error reporting disabled."); + beammp_info("Sentry disabled in unofficial build. Automatic error reporting disabled."); } else { - info("Sentry disabled in unofficial build"); + beammp_info("Sentry disabled in unofficial build"); } } } diff --git a/src/TServer.cpp b/src/TServer.cpp index 147aa06..f2acee6 100644 --- a/src/TServer.cpp +++ b/src/TServer.cpp @@ -92,7 +92,7 @@ void TServer::GlobalParser(const std::weak_ptr& Client, std::string Pac } switch (Code) { case 'H': // initial connection - trace(std::string("got 'H' packet: '") + Packet + "' (" + std::to_string(Packet.size()) + ")"); + beammp_trace(std::string("got 'H' packet: '") + Packet + "' (" + std::to_string(Packet.size()) + ")"); beammp_debug(std::string("got 'H' packet: '") + Packet + "' (" + std::to_string(Packet.size()) + ")"); if (!Network.SyncClient(Client)) { // TODO handle @@ -115,12 +115,12 @@ void TServer::GlobalParser(const std::weak_ptr& Client, std::string Pac ParseVehicle(*LockedClient, Packet, Network); return; case 'J': - trace(std::string(("got 'J' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); + beammp_trace(std::string(("got 'J' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); beammp_debug(std::string(("got 'J' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); Network.SendToAll(LockedClient.get(), Packet, false, true); return; case 'C': { - trace(std::string(("got 'C' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); + beammp_trace(std::string(("got 'C' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); beammp_debug(std::string(("got 'C' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); if (Packet.length() < 4 || Packet.find(':', 3) == std::string::npos) break; @@ -139,12 +139,12 @@ void TServer::GlobalParser(const std::weak_ptr& Client, std::string Pac return; } case 'E': - trace(std::string(("got 'E' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); + beammp_trace(std::string(("got 'E' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); beammp_debug(std::string(("got 'E' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); HandleEvent(*LockedClient, Packet); return; case 'N': - trace("got 'N' packet (" + std::to_string(Packet.size()) + ")"); + beammp_trace("got 'N' packet (" + std::to_string(Packet.size()) + ")"); Network.SendToAll(LockedClient.get(), Packet, false, true); return; default: @@ -206,7 +206,7 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ std::string Data = Packet.substr(3), pid, vid; switch (Code) { //Spawned Destroyed Switched/Moved NotFound Reset case 's': - trace(std::string(("got 'Os' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); + beammp_trace(std::string(("got 'Os' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); if (Data.at(0) == '0') { int CarID = c.GetOpenCarID(); beammp_debug(c.GetName() + (" created a car with ID ") + std::to_string(CarID)); @@ -236,7 +236,7 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ } return; case 'c': - trace(std::string(("got 'Oc' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); + beammp_trace(std::string(("got 'Oc' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); pid = Data.substr(0, Data.find('-')); vid = Data.substr(Data.find('-') + 1, Data.find(':', 1) - Data.find('-') - 1); if (pid.find_first_not_of("0123456789") == std::string::npos && vid.find_first_not_of("0123456789") == std::string::npos) { @@ -270,7 +270,7 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ } return; case 'd': - trace(std::string(("got 'Od' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); + beammp_trace(std::string(("got 'Od' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); pid = Data.substr(0, Data.find('-')); vid = Data.substr(Data.find('-') + 1); if (pid.find_first_not_of("0123456789") == std::string::npos && vid.find_first_not_of("0123456789") == std::string::npos) { @@ -288,7 +288,7 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ } return; case 'r': - trace(std::string(("got 'Or' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); + beammp_trace(std::string(("got 'Or' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); Pos = int(Data.find('-')); pid = Data.substr(0, Pos++); vid = Data.substr(Pos, Data.find(':') - Pos); @@ -305,11 +305,11 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ } return; case 't': - trace(std::string(("got 'Ot' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); + beammp_trace(std::string(("got 'Ot' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); Network.SendToAll(&c, Packet, false, true); return; default: - trace(std::string(("possibly not implemented: '") + Packet + ("' (") + std::to_string(Packet.size()) + (")"))); + beammp_trace(std::string(("possibly not implemented: '") + Packet + ("' (") + std::to_string(Packet.size()) + (")"))); return; } } diff --git a/src/VehicleData.cpp b/src/VehicleData.cpp index d13bf68..00905fa 100644 --- a/src/VehicleData.cpp +++ b/src/VehicleData.cpp @@ -6,9 +6,9 @@ TVehicleData::TVehicleData(int ID, std::string Data) : mID(ID) , mData(std::move(Data)) { - trace("vehicle " + std::to_string(mID) + " constructed"); + beammp_trace("vehicle " + std::to_string(mID) + " constructed"); } TVehicleData::~TVehicleData() { - trace("vehicle " + std::to_string(mID) + " destroyed"); + beammp_trace("vehicle " + std::to_string(mID) + " destroyed"); } diff --git a/src/main.cpp b/src/main.cpp index 79c6003..5d2a092 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -48,7 +48,7 @@ int main(int argc, char** argv) try { RegisterThread("Main"); - trace("Running in debug mode on a debug build"); + beammp_trace("Running in debug mode on a debug build"); Sentry.SetupUser(); Sentry.PrintWelcome(); @@ -65,8 +65,8 @@ int main(int argc, char** argv) try { while (!Shutdown) { std::this_thread::sleep_for(std::chrono::milliseconds(50)); } - info("Shutdown."); + beammp_info("Shutdown."); } catch (const std::exception& e) { - error(e.what()); + beammp_error(e.what()); Sentry.LogException(e, _file_basename, _line); } From 11d4d9ff91e01ac9911de9dcdd952a4f62aebfea Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 17 Sep 2021 15:02:53 +0200 Subject: [PATCH 121/255] remove old commandline path --- include/commandline | 1 - 1 file changed, 1 deletion(-) delete mode 160000 include/commandline diff --git a/include/commandline b/include/commandline deleted file mode 160000 index 4931aa8..0000000 --- a/include/commandline +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 4931aa89c1b400732394d8b8523974ed09f427dc From 82a5fc39990ae93074dd69ab2858a226ed85435b Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 17 Sep 2021 15:06:13 +0200 Subject: [PATCH 122/255] Assert: Fix compiler error --- include/CustomAssert.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/CustomAssert.h b/include/CustomAssert.h index 96e52e8..5465651 100644 --- a/include/CustomAssert.h +++ b/include/CustomAssert.h @@ -59,7 +59,7 @@ inline void _assert([[maybe_unused]] const char* file, [[maybe_unused]] const ch #define beammp_assert_not_reachable() _assert(__FILE__, __func__, __LINE__, "reached unreachable code", false) #else // In release build, these macros turn into NOPs. The compiler will optimize these out. -#define beammp_assert(x) \ +#define beammp_assert(cond) \ do { \ bool result = (cond); \ if (!result) { \ From 3c7109b23f0a4836e0c752acd9a57556fa069dda Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 17 Sep 2021 15:21:06 +0200 Subject: [PATCH 123/255] Update Changelog, fix assert formatting --- Changelog.md | 13 +++++++++++++ include/CustomAssert.h | 4 ++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Changelog.md b/Changelog.md index f4df1f1..4526f1a 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,16 @@ +# v2.4.0 + +- CHANGED entire plugin Lua implementation (rewrite) +- CHANGED moved *all* functions into MP.\* +- CHANGED all files of a Lua plugin to share a Lua state +- ADDED `MP.GetOSName() -> string`: Returns "Linux", "Windows" or "Other" +- ADDED `MP.GetServerVersion() -> string`: Returns major,minor,patch version +- ADDED `MP.IsPlayerGuest(id) -> boolean`: Whether player with id is a guest +- ADDED `MP.Settings` table providing aliases for 0,1,2,etc. in MP.Set(id,val) +- ADDED plugin directories to `package.path` and `package.cpath` before `onInit` +- ADDED ability to add `PluginConfig.toml` to your plugin folder to change some settings +- ADDED ability to share a lua state with other plugins via `StateId` setting in `PluginConfig.toml` + # v2.3.3 - CHANGED servers to be private by default diff --git a/include/CustomAssert.h b/include/CustomAssert.h index 5465651..73179f0 100644 --- a/include/CustomAssert.h +++ b/include/CustomAssert.h @@ -59,14 +59,14 @@ inline void _assert([[maybe_unused]] const char* file, [[maybe_unused]] const ch #define beammp_assert_not_reachable() _assert(__FILE__, __func__, __LINE__, "reached unreachable code", false) #else // In release build, these macros turn into NOPs. The compiler will optimize these out. -#define beammp_assert(cond) \ +#define beammp_assert(cond) \ do { \ bool result = (cond); \ if (!result) { \ Sentry.LogAssert(#cond, _file_basename, _line, __func__); \ } \ } while (false) -#define beammp_assert_not_reachable() \ +#define beammp_assert_not_reachable() \ do { \ Sentry.LogAssert("code is unreachable", _file_basename, _line, __func__); \ } while (false) From 246f8289b68bd2ac89438a9c97fbcc325edc3a8f Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 17 Sep 2021 15:22:06 +0200 Subject: [PATCH 124/255] CMake: Fix compiler error with mismatching visibility of target_link_libraries --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4754864..bdcf042 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -133,7 +133,7 @@ elseif (WIN32) message(STATUS "Looking for RapidJSON") find_package(RapidJSON CONFIG REQUIRED) target_include_directories(BeamMP-Server PRIVATE ${RAPIDJSON_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}) - target_link_libraries(BeamMP-Server PRIVATE + target_link_libraries(BeamMP-Server ws2_32 ZLIB::ZLIB ${LUA_LIBRARIES} From be3ac45abb7b1ba8dcce42bc20b5266c46245f43 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 17 Sep 2021 15:30:30 +0200 Subject: [PATCH 125/255] add MP.HttpsGET, MP.HttpsPOST --- src/TLuaEngine.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 3421f5d..fbcb938 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -1,11 +1,13 @@ #include "TLuaEngine.h" #include "Client.h" #include "CustomAssert.h" +#include "Http.h" #include "LuaAPI.h" #include "TLuaPlugin.h" #include #include +#include static std::mt19937_64 MTGen64; @@ -307,8 +309,16 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi }); Table.set_function("Sleep", &LuaAPI::MP::Sleep); Table.set_function("Set", &LuaAPI::MP::Set); - //Table.set_function("HttpsGET", &LuaAPI::MP::HttpsGET); - //Table.set_function("HttpsPOST", &LuaAPI::MP::HttpsPOST); + Table.set_function("HttpsGET", [&](const std::string& Host, int Port, const std::string& Target) -> std::tuple { + unsigned Status; + auto Body = Http::GET(Host, Port, Target, &Status); + return { Status, Body }; + }); + Table.set_function("HttpsPOST", [&](const std::string& Host, int Port, const std::string& Target, const std::string& Body, const std::string& ContentType) -> std::tuple { + unsigned Status; + auto ResponseBody = Http::POST(Host, Port, Target, {}, Body, ContentType, &Status); + return { Status, ResponseBody }; + }); Table.create_named("Settings", "Debug", 0, "Private", 1, From e53f2d9877631a9708cf30b3ff9f29a1950e4532 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 17 Sep 2021 15:32:01 +0200 Subject: [PATCH 126/255] Changelog: Add MP.Https* documentation --- Changelog.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Changelog.md b/Changelog.md index 4526f1a..e54d460 100644 --- a/Changelog.md +++ b/Changelog.md @@ -10,6 +10,8 @@ - ADDED plugin directories to `package.path` and `package.cpath` before `onInit` - ADDED ability to add `PluginConfig.toml` to your plugin folder to change some settings - ADDED ability to share a lua state with other plugins via `StateId` setting in `PluginConfig.toml` +- ADDED `MP.HttpsGET(host,port,target) -> status,body`: Does a synchronous HTTPS GET request +- ADDED `MP.HttpsPOST(host,port,target,body,content_type) -> status,body`: Does a synchronous HTTPS POST request # v2.3.3 From 29a858e74a420270c7297ffabc6c16b91d457121 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 17 Sep 2021 15:33:16 +0200 Subject: [PATCH 127/255] Network: Fix TConnection related compiler issue --- src/TNetwork.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index a32d4e1..c31f334 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -158,7 +158,7 @@ void TNetwork::TCPServerMain() { CloseSocketProper(client.Socket); #ifdef WIN32 - CloseSocketProper(client); + CloseSocketProper(client.Socket); WSACleanup(); #endif // WIN32 } From f98ef7d41cf0bb634820b997985e7c497857b933 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sat, 18 Sep 2021 00:05:51 +0200 Subject: [PATCH 128/255] Lua: Call local eventhandlers synchronously when TriggerGlobalEvent is called from inside a handling state --- Changelog.md | 2 +- include/TLuaEngine.h | 11 +++++++---- src/LuaAPI.cpp | 3 +++ src/TLuaEngine.cpp | 39 +++++++++++++++++++++++++++++---------- src/TNetwork.cpp | 10 +++++----- src/TServer.cpp | 12 ++++++------ src/main.cpp | 2 +- 7 files changed, 52 insertions(+), 27 deletions(-) diff --git a/Changelog.md b/Changelog.md index e54d460..e764192 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,7 +2,7 @@ - CHANGED entire plugin Lua implementation (rewrite) - CHANGED moved *all* functions into MP.\* -- CHANGED all files of a Lua plugin to share a Lua state +- CHANGED all files of a Lua plugin to share a Lua state (no more state-per-file) - ADDED `MP.GetOSName() -> string`: Returns "Linux", "Windows" or "Other" - ADDED `MP.GetServerVersion() -> string`: Returns major,minor,patch version - ADDED `MP.IsPlayerGuest(id) -> boolean`: Whether player with id is a guest diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index 8251a05..569122b 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -60,7 +60,8 @@ public: void EnsureStateExists(TLuaStateId StateId, const std::string& Name, bool DontCallOnInit = false); void RegisterEvent(const std::string& EventName, TLuaStateId StateId, const std::string& FunctionName); template - [[nodiscard]] std::vector> TriggerEvent(const std::string& EventName, ArgsT&&... Args) { + [[nodiscard]] std::vector> TriggerEvent(const std::string& EventName, TLuaStateId IgnoreId, ArgsT&&... Args) { + beammp_info("TriggerEvent called from: "); std::unique_lock Lock(mEventsMutex); if (mEvents.find(EventName) == mEvents.end()) { return {}; @@ -69,7 +70,9 @@ public: for (const auto& Event : mEvents.at(EventName)) { for (const auto& Function : Event.second) { beammp_debug("TriggerEvent: triggering \"" + Function + "\" on \"" + Event.first + "\""); - Results.push_back(EnqueueFunctionCall(Event.first, Function, { std::forward(Args)... })); + if (Event.first != IgnoreId) { + Results.push_back(EnqueueFunctionCall(Event.first, Function, { std::forward(Args)... })); + } } } return Results; @@ -95,8 +98,8 @@ private: void operator()() override; private: - sol::table Lua_TriggerGlobalEvent(const std::string& EventName); - sol::table Lua_TriggerLocalEvent(const std::string& EventName); + sol::table Lua_TriggerGlobalEvent(const std::string& EventName, sol::variadic_args EventArgs); + sol::table Lua_TriggerLocalEvent(const std::string& EventName, sol::variadic_args EventArgs); sol::table Lua_GetPlayerIdentifiers(int ID); sol::table Lua_GetPlayers(); std::string Lua_GetPlayerName(int ID); diff --git a/src/LuaAPI.cpp b/src/LuaAPI.cpp index fbf34cc..2c8472a 100644 --- a/src/LuaAPI.cpp +++ b/src/LuaAPI.cpp @@ -3,6 +3,9 @@ #include "Common.h" #include "TLuaEngine.h" +#define SOL_ALL_SAFETIES_ON 1 +#include + static std::string LuaToString(const sol::object Value, size_t Indent = 1) { switch (Value.get_type()) { case sol::type::userdata: { diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index fbcb938..1ac0fe2 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -42,7 +42,7 @@ void TLuaEngine::operator()() { // lua engine main thread CollectAndInitPlugins(); // now call all onInit's - auto Futures = TriggerEvent("onInit"); + auto Futures = TriggerEvent("onInit", ""); WaitForAll(Futures); for (const auto& Future : Futures) { if (Future->Error && Future->ErrorMessage != BeamMPFnNotFoundError) { @@ -83,7 +83,7 @@ void TLuaEngine::CollectAndInitPlugins() { beammp_error("\"" + Dir.path().string() + "\" is not a directory, skipping"); } else { beammp_debug("found plugin directory: " + Path.string()); - TLuaPluginConfig Config { GenerateUniqueStateId() }; + TLuaPluginConfig Config { Path.string() }; FindAndParseConfig(Path, Config); InitializePlugin(Path, Config); } @@ -148,8 +148,26 @@ std::set TLuaEngine::GetEventHandlersForState(const std::string& Ev return mEvents[EventName][StateId]; } -sol::table TLuaEngine::StateThreadData::Lua_TriggerGlobalEvent(const std::string& EventName) { - auto Return = mEngine->TriggerEvent(EventName); +sol::table TLuaEngine::StateThreadData::Lua_TriggerGlobalEvent(const std::string& EventName, sol::variadic_args EventArgs) { + auto Return = mEngine->TriggerEvent(EventName, mStateId, EventArgs); + // TODO Synchronous call to the event handlers + auto MyHandlers = mEngine->GetEventHandlersForState(EventName, mStateId); + for (const auto& Handler : MyHandlers) { + auto Fn = mStateView[Handler]; + if (Fn.valid()) { + auto LuaResult = Fn(EventArgs); + auto Result = std::make_shared(); + Result->Ready = true; + if (LuaResult.valid()) { + Result->Error = false; + Result->Result = LuaResult; + } else { + Result->Error = true; + Result->ErrorMessage = "Function result in TriggerGlobalEvent was invalid"; + } + Return.push_back(Result); + } + } beammp_debug("Triggering event \"" + EventName + "\" in \"" + mStateId + "\""); sol::state_view StateView(mState); sol::table AsyncEventReturn = StateView.create_table(); @@ -180,12 +198,13 @@ sol::table TLuaEngine::StateThreadData::Lua_TriggerGlobalEvent(const std::string return AsyncEventReturn; } -sol::table TLuaEngine::StateThreadData::Lua_TriggerLocalEvent(const std::string& EventName) { +sol::table TLuaEngine::StateThreadData::Lua_TriggerLocalEvent(const std::string& EventName, sol::variadic_args EventArgs) { + // TODO: make asynchronous? sol::table Result = mStateView.create_table(); for (const auto& Handler : mEngine->GetEventHandlersForState(EventName, mStateId)) { auto Fn = mStateView[Handler]; if (Fn.valid() && Fn.get_type() == sol::type::function) { - Result.add(Fn()); + Result.add(Fn(EventArgs)); } } return Result; @@ -282,11 +301,11 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi Table.set_function("RegisterEvent", [this](const std::string& EventName, const std::string& FunctionName) { RegisterEvent(EventName, FunctionName); }); - Table.set_function("TriggerGlobalEvent", [&](const std::string& EventName) -> sol::table { - return Lua_TriggerGlobalEvent(EventName); + Table.set_function("TriggerGlobalEvent", [&](const std::string& EventName, sol::variadic_args EventArgs) -> sol::table { + return Lua_TriggerGlobalEvent(EventName, EventArgs); }); - Table.set_function("TriggerLocalEvent", [&](const std::string& EventName) -> sol::table { - return Lua_TriggerLocalEvent(EventName); + Table.set_function("TriggerLocalEvent", [&](const std::string& EventName, sol::variadic_args EventArgs) -> sol::table { + return Lua_TriggerLocalEvent(EventName, EventArgs); }); Table.set_function("TriggerClientEvent", &LuaAPI::MP::TriggerClientEvent); Table.set_function("GetPlayerCount", &LuaAPI::MP::GetPlayerCount); diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index c31f334..4c08fc6 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -307,7 +307,7 @@ void TNetwork::Authentication(const TConnection& ClientConnection) { return true; }); - auto Futures = LuaAPI::MP::Engine->TriggerEvent("onPlayerAuth", Client->GetName(), Client->GetRoles(), Client->IsGuest()); + auto Futures = LuaAPI::MP::Engine->TriggerEvent("onPlayerAuth", "", Client->GetName(), Client->GetRoles(), Client->IsGuest()); TLuaEngine::WaitForAll(Futures); bool NotAllowed = std::any_of(Futures.begin(), Futures.end(), [](const std::shared_ptr& Result) { @@ -570,7 +570,7 @@ void TNetwork::OnDisconnect(const std::weak_ptr& ClientPtr, bool kicked Packet = ("L") + c.GetName() + (" left the server!"); SendToAll(&c, Packet, false, true); Packet.clear(); - auto Futures = LuaAPI::MP::Engine->TriggerEvent("onPlayerDisconnect", c.GetID()); + auto Futures = LuaAPI::MP::Engine->TriggerEvent("onPlayerDisconnect", "", c.GetID()); beammp_ignore(Futures); if (c.GetTCPSock()) CloseSocketProper(c.GetTCPSock()); @@ -605,13 +605,13 @@ void TNetwork::OnConnect(const std::weak_ptr& c) { auto LockedClient = c.lock(); LockedClient->SetID(OpenID()); beammp_info("Assigned ID " + std::to_string(LockedClient->GetID()) + " to " + LockedClient->GetName()); - beammp_ignore(LuaAPI::MP::Engine->TriggerEvent("onPlayerConnecting", LockedClient->GetID())); + beammp_ignore(LuaAPI::MP::Engine->TriggerEvent("onPlayerConnecting", "", LockedClient->GetID())); SyncResources(*LockedClient); if (LockedClient->GetStatus() < 0) return; (void)Respond(*LockedClient, "M" + Application::Settings.MapName, true); //Send the Map on connect beammp_info(LockedClient->GetName() + " : Connected"); - beammp_ignore(LuaAPI::MP::Engine->TriggerEvent("onPlayerJoining", LockedClient->GetID())); + beammp_ignore(LuaAPI::MP::Engine->TriggerEvent("onPlayerJoining", "", LockedClient->GetID())); } void TNetwork::SyncResources(TClient& c) { @@ -810,7 +810,7 @@ bool TNetwork::SyncClient(const std::weak_ptr& c) { // ignore error (void)SendToAll(LockedClient.get(), ("JWelcome ") + LockedClient->GetName() + "!", false, true); - beammp_ignore(LuaAPI::MP::Engine->TriggerEvent("onPlayerJoin", LockedClient->GetID())); + beammp_ignore(LuaAPI::MP::Engine->TriggerEvent("onPlayerJoin", "", LockedClient->GetID())); LockedClient->SetIsSyncing(true); bool Return = false; bool res = true; diff --git a/src/TServer.cpp b/src/TServer.cpp index f2acee6..abf328a 100644 --- a/src/TServer.cpp +++ b/src/TServer.cpp @@ -124,7 +124,7 @@ void TServer::GlobalParser(const std::weak_ptr& Client, std::string Pac beammp_debug(std::string(("got 'C' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); if (Packet.length() < 4 || Packet.find(':', 3) == std::string::npos) break; - auto Futures = LuaAPI::MP::Engine->TriggerEvent("onChatMessage", LockedClient->GetID(), LockedClient->GetName(), Packet.substr(Packet.find(':', 3) + 1)); + auto Futures = LuaAPI::MP::Engine->TriggerEvent("onChatMessage", "", LockedClient->GetID(), LockedClient->GetName(), Packet.substr(Packet.find(':', 3) + 1)); TLuaEngine::WaitForAll(Futures); LogChatMessage(LockedClient->GetName(), LockedClient->GetID(), Packet.substr(Packet.find(':', 3) + 1)); // FIXME: this needs to be adjusted once lua is merged if (std::any_of(Futures.begin(), Futures.end(), @@ -162,7 +162,7 @@ void TServer::HandleEvent(TClient& c, const std::string& Data) { Name = t; break; case 2: - beammp_ignore(LuaAPI::MP::Engine->TriggerEvent(Name, c.GetID(), t)); + beammp_ignore(LuaAPI::MP::Engine->TriggerEvent(Name, "", c.GetID(), t)); break; default: break; @@ -213,7 +213,7 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ std::string CarJson = Packet.substr(5); Packet = "Os:" + c.GetRoles() + ":" + c.GetName() + ":" + std::to_string(c.GetID()) + "-" + std::to_string(CarID) + ":" + CarJson; - auto Futures = LuaAPI::MP::Engine->TriggerEvent("onVehicleSpawn", c.GetID(), CarID, Packet.substr(3)); + auto Futures = LuaAPI::MP::Engine->TriggerEvent("onVehicleSpawn", "", c.GetID(), CarID, Packet.substr(3)); TLuaEngine::WaitForAll(Futures); bool ShouldntSpawn = std::any_of(Futures.begin(), Futures.end(), [](const std::shared_ptr& Result) { @@ -244,7 +244,7 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ VID = stoi(vid); } if (PID != -1 && VID != -1 && PID == c.GetID()) { - auto Futures = LuaAPI::MP::Engine->TriggerEvent("onVehicleEdited", c.GetID(), VID, Packet.substr(3)); + auto Futures = LuaAPI::MP::Engine->TriggerEvent("onVehicleEdited", "", c.GetID(), VID, Packet.substr(3)); TLuaEngine::WaitForAll(Futures); bool ShouldntAllow = std::any_of(Futures.begin(), Futures.end(), [](const std::shared_ptr& Result) { @@ -282,7 +282,7 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ c.SetUnicycleID(-1); } Network.SendToAll(nullptr, Packet, true, true); - beammp_ignore(LuaAPI::MP::Engine->TriggerEvent("onVehicleDeleted", c.GetID(), VID)); + beammp_ignore(LuaAPI::MP::Engine->TriggerEvent("onVehicleDeleted", "", c.GetID(), VID)); c.DeleteCar(VID); beammp_debug(c.GetName() + (" deleted car with ID ") + std::to_string(VID)); } @@ -300,7 +300,7 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ if (PID != -1 && VID != -1 && PID == c.GetID()) { Data = Data.substr(Data.find('{')); - beammp_ignore(LuaAPI::MP::Engine->TriggerEvent("onVehicleReset", c.GetID(), VID, Data)); + beammp_ignore(LuaAPI::MP::Engine->TriggerEvent("onVehicleReset", "", c.GetID(), VID, Data)); Network.SendToAll(&c, Packet, false, true); } return; diff --git a/src/main.cpp b/src/main.cpp index 5d2a092..d8c5255 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -28,7 +28,7 @@ int main(int argc, char** argv) try { bool Shutdown = false; Application::RegisterShutdownHandler([&Shutdown] { Shutdown = true; }); Application::RegisterShutdownHandler([] { - auto Futures = LuaAPI::MP::Engine->TriggerEvent("onShutdown"); + auto Futures = LuaAPI::MP::Engine->TriggerEvent("onShutdown", ""); TLuaEngine::WaitForAll(Futures); }); From 38dffc5462c17ff0b935eb3173ea706f0c5d8dcd Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sat, 18 Sep 2021 01:20:26 +0200 Subject: [PATCH 129/255] Lua: Pass plugin path and filename to queue for later --- include/TLuaEngine.h | 12 +++++++++--- src/TConsole.cpp | 2 +- src/TLuaEngine.cpp | 6 +++--- src/TLuaPlugin.cpp | 2 +- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index 569122b..e21bfb1 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -39,6 +39,12 @@ struct TLuaPluginConfig { // TODO: Add execute list }; +struct TLuaChunk { + std::shared_ptr Content; + std::string FileName; + std::string PluginPath; +}; + class TLuaEngine : IThreaded { public: TLuaEngine(); @@ -55,7 +61,7 @@ public: void SetServer(TServer* Server) { mServer = Server; } static void WaitForAll(std::vector>& Results); - [[nodiscard]] std::shared_ptr EnqueueScript(TLuaStateId StateID, const std::shared_ptr& Script); + [[nodiscard]] std::shared_ptr EnqueueScript(TLuaStateId StateID, const TLuaChunk& Script); [[nodiscard]] std::shared_ptr EnqueueFunctionCall(TLuaStateId StateID, const std::string& FunctionName, const std::initializer_list& Args); void EnsureStateExists(TLuaStateId StateId, const std::string& Name, bool DontCallOnInit = false); void RegisterEvent(const std::string& EventName, TLuaStateId StateId, const std::string& FunctionName); @@ -91,7 +97,7 @@ private: StateThreadData(const std::string& Name, std::atomic_bool& Shutdown, TLuaStateId StateId, TLuaEngine& Engine); StateThreadData(const StateThreadData&) = delete; ~StateThreadData() noexcept { beammp_debug("\"" + mStateId + "\" destroyed"); } - [[nodiscard]] std::shared_ptr EnqueueScript(const std::shared_ptr& Script); + [[nodiscard]] std::shared_ptr EnqueueScript(const TLuaChunk& Script); [[nodiscard]] std::shared_ptr EnqueueFunctionCall(const std::string& FunctionName, const std::initializer_list& Args); void RegisterEvent(const std::string& EventName, const std::string& FunctionName); void AddPath(const fs::path& Path); // to be added to path and cpath @@ -110,7 +116,7 @@ private: TLuaStateId mStateId; lua_State* mState; std::thread mThread; - std::queue, std::shared_ptr>> mStateExecuteQueue; + std::queue>> mStateExecuteQueue; std::recursive_mutex mStateExecuteQueueMutex; std::queue, std::initializer_list>> mStateFunctionQueue; std::recursive_mutex mStateFunctionQueueMutex; diff --git a/src/TConsole.cpp b/src/TConsole.cpp index 841a76d..43834da 100644 --- a/src/TConsole.cpp +++ b/src/TConsole.cpp @@ -61,7 +61,7 @@ TConsole::TConsole() { if (!mLuaEngine) { beammp_info("Lua not started yet, please try again in a second"); } else { - auto Future = mLuaEngine->EnqueueScript(mStateId, std::make_shared(cmd)); + auto Future = mLuaEngine->EnqueueScript(mStateId, { std::make_shared(cmd), "", "" }); while (!Future->Ready) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); } diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 1ac0fe2..2d12e8b 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -63,7 +63,7 @@ void TLuaEngine::WaitForAll(std::vector>& Results) { } } -std::shared_ptr TLuaEngine::EnqueueScript(TLuaStateId StateID, const std::shared_ptr& Script) { +std::shared_ptr TLuaEngine::EnqueueScript(TLuaStateId StateID, const TLuaChunk& Script) { std::unique_lock Lock(mLuaStatesMutex); beammp_debug("enqueuing script into \"" + StateID + "\""); return mLuaStates.at(StateID)->EnqueueScript(Script); @@ -349,7 +349,7 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi Start(); } -std::shared_ptr TLuaEngine::StateThreadData::EnqueueScript(const std::shared_ptr& Script) { +std::shared_ptr TLuaEngine::StateThreadData::EnqueueScript(const TLuaChunk& Script) { beammp_debug("enqueuing script into \"" + mStateId + "\""); std::unique_lock Lock(mStateExecuteQueueMutex); auto Result = std::make_shared(); @@ -409,7 +409,7 @@ void TLuaEngine::StateThreadData::operator()() { beammp_debug("Running script"); sol::state_view StateView(mState); - auto Res = StateView.safe_script(*S.first, sol::script_pass_on_error); + auto Res = StateView.safe_script(*S.first.Content, sol::script_pass_on_error, S.first.FileName); S.second->Ready = true; if (Res.valid()) { S.second->Error = false; diff --git a/src/TLuaPlugin.cpp b/src/TLuaPlugin.cpp index e156b5a..f7b52c7 100644 --- a/src/TLuaPlugin.cpp +++ b/src/TLuaPlugin.cpp @@ -40,7 +40,7 @@ TLuaPlugin::TLuaPlugin(TLuaEngine& Engine, const TLuaPluginConfig& Config, const beammp_debug("Successfully read \"" + Entry.string() + "\" (" + std::to_string(NRead) + " Bytes)"); mFileContents[fs::relative(Entry).string()] = Contents; // Execute first time - auto Result = mEngine.EnqueueScript(mConfig.StateId, Contents); + auto Result = mEngine.EnqueueScript(mConfig.StateId, { Contents, Entry, MainFolder }); ResultsToCheck.emplace_back(Entry.string(), std::move(Result)); } else { beammp_error("Error while reading script file \"" + Entry.string() + "\". Did the file change while reading?"); From dd70e88e4c0e290492a128454404776393d4dd82 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sat, 18 Sep 2021 22:08:20 +0200 Subject: [PATCH 130/255] SignalHandling: ensure that a signal handler is present on compilation --- src/SignalHandling.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/SignalHandling.cpp b/src/SignalHandling.cpp index 7a7f971..f95c54e 100644 --- a/src/SignalHandling.cpp +++ b/src/SignalHandling.cpp @@ -48,18 +48,17 @@ BOOL WINAPI Win32CtrlC_Handler(DWORD CtrlType) { void SetupSignalHandlers() { // signal handlers for unix#include -#ifdef __unix - beammp_trace("registering handlers for SIGINT, SIGTERM, SIGPIPE"); +#if defined(__unix) || defined(__linux) + beammp_trace("registering handlers for signals"); signal(SIGPIPE, UnixSignalHandler); signal(SIGTERM, UnixSignalHandler); #ifndef DEBUG signal(SIGINT, UnixSignalHandler); #endif // DEBUG -#endif // __unix - - // signal handlers for win32 -#ifdef WIN32 +#elif defined(WIN32) beammp_trace("registering handlers for CTRL_*_EVENTs"); SetConsoleCtrlHandler(Win32CtrlC_Handler, TRUE); -#endif // WIN32 +#else +#error "Please implement necessary signals like Ctrl+C handling here" +#endif } From 1ff5107707fb00867b410e53b64edc151d686414 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sun, 19 Sep 2021 01:20:17 +0200 Subject: [PATCH 131/255] Lua: Add MP.PrintRaw --- include/LuaAPI.h | 1 + src/LuaAPI.cpp | 9 +++++++++ src/TLuaEngine.cpp | 8 +------- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/include/LuaAPI.h b/include/LuaAPI.h index 091de13..d18a27d 100644 --- a/include/LuaAPI.h +++ b/include/LuaAPI.h @@ -19,5 +19,6 @@ namespace MP { bool IsPlayerGuest(int ID); bool IsPlayerConnected(int ID); void Sleep(size_t Ms); + void PrintRaw(sol::variadic_args); } } diff --git a/src/LuaAPI.cpp b/src/LuaAPI.cpp index 2c8472a..e59860b 100644 --- a/src/LuaAPI.cpp +++ b/src/LuaAPI.cpp @@ -234,3 +234,12 @@ bool LuaAPI::MP::IsPlayerGuest(int ID) { return false; } } + +void LuaAPI::MP::PrintRaw(sol::variadic_args Args) { + std::string ToPrint = ""; + for (const auto& Arg : Args) { + ToPrint += LuaToString(static_cast(Arg)); + ToPrint += "\t"; + } + Application::Console().WriteRaw(ToPrint); +} diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 2d12e8b..0ac839d 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -9,13 +9,6 @@ #include #include -static std::mt19937_64 MTGen64; - -static TLuaStateId GenerateUniqueStateId() { - auto Time = std::chrono::high_resolution_clock::now().time_since_epoch(); - return std::to_string(MTGen64()) + std::to_string(std::chrono::duration_cast(Time).count()); -} - TLuaEngine* LuaAPI::MP::Engine; TLuaEngine::TLuaEngine() { @@ -327,6 +320,7 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi return Lua_GetPlayerIdentifiers(ID); }); Table.set_function("Sleep", &LuaAPI::MP::Sleep); + Table.set_function("PrintRaw", &LuaAPI::MP::PrintRaw); Table.set_function("Set", &LuaAPI::MP::Set); Table.set_function("HttpsGET", [&](const std::string& Host, int Port, const std::string& Target) -> std::tuple { unsigned Status; From da78d77e6c55cb03cd433cd9adfd3c5a824744f0 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sun, 19 Sep 2021 01:21:30 +0200 Subject: [PATCH 132/255] Changelog: add MP.PrintRaw --- Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog.md b/Changelog.md index e764192..127b9a0 100644 --- a/Changelog.md +++ b/Changelog.md @@ -7,6 +7,7 @@ - ADDED `MP.GetServerVersion() -> string`: Returns major,minor,patch version - ADDED `MP.IsPlayerGuest(id) -> boolean`: Whether player with id is a guest - ADDED `MP.Settings` table providing aliases for 0,1,2,etc. in MP.Set(id,val) +- ADDED `MP.PrintRaw` prints messages without `[TIME DATE] [LUA]` etc. - ADDED plugin directories to `package.path` and `package.cpath` before `onInit` - ADDED ability to add `PluginConfig.toml` to your plugin folder to change some settings - ADDED ability to share a lua state with other plugins via `StateId` setting in `PluginConfig.toml` From 7f63dd8d7d2c630bac83526d84ca188c3ba0fd50 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sun, 19 Sep 2021 01:28:26 +0200 Subject: [PATCH 133/255] Lua: Add FS, FS.CreateDirectory --- Changelog.md | 2 ++ src/TLuaEngine.cpp | 60 +++++++++++++++++++++++++++------------------- 2 files changed, 38 insertions(+), 24 deletions(-) diff --git a/Changelog.md b/Changelog.md index 127b9a0..bb845df 100644 --- a/Changelog.md +++ b/Changelog.md @@ -8,6 +8,8 @@ - ADDED `MP.IsPlayerGuest(id) -> boolean`: Whether player with id is a guest - ADDED `MP.Settings` table providing aliases for 0,1,2,etc. in MP.Set(id,val) - ADDED `MP.PrintRaw` prints messages without `[TIME DATE] [LUA]` etc. +- ADDED `FS` table to host some effective filesystem manipulation functions +- ADDED `FS.CreateDirectory(path) -> bool,string` creates the path's directory (all missing pieces) and returns whether it fails and why if it did - ADDED plugin directories to `package.path` and `package.cpath` before `onInit` - ADDED ability to add `PluginConfig.toml` to your plugin folder to change some settings - ADDED ability to share a lua state with other plugins via `StateId` setting in `PluginConfig.toml` diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 0ac839d..54cac6a 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -274,8 +274,9 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi // StateView.globals()["package"].get() StateView.set_function("print", &LuaAPI::Print); StateView.set_function("exit", &Application::GracefullyShutdown); - auto Table = StateView.create_named_table("MP"); - Table.set_function("CreateTimer", [&]() -> sol::table { + + auto MPTable = StateView.create_named_table("MP"); + MPTable.set_function("CreateTimer", [&]() -> sol::table { sol::state_view StateView(mState); sol::table Result = StateView.create_table(); Result["__StartTime"] = std::chrono::high_resolution_clock::now(); @@ -289,50 +290,50 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi }); return Result; }); - Table.set_function("GetOSName", &LuaAPI::MP::GetOSName); - Table.set_function("GetServerVersion", &LuaAPI::MP::GetServerVersion); - Table.set_function("RegisterEvent", [this](const std::string& EventName, const std::string& FunctionName) { + MPTable.set_function("GetOSName", &LuaAPI::MP::GetOSName); + MPTable.set_function("GetServerVersion", &LuaAPI::MP::GetServerVersion); + MPTable.set_function("RegisterEvent", [this](const std::string& EventName, const std::string& FunctionName) { RegisterEvent(EventName, FunctionName); }); - Table.set_function("TriggerGlobalEvent", [&](const std::string& EventName, sol::variadic_args EventArgs) -> sol::table { + MPTable.set_function("TriggerGlobalEvent", [&](const std::string& EventName, sol::variadic_args EventArgs) -> sol::table { return Lua_TriggerGlobalEvent(EventName, EventArgs); }); - Table.set_function("TriggerLocalEvent", [&](const std::string& EventName, sol::variadic_args EventArgs) -> sol::table { + MPTable.set_function("TriggerLocalEvent", [&](const std::string& EventName, sol::variadic_args EventArgs) -> sol::table { return Lua_TriggerLocalEvent(EventName, EventArgs); }); - Table.set_function("TriggerClientEvent", &LuaAPI::MP::TriggerClientEvent); - Table.set_function("GetPlayerCount", &LuaAPI::MP::GetPlayerCount); - Table.set_function("IsPlayerConnected", &LuaAPI::MP::IsPlayerConnected); - Table.set_function("GetPlayerName", [&](int ID) -> std::string { + MPTable.set_function("TriggerClientEvent", &LuaAPI::MP::TriggerClientEvent); + MPTable.set_function("GetPlayerCount", &LuaAPI::MP::GetPlayerCount); + MPTable.set_function("IsPlayerConnected", &LuaAPI::MP::IsPlayerConnected); + MPTable.set_function("GetPlayerName", [&](int ID) -> std::string { return Lua_GetPlayerName(ID); }); - Table.set_function("RemoveVehicle", &LuaAPI::MP::RemoveVehicle); - Table.set_function("GetPlayerVehicles", [&](int ID) -> sol::table { + MPTable.set_function("RemoveVehicle", &LuaAPI::MP::RemoveVehicle); + MPTable.set_function("GetPlayerVehicles", [&](int ID) -> sol::table { return Lua_GetPlayerVehicles(ID); }); - Table.set_function("SendChatMessage", &LuaAPI::MP::SendChatMessage); - Table.set_function("GetPlayers", [&]() -> sol::table { + MPTable.set_function("SendChatMessage", &LuaAPI::MP::SendChatMessage); + MPTable.set_function("GetPlayers", [&]() -> sol::table { return Lua_GetPlayers(); }); - Table.set_function("IsPlayerGuest", &LuaAPI::MP::IsPlayerGuest); - Table.set_function("DropPlayer", &LuaAPI::MP::DropPlayer); - Table.set_function("GetPlayerIdentifiers", [&](int ID) -> sol::table { + MPTable.set_function("IsPlayerGuest", &LuaAPI::MP::IsPlayerGuest); + MPTable.set_function("DropPlayer", &LuaAPI::MP::DropPlayer); + MPTable.set_function("GetPlayerIdentifiers", [&](int ID) -> sol::table { return Lua_GetPlayerIdentifiers(ID); }); - Table.set_function("Sleep", &LuaAPI::MP::Sleep); - Table.set_function("PrintRaw", &LuaAPI::MP::PrintRaw); - Table.set_function("Set", &LuaAPI::MP::Set); - Table.set_function("HttpsGET", [&](const std::string& Host, int Port, const std::string& Target) -> std::tuple { + MPTable.set_function("Sleep", &LuaAPI::MP::Sleep); + MPTable.set_function("PrintRaw", &LuaAPI::MP::PrintRaw); + MPTable.set_function("Set", &LuaAPI::MP::Set); + MPTable.set_function("HttpsGET", [&](const std::string& Host, int Port, const std::string& Target) -> std::tuple { unsigned Status; auto Body = Http::GET(Host, Port, Target, &Status); return { Status, Body }; }); - Table.set_function("HttpsPOST", [&](const std::string& Host, int Port, const std::string& Target, const std::string& Body, const std::string& ContentType) -> std::tuple { + MPTable.set_function("HttpsPOST", [&](const std::string& Host, int Port, const std::string& Target, const std::string& Body, const std::string& ContentType) -> std::tuple { unsigned Status; auto ResponseBody = Http::POST(Host, Port, Target, {}, Body, ContentType, &Status); return { Status, ResponseBody }; }); - Table.create_named("Settings", + MPTable.create_named("Settings", "Debug", 0, "Private", 1, "MaxCars", 2, @@ -340,6 +341,17 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi "Map", 4, "Name", 5, "Description", 6); + + auto FSTable = StateView.create_named_table("FS"); + FSTable.set_function("CreateDirectory", [&](const std::string& Path) -> std::pair { + std::error_code errc; + std::pair Result; + Result.first = fs::create_directories(Path, errc); + if (!Result.first) { + Result.second = errc.message(); + } + return Result; + }); Start(); } From 8419ca223409bf88a7dd99c6c028d807186c782c Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sun, 19 Sep 2021 01:32:30 +0200 Subject: [PATCH 134/255] possible windows compiler fix --- src/TLuaPlugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TLuaPlugin.cpp b/src/TLuaPlugin.cpp index f7b52c7..25561ef 100644 --- a/src/TLuaPlugin.cpp +++ b/src/TLuaPlugin.cpp @@ -40,7 +40,7 @@ TLuaPlugin::TLuaPlugin(TLuaEngine& Engine, const TLuaPluginConfig& Config, const beammp_debug("Successfully read \"" + Entry.string() + "\" (" + std::to_string(NRead) + " Bytes)"); mFileContents[fs::relative(Entry).string()] = Contents; // Execute first time - auto Result = mEngine.EnqueueScript(mConfig.StateId, { Contents, Entry, MainFolder }); + auto Result = mEngine.EnqueueScript(mConfig.StateId, TLuaChunk { Contents, Entry, MainFolder }); ResultsToCheck.emplace_back(Entry.string(), std::move(Result)); } else { beammp_error("Error while reading script file \"" + Entry.string() + "\". Did the file change while reading?"); From 7dbf8595295197b77730ca79a12c5641950bb352 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sun, 19 Sep 2021 11:45:58 +0200 Subject: [PATCH 135/255] Lua: Implement event arguments --- include/TLuaEngine.h | 13 +++++++++---- src/TLuaEngine.cpp | 36 ++++++++++++++++++++++++++++++------ 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index e21bfb1..6653492 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -19,6 +19,11 @@ using TLuaStateId = std::string; namespace fs = std::filesystem; +using TLuaArgTypes = std::variant; +static constexpr size_t TLuaArgTypes_String = 0; +static constexpr size_t TLuaArgTypes_Int = 1; +static constexpr size_t TLuaArgTypes_VariadicArgs = 2; +static constexpr size_t TLuaArgTypes_Bool = 3; class TLuaPlugin; @@ -62,7 +67,7 @@ public: static void WaitForAll(std::vector>& Results); [[nodiscard]] std::shared_ptr EnqueueScript(TLuaStateId StateID, const TLuaChunk& Script); - [[nodiscard]] std::shared_ptr EnqueueFunctionCall(TLuaStateId StateID, const std::string& FunctionName, const std::initializer_list& Args); + [[nodiscard]] std::shared_ptr EnqueueFunctionCall(TLuaStateId StateID, const std::string& FunctionName, const std::vector& Args); void EnsureStateExists(TLuaStateId StateId, const std::string& Name, bool DontCallOnInit = false); void RegisterEvent(const std::string& EventName, TLuaStateId StateId, const std::string& FunctionName); template @@ -77,7 +82,7 @@ public: for (const auto& Function : Event.second) { beammp_debug("TriggerEvent: triggering \"" + Function + "\" on \"" + Event.first + "\""); if (Event.first != IgnoreId) { - Results.push_back(EnqueueFunctionCall(Event.first, Function, { std::forward(Args)... })); + Results.push_back(EnqueueFunctionCall(Event.first, Function, { TLuaArgTypes { std::forward(Args) }... })); } } } @@ -98,7 +103,7 @@ private: StateThreadData(const StateThreadData&) = delete; ~StateThreadData() noexcept { beammp_debug("\"" + mStateId + "\" destroyed"); } [[nodiscard]] std::shared_ptr EnqueueScript(const TLuaChunk& Script); - [[nodiscard]] std::shared_ptr EnqueueFunctionCall(const std::string& FunctionName, const std::initializer_list& Args); + [[nodiscard]] std::shared_ptr EnqueueFunctionCall(const std::string& FunctionName, const std::vector& Args); void RegisterEvent(const std::string& EventName, const std::string& FunctionName); void AddPath(const fs::path& Path); // to be added to path and cpath void operator()() override; @@ -118,7 +123,7 @@ private: std::thread mThread; std::queue>> mStateExecuteQueue; std::recursive_mutex mStateExecuteQueueMutex; - std::queue, std::initializer_list>> mStateFunctionQueue; + std::queue, std::vector>> mStateFunctionQueue; std::recursive_mutex mStateFunctionQueueMutex; TLuaEngine* mEngine; sol::state_view mStateView { mState }; diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 54cac6a..c198de0 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -62,7 +62,7 @@ std::shared_ptr TLuaEngine::EnqueueScript(TLuaStateId StateID, const return mLuaStates.at(StateID)->EnqueueScript(Script); } -std::shared_ptr TLuaEngine::EnqueueFunctionCall(TLuaStateId StateID, const std::string& FunctionName, const std::initializer_list& Args) { +std::shared_ptr TLuaEngine::EnqueueFunctionCall(TLuaStateId StateID, const std::string& FunctionName, const std::vector& Args) { std::unique_lock Lock(mLuaStatesMutex); beammp_debug("calling \"" + FunctionName + "\" in \"" + StateID + "\""); return mLuaStates.at(StateID)->EnqueueFunctionCall(FunctionName, Args); @@ -346,7 +346,8 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi FSTable.set_function("CreateDirectory", [&](const std::string& Path) -> std::pair { std::error_code errc; std::pair Result; - Result.first = fs::create_directories(Path, errc); + fs::create_directories(Path, errc); + Result.first = errc == std::error_code {}; if (!Result.first) { Result.second = errc.message(); } @@ -363,7 +364,7 @@ std::shared_ptr TLuaEngine::StateThreadData::EnqueueScript(const TLu return Result; } -std::shared_ptr TLuaEngine::StateThreadData::EnqueueFunctionCall(const std::string& FunctionName, const std::initializer_list& Args) { +std::shared_ptr TLuaEngine::StateThreadData::EnqueueFunctionCall(const std::string& FunctionName, const std::vector& Args) { beammp_debug("calling \"" + FunctionName + "\" in \"" + mName + "\""); auto Result = std::make_shared(); Result->StateId = mStateId; @@ -430,19 +431,42 @@ void TLuaEngine::StateThreadData::operator()() { { // StateFunctionQueue Scope std::unique_lock Lock(mStateFunctionQueueMutex); if (!mStateFunctionQueue.empty()) { - auto FnNameResultPair = mStateFunctionQueue.front(); + auto FnNameResultPair = std::move(mStateFunctionQueue.front()); mStateFunctionQueue.pop(); Lock.unlock(); auto& StateId = std::get<0>(FnNameResultPair); auto& Result = std::get<1>(FnNameResultPair); - auto& Args = std::get<1>(FnNameResultPair); + auto Args = std::get<2>(FnNameResultPair); Result->StateId = mStateId; beammp_debug("Running function \"" + std::get<0>(FnNameResultPair) + "\""); sol::state_view StateView(mState); auto Fn = StateView[StateId]; beammp_debug("Done running function \"" + StateId + "\""); if (Fn.valid() && Fn.get_type() == sol::type::function) { - auto Res = Fn(Args); + std::vector LuaArgs; + for (const auto& Arg : Args) { + if (Arg.valueless_by_exception()) { + continue; + } + switch (Arg.index()) { + case TLuaArgTypes_String: + LuaArgs.push_back(sol::make_object(StateView, std::get(Arg))); + break; + case TLuaArgTypes_Int: + LuaArgs.push_back(sol::make_object(StateView, std::get(Arg))); + break; + case TLuaArgTypes_VariadicArgs: + LuaArgs.push_back(sol::make_object(StateView, std::get(Arg))); + break; + case TLuaArgTypes_Bool: + LuaArgs.push_back(sol::make_object(StateView, std::get(Arg))); + break; + default: + beammp_error("Unknown argument type, passed as nil"); + break; + } + } + auto Res = Fn(sol::as_args(LuaArgs)); if (Res.valid()) { Result->Error = false; Result->Result = std::move(Res); From 701e6139903fbd117a29d7a8c276658b80f53e95 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sun, 19 Sep 2021 12:10:38 +0200 Subject: [PATCH 136/255] Lua: Fix float printing Now prints 0, not 0.000000, etc. --- include/TLuaEngine.h | 1 - src/LuaAPI.cpp | 7 +++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index 6653492..f2bd809 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -72,7 +72,6 @@ public: void RegisterEvent(const std::string& EventName, TLuaStateId StateId, const std::string& FunctionName); template [[nodiscard]] std::vector> TriggerEvent(const std::string& EventName, TLuaStateId IgnoreId, ArgsT&&... Args) { - beammp_info("TriggerEvent called from: "); std::unique_lock Lock(mEventsMutex); if (mEvents.find(EventName) == mEvents.end()) { return {}; diff --git a/src/LuaAPI.cpp b/src/LuaAPI.cpp index e59860b..01f4db0 100644 --- a/src/LuaAPI.cpp +++ b/src/LuaAPI.cpp @@ -30,8 +30,11 @@ static std::string LuaToString(const sol::object Value, size_t Indent = 1) { } case sol::type::string: return Value.as(); - case sol::type::number: - return std::to_string(Value.as()); + case sol::type::number: { + std::stringstream ss; + ss << Value.as(); + return ss.str(); + } case sol::type::nil: case sol::type::none: return ""; From 60b86e2be6fb201843adfc0b9692814c4149b791 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sun, 19 Sep 2021 12:12:38 +0200 Subject: [PATCH 137/255] Create TLuaChunk constructor to satisfy MSVC --- include/TLuaEngine.h | 3 +++ src/TLuaEngine.cpp | 6 ++++++ src/TLuaPlugin.cpp | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index f2bd809..eb67c48 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -45,6 +45,9 @@ struct TLuaPluginConfig { }; struct TLuaChunk { + TLuaChunk(std::shared_ptr Content, + std::string FileName, + std::string PluginPath); std::shared_ptr Content; std::string FileName; std::string PluginPath; diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index c198de0..820a44e 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -497,3 +497,9 @@ void TLuaResult::WaitUntilReady() { std::this_thread::sleep_for(std::chrono::milliseconds(10)); } } + +TLuaChunk::TLuaChunk(std::shared_ptr Content, std::string FileName, std::string PluginPath) + : Content(Content) + , FileName(FileName) + , PluginPath(PluginPath) { +} diff --git a/src/TLuaPlugin.cpp b/src/TLuaPlugin.cpp index 25561ef..8661387 100644 --- a/src/TLuaPlugin.cpp +++ b/src/TLuaPlugin.cpp @@ -40,7 +40,7 @@ TLuaPlugin::TLuaPlugin(TLuaEngine& Engine, const TLuaPluginConfig& Config, const beammp_debug("Successfully read \"" + Entry.string() + "\" (" + std::to_string(NRead) + " Bytes)"); mFileContents[fs::relative(Entry).string()] = Contents; // Execute first time - auto Result = mEngine.EnqueueScript(mConfig.StateId, TLuaChunk { Contents, Entry, MainFolder }); + auto Result = mEngine.EnqueueScript(mConfig.StateId, TLuaChunk(Contents, Entry, MainFolder)); ResultsToCheck.emplace_back(Entry.string(), std::move(Result)); } else { beammp_error("Error while reading script file \"" + Entry.string() + "\". Did the file change while reading?"); From a4ff9488c5f22d47493e7b82cd040262f061547c Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sun, 19 Sep 2021 12:23:26 +0200 Subject: [PATCH 138/255] Satisfy MSVC's weird attraction to using `.string()` when its not necessary I cannot bear another minute of msvc, i swear --- src/TLuaPlugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TLuaPlugin.cpp b/src/TLuaPlugin.cpp index 8661387..d128e69 100644 --- a/src/TLuaPlugin.cpp +++ b/src/TLuaPlugin.cpp @@ -40,7 +40,7 @@ TLuaPlugin::TLuaPlugin(TLuaEngine& Engine, const TLuaPluginConfig& Config, const beammp_debug("Successfully read \"" + Entry.string() + "\" (" + std::to_string(NRead) + " Bytes)"); mFileContents[fs::relative(Entry).string()] = Contents; // Execute first time - auto Result = mEngine.EnqueueScript(mConfig.StateId, TLuaChunk(Contents, Entry, MainFolder)); + auto Result = mEngine.EnqueueScript(mConfig.StateId, TLuaChunk(Contents, Entry.string(), MainFolder)); ResultsToCheck.emplace_back(Entry.string(), std::move(Result)); } else { beammp_error("Error while reading script file \"" + Entry.string() + "\". Did the file change while reading?"); From 785b858651de6566d264a1f191b7398ca2bcc7a4 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sun, 19 Sep 2021 12:29:02 +0200 Subject: [PATCH 139/255] Same as last one yikes. --- src/TLuaPlugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TLuaPlugin.cpp b/src/TLuaPlugin.cpp index d128e69..d0631a9 100644 --- a/src/TLuaPlugin.cpp +++ b/src/TLuaPlugin.cpp @@ -40,7 +40,7 @@ TLuaPlugin::TLuaPlugin(TLuaEngine& Engine, const TLuaPluginConfig& Config, const beammp_debug("Successfully read \"" + Entry.string() + "\" (" + std::to_string(NRead) + " Bytes)"); mFileContents[fs::relative(Entry).string()] = Contents; // Execute first time - auto Result = mEngine.EnqueueScript(mConfig.StateId, TLuaChunk(Contents, Entry.string(), MainFolder)); + auto Result = mEngine.EnqueueScript(mConfig.StateId, TLuaChunk(Contents, Entry.string(), MainFolder.string())); ResultsToCheck.emplace_back(Entry.string(), std::move(Result)); } else { beammp_error("Error while reading script file \"" + Entry.string() + "\". Did the file change while reading?"); From 366a7dc9a6ced960a0d9d124be36b8acdd389e08 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sun, 19 Sep 2021 23:34:27 +0200 Subject: [PATCH 140/255] Lua: Add Lua panic handler --- include/LuaAPI.h | 2 ++ include/TLuaEngine.h | 2 ++ src/LuaAPI.cpp | 5 +++++ src/TLuaEngine.cpp | 20 +++++++++++++++++++- 4 files changed, 28 insertions(+), 1 deletion(-) diff --git a/include/LuaAPI.h b/include/LuaAPI.h index d18a27d..115d7ec 100644 --- a/include/LuaAPI.h +++ b/include/LuaAPI.h @@ -4,6 +4,8 @@ #include namespace LuaAPI { +int PanicHandler(lua_State* State); + void Print(sol::variadic_args); namespace MP { extern TLuaEngine* Engine; diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index eb67c48..360dc04 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -98,6 +98,7 @@ private: void CollectAndInitPlugins(); void InitializePlugin(const fs::path& Folder, const TLuaPluginConfig& Config); void FindAndParseConfig(const fs::path& Folder, TLuaPluginConfig& Config); + size_t CalculateMemoryUsage(); class StateThreadData : IThreaded { public: @@ -109,6 +110,7 @@ private: void RegisterEvent(const std::string& EventName, const std::string& FunctionName); void AddPath(const fs::path& Path); // to be added to path and cpath void operator()() override; + sol::state_view State() { return sol::state_view(mState); } private: sol::table Lua_TriggerGlobalEvent(const std::string& EventName, sol::variadic_args EventArgs); diff --git a/src/LuaAPI.cpp b/src/LuaAPI.cpp index 01f4db0..14cf22c 100644 --- a/src/LuaAPI.cpp +++ b/src/LuaAPI.cpp @@ -246,3 +246,8 @@ void LuaAPI::MP::PrintRaw(sol::variadic_args Args) { } Application::Console().WriteRaw(ToPrint); } + +int LuaAPI::PanicHandler(lua_State* State) { + beammp_lua_error("PANIC: " + sol::stack::get(State, 1)); + return 0; +} diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 820a44e..663f9b7 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -44,10 +44,20 @@ void TLuaEngine::operator()() { } // this thread handles timers while (!mShutdown) { - std::this_thread::sleep_for(std::chrono::milliseconds(10)); + std::this_thread::sleep_for(std::chrono::seconds(1)); + beammp_debug("Lua uses " + std::to_string(CalculateMemoryUsage()) + " B of memory"); } } +size_t TLuaEngine::CalculateMemoryUsage() { + size_t Usage = 0; + std::unique_lock Lock(mLuaStatesMutex); + for (auto& State : mLuaStates) { + Usage += State.second->State().memory_used(); + } + return Usage; +} + void TLuaEngine::WaitForAll(std::vector>& Results) { for (const auto& Result : Results) { while (!Result->Ready) { @@ -269,8 +279,13 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi , mStateId(StateId) , mState(luaL_newstate()) , mEngine(&Engine) { + if (!mState) { + beammp_error("failed to create lua state for \"" + StateId + "\""); + return; + } luaL_openlibs(mState); sol::state_view StateView(mState); + lua_atpanic(mState, LuaAPI::PanicHandler); // StateView.globals()["package"].get() StateView.set_function("print", &LuaAPI::Print); StateView.set_function("exit", &Application::GracefullyShutdown); @@ -317,6 +332,9 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi }); MPTable.set_function("IsPlayerGuest", &LuaAPI::MP::IsPlayerGuest); MPTable.set_function("DropPlayer", &LuaAPI::MP::DropPlayer); + MPTable.set_function("GetStateMemoryUsage", [&]() -> size_t { + return mStateView.memory_used(); + }); MPTable.set_function("GetPlayerIdentifiers", [&](int ID) -> sol::table { return Lua_GetPlayerIdentifiers(ID); }); From 4de80e0c7a7faa980d6e47f5937af282e0aae72f Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sun, 19 Sep 2021 23:51:22 +0200 Subject: [PATCH 141/255] Lua: Remove debug prints, add GetLuaMemoryUsage --- Changelog.md | 2 ++ include/TLuaEngine.h | 1 - src/TLuaEngine.cpp | 24 ++++++++++-------------- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/Changelog.md b/Changelog.md index bb845df..b2faea9 100644 --- a/Changelog.md +++ b/Changelog.md @@ -15,6 +15,8 @@ - ADDED ability to share a lua state with other plugins via `StateId` setting in `PluginConfig.toml` - ADDED `MP.HttpsGET(host,port,target) -> status,body`: Does a synchronous HTTPS GET request - ADDED `MP.HttpsPOST(host,port,target,body,content_type) -> status,body`: Does a synchronous HTTPS POST request +- ADDED `MP.GetStateMemoryUsage() -> number`: Current memory usage of the current state in bytes +- ADDED `MP.GetLuaMemoryUsage() -> number`: Current memory usage of all states combined, in bytes # v2.3.3 diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index 360dc04..4cdba0d 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -82,7 +82,6 @@ public: std::vector> Results; for (const auto& Event : mEvents.at(EventName)) { for (const auto& Function : Event.second) { - beammp_debug("TriggerEvent: triggering \"" + Function + "\" on \"" + Event.first + "\""); if (Event.first != IgnoreId) { Results.push_back(EnqueueFunctionCall(Event.first, Function, { TLuaArgTypes { std::forward(Args) }... })); } diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 663f9b7..73b7694 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -44,8 +44,7 @@ void TLuaEngine::operator()() { } // this thread handles timers while (!mShutdown) { - std::this_thread::sleep_for(std::chrono::seconds(1)); - beammp_debug("Lua uses " + std::to_string(CalculateMemoryUsage()) + " B of memory"); + std::this_thread::sleep_for(std::chrono::mi)); } } @@ -68,13 +67,11 @@ void TLuaEngine::WaitForAll(std::vector>& Results) { std::shared_ptr TLuaEngine::EnqueueScript(TLuaStateId StateID, const TLuaChunk& Script) { std::unique_lock Lock(mLuaStatesMutex); - beammp_debug("enqueuing script into \"" + StateID + "\""); return mLuaStates.at(StateID)->EnqueueScript(Script); } std::shared_ptr TLuaEngine::EnqueueFunctionCall(TLuaStateId StateID, const std::string& FunctionName, const std::vector& Args) { std::unique_lock Lock(mLuaStatesMutex); - beammp_debug("calling \"" + FunctionName + "\" in \"" + StateID + "\""); return mLuaStates.at(StateID)->EnqueueFunctionCall(FunctionName, Args); } @@ -85,7 +82,6 @@ void TLuaEngine::CollectAndInitPlugins() { if (!Dir.is_directory()) { beammp_error("\"" + Dir.path().string() + "\" is not a directory, skipping"); } else { - beammp_debug("found plugin directory: " + Path.string()); TLuaPluginConfig Config { Path.string() }; FindAndParseConfig(Path, Config); InitializePlugin(Path, Config); @@ -106,7 +102,6 @@ void TLuaEngine::InitializePlugin(const fs::path& Folder, const TLuaPluginConfig void TLuaEngine::FindAndParseConfig(const fs::path& Folder, TLuaPluginConfig& Config) { auto ConfigFile = Folder / TLuaPluginConfig::FileName; if (fs::exists(ConfigFile) && fs::is_regular_file(ConfigFile)) { - beammp_debug("\"" + ConfigFile.string() + "\" found"); try { auto Data = toml::parse(ConfigFile); if (Data.contains("LuaStateID")) { @@ -171,7 +166,6 @@ sol::table TLuaEngine::StateThreadData::Lua_TriggerGlobalEvent(const std::string Return.push_back(Result); } } - beammp_debug("Triggering event \"" + EventName + "\" in \"" + mStateId + "\""); sol::state_view StateView(mState); sol::table AsyncEventReturn = StateView.create_table(); AsyncEventReturn["ReturnValueImpl"] = Return; @@ -207,7 +201,12 @@ sol::table TLuaEngine::StateThreadData::Lua_TriggerLocalEvent(const std::string& for (const auto& Handler : mEngine->GetEventHandlersForState(EventName, mStateId)) { auto Fn = mStateView[Handler]; if (Fn.valid() && Fn.get_type() == sol::type::function) { - Result.add(Fn(EventArgs)); + auto FnRet = Fn(EventArgs); + if (FnRet.valid()) { + Result.add(FnRet); + } else { + beammp_lua_error(sol::error(FnRet).what()); + } } } return Result; @@ -335,6 +334,9 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi MPTable.set_function("GetStateMemoryUsage", [&]() -> size_t { return mStateView.memory_used(); }); + MPTable.set_function("GetLuaMemoryUsage", [&]() -> size_t { + return mEngine->CalculateMemoryUsage(); + }); MPTable.set_function("GetPlayerIdentifiers", [&](int ID) -> sol::table { return Lua_GetPlayerIdentifiers(ID); }); @@ -375,7 +377,6 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi } std::shared_ptr TLuaEngine::StateThreadData::EnqueueScript(const TLuaChunk& Script) { - beammp_debug("enqueuing script into \"" + mStateId + "\""); std::unique_lock Lock(mStateExecuteQueueMutex); auto Result = std::make_shared(); mStateExecuteQueue.push({ Script, Result }); @@ -383,7 +384,6 @@ std::shared_ptr TLuaEngine::StateThreadData::EnqueueScript(const TLu } std::shared_ptr TLuaEngine::StateThreadData::EnqueueFunctionCall(const std::string& FunctionName, const std::vector& Args) { - beammp_debug("calling \"" + FunctionName + "\" in \"" + mName + "\""); auto Result = std::make_shared(); Result->StateId = mStateId; Result->Function = FunctionName; @@ -431,8 +431,6 @@ void TLuaEngine::StateThreadData::operator()() { StateView.globals()["package"] = PackageTable; } } - - beammp_debug("Running script"); sol::state_view StateView(mState); auto Res = StateView.safe_script(*S.first.Content, sol::script_pass_on_error, S.first.FileName); S.second->Ready = true; @@ -456,10 +454,8 @@ void TLuaEngine::StateThreadData::operator()() { auto& Result = std::get<1>(FnNameResultPair); auto Args = std::get<2>(FnNameResultPair); Result->StateId = mStateId; - beammp_debug("Running function \"" + std::get<0>(FnNameResultPair) + "\""); sol::state_view StateView(mState); auto Fn = StateView[StateId]; - beammp_debug("Done running function \"" + StateId + "\""); if (Fn.valid() && Fn.get_type() == sol::type::function) { std::vector LuaArgs; for (const auto& Arg : Args) { From 6f9f790c5b3f4e300fb0a64618cd2848f6ee0e7a Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 20 Sep 2021 00:36:22 +0200 Subject: [PATCH 142/255] Lua: Add FS.Remove, FS.Rename (move), FS.Copy, FS.Exists --- include/LuaAPI.h | 7 ++++++ src/LuaAPI.cpp | 60 ++++++++++++++++++++++++++++++++++++++++++++++ src/TLuaEngine.cpp | 17 +++++-------- src/TLuaPlugin.cpp | 2 -- 4 files changed, 73 insertions(+), 13 deletions(-) diff --git a/include/LuaAPI.h b/include/LuaAPI.h index 115d7ec..2ec90c4 100644 --- a/include/LuaAPI.h +++ b/include/LuaAPI.h @@ -23,4 +23,11 @@ namespace MP { void Sleep(size_t Ms); void PrintRaw(sol::variadic_args); } +namespace FS { + std::pair CreateDirectory(const std::string& Path); + std::pair Remove(const std::string& Path); + std::pair Rename(const std::string& Path, const std::string& NewPath); + std::pair Copy(const std::string& Path, const std::string& NewPath); + bool Exists(const std::string& Path); +} } diff --git a/src/LuaAPI.cpp b/src/LuaAPI.cpp index 14cf22c..af02a59 100644 --- a/src/LuaAPI.cpp +++ b/src/LuaAPI.cpp @@ -251,3 +251,63 @@ int LuaAPI::PanicHandler(lua_State* State) { beammp_lua_error("PANIC: " + sol::stack::get(State, 1)); return 0; } + +template +static std::pair FSWrapper(FnT Fn, ArgsT&&... Args) { + std::error_code errc; + std::pair Result; + Fn(std::forward(Args)..., errc); + Result.first = errc == std::error_code {}; + if (!Result.first) { + Result.second = errc.message(); + } + return Result; +} + +std::pair LuaAPI::FS::CreateDirectory(const std::string& Path) { + std::error_code errc; + std::pair Result; + fs::create_directories(fs::relative(Path), errc); + Result.first = errc == std::error_code {}; + if (!Result.first) { + Result.second = errc.message(); + } + return Result; +} + +std::pair LuaAPI::FS::Remove(const std::string& Path) { + std::error_code errc; + std::pair Result; + fs::remove(fs::relative(Path), errc); + Result.first = errc == std::error_code {}; + if (!Result.first) { + Result.second = errc.message(); + } + return Result; +} + +std::pair LuaAPI::FS::Rename(const std::string& Path, const std::string& NewPath) { + std::error_code errc; + std::pair Result; + fs::rename(fs::relative(Path), fs::relative(NewPath), errc); + Result.first = errc == std::error_code {}; + if (!Result.first) { + Result.second = errc.message(); + } + return Result; +} + +std::pair LuaAPI::FS::Copy(const std::string& Path, const std::string& NewPath) { + std::error_code errc; + std::pair Result; + fs::copy(fs::relative(Path), fs::relative(NewPath), fs::copy_options::recursive, errc); + Result.first = errc == std::error_code {}; + if (!Result.first) { + Result.second = errc.message(); + } + return Result; +} + +bool LuaAPI::FS::Exists(const std::string& Path) { + return fs::exists(fs::relative(Path)); +} diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 73b7694..cae6563 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -44,7 +44,7 @@ void TLuaEngine::operator()() { } // this thread handles timers while (!mShutdown) { - std::this_thread::sleep_for(std::chrono::mi)); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); } } @@ -363,16 +363,11 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi "Description", 6); auto FSTable = StateView.create_named_table("FS"); - FSTable.set_function("CreateDirectory", [&](const std::string& Path) -> std::pair { - std::error_code errc; - std::pair Result; - fs::create_directories(Path, errc); - Result.first = errc == std::error_code {}; - if (!Result.first) { - Result.second = errc.message(); - } - return Result; - }); + FSTable.set_function("CreateDirectory", &LuaAPI::FS::CreateDirectory); + FSTable.set_function("Exists", &LuaAPI::FS::Exists); + FSTable.set_function("Remove", &LuaAPI::FS::Remove); + FSTable.set_function("Rename", &LuaAPI::FS::Rename); + FSTable.set_function("Copy", &LuaAPI::FS::Copy); Start(); } diff --git a/src/TLuaPlugin.cpp b/src/TLuaPlugin.cpp index d0631a9..ec5e176 100644 --- a/src/TLuaPlugin.cpp +++ b/src/TLuaPlugin.cpp @@ -14,7 +14,6 @@ TLuaPlugin::TLuaPlugin(TLuaEngine& Engine, const TLuaPluginConfig& Config, const std::vector Entries; for (const auto& Entry : fs::directory_iterator(mFolder)) { if (Entry.is_regular_file() && Entry.path().extension() == ".lua") { - beammp_debug("Found script \"" + Entry.path().string() + "\" in \"" + mFolder.string() + "\""); Entries.push_back(Entry); } } @@ -37,7 +36,6 @@ TLuaPlugin::TLuaPlugin(TLuaEngine& Engine, const TLuaPluginConfig& Config, const Contents->resize(Size); auto NRead = std::fread(Contents->data(), 1, Contents->size(), File); if (NRead == Contents->size()) { - beammp_debug("Successfully read \"" + Entry.string() + "\" (" + std::to_string(NRead) + " Bytes)"); mFileContents[fs::relative(Entry).string()] = Contents; // Execute first time auto Result = mEngine.EnqueueScript(mConfig.StateId, TLuaChunk(Contents, Entry.string(), MainFolder.string())); From 323184911d4958c31fb92fee9e77dd72ba892da0 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 20 Sep 2021 00:39:12 +0200 Subject: [PATCH 143/255] Add new FS functions to Changelog --- Changelog.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Changelog.md b/Changelog.md index b2faea9..0ee3158 100644 --- a/Changelog.md +++ b/Changelog.md @@ -7,9 +7,13 @@ - ADDED `MP.GetServerVersion() -> string`: Returns major,minor,patch version - ADDED `MP.IsPlayerGuest(id) -> boolean`: Whether player with id is a guest - ADDED `MP.Settings` table providing aliases for 0,1,2,etc. in MP.Set(id,val) -- ADDED `MP.PrintRaw` prints messages without `[TIME DATE] [LUA]` etc. +- ADDED `MP.PrintRaw(...)`: prints messages without `[TIME DATE] [LUA]` etc. - ADDED `FS` table to host some effective filesystem manipulation functions -- ADDED `FS.CreateDirectory(path) -> bool,string` creates the path's directory (all missing pieces) and returns whether it fails and why if it did +- ADDED `FS.CreateDirectory(path) -> bool,string`: Creates the path's directory (all missing pieces) and returns whether it fails and why if it did +- ADDED `FS.Exists(path) -> bool`: Whether the file exists +- ADDED `FS.Rename(old,new) -> bool,string`: Renames a file or folder (same as "move") +- ADDED `FS.Remove(path) -> bool,string`: Removes a file or (empty) folder +- ADDED `FS.Copy(original,copy) -> bool,string`: Copies a file or directory - ADDED plugin directories to `package.path` and `package.cpath` before `onInit` - ADDED ability to add `PluginConfig.toml` to your plugin folder to change some settings - ADDED ability to share a lua state with other plugins via `StateId` setting in `PluginConfig.toml` From a97791d4ee029a8202cee3521d4d7c11f3ce2a01 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 20 Sep 2021 00:46:13 +0200 Subject: [PATCH 144/255] Please MSVC stop being so bad --- src/TLuaEngine.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index cae6563..d58de2e 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -205,7 +205,8 @@ sol::table TLuaEngine::StateThreadData::Lua_TriggerLocalEvent(const std::string& if (FnRet.valid()) { Result.add(FnRet); } else { - beammp_lua_error(sol::error(FnRet).what()); + sol::error Err = FnRet; + beammp_lua_error(Err.what()); } } } From 4bf89706b43ef71d9eb3e4b71e7eb1f0da131a44 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 20 Sep 2021 12:43:00 +0300 Subject: [PATCH 145/255] Lua: Add MP.CreateTimedEvent as CreateThread replacement --- Changelog.md | 1 + include/TLuaEngine.h | 22 ++++++++++++++++----- src/TLuaEngine.cpp | 47 +++++++++++++++++++++++++++++++++++++++----- 3 files changed, 60 insertions(+), 10 deletions(-) diff --git a/Changelog.md b/Changelog.md index 0ee3158..f1a6bbc 100644 --- a/Changelog.md +++ b/Changelog.md @@ -21,6 +21,7 @@ - ADDED `MP.HttpsPOST(host,port,target,body,content_type) -> status,body`: Does a synchronous HTTPS POST request - ADDED `MP.GetStateMemoryUsage() -> number`: Current memory usage of the current state in bytes - ADDED `MP.GetLuaMemoryUsage() -> number`: Current memory usage of all states combined, in bytes +- ADDED `MP.CreateTimedEvent(event,interval_ms)`: Replacement for `CreateThread` - calls the event in the given interval # v2.3.3 diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index 4cdba0d..5fd60c9 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -75,12 +75,12 @@ public: void RegisterEvent(const std::string& EventName, TLuaStateId StateId, const std::string& FunctionName); template [[nodiscard]] std::vector> TriggerEvent(const std::string& EventName, TLuaStateId IgnoreId, ArgsT&&... Args) { - std::unique_lock Lock(mEventsMutex); - if (mEvents.find(EventName) == mEvents.end()) { + std::unique_lock Lock(mLuaEventsMutex); + if (mLuaEvents.find(EventName) == mLuaEvents.end()) { return {}; } std::vector> Results; - for (const auto& Event : mEvents.at(EventName)) { + for (const auto& Event : mLuaEvents.at(EventName)) { for (const auto& Function : Event.second) { if (Event.first != IgnoreId) { Results.push_back(EnqueueFunctionCall(Event.first, Function, { TLuaArgTypes { std::forward(Args) }... })); @@ -90,6 +90,7 @@ public: return Results; } std::set GetEventHandlersForState(const std::string& EventName, TLuaStateId StateId); + void CreateTimedEvent(const std::string& EventName, TLuaStateId StateId, size_t IntervalMS); static constexpr const char* BeamMPFnNotFoundError = "BEAMMP_FN_NOT_FOUND"; @@ -134,6 +135,15 @@ private: std::recursive_mutex mPathsMutex; }; + struct TimedEvent { + const std::chrono::high_resolution_clock::duration Duration {}; + std::chrono::high_resolution_clock::time_point LastCompletion { }; + std::string EventName; + TLuaStateId StateId; + bool Expired(); + void Reset(); + }; + TNetwork* mNetwork; TServer* mServer; std::atomic_bool mShutdown { false }; @@ -141,8 +151,10 @@ private: std::vector mLuaPlugins; std::unordered_map> mLuaStates; std::recursive_mutex mLuaStatesMutex; - std::unordered_map>> mEvents; - std::recursive_mutex mEventsMutex; + std::unordered_map>> mLuaEvents; + std::recursive_mutex mLuaEventsMutex; + std::vector mTimedEvents; + std::recursive_mutex mTimedEventsMutex; }; //std::any TriggerLuaEvent(const std::string& Event, bool local, TLuaPlugin* Caller, std::shared_ptr arg, bool Wait); diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index d58de2e..a2b400e 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -42,9 +42,23 @@ void TLuaEngine::operator()() { beammp_lua_error("Calling \"onInit\" on \"" + Future->StateId + "\" failed: " + Future->ErrorMessage); } } - // this thread handles timers + // event loop while (!mShutdown) { - std::this_thread::sleep_for(std::chrono::milliseconds(10)); + auto Before = std::chrono::high_resolution_clock::now(); + std::unique_lock Lock(mTimedEventsMutex); + for (auto& Timer : mTimedEvents) { + if (Timer.Expired()) { + Timer.Reset(); + std::unique_lock Lock2(mLuaStatesMutex); + beammp_ignore(mLuaStates[Timer.StateId]->EnqueueFunctionCall("TriggerLocalEvent", { Timer.EventName })); + } + } + // sleep for the remaining time to get to 1ms (our atom duration) + if (std::chrono::high_resolution_clock::duration Diff; + (Diff = Before - std::chrono::high_resolution_clock::now()) + < std::chrono::milliseconds(1)) { + std::this_thread::sleep_for(Diff); + } } } @@ -138,12 +152,12 @@ void TLuaEngine::EnsureStateExists(TLuaStateId StateId, const std::string& Name, } void TLuaEngine::RegisterEvent(const std::string& EventName, TLuaStateId StateId, const std::string& FunctionName) { - std::unique_lock Lock(mEventsMutex); - mEvents[EventName][StateId].insert(FunctionName); + std::unique_lock Lock(mLuaEventsMutex); + mLuaEvents[EventName][StateId].insert(FunctionName); } std::set TLuaEngine::GetEventHandlersForState(const std::string& EventName, TLuaStateId StateId) { - return mEvents[EventName][StateId]; + return mLuaEvents[EventName][StateId]; } sol::table TLuaEngine::StateThreadData::Lua_TriggerGlobalEvent(const std::string& EventName, sol::variadic_args EventArgs) { @@ -343,6 +357,9 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi }); MPTable.set_function("Sleep", &LuaAPI::MP::Sleep); MPTable.set_function("PrintRaw", &LuaAPI::MP::PrintRaw); + MPTable.set_function("CreateTimedEvent", [&](const std::string& EventName, size_t IntervalMS) { + mEngine->CreateTimedEvent(EventName, mStateId, IntervalMS); + }); MPTable.set_function("Set", &LuaAPI::MP::Set); MPTable.set_function("HttpsGET", [&](const std::string& Host, int Port, const std::string& Target) -> std::tuple { unsigned Status; @@ -497,6 +514,17 @@ void TLuaEngine::StateThreadData::operator()() { } } +void TLuaEngine::CreateTimedEvent(const std::string& EventName, TLuaStateId StateId, size_t IntervalMS) { + std::unique_lock Lock(mTimedEventsMutex); + TimedEvent Event { + std::chrono::high_resolution_clock::duration { std::chrono::milliseconds(IntervalMS) }, + std::chrono::high_resolution_clock::now(), + EventName, + StateId + }; + mTimedEvents.push_back(std::move(Event)); +} + void TLuaEngine::StateThreadData::AddPath(const fs::path& Path) { std::unique_lock Lock(mPathsMutex); mPaths.push(Path); @@ -513,3 +541,12 @@ TLuaChunk::TLuaChunk(std::shared_ptr Content, std::string FileName, , FileName(FileName) , PluginPath(PluginPath) { } + +bool TLuaEngine::TimedEvent::Expired() { + auto Waited = (std::chrono::high_resolution_clock::now() - LastCompletion); + return Waited < Duration; +} + +void TLuaEngine::TimedEvent::Reset() { + LastCompletion = std::chrono::high_resolution_clock::now(); +} From 3edb9322d4e340fb6a6bb406979bcb36690022ca Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 20 Sep 2021 13:39:14 +0300 Subject: [PATCH 146/255] Lua: Simple CreateEventTimer improvements --- Changelog.md | 2 +- include/TLuaEngine.h | 4 +-- src/TLuaEngine.cpp | 58 ++++++++++++++++++++++++++++++++++++-------- 3 files changed, 51 insertions(+), 13 deletions(-) diff --git a/Changelog.md b/Changelog.md index f1a6bbc..7138c71 100644 --- a/Changelog.md +++ b/Changelog.md @@ -21,7 +21,7 @@ - ADDED `MP.HttpsPOST(host,port,target,body,content_type) -> status,body`: Does a synchronous HTTPS POST request - ADDED `MP.GetStateMemoryUsage() -> number`: Current memory usage of the current state in bytes - ADDED `MP.GetLuaMemoryUsage() -> number`: Current memory usage of all states combined, in bytes -- ADDED `MP.CreateTimedEvent(event,interval_ms)`: Replacement for `CreateThread` - calls the event in the given interval +- ADDED `MP.CreateEventTimer(event,interval_ms)`: Replacement for `CreateThread` - calls the event in the given interval # v2.3.3 diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index 5fd60c9..545ae11 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -90,7 +90,7 @@ public: return Results; } std::set GetEventHandlersForState(const std::string& EventName, TLuaStateId StateId); - void CreateTimedEvent(const std::string& EventName, TLuaStateId StateId, size_t IntervalMS); + void CreateEventTimer(const std::string& EventName, TLuaStateId StateId, size_t IntervalMS); static constexpr const char* BeamMPFnNotFoundError = "BEAMMP_FN_NOT_FOUND"; @@ -137,7 +137,7 @@ private: struct TimedEvent { const std::chrono::high_resolution_clock::duration Duration {}; - std::chrono::high_resolution_clock::time_point LastCompletion { }; + std::chrono::high_resolution_clock::time_point LastCompletion {}; std::string EventName; TLuaStateId StateId; bool Expired(); diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index a2b400e..91f4286 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -6,7 +6,9 @@ #include "TLuaPlugin.h" #include +#include #include +#include #include TLuaEngine* LuaAPI::MP::Engine; @@ -42,22 +44,57 @@ void TLuaEngine::operator()() { beammp_lua_error("Calling \"onInit\" on \"" + Future->StateId + "\" failed: " + Future->ErrorMessage); } } + std::queue> ToTrigger; + std::mutex ToTriggerMutex; + std::condition_variable ToTriggerCond; + auto TriggerThread = [&] { + while (!mShutdown) { + std::unique_lock Lock(ToTriggerMutex); + ToTriggerCond.wait_for(Lock, std::chrono::milliseconds(10), [&ToTrigger] { return !ToTrigger.empty(); }); + auto Timer = ToTrigger.front(); + ToTrigger.pop(); + auto Handlers = GetEventHandlersForState(Timer.first, Timer.second); + for (auto& Handler : Handlers) { + beammp_ignore(mLuaStates[Timer.second]->EnqueueFunctionCall(Handler, {})); + } + } + }; + std::vector Threads; + Threads.resize(1); + for (auto& Elem : Threads) { + Elem = std::thread(TriggerThread); + } // event loop + auto Before = std::chrono::high_resolution_clock::now(); while (!mShutdown) { - auto Before = std::chrono::high_resolution_clock::now(); std::unique_lock Lock(mTimedEventsMutex); for (auto& Timer : mTimedEvents) { if (Timer.Expired()) { + if (Timer.EventName != "Asd") { + beammp_debug("\"" + Timer.EventName + "\" expired"); + } Timer.Reset(); - std::unique_lock Lock2(mLuaStatesMutex); - beammp_ignore(mLuaStates[Timer.StateId]->EnqueueFunctionCall("TriggerLocalEvent", { Timer.EventName })); + { + std::unique_lock Lock2(ToTriggerMutex); + ToTrigger.emplace(Timer.EventName, Timer.StateId); + } + ToTriggerCond.notify_one(); } } // sleep for the remaining time to get to 1ms (our atom duration) if (std::chrono::high_resolution_clock::duration Diff; - (Diff = Before - std::chrono::high_resolution_clock::now()) + (Diff = std::chrono::high_resolution_clock::now() - Before) < std::chrono::milliseconds(1)) { - std::this_thread::sleep_for(Diff); + // std::this_thread::sleep_for(Diff); + } else { + beammp_debug("Event loop cannot keep up! Currently using " + std::to_string(Threads.size()) + " threads, adding one"); + Threads.push_back(std::thread(TriggerThread)); + } + Before = std::chrono::high_resolution_clock::now(); + } + for (auto& Elem : Threads) { + if (Elem.joinable()) { + Elem.join(); } } } @@ -357,8 +394,8 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi }); MPTable.set_function("Sleep", &LuaAPI::MP::Sleep); MPTable.set_function("PrintRaw", &LuaAPI::MP::PrintRaw); - MPTable.set_function("CreateTimedEvent", [&](const std::string& EventName, size_t IntervalMS) { - mEngine->CreateTimedEvent(EventName, mStateId, IntervalMS); + MPTable.set_function("CreateEventTimer", [&](const std::string& EventName, size_t IntervalMS) { + mEngine->CreateEventTimer(EventName, mStateId, IntervalMS); }); MPTable.set_function("Set", &LuaAPI::MP::Set); MPTable.set_function("HttpsGET", [&](const std::string& Host, int Port, const std::string& Target) -> std::tuple { @@ -510,11 +547,11 @@ void TLuaEngine::StateThreadData::operator()() { } } } - std::this_thread::sleep_for(std::chrono::milliseconds(10)); + std::this_thread::sleep_for(std::chrono::microseconds(500)); } } -void TLuaEngine::CreateTimedEvent(const std::string& EventName, TLuaStateId StateId, size_t IntervalMS) { +void TLuaEngine::CreateEventTimer(const std::string& EventName, TLuaStateId StateId, size_t IntervalMS) { std::unique_lock Lock(mTimedEventsMutex); TimedEvent Event { std::chrono::high_resolution_clock::duration { std::chrono::milliseconds(IntervalMS) }, @@ -523,6 +560,7 @@ void TLuaEngine::CreateTimedEvent(const std::string& EventName, TLuaStateId Stat StateId }; mTimedEvents.push_back(std::move(Event)); + beammp_debug("created event timer for \"" + EventName + "\" on \"" + StateId + " with " + std::to_string(IntervalMS) + "ms interval"); } void TLuaEngine::StateThreadData::AddPath(const fs::path& Path) { @@ -544,7 +582,7 @@ TLuaChunk::TLuaChunk(std::shared_ptr Content, std::string FileName, bool TLuaEngine::TimedEvent::Expired() { auto Waited = (std::chrono::high_resolution_clock::now() - LastCompletion); - return Waited < Duration; + return Waited >= Duration; } void TLuaEngine::TimedEvent::Reset() { From 9efe352e7a45f2479a64414dd99fc703178c841d Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 20 Sep 2021 15:41:40 +0300 Subject: [PATCH 147/255] Lua: Working MP.CreateEventTimer --- CMakeLists.txt | 2 +- src/TLuaEngine.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bdcf042..d008a61 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,7 +40,7 @@ if (WIN32) elseif (UNIX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic -static-libstdc++") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0 -g") - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2 -gz -fno-builtin") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2 -g -fno-builtin") if (SANITIZE) message(STATUS "sanitize is ON") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined,thread") diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 91f4286..81d28c5 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -547,7 +547,7 @@ void TLuaEngine::StateThreadData::operator()() { } } } - std::this_thread::sleep_for(std::chrono::microseconds(500)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); } } From a3a18a3b56e30889694587470bf120b6d3345953 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 20 Sep 2021 16:09:17 +0200 Subject: [PATCH 148/255] Lua: Add CancelEventTimer --- Changelog.md | 1 + include/TLuaEngine.h | 5 ++- src/Common.cpp | 1 + src/TLuaEngine.cpp | 100 +++++++++++++++++++++++++++---------------- 4 files changed, 67 insertions(+), 40 deletions(-) diff --git a/Changelog.md b/Changelog.md index 7138c71..e5ace3e 100644 --- a/Changelog.md +++ b/Changelog.md @@ -22,6 +22,7 @@ - ADDED `MP.GetStateMemoryUsage() -> number`: Current memory usage of the current state in bytes - ADDED `MP.GetLuaMemoryUsage() -> number`: Current memory usage of all states combined, in bytes - ADDED `MP.CreateEventTimer(event,interval_ms)`: Replacement for `CreateThread` - calls the event in the given interval +- ADDED `MP.CancelEventTimer(event)`: Cancels all event timers for that event # v2.3.3 diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index 545ae11..9a69113 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -91,9 +91,10 @@ public: } std::set GetEventHandlersForState(const std::string& EventName, TLuaStateId StateId); void CreateEventTimer(const std::string& EventName, TLuaStateId StateId, size_t IntervalMS); + void CancelEventTimers(const std::string& EventName, TLuaStateId StateId); static constexpr const char* BeamMPFnNotFoundError = "BEAMMP_FN_NOT_FOUND"; - + private: void CollectAndInitPlugins(); void InitializePlugin(const fs::path& Folder, const TLuaPluginConfig& Config); @@ -136,7 +137,7 @@ private: }; struct TimedEvent { - const std::chrono::high_resolution_clock::duration Duration {}; + std::chrono::high_resolution_clock::duration Duration {}; std::chrono::high_resolution_clock::time_point LastCompletion {}; std::string EventName; TLuaStateId StateId; diff --git a/src/Common.cpp b/src/Common.cpp index d058de5..375b399 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -159,6 +159,7 @@ std::string ThreadName(bool DebugModeOverride) { } void RegisterThread(const std::string& str) { + beammp_info(str + " is " + std::to_string(gettid())); auto Lock = std::unique_lock(ThreadNameMapMutex); threadNameMap[std::this_thread::get_id()] = str; } diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 81d28c5..d6c8c81 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -44,58 +44,61 @@ void TLuaEngine::operator()() { beammp_lua_error("Calling \"onInit\" on \"" + Future->StateId + "\" failed: " + Future->ErrorMessage); } } - std::queue> ToTrigger; - std::mutex ToTriggerMutex; - std::condition_variable ToTriggerCond; - auto TriggerThread = [&] { + std::queue> ResultsToCheck; + std::recursive_mutex ResultsToCheckMutex; + std::thread ResultCheckThread([&] { while (!mShutdown) { - std::unique_lock Lock(ToTriggerMutex); - ToTriggerCond.wait_for(Lock, std::chrono::milliseconds(10), [&ToTrigger] { return !ToTrigger.empty(); }); - auto Timer = ToTrigger.front(); - ToTrigger.pop(); - auto Handlers = GetEventHandlersForState(Timer.first, Timer.second); - for (auto& Handler : Handlers) { - beammp_ignore(mLuaStates[Timer.second]->EnqueueFunctionCall(Handler, {})); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + std::unique_lock Lock(ResultsToCheckMutex); + if (!ResultsToCheck.empty()) { + auto Res = ResultsToCheck.front(); + ResultsToCheck.pop(); + Lock.unlock(); + + size_t Waited = 0; + while (!Res->Ready) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + Waited++; + if (Waited > 1000) { + beammp_lua_error(Res->Function + " in " + Res->StateId + " took >1s to respond, not printing possible errors"); + } + } + if (Res->Error) { + beammp_lua_error(Res->ErrorMessage); + } } } - }; - std::vector Threads; - Threads.resize(1); - for (auto& Elem : Threads) { - Elem = std::thread(TriggerThread); - } + }); // event loop auto Before = std::chrono::high_resolution_clock::now(); while (!mShutdown) { - std::unique_lock Lock(mTimedEventsMutex); - for (auto& Timer : mTimedEvents) { - if (Timer.Expired()) { - if (Timer.EventName != "Asd") { - beammp_debug("\"" + Timer.EventName + "\" expired"); + { // Timed Events Scope + std::unique_lock Lock(mTimedEventsMutex); + for (auto& Timer : mTimedEvents) { + if (Timer.Expired()) { + Timer.Reset(); + auto Handlers = GetEventHandlersForState(Timer.EventName, Timer.StateId); + std::unique_lock StateLock(mLuaStatesMutex); + std::unique_lock Lock2(ResultsToCheckMutex); + for (auto& Handler : Handlers) { + auto Res = mLuaStates[Timer.StateId]->EnqueueFunctionCall(Handler, {}); + ResultsToCheck.push(Res); + } } - Timer.Reset(); - { - std::unique_lock Lock2(ToTriggerMutex); - ToTrigger.emplace(Timer.EventName, Timer.StateId); - } - ToTriggerCond.notify_one(); } } // sleep for the remaining time to get to 1ms (our atom duration) if (std::chrono::high_resolution_clock::duration Diff; (Diff = std::chrono::high_resolution_clock::now() - Before) - < std::chrono::milliseconds(1)) { - // std::this_thread::sleep_for(Diff); + < std::chrono::milliseconds(10)) { + std::this_thread::sleep_for(Diff); } else { - beammp_debug("Event loop cannot keep up! Currently using " + std::to_string(Threads.size()) + " threads, adding one"); - Threads.push_back(std::thread(TriggerThread)); + beammp_debug("Event loop cannot keep up!"); } Before = std::chrono::high_resolution_clock::now(); } - for (auto& Elem : Threads) { - if (Elem.joinable()) { - Elem.join(); - } + if (ResultCheckThread.joinable()) { + ResultCheckThread.join(); } } @@ -395,8 +398,14 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi MPTable.set_function("Sleep", &LuaAPI::MP::Sleep); MPTable.set_function("PrintRaw", &LuaAPI::MP::PrintRaw); MPTable.set_function("CreateEventTimer", [&](const std::string& EventName, size_t IntervalMS) { + if (IntervalMS < 25) { + beammp_warn("Timer for \"" + EventName + "\" on \"" + mStateId + "\" is set to trigger at <25ms, which is likely too fast and won't cancel properly."); + } mEngine->CreateEventTimer(EventName, mStateId, IntervalMS); }); + MPTable.set_function("CancelEventTimer", [&](const std::string& EventName) { + mEngine->CancelEventTimers(EventName, mStateId); + }); MPTable.set_function("Set", &LuaAPI::MP::Set); MPTable.set_function("HttpsGET", [&](const std::string& Host, int Port, const std::string& Target) -> std::tuple { unsigned Status; @@ -547,7 +556,7 @@ void TLuaEngine::StateThreadData::operator()() { } } } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); } } @@ -560,7 +569,22 @@ void TLuaEngine::CreateEventTimer(const std::string& EventName, TLuaStateId Stat StateId }; mTimedEvents.push_back(std::move(Event)); - beammp_debug("created event timer for \"" + EventName + "\" on \"" + StateId + " with " + std::to_string(IntervalMS) + "ms interval"); + beammp_trace("created event timer for \"" + EventName + "\" on \"" + StateId + "\" with " + std::to_string(IntervalMS) + "ms interval"); +} + +void TLuaEngine::CancelEventTimers(const std::string& EventName, TLuaStateId StateId) { + std::unique_lock Lock(mTimedEventsMutex); + beammp_trace("cancelling event timer for \"" + EventName + "\" on \"" + StateId + "\""); + for (;;) { + auto Iter = std::find_if(mTimedEvents.begin(), mTimedEvents.end(), [&](const TimedEvent& Event) -> bool { + return Event.EventName == EventName && Event.StateId == StateId; + }); + if (Iter != mTimedEvents.end()) { + mTimedEvents.erase(Iter); + } else { + break; + } + } } void TLuaEngine::StateThreadData::AddPath(const fs::path& Path) { From 041db23a6973b20d7358c4be01ceaf88d7addb06 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 20 Sep 2021 16:23:38 +0200 Subject: [PATCH 149/255] Lua: info,debug -> trace --- src/Common.cpp | 2 +- src/TLuaEngine.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Common.cpp b/src/Common.cpp index 375b399..1fe02d6 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -159,7 +159,7 @@ std::string ThreadName(bool DebugModeOverride) { } void RegisterThread(const std::string& str) { - beammp_info(str + " is " + std::to_string(gettid())); + beammp_trace(str + " is " + std::to_string(gettid())); auto Lock = std::unique_lock(ThreadNameMapMutex); threadNameMap[std::this_thread::get_id()] = str; } diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index d6c8c81..6bfadca 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -93,7 +93,7 @@ void TLuaEngine::operator()() { < std::chrono::milliseconds(10)) { std::this_thread::sleep_for(Diff); } else { - beammp_debug("Event loop cannot keep up!"); + beammp_trace("Event loop cannot keep up!"); } Before = std::chrono::high_resolution_clock::now(); } From 238577a4f79963dd23d8f790068497802e18f6cd Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 20 Sep 2021 16:36:37 +0200 Subject: [PATCH 150/255] Remove debug symbols --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d008a61..a8be07c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,7 +40,7 @@ if (WIN32) elseif (UNIX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic -static-libstdc++") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0 -g") - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2 -g -fno-builtin") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2 -fno-builtin") if (SANITIZE) message(STATUS "sanitize is ON") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined,thread") From d84051bdd30937b638cb389bda81935ab873b6b6 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 20 Sep 2021 16:59:42 +0200 Subject: [PATCH 151/255] possible fix for windows path issue --- src/TConfig.cpp | 1 + src/TLuaPlugin.cpp | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/TConfig.cpp b/src/TConfig.cpp index b5313a9..8e014f5 100644 --- a/src/TConfig.cpp +++ b/src/TConfig.cpp @@ -107,6 +107,7 @@ void TConfig::CreateConfigFile(std::string_view name) { beammp_error("There was no \"" + std::string(ConfigFileName) + "\" file (this is normal for the first time running the server), so one was generated for you. It was automatically filled with the settings from your Server.cfg, if you have one. Please open ServerConfig.toml and ensure your AuthKey and other settings are filled in and correct, then restart the server. The old Server.cfg file will no longer be used and causes a warning if it exists from now on."); mFailed = true; ofs.close(); + // FIXME WriteSendErrors(std::string(name)); } else { beammp_error("Couldn't create " + std::string(name) + ". Check permissions, try again, and contact support if it continues not to work."); diff --git a/src/TLuaPlugin.cpp b/src/TLuaPlugin.cpp index ec5e176..f8826de 100644 --- a/src/TLuaPlugin.cpp +++ b/src/TLuaPlugin.cpp @@ -28,8 +28,12 @@ TLuaPlugin::TLuaPlugin(TLuaEngine& Engine, const TLuaPluginConfig& Config, const }); std::vector>> ResultsToCheck; for (const auto& Entry : Entries) { - // read in entire file +// read in entire file +#if defined(WIN32) + std::FILE* File = _wfopen(reinterpret_cast(Entry.c_str()), "r"); +#else std::FILE* File = std::fopen(reinterpret_cast(Entry.c_str()), "r"); +#endif if (File) { auto Size = std::filesystem::file_size(Entry); auto Contents = std::make_shared(); From d7a4322313d1dd0425739039136b059d16bf7ed6 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 20 Sep 2021 17:00:30 +0200 Subject: [PATCH 152/255] More windows fixes --- src/TLuaPlugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TLuaPlugin.cpp b/src/TLuaPlugin.cpp index f8826de..445c166 100644 --- a/src/TLuaPlugin.cpp +++ b/src/TLuaPlugin.cpp @@ -30,7 +30,7 @@ TLuaPlugin::TLuaPlugin(TLuaEngine& Engine, const TLuaPluginConfig& Config, const for (const auto& Entry : Entries) { // read in entire file #if defined(WIN32) - std::FILE* File = _wfopen(reinterpret_cast(Entry.c_str()), "r"); + std::FILE* File = _wfopen(reinterpret_cast(Entry.c_str()), "r"); #else std::FILE* File = std::fopen(reinterpret_cast(Entry.c_str()), "r"); #endif From 3626f4108e203ece1bfa808079c308ce58982e71 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 20 Sep 2021 17:05:28 +0200 Subject: [PATCH 153/255] Use filestreams instead of c-lib --- src/TLuaPlugin.cpp | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/src/TLuaPlugin.cpp b/src/TLuaPlugin.cpp index 445c166..931ac9c 100644 --- a/src/TLuaPlugin.cpp +++ b/src/TLuaPlugin.cpp @@ -28,28 +28,19 @@ TLuaPlugin::TLuaPlugin(TLuaEngine& Engine, const TLuaPluginConfig& Config, const }); std::vector>> ResultsToCheck; for (const auto& Entry : Entries) { -// read in entire file -#if defined(WIN32) - std::FILE* File = _wfopen(reinterpret_cast(Entry.c_str()), "r"); -#else - std::FILE* File = std::fopen(reinterpret_cast(Entry.c_str()), "r"); -#endif - if (File) { + // read in entire file + try { + std::ifstream FileStream(Entry.string()); auto Size = std::filesystem::file_size(Entry); auto Contents = std::make_shared(); Contents->resize(Size); - auto NRead = std::fread(Contents->data(), 1, Contents->size(), File); - if (NRead == Contents->size()) { - mFileContents[fs::relative(Entry).string()] = Contents; - // Execute first time - auto Result = mEngine.EnqueueScript(mConfig.StateId, TLuaChunk(Contents, Entry.string(), MainFolder.string())); - ResultsToCheck.emplace_back(Entry.string(), std::move(Result)); - } else { - beammp_error("Error while reading script file \"" + Entry.string() + "\". Did the file change while reading?"); - } - std::fclose(File); - } else { - beammp_error("Could not read script file \"" + Entry.string() + "\": " + std::strerror(errno)); + FileStream.rdbuf()->sgetn(Contents->data(), Contents->size()); + mFileContents[fs::relative(Entry).string()] = Contents; + // Execute first time + auto Result = mEngine.EnqueueScript(mConfig.StateId, TLuaChunk(Contents, Entry.string(), MainFolder.string())); + ResultsToCheck.emplace_back(Entry.string(), std::move(Result)); + } catch (const std::exception& e) { + beammp_error("Error loading file \"" + Entry.string() + "\": " + e.what()); } } for (auto& Result : ResultsToCheck) { From 32756ccc4a96a0fb85159a563db38fb3f16f82bc Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 20 Sep 2021 17:19:38 +0200 Subject: [PATCH 154/255] Use read instead of ifstream rdbuf --- src/TLuaPlugin.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/TLuaPlugin.cpp b/src/TLuaPlugin.cpp index 931ac9c..cbaa25c 100644 --- a/src/TLuaPlugin.cpp +++ b/src/TLuaPlugin.cpp @@ -30,11 +30,11 @@ TLuaPlugin::TLuaPlugin(TLuaEngine& Engine, const TLuaPluginConfig& Config, const for (const auto& Entry : Entries) { // read in entire file try { - std::ifstream FileStream(Entry.string()); + std::ifstream FileStream(Entry.string(), std::ios::in | std::ios::binary); auto Size = std::filesystem::file_size(Entry); auto Contents = std::make_shared(); Contents->resize(Size); - FileStream.rdbuf()->sgetn(Contents->data(), Contents->size()); + FileStream.read(Contents->data(), Contents->size()); mFileContents[fs::relative(Entry).string()] = Contents; // Execute first time auto Result = mEngine.EnqueueScript(mConfig.StateId, TLuaChunk(Contents, Entry.string(), MainFolder.string())); From 27b5c6d8501fdfc18f018298fc671b7320a19755 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 20 Sep 2021 22:45:12 +0200 Subject: [PATCH 155/255] Add GetFilename, GetExtension, --- include/LuaAPI.h | 2 ++ include/TLuaEngine.h | 18 +++++++++- include/TLuaPlugin.h | 1 + src/LuaAPI.cpp | 8 +++++ src/TLuaEngine.cpp | 83 +++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 110 insertions(+), 2 deletions(-) diff --git a/include/LuaAPI.h b/include/LuaAPI.h index 2ec90c4..f825149 100644 --- a/include/LuaAPI.h +++ b/include/LuaAPI.h @@ -28,6 +28,8 @@ namespace FS { std::pair Remove(const std::string& Path); std::pair Rename(const std::string& Path, const std::string& NewPath); std::pair Copy(const std::string& Path, const std::string& NewPath); + std::string GetFilename(const std::string& Path); + std::string GetExtension(const std::string& Path); bool Exists(const std::string& Path); } } diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index 9a69113..e6bd085 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -53,6 +53,19 @@ struct TLuaChunk { std::string PluginPath; }; +class TPluginMonitor : IThreaded { +public: + TPluginMonitor(const fs::path& Path, TLuaEngine& Engine, std::atomic_bool& Shutdown); + + void operator()(); + +private: + TLuaEngine& mEngine; + fs::path mPath; + std::atomic_bool& mShutdown; + std::unordered_map mFileTimes; +}; + class TLuaEngine : IThreaded { public: TLuaEngine(); @@ -92,9 +105,11 @@ public: std::set GetEventHandlersForState(const std::string& EventName, TLuaStateId StateId); void CreateEventTimer(const std::string& EventName, TLuaStateId StateId, size_t IntervalMS); void CancelEventTimers(const std::string& EventName, TLuaStateId StateId); + sol::state_view GetStateForPlugin(const fs::path& PluginPath); + TLuaStateId GetStateIDForPlugin(const fs::path& PluginPath); static constexpr const char* BeamMPFnNotFoundError = "BEAMMP_FN_NOT_FOUND"; - + private: void CollectAndInitPlugins(); void InitializePlugin(const fs::path& Folder, const TLuaPluginConfig& Config); @@ -147,6 +162,7 @@ private: TNetwork* mNetwork; TServer* mServer; + TPluginMonitor mPluginMonitor; std::atomic_bool mShutdown { false }; fs::path mResourceServerPath; std::vector mLuaPlugins; diff --git a/include/TLuaPlugin.h b/include/TLuaPlugin.h index a4cb5bd..92d54b9 100644 --- a/include/TLuaPlugin.h +++ b/include/TLuaPlugin.h @@ -8,6 +8,7 @@ public: ~TLuaPlugin() noexcept = default; const TLuaPluginConfig& GetConfig() const { return mConfig; } + fs::path GetFolder() const { return mFolder; } private: TLuaPluginConfig mConfig; diff --git a/src/LuaAPI.cpp b/src/LuaAPI.cpp index af02a59..cfd27cc 100644 --- a/src/LuaAPI.cpp +++ b/src/LuaAPI.cpp @@ -311,3 +311,11 @@ std::pair LuaAPI::FS::Copy(const std::string& Path, const std bool LuaAPI::FS::Exists(const std::string& Path) { return fs::exists(fs::relative(Path)); } + +std::string LuaAPI::FS::GetFilename(const std::string& Path) { + return fs::path(Path).filename().string(); +} + +std::string LuaAPI::FS::GetExtension(const std::string& Path) { + return fs::path(Path).extension().string(); +} diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 6bfadca..bc49d68 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -13,7 +13,8 @@ TLuaEngine* LuaAPI::MP::Engine; -TLuaEngine::TLuaEngine() { +TLuaEngine::TLuaEngine() + : mPluginMonitor(fs::path(Application::Settings.Resource) / "Server", *this, mShutdown) { LuaAPI::MP::Engine = this; if (!fs::exists(Application::Settings.Resource)) { fs::create_directory(Application::Settings.Resource); @@ -111,6 +112,28 @@ size_t TLuaEngine::CalculateMemoryUsage() { return Usage; } +sol::state_view TLuaEngine::GetStateForPlugin(const fs::path& PluginPath) { + for (const auto& Plugin : mLuaPlugins) { + if (fs::equivalent(Plugin->GetFolder(), PluginPath)) { + std::unique_lock Lock(mLuaStatesMutex); + return mLuaStates.at(Plugin->GetConfig().StateId)->State(); + } + } + beammp_assert_not_reachable(); + return mLuaStates.begin()->second->State(); +} + +TLuaStateId TLuaEngine::GetStateIDForPlugin(const fs::path& PluginPath) { + for (const auto& Plugin : mLuaPlugins) { + if (fs::equivalent(Plugin->GetFolder(), PluginPath)) { + std::unique_lock Lock(mLuaStatesMutex); + return Plugin->GetConfig().StateId; + } + } + beammp_assert_not_reachable(); + return ""; +} + void TLuaEngine::WaitForAll(std::vector>& Results) { for (const auto& Result : Results) { while (!Result->Ready) { @@ -432,6 +455,8 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi FSTable.set_function("Remove", &LuaAPI::FS::Remove); FSTable.set_function("Rename", &LuaAPI::FS::Rename); FSTable.set_function("Copy", &LuaAPI::FS::Copy); + FSTable.set_function("GetFilename", &LuaAPI::FS::GetFilename); + FSTable.set_function("GetExtension", &LuaAPI::FS::GetExtension); Start(); } @@ -612,3 +637,59 @@ bool TLuaEngine::TimedEvent::Expired() { void TLuaEngine::TimedEvent::Reset() { LastCompletion = std::chrono::high_resolution_clock::now(); } + +TPluginMonitor::TPluginMonitor(const fs::path& Path, TLuaEngine& Engine, std::atomic_bool& Shutdown) + : mEngine(Engine) + , mPath(Path) + , mShutdown(Shutdown) { + for (const auto& Entry : fs::recursive_directory_iterator(mPath)) { + // TODO: trigger an event when a subfolder file changes + if (Entry.is_regular_file()) { + mFileTimes[Entry.path().string()] = fs::last_write_time(Entry.path()); + } + } + Start(); +} + +void TPluginMonitor::operator()() { + RegisterThread("PluginMonitor"); + beammp_info("PluginMonitor started"); + while (!mShutdown) { + std::this_thread::sleep_for(std::chrono::seconds(3)); + for (const auto& Pair : mFileTimes) { + auto CurrentTime = fs::last_write_time(Pair.first); + if (CurrentTime != Pair.second) { + mFileTimes[Pair.first] = CurrentTime; + if (fs::path(Pair.first)) { + beammp_info("File \"" + Pair.first + "\" changed, reloading"); + // is in root folder, so reload + std::ifstream FileStream(Pair.first, std::ios::in | std::ios::binary); + auto Size = std::filesystem::file_size(Pair.first); + auto Contents = std::make_shared(); + Contents->resize(Size); + FileStream.read(Contents->data(), Contents->size()); + TLuaChunk Chunk(Contents, Pair.first, fs::path(Pair.first).parent_path().string()); + auto StateID = mEngine.GetStateIDForPlugin(fs::path(Pair.first).parent_path()); + auto Res = mEngine.EnqueueScript(StateID, Chunk); + while (!Res->Ready) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + if (Res->Error) { + beammp_lua_error(Res->ErrorMessage); + } + } else { + beammp_trace("Change detected in file \"" + Pair.first + "\", event trigger not implemented yet"); + /* + // is in subfolder, dont reload, just trigger an event + auto Results = mEngine.TriggerEvent("onFileChanged", "", Pair.first); + mEngine.WaitForAll(Results); + for (const auto& Result : Results) { + if (Result->Error) { + beammp_lua_error(Result->ErrorMessage); + } + }*/ + } + } + } + } +} From 908f67a799af3566e9bcf6119ecb38a9fa7067a7 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 20 Sep 2021 23:40:28 +0200 Subject: [PATCH 156/255] Fix compile error --- src/TLuaEngine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index bc49d68..b890541 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -660,7 +660,7 @@ void TPluginMonitor::operator()() { auto CurrentTime = fs::last_write_time(Pair.first); if (CurrentTime != Pair.second) { mFileTimes[Pair.first] = CurrentTime; - if (fs::path(Pair.first)) { + if (fs::equivalent(fs::path(Pair.first), mPath / "Server")) { beammp_info("File \"" + Pair.first + "\" changed, reloading"); // is in root folder, so reload std::ifstream FileStream(Pair.first, std::ios::in | std::ios::binary); From 23ffa25d784d6d1085e060aa8a4358d6e037b279 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 20 Sep 2021 23:43:54 +0200 Subject: [PATCH 157/255] Lua: Add FS.GetParentFolder --- include/LuaAPI.h | 1 + src/LuaAPI.cpp | 4 ++++ src/TLuaEngine.cpp | 1 + 3 files changed, 6 insertions(+) diff --git a/include/LuaAPI.h b/include/LuaAPI.h index f825149..3444a1a 100644 --- a/include/LuaAPI.h +++ b/include/LuaAPI.h @@ -30,6 +30,7 @@ namespace FS { std::pair Copy(const std::string& Path, const std::string& NewPath); std::string GetFilename(const std::string& Path); std::string GetExtension(const std::string& Path); + std::string GetParentFolder(const std::string& Path); bool Exists(const std::string& Path); } } diff --git a/src/LuaAPI.cpp b/src/LuaAPI.cpp index cfd27cc..a19049b 100644 --- a/src/LuaAPI.cpp +++ b/src/LuaAPI.cpp @@ -319,3 +319,7 @@ std::string LuaAPI::FS::GetFilename(const std::string& Path) { std::string LuaAPI::FS::GetExtension(const std::string& Path) { return fs::path(Path).extension().string(); } + +std::string LuaAPI::FS::GetParentFolder(const std::string& Path) { + return fs::relative(Path).parent_path().string(); +} diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index b890541..8b9cef1 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -457,6 +457,7 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi FSTable.set_function("Copy", &LuaAPI::FS::Copy); FSTable.set_function("GetFilename", &LuaAPI::FS::GetFilename); FSTable.set_function("GetExtension", &LuaAPI::FS::GetExtension); + FSTable.set_function("GetParentFolder", &LuaAPI::FS::GetParentFolder); Start(); } From fe3ccafc1d55362692aa5e536c3ba0676f6644e6 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Tue, 21 Sep 2021 00:27:09 +0200 Subject: [PATCH 158/255] Lua: Add various FS functions --- include/LuaAPI.h | 3 +++ src/LuaAPI.cpp | 27 ++++++++++++++++++++++++++- src/TLuaEngine.cpp | 3 +++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/include/LuaAPI.h b/include/LuaAPI.h index 3444a1a..188cb78 100644 --- a/include/LuaAPI.h +++ b/include/LuaAPI.h @@ -32,5 +32,8 @@ namespace FS { std::string GetExtension(const std::string& Path); std::string GetParentFolder(const std::string& Path); bool Exists(const std::string& Path); + bool IsDirectory(const std::string& Path); + bool IsFile(const std::string& Path); + std::string ConcatPaths(sol::variadic_args Args); } } diff --git a/src/LuaAPI.cpp b/src/LuaAPI.cpp index a19049b..46fffe4 100644 --- a/src/LuaAPI.cpp +++ b/src/LuaAPI.cpp @@ -321,5 +321,30 @@ std::string LuaAPI::FS::GetExtension(const std::string& Path) { } std::string LuaAPI::FS::GetParentFolder(const std::string& Path) { - return fs::relative(Path).parent_path().string(); + return fs::path(Path).parent_path().string(); +} + +bool LuaAPI::FS::IsDirectory(const std::string& Path) { + return fs::is_directory(Path); +} + +bool LuaAPI::FS::IsFile(const std::string& Path) { + return fs::is_regular_file(Path); +} + +std::string LuaAPI::FS::ConcatPaths(sol::variadic_args Args) { + fs::path Path; + for (size_t i = 0; i < Args.size(); ++i) { + auto Obj = Args[i]; + if (!Obj.is()) { + beammp_lua_error("FS.Concat called with non-string argument"); + return ""; + } + Path += Obj.as(); + if (i < Args.size() - 1 && !Path.empty()) { + Path += fs::path::preferred_separator; + } + } + auto Result = Path.lexically_normal().string(); + return Result; } diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 8b9cef1..e678f54 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -458,6 +458,9 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi FSTable.set_function("GetFilename", &LuaAPI::FS::GetFilename); FSTable.set_function("GetExtension", &LuaAPI::FS::GetExtension); FSTable.set_function("GetParentFolder", &LuaAPI::FS::GetParentFolder); + FSTable.set_function("IsDirectory", &LuaAPI::FS::IsDirectory); + FSTable.set_function("IsFile", &LuaAPI::FS::IsFile); + FSTable.set_function("ConcatPaths", &LuaAPI::FS::ConcatPaths); Start(); } From 9d0caf2c7dede0a87c41890486f9089a3c91bb2b Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Tue, 21 Sep 2021 16:17:40 +0200 Subject: [PATCH 159/255] Lua: Implement Hot-Reload --- include/TLuaEngine.h | 2 +- src/Common.cpp | 2 ++ src/TLuaEngine.cpp | 9 +++++++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index e6bd085..1b1608b 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -165,7 +165,7 @@ private: TPluginMonitor mPluginMonitor; std::atomic_bool mShutdown { false }; fs::path mResourceServerPath; - std::vector mLuaPlugins; + std::vector> mLuaPlugins; std::unordered_map> mLuaStates; std::recursive_mutex mLuaStatesMutex; std::unordered_map>> mLuaEvents; diff --git a/src/Common.cpp b/src/Common.cpp index 1fe02d6..f1bcfab 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -159,7 +159,9 @@ std::string ThreadName(bool DebugModeOverride) { } void RegisterThread(const std::string& str) { +#if defined(__linux) beammp_trace(str + " is " + std::to_string(gettid())); +#endif // __linux auto Lock = std::unique_lock(ThreadNameMapMutex); threadNameMap[std::this_thread::get_id()] = str; } diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index e678f54..b967bdf 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -173,7 +173,8 @@ void TLuaEngine::InitializePlugin(const fs::path& Folder, const TLuaPluginConfig EnsureStateExists(Config.StateId, Folder.stem().string(), true); mLuaStates[Config.StateId]->AddPath(Folder); // add to cpath + path Lock.unlock(); - TLuaPlugin Plugin(*this, Config, Folder); + auto Plugin = std::make_shared(*this, Config, Folder); + mLuaPlugins.emplace_back(std::move(Plugin)); } void TLuaEngine::FindAndParseConfig(const fs::path& Folder, TLuaPluginConfig& Config) { @@ -661,10 +662,12 @@ void TPluginMonitor::operator()() { while (!mShutdown) { std::this_thread::sleep_for(std::chrono::seconds(3)); for (const auto& Pair : mFileTimes) { + beammp_trace("checking for hot-reloadable files"); auto CurrentTime = fs::last_write_time(Pair.first); if (CurrentTime != Pair.second) { mFileTimes[Pair.first] = CurrentTime; - if (fs::equivalent(fs::path(Pair.first), mPath / "Server")) { + // grandparent of the path should be Resources/Server + if (fs::equivalent(fs::path(Pair.first).parent_path().parent_path(), mPath)) { beammp_info("File \"" + Pair.first + "\" changed, reloading"); // is in root folder, so reload std::ifstream FileStream(Pair.first, std::ios::in | std::ios::binary); @@ -675,6 +678,7 @@ void TPluginMonitor::operator()() { TLuaChunk Chunk(Contents, Pair.first, fs::path(Pair.first).parent_path().string()); auto StateID = mEngine.GetStateIDForPlugin(fs::path(Pair.first).parent_path()); auto Res = mEngine.EnqueueScript(StateID, Chunk); + // TODO: call onInit while (!Res->Ready) { std::this_thread::sleep_for(std::chrono::milliseconds(10)); } @@ -682,6 +686,7 @@ void TPluginMonitor::operator()() { beammp_lua_error(Res->ErrorMessage); } } else { + // TODO: trigger onFileChanged event beammp_trace("Change detected in file \"" + Pair.first + "\", event trigger not implemented yet"); /* // is in subfolder, dont reload, just trigger an event From 33ebfa82f0033cbe83a3acefa62789f4f40226d0 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Wed, 22 Sep 2021 21:08:01 +0200 Subject: [PATCH 160/255] Remove spammy TRACE --- src/TLuaEngine.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index b967bdf..6e91cea 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -662,7 +662,6 @@ void TPluginMonitor::operator()() { while (!mShutdown) { std::this_thread::sleep_for(std::chrono::seconds(3)); for (const auto& Pair : mFileTimes) { - beammp_trace("checking for hot-reloadable files"); auto CurrentTime = fs::last_write_time(Pair.first); if (CurrentTime != Pair.second) { mFileTimes[Pair.first] = CurrentTime; From e948edca8d383ace0706d4160f7be82de9ccb976 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 30 Sep 2021 23:24:23 +0200 Subject: [PATCH 161/255] Add zip files with past logs --- .gitmodules | 3 +++ CMakeLists.txt | 13 ++++++++---- deps/libzip | 1 + include/Common.h | 53 ++++++++++++++++++++++++++++++++++++++++++++-- include/TConsole.h | 3 ++- src/Common.cpp | 45 ++------------------------------------- src/TConsole.cpp | 41 +++++++++++++++++++++++++++++++++++ 7 files changed, 109 insertions(+), 50 deletions(-) create mode 160000 deps/libzip diff --git a/.gitmodules b/.gitmodules index 083c21f..1822884 100644 --- a/.gitmodules +++ b/.gitmodules @@ -19,3 +19,6 @@ [submodule "deps/sol2"] path = deps/sol2 url = https://github.com/ThePhD/sol2 +[submodule "deps/libzip"] + path = deps/libzip + url = https://github.com/nih-at/libzip diff --git a/CMakeLists.txt b/CMakeLists.txt index a8be07c..a197127 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,13 @@ endif() set(SENTRY_BACKEND breakpad) add_subdirectory("deps/sentry-native") +set(BUILD_SHARED_LIBS OFF) +find_package(libzip) +if (NOT LIBZIP_FOUND) +add_subdirectory("deps/libzip") +find_package(libzip REQUIRED) +endif() + message(STATUS "Setting compiler flags") if (WIN32) @@ -63,8 +70,6 @@ message(STATUS "Adding local source dependencies") # this has to happen before -DDEBUG since it wont compile properly with -DDEBUG add_subdirectory(deps) - - set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG") @@ -93,7 +98,7 @@ add_executable(BeamMP-Server include/SignalHandling.h src/SignalHandling.cpp) target_compile_definitions(BeamMP-Server PRIVATE SECRET_SENTRY_URL="${BEAMMP_SECRET_SENTRY_URL}") -include_directories(BeamMP-Server PUBLIC ${Boost_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}/include) +include_directories(BeamMP-Server PUBLIC ${libzip_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}/include) target_include_directories(BeamMP-Server PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" @@ -113,7 +118,7 @@ message(STATUS "Looking for SSL") find_package(OpenSSL REQUIRED) -target_link_libraries(BeamMP-Server sol2::sol2 ${LUA_LIBRARIES}) +target_link_libraries(BeamMP-Server sol2::sol2 ${LUA_LIBRARIES} libzip::zip) message(STATUS "CURL IS ${CURL_LIBRARIES}") if (UNIX) diff --git a/deps/libzip b/deps/libzip new file mode 160000 index 0000000..76df02f --- /dev/null +++ b/deps/libzip @@ -0,0 +1 @@ +Subproject commit 76df02f86b9746e139fd9fc934a70e3a21bbc557 diff --git a/include/Common.h b/include/Common.h index f8436d6..c6b8b1e 100644 --- a/include/Common.h +++ b/include/Common.h @@ -11,6 +11,7 @@ extern TSentry Sentry; #include #include #include +#include #include "Compat.h" @@ -175,8 +176,56 @@ void RegisterThread(const std::string& str); void LogChatMessage(const std::string& name, int id, const std::string& msg); #define Biggest 30000 -std::string Comp(std::string Data); -std::string DeComp(std::string Compressed); + +template +inline T Comp(const T& Data) { + std::array C {}; + // obsolete + C.fill(0); + z_stream defstream; + defstream.zalloc = Z_NULL; + defstream.zfree = Z_NULL; + defstream.opaque = Z_NULL; + defstream.avail_in = (uInt)Data.size(); + defstream.next_in = (Bytef*)&Data[0]; + defstream.avail_out = Biggest; + defstream.next_out = reinterpret_cast(C.data()); + deflateInit(&defstream, Z_BEST_COMPRESSION); + deflate(&defstream, Z_SYNC_FLUSH); + deflate(&defstream, Z_FINISH); + deflateEnd(&defstream); + size_t TotalOut = defstream.total_out; + T Ret; + Ret.resize(TotalOut); + std::fill(Ret.begin(), Ret.end(), 0); + std::copy_n(C.begin(), TotalOut, Ret.begin()); + return Ret; +} + +template +inline T DeComp(const T& Compressed) { + std::array C {}; + // not needed + C.fill(0); + z_stream infstream; + infstream.zalloc = Z_NULL; + infstream.zfree = Z_NULL; + infstream.opaque = Z_NULL; + infstream.avail_in = Biggest; + infstream.next_in = (Bytef*)(&Compressed[0]); + infstream.avail_out = Biggest; + infstream.next_out = (Bytef*)(C.data()); + inflateInit(&infstream); + inflate(&infstream, Z_SYNC_FLUSH); + inflate(&infstream, Z_FINISH); + inflateEnd(&infstream); + size_t TotalOut = infstream.total_out; + T Ret; + Ret.resize(TotalOut); + std::fill(Ret.begin(), Ret.end(), 0); + std::copy_n(C.begin(), TotalOut, Ret.begin()); + return Ret; +} std::string GetPlatformAgnosticErrorString(); #define S_DSN SU_RAW diff --git a/include/TConsole.h b/include/TConsole.h index 8e6ad31..4f9cad6 100644 --- a/include/TConsole.h +++ b/include/TConsole.h @@ -1,7 +1,7 @@ #pragma once -#include "commandline.h" #include "Cryptography.h" +#include "commandline.h" #include #include @@ -14,6 +14,7 @@ public: void Write(const std::string& str); void WriteRaw(const std::string& str); void InitializeLuaConsole(TLuaEngine& Engine); + void BackupOldLog(); private: Commandline mCommandline; diff --git a/src/Common.cpp b/src/Common.cpp index f1bcfab..7bfae72 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include "CustomAssert.h" #include "Http.h" @@ -97,49 +96,9 @@ void Application::CheckForUpdates() { } } -std::string Comp(std::string Data) { - std::array C {}; - // obsolete - C.fill(0); - z_stream defstream; - defstream.zalloc = Z_NULL; - defstream.zfree = Z_NULL; - defstream.opaque = Z_NULL; - defstream.avail_in = (uInt)Data.length(); - defstream.next_in = (Bytef*)&Data[0]; - defstream.avail_out = Biggest; - defstream.next_out = reinterpret_cast(C.data()); - deflateInit(&defstream, Z_BEST_COMPRESSION); - deflate(&defstream, Z_SYNC_FLUSH); - deflate(&defstream, Z_FINISH); - deflateEnd(&defstream); - size_t TO = defstream.total_out; - std::string Ret(TO, 0); - std::copy_n(C.begin(), TO, Ret.begin()); - return Ret; -} -std::string DeComp(std::string Compressed) { - std::array C {}; - // not needed - C.fill(0); - z_stream infstream; - infstream.zalloc = Z_NULL; - infstream.zfree = Z_NULL; - infstream.opaque = Z_NULL; - infstream.avail_in = Biggest; - infstream.next_in = (Bytef*)(&Compressed[0]); - infstream.avail_out = Biggest; - infstream.next_out = (Bytef*)(C.data()); - inflateInit(&infstream); - inflate(&infstream, Z_SYNC_FLUSH); - inflate(&infstream, Z_FINISH); - inflateEnd(&infstream); - size_t TO = infstream.total_out; - std::string Ret(TO, 0); - std::copy_n(C.begin(), TO, Ret.begin()); - return Ret; -} + + // thread name stuff diff --git a/src/TConsole.cpp b/src/TConsole.cpp index 43834da..7905839 100644 --- a/src/TConsole.cpp +++ b/src/TConsole.cpp @@ -6,6 +6,7 @@ #include #include +#include std::string GetDate() { std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); @@ -41,10 +42,50 @@ std::string GetDate() { return date.str(); } +void TConsole::BackupOldLog() { + fs::path Path = "Server.log"; + if (fs::exists(Path)) { + int err = 0; + zip* z = zip_open("ServerLogs.zip", ZIP_CREATE, &err); + if (!z) { + std::cerr << GetPlatformAgnosticErrorString() << std::endl; + return; + } + FILE* File = std::fopen(Path.string().c_str(), "r"); + if (!File) { + std::cerr << GetPlatformAgnosticErrorString() << std::endl; + return; + } + std::vector Buffer; + Buffer.resize(fs::file_size(Path)); + std::fread(Buffer.data(), 1, Buffer.size(), File); + std::fclose(File); + + auto s = zip_source_buffer(z, Buffer.data(), Buffer.size(), 0); + + auto TimePoint = fs::last_write_time(Path); + auto Secs = TimePoint.time_since_epoch().count(); + auto MyTimeT = std::time(&Secs); + + std::string NewName = Path.stem().string(); + NewName += "_"; + std::string Time; + Time.resize(32); + size_t n = strftime(Time.data(), Time.size(), "%F_%H.%M.%S", localtime(&MyTimeT)); + Time.resize(n); + NewName += Time; + NewName += ".log"; + + zip_file_add(z, NewName.c_str(), s, 0); + zip_close(z); + } +} + TConsole::TConsole() { mCommandline.enable_history(); mCommandline.set_history_limit(20); mCommandline.set_prompt("> "); + BackupOldLog(); bool success = mCommandline.enable_write_to_file("Server.log"); if (!success) { beammp_error("unable to open file for writing: \"Server.log\""); From e7f29ce04f6cd53ac68439bdc5b97d902041dc1f Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 1 Oct 2021 01:40:37 +0200 Subject: [PATCH 162/255] Fix server event timing --- include/TLuaEngine.h | 4 +++- src/TConsole.cpp | 50 +++++++++++++++++++------------------------- src/TLuaEngine.cpp | 26 ++++++++++++++--------- 3 files changed, 41 insertions(+), 39 deletions(-) diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index 1b1608b..75fe655 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -3,6 +3,7 @@ #include "TNetwork.h" #include "TServer.h" #include +#include #include #include #include @@ -144,7 +145,8 @@ private: std::queue>> mStateExecuteQueue; std::recursive_mutex mStateExecuteQueueMutex; std::queue, std::vector>> mStateFunctionQueue; - std::recursive_mutex mStateFunctionQueueMutex; + std::mutex mStateFunctionQueueMutex; + std::condition_variable mStateFunctionQueueCond; TLuaEngine* mEngine; sol::state_view mStateView { mState }; std::queue mPaths; diff --git a/src/TConsole.cpp b/src/TConsole.cpp index 7905839..2818ba6 100644 --- a/src/TConsole.cpp +++ b/src/TConsole.cpp @@ -11,35 +11,29 @@ std::string GetDate() { std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); time_t tt = std::chrono::system_clock::to_time_t(now); - tm local_tm {}; -#ifdef WIN32 - localtime_s(&local_tm, &tt); -#else // unix - localtime_r(&tt, &local_tm); -#endif // WIN32 - std::stringstream date; - int S = local_tm.tm_sec; - int M = local_tm.tm_min; - int H = local_tm.tm_hour; - std::string Secs = (S > 9 ? std::to_string(S) : "0" + std::to_string(S)); - std::string Min = (M > 9 ? std::to_string(M) : "0" + std::to_string(M)); - std::string Hour = (H > 9 ? std::to_string(H) : "0" + std::to_string(H)); - date - << "[" - << local_tm.tm_mday << "/" - << local_tm.tm_mon + 1 << "/" - << local_tm.tm_year + 1900 << " " - << Hour << ":" - << Min << ":" - << Secs - << "] "; - /* TODO - if (Debug) { - date << ThreadName() - << " "; + auto local_tm = std::localtime(&tt); + char buf[30]; + std::string date; +#if defined(DEBUG) + if (Application::Settings.DebugModeEnabled) { + std::strftime(buf, sizeof(buf), "[%d/%m/%y %T.", local_tm); + date += buf; + auto seconds = std::chrono::time_point_cast(now); + auto fraction = now - seconds; + size_t ms = std::chrono::duration_cast(fraction).count(); + char fracstr[5]; + std::sprintf(fracstr, "%0.3lu", ms); + date += fracstr; + date += "] "; + } else { +#endif + std::strftime(buf, sizeof(buf), "[%d/%m/%y %T] ", local_tm); + date += buf; +#if defined(DEBUG) } - */ - return date.str(); +#endif + + return date; } void TConsole::BackupOldLog() { diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 6e91cea..177fab8 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -45,11 +45,11 @@ void TLuaEngine::operator()() { beammp_lua_error("Calling \"onInit\" on \"" + Future->StateId + "\" failed: " + Future->ErrorMessage); } } - std::queue> ResultsToCheck; + /*std::queue> ResultsToCheck; std::recursive_mutex ResultsToCheckMutex; std::thread ResultCheckThread([&] { while (!mShutdown) { - std::this_thread::sleep_for(std::chrono::milliseconds(100)); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); std::unique_lock Lock(ResultsToCheckMutex); if (!ResultsToCheck.empty()) { auto Res = ResultsToCheck.front(); @@ -62,6 +62,7 @@ void TLuaEngine::operator()() { Waited++; if (Waited > 1000) { beammp_lua_error(Res->Function + " in " + Res->StateId + " took >1s to respond, not printing possible errors"); + break; } } if (Res->Error) { @@ -70,6 +71,7 @@ void TLuaEngine::operator()() { } } }); + */ // event loop auto Before = std::chrono::high_resolution_clock::now(); while (!mShutdown) { @@ -80,15 +82,14 @@ void TLuaEngine::operator()() { Timer.Reset(); auto Handlers = GetEventHandlersForState(Timer.EventName, Timer.StateId); std::unique_lock StateLock(mLuaStatesMutex); - std::unique_lock Lock2(ResultsToCheckMutex); + //std::unique_lock Lock2(ResultsToCheckMutex); for (auto& Handler : Handlers) { auto Res = mLuaStates[Timer.StateId]->EnqueueFunctionCall(Handler, {}); - ResultsToCheck.push(Res); + //ResultsToCheck.push(Res); } } } } - // sleep for the remaining time to get to 1ms (our atom duration) if (std::chrono::high_resolution_clock::duration Diff; (Diff = std::chrono::high_resolution_clock::now() - Before) < std::chrono::milliseconds(10)) { @@ -98,9 +99,10 @@ void TLuaEngine::operator()() { } Before = std::chrono::high_resolution_clock::now(); } + /* if (ResultCheckThread.joinable()) { ResultCheckThread.join(); - } + }*/ } size_t TLuaEngine::CalculateMemoryUsage() { @@ -478,6 +480,7 @@ std::shared_ptr TLuaEngine::StateThreadData::EnqueueFunctionCall(con Result->Function = FunctionName; std::unique_lock Lock(mStateFunctionQueueMutex); mStateFunctionQueue.push({ FunctionName, Result, Args }); + mStateFunctionQueueCond.notify_all(); return Result; } @@ -535,16 +538,20 @@ void TLuaEngine::StateThreadData::operator()() { } { // StateFunctionQueue Scope std::unique_lock Lock(mStateFunctionQueueMutex); - if (!mStateFunctionQueue.empty()) { + auto NotExpired = mStateFunctionQueueCond.wait_for(Lock, + std::chrono::milliseconds(500), + [&]() -> bool { return !mStateFunctionQueue.empty(); }); + if (NotExpired) { auto FnNameResultPair = std::move(mStateFunctionQueue.front()); mStateFunctionQueue.pop(); Lock.unlock(); - auto& StateId = std::get<0>(FnNameResultPair); + auto& FnName = std::get<0>(FnNameResultPair); auto& Result = std::get<1>(FnNameResultPair); auto Args = std::get<2>(FnNameResultPair); Result->StateId = mStateId; sol::state_view StateView(mState); - auto Fn = StateView[StateId]; + auto Fn = StateView[FnName]; + beammp_debug("something found in the queue: call to \"" + FnName + "\" in \"" + mStateId + "\""); if (Fn.valid() && Fn.get_type() == sol::type::function) { std::vector LuaArgs; for (const auto& Arg : Args) { @@ -586,7 +593,6 @@ void TLuaEngine::StateThreadData::operator()() { } } } - std::this_thread::sleep_for(std::chrono::milliseconds(10)); } } From 013ca14ab8a06201b373366ad5a4d961018480ff Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 1 Oct 2021 01:51:22 +0200 Subject: [PATCH 163/255] add libzip module path --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index a197127..05a7683 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,6 +34,7 @@ set(BUILD_SHARED_LIBS OFF) find_package(libzip) if (NOT LIBZIP_FOUND) add_subdirectory("deps/libzip") +set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${PROJECT_SOURCE_DIR}/deps/libzip/cmake") find_package(libzip REQUIRED) endif() From 255feb4f8e5cac2d1d3d9a34229bb96347a55932 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 1 Oct 2021 01:52:13 +0200 Subject: [PATCH 164/255] CMake: Fix minor mistake in cmakelists --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 05a7683..02c946e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,7 +34,7 @@ set(BUILD_SHARED_LIBS OFF) find_package(libzip) if (NOT LIBZIP_FOUND) add_subdirectory("deps/libzip") -set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${PROJECT_SOURCE_DIR}/deps/libzip/cmake") +set(CMAKE_PREFIX_PATH "${CMAKE_PREFIX_PATH};${PROJECT_SOURCE_DIR}/deps/libzip/cmake") find_package(libzip REQUIRED) endif() From 7f1d37a0e648b509a4985896fb6d110c46b9d514 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 1 Oct 2021 01:57:29 +0200 Subject: [PATCH 165/255] Fix libzip --- CMakeLists.txt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 02c946e..8d15188 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,12 +30,10 @@ endif() set(SENTRY_BACKEND breakpad) add_subdirectory("deps/sentry-native") -set(BUILD_SHARED_LIBS OFF) find_package(libzip) if (NOT LIBZIP_FOUND) -add_subdirectory("deps/libzip") -set(CMAKE_PREFIX_PATH "${CMAKE_PREFIX_PATH};${PROJECT_SOURCE_DIR}/deps/libzip/cmake") -find_package(libzip REQUIRED) + set(BUILD_SHARED_LIBS OFF) + add_subdirectory("deps/libzip") endif() message(STATUS "Setting compiler flags") From 87ecc3f9f624099ff4d24298d330950dc0037a02 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 1 Oct 2021 02:03:11 +0200 Subject: [PATCH 166/255] fix readme invalid cmake invocation, show ms in debug output --- README.md | 2 +- src/TConsole.cpp | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/README.md b/README.md index a138fa8..7ad35c9 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,7 @@ On windows, use git-bash for these commands. On Linux, these should work in your 2. Clone the repository in a location of your choice with `git clone --recurse-submodules https://github.com/BeamMP/BeamMP-Server`. 3. Ensure that all submodules are initialized by running `git submodule update --init --recursive`. Then change into the cloned directory by running `cd BeamMP-Server`. 4. Checkout the branch of the release you want to compile (`master` is often unstable), for example `git checkout tags/v1.20` for version 1.20. You can find the latest version [here](https://github.com/BeamMP/BeamMP-Server/tags). -5. Run `cmake .` (with `.`) +5. Run `cmake . -DCMAKE_BUILD_TYPE=Release` (with `.`) 6. Run `make` 7. You will now have a `BeamMP-Server` file in your directory, which is executable with `./BeamMP-Server` (`.\BeamMP-Server.exe` for windows). Follow the (windows or linux, doesnt matter) instructions on the [wiki](https://wiki.beammp.com/en/home/Server_Mod) for further setup after installation (which we just did), such as port-forwarding and getting a key to actually run the server. diff --git a/src/TConsole.cpp b/src/TConsole.cpp index 2818ba6..6efebd9 100644 --- a/src/TConsole.cpp +++ b/src/TConsole.cpp @@ -14,7 +14,6 @@ std::string GetDate() { auto local_tm = std::localtime(&tt); char buf[30]; std::string date; -#if defined(DEBUG) if (Application::Settings.DebugModeEnabled) { std::strftime(buf, sizeof(buf), "[%d/%m/%y %T.", local_tm); date += buf; @@ -26,12 +25,9 @@ std::string GetDate() { date += fracstr; date += "] "; } else { -#endif std::strftime(buf, sizeof(buf), "[%d/%m/%y %T] ", local_tm); date += buf; -#if defined(DEBUG) } -#endif return date; } From 26ec50b1998d2b88bcbdc2105d7e2e648f75cac9 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 1 Oct 2021 02:31:48 +0200 Subject: [PATCH 167/255] Build libzip statically --- CMakeLists.txt | 7 ++----- src/TNetwork.cpp | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8d15188..0d7a13f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,11 +30,8 @@ endif() set(SENTRY_BACKEND breakpad) add_subdirectory("deps/sentry-native") -find_package(libzip) -if (NOT LIBZIP_FOUND) - set(BUILD_SHARED_LIBS OFF) - add_subdirectory("deps/libzip") -endif() +set(BUILD_SHARED_LIBS OFF) +add_subdirectory("deps/libzip") message(STATUS "Setting compiler flags") if (WIN32) diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index 4c08fc6..cccae89 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -732,7 +732,7 @@ void TNetwork::SplitLoad(TClient& c, size_t Sent, size_t Size, bool D, const std TCPSock = c.GetDownSock(); else TCPSock = c.GetTCPSock(); - beammp_info("Split load Socket " + std::to_string(TCPSock)); + beammp_debug("Split load Socket " + std::to_string(TCPSock)); while (c.GetStatus() > -1 && Sent < Size) { size_t Diff = Size - Sent; if (Diff > Split) { From 932fbe2b2f4bcbdbb100ad5b282ad68a2e40b40c Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 1 Oct 2021 03:01:28 +0200 Subject: [PATCH 168/255] reintroduce waiting for results --- src/TLuaEngine.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 177fab8..eee4cce 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -45,7 +45,7 @@ void TLuaEngine::operator()() { beammp_lua_error("Calling \"onInit\" on \"" + Future->StateId + "\" failed: " + Future->ErrorMessage); } } - /*std::queue> ResultsToCheck; + std::queue> ResultsToCheck; std::recursive_mutex ResultsToCheckMutex; std::thread ResultCheckThread([&] { while (!mShutdown) { @@ -71,7 +71,6 @@ void TLuaEngine::operator()() { } } }); - */ // event loop auto Before = std::chrono::high_resolution_clock::now(); while (!mShutdown) { @@ -99,10 +98,10 @@ void TLuaEngine::operator()() { } Before = std::chrono::high_resolution_clock::now(); } - /* + if (ResultCheckThread.joinable()) { ResultCheckThread.join(); - }*/ + } } size_t TLuaEngine::CalculateMemoryUsage() { From 243e96d503ff25aa769c4281eda047d0176972b0 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 1 Oct 2021 03:27:24 +0200 Subject: [PATCH 169/255] Check all futures --- include/TLuaEngine.h | 3 +++ src/TLuaEngine.cpp | 29 ++++++++++++++++++----------- src/TNetwork.cpp | 8 ++++---- src/TServer.cpp | 6 +++--- 4 files changed, 28 insertions(+), 18 deletions(-) diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index 75fe655..27ee769 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -83,6 +83,7 @@ public: void SetServer(TServer* Server) { mServer = Server; } static void WaitForAll(std::vector>& Results); + void IgnoreIfNotError(const std::vector >& Results); [[nodiscard]] std::shared_ptr EnqueueScript(TLuaStateId StateID, const TLuaChunk& Script); [[nodiscard]] std::shared_ptr EnqueueFunctionCall(TLuaStateId StateID, const std::string& FunctionName, const std::vector& Args); void EnsureStateExists(TLuaStateId StateId, const std::string& Name, bool DontCallOnInit = false); @@ -174,6 +175,8 @@ private: std::recursive_mutex mLuaEventsMutex; std::vector mTimedEvents; std::recursive_mutex mTimedEventsMutex; + std::queue> mResultsToCheck; + std::recursive_mutex mResultsToCheckMutex; }; //std::any TriggerLuaEvent(const std::string& Event, bool local, TLuaPlugin* Caller, std::shared_ptr arg, bool Wait); diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index eee4cce..3b60317 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -45,15 +45,14 @@ void TLuaEngine::operator()() { beammp_lua_error("Calling \"onInit\" on \"" + Future->StateId + "\" failed: " + Future->ErrorMessage); } } - std::queue> ResultsToCheck; - std::recursive_mutex ResultsToCheckMutex; - std::thread ResultCheckThread([&] { + + auto ResultCheckThread = std::thread([&] { while (!mShutdown) { - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - std::unique_lock Lock(ResultsToCheckMutex); - if (!ResultsToCheck.empty()) { - auto Res = ResultsToCheck.front(); - ResultsToCheck.pop(); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + std::unique_lock Lock(mResultsToCheckMutex); + if (!mResultsToCheck.empty()) { + auto Res = mResultsToCheck.front(); + mResultsToCheck.pop(); Lock.unlock(); size_t Waited = 0; @@ -81,10 +80,10 @@ void TLuaEngine::operator()() { Timer.Reset(); auto Handlers = GetEventHandlersForState(Timer.EventName, Timer.StateId); std::unique_lock StateLock(mLuaStatesMutex); - //std::unique_lock Lock2(ResultsToCheckMutex); + std::unique_lock Lock2(mResultsToCheckMutex); for (auto& Handler : Handlers) { auto Res = mLuaStates[Timer.StateId]->EnqueueFunctionCall(Handler, {}); - //ResultsToCheck.push(Res); + mResultsToCheck.push(Res); } } } @@ -98,7 +97,7 @@ void TLuaEngine::operator()() { } Before = std::chrono::high_resolution_clock::now(); } - + if (ResultCheckThread.joinable()) { ResultCheckThread.join(); } @@ -143,6 +142,14 @@ void TLuaEngine::WaitForAll(std::vector>& Results) { } } +// run this on the error checking thread +void TLuaEngine::IgnoreIfNotError(const std::vector>& Results) { + std::unique_lock Lock2(mResultsToCheckMutex); + for (const auto& Result : Results) { + mResultsToCheck.push(Result); + } +} + std::shared_ptr TLuaEngine::EnqueueScript(TLuaStateId StateID, const TLuaChunk& Script) { std::unique_lock Lock(mLuaStatesMutex); return mLuaStates.at(StateID)->EnqueueScript(Script); diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index cccae89..f0c1c28 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -571,7 +571,7 @@ void TNetwork::OnDisconnect(const std::weak_ptr& ClientPtr, bool kicked SendToAll(&c, Packet, false, true); Packet.clear(); auto Futures = LuaAPI::MP::Engine->TriggerEvent("onPlayerDisconnect", "", c.GetID()); - beammp_ignore(Futures); + LuaAPI::MP::Engine->IgnoreIfNotError(Futures); if (c.GetTCPSock()) CloseSocketProper(c.GetTCPSock()); if (c.GetDownSock()) @@ -605,13 +605,13 @@ void TNetwork::OnConnect(const std::weak_ptr& c) { auto LockedClient = c.lock(); LockedClient->SetID(OpenID()); beammp_info("Assigned ID " + std::to_string(LockedClient->GetID()) + " to " + LockedClient->GetName()); - beammp_ignore(LuaAPI::MP::Engine->TriggerEvent("onPlayerConnecting", "", LockedClient->GetID())); + LuaAPI::MP::Engine->IgnoreIfNotError(LuaAPI::MP::Engine->TriggerEvent("onPlayerConnecting", "", LockedClient->GetID())); SyncResources(*LockedClient); if (LockedClient->GetStatus() < 0) return; (void)Respond(*LockedClient, "M" + Application::Settings.MapName, true); //Send the Map on connect beammp_info(LockedClient->GetName() + " : Connected"); - beammp_ignore(LuaAPI::MP::Engine->TriggerEvent("onPlayerJoining", "", LockedClient->GetID())); + LuaAPI::MP::Engine->IgnoreIfNotError(LuaAPI::MP::Engine->TriggerEvent("onPlayerJoining", "", LockedClient->GetID())); } void TNetwork::SyncResources(TClient& c) { @@ -810,7 +810,7 @@ bool TNetwork::SyncClient(const std::weak_ptr& c) { // ignore error (void)SendToAll(LockedClient.get(), ("JWelcome ") + LockedClient->GetName() + "!", false, true); - beammp_ignore(LuaAPI::MP::Engine->TriggerEvent("onPlayerJoin", "", LockedClient->GetID())); + LuaAPI::MP::Engine->IgnoreIfNotError(LuaAPI::MP::Engine->TriggerEvent("onPlayerJoin", "", LockedClient->GetID())); LockedClient->SetIsSyncing(true); bool Return = false; bool res = true; diff --git a/src/TServer.cpp b/src/TServer.cpp index abf328a..8b3249a 100644 --- a/src/TServer.cpp +++ b/src/TServer.cpp @@ -162,7 +162,7 @@ void TServer::HandleEvent(TClient& c, const std::string& Data) { Name = t; break; case 2: - beammp_ignore(LuaAPI::MP::Engine->TriggerEvent(Name, "", c.GetID(), t)); + LuaAPI::MP::Engine->IgnoreIfNotError(LuaAPI::MP::Engine->TriggerEvent(Name, "", c.GetID(), t)); break; default: break; @@ -282,7 +282,7 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ c.SetUnicycleID(-1); } Network.SendToAll(nullptr, Packet, true, true); - beammp_ignore(LuaAPI::MP::Engine->TriggerEvent("onVehicleDeleted", "", c.GetID(), VID)); + LuaAPI::MP::Engine->IgnoreIfNotError(LuaAPI::MP::Engine->TriggerEvent("onVehicleDeleted", "", c.GetID(), VID)); c.DeleteCar(VID); beammp_debug(c.GetName() + (" deleted car with ID ") + std::to_string(VID)); } @@ -300,7 +300,7 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ if (PID != -1 && VID != -1 && PID == c.GetID()) { Data = Data.substr(Data.find('{')); - beammp_ignore(LuaAPI::MP::Engine->TriggerEvent("onVehicleReset", "", c.GetID(), VID, Data)); + LuaAPI::MP::Engine->IgnoreIfNotError(LuaAPI::MP::Engine->TriggerEvent("onVehicleReset", "", c.GetID(), VID, Data)); Network.SendToAll(&c, Packet, false, true); } return; From ae7a63669f467a23788f9734e3ff39ea30dd2e64 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 1 Oct 2021 03:35:13 +0200 Subject: [PATCH 170/255] detect recursion in LuaToString --- src/LuaAPI.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/LuaAPI.cpp b/src/LuaAPI.cpp index 46fffe4..fba9264 100644 --- a/src/LuaAPI.cpp +++ b/src/LuaAPI.cpp @@ -7,6 +7,9 @@ #include static std::string LuaToString(const sol::object Value, size_t Indent = 1) { + if (Indent > 80) { + return "[[possible recursion, refusing to keep printing]]"; + } switch (Value.get_type()) { case sol::type::userdata: { std::stringstream ss; From 9eabd19e1795c24a2da40da2c15590fb94755b28 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 1 Oct 2021 03:52:12 +0200 Subject: [PATCH 171/255] Report more errors, better --- include/TLuaEngine.h | 2 +- src/TLuaEngine.cpp | 2 +- src/TNetwork.cpp | 10 ++++++---- src/TServer.cpp | 6 +++--- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index 27ee769..1c9de93 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -83,7 +83,7 @@ public: void SetServer(TServer* Server) { mServer = Server; } static void WaitForAll(std::vector>& Results); - void IgnoreIfNotError(const std::vector >& Results); + void ReportErrors(const std::vector >& Results); [[nodiscard]] std::shared_ptr EnqueueScript(TLuaStateId StateID, const TLuaChunk& Script); [[nodiscard]] std::shared_ptr EnqueueFunctionCall(TLuaStateId StateID, const std::string& FunctionName, const std::vector& Args); void EnsureStateExists(TLuaStateId StateId, const std::string& Name, bool DontCallOnInit = false); diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 3b60317..e43b0a3 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -143,7 +143,7 @@ void TLuaEngine::WaitForAll(std::vector>& Results) { } // run this on the error checking thread -void TLuaEngine::IgnoreIfNotError(const std::vector>& Results) { +void TLuaEngine::ReportErrors(const std::vector>& Results) { std::unique_lock Lock2(mResultsToCheckMutex); for (const auto& Result : Results) { mResultsToCheck.push(Result); diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index f0c1c28..6ba9972 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -330,6 +330,8 @@ void TNetwork::Authentication(const TConnection& ClientConnection) { ClientKick(*Client, Reason); return; } + + LuaAPI::MP::Engine->ReportErrors(Futures); if (mServer.ClientCount() < size_t(Application::Settings.MaxPlayers)) { beammp_info("Identification success"); @@ -571,7 +573,7 @@ void TNetwork::OnDisconnect(const std::weak_ptr& ClientPtr, bool kicked SendToAll(&c, Packet, false, true); Packet.clear(); auto Futures = LuaAPI::MP::Engine->TriggerEvent("onPlayerDisconnect", "", c.GetID()); - LuaAPI::MP::Engine->IgnoreIfNotError(Futures); + LuaAPI::MP::Engine->ReportErrors(Futures); if (c.GetTCPSock()) CloseSocketProper(c.GetTCPSock()); if (c.GetDownSock()) @@ -605,13 +607,13 @@ void TNetwork::OnConnect(const std::weak_ptr& c) { auto LockedClient = c.lock(); LockedClient->SetID(OpenID()); beammp_info("Assigned ID " + std::to_string(LockedClient->GetID()) + " to " + LockedClient->GetName()); - LuaAPI::MP::Engine->IgnoreIfNotError(LuaAPI::MP::Engine->TriggerEvent("onPlayerConnecting", "", LockedClient->GetID())); + LuaAPI::MP::Engine->ReportErrors(LuaAPI::MP::Engine->TriggerEvent("onPlayerConnecting", "", LockedClient->GetID())); SyncResources(*LockedClient); if (LockedClient->GetStatus() < 0) return; (void)Respond(*LockedClient, "M" + Application::Settings.MapName, true); //Send the Map on connect beammp_info(LockedClient->GetName() + " : Connected"); - LuaAPI::MP::Engine->IgnoreIfNotError(LuaAPI::MP::Engine->TriggerEvent("onPlayerJoining", "", LockedClient->GetID())); + LuaAPI::MP::Engine->ReportErrors(LuaAPI::MP::Engine->TriggerEvent("onPlayerJoining", "", LockedClient->GetID())); } void TNetwork::SyncResources(TClient& c) { @@ -810,7 +812,7 @@ bool TNetwork::SyncClient(const std::weak_ptr& c) { // ignore error (void)SendToAll(LockedClient.get(), ("JWelcome ") + LockedClient->GetName() + "!", false, true); - LuaAPI::MP::Engine->IgnoreIfNotError(LuaAPI::MP::Engine->TriggerEvent("onPlayerJoin", "", LockedClient->GetID())); + LuaAPI::MP::Engine->ReportErrors(LuaAPI::MP::Engine->TriggerEvent("onPlayerJoin", "", LockedClient->GetID())); LockedClient->SetIsSyncing(true); bool Return = false; bool res = true; diff --git a/src/TServer.cpp b/src/TServer.cpp index 8b3249a..ac466a4 100644 --- a/src/TServer.cpp +++ b/src/TServer.cpp @@ -162,7 +162,7 @@ void TServer::HandleEvent(TClient& c, const std::string& Data) { Name = t; break; case 2: - LuaAPI::MP::Engine->IgnoreIfNotError(LuaAPI::MP::Engine->TriggerEvent(Name, "", c.GetID(), t)); + LuaAPI::MP::Engine->ReportErrors(LuaAPI::MP::Engine->TriggerEvent(Name, "", c.GetID(), t)); break; default: break; @@ -282,7 +282,7 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ c.SetUnicycleID(-1); } Network.SendToAll(nullptr, Packet, true, true); - LuaAPI::MP::Engine->IgnoreIfNotError(LuaAPI::MP::Engine->TriggerEvent("onVehicleDeleted", "", c.GetID(), VID)); + LuaAPI::MP::Engine->ReportErrors(LuaAPI::MP::Engine->TriggerEvent("onVehicleDeleted", "", c.GetID(), VID)); c.DeleteCar(VID); beammp_debug(c.GetName() + (" deleted car with ID ") + std::to_string(VID)); } @@ -300,7 +300,7 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ if (PID != -1 && VID != -1 && PID == c.GetID()) { Data = Data.substr(Data.find('{')); - LuaAPI::MP::Engine->IgnoreIfNotError(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, Packet, false, true); } return; From d1f890752a7fafd41d8d5025c9bdd948ff40d53e Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 1 Oct 2021 03:56:18 +0200 Subject: [PATCH 172/255] Report errors on WaitForAll --- src/TLuaEngine.cpp | 5 ++++- src/TNetwork.cpp | 2 -- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index e43b0a3..a3f3150 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -65,7 +65,7 @@ void TLuaEngine::operator()() { } } if (Res->Error) { - beammp_lua_error(Res->ErrorMessage); + beammp_lua_error(Res->Function + ": " + Res->ErrorMessage); } } } @@ -139,6 +139,9 @@ void TLuaEngine::WaitForAll(std::vector>& Results) { while (!Result->Ready) { std::this_thread::sleep_for(std::chrono::milliseconds(10)); } + if (Result->Error) { + beammp_lua_error(Result->Function + ": " + Result->ErrorMessage); + } } } diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index 6ba9972..53b1087 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -331,8 +331,6 @@ void TNetwork::Authentication(const TConnection& ClientConnection) { return; } - LuaAPI::MP::Engine->ReportErrors(Futures); - if (mServer.ClientCount() < size_t(Application::Settings.MaxPlayers)) { beammp_info("Identification success"); mServer.InsertClient(Client); From 1ee45c9d1a4d4daca02b22ac4ea888b67a0b9148 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 1 Oct 2021 04:09:40 +0200 Subject: [PATCH 173/255] Ignore BEAMMP_FN_NOT_FOUND errors --- src/TLuaEngine.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index a3f3150..207b7cd 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -65,7 +65,9 @@ void TLuaEngine::operator()() { } } if (Res->Error) { - beammp_lua_error(Res->Function + ": " + Res->ErrorMessage); + if (Res->ErrorMessage != BeamMPFnNotFoundError) { + beammp_lua_error(Res->Function + ": " + Res->ErrorMessage); + } } } } @@ -140,7 +142,9 @@ void TLuaEngine::WaitForAll(std::vector>& Results) { std::this_thread::sleep_for(std::chrono::milliseconds(10)); } if (Result->Error) { - beammp_lua_error(Result->Function + ": " + Result->ErrorMessage); + if (Result->ErrorMessage != BeamMPFnNotFoundError) { + beammp_lua_error(Result->Function + ": " + Result->ErrorMessage); + } } } } From af14188ec0225539e2e4614a55368d8d60cead32 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 1 Oct 2021 04:22:33 +0200 Subject: [PATCH 174/255] remove spammy debug --- src/TLuaEngine.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 207b7cd..905f338 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -564,7 +564,6 @@ void TLuaEngine::StateThreadData::operator()() { Result->StateId = mStateId; sol::state_view StateView(mState); auto Fn = StateView[FnName]; - beammp_debug("something found in the queue: call to \"" + FnName + "\" in \"" + mStateId + "\""); if (Fn.valid() && Fn.get_type() == sol::type::function) { std::vector LuaArgs; for (const auto& Arg : Args) { From d027f7f29fb2bd828ffaca3c6aa96e2a0bb1e487 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sat, 2 Oct 2021 01:28:58 +0200 Subject: [PATCH 175/255] Lua: Kick properly (with ClientKick), add chat message printing --- src/Common.cpp | 2 ++ src/LuaAPI.cpp | 8 ++------ src/TConsole.cpp | 1 - src/TNetwork.cpp | 1 + 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/Common.cpp b/src/Common.cpp index 7bfae72..5216c81 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -142,6 +142,7 @@ std::string Version::AsString() { void LogChatMessage(const std::string& name, int id, const std::string& msg) { std::stringstream ss; + ss << ThreadName(); ss << "[CHAT] "; if (id != -1) { ss << "(" << id << ") <" << name << ">"; @@ -149,6 +150,7 @@ void LogChatMessage(const std::string& name, int id, const std::string& msg) { ss << name << ""; } ss << msg; + Application::Console().Write(ss.str()); } std::string GetPlatformAgnosticErrorString() { diff --git a/src/LuaAPI.cpp b/src/LuaAPI.cpp index fba9264..d420d9a 100644 --- a/src/LuaAPI.cpp +++ b/src/LuaAPI.cpp @@ -118,15 +118,11 @@ bool LuaAPI::MP::TriggerClientEvent(int PlayerID, const std::string& EventName, void LuaAPI::MP::DropPlayer(int ID, std::optional MaybeReason) { auto MaybeClient = GetClient(Engine->Server(), ID); if (!MaybeClient || MaybeClient.value().expired()) { + beammp_lua_error("Tried to drop client with id " + std::to_string(ID) + ", who doesn't exist"); return; } auto c = MaybeClient.value().lock(); - if (!Engine->Network().Respond(*c, "C:Server:You have been Kicked from the server! Reason: " + MaybeReason.value_or("No reason"), true)) { - // Ignore - } - c->SetStatus(-2); - beammp_info("Closing socket due to kick"); - CloseSocketProper(c->GetTCPSock()); + LuaAPI::MP::Engine->Network().ClientKick(*c, MaybeReason.value_or("No reason")); } void LuaAPI::MP::SendChatMessage(int ID, const std::string& Message) { diff --git a/src/TConsole.cpp b/src/TConsole.cpp index 6efebd9..bc6e285 100644 --- a/src/TConsole.cpp +++ b/src/TConsole.cpp @@ -107,7 +107,6 @@ TConsole::TConsole() { void TConsole::Write(const std::string& str) { auto ToWrite = GetDate() + str; mCommandline.write(ToWrite); - // TODO write to logfile, too } void TConsole::WriteRaw(const std::string& str) { diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index 53b1087..326f735 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -458,6 +458,7 @@ void TNetwork::ClientKick(TClient& c, const std::string& R) { if (c.GetDownSock()) CloseSocketProper(c.GetDownSock()); } + void TNetwork::Looper(const std::weak_ptr& c) { while (!c.expired()) { auto Client = c.lock(); From 577d4c429d4090fdabcc0791a89a24007b3a26b2 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sat, 2 Oct 2021 01:44:13 +0200 Subject: [PATCH 176/255] TNetwork: Use 'K' packet instead of 'E' to kick players --- src/TNetwork.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index 326f735..d71e23d 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -447,7 +447,7 @@ std::string TNetwork::TCPRcv(TClient& c) { void TNetwork::ClientKick(TClient& c, const std::string& R) { beammp_info("Client kicked: " + R); - if (!TCPSend(c, "E" + R)) { + if (!TCPSend(c, "K" + R)) { // TODO handle } c.SetStatus(-2); From c4d6aab08ba2bb2e5f4265cca3c5f964040a87d3 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 8 Oct 2021 08:44:20 +0200 Subject: [PATCH 177/255] fix MP.HttpGET (was not passing contentType) --- src/Http.cpp | 2 +- src/TServer.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Http.cpp b/src/Http.cpp index b58360f..6e2f2bd 100644 --- a/src/Http.cpp +++ b/src/Http.cpp @@ -134,7 +134,7 @@ std::string GenericRequest(http::verb verb, const std::string& host, int port, c } std::string Http::GET(const std::string& host, int port, const std::string& target, unsigned int* status) { - return GenericRequest(http::verb::get, host, port, target, {}, {}, {}, status); + return GenericRequest(http::verb::get, host, port, target, {}, {}, content_type, status); } std::string Http::POST(const std::string& host, int port, const std::string& target, const std::unordered_map& fields, const std::string& body, const std::string& ContentType, unsigned int* status) { diff --git a/src/TServer.cpp b/src/TServer.cpp index ac466a4..2fe077f 100644 --- a/src/TServer.cpp +++ b/src/TServer.cpp @@ -282,6 +282,7 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ c.SetUnicycleID(-1); } Network.SendToAll(nullptr, Packet, true, true); + // TODO: should this trigger on all vehicle deletions? LuaAPI::MP::Engine->ReportErrors(LuaAPI::MP::Engine->TriggerEvent("onVehicleDeleted", "", c.GetID(), VID)); c.DeleteCar(VID); beammp_debug(c.GetName() + (" deleted car with ID ") + std::to_string(VID)); From 6189aed6e70893ce6d92e3b25420c6c619ddb607 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Tue, 26 Oct 2021 02:08:02 +0200 Subject: [PATCH 178/255] broadcast Om packets --- src/TServer.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/TServer.cpp b/src/TServer.cpp index 2fe077f..e040c36 100644 --- a/src/TServer.cpp +++ b/src/TServer.cpp @@ -309,6 +309,9 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ beammp_trace(std::string(("got 'Ot' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); Network.SendToAll(&c, Packet, false, true); return; + case 'm': + Network.SendToAll(&c, Packet, false, true); + return; default: beammp_trace(std::string(("possibly not implemented: '") + Packet + ("' (") + std::to_string(Packet.size()) + (")"))); return; From 6de625682d352ac0c9a0e6da49864e5492c4e285 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Tue, 26 Oct 2021 02:12:17 +0200 Subject: [PATCH 179/255] fix compiler error, empty content_type does nothing now --- src/Http.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Http.cpp b/src/Http.cpp index 6e2f2bd..d7faad7 100644 --- a/src/Http.cpp +++ b/src/Http.cpp @@ -58,8 +58,10 @@ std::string GenericRequest(http::verb verb, const std::string& host, int port, c req.set(http::field::host, host); if (!body.empty()) { - req.set(http::field::content_type, ContentType); // "application/json" - // "application/x-www-form-urlencoded" + if (!ContentType.empty()) { + req.set(http::field::content_type, ContentType); // "application/json" + // "application/x-www-form-urlencoded" + } req.set(http::field::content_length, std::to_string(body.size())); req.body() = body; @@ -134,7 +136,7 @@ std::string GenericRequest(http::verb verb, const std::string& host, int port, c } std::string Http::GET(const std::string& host, int port, const std::string& target, unsigned int* status) { - return GenericRequest(http::verb::get, host, port, target, {}, {}, content_type, status); + return GenericRequest(http::verb::get, host, port, target, {}, {}, "", status); } std::string Http::POST(const std::string& host, int port, const std::string& target, const std::unordered_map& fields, const std::string& body, const std::string& ContentType, unsigned int* status) { @@ -143,7 +145,7 @@ std::string Http::POST(const std::string& host, int port, const std::string& tar // RFC 2616, RFC 7231 static std::map Map = { - { -1, "Invalid Response Code"}, + { -1, "Invalid Response Code" }, { 100, "Continue" }, { 101, "Switching Protocols" }, { 102, "Processing" }, From 7287fce3412923ed91e7341891b30c13878aa2aa Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Tue, 26 Oct 2021 02:22:03 +0200 Subject: [PATCH 180/255] possible actions fix thank you, anon! --- .github/workflows/cmake-windows.yml | 2 +- .github/workflows/release-build.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cmake-windows.yml b/.github/workflows/cmake-windows.yml index adbeb4b..e4c5fac 100644 --- a/.github/workflows/cmake-windows.yml +++ b/.github/workflows/cmake-windows.yml @@ -15,7 +15,7 @@ jobs: submodules: 'recursive' - name: Restore artifacts, or run vcpkg, build and cache artifacts - uses: lukka/run-vcpkg@main + uses: lukka/run-vcpkg@v7 id: runvcpkg with: vcpkgArguments: 'lua zlib rapidjson boost-beast boost-asio openssl websocketpp curl' diff --git a/.github/workflows/release-build.yml b/.github/workflows/release-build.yml index 3392448..97abe0c 100644 --- a/.github/workflows/release-build.yml +++ b/.github/workflows/release-build.yml @@ -82,7 +82,7 @@ jobs: submodules: 'recursive' - name: Restore artifacts, or run vcpkg, build and cache artifacts - uses: lukka/run-vcpkg@main + uses: lukka/run-vcpkg@v7 id: runvcpkg with: vcpkgArguments: 'lua zlib rapidjson boost-beast boost-asio openssl websocketpp curl' From 50589fbe3d7516d379b52c005d7cc3b67b601357 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Tue, 26 Oct 2021 17:39:59 +0200 Subject: [PATCH 181/255] send 'Om' to self --- src/TServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TServer.cpp b/src/TServer.cpp index e040c36..3d9f7a7 100644 --- a/src/TServer.cpp +++ b/src/TServer.cpp @@ -310,7 +310,7 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ Network.SendToAll(&c, Packet, false, true); return; case 'm': - Network.SendToAll(&c, Packet, false, true); + Network.SendToAll(&c, Packet, true, true); return; default: beammp_trace(std::string(("possibly not implemented: '") + Packet + ("' (") + std::to_string(Packet.size()) + (")"))); From fdc205f52139c636ba5be12b42f81c905605ee70 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sun, 31 Oct 2021 01:27:21 +0200 Subject: [PATCH 182/255] Add ScopedTimer, Remove some comments --- CMakeLists.txt | 1 + include/TScopedTimer.h | 19 +++++++++++++++++++ include/TServer.h | 3 +++ src/TScopedTimer.cpp | 27 +++++++++++++++++++++++++++ src/TServer.cpp | 4 ---- src/main.cpp | 3 ++- 6 files changed, 52 insertions(+), 5 deletions(-) create mode 100644 include/TScopedTimer.h create mode 100644 src/TScopedTimer.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 0d7a13f..4be7b20 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,6 +91,7 @@ add_executable(BeamMP-Server include/TPPSMonitor.h src/TPPSMonitor.cpp include/TNetwork.h src/TNetwork.cpp include/LuaAPI.h src/LuaAPI.cpp + include/TScopedTimer.h src/TScopedTimer.cpp include/SignalHandling.h src/SignalHandling.cpp) target_compile_definitions(BeamMP-Server PRIVATE SECRET_SENTRY_URL="${BEAMMP_SECRET_SENTRY_URL}") diff --git a/include/TScopedTimer.h b/include/TScopedTimer.h new file mode 100644 index 0000000..3eea0ee --- /dev/null +++ b/include/TScopedTimer.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include +#include + +class TScopedTimer { +public: + TScopedTimer(); + TScopedTimer(const std::string& Name); + TScopedTimer(std::function OnDestroy); + ~TScopedTimer(); + + std::function OnDestroy { nullptr }; + +private: + std::chrono::high_resolution_clock::time_point mStartTime; + std::string Name; +}; diff --git a/include/TServer.h b/include/TServer.h index 472bfce..71025d1 100644 --- a/include/TServer.h +++ b/include/TServer.h @@ -2,6 +2,7 @@ #include "IThreaded.h" #include "RWMutex.h" +#include "TScopedTimer.h" #include #include #include @@ -27,6 +28,7 @@ public: static void GlobalParser(const std::weak_ptr& Client, std::string Packet, TPPSMonitor& PPSMonitor, TNetwork& Network); static void HandleEvent(TClient& c, const std::string& Data); RWMutex& GetClientMutex() const { return mClientsMutex; } + private: TClientSet mClients; mutable RWMutex mClientsMutex; @@ -34,4 +36,5 @@ private: static bool ShouldSpawn(TClient& c, const std::string& CarJson, int ID); static bool IsUnicycle(TClient& c, const std::string& CarJson); static void Apply(TClient& c, int VID, const std::string& pckt); + TScopedTimer mLifeTimer { "Server" }; }; diff --git a/src/TScopedTimer.cpp b/src/TScopedTimer.cpp new file mode 100644 index 0000000..9e15056 --- /dev/null +++ b/src/TScopedTimer.cpp @@ -0,0 +1,27 @@ +#include "TScopedTimer.h" +#include "Common.h" + +TScopedTimer::TScopedTimer() + : mStartTime(std::chrono::high_resolution_clock::now()) { +} + +TScopedTimer::TScopedTimer(const std::string& mName) + : mStartTime(std::chrono::high_resolution_clock::now()) + , Name(mName) { +} + +TScopedTimer::TScopedTimer(std::function OnDestroy) + : OnDestroy(OnDestroy) + , mStartTime(std::chrono::high_resolution_clock::now()) { +} + +TScopedTimer::~TScopedTimer() { + auto EndTime = std::chrono::high_resolution_clock::now(); + auto Delta = EndTime - mStartTime; + size_t TimeDelta = Delta / std::chrono::milliseconds(1); + if (OnDestroy) { + OnDestroy(TimeDelta); + } else { + beammp_info("Scoped timer: \"" + Name + "\" took " + std::to_string(TimeDelta) + "ms "); + } +} diff --git a/src/TServer.cpp b/src/TServer.cpp index 3d9f7a7..6ef4b07 100644 --- a/src/TServer.cpp +++ b/src/TServer.cpp @@ -93,7 +93,6 @@ void TServer::GlobalParser(const std::weak_ptr& Client, std::string Pac switch (Code) { case 'H': // initial connection beammp_trace(std::string("got 'H' packet: '") + Packet + "' (" + std::to_string(Packet.size()) + ")"); - beammp_debug(std::string("got 'H' packet: '") + Packet + "' (" + std::to_string(Packet.size()) + ")"); if (!Network.SyncClient(Client)) { // TODO handle } @@ -116,12 +115,10 @@ void TServer::GlobalParser(const std::weak_ptr& Client, std::string Pac return; case 'J': beammp_trace(std::string(("got 'J' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); - beammp_debug(std::string(("got 'J' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); Network.SendToAll(LockedClient.get(), Packet, false, true); return; case 'C': { beammp_trace(std::string(("got 'C' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); - beammp_debug(std::string(("got 'C' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); if (Packet.length() < 4 || Packet.find(':', 3) == std::string::npos) break; auto Futures = LuaAPI::MP::Engine->TriggerEvent("onChatMessage", "", LockedClient->GetID(), LockedClient->GetName(), Packet.substr(Packet.find(':', 3) + 1)); @@ -140,7 +137,6 @@ void TServer::GlobalParser(const std::weak_ptr& Client, std::string Pac } case 'E': beammp_trace(std::string(("got 'E' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); - beammp_debug(std::string(("got 'E' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); HandleEvent(*LockedClient, Packet); return; case 'N': diff --git a/src/main.cpp b/src/main.cpp index d8c5255..a2b8aa1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -11,6 +11,7 @@ #include "TNetwork.h" #include "TPPSMonitor.h" #include "TResourceManager.h" +#include "TScopedTimer.h" #include "TServer.h" #include @@ -49,7 +50,6 @@ int main(int argc, char** argv) try { RegisterThread("Main"); beammp_trace("Running in debug mode on a debug build"); - Sentry.SetupUser(); Sentry.PrintWelcome(); TResourceManager ResourceManager; @@ -66,6 +66,7 @@ int main(int argc, char** argv) try { std::this_thread::sleep_for(std::chrono::milliseconds(50)); } beammp_info("Shutdown."); + return 0; } catch (const std::exception& e) { beammp_error(e.what()); Sentry.LogException(e, _file_basename, _line); From 9f5fa8fb9b643702029ea24b80597cc8dab1067e Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sat, 6 Nov 2021 13:03:20 +0100 Subject: [PATCH 183/255] Remove libzip --- CMakeLists.txt | 7 ++----- src/TConsole.cpp | 9 +++++++++ src/TPPSMonitor.cpp | 2 +- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4be7b20..acac6e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,9 +30,6 @@ endif() set(SENTRY_BACKEND breakpad) add_subdirectory("deps/sentry-native") -set(BUILD_SHARED_LIBS OFF) -add_subdirectory("deps/libzip") - message(STATUS "Setting compiler flags") if (WIN32) @@ -95,7 +92,7 @@ add_executable(BeamMP-Server include/SignalHandling.h src/SignalHandling.cpp) target_compile_definitions(BeamMP-Server PRIVATE SECRET_SENTRY_URL="${BEAMMP_SECRET_SENTRY_URL}") -include_directories(BeamMP-Server PUBLIC ${libzip_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}/include) +include_directories(BeamMP-Server PUBLIC ${Boost_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}/include) target_include_directories(BeamMP-Server PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" @@ -115,7 +112,7 @@ message(STATUS "Looking for SSL") find_package(OpenSSL REQUIRED) -target_link_libraries(BeamMP-Server sol2::sol2 ${LUA_LIBRARIES} libzip::zip) +target_link_libraries(BeamMP-Server sol2::sol2 ${LUA_LIBRARIES}) message(STATUS "CURL IS ${CURL_LIBRARIES}") if (UNIX) diff --git a/src/TConsole.cpp b/src/TConsole.cpp index bc6e285..77734e2 100644 --- a/src/TConsole.cpp +++ b/src/TConsole.cpp @@ -35,6 +35,14 @@ std::string GetDate() { void TConsole::BackupOldLog() { fs::path Path = "Server.log"; if (fs::exists(Path)) { + auto OldLog = Path.filename().stem().string() + ".old.log"; + try { + fs::rename(Path, OldLog); + beammp_debug("renamed old log file to '" + OldLog + "'"); + } catch (const std::exception& e) { + beammp_warn(e.what()); + } + /* int err = 0; zip* z = zip_open("ServerLogs.zip", ZIP_CREATE, &err); if (!z) { @@ -68,6 +76,7 @@ void TConsole::BackupOldLog() { zip_file_add(z, NewName.c_str(), s, 0); zip_close(z); + */ } } diff --git a/src/TPPSMonitor.cpp b/src/TPPSMonitor.cpp index 9962107..9ea80dc 100644 --- a/src/TPPSMonitor.cpp +++ b/src/TPPSMonitor.cpp @@ -21,7 +21,7 @@ void TPPSMonitor::operator()() { // hard spi std::this_thread::sleep_for(std::chrono::milliseconds(1)); } - beammp_info("PPSMonitor starting"); + beammp_debug("PPSMonitor starting"); std::vector> TimedOutClients; while (!mShutdown) { std::this_thread::sleep_for(std::chrono::seconds(1)); From 1e305c3c90d17ffd38e072cebc2dc840574f47ea Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sun, 7 Nov 2021 23:09:06 +0100 Subject: [PATCH 184/255] Http: cleanup --- src/Http.cpp | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/Http.cpp b/src/Http.cpp index d7faad7..9d7203e 100644 --- a/src/Http.cpp +++ b/src/Http.cpp @@ -32,9 +32,6 @@ std::string GenericRequest(http::verb verb, const std::string& host, int port, c results = resolver.resolve(protocol, host, std::to_string(port)); if (!SSL_set_tlsext_host_name(stream.native_handle(), host.c_str())) { boost::system::error_code ec { static_cast(::ERR_get_error()), boost::asio::error::get_ssl_category() }; - // FIXME: we could throw and crash, if we like - // throw boost::system::system_error { ec }; - //debug("POST " + host + target + " failed."); return false; } beast::get_lowest_layer(stream).connect(results); @@ -43,16 +40,12 @@ std::string GenericRequest(http::verb verb, const std::string& host, int port, c } return true; }; - //bool ok = try_connect_with_protocol(tcp::v6()); - //if (!ok) { - //debug("IPv6 connect failed, trying IPv4"); bool ok = try_connect_with_protocol(tcp::v4()); if (!ok) { Application::Console().Write("[ERROR] failed to resolve or connect in POST " + host + target); Sentry.AddErrorBreadcrumb("failed to resolve or connect to " + host + target, __FILE__, std::to_string(__LINE__)); // FIXME: this is ugly. return "-1"; } - //} stream.handshake(ssl::stream_base::client); http::request req { verb, target, 11 /* http 1.1 */ }; @@ -65,11 +58,8 @@ std::string GenericRequest(http::verb verb, const std::string& host, int port, c req.set(http::field::content_length, std::to_string(body.size())); req.body() = body; - // beammp_info("body is " + body + " (" + req.body() + ")"); - // beammp_info("content size is " + std::to_string(body.size()) + " (" + boost::lexical_cast(body.size()) + ")"); } for (const auto& pair : fields) { - // beammp_info("setting " + pair.first + " to " + pair.second); req.set(pair.first, pair.second); } @@ -81,7 +71,7 @@ std::string GenericRequest(http::verb verb, const std::string& host, int port, c std::string ValueString(header.value()); request_data[KeyString] = ValueString; } - Sentry.SetContext("https-post-request-data", request_data); + Sentry.SetContext("https-request-data", request_data); std::stringstream oss; oss << req; @@ -108,7 +98,7 @@ std::string GenericRequest(http::verb verb, const std::string& host, int port, c std::string ValueString(header.value()); response_data[KeyString] = ValueString; } - Sentry.SetContext("https-post-response-data", response_data); + Sentry.SetContext("https-response-data", response_data); if (status) { *status = response.base().result_int(); @@ -121,11 +111,9 @@ std::string GenericRequest(http::verb verb, const std::string& host, int port, c stream.shutdown(ec); // IGNORING ec - // beammp_info(result.str()); std::string debug_response_str; std::getline(result, debug_response_str); - //debug("POST " + host + target + ": " + debug_response_str); return std::string(response.body()); } catch (const std::exception& e) { From 701a7feee3ca4e7faf1c9596b6c99dff5672bbf2 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sun, 7 Nov 2021 23:54:33 +0100 Subject: [PATCH 185/255] remove boost, add httplib, temporarily remove http* lua --- .github/workflows/cmake-linux.yml | 2 - .github/workflows/cmake-windows.yml | 2 +- .gitmodules | 3 + CMakeLists.txt | 11 +-- README.md | 9 +- deps/cpp-httplib | 1 + include/Http.h | 2 +- src/Http.cpp | 139 +++++----------------------- src/THeartbeatThread.cpp | 6 +- src/TLuaEngine.cpp | 13 +-- src/TNetwork.cpp | 2 +- 11 files changed, 43 insertions(+), 147 deletions(-) create mode 160000 deps/cpp-httplib diff --git a/.github/workflows/cmake-linux.yml b/.github/workflows/cmake-linux.yml index 098deaa..3ddf653 100644 --- a/.github/workflows/cmake-linux.yml +++ b/.github/workflows/cmake-linux.yml @@ -21,8 +21,6 @@ jobs: echo ${#beammp_sentry_url} sudo apt-get update sudo apt-get install -y libz-dev rapidjson-dev liblua5.3 libssl-dev libwebsocketpp-dev libcurl4-openssl-dev - sudo add-apt-repository ppa:mhier/libboost-latest - sudo apt-get install -y libboost1.70-dev libboost1.70 - name: Create Build Environment run: cmake -E make_directory ${{github.workspace}}/build-linux diff --git a/.github/workflows/cmake-windows.yml b/.github/workflows/cmake-windows.yml index e4c5fac..9ea76a7 100644 --- a/.github/workflows/cmake-windows.yml +++ b/.github/workflows/cmake-windows.yml @@ -18,7 +18,7 @@ jobs: uses: lukka/run-vcpkg@v7 id: runvcpkg with: - vcpkgArguments: 'lua zlib rapidjson boost-beast boost-asio openssl websocketpp curl' + vcpkgArguments: 'lua zlib rapidjson openssl websocketpp curl' vcpkgDirectory: '${{ runner.workspace }}/b/vcpkg' vcpkgGitCommitId: '8dddc6c899ce6fdbeab38b525a31e7f23cb2d5bb' vcpkgTriplet: 'x64-windows-static' diff --git a/.gitmodules b/.gitmodules index 1822884..d81806c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -22,3 +22,6 @@ [submodule "deps/libzip"] path = deps/libzip url = https://github.com/nih-at/libzip +[submodule "deps/cpp-httplib"] + path = deps/cpp-httplib + url = https://github.com/yhirose/cpp-httplib diff --git a/CMakeLists.txt b/CMakeLists.txt index acac6e2..b21de0e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,8 +13,11 @@ include_directories("${PROJECT_SOURCE_DIR}/deps/rapidjson/include") include_directories("${PROJECT_SOURCE_DIR}/deps/websocketpp") include_directories("${PROJECT_SOURCE_DIR}/deps/commandline") include_directories("${PROJECT_SOURCE_DIR}/deps/sol2/include") +include_directories("${PROJECT_SOURCE_DIR}/deps/cpp-httplib") include_directories("${PROJECT_SOURCE_DIR}/deps") +add_compile_definitions(CPPHTTPLIB_OPENSSL_SUPPORT) + if (WIN32) # this has to happen before sentry, so that crashpad on windows links with these settings. message(STATUS "MSVC -> forcing use of statically-linked runtime.") @@ -67,9 +70,6 @@ set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG") -message(STATUS "Looking for Boost") -find_package(Boost REQUIRED COMPONENTS system thread) - add_executable(BeamMP-Server src/main.cpp include/TConsole.h src/TConsole.cpp @@ -92,7 +92,7 @@ add_executable(BeamMP-Server include/SignalHandling.h src/SignalHandling.cpp) target_compile_definitions(BeamMP-Server PRIVATE SECRET_SENTRY_URL="${BEAMMP_SECRET_SENTRY_URL}") -include_directories(BeamMP-Server PUBLIC ${Boost_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}/include) +include_directories(BeamMP-Server PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) target_include_directories(BeamMP-Server PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" @@ -101,7 +101,6 @@ target_include_directories(BeamMP-Server PUBLIC message(STATUS "Looking for Lua") find_package(Lua REQUIRED) target_include_directories(BeamMP-Server PUBLIC - ${Boost_INCLUDE_DIRS} ${LUA_INCLUDE_DIR} ${CURL_INCLUDE_DIRS} "include/tomlplusplus" @@ -131,7 +130,7 @@ elseif (WIN32) find_package(ZLIB REQUIRED) message(STATUS "Looking for RapidJSON") find_package(RapidJSON CONFIG REQUIRED) - target_include_directories(BeamMP-Server PRIVATE ${RAPIDJSON_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}) + target_include_directories(BeamMP-Server PRIVATE ${RAPIDJSON_INCLUDE_DIRS}) target_link_libraries(BeamMP-Server ws2_32 ZLIB::ZLIB diff --git a/README.md b/README.md index 7ad35c9..fe909d5 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ Currently only linux and windows are supported (generally). See [Releases](https Please use the prepackaged binaries in [Releases](https://github.com/BeamMP/BeamMP-Server/releases/). -Dependencies for windows can be installed with `vcpkg`, in which case the current dependencies are the `x64-windows-static` versions of `lua`, `zlib`, `rapidjson`, `boost-beast`, `boost-asio` and `openssl`. +Dependencies for windows can be installed with `vcpkg`, in which case the current dependencies are the `x64-windows-static` versions of `lua`, `zlib`, `rapidjson`, and `openssl`. #### Linux / \*nix @@ -72,19 +72,16 @@ These package names are in the debian / ubuntu style. Feel free to PR your own g - `rapidjson-dev` - `libopenssl-dev` or `libssl-dev` -**If** you're building it from source, you'll need `libboost1.70-all-dev` or `libboost1.71-all-dev` or higher as well. -If you can't find this version of boost (only 1.6x, for example), you can either update to a newer version of your distro, build boost yourself, or use an unstable rolling release (like Debian `sid` aka `unstable`). - In the end you should end up with a command something like this: ```sh -sudo apt install git make cmake g++-10 liblua5.3 libz-dev rapidjson-dev libopenssl-dev libboost1.71-all-dev +sudo apt install git make cmake g++-10 liblua5.3 libz-dev rapidjson-dev libopenssl-dev ``` In the end you should end up with a command something like this: ```sh -sudo apt install git make cmake g++-10 liblua5.3 libz-dev rapidjson-dev libopenssl-dev libboost1.71-all-dev +sudo apt install git make cmake g++-10 liblua5.3 libz-dev rapidjson-dev libopenssl-dev ``` ### How to build diff --git a/deps/cpp-httplib b/deps/cpp-httplib new file mode 160000 index 0000000..301faa0 --- /dev/null +++ b/deps/cpp-httplib @@ -0,0 +1 @@ +Subproject commit 301faa074c4a0fa1dbe470dfb4f77912caa1c57f diff --git a/include/Http.h b/include/Http.h index daf38da..568054b 100644 --- a/include/Http.h +++ b/include/Http.h @@ -5,7 +5,7 @@ namespace Http { std::string GET(const std::string& host, int port, const std::string& target, unsigned int* status = nullptr); -std::string POST(const std::string& host, int port, const std::string& target, const std::unordered_map& fields, const std::string& body, const std::string& ContentType, unsigned int* status = nullptr); +std::string POST(const std::string& host, int port, const std::string& target, const std::string& body, const std::string& ContentType, unsigned int* status = nullptr); namespace Status { std::string ToString(int code); } diff --git a/src/Http.cpp b/src/Http.cpp index 9d7203e..2ad735c 100644 --- a/src/Http.cpp +++ b/src/Http.cpp @@ -1,134 +1,39 @@ #include "Http.h" #include "Common.h" -#undef error -#include -#include -#include -#include #include -namespace beast = boost::beast; // from -namespace http = beast::http; // from -namespace net = boost::asio; // from -namespace ssl = net::ssl; // from -using tcp = net::ip::tcp; // from +#include -std::string GenericRequest(http::verb verb, const std::string& host, int port, const std::string& target, const std::unordered_map& fields, const std::string& body, const std::string& ContentType, unsigned int* status) { - try { - net::io_context io; +// TODO: Add sentry error handling back - // The SSL context is required, and holds certificates - ssl::context ctx(ssl::context::tlsv13); - - ctx.set_verify_mode(ssl::verify_none); - - tcp::resolver resolver(io); - beast::ssl_stream stream(io, ctx); - decltype(resolver)::results_type results; - auto try_connect_with_protocol = [&](tcp protocol) { - try { - results = resolver.resolve(protocol, host, std::to_string(port)); - if (!SSL_set_tlsext_host_name(stream.native_handle(), host.c_str())) { - boost::system::error_code ec { static_cast(::ERR_get_error()), boost::asio::error::get_ssl_category() }; - return false; - } - beast::get_lowest_layer(stream).connect(results); - } catch (const boost::system::system_error&) { - return false; - } - return true; - }; - bool ok = try_connect_with_protocol(tcp::v4()); - if (!ok) { - Application::Console().Write("[ERROR] failed to resolve or connect in POST " + host + target); - Sentry.AddErrorBreadcrumb("failed to resolve or connect to " + host + target, __FILE__, std::to_string(__LINE__)); // FIXME: this is ugly. - return "-1"; - } - stream.handshake(ssl::stream_base::client); - http::request req { verb, target, 11 /* http 1.1 */ }; - - req.set(http::field::host, host); - if (!body.empty()) { - if (!ContentType.empty()) { - req.set(http::field::content_type, ContentType); // "application/json" - // "application/x-www-form-urlencoded" - } - - req.set(http::field::content_length, std::to_string(body.size())); - req.body() = body; - } - for (const auto& pair : fields) { - req.set(pair.first, pair.second); - } - - std::unordered_map request_data; - for (const auto& header : req.base()) { - // need to do explicit casts to convert string_view to string - // since string_view may not be null-terminated (and in fact isn't, here) - std::string KeyString(header.name_string()); - std::string ValueString(header.value()); - request_data[KeyString] = ValueString; - } - Sentry.SetContext("https-request-data", request_data); - - std::stringstream oss; - oss << req; - - beast::get_lowest_layer(stream).expires_after(std::chrono::seconds(5)); - - http::write(stream, req); - - // used for reading - beast::flat_buffer buffer; - http::response response; - - http::read(stream, buffer, response); - - std::unordered_map response_data; - response_data["reponse-code"] = std::to_string(response.result_int()); +std::string Http::GET(const std::string& host, int port, const std::string& target, unsigned int* status) { + httplib::SSLClient client(host, port); + client.enable_server_certificate_verification(false); + auto res = client.Get(target.c_str()); + if (res) { if (status) { - *status = response.result_int(); + *status = res->status; } - for (const auto& header : response.base()) { - // need to do explicit casts to convert string_view to string - // since string_view may not be null-terminated (and in fact isn't, here) - std::string KeyString(header.name_string()); - std::string ValueString(header.value()); - response_data[KeyString] = ValueString; - } - Sentry.SetContext("https-response-data", response_data); - - if (status) { - *status = response.base().result_int(); - } - - std::stringstream result; - result << response; - - beast::error_code ec; - stream.shutdown(ec); - // IGNORING ec - - std::string debug_response_str; - std::getline(result, debug_response_str); - - return std::string(response.body()); - - } catch (const std::exception& e) { - Application::Console().Write(__func__ + std::string(": ") + e.what()); - Sentry.AddErrorBreadcrumb(e.what(), __FILE__, std::to_string(__LINE__)); // FIXME: this is ugly. + return res->body; + } else { return Http::ErrorString; } } -std::string Http::GET(const std::string& host, int port, const std::string& target, unsigned int* status) { - return GenericRequest(http::verb::get, host, port, target, {}, {}, "", status); -} - -std::string Http::POST(const std::string& host, int port, const std::string& target, const std::unordered_map& fields, const std::string& body, const std::string& ContentType, unsigned int* status) { - return GenericRequest(http::verb::post, host, port, target, fields, body, ContentType, status); +std::string Http::POST(const std::string& host, int port, const std::string& target, const std::string& body, const std::string& ContentType, unsigned int* status) { + httplib::SSLClient client(host, port); + client.enable_server_certificate_verification(false); + auto res = client.Post(target.c_str(), body.c_str(), body.size(), ContentType.c_str()); + if (res) { + if (status) { + *status = res->status; + } + return res->body; + } else { + return Http::ErrorString; + } } // RFC 2616, RFC 7231 diff --git a/src/THeartbeatThread.cpp b/src/THeartbeatThread.cpp index cd5aa83..92e8585 100644 --- a/src/THeartbeatThread.cpp +++ b/src/THeartbeatThread.cpp @@ -48,17 +48,17 @@ void THeartbeatThread::operator()() { auto Target = "/heartbeat"; unsigned int ResponseCode = 0; - T = Http::POST(Application::GetBackendHostname(), 443, Target, {}, Body, "application/x-www-form-urlencoded", &ResponseCode); + T = Http::POST(Application::GetBackendHostname(), 443, Target, Body, "application/x-www-form-urlencoded", &ResponseCode); if ((T.substr(0, 2) != "20" && ResponseCode != 200) || ResponseCode != 200) { beammp_trace("got " + T + " from backend"); SentryReportError(Application::GetBackendHostname() + Target, ResponseCode); std::this_thread::sleep_for(std::chrono::milliseconds(500)); - T = Http::POST(Application::GetBackup1Hostname(), 443, Target, {}, Body, "application/x-www-form-urlencoded", &ResponseCode); + T = Http::POST(Application::GetBackup1Hostname(), 443, Target, Body, "application/x-www-form-urlencoded", &ResponseCode); if ((T.substr(0, 2) != "20" && ResponseCode != 200) || ResponseCode != 200) { SentryReportError(Application::GetBackup1Hostname() + Target, ResponseCode); std::this_thread::sleep_for(std::chrono::milliseconds(500)); - T = Http::POST(Application::GetBackup2Hostname(), 443, Target, {}, Body, "application/x-www-form-urlencoded", &ResponseCode); + T = Http::POST(Application::GetBackup2Hostname(), 443, Target, Body, "application/x-www-form-urlencoded", &ResponseCode); if ((T.substr(0, 2) != "20" && ResponseCode != 200) || ResponseCode != 200) { beammp_warn("Backend system refused server! Server will not show in the public server list."); diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 905f338..c9bdd71 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -446,16 +446,9 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi mEngine->CancelEventTimers(EventName, mStateId); }); MPTable.set_function("Set", &LuaAPI::MP::Set); - MPTable.set_function("HttpsGET", [&](const std::string& Host, int Port, const std::string& Target) -> std::tuple { - unsigned Status; - auto Body = Http::GET(Host, Port, Target, &Status); - return { Status, Body }; - }); - MPTable.set_function("HttpsPOST", [&](const std::string& Host, int Port, const std::string& Target, const std::string& Body, const std::string& ContentType) -> std::tuple { - unsigned Status; - auto ResponseBody = Http::POST(Host, Port, Target, {}, Body, ContentType, &Status); - return { Status, ResponseBody }; - }); + auto HttpTable = StateView.create_named_table("Http"); + //HttpTable.set_function("CreateConnection", &LuaAPI::Http::CreateConnection); + MPTable.create_named("Settings", "Debug", 0, "Private", 1, diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index d71e23d..859579f 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -241,7 +241,7 @@ void TNetwork::Authentication(const TConnection& ClientConnection) { auto Target = "/pkToUser"; unsigned int ResponseCode = 0; if (!Rc.empty()) { - Rc = Http::POST(Application::GetBackendUrlForAuth(), 443, Target, {}, RequestString, "application/json", &ResponseCode); + Rc = Http::POST(Application::GetBackendUrlForAuth(), 443, Target, RequestString, "application/json", &ResponseCode); } json::Document AuthResponse; From 5fdd7beac8c3079ef5522492318e4d1a6dacab00 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sun, 7 Nov 2021 23:56:22 +0100 Subject: [PATCH 186/255] remove stray zip.h include --- src/TConsole.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/TConsole.cpp b/src/TConsole.cpp index 77734e2..4c49e96 100644 --- a/src/TConsole.cpp +++ b/src/TConsole.cpp @@ -6,7 +6,6 @@ #include #include -#include std::string GetDate() { std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); From 3e7aa763ed277da949305cad3931d9dc889b95dc Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 8 Nov 2021 00:01:41 +0100 Subject: [PATCH 187/255] fix release build --- .github/workflows/release-build.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/release-build.yml b/.github/workflows/release-build.yml index 97abe0c..8d2063a 100644 --- a/.github/workflows/release-build.yml +++ b/.github/workflows/release-build.yml @@ -43,8 +43,6 @@ jobs: run: | sudo apt-get update sudo apt-get install -y libz-dev rapidjson-dev liblua5.3 libssl-dev libwebsocketpp-dev libcurl4-openssl-dev - sudo add-apt-repository ppa:mhier/libboost-latest - sudo apt-get install -y libboost1.70-dev libboost1.70 - name: Create Build Environment run: cmake -E make_directory ${{github.workspace}}/build-linux @@ -85,7 +83,7 @@ jobs: uses: lukka/run-vcpkg@v7 id: runvcpkg with: - vcpkgArguments: 'lua zlib rapidjson boost-beast boost-asio openssl websocketpp curl' + vcpkgArguments: 'lua zlib rapidjson openssl websocketpp curl' vcpkgDirectory: '${{ runner.workspace }}/b/vcpkg' vcpkgGitCommitId: '8dddc6c899ce6fdbeab38b525a31e7f23cb2d5bb' vcpkgTriplet: 'x64-windows-static' From f8af134dc95178368ba944c382eb9950c10e5422 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 8 Nov 2021 22:08:07 +0100 Subject: [PATCH 188/255] start writing http lua stuff, also heartbeat debug printing --- include/TLuaEngine.h | 1 + src/THeartbeatThread.cpp | 6 ++++-- src/TLuaEngine.cpp | 36 ++++++++++++++++++++++++++++++++---- src/main.cpp | 10 ++++++---- 4 files changed, 43 insertions(+), 10 deletions(-) diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index 1c9de93..50d5235 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -137,6 +137,7 @@ private: sol::table Lua_GetPlayers(); std::string Lua_GetPlayerName(int ID); sol::table Lua_GetPlayerVehicles(int ID); + sol::table Lua_HttpCreateConnection(const std::string& host, uint16_t port); std::string mName; std::atomic_bool& mShutdown; diff --git a/src/THeartbeatThread.cpp b/src/THeartbeatThread.cpp index 92e8585..574eda3 100644 --- a/src/THeartbeatThread.cpp +++ b/src/THeartbeatThread.cpp @@ -30,13 +30,15 @@ void THeartbeatThread::operator()() { Last = Body; LastNormalUpdateTime = Now; - if (!Application::Settings.CustomIP.empty()) + if (!Application::Settings.CustomIP.empty()) { Body += "&ip=" + Application::Settings.CustomIP; + } Body += "&pps=" + Application::PPS(); - auto SentryReportError = [&](const std::string& transaction, int status) { + beammp_trace("heartbeat body: '" + Body + "'"); + auto SentryReportError = [&](const std::string& transaction, int status) { auto Lock = Sentry.CreateExclusiveContext(); Sentry.SetContext("heartbeat", { { "response-body", T }, diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index c9bdd71..fc330bb 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -90,12 +91,12 @@ void TLuaEngine::operator()() { } } } - if (std::chrono::high_resolution_clock::duration Diff; - (Diff = std::chrono::high_resolution_clock::now() - Before) + std::chrono::high_resolution_clock::duration Diff; + if ((Diff = std::chrono::high_resolution_clock::now() - Before) < std::chrono::milliseconds(10)) { std::this_thread::sleep_for(Diff); } else { - beammp_trace("Event loop cannot keep up!"); + beammp_trace("Event loop cannot keep up! Running " + std::to_string(Diff.count()) + "s behind"); } Before = std::chrono::high_resolution_clock::now(); } @@ -366,6 +367,28 @@ sol::table TLuaEngine::StateThreadData::Lua_GetPlayerVehicles(int ID) { return sol::nil; } +sol::table TLuaEngine::StateThreadData::Lua_HttpCreateConnection(const std::string& host, uint16_t port) { + auto table = mStateView.create_table(); + constexpr const char* InternalClient = "__InternalClient"; + table["host"] = host; + table["port"] = port; + auto client = std::make_shared(host, port); + table[InternalClient] = client; + table.set_function("Get", [&InternalClient](const sol::table& table, const std::string& path, const sol::table& headers) { + httplib::Headers GetHeaders; + for (const auto& pair : headers) { + if (pair.first.is() && pair.second.is()) { + GetHeaders.insert(std::pair(pair.first.as(), pair.second.as())); + } else { + beammp_lua_error("Http:Get: Expected string-string pairs for headers, got something else, ignoring that header"); + } + } + auto client = table[InternalClient].get>(); + client->Get(path.c_str(), GetHeaders); + }); + return table; +} + TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomic_bool& Shutdown, TLuaStateId StateId, TLuaEngine& Engine) : mName(Name) , mShutdown(Shutdown) @@ -447,7 +470,9 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi }); MPTable.set_function("Set", &LuaAPI::MP::Set); auto HttpTable = StateView.create_named_table("Http"); - //HttpTable.set_function("CreateConnection", &LuaAPI::Http::CreateConnection); + HttpTable.set_function("CreateConnection", [this](const std::string& host, uint16_t port) { + return Lua_HttpCreateConnection(host, port); + }); MPTable.create_named("Settings", "Debug", 0, @@ -658,6 +683,9 @@ TPluginMonitor::TPluginMonitor(const fs::path& Path, TLuaEngine& Engine, std::at : mEngine(Engine) , mPath(Path) , mShutdown(Shutdown) { + if (!fs::exists(mPath)) { + fs::create_directories(mPath); + } for (const auto& Entry : fs::recursive_directory_iterator(mPath)) { // TODO: trigger an event when a subfolder file changes if (Entry.is_regular_file()) { diff --git a/src/main.cpp b/src/main.cpp index a2b8aa1..7af0ae9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -21,7 +21,8 @@ // global, yes, this is ugly, no, it cant be done another way TSentry Sentry {}; -int main(int argc, char** argv) try { +int main(int argc, char** argv) //try { +{ setlocale(LC_ALL, "C"); SetupSignalHandlers(); @@ -67,7 +68,8 @@ int main(int argc, char** argv) try { } beammp_info("Shutdown."); return 0; -} catch (const std::exception& e) { - beammp_error(e.what()); - Sentry.LogException(e, _file_basename, _line); +//} catch (const std::exception& e) { +// beammp_error(e.what()); +// Sentry.LogException(e, _file_basename, _line); +//} } From b5ea084c9b201e3bece3c64f7312fdde1fd72490 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 8 Nov 2021 22:25:23 +0100 Subject: [PATCH 189/255] update commandline --- deps/commandline | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/commandline b/deps/commandline index 4931aa8..4b6ae33 160000 --- a/deps/commandline +++ b/deps/commandline @@ -1 +1 @@ -Subproject commit 4931aa89c1b400732394d8b8523974ed09f427dc +Subproject commit 4b6ae338caea7564479c2a7d6203794eb05feb7e From 7197c236323839deaddd281e0bc779e4195f90e9 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 8 Nov 2021 23:10:24 +0100 Subject: [PATCH 190/255] TNetwork: Possible ip address fix --- src/TNetwork.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index 859579f..5d511ea 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -205,9 +205,9 @@ void TNetwork::HandleDownload(SOCKET TCPSock) { void TNetwork::Authentication(const TConnection& ClientConnection) { auto Client = CreateClient(ClientConnection.Socket); - char AddrBuf[30]; - inet_ntoa(reinterpret_cast(&ClientConnection.SockAddr)->sin_addr); - auto str = inet_ntop(AF_INET, static_cast(reinterpret_cast(&ClientConnection.SockAddr)), AddrBuf, sizeof(struct sockaddr_in)); + char AddrBuf[64]; + // TODO: IPv6 would need this to be changed + auto str = inet_ntop(AF_INET, static_cast(reinterpret_cast(&ClientConnection.SockAddr)), AddrBuf, sizeof(ClientConnection.SockAddr)); Client->SetIdentifier("ip", str); std::string Rc; From 87f23427a142e05d855d9346d75f3b75d9092a10 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 8 Nov 2021 23:13:47 +0100 Subject: [PATCH 191/255] CMake: Nail down lua to be 5.3 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b21de0e..b0eab53 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -99,7 +99,7 @@ target_include_directories(BeamMP-Server PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/commandline") message(STATUS "Looking for Lua") -find_package(Lua REQUIRED) +find_package(Lua REQUIRED VERSION 5.3) target_include_directories(BeamMP-Server PUBLIC ${LUA_INCLUDE_DIR} ${CURL_INCLUDE_DIRS} From c36ea52f60ff9d1f162556cdf1b30315273f1b10 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 8 Nov 2021 23:45:35 +0100 Subject: [PATCH 192/255] Http: Use ipv4 --- src/Http.cpp | 2 ++ src/TNetwork.cpp | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Http.cpp b/src/Http.cpp index 2ad735c..609a4e8 100644 --- a/src/Http.cpp +++ b/src/Http.cpp @@ -11,6 +11,7 @@ std::string Http::GET(const std::string& host, int port, const std::string& target, unsigned int* status) { httplib::SSLClient client(host, port); client.enable_server_certificate_verification(false); + client.set_address_family(AF_INET); auto res = client.Get(target.c_str()); if (res) { if (status) { @@ -25,6 +26,7 @@ std::string Http::GET(const std::string& host, int port, const std::string& targ std::string Http::POST(const std::string& host, int port, const std::string& target, const std::string& body, const std::string& ContentType, unsigned int* status) { httplib::SSLClient client(host, port); client.enable_server_certificate_verification(false); + client.set_address_family(AF_INET); auto res = client.Post(target.c_str(), body.c_str(), body.size(), ContentType.c_str()); if (res) { if (status) { diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index 5d511ea..2346992 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -207,7 +207,8 @@ void TNetwork::Authentication(const TConnection& ClientConnection) { auto Client = CreateClient(ClientConnection.Socket); char AddrBuf[64]; // TODO: IPv6 would need this to be changed - auto str = inet_ntop(AF_INET, static_cast(reinterpret_cast(&ClientConnection.SockAddr)), AddrBuf, sizeof(ClientConnection.SockAddr)); + auto str = inet_ntop(AF_INET, reinterpret_cast(&ClientConnection.SockAddr), AddrBuf, sizeof(ClientConnection.SockAddr)); + beammp_trace("This thread is ip " + std::string(str)); Client->SetIdentifier("ip", str); std::string Rc; From 48b9aa72dc7d7f74e8123f77cb2d21dc111bc830 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Wed, 10 Nov 2021 00:38:03 +0100 Subject: [PATCH 193/255] update commandline --- deps/commandline | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/commandline b/deps/commandline index 4b6ae33..242225d 160000 --- a/deps/commandline +++ b/deps/commandline @@ -1 +1 @@ -Subproject commit 4b6ae338caea7564479c2a7d6203794eb05feb7e +Subproject commit 242225dd41f752199c6284f0838d449339460b54 From 7079e80b7156c89ba04f7ce17e1b489e712ae2c0 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 19 Nov 2021 12:43:27 +0100 Subject: [PATCH 194/255] Lua: Remove leading space in onChatMessage (fix #35) --- include/TServer.h | 1 - src/TServer.cpp | 2 +- src/main.cpp | 11 ++++------- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/include/TServer.h b/include/TServer.h index 71025d1..2f203d8 100644 --- a/include/TServer.h +++ b/include/TServer.h @@ -36,5 +36,4 @@ private: static bool ShouldSpawn(TClient& c, const std::string& CarJson, int ID); static bool IsUnicycle(TClient& c, const std::string& CarJson); static void Apply(TClient& c, int VID, const std::string& pckt); - TScopedTimer mLifeTimer { "Server" }; }; diff --git a/src/TServer.cpp b/src/TServer.cpp index 6ef4b07..0ac6b0e 100644 --- a/src/TServer.cpp +++ b/src/TServer.cpp @@ -121,7 +121,7 @@ void TServer::GlobalParser(const std::weak_ptr& Client, std::string Pac beammp_trace(std::string(("got 'C' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); if (Packet.length() < 4 || Packet.find(':', 3) == std::string::npos) break; - auto Futures = LuaAPI::MP::Engine->TriggerEvent("onChatMessage", "", LockedClient->GetID(), LockedClient->GetName(), Packet.substr(Packet.find(':', 3) + 1)); + auto Futures = LuaAPI::MP::Engine->TriggerEvent("onChatMessage", "", LockedClient->GetID(), LockedClient->GetName(), Packet.substr(Packet.find(':', 3) + 2)); TLuaEngine::WaitForAll(Futures); LogChatMessage(LockedClient->GetName(), LockedClient->GetID(), Packet.substr(Packet.find(':', 3) + 1)); // FIXME: this needs to be adjusted once lua is merged if (std::any_of(Futures.begin(), Futures.end(), diff --git a/src/main.cpp b/src/main.cpp index 7af0ae9..0fda7eb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -21,8 +21,7 @@ // global, yes, this is ugly, no, it cant be done another way TSentry Sentry {}; -int main(int argc, char** argv) //try { -{ +int main(int argc, char** argv) try { setlocale(LC_ALL, "C"); SetupSignalHandlers(); @@ -62,14 +61,12 @@ int main(int argc, char** argv) //try { Application::Console().InitializeLuaConsole(LuaEngine); Application::CheckForUpdates(); - // TODO: replace while (!Shutdown) { std::this_thread::sleep_for(std::chrono::milliseconds(50)); } beammp_info("Shutdown."); return 0; -//} catch (const std::exception& e) { -// beammp_error(e.what()); -// Sentry.LogException(e, _file_basename, _line); -//} +} catch (const std::exception& e) { + beammp_error(e.what()); + Sentry.LogException(e, _file_basename, _line); } From b6fa3574fd27c421c0564fff04f548894edfca7b Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 19 Nov 2021 12:46:43 +0100 Subject: [PATCH 195/255] RegisterThread: Add TID print (#63) --- src/Common.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Common.cpp b/src/Common.cpp index 5216c81..158c5a9 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -118,9 +118,7 @@ std::string ThreadName(bool DebugModeOverride) { } void RegisterThread(const std::string& str) { -#if defined(__linux) - beammp_trace(str + " is " + std::to_string(gettid())); -#endif // __linux + beammp_debug("Thread \"" + str + "\" is TID " + std::to_string(gettid())); auto Lock = std::unique_lock(ThreadNameMapMutex); threadNameMap[std::this_thread::get_id()] = str; } From f1148ed1c46b159c6a061b37f419f3045f5eb735 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 19 Nov 2021 12:54:16 +0100 Subject: [PATCH 196/255] LuaAPI: Show quotes around strings in table dumps (#60) --- src/Common.cpp | 4 ---- src/LuaAPI.cpp | 24 ++++++++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Common.cpp b/src/Common.cpp index 158c5a9..b1641a9 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -96,10 +96,6 @@ void Application::CheckForUpdates() { } } - - - - // thread name stuff static std::map threadNameMap {}; diff --git a/src/LuaAPI.cpp b/src/LuaAPI.cpp index d420d9a..d1ff0a8 100644 --- a/src/LuaAPI.cpp +++ b/src/LuaAPI.cpp @@ -6,7 +6,7 @@ #define SOL_ALL_SAFETIES_ON 1 #include -static std::string LuaToString(const sol::object Value, size_t Indent = 1) { +static std::string LuaToString(const sol::object Value, size_t Indent = 1, bool QuoteStrings = false) { if (Indent > 80) { return "[[possible recursion, refusing to keep printing]]"; } @@ -32,7 +32,11 @@ static std::string LuaToString(const sol::object Value, size_t Indent = 1) { return ss.str(); } case sol::type::string: - return Value.as(); + if (QuoteStrings) { + return "\"" + Value.as() + "\""; + } else { + return Value.as(); + } case sol::type::number: { std::stringstream ss; ss << Value.as(); @@ -53,7 +57,7 @@ static std::string LuaToString(const sol::object Value, size_t Indent = 1) { for (size_t i = 0; i < Indent; ++i) { Result << "\t"; } - Result << LuaToString(Entry.first, Indent + 1) << ": " << LuaToString(Entry.second, Indent + 1) << ","; + Result << LuaToString(Entry.first, Indent + 1) << ": " << LuaToString(Entry.second, Indent + 1, true) << ","; } Result << "\n"; } @@ -160,49 +164,49 @@ void LuaAPI::MP::RemoveVehicle(int PID, int VID) { void LuaAPI::MP::Set(int ConfigID, sol::object NewValue) { switch (ConfigID) { - case 0: //debug + case 0: // debug if (NewValue.is()) { Application::Settings.DebugModeEnabled = NewValue.as(); beammp_info(std::string("Set `Debug` to ") + (Application::Settings.DebugModeEnabled ? "true" : "false")); } else beammp_lua_error("set invalid argument [2] expected boolean"); break; - case 1: //private + case 1: // private if (NewValue.is()) { Application::Settings.Private = NewValue.as(); beammp_info(std::string("Set `Private` to ") + (Application::Settings.Private ? "true" : "false")); } else beammp_lua_error("set invalid argument [2] expected boolean"); break; - case 2: //max cars + case 2: // max cars if (NewValue.is()) { Application::Settings.MaxCars = NewValue.as(); beammp_info(std::string("Set `MaxCars` to ") + std::to_string(Application::Settings.MaxCars)); } else beammp_lua_error("set invalid argument [2] expected integer"); break; - case 3: //max players + case 3: // max players if (NewValue.is()) { Application::Settings.MaxPlayers = NewValue.as(); beammp_info(std::string("Set `MaxPlayers` to ") + std::to_string(Application::Settings.MaxPlayers)); } else beammp_lua_error("set invalid argument [2] expected integer"); break; - case 4: //Map + case 4: // Map if (NewValue.is()) { Application::Settings.MapName = NewValue.as(); beammp_info(std::string("Set `Map` to ") + Application::Settings.MapName); } else beammp_lua_error("set invalid argument [2] expected string"); break; - case 5: //Name + case 5: // Name if (NewValue.is()) { Application::Settings.ServerName = NewValue.as(); beammp_info(std::string("Set `Name` to ") + Application::Settings.ServerName); } else beammp_lua_error("set invalid argument [2] expected string"); break; - case 6: //Desc + case 6: // Desc if (NewValue.is()) { Application::Settings.ServerDesc = NewValue.as(); beammp_info(std::string("Set `Description` to ") + Application::Settings.ServerDesc); From cf08dee84f226fd32b10ecc534f2fef3f88b11d5 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 19 Nov 2021 13:12:27 +0100 Subject: [PATCH 197/255] Common: Make TID work on Windows --- src/Common.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Common.cpp b/src/Common.cpp index b1641a9..6ea929f 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -114,7 +114,13 @@ std::string ThreadName(bool DebugModeOverride) { } void RegisterThread(const std::string& str) { - beammp_debug("Thread \"" + str + "\" is TID " + std::to_string(gettid())); + std::string ThreadId; + #ifdef WIN32 + ThreadId = std::to_string(GetCurrentThreadId()); + #else + ThreadId = std::to_string(gettid()); + #endif + beammp_debug("Thread \"" + str + "\" is TID " + ThreadId); auto Lock = std::unique_lock(ThreadNameMapMutex); threadNameMap[std::this_thread::get_id()] = str; } From 2ddac7f13830cd75d4b7c82573abd2302c49f002 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sun, 21 Nov 2021 02:26:02 +0100 Subject: [PATCH 198/255] update commandline --- deps/commandline | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/commandline b/deps/commandline index 242225d..6f935f0 160000 --- a/deps/commandline +++ b/deps/commandline @@ -1 +1 @@ -Subproject commit 242225dd41f752199c6284f0838d449339460b54 +Subproject commit 6f935f0567d74851f43e41d4e01acc119a6507f6 From 1ec47252f2b7e3c1406cb02ff8c58e0a8f57aaff Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sun, 21 Nov 2021 02:31:52 +0100 Subject: [PATCH 199/255] update commandline --- deps/commandline | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/commandline b/deps/commandline index 6f935f0..de188cd 160000 --- a/deps/commandline +++ b/deps/commandline @@ -1 +1 @@ -Subproject commit 6f935f0567d74851f43e41d4e01acc119a6507f6 +Subproject commit de188cd93401d19c9a2efa78eb2099deb275b9cf From 097e52674bd73176db26b06c371f2ea1378b586b Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sun, 21 Nov 2021 03:04:50 +0100 Subject: [PATCH 200/255] update commandline --- deps/commandline | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/commandline b/deps/commandline index de188cd..9144d09 160000 --- a/deps/commandline +++ b/deps/commandline @@ -1 +1 @@ -Subproject commit de188cd93401d19c9a2efa78eb2099deb275b9cf +Subproject commit 9144d0978922d08f3bdf5dc32db51973fc915ab2 From 7169e653055bd46f523ebcd64cdb1eb4c2118f22 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sun, 21 Nov 2021 03:19:02 +0100 Subject: [PATCH 201/255] clarify thread names --- src/TLuaEngine.cpp | 1 + src/TNetwork.cpp | 33 ++++++++++++++++++--------------- src/main.cpp | 1 + 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index fc330bb..6d80e67 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -48,6 +48,7 @@ void TLuaEngine::operator()() { } auto ResultCheckThread = std::thread([&] { + RegisterThread("ResultCheckThread"); while (!mShutdown) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); std::unique_lock Lock(mResultsToCheckMutex); diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index 2346992..18a710a 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -42,13 +42,13 @@ void TNetwork::UDPServerMain() { WSADATA data; if (WSAStartup(514, &data)) { beammp_error(("Can't start Winsock!")); - //return; + // return; } #endif // WIN32 mUDPSock = socket(AF_INET, SOCK_DGRAM, 0); // Create a server hint structure for the server sockaddr_in serverAddr {}; - serverAddr.sin_addr.s_addr = INADDR_ANY; //Any Local + serverAddr.sin_addr.s_addr = INADDR_ANY; // Any Local serverAddr.sin_family = AF_INET; // Address format is IPv4 serverAddr.sin_port = htons(uint16_t(Application::Settings.Port)); // Convert from little to big endian @@ -57,7 +57,7 @@ void TNetwork::UDPServerMain() { beammp_error("bind() failed: " + GetPlatformAgnosticErrorString()); std::this_thread::sleep_for(std::chrono::seconds(5)); exit(-1); - //return; + // return; } beammp_info(("Vehicle data network online on port ") + std::to_string(Application::Settings.Port) + (" with a Max of ") @@ -65,7 +65,7 @@ void TNetwork::UDPServerMain() { while (!mShutdown) { try { sockaddr_in client {}; - std::string Data = UDPRcvFromClient(client); //Receives any data from Socket + std::string Data = UDPRcvFromClient(client); // Receives any data from Socket size_t Pos = Data.find(':'); if (Data.empty() || Pos > 2) continue; @@ -163,7 +163,7 @@ void TNetwork::TCPServerMain() { #endif // WIN32 } -#undef GetObject //Fixes Windows +#undef GetObject // Fixes Windows #include "Json.h" namespace json = rapidjson; @@ -331,7 +331,7 @@ void TNetwork::Authentication(const TConnection& ClientConnection) { ClientKick(*Client, Reason); return; } - + if (mServer.ClientCount() < size_t(Application::Settings.MaxPlayers)) { beammp_info("Identification success"); mServer.InsertClient(Client); @@ -368,16 +368,16 @@ bool TNetwork::TCPSend(TClient& c, const std::string& Data, bool IsSync) { do { #ifdef WIN32 int32_t Temp = send(c.GetTCPSock(), &Send[Sent], Size - Sent, 0); -#else //WIN32 +#else // WIN32 int32_t Temp = send(c.GetTCPSock(), &Send[Sent], Size - Sent, MSG_NOSIGNAL); -#endif //WIN32 +#endif // WIN32 if (Temp == 0) { beammp_debug("send() == 0: " + GetPlatformAgnosticErrorString()); if (c.GetStatus() > -1) c.SetStatus(-1); return false; } else if (Temp < 0) { - beammp_debug("send() < 0: " + GetPlatformAgnosticErrorString()); //TODO fix it was spamming yet everyone stayed on the server + beammp_debug("send() < 0: " + GetPlatformAgnosticErrorString()); // TODO fix it was spamming yet everyone stayed on the server if (c.GetStatus() > -1) c.SetStatus(-1); CloseSocketProper(c.GetTCPSock()); @@ -461,6 +461,7 @@ void TNetwork::ClientKick(TClient& c, const std::string& R) { } void TNetwork::Looper(const std::weak_ptr& c) { + RegisterThreadAuto(); while (!c.expired()) { auto Client = c.lock(); if (Client->GetStatus() < 0) { @@ -468,7 +469,7 @@ void TNetwork::Looper(const std::weak_ptr& c) { break; } if (!Client->IsSyncing() && Client->IsSynced() && Client->MissedPacketQueueSize() != 0) { - //debug("sending " + std::to_string(Client->MissedPacketQueueSize()) + " queued packets"); + // debug("sending " + std::to_string(Client->MissedPacketQueueSize()) + " queued packets"); while (Client->MissedPacketQueueSize() > 0) { std::string QData {}; { // locked context @@ -611,7 +612,7 @@ void TNetwork::OnConnect(const std::weak_ptr& c) { SyncResources(*LockedClient); if (LockedClient->GetStatus() < 0) return; - (void)Respond(*LockedClient, "M" + Application::Settings.MapName, true); //Send the Map on connect + (void)Respond(*LockedClient, "M" + Application::Settings.MapName, true); // Send the Map on connect beammp_info(LockedClient->GetName() + " : Connected"); LuaAPI::MP::Engine->ReportErrors(LuaAPI::MP::Engine->TriggerEvent("onPlayerJoining", "", LockedClient->GetID())); } @@ -689,7 +690,7 @@ void TNetwork::SendFile(TClient& c, const std::string& UnsafeName) { // TODO: handle } - ///Wait for connections + /// Wait for connections int T = 0; while (c.GetDownSock() < 1 && T < 50) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); @@ -707,9 +708,11 @@ void TNetwork::SendFile(TClient& c, const std::string& UnsafeName) { std::thread SplitThreads[2] { std::thread([&] { + RegisterThread("SplitLoad_0"); SplitLoad(c, 0, MSize, false, FileName); }), std::thread([&] { + RegisterThread("SplitLoad_1"); SplitLoad(c, MSize, Size, true, FileName); }) }; @@ -723,7 +726,7 @@ void TNetwork::SendFile(TClient& c, const std::string& UnsafeName) { void TNetwork::SplitLoad(TClient& c, size_t Sent, size_t Size, bool D, const std::string& Name) { std::ifstream f(Name.c_str(), std::ios::binary); - uint32_t Split = 0x7735940; //125MB + uint32_t Split = 0x7735940; // 125MB char* Data; if (Size > Split) Data = new char[Split]; @@ -876,10 +879,10 @@ void TNetwork::SendToAll(TClient* c, const std::string& Data, bool Self, bool Re } else { Client->EnqueuePacket(Data); } - //ret = SendLarge(*Client, Data); + // ret = SendLarge(*Client, Data); } else { Client->EnqueuePacket(Data); - //ret = TCPSend(*Client, Data); + // ret = TCPSend(*Client, Data); } } else { ret = UDPSend(*Client, Data); diff --git a/src/main.cpp b/src/main.cpp index 0fda7eb..e7002a1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -61,6 +61,7 @@ int main(int argc, char** argv) try { Application::Console().InitializeLuaConsole(LuaEngine); Application::CheckForUpdates(); + RegisterThread("Main(Waiting)"); while (!Shutdown) { std::this_thread::sleep_for(std::chrono::milliseconds(50)); } From 66d4e34a7556b136e0e9509346ad85e652531f0f Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sun, 21 Nov 2021 03:29:22 +0100 Subject: [PATCH 202/255] print always --- src/Common.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Common.cpp b/src/Common.cpp index 6ea929f..8f489fd 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -115,12 +115,14 @@ std::string ThreadName(bool DebugModeOverride) { void RegisterThread(const std::string& str) { std::string ThreadId; - #ifdef WIN32 - ThreadId = std::to_string(GetCurrentThreadId()); - #else - ThreadId = std::to_string(gettid()); - #endif - beammp_debug("Thread \"" + str + "\" is TID " + ThreadId); +#ifdef WIN32 + ThreadId = std::to_string(GetCurrentThreadId()); +#else + ThreadId = std::to_string(gettid()); +#endif + if (Application::Settings.DebugModeEnabled) { + std::cout << ("Thread \"" + str + "\" is TID " + ThreadId) << std::endl; + } auto Lock = std::unique_lock(ThreadNameMapMutex); threadNameMap[std::this_thread::get_id()] = str; } From a7db41ebaa4921b2887bbd6e310f819433ba7cc7 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sun, 21 Nov 2021 03:31:35 +0100 Subject: [PATCH 203/255] write thread ids to file --- src/Common.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Common.cpp b/src/Common.cpp index 8f489fd..8a830cd 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -121,7 +121,8 @@ void RegisterThread(const std::string& str) { ThreadId = std::to_string(gettid()); #endif if (Application::Settings.DebugModeEnabled) { - std::cout << ("Thread \"" + str + "\" is TID " + ThreadId) << std::endl; + std::ofstream ThreadFile("Threads.log", std::ios::app); + ThreadFile << ("Thread \"" + str + "\" is TID " + ThreadId) << std::endl; } auto Lock = std::unique_lock(ThreadNameMapMutex); threadNameMap[std::this_thread::get_id()] = str; From 08a62261e730f5f5a0bc356f6e8d9585a83f2f66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucca=20Jim=C3=A9nez=20K=C3=B6nings?= Date: Thu, 25 Nov 2021 01:00:24 +0100 Subject: [PATCH 204/255] Add temporary cmake mods to make project compile on macOS, add ifdefs in 'Compat.h' for target darwin --- CMakeLists.txt | 12 +++++++++--- include/Compat.h | 19 ++++++++++++++++++- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b0eab53..7ba8e99 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,13 @@ include_directories("${PROJECT_SOURCE_DIR}/deps/sol2/include") include_directories("${PROJECT_SOURCE_DIR}/deps/cpp-httplib") include_directories("${PROJECT_SOURCE_DIR}/deps") -add_compile_definitions(CPPHTTPLIB_OPENSSL_SUPPORT) +add_compile_definitions(CPPHTTPLIB_OPENSSL_SUPPORT __linux) + +if(APPLE) + set(LUA_INCLUDE_DIR /usr/local/Cellar/lua@5.3/5.3.6/include/lua5.3) + set(LUA_LIBRARIES lua) + link_directories(/usr/local/Cellar/lua@5.3/5.3.6/lib) +endif() if (WIN32) # this has to happen before sentry, so that crashpad on windows links with these settings. @@ -99,7 +105,7 @@ target_include_directories(BeamMP-Server PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/commandline") message(STATUS "Looking for Lua") -find_package(Lua REQUIRED VERSION 5.3) +# find_package(Lua REQUIRED VERSION 5.3) target_include_directories(BeamMP-Server PUBLIC ${LUA_INCLUDE_DIR} ${CURL_INCLUDE_DIRS} @@ -109,7 +115,7 @@ target_include_directories(BeamMP-Server PUBLIC message(STATUS "Looking for SSL") -find_package(OpenSSL REQUIRED) +# find_package(OpenSSL REQUIRED) target_link_libraries(BeamMP-Server sol2::sol2 ${LUA_LIBRARIES}) message(STATUS "CURL IS ${CURL_LIBRARIES}") diff --git a/include/Compat.h b/include/Compat.h index 8c1b662..7a366d8 100644 --- a/include/Compat.h +++ b/include/Compat.h @@ -19,6 +19,23 @@ inline void CloseSocketProper(int TheSocket) { } #endif // unix +#ifdef __APPLE__ +#include +#include +#include +#include +#include +using SOCKET = int; +using DWORD = unsigned long; +using PDWORD = unsigned long*; +using LPDWORD = unsigned long*; +char _getch(); +inline void CloseSocketProper(int TheSocket) { + shutdown(TheSocket, SHUT_RDWR); + close(TheSocket); +} +#endif // unix + // ======================= WIN32 ======================= #ifdef WIN32 @@ -33,6 +50,6 @@ inline void CloseSocketProper(SOCKET TheSocket) { // ======================= OTHER ======================= -#if !defined(WIN32) && !defined(__unix) +#if !defined(WIN32) && !defined(__unix) && !defined(__APPLE__) #error "OS not supported" #endif \ No newline at end of file From 6247061d09e186799e2ee86958106b26289170c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucca=20Jim=C3=A9nez=20K=C3=B6nings?= Date: Thu, 25 Nov 2021 01:06:34 +0100 Subject: [PATCH 205/255] Replace gettid() call with POSIX compliant getpid() call in 'Common.cpp' --- src/Common.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Common.cpp b/src/Common.cpp index 8a830cd..d578241 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -117,6 +117,8 @@ void RegisterThread(const std::string& str) { std::string ThreadId; #ifdef WIN32 ThreadId = std::to_string(GetCurrentThreadId()); +#elif __APPLE__ + ThreadId = std::to_string(getpid()); #else ThreadId = std::to_string(gettid()); #endif From 1a2a123d87a08304eb3edf9f6f6c30f35d33620d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucca=20Jim=C3=A9nez=20K=C3=B6nings?= Date: Thu, 25 Nov 2021 01:41:41 +0100 Subject: [PATCH 206/255] Fix various macOS compatibility issues --- CMakeLists.txt | 11 +++++++---- include/TLuaEngine.h | 2 +- src/Common.cpp | 2 +- src/LuaAPI.cpp | 2 +- src/SignalHandling.cpp | 4 ++-- src/TLuaEngine.cpp | 10 +++++----- 6 files changed, 17 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7ba8e99..70bf321 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,7 +21,9 @@ add_compile_definitions(CPPHTTPLIB_OPENSSL_SUPPORT __linux) if(APPLE) set(LUA_INCLUDE_DIR /usr/local/Cellar/lua@5.3/5.3.6/include/lua5.3) set(LUA_LIBRARIES lua) + include_directories(/usr/local/opt/openssl@1.1/include) link_directories(/usr/local/Cellar/lua@5.3/5.3.6/lib) + link_directories(/usr/local/opt/openssl@1.1/lib) endif() if (WIN32) @@ -121,15 +123,16 @@ target_link_libraries(BeamMP-Server sol2::sol2 ${LUA_LIBRARIES}) message(STATUS "CURL IS ${CURL_LIBRARIES}") if (UNIX) - target_link_libraries(BeamMP-Server + target_link_libraries(BeamMP-Server z - pthread - stdc++fs + pthread ${LUA_LIBRARIES} crypto ${OPENSSL_LIBRARIES} commandline - sentry) + sentry + ssl + ) elseif (WIN32) include(FindLua) message(STATUS "Looking for libz") diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index 50d5235..c38afc8 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -32,7 +32,7 @@ struct TLuaResult { std::atomic_bool Ready; std::atomic_bool Error; std::string ErrorMessage; - sol::object Result { sol::nil }; + sol::object Result { sol::lua_nil }; TLuaStateId StateId; std::string Function; // TODO: Add condition_variable diff --git a/src/Common.cpp b/src/Common.cpp index d578241..59fb366 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -118,7 +118,7 @@ void RegisterThread(const std::string& str) { #ifdef WIN32 ThreadId = std::to_string(GetCurrentThreadId()); #elif __APPLE__ - ThreadId = std::to_string(getpid()); + ThreadId = std::to_string(getpid()); // todo: research if 'getpid()' is a valid, posix compliant alternative to 'gettid()' #else ThreadId = std::to_string(gettid()); #endif diff --git a/src/LuaAPI.cpp b/src/LuaAPI.cpp index d1ff0a8..7b56543 100644 --- a/src/LuaAPI.cpp +++ b/src/LuaAPI.cpp @@ -42,7 +42,7 @@ static std::string LuaToString(const sol::object Value, size_t Indent = 1, bool ss << Value.as(); return ss.str(); } - case sol::type::nil: + case sol::type::lua_nil: case sol::type::none: return ""; case sol::type::boolean: diff --git a/src/SignalHandling.cpp b/src/SignalHandling.cpp index f95c54e..49f50c5 100644 --- a/src/SignalHandling.cpp +++ b/src/SignalHandling.cpp @@ -1,7 +1,7 @@ #include "SignalHandling.h" #include "Common.h" -#ifdef __unix +#if defined(__unix) || defined(__linux) || defined(__APPLE__) #include static void UnixSignalHandler(int sig) { switch (sig) { @@ -48,7 +48,7 @@ BOOL WINAPI Win32CtrlC_Handler(DWORD CtrlType) { void SetupSignalHandlers() { // signal handlers for unix#include -#if defined(__unix) || defined(__linux) +#if defined(__unix) || defined(__linux) || defined(__APPLE__) beammp_trace("registering handlers for signals"); signal(SIGPIPE, UnixSignalHandler); signal(SIGTERM, UnixSignalHandler); diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 6d80e67..cd712c1 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -281,7 +281,7 @@ sol::table TLuaEngine::StateThreadData::Lua_TriggerGlobalEvent(const std::string auto Vector = Self.get>>("ReturnValueImpl"); for (const auto& Value : Vector) { if (!Value->Ready) { - return sol::nil; + return sol::lua_nil; } Result.add(Value->Result); } @@ -313,7 +313,7 @@ sol::table TLuaEngine::StateThreadData::Lua_GetPlayerIdentifiers(int ID) { if (MaybeClient && !MaybeClient.value().expired()) { auto IDs = MaybeClient.value().lock()->GetIdentifiers(); if (IDs.empty()) { - return sol::nil; + return sol::lua_nil; } sol::table Result = mStateView.create_table(); for (const auto& Pair : IDs) { @@ -321,7 +321,7 @@ sol::table TLuaEngine::StateThreadData::Lua_GetPlayerIdentifiers(int ID) { } return Result; } else { - return sol::nil; + return sol::lua_nil; } } @@ -356,7 +356,7 @@ sol::table TLuaEngine::StateThreadData::Lua_GetPlayerVehicles(int ID) { VehicleData = *LockedData.VehicleData; } // End Vehicle Data Lock Scope if (VehicleData.empty()) { - return sol::nil; + return sol::lua_nil; } sol::state_view StateView(mState); sol::table Result = StateView.create_table(); @@ -365,7 +365,7 @@ sol::table TLuaEngine::StateThreadData::Lua_GetPlayerVehicles(int ID) { } return Result; } else - return sol::nil; + return sol::lua_nil; } sol::table TLuaEngine::StateThreadData::Lua_HttpCreateConnection(const std::string& host, uint16_t port) { From 938774618c68abf14b63d7256a6ee2957ee6687a Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 26 Nov 2021 13:25:09 +0100 Subject: [PATCH 207/255] Fix apple + linux compatibility --- CMakeLists.txt | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 70bf321..12523de 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -106,8 +106,13 @@ target_include_directories(BeamMP-Server PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_SOURCE_DIR}/commandline") -message(STATUS "Looking for Lua") -# find_package(Lua REQUIRED VERSION 5.3) +if (APPLE) + message(STATUS "NOT looking for Lua on APPLE") +else() + message(STATUS "Looking for Lua") + find_package(Lua REQUIRED VERSION 5.3) +endif() + target_include_directories(BeamMP-Server PUBLIC ${LUA_INCLUDE_DIR} ${CURL_INCLUDE_DIRS} @@ -117,7 +122,11 @@ target_include_directories(BeamMP-Server PUBLIC message(STATUS "Looking for SSL") -# find_package(OpenSSL REQUIRED) +if (APPLE) + set(OPENSSL_LIBRARIES ssl crypto) +else() + find_package(OpenSSL REQUIRED) +endif() target_link_libraries(BeamMP-Server sol2::sol2 ${LUA_LIBRARIES}) message(STATUS "CURL IS ${CURL_LIBRARIES}") @@ -131,8 +140,7 @@ if (UNIX) ${OPENSSL_LIBRARIES} commandline sentry - ssl - ) + ssl) elseif (WIN32) include(FindLua) message(STATUS "Looking for libz") From eae27633db83b119f5abac74d41350204a55a9e7 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 26 Nov 2021 19:04:21 +0100 Subject: [PATCH 208/255] Add commandline arguments, implement --config, --version, --help --- CMakeLists.txt | 3 +- include/ArgsParser.h | 49 ++++++++++++++++++++++ include/TConfig.h | 3 +- include/TConsole.h | 1 + include/TServer.h | 2 +- src/ArgsParser.cpp | 94 ++++++++++++++++++++++++++++++++++++++++++ src/TConfig.cpp | 37 ++++++++--------- src/TServer.cpp | 14 +++---- src/main.cpp | 98 +++++++++++++++++++++++++++++++++++++++++--- 9 files changed, 266 insertions(+), 35 deletions(-) create mode 100644 include/ArgsParser.h create mode 100644 src/ArgsParser.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 12523de..0a50caa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -97,7 +97,8 @@ add_executable(BeamMP-Server include/TNetwork.h src/TNetwork.cpp include/LuaAPI.h src/LuaAPI.cpp include/TScopedTimer.h src/TScopedTimer.cpp - include/SignalHandling.h src/SignalHandling.cpp) + include/SignalHandling.h src/SignalHandling.cpp + include/ArgsParser.h src/ArgsParser.cpp) target_compile_definitions(BeamMP-Server PRIVATE SECRET_SENTRY_URL="${BEAMMP_SECRET_SENTRY_URL}") include_directories(BeamMP-Server PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) diff --git a/include/ArgsParser.h b/include/ArgsParser.h new file mode 100644 index 0000000..c951849 --- /dev/null +++ b/include/ArgsParser.h @@ -0,0 +1,49 @@ +#pragma once + +#include +#include +#include +#include +#include + +/* + * Allows syntax: + * --help : long flags + * --path=/home/lion : long assignments + */ +class ArgsParser { +public: + enum Flags : int { + NONE = 0, + REQUIRED = 1, // argument is required + HAS_VALUE = 2, // argument must have a value + }; + + ArgsParser() = default; + + void Parse(const std::vector& ArgList); + // prints errors if any errors occurred, in that case also returns false + bool Verify(); + void RegisterArgument(std::vector&& ArgumentNames, int Flags); + // pass all possible names for this argument (short, long, etc) + bool FoundArgument(const std::vector& Names); + std::optional GetValueOfArgument(const std::vector& Names); + +private: + void ConsumeLongAssignment(const std::string& Arg); + void ConsumeLongFlag(const std::string& Arg); + bool IsRegistered(const std::string& Name); + + struct Argument { + std::string Name; + std::optional Value; + }; + + struct RegisteredArgument { + std::vector Names; + int Flags; + }; + + std::vector mRegisteredArguments; + std::vector mFoundArgs; +}; diff --git a/include/TConfig.h b/include/TConfig.h index 1399aa6..f20766f 100644 --- a/include/TConfig.h +++ b/include/TConfig.h @@ -8,7 +8,7 @@ namespace fs = std::filesystem; class TConfig { public: - explicit TConfig(); + explicit TConfig(const std::string& ConfigFileName); [[nodiscard]] bool Failed() const { return mFailed; } @@ -22,4 +22,5 @@ private: void ParseOldFormat(); bool mFailed { false }; + std::string mConfigFileName; }; diff --git a/include/TConsole.h b/include/TConsole.h index 4f9cad6..053deaa 100644 --- a/include/TConsole.h +++ b/include/TConsole.h @@ -15,6 +15,7 @@ public: void WriteRaw(const std::string& str); void InitializeLuaConsole(TLuaEngine& Engine); void BackupOldLog(); + Commandline& Internal() { return mCommandline; } private: Commandline mCommandline; diff --git a/include/TServer.h b/include/TServer.h index 2f203d8..dded2d9 100644 --- a/include/TServer.h +++ b/include/TServer.h @@ -16,7 +16,7 @@ class TServer final { public: using TClientSet = std::unordered_set>; - TServer(int argc, char** argv); + TServer(const std::vector& Arguments); void InsertClient(const std::shared_ptr& Ptr); std::weak_ptr InsertNewClient(); diff --git a/src/ArgsParser.cpp b/src/ArgsParser.cpp new file mode 100644 index 0000000..8440661 --- /dev/null +++ b/src/ArgsParser.cpp @@ -0,0 +1,94 @@ +#include "ArgsParser.h" +#include "Common.h" +#include + +void ArgsParser::Parse(const std::vector& ArgList) { + for (const auto& Arg : ArgList) { + if (Arg.size() > 2 && Arg.substr(0, 2) == "--") { + // long arg + if (Arg.find("=") != Arg.npos) { + ConsumeLongAssignment(std::string(Arg)); + } else { + ConsumeLongFlag(std::string(Arg)); + } + } else { + beammp_error("Error parsing commandline arguments: Supplied argument '" + std::string(Arg) + "' is not a valid argument and was ignored."); + } + } +} + +bool ArgsParser::Verify() { + bool Ok = true; + for (const auto& RegisteredArg : mRegisteredArguments) { + if (RegisteredArg.Flags & Flags::REQUIRED && !FoundArgument(RegisteredArg.Names)) { + beammp_error("Error in commandline arguments: Argument '" + std::string(RegisteredArg.Names.at(0)) + "' is required but wasn't found."); + Ok = false; + continue; + } else if (FoundArgument(RegisteredArg.Names)) { + if (RegisteredArg.Flags & Flags::HAS_VALUE) { + if (!GetValueOfArgument(RegisteredArg.Names).has_value()) { + beammp_error("Error in commandline arguments: Argument '" + std::string(RegisteredArg.Names.at(0)) + "' expects a value, but no value was given."); + Ok = false; + } + } else if (GetValueOfArgument(RegisteredArg.Names).has_value()) { + beammp_error("Error in commandline arguments: Argument '" + std::string(RegisteredArg.Names.at(0)) + "' does not expect a value, but one was given."); + Ok = false; + } + } + } + return Ok; +} + +void ArgsParser::RegisterArgument(std::vector&& ArgumentNames, int Flags) { + mRegisteredArguments.push_back({ ArgumentNames, Flags }); +} + +bool ArgsParser::FoundArgument(const std::vector& Names) { + // if any of the found args match any of the names + return std::any_of(mFoundArgs.begin(), mFoundArgs.end(), + [&Names](const Argument& Arg) -> bool { + // if any of the names match this arg's name + return std::any_of(Names.begin(), Names.end(), [&Arg](const std::string& Name) -> bool { + return Arg.Name == Name; + }); + }); +} + +std::optional ArgsParser::GetValueOfArgument(const std::vector& Names) { + // finds an entry which has a name that is any of the names in 'Names' + auto Found = std::find_if(mFoundArgs.begin(), mFoundArgs.end(), [&Names](const Argument& Arg) -> bool { + return std::any_of(Names.begin(), Names.end(), [&Arg](const std::string_view& Name) -> bool { + return Arg.Name == Name; + }); + }); + if (Found != mFoundArgs.end()) { + // found + return Found->Value; + } else { + return std::nullopt; + } +} + +bool ArgsParser::IsRegistered(const std::string& Name) { + return std::any_of(mRegisteredArguments.begin(), mRegisteredArguments.end(), [&Name](const RegisteredArgument& Arg) { + auto Iter = std::find(Arg.Names.begin(), Arg.Names.end(), Name); + return Iter != Arg.Names.end(); + }); +} + +void ArgsParser::ConsumeLongAssignment(const std::string& Arg) { + auto Value = Arg.substr(Arg.rfind("=") + 1); + auto Name = Arg.substr(2, Arg.rfind("=") - 2); + if (!IsRegistered(Name)) { + beammp_warn("Argument '" + Name + "' was supplied but isn't a known argument, so it is likely being ignored."); + } + mFoundArgs.push_back({ Name, Value }); +} + +void ArgsParser::ConsumeLongFlag(const std::string& Arg) { + auto Name = Arg.substr(2, Arg.rfind("=") - 2); + mFoundArgs.push_back({ Name, std::nullopt }); + if (!IsRegistered(Name)) { + beammp_warn("Argument '" + Name + "' was supplied but isn't a known argument, so it is likely being ignored."); + } +} diff --git a/src/TConfig.cpp b/src/TConfig.cpp index 8e014f5..a6f20c2 100644 --- a/src/TConfig.cpp +++ b/src/TConfig.cpp @@ -8,8 +8,6 @@ #include #include -static const char* ConfigFileName = static_cast("ServerConfig.toml"); - static constexpr std::string_view StrDebug = "Debug"; static constexpr std::string_view StrPrivate = "Private"; static constexpr std::string_view StrPort = "Port"; @@ -23,19 +21,6 @@ static constexpr std::string_view StrAuthKey = "AuthKey"; static constexpr std::string_view StrSendErrors = "SendErrors"; static constexpr std::string_view StrSendErrorsMessageEnabled = "SendErrorsShowMessage"; -TConfig::TConfig() { - if (!fs::exists(ConfigFileName) || !fs::is_regular_file(ConfigFileName)) { - beammp_info("No config file found! Generating one..."); - CreateConfigFile(ConfigFileName); - } - if (!mFailed) { - if (fs::exists("Server.cfg")) { - beammp_warn("An old \"Server.cfg\" file still exists. Please note that this is no longer used. Instead, \"" + std::string(ConfigFileName) + "\" is used. You can safely delete the \"Server.cfg\"."); - } - ParseFromFile(ConfigFileName); - } -} - void WriteSendErrors(const std::string& name) { std::ofstream CfgFile { name, std::ios::out | std::ios::app }; CfgFile << "# You can turn on/off the SendErrors message you get on startup here" << std::endl @@ -45,8 +30,22 @@ void WriteSendErrors(const std::string& name) { << StrSendErrors << " = true" << std::endl; } +TConfig::TConfig(const std::string& ConfigFileName) + : mConfigFileName(ConfigFileName) { + if (!fs::exists(mConfigFileName) || !fs::is_regular_file(mConfigFileName)) { + beammp_info("No config file found! Generating one..."); + CreateConfigFile(mConfigFileName); + } + if (!mFailed) { + if (fs::exists("Server.cfg")) { + beammp_warn("An old \"Server.cfg\" file still exists. Please note that this is no longer used. Instead, \"" + std::string(mConfigFileName) + "\" is used. You can safely delete the \"Server.cfg\"."); + } + ParseFromFile(mConfigFileName); + } +} + void TConfig::FlushToFile() { - auto data = toml::parse(ConfigFileName); + auto data = toml::parse(mConfigFileName); data["General"] = toml::table(); data["General"][StrAuthKey.data()] = Application::Settings.Key; data["General"][StrDebug.data()] = Application::Settings.DebugModeEnabled; @@ -60,7 +59,7 @@ void TConfig::FlushToFile() { data["General"][StrResourceFolder.data()] = Application::Settings.Resource; data["General"][StrSendErrors.data()] = Application::Settings.SendErrors; data["General"][StrSendErrorsMessageEnabled.data()] = Application::Settings.SendErrorsMessageEnabled; - std::ofstream Stream(ConfigFileName); + std::ofstream Stream(mConfigFileName); Stream << data << std::flush; } @@ -104,7 +103,7 @@ void TConfig::CreateConfigFile(std::string_view name) { "# IMPORTANT: Fill in the AuthKey with the key you got from `https://beammp.com/k/dashboard` on the left under \"Keys\"\n" << '\n'; ofs << data << '\n'; - beammp_error("There was no \"" + std::string(ConfigFileName) + "\" file (this is normal for the first time running the server), so one was generated for you. It was automatically filled with the settings from your Server.cfg, if you have one. Please open ServerConfig.toml and ensure your AuthKey and other settings are filled in and correct, then restart the server. The old Server.cfg file will no longer be used and causes a warning if it exists from now on."); + beammp_error("There was no \"" + std::string(mConfigFileName) + "\" file (this is normal for the first time running the server), so one was generated for you. It was automatically filled with the settings from your Server.cfg, if you have one. Please open ServerConfig.toml and ensure your AuthKey and other settings are filled in and correct, then restart the server. The old Server.cfg file will no longer be used and causes a warning if it exists from now on."); mFailed = true; ofs.close(); // FIXME @@ -143,7 +142,7 @@ void TConfig::ParseFromFile(std::string_view name) { PrintDebug(); // all good so far, let's check if there's a key if (Application::Settings.Key.empty()) { - beammp_error("No AuthKey specified in the \"" + std::string(ConfigFileName) + "\" file. Please get an AuthKey, enter it into the config file, and restart this server."); + beammp_error("No AuthKey specified in the \"" + std::string(mConfigFileName) + "\" file. Please get an AuthKey, enter it into the config file, and restart this server."); mFailed = true; } } diff --git a/src/TServer.cpp b/src/TServer.cpp index 0ac6b0e..69d6bb9 100644 --- a/src/TServer.cpp +++ b/src/TServer.cpp @@ -15,10 +15,10 @@ namespace json = rapidjson; -TServer::TServer(int argc, char** argv) { +TServer::TServer(const std::vector& Arguments) { beammp_info("BeamMP Server v" + Application::ServerVersionString()); - if (argc > 1) { - Application::Settings.CustomIP = argv[1]; + if (Arguments.size() > 1) { + Application::Settings.CustomIP = Arguments[0]; size_t n = std::count(Application::Settings.CustomIP.begin(), Application::Settings.CustomIP.end(), '.'); auto p = Application::Settings.CustomIP.find_first_not_of(".0123456789"); if (p != std::string::npos || n != 3 || Application::Settings.CustomIP.substr(0, 3) == "127") { @@ -67,7 +67,7 @@ size_t TServer::ClientCount() const { void TServer::GlobalParser(const std::weak_ptr& Client, std::string Packet, TPPSMonitor& PPSMonitor, TNetwork& Network) { if (Packet.find("Zp") != std::string::npos && Packet.size() > 500) { - //abort(); + // abort(); } if (Packet.substr(0, 4) == "ABG:") { Packet = DeComp(Packet.substr(4)); @@ -84,7 +84,7 @@ void TServer::GlobalParser(const std::weak_ptr& Client, std::string Pac std::any Res; char Code = Packet.at(0); - //V to Z + // V to Z if (Code <= 90 && Code >= 86) { PPSMonitor.IncrementInternalPPS(); Network.SendToAll(LockedClient.get(), Packet, false, false); @@ -200,7 +200,7 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ int PID = -1; int VID = -1, Pos; std::string Data = Packet.substr(3), pid, vid; - switch (Code) { //Spawned Destroyed Switched/Moved NotFound Reset + switch (Code) { // Spawned Destroyed Switched/Moved NotFound Reset case 's': beammp_trace(std::string(("got 'Os' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); if (Data.at(0) == '0') { @@ -370,6 +370,6 @@ void TServer::Apply(TClient& c, int VID, const std::string& pckt) { void TServer::InsertClient(const std::shared_ptr& NewClient) { beammp_debug("inserting client (" + std::to_string(ClientCount()) + ")"); - WriteLock Lock(mClientsMutex); //TODO why is there 30+ threads locked here + WriteLock Lock(mClientsMutex); // TODO why is there 30+ threads locked here (void)mClients.insert(NewClient); } diff --git a/src/main.cpp b/src/main.cpp index e7002a1..94897bc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,6 @@ #include "TSentry.h" +#include "ArgsParser.h" #include "Common.h" #include "CustomAssert.h" #include "Http.h" @@ -17,15 +18,103 @@ #include #include +static const std::string sCommandlineArguments = R"( +USAGE: + BeamMP-Server [arguments] + +ARGUMENTS: + --help + Displays this help and exits. + --ip= + Asks the server to bind to the + specified IPv4 address. ONLY allows + IPv4 addresses of the format + A.B.C.D, where A-D are between 0 and + 255 each. + --config=/path/to/ServerConfig.toml + Absolute or relative path to the + Server Config file, including the + filename. For paths and filenames with + spaces, put quotes around the path. + --version + Prints version info and exits. + +EXAMPLES: + BeamMP-Server --ip=203.0.113.0 + Runs the BeamMP-Server and binds its address to the + specified IP '203.0.113.0'. + + BeamMP-Server --config=../MyWestCoastServerConfig.toml + Runs the BeamMP-Server and uses the server config file + which is one directory above it and is named + 'MyWestCoastServerConfig.toml'. +)"; + // this is provided by the build system, leave empty for source builds // global, yes, this is ugly, no, it cant be done another way TSentry Sentry {}; -int main(int argc, char** argv) try { +struct MainArguments { + int argc {}; + char** argv {}; + std::vector List; + std::string InvokedAs; +}; + +int BeamMPServerMain(MainArguments Arguments); + +int main(int argc, char** argv) { + MainArguments Args { argc, argv, {}, argv[0] }; + Args.List.reserve(argc); + for (int i = 1; i < argc; ++i) { + Args.List.push_back(argv[i]); + } + int MainRet = 0; + try { + MainRet = BeamMPServerMain(std::move(Args)); + } catch (const std::exception& e) { + beammp_error("A fatal exception has occurred and the server is forcefully shutting down."); + beammp_error(e.what()); + Sentry.LogException(e, _file_basename, _line); + MainRet = -1; + } + return MainRet; +} + +int BeamMPServerMain(MainArguments Arguments) { setlocale(LC_ALL, "C"); SetupSignalHandlers(); + ArgsParser Parser; + Parser.RegisterArgument({ "help" }, ArgsParser::NONE); + Parser.RegisterArgument({ "version" }, ArgsParser::NONE); + Parser.RegisterArgument({ "config" }, ArgsParser::HAS_VALUE); + Parser.RegisterArgument({ "ip" }, ArgsParser::HAS_VALUE); + Parser.Parse(Arguments.List); + if (!Parser.Verify()) { + return 1; + } + if (Parser.FoundArgument({ "help" })) { + Application::Console().Internal().set_prompt(""); + Application::Console().WriteRaw(sCommandlineArguments); + return 0; + } + if (Parser.FoundArgument({ "version" })) { + Application::Console().Internal().set_prompt(""); + Application::Console().WriteRaw("BeamMP-Server v" + Application::ServerVersionString()); + return 0; + } + + std::string ConfigPath = "ServerConfig.toml"; + if (Parser.FoundArgument({ "config" })) { + auto MaybeConfigPath = Parser.GetValueOfArgument({ "config" }); + if (MaybeConfigPath.has_value()) { + ConfigPath = MaybeConfigPath.value(); + beammp_info("Custom config requested via commandline: '" + ConfigPath + "'"); + } + } + bool Shutdown = false; Application::RegisterShutdownHandler([&Shutdown] { Shutdown = true; }); Application::RegisterShutdownHandler([] { @@ -33,8 +122,8 @@ int main(int argc, char** argv) try { TLuaEngine::WaitForAll(Futures); }); - TServer Server(argc, argv); - TConfig Config; + TServer Server(Arguments.List); + TConfig Config(ConfigPath); TLuaEngine LuaEngine; LuaEngine.SetServer(&Server); @@ -67,7 +156,4 @@ int main(int argc, char** argv) try { } beammp_info("Shutdown."); return 0; -} catch (const std::exception& e) { - beammp_error(e.what()); - Sentry.LogException(e, _file_basename, _line); } From e1756298af14cc6b2e158245def9f4d38dbfb799 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 26 Nov 2021 19:07:08 +0100 Subject: [PATCH 209/255] Fix doubled consent settings in ServerConfig --- Changelog.md | 1 + src/TConfig.cpp | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Changelog.md b/Changelog.md index e5ace3e..9510032 100644 --- a/Changelog.md +++ b/Changelog.md @@ -3,6 +3,7 @@ - CHANGED entire plugin Lua implementation (rewrite) - CHANGED moved *all* functions into MP.\* - CHANGED all files of a Lua plugin to share a Lua state (no more state-per-file) +- ADDED Commandline options. Run with `--help` to see all options. - ADDED `MP.GetOSName() -> string`: Returns "Linux", "Windows" or "Other" - ADDED `MP.GetServerVersion() -> string`: Returns major,minor,patch version - ADDED `MP.IsPlayerGuest(id) -> boolean`: Whether player with id is a guest diff --git a/src/TConfig.cpp b/src/TConfig.cpp index a6f20c2..ba90e39 100644 --- a/src/TConfig.cpp +++ b/src/TConfig.cpp @@ -93,8 +93,6 @@ void TConfig::CreateConfigFile(std::string_view name) { data["General"][StrMap.data()] = Application::Settings.MapName; data["General"][StrDescription.data()] = Application::Settings.ServerDesc; data["General"][StrResourceFolder.data()] = Application::Settings.Resource; - data["General"][StrSendErrors.data()] = Application::Settings.SendErrors; - data["General"][StrSendErrorsMessageEnabled.data()] = Application::Settings.SendErrorsMessageEnabled; std::ofstream ofs { std::string(name) }; if (ofs.good()) { @@ -106,7 +104,6 @@ void TConfig::CreateConfigFile(std::string_view name) { beammp_error("There was no \"" + std::string(mConfigFileName) + "\" file (this is normal for the first time running the server), so one was generated for you. It was automatically filled with the settings from your Server.cfg, if you have one. Please open ServerConfig.toml and ensure your AuthKey and other settings are filled in and correct, then restart the server. The old Server.cfg file will no longer be used and causes a warning if it exists from now on."); mFailed = true; ofs.close(); - // FIXME WriteSendErrors(std::string(name)); } else { beammp_error("Couldn't create " + std::string(name) + ". Check permissions, try again, and contact support if it continues not to work."); From 9d2d4bb221dc68a00a31228f41268ef12fc9c925 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Fri, 26 Nov 2021 19:08:05 +0100 Subject: [PATCH 210/255] Remove --ip This should be re-added later as a ServerConfig value --- src/main.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 94897bc..480d33e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -25,12 +25,6 @@ USAGE: ARGUMENTS: --help Displays this help and exits. - --ip= - Asks the server to bind to the - specified IPv4 address. ONLY allows - IPv4 addresses of the format - A.B.C.D, where A-D are between 0 and - 255 each. --config=/path/to/ServerConfig.toml Absolute or relative path to the Server Config file, including the @@ -90,7 +84,6 @@ int BeamMPServerMain(MainArguments Arguments) { Parser.RegisterArgument({ "help" }, ArgsParser::NONE); Parser.RegisterArgument({ "version" }, ArgsParser::NONE); Parser.RegisterArgument({ "config" }, ArgsParser::HAS_VALUE); - Parser.RegisterArgument({ "ip" }, ArgsParser::HAS_VALUE); Parser.Parse(Arguments.List); if (!Parser.Verify()) { return 1; From fd7bea0f36c363e1efe67b76db37611cbc4235d5 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sat, 27 Nov 2021 02:11:22 +0100 Subject: [PATCH 211/255] Add BEAMMP_{WINDOWS,LINUX,APPLE} preprocessor defines instead of platform specific ones --- CMakeLists.txt | 3 ++- include/Client.h | 4 ++-- include/Compat.h | 18 ++++++++---------- include/Environment.h | 17 +++++++++++++++++ src/Common.cpp | 10 +++++----- src/SignalHandling.cpp | 14 ++++++-------- src/TNetwork.cpp | 22 +++++++++++----------- 7 files changed, 51 insertions(+), 37 deletions(-) create mode 100644 include/Environment.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a50caa..133b274 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -98,7 +98,8 @@ add_executable(BeamMP-Server include/LuaAPI.h src/LuaAPI.cpp include/TScopedTimer.h src/TScopedTimer.cpp include/SignalHandling.h src/SignalHandling.cpp - include/ArgsParser.h src/ArgsParser.cpp) + include/ArgsParser.h src/ArgsParser.cpp + include/Environment.h) target_compile_definitions(BeamMP-Server PRIVATE SECRET_SENTRY_URL="${BEAMMP_SECRET_SENTRY_URL}") include_directories(BeamMP-Server PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) diff --git a/include/Client.h b/include/Client.h index 0d66e50..93882f2 100644 --- a/include/Client.h +++ b/include/Client.h @@ -13,10 +13,10 @@ class TServer; -#ifdef WIN32 +#ifdef BEAMMP_WINDOWS // for socklen_t #include -#endif // WIN32 +#endif // WINDOWS struct TConnection final { SOCKET Socket; diff --git a/include/Compat.h b/include/Compat.h index 7a366d8..e1e906d 100644 --- a/include/Compat.h +++ b/include/Compat.h @@ -1,8 +1,10 @@ #pragma once +#include "Environment.h" + // ======================= UNIX ======================== -#ifdef __unix +#ifdef BEAMMP_LINUX #include #include #include @@ -19,7 +21,9 @@ inline void CloseSocketProper(int TheSocket) { } #endif // unix -#ifdef __APPLE__ +// ======================= APPLE ======================== + +#ifdef BEAMMP_APPLE #include #include #include @@ -36,9 +40,9 @@ inline void CloseSocketProper(int TheSocket) { } #endif // unix -// ======================= WIN32 ======================= +// ======================= WINDOWS ======================= -#ifdef WIN32 +#ifdef BEAMMP_WINDOWS #include #include inline void CloseSocketProper(SOCKET TheSocket) { @@ -47,9 +51,3 @@ inline void CloseSocketProper(SOCKET TheSocket) { } #endif // WIN32 - -// ======================= OTHER ======================= - -#if !defined(WIN32) && !defined(__unix) && !defined(__APPLE__) -#error "OS not supported" -#endif \ No newline at end of file diff --git a/include/Environment.h b/include/Environment.h new file mode 100644 index 0000000..5c01601 --- /dev/null +++ b/include/Environment.h @@ -0,0 +1,17 @@ +#pragma once + +// one of BEAMMP_{WINDOWS,LINUX,APPLE} will be set at the end of this + +// clang-format off +#if !defined(BEAMMP_WINDOWS) && !defined(BEAMMP_UNIX) && !defined(BEAMMP_APPLE) + #if defined(_WIN32) || defined(__CYGWIN__) + #define BEAMMP_WINDOWS + #elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__unix__) || defined(__unix) || defined(unix) + #define BEAMMP_LINUX + #elif defined(__APPLE__) || defined(__MACH__) + #define BEAMMP_APPLE + #else + #error "This platform is not known. Please define one of the above for your OS." + #endif +#endif +// clang-format on diff --git a/src/Common.cpp b/src/Common.cpp index 59fb366..acf3b21 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -115,11 +115,11 @@ std::string ThreadName(bool DebugModeOverride) { void RegisterThread(const std::string& str) { std::string ThreadId; -#ifdef WIN32 +#ifdef BEAMMP_WINDOWS ThreadId = std::to_string(GetCurrentThreadId()); -#elif __APPLE__ +#elif defined(BEAMMP_APPLE) ThreadId = std::to_string(getpid()); // todo: research if 'getpid()' is a valid, posix compliant alternative to 'gettid()' -#else +#elif defined(BEAMMP_LINUX) ThreadId = std::to_string(gettid()); #endif if (Application::Settings.DebugModeEnabled) { @@ -159,7 +159,7 @@ void LogChatMessage(const std::string& name, int id, const std::string& msg) { } std::string GetPlatformAgnosticErrorString() { -#ifdef WIN32 +#ifdef BEAMMP_WINDOWS // This will provide us with the error code and an error message, all in one. int err; char msgbuf[256]; @@ -180,7 +180,7 @@ std::string GetPlatformAgnosticErrorString() { } else { return std::to_string(GetLastError()); } -#else // posix +#elif defined(BEAMMP_LINUX) || defined(BEAMMP_APPLE) return std::strerror(errno); #endif } diff --git a/src/SignalHandling.cpp b/src/SignalHandling.cpp index 49f50c5..2b5070e 100644 --- a/src/SignalHandling.cpp +++ b/src/SignalHandling.cpp @@ -1,7 +1,7 @@ #include "SignalHandling.h" #include "Common.h" -#if defined(__unix) || defined(__linux) || defined(__APPLE__) +#if defined(BEAMMP_LINUX) || defined(BEAMMP_APPLE) #include static void UnixSignalHandler(int sig) { switch (sig) { @@ -21,9 +21,9 @@ static void UnixSignalHandler(int sig) { break; } } -#endif // __unix +#endif // UNIX -#ifdef WIN32 +#ifdef BEAMMP_WINDOWS #include // return TRUE if handled, FALSE if not BOOL WINAPI Win32CtrlC_Handler(DWORD CtrlType) { @@ -44,21 +44,19 @@ BOOL WINAPI Win32CtrlC_Handler(DWORD CtrlType) { // we dont care for any others like CTRL_LOGOFF_EVENT and CTRL_SHUTDOWN_EVENT return FALSE; } -#endif // WIN32 +#endif // WINDOWS void SetupSignalHandlers() { // signal handlers for unix#include -#if defined(__unix) || defined(__linux) || defined(__APPLE__) +#if defined(BEAMMP_LINUX) || defined(BEAMMP_APPLE) beammp_trace("registering handlers for signals"); signal(SIGPIPE, UnixSignalHandler); signal(SIGTERM, UnixSignalHandler); #ifndef DEBUG signal(SIGINT, UnixSignalHandler); #endif // DEBUG -#elif defined(WIN32) +#elif defined(BEAMMP_WINDOWS) beammp_trace("registering handlers for CTRL_*_EVENTs"); SetConsoleCtrlHandler(Win32CtrlC_Handler, TRUE); -#else -#error "Please implement necessary signals like Ctrl+C handling here" #endif } diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index 18a710a..c3e9169 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -38,13 +38,13 @@ TNetwork::TNetwork(TServer& Server, TPPSMonitor& PPSMonitor, TResourceManager& R void TNetwork::UDPServerMain() { RegisterThread("UDPServer"); -#ifdef WIN32 +#if defined(BEAMMP_WINDOWS) WSADATA data; if (WSAStartup(514, &data)) { beammp_error(("Can't start Winsock!")); // return; } -#endif // WIN32 +#endif // WINDOWS mUDPSock = socket(AF_INET, SOCK_DGRAM, 0); // Create a server hint structure for the server sockaddr_in serverAddr {}; @@ -99,19 +99,19 @@ void TNetwork::UDPServerMain() { void TNetwork::TCPServerMain() { RegisterThread("TCPServer"); -#ifdef WIN32 +#if defined(BEAMMP_WINDOWS) WSADATA wsaData; if (WSAStartup(514, &wsaData)) { beammp_error("Can't start Winsock!"); return; } -#endif // WIN32 +#endif // WINDOWS TConnection client {}; SOCKET Listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); int optval = 1; -#ifdef WIN32 +#if defined(BEAMMP_WINDOWS) const char* optval_ptr = reinterpret_cast(&optval); -#else +#elif defined(BEAMMP_LINUX) || defined(BEAMMP_APPLE) void* optval_ptr = reinterpret_cast(&optval); #endif setsockopt(Listener, SOL_SOCKET, SO_REUSEADDR, optval_ptr, sizeof(optval)); @@ -157,10 +157,10 @@ void TNetwork::TCPServerMain() { beammp_debug("all ok, arrived at " + std::string(__func__) + ":" + std::to_string(__LINE__)); CloseSocketProper(client.Socket); -#ifdef WIN32 +#ifdef BEAMMP_WINDOWS CloseSocketProper(client.Socket); WSACleanup(); -#endif // WIN32 +#endif // WINDOWS } #undef GetObject // Fixes Windows @@ -366,11 +366,11 @@ bool TNetwork::TCPSend(TClient& c, const std::string& Data, bool IsSync) { Sent = 0; Size += 4; do { -#ifdef WIN32 +#if defined(BEAMMP_WINDOWS) int32_t Temp = send(c.GetTCPSock(), &Send[Sent], Size - Sent, 0); -#else // WIN32 +#elif defined(BEAMMP_LINUX) || defined(BEAMMP_APPLE) int32_t Temp = send(c.GetTCPSock(), &Send[Sent], Size - Sent, MSG_NOSIGNAL); -#endif // WIN32 +#endif if (Temp == 0) { beammp_debug("send() == 0: " + GetPlatformAgnosticErrorString()); if (c.GetStatus() > -1) From 6fd54f7907c90a41bdd8675d8fae93b7c3654b8f Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sat, 27 Nov 2021 02:31:21 +0100 Subject: [PATCH 212/255] Fix server message printing bug There was a space missing --- src/Common.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Common.cpp b/src/Common.cpp index acf3b21..b5db30d 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -150,7 +150,7 @@ void LogChatMessage(const std::string& name, int id, const std::string& msg) { ss << ThreadName(); ss << "[CHAT] "; if (id != -1) { - ss << "(" << id << ") <" << name << ">"; + ss << "(" << id << ") <" << name << "> "; } else { ss << name << ""; } From a4123d7d7c7683fed200db78a7b69090864bf849 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sat, 27 Nov 2021 03:28:35 +0100 Subject: [PATCH 213/255] Remove --ip example --- src/main.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 480d33e..0454d10 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -34,10 +34,6 @@ ARGUMENTS: Prints version info and exits. EXAMPLES: - BeamMP-Server --ip=203.0.113.0 - Runs the BeamMP-Server and binds its address to the - specified IP '203.0.113.0'. - BeamMP-Server --config=../MyWestCoastServerConfig.toml Runs the BeamMP-Server and uses the server config file which is one directory above it and is named From 472ec3390c4c608e303b32db4b5796a77ba4caea Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sat, 27 Nov 2021 12:25:31 +0100 Subject: [PATCH 214/255] Update changelog --- Changelog.md | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/Changelog.md b/Changelog.md index 9510032..567058b 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,29 +1,20 @@ # v2.4.0 - CHANGED entire plugin Lua implementation (rewrite) -- CHANGED moved *all* functions into MP.\* +- CHANGED moved *almost all* functions into MP.\* - CHANGED all files of a Lua plugin to share a Lua state (no more state-per-file) +- ADDED many new Lua API functions, which can be found at - ADDED Commandline options. Run with `--help` to see all options. -- ADDED `MP.GetOSName() -> string`: Returns "Linux", "Windows" or "Other" -- ADDED `MP.GetServerVersion() -> string`: Returns major,minor,patch version -- ADDED `MP.IsPlayerGuest(id) -> boolean`: Whether player with id is a guest -- ADDED `MP.Settings` table providing aliases for 0,1,2,etc. in MP.Set(id,val) -- ADDED `MP.PrintRaw(...)`: prints messages without `[TIME DATE] [LUA]` etc. -- ADDED `FS` table to host some effective filesystem manipulation functions -- ADDED `FS.CreateDirectory(path) -> bool,string`: Creates the path's directory (all missing pieces) and returns whether it fails and why if it did -- ADDED `FS.Exists(path) -> bool`: Whether the file exists -- ADDED `FS.Rename(old,new) -> bool,string`: Renames a file or folder (same as "move") -- ADDED `FS.Remove(path) -> bool,string`: Removes a file or (empty) folder -- ADDED `FS.Copy(original,copy) -> bool,string`: Copies a file or directory - ADDED plugin directories to `package.path` and `package.cpath` before `onInit` - ADDED ability to add `PluginConfig.toml` to your plugin folder to change some settings - ADDED ability to share a lua state with other plugins via `StateId` setting in `PluginConfig.toml` -- ADDED `MP.HttpsGET(host,port,target) -> status,body`: Does a synchronous HTTPS GET request -- ADDED `MP.HttpsPOST(host,port,target,body,content_type) -> status,body`: Does a synchronous HTTPS POST request -- ADDED `MP.GetStateMemoryUsage() -> number`: Current memory usage of the current state in bytes -- ADDED `MP.GetLuaMemoryUsage() -> number`: Current memory usage of all states combined, in bytes -- ADDED `MP.CreateEventTimer(event,interval_ms)`: Replacement for `CreateThread` - calls the event in the given interval -- ADDED `MP.CancelEventTimer(event)`: Cancels all event timers for that event +- ADDED ability to see name-to-thread-ID association in debug mode +- ADDED dumping tables with `print()` (try it with `print(MP)`) +- ADDED `MP.GetOSName()`, `MP.CreateTimer()`, `MP.GetLuaMemoryUsage()` and many more (see ) +- ADDED `MP.Settings` table to make usage of `MP.Set()` easier +- ADDED `FS.*` table with common filesystem operations +- FIXED i/o thread spin when stdout is /dev/null on linux +- FIXED removed extra whitespace infront of onChatMessage message # v2.3.3 From 1e0ab6bbb32214511ee602704897d5ebfd7e6c10 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sun, 28 Nov 2021 23:44:56 +0100 Subject: [PATCH 215/255] Update commandline --- deps/commandline | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/commandline b/deps/commandline index 9144d09..75e27be 160000 --- a/deps/commandline +++ b/deps/commandline @@ -1 +1 @@ -Subproject commit 9144d0978922d08f3bdf5dc32db51973fc915ab2 +Subproject commit 75e27be787c86a16e2ef456f929cbafab4393087 From 768d0466f47d1e6d5c8de415af7b4f2805909297 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sun, 28 Nov 2021 23:45:03 +0100 Subject: [PATCH 216/255] Add simple command interface --- include/LuaAPI.h | 2 +- include/TConsole.h | 7 +++ src/LuaAPI.cpp | 2 +- src/TConsole.cpp | 110 +++++++++++++++++++++++++++++++++++++++------ src/TLuaEngine.cpp | 3 ++ src/TNetwork.cpp | 2 +- 6 files changed, 109 insertions(+), 17 deletions(-) diff --git a/include/LuaAPI.h b/include/LuaAPI.h index 188cb78..0cd0e1f 100644 --- a/include/LuaAPI.h +++ b/include/LuaAPI.h @@ -5,7 +5,7 @@ namespace LuaAPI { int PanicHandler(lua_State* State); - +std::string LuaToString(const sol::object Value, size_t Indent = 1, bool QuoteStrings = false); void Print(sol::variadic_args); namespace MP { extern TLuaEngine* Engine; diff --git a/include/TConsole.h b/include/TConsole.h index 053deaa..ae34001 100644 --- a/include/TConsole.h +++ b/include/TConsole.h @@ -18,7 +18,14 @@ public: Commandline& Internal() { return mCommandline; } private: + void ChangeToLuaConsole(); + void ChangeToRegularConsole(); + Commandline mCommandline; + std::vector mCachedLuaHistory; + std::vector mCachedRegularHistory; TLuaEngine* mLuaEngine { nullptr }; + bool mIsLuaConsole { false }; + bool mFirstTime { true }; const std::string mStateId = "BEAMMP_SERVER_CONSOLE"; }; diff --git a/src/LuaAPI.cpp b/src/LuaAPI.cpp index 7b56543..14cd8f6 100644 --- a/src/LuaAPI.cpp +++ b/src/LuaAPI.cpp @@ -6,7 +6,7 @@ #define SOL_ALL_SAFETIES_ON 1 #include -static std::string LuaToString(const sol::object Value, size_t Indent = 1, bool QuoteStrings = false) { +std::string LuaAPI::LuaToString(const sol::object Value, size_t Indent, bool QuoteStrings) { if (Indent > 80) { return "[[possible recursion, refusing to keep printing]]"; } diff --git a/src/TConsole.cpp b/src/TConsole.cpp index 4c49e96..b45a0a7 100644 --- a/src/TConsole.cpp +++ b/src/TConsole.cpp @@ -2,11 +2,23 @@ #include "Common.h" #include "Compat.h" +#include "LuaAPI.h" #include "TLuaEngine.h" #include #include +static inline std::string TrimString(std::string S) { + S.erase(S.begin(), std::find_if(S.begin(), S.end(), [](unsigned char ch) { + return !std::isspace(ch); + })); + S.erase(std::find_if(S.rbegin(), S.rend(), [](unsigned char ch) { + return !std::isspace(ch); + }).base(), + S.end()); + return S; +} + std::string GetDate() { std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); time_t tt = std::chrono::system_clock::to_time_t(now); @@ -79,6 +91,26 @@ void TConsole::BackupOldLog() { } } +void TConsole::ChangeToLuaConsole() { + if (!mIsLuaConsole) { + mIsLuaConsole = true; + beammp_info("Entered Lua console. To exit, type `exit()`"); + mCachedRegularHistory = mCommandline.history(); + mCommandline.set_history(mCachedLuaHistory); + mCommandline.set_prompt("lua> "); + } +} + +void TConsole::ChangeToRegularConsole() { + if (mIsLuaConsole) { + mIsLuaConsole = false; + beammp_info("Left Lua console."); + mCachedLuaHistory = mCommandline.history(); + mCommandline.set_history(mCachedRegularHistory); + mCommandline.set_prompt("> "); + } +} + TConsole::TConsole() { mCommandline.enable_history(); mCommandline.set_history_limit(20); @@ -89,25 +121,75 @@ TConsole::TConsole() { beammp_error("unable to open file for writing: \"Server.log\""); } mCommandline.on_command = [this](Commandline& c) { - auto cmd = c.get_command(); - mCommandline.write("> " + cmd); - if (cmd == "exit") { - beammp_info("gracefully shutting down"); - Application::GracefullyShutdown(); - } else if (cmd == "clear" || cmd == "cls") { - // TODO: clear screen - } else { + try { + auto cmd = c.get_command(); + cmd = TrimString(cmd); + mCommandline.write(mCommandline.prompt() + cmd); if (!mLuaEngine) { beammp_info("Lua not started yet, please try again in a second"); } else { - auto Future = mLuaEngine->EnqueueScript(mStateId, { std::make_shared(cmd), "", "" }); - while (!Future->Ready) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - if (Future->Error) { - beammp_lua_error(Future->ErrorMessage); + if (mIsLuaConsole) { + if (cmd == "exit()") { + ChangeToRegularConsole(); + } else { + auto Future = mLuaEngine->EnqueueScript(mStateId, { std::make_shared(cmd), "", "" }); + while (!Future->Ready) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // TODO: Add a timeout + } + if (Future->Error) { + beammp_lua_error(Future->ErrorMessage); + } + } + } else { + if (cmd == "exit") { + beammp_info("gracefully shutting down"); + Application::GracefullyShutdown(); + } else if (cmd == "lua") { + ChangeToLuaConsole(); + } else if (!cmd.empty()) { + auto FutureIsNonNil = + [](const std::shared_ptr& Future) { + auto Type = Future->Result.get_type(); + return Type != sol::type::lua_nil && Type != sol::type::none; + }; + std::vector> NonNilFutures; + { // Futures scope + auto Futures = mLuaEngine->TriggerEvent("onConsoleInput", "", cmd); + TLuaEngine::WaitForAll(Futures); + size_t Count = 0; + for (auto& Future : Futures) { + if (!Future->Error) { + ++Count; + } + } + for (const auto& Future : Futures) { + if (FutureIsNonNil(Future)) { + NonNilFutures.push_back(Future); + } + } + } + if (NonNilFutures.size() == 0) { + Application::Console().WriteRaw("Error: Unknown command: '" + cmd + "'"); + } else { + std::stringstream Reply; + if (NonNilFutures.size() > 1) { + for (size_t i = 0; i < NonNilFutures.size(); ++i) { + Reply << NonNilFutures[i]->StateId << ": \n" + << LuaAPI::LuaToString(NonNilFutures[i]->Result); + if (i < NonNilFutures.size() - 1) { + Reply << "\n"; + } + } + } else { + Reply << LuaAPI::LuaToString(NonNilFutures[0]->Result); + } + Application::Console().WriteRaw(Reply.str()); + } + } } } + } catch (const std::exception& e) { + beammp_error("Console died with: " + std::string(e.what()) + ". This could be a fatal error and could cause the server to terminate."); } }; } diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index cd712c1..b493f75 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -77,6 +77,9 @@ void TLuaEngine::operator()() { // event loop auto Before = std::chrono::high_resolution_clock::now(); while (!mShutdown) { + if (mLuaStates.size() == 0) { + std::this_thread::sleep_for(std::chrono::seconds(500)); + } { // Timed Events Scope std::unique_lock Lock(mTimedEventsMutex); for (auto& Timer : mTimedEvents) { diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index c3e9169..49cfca8 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -203,7 +203,7 @@ void TNetwork::HandleDownload(SOCKET TCPSock) { }); } -void TNetwork::Authentication(const TConnection& ClientConnection) { +void TNetwork:: Authentication(const TConnection& ClientConnection) { auto Client = CreateClient(ClientConnection.Socket); char AddrBuf[64]; // TODO: IPv6 would need this to be changed From 297b646d333a21a040022c1c87135d3ccd5d36d4 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 29 Nov 2021 00:17:03 +0100 Subject: [PATCH 217/255] update commandline --- deps/commandline | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/commandline b/deps/commandline index 75e27be..e796b5e 160000 --- a/deps/commandline +++ b/deps/commandline @@ -1 +1 @@ -Subproject commit 75e27be787c86a16e2ef456f929cbafab4393087 +Subproject commit e796b5e62c0c78a83674ecce2867ba7e76f91c62 From c91f3ee33c3087dd12bfb76a977f7cd7a3dfbc2a Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 29 Nov 2021 00:17:09 +0100 Subject: [PATCH 218/255] Print entering and leaving lua as raw --- src/TConsole.cpp | 11 +++++++---- src/TLuaEngine.cpp | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/TConsole.cpp b/src/TConsole.cpp index b45a0a7..da71a78 100644 --- a/src/TConsole.cpp +++ b/src/TConsole.cpp @@ -94,7 +94,7 @@ void TConsole::BackupOldLog() { void TConsole::ChangeToLuaConsole() { if (!mIsLuaConsole) { mIsLuaConsole = true; - beammp_info("Entered Lua console. To exit, type `exit()`"); + Application::Console().WriteRaw("Entered Lua console. To exit, type `exit()`"); mCachedRegularHistory = mCommandline.history(); mCommandline.set_history(mCachedLuaHistory); mCommandline.set_prompt("lua> "); @@ -104,7 +104,7 @@ void TConsole::ChangeToLuaConsole() { void TConsole::ChangeToRegularConsole() { if (mIsLuaConsole) { mIsLuaConsole = false; - beammp_info("Left Lua console."); + Application::Console().WriteRaw("Left Lua console."); mCachedLuaHistory = mCommandline.history(); mCommandline.set_history(mCachedRegularHistory); mCommandline.set_prompt("> "); @@ -149,8 +149,11 @@ TConsole::TConsole() { } else if (!cmd.empty()) { auto FutureIsNonNil = [](const std::shared_ptr& Future) { - auto Type = Future->Result.get_type(); - return Type != sol::type::lua_nil && Type != sol::type::none; + if (!Future->Error) { + auto Type = Future->Result.get_type(); + return Type != sol::type::lua_nil && Type != sol::type::none; + } + return false; }; std::vector> NonNilFutures; { // Futures scope diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index b493f75..72e0b94 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -408,6 +408,7 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi lua_atpanic(mState, LuaAPI::PanicHandler); // StateView.globals()["package"].get() StateView.set_function("print", &LuaAPI::Print); + StateView.set_function("printRaw", &LuaAPI::MP::PrintRaw); StateView.set_function("exit", &Application::GracefullyShutdown); auto MPTable = StateView.create_named_table("MP"); @@ -462,7 +463,6 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi return Lua_GetPlayerIdentifiers(ID); }); MPTable.set_function("Sleep", &LuaAPI::MP::Sleep); - MPTable.set_function("PrintRaw", &LuaAPI::MP::PrintRaw); MPTable.set_function("CreateEventTimer", [&](const std::string& EventName, size_t IntervalMS) { if (IntervalMS < 25) { beammp_warn("Timer for \"" + EventName + "\" on \"" + mStateId + "\" is set to trigger at <25ms, which is likely too fast and won't cancel properly."); From fc440bea2abd467c2275089c813139277436c5b5 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 29 Nov 2021 00:37:00 +0100 Subject: [PATCH 219/255] Add ability to switch into other lua states --- include/TConsole.h | 5 +++-- include/TLuaEngine.h | 1 + src/TConsole.cpp | 33 +++++++++++++++++++++++++++------ src/TLuaEngine.cpp | 5 +++++ 4 files changed, 36 insertions(+), 8 deletions(-) diff --git a/include/TConsole.h b/include/TConsole.h index ae34001..ab45eb0 100644 --- a/include/TConsole.h +++ b/include/TConsole.h @@ -18,7 +18,7 @@ public: Commandline& Internal() { return mCommandline; } private: - void ChangeToLuaConsole(); + void ChangeToLuaConsole(const std::string& LuaStateId); void ChangeToRegularConsole(); Commandline mCommandline; @@ -27,5 +27,6 @@ private: TLuaEngine* mLuaEngine { nullptr }; bool mIsLuaConsole { false }; bool mFirstTime { true }; - const std::string mStateId = "BEAMMP_SERVER_CONSOLE"; + std::string mStateId; + const std::string mDefaultStateId = "BEAMMP_SERVER_CONSOLE"; }; diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index c38afc8..87e0c0d 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -84,6 +84,7 @@ public: static void WaitForAll(std::vector>& Results); void ReportErrors(const std::vector >& Results); + bool HasState(TLuaStateId StateId); [[nodiscard]] std::shared_ptr EnqueueScript(TLuaStateId StateID, const TLuaChunk& Script); [[nodiscard]] std::shared_ptr EnqueueFunctionCall(TLuaStateId StateID, const std::string& FunctionName, const std::vector& Args); void EnsureStateExists(TLuaStateId StateId, const std::string& Name, bool DontCallOnInit = false); diff --git a/src/TConsole.cpp b/src/TConsole.cpp index da71a78..10bd03d 100644 --- a/src/TConsole.cpp +++ b/src/TConsole.cpp @@ -2,6 +2,7 @@ #include "Common.h" #include "Compat.h" +#include "CustomAssert.h" #include "LuaAPI.h" #include "TLuaEngine.h" @@ -91,10 +92,15 @@ void TConsole::BackupOldLog() { } } -void TConsole::ChangeToLuaConsole() { +void TConsole::ChangeToLuaConsole(const std::string& LuaStateId) { if (!mIsLuaConsole) { + mStateId = LuaStateId; mIsLuaConsole = true; - Application::Console().WriteRaw("Entered Lua console. To exit, type `exit()`"); + if (mStateId != mDefaultStateId) { + Application::Console().WriteRaw("Entered Lua console for state '" + mStateId + "'. To exit, type `exit()`"); + } else { + Application::Console().WriteRaw("Entered Lua console. To exit, type `exit()`"); + } mCachedRegularHistory = mCommandline.history(); mCommandline.set_history(mCachedLuaHistory); mCommandline.set_prompt("lua> "); @@ -104,10 +110,15 @@ void TConsole::ChangeToLuaConsole() { void TConsole::ChangeToRegularConsole() { if (mIsLuaConsole) { mIsLuaConsole = false; - Application::Console().WriteRaw("Left Lua console."); + if (mStateId != mDefaultStateId) { + Application::Console().WriteRaw("Left Lua console for state '" + mStateId + "'."); + } else { + Application::Console().WriteRaw("Left Lua console."); + } mCachedLuaHistory = mCommandline.history(); mCommandline.set_history(mCachedRegularHistory); mCommandline.set_prompt("> "); + mStateId = mDefaultStateId; } } @@ -144,8 +155,18 @@ TConsole::TConsole() { if (cmd == "exit") { beammp_info("gracefully shutting down"); Application::GracefullyShutdown(); - } else if (cmd == "lua") { - ChangeToLuaConsole(); + } else if (cmd.size() >= 3 && cmd.substr(0, 3) == "lua") { + if (cmd.size() > 3) { + auto NewStateId = cmd.substr(4); + beammp_assert(!NewStateId.empty()); + if (mLuaEngine->HasState(NewStateId)) { + ChangeToLuaConsole(NewStateId); + } else { + Application::Console().WriteRaw("Lua state '" + NewStateId + "' is not a known state. Didn't switch to Lua."); + } + } else { + ChangeToLuaConsole(mDefaultStateId); + } } else if (!cmd.empty()) { auto FutureIsNonNil = [](const std::shared_ptr& Future) { @@ -208,5 +229,5 @@ void TConsole::WriteRaw(const std::string& str) { void TConsole::InitializeLuaConsole(TLuaEngine& Engine) { mLuaEngine = &Engine; - Engine.EnsureStateExists(mStateId, "Console"); + Engine.EnsureStateExists(mDefaultStateId, "Console"); } diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 72e0b94..7c1a5d2 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -162,6 +162,11 @@ void TLuaEngine::ReportErrors(const std::vector>& Re } } +bool TLuaEngine::HasState(TLuaStateId StateId) { + std::unique_lock Lock(mLuaStatesMutex); + return mLuaStates.find(StateId) != mLuaStates.end(); +} + std::shared_ptr TLuaEngine::EnqueueScript(TLuaStateId StateID, const TLuaChunk& Script) { std::unique_lock Lock(mLuaStatesMutex); return mLuaStates.at(StateID)->EnqueueScript(Script); From 19d67dee95f9cb5344ad6752502541eae33dc04a Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 29 Nov 2021 01:14:37 +0100 Subject: [PATCH 220/255] Add GetPlayerIDByName, kick, say --- include/TConsole.h | 10 ++- include/TLuaEngine.h | 5 +- src/TConsole.cpp | 144 +++++++++++++++++++++++++++---------------- src/TLuaEngine.cpp | 22 ++++++- 4 files changed, 122 insertions(+), 59 deletions(-) diff --git a/include/TConsole.h b/include/TConsole.h index ab45eb0..110cfc9 100644 --- a/include/TConsole.h +++ b/include/TConsole.h @@ -16,11 +16,17 @@ public: void InitializeLuaConsole(TLuaEngine& Engine); void BackupOldLog(); Commandline& Internal() { return mCommandline; } - + private: + void RunAsCommand(const std::string& cmd, bool IgnoreNotACommand = false); void ChangeToLuaConsole(const std::string& LuaStateId); void ChangeToRegularConsole(); - + + void Command_Lua(const std::string& cmd); + void Command_Help(const std::string& cmd); + void Command_Kick(const std::string& cmd); + void Command_Say(const std::string& cmd); + Commandline mCommandline; std::vector mCachedLuaHistory; std::vector mCachedRegularHistory; diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index 87e0c0d..7e2cadf 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -83,7 +83,7 @@ public: void SetServer(TServer* Server) { mServer = Server; } static void WaitForAll(std::vector>& Results); - void ReportErrors(const std::vector >& Results); + void ReportErrors(const std::vector>& Results); bool HasState(TLuaStateId StateId); [[nodiscard]] std::shared_ptr EnqueueScript(TLuaStateId StateID, const TLuaChunk& Script); [[nodiscard]] std::shared_ptr EnqueueFunctionCall(TLuaStateId StateID, const std::string& FunctionName, const std::vector& Args); @@ -139,6 +139,7 @@ private: std::string Lua_GetPlayerName(int ID); sol::table Lua_GetPlayerVehicles(int ID); sol::table Lua_HttpCreateConnection(const std::string& host, uint16_t port); + int Lua_GetPlayerIDByName(const std::string& Name); std::string mName; std::atomic_bool& mShutdown; @@ -181,4 +182,4 @@ private: std::recursive_mutex mResultsToCheckMutex; }; -//std::any TriggerLuaEvent(const std::string& Event, bool local, TLuaPlugin* Caller, std::shared_ptr arg, bool Wait); +// std::any TriggerLuaEvent(const std::string& Event, bool local, TLuaPlugin* Caller, std::shared_ptr arg, bool Wait); diff --git a/src/TConsole.cpp b/src/TConsole.cpp index 10bd03d..3b91ea7 100644 --- a/src/TConsole.cpp +++ b/src/TConsole.cpp @@ -9,6 +9,10 @@ #include #include +static inline bool StringStartsWith(const std::string& What, const std::string& StartsWith) { + return What.size() >= StartsWith.size() && What.substr(0, StartsWith.size()) == StartsWith; +} + static inline std::string TrimString(std::string S) { S.erase(S.begin(), std::find_if(S.begin(), S.end(), [](unsigned char ch) { return !std::isspace(ch); @@ -122,6 +126,81 @@ void TConsole::ChangeToRegularConsole() { } } +void TConsole::Command_Lua(const std::string& cmd) { + if (cmd.size() > 3) { + auto NewStateId = cmd.substr(4); + beammp_assert(!NewStateId.empty()); + if (mLuaEngine->HasState(NewStateId)) { + ChangeToLuaConsole(NewStateId); + } else { + Application::Console().WriteRaw("Lua state '" + NewStateId + "' is not a known state. Didn't switch to Lua."); + } + } else { + ChangeToLuaConsole(mDefaultStateId); + } +} + +void TConsole::Command_Help(const std::string&) { + static constexpr const char* sHelpString = R"( + Commands: + help displays this help + exit shuts down the server + lua [state id] switches to lua, optionally into a specific state id's lua +)"; + Application::Console().WriteRaw("BeamMP-Server Console: " + std::string(sHelpString)); +} + +void TConsole::Command_Kick(const std::string& cmd) { + cmd.compare() +} + +void TConsole::Command_Say(const std::string& cmd) { +} + +void TConsole::RunAsCommand(const std::string& cmd, bool IgnoreNotACommand) { + auto FutureIsNonNil = + [](const std::shared_ptr& Future) { + if (!Future->Error) { + auto Type = Future->Result.get_type(); + return Type != sol::type::lua_nil && Type != sol::type::none; + } + return false; + }; + std::vector> NonNilFutures; + { // Futures scope + auto Futures = mLuaEngine->TriggerEvent("onConsoleInput", "", cmd); + TLuaEngine::WaitForAll(Futures); + size_t Count = 0; + for (auto& Future : Futures) { + if (!Future->Error) { + ++Count; + } + } + for (const auto& Future : Futures) { + if (FutureIsNonNil(Future)) { + NonNilFutures.push_back(Future); + } + } + } + if (NonNilFutures.size() == 0 && !IgnoreNotACommand) { + Application::Console().WriteRaw("Error: Unknown command: '" + cmd + "'"); + } else { + std::stringstream Reply; + if (NonNilFutures.size() > 1) { + for (size_t i = 0; i < NonNilFutures.size(); ++i) { + Reply << NonNilFutures[i]->StateId << ": \n" + << LuaAPI::LuaToString(NonNilFutures[i]->Result); + if (i < NonNilFutures.size() - 1) { + Reply << "\n"; + } + } + } else { + Reply << LuaAPI::LuaToString(NonNilFutures[0]->Result); + } + Application::Console().WriteRaw(Reply.str()); + } +} + TConsole::TConsole() { mCommandline.enable_history(); mCommandline.set_history_limit(20); @@ -155,60 +234,19 @@ TConsole::TConsole() { if (cmd == "exit") { beammp_info("gracefully shutting down"); Application::GracefullyShutdown(); - } else if (cmd.size() >= 3 && cmd.substr(0, 3) == "lua") { - if (cmd.size() > 3) { - auto NewStateId = cmd.substr(4); - beammp_assert(!NewStateId.empty()); - if (mLuaEngine->HasState(NewStateId)) { - ChangeToLuaConsole(NewStateId); - } else { - Application::Console().WriteRaw("Lua state '" + NewStateId + "' is not a known state. Didn't switch to Lua."); - } - } else { - ChangeToLuaConsole(mDefaultStateId); - } + } else if (StringStartsWith(cmd, "lua")) { + Command_Lua(cmd); + } else if (StringStartsWith(cmd, "help")) { + RunAsCommand(cmd, true); + Command_Help(cmd); + } else if (StringStartsWith(cmd, "kick")) { + RunAsCommand(cmd, true); + Command_Kick(cmd); + } else if (StringStartsWith(cmd, "say")) { + RunAsCommand(cmd, true); + Command_Say(cmd); } else if (!cmd.empty()) { - auto FutureIsNonNil = - [](const std::shared_ptr& Future) { - if (!Future->Error) { - auto Type = Future->Result.get_type(); - return Type != sol::type::lua_nil && Type != sol::type::none; - } - return false; - }; - std::vector> NonNilFutures; - { // Futures scope - auto Futures = mLuaEngine->TriggerEvent("onConsoleInput", "", cmd); - TLuaEngine::WaitForAll(Futures); - size_t Count = 0; - for (auto& Future : Futures) { - if (!Future->Error) { - ++Count; - } - } - for (const auto& Future : Futures) { - if (FutureIsNonNil(Future)) { - NonNilFutures.push_back(Future); - } - } - } - if (NonNilFutures.size() == 0) { - Application::Console().WriteRaw("Error: Unknown command: '" + cmd + "'"); - } else { - std::stringstream Reply; - if (NonNilFutures.size() > 1) { - for (size_t i = 0; i < NonNilFutures.size(); ++i) { - Reply << NonNilFutures[i]->StateId << ": \n" - << LuaAPI::LuaToString(NonNilFutures[i]->Result); - if (i < NonNilFutures.size() - 1) { - Reply << "\n"; - } - } - } else { - Reply << LuaAPI::LuaToString(NonNilFutures[0]->Result); - } - Application::Console().WriteRaw(Reply.str()); - } + RunAsCommand(cmd); } } } diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 7c1a5d2..a835aae 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -184,7 +184,7 @@ void TLuaEngine::CollectAndInitPlugins() { if (!Dir.is_directory()) { beammp_error("\"" + Dir.path().string() + "\" is not a directory, skipping"); } else { - TLuaPluginConfig Config { Path.string() }; + TLuaPluginConfig Config { Path.stem().string() }; FindAndParseConfig(Path, Config); InitializePlugin(Path, Config); } @@ -213,7 +213,7 @@ void TLuaEngine::FindAndParseConfig(const fs::path& Folder, TLuaPluginConfig& Co beammp_debug("Plugin \"" + Folder.string() + "\" specified it wants LuaStateID \"" + ID + "\""); Config.StateId = ID; } else { - beammp_debug("LuaStateID empty, using randomized state ID"); + beammp_debug("LuaStateID empty, using plugin name"); } } } catch (const std::exception& e) { @@ -345,6 +345,21 @@ sol::table TLuaEngine::StateThreadData::Lua_GetPlayers() { return Result; } +int TLuaEngine::StateThreadData::Lua_GetPlayerIDByName(const std::string& Name) { + int Id = -1; + mEngine->mServer->ForEachClient([&Id, &Name](std::weak_ptr Client) -> bool { + if (!Client.expired()) { + auto locked = Client.lock(); + if (locked->GetName() == Name) { + Id = locked->GetID(); + return false; + } + } + return true; + }); + return Id; +} + std::string TLuaEngine::StateThreadData::Lua_GetPlayerName(int ID) { auto MaybeClient = GetClient(mEngine->Server(), ID); if (MaybeClient && !MaybeClient.value().expired()) { @@ -445,6 +460,9 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi MPTable.set_function("TriggerClientEvent", &LuaAPI::MP::TriggerClientEvent); MPTable.set_function("GetPlayerCount", &LuaAPI::MP::GetPlayerCount); MPTable.set_function("IsPlayerConnected", &LuaAPI::MP::IsPlayerConnected); + MPTable.set_function("GetPlayerIDByName", [&](const std::string& Name) -> std::string { + return Lua_GetPlayerIDByName(Name); + }); MPTable.set_function("GetPlayerName", [&](int ID) -> std::string { return Lua_GetPlayerName(ID); }); From 8f77f1c8c01094d025fa760ac4ca90beed4e1b0a Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 29 Nov 2021 01:34:35 +0100 Subject: [PATCH 221/255] Add kick, fix cmakelists pretending to be on linux all the time lol --- CMakeLists.txt | 3 ++- src/TConsole.cpp | 44 ++++++++++++++++++++++++++++++++++++++------ src/TLuaEngine.cpp | 2 +- 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 133b274..b51ee20 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,7 @@ include_directories("${PROJECT_SOURCE_DIR}/deps/sol2/include") include_directories("${PROJECT_SOURCE_DIR}/deps/cpp-httplib") include_directories("${PROJECT_SOURCE_DIR}/deps") -add_compile_definitions(CPPHTTPLIB_OPENSSL_SUPPORT __linux) +add_compile_definitions(CPPHTTPLIB_OPENSSL_SUPPORT) if(APPLE) set(LUA_INCLUDE_DIR /usr/local/Cellar/lua@5.3/5.3.6/include/lua5.3) @@ -24,6 +24,7 @@ if(APPLE) include_directories(/usr/local/opt/openssl@1.1/include) link_directories(/usr/local/Cellar/lua@5.3/5.3.6/lib) link_directories(/usr/local/opt/openssl@1.1/lib) + add_compile_definitions(__linux) endif() if (WIN32) diff --git a/src/TConsole.cpp b/src/TConsole.cpp index 3b91ea7..6ed9f58 100644 --- a/src/TConsole.cpp +++ b/src/TConsole.cpp @@ -2,6 +2,7 @@ #include "Common.h" #include "Compat.h" +#include "Client.h" #include "CustomAssert.h" #include "LuaAPI.h" #include "TLuaEngine.h" @@ -143,15 +144,44 @@ void TConsole::Command_Lua(const std::string& cmd) { void TConsole::Command_Help(const std::string&) { static constexpr const char* sHelpString = R"( Commands: - help displays this help - exit shuts down the server - lua [state id] switches to lua, optionally into a specific state id's lua + help displays this help + exit shuts down the server + kick [reason] kicks specified player with an optional reason + list lists all players and info about them + say sends the message to all players in chat + lua [state id] switches to lua, optionally into a specific state id's lua )"; Application::Console().WriteRaw("BeamMP-Server Console: " + std::string(sHelpString)); } void TConsole::Command_Kick(const std::string& cmd) { - cmd.compare() + if (cmd.size() > 4) { + auto Name = cmd.substr(5); + std::string Reason = "Kicked by server console"; + auto SpacePos = Name.find(' '); + if (SpacePos != Name.npos) { + Reason = Name.substr(SpacePos + 1); + Name = cmd.substr(5, cmd.size() - Reason.size() - 5 - 1); + } + beammp_trace("attempt to kick '" + Name + "' for '" + Reason + "'"); + bool Kicked = false; + auto NameCompare = [](std::string Name1, std::string Name2) -> bool { + std::for_each(Name1.begin(), Name1.end(), [](char& c) { c = tolower(c); }); + std::for_each(Name2.begin(), Name2.end(), [](char& c) { c = tolower(c); }); + return StringStartsWith(Name1, Name2) || StringStartsWith(Name2, Name1); + }; + mLuaEngine->Server().ForEachClient([&](std::weak_ptr Client) -> bool { + if (!Client.expired()) { + auto locked = Client.lock(); + if (NameCompare(locked->GetName(), Name)) { + mLuaEngine->Network().ClientKick(*locked, Reason); + Kicked = true; + return false; + } + } + return true; + }); + } } void TConsole::Command_Say(const std::string& cmd) { @@ -182,8 +212,10 @@ void TConsole::RunAsCommand(const std::string& cmd, bool IgnoreNotACommand) { } } } - if (NonNilFutures.size() == 0 && !IgnoreNotACommand) { - Application::Console().WriteRaw("Error: Unknown command: '" + cmd + "'"); + if (NonNilFutures.size() == 0) { + if (!IgnoreNotACommand) { + Application::Console().WriteRaw("Error: Unknown command: '" + cmd + "'"); + } } else { std::stringstream Reply; if (NonNilFutures.size() > 1) { diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index a835aae..e0cbd89 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -460,7 +460,7 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi MPTable.set_function("TriggerClientEvent", &LuaAPI::MP::TriggerClientEvent); MPTable.set_function("GetPlayerCount", &LuaAPI::MP::GetPlayerCount); MPTable.set_function("IsPlayerConnected", &LuaAPI::MP::IsPlayerConnected); - MPTable.set_function("GetPlayerIDByName", [&](const std::string& Name) -> std::string { + MPTable.set_function("GetPlayerIDByName", [&](const std::string& Name) -> int { return Lua_GetPlayerIDByName(Name); }); MPTable.set_function("GetPlayerName", [&](int ID) -> std::string { From c3151093e28c3e6f0e307a61b1f2d1188a5a5d90 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 29 Nov 2021 01:42:23 +0100 Subject: [PATCH 222/255] CMake: remove __linux completely --- CMakeLists.txt | 1 - include/TConsole.h | 1 + src/TConsole.cpp | 15 +++++++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b51ee20..a8f37ca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,7 +24,6 @@ if(APPLE) include_directories(/usr/local/opt/openssl@1.1/include) link_directories(/usr/local/Cellar/lua@5.3/5.3.6/lib) link_directories(/usr/local/opt/openssl@1.1/lib) - add_compile_definitions(__linux) endif() if (WIN32) diff --git a/include/TConsole.h b/include/TConsole.h index 110cfc9..25ff258 100644 --- a/include/TConsole.h +++ b/include/TConsole.h @@ -26,6 +26,7 @@ private: void Command_Help(const std::string& cmd); void Command_Kick(const std::string& cmd); void Command_Say(const std::string& cmd); + void Command_List(const std::string& cmd); Commandline mCommandline; std::vector mCachedLuaHistory; diff --git a/src/TConsole.cpp b/src/TConsole.cpp index 6ed9f58..f7aa3fa 100644 --- a/src/TConsole.cpp +++ b/src/TConsole.cpp @@ -185,6 +185,21 @@ void TConsole::Command_Kick(const std::string& cmd) { } void TConsole::Command_Say(const std::string& cmd) { + if (cmd.size() > 3) { + auto Message = cmd.substr(4); + LuaAPI::MP::SendChatMessage(-1, Message); + } +} + +void TConsole::Command_List(const std::string& cmd) { + std::stringstream ss; + mLuaEngine->Server().ForEachClient([&](std::weak_ptr Client) -> bool { + if (!Client.expired()) { + auto locked = Client.lock(); + ss << + } + return true; + }); } void TConsole::RunAsCommand(const std::string& cmd, bool IgnoreNotACommand) { From 1bc9a5293e7356b63ee5099683413a9c5db41465 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 29 Nov 2021 02:03:20 +0100 Subject: [PATCH 223/255] Add kick response --- src/TConsole.cpp | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/src/TConsole.cpp b/src/TConsole.cpp index f7aa3fa..e7b5a98 100644 --- a/src/TConsole.cpp +++ b/src/TConsole.cpp @@ -181,6 +181,11 @@ void TConsole::Command_Kick(const std::string& cmd) { } return true; }); + if (!Kicked) { + Application::Console().WriteRaw("Error: No player with name matching '" + Name + "' was found."); + } else { + Application::Console().WriteRaw("Kicked player '" + Name + "' for reason: '" + Reason + "'."); + } } } @@ -191,15 +196,24 @@ void TConsole::Command_Say(const std::string& cmd) { } } -void TConsole::Command_List(const std::string& cmd) { - std::stringstream ss; - mLuaEngine->Server().ForEachClient([&](std::weak_ptr Client) -> bool { - if (!Client.expired()) { - auto locked = Client.lock(); - ss << - } - return true; - }); +void TConsole::Command_List(const std::string&) { + if (mLuaEngine->Server().ClientCount() == 0) { + Application::Console().WriteRaw("No players online."); + } else { + std::stringstream ss; + ss << std::left << std::setw(25) << "Name" << std::setw(6) << "ID" << std::setw(6) << "Cars" << std::endl; + mLuaEngine->Server().ForEachClient([&](std::weak_ptr Client) -> bool { + if (!Client.expired()) { + auto locked = Client.lock(); + ss << std::left << std::setw(25) << locked->GetName() + << std::setw(6) << locked->GetID() + << std::setw(6) << locked->GetCarCount() << "\n"; + } + return true; + }); + auto Str = ss.str(); + Application::Console().WriteRaw(Str.substr(0, Str.size() - 1)); + } } void TConsole::RunAsCommand(const std::string& cmd, bool IgnoreNotACommand) { @@ -292,6 +306,9 @@ TConsole::TConsole() { } else if (StringStartsWith(cmd, "say")) { RunAsCommand(cmd, true); Command_Say(cmd); + } else if (StringStartsWith(cmd, "list")) { + RunAsCommand(cmd, true); + Command_List(cmd); } else if (!cmd.empty()) { RunAsCommand(cmd); } From ccdc5dae17b293d698328f64832998d18c88908e Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 29 Nov 2021 02:09:05 +0100 Subject: [PATCH 224/255] update commandline --- deps/commandline | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/commandline b/deps/commandline index e796b5e..3d11606 160000 --- a/deps/commandline +++ b/deps/commandline @@ -1 +1 @@ -Subproject commit e796b5e62c0c78a83674ecce2867ba7e76f91c62 +Subproject commit 3d11606d02b449b8afd40a7132160d2392043eb3 From 98c7fea1396bf00ef8319c7f194387ddf972e607 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 29 Nov 2021 02:56:41 +0100 Subject: [PATCH 225/255] Possible fix for event handler timeouts --- src/TConsole.cpp | 3 +-- src/TLuaEngine.cpp | 7 +++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/TConsole.cpp b/src/TConsole.cpp index e7b5a98..5cca537 100644 --- a/src/TConsole.cpp +++ b/src/TConsole.cpp @@ -149,8 +149,7 @@ void TConsole::Command_Help(const std::string&) { kick [reason] kicks specified player with an optional reason list lists all players and info about them say 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)"; Application::Console().WriteRaw("BeamMP-Server Console: " + std::string(sHelpString)); } diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index e0cbd89..6881cfc 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -61,8 +61,11 @@ void TLuaEngine::operator()() { while (!Res->Ready) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); Waited++; - if (Waited > 1000) { - beammp_lua_error(Res->Function + " in " + Res->StateId + " took >1s to respond, not printing possible errors"); + if (Waited > 250) { + // FIXME: This should *eventually* timeout. + // beammp_lua_error(Res->Function + " in " + Res->StateId + " took >1s to respond, not printing possible errors"); + std::unique_lock Lock(mResultsToCheckMutex); + mResultsToCheck.push(Res); break; } } From eb67f483b2740b848c89863abc910ea0a237cf73 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 29 Nov 2021 03:07:20 +0100 Subject: [PATCH 226/255] Another possible fix for deadlock --- src/TLuaEngine.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 6881cfc..d814a22 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -64,8 +64,9 @@ void TLuaEngine::operator()() { if (Waited > 250) { // FIXME: This should *eventually* timeout. // beammp_lua_error(Res->Function + " in " + Res->StateId + " took >1s to respond, not printing possible errors"); - std::unique_lock Lock(mResultsToCheckMutex); + Lock.lock(); mResultsToCheck.push(Res); + Lock.unlock(); break; } } From 265dd710cf5c5d8a754c9747399db306c765cae2 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 2 Dec 2021 01:25:17 +0100 Subject: [PATCH 227/255] add `status` command --- include/TConsole.h | 1 + include/TLuaEngine.h | 23 +++++++++++++++++++ include/TScopedTimer.h | 6 +++++ include/TServer.h | 2 ++ src/TConsole.cpp | 52 +++++++++++++++++++++++++++++++++++++++++- 5 files changed, 83 insertions(+), 1 deletion(-) diff --git a/include/TConsole.h b/include/TConsole.h index 25ff258..618c586 100644 --- a/include/TConsole.h +++ b/include/TConsole.h @@ -27,6 +27,7 @@ private: void Command_Kick(const std::string& cmd); void Command_Say(const std::string& cmd); void Command_List(const std::string& cmd); + void Command_Status(const std::string& cmd); Commandline mCommandline; std::vector mCachedLuaHistory; diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index 7e2cadf..8a87c7d 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -82,6 +82,29 @@ public: void SetNetwork(TNetwork* Network) { mNetwork = Network; } void SetServer(TServer* Server) { mServer = Server; } + size_t GetResultsToCheckSize() { + std::unique_lock Lock(mResultsToCheckMutex); + return mResultsToCheck.size(); + } + size_t GetLuaStateCount() { + std::unique_lock Lock(mLuaStatesMutex); + return mLuaStates.size(); + } + size_t GetTimedEventsCount() { + std::unique_lock Lock(mTimedEventsMutex); + return mTimedEvents.size(); + } + size_t GetRegisteredEventHandlerCount() { + std::unique_lock Lock(mLuaEventsMutex); + size_t LuaEventsCount = 0; + for (const auto& State : mLuaEvents) { + for (const auto& Events : State.second) { + LuaEventsCount += Events.second.size(); + } + } + return LuaEventsCount - GetLuaStateCount(); + } + static void WaitForAll(std::vector>& Results); void ReportErrors(const std::vector>& Results); bool HasState(TLuaStateId StateId); diff --git a/include/TScopedTimer.h b/include/TScopedTimer.h index 3eea0ee..600e69a 100644 --- a/include/TScopedTimer.h +++ b/include/TScopedTimer.h @@ -10,6 +10,12 @@ public: TScopedTimer(const std::string& Name); TScopedTimer(std::function OnDestroy); ~TScopedTimer(); + auto GetElapsedTime() const { + auto EndTime = std::chrono::high_resolution_clock::now(); + auto Delta = EndTime - mStartTime; + size_t TimeDelta = Delta / std::chrono::milliseconds(1); + return TimeDelta; + } std::function OnDestroy { nullptr }; diff --git a/include/TServer.h b/include/TServer.h index dded2d9..2e51e12 100644 --- a/include/TServer.h +++ b/include/TServer.h @@ -29,6 +29,8 @@ public: static void HandleEvent(TClient& c, const std::string& Data); RWMutex& GetClientMutex() const { return mClientsMutex; } + + const TScopedTimer UptimeTimer; private: TClientSet mClients; mutable RWMutex mClientsMutex; diff --git a/src/TConsole.cpp b/src/TConsole.cpp index 5cca537..0bca9a8 100644 --- a/src/TConsole.cpp +++ b/src/TConsole.cpp @@ -149,7 +149,8 @@ void TConsole::Command_Help(const std::string&) { kick [reason] kicks specified player with an optional reason list lists all players and info about them say 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 + status how the server is doing and what it's up to)"; Application::Console().WriteRaw("BeamMP-Server Console: " + std::string(sHelpString)); } @@ -215,6 +216,52 @@ void TConsole::Command_List(const std::string&) { } } +void TConsole::Command_Status(const std::string&) { + std::stringstream Status; + + size_t CarCount = 0; + size_t ConnectedCount = 0; + size_t GuestCount = 0; + size_t SyncedCount = 0; + size_t SyncingCount = 0; + size_t MissedPacketQueueSum = 0; + int LargestSecondsSinceLastPing = 0; + mLuaEngine->Server().ForEachClient([&](std::weak_ptr Client) -> bool { + if (!Client.expired()) { + auto Locked = Client.lock(); + CarCount += Locked->GetCarCount(); + ConnectedCount += Locked->IsConnected() ? 1 : 0; + GuestCount += Locked->IsGuest() ? 1 : 0; + SyncedCount += Locked->IsSynced() ? 1 : 0; + SyncingCount += Locked->IsSyncing() ? 1 : 0; + MissedPacketQueueSum += Locked->MissedPacketQueueSize(); + if (Locked->SecondsSinceLastPing() < LargestSecondsSinceLastPing) { + LargestSecondsSinceLastPing = Locked->SecondsSinceLastPing(); + } + } + return true; + }); + + auto ElapsedTime = mLuaEngine->Server().UptimeTimer.GetElapsedTime(); + + Status << "BeamMP-Server Status:\n" + << "\tTotal Players: " << mLuaEngine->Server().ClientCount() << "\n" + << "\tSyncing Players: " << SyncingCount << "\n" + << "\tSynced Players: " << SyncedCount << "\n" + << "\tConnected Players: " << ConnectedCount << "\n" + << "\tGuests: " << GuestCount << "\n" + << "\tCars: " << CarCount << "\n" + << "\tUptime: " << ElapsedTime << "ms (~" << size_t(ElapsedTime / 1000.0 / 60.0 / 60.0) << "h) \n" + << "\tLua:\n" + << "\t\tQueued results to check: " << mLuaEngine->GetResultsToCheckSize() << "\n" + << "\t\tStates: " << mLuaEngine->GetLuaStateCount() << "\n" + << "\t\tEvent timers: " << mLuaEngine->GetTimedEventsCount() << "\n" + << "\t\tEvent handlers: " << mLuaEngine->GetRegisteredEventHandlerCount() << "\n" + << ""; + + Application::Console().WriteRaw(Status.str()); +} + void TConsole::RunAsCommand(const std::string& cmd, bool IgnoreNotACommand) { auto FutureIsNonNil = [](const std::shared_ptr& Future) { @@ -308,6 +355,9 @@ TConsole::TConsole() { } else if (StringStartsWith(cmd, "list")) { RunAsCommand(cmd, true); Command_List(cmd); + } else if (StringStartsWith(cmd, "status")) { + RunAsCommand(cmd, true); + Command_Status(cmd); } else if (!cmd.empty()) { RunAsCommand(cmd); } From 7b99ccb08e7d4848161e275c9126a72b09db1c66 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sun, 5 Dec 2021 00:42:50 +0100 Subject: [PATCH 228/255] Add --working-directory flag --- src/main.cpp | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 0454d10..8dc25b9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -30,6 +30,10 @@ ARGUMENTS: Server Config file, including the filename. For paths and filenames with spaces, put quotes around the path. + --working-directory=/path/to/folder + Sets the working directory of the Server. + All paths are considered relative to this, + including the path given in --path. --version Prints version info and exits. @@ -80,6 +84,7 @@ int BeamMPServerMain(MainArguments Arguments) { Parser.RegisterArgument({ "help" }, ArgsParser::NONE); Parser.RegisterArgument({ "version" }, ArgsParser::NONE); Parser.RegisterArgument({ "config" }, ArgsParser::HAS_VALUE); + Parser.RegisterArgument({ "working-directory" }, ArgsParser::HAS_VALUE); Parser.Parse(Arguments.List); if (!Parser.Verify()) { return 1; @@ -94,13 +99,24 @@ int BeamMPServerMain(MainArguments Arguments) { Application::Console().WriteRaw("BeamMP-Server v" + Application::ServerVersionString()); return 0; } - + std::string ConfigPath = "ServerConfig.toml"; if (Parser.FoundArgument({ "config" })) { auto MaybeConfigPath = Parser.GetValueOfArgument({ "config" }); if (MaybeConfigPath.has_value()) { ConfigPath = MaybeConfigPath.value(); - beammp_info("Custom config requested via commandline: '" + ConfigPath + "'"); + beammp_info("Custom config requested via commandline arguments: '" + ConfigPath + "'"); + } + } + if (Parser.FoundArgument({ "working-directory" })) { + auto MaybeWorkingDirectory = Parser.GetValueOfArgument({ "working-directory" }); + if (MaybeWorkingDirectory.has_value()) { + beammp_info("Custom working directory requested via commandline arguments: '" + ConfigPath + "'"); + try { + fs::current_path(fs::path(MaybeWorkingDirectory.value())); + } catch (const std::exception& e) { + beammp_error("Could not set working directory to '" + MaybeWorkingDirectory.value() + "': " + e.what()); + } } } From f477570a1c75619f27c6693786738a305937b375 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sun, 5 Dec 2021 00:54:24 +0100 Subject: [PATCH 229/255] Add changelog about new console --- Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog.md b/Changelog.md index 567058b..0066bc6 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,6 +2,7 @@ - CHANGED entire plugin Lua implementation (rewrite) - CHANGED moved *almost all* functions into MP.\* +- CHANGED console to use a custom language (type `help`!) - CHANGED all files of a Lua plugin to share a Lua state (no more state-per-file) - ADDED many new Lua API functions, which can be found at - ADDED Commandline options. Run with `--help` to see all options. From 86169ad0fad168e69d25dcb065d2c7ecfc45be58 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sun, 5 Dec 2021 00:55:42 +0100 Subject: [PATCH 230/255] TConsole: Add notice about help command on wrong command --- src/TConsole.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TConsole.cpp b/src/TConsole.cpp index 0bca9a8..afb44ac 100644 --- a/src/TConsole.cpp +++ b/src/TConsole.cpp @@ -289,7 +289,7 @@ void TConsole::RunAsCommand(const std::string& cmd, bool IgnoreNotACommand) { } if (NonNilFutures.size() == 0) { if (!IgnoreNotACommand) { - Application::Console().WriteRaw("Error: Unknown command: '" + cmd + "'"); + Application::Console().WriteRaw("Error: Unknown command: '" + cmd + "'. Type 'help' to see a list of valid commands."); } } else { std::stringstream Reply; From a289d0e872b969651fd788132fd4bb8ef3ea2706 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sun, 5 Dec 2021 01:09:41 +0100 Subject: [PATCH 231/255] Add timeout to WaitForAll --- include/TLuaEngine.h | 3 ++- src/TLuaEngine.cpp | 10 ++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index 8a87c7d..ade2d25 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -105,7 +105,8 @@ public: return LuaEventsCount - GetLuaStateCount(); } - static void WaitForAll(std::vector>& Results); + static void WaitForAll(std::vector>& Results, + const std::chrono::high_resolution_clock::duration& Max = std::chrono::hours(std::numeric_limits().max())); void ReportErrors(const std::vector>& Results); bool HasState(TLuaStateId StateId); [[nodiscard]] std::shared_ptr EnqueueScript(TLuaStateId StateID, const TLuaChunk& Script); diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index d814a22..f3bd977 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -145,10 +145,16 @@ TLuaStateId TLuaEngine::GetStateIDForPlugin(const fs::path& PluginPath) { return ""; } -void TLuaEngine::WaitForAll(std::vector>& Results) { +void TLuaEngine::WaitForAll(std::vector>& Results, const std::chrono::high_resolution_clock::duration& max) { + size_t ms = 0; + bool Cancelled = false; for (const auto& Result : Results) { - while (!Result->Ready) { + while (!Result->Ready && !Cancelled) { std::this_thread::sleep_for(std::chrono::milliseconds(10)); + ms += 10; + if (std::chrono::milliseconds(ms) > max) { + Cancelled = true; + } } if (Result->Error) { if (Result->ErrorMessage != BeamMPFnNotFoundError) { From 672c7d02d1eb6a2ef1a4f65de37b9a807110734e Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sun, 5 Dec 2021 01:31:44 +0100 Subject: [PATCH 232/255] Common: Add lua warn --- include/Common.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/Common.h b/include/Common.h index c6b8b1e..4541ba3 100644 --- a/include/Common.h +++ b/include/Common.h @@ -149,7 +149,11 @@ void RegisterThread(const std::string& str); } while (false) #define beammp_lua_error(x) \ do { \ - Application::Console().Write(_this_location + std::string("[LUA_ERROR] ") + (x)); \ + Application::Console().Write(_this_location + std::string("[LUA ERROR] ") + (x)); \ + } while (false) +#define beammp_lua_warn(x) \ + do { \ + Application::Console().Write(_this_location + std::string("[LUA WARN] ") + (x)); \ } while (false) #define luaprint(x) Application::Console().Write(_this_location + std::string("[LUA] ") + (x)) #define beammp_debug(x) \ From 479bb9f931cbc7b3ffb949a907176855b1a72706 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sun, 5 Dec 2021 01:32:15 +0100 Subject: [PATCH 233/255] TLuaEngine: Make WaitForAll timeout optional --- include/TLuaEngine.h | 2 +- src/TConsole.cpp | 4 ++-- src/TLuaEngine.cpp | 13 ++++++++----- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index ade2d25..63e5c3d 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -106,7 +106,7 @@ public: } static void WaitForAll(std::vector>& Results, - const std::chrono::high_resolution_clock::duration& Max = std::chrono::hours(std::numeric_limits().max())); + const std::optional& Max = std::nullopt); void ReportErrors(const std::vector>& Results); bool HasState(TLuaStateId StateId); [[nodiscard]] std::shared_ptr EnqueueScript(TLuaStateId StateID, const TLuaChunk& Script); diff --git a/src/TConsole.cpp b/src/TConsole.cpp index afb44ac..857941a 100644 --- a/src/TConsole.cpp +++ b/src/TConsole.cpp @@ -265,7 +265,7 @@ void TConsole::Command_Status(const std::string&) { void TConsole::RunAsCommand(const std::string& cmd, bool IgnoreNotACommand) { auto FutureIsNonNil = [](const std::shared_ptr& Future) { - if (!Future->Error) { + if (!Future->Error && Future->Result.valid()) { auto Type = Future->Result.get_type(); return Type != sol::type::lua_nil && Type != sol::type::none; } @@ -274,7 +274,7 @@ void TConsole::RunAsCommand(const std::string& cmd, bool IgnoreNotACommand) { std::vector> NonNilFutures; { // Futures scope auto Futures = mLuaEngine->TriggerEvent("onConsoleInput", "", cmd); - TLuaEngine::WaitForAll(Futures); + TLuaEngine::WaitForAll(Futures, std::chrono::seconds(5)); size_t Count = 0; for (auto& Future : Futures) { if (!Future->Error) { diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index f3bd977..f473b21 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -145,18 +145,21 @@ TLuaStateId TLuaEngine::GetStateIDForPlugin(const fs::path& PluginPath) { return ""; } -void TLuaEngine::WaitForAll(std::vector>& Results, const std::chrono::high_resolution_clock::duration& max) { - size_t ms = 0; - bool Cancelled = false; +void TLuaEngine::WaitForAll(std::vector>& Results, const std::optional& Max) { for (const auto& Result : Results) { + bool Cancelled = false; + size_t ms = 0; while (!Result->Ready && !Cancelled) { std::this_thread::sleep_for(std::chrono::milliseconds(10)); ms += 10; - if (std::chrono::milliseconds(ms) > max) { + if (Max.has_value() && std::chrono::milliseconds(ms) > Max.value()) { + beammp_trace("'" + Result->Function + "' in '" + Result->StateId + "' did not finish executing in time (took: " + std::to_string(ms) + "ms)"); Cancelled = true; } } - if (Result->Error) { + if (Cancelled) { + beammp_lua_warn("'" + Result->Function + "' in '" + Result->StateId + "' failed to execute in time and was not waited for. It may still finish executing at a later time."); + } else if (Result->Error) { if (Result->ErrorMessage != BeamMPFnNotFoundError) { beammp_lua_error(Result->Function + ": " + Result->ErrorMessage); } From b33d50361c38af430b9bf76d51d8689a535f4d4a Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Sun, 5 Dec 2021 01:40:39 +0100 Subject: [PATCH 234/255] fix typo in --help --- src/TNetwork.cpp | 2 +- src/main.cpp | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index 49cfca8..c3e9169 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -203,7 +203,7 @@ void TNetwork::HandleDownload(SOCKET TCPSock) { }); } -void TNetwork:: Authentication(const TConnection& ClientConnection) { +void TNetwork::Authentication(const TConnection& ClientConnection) { auto Client = CreateClient(ClientConnection.Socket); char AddrBuf[64]; // TODO: IPv6 would need this to be changed diff --git a/src/main.cpp b/src/main.cpp index 8dc25b9..be58b64 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -33,7 +33,7 @@ ARGUMENTS: --working-directory=/path/to/folder Sets the working directory of the Server. All paths are considered relative to this, - including the path given in --path. + including the path given in --config. --version Prints version info and exits. @@ -111,7 +111,7 @@ int BeamMPServerMain(MainArguments Arguments) { if (Parser.FoundArgument({ "working-directory" })) { auto MaybeWorkingDirectory = Parser.GetValueOfArgument({ "working-directory" }); if (MaybeWorkingDirectory.has_value()) { - beammp_info("Custom working directory requested via commandline arguments: '" + ConfigPath + "'"); + beammp_info("Custom working directory requested via commandline arguments: '" + MaybeWorkingDirectory.value() + "'"); try { fs::current_path(fs::path(MaybeWorkingDirectory.value())); } catch (const std::exception& e) { @@ -156,6 +156,7 @@ int BeamMPServerMain(MainArguments Arguments) { Application::CheckForUpdates(); RegisterThread("Main(Waiting)"); + while (!Shutdown) { std::this_thread::sleep_for(std::chrono::milliseconds(50)); } From 9d283738aa596e53a6f3c7435e24b592cf2d9d91 Mon Sep 17 00:00:00 2001 From: awesome_milou <46608440+jimkoen@users.noreply.github.com> Date: Sun, 5 Dec 2021 18:24:55 +0100 Subject: [PATCH 235/255] Add preliminary work for HTTP health endpoint (#68) * Add preliminary work for HTTP health endpoint * Http: Fix infinite loop bug in Tx509KeypairGenerator::generateKey() * update commandline * Add TLS Support class for use with http server * Add preliminary HTTP Server; TLS still broken; fix in later commit * Fix TLS handshake, due to server being unable to serve key/certfile in 'Http.h/Http.cpp'; Cause was httlib not being threadsafe due to being a blocking http library * Run clang format * Add option to configure http server port via ServerConfig * TConfig: add HTTPServerPort to config parsing step * Fix SSL Cert / Key path not auto generating when not existing * Add health endpoint; Fix SSL Cert serial no. not refreshing when regenerating * Switch arround status codes in /health route * Run clang format Co-authored-by: Lion Kortlepel --- deps/commandline | 1 - include/Common.h | 12 +++ include/Http.h | 44 ++++++++++ include/TConfig.h | 3 +- include/TLuaEngine.h | 17 +++- src/Http.cpp | 169 +++++++++++++++++++++++++++++++++++++-- src/TConfig.cpp | 25 +++++- src/TConsole.cpp | 8 +- src/THeartbeatThread.cpp | 2 + src/TNetwork.cpp | 2 +- src/main.cpp | 8 +- 11 files changed, 273 insertions(+), 18 deletions(-) delete mode 160000 deps/commandline diff --git a/deps/commandline b/deps/commandline deleted file mode 160000 index 3d11606..0000000 --- a/deps/commandline +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3d11606d02b449b8afd40a7132160d2392043eb3 diff --git a/include/Common.h b/include/Common.h index 4541ba3..79d53f8 100644 --- a/include/Common.h +++ b/include/Common.h @@ -40,6 +40,9 @@ public: , ServerDesc("BeamMP Default Description") , Resource("Resources") , MapName("/levels/gridmap_v2/info.json") + , SSLKeyPath("./.ssl/HttpServer/key.pem") + , SSLCertPath("./.ssl/HttpServer/cert.pem") + , HTTPServerPort(8080) , MaxPlayers(10) , Private(true) , MaxCars(1) @@ -52,6 +55,8 @@ public: std::string Resource; std::string MapName; std::string Key; + std::string SSLKeyPath; + std::string SSLCertPath; int MaxPlayers; bool Private; int MaxCars; @@ -61,6 +66,7 @@ public: bool SendErrors; bool SendErrorsMessageEnabled; [[nodiscard]] bool HasCustomIP() const { return !CustomIP.empty(); } + int HTTPServerPort; }; using TShutdownHandler = std::function; @@ -162,6 +168,12 @@ void RegisterThread(const std::string& str); Application::Console().Write(_this_location + std::string("[DEBUG] ") + (x)); \ } \ } while (false) +#define beammp_event(x) \ + do { \ + if (Application::Settings.DebugModeEnabled) { \ + Application::Console().Write(_this_location + std::string("[EVENT] ") + (x)); \ + } \ + }while(false) // for those times when you just need to ignore something :^) // explicity disables a [[nodiscard]] warning #define beammp_ignore(x) (void)x diff --git a/include/Http.h b/include/Http.h index 568054b..e5c1495 100644 --- a/include/Http.h +++ b/include/Http.h @@ -1,8 +1,20 @@ #pragma once +#include +#include +#include +#include +#include +#include #include #include +namespace fs = std::filesystem; + +namespace Crypto { +constexpr size_t RSA_DEFAULT_KEYLENGTH { 2048 }; +} + namespace Http { std::string GET(const std::string& host, int port, const std::string& target, unsigned int* status = nullptr); std::string POST(const std::string& host, int port, const std::string& target, const std::string& body, const std::string& ContentType, unsigned int* status = nullptr); @@ -10,4 +22,36 @@ namespace Status { std::string ToString(int code); } const std::string ErrorString = "-1"; + +namespace Server { + void SetupEnvironment(); + // todo: Add non TLS Server Instance, this one is TLS only + class THttpServerInstance : IThreaded { + public: + THttpServerInstance(); + static fs::path KeyFilePath; + static fs::path CertFilePath; + + protected: + void operator()(); + + private: + /** + * the shared pointer is necessary because httplib is a blocking library and due lacking thread-safety + * will "forget" about its environment, when configured across multiple threads. + * So we need to able to start the server (make it "listen()") in a single Thread. + */ + std::shared_ptr mHttpLibServerInstancePtr; + }; + // todo: all of these functions are likely unsafe, + // todo: replace with something that's managed by a domain specific crypto library + class Tx509KeypairGenerator { + public: + static long GenerateRandomId(); + static bool EnsureTLSConfigExists(); + static X509* GenerateCertificate(EVP_PKEY& pkey); + static EVP_PKEY* GenerateKey(); + static void GenerateAndWriteToDisk(const fs::path& KeyFilePath, const fs::path& CertFilePath); + }; +} } diff --git a/include/TConfig.h b/include/TConfig.h index f20766f..bd8f46d 100644 --- a/include/TConfig.h +++ b/include/TConfig.h @@ -20,7 +20,8 @@ private: void PrintDebug(); void ParseOldFormat(); - + bool IsDefault(); bool mFailed { false }; std::string mConfigFileName; }; + diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index 63e5c3d..3b2e070 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -20,6 +20,9 @@ using TLuaStateId = std::string; namespace fs = std::filesystem; +/** + * std::variant means, that TLuaArgTypes may be one of the Types listed as template args + */ using TLuaArgTypes = std::variant; static constexpr size_t TLuaArgTypes_String = 0; static constexpr size_t TLuaArgTypes_Int = 1; @@ -114,11 +117,21 @@ public: void EnsureStateExists(TLuaStateId StateId, const std::string& Name, bool DontCallOnInit = false); void RegisterEvent(const std::string& EventName, TLuaStateId StateId, const std::string& FunctionName); template + /** + * + * @tparam ArgsT Template Arguments for the event (Metadata) todo: figure out what this means + * @param EventName Name of the event + * @param IgnoreId + * @param Args + * @return + */ [[nodiscard]] std::vector> TriggerEvent(const std::string& EventName, TLuaStateId IgnoreId, ArgsT&&... Args) { std::unique_lock Lock(mLuaEventsMutex); - if (mLuaEvents.find(EventName) == mLuaEvents.end()) { + beammp_event(EventName); + if (mLuaEvents.find(EventName) == mLuaEvents.end()) { // if no event handler is defined for 'EventName', return immediately return {}; } + std::vector> Results; for (const auto& Event : mLuaEvents.at(EventName)) { for (const auto& Function : Event.second) { @@ -127,7 +140,7 @@ public: } } } - return Results; + return Results; // } std::set GetEventHandlersForState(const std::string& EventName, TLuaStateId StateId); void CreateEventTimer(const std::string& EventName, TLuaStateId StateId, size_t IntervalMS); diff --git a/src/Http.cpp b/src/Http.cpp index 609a4e8..598ae7b 100644 --- a/src/Http.cpp +++ b/src/Http.cpp @@ -1,11 +1,13 @@ #include "Http.h" #include "Common.h" +#include "CustomAssert.h" #include - -#include - +#include +#include +fs::path Http::Server::THttpServerInstance::KeyFilePath; +fs::path Http::Server::THttpServerInstance::CertFilePath; // TODO: Add sentry error handling back std::string Http::GET(const std::string& host, int port, const std::string& target, unsigned int* status) { @@ -115,10 +117,163 @@ static std::map Map = { { 530, "(CDN) 1XXX Internal Error" }, }; -std::string Http::Status::ToString(int code) { - if (Map.find(code) != Map.end()) { - return Map.at(code); +std::string Http::Status::ToString(int Code) { + if (Map.find(Code) != Map.end()) { + return Map.at(Code); } else { - return std::to_string(code); + return std::to_string(Code); } } + +long Http::Server::Tx509KeypairGenerator::GenerateRandomId() { + std::random_device R; + std::default_random_engine E1(R()); + std::uniform_int_distribution UniformDist(0, ULONG_MAX); + return UniformDist(E1); +} + +// Http::Server::THttpServerInstance::THttpServerInstance() { } +EVP_PKEY* Http::Server::Tx509KeypairGenerator::GenerateKey() { + /** + * Allocate memory for the pkey + */ + EVP_PKEY* PKey = EVP_PKEY_new(); + if (PKey == nullptr) { + beammp_error("Could not allocate memory for X.509 private key (PKEY) generation."); + throw std::runtime_error { std::string { "X.509 PKEY allocation error" } }; + } + BIGNUM* E = BN_new(); + beammp_assert(E); // TODO: replace all these asserts with beammp_errors + unsigned char three = 3; + BIGNUM* EErr = BN_bin2bn(&three, sizeof(three), E); + beammp_assert(EErr); + RSA* Rsa = RSA_new(); + beammp_assert(Rsa); + int Ret = RSA_generate_key_ex(Rsa, Crypto::RSA_DEFAULT_KEYLENGTH, E, nullptr); + beammp_assert(Ret == 1); + BN_free(E); + if (!EVP_PKEY_assign_RSA(PKey, Rsa)) { + EVP_PKEY_free(PKey); + beammp_error(std::string("Could not generate " + std::to_string(Crypto::RSA_DEFAULT_KEYLENGTH) + "-bit RSA key.")); + throw std::runtime_error { std::string("X.509 RSA key generation error") }; + } + // todo: figure out if returning by reference instead of passing pointers is a security breach + return PKey; +} + +X509* Http::Server::Tx509KeypairGenerator::GenerateCertificate(EVP_PKEY& PKey) { + X509* X509 = X509_new(); + if (X509 == nullptr) { + X509_free(X509); + beammp_error("Could not allocate memory for X.509 certificate generation."); + throw std::runtime_error { std::string("X.509 certificate generation error") }; + } + + /**Set the metadata of the certificate*/ + ASN1_INTEGER_set(X509_get_serialNumber(X509), GenerateRandomId()); + + /**Set the cert validity to a year*/ + X509_gmtime_adj(X509_get_notBefore(X509), 0); + X509_gmtime_adj(X509_get_notAfter(X509), 31536000L); + + /**Set the public key of the cert*/ + X509_set_pubkey(X509, &PKey); + + X509_NAME* Name = X509_get_subject_name(X509); + + /**Set cert metadata*/ + X509_NAME_add_entry_by_txt(Name, "C", MBSTRING_ASC, (unsigned char*)"GB", -1, -1, 0); + X509_NAME_add_entry_by_txt(Name, "O", MBSTRING_ASC, (unsigned char*)"BeamMP Ltd.", -1, -1, 0); + X509_NAME_add_entry_by_txt(Name, "CN", MBSTRING_ASC, (unsigned char*)"localhost", -1, -1, 0); + + X509_set_issuer_name(X509, Name); + + // TODO: Hashing with sha256 might cause problems, check later + if (!X509_sign(X509, &PKey, EVP_sha1())) { + X509_free(X509); + beammp_error("Could not sign X.509 certificate."); + throw std::runtime_error { std::string("X.509 certificate signing error") }; + } + return X509; +} + +void Http::Server::Tx509KeypairGenerator::GenerateAndWriteToDisk(const fs::path& KeyFilePath, const fs::path& CertFilePath) { + // todo: generate directories for ssl keys + FILE* KeyFile = std::fopen(KeyFilePath.c_str(), "wb"); + if (!KeyFile) { + beammp_error("Could not create file 'key.pem', check your permissions"); + throw std::runtime_error("Could not create file 'key.pem'"); + } + + EVP_PKEY* PKey = Http::Server::Tx509KeypairGenerator::GenerateKey(); + + bool WriteOpResult = PEM_write_PrivateKey(KeyFile, PKey, nullptr, nullptr, 0, nullptr, nullptr); + fclose(KeyFile); + + if (!WriteOpResult) { + beammp_error("Could not write to file 'key.pem', check your permissions"); + throw std::runtime_error("Could not write to file 'key.pem'"); + } + + FILE* CertFile = std::fopen(CertFilePath.c_str(), "wb"); // x509 file + if (!CertFile) { + beammp_error("Could not create file 'cert.pem', check your permissions"); + throw std::runtime_error("Could not create file 'cert.pem'"); + } + + X509* x509 = Http::Server::Tx509KeypairGenerator::GenerateCertificate(*PKey); + WriteOpResult = PEM_write_X509(CertFile, x509); + fclose(CertFile); + + if (!WriteOpResult) { + beammp_error("Could not write to file 'cert.pem', check your permissions"); + throw std::runtime_error("Could not write to file 'cert.pem'"); + } + EVP_PKEY_free(PKey); + X509_free(x509); + return; +} +bool Http::Server::Tx509KeypairGenerator::EnsureTLSConfigExists() { + if (fs::is_regular_file(Application::Settings.SSLKeyPath) + && fs::is_regular_file(Application::Settings.SSLCertPath)) { + return true; + } else { + return false; + } +} + +void Http::Server::SetupEnvironment() { + auto parent = fs::path(Application::Settings.SSLKeyPath).parent_path(); + if (!fs::exists(parent)) + fs::create_directories(parent); + + Application::TSettings defaultSettings {}; + if (!Tx509KeypairGenerator::EnsureTLSConfigExists()) { + beammp_warn(std::string("No default TLS Key / Cert found. " + "IF YOU HAVE NOT MODIFIED THE SSLKeyPath OR SSLCertPath VALUES " + "THIS IS NORMAL ON FIRST STARTUP! BeamMP will generate it's own certs in the default directory " + "(Check for permissions or corrupted key-/certfile)")); + Tx509KeypairGenerator::GenerateAndWriteToDisk(defaultSettings.SSLKeyPath, defaultSettings.SSLCertPath); + Http::Server::THttpServerInstance::KeyFilePath = defaultSettings.SSLKeyPath; + Http::Server::THttpServerInstance::CertFilePath = defaultSettings.SSLCertPath; + } else { + Http::Server::THttpServerInstance::KeyFilePath = Application::Settings.SSLKeyPath; + Http::Server::THttpServerInstance::CertFilePath = Application::Settings.SSLCertPath; + } +} + +Http::Server::THttpServerInstance::THttpServerInstance() { + Start(); +} +void Http::Server::THttpServerInstance::operator()() { + // todo: make this IP agnostic so people can set their own IP + this->mHttpLibServerInstancePtr = std::make_shared(Application::Settings.SSLCertPath.c_str(), Application::Settings.SSLKeyPath.c_str()); + this->mHttpLibServerInstancePtr->Get("/", [](const httplib::Request&, httplib::Response& res) { + res.set_content("

Hello World!

BeamMP Server can now serve HTTP requests!

", "text/html"); + }); + this->mHttpLibServerInstancePtr->Get("/health", [](const httplib::Request& req, httplib::Response& res) { + res.set_content("0", "text/plain"); + res.status = 200; + }); + this->mHttpLibServerInstancePtr->listen("0.0.0.0", Application::Settings.HTTPServerPort); +} diff --git a/src/TConfig.cpp b/src/TConfig.cpp index ba90e39..276d993 100644 --- a/src/TConfig.cpp +++ b/src/TConfig.cpp @@ -1,3 +1,4 @@ +#include "Common.h" #define TOML11_PRESERVE_COMMENTS_BY_DEFAULT #include // header-only version of TOML++ @@ -20,6 +21,9 @@ static constexpr std::string_view StrResourceFolder = "ResourceFolder"; static constexpr std::string_view StrAuthKey = "AuthKey"; static constexpr std::string_view StrSendErrors = "SendErrors"; static constexpr std::string_view StrSendErrorsMessageEnabled = "SendErrorsShowMessage"; +static constexpr std::string_view StrSSLKeyPath = "SSLKeyPath"; +static constexpr std::string_view StrSSLCertPath = "SSLCertPath"; +static constexpr std::string_view StrHTTPServerPort = "HTTPServerPort"; void WriteSendErrors(const std::string& name) { std::ofstream CfgFile { name, std::ios::out | std::ios::app }; @@ -43,7 +47,15 @@ TConfig::TConfig(const std::string& ConfigFileName) ParseFromFile(mConfigFileName); } } - +/** + * @brief Writes out the loaded application state into ServerConfig.toml + * + * This writes out the current state of application settings that are + * applied to the server instance (i.e. the current application settings loaded in the server). + * If the state of the application settings changes during runtime, + * call this function whenever something about the config changes + * whether it is in TConfig.cpp or the configuration file. + */ void TConfig::FlushToFile() { auto data = toml::parse(mConfigFileName); data["General"] = toml::table(); @@ -59,6 +71,9 @@ void TConfig::FlushToFile() { data["General"][StrResourceFolder.data()] = Application::Settings.Resource; data["General"][StrSendErrors.data()] = Application::Settings.SendErrors; data["General"][StrSendErrorsMessageEnabled.data()] = Application::Settings.SendErrorsMessageEnabled; + data["General"][StrSSLKeyPath.data()] = Application::Settings.SSLKeyPath; + data["General"][StrSSLCertPath.data()] = Application::Settings.SSLCertPath; + data["General"][StrHTTPServerPort.data()] = Application::Settings.HTTPServerPort; std::ofstream Stream(mConfigFileName); Stream << data << std::flush; } @@ -93,6 +108,9 @@ void TConfig::CreateConfigFile(std::string_view name) { data["General"][StrMap.data()] = Application::Settings.MapName; data["General"][StrDescription.data()] = Application::Settings.ServerDesc; data["General"][StrResourceFolder.data()] = Application::Settings.Resource; + data["General"][StrSSLKeyPath.data()] = Application::Settings.SSLKeyPath; + data["General"][StrSSLCertPath.data()] = Application::Settings.SSLCertPath; + data["General"][StrHTTPServerPort.data()] = Application::Settings.HTTPServerPort; std::ofstream ofs { std::string(name) }; if (ofs.good()) { @@ -124,6 +142,9 @@ void TConfig::ParseFromFile(std::string_view name) { Application::Settings.ServerDesc = data["General"][StrDescription.data()].as_string(); Application::Settings.Resource = data["General"][StrResourceFolder.data()].as_string(); Application::Settings.Key = data["General"][StrAuthKey.data()].as_string(); + Application::Settings.SSLKeyPath = data["General"][StrSSLKeyPath.data()].as_string(); + Application::Settings.SSLCertPath = data["General"][StrSSLCertPath.data()].as_string(); + Application::Settings.HTTPServerPort = data["General"][StrHTTPServerPort.data()].as_integer(); if (!data["General"][StrSendErrors.data()].is_boolean() || !data["General"][StrSendErrorsMessageEnabled.data()].is_boolean()) { WriteSendErrors(std::string(name)); @@ -154,6 +175,8 @@ void TConfig::PrintDebug() { beammp_debug(std::string(StrName) + ": \"" + Application::Settings.ServerName + "\""); beammp_debug(std::string(StrDescription) + ": \"" + Application::Settings.ServerDesc + "\""); beammp_debug(std::string(StrResourceFolder) + ": \"" + Application::Settings.Resource + "\""); + beammp_debug(std::string(StrSSLKeyPath) + ": \"" + Application::Settings.SSLKeyPath + "\""); + beammp_debug(std::string(StrSSLCertPath) + ": \"" + Application::Settings.SSLCertPath + "\""); // special! beammp_debug("Key Length: " + std::to_string(Application::Settings.Key.length()) + ""); } diff --git a/src/TConsole.cpp b/src/TConsole.cpp index 857941a..f0293bd 100644 --- a/src/TConsole.cpp +++ b/src/TConsole.cpp @@ -106,8 +106,8 @@ void TConsole::ChangeToLuaConsole(const std::string& LuaStateId) { } else { Application::Console().WriteRaw("Entered Lua console. To exit, type `exit()`"); } - mCachedRegularHistory = mCommandline.history(); - mCommandline.set_history(mCachedLuaHistory); + //mCachedRegularHistory = mCommandline.history(); + //mCommandline.set_history(mCachedLuaHistory); mCommandline.set_prompt("lua> "); } } @@ -120,8 +120,8 @@ void TConsole::ChangeToRegularConsole() { } else { Application::Console().WriteRaw("Left Lua console."); } - mCachedLuaHistory = mCommandline.history(); - mCommandline.set_history(mCachedRegularHistory); + //mCachedLuaHistory = mCommandline.history(); + //mCommandline.set_history(mCachedRegularHistory); mCommandline.set_prompt("> "); mStateId = mDefaultStateId; } diff --git a/src/THeartbeatThread.cpp b/src/THeartbeatThread.cpp index 574eda3..ac7a293 100644 --- a/src/THeartbeatThread.cpp +++ b/src/THeartbeatThread.cpp @@ -6,6 +6,7 @@ #include void THeartbeatThread::operator()() { + return;/* RegisterThread("Heartbeat"); std::string Body; std::string T; @@ -82,6 +83,7 @@ void THeartbeatThread::operator()() { //SocketIO::Get().SetAuthenticated(isAuth); } + */ } std::string THeartbeatThread::GenerateCall() { diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index c3e9169..914bf85 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -211,7 +211,7 @@ void TNetwork::Authentication(const TConnection& ClientConnection) { beammp_trace("This thread is ip " + std::string(str)); Client->SetIdentifier("ip", str); - std::string Rc; + std::string Rc; //TODO: figure out why this is not default constructed beammp_info("Identifying new ClientConnection..."); Rc = TCPRcv(*Client); diff --git a/src/main.cpp b/src/main.cpp index be58b64..5701ea4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -17,7 +17,7 @@ #include #include - +#define CPPHTTPLIB_OPENSSL_SUPPORT 1 static const std::string sCommandlineArguments = R"( USAGE: BeamMP-Server [arguments] @@ -155,6 +155,12 @@ int BeamMPServerMain(MainArguments Arguments) { Application::Console().InitializeLuaConsole(LuaEngine); Application::CheckForUpdates(); + Http::Server::SetupEnvironment(); + Http::Server::THttpServerInstance HttpServerInstance {}; + + beammp_debug("cert.pem is " + std::to_string(fs::file_size("cert.pem")) + " bytes"); + beammp_debug("key.pem is " + std::to_string(fs::file_size("key.pem")) + " bytes"); + RegisterThread("Main(Waiting)"); while (!Shutdown) { From bd41382233ab671cd65841bacd03235101f0baa4 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 6 Dec 2021 09:00:57 +0100 Subject: [PATCH 236/255] Application::TSettings: Improve default initialisation --- include/Common.h | 49 +++++++++++++++++------------------------------- 1 file changed, 17 insertions(+), 32 deletions(-) diff --git a/include/Common.h b/include/Common.h index 79d53f8..7b0322b 100644 --- a/include/Common.h +++ b/include/Common.h @@ -35,38 +35,23 @@ class Application final { public: // types struct TSettings { - TSettings() noexcept - : ServerName("BeamMP Server") - , ServerDesc("BeamMP Default Description") - , Resource("Resources") - , MapName("/levels/gridmap_v2/info.json") - , SSLKeyPath("./.ssl/HttpServer/key.pem") - , SSLCertPath("./.ssl/HttpServer/cert.pem") - , HTTPServerPort(8080) - , MaxPlayers(10) - , Private(true) - , MaxCars(1) - , DebugModeEnabled(false) - , Port(30814) - , SendErrors(true) - , SendErrorsMessageEnabled(true) { } - std::string ServerName; - std::string ServerDesc; - std::string Resource; - std::string MapName; - std::string Key; - std::string SSLKeyPath; - std::string SSLCertPath; - int MaxPlayers; - bool Private; - int MaxCars; - bool DebugModeEnabled; - int Port; - std::string CustomIP; - bool SendErrors; - bool SendErrorsMessageEnabled; + std::string ServerName { "BeamMP Server" }; + std::string ServerDesc { "BeamMP Default Description" }; + std::string Resource { "Resources" }; + std::string MapName { "/levels/gridmap_v2/info.json" }; + std::string Key {}; + std::string SSLKeyPath { "./.ssl/HttpServer/key.pem" }; + std::string SSLCertPath { "./.ssl/HttpServer/cert.pem" }; + int MaxPlayers { 10 }; + bool Private { true }; + int MaxCars { 1 }; + bool DebugModeEnabled { false }; + int Port { 30814 }; + std::string CustomIP {}; + bool SendErrors { true }; + bool SendErrorsMessageEnabled { true }; + int HTTPServerPort { 8080 }; [[nodiscard]] bool HasCustomIP() const { return !CustomIP.empty(); } - int HTTPServerPort; }; using TShutdownHandler = std::function; @@ -173,7 +158,7 @@ void RegisterThread(const std::string& str); if (Application::Settings.DebugModeEnabled) { \ Application::Console().Write(_this_location + std::string("[EVENT] ") + (x)); \ } \ - }while(false) + } while (false) // for those times when you just need to ignore something :^) // explicity disables a [[nodiscard]] warning #define beammp_ignore(x) (void)x From 62cc1e9ce4b303600573970be3e5eb842e82e795 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 6 Dec 2021 09:53:13 +0100 Subject: [PATCH 237/255] Http: Add config value to turn it off, move all http settings into a category in the config --- include/Common.h | 3 +- src/Common.cpp | 1 + src/TConfig.cpp | 76 +++++++++++++++++++++++----------------------- src/TLuaEngine.cpp | 1 + src/main.cpp | 6 ++-- 5 files changed, 46 insertions(+), 41 deletions(-) diff --git a/include/Common.h b/include/Common.h index 7b0322b..00a3fca 100644 --- a/include/Common.h +++ b/include/Common.h @@ -42,6 +42,7 @@ public: std::string Key {}; std::string SSLKeyPath { "./.ssl/HttpServer/key.pem" }; std::string SSLCertPath { "./.ssl/HttpServer/cert.pem" }; + bool HTTPServerEnabled { true }; int MaxPlayers { 10 }; bool Private { true }; int MaxCars { 1 }; @@ -70,7 +71,7 @@ public: static std::string PPS() { return mPPS; } static void SetPPS(const std::string& NewPPS) { mPPS = NewPPS; } - static inline TSettings Settings {}; + static TSettings Settings; static std::string GetBackendUrlForAuth() { return "auth.beammp.com"; } static std::string GetBackendHostname() { return "backend.beammp.com"; } diff --git a/src/Common.cpp b/src/Common.cpp index b5db30d..31b8d6e 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -12,6 +12,7 @@ #include "CustomAssert.h" #include "Http.h" +Application::TSettings Application::Settings = {}; std::unique_ptr Application::mConsole = std::make_unique(); void Application::RegisterShutdownHandler(const TShutdownHandler& Handler) { diff --git a/src/TConfig.cpp b/src/TConfig.cpp index 276d993..fff6304 100644 --- a/src/TConfig.cpp +++ b/src/TConfig.cpp @@ -9,6 +9,7 @@ #include #include +// General static constexpr std::string_view StrDebug = "Debug"; static constexpr std::string_view StrPrivate = "Private"; static constexpr std::string_view StrPort = "Port"; @@ -21,19 +22,13 @@ static constexpr std::string_view StrResourceFolder = "ResourceFolder"; static constexpr std::string_view StrAuthKey = "AuthKey"; static constexpr std::string_view StrSendErrors = "SendErrors"; static constexpr std::string_view StrSendErrorsMessageEnabled = "SendErrorsShowMessage"; +static constexpr std::string_view StrHTTPServerEnabled = "HTTPServerEnabled"; + +// HTTP static constexpr std::string_view StrSSLKeyPath = "SSLKeyPath"; static constexpr std::string_view StrSSLCertPath = "SSLCertPath"; static constexpr std::string_view StrHTTPServerPort = "HTTPServerPort"; -void WriteSendErrors(const std::string& name) { - std::ofstream CfgFile { name, std::ios::out | std::ios::app }; - CfgFile << "# You can turn on/off the SendErrors message you get on startup here" << std::endl - << StrSendErrorsMessageEnabled << " = true" << std::endl - << "# If SendErrors is `true`, the server will send helpful info about crashes and other issues back to the BeamMP developers. This info may include your config, who is on your server at the time of the error, and similar general information. This kind of data is vital in helping us diagnose and fix issues faster. This has no impact on server performance. You can opt-out of this system by setting this to `false`." - << std::endl - << StrSendErrors << " = true" << std::endl; -} - TConfig::TConfig(const std::string& ConfigFileName) : mConfigFileName(ConfigFileName) { if (!fs::exists(mConfigFileName) || !fs::is_regular_file(mConfigFileName)) { @@ -57,9 +52,11 @@ TConfig::TConfig(const std::string& ConfigFileName) * whether it is in TConfig.cpp or the configuration file. */ void TConfig::FlushToFile() { - auto data = toml::parse(mConfigFileName); + auto data = toml::parse(mConfigFileName); data["General"] = toml::table(); + data["General"].comments().push_back(" General BeamMP Server settings"); data["General"][StrAuthKey.data()] = Application::Settings.Key; + data["General"][StrAuthKey.data()].comments().push_back(" AuthKey has to be filled out in order to run the server"); data["General"][StrDebug.data()] = Application::Settings.DebugModeEnabled; data["General"][StrPrivate.data()] = Application::Settings.Private; data["General"][StrPort.data()] = Application::Settings.Port; @@ -70,10 +67,14 @@ void TConfig::FlushToFile() { data["General"][StrDescription.data()] = Application::Settings.ServerDesc; data["General"][StrResourceFolder.data()] = Application::Settings.Resource; data["General"][StrSendErrors.data()] = Application::Settings.SendErrors; + data["General"][StrSendErrors.data()].comments().push_back(" You can turn on/off the SendErrors message you get on startup here"); data["General"][StrSendErrorsMessageEnabled.data()] = Application::Settings.SendErrorsMessageEnabled; - data["General"][StrSSLKeyPath.data()] = Application::Settings.SSLKeyPath; - data["General"][StrSSLCertPath.data()] = Application::Settings.SSLCertPath; - data["General"][StrHTTPServerPort.data()] = Application::Settings.HTTPServerPort; + data["General"][StrSendErrorsMessageEnabled.data()].comments().push_back(" If SendErrors is `true`, the server will send helpful info about crashes and other issues back to the BeamMP developers. This info may include your config, who is on your server at the time of the error, and similar general information. This kind of data is vital in helping us diagnose and fix issues faster. This has no impact on server performance. You can opt-out of this system by setting this to `false`"); + data["HTTP"][StrSSLKeyPath.data()] = Application::Settings.SSLKeyPath; + data["HTTP"][StrSSLCertPath.data()] = Application::Settings.SSLCertPath; + data["HTTP"][StrHTTPServerPort.data()] = Application::Settings.HTTPServerPort; + data["HTTP"][StrHTTPServerEnabled.data()] = Application::Settings.HTTPServerEnabled; + data["HTTP"][StrHTTPServerEnabled.data()].comments().push_back(" Enables the internal HTTP server"); std::ofstream Stream(mConfigFileName); Stream << data << std::flush; } @@ -94,35 +95,23 @@ void TConfig::CreateConfigFile(std::string_view name) { std::ofstream ofs(name.data()); } - auto data = toml::parse(name.data()); - //{ StrSendErrors, Application::Settings.SendErrors }, + FlushToFile(); - data["General"] = toml::table(); - data["General"][StrAuthKey.data()] = Application::Settings.Key; - data["General"][StrDebug.data()] = Application::Settings.DebugModeEnabled; - data["General"][StrPrivate.data()] = Application::Settings.Private; - data["General"][StrPort.data()] = Application::Settings.Port; - data["General"][StrName.data()] = Application::Settings.ServerName; - data["General"][StrMaxCars.data()] = Application::Settings.MaxCars; - data["General"][StrMaxPlayers.data()] = Application::Settings.MaxPlayers; - data["General"][StrMap.data()] = Application::Settings.MapName; - data["General"][StrDescription.data()] = Application::Settings.ServerDesc; - data["General"][StrResourceFolder.data()] = Application::Settings.Resource; - data["General"][StrSSLKeyPath.data()] = Application::Settings.SSLKeyPath; - data["General"][StrSSLCertPath.data()] = Application::Settings.SSLCertPath; - data["General"][StrHTTPServerPort.data()] = Application::Settings.HTTPServerPort; - - std::ofstream ofs { std::string(name) }; + size_t FileSize = fs::file_size(name); + std::fstream ofs { std::string(name), std::ios::in | std::ios::out }; if (ofs.good()) { + std::string Contents {}; + Contents.resize(FileSize); + ofs.readsome(Contents.data(), FileSize); + ofs.seekp(0); ofs << "# This is the BeamMP-Server config file.\n" "# Help & Documentation: `https://wiki.beammp.com/en/home/server-maintenance`\n" "# IMPORTANT: Fill in the AuthKey with the key you got from `https://beammp.com/k/dashboard` on the left under \"Keys\"\n" - << '\n'; - ofs << data << '\n'; + << '\n' + << Contents; beammp_error("There was no \"" + std::string(mConfigFileName) + "\" file (this is normal for the first time running the server), so one was generated for you. It was automatically filled with the settings from your Server.cfg, if you have one. Please open ServerConfig.toml and ensure your AuthKey and other settings are filled in and correct, then restart the server. The old Server.cfg file will no longer be used and causes a warning if it exists from now on."); mFailed = true; ofs.close(); - WriteSendErrors(std::string(name)); } else { beammp_error("Couldn't create " + std::string(name) + ". Check permissions, try again, and contact support if it continues not to work."); mFailed = true; @@ -130,6 +119,7 @@ void TConfig::CreateConfigFile(std::string_view name) { } void TConfig::ParseFromFile(std::string_view name) { + bool UpdateConfigFile = false; try { toml::value data = toml::parse(name.data()); Application::Settings.DebugModeEnabled = data["General"][StrDebug.data()].as_boolean(); @@ -142,12 +132,17 @@ void TConfig::ParseFromFile(std::string_view name) { Application::Settings.ServerDesc = data["General"][StrDescription.data()].as_string(); Application::Settings.Resource = data["General"][StrResourceFolder.data()].as_string(); Application::Settings.Key = data["General"][StrAuthKey.data()].as_string(); - Application::Settings.SSLKeyPath = data["General"][StrSSLKeyPath.data()].as_string(); - Application::Settings.SSLCertPath = data["General"][StrSSLCertPath.data()].as_string(); - Application::Settings.HTTPServerPort = data["General"][StrHTTPServerPort.data()].as_integer(); + if (!data["HTTP"][StrSSLKeyPath.data()].is_string()) { + UpdateConfigFile = true; + } else { + Application::Settings.SSLKeyPath = data["HTTP"][StrSSLKeyPath.data()].as_string(); + Application::Settings.SSLCertPath = data["HTTP"][StrSSLCertPath.data()].as_string(); + Application::Settings.HTTPServerPort = data["HTTP"][StrHTTPServerPort.data()].as_integer(); + Application::Settings.HTTPServerEnabled = data["HTTP"][StrHTTPServerEnabled.data()].as_boolean(); + } if (!data["General"][StrSendErrors.data()].is_boolean() || !data["General"][StrSendErrorsMessageEnabled.data()].is_boolean()) { - WriteSendErrors(std::string(name)); + UpdateConfigFile = true; } else { Application::Settings.SendErrors = data["General"][StrSendErrors.data()].as_boolean(); Application::Settings.SendErrorsMessageEnabled = data["General"][StrSendErrorsMessageEnabled.data()].as_boolean(); @@ -158,6 +153,10 @@ void TConfig::ParseFromFile(std::string_view name) { return; } PrintDebug(); + + if (UpdateConfigFile) { + FlushToFile(); + } // all good so far, let's check if there's a key if (Application::Settings.Key.empty()) { beammp_error("No AuthKey specified in the \"" + std::string(mConfigFileName) + "\" file. Please get an AuthKey, enter it into the config file, and restart this server."); @@ -177,6 +176,7 @@ void TConfig::PrintDebug() { beammp_debug(std::string(StrResourceFolder) + ": \"" + Application::Settings.Resource + "\""); beammp_debug(std::string(StrSSLKeyPath) + ": \"" + Application::Settings.SSLKeyPath + "\""); beammp_debug(std::string(StrSSLCertPath) + ": \"" + Application::Settings.SSLCertPath + "\""); + beammp_debug(std::string(StrHTTPServerPort) + ": \"" + std::to_string(Application::Settings.HTTPServerPort) + "\""); // special! beammp_debug("Key Length: " + std::to_string(Application::Settings.Key.length()) + ""); } diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index f473b21..97d2ed7 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -159,6 +159,7 @@ void TLuaEngine::WaitForAll(std::vector>& Results, c } if (Cancelled) { beammp_lua_warn("'" + Result->Function + "' in '" + Result->StateId + "' failed to execute in time and was not waited for. It may still finish executing at a later time."); + LuaAPI::MP::Engine->ReportErrors({ Result }); } else if (Result->Error) { if (Result->ErrorMessage != BeamMPFnNotFoundError) { beammp_lua_error(Result->Function + ": " + Result->ErrorMessage); diff --git a/src/main.cpp b/src/main.cpp index 5701ea4..8e92f9c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -155,8 +155,10 @@ int BeamMPServerMain(MainArguments Arguments) { Application::Console().InitializeLuaConsole(LuaEngine); Application::CheckForUpdates(); - Http::Server::SetupEnvironment(); - Http::Server::THttpServerInstance HttpServerInstance {}; + if (Application::Settings.HTTPServerEnabled) { + Http::Server::SetupEnvironment(); + Http::Server::THttpServerInstance HttpServerInstance {}; + } beammp_debug("cert.pem is " + std::to_string(fs::file_size("cert.pem")) + " bytes"); beammp_debug("key.pem is " + std::to_string(fs::file_size("key.pem")) + " bytes"); From 279c93179c2a70dbfa6380a3128c8fe8fa086a58 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 6 Dec 2021 10:22:52 +0100 Subject: [PATCH 238/255] Fix segfault in http --- include/Http.h | 3 ++- include/IThreaded.h | 8 ++++---- src/Http.cpp | 14 +++++++++----- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/include/Http.h b/include/Http.h index e5c1495..92d1279 100644 --- a/include/Http.h +++ b/include/Http.h @@ -26,7 +26,7 @@ const std::string ErrorString = "-1"; namespace Server { void SetupEnvironment(); // todo: Add non TLS Server Instance, this one is TLS only - class THttpServerInstance : IThreaded { + class THttpServerInstance { public: THttpServerInstance(); static fs::path KeyFilePath; @@ -42,6 +42,7 @@ namespace Server { * So we need to able to start the server (make it "listen()") in a single Thread. */ std::shared_ptr mHttpLibServerInstancePtr; + std::thread mThread; }; // todo: all of these functions are likely unsafe, // todo: replace with something that's managed by a domain specific crypto library diff --git a/include/IThreaded.h b/include/IThreaded.h index d08e428..2158b46 100644 --- a/include/IThreaded.h +++ b/include/IThreaded.h @@ -8,11 +8,11 @@ public: IThreaded() // invokes operator() on this object : mThread() { } - ~IThreaded() noexcept { - if (mThread.joinable()) { - mThread.join(); - } + ~IThreaded() noexcept { + if (mThread.joinable()) { + mThread.join(); } + } virtual void Start() final { mThread = std::thread([this] { (*this)(); }); diff --git a/src/Http.cpp b/src/Http.cpp index 598ae7b..b59a8b3 100644 --- a/src/Http.cpp +++ b/src/Http.cpp @@ -233,6 +233,7 @@ void Http::Server::Tx509KeypairGenerator::GenerateAndWriteToDisk(const fs::path& X509_free(x509); return; } + bool Http::Server::Tx509KeypairGenerator::EnsureTLSConfigExists() { if (fs::is_regular_file(Application::Settings.SSLKeyPath) && fs::is_regular_file(Application::Settings.SSLCertPath)) { @@ -263,17 +264,20 @@ void Http::Server::SetupEnvironment() { } Http::Server::THttpServerInstance::THttpServerInstance() { - Start(); + mThread = std::thread(&Http::Server::THttpServerInstance::operator(), this); + mThread.detach(); } + void Http::Server::THttpServerInstance::operator()() { + beammp_info("HTTPS Server started on port " + std::to_string(Application::Settings.HTTPServerPort)); // todo: make this IP agnostic so people can set their own IP - this->mHttpLibServerInstancePtr = std::make_shared(Application::Settings.SSLCertPath.c_str(), Application::Settings.SSLKeyPath.c_str()); - this->mHttpLibServerInstancePtr->Get("/", [](const httplib::Request&, httplib::Response& res) { + mHttpLibServerInstancePtr = std::make_shared(Application::Settings.SSLCertPath.c_str(), Application::Settings.SSLKeyPath.c_str()); + mHttpLibServerInstancePtr->Get("/", [](const httplib::Request&, httplib::Response& res) { res.set_content("

Hello World!

BeamMP Server can now serve HTTP requests!

", "text/html"); }); - this->mHttpLibServerInstancePtr->Get("/health", [](const httplib::Request& req, httplib::Response& res) { + mHttpLibServerInstancePtr->Get("/health", [](const httplib::Request&, httplib::Response& res) { res.set_content("0", "text/plain"); res.status = 200; }); - this->mHttpLibServerInstancePtr->listen("0.0.0.0", Application::Settings.HTTPServerPort); + mHttpLibServerInstancePtr->listen("0.0.0.0", Application::Settings.HTTPServerPort); } From 0f74eca2ee709065b89dd0a6f4eb8af6a1d90a6b Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 6 Dec 2021 12:28:52 +0100 Subject: [PATCH 239/255] Fix various issues and crashes --- include/Common.h | 25 +++++++++++- include/Cryptography.h | 4 +- include/Http.h | 12 +++--- include/TConsole.h | 6 +-- src/Common.cpp | 1 - src/Http.cpp | 8 ++-- src/TConfig.cpp | 1 + src/TConsole.cpp | 90 ++++++++++++++++++++++-------------------- src/main.cpp | 15 ++++--- 9 files changed, 96 insertions(+), 66 deletions(-) diff --git a/include/Common.h b/include/Common.h index 00a3fca..ed34b7f 100644 --- a/include/Common.h +++ b/include/Common.h @@ -82,9 +82,32 @@ public: static std::array VersionStrToInts(const std::string& str); static bool IsOutdated(const Version& Current, const Version& Newest); + static void InitializeConsole() { + if (!mConsole) { + mConsole = std::make_unique(); + } + } + + enum class Status { + Starting, + Good, + Bad, + }; + + using SystemStatusMap = std::unordered_map; + + static const SystemStatusMap& GetSubsystemStatuses() { + return mSystemStatusMap; + } + + static void SetSubsystemStatus(const std::string& Subsystem, Status status) { + mSystemStatusMap[Subsystem] = status; + } + private: + static inline SystemStatusMap mSystemStatusMap {}; static inline std::string mPPS; - static std::unique_ptr mConsole; + static inline std::unique_ptr mConsole; static inline std::mutex mShutdownHandlersMutex {}; static inline std::deque mShutdownHandlers {}; diff --git a/include/Cryptography.h b/include/Cryptography.h index 5d710a0..bef2e58 100644 --- a/include/Cryptography.h +++ b/include/Cryptography.h @@ -91,14 +91,14 @@ static auto w_printf_s = [](const char* fmt, ...) { va_end(args); }; -static auto w_sprintf_s = [](char* buf, size_t buf_size, const char* fmt, ...) { +static auto w_sprintf_s = [](char* buf, size_t, const char* fmt, ...) { va_list args; va_start(args, fmt); vsprintf(buf, fmt, args); va_end(args); }; -static auto w_sprintf_s_ret = [](char* buf, size_t buf_size, const char* fmt, ...) { +static auto w_sprintf_s_ret = [](char* buf, size_t, const char* fmt, ...) { int ret; va_list args; va_start(args, fmt); diff --git a/include/Http.h b/include/Http.h index 92d1279..3673edc 100644 --- a/include/Http.h +++ b/include/Http.h @@ -3,12 +3,16 @@ #include #include #include -#include #include #include #include #include +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +#include +#pragma GCC diagnostic pop + namespace fs = std::filesystem; namespace Crypto { @@ -36,12 +40,6 @@ namespace Server { void operator()(); private: - /** - * the shared pointer is necessary because httplib is a blocking library and due lacking thread-safety - * will "forget" about its environment, when configured across multiple threads. - * So we need to able to start the server (make it "listen()") in a single Thread. - */ - std::shared_ptr mHttpLibServerInstancePtr; std::thread mThread; }; // todo: all of these functions are likely unsafe, diff --git a/include/TConsole.h b/include/TConsole.h index 618c586..c393842 100644 --- a/include/TConsole.h +++ b/include/TConsole.h @@ -16,19 +16,19 @@ public: void InitializeLuaConsole(TLuaEngine& Engine); void BackupOldLog(); Commandline& Internal() { return mCommandline; } - + private: void RunAsCommand(const std::string& cmd, bool IgnoreNotACommand = false); void ChangeToLuaConsole(const std::string& LuaStateId); void ChangeToRegularConsole(); - + void Command_Lua(const std::string& cmd); void Command_Help(const std::string& cmd); void Command_Kick(const std::string& cmd); void Command_Say(const std::string& cmd); void Command_List(const std::string& cmd); void Command_Status(const std::string& cmd); - + Commandline mCommandline; std::vector mCachedLuaHistory; std::vector mCachedRegularHistory; diff --git a/src/Common.cpp b/src/Common.cpp index 31b8d6e..26f7619 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -13,7 +13,6 @@ #include "Http.h" Application::TSettings Application::Settings = {}; -std::unique_ptr Application::mConsole = std::make_unique(); void Application::RegisterShutdownHandler(const TShutdownHandler& Handler) { std::unique_lock Lock(mShutdownHandlersMutex); diff --git a/src/Http.cpp b/src/Http.cpp index b59a8b3..813a26d 100644 --- a/src/Http.cpp +++ b/src/Http.cpp @@ -270,14 +270,14 @@ Http::Server::THttpServerInstance::THttpServerInstance() { void Http::Server::THttpServerInstance::operator()() { beammp_info("HTTPS Server started on port " + std::to_string(Application::Settings.HTTPServerPort)); + httplib::SSLServer HttpLibServerInstance { Application::Settings.SSLCertPath.c_str(), Application::Settings.SSLKeyPath.c_str() }; // todo: make this IP agnostic so people can set their own IP - mHttpLibServerInstancePtr = std::make_shared(Application::Settings.SSLCertPath.c_str(), Application::Settings.SSLKeyPath.c_str()); - mHttpLibServerInstancePtr->Get("/", [](const httplib::Request&, httplib::Response& res) { + HttpLibServerInstance.Get("/", [](const httplib::Request&, httplib::Response& res) { res.set_content("

Hello World!

BeamMP Server can now serve HTTP requests!

", "text/html"); }); - mHttpLibServerInstancePtr->Get("/health", [](const httplib::Request&, httplib::Response& res) { + HttpLibServerInstance.Get("/health", [](const httplib::Request&, httplib::Response& res) { res.set_content("0", "text/plain"); res.status = 200; }); - mHttpLibServerInstancePtr->listen("0.0.0.0", Application::Settings.HTTPServerPort); + HttpLibServerInstance.listen("0.0.0.0", Application::Settings.HTTPServerPort); } diff --git a/src/TConfig.cpp b/src/TConfig.cpp index fff6304..9817fc6 100644 --- a/src/TConfig.cpp +++ b/src/TConfig.cpp @@ -42,6 +42,7 @@ TConfig::TConfig(const std::string& ConfigFileName) ParseFromFile(mConfigFileName); } } + /** * @brief Writes out the loaded application state into ServerConfig.toml * diff --git a/src/TConsole.cpp b/src/TConsole.cpp index f0293bd..9acf574 100644 --- a/src/TConsole.cpp +++ b/src/TConsole.cpp @@ -38,7 +38,7 @@ std::string GetDate() { auto fraction = now - seconds; size_t ms = std::chrono::duration_cast(fraction).count(); char fracstr[5]; - std::sprintf(fracstr, "%0.3lu", ms); + std::sprintf(fracstr, "%03lu", ms); date += fracstr; date += "] "; } else { @@ -99,6 +99,11 @@ void TConsole::BackupOldLog() { void TConsole::ChangeToLuaConsole(const std::string& LuaStateId) { if (!mIsLuaConsole) { + if (!mLuaEngine) { + beammp_error("Lua engine not initialized yet, please wait and try again"); + return; + } + mLuaEngine->EnsureStateExists(mDefaultStateId, "Console"); mStateId = LuaStateId; mIsLuaConsole = true; if (mStateId != mDefaultStateId) { @@ -106,8 +111,8 @@ void TConsole::ChangeToLuaConsole(const std::string& LuaStateId) { } else { Application::Console().WriteRaw("Entered Lua console. To exit, type `exit()`"); } - //mCachedRegularHistory = mCommandline.history(); - //mCommandline.set_history(mCachedLuaHistory); + // mCachedRegularHistory = mCommandline.history(); + // mCommandline.set_history(mCachedLuaHistory); mCommandline.set_prompt("lua> "); } } @@ -120,8 +125,8 @@ void TConsole::ChangeToRegularConsole() { } else { Application::Console().WriteRaw("Left Lua console."); } - //mCachedLuaHistory = mCommandline.history(); - //mCommandline.set_history(mCachedRegularHistory); + // mCachedLuaHistory = mCommandline.history(); + // mCommandline.set_history(mCachedRegularHistory); mCommandline.set_prompt("> "); mStateId = mDefaultStateId; } @@ -322,45 +327,45 @@ TConsole::TConsole() { auto cmd = c.get_command(); cmd = TrimString(cmd); mCommandline.write(mCommandline.prompt() + cmd); - if (!mLuaEngine) { - beammp_info("Lua not started yet, please try again in a second"); - } else { - if (mIsLuaConsole) { - if (cmd == "exit()") { - ChangeToRegularConsole(); - } else { - auto Future = mLuaEngine->EnqueueScript(mStateId, { std::make_shared(cmd), "", "" }); - while (!Future->Ready) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); // TODO: Add a timeout - } - if (Future->Error) { - beammp_lua_error(Future->ErrorMessage); - } - } + if (mIsLuaConsole) { + if (!mLuaEngine) { + beammp_info("Lua not started yet, please try again in a second"); + } else if (cmd == "exit()") { + ChangeToRegularConsole(); } else { - if (cmd == "exit") { - beammp_info("gracefully shutting down"); - Application::GracefullyShutdown(); - } else if (StringStartsWith(cmd, "lua")) { - Command_Lua(cmd); - } else if (StringStartsWith(cmd, "help")) { - RunAsCommand(cmd, true); - Command_Help(cmd); - } else if (StringStartsWith(cmd, "kick")) { - RunAsCommand(cmd, true); - Command_Kick(cmd); - } else if (StringStartsWith(cmd, "say")) { - RunAsCommand(cmd, true); - Command_Say(cmd); - } else if (StringStartsWith(cmd, "list")) { - RunAsCommand(cmd, true); - Command_List(cmd); - } else if (StringStartsWith(cmd, "status")) { - RunAsCommand(cmd, true); - Command_Status(cmd); - } else if (!cmd.empty()) { - RunAsCommand(cmd); + auto Future = mLuaEngine->EnqueueScript(mStateId, { std::make_shared(cmd), "", "" }); + while (!Future->Ready) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // TODO: Add a timeout } + if (Future->Error) { + beammp_lua_error(Future->ErrorMessage); + } + } + } else { + if (!mLuaEngine) { + beammp_error("Attempted to run a command before Lua engine started. Please wait and try again."); + } else if (cmd == "exit") { + beammp_info("gracefully shutting down"); + Application::GracefullyShutdown(); + } else if (StringStartsWith(cmd, "lua")) { + Command_Lua(cmd); + } else if (StringStartsWith(cmd, "help")) { + RunAsCommand(cmd, true); + Command_Help(cmd); + } else if (StringStartsWith(cmd, "kick")) { + RunAsCommand(cmd, true); + Command_Kick(cmd); + } else if (StringStartsWith(cmd, "say")) { + RunAsCommand(cmd, true); + Command_Say(cmd); + } else if (StringStartsWith(cmd, "list")) { + RunAsCommand(cmd, true); + Command_List(cmd); + } else if (StringStartsWith(cmd, "status")) { + RunAsCommand(cmd, true); + Command_Status(cmd); + } else if (!cmd.empty()) { + RunAsCommand(cmd); } } } catch (const std::exception& e) { @@ -380,5 +385,4 @@ void TConsole::WriteRaw(const std::string& str) { void TConsole::InitializeLuaConsole(TLuaEngine& Engine) { mLuaEngine = &Engine; - Engine.EnsureStateExists(mDefaultStateId, "Console"); } diff --git a/src/main.cpp b/src/main.cpp index 8e92f9c..ca29d12 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -77,6 +77,7 @@ int main(int argc, char** argv) { int BeamMPServerMain(MainArguments Arguments) { setlocale(LC_ALL, "C"); + Application::InitializeConsole(); SetupSignalHandlers(); @@ -131,6 +132,7 @@ int BeamMPServerMain(MainArguments Arguments) { TConfig Config(ConfigPath); TLuaEngine LuaEngine; LuaEngine.SetServer(&Server); + Application::Console().InitializeLuaConsole(LuaEngine); if (Config.Failed()) { beammp_info("Closing in 10 seconds"); @@ -146,13 +148,12 @@ int BeamMPServerMain(MainArguments Arguments) { beammp_trace("Running in debug mode on a debug build"); Sentry.SetupUser(); Sentry.PrintWelcome(); - TResourceManager ResourceManager; + TResourceManager ResourceManager; TPPSMonitor PPSMonitor(Server); THeartbeatThread Heartbeat(ResourceManager, Server); TNetwork Network(Server, PPSMonitor, ResourceManager); LuaEngine.SetNetwork(&Network); PPSMonitor.SetNetwork(Network); - Application::Console().InitializeLuaConsole(LuaEngine); Application::CheckForUpdates(); if (Application::Settings.HTTPServerEnabled) { @@ -160,11 +161,15 @@ int BeamMPServerMain(MainArguments Arguments) { Http::Server::THttpServerInstance HttpServerInstance {}; } - beammp_debug("cert.pem is " + std::to_string(fs::file_size("cert.pem")) + " bytes"); - beammp_debug("key.pem is " + std::to_string(fs::file_size("key.pem")) + " bytes"); - RegisterThread("Main(Waiting)"); + auto Statuses = Application::GetSubsystemStatuses(); + for (const auto& NameStatusPair : Statuses) { + if (NameStatusPair.second != Application::Status::Good) { + beammp_info("not good: " + NameStatusPair.first); + } + } + while (!Shutdown) { std::this_thread::sleep_for(std::chrono::milliseconds(50)); } From a1335e8c7d74090696160aeacfd78de6fdcda6e0 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 6 Dec 2021 13:17:54 +0100 Subject: [PATCH 240/255] Add statuses, status messages --- include/Common.h | 8 ++++---- src/Common.cpp | 19 +++++++++++++++++++ src/Http.cpp | 2 ++ src/TConfig.cpp | 9 +++++++++ src/TConsole.cpp | 33 +++++++++++++++++++++++++++++++++ src/THeartbeatThread.cpp | 15 +++++++++++---- src/TLuaEngine.cpp | 2 ++ src/TNetwork.cpp | 11 +++++++---- src/TPPSMonitor.cpp | 2 ++ src/TResourceManager.cpp | 9 ++++++--- src/TSentry.cpp | 1 + src/TServer.cpp | 2 ++ src/main.cpp | 37 ++++++++++++++++++++++++++++--------- 13 files changed, 126 insertions(+), 24 deletions(-) diff --git a/include/Common.h b/include/Common.h index ed34b7f..373f0a2 100644 --- a/include/Common.h +++ b/include/Common.h @@ -97,15 +97,15 @@ public: using SystemStatusMap = std::unordered_map; static const SystemStatusMap& GetSubsystemStatuses() { + std::unique_lock Lock(mSystemStatusMapMutex); return mSystemStatusMap; } - - static void SetSubsystemStatus(const std::string& Subsystem, Status status) { - mSystemStatusMap[Subsystem] = status; - } + + static void SetSubsystemStatus(const std::string& Subsystem, Status status); private: static inline SystemStatusMap mSystemStatusMap {}; + static inline std::mutex mSystemStatusMapMutex {}; static inline std::string mPPS; static inline std::unique_ptr mConsole; static inline std::mutex mShutdownHandlersMutex {}; diff --git a/src/Common.cpp b/src/Common.cpp index 26f7619..620c609 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -73,7 +73,24 @@ bool Application::IsOutdated(const Version& Current, const Version& Newest) { } } +void Application::SetSubsystemStatus(const std::string& Subsystem, Status status) { + switch (status) { + case Status::Good: + beammp_trace("Subsystem '" + Subsystem + "': Good"); + break; + case Status::Bad: + beammp_trace("Subsystem '" + Subsystem + "': Bad"); + break; + case Status::Starting: + beammp_trace("Subsystem '" + Subsystem + "': Starting"); + break; + } + std::unique_lock Lock(mSystemStatusMapMutex); + mSystemStatusMap[Subsystem] = status; +} + void Application::CheckForUpdates() { + Application::SetSubsystemStatus("UpdateCheck", Application::Status::Starting); // checks current version against latest version std::regex VersionRegex { R"(\d+\.\d+\.\d+\n*)" }; auto Response = Http::GET(GetBackendHostname(), 443, "/v/s"); @@ -87,12 +104,14 @@ void Application::CheckForUpdates() { } else { beammp_info("Server up-to-date!"); } + Application::SetSubsystemStatus("UpdateCheck", Application::Status::Good); } else { beammp_warn("Unable to fetch version from backend."); beammp_trace("got " + Response); auto Lock = Sentry.CreateExclusiveContext(); Sentry.SetContext("get-response", { { "response", Response } }); Sentry.LogError("failed to get server version", _file_basename, _line); + Application::SetSubsystemStatus("UpdateCheck", Application::Status::Bad); } } diff --git a/src/Http.cpp b/src/Http.cpp index 813a26d..3f53517 100644 --- a/src/Http.cpp +++ b/src/Http.cpp @@ -264,6 +264,7 @@ void Http::Server::SetupEnvironment() { } Http::Server::THttpServerInstance::THttpServerInstance() { + Application::SetSubsystemStatus("HTTPServer", Application::Status::Starting); mThread = std::thread(&Http::Server::THttpServerInstance::operator(), this); mThread.detach(); } @@ -279,5 +280,6 @@ void Http::Server::THttpServerInstance::operator()() { res.set_content("0", "text/plain"); res.status = 200; }); + Application::SetSubsystemStatus("HTTPServer", Application::Status::Good); HttpLibServerInstance.listen("0.0.0.0", Application::Settings.HTTPServerPort); } diff --git a/src/TConfig.cpp b/src/TConfig.cpp index 9817fc6..db46739 100644 --- a/src/TConfig.cpp +++ b/src/TConfig.cpp @@ -31,6 +31,7 @@ static constexpr std::string_view StrHTTPServerPort = "HTTPServerPort"; TConfig::TConfig(const std::string& ConfigFileName) : mConfigFileName(ConfigFileName) { + Application::SetSubsystemStatus("Config", Application::Status::Starting); if (!fs::exists(mConfigFileName) || !fs::is_regular_file(mConfigFileName)) { beammp_info("No config file found! Generating one..."); CreateConfigFile(mConfigFileName); @@ -115,6 +116,7 @@ void TConfig::CreateConfigFile(std::string_view name) { ofs.close(); } else { beammp_error("Couldn't create " + std::string(name) + ". Check permissions, try again, and contact support if it continues not to work."); + Application::SetSubsystemStatus("Config", Application::Status::Bad); mFailed = true; } } @@ -151,6 +153,7 @@ void TConfig::ParseFromFile(std::string_view name) { } catch (const std::exception& err) { beammp_error("Error parsing config file value: " + std::string(err.what())); mFailed = true; + Application::SetSubsystemStatus("Config", Application::Status::Bad); return; } PrintDebug(); @@ -161,7 +164,13 @@ void TConfig::ParseFromFile(std::string_view name) { // all good so far, let's check if there's a key if (Application::Settings.Key.empty()) { beammp_error("No AuthKey specified in the \"" + std::string(mConfigFileName) + "\" file. Please get an AuthKey, enter it into the config file, and restart this server."); + Application::SetSubsystemStatus("Config", Application::Status::Bad); mFailed = true; + return; + } + Application::SetSubsystemStatus("Config", Application::Status::Good); + if (Application::Settings.Key.size() != 36) { + beammp_warn("AuthKey specified is the wrong length and likely isn't valid."); } } diff --git a/src/TConsole.cpp b/src/TConsole.cpp index 9acf574..e947d65 100644 --- a/src/TConsole.cpp +++ b/src/TConsole.cpp @@ -247,6 +247,34 @@ void TConsole::Command_Status(const std::string&) { return true; }); + size_t SystemsStarting = 0; + size_t SystemsGood = 0; + size_t SystemsBad = 0; + std::string SystemsBadList {}; + std::string SystemsGoodList {}; + std::string SystemsStartingList {}; + auto Statuses = Application::GetSubsystemStatuses(); + for (const auto& NameStatusPair : Statuses) { + switch (NameStatusPair.second) { + case Application::Status::Good: + SystemsGood++; + SystemsGoodList += NameStatusPair.first + ", "; + break; + case Application::Status::Bad: + SystemsBad++; + SystemsBadList += NameStatusPair.first + ", "; + break; + case Application::Status::Starting: + SystemsStarting++; + SystemsStartingList += NameStatusPair.first + ", "; + break; + } + } + // remove ", " at the end + SystemsBadList = SystemsBadList.substr(0, SystemsBadList.size() - 2); + SystemsGoodList = SystemsGoodList.substr(0, SystemsGoodList.size() - 2); + SystemsStartingList = SystemsStartingList.substr(0, SystemsStartingList.size() - 2); + auto ElapsedTime = mLuaEngine->Server().UptimeTimer.GetElapsedTime(); Status << "BeamMP-Server Status:\n" @@ -262,6 +290,11 @@ void TConsole::Command_Status(const std::string&) { << "\t\tStates: " << mLuaEngine->GetLuaStateCount() << "\n" << "\t\tEvent timers: " << mLuaEngine->GetTimedEventsCount() << "\n" << "\t\tEvent handlers: " << mLuaEngine->GetRegisteredEventHandlerCount() << "\n" + << "\tSubsystems:\n" + << "\t\tGood/Starting/Bad: " << SystemsGood << "/" << SystemsStarting << "/" << SystemsBad << "\n" + << "\t\tGood: [ " << SystemsGoodList << " ]\n" + << "\t\tStarting: [ " << SystemsStartingList << " ]\n" + << "\t\tBad: [ " << SystemsBadList << " ]\n" << ""; Application::Console().WriteRaw(Status.str()); diff --git a/src/THeartbeatThread.cpp b/src/THeartbeatThread.cpp index ac7a293..4f7ef55 100644 --- a/src/THeartbeatThread.cpp +++ b/src/THeartbeatThread.cpp @@ -6,7 +6,6 @@ #include void THeartbeatThread::operator()() { - return;/* RegisterThread("Heartbeat"); std::string Body; std::string T; @@ -55,20 +54,28 @@ void THeartbeatThread::operator()() { if ((T.substr(0, 2) != "20" && ResponseCode != 200) || ResponseCode != 200) { beammp_trace("got " + T + " from backend"); + Application::SetSubsystemStatus("Heartbeat", Application::Status::Bad); SentryReportError(Application::GetBackendHostname() + Target, ResponseCode); std::this_thread::sleep_for(std::chrono::milliseconds(500)); T = Http::POST(Application::GetBackup1Hostname(), 443, Target, Body, "application/x-www-form-urlencoded", &ResponseCode); if ((T.substr(0, 2) != "20" && ResponseCode != 200) || ResponseCode != 200) { SentryReportError(Application::GetBackup1Hostname() + Target, ResponseCode); + Application::SetSubsystemStatus("Heartbeat", Application::Status::Bad); std::this_thread::sleep_for(std::chrono::milliseconds(500)); T = Http::POST(Application::GetBackup2Hostname(), 443, Target, Body, "application/x-www-form-urlencoded", &ResponseCode); if ((T.substr(0, 2) != "20" && ResponseCode != 200) || ResponseCode != 200) { beammp_warn("Backend system refused server! Server will not show in the public server list."); - + Application::SetSubsystemStatus("Heartbeat", Application::Status::Bad); isAuth = false; SentryReportError(Application::GetBackup2Hostname() + Target, ResponseCode); + } else { + Application::SetSubsystemStatus("Heartbeat", Application::Status::Good); } + } else { + Application::SetSubsystemStatus("Heartbeat", Application::Status::Good); } + } else { + Application::SetSubsystemStatus("Heartbeat", Application::Status::Good); } if (!isAuth) { @@ -81,9 +88,8 @@ void THeartbeatThread::operator()() { } } - //SocketIO::Get().SetAuthenticated(isAuth); + // SocketIO::Get().SetAuthenticated(isAuth); } - */ } std::string THeartbeatThread::GenerateCall() { @@ -108,6 +114,7 @@ std::string THeartbeatThread::GenerateCall() { THeartbeatThread::THeartbeatThread(TResourceManager& ResourceManager, TServer& Server) : mResourceManager(ResourceManager) , mServer(Server) { + Application::SetSubsystemStatus("Heartbeat", Application::Status::Starting); Application::RegisterShutdownHandler([&] { if (mThread.joinable()) { mShutdown = true; diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 97d2ed7..4deafc6 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -16,6 +16,7 @@ TLuaEngine* LuaAPI::MP::Engine; TLuaEngine::TLuaEngine() : mPluginMonitor(fs::path(Application::Settings.Resource) / "Server", *this, mShutdown) { + Application::SetSubsystemStatus("LuaEngine", Application::Status::Starting); LuaAPI::MP::Engine = this; if (!fs::exists(Application::Settings.Resource)) { fs::create_directory(Application::Settings.Resource); @@ -36,6 +37,7 @@ TLuaEngine::TLuaEngine() void TLuaEngine::operator()() { RegisterThread("LuaEngine"); + Application::SetSubsystemStatus("LuaEngine", Application::Status::Good); // lua engine main thread CollectAndInitPlugins(); // now call all onInit's diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index 914bf85..2534052 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -11,6 +11,8 @@ TNetwork::TNetwork(TServer& Server, TPPSMonitor& PPSMonitor, TResourceManager& R : mServer(Server) , mPPSMonitor(PPSMonitor) , mResourceManager(ResourceManager) { + Application::SetSubsystemStatus("TCPNetwork", Application::Status::Starting); + Application::SetSubsystemStatus("UDPNetwork", Application::Status::Starting); Application::RegisterShutdownHandler([&] { beammp_debug("Kicking all players due to shutdown"); Server.ForEachClient([&](std::weak_ptr client) -> bool { @@ -56,10 +58,10 @@ void TNetwork::UDPServerMain() { if (bind(mUDPSock, (sockaddr*)&serverAddr, sizeof(serverAddr)) != 0) { beammp_error("bind() failed: " + GetPlatformAgnosticErrorString()); std::this_thread::sleep_for(std::chrono::seconds(5)); - exit(-1); + exit(-1); // TODO: Wtf. // return; } - + Application::SetSubsystemStatus("UDPNetwork", Application::Status::Good); beammp_info(("Vehicle data network online on port ") + std::to_string(Application::Settings.Port) + (" with a Max of ") + std::to_string(Application::Settings.MaxPlayers) + (" Clients")); while (!mShutdown) { @@ -123,7 +125,7 @@ void TNetwork::TCPServerMain() { if (bind(Listener, (sockaddr*)&addr, sizeof(addr)) != 0) { beammp_error("bind() failed: " + GetPlatformAgnosticErrorString()); std::this_thread::sleep_for(std::chrono::seconds(5)); - exit(-1); + exit(-1); // TODO: Wtf. } if (Listener == -1) { beammp_error("Invalid listening socket"); @@ -134,6 +136,7 @@ void TNetwork::TCPServerMain() { // FIXME leak Listener return; } + Application::SetSubsystemStatus("TCPNetwork", Application::Status::Good); beammp_info(("Vehicle event network online")); do { try { @@ -211,7 +214,7 @@ void TNetwork::Authentication(const TConnection& ClientConnection) { beammp_trace("This thread is ip " + std::string(str)); Client->SetIdentifier("ip", str); - std::string Rc; //TODO: figure out why this is not default constructed + std::string Rc; // TODO: figure out why this is not default constructed beammp_info("Identifying new ClientConnection..."); Rc = TCPRcv(*Client); diff --git a/src/TPPSMonitor.cpp b/src/TPPSMonitor.cpp index 9ea80dc..5d28187 100644 --- a/src/TPPSMonitor.cpp +++ b/src/TPPSMonitor.cpp @@ -4,6 +4,7 @@ TPPSMonitor::TPPSMonitor(TServer& Server) : mServer(Server) { + Application::SetSubsystemStatus("PPSMonitor", Application::Status::Starting); Application::SetPPS("-"); Application::RegisterShutdownHandler([&] { if (mThread.joinable()) { @@ -22,6 +23,7 @@ void TPPSMonitor::operator()() { std::this_thread::sleep_for(std::chrono::milliseconds(1)); } beammp_debug("PPSMonitor starting"); + Application::SetSubsystemStatus("PPSMonitor", Application::Status::Good); std::vector> TimedOutClients; while (!mShutdown) { std::this_thread::sleep_for(std::chrono::seconds(1)); diff --git a/src/TResourceManager.cpp b/src/TResourceManager.cpp index 96bc42a..afb0e6b 100644 --- a/src/TResourceManager.cpp +++ b/src/TResourceManager.cpp @@ -6,6 +6,7 @@ namespace fs = std::filesystem; TResourceManager::TResourceManager() { + Application::SetSubsystemStatus("ResourceManager", Application::Status::Starting); std::string Path = Application::Settings.Resource + "/Client"; if (!fs::exists(Path)) fs::create_directories(Path); @@ -13,11 +14,11 @@ TResourceManager::TResourceManager() { std::string File(entry.path().string()); if (auto pos = File.find(".zip"); pos != std::string::npos) { if (File.length() - pos == 4) { - std::replace(File.begin(), File.end(),'\\','/'); + std::replace(File.begin(), File.end(), '\\', '/'); mFileList += File + ';'; - if(auto i = File.find_last_of('/'); i != std::string::npos){ + if (auto i = File.find_last_of('/'); i != std::string::npos) { ++i; - File = File.substr(i,pos-i); + File = File.substr(i, pos - i); } mTrimmedList += "/" + fs::path(File).filename().string() + ';'; mFileSizes += std::to_string(size_t(fs::file_size(entry.path()))) + ';'; @@ -29,4 +30,6 @@ TResourceManager::TResourceManager() { if (mModsLoaded) beammp_info("Loaded " + std::to_string(mModsLoaded) + " Mods"); + + Application::SetSubsystemStatus("ResourceManager", Application::Status::Good); } diff --git a/src/TSentry.cpp b/src/TSentry.cpp index 447392f..da05c10 100644 --- a/src/TSentry.cpp +++ b/src/TSentry.cpp @@ -55,6 +55,7 @@ void TSentry::SetupUser() { if (!mValid) { return; } + Application::SetSubsystemStatus("Sentry", Application::Status::Good); sentry_value_t user = sentry_value_new_object(); if (Application::Settings.Key.size() == 36) { sentry_value_set_by_key(user, "id", sentry_value_new_string(Application::Settings.Key.c_str())); diff --git a/src/TServer.cpp b/src/TServer.cpp index 69d6bb9..0f1ad32 100644 --- a/src/TServer.cpp +++ b/src/TServer.cpp @@ -17,6 +17,7 @@ namespace json = rapidjson; TServer::TServer(const std::vector& Arguments) { beammp_info("BeamMP Server v" + Application::ServerVersionString()); + Application::SetSubsystemStatus("Server", Application::Status::Starting); if (Arguments.size() > 1) { Application::Settings.CustomIP = Arguments[0]; size_t n = std::count(Application::Settings.CustomIP.begin(), Application::Settings.CustomIP.end(), '.'); @@ -28,6 +29,7 @@ TServer::TServer(const std::vector& Arguments) { beammp_info("server started with custom IP"); } } + Application::SetSubsystemStatus("Server", Application::Status::Good); } void TServer::RemoveClient(const std::weak_ptr& WeakClientPtr) { diff --git a/src/main.cpp b/src/main.cpp index ca29d12..0d3ae5b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -78,6 +78,7 @@ int main(int argc, char** argv) { int BeamMPServerMain(MainArguments Arguments) { setlocale(LC_ALL, "C"); Application::InitializeConsole(); + Application::SetSubsystemStatus("Main", Application::Status::Starting); SetupSignalHandlers(); @@ -148,7 +149,7 @@ int BeamMPServerMain(MainArguments Arguments) { beammp_trace("Running in debug mode on a debug build"); Sentry.SetupUser(); Sentry.PrintWelcome(); - TResourceManager ResourceManager; + TResourceManager ResourceManager; TPPSMonitor PPSMonitor(Server); THeartbeatThread Heartbeat(ResourceManager, Server); TNetwork Network(Server, PPSMonitor, ResourceManager); @@ -161,17 +162,35 @@ int BeamMPServerMain(MainArguments Arguments) { Http::Server::THttpServerInstance HttpServerInstance {}; } + Application::SetSubsystemStatus("Main", Application::Status::Good); RegisterThread("Main(Waiting)"); - auto Statuses = Application::GetSubsystemStatuses(); - for (const auto& NameStatusPair : Statuses) { - if (NameStatusPair.second != Application::Status::Good) { - beammp_info("not good: " + NameStatusPair.first); - } - } - + bool FullyStarted = false; while (!Shutdown) { - std::this_thread::sleep_for(std::chrono::milliseconds(50)); + if (!FullyStarted) { + FullyStarted = true; + bool WithErrors = false; + std::string SystemsBadList {}; + auto Statuses = Application::GetSubsystemStatuses(); + for (const auto& NameStatusPair : Statuses) { + if (NameStatusPair.second == Application::Status::Starting) { + FullyStarted = false; + } else if (NameStatusPair.second == Application::Status::Bad) { + SystemsBadList += NameStatusPair.first + ", "; + WithErrors = true; + } + } + // remove ", " + SystemsBadList = SystemsBadList.substr(0, SystemsBadList.size() - 2); + if (FullyStarted) { + if (!WithErrors) { + beammp_info("ALL SYSTEMS STARTED SUCCESSFULLY, EVERYTHING IS OKAY"); + } else { + beammp_error("STARTUP NOT SUCCESSFUL, SYSTEMS " + SystemsBadList + " HAD ERRORS. THIS MAY OR MAY NOT CAUSE ISSUES."); + } + } + } + std::this_thread::sleep_for(std::chrono::milliseconds(100)); } beammp_info("Shutdown."); return 0; From 3cce875fbb5a0345b01d1f932da14a6581179632 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 6 Dec 2021 13:47:07 +0100 Subject: [PATCH 241/255] Add UseSSL option to server config --- include/Common.h | 1 + include/TConfig.h | 7 +++- src/Http.cpp | 15 +++++--- src/TConfig.cpp | 89 +++++++++++++++++++++++++++-------------------- 4 files changed, 69 insertions(+), 43 deletions(-) diff --git a/include/Common.h b/include/Common.h index 373f0a2..299e5a3 100644 --- a/include/Common.h +++ b/include/Common.h @@ -52,6 +52,7 @@ public: bool SendErrors { true }; bool SendErrorsMessageEnabled { true }; int HTTPServerPort { 8080 }; + bool HTTPServerUseSSL { true }; [[nodiscard]] bool HasCustomIP() const { return !CustomIP.empty(); } }; diff --git a/include/TConfig.h b/include/TConfig.h index bd8f46d..3fcc597 100644 --- a/include/TConfig.h +++ b/include/TConfig.h @@ -4,6 +4,9 @@ #include +#define TOML11_PRESERVE_COMMENTS_BY_DEFAULT +#include // header-only version of TOML++ + namespace fs = std::filesystem; class TConfig { @@ -18,10 +21,12 @@ private: void CreateConfigFile(std::string_view name); void ParseFromFile(std::string_view name); void PrintDebug(); + void TryReadValue(toml::value& Table, const std::string& Category, const std::string_view& Key, std::string& OutValue); + void TryReadValue(toml::value& Table, const std::string& Category, const std::string_view& Key, bool& OutValue); + void TryReadValue(toml::value& Table, const std::string& Category, const std::string_view& Key, int& OutValue); void ParseOldFormat(); bool IsDefault(); bool mFailed { false }; std::string mConfigFileName; }; - diff --git a/src/Http.cpp b/src/Http.cpp index 3f53517..0aff8da 100644 --- a/src/Http.cpp +++ b/src/Http.cpp @@ -270,16 +270,21 @@ Http::Server::THttpServerInstance::THttpServerInstance() { } void Http::Server::THttpServerInstance::operator()() { - beammp_info("HTTPS Server started on port " + std::to_string(Application::Settings.HTTPServerPort)); - httplib::SSLServer HttpLibServerInstance { Application::Settings.SSLCertPath.c_str(), Application::Settings.SSLKeyPath.c_str() }; + beammp_info("HTTP(S) Server started on port " + std::to_string(Application::Settings.HTTPServerPort)); + std::unique_ptr HttpLibServerInstance; + if (Application::Settings.HTTPServerUseSSL) { + HttpLibServerInstance = std::make_unique(Application::Settings.SSLCertPath.c_str(), Application::Settings.SSLKeyPath.c_str()); + } else { + HttpLibServerInstance = std::make_unique(); + } // todo: make this IP agnostic so people can set their own IP - HttpLibServerInstance.Get("/", [](const httplib::Request&, httplib::Response& res) { + HttpLibServerInstance->Get("/", [](const httplib::Request&, httplib::Response& res) { res.set_content("

Hello World!

BeamMP Server can now serve HTTP requests!

", "text/html"); }); - HttpLibServerInstance.Get("/health", [](const httplib::Request&, httplib::Response& res) { + HttpLibServerInstance->Get("/health", [](const httplib::Request&, httplib::Response& res) { res.set_content("0", "text/plain"); res.status = 200; }); Application::SetSubsystemStatus("HTTPServer", Application::Status::Good); - HttpLibServerInstance.listen("0.0.0.0", Application::Settings.HTTPServerPort); + HttpLibServerInstance->listen("0.0.0.0", Application::Settings.HTTPServerPort); } diff --git a/src/TConfig.cpp b/src/TConfig.cpp index db46739..f1c3126 100644 --- a/src/TConfig.cpp +++ b/src/TConfig.cpp @@ -1,7 +1,4 @@ #include "Common.h" -#define TOML11_PRESERVE_COMMENTS_BY_DEFAULT - -#include // header-only version of TOML++ #include "TConfig.h" #include @@ -23,6 +20,7 @@ static constexpr std::string_view StrAuthKey = "AuthKey"; static constexpr std::string_view StrSendErrors = "SendErrors"; static constexpr std::string_view StrSendErrorsMessageEnabled = "SendErrorsShowMessage"; static constexpr std::string_view StrHTTPServerEnabled = "HTTPServerEnabled"; +static constexpr std::string_view StrHTTPServerUseSSL = "UseSSL"; // HTTP static constexpr std::string_view StrSSLKeyPath = "SSLKeyPath"; @@ -44,6 +42,12 @@ TConfig::TConfig(const std::string& ConfigFileName) } } +template +void SetComment(CommentsT& Comments, const std::string& Comment) { + Comments.clear(); + Comments.push_back(Comment); +} + /** * @brief Writes out the loaded application state into ServerConfig.toml * @@ -56,9 +60,8 @@ TConfig::TConfig(const std::string& ConfigFileName) void TConfig::FlushToFile() { auto data = toml::parse(mConfigFileName); data["General"] = toml::table(); - data["General"].comments().push_back(" General BeamMP Server settings"); data["General"][StrAuthKey.data()] = Application::Settings.Key; - data["General"][StrAuthKey.data()].comments().push_back(" AuthKey has to be filled out in order to run the server"); + SetComment(data["General"][StrAuthKey.data()].comments(), " AuthKey has to be filled out in order to run the server"); data["General"][StrDebug.data()] = Application::Settings.DebugModeEnabled; data["General"][StrPrivate.data()] = Application::Settings.Private; data["General"][StrPort.data()] = Application::Settings.Port; @@ -69,14 +72,16 @@ void TConfig::FlushToFile() { data["General"][StrDescription.data()] = Application::Settings.ServerDesc; data["General"][StrResourceFolder.data()] = Application::Settings.Resource; data["General"][StrSendErrors.data()] = Application::Settings.SendErrors; - data["General"][StrSendErrors.data()].comments().push_back(" You can turn on/off the SendErrors message you get on startup here"); + SetComment(data["General"][StrSendErrors.data()].comments(), " You can turn on/off the SendErrors message you get on startup here"); data["General"][StrSendErrorsMessageEnabled.data()] = Application::Settings.SendErrorsMessageEnabled; - data["General"][StrSendErrorsMessageEnabled.data()].comments().push_back(" If SendErrors is `true`, the server will send helpful info about crashes and other issues back to the BeamMP developers. This info may include your config, who is on your server at the time of the error, and similar general information. This kind of data is vital in helping us diagnose and fix issues faster. This has no impact on server performance. You can opt-out of this system by setting this to `false`"); + SetComment(data["General"][StrSendErrorsMessageEnabled.data()].comments(), " If SendErrors is `true`, the server will send helpful info about crashes and other issues back to the BeamMP developers. This info may include your config, who is on your server at the time of the error, and similar general information. This kind of data is vital in helping us diagnose and fix issues faster. This has no impact on server performance. You can opt-out of this system by setting this to `false`"); data["HTTP"][StrSSLKeyPath.data()] = Application::Settings.SSLKeyPath; data["HTTP"][StrSSLCertPath.data()] = Application::Settings.SSLCertPath; data["HTTP"][StrHTTPServerPort.data()] = Application::Settings.HTTPServerPort; + data["HTTP"][StrHTTPServerUseSSL.data()] = Application::Settings.HTTPServerUseSSL; + SetComment(data["HTTP"][StrHTTPServerUseSSL.data()].comments(), " Recommended to keep enabled. With SSL the server will serve https and requires valid key and cert files"); data["HTTP"][StrHTTPServerEnabled.data()] = Application::Settings.HTTPServerEnabled; - data["HTTP"][StrHTTPServerEnabled.data()].comments().push_back(" Enables the internal HTTP server"); + SetComment(data["HTTP"][StrHTTPServerEnabled.data()].comments(), " Enables the internal HTTP server"); std::ofstream Stream(mConfigFileName); Stream << data << std::flush; } @@ -121,35 +126,46 @@ void TConfig::CreateConfigFile(std::string_view name) { } } +void TConfig::TryReadValue(toml::value& Table, const std::string& Category, const std::string_view& Key, std::string& OutValue) { + if (Table[Category.c_str()][Key.data()].is_string()) { + OutValue = Table[Category.c_str()][Key.data()].as_string(); + } +} + +void TConfig::TryReadValue(toml::value& Table, const std::string& Category, const std::string_view& Key, bool& OutValue) { + if (Table[Category.c_str()][Key.data()].is_boolean()) { + OutValue = Table[Category.c_str()][Key.data()].as_boolean(); + } +} + +void TConfig::TryReadValue(toml::value& Table, const std::string& Category, const std::string_view& Key, int& OutValue) { + if (Table[Category.c_str()][Key.data()].is_integer()) { + OutValue = Table[Category.c_str()][Key.data()].as_integer(); + } +} + void TConfig::ParseFromFile(std::string_view name) { - bool UpdateConfigFile = false; try { toml::value data = toml::parse(name.data()); - Application::Settings.DebugModeEnabled = data["General"][StrDebug.data()].as_boolean(); - Application::Settings.Private = data["General"][StrPrivate.data()].as_boolean(); - Application::Settings.Port = data["General"][StrPort.data()].as_integer(); - Application::Settings.MaxCars = data["General"][StrMaxCars.data()].as_integer(); - Application::Settings.MaxPlayers = data["General"][StrMaxPlayers.data()].as_integer(); - Application::Settings.MapName = data["General"][StrMap.data()].as_string(); - Application::Settings.ServerName = data["General"][StrName.data()].as_string(); - Application::Settings.ServerDesc = data["General"][StrDescription.data()].as_string(); - Application::Settings.Resource = data["General"][StrResourceFolder.data()].as_string(); - Application::Settings.Key = data["General"][StrAuthKey.data()].as_string(); - if (!data["HTTP"][StrSSLKeyPath.data()].is_string()) { - UpdateConfigFile = true; - } else { - Application::Settings.SSLKeyPath = data["HTTP"][StrSSLKeyPath.data()].as_string(); - Application::Settings.SSLCertPath = data["HTTP"][StrSSLCertPath.data()].as_string(); - Application::Settings.HTTPServerPort = data["HTTP"][StrHTTPServerPort.data()].as_integer(); - Application::Settings.HTTPServerEnabled = data["HTTP"][StrHTTPServerEnabled.data()].as_boolean(); - } - if (!data["General"][StrSendErrors.data()].is_boolean() - || !data["General"][StrSendErrorsMessageEnabled.data()].is_boolean()) { - UpdateConfigFile = true; - } else { - Application::Settings.SendErrors = data["General"][StrSendErrors.data()].as_boolean(); - Application::Settings.SendErrorsMessageEnabled = data["General"][StrSendErrorsMessageEnabled.data()].as_boolean(); - } + // GENERAL + TryReadValue(data, "General", StrDebug, Application::Settings.DebugModeEnabled); + TryReadValue(data, "General", StrPrivate, Application::Settings.Private); + TryReadValue(data, "General", StrPort, Application::Settings.Port); + TryReadValue(data, "General", StrMaxCars, Application::Settings.MaxCars); + TryReadValue(data, "General", StrMaxPlayers, Application::Settings.MaxPlayers); + TryReadValue(data, "General", StrMap, Application::Settings.MapName); + TryReadValue(data, "General", StrName, Application::Settings.ServerName); + TryReadValue(data, "General", StrDescription, Application::Settings.ServerDesc); + TryReadValue(data, "General", StrResourceFolder, Application::Settings.Resource); + TryReadValue(data, "General", StrAuthKey, Application::Settings.Key); + TryReadValue(data, "General", StrSendErrors, Application::Settings.SendErrors); + TryReadValue(data, "General", StrSendErrorsMessageEnabled, Application::Settings.SendErrorsMessageEnabled); + // HTTP + TryReadValue(data, "HTTP", StrSSLKeyPath, Application::Settings.SSLKeyPath); + TryReadValue(data, "HTTP", StrSSLCertPath, Application::Settings.SSLCertPath); + TryReadValue(data, "HTTP", StrHTTPServerPort, Application::Settings.HTTPServerPort); + TryReadValue(data, "HTTP", StrHTTPServerEnabled, Application::Settings.HTTPServerEnabled); + TryReadValue(data, "HTTP", StrHTTPServerUseSSL, Application::Settings.HTTPServerUseSSL); } catch (const std::exception& err) { beammp_error("Error parsing config file value: " + std::string(err.what())); mFailed = true; @@ -158,9 +174,8 @@ void TConfig::ParseFromFile(std::string_view name) { } PrintDebug(); - if (UpdateConfigFile) { - FlushToFile(); - } + // Update in any case + FlushToFile(); // all good so far, let's check if there's a key if (Application::Settings.Key.empty()) { beammp_error("No AuthKey specified in the \"" + std::string(mConfigFileName) + "\" file. Please get an AuthKey, enter it into the config file, and restart this server."); From 817a146699ff4d43f9508fb1f3e99b348a43bbbc Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 6 Dec 2021 13:57:40 +0100 Subject: [PATCH 242/255] Add state id to lua prompt --- src/TConsole.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/TConsole.cpp b/src/TConsole.cpp index e947d65..7ef2f04 100644 --- a/src/TConsole.cpp +++ b/src/TConsole.cpp @@ -108,12 +108,13 @@ void TConsole::ChangeToLuaConsole(const std::string& LuaStateId) { mIsLuaConsole = true; if (mStateId != mDefaultStateId) { Application::Console().WriteRaw("Entered Lua console for state '" + mStateId + "'. To exit, type `exit()`"); + mCommandline.set_prompt("lua @" + LuaStateId + "> "); } else { Application::Console().WriteRaw("Entered Lua console. To exit, type `exit()`"); + mCommandline.set_prompt("lua> "); } // mCachedRegularHistory = mCommandline.history(); // mCommandline.set_history(mCachedLuaHistory); - mCommandline.set_prompt("lua> "); } } From 816d3d5df8faaab2175537ca163e0cc78835b548 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 6 Dec 2021 14:12:54 +0100 Subject: [PATCH 243/255] Re-add split history (?) --- src/TConsole.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/TConsole.cpp b/src/TConsole.cpp index 7ef2f04..74d257c 100644 --- a/src/TConsole.cpp +++ b/src/TConsole.cpp @@ -113,8 +113,8 @@ void TConsole::ChangeToLuaConsole(const std::string& LuaStateId) { Application::Console().WriteRaw("Entered Lua console. To exit, type `exit()`"); mCommandline.set_prompt("lua> "); } - // mCachedRegularHistory = mCommandline.history(); - // mCommandline.set_history(mCachedLuaHistory); + mCachedRegularHistory = mCommandline.history(); + mCommandline.set_history(mCachedLuaHistory); } } @@ -126,8 +126,8 @@ void TConsole::ChangeToRegularConsole() { } else { Application::Console().WriteRaw("Left Lua console."); } - // mCachedLuaHistory = mCommandline.history(); - // mCommandline.set_history(mCachedRegularHistory); + mCachedLuaHistory = mCommandline.history(); + mCommandline.set_history(mCachedRegularHistory); mCommandline.set_prompt("> "); mStateId = mDefaultStateId; } From 92d985790279d3f7fdfc1f86d3f7aabab68d1215 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 6 Dec 2021 14:16:40 +0100 Subject: [PATCH 244/255] Re-add commandline Bruh @jimkoen --- .gitmodules | 6 +++--- deps/commandline | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) create mode 160000 deps/commandline diff --git a/.gitmodules b/.gitmodules index d81806c..8199b24 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,6 @@ [submodule "deps/https:/github.com/chriskohlhoff/asio"] path = deps/https:/github.com/chriskohlhoff/asio url = https://github.com/lionkor/commandline -[submodule "deps/commandline"] - path = deps/commandline - url = https://github.com/lionkor/commandline [submodule "deps/asio"] path = deps/asio url = https://github.com/chriskohlhoff/asio @@ -25,3 +22,6 @@ [submodule "deps/cpp-httplib"] path = deps/cpp-httplib url = https://github.com/yhirose/cpp-httplib +[submodule "deps/commandline"] + path = deps/commandline + url = git@github.com:/lionkor/commandline diff --git a/deps/commandline b/deps/commandline new file mode 160000 index 0000000..3d11606 --- /dev/null +++ b/deps/commandline @@ -0,0 +1 @@ +Subproject commit 3d11606d02b449b8afd40a7132160d2392043eb3 From 1172420b77a8f4f86bbeb0eb814691f104643f38 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 6 Dec 2021 14:21:25 +0100 Subject: [PATCH 245/255] Add https to changelog --- Changelog.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Changelog.md b/Changelog.md index 0066bc6..7166f09 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,10 +2,11 @@ - CHANGED entire plugin Lua implementation (rewrite) - CHANGED moved *almost all* functions into MP.\* -- CHANGED console to use a custom language (type `help`!) +- CHANGED console to use a custom language (type `help`, `list`, or `status`!) - CHANGED all files of a Lua plugin to share a Lua state (no more state-per-file) - ADDED many new Lua API functions, which can be found at - ADDED Commandline options. Run with `--help` to see all options. +- ADDED HTTP(S) Server (OpenAPI spec coming soon!) - ADDED plugin directories to `package.path` and `package.cpath` before `onInit` - ADDED ability to add `PluginConfig.toml` to your plugin folder to change some settings - ADDED ability to share a lua state with other plugins via `StateId` setting in `PluginConfig.toml` From 2c115a2b2cf6da19c35be09f9c91ea530bbe43fa Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 6 Dec 2021 15:04:28 +0100 Subject: [PATCH 246/255] Fix GCC pragma to not appear on windows --- include/Http.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/Http.h b/include/Http.h index 3673edc..62ded67 100644 --- a/include/Http.h +++ b/include/Http.h @@ -8,10 +8,14 @@ #include #include +#if defined(BEAMMP_LINUX) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +#endif #include +#if defined(BEAMMP_LINUX) #pragma GCC diagnostic pop +#endif namespace fs = std::filesystem; From fe652cbf42e426027c649b7c16d52a4ef308a0e2 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 6 Dec 2021 15:08:01 +0100 Subject: [PATCH 247/255] Fix server paths --- src/Http.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Http.cpp b/src/Http.cpp index 0aff8da..136facb 100644 --- a/src/Http.cpp +++ b/src/Http.cpp @@ -273,7 +273,7 @@ void Http::Server::THttpServerInstance::operator()() { beammp_info("HTTP(S) Server started on port " + std::to_string(Application::Settings.HTTPServerPort)); std::unique_ptr HttpLibServerInstance; if (Application::Settings.HTTPServerUseSSL) { - HttpLibServerInstance = std::make_unique(Application::Settings.SSLCertPath.c_str(), Application::Settings.SSLKeyPath.c_str()); + HttpLibServerInstance = std::make_unique(Http::Server::THttpServerInstance::CertFilePath.c_str(), Http::Server::THttpServerInstance::KeyFilePath.c_str()); } else { HttpLibServerInstance = std::make_unique(); } From 3ee83904a12de84e71d2ed79da1b081cf8843f00 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 6 Dec 2021 15:13:55 +0100 Subject: [PATCH 248/255] Windows rewrite when jfc since when is `c_str()` not convertible to `const char*`? --- src/Http.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Http.cpp b/src/Http.cpp index 136facb..8f16cf4 100644 --- a/src/Http.cpp +++ b/src/Http.cpp @@ -199,7 +199,7 @@ X509* Http::Server::Tx509KeypairGenerator::GenerateCertificate(EVP_PKEY& PKey) { void Http::Server::Tx509KeypairGenerator::GenerateAndWriteToDisk(const fs::path& KeyFilePath, const fs::path& CertFilePath) { // todo: generate directories for ssl keys - FILE* KeyFile = std::fopen(KeyFilePath.c_str(), "wb"); + FILE* KeyFile = std::fopen(reinterpret_cast(KeyFilePath.c_str()), "wb"); if (!KeyFile) { beammp_error("Could not create file 'key.pem', check your permissions"); throw std::runtime_error("Could not create file 'key.pem'"); @@ -215,7 +215,7 @@ void Http::Server::Tx509KeypairGenerator::GenerateAndWriteToDisk(const fs::path& throw std::runtime_error("Could not write to file 'key.pem'"); } - FILE* CertFile = std::fopen(CertFilePath.c_str(), "wb"); // x509 file + FILE* CertFile = std::fopen(reinterpret_cast(CertFilePath.c_str()), "wb"); // x509 file if (!CertFile) { beammp_error("Could not create file 'cert.pem', check your permissions"); throw std::runtime_error("Could not create file 'cert.pem'"); From cd19ae0836ba3097da5ed04bd42353e55226b0ef Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Tue, 7 Dec 2021 14:25:04 +0100 Subject: [PATCH 249/255] Add shutting down / shutdown states to state keeper --- include/Common.h | 2 ++ src/Common.cpp | 6 ++++++ src/Http.cpp | 14 ++++++++++++++ src/TConsole.cpp | 17 +++++++++++++++++ src/THeartbeatThread.cpp | 2 ++ src/TLuaEngine.cpp | 2 ++ src/TNetwork.cpp | 4 ++++ src/TPPSMonitor.cpp | 2 ++ src/main.cpp | 6 +++++- 9 files changed, 54 insertions(+), 1 deletion(-) diff --git a/include/Common.h b/include/Common.h index 299e5a3..5772317 100644 --- a/include/Common.h +++ b/include/Common.h @@ -93,6 +93,8 @@ public: Starting, Good, Bad, + ShuttingDown, + Shutdown, }; using SystemStatusMap = std::unordered_map; diff --git a/src/Common.cpp b/src/Common.cpp index 620c609..4ed5814 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -84,6 +84,12 @@ void Application::SetSubsystemStatus(const std::string& Subsystem, Status status case Status::Starting: beammp_trace("Subsystem '" + Subsystem + "': Starting"); break; + case Status::ShuttingDown: + beammp_trace("Subsystem '" + Subsystem + "': Shutting down"); + break; + case Status::Shutdown: + beammp_trace("Subsystem '" + Subsystem + "': Shutdown"); + break; } std::unique_lock Lock(mSystemStatusMapMutex); mSystemStatusMap[Subsystem] = status; diff --git a/src/Http.cpp b/src/Http.cpp index 8f16cf4..f321bf5 100644 --- a/src/Http.cpp +++ b/src/Http.cpp @@ -117,6 +117,15 @@ static std::map Map = { { 530, "(CDN) 1XXX Internal Error" }, }; +static const char Magic[] = { + 0x20, 0x2f, 0x5c, 0x5f, + 0x2f, 0x5c, 0x0a, 0x28, + 0x20, 0x6f, 0x2e, 0x6f, + 0x20, 0x29, 0x0a, 0x20, + 0x3e, 0x20, 0x5e, 0x20, + 0x3c, 0x0a, 0x00 +}; + std::string Http::Status::ToString(int Code) { if (Map.find(Code) != Map.end()) { return Map.at(Code); @@ -285,6 +294,11 @@ void Http::Server::THttpServerInstance::operator()() { res.set_content("0", "text/plain"); res.status = 200; }); + + // magic endpoint + HttpLibServerInstance->Get({ 0x2f, 0x6b, 0x69, 0x74, 0x74, 0x79 }, [](const httplib::Request&, httplib::Response& res) { + res.set_content(std::string(Magic), "text/plain"); + }); Application::SetSubsystemStatus("HTTPServer", Application::Status::Good); HttpLibServerInstance->listen("0.0.0.0", Application::Settings.HTTPServerPort); } diff --git a/src/TConsole.cpp b/src/TConsole.cpp index 74d257c..79df8d2 100644 --- a/src/TConsole.cpp +++ b/src/TConsole.cpp @@ -251,9 +251,13 @@ void TConsole::Command_Status(const std::string&) { size_t SystemsStarting = 0; size_t SystemsGood = 0; size_t SystemsBad = 0; + size_t SystemsShuttingDown = 0; + size_t SystemsShutdown = 0; std::string SystemsBadList {}; std::string SystemsGoodList {}; std::string SystemsStartingList {}; + std::string SystemsShuttingDownList {}; + std::string SystemsShutdownList {}; auto Statuses = Application::GetSubsystemStatuses(); for (const auto& NameStatusPair : Statuses) { switch (NameStatusPair.second) { @@ -269,12 +273,22 @@ void TConsole::Command_Status(const std::string&) { SystemsStarting++; SystemsStartingList += NameStatusPair.first + ", "; break; + case Application::Status::ShuttingDown: + SystemsShuttingDown++; + SystemsShuttingDownList += NameStatusPair.first + ", "; + break; + case Application::Status::Shutdown: + SystemsShutdown++; + SystemsShutdownList += NameStatusPair.first + ", "; + break; } } // remove ", " at the end SystemsBadList = SystemsBadList.substr(0, SystemsBadList.size() - 2); SystemsGoodList = SystemsGoodList.substr(0, SystemsGoodList.size() - 2); SystemsStartingList = SystemsStartingList.substr(0, SystemsStartingList.size() - 2); + SystemsShuttingDownList = SystemsShuttingDownList.substr(0, SystemsShuttingDownList.size() - 2); + SystemsShutdownList = SystemsShutdownList.substr(0, SystemsShutdownList.size() - 2); auto ElapsedTime = mLuaEngine->Server().UptimeTimer.GetElapsedTime(); @@ -293,9 +307,12 @@ void TConsole::Command_Status(const std::string&) { << "\t\tEvent handlers: " << mLuaEngine->GetRegisteredEventHandlerCount() << "\n" << "\tSubsystems:\n" << "\t\tGood/Starting/Bad: " << SystemsGood << "/" << SystemsStarting << "/" << SystemsBad << "\n" + << "\t\tShutting down/Shutdown: " << SystemsShuttingDown << "/" << SystemsShutdown << "\n" << "\t\tGood: [ " << SystemsGoodList << " ]\n" << "\t\tStarting: [ " << SystemsStartingList << " ]\n" << "\t\tBad: [ " << SystemsBadList << " ]\n" + << "\t\tShutting down: [ " << SystemsShuttingDownList << " ]\n" + << "\t\tShutdown: [ " << SystemsShutdownList << " ]\n" << ""; Application::Console().WriteRaw(Status.str()); diff --git a/src/THeartbeatThread.cpp b/src/THeartbeatThread.cpp index 4f7ef55..6588d75 100644 --- a/src/THeartbeatThread.cpp +++ b/src/THeartbeatThread.cpp @@ -116,10 +116,12 @@ THeartbeatThread::THeartbeatThread(TResourceManager& ResourceManager, TServer& S , mServer(Server) { Application::SetSubsystemStatus("Heartbeat", Application::Status::Starting); Application::RegisterShutdownHandler([&] { + Application::SetSubsystemStatus("Heartbeat", Application::Status::ShuttingDown); if (mThread.joinable()) { mShutdown = true; mThread.join(); } + Application::SetSubsystemStatus("Heartbeat", Application::Status::Shutdown); }); Start(); } diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 4deafc6..89742e2 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -27,10 +27,12 @@ TLuaEngine::TLuaEngine() } mResourceServerPath = Path; Application::RegisterShutdownHandler([&] { + Application::SetSubsystemStatus("LuaEngine", Application::Status::ShuttingDown); mShutdown = true; if (mThread.joinable()) { mThread.join(); } + Application::SetSubsystemStatus("LuaEngine", Application::Status::Shutdown); }); Start(); } diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index 2534052..13b089d 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -23,16 +23,20 @@ TNetwork::TNetwork(TServer& Server, TPPSMonitor& PPSMonitor, TResourceManager& R }); }); Application::RegisterShutdownHandler([&] { + Application::SetSubsystemStatus("UDPNetwork", Application::Status::ShuttingDown); if (mUDPThread.joinable()) { mShutdown = true; mUDPThread.detach(); } + Application::SetSubsystemStatus("UDPNetwork", Application::Status::Shutdown); }); Application::RegisterShutdownHandler([&] { + Application::SetSubsystemStatus("TCPNetwork", Application::Status::ShuttingDown); if (mTCPThread.joinable()) { mShutdown = true; mTCPThread.detach(); } + Application::SetSubsystemStatus("TCPNetwork", Application::Status::Shutdown); }); mTCPThread = std::thread(&TNetwork::TCPServerMain, this); mUDPThread = std::thread(&TNetwork::UDPServerMain, this); diff --git a/src/TPPSMonitor.cpp b/src/TPPSMonitor.cpp index 5d28187..8d58d84 100644 --- a/src/TPPSMonitor.cpp +++ b/src/TPPSMonitor.cpp @@ -7,12 +7,14 @@ TPPSMonitor::TPPSMonitor(TServer& Server) Application::SetSubsystemStatus("PPSMonitor", Application::Status::Starting); Application::SetPPS("-"); Application::RegisterShutdownHandler([&] { + Application::SetSubsystemStatus("PPSMonitor", Application::Status::ShuttingDown); if (mThread.joinable()) { beammp_debug("shutting down PPSMonitor"); mShutdown = true; mThread.join(); beammp_debug("shut down PPSMonitor"); } + Application::SetSubsystemStatus("PPSMonitor", Application::Status::Shutdown); }); Start(); } diff --git a/src/main.cpp b/src/main.cpp index 0d3ae5b..59764f2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -123,7 +123,10 @@ int BeamMPServerMain(MainArguments Arguments) { } bool Shutdown = false; - Application::RegisterShutdownHandler([&Shutdown] { Shutdown = true; }); + Application::RegisterShutdownHandler([&Shutdown] { + Application::SetSubsystemStatus("Main", Application::Status::ShuttingDown); + Shutdown = true; + }); Application::RegisterShutdownHandler([] { auto Futures = LuaAPI::MP::Engine->TriggerEvent("onShutdown", ""); TLuaEngine::WaitForAll(Futures); @@ -192,6 +195,7 @@ int BeamMPServerMain(MainArguments Arguments) { } std::this_thread::sleep_for(std::chrono::milliseconds(100)); } + Application::SetSubsystemStatus("Main", Application::Status::Shutdown); beammp_info("Shutdown."); return 0; } From a19943c96d46a261c05be8226d50afc3f24ddace Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Tue, 7 Dec 2021 15:34:01 +0100 Subject: [PATCH 250/255] Example impl for /status --- src/Http.cpp | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/src/Http.cpp b/src/Http.cpp index f321bf5..31d929f 100644 --- a/src/Http.cpp +++ b/src/Http.cpp @@ -1,15 +1,23 @@ #include "Http.h" +#include "Client.h" #include "Common.h" #include "CustomAssert.h" +#include "LuaAPI.h" #include #include +#include +#include +#include +#include #include fs::path Http::Server::THttpServerInstance::KeyFilePath; fs::path Http::Server::THttpServerInstance::CertFilePath; // TODO: Add sentry error handling back +namespace json = rapidjson; + std::string Http::GET(const std::string& host, int port, const std::string& target, unsigned int* status) { httplib::SSLClient client(host, port); client.enable_server_certificate_verification(false); @@ -291,10 +299,62 @@ void Http::Server::THttpServerInstance::operator()() { res.set_content("

Hello World!

BeamMP Server can now serve HTTP requests!

", "text/html"); }); HttpLibServerInstance->Get("/health", [](const httplib::Request&, httplib::Response& res) { - res.set_content("0", "text/plain"); + size_t SystemsGood = 0; + size_t SystemsBad = 0; + auto Statuses = Application::GetSubsystemStatuses(); + for (const auto& NameStatusPair : Statuses) { + switch (NameStatusPair.second) { + case Application::Status::Starting: + case Application::Status::ShuttingDown: + case Application::Status::Shutdown: + case Application::Status::Good: + SystemsGood++; + break; + case Application::Status::Bad: + SystemsBad++; + break; + } + } + res.set_content(SystemsBad == 0 ? "0" : "1", "text/plain"); res.status = 200; }); + HttpLibServerInstance->Get("/status", [](const httplib::Request&, httplib::Response& res) { + try { + json::Document response; + response.SetObject(); + rapidjson::Document::AllocatorType& Allocator = response.GetAllocator(); + // add to response + auto& Server = LuaAPI::MP::Engine->Server(); + size_t CarCount = 0; + size_t GuestCount = 0; + json::Value Array(rapidjson::kArrayType); + LuaAPI::MP::Engine->Server().ForEachClient([&](std::weak_ptr Client) -> bool { + if (!Client.expired()) { + auto Locked = Client.lock(); + CarCount += Locked->GetCarCount(); + GuestCount += Locked->IsGuest() ? 1 : 0; + json::Value Player(json::kObjectType); + Player.AddMember("name", json::StringRef(Locked->GetName().c_str()), Allocator); + Player.AddMember("id", Locked->GetID(), Allocator); + Array.PushBack(Player, Allocator); + } + return true; + }); + response.AddMember("players", Array, Allocator); + response.AddMember("player_count", Server.ClientCount(), Allocator); + response.AddMember("guest_count", GuestCount, Allocator); + response.AddMember("car_count", CarCount, Allocator); + // compile & send response + json::StringBuffer sb; + json::Writer writer(sb); + response.Accept(writer); + res.set_content(sb.GetString(), "application/json"); + } catch (const std::exception& e) { + beammp_error("Exception in /status endpoint: " + std::string(e.what())); + res.status = 500; + } + }); // magic endpoint HttpLibServerInstance->Get({ 0x2f, 0x6b, 0x69, 0x74, 0x74, 0x79 }, [](const httplib::Request&, httplib::Response& res) { res.set_content(std::string(Magic), "text/plain"); From bbe92dfa0fcc09418f1af37c632308c705ef2b1b Mon Sep 17 00:00:00 2001 From: Rouven Himmelstein Date: Wed, 8 Dec 2021 07:57:37 +0100 Subject: [PATCH 251/255] fix: broken .gitmodules file --- .gitmodules | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/.gitmodules b/.gitmodules index 8199b24..178fa5a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,5 +1,5 @@ -[submodule "deps/https:/github.com/chriskohlhoff/asio"] - path = deps/https:/github.com/chriskohlhoff/asio +[submodule "deps/commandline"] + path = deps/commandline url = https://github.com/lionkor/commandline [submodule "deps/asio"] path = deps/asio @@ -21,7 +21,4 @@ url = https://github.com/nih-at/libzip [submodule "deps/cpp-httplib"] path = deps/cpp-httplib - url = https://github.com/yhirose/cpp-httplib -[submodule "deps/commandline"] - path = deps/commandline - url = git@github.com:/lionkor/commandline + url = https://github.com/yhirose/cpp-httplib \ No newline at end of file From 924e18c163a923415dd88d73dde4e9f00727728e Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Wed, 8 Dec 2021 17:37:06 +0100 Subject: [PATCH 252/255] Remove /status placeholder --- src/Http.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Http.cpp b/src/Http.cpp index 31d929f..c31dae5 100644 --- a/src/Http.cpp +++ b/src/Http.cpp @@ -318,6 +318,7 @@ void Http::Server::THttpServerInstance::operator()() { res.set_content(SystemsBad == 0 ? "0" : "1", "text/plain"); res.status = 200; }); + /* HttpLibServerInstance->Get("/status", [](const httplib::Request&, httplib::Response& res) { try { json::Document response; @@ -355,6 +356,7 @@ void Http::Server::THttpServerInstance::operator()() { res.status = 500; } }); + */ // magic endpoint HttpLibServerInstance->Get({ 0x2f, 0x6b, 0x69, 0x74, 0x74, 0x79 }, [](const httplib::Request&, httplib::Response& res) { res.set_content(std::string(Magic), "text/plain"); From ca5b3956a1ba5f7166cd5eb267f50c141757556c Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Wed, 8 Dec 2021 17:38:36 +0100 Subject: [PATCH 253/255] Http: Dont generate ssl key/cert with ssl off, reinterpret_cast for windows --- src/Http.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Http.cpp b/src/Http.cpp index c31dae5..11bea18 100644 --- a/src/Http.cpp +++ b/src/Http.cpp @@ -261,6 +261,9 @@ bool Http::Server::Tx509KeypairGenerator::EnsureTLSConfigExists() { } void Http::Server::SetupEnvironment() { + if (!Application::Settings.HTTPServerUseSSL) { + return; + } auto parent = fs::path(Application::Settings.SSLKeyPath).parent_path(); if (!fs::exists(parent)) fs::create_directories(parent); @@ -290,7 +293,9 @@ void Http::Server::THttpServerInstance::operator()() { beammp_info("HTTP(S) Server started on port " + std::to_string(Application::Settings.HTTPServerPort)); std::unique_ptr HttpLibServerInstance; if (Application::Settings.HTTPServerUseSSL) { - HttpLibServerInstance = std::make_unique(Http::Server::THttpServerInstance::CertFilePath.c_str(), Http::Server::THttpServerInstance::KeyFilePath.c_str()); + HttpLibServerInstance = std::make_unique( + reinterpret_cast(Http::Server::THttpServerInstance::CertFilePath.c_str()), + reinterpret_cast(Http::Server::THttpServerInstance::KeyFilePath.c_str())); } else { HttpLibServerInstance = std::make_unique(); } From a5c23f8dde0c36043c8a8ef8008a837b99e61cb7 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 9 Dec 2021 12:08:24 +0100 Subject: [PATCH 254/255] Add ping packet support --- src/TNetwork.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index 13b089d..79ddc15 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -186,6 +186,10 @@ void TNetwork::Identify(const TConnection& client) { Authentication(client); } else if (Code == 'D') { HandleDownload(client.Socket); + } else if (Code == 'P') { + send(client.Socket, "P", 1, 0); + CloseSocketProper(client.Socket); + return; } else { CloseSocketProper(client.Socket); } From 435d73f0c168b113c35729c460a5c540bd5565a7 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 9 Dec 2021 12:09:55 +0100 Subject: [PATCH 255/255] Remove message thing from master, reimplement this later --- src/THeartbeatThread.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/THeartbeatThread.cpp b/src/THeartbeatThread.cpp index 75118e0..27ef253 100644 --- a/src/THeartbeatThread.cpp +++ b/src/THeartbeatThread.cpp @@ -89,11 +89,6 @@ void THeartbeatThread::operator()() { } else if (T == "200") { beammp_info(("Resumed authenticated session!")); isAuth = true; - } else { - if (Message.empty()) { - Message = "Backend didn't provide a reason"; - } - error("Backend REFUSED the auth key. " + Message); } } }