diff --git a/src/client/component/filesystem.cpp b/src/client/component/filesystem.cpp index 321364a5..9d298857 100644 --- a/src/client/component/filesystem.cpp +++ b/src/client/component/filesystem.cpp @@ -2,25 +2,84 @@ #include "loader/component_loader.hpp" #include "filesystem.hpp" +#include "console.hpp" + +#include "game/game.hpp" #include +#include namespace filesystem { - std::unordered_set& get_search_paths() + namespace { - static std::unordered_set search_paths{}; - return search_paths; + bool initialized = false; + + std::vector& get_search_paths_internal() + { + static std::vector search_paths{}; + return search_paths; + } + + bool is_polrus_lang() + { + static auto* loc_language = game::Dvar_FindVar("loc_language"); + const auto id = loc_language->current.integer; + return id == 5 || id == 6 || id == 17; + } + + void fs_startup_stub(const char* name) + { + console::info("[FS] Startup\n"); + + initialized = true; + + filesystem::register_path(L"."); + filesystem::register_path(L"h2-mod"); + filesystem::register_path(L"data"); + + utils::hook::invoke(0x14060BF50, name); + } + + std::vector get_paths(const std::filesystem::path& path) + { + std::vector paths{}; + + const auto code = game::SEH_GetCurrentLanguageCode(); + + paths.push_back(path); + paths.push_back(path / code); + + if (is_polrus_lang()) + { + paths.push_back(path / "polrus"); + } + + return paths; + } + + bool can_insert_path(const std::filesystem::path& path) + { + for (const auto& path_ : get_search_paths_internal()) + { + if (path_ == path) + { + return false; + } + } + + return true; + } } std::string read_file(const std::string& path) { - for (const auto& search_path : get_search_paths()) + for (const auto& search_path : get_search_paths_internal()) { - const auto path_ = search_path + "/" + path; - if (utils::io::file_exists(path_)) + const auto path_ = search_path / path; + if (utils::io::file_exists(path_.generic_string())) { - return utils::io::read_file(path_); + return utils::io::read_file(path_.generic_string()); } } @@ -29,14 +88,14 @@ namespace filesystem bool read_file(const std::string& path, std::string* data, std::string* real_path) { - for (const auto& search_path : get_search_paths()) + for (const auto& search_path : get_search_paths_internal()) { - const auto path_ = search_path + "/" + path; - if (utils::io::read_file(path_, data)) + const auto path_ = search_path / path; + if (utils::io::read_file(path_.generic_string(), data)) { if (real_path != nullptr) { - *real_path = path_; + *real_path = path_.generic_string(); } return true; @@ -46,14 +105,68 @@ namespace filesystem return false; } + void register_path(const std::filesystem::path& path) + { + if (!initialized) + { + return; + } + + const auto paths = get_paths(path); + for (const auto& path_ : paths) + { + if (can_insert_path(path_)) + { + console::info("[FS] Registering path '%s'\n", path_.generic_string().data()); + get_search_paths_internal().push_back(path_); + } + } + } + + void unregister_path(const std::filesystem::path& path) + { + if (!initialized) + { + return; + } + + const auto paths = get_paths(path); + for (const auto& path_ : paths) + { + auto& search_paths = get_search_paths_internal(); + for (auto i = search_paths.begin(); i != search_paths.end();) + { + if (*i == path_) + { + console::info("[FS] Unregistering path '%s'\n", path_.generic_string().data()); + i = search_paths.erase(i); + } + else + { + ++i; + } + } + } + } + + std::vector get_search_paths() + { + std::vector paths{}; + + for (const auto& path : get_search_paths_internal()) + { + paths.push_back(path.generic_string()); + } + + return paths; + } + class component final : public component_interface { public: void post_unpack() override { - get_search_paths().insert("."); - get_search_paths().insert("h2-mod"); - get_search_paths().insert("data"); + utils::hook::call(0x14060B052, fs_startup_stub); } }; } diff --git a/src/client/component/filesystem.hpp b/src/client/component/filesystem.hpp index 3e9c5b02..d65af0d0 100644 --- a/src/client/component/filesystem.hpp +++ b/src/client/component/filesystem.hpp @@ -2,7 +2,11 @@ namespace filesystem { - std::unordered_set& get_search_paths(); std::string read_file(const std::string& path); bool read_file(const std::string& path, std::string* data, std::string* real_path = nullptr); + + void register_path(const std::filesystem::path& path); + void unregister_path(const std::filesystem::path& path); + + std::vector get_search_paths(); } \ No newline at end of file diff --git a/src/client/component/mods.cpp b/src/client/component/mods.cpp index f8bf4af2..a67f7c08 100644 --- a/src/client/component/mods.cpp +++ b/src/client/component/mods.cpp @@ -88,8 +88,8 @@ namespace mods } console::info("Loading mod %s\n", path); - filesystem::get_search_paths().erase(mod_path); - filesystem::get_search_paths().insert(path); + filesystem::unregister_path(mod_path); + filesystem::register_path(path); mod_path = path; restart(); }); @@ -110,7 +110,7 @@ namespace mods } console::info("Unloading mod %s\n", mod_path.data()); - filesystem::get_search_paths().erase(mod_path); + filesystem::unregister_path(mod_path); mod_path.clear(); restart(); }); diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index 958ec112..c0a7284f 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -155,6 +155,8 @@ namespace game WEAK symbol Sys_EnterCriticalSection{0x140624240}; WEAK symbol Sys_LeaveCriticalSection{0x1406242C0}; + WEAK symbol SEH_GetCurrentLanguageCode{0x1405E5180}; + WEAK symbol UI_SafeTranslateString{0x1405A2930}; WEAK symbol UI_PlayLocalSoundAlias{0x140606080};