mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-11-04 08:26:39 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			107 lines
		
	
	
	
		
			4.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			107 lines
		
	
	
	
		
			4.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#ifndef COMPONENTS_LUA_LUASTATE_H
 | 
						|
#define COMPONENTS_LUA_LUASTATE_H
 | 
						|
 | 
						|
#include <map>
 | 
						|
 | 
						|
#include <sol/sol.hpp>
 | 
						|
 | 
						|
#include <components/vfs/manager.hpp>
 | 
						|
 | 
						|
namespace LuaUtil
 | 
						|
{
 | 
						|
 | 
						|
    std::string getLuaVersion();
 | 
						|
 | 
						|
    // Holds Lua state.
 | 
						|
    // Provides additional features:
 | 
						|
    //   - Load scripts from the virtual filesystem;
 | 
						|
    //   - Caching of loaded scripts;
 | 
						|
    //   - Disable unsafe Lua functions;
 | 
						|
    //   - Run every instance of every script in a separate sandbox;
 | 
						|
    //   - Forbid any interactions between sandboxes except than via provided API;
 | 
						|
    //   - Access to common read-only resources from different sandboxes;
 | 
						|
    //   - Replace standard `require` with a safe version that allows to search
 | 
						|
    //         Lua libraries (only source, no dll's) in the virtual filesystem;
 | 
						|
    //   - Make `print` to add the script name to the every message and
 | 
						|
    //         write to Log rather than directly to stdout;
 | 
						|
    class LuaState
 | 
						|
    {
 | 
						|
    public:
 | 
						|
        explicit LuaState(const VFS::Manager* vfs);
 | 
						|
        ~LuaState();
 | 
						|
 | 
						|
        // Returns underlying sol::state.
 | 
						|
        sol::state& sol() { return mLua; }
 | 
						|
 | 
						|
        // A shortcut to create a new Lua table.
 | 
						|
        sol::table newTable() { return sol::table(mLua, sol::create); }
 | 
						|
 | 
						|
        // Makes a table read only (when accessed from Lua) by wrapping it with an empty userdata.
 | 
						|
        // Needed to forbid any changes in common resources that can accessed from different sandboxes.
 | 
						|
        sol::table makeReadOnly(sol::table);
 | 
						|
        sol::table getMutableFromReadOnly(const sol::userdata&);
 | 
						|
 | 
						|
        // Registers a package that will be available from every sandbox via `require(name)`.
 | 
						|
        // The package can be either a sol::table with an API or a sol::function. If it is a function,
 | 
						|
        // it will be evaluated (once per sandbox) the first time when requested. If the package
 | 
						|
        // is a table, then `makeReadOnly` is applied to it automatically (but not to other tables it contains).
 | 
						|
        void addCommonPackage(const std::string& packageName, const sol::object& package);
 | 
						|
 | 
						|
        // Creates a new sandbox, runs a script, and returns the result
 | 
						|
        // (the result is expected to be an interface of the script).
 | 
						|
        // Args:
 | 
						|
        //     path: path to the script in the virtual filesystem;
 | 
						|
        //     namePrefix: sandbox name will be "<namePrefix>[<filePath>]". Sandbox name
 | 
						|
        //         will be added to every `print` output.
 | 
						|
        //     packages: additional packages that should be available from the sandbox via `require`. Each package
 | 
						|
        //         should be either a sol::table or a sol::function. If it is a function, it will be evaluated
 | 
						|
        //         (once per sandbox) with the argument 'hiddenData' the first time when requested.
 | 
						|
        sol::protected_function_result runInNewSandbox(const std::string& path,
 | 
						|
                                                       const std::string& namePrefix = "",
 | 
						|
                                                       const std::map<std::string, sol::object>& packages = {},
 | 
						|
                                                       const sol::object& hiddenData = sol::nil);
 | 
						|
 | 
						|
        void dropScriptCache() { mCompiledScripts.clear(); }
 | 
						|
 | 
						|
    private:
 | 
						|
        static sol::protected_function_result throwIfError(sol::protected_function_result&&);
 | 
						|
        template <typename... Args>
 | 
						|
        friend sol::protected_function_result call(sol::protected_function fn, Args&&... args);
 | 
						|
 | 
						|
        sol::protected_function loadScript(const std::string& path);
 | 
						|
 | 
						|
        sol::state mLua;
 | 
						|
        sol::table mSandboxEnv;
 | 
						|
        std::map<std::string, sol::bytecode> mCompiledScripts;
 | 
						|
        std::map<std::string, sol::object> mCommonPackages;
 | 
						|
        const VFS::Manager* mVFS;
 | 
						|
    };
 | 
						|
 | 
						|
    // Should be used for every call of every Lua function.
 | 
						|
    // It is a workaround for a bug in `sol`. See https://github.com/ThePhD/sol2/issues/1078
 | 
						|
    template <typename... Args>
 | 
						|
    sol::protected_function_result call(sol::protected_function fn, Args&&... args)
 | 
						|
    {
 | 
						|
        try
 | 
						|
        {
 | 
						|
            return LuaState::throwIfError(fn(std::forward<Args>(args)...));
 | 
						|
        }
 | 
						|
        catch (std::exception&) { throw; }
 | 
						|
        catch (...) { throw std::runtime_error("Unknown error"); }
 | 
						|
    }
 | 
						|
 | 
						|
    // getFieldOrNil(table, "a", "b", "c") returns table["a"]["b"]["c"] or nil if some of the fields doesn't exist.
 | 
						|
    template <class... Str>
 | 
						|
    sol::object getFieldOrNil(const sol::object& table, std::string_view first, const Str&... str)
 | 
						|
    {
 | 
						|
        if (!table.is<sol::table>())
 | 
						|
            return sol::nil;
 | 
						|
        if constexpr (sizeof...(str) == 0)
 | 
						|
            return table.as<sol::table>()[first];
 | 
						|
        else
 | 
						|
            return getFieldOrNil(table.as<sol::table>()[first], str...);
 | 
						|
    }
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
#endif // COMPONENTS_LUA_LUASTATE_H
 |