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:
parent
e4ac08496c
commit
a4d623ca74
@ -891,7 +891,14 @@ namespace big
|
|||||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE(stat_editor, stat, packed_stat)
|
NLOHMANN_DEFINE_TYPE_INTRUSIVE(stat_editor, stat, packed_stat)
|
||||||
} stat_editor{};
|
} 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();
|
inline auto g = menu_settings();
|
||||||
|
@ -8,6 +8,9 @@ namespace big
|
|||||||
{
|
{
|
||||||
m_schedule_reload_modules = false;
|
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();
|
load_all_modules();
|
||||||
|
|
||||||
g_lua_manager = this;
|
g_lua_manager = this;
|
||||||
@ -58,6 +61,39 @@ namespace big
|
|||||||
m_modules.push_back(std::make_shared<lua_module>(module_name));
|
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)
|
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});
|
m_modules_load_queue.push({module_name, on_module_loaded});
|
||||||
@ -73,6 +109,7 @@ namespace big
|
|||||||
|
|
||||||
load_module(module_load_info.m_name);
|
load_module(module_load_info.m_name);
|
||||||
auto loaded_module = get_module(id);
|
auto loaded_module = get_module(id);
|
||||||
|
if (module_load_info.m_on_module_loaded)
|
||||||
module_load_info.m_on_module_loaded(loaded_module);
|
module_load_info.m_on_module_loaded(loaded_module);
|
||||||
|
|
||||||
m_modules_load_queue.pop();
|
m_modules_load_queue.pop();
|
||||||
|
@ -6,7 +6,19 @@ namespace big
|
|||||||
{
|
{
|
||||||
class lua_manager
|
class lua_manager
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
std::mutex m_module_lock;
|
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:
|
public:
|
||||||
bool m_schedule_reload_modules;
|
bool m_schedule_reload_modules;
|
||||||
@ -28,6 +40,8 @@ namespace big
|
|||||||
void unload_module(rage::joaat_t module_id);
|
void unload_module(rage::joaat_t module_id);
|
||||||
void load_module(const std::string& module_name);
|
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 queue_load_module(const std::string& module_name, std::function<void(std::weak_ptr<lua_module>)> on_module_loaded);
|
||||||
void load_modules_from_queue();
|
void load_modules_from_queue();
|
||||||
|
|
||||||
@ -81,16 +95,6 @@ namespace big
|
|||||||
func(module);
|
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;
|
inline lua_manager* g_lua_manager;
|
||||||
|
@ -63,7 +63,9 @@ namespace big
|
|||||||
m_state.set_exception_handler((sol::exception_handler_function)exception_handler);
|
m_state.set_exception_handler((sol::exception_handler_function)exception_handler);
|
||||||
m_state.set_panic(panic_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())
|
if (!result.valid())
|
||||||
{
|
{
|
||||||
@ -90,16 +92,21 @@ namespace big
|
|||||||
m_registered_patches.clear();
|
m_registered_patches.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
rage::joaat_t lua_module::module_id()
|
rage::joaat_t lua_module::module_id() const
|
||||||
{
|
{
|
||||||
return m_module_id;
|
return m_module_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& lua_module::module_name()
|
const std::string& lua_module::module_name() const
|
||||||
{
|
{
|
||||||
return m_module_name;
|
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)
|
void lua_module::add_folder_to_require_available_paths(const big::folder& scripts_folder)
|
||||||
{
|
{
|
||||||
const std::string package_path = m_state["package"]["path"];
|
const std::string package_path = m_state["package"]["path"];
|
||||||
|
@ -11,9 +11,12 @@ namespace big
|
|||||||
class lua_module
|
class lua_module
|
||||||
{
|
{
|
||||||
sol::state m_state;
|
sol::state m_state;
|
||||||
|
|
||||||
std::string m_module_name;
|
std::string m_module_name;
|
||||||
rage::joaat_t m_module_id;
|
rage::joaat_t m_module_id;
|
||||||
|
|
||||||
|
std::chrono::time_point<std::chrono::file_clock> m_last_write_time;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::vector<script*> m_registered_scripts;
|
std::vector<script*> m_registered_scripts;
|
||||||
std::vector<std::shared_ptr<lua_patch>> m_registered_patches;
|
std::vector<std::shared_ptr<lua_patch>> m_registered_patches;
|
||||||
@ -24,8 +27,9 @@ namespace big
|
|||||||
lua_module(std::string module_name);
|
lua_module(std::string module_name);
|
||||||
~lua_module();
|
~lua_module();
|
||||||
|
|
||||||
rage::joaat_t module_id();
|
rage::joaat_t module_id() const;
|
||||||
const std::string& module_name();
|
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
|
// 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);
|
void add_folder_to_require_available_paths(const big::folder& scripts_folder);
|
||||||
|
@ -49,6 +49,8 @@ namespace big
|
|||||||
g_lua_manager->unload_all_modules();
|
g_lua_manager->unload_all_modules();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_lua_manager->reload_changed_scripts();
|
||||||
|
|
||||||
std::erase_if(m_scripts, [](std::unique_ptr<script>& iter) {
|
std::erase_if(m_scripts, [](std::unique_ptr<script>& iter) {
|
||||||
return iter->m_should_be_deleted;
|
return iter->m_should_be_deleted;
|
||||||
});
|
});
|
||||||
|
@ -53,5 +53,7 @@ namespace big
|
|||||||
{
|
{
|
||||||
g_lua_manager->m_schedule_reload_modules = true;
|
g_lua_manager->m_schedule_reload_modules = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImGui::Checkbox("Auto Reload Changed Scripts", &g.lua.enable_auto_reload_changed_scripts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user