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,