basic fs_game loading

This commit is contained in:
quaK 2024-07-14 02:04:41 +03:00
parent b311c04b18
commit e90ef0fa0d
5 changed files with 269 additions and 122 deletions

View File

@ -37,6 +37,7 @@ namespace fastfiles
utils::hook::detour db_load_x_zone_hook;
utils::hook::detour db_find_xasset_header_hook;
utils::hook::detour db_add_xasset_hook;
utils::hook::detour sys_createfile_hook;
void db_try_load_x_file_internal_stub(const char* zone_name, const unsigned int zone_flags,
const bool is_base_map, const bool was_paused, const int failure_mode)
@ -107,6 +108,63 @@ namespace fastfiles
auto result = db_add_xasset_hook.invoke<game::XAssetHeader>(type, header_ptr);
return result;
}
HANDLE sys_create_file_stub(game::Sys_Folder folder, const char* base_filename)
{
if (base_filename == "mod.ff"s)
{
auto* fs_basepath = game::Dvar_FindVar("fs_basepath");
auto* fs_game = game::Dvar_FindVar("fs_game");
std::string dir = fs_basepath ? fs_basepath->current.string : "";
std::string mod_dir = fs_game ? fs_game->current.string : "";
if (!mod_dir.empty())
{
const auto path = utils::string::va("%s\\%s\\%s", dir.data(), mod_dir.data(), base_filename);
if (utils::io::file_exists(path))
{
return CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, nullptr);
}
}
return INVALID_HANDLE_VALUE;
}
return sys_createfile_hook.invoke<HANDLE>(folder, base_filename);
}
template <typename T> inline void merge(std::vector<T>* target, T* source, size_t length)
{
if (source)
{
for (size_t i = 0; i < length; ++i)
{
target->push_back(source[i]);
}
}
}
template <typename T> inline void merge(std::vector<T>* target, std::vector<T> source)
{
for (auto& entry : source)
{
target->push_back(entry);
}
}
void load_fastfiles1_stub(game::XZoneInfo* zoneInfo, unsigned int zoneCount, game::DBSyncMode syncMode)
{
std::vector<game::XZoneInfo> data;
merge(&data, zoneInfo, zoneCount);
if (fastfiles::exists("mod"))
{
data.push_back({ "mod", game::DB_ZONE_GAME | game::DB_ZONE_CUSTOM, 0 });
}
game::DB_LoadXAssets(data.data(), static_cast<std::uint32_t>(data.size()), syncMode);
}
}
namespace zone_loading
@ -205,6 +263,12 @@ namespace fastfiles
// Skip signature validation
utils::hook::set(0x1409E6390, 0xC301B0);
// Add custom zone paths
sys_createfile_hook.create(game::Sys_CreateFile, sys_create_file_stub);
// Add custom zones in fastfiles load (level specific) (mod)
utils::hook::call(0x1403B9E9F, load_fastfiles1_stub);
command::add("loadzone", [](const command::params& params)
{
if (params.size() < 2)

View File

@ -19,75 +19,6 @@ namespace filesystem
utils::hook::detour fs_startup_hook;
utils::hook::detour fs_build_os_path_hook;
bool initialized = false;
std::deque<std::filesystem::path>& get_search_paths_internal()
{
static std::deque<std::filesystem::path> search_paths{};
return search_paths;
}
void fs_display_path()
{
console::info("Current language: %s\n", game::SEH_GetLanguageName(*reinterpret_cast<int*>(0x1474C6420)));
console::info("Current search paths:\n");
if (game::fs_searchpaths.get())
{
for (auto i = game::fs_searchpaths.get()->next; i; i = i->next)
{
console::info("%s/%s\n", i->dir->path, i->dir->gamedir);
}
}
for (auto path : filesystem::get_search_paths())
{
console::info("%s\n", path.data());
}
}
void fs_startup_stub(const char* name)
{
console::info("----- FS_Startup -----\n");
initialized = true;
filesystem::register_path(utils::properties::get_appdata_path() / "cdata"); // CLIENT_DATA_FOLDER
filesystem::register_path(L".");
filesystem::register_path(L"iw7-mod");
filesystem::register_path(L"devraw_shared");
filesystem::register_path(L"devraw");
filesystem::register_path(L"raw_shared");
filesystem::register_path(L"raw");
filesystem::register_path(L"main_shared");
filesystem::register_path(L"main");
fs_startup_hook.invoke<void>(name);
fs_display_path();
console::info("----------------------\n");
}
std::vector<std::filesystem::path> get_paths(const std::filesystem::path& path)
{
std::vector<std::filesystem::path> paths{};
paths.push_back(path);
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();
@ -107,14 +38,71 @@ namespace filesystem
}
}
namespace
{
bool initialized = false;
std::deque<std::filesystem::path>& get_search_paths_internal()
{
static std::deque<std::filesystem::path> search_paths{};
return search_paths;
}
void fs_display_path()
{
console::info("Current language: %s\n", game::SEH_GetLanguageName(*reinterpret_cast<int*>(0x1474C6420)));
console::info("Current search paths:\n");
for (auto& path : filesystem::get_search_paths())
{
console::info("%s\n", path.data());
}
}
void fs_startup_stub(const char* name)
{
console::info("----- FS_Startup -----\n");
initialized = true;
filesystem::register_path(utils::properties::get_appdata_path() / "cdata"); // CLIENT_DATA_FOLDER
filesystem::register_path(sys_default_install_path_stub() + "/"s + "iw7-mod"s);
fs_startup_hook.invoke<void>(name);
fs_display_path();
console::info("----------------------\n");
}
std::vector<std::filesystem::path> get_paths(const std::filesystem::path& path)
{
std::vector<std::filesystem::path> paths{};
paths.push_back(path);
return paths;
}
bool can_insert_path(const std::filesystem::path& path)
{
for (const auto& path_ : get_search_paths())
{
if (path_ == path)
{
return false;
}
}
return true;
}
}
std::string read_file(const std::string& path)
{
for (const auto& search_path : get_search_paths_internal())
for (const auto& search_path : get_search_paths())
{
const auto path_ = search_path / path;
if (utils::io::file_exists(path_.generic_string()))
const auto path_ = search_path + "/" + path;
if (utils::io::file_exists(path_))
{
return utils::io::read_file(path_.generic_string());
return utils::io::read_file(path_);
}
}
@ -123,14 +111,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_internal())
for (const auto& search_path : get_search_paths())
{
const auto path_ = search_path / path;
if (utils::io::read_file(path_.generic_string(), data))
const auto path_ = search_path + "/" + path;
if (utils::io::read_file(path_, data))
{
if (real_path != nullptr)
{
*real_path = path_.generic_string();
*real_path = path_;
}
return true;
@ -142,12 +130,12 @@ namespace filesystem
bool find_file(const std::string& path, std::string* real_path)
{
for (const auto& search_path : get_search_paths_internal())
for (const auto& search_path : get_search_paths())
{
const auto path_ = search_path / path;
if (utils::io::file_exists(path_.generic_string()))
const auto path_ = search_path + "/" + path;
if (utils::io::file_exists(path_))
{
*real_path = path_.generic_string();
*real_path = path_;
return true;
}
}
@ -157,10 +145,10 @@ namespace filesystem
bool exists(const std::string& path)
{
for (const auto& search_path : get_search_paths_internal())
for (const auto& search_path : get_search_paths())
{
const auto path_ = search_path / path;
if (utils::io::file_exists(path_.generic_string()))
const auto path_ = search_path + "/" + path;
if (utils::io::file_exists(path_))
{
return true;
}
@ -222,17 +210,27 @@ namespace filesystem
paths.push_back(path.generic_string());
}
if (game::fs_searchpaths.get())
{
for (auto i = game::fs_searchpaths.get()->next; i; i = i->next)
{
paths.push_back(utils::string::va("%s/%s", i->dir->path, i->dir->gamedir));
}
}
std::sort(paths.begin(), paths.end());
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)
auto paths_oridinal = get_search_paths();
for (auto i = paths_oridinal.rbegin(); i != paths_oridinal.rend(); ++i)
{
paths.push_back(i->generic_string());
paths.push_back(*i);
}
return paths;

View File

@ -312,8 +312,7 @@ namespace gsc
{
for (const auto& path : filesystem::get_search_paths())
{
load_scripts(path, "scripts/"); // meant to override stock GSC
load_scripts(path, "custom_scripts/"); // for no issues, use custom_scripts/
load_scripts(path, "custom_scripts/");
load_scripts(path, "custom_scripts/"s + game::Com_GameMode_GetActiveGameModeStr() + "/");
if (game::Com_GameMode_GetActiveGameMode() == game::GAME_MODE_CP || game::Com_GameMode_GetActiveGameMode() == game::GAME_MODE_MP)

View File

@ -23,33 +23,127 @@ namespace party
{
namespace
{
connection_state server_connection_state{};
std::optional<discord_information> server_discord_info{};
/*
struct usermap_file
/*struct moddl_file
{
std::string extension;
std::string name;
bool optional;
};
// snake case these names before release
std::vector<usermap_file> usermap_files =
{
{".ff", "usermap_hash", false},
{"_load.ff", "usermap_load_hash", true},
{".arena", "usermap_arena_hash", true},
{".pak", "usermap_pak_hash", true},
};
std::vector<usermap_file> mod_files =
std::vector<moddl_file> mod_files =
{
{".ff", "mod_hash", false},
{"_pre_gfx.ff", "mod_pre_gfx_hash", true},
{".pak", "mod_pak_hash", true},
};
*/
std::unordered_map<std::string, std::string> hash_cache;
std::string get_file_hash(const std::string& file)
{
const auto iter = hash_cache.find(file);
if (iter != hash_cache.end())
{
return iter->second;
}
const auto hash = utils::hash::get_file_hash(file);
if (!hash.empty())
{
hash_cache.insert(std::make_pair(file, hash));
}
return hash;
}
// generate hashes so they are cached
void generate_hashes(const std::string& mapname)
{
// mod
const auto fs_game = get_dvar_string("fs_game");
if (!fs_game.empty())
{
for (const auto& file : mod_files)
{
const auto path = std::format("{}\\mod{}", fs_game, file.extension);
get_file_hash(path);
}
}
}
bool check_download_mod(const utils::info_string& info, std::vector<download::file_t>& files)
{
static const auto fs_game = game::Dvar_FindVar("fs_game");
const auto client_fs_game = utils::string::to_lower(fs_game->current.string);
const auto server_fs_game = utils::string::to_lower(info.get("fs_game"));
if (server_fs_game.empty() && client_fs_game.empty())
{
return false;
}
if (server_fs_game.empty() && !client_fs_game.empty())
{
mods::set_mod("");
return true;
}
if (!server_fs_game.starts_with("mods/") || server_fs_game.contains('.') || server_fs_game.contains("::"))
{
throw std::runtime_error(utils::string::va("Invalid server fs_game value '%s'", server_fs_game.data()));
}
auto needs_restart = false;
for (const auto& file : mod_files)
{
const auto source_hash = info.get(file.name);
if (source_hash.empty())
{
if (file.optional)
{
continue;
}
throw std::runtime_error(
utils::string::va("Server '%s' is empty", file.name.data()));
}
const auto file_path = server_fs_game + "/mod" + file.extension;
auto has_to_download = !utils::io::file_exists(file_path);
if (!has_to_download)
{
const auto hash = get_file_hash(file_path);
console::debug("has_to_download = %s != %s\n", source_hash.data(), hash.data());
has_to_download = source_hash != hash;
}
if (has_to_download)
{
// unload mod before downloading it
if (client_fs_game == server_fs_game)
{
mods::set_mod("", true);
return true;
}
else
{
files.emplace_back(file_path, source_hash);
}
}
else if (client_fs_game != server_fs_game)
{
mods::set_mod(server_fs_game);
needs_restart = true;
}
}
return needs_restart;
}*/
}
namespace
{
connection_state server_connection_state{};
std::optional<discord_information> server_discord_info{};
bool preloaded_map = false;
@ -635,18 +729,7 @@ namespace party
info.set("sv_discordImageUrl", get_dvar_string("sv_discordImageUrl"));
info.set("sv_discordImageText", get_dvar_string("sv_discordImageText"));
/*
if (!fastfiles::is_stock_map(mapname))
{
for (const auto& file : usermap_files)
{
const auto path = get_usermap_file_path(mapname, file.extension);
const auto hash = get_file_hash(path);
info.set(file.name, hash);
}
}
const auto fs_game = get_dvar_string("fs_game");
/*const auto fs_game = get_dvar_string("fs_game");
info.set("fs_game", fs_game);
if (!fs_game.empty())
@ -657,8 +740,7 @@ namespace party
fs_game.data(), file.extension.data()));
info.set(file.name, hash);
}
}
*/
}*/
network::send(target, "infoResponse", info.build(), '\n');
});

View File

@ -11909,7 +11909,11 @@ namespace database
enum DBAllocFlags : std::int32_t
{
DB_ZONE_NONE = 0x0,
DB_ZONE_PERMAMENT = 0x1,
DB_ZONE_PERMANENT = 0x1,
DB_ZONE_GLOBAL_TIER1 = 0x2,
DB_ZONE_GLOBAL_TIER2 = 0x4,
DB_ZONE_GAMEMODE_TIER1 = 0x8,
DB_ZONE_GAMEMODE_TIER2 = 0x10,
DB_ZONE_UI = 0x20,
DB_ZONE_UI_SCENE = 0x40,
DB_ZONE_GAME = 0x80,