Feat lua file watch (#1584)

* feat lua: file watcher for lua script file: reload scripts if they got changed since they were initially loaded
* feat lua auto reload: enable / disable the feature through the ui and settings
This commit is contained in:
Quentin 2023-07-02 22:32:46 +02:00 committed by GitHub
parent e9ae5d5491
commit b44b2f04e6
7 changed files with 80 additions and 17 deletions

View File

@ -891,7 +891,14 @@ namespace big
NLOHMANN_DEFINE_TYPE_INTRUSIVE(stat_editor, stat, packed_stat)
} stat_editor{};
NLOHMANN_DEFINE_TYPE_INTRUSIVE(menu_settings, debug, tunables, notifications, player, player_db, protections, self, session, settings, spawn_vehicle, clone_pv, spoofing, vehicle, weapons, window, context_menu, esp, session_browser, ugc, reactions, world, stat_editor)
struct lua
{
bool enable_auto_reload_changed_scripts = false;
NLOHMANN_DEFINE_TYPE_INTRUSIVE(lua, enable_auto_reload_changed_scripts)
} lua{};
NLOHMANN_DEFINE_TYPE_INTRUSIVE(menu_settings, debug, tunables, notifications, player, player_db, protections, self, session, settings, spawn_vehicle, clone_pv, spoofing, vehicle, weapons, window, context_menu, esp, session_browser, ugc, reactions, world, stat_editor, lua)
};
inline auto g = menu_settings();

View File

@ -8,6 +8,9 @@ namespace big
{
m_schedule_reload_modules = false;
m_wake_time_changed_scripts_check =
std::chrono::high_resolution_clock::now() + m_delay_between_changed_scripts_check;
load_all_modules();
g_lua_manager = this;
@ -58,6 +61,39 @@ namespace big
m_modules.push_back(std::make_shared<lua_module>(module_name));
}
void lua_manager::reload_changed_scripts()
{
if (!g.lua.enable_auto_reload_changed_scripts)
{
return;
}
if (m_wake_time_changed_scripts_check <= std::chrono::high_resolution_clock::now())
{
for (const auto& entry : std::filesystem::directory_iterator(g_file_manager->get_project_folder("scripts").get_path()))
{
if (entry.is_regular_file())
{
const auto module_name = entry.path().filename().string();
const auto last_write_time = entry.last_write_time();
for (const auto& module : m_modules)
{
if (module->module_name() == module_name &&
module->last_write_time() < last_write_time)
{
unload_module(module->module_id());
queue_load_module(module_name, nullptr);
break;
}
}
}
}
m_wake_time_changed_scripts_check = std::chrono::high_resolution_clock::now() + m_delay_between_changed_scripts_check;
}
}
void lua_manager::queue_load_module(const std::string& module_name, std::function<void(std::weak_ptr<lua_module>)> on_module_loaded)
{
m_modules_load_queue.push({module_name, on_module_loaded});
@ -73,7 +109,8 @@ namespace big
load_module(module_load_info.m_name);
auto loaded_module = get_module(id);
module_load_info.m_on_module_loaded(loaded_module);
if (module_load_info.m_on_module_loaded)
module_load_info.m_on_module_loaded(loaded_module);
m_modules_load_queue.pop();
}

View File

@ -6,7 +6,19 @@ namespace big
{
class lua_manager
{
private:
std::mutex m_module_lock;
std::vector<std::shared_ptr<lua_module>> m_modules;
struct module_load_info
{
std::string m_name;
std::function<void(std::weak_ptr<lua_module>)> m_on_module_loaded;
};
std::queue<module_load_info> m_modules_load_queue;
static constexpr std::chrono::seconds m_delay_between_changed_scripts_check = 3s;
std::chrono::high_resolution_clock::time_point m_wake_time_changed_scripts_check;
public:
bool m_schedule_reload_modules;
@ -28,6 +40,8 @@ namespace big
void unload_module(rage::joaat_t module_id);
void load_module(const std::string& module_name);
void reload_changed_scripts();
void queue_load_module(const std::string& module_name, std::function<void(std::weak_ptr<lua_module>)> on_module_loaded);
void load_modules_from_queue();
@ -81,16 +95,6 @@ namespace big
func(module);
}
}
private:
std::vector<std::shared_ptr<lua_module>> m_modules;
struct module_load_info
{
std::string m_name;
std::function<void(std::weak_ptr<lua_module>)> m_on_module_loaded;
};
std::queue<module_load_info> m_modules_load_queue;
};
inline lua_manager* g_lua_manager;

View File

@ -63,7 +63,9 @@ namespace big
m_state.set_exception_handler((sol::exception_handler_function)exception_handler);
m_state.set_panic(panic_handler);
auto result = m_state.load_file(scripts_folder.get_file(module_name).get_path().string());
const auto script_file_path = scripts_folder.get_file(module_name).get_path();
m_last_write_time = std::filesystem::last_write_time(script_file_path);
auto result = m_state.load_file(script_file_path.string());
if (!result.valid())
{
@ -90,16 +92,21 @@ namespace big
m_registered_patches.clear();
}
rage::joaat_t lua_module::module_id()
rage::joaat_t lua_module::module_id() const
{
return m_module_id;
}
const std::string& lua_module::module_name()
const std::string& lua_module::module_name() const
{
return m_module_name;
}
const std::chrono::time_point<std::chrono::file_clock> lua_module::last_write_time() const
{
return m_last_write_time;
}
void lua_module::add_folder_to_require_available_paths(const big::folder& scripts_folder)
{
const std::string package_path = m_state["package"]["path"];

View File

@ -11,9 +11,12 @@ namespace big
class lua_module
{
sol::state m_state;
std::string m_module_name;
rage::joaat_t m_module_id;
std::chrono::time_point<std::chrono::file_clock> m_last_write_time;
public:
std::vector<script*> m_registered_scripts;
std::vector<std::shared_ptr<lua_patch>> m_registered_patches;
@ -24,8 +27,9 @@ namespace big
lua_module(std::string module_name);
~lua_module();
rage::joaat_t module_id();
const std::string& module_name();
rage::joaat_t module_id() const;
const std::string& module_name() const;
const std::chrono::time_point<std::chrono::file_clock> last_write_time() const;
// used for adding our own paths to the search paths of the lua require function
void add_folder_to_require_available_paths(const big::folder& scripts_folder);

View File

@ -49,6 +49,8 @@ namespace big
g_lua_manager->unload_all_modules();
}
g_lua_manager->reload_changed_scripts();
std::erase_if(m_scripts, [](std::unique_ptr<script>& iter) {
return iter->m_should_be_deleted;
});

View File

@ -53,5 +53,7 @@ namespace big
{
g_lua_manager->m_schedule_reload_modules = true;
}
ImGui::Checkbox("Auto Reload Changed Scripts", &g.lua.enable_auto_reload_changed_scripts);
}
}