basic custom fastfile support
This commit is contained in:
parent
4dd9eb2419
commit
664a6b644a
@ -2,18 +2,43 @@
|
|||||||
#include "loader/component_loader.hpp"
|
#include "loader/component_loader.hpp"
|
||||||
#include "game/dvars.hpp"
|
#include "game/dvars.hpp"
|
||||||
|
|
||||||
#include "fastfiles.hpp"
|
|
||||||
#include "command.hpp"
|
#include "command.hpp"
|
||||||
#include "console.hpp"
|
#include "console.hpp"
|
||||||
|
#include "fastfiles.hpp"
|
||||||
|
|
||||||
|
#include <utils/concurrency.hpp>
|
||||||
#include <utils/hook.hpp>
|
#include <utils/hook.hpp>
|
||||||
#include <utils/io.hpp>
|
#include <utils/io.hpp>
|
||||||
#include <utils/concurrency.hpp>
|
#include <utils/string.hpp>
|
||||||
|
|
||||||
namespace fastfiles
|
namespace fastfiles
|
||||||
{
|
{
|
||||||
static utils::concurrency::container<std::string> current_fastfile;
|
static utils::concurrency::container<std::string> current_fastfile;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
utils::hook::detour db_try_load_x_file_internal_hook;
|
utils::hook::detour db_try_load_x_file_internal_hook;
|
||||||
@ -21,11 +46,21 @@ namespace fastfiles
|
|||||||
|
|
||||||
void db_try_load_x_file_internal(const char* zone_name, const int flags)
|
void db_try_load_x_file_internal(const char* zone_name, const int flags)
|
||||||
{
|
{
|
||||||
|
static std::unordered_map<std::string, std::string> zone_overrides = {};
|
||||||
|
|
||||||
|
auto override_zone_name = zone_overrides.find(zone_name);
|
||||||
|
if (override_zone_name != zone_overrides.end())
|
||||||
|
{
|
||||||
|
console::info("Overriding fastfile %s with %s\n", zone_name, override_zone_name->second.c_str());
|
||||||
|
zone_name = override_zone_name->second.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
console::info("Loading fastfile %s\n", zone_name);
|
console::info("Loading fastfile %s\n", zone_name);
|
||||||
current_fastfile.access([&](std::string& fastfile)
|
current_fastfile.access([&](std::string& fastfile)
|
||||||
{
|
{
|
||||||
fastfile = zone_name;
|
fastfile = zone_name;
|
||||||
});
|
});
|
||||||
|
|
||||||
return db_try_load_x_file_internal_hook.invoke<void>(zone_name, flags);
|
return db_try_load_x_file_internal_hook.invoke<void>(zone_name, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,10 +91,12 @@ namespace fastfiles
|
|||||||
const auto result = db_find_x_asset_header_hook.invoke<game::XAssetHeader>(type, name, allow_create_default);
|
const auto result = db_find_x_asset_header_hook.invoke<game::XAssetHeader>(type, name, allow_create_default);
|
||||||
const auto diff = game::Sys_Milliseconds() - start;
|
const auto diff = game::Sys_Milliseconds() - start;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
if (type == game::ASSET_TYPE_SCRIPTFILE)
|
if (type == game::ASSET_TYPE_SCRIPTFILE)
|
||||||
{
|
{
|
||||||
dump_gsc_script(name, result);
|
dump_gsc_script(name, result);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (diff > 100)
|
if (diff > 100)
|
||||||
{
|
{
|
||||||
@ -73,6 +110,223 @@ namespace fastfiles
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
utils::hook::detour db_link_xasset_entry1_hook;
|
||||||
|
game::XAssetEntry* db_link_xasset_entry1(game::XAssetType type, game::XAssetHeader* header)
|
||||||
|
{
|
||||||
|
if (type == game::ASSET_TYPE_SCRIPTFILE)
|
||||||
|
{
|
||||||
|
dump_gsc_script(header->scriptfile->name, *header);
|
||||||
|
}
|
||||||
|
|
||||||
|
return db_link_xasset_entry1_hook.invoke<game::XAssetEntry*>(type, header);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace mp
|
||||||
|
{
|
||||||
|
void skip_extra_zones_stub(utils::hook::assembler& a)
|
||||||
|
{
|
||||||
|
const auto skip = a.newLabel();
|
||||||
|
const auto original = a.newLabel();
|
||||||
|
|
||||||
|
a.pushad64();
|
||||||
|
a.test(esi, game::DB_ZONE_CUSTOM); // allocFlags
|
||||||
|
a.jnz(skip);
|
||||||
|
|
||||||
|
a.bind(original);
|
||||||
|
a.popad64();
|
||||||
|
a.mov(rdx, 0x140809D40);
|
||||||
|
a.mov(rcx, rbp);
|
||||||
|
a.call(0x1406FE120);
|
||||||
|
a.jmp(0x140271B63);
|
||||||
|
|
||||||
|
a.bind(skip);
|
||||||
|
a.popad64();
|
||||||
|
a.mov(r13d, game::DB_ZONE_CUSTOM);
|
||||||
|
a.not_(r13d);
|
||||||
|
a.and_(esi, r13d);
|
||||||
|
a.jmp(0x140271D02);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace sp
|
||||||
|
{
|
||||||
|
void skip_extra_zones_stub(utils::hook::assembler& a)
|
||||||
|
{
|
||||||
|
const auto skip = a.newLabel();
|
||||||
|
const auto original = a.newLabel();
|
||||||
|
|
||||||
|
a.pushad64();
|
||||||
|
a.test(edi, game::DB_ZONE_CUSTOM); // allocFlags
|
||||||
|
a.jnz(skip);
|
||||||
|
|
||||||
|
a.bind(original);
|
||||||
|
a.popad64();
|
||||||
|
a.call(0x140379360);
|
||||||
|
a.xor_(ecx, ecx);
|
||||||
|
a.test(eax, eax);
|
||||||
|
a.setz(cl);
|
||||||
|
a.jmp(0x1401802D6);
|
||||||
|
|
||||||
|
a.bind(skip);
|
||||||
|
a.popad64();
|
||||||
|
a.mov(r13d, game::DB_ZONE_CUSTOM);
|
||||||
|
a.not_(r13d);
|
||||||
|
a.and_(edi, r13d);
|
||||||
|
a.jmp(0x1401803EF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::hook::detour db_read_stream_file_hook;
|
||||||
|
void db_read_stream_file_stub(int a1, int a2)
|
||||||
|
{
|
||||||
|
// always use lz4 compressor type when reading stream files
|
||||||
|
*game::g_compressor = 4;
|
||||||
|
return db_read_stream_file_hook.invoke<void>(a1, a2);
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::hook::detour sys_createfile_hook;
|
||||||
|
HANDLE sys_create_file(game::Sys_Folder folder, const char* base_filename)
|
||||||
|
{
|
||||||
|
const auto* fs_basepath = game::Dvar_FindVar("fs_basepath");
|
||||||
|
const auto* fs_game = game::Dvar_FindVar("fs_game");
|
||||||
|
|
||||||
|
const std::string dir = fs_basepath ? fs_basepath->current.string : "";
|
||||||
|
const std::string mod_dir = fs_game ? fs_game->current.string : "";
|
||||||
|
const std::string name = base_filename;
|
||||||
|
|
||||||
|
if (name == "mod.ff")
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLE sys_create_file_stub(game::Sys_Folder folder, const char* base_filename)
|
||||||
|
{
|
||||||
|
return sys_create_file(folder, base_filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool try_load_zone(std::string name, bool localized, bool game = false)
|
||||||
|
{
|
||||||
|
if (localized)
|
||||||
|
{
|
||||||
|
const auto language = game::SEH_GetCurrentLanguageCode();
|
||||||
|
try_load_zone(language + "_"s + name, false);
|
||||||
|
if (game::environment::is_mp())
|
||||||
|
{
|
||||||
|
try_load_zone(language + "_"s + name + "_mp"s, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fastfiles::exists(name))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
game::XZoneInfo info{};
|
||||||
|
info.name = name.data();
|
||||||
|
info.allocFlags = (game ? game::DB_ZONE_GAME : game::DB_ZONE_COMMON) | game::DB_ZONE_CUSTOM;
|
||||||
|
info.freeFlags = 0;
|
||||||
|
game::DB_LoadXAssets(&info, 1u, game::DBSyncMode::DB_LOAD_ASYNC);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void load_pre_gfx_zones(game::XZoneInfo* zoneInfo, unsigned int zoneCount, game::DBSyncMode syncMode)
|
||||||
|
{
|
||||||
|
//imagefiles::close_custom_handles();
|
||||||
|
|
||||||
|
std::vector<game::XZoneInfo> data;
|
||||||
|
merge(&data, zoneInfo, zoneCount);
|
||||||
|
|
||||||
|
// code_pre_gfx
|
||||||
|
|
||||||
|
//weapon::clear_modifed_enums();
|
||||||
|
try_load_zone("mod_pre_gfx", true);
|
||||||
|
try_load_zone("s1_mod_pre_gfx", true);
|
||||||
|
|
||||||
|
game::DB_LoadXAssets(data.data(), static_cast<std::uint32_t>(data.size()), syncMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void load_post_gfx_and_ui_and_common_zones(game::XZoneInfo* zoneInfo, unsigned int zoneCount, game::DBSyncMode syncMode)
|
||||||
|
{
|
||||||
|
std::vector<game::XZoneInfo> data;
|
||||||
|
merge(&data, zoneInfo, zoneCount);
|
||||||
|
|
||||||
|
// code_post_gfx
|
||||||
|
// ui
|
||||||
|
// common
|
||||||
|
|
||||||
|
try_load_zone("s1_mod_common", true);
|
||||||
|
|
||||||
|
game::DB_LoadXAssets(data.data(), static_cast<std::uint32_t>(data.size()), syncMode);
|
||||||
|
|
||||||
|
try_load_zone("mod_common", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void load_ui_zones(game::XZoneInfo* zoneInfo, unsigned int zoneCount, game::DBSyncMode syncMode)
|
||||||
|
{
|
||||||
|
std::vector<game::XZoneInfo> data;
|
||||||
|
merge(&data, zoneInfo, zoneCount);
|
||||||
|
|
||||||
|
// ui
|
||||||
|
|
||||||
|
game::DB_LoadXAssets(data.data(), static_cast<std::uint32_t>(data.size()), syncMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void load_lua_file_asset_stub(void* a1)
|
||||||
|
{
|
||||||
|
const auto fastfile = fastfiles::get_current_fastfile();
|
||||||
|
if (fastfile == "mod")
|
||||||
|
{
|
||||||
|
console::error("Mod tried to load a lua file!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: add usermap LUI loading checks
|
||||||
|
/*
|
||||||
|
const auto usermap = fastfiles::get_current_usermap();
|
||||||
|
if (usermap.has_value())
|
||||||
|
{
|
||||||
|
const auto& usermap_value = usermap.value();
|
||||||
|
const auto usermap_load = usermap_value + "_load";
|
||||||
|
|
||||||
|
if (fastfile == usermap_value || fastfile == usermap_load)
|
||||||
|
{
|
||||||
|
console::error("Usermap tried to load a lua file!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
utils::hook::invoke<void>(0x140276480, a1);
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::hook::detour db_level_load_add_zone_hook;
|
||||||
|
void db_level_load_add_zone_stub(void* load, const char* name, const unsigned int alloc_flags,
|
||||||
|
const size_t size_est)
|
||||||
|
{
|
||||||
|
if (!strcmp(name, "mp_terminal_cls"))
|
||||||
|
{
|
||||||
|
db_level_load_add_zone_hook.invoke<void>(load, name, alloc_flags | game::DB_ZONE_CUSTOM, size_est);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
db_level_load_add_zone_hook.invoke<void>(load, name, alloc_flags, size_est);
|
||||||
|
; }
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string get_current_fastfile()
|
std::string get_current_fastfile()
|
||||||
@ -85,37 +339,35 @@ namespace fastfiles
|
|||||||
return fastfile_copy;
|
return fastfile_copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr int get_asset_type_size(const game::XAssetType type)
|
bool exists(const std::string& zone)
|
||||||
{
|
{
|
||||||
constexpr int asset_type_sizes[] =
|
const auto is_localized = game::DB_IsLocalized(zone.data());
|
||||||
{
|
const auto handle = sys_create_file((is_localized ? game::SF_ZONE_LOC : game::SF_ZONE),
|
||||||
96, 88, 128, 56, 40, 216, 56, 680,
|
utils::string::va("%s.ff", zone.data()));
|
||||||
480, 32, 32, 32, 32, 32, 352, 1456,
|
|
||||||
104, 32, 24, 152, 152, 152, 16, 64,
|
|
||||||
640, 40, 16, 408, 24, 288, 176, 2800,
|
|
||||||
48, -1, 40, 24, 200, 88, 16, 120,
|
|
||||||
3560, 32, 64, 16, 16, -1, -1, -1,
|
|
||||||
-1, 24, 40, 24, 40, 24, 128, 2256,
|
|
||||||
136, 32, 72, 24, 64, 88, 48, 32,
|
|
||||||
96, 152, 64, 32,
|
|
||||||
};
|
|
||||||
|
|
||||||
return asset_type_sizes[type];
|
if (handle != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
CloseHandle(handle);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <game::XAssetType Type, size_t Size>
|
return false;
|
||||||
char* reallocate_asset_pool()
|
}
|
||||||
{
|
|
||||||
constexpr auto element_size = get_asset_type_size(Type);
|
|
||||||
static char new_pool[element_size * Size] = {0};
|
|
||||||
assert(get_asset_type_size(Type) == game::DB_GetXAssetTypeSize(Type));
|
|
||||||
|
|
||||||
|
void reallocate_asset_pool(game::XAssetType Type, size_t Size)
|
||||||
|
{
|
||||||
|
const size_t element_size = game::DB_GetXAssetTypeSize(Type);
|
||||||
|
auto* new_pool = utils::memory::get_allocator()->allocate(Size * element_size);
|
||||||
std::memmove(new_pool, game::DB_XAssetPool[Type], game::g_poolSize[Type] * element_size);
|
std::memmove(new_pool, game::DB_XAssetPool[Type], game::g_poolSize[Type] * element_size);
|
||||||
|
|
||||||
game::DB_XAssetPool[Type] = new_pool;
|
game::DB_XAssetPool[Type] = new_pool;
|
||||||
game::g_poolSize[Type] = Size;
|
game::g_poolSize[Type] = static_cast<int>(Size);
|
||||||
|
}
|
||||||
|
|
||||||
return new_pool;
|
template <game::XAssetType Type, size_t Multiplier>
|
||||||
|
void reallocate_asset_pool_multiplier()
|
||||||
|
{
|
||||||
|
reallocate_asset_pool(Type, Multiplier * game::g_poolSize[Type]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void enum_assets(const game::XAssetType type, const std::function<void(game::XAssetHeader)>& callback, const bool include_override)
|
void enum_assets(const game::XAssetType type, const std::function<void(game::XAssetHeader)>& callback, const bool include_override)
|
||||||
@ -127,6 +379,75 @@ namespace fastfiles
|
|||||||
}), &callback, include_override);
|
}), &callback, include_override);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* get_zone_name(const unsigned int index)
|
||||||
|
{
|
||||||
|
if (game::environment::is_sp())
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return game::g_zones[index].name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void reallocate_asset_pools()
|
||||||
|
{
|
||||||
|
reallocate_asset_pool(game::ASSET_TYPE_FONT, 48);
|
||||||
|
|
||||||
|
if (!game::environment::is_sp())
|
||||||
|
{
|
||||||
|
reallocate_asset_pool_multiplier<game::ASSET_TYPE_LUA_FILE, 2>();
|
||||||
|
reallocate_asset_pool_multiplier<game::ASSET_TYPE_WEAPON, 2>();
|
||||||
|
reallocate_asset_pool_multiplier<game::ASSET_TYPE_LOCALIZE_ENTRY, 2>();
|
||||||
|
reallocate_asset_pool_multiplier<game::ASSET_TYPE_XANIMPARTS, 2>();
|
||||||
|
reallocate_asset_pool_multiplier<game::ASSET_TYPE_ATTACHMENT, 2>();
|
||||||
|
reallocate_asset_pool_multiplier<game::ASSET_TYPE_FONT, 2>();
|
||||||
|
reallocate_asset_pool_multiplier<game::ASSET_TYPE_SNDDRIVER_GLOBALS, 4>();
|
||||||
|
reallocate_asset_pool_multiplier<game::ASSET_TYPE_EQUIPMENT_SND_TABLE, 4>();
|
||||||
|
reallocate_asset_pool_multiplier<game::ASSET_TYPE_SOUND, 2>();
|
||||||
|
reallocate_asset_pool_multiplier<game::ASSET_TYPE_LOADED_SOUND, 2>();
|
||||||
|
reallocate_asset_pool_multiplier<game::ASSET_TYPE_LEADERBOARD, 2>();
|
||||||
|
reallocate_asset_pool_multiplier<game::ASSET_TYPE_VERTEXDECL, 6>();
|
||||||
|
reallocate_asset_pool_multiplier<game::ASSET_TYPE_COMPUTESHADER, 4>();
|
||||||
|
reallocate_asset_pool_multiplier<game::ASSET_TYPE_REVERB_PRESET, 2>();
|
||||||
|
reallocate_asset_pool_multiplier<game::ASSET_TYPE_IMPACT_FX, 10>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void enum_asset_entries(const game::XAssetType type, const std::function<void(game::XAssetEntry*)>& callback, bool include_override)
|
||||||
|
{
|
||||||
|
constexpr auto max_asset_count = 0x1D8A8;
|
||||||
|
auto hash = &game::db_hashTable[0];
|
||||||
|
for (auto c = 0; c < max_asset_count; c++)
|
||||||
|
{
|
||||||
|
for (auto i = *hash; i; )
|
||||||
|
{
|
||||||
|
const auto entry = &game::g_assetEntryPool[i];
|
||||||
|
|
||||||
|
if (entry->asset.type == type)
|
||||||
|
{
|
||||||
|
callback(entry);
|
||||||
|
|
||||||
|
if (include_override && entry->nextOverride)
|
||||||
|
{
|
||||||
|
auto next_ovveride = entry->nextOverride;
|
||||||
|
while (next_ovveride)
|
||||||
|
{
|
||||||
|
const auto override = &game::g_assetEntryPool[next_ovveride];
|
||||||
|
callback(override);
|
||||||
|
next_ovveride = override->nextOverride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i = entry->nextHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
++hash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class component final : public component_interface
|
class component final : public component_interface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -135,6 +456,7 @@ namespace fastfiles
|
|||||||
db_try_load_x_file_internal_hook.create(SELECT_VALUE(0x1401816F0, 0x1402741C0), &db_try_load_x_file_internal);
|
db_try_load_x_file_internal_hook.create(SELECT_VALUE(0x1401816F0, 0x1402741C0), &db_try_load_x_file_internal);
|
||||||
|
|
||||||
db_find_x_asset_header_hook.create(game::DB_FindXAssetHeader, db_find_x_asset_header_stub);
|
db_find_x_asset_header_hook.create(game::DB_FindXAssetHeader, db_find_x_asset_header_stub);
|
||||||
|
db_link_xasset_entry1_hook.create(SELECT_VALUE(0x14017F390, 0x1402708F0), db_link_xasset_entry1);
|
||||||
dvars::g_dump_scripts = game::Dvar_RegisterBool("g_dumpScripts", false, game::DVAR_FLAG_NONE);
|
dvars::g_dump_scripts = game::Dvar_RegisterBool("g_dumpScripts", false, game::DVAR_FLAG_NONE);
|
||||||
|
|
||||||
command::add("loadzone", [](const command::params& params)
|
command::add("loadzone", [](const command::params& params)
|
||||||
@ -147,7 +469,7 @@ namespace fastfiles
|
|||||||
|
|
||||||
game::XZoneInfo info{};
|
game::XZoneInfo info{};
|
||||||
info.name = params.get(1);
|
info.name = params.get(1);
|
||||||
info.allocFlags = 1;
|
info.allocFlags = game::DB_ZONE_COMMON | game::DB_ZONE_CUSTOM;
|
||||||
info.freeFlags = 0;
|
info.freeFlags = 0;
|
||||||
game::DB_LoadXAssets(&info, 1u, game::DBSyncMode::DB_LOAD_SYNC);
|
game::DB_LoadXAssets(&info, 1u, game::DBSyncMode::DB_LOAD_SYNC);
|
||||||
});
|
});
|
||||||
@ -160,16 +482,50 @@ namespace fastfiles
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
reallocate_asset_pool<game::ASSET_TYPE_FONT, 48>();
|
#ifdef DEBUG
|
||||||
|
//reallocate_asset_pools();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Allow loading of unsigned fastfiles
|
||||||
if (!game::environment::is_sp())
|
if (!game::environment::is_sp())
|
||||||
{
|
{
|
||||||
const auto* xmodel_pool = reallocate_asset_pool<game::ASSET_TYPE_XMODEL, 8832>();
|
utils::hook::nop(0x1402427A5, 2); // DB_InflateInit
|
||||||
utils::hook::inject(0x14026FD63, xmodel_pool + 8);
|
}
|
||||||
utils::hook::inject(0x14026FDB3, xmodel_pool + 8);
|
|
||||||
utils::hook::inject(0x14026FFAC, xmodel_pool + 8);
|
// Don't load extra zones with loadzone
|
||||||
utils::hook::inject(0x14027463C, xmodel_pool + 8);
|
if (game::environment::is_sp())
|
||||||
utils::hook::inject(0x140274689, xmodel_pool + 8);
|
{
|
||||||
|
utils::hook::nop(0x1401802CA, 12);
|
||||||
|
utils::hook::jump(0x1401802CA, utils::hook::assemble(sp::skip_extra_zones_stub), true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
utils::hook::nop(0x140271B54, 15);
|
||||||
|
utils::hook::jump(0x140271B54, utils::hook::assemble(mp::skip_extra_zones_stub), true);
|
||||||
|
|
||||||
|
// dont load localized zone for custom maps (proper patch for this is here: https://github.com/auroramod/h1-mod/blob/develop/src/client/component/fastfiles.cpp#L442)
|
||||||
|
db_level_load_add_zone_hook.create(0x1402705C0, db_level_load_add_zone_stub);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow loading of mixed compressor types
|
||||||
|
utils::hook::nop(SELECT_VALUE(0x1401536D7, 0x140242DF7), 2);
|
||||||
|
|
||||||
|
// Fix compressor type on streamed file load
|
||||||
|
db_read_stream_file_hook.create(SELECT_VALUE(0x140187450, 0x14027AA70), db_read_stream_file_stub);
|
||||||
|
|
||||||
|
// Add custom zone paths
|
||||||
|
sys_createfile_hook.create(game::Sys_CreateFile, sys_create_file_stub);
|
||||||
|
|
||||||
|
// load our custom ui and common zones
|
||||||
|
utils::hook::call(SELECT_VALUE(0x140487CF8, 0x1405A562A), load_post_gfx_and_ui_and_common_zones);
|
||||||
|
|
||||||
|
// load our custom ui zones
|
||||||
|
utils::hook::call(SELECT_VALUE(0x1402F91D4, 0x1403D06FC), load_ui_zones);
|
||||||
|
|
||||||
|
// prevent mod.ff from loading lua files
|
||||||
|
if (game::environment::is_mp())
|
||||||
|
{
|
||||||
|
utils::hook::call(0x14024F1B4, load_lua_file_asset_stub);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -6,5 +6,11 @@ namespace fastfiles
|
|||||||
{
|
{
|
||||||
std::string get_current_fastfile();
|
std::string get_current_fastfile();
|
||||||
|
|
||||||
|
bool exists(const std::string& zone);
|
||||||
|
|
||||||
void enum_assets(game::XAssetType type, const std::function<void(game::XAssetHeader)>& callback, bool include_override);
|
void enum_assets(game::XAssetType type, const std::function<void(game::XAssetHeader)>& callback, bool include_override);
|
||||||
|
|
||||||
|
const char* get_zone_name(const unsigned int index);
|
||||||
|
|
||||||
|
void enum_asset_entries(const game::XAssetType type, const std::function<void(game::XAssetEntry*)>& callback, bool include_override);
|
||||||
}
|
}
|
||||||
|
239
src/client/component/imagefiles.cpp
Normal file
239
src/client/component/imagefiles.cpp
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "loader/component_loader.hpp"
|
||||||
|
|
||||||
|
#include "console.hpp"
|
||||||
|
#include "filesystem.hpp"
|
||||||
|
#include "fastfiles.hpp"
|
||||||
|
#include "scheduler.hpp"
|
||||||
|
#include "imagefiles.hpp"
|
||||||
|
|
||||||
|
#include "game/game.hpp"
|
||||||
|
|
||||||
|
#include <utils/hook.hpp>
|
||||||
|
#include <utils/string.hpp>
|
||||||
|
#include <utils/io.hpp>
|
||||||
|
#include <utils/concurrency.hpp>
|
||||||
|
|
||||||
|
#define CUSTOM_IMAGE_FILE_INDEX 96
|
||||||
|
|
||||||
|
namespace imagefiles
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
utils::memory::allocator image_file_allocator;
|
||||||
|
std::unordered_map<std::string, HANDLE> image_file_handles;
|
||||||
|
|
||||||
|
std::string get_image_file_name()
|
||||||
|
{
|
||||||
|
return fastfiles::get_current_fastfile();
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace mp
|
||||||
|
{
|
||||||
|
struct image_file_unk
|
||||||
|
{
|
||||||
|
char __pad0[112]; // 120 in H1
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unordered_map<std::string, image_file_unk*> image_file_unk_map;
|
||||||
|
|
||||||
|
void* get_image_file_unk_mp(unsigned int index)
|
||||||
|
{
|
||||||
|
if (index != CUSTOM_IMAGE_FILE_INDEX)
|
||||||
|
{
|
||||||
|
return &reinterpret_cast<image_file_unk*>(
|
||||||
|
SELECT_VALUE(0x0, 0x143DC4E90))[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto name = get_image_file_name();
|
||||||
|
if (image_file_unk_map.find(name) == image_file_unk_map.end())
|
||||||
|
{
|
||||||
|
const auto unk = image_file_allocator.allocate<image_file_unk>();
|
||||||
|
image_file_unk_map[name] = unk;
|
||||||
|
return unk;
|
||||||
|
}
|
||||||
|
|
||||||
|
return image_file_unk_map[name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
namespace sp
|
||||||
|
{
|
||||||
|
struct image_file_unk
|
||||||
|
{
|
||||||
|
char __pad0[96];
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unordered_map<std::string, image_file_unk*> image_file_unk_map;
|
||||||
|
|
||||||
|
void* get_image_file_unk_mp(unsigned int index)
|
||||||
|
{
|
||||||
|
if (index != CUSTOM_IMAGE_FILE_INDEX)
|
||||||
|
{
|
||||||
|
return &reinterpret_cast<image_file_unk*>(
|
||||||
|
SELECT_VALUE(0x0, 0x143DC4E90))[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto name = get_image_file_name();
|
||||||
|
if (image_file_unk_map.find(name) == image_file_unk_map.end())
|
||||||
|
{
|
||||||
|
const auto unk = image_file_allocator.allocate<image_file_unk>();
|
||||||
|
image_file_unk_map[name] = unk;
|
||||||
|
return unk;
|
||||||
|
}
|
||||||
|
|
||||||
|
return image_file_unk_map[name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
HANDLE get_image_file_handle(unsigned int index)
|
||||||
|
{
|
||||||
|
if (index != CUSTOM_IMAGE_FILE_INDEX)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<HANDLE*>(
|
||||||
|
SELECT_VALUE(0x0, 0x143B74E80))[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto name = get_image_file_name();
|
||||||
|
return image_file_handles[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
void db_create_gfx_image_stream_stub(utils::hook::assembler& a)
|
||||||
|
{
|
||||||
|
const auto handle_is_open = a.newLabel();
|
||||||
|
|
||||||
|
a.movzx(eax, cx);
|
||||||
|
a.mov(esi, eax);
|
||||||
|
a.imul(rsi, 0x70);
|
||||||
|
a.add(rsi, r15);
|
||||||
|
|
||||||
|
a.push(rax);
|
||||||
|
a.push(rax);
|
||||||
|
a.pushad64();
|
||||||
|
a.mov(rcx, rax);
|
||||||
|
a.call_aligned(mp::get_image_file_unk_mp);
|
||||||
|
a.mov(qword_ptr(rsp, 0x80), rax);
|
||||||
|
a.popad64();
|
||||||
|
a.pop(rax);
|
||||||
|
a.mov(rsi, rax);
|
||||||
|
a.pop(rax);
|
||||||
|
|
||||||
|
a.push(rax);
|
||||||
|
a.push(rax);
|
||||||
|
a.pushad64();
|
||||||
|
a.mov(rcx, rax);
|
||||||
|
a.call_aligned(get_image_file_handle);
|
||||||
|
a.mov(qword_ptr(rsp, 0x80), rax);
|
||||||
|
a.popad64();
|
||||||
|
a.pop(rax);
|
||||||
|
a.mov(r12, rax);
|
||||||
|
a.pop(rax);
|
||||||
|
|
||||||
|
a.cmp(r12, r13);
|
||||||
|
a.jnz(handle_is_open);
|
||||||
|
a.jmp(SELECT_VALUE(0x0, 0x140279C8B));
|
||||||
|
|
||||||
|
a.bind(handle_is_open);
|
||||||
|
a.jmp(SELECT_VALUE(0x0, 0x140279CDB));
|
||||||
|
}
|
||||||
|
|
||||||
|
void* pakfile_open_stub(void* /*handles*/, unsigned int count, int is_imagefile,
|
||||||
|
unsigned int index, short is_localized)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
console::info("Opening %s%d.pak (localized:%d)\n", is_imagefile ? "imagefile" : "soundfile", index, is_localized);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (index != CUSTOM_IMAGE_FILE_INDEX)
|
||||||
|
{
|
||||||
|
return utils::hook::invoke<void*>(
|
||||||
|
SELECT_VALUE(0x0, 0x1404CC180),
|
||||||
|
SELECT_VALUE(0x0, 0x143B74E80),
|
||||||
|
count, is_imagefile, index, is_localized
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto name = get_image_file_name();
|
||||||
|
const auto handle = game::Sys_CreateFile(is_localized ? game::SF_PAKFILE_LOC : game::SF_PAKFILE, utils::string::va("%s.pak", name.data()));
|
||||||
|
if (handle != nullptr)
|
||||||
|
{
|
||||||
|
image_file_handles[name] = handle;
|
||||||
|
}
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
int com_sprintf_stub(char* buffer, const int len, const char* fmt, unsigned int index)
|
||||||
|
{
|
||||||
|
if (index != CUSTOM_IMAGE_FILE_INDEX)
|
||||||
|
{
|
||||||
|
return game::Com_sprintf(buffer, len, fmt, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto name = get_image_file_name();
|
||||||
|
return game::Com_sprintf(buffer, len, "%s.pak", name.data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void close_custom_handles()
|
||||||
|
{
|
||||||
|
for (const auto& handle : image_file_handles)
|
||||||
|
{
|
||||||
|
if (handle.second != nullptr)
|
||||||
|
{
|
||||||
|
utils::hook::invoke<void>(0x140608A20, handle.second); // Sys_CloseFile
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
image_file_handles.clear();
|
||||||
|
//sp::image_file_unk_map.clear();
|
||||||
|
mp::image_file_unk_map.clear();
|
||||||
|
image_file_allocator.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void close_handle(const std::string& fastfile)
|
||||||
|
{
|
||||||
|
if (!image_file_handles.contains(fastfile))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto handle = image_file_handles[fastfile];
|
||||||
|
if (handle != nullptr)
|
||||||
|
{
|
||||||
|
utils::hook::invoke<void>(0x140608A20, handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
image_file_handles.erase(fastfile);
|
||||||
|
if (game::environment::is_sp())
|
||||||
|
{
|
||||||
|
//image_file_allocator.free(sp::image_file_unk_map[fastfile]);
|
||||||
|
//sp::image_file_unk_map.erase(fastfile);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
image_file_allocator.free(mp::image_file_unk_map[fastfile]);
|
||||||
|
mp::image_file_unk_map.erase(fastfile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class component final : public component_interface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void post_unpack() override
|
||||||
|
{
|
||||||
|
if (!game::environment::is_mp())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::hook::jump(SELECT_VALUE(0x0, 0x140279C79),
|
||||||
|
utils::hook::assemble(db_create_gfx_image_stream_stub), true);
|
||||||
|
utils::hook::call(SELECT_VALUE(0x0, 0x140279CBD), pakfile_open_stub);
|
||||||
|
utils::hook::call(SELECT_VALUE(0x0, 0x140279C9F), com_sprintf_stub);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
REGISTER_COMPONENT(imagefiles::component)
|
7
src/client/component/imagefiles.hpp
Normal file
7
src/client/component/imagefiles.hpp
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace imagefiles
|
||||||
|
{
|
||||||
|
void close_custom_handles();
|
||||||
|
void close_handle(const std::string& fastfile);
|
||||||
|
}
|
113
src/client/component/weapon.cpp
Normal file
113
src/client/component/weapon.cpp
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "loader/component_loader.hpp"
|
||||||
|
|
||||||
|
#include "console.hpp"
|
||||||
|
#include "fastfiles.hpp"
|
||||||
|
|
||||||
|
#include "game/game.hpp"
|
||||||
|
#include "game/dvars.hpp"
|
||||||
|
|
||||||
|
#include <utils/hook.hpp>
|
||||||
|
#include <utils/memory.hpp>
|
||||||
|
|
||||||
|
namespace weapon
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
utils::hook::detour g_setup_level_weapon_def_hook;
|
||||||
|
void g_setup_level_weapon_def_stub()
|
||||||
|
{
|
||||||
|
// precache level weapons first
|
||||||
|
g_setup_level_weapon_def_hook.invoke<void>();
|
||||||
|
|
||||||
|
std::vector<game::WeaponDef*> weapons;
|
||||||
|
|
||||||
|
// find all weapons in asset pools
|
||||||
|
fastfiles::enum_assets(game::ASSET_TYPE_WEAPON, [&weapons](game::XAssetHeader header)
|
||||||
|
{
|
||||||
|
weapons.push_back(reinterpret_cast<game::WeaponDef*>(header.data));
|
||||||
|
}, false);
|
||||||
|
|
||||||
|
// sort weapons
|
||||||
|
std::sort(weapons.begin(), weapons.end(), [](game::WeaponDef* weapon1, game::WeaponDef* weapon2)
|
||||||
|
{
|
||||||
|
return std::string_view(weapon1->name) <
|
||||||
|
std::string_view(weapon2->name);
|
||||||
|
});
|
||||||
|
|
||||||
|
// precache items
|
||||||
|
for (std::size_t i = 0; i < weapons.size(); i++)
|
||||||
|
{
|
||||||
|
//console::info("precaching weapon \"%s\"\n", weapons[i]->name);
|
||||||
|
game::G_GetWeaponForName(weapons[i]->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::hook::detour xmodel_get_bone_index_hook;
|
||||||
|
int xmodel_get_bone_index_stub(game::XModel* model, game::scr_string_t name, unsigned int offset, char* index)
|
||||||
|
{
|
||||||
|
auto result = xmodel_get_bone_index_hook.invoke<int>(model, name, offset, index);
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto original_index = *index;
|
||||||
|
const auto original_result = result;
|
||||||
|
|
||||||
|
if (name == game::SL_FindString("tag_weapon_right") ||
|
||||||
|
name == game::SL_FindString("tag_knife_attach"))
|
||||||
|
{
|
||||||
|
const auto tag_weapon = game::SL_FindString("tag_weapon");
|
||||||
|
result = xmodel_get_bone_index_hook.invoke<int>(model, tag_weapon, offset, index);
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
console::info("using tag_weapon instead of %s (%s, %d, %d)\n", game::SL_ConvertToString(name), model->name, offset, *index);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*index = original_index;
|
||||||
|
result = original_result;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cw_mismatch_error_stub(int, const char* msg, ...)
|
||||||
|
{
|
||||||
|
char buffer[0x100];
|
||||||
|
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, msg);
|
||||||
|
|
||||||
|
vsnprintf_s(buffer, sizeof(buffer), _TRUNCATE, msg, ap);
|
||||||
|
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
console::error(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class component final : public component_interface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void post_unpack() override
|
||||||
|
{
|
||||||
|
if (!game::environment::is_mp())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// precache all weapons that are loaded in zones
|
||||||
|
g_setup_level_weapon_def_hook.create(0x140340DE0, g_setup_level_weapon_def_stub);
|
||||||
|
|
||||||
|
// use tag_weapon if tag_weapon_right or tag_knife_attach are not found on model
|
||||||
|
xmodel_get_bone_index_hook.create(0x1404E2A50, xmodel_get_bone_index_stub);
|
||||||
|
|
||||||
|
// make custom weapon index mismatch not drop in CG_SetupCustomWeapon
|
||||||
|
utils::hook::call(0x1401E973D, cw_mismatch_error_stub);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
REGISTER_COMPONENT(weapon::component)
|
@ -1951,4 +1951,25 @@ namespace game
|
|||||||
HksError m_error;
|
HksError m_error;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum DBAllocFlags : std::int32_t
|
||||||
|
{
|
||||||
|
DB_ZONE_NONE = 0x0,
|
||||||
|
DB_ZONE_COMMON = 0x1,
|
||||||
|
DB_ZONE_UI = 0x2,
|
||||||
|
DB_ZONE_GAME = 0x4,
|
||||||
|
DB_ZONE_LOAD = 0x8,
|
||||||
|
DB_ZONE_DEV = 0x10,
|
||||||
|
DB_ZONE_BASEMAP = 0x20,
|
||||||
|
DB_ZONE_TRANSIENT_POOL = 0x40,
|
||||||
|
DB_ZONE_TRANSIENT_MASK = 0x40,
|
||||||
|
DB_ZONE_CUSTOM = 0x1000 // added for custom zone loading
|
||||||
|
};
|
||||||
|
|
||||||
|
struct XZone
|
||||||
|
{
|
||||||
|
char name[64];
|
||||||
|
char pad_0040[432];
|
||||||
|
};
|
||||||
|
static_assert(sizeof(XZone) == 496);
|
||||||
}
|
}
|
||||||
|
@ -58,6 +58,7 @@ namespace game
|
|||||||
WEAK symbol<int(const RawFile* rawfile)> DB_GetRawFileLen{0x14017E890, 0x14026FCC0};
|
WEAK symbol<int(const RawFile* rawfile)> DB_GetRawFileLen{0x14017E890, 0x14026FCC0};
|
||||||
WEAK symbol<void(const RawFile* rawfile, char* buf, int size)> DB_GetRawBuffer{0x14017E750, 0x14026FB90};
|
WEAK symbol<void(const RawFile* rawfile, char* buf, int size)> DB_GetRawBuffer{0x14017E750, 0x14026FB90};
|
||||||
WEAK symbol<char*(const char* filename, char* buf, int size)> DB_ReadRawFile{0x140180E30, 0x140273080};
|
WEAK symbol<char*(const char* filename, char* buf, int size)> DB_ReadRawFile{0x140180E30, 0x140273080};
|
||||||
|
WEAK symbol<bool(const char* filename)> DB_IsLocalized{0x14017EC80, 0x140270190};
|
||||||
|
|
||||||
WEAK symbol<dvar_t*(const char* name)> Dvar_FindVar{0x140370860, 0x1404BF8B0};
|
WEAK symbol<dvar_t*(const char* name)> Dvar_FindVar{0x140370860, 0x1404BF8B0};
|
||||||
WEAK symbol<void(const dvar_t* dvar)> Dvar_ClearModified{0x140370700, 0x1404BF690};
|
WEAK symbol<void(const dvar_t* dvar)> Dvar_ClearModified{0x140370700, 0x1404BF690};
|
||||||
@ -212,6 +213,7 @@ namespace game
|
|||||||
WEAK symbol<void(unsigned int localClientNum, const char** args)> UI_RunMenuScript{0, 0x140490060};
|
WEAK symbol<void(unsigned int localClientNum, const char** args)> UI_RunMenuScript{0, 0x140490060};
|
||||||
WEAK symbol<int(const char* text, int maxChars, Font_s* font, float scale)> UI_TextWidth{0, 0x140492380};
|
WEAK symbol<int(const char* text, int maxChars, Font_s* font, float scale)> UI_TextWidth{0, 0x140492380};
|
||||||
|
|
||||||
|
WEAK symbol<const char* ()> SEH_GetCurrentLanguageCode{0x140339280, 0x140474560};
|
||||||
WEAK symbol<const char*()> SEH_GetCurrentLanguageName{0x140339300, 0x1404745C0};
|
WEAK symbol<const char*()> SEH_GetCurrentLanguageName{0x140339300, 0x1404745C0};
|
||||||
|
|
||||||
WEAK symbol<void*(unsigned int size, unsigned int alignment, unsigned int type, int source)> PMem_AllocFromSource_NoDebug{0x1403775F0, 0x1404C7BA0};
|
WEAK symbol<void*(unsigned int size, unsigned int alignment, unsigned int type, int source)> PMem_AllocFromSource_NoDebug{0x1403775F0, 0x1404C7BA0};
|
||||||
@ -260,6 +262,7 @@ namespace game
|
|||||||
WEAK symbol<XAssetEntry> g_assetEntryPool{0x142CC2400, 0x14379F100};
|
WEAK symbol<XAssetEntry> g_assetEntryPool{0x142CC2400, 0x14379F100};
|
||||||
WEAK symbol<int> g_poolSize{0x140804140, 0x1409B4B90};
|
WEAK symbol<int> g_poolSize{0x140804140, 0x1409B4B90};
|
||||||
WEAK symbol<const char*> g_assetNames{0x140803C90, 0x1409B3180};
|
WEAK symbol<const char*> g_assetNames{0x140803C90, 0x1409B3180};
|
||||||
|
WEAK symbol<int> g_compressor{0x141598580, 0x141E0B080};
|
||||||
|
|
||||||
WEAK symbol<DWORD> threadIds{0x149632EC0, 0x147DCEA30};
|
WEAK symbol<DWORD> threadIds{0x149632EC0, 0x147DCEA30};
|
||||||
|
|
||||||
@ -267,6 +270,9 @@ namespace game
|
|||||||
|
|
||||||
WEAK symbol<unsigned int> tls_index{0x14F65DAF0, 0x150085C44};
|
WEAK symbol<unsigned int> tls_index{0x14F65DAF0, 0x150085C44};
|
||||||
|
|
||||||
|
WEAK symbol<unsigned int> g_zoneCount{0x0, 0x14379DBCC};
|
||||||
|
WEAK symbol<XZone> g_zones{0x0, 0x143B50618};
|
||||||
|
|
||||||
namespace mp
|
namespace mp
|
||||||
{
|
{
|
||||||
WEAK symbol<gentity_s> g_entities{0, 0x144758C70};
|
WEAK symbol<gentity_s> g_entities{0, 0x144758C70};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user