#pragma once #include "TNetwork.h" #include "TServer.h" #include #include #include #include #include #include #include #include #include #include #include #define SOL_ALL_SAFETIES_ON 1 #include 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; struct TLuaResult { std::atomic_bool Ready; std::atomic_bool Error; std::string ErrorMessage; sol::object Result { sol::nil }; TLuaStateId StateId; std::string Function; // TODO: Add condition_variable void WaitUntilReady(); }; struct TLuaPluginConfig { static inline const std::string FileName = "PluginConfig.toml"; TLuaStateId StateId; // TODO: Add execute list }; struct TLuaChunk { TLuaChunk(std::shared_ptr Content, std::string FileName, std::string PluginPath); std::shared_ptr Content; std::string FileName; std::string PluginPath; }; class TLuaEngine : IThreaded { public: TLuaEngine(); ~TLuaEngine() noexcept { beammp_debug("Lua Engine terminated"); } void operator()() override; 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 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); 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()) { 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 + "\""); if (Event.first != IgnoreId) { Results.push_back(EnqueueFunctionCall(Event.first, Function, { TLuaArgTypes { std::forward(Args) }... })); } } } return Results; } std::set GetEventHandlersForState(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); void FindAndParseConfig(const fs::path& Folder, TLuaPluginConfig& Config); size_t CalculateMemoryUsage(); class StateThreadData : IThreaded { 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 TLuaChunk& Script); [[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; sol::state_view State() { return sol::state_view(mState); } private: 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); sol::table Lua_GetPlayerVehicles(int ID); std::string mName; std::atomic_bool& mShutdown; TLuaStateId mStateId; lua_State* mState; std::thread mThread; std::queue>> mStateExecuteQueue; std::recursive_mutex mStateExecuteQueueMutex; std::queue, std::vector>> mStateFunctionQueue; std::recursive_mutex mStateFunctionQueueMutex; TLuaEngine* mEngine; sol::state_view mStateView { mState }; std::queue mPaths; std::recursive_mutex mPathsMutex; }; TNetwork* mNetwork; TServer* mServer; std::atomic_bool mShutdown { false }; fs::path mResourceServerPath; std::vector mLuaPlugins; std::unordered_map> mLuaStates; std::recursive_mutex mLuaStatesMutex; std::unordered_map>> mEvents; std::recursive_mutex mEventsMutex; }; //std::any TriggerLuaEvent(const std::string& Event, bool local, TLuaPlugin* Caller, std::shared_ptr arg, bool Wait);