//////////////////////////////////////////////////////////// // // LockedWrapper.h // // Mutex-guarded access to the EngineWrapper. // //////////////////////////////////////////////////////////// #pragma once #include "CoreMinimal.h" #include "lpx-enginewrapper.hpp" #include "Common.h" #include "StreamBuffer.h" #include "Subsystems/GameInstanceSubsystem.h" #include "LockedWrapper.generated.h" //////////////////////////////////////////////////////////// // // UlxEngineWrapper // // GameInstanceSubsystem that owns the EngineWrapper and // a Mutex to lock it. To access the EngineWrapper, // construct a FlxLockedWrapper. // //////////////////////////////////////////////////////////// UCLASS() class INTEGRATION_API UlxEngineWrapper : public UGameInstanceSubsystem { GENERATED_BODY() private: static UlxEngineWrapper* Instance; // Called by luprex to output debugging messages. // A thin wrapper around UE_LOG. // static void DPrintHook(const char *Msg, size_t Size); FCriticalSection Mutex; EngineWrapper Wrapper; // The Lua Call Assembly Buffer. Used to build up a call // across multiple UFUNCTION invocations. This is not protected // by the mutex, so it should only be used by the game thread. // FlxStreamBuffer LuaCallBuffer; public: virtual void Initialize(FSubsystemCollectionBase& Collection) override; virtual void Deinitialize() override; // Get the Lua Call Assembly Buffer. // Only called from the game thread. // static FlxStreamBuffer& GetLuaCallBuffer() { return Instance->LuaCallBuffer; } friend class FlxLockedWrapper; }; //////////////////////////////////////////////////////////// // // FlxLockedWrapper // // RAII lock guard. The constructor claims the mutex, // the destructor releases it. Use operator-> to // access the EngineWrapper. // //////////////////////////////////////////////////////////// class FlxLockedWrapper { private: UlxEngineWrapper& Lockable; public: // Import these types into our namespace. // using IdArray = LpxCommonTypes::IdArray; using IdView = LpxCommonTypes::IdView; using StringViewVec = LpxCommonTypes::StringViewVec; public: // The constructor claims the mutex. // FlxLockedWrapper() : Lockable(*UlxEngineWrapper::Instance) { Lockable.Mutex.Lock(); } // The destructor releases the mutex. // ~FlxLockedWrapper() { Lockable.Mutex.Unlock(); } // Operator-> accesses the EngineWrapper. // EngineWrapper* operator ->() { return &Lockable.Wrapper; } // Get a pointer to the EngineWrapper. Not very // safe because you could keep the pointer after // the LockedWrapper is destroyed. Don't do that. // EngineWrapper* Get() { return &Lockable.Wrapper; } // Fetch Stdout as a string. // FString ChannelPrints(); // Get the current Actor ID. // int64 GetActor(); // Get the list of tangibles near the actor. // // This function is fast but not free. You should // fetch this once per frame and then store the // IdView somewhere (like in the TangibleManager). // IdView GetNear(int64 id, double rx, double ry, double rz); // Get animation queues. // // The array returned by this is valid until the // next time you call this. // StringViewVec GetAnimationQueues(IdView ids); // Call a Lua function. The datapk contains the // serialized class name, function name, and // arguments. If place_id is 0, defaults to the // current actor. The OnResult callback receives // the raw return data while the lock is held; // use it to copy the data before it goes away. // void ProbeLuaFunction(std::string_view datapk, int64 place_id, TFunction OnResult); // Invoke a Lua function (fire-and-forget, no // return values). // void InvokeLuaFunction(std::string_view datapk, int64 place_id); // Validate a Lua expression. Returns a syntax // classification and an error message. The error // message is empty if the code is valid. // ElxLuaSyntaxCheck ValidateLuaExpr(const FString &Code, FString &ErrorMessage); // Execute a Lua expression. // void InvokeLuaExpr(const FString &Code); };