2022-03-03 07:56:46 -05:00
|
|
|
#include <std_include.hpp>
|
|
|
|
#include "loader/component_loader.hpp"
|
2022-09-03 01:23:04 -04:00
|
|
|
|
2022-09-09 21:38:04 -04:00
|
|
|
#include "command.hpp"
|
2022-09-03 01:23:04 -04:00
|
|
|
#include "console.hpp"
|
2022-03-03 07:56:46 -05:00
|
|
|
#include "filesystem.hpp"
|
2022-09-03 01:23:04 -04:00
|
|
|
#include "localized_strings.hpp"
|
2022-09-03 07:00:31 -04:00
|
|
|
#include "updater.hpp"
|
2022-03-03 07:56:46 -05:00
|
|
|
|
|
|
|
#include "game/game.hpp"
|
|
|
|
|
2022-04-08 10:18:00 -04:00
|
|
|
#include <utils/io.hpp>
|
2022-09-03 01:23:04 -04:00
|
|
|
#include <utils/flags.hpp>
|
2022-09-03 07:00:31 -04:00
|
|
|
#include <utils/hook.hpp>
|
|
|
|
#include <utils/properties.hpp>
|
2022-03-03 07:56:46 -05:00
|
|
|
|
2022-12-11 23:30:58 -05:00
|
|
|
#define LANGUAGE_FILE "players2/default/language"
|
|
|
|
|
2022-03-03 07:56:46 -05:00
|
|
|
namespace filesystem
|
|
|
|
{
|
2022-09-03 01:23:04 -04:00
|
|
|
namespace
|
2022-03-03 07:56:46 -05:00
|
|
|
{
|
2022-09-03 05:50:08 -04:00
|
|
|
utils::hook::detour fs_startup_hook;
|
|
|
|
|
2022-09-03 01:23:04 -04:00
|
|
|
bool initialized = false;
|
|
|
|
|
|
|
|
std::deque<std::filesystem::path>& get_search_paths_internal()
|
|
|
|
{
|
|
|
|
static std::deque<std::filesystem::path> search_paths{};
|
|
|
|
return search_paths;
|
|
|
|
}
|
2022-03-03 07:56:46 -05:00
|
|
|
|
2022-09-03 01:23:04 -04:00
|
|
|
bool is_fallback_lang()
|
2022-03-03 07:56:46 -05:00
|
|
|
{
|
2022-09-03 01:23:04 -04:00
|
|
|
static const auto* loc_language = game::Dvar_FindVar("loc_language");
|
|
|
|
const auto id = loc_language->current.integer;
|
2022-09-25 11:12:58 -04:00
|
|
|
return id == 5 || id == 6 || id == 8 || id == 9 || id == 10 || id == 11 || id == 13 || id == 15;
|
2022-09-03 01:23:04 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void fs_startup_stub(const char* name)
|
|
|
|
{
|
2022-09-03 05:50:08 -04:00
|
|
|
console::debug("[FS] Startup\n");
|
2022-09-03 01:23:04 -04:00
|
|
|
|
|
|
|
initialized = true;
|
|
|
|
|
2022-09-03 05:50:08 -04:00
|
|
|
// hardcoded paths
|
2022-09-03 07:00:31 -04:00
|
|
|
filesystem::register_path(utils::properties::get_appdata_path() / CLIENT_DATA_FOLDER);
|
2022-09-03 01:23:04 -04:00
|
|
|
filesystem::register_path(L".");
|
|
|
|
filesystem::register_path(L"h1-mod");
|
|
|
|
|
2022-09-03 05:50:08 -04:00
|
|
|
fs_startup_hook.invoke<void>(name);
|
2022-09-09 21:38:04 -04:00
|
|
|
|
|
|
|
command::register_fs_game_path();
|
2022-09-03 01:23:04 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<std::filesystem::path> get_paths(const std::filesystem::path& path)
|
|
|
|
{
|
|
|
|
std::vector<std::filesystem::path> paths{};
|
|
|
|
|
|
|
|
const auto code = game::SEH_GetCurrentLanguageName();
|
|
|
|
|
2022-12-11 23:30:58 -05:00
|
|
|
if (!::utils::io::file_exists(LANGUAGE_FILE) or ::utils::io::file_size(LANGUAGE_FILE) == 0)
|
|
|
|
{
|
|
|
|
::utils::io::write_file(LANGUAGE_FILE, code);
|
|
|
|
}
|
|
|
|
|
2022-09-03 01:23:04 -04:00
|
|
|
paths.push_back(path);
|
|
|
|
|
|
|
|
if (is_fallback_lang())
|
|
|
|
{
|
|
|
|
paths.push_back(path / "fallback");
|
|
|
|
}
|
|
|
|
|
|
|
|
paths.push_back(path / code);
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* sys_default_install_path_stub()
|
|
|
|
{
|
|
|
|
static auto current_path = std::filesystem::current_path().string();
|
|
|
|
return current_path.data();
|
2022-03-03 07:56:46 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-03 01:23:04 -04:00
|
|
|
std::string read_file(const std::string& path)
|
2022-03-03 07:56:46 -05:00
|
|
|
{
|
2022-09-03 01:23:04 -04:00
|
|
|
for (const auto& search_path : get_search_paths_internal())
|
|
|
|
{
|
|
|
|
const auto path_ = search_path / path;
|
|
|
|
if (utils::io::file_exists(path_.generic_string()))
|
|
|
|
{
|
|
|
|
return utils::io::read_file(path_.generic_string());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return {};
|
2022-03-03 07:56:46 -05:00
|
|
|
}
|
|
|
|
|
2022-09-03 01:23:04 -04:00
|
|
|
bool read_file(const std::string& path, std::string* data, std::string* real_path)
|
2022-03-03 07:56:46 -05:00
|
|
|
{
|
2022-09-03 01:23:04 -04:00
|
|
|
for (const auto& search_path : get_search_paths_internal())
|
|
|
|
{
|
|
|
|
const auto path_ = search_path / path;
|
|
|
|
if (utils::io::read_file(path_.generic_string(), data))
|
|
|
|
{
|
|
|
|
if (real_path != nullptr)
|
|
|
|
{
|
|
|
|
*real_path = path_.generic_string();
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2022-03-03 07:56:46 -05:00
|
|
|
}
|
|
|
|
|
2022-09-03 01:23:04 -04:00
|
|
|
bool find_file(const std::string& path, std::string* real_path)
|
2022-03-03 07:56:46 -05:00
|
|
|
{
|
2022-09-03 01:23:04 -04:00
|
|
|
for (const auto& search_path : get_search_paths_internal())
|
|
|
|
{
|
|
|
|
const auto path_ = search_path / path;
|
|
|
|
if (utils::io::file_exists(path_.generic_string()))
|
|
|
|
{
|
|
|
|
*real_path = path_.generic_string();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2022-03-03 07:56:46 -05:00
|
|
|
}
|
|
|
|
|
2022-09-03 01:23:04 -04:00
|
|
|
bool exists(const std::string& path)
|
2022-04-08 10:18:00 -04:00
|
|
|
{
|
2022-09-03 01:23:04 -04:00
|
|
|
for (const auto& search_path : get_search_paths_internal())
|
|
|
|
{
|
|
|
|
const auto path_ = search_path / path;
|
|
|
|
if (utils::io::file_exists(path_.generic_string()))
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2022-04-08 10:18:00 -04:00
|
|
|
}
|
|
|
|
|
2022-09-03 01:23:04 -04:00
|
|
|
void register_path(const std::filesystem::path& path)
|
2022-04-08 10:18:00 -04:00
|
|
|
{
|
2022-09-03 01:23:04 -04:00
|
|
|
if (!initialized)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto paths = get_paths(path);
|
|
|
|
for (const auto& path_ : paths)
|
2022-04-08 10:18:00 -04:00
|
|
|
{
|
2022-09-03 01:23:04 -04:00
|
|
|
if (can_insert_path(path_))
|
2022-04-08 10:18:00 -04:00
|
|
|
{
|
2022-09-03 05:50:08 -04:00
|
|
|
console::debug("[FS] Registering path '%s'\n", path_.generic_string().data());
|
2022-09-03 01:23:04 -04:00
|
|
|
get_search_paths_internal().push_front(path_);
|
2022-04-08 10:18:00 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-03 01:23:04 -04:00
|
|
|
void unregister_path(const std::filesystem::path& path)
|
2022-04-08 10:18:00 -04:00
|
|
|
{
|
2022-09-03 01:23:04 -04:00
|
|
|
if (!initialized)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto paths = get_paths(path);
|
|
|
|
for (const auto& path_ : paths)
|
2022-04-08 10:18:00 -04:00
|
|
|
{
|
2022-09-03 01:23:04 -04:00
|
|
|
auto& search_paths = get_search_paths_internal();
|
|
|
|
for (auto i = search_paths.begin(); i != search_paths.end();)
|
2022-04-08 10:18:00 -04:00
|
|
|
{
|
2022-09-03 01:23:04 -04:00
|
|
|
if (*i == path_)
|
|
|
|
{
|
2022-09-03 05:50:08 -04:00
|
|
|
console::debug("[FS] Unregistering path '%s'\n", path_.generic_string().data());
|
2022-09-03 01:23:04 -04:00
|
|
|
i = search_paths.erase(i);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
++i;
|
|
|
|
}
|
2022-04-08 10:18:00 -04:00
|
|
|
}
|
|
|
|
}
|
2022-09-03 01:23:04 -04:00
|
|
|
}
|
2022-04-08 10:18:00 -04:00
|
|
|
|
2022-09-03 01:23:04 -04:00
|
|
|
std::vector<std::string> get_search_paths()
|
|
|
|
{
|
|
|
|
std::vector<std::string> paths{};
|
|
|
|
|
|
|
|
for (const auto& path : get_search_paths_internal())
|
|
|
|
{
|
|
|
|
paths.push_back(path.generic_string());
|
|
|
|
}
|
|
|
|
|
|
|
|
return paths;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<std::string> get_search_paths_rev()
|
|
|
|
{
|
|
|
|
std::vector<std::string> paths{};
|
|
|
|
const auto& search_paths = get_search_paths_internal();
|
|
|
|
|
|
|
|
for (auto i = search_paths.rbegin(); i != search_paths.rend(); ++i)
|
|
|
|
{
|
|
|
|
paths.push_back(i->generic_string());
|
|
|
|
}
|
|
|
|
|
|
|
|
return paths;
|
2022-04-08 10:18:00 -04:00
|
|
|
}
|
|
|
|
|
2022-03-03 07:56:46 -05:00
|
|
|
class component final : public component_interface
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
void post_unpack() override
|
|
|
|
{
|
2022-09-03 05:50:08 -04:00
|
|
|
fs_startup_hook.create(SELECT_VALUE(0x40D890_b, 0x189A40_b), fs_startup_stub);
|
|
|
|
|
2022-09-03 01:23:04 -04:00
|
|
|
utils::hook::jump(SELECT_VALUE(0x42CE00_b, 0x5B3440_b), sys_default_install_path_stub);
|
2022-08-16 18:23:36 -04:00
|
|
|
|
|
|
|
// fs_game flags
|
2022-08-20 09:27:41 -04:00
|
|
|
utils::hook::set<uint32_t>(SELECT_VALUE(0x40D2A5_b, 0x189275_b), 0);
|
2022-03-03 07:56:46 -05:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-09-03 01:23:04 -04:00
|
|
|
REGISTER_COMPONENT(filesystem::component)
|