2023-06-06 07:40:40 +00:00
|
|
|
#include "lua_module.hpp"
|
|
|
|
|
|
|
|
#include "bindings/command.hpp"
|
2023-07-21 21:21:51 +02:00
|
|
|
#include "bindings/entities.hpp"
|
2023-06-06 07:40:40 +00:00
|
|
|
#include "bindings/event.hpp"
|
2023-07-15 22:07:10 +02:00
|
|
|
#include "bindings/global_table.hpp"
|
2023-06-06 07:40:40 +00:00
|
|
|
#include "bindings/globals.hpp"
|
|
|
|
#include "bindings/gui.hpp"
|
2023-07-21 21:21:51 +02:00
|
|
|
#include "bindings/imgui.hpp"
|
2023-06-06 07:40:40 +00:00
|
|
|
#include "bindings/locals.hpp"
|
|
|
|
#include "bindings/log.hpp"
|
|
|
|
#include "bindings/memory.hpp"
|
|
|
|
#include "bindings/native.hpp"
|
|
|
|
#include "bindings/network.hpp"
|
|
|
|
#include "bindings/script.hpp"
|
2023-07-28 10:07:17 +02:00
|
|
|
#include "bindings/stats.hpp"
|
2023-06-06 07:40:40 +00:00
|
|
|
#include "bindings/tunables.hpp"
|
|
|
|
#include "bindings/vector.hpp"
|
2023-12-05 03:58:35 -05:00
|
|
|
#include "bindings/weapons.hpp"
|
|
|
|
#include "bindings/vehicles.hpp"
|
2023-06-06 07:40:40 +00:00
|
|
|
#include "file_manager.hpp"
|
|
|
|
#include "script_mgr.hpp"
|
|
|
|
|
|
|
|
namespace big
|
|
|
|
{
|
2023-07-16 23:32:34 +02:00
|
|
|
// https://sol2.readthedocs.io/en/latest/exceptions.html
|
|
|
|
int exception_handler(lua_State* L, sol::optional<const std::exception&> maybe_exception, sol::string_view description)
|
2023-06-06 07:40:40 +00:00
|
|
|
{
|
2023-07-16 23:32:34 +02:00
|
|
|
// L is the lua state, which you can wrap in a state_view if necessary
|
|
|
|
// maybe_exception will contain exception, if it exists
|
|
|
|
// description will either be the what() of the exception or a description saying that we hit the general-case catch(...)
|
|
|
|
if (maybe_exception)
|
|
|
|
{
|
|
|
|
const std::exception& ex = *maybe_exception;
|
|
|
|
LOG(FATAL) << ex.what();
|
|
|
|
}
|
2023-06-06 07:40:40 +00:00
|
|
|
else
|
2023-07-16 23:32:34 +02:00
|
|
|
{
|
|
|
|
LOG(FATAL) << description;
|
|
|
|
}
|
|
|
|
Logger::FlushQueue();
|
2023-06-06 07:40:40 +00:00
|
|
|
|
2023-07-16 23:32:34 +02:00
|
|
|
// you must push 1 element onto the stack to be
|
|
|
|
// transported through as the error object in Lua
|
|
|
|
// note that Lua -- and 99.5% of all Lua users and libraries -- expects a string
|
|
|
|
// so we push a single string (in our case, the description of the error)
|
|
|
|
return sol::stack::push(L, description);
|
2023-06-06 07:40:40 +00:00
|
|
|
}
|
|
|
|
|
2023-07-16 23:32:34 +02:00
|
|
|
inline void panic_handler(sol::optional<std::string> maybe_msg)
|
2023-06-06 07:40:40 +00:00
|
|
|
{
|
2023-07-16 23:32:34 +02:00
|
|
|
LOG(FATAL) << "Lua is in a panic state and will now abort() the application";
|
|
|
|
if (maybe_msg)
|
2023-06-06 07:40:40 +00:00
|
|
|
{
|
2023-07-16 23:32:34 +02:00
|
|
|
const std::string& msg = maybe_msg.value();
|
|
|
|
LOG(FATAL) << "error message: " << msg;
|
2023-06-06 07:40:40 +00:00
|
|
|
}
|
2023-07-16 23:32:34 +02:00
|
|
|
Logger::FlushQueue();
|
|
|
|
|
|
|
|
// When this function exits, Lua will exhibit default behavior and abort()
|
2023-06-06 07:40:40 +00:00
|
|
|
}
|
|
|
|
|
2023-07-22 13:05:43 +02:00
|
|
|
lua_module::lua_module(const std::filesystem::path& module_path, folder& scripts_folder) :
|
|
|
|
m_state(),
|
|
|
|
m_module_path(module_path),
|
|
|
|
m_module_name(module_path.filename().string()),
|
|
|
|
m_module_id(rage::joaat(m_module_name))
|
2023-06-06 07:40:40 +00:00
|
|
|
{
|
2023-07-15 22:07:10 +02:00
|
|
|
// clang-format off
|
2023-07-22 13:05:43 +02:00
|
|
|
m_state.open_libraries(
|
2023-07-11 09:24:44 +02:00
|
|
|
sol::lib::base,
|
|
|
|
sol::lib::package,
|
|
|
|
sol::lib::coroutine,
|
|
|
|
sol::lib::string,
|
2023-07-13 09:36:13 +02:00
|
|
|
sol::lib::os,
|
2023-07-11 09:24:44 +02:00
|
|
|
sol::lib::math,
|
|
|
|
sol::lib::table,
|
|
|
|
sol::lib::bit32,
|
|
|
|
sol::lib::utf8
|
|
|
|
);
|
2023-07-15 22:07:10 +02:00
|
|
|
// clang-format on
|
2023-06-06 07:40:40 +00:00
|
|
|
|
2023-07-18 13:07:33 +02:00
|
|
|
init_lua_api(scripts_folder);
|
2023-06-06 07:40:40 +00:00
|
|
|
|
2023-07-22 13:05:43 +02:00
|
|
|
m_state["!module_name"] = m_module_name;
|
|
|
|
m_state["!this"] = this;
|
2023-06-06 07:40:40 +00:00
|
|
|
|
2023-07-22 13:05:43 +02:00
|
|
|
m_state.set_exception_handler(exception_handler);
|
|
|
|
m_state.set_panic(sol::c_call<decltype(&panic_handler), &panic_handler>);
|
2023-07-16 23:32:34 +02:00
|
|
|
|
2023-07-22 13:05:43 +02:00
|
|
|
m_last_write_time = std::filesystem::last_write_time(m_module_path);
|
2023-06-06 07:40:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
lua_module::~lua_module()
|
|
|
|
{
|
2023-07-05 00:30:57 +02:00
|
|
|
{
|
2023-07-22 13:05:43 +02:00
|
|
|
std::lock_guard guard(m_registered_scripts_mutex);
|
|
|
|
m_registered_scripts.clear();
|
2023-07-05 00:30:57 +02:00
|
|
|
}
|
|
|
|
|
2023-07-22 13:05:43 +02:00
|
|
|
for (const auto owned_tab : m_owned_tabs)
|
2023-07-13 09:36:13 +02:00
|
|
|
{
|
2023-07-22 13:05:43 +02:00
|
|
|
big::g_gui_service->remove_from_nav(owned_tab);
|
2023-07-13 09:36:13 +02:00
|
|
|
}
|
|
|
|
|
2023-06-06 07:40:40 +00:00
|
|
|
for (auto memory : m_allocated_memory)
|
|
|
|
delete[] memory;
|
|
|
|
}
|
|
|
|
|
2023-07-02 22:32:46 +02:00
|
|
|
rage::joaat_t lua_module::module_id() const
|
2023-06-06 07:40:40 +00:00
|
|
|
{
|
|
|
|
return m_module_id;
|
|
|
|
}
|
|
|
|
|
2023-07-02 22:32:46 +02:00
|
|
|
const std::string& lua_module::module_name() const
|
2023-06-06 07:40:40 +00:00
|
|
|
{
|
|
|
|
return m_module_name;
|
|
|
|
}
|
2023-06-27 20:13:05 +02:00
|
|
|
|
2023-07-22 13:05:43 +02:00
|
|
|
const std::filesystem::path& lua_module::module_path() const
|
|
|
|
{
|
|
|
|
return m_module_path;
|
|
|
|
}
|
|
|
|
|
2023-07-02 22:32:46 +02:00
|
|
|
const std::chrono::time_point<std::chrono::file_clock> lua_module::last_write_time() const
|
|
|
|
{
|
|
|
|
return m_last_write_time;
|
|
|
|
}
|
|
|
|
|
2023-07-18 13:07:33 +02:00
|
|
|
void lua_module::set_folder_for_lua_require(folder& scripts_folder)
|
2023-07-13 09:36:13 +02:00
|
|
|
{
|
2023-07-22 13:05:43 +02:00
|
|
|
std::string scripts_search_path = scripts_folder.get_path().string() + "/?.lua;";
|
2023-07-13 09:36:13 +02:00
|
|
|
|
2023-07-22 13:05:43 +02:00
|
|
|
for (const auto& entry : std::filesystem::recursive_directory_iterator(scripts_folder.get_path(), std::filesystem::directory_options::skip_permission_denied))
|
|
|
|
{
|
|
|
|
if (!entry.is_directory())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
scripts_search_path += entry.path().string() + "/?.lua;";
|
|
|
|
}
|
|
|
|
// Remove final ';'
|
|
|
|
scripts_search_path.pop_back();
|
|
|
|
|
|
|
|
m_state["package"]["path"] = scripts_search_path;
|
2023-07-13 09:36:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void lua_module::sandbox_lua_os_library()
|
2023-06-27 20:13:05 +02:00
|
|
|
{
|
2023-07-22 13:05:43 +02:00
|
|
|
const auto& os = m_state["os"];
|
|
|
|
sol::table sandbox_os(m_state, sol::create);
|
2023-07-13 09:36:13 +02:00
|
|
|
|
2023-07-15 22:07:10 +02:00
|
|
|
sandbox_os["clock"] = os["clock"];
|
|
|
|
sandbox_os["date"] = os["date"];
|
|
|
|
sandbox_os["difftime"] = os["difftime"];
|
|
|
|
sandbox_os["time"] = os["time"];
|
2023-07-13 09:36:13 +02:00
|
|
|
|
2023-07-22 13:05:43 +02:00
|
|
|
m_state["os"] = sandbox_os;
|
2023-07-13 09:36:13 +02:00
|
|
|
}
|
|
|
|
|
2023-07-15 22:07:10 +02:00
|
|
|
template<size_t N>
|
|
|
|
static constexpr auto not_supported_lua_function(const char (&function_name)[N])
|
|
|
|
{
|
2023-07-22 13:05:43 +02:00
|
|
|
return [function_name](sol::this_state state, sol::variadic_args args) {
|
|
|
|
big::lua_module* module = sol::state_view(state)["!this"];
|
2023-07-15 22:07:10 +02:00
|
|
|
|
|
|
|
LOG(FATAL) << module->module_name() << " tried calling a currently not supported lua function: " << function_name;
|
2023-07-16 23:32:34 +02:00
|
|
|
Logger::FlushQueue();
|
2023-07-15 22:07:10 +02:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-07-18 13:07:33 +02:00
|
|
|
void lua_module::sandbox_lua_loads(folder& scripts_folder)
|
2023-07-13 09:36:13 +02:00
|
|
|
{
|
|
|
|
// That's from lua base lib, luaB
|
2023-07-22 13:05:43 +02:00
|
|
|
m_state["load"] = not_supported_lua_function("load");
|
|
|
|
m_state["loadstring"] = not_supported_lua_function("loadstring");
|
|
|
|
m_state["loadfile"] = not_supported_lua_function("loadfile");
|
|
|
|
m_state["dofile"] = not_supported_lua_function("dofile");
|
2023-07-13 09:36:13 +02:00
|
|
|
|
|
|
|
// That's from lua package lib.
|
|
|
|
// We only allow dependencies between .lua files, no DLLs.
|
2023-07-22 13:05:43 +02:00
|
|
|
m_state["package"]["loadlib"] = not_supported_lua_function("package.loadlib");
|
|
|
|
m_state["package"]["cpath"] = "";
|
2023-07-13 09:36:13 +02:00
|
|
|
|
|
|
|
// 1 2 3 4
|
|
|
|
// {searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL};
|
2023-07-22 13:05:43 +02:00
|
|
|
m_state["package"]["searchers"][3] = not_supported_lua_function("package.searcher C");
|
|
|
|
m_state["package"]["searchers"][4] = not_supported_lua_function("package.searcher Croot");
|
2023-07-13 09:36:13 +02:00
|
|
|
|
2023-07-18 13:07:33 +02:00
|
|
|
set_folder_for_lua_require(scripts_folder);
|
2023-06-27 20:13:05 +02:00
|
|
|
}
|
|
|
|
|
2023-07-18 13:07:33 +02:00
|
|
|
void lua_module::init_lua_api(folder& scripts_folder)
|
2023-06-27 20:13:05 +02:00
|
|
|
{
|
2023-07-13 09:36:13 +02:00
|
|
|
// https://blog.rubenwardy.com/2020/07/26/sol3-script-sandbox/
|
|
|
|
// https://www.lua.org/manual/5.4/manual.html#pdf-require
|
|
|
|
sandbox_lua_os_library();
|
2023-07-18 13:07:33 +02:00
|
|
|
sandbox_lua_loads(scripts_folder);
|
2023-07-13 09:36:13 +02:00
|
|
|
|
2023-07-22 13:05:43 +02:00
|
|
|
lua::log::bind(m_state);
|
|
|
|
lua::globals::bind(m_state);
|
|
|
|
lua::script::bind(m_state);
|
|
|
|
lua::native::bind(m_state);
|
|
|
|
lua::memory::bind(m_state);
|
|
|
|
lua::gui::bind(m_state);
|
|
|
|
lua::network::bind(m_state);
|
|
|
|
lua::command::bind(m_state);
|
|
|
|
lua::tunables::bind(m_state);
|
|
|
|
lua::locals::bind(m_state);
|
|
|
|
lua::event::bind(m_state);
|
|
|
|
lua::vector::bind(m_state);
|
|
|
|
lua::global_table::bind(m_state);
|
|
|
|
lua::imgui::bind(m_state, m_state.globals());
|
|
|
|
lua::entities::bind(m_state);
|
2023-07-28 10:07:17 +02:00
|
|
|
lua::stats::bind(m_state);
|
2023-12-05 03:58:35 -05:00
|
|
|
lua::weapons::bind(m_state);
|
|
|
|
lua::vehicles::bind(m_state);
|
2023-07-22 13:05:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void lua_module::load_and_call_script()
|
|
|
|
{
|
|
|
|
auto result = m_state.safe_script_file(m_module_path.string(), &sol::script_pass_on_error, sol::load_mode::text);
|
|
|
|
|
|
|
|
if (!result.valid())
|
|
|
|
{
|
|
|
|
LOG(FATAL) << m_module_name << " failed to load: " << result.get<sol::error>().what();
|
|
|
|
Logger::FlushQueue();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
LOG(INFO) << "Loaded " << m_module_name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void lua_module::tick_scripts()
|
|
|
|
{
|
|
|
|
std::lock_guard guard(m_registered_scripts_mutex);
|
|
|
|
|
2023-07-29 11:22:04 +02:00
|
|
|
const auto script_count = m_registered_scripts.size();
|
|
|
|
for (size_t i = 0; i < script_count; i++)
|
2023-07-22 13:05:43 +02:00
|
|
|
{
|
2023-07-29 11:22:04 +02:00
|
|
|
const auto script = m_registered_scripts[i].get();
|
|
|
|
|
2023-07-22 13:05:43 +02:00
|
|
|
if (script->is_enabled())
|
|
|
|
{
|
|
|
|
script->tick();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void lua_module::cleanup_done_scripts()
|
|
|
|
{
|
|
|
|
std::lock_guard guard(m_registered_scripts_mutex);
|
|
|
|
|
|
|
|
std::erase_if(m_registered_scripts, [](auto& script) {
|
|
|
|
return script->is_done();
|
|
|
|
});
|
2023-06-27 20:13:05 +02:00
|
|
|
}
|
2023-06-06 07:40:40 +00:00
|
|
|
}
|