basic fs_game loading
This commit is contained in:
parent
b311c04b18
commit
e90ef0fa0d
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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');
|
||||
});
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user