Merge branch 'develop' into feature/scripting

This commit is contained in:
quaK 2021-03-15 20:05:14 +02:00
commit 63473b92c5
23 changed files with 345 additions and 167 deletions

View File

@ -226,6 +226,15 @@ namespace command
}
}
void enum_assets(const game::XAssetType type, const std::function<void(game::XAssetHeader)>& callback, const bool includeOverride)
{
game::DB_EnumXAssets_Internal(type, static_cast<void(*)(game::XAssetHeader, void*)>([](game::XAssetHeader header, void* data)
{
const auto& cb = *static_cast<const std::function<void(game::XAssetHeader)>*>(data);
cb(header);
}), &callback, includeOverride);
}
class component final : public component_interface
{
public:
@ -254,6 +263,29 @@ namespace command
*reinterpret_cast<int*>(1) = 0;
});
add("consoleList", [](const params& params)
{
const std::string input = params.get(1);
std::vector<std::string> matches;
game_console::find_matches(input, matches, false);
for(auto& match : matches)
{
auto* dvar = game::Dvar_FindVar(match.c_str());
if (!dvar)
{
game_console::print(game_console::con_type_info, "[CMD]\t %s", match.c_str());
}
else
{
game_console::print(game_console::con_type_info, "[DVAR]\t%s \"%s\"", match.c_str(), game::Dvar_ValueToString(dvar, dvar->current));
}
}
game_console::print(game_console::con_type_info, "Total %i matches", matches.size());
});
add("dvarDump", []()
{
game_console::print(game_console::con_type_info,
@ -291,6 +323,44 @@ namespace command
game_console::print(game_console::con_type_info,
"================================ END COMMAND DUMP =================================\n");
});
add("listassetpool", [](const params& params)
{
if (params.size() < 2)
{
game_console::print(game_console::con_type_info,
"listassetpool <poolnumber>: list all the assets in the specified pool\n");
for (auto i = 0; i < game::XAssetType::ASSET_TYPE_COUNT; i++)
{
game_console::print(game_console::con_type_info, "%d %s\n", i, game::g_assetNames[i]);
}
}
else
{
const auto type = static_cast<game::XAssetType>(atoi(params.get(1)));
if (type < 0 || type >= game::XAssetType::ASSET_TYPE_COUNT)
{
game_console::print(game_console::con_type_error,
"Invalid pool passed must be between [%d, %d]", 0,
game::XAssetType::ASSET_TYPE_COUNT - 1);
return;
}
game_console::print(game_console::con_type_info, "Listing assets in pool %s",
game::g_assetNames[type]);
enum_assets(type, [type](game::XAssetHeader header)
{
const auto asset = game::XAsset{ type, header };
const auto* const asset_name = game::DB_GetXAssetName(&asset);
//const auto entry = game::DB_FindXAssetEntry(type, asset_name);
//TODO: display which zone the asset is from
game_console::print(game_console::con_type_info, "%s", asset_name);
}, true);
}
});
}
static void add_commands_sp()

View File

@ -8,6 +8,7 @@
#include "game/demonware/servers/lobby_server.hpp"
#include "game/demonware/servers/auth3_server.hpp"
#include "game/demonware/servers/stun_server.hpp"
#include "game/demonware/servers/umbrella_server.hpp"
#include "game/demonware/server_registry.hpp"
#define TCP_BLOCKING true
@ -248,6 +249,11 @@ namespace demonware
int select_stub(const int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds,
struct timeval* timeout)
{
if (exit_server)
{
return select(nfds, readfds, writefds, exceptfds, timeout);
}
auto result = 0;
std::vector<SOCKET> read_sockets;
std::vector<SOCKET> write_sockets;
@ -326,6 +332,12 @@ namespace demonware
return ioctlsocket(s, cmd, argp);
}
BOOL internet_get_connected_state_stub(LPDWORD, DWORD)
{
// Allow offline play
return TRUE;
}
}
void bd_logger_stub(const char* const function, const char* const msg, ...)
@ -366,6 +378,7 @@ namespace demonware
tcp_servers.create<auth3_server>("aw-pc-auth3.prod.demonware.net");
tcp_servers.create<lobby_server>("aw-pc-lobby.prod.demonware.net");
tcp_servers.create<umbrella_server>("prod.umbrella.demonware.net");
}
void post_load() override
@ -388,6 +401,11 @@ namespace demonware
if (function == "#52") return io::gethostbyname_stub;
}
if (function == "InternetGetConnectedState")
{
return io::internet_get_connected_state_stub;
}
return nullptr;
}
@ -406,6 +424,11 @@ namespace demonware
utils::hook::set<uint8_t>(0x140698B69, 0xAF); // CURLOPT_SSL_VERIFYHOST
utils::hook::set<uint8_t>(0x14088D0E8, 0x0); // HTTPS -> HTTP
// HTTPS -> HTTP
utils::hook::inject(0x14003852E, "http://prod.umbrella.demonware.net/v1.0/");
utils::hook::inject(0x14003884F, "http://prod.umbrella.demonware.net/v1.0/");
utils::hook::inject(0x140038A07, "http://prod.umbrella.demonware.net/v1.0/");
utils::hook::set<uint8_t>(0x140437CC0, 0xC3); // SV_SendMatchData
}

View File

@ -16,11 +16,11 @@ namespace fastfiles
{
utils::hook::detour db_try_load_x_file_internal_hook;
void db_try_load_x_file_internal(const char* zoneName, const int flags)
void db_try_load_x_file_internal(const char* zone_name, const int flags)
{
game_console::print(game_console::con_type_info, "Loading fastfile %s\n", zoneName);
current_fastfile = zoneName;
return db_try_load_x_file_internal_hook.invoke<void>(zoneName, flags);
game_console::print(game_console::con_type_info, "Loading fastfile %s\n", zone_name);
current_fastfile = zone_name;
return db_try_load_x_file_internal_hook.invoke<void>(zone_name, flags);
}
}
@ -63,39 +63,6 @@ namespace fastfiles
game::DB_LoadXAssets(&info, 1u, game::DBSyncMode::DB_LOAD_SYNC);
});
command::add("materiallist", [](const command::params& params)
{
game::DB_EnumXAssets_FastFile(game::ASSET_TYPE_MATERIAL, [](const game::XAssetHeader header, void*)
{
if (header.material && header.material->name)
{
printf("%s\n", header.material->name);
}
}, 0, false);
});
command::add("fontlist", [](const command::params& params)
{
game::DB_EnumXAssets_FastFile(game::ASSET_TYPE_FONT, [](const game::XAssetHeader header, void*)
{
if (header.font && header.font->fontName)
{
printf("%s\n", header.font->fontName);
}
}, 0, false);
});
command::add("rawfilelist", [](const command::params& params)
{
game::DB_EnumXAssets_FastFile(game::ASSET_TYPE_RAWFILE, [](const game::XAssetHeader header, void*)
{
if (header.rawfile && header.rawfile->name)
{
printf("%s\n", header.rawfile->name);
}
}, 0, false);
});
command::add("g_poolSizes", []()
{
for (auto i = 0; i < game::ASSET_TYPE_COUNT; i++)

View File

@ -171,57 +171,7 @@ namespace game_console
const auto _y = con.globals.font_height + con.globals.y + (con.globals.font_height * (line + 1)) + 15.0f;
game::R_AddCmdDrawText(text, 0x7FFFFFFF, console_font, con.globals.x + offset, _y, 1.0f, 1.0f, 0.0f, color,
0);
}
bool match_compare(const std::string& input, const std::string& text, const bool exact)
{
if (exact && text == input) return true;
if (!exact && text.find(input) != std::string::npos) return true;
return false;
}
void find_matches(std::string input, std::vector<std::string>& suggestions, const bool exact)
{
input = utils::string::to_lower(input);
for (int i = 0; i < *game::dvarCount; i++)
{
if (game::sortedDvars[i] && game::sortedDvars[i]->name)
{
std::string name = utils::string::to_lower(game::sortedDvars[i]->name);
if (match_compare(input, name, exact))
{
suggestions.push_back(game::sortedDvars[i]->name);
}
if (exact && suggestions.size() > 1)
{
return;
}
}
}
game::cmd_function_s* cmd = (*game::cmd_functions);
while (cmd)
{
if (cmd->name)
{
std::string name = utils::string::to_lower(cmd->name);
if (match_compare(input, name, exact))
{
suggestions.push_back(cmd->name);
}
if (exact && suggestions.size() > 1)
{
return;
}
}
cmd = cmd->next;
}
0);
}
void draw_input()
@ -379,7 +329,7 @@ namespace game_console
const auto height = ((con.screen_max[1] - con.screen_min[1]) - 32.0f) - 12.0f;
game::R_AddCmdDrawText(game::Dvar_FindVar("version")->current.string, 0x7FFFFFFF, console_font, x,
((height - 16.0f) + y) + console_font->pixelHeight, 1.0f, 1.0f, 0.0f, color_s1, 0);
((height - 12.0f) + y) + console_font->pixelHeight, 1.0f, 1.0f, 0.0f, color_s1, 0);
draw_output_scrollbar(x, y, width, height);
draw_output_text(x, y);
@ -496,6 +446,7 @@ namespace game_console
{
clear();
con.line_count = 0;
con.display_line_offset = 0;
con.output.clear();
history_index = -1;
history.clear();
@ -542,6 +493,11 @@ namespace game_console
{
if (key == game::keyNum_t::K_F10)
{
if (game::mp::svs_clients[localClientNum].header.state >= 1)
{
return false;
}
game::Cmd_ExecuteSingleCommand(localClientNum, 0, "lui_open menu_systemlink_join\n");
}
@ -672,6 +628,56 @@ namespace game_console
return true;
}
bool match_compare(const std::string& input, const std::string& text, const bool exact)
{
if (exact && text == input) return true;
if (!exact && text.find(input) != std::string::npos) return true;
return false;
}
void find_matches(std::string input, std::vector<std::string>& suggestions, const bool exact)
{
input = utils::string::to_lower(input);
for (int i = 0; i < *game::dvarCount; i++)
{
if (game::sortedDvars[i] && game::sortedDvars[i]->name)
{
std::string name = utils::string::to_lower(game::sortedDvars[i]->name);
if (game_console::match_compare(input, name, exact))
{
suggestions.push_back(game::sortedDvars[i]->name);
}
if (exact && suggestions.size() > 1)
{
return;
}
}
}
game::cmd_function_s* cmd = (*game::cmd_functions);
while (cmd)
{
if (cmd->name)
{
std::string name = utils::string::to_lower(cmd->name);
if (game_console::match_compare(input, name, exact))
{
suggestions.push_back(cmd->name);
}
if (exact && suggestions.size() > 1)
{
return;
}
}
cmd = cmd->next;
}
}
class component final : public component_interface
{
public:
@ -713,6 +719,7 @@ namespace game_console
{
clear();
con.line_count = 0;
con.display_line_offset = 0;
con.output.clear();
history_index = -1;
history.clear();

View File

@ -14,4 +14,7 @@ namespace game_console
bool console_char_event(int local_client_num, int key);
bool console_key_event(int local_client_num, int key, int down);
bool match_compare(const std::string& input, const std::string& text, const bool exact);
void find_matches(std::string input, std::vector<std::string>& suggestions, const bool exact);
}

View File

@ -3,6 +3,7 @@
#include "localized_strings.hpp"
#include <utils/hook.hpp>
#include <utils/string.hpp>
#include <utils/concurrency.hpp>
#include "game/game.hpp"
namespace localized_strings
@ -11,37 +12,30 @@ namespace localized_strings
{
utils::hook::detour seh_string_ed_get_string_hook;
std::unordered_map<std::string, std::string>& get_localized_overrides()
{
static std::unordered_map<std::string, std::string> overrides;
return overrides;
}
std::mutex& get_synchronization_mutex()
{
static std::mutex mutex;
return mutex;
}
using localized_map = std::unordered_map<std::string, std::string>;
utils::concurrency::container<localized_map> localized_overrides;
const char* seh_string_ed_get_string(const char* reference)
{
std::lock_guard<std::mutex> _(get_synchronization_mutex());
auto& overrides = get_localized_overrides();
const auto entry = overrides.find(reference);
if (entry != overrides.end())
return localized_overrides.access<const char*>([&](const localized_map& map)
{
return utils::string::va("%s", entry->second.data());
}
const auto entry = map.find(reference);
if (entry != map.end())
{
return utils::string::va("%s", entry->second.data());
}
return seh_string_ed_get_string_hook.invoke<const char*>(reference);
return seh_string_ed_get_string_hook.invoke<const char*>(reference);
});
}
}
void override(const std::string& key, const std::string& value)
{
std::lock_guard<std::mutex> _(get_synchronization_mutex());
get_localized_overrides()[key] = value;
localized_overrides.access([&](localized_map& map)
{
map[key] = value;
});
}
class component final : public component_interface

View File

@ -10,19 +10,67 @@ namespace logger
{
namespace
{
void print_error(const char* msg)
void print_error(const char* msg, ...)
{
game_console::print(game_console::con_type_error, msg);
char buffer[2048];
va_list ap;
va_start(ap, msg);
vsnprintf_s(buffer, sizeof(buffer), _TRUNCATE, msg, ap);
va_end(ap);
game_console::print(game_console::con_type_error, buffer);
}
void print_warning(const char* msg)
void print_warning(const char* msg, ...)
{
game_console::print(game_console::con_type_warning, msg);
char buffer[2048];
va_list ap;
va_start(ap, msg);
vsnprintf_s(buffer, sizeof(buffer), _TRUNCATE, msg, ap);
va_end(ap);
game_console::print(game_console::con_type_warning, buffer);
}
void print(const char* msg)
void print(const char* msg, ...)
{
game_console::print(game_console::con_type_info, msg);
char buffer[2048];
va_list ap;
va_start(ap, msg);
vsnprintf_s(buffer, sizeof(buffer), _TRUNCATE, msg, ap);
va_end(ap);
game_console::print(game_console::con_type_info, buffer);
}
void print_dev(const char* msg, ...)
{
static auto* enabled =
game::Dvar_RegisterBool("logger_dev", false, game::DVAR_FLAG_SAVED, "Print dev stuff");
if (!enabled->current.enabled)
{
return;
}
char buffer[2048];
va_list ap;
va_start(ap, msg);
vsnprintf_s(buffer, sizeof(buffer), _TRUNCATE, msg, ap);
va_end(ap);
game_console::print(game_console::con_type_info, buffer);
}
// nullsub_56
@ -58,6 +106,18 @@ namespace logger
utils::hook::call(0x1400DAE67, print_warning);
utils::hook::call(0x1400DB019, print_warning);
}
// sub_1400E7420
void sub_1400E7420()
{
utils::hook::call(0x1400CEC1C, print_warning);
utils::hook::call(0x1400D218E, print_warning);
utils::hook::call(0x1400D2319, print_warning);
utils::hook::call(0x1400D65BC, print_dev);
utils::hook::call(0x1400D7C94, print_dev);
utils::hook::call(0x1400DAB6A, print_dev);
utils::hook::call(0x1400DB9BC, print_dev);
}
}
class component final : public component_interface
@ -68,6 +128,7 @@ namespace logger
if (!game::environment::is_mp()) return;
nullsub_56();
sub_1400E7420();
}
};
}

View File

@ -210,6 +210,12 @@ namespace party
if (!game::environment::is_dedi())
{
if(game::SV_Loaded())
{
const auto* args = "Leave";
game::UI_RunMenuScript(0, &args);
}
perform_game_initialization();
}
@ -238,11 +244,8 @@ namespace party
command::execute(utils::string::va("party_maxplayers %i", maxclients->current.integer), true);
}*/
// StartServer
reinterpret_cast<void(*)(unsigned int)>(0x140492260)(0);
//game::SV_StartMapForParty(0, mapname.data(), false, false);
//return;
const auto* args = "StartServer";
game::UI_RunMenuScript(0, &args);
}
}

View File

@ -198,6 +198,10 @@ namespace patches
SetThreadExecutionState(ES_DISPLAY_REQUIRED);
}, scheduler::pipeline::main);
// Allow kbam input when gamepad is enabled
utils::hook::nop(SELECT_VALUE(0x14013EF83, 0x140206DB3), 2);
utils::hook::nop(SELECT_VALUE(0x14013CBAC, 0x140204710), 6);
if (game::environment::is_sp())
{
patch_sp();

View File

@ -8,7 +8,8 @@
#include <version.hpp>
#define APPVEYOR_ARTIFACT_BASE "https://ci.appveyor.com/api/projects/XLabsProject/s1x-client/artifacts/"
#define APPVEYOR_ARTIFACT_BASE "https://master.xlabs.dev:444"
#define APPVEYOR_PROJECT "s1x"
#define APPVEYOR_BRANCH GIT_BRANCH
#ifdef DEBUG
@ -17,12 +18,9 @@
#define APPVEYOR_CONFIGURATION "Release"
#endif
#define APPVEYOR_JOB "Environment%3A%20APPVEYOR_BUILD_WORKER_IMAGE%3DVisual%20Studio%202019%2C%20PREMAKE_ACTION%3Dvs2019%2C%20CI%3D1%3B%20Configuration%3A%20" APPVEYOR_CONFIGURATION
#define APPVEYOR_ARTIFACT_SUFFIX "?branch=" APPVEYOR_BRANCH "&job=" APPVEYOR_JOB
#define APPVEYOR_ARTIFACT_URL(artifact) (APPVEYOR_ARTIFACT_BASE "/" APPVEYOR_PROJECT "/" APPVEYOR_BRANCH "/" APPVEYOR_CONFIGURATION "/" artifact)
#define APPVEYOR_ARTIFACT_URL(artifact) (APPVEYOR_ARTIFACT_BASE artifact APPVEYOR_ARTIFACT_SUFFIX)
#define APPVEYOR_S1X_EXE APPVEYOR_ARTIFACT_URL("build/bin/x64/" APPVEYOR_CONFIGURATION "/s1x.exe")
#define APPVEYOR_S1X_EXE APPVEYOR_ARTIFACT_URL("build/bin/x64/" APPVEYOR_CONFIGURATION "/" APPVEYOR_PROJECT ".exe")
#define APPVEYOR_VERSION_TXT APPVEYOR_ARTIFACT_URL("build/version.txt")
namespace updater

View File

@ -98,22 +98,22 @@ namespace demonware
std::memcpy(ticket.m_sessionKey, session_key.data(), 24);
const auto iv = utils::cryptography::tiger::compute(std::string(reinterpret_cast<char*>(&iv_seed), 4));
std::string ticket_enc = utils::cryptography::des3::encrypt(
const auto ticket_enc = utils::cryptography::des3::encrypt(
std::string(reinterpret_cast<char*>(&ticket), sizeof(ticket)), iv, auth_key);
std::string ticket_b64 = utils::cryptography::base64::encode(
const auto ticket_b64 = utils::cryptography::base64::encode(
reinterpret_cast<const unsigned char*>(ticket_enc.data()), 128);
// server_ticket
uint8_t auth_data[128];
std::memset(&auth_data, 0, sizeof auth_data);
std::memcpy(auth_data, session_key.data(), 24);
std::string auth_data_b64 = utils::cryptography::base64::encode(auth_data, 128);
const auto auth_data_b64 = utils::cryptography::base64::encode(auth_data, 128);
demonware::set_session_key(session_key);
// header time
char date[64];
time_t now = time(nullptr);
const auto now = time(nullptr);
tm gmtm{};
gmtime_s(&gmtm, &now);
strftime(date, 64, "%a, %d %b %G %T", &gmtm);

View File

@ -25,7 +25,7 @@ namespace demonware
this->register_service<bdUNK63>();
this->register_service<bdUNK80>();
this->register_service<bdPresence>();
this->register_service<bdUNK104>();
this->register_service<bdMarketingComms>();
this->register_service<bdMatchMaking2>();
this->register_service<bdMarketing>();
};

View File

@ -0,0 +1,11 @@
#include <std_include.hpp>
#include "umbrella_server.hpp"
namespace demonware
{
void umbrella_server::handle(const std::string& packet)
{
// TODO:
}
}

View File

@ -0,0 +1,14 @@
#pragma once
#include "tcp_server.hpp"
namespace demonware
{
class umbrella_server : public tcp_server
{
public:
using tcp_server::tcp_server;
private:
void handle(const std::string& packet) override;
};
}

View File

@ -41,7 +41,7 @@ namespace demonware
virtual void exec_task(service_server* server, const std::string& data)
{
std::lock_guard $(this->mutex_);
std::lock_guard<std::mutex> _(this->mutex_);
byte_buffer buffer(data);
@ -52,14 +52,14 @@ namespace demonware
if (it != this->tasks_.end())
{
#ifdef DEBUG
printf("demonware::%s: executing task '%d'\n", name_.data(), this->task_id_);
printf("[DW] %s: executing task '%d'\n", name_.data(), this->task_id_);
#endif
it->second(server, &buffer);
}
else
{
printf("demonware::%s: missing task '%d'\n", name_.data(), this->task_id_);
printf("[DW] %s: missing task '%d'\n", name_.data(), this->task_id_);
// return no error
server->create_reply(this->task_id_)->send();

View File

@ -30,6 +30,6 @@
#include "services/bdUNK80.hpp"
// AccountLinking // 86
#include "services/bdPresence.hpp" //103
#include "services/bdUNK104.hpp" //104 Marketing
#include "services/bdMarketingComms.hpp" //104
#include "services/bdMatchMaking2.hpp" //138
#include "services/bdMarketing.hpp" //139

View File

@ -0,0 +1,17 @@
#include <std_include.hpp>
#include "../services.hpp"
namespace demonware
{
bdMarketingComms::bdMarketingComms() : service(104, "bdMarketingComms")
{
this->register_task(1, &bdMarketingComms::get_messages);
}
void bdMarketingComms::get_messages(service_server* server, byte_buffer* /*buffer*/) const
{
// TODO:
auto reply = server->create_reply(this->task_id());
reply->send();
}
}

View File

@ -0,0 +1,13 @@
#pragma once
namespace demonware
{
class bdMarketingComms final : public service
{
public:
bdMarketingComms();
private:
void get_messages(service_server* server, byte_buffer* buffer) const;
};
}

View File

@ -10,7 +10,7 @@ namespace demonware
void bdTitleUtilities::get_server_time(service_server* server, byte_buffer* /*buffer*/) const
{
const auto time_result = new bdTimeStamp;
auto* const time_result = new bdTimeStamp;
time_result->unix_time = uint32_t(time(nullptr));
auto reply = server->create_reply(this->task_id());

View File

@ -1,17 +0,0 @@
#include <std_include.hpp>
#include "../services.hpp"
namespace demonware
{
bdUNK104::bdUNK104() : service(104, "bdUNK104")
{
this->register_task(1, &bdUNK104::unk1);
}
void bdUNK104::unk1(service_server* server, byte_buffer* /*buffer*/) const
{
// TODO:
auto reply = server->create_reply(this->task_id());
reply->send();
}
}

View File

@ -1,13 +0,0 @@
#pragma once
namespace demonware
{
class bdUNK104 final : public service
{
public:
bdUNK104();
private:
void unk1(service_server* server, byte_buffer* buffer) const;
};
}

View File

@ -1234,6 +1234,22 @@ namespace game
LuaFile* luaFile;
};
struct XAsset
{
XAssetType type;
XAssetHeader header;
};
struct XAssetEntry
{
XAsset asset;
char zoneIndex;
volatile char inuseMask;
unsigned int nextHash;
unsigned int nextOverride;
unsigned int nextPoolEntry;
};
enum TestClientType
{
TC_NONE = 0x0,

View File

@ -44,6 +44,11 @@ namespace game
WEAK symbol<void(XAssetType type, void (__cdecl* func)(XAssetHeader, void*), void* inData, bool includeOverride)>
DB_EnumXAssets_FastFile{0x14017D7C0, 0x14026EC10};
WEAK symbol<void(XAssetType type, void(__cdecl* func)(game::XAssetHeader, void*), const void* inData, bool includeOverride)>
DB_EnumXAssets_Internal{ 0x14017D830, 0x14026EC80 };
WEAK symbol<game::XAssetEntry(game::XAssetType type, const char* name)>
DB_FindXAssetEntry{ 0x14017D830, 0x14026F020 };
WEAK symbol<const char* (const XAsset* asset)> DB_GetXAssetName{0x140151C00, 0x140240DD0};
WEAK symbol<int(XAssetType type)> DB_GetXAssetTypeSize{0x140151C20, 0x140240DF0};
WEAK symbol<void(XZoneInfo* zoneInfo, unsigned int zoneCount, DBSyncMode syncMode)> DB_LoadXAssets{
0x1402F8B50, 0x140270F30
@ -222,6 +227,8 @@ namespace game
WEAK symbol<SOCKET> query_socket{0, 0x14B5B9180};
WEAK symbol<void*> DB_XAssetPool{0x140804690, 0x1409B40D0};
WEAK symbol<unsigned int> db_hashTable{0x142C3E050, 0x143716B10};
WEAK symbol<XAssetEntry> g_assetEntryPool{0x142CC2400, 0x14379F100};
WEAK symbol<int> g_poolSize{0x140804140, 0x1409B4B90};
WEAK symbol<const char*> g_assetNames{0x140803C90, 0x1409B3180};