diff --git a/src/client/component/command.cpp b/src/client/component/command.cpp index 90ee1596..f003187d 100644 --- a/src/client/component/command.cpp +++ b/src/client/component/command.cpp @@ -28,6 +28,8 @@ namespace command std::unordered_map> handlers; std::unordered_map> handlers_sv; + std::string saved_fs_game; + void main_handler() { params params = {}; @@ -106,6 +108,33 @@ namespace command parsed = true; } + void register_fs_game_path() + { + console::debug("[FS] " __FUNCTION__ " called\n"); + + static const auto* fs_game = game::Dvar_FindVar("fs_game"); + const auto* new_mod_path = fs_game->current.string; + + // check if the last saved fs_game value isn't empty and if it doesn't equal the new fs_game + if (!saved_fs_game.empty() && saved_fs_game != new_mod_path) + { + // unregister path to be used as a fs directory + filesystem::unregister_path(saved_fs_game); + } + + if (new_mod_path && !new_mod_path[0]) + { + console::debug("[FS] " __FUNCTION__ " returning because new mod path is blank\n"); + return; + } + + console::debug("[FS] " __FUNCTION__ " registering new mod path\n"); + + // register fs_game value as a fs directory used for many things + filesystem::register_path(new_mod_path); + saved_fs_game = new_mod_path; + } + void parse_startup_variables() { auto& com_num_console_lines = *reinterpret_cast(0x35634B8_b); @@ -128,14 +157,9 @@ namespace command } else { - dvars::on_register(dvar_name, [dvar_name, value]() + dvars::callback::on_register(dvar_name, [dvar_name, value]() { game::Dvar_SetCommand(game::generateHashValue(dvar_name.data()), "", value.data()); - - if (dvar_name == "fs_game") - { - filesystem::register_path(value); - } }); } } @@ -565,6 +589,17 @@ namespace command public: void post_unpack() override { + // monitor fs_game register and new value changes to adjust our paths for searching + dvars::callback::on_register("fs_game", []() + { + register_fs_game_path(); + }); + + dvars::callback::on_new_value("fs_game", []() + { + register_fs_game_path(); + }); + if (game::environment::is_sp()) { add_commands_sp(); diff --git a/src/client/component/dvars.cpp b/src/client/component/dvars.cpp index 416aaace..a1e4a4ee 100644 --- a/src/client/component/dvars.cpp +++ b/src/client/component/dvars.cpp @@ -252,6 +252,23 @@ namespace dvars } } + namespace callback + { + static std::unordered_map> new_value_callbacks; + + static std::unordered_map> dvar_on_register_function_map; + + void on_new_value(const std::string& name, const std::function callback) + { + new_value_callbacks[game::generateHashValue(name.data())] = callback; + } + + void on_register(const std::string& name, const std::function& callback) + { + dvar_on_register_function_map[game::generateHashValue(name.data())] = callback; + } + } + utils::hook::detour dvar_register_bool_hook; utils::hook::detour dvar_register_bool_hashed_hook; utils::hook::detour dvar_register_float_hook; @@ -271,6 +288,8 @@ namespace dvars utils::hook::detour dvar_set_string_hook; utils::hook::detour dvar_set_from_string_hook; + utils::hook::detour dvar_set_variant_hook; + game::dvar_t* dvar_register_bool(const int hash, const char* name, bool value, unsigned int flags) { auto* var = find_dvar(override::register_bool_overrides, hash); @@ -409,21 +428,15 @@ namespace dvars return dvar_register_enum_hook.invoke(hash, name, value_list, default_index, flags); } - std::unordered_map> dvar_on_register_function_map; - void on_register(const std::string& name, const std::function& callback) - { - dvar_on_register_function_map[game::generateHashValue(name.data())] = callback; - } - game::dvar_t* dvar_register_new(const int hash, const char* name, game::dvar_type type, unsigned int flags, game::dvar_value* value, game::dvar_limits* domain, const char* description) { auto* dvar = dvar_register_new_hook.invoke(hash, name, type, flags, value, domain, description); - if (dvar && dvar_on_register_function_map.find(hash) != dvar_on_register_function_map.end()) + if (dvar && callback::dvar_on_register_function_map.find(hash) != callback::dvar_on_register_function_map.end()) { - dvar_on_register_function_map[hash](); - dvar_on_register_function_map.erase(hash); + callback::dvar_on_register_function_map[hash](); + callback::dvar_on_register_function_map.erase(hash); } return dvar; @@ -514,6 +527,16 @@ namespace dvars return dvar_set_from_string_hook.invoke(dvar, string, source); } + void dvar_set_variant(game::dvar_t* dvar, game::dvar_value* value, game::DvarSetSource source) + { + dvar_set_variant_hook.invoke(dvar, value, source); + + if (callback::new_value_callbacks.find(dvar->hash) != callback::new_value_callbacks.end()) + { + callback::new_value_callbacks[dvar->hash](); + } + } + class component final : public component_interface { public: @@ -541,6 +564,8 @@ namespace dvars dvar_set_int_hook.create(SELECT_VALUE(0x41BEE0_b, 0x185D10_b), &dvar_set_int); dvar_set_string_hook.create(SELECT_VALUE(0x41C0F0_b, 0x186080_b), &dvar_set_string); dvar_set_from_string_hook.create(SELECT_VALUE(0x41BE20_b, 0x185C60_b), &dvar_set_from_string); + + dvar_set_variant_hook.create(SELECT_VALUE(0x41C190_b, 0x186120_b), &dvar_set_variant); } }; } diff --git a/src/client/component/dvars.hpp b/src/client/component/dvars.hpp index c00eafa6..3c9831c8 100644 --- a/src/client/component/dvars.hpp +++ b/src/client/component/dvars.hpp @@ -27,5 +27,10 @@ namespace dvars void set_from_string(const std::string& name, const std::string& value); } - void on_register(const std::string& name, const std::function& callback); + namespace callback + { + void on_new_value(const std::string& name, const std::function callback); + + void on_register(const std::string& name, const std::function& callback); + } } diff --git a/src/client/component/filesystem.cpp b/src/client/component/filesystem.cpp index 233bf416..ccd0807e 100644 --- a/src/client/component/filesystem.cpp +++ b/src/client/component/filesystem.cpp @@ -15,6 +15,8 @@ namespace filesystem { namespace { + utils::hook::detour fs_startup_hook; + bool initialized = false; std::deque& get_search_paths_internal() @@ -32,17 +34,19 @@ namespace filesystem void fs_startup_stub(const char* name) { - console::info("[FS] Startup\n"); + console::debug("[FS] Startup\n"); initialized = true; + // hardcoded paths filesystem::register_path(L"."); filesystem::register_path(L"h1-mod"); filesystem::register_path(L"data"); + // while this clears localizations, it also calls a function to load them again localized_strings::clear(); - utils::hook::invoke(SELECT_VALUE(0x40D890_b, 0x189A40_b), name); + fs_startup_hook.invoke(name); } std::vector get_paths(const std::filesystem::path& path) @@ -157,7 +161,7 @@ namespace filesystem { if (can_insert_path(path_)) { - console::info("[FS] Registering path '%s'\n", path_.generic_string().data()); + console::debug("[FS] Registering path '%s'\n", path_.generic_string().data()); get_search_paths_internal().push_front(path_); } } @@ -178,7 +182,7 @@ namespace filesystem { if (*i == path_) { - console::info("[FS] Unregistering path '%s'\n", path_.generic_string().data()); + console::debug("[FS] Unregistering path '%s'\n", path_.generic_string().data()); i = search_paths.erase(i); } else @@ -219,7 +223,8 @@ namespace filesystem public: void post_unpack() override { - utils::hook::call(SELECT_VALUE(0x40C992_b, 0x18939F_b), fs_startup_stub); + fs_startup_hook.create(SELECT_VALUE(0x40D890_b, 0x189A40_b), fs_startup_stub); + utils::hook::jump(SELECT_VALUE(0x42CE00_b, 0x5B3440_b), sys_default_install_path_stub); // fs_game flags diff --git a/src/client/component/ui_scripting.cpp b/src/client/component/ui_scripting.cpp index 7c2e8ea8..ac566a2e 100644 --- a/src/client/component/ui_scripting.cpp +++ b/src/client/component/ui_scripting.cpp @@ -390,7 +390,7 @@ namespace ui_scripting load_script("lui_updater", lui_updater); load_script("lua_json", lua_json); - for (const auto& path : filesystem::get_search_paths()) + for (const auto& path : filesystem::get_search_paths_rev()) { load_scripts(path + "/ui_scripts/"); if (game::environment::is_sp()) diff --git a/src/client/game/scripting/lua/engine.cpp b/src/client/game/scripting/lua/engine.cpp index 6d025409..07fae1c4 100644 --- a/src/client/game/scripting/lua/engine.cpp +++ b/src/client/game/scripting/lua/engine.cpp @@ -50,7 +50,7 @@ namespace scripting::lua::engine { stop(); running = true; - for (const auto& path : filesystem::get_search_paths()) + for (const auto& path : filesystem::get_search_paths_rev()) { load_scripts(path + "/scripts/"); if (game::environment::is_sp()) diff --git a/src/client/main.cpp b/src/client/main.cpp index 5c3995be..f769f457 100644 --- a/src/client/main.cpp +++ b/src/client/main.cpp @@ -202,7 +202,6 @@ void limit_parallel_dll_loading() int main() { ShowWindow(GetConsoleWindow(), SW_HIDE); - ShowWindow(GetConsoleWindow(), SW_SHOW); FARPROC entry_point;