9 Commits

57 changed files with 978 additions and 922 deletions

2
deps/GSL vendored

Submodule deps/GSL updated: 272463043e...f1a494cfd2

2
deps/WinToast vendored

2
deps/asmjit vendored

2
deps/gsc-tool vendored

2
deps/minhook vendored

2
deps/rapidjson vendored

2
deps/zlib vendored

Submodule deps/zlib updated: ef24c4c750...9f0f2d4f9f

View File

@ -1,35 +0,0 @@
#include <std_include.hpp>
#include <loader/component_loader.hpp>
#include "game/game.hpp"
#include <utils/memory.hpp>
namespace asset_restrict
{
namespace
{
void reallocate_asset_pool(game::XAssetType type, const int size)
{
const auto asset_size = game::DB_GetXAssetTypeSize(type);
const auto new_size = size * game::g_poolSize[type];
const auto new_allocation_size = static_cast<std::size_t>(new_size * asset_size);
const game::XAssetHeader pool_entry = { .data = utils::memory::allocate(new_allocation_size) };
game::DB_XAssetPool[type] = pool_entry.data;
game::g_poolSize[type] = new_size;
}
}
class component final : public component_interface
{
public:
void post_unpack() override
{
reallocate_asset_pool(game::ASSET_TYPE_XANIMPARTS, 2);
reallocate_asset_pool(game::ASSET_TYPE_ATTACHMENT, 2);
}
};
}
REGISTER_COMPONENT(asset_restrict::component)

View File

@ -8,13 +8,11 @@
#include "console.hpp" #include "console.hpp"
#include "network.hpp" #include "network.hpp"
#include <utils/cryptography.hpp>
#include <utils/hook.hpp> #include <utils/hook.hpp>
#include <utils/info_string.hpp>
#include <utils/io.hpp>
#include <utils/properties.hpp>
#include <utils/smbios.hpp>
#include <utils/string.hpp> #include <utils/string.hpp>
#include <utils/smbios.hpp>
#include <utils/info_string.hpp>
#include <utils/cryptography.hpp>
namespace auth namespace auth
{ {
@ -33,26 +31,13 @@ namespace auth
std::string get_hw_profile_guid() std::string get_hw_profile_guid()
{ {
auto hw_profile_path = (utils::properties::get_appdata_path() / "iw6-guid.dat").generic_string();
if (utils::io::file_exists(hw_profile_path))
{
std::string hw_profile_info;
if (utils::io::read_file(hw_profile_path, &hw_profile_info) && !hw_profile_info.empty())
{
return hw_profile_info;
}
}
HW_PROFILE_INFO info; HW_PROFILE_INFO info;
if (!GetCurrentHwProfileA(&info)) if (!GetCurrentHwProfileA(&info))
{ {
return {}; return {};
} }
auto hw_profile_info = std::string{ info.szHwProfileGuid, sizeof(info.szHwProfileGuid) }; return std::string{ info.szHwProfileGuid, sizeof(info.szHwProfileGuid) };
utils::io::write_file(hw_profile_path, hw_profile_info);
return hw_profile_info;
} }
std::string get_protected_data() std::string get_protected_data()
@ -97,7 +82,7 @@ namespace auth
return key; return key;
} }
int send_connect_data_stub(game::netsrc_t sock, game::netadr_s* adr, const char* format, const int len) int send_connect_data_stub(game::netsrc_t sock, game::netadr_t* adr, const char* format, const int len)
{ {
std::string connect_string(format, len); std::string connect_string(format, len);
game::SV_Cmd_TokenizeString(connect_string.data()); game::SV_Cmd_TokenizeString(connect_string.data());
@ -131,7 +116,7 @@ namespace auth
return true; return true;
} }
void direct_connect(game::netadr_s* from, game::msg_t* msg) void direct_connect(game::netadr_t* from, game::msg_t* msg)
{ {
const auto offset = sizeof("connect") + 4; const auto offset = sizeof("connect") + 4;

View File

@ -21,7 +21,7 @@ namespace bots
bool can_add() bool can_add()
{ {
return party::get_client_count() < *game::mp::svs_clientCount; return party::get_client_count() < game::mp::svs->clientCount;
} }
void bot_team_join(const int entity_num) void bot_team_join(const int entity_num)
@ -29,14 +29,14 @@ namespace bots
// schedule the select team call // schedule the select team call
scheduler::once([entity_num]() scheduler::once([entity_num]()
{ {
game::SV_ExecuteClientCommand(&game::mp::svs_clients[entity_num], game::SV_ExecuteClientCommand(&game::mp::svs->clients[entity_num],
utils::string::va("lui 68 2 %i", *game::mp::sv_serverId_value), utils::string::va("lui 68 2 %i", *game::mp::sv_serverId_value),
false); false);
// scheduler the select class call // scheduler the select class call
scheduler::once([entity_num]() scheduler::once([entity_num]()
{ {
game::SV_ExecuteClientCommand(&game::mp::svs_clients[entity_num], game::SV_ExecuteClientCommand(&game::mp::svs->clients[entity_num],
utils::string::va("lui 5 %i %i", (rand() % 5) + 10, utils::string::va("lui 5 %i %i", (rand() % 5) + 10,
*game::mp::sv_serverId_value), false); *game::mp::sv_serverId_value), false);
}, scheduler::pipeline::server, 1s); }, scheduler::pipeline::server, 1s);
@ -144,7 +144,7 @@ namespace bots
{ {
bot_names_received = false; bot_names_received = false;
game::netadr_s master{}; game::netadr_t master{};
if (server_list::get_master_server(master)) if (server_list::get_master_server(master))
{ {
console::info("Getting bots...\n"); console::info("Getting bots...\n");
@ -175,7 +175,7 @@ namespace bots
num_bots = std::strtoul(params.get(1), nullptr, 10); num_bots = std::strtoul(params.get(1), nullptr, 10);
} }
num_bots = std::min(num_bots, static_cast<std::size_t>(*game::mp::svs_clientCount)); num_bots = std::min(num_bots, static_cast<std::size_t>(game::mp::svs->clientCount));
console::info("Spawning %zu %s\n", num_bots, (num_bots == 1 ? "bot" : "bots")); console::info("Spawning %zu %s\n", num_bots, (num_bots == 1 ? "bot" : "bots"));
@ -198,9 +198,9 @@ namespace bots
parse_bot_names_from_file(); parse_bot_names_from_file();
} }
network::on("getbotsResponse", [](const game::netadr_s& target, const std::string& data) network::on("getbotsResponse", [](const game::netadr_t& target, const std::string& data)
{ {
game::netadr_s master{}; game::netadr_t master{};
if (server_list::get_master_server(master) && !bot_names_received && target == master) if (server_list::get_master_server(master) && !bot_names_received && target == master)
{ {
bot_names = utils::string::split(data, '\n'); bot_names = utils::string::split(data, '\n');

View File

@ -86,18 +86,28 @@ namespace colors
return string; return string;
} }
size_t get_client_name_stub(const int local_client_num, const int index, char* buf, const int size, size_t get_client_name_stub(const int local_client_num, const int index, char* name_buf,
const size_t unk, const size_t unk2) const int max_name_size, char* clan_buf, const int max_clan_size)
{ {
// CL_GetClientName (CL_GetClientNameAndClantag?) // CL_GetClientNameAndClanTag (wrapper for CL_GetClientNameAndClanTagColorize)
const auto result = reinterpret_cast<size_t(*)(int, int, char*, int, size_t, size_t)>(0x1402CF790)( const auto result = reinterpret_cast<size_t(*)(int, int, char*, int, char*, int)>(0x1402CF790)(
local_client_num, index, buf, size, unk, unk2); local_client_num, index, name_buf, max_name_size, clan_buf, max_clan_size);
utils::string::strip(buf, buf, size); utils::string::strip(name_buf, name_buf, static_cast<size_t>(max_name_size));
return result; return result;
} }
int clean_agent_name_stub(char* out, int max_size, const char* fmt, const char* in)
{
// format agent overhead name like [%s]
const auto length = sprintf_s(out, max_size, fmt, in);
utils::string::strip(in, out, std::min(static_cast<size_t>(length), static_cast<size_t>(max_size)));
return length;
}
void rb_lookup_color_stub(const char index, DWORD* color) void rb_lookup_color_stub(const char index, DWORD* color)
{ {
*color = RGB(255, 255, 255); *color = RGB(255, 255, 255);
@ -143,6 +153,9 @@ namespace colors
// don't apply colors to overhead names // don't apply colors to overhead names
utils::hook::call(0x14025CE79, get_client_name_stub); utils::hook::call(0x14025CE79, get_client_name_stub);
// don't apply colors to overhead names of agents (like dogs or juggernauts)
utils::hook::call(0x1402CF760, clean_agent_name_stub);
// patch I_CleanStr // patch I_CleanStr
utils::hook::jump(0x1404F63C0, i_clean_str_stub); utils::hook::jump(0x1404F63C0, i_clean_str_stub);
} }

View File

@ -194,7 +194,7 @@ namespace command
void add_raw(const char* name, void (*callback)()) void add_raw(const char* name, void (*callback)())
{ {
game::Cmd_AddCommandInternal(name, callback, utils::memory::get_allocator()->allocate<game::cmd_function_s>()); game::Cmd_AddCommandInternal(name, callback, utils::memory::get_allocator()->allocate<game::cmd_function_t>());
} }
void add(const char* name, const std::function<void(const params&)>& callback) void add(const char* name, const std::function<void(const params&)>& callback)
@ -231,11 +231,8 @@ namespace command
} }
void execute(std::string command, const bool sync) void execute(std::string command, const bool sync)
{
if (!command.ends_with('\n'))
{ {
command += "\n"; command += "\n";
}
if (sync) if (sync)
{ {
@ -321,7 +318,7 @@ namespace command
} }
console::info("================================ COMMAND DUMP =====================================\n"); console::info("================================ COMMAND DUMP =====================================\n");
game::cmd_function_s* cmd = *game::cmd_functions; game::cmd_function_t* cmd = *game::cmd_functions;
auto i = 0; auto i = 0;
while (cmd) while (cmd)
{ {
@ -556,12 +553,12 @@ namespace command
{ {
if (!dvars::sv_cheats->current.enabled) if (!dvars::sv_cheats->current.enabled)
{ {
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, "f \"Cheats are not enabled on this server\""); game::SV_GameSendServerCommand(client_num, 1, "f \"Cheats are not enabled on this server\"");
return; return;
} }
game::mp::g_entities[client_num].flags ^= game::FL_GODMODE; game::mp::g_entities[client_num].flags ^= game::FL_GODMODE;
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, game::SV_GameSendServerCommand(client_num, 1,
utils::string::va("f \"godmode %s\"", utils::string::va("f \"godmode %s\"",
game::mp::g_entities[client_num].flags & game::FL_GODMODE game::mp::g_entities[client_num].flags & game::FL_GODMODE
? "^2on" ? "^2on"
@ -572,12 +569,12 @@ namespace command
{ {
if (!dvars::sv_cheats->current.enabled) if (!dvars::sv_cheats->current.enabled)
{ {
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, "f \"Cheats are not enabled on this server\""); game::SV_GameSendServerCommand(client_num, 1, "f \"Cheats are not enabled on this server\"");
return; return;
} }
game::mp::g_entities[client_num].flags ^= game::FL_NOTARGET; game::mp::g_entities[client_num].flags ^= game::FL_NOTARGET;
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, game::SV_GameSendServerCommand(client_num, 1,
utils::string::va("f \"notarget %s\"", utils::string::va("f \"notarget %s\"",
game::mp::g_entities[client_num].flags & game::FL_NOTARGET game::mp::g_entities[client_num].flags & game::FL_NOTARGET
? "^2on" ? "^2on"
@ -588,12 +585,12 @@ namespace command
{ {
if (!dvars::sv_cheats->current.enabled) if (!dvars::sv_cheats->current.enabled)
{ {
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, "f \"Cheats are not enabled on this server\""); game::SV_GameSendServerCommand(client_num, 1, "f \"Cheats are not enabled on this server\"");
return; return;
} }
game::mp::g_entities[client_num].client->flags ^= 1; game::mp::g_entities[client_num].client->flags ^= 1;
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, game::SV_GameSendServerCommand(client_num, 1,
utils::string::va("f \"noclip %s\"", utils::string::va("f \"noclip %s\"",
game::mp::g_entities[client_num].client->flags & 1 game::mp::g_entities[client_num].client->flags & 1
? "^2on" ? "^2on"
@ -604,12 +601,12 @@ namespace command
{ {
if (!dvars::sv_cheats->current.enabled) if (!dvars::sv_cheats->current.enabled)
{ {
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, "f \"Cheats are not enabled on this server\""); game::SV_GameSendServerCommand(client_num, 1, "f \"Cheats are not enabled on this server\"");
return; return;
} }
game::mp::g_entities[client_num].client->flags ^= 2; game::mp::g_entities[client_num].client->flags ^= 2;
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, game::SV_GameSendServerCommand(client_num, 1,
utils::string::va("f \"ufo %s\"", utils::string::va("f \"ufo %s\"",
game::mp::g_entities[client_num].client->flags & 2 game::mp::g_entities[client_num].client->flags & 2
? "^2on" ? "^2on"
@ -620,13 +617,13 @@ namespace command
{ {
if (!dvars::sv_cheats->current.enabled) if (!dvars::sv_cheats->current.enabled)
{ {
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, "f \"Cheats are not enabled on this server\""); game::SV_GameSendServerCommand(client_num, 1, "f \"Cheats are not enabled on this server\"");
return; return;
} }
if (params.size() < 4) if (params.size() < 4)
{ {
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, game::SV_GameSendServerCommand(client_num, 1,
"f \"You did not specify the correct number of coordinates\""); "f \"You did not specify the correct number of coordinates\"");
return; return;
} }
@ -640,13 +637,13 @@ namespace command
{ {
if (!dvars::sv_cheats->current.enabled) if (!dvars::sv_cheats->current.enabled)
{ {
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, "f \"Cheats are not enabled on this server\""); game::SV_GameSendServerCommand(client_num, 1, "f \"Cheats are not enabled on this server\"");
return; return;
} }
if (params.size() < 4) if (params.size() < 4)
{ {
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, game::SV_GameSendServerCommand(client_num, 1,
"f \"You did not specify the correct number of coordinates\""); "f \"You did not specify the correct number of coordinates\"");
return; return;
} }
@ -660,13 +657,13 @@ namespace command
{ {
if (!dvars::sv_cheats->current.enabled) if (!dvars::sv_cheats->current.enabled)
{ {
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, "f \"Cheats are not enabled on this server\""); game::SV_GameSendServerCommand(client_num, 1, "f \"Cheats are not enabled on this server\"");
return; return;
} }
if (params.size() < 2) if (params.size() < 2)
{ {
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, "f \"You did not specify a weapon name\""); game::SV_GameSendServerCommand(client_num, 1, "f \"You did not specify a weapon name\"");
return; return;
} }
@ -683,13 +680,13 @@ namespace command
{ {
if (!dvars::sv_cheats->current.enabled) if (!dvars::sv_cheats->current.enabled)
{ {
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, "f \"Cheats are not enabled on this server\""); game::SV_GameSendServerCommand(client_num, 1, "f \"Cheats are not enabled on this server\"");
return; return;
} }
if (params.size() < 2) if (params.size() < 2)
{ {
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, "f \"You did not specify a weapon name\""); game::SV_GameSendServerCommand(client_num, 1, "f \"You did not specify a weapon name\"");
return; return;
} }

View File

@ -110,7 +110,7 @@ namespace dedicated
return; return;
} }
game::netadr_s target{}; game::netadr_t target{};
if (server_list::get_master_server(target)) if (server_list::get_master_server(target))
{ {
network::send(target, "heartbeat", "IW6"); network::send(target, "heartbeat", "IW6");

View File

@ -25,28 +25,28 @@ namespace dedicated_info
scheduler::loop([]() scheduler::loop([]()
{ {
const auto* sv_running = game::Dvar_FindVar("sv_running"); auto* sv_running = game::Dvar_FindVar("sv_running");
if (!sv_running || !sv_running->current.enabled) if (!sv_running || !sv_running->current.enabled)
{ {
console::set_title("iw6-mod Dedicated Server"); console::set_title("iw6-mod Dedicated Server");
return; return;
} }
const auto* sv_hostname = game::Dvar_FindVar("sv_hostname"); auto* const sv_hostname = game::Dvar_FindVar("sv_hostname");
const auto* sv_maxclients = game::Dvar_FindVar("sv_maxclients"); auto* const sv_maxclients = game::Dvar_FindVar("sv_maxclients");
const auto* mapname = game::Dvar_FindVar("mapname"); auto* const mapname = game::Dvar_FindVar("mapname");
auto client_count = 0; auto client_count = 0;
auto bot_count = 0; auto bot_count = 0;
for (auto i = 0; i < sv_maxclients->current.integer; ++i) for (auto i = 0; i < sv_maxclients->current.integer; i++)
{ {
auto* client = &game::mp::svs_clients[i]; auto* client = &game::mp::svs->clients[i];
auto* self = &game::mp::g_entities[i]; auto* self = &game::mp::g_entities[i];
if (client->header.state > game::CS_FREE && self && self->client) if (client->header.state > game::CS_FREE && self && self->client)
{ {
++client_count; client_count++;
if (game::SV_BotIsBot(i)) if (game::SV_BotIsBot(i))
{ {
++bot_count; ++bot_count;

View File

@ -54,8 +54,8 @@ namespace discord
discord_presence.details = utils::string::va("%s on %s", gametype, map); discord_presence.details = utils::string::va("%s on %s", gametype, map);
discord_presence.partySize = game::mp::cgArray->snap != nullptr discord_presence.partySize = game::mp::cg->snap != nullptr
? game::mp::cgArray->snap->numClients ? game::mp::cg->snap->numClients
: 1; : 1;
if (game::Dvar_GetBool("xblive_privatematch")) if (game::Dvar_GetBool("xblive_privatematch"))
@ -65,13 +65,13 @@ namespace discord
} }
else else
{ {
auto* host_name = reinterpret_cast<char*>(0x14187EBC4); auto* host_name = game::mp::cgs->szHostName;
utils::string::strip(host_name, host_name, std::strlen(host_name) + 1); utils::string::strip(host_name, host_name, std::strlen(host_name) + 1);
discord_presence.state = host_name; discord_presence.state = host_name;
discord_presence.partyMax = party::server_client_count(); discord_presence.partyMax = party::server_client_count();
std::hash<game::netadr_s> hash_fn; std::hash<game::netadr_t> hash_fn;
static const auto nonce = utils::cryptography::random::get_integer(); static const auto nonce = utils::cryptography::random::get_integer();
const auto& address = party::get_target(); const auto& address = party::get_target();

View File

@ -110,7 +110,7 @@ namespace dvar_cheats
a.jmp(0x1404F0D74); a.jmp(0x1404F0D74);
}); });
void cg_set_client_dvar_from_server(const int local_client_num, game::mp::cg_s* cg, const char* dvar_id, const char* value) void cg_set_client_dvar_from_server(const int local_client_num, game::mp::cg_t* cg, const char* dvar_id, const char* value)
{ {
if (dvar_id == "cg_fov"s || dvar_id == "com_maxfps"s) if (dvar_id == "cg_fov"s || dvar_id == "com_maxfps"s)
{ {
@ -136,7 +136,7 @@ namespace dvar_cheats
const auto* dvar = game::Scr_GetString(0); // grab the original dvar again since it's never stored on stack const auto* dvar = game::Scr_GetString(0); // grab the original dvar again since it's never stored on stack
const auto* command = utils::string::va("q %s \"%s\"", dvar, value); const auto* command = utils::string::va("q %s \"%s\"", dvar, value);
game::SV_GameSendServerCommand(entity_num, game::SV_CMD_RELIABLE, command); game::SV_GameSendServerCommand(entity_num, 1, command);
} }
const auto player_cmd_set_client_dvar = utils::hook::assemble([](utils::hook::assembler& a) const auto player_cmd_set_client_dvar = utils::hook::assemble([](utils::hook::assembler& a)

View File

@ -1,12 +1,12 @@
#include <std_include.hpp> #include <std_include.hpp>
#include "loader/component_loader.hpp" #include "loader/component_loader.hpp"
#include "game/game.hpp" #include "game/game.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/hook.hpp> #include <utils/hook.hpp>
#include <utils/memory.hpp> #include <utils/memory.hpp>
@ -22,7 +22,7 @@ namespace fastfiles
void db_try_load_x_file_internal(const char* zone_name, const int zone_flags, const int is_base_map) void db_try_load_x_file_internal(const char* zone_name, const int zone_flags, const int is_base_map)
{ {
console::info("Loading fastfile %s\n", zone_name); console::info("Loading fastfile %s\n", zone_name);
db_try_load_x_file_internal_hook.invoke<void>(zone_name, zone_flags, is_base_map); return db_try_load_x_file_internal_hook.invoke<void>(zone_name, zone_flags, is_base_map);
} }
void dump_gsc_script(const std::string& name, game::XAssetHeader header) void dump_gsc_script(const std::string& name, game::XAssetHeader header)
@ -114,9 +114,21 @@ namespace fastfiles
utils::hook::call(SELECT_VALUE(0x1402752DF, 0x140156350), p_mem_free_stub); utils::hook::call(SELECT_VALUE(0x1402752DF, 0x140156350), p_mem_free_stub);
utils::hook::call(SELECT_VALUE(0x140276004, 0x140324259), p_mem_free_stub); utils::hook::call(SELECT_VALUE(0x140276004, 0x140324259), p_mem_free_stub);
// Allow loading of unsigned fastfiles command::add("loadzone", [](const command::params& params)
utils::hook::set<uint8_t>(0x1402FBF23, 0xEB); // DB_LoadXFile {
utils::hook::nop(0x1402FC445, 2); // DB_SetFileLoadCompressor if (params.size() < 2)
{
console::info("usage: loadzone <zone>\n");
return;
}
game::XZoneInfo info;
info.name = params.get(1);
info.allocFlags = 1;
info.freeFlags = 0;
game::DB_LoadXAssets(&info, 1, game::DBSyncMode::DB_LOAD_SYNC);
});
command::add("materiallist", [](const command::params& params) command::add("materiallist", [](const command::params& params)
{ {

View File

@ -86,11 +86,6 @@ namespace filesystem
register_path("iw6"); register_path("iw6");
register_path(get_binary_directory() + "\\data"); register_path(get_binary_directory() + "\\data");
if (get_binary_directory() != std::filesystem::current_path())
{
register_path(std::filesystem::current_path() / "data");
}
// game's search paths // game's search paths
register_path("devraw"); register_path("devraw");
register_path("devraw_shared"); register_path("devraw_shared");

View File

@ -505,7 +505,7 @@ namespace game_console
{ {
if (key == game::keyNum_t::K_F10) if (key == game::keyNum_t::K_F10)
{ {
if(game::mp::svs_clients[localClientNum].header.state > game::CS_FREE) if(game::mp::svs->clients[localClientNum].header.state > game::CS_FREE)
{ {
return false; return false;
} }
@ -674,7 +674,7 @@ namespace game_console
} }
} }
game::cmd_function_s* cmd = (*game::cmd_functions); game::cmd_function_t* cmd = (*game::cmd_functions);
while (cmd) while (cmd)
{ {
if (cmd->name) if (cmd->name)

View File

@ -102,14 +102,9 @@ namespace game_log
g_log_printf("InitGame\n"); g_log_printf("InitGame\n");
}); });
scripting::on_shutdown([](const int clear_scripts, const int post_shutdown) -> void scripting::on_shutdown([](int free_scripts)
{ {
if (post_shutdown) console::info("==== ShutdownGame (%d) ====\n", free_scripts);
{
return;
}
console::info("==== ShutdownGame (%d) ====\n", clear_scripts);
g_log_printf("ShutdownGame:\n"); g_log_printf("ShutdownGame:\n");
g_log_printf("------------------------------------------------------------\n"); g_log_printf("------------------------------------------------------------\n");

View File

@ -133,7 +133,7 @@ namespace gameplay
return jump_height; return jump_height;
} }
void jump_apply_slowdown_stub(game::mp::playerState_s* ps) void jump_apply_slowdown_stub(game::mp::playerState_t* ps)
{ {
assert(ps->pm_flags & game::PMF_JUMPING); assert(ps->pm_flags & game::PMF_JUMPING);
@ -163,7 +163,7 @@ namespace gameplay
} }
} }
float jump_get_slowdown_friction(game::mp::playerState_s* ps) float jump_get_slowdown_friction(game::mp::playerState_t* ps)
{ {
assert(ps->pm_flags & game::PMF_JUMPING); assert(ps->pm_flags & game::PMF_JUMPING);
assert(ps->pm_time <= game::JUMP_LAND_SLOWDOWN_TIME); assert(ps->pm_time <= game::JUMP_LAND_SLOWDOWN_TIME);
@ -181,7 +181,7 @@ namespace gameplay
return 2.5f; return 2.5f;
} }
float jump_reduce_friction_stub(game::mp::playerState_s* ps) float jump_reduce_friction_stub(game::mp::playerState_t* ps)
{ {
float control; float control;
@ -199,7 +199,7 @@ namespace gameplay
return control; return control;
} }
float jump_get_land_factor(game::mp::playerState_s* ps) float jump_get_land_factor(game::mp::playerState_t* ps)
{ {
assert(ps->pm_flags & game::PMF_JUMPING); assert(ps->pm_flags & game::PMF_JUMPING);
assert(ps->pm_time <= game::JUMP_LAND_SLOWDOWN_TIME); assert(ps->pm_time <= game::JUMP_LAND_SLOWDOWN_TIME);
@ -219,9 +219,9 @@ namespace gameplay
void jump_start_stub(game::pmove_t* pm, game::pml_t* pml, float height) void jump_start_stub(game::pmove_t* pm, game::pml_t* pml, float height)
{ {
static_assert(offsetof(game::mp::playerState_s, groundEntityNum) == 0x70); static_assert(offsetof(game::mp::playerState_t, groundEntityNum) == 0x70);
static_assert(offsetof(game::mp::playerState_s, pm_time) == 0x8); static_assert(offsetof(game::mp::playerState_t, pm_time) == 0x8);
static_assert(offsetof(game::mp::playerState_s, sprintState.sprintButtonUpRequired) == 0x240); static_assert(offsetof(game::mp::playerState_t, sprintState.sprintButtonUpRequired) == 0x240);
static_assert(offsetof(game::pml_t, frametime) == 0x24); static_assert(offsetof(game::pml_t, frametime) == 0x24);
static_assert(offsetof(game::pml_t, walking) == 0x2C); static_assert(offsetof(game::pml_t, walking) == 0x2C);
static_assert(offsetof(game::pml_t, groundPlane) == 0x30); static_assert(offsetof(game::pml_t, groundPlane) == 0x30);
@ -229,9 +229,9 @@ namespace gameplay
float factor; float factor;
float velocity_sqrd; float velocity_sqrd;
game::mp::playerState_s* ps; game::mp::playerState_t* ps;
ps = static_cast<game::mp::playerState_s*>(pm->ps); ps = static_cast<game::mp::playerState_t*>(pm->ps);
assert(ps); assert(ps);
@ -295,7 +295,7 @@ namespace gameplay
} }
} }
void pm_weapon_use_ammo_stub(game::playerState_s* ps, game::Weapon weapon, void pm_weapon_use_ammo_stub(game::playerState_t* ps, game::Weapon weapon,
bool is_alternate, int amount, game::PlayerHandIndex hand) bool is_alternate, int amount, game::PlayerHandIndex hand)
{ {
if (!dvars::player_sustainAmmo->current.enabled) if (!dvars::player_sustainAmmo->current.enabled)
@ -304,10 +304,10 @@ namespace gameplay
} }
} }
game::mp::gentity_s* weapon_rocket_launcher_fire_stub(game::mp::gentity_s* ent, game::Weapon weapon, float spread, game::weaponParms* wp, game::mp::gentity_t* weapon_rocket_launcher_fire_stub(game::mp::gentity_t* ent, game::Weapon weapon, float spread, game::weaponParms* wp,
const float* gun_vel, game::mp::missileFireParms* fire_parms, bool magic_bullet) const float* gun_vel, game::mp::missileFireParms* fire_parms, bool magic_bullet)
{ {
auto* result = utils::hook::invoke<game::mp::gentity_s*>(0x1403DB8A0, ent, weapon, spread, wp, gun_vel, fire_parms, magic_bullet); auto* result = utils::hook::invoke<game::mp::gentity_t*>(0x1403DB8A0, ent, weapon, spread, wp, gun_vel, fire_parms, magic_bullet);
if (ent->client != nullptr && wp->weapDef->inventoryType != game::WEAPINVENTORY_EXCLUSIVE) if (ent->client != nullptr && wp->weapDef->inventoryType != game::WEAPINVENTORY_EXCLUSIVE)
{ {

View File

@ -113,6 +113,7 @@ namespace gsc
return res; return res;
} }
} }
unsigned int scr_get_object(unsigned int index) unsigned int scr_get_object(unsigned int index)
@ -283,23 +284,28 @@ namespace gsc
public: public:
void post_unpack() override void post_unpack() override
{ {
scr_emit_function_hook.create(SELECT_VALUE(0x1403D3350, 0x14042E150), &scr_emit_function_stub); if (game::environment::is_sp())
{
return;
}
utils::hook::call(SELECT_VALUE(0x1403D32E4, 0x14042E0E4), compile_error_stub); // LinkFile scr_emit_function_hook.create(0x14042E150, &scr_emit_function_stub);
utils::hook::call(SELECT_VALUE(0x1403D3338, 0x14042E138), compile_error_stub); // LinkFile
utils::hook::call(SELECT_VALUE(0x1403D342A, 0x14042E22B), find_variable_stub); // Scr_EmitFunction utils::hook::call(0x14042E0E4, compile_error_stub); // LinkFile
utils::hook::call(0x14042E138, compile_error_stub); // LinkFile
utils::hook::call(0x14042E22B, find_variable_stub); // Scr_EmitFunction
// Restore basic error messages to scr functions // Restore basic error messages to scr functions
utils::hook::jump(game::Scr_GetObject, scr_get_object); utils::hook::jump(0x140438ED0, scr_get_object);
utils::hook::jump(game::Scr_GetConstString, scr_get_const_string); utils::hook::jump(0x140438AD0, scr_get_const_string);
utils::hook::jump(game::Scr_GetConstIString, scr_get_const_istring); utils::hook::jump(0x1404388B0, scr_get_const_istring);
utils::hook::jump(game::Scr_GetVector, scr_get_vector); utils::hook::jump(0x1404393D0, scr_get_vector);
utils::hook::jump(game::Scr_GetInt, scr_get_int); utils::hook::jump(0x140438E10, scr_get_int);
utils::hook::jump(game::Scr_GetFloat, scr_get_float); utils::hook::jump(0x140438D60, scr_get_float);
utils::hook::jump(SELECT_VALUE(0x1403DE150, 0x1404390B0), scr_get_pointer_type); utils::hook::jump(0x1404390B0, scr_get_pointer_type);
utils::hook::jump(SELECT_VALUE(0x1403DE320, 0x140439280), scr_get_type); utils::hook::jump(0x140439280, scr_get_type);
utils::hook::jump(SELECT_VALUE(0x1403DE390, 0x1404392F0), scr_get_type_name); utils::hook::jump(0x1404392F0, scr_get_type_name);
} }
void pre_destroy() override void pre_destroy() override

View File

@ -37,60 +37,9 @@ namespace gsc
bool force_error_print = false; bool force_error_print = false;
std::optional<std::string> gsc_error_msg; std::optional<std::string> gsc_error_msg;
std::vector<devmap_entry> devmap_entries{};
std::optional<devmap_entry> get_devmap_entry(const std::uint8_t* codepos)
{
const auto itr = std::ranges::find_if(devmap_entries, [codepos](const devmap_entry& entry) -> bool
{
return codepos >= entry.bytecode && codepos < entry.bytecode + entry.size;
});
if (itr != devmap_entries.end())
{
return *itr;
}
return {};
}
std::optional<std::pair<std::uint16_t, std::uint16_t>> get_line_and_col_for_codepos(const std::uint8_t* codepos)
{
const auto entry = get_devmap_entry(codepos);
if (!entry.has_value())
{
return {};
}
std::optional<std::pair<std::uint16_t, std::uint16_t>> best_line_info{};
std::uint32_t best_codepos = 0;
assert(codepos >= entry->bytecode);
const std::uint32_t codepos_offset = static_cast<std::uint32_t>(codepos - entry->bytecode);
for (const auto& instruction : entry->devmap)
{
if (instruction.codepos > codepos_offset)
{
continue;
}
if (best_line_info.has_value() && codepos_offset - instruction.codepos > codepos_offset - best_codepos)
{
continue;
}
best_line_info = { { instruction.line, instruction.col } };
best_codepos = instruction.codepos;
}
return best_line_info;
}
unsigned int scr_get_function_stub(const char** p_name, int* type) unsigned int scr_get_function_stub(const char** p_name, int* type)
{ {
const auto result = game::Scr_GetFunction(p_name, type); const auto result = utils::hook::invoke<unsigned int>(0x1403CD9F0, p_name, type);
for (const auto& [name, func] : functions) for (const auto& [name, func] : functions)
{ {
@ -171,36 +120,27 @@ namespace gsc
const auto pos = frame == game::scr_VmPub->function_frame ? game::scr_function_stack->pos : frame->fs.pos; const auto pos = frame == game::scr_VmPub->function_frame ? game::scr_function_stack->pos : frame->fs.pos;
const auto function = find_function(frame->fs.pos); const auto function = find_function(frame->fs.pos);
const char* location;
if (function.has_value()) if (function.has_value())
{ {
location = utils::string::va("function \"%s\" in file \"%s\"", function.value().first.data(), function.value().second.data()); console::warn("\tat function \"%s\" in file \"%s.gsc\"\n", function.value().first.data(), function.value().second.data());
} }
else else
{ {
location = utils::string::va("unknown location %p", pos); console::warn("\tat unknown location %p\n", pos);
} }
const auto line_info = get_line_and_col_for_codepos(reinterpret_cast<const std::uint8_t*>(pos));
if (line_info.has_value())
{
location = utils::string::va("%s line \"%d\" column \"%d\"", location, line_info->first, line_info->second);
}
console::warn("\tat %s\n", location);
} }
} }
void vm_error_stub(const unsigned __int64 mark_pos) void vm_error_stub(int mark_pos)
{ {
if (!dvars::com_developer_script->current.enabled && !force_error_print) if (!dvars::com_developer_script->current.enabled && !force_error_print)
{ {
game::LargeLocalResetToMark(mark_pos); utils::hook::invoke<void>(0x1404E4D00, mark_pos);
return; return;
} }
console::warn("******* script runtime error ********\n"); console::warn("******* script runtime error ********\n");
const auto opcode_id = *reinterpret_cast<std::uint8_t*>(SELECT_VALUE(0x1455BE740, 0x144D57840)); const auto opcode_id = *reinterpret_cast<std::uint8_t*>(0x144D57840);
const std::string error = gsc_error_msg.has_value() ? std::format(": {}", gsc_error_msg.value()) : std::string(); const std::string error = gsc_error_msg.has_value() ? std::format(": {}", gsc_error_msg.value()) : std::string();
@ -226,7 +166,7 @@ namespace gsc
print_callstack(); print_callstack();
console::warn("************************************\n"); console::warn("************************************\n");
game::LargeLocalResetToMark(mark_pos); utils::hook::invoke<void>(0x1404E4D00, mark_pos);
} }
void inc_in_param() void inc_in_param()
@ -288,11 +228,6 @@ namespace gsc
scr_error(utils::string::va("Assert fail: %s", game::Scr_GetString(0))); scr_error(utils::string::va("Assert fail: %s", game::Scr_GetString(0)));
} }
void scr_cmd_is_dedicated_server()
{
game::Scr_AddInt(game::environment::is_dedi());
}
const char* get_code_pos(const int index) const char* get_code_pos(const int index)
{ {
if (static_cast<unsigned int>(index) >= game::scr_VmPub->outparamcount) if (static_cast<unsigned int>(index) >= game::scr_VmPub->outparamcount)
@ -313,22 +248,6 @@ namespace gsc
} }
} }
void add_devmap_entry(std::uint8_t* codepos, std::size_t size, const std::string& name, xsk::gsc::buffer devmap_buf)
{
std::vector<dev_map_instruction> devmap{};
const auto* devmap_ptr = reinterpret_cast<const dev_map*>(devmap_buf.data);
devmap.resize(devmap_ptr->num_instructions);
std::memcpy(devmap.data(), devmap_ptr->instructions, sizeof(dev_map_instruction) * devmap_ptr->num_instructions);
devmap_entries.emplace_back(codepos, size, name, std::move(devmap));
}
void clear_devmap()
{
devmap_entries.clear();
}
void add_function(const std::string& name, game::BuiltinFunction function) void add_function(const std::string& name, game::BuiltinFunction function)
{ {
++function_id_start; ++function_id_start;
@ -352,18 +271,27 @@ namespace gsc
utils::hook::set<game::BuiltinFunction>(SELECT_VALUE(0x14086F468, 0x1409E6CE8), scr_print); utils::hook::set<game::BuiltinFunction>(SELECT_VALUE(0x14086F468, 0x1409E6CE8), scr_print);
utils::hook::set<game::BuiltinFunction>(SELECT_VALUE(0x14086F480, 0x1409E6D00), scr_print_ln); utils::hook::set<game::BuiltinFunction>(SELECT_VALUE(0x14086F480, 0x1409E6D00), scr_print_ln);
utils::hook::set<std::uint32_t>(SELECT_VALUE(0x1403D353B + 1, 0x14042E33B + 1), 0x1000); // Scr_RegisterFunction utils::hook::set<std::uint32_t>(SELECT_VALUE(0x1403D353C, 0x14042E33C), 0x1000); // Scr_RegisterFunction
utils::hook::set<std::uint32_t>(SELECT_VALUE(0x1403D3542 + 4, 0x14042E342 + 4), RVA(&func_table)); // Scr_RegisterFunction utils::hook::set<std::uint32_t>(SELECT_VALUE(0x1403D3542 + 4, 0x14042E342 + 4), RVA(&func_table)); // Scr_RegisterFunction
// utils::hook::set<std::uint32_t>(SELECT_VALUE(0x1403E0BDD + 3, 0x14043BBBE + 3), RVA(&func_table)); // VM_Execute_0 utils::hook::set<std::uint32_t>(SELECT_VALUE(0x1403E0BDD + 3, 0x14043BBBE + 3), RVA(&func_table)); // VM_Execute_0
utils::hook::inject(SELECT_VALUE(0x1403D38E4 + 3, 0x14042E734 + 3), &func_table); // Scr_BeginLoadScripts utils::hook::inject(SELECT_VALUE(0x1403D38E4 + 3, 0x14042E734 + 3), &func_table); // Scr_BeginLoadScripts
utils::hook::nop(SELECT_VALUE(0x1403E0BDD + 5, 0x14043BBBE + 5), 2); if (game::environment::is_sp())
utils::hook::call(SELECT_VALUE(0x1403E0BDD, 0x14043BBBE), vm_call_builtin_function); {
return;
}
utils::hook::call(SELECT_VALUE(0x1403D391F, 0x14042E76F), scr_get_function_stub); utils::hook::nop(0x14043BBBE + 5, 2);
utils::hook::call(0x14043BBBE, vm_call_builtin_function);
utils::hook::call(SELECT_VALUE(0x1403E1ED0, 0x14043CEB1), vm_error_stub); utils::hook::call(0x14043CEB1, vm_error_stub);
utils::hook::call(0x14042E76F, scr_get_function_stub);
utils::hook::set<game::BuiltinFunction>(0x1409E6E38, assert_ex_cmd);
utils::hook::set<game::BuiltinFunction>(0x1409E6E50, assert_msg_cmd);
utils::hook::set<game::BuiltinFunction>(0x1409E6E20, assert_cmd);
add_function("replacefunc", [] add_function("replacefunc", []
{ {
@ -381,16 +309,10 @@ namespace gsc
command::execute(cmd); command::execute(cmd);
}); });
if (game::environment::is_sp()) add_function("isdedicated", []
{ {
return; game::Scr_AddInt(game::environment::is_dedi());
} });
utils::hook::set<game::BuiltinFunction>(0x1409E6E38, assert_ex_cmd);
utils::hook::set<game::BuiltinFunction>(0x1409E6E50, assert_msg_cmd);
utils::hook::set<game::BuiltinFunction>(0x1409E6E20, assert_cmd);
utils::hook::set<game::BuiltinFunction>(0x1409E94D0, scr_cmd_is_dedicated_server);
} }
}; };
} }

View File

@ -1,36 +1,9 @@
#pragma once #pragma once
#include <xsk/gsc/engine/iw6_pc.hpp>
namespace gsc namespace gsc
{ {
extern void* func_table[0x1000]; extern void* func_table[0x1000];
#pragma pack(push, 1)
struct dev_map_instruction
{
std::uint32_t codepos;
std::uint16_t line;
std::uint16_t col;
};
struct dev_map
{
std::uint32_t num_instructions;
dev_map_instruction instructions[1];
};
#pragma pack(pop)
struct devmap_entry
{
const std::uint8_t* bytecode;
std::size_t size;
std::string script_name;
std::vector<dev_map_instruction> devmap;
};
void add_devmap_entry(std::uint8_t*, std::size_t, const std::string&, xsk::gsc::buffer);
void clear_devmap();
void add_function(const std::string& name, game::BuiltinFunction function); void add_function(const std::string& name, game::BuiltinFunction function);
void scr_error(const char* error); void scr_error(const char* error);

View File

@ -3,16 +3,15 @@
#include "game/game.hpp" #include "game/game.hpp"
#include "game/dvars.hpp" #include "game/dvars.hpp"
#include <utils/compression.hpp>
#include <utils/hook.hpp>
#include <utils/io.hpp> #include <utils/io.hpp>
#include <utils/hook.hpp>
#include <utils/memory.hpp> #include <utils/memory.hpp>
#include <utils/compression.hpp>
#include "component/console.hpp"
#include "component/filesystem.hpp" #include "component/filesystem.hpp"
#include "component/console.hpp"
#include "component/scripting.hpp" #include "component/scripting.hpp"
#include "script_extension.hpp"
#include "script_loading.hpp" #include "script_loading.hpp"
namespace gsc namespace gsc
@ -33,7 +32,6 @@ namespace gsc
init_handles.clear(); init_handles.clear();
loaded_scripts.clear(); loaded_scripts.clear();
script_allocator.clear(); script_allocator.clear();
clear_devmap();
} }
bool read_raw_script_file(const std::string& name, std::string* data) bool read_raw_script_file(const std::string& name, std::string* data)
@ -116,12 +114,6 @@ namespace gsc
loaded_scripts[real_name] = script_file_ptr; loaded_scripts[real_name] = script_file_ptr;
const auto devmap = std::get<2>(output_script);
if (devmap.size > 0 && (gsc_ctx->build() & xsk::gsc::build::dev_maps) != xsk::gsc::build::prod)
{
add_devmap_entry(script_file_ptr->bytecode, byte_code_size, real_name, devmap);
}
return script_file_ptr; return script_file_ptr;
} }
catch (const std::exception& ex) catch (const std::exception& ex)
@ -188,9 +180,13 @@ namespace gsc
} }
} }
void load_scripts_from_folder(const std::filesystem::path& root_dir, const std::filesystem::path& script_dir) void load_scripts(const std::filesystem::path& root_dir)
{ {
console::info("Scanning directory '%s' for custom GSC scripts...\n", script_dir.generic_string().data()); const std::filesystem::path script_dir = root_dir / "scripts";
if (!utils::io::directory_exists(script_dir.generic_string()))
{
return;
}
const auto scripts = utils::io::list_files(script_dir.generic_string()); const auto scripts = utils::io::list_files(script_dir.generic_string());
for (const auto& script : scripts) for (const auto& script : scripts)
@ -208,44 +204,6 @@ namespace gsc
} }
} }
void load_scripts(const std::filesystem::path& root_dir)
{
const auto load = [&root_dir](const std::filesystem::path& folder) -> void
{
const std::filesystem::path script_dir = root_dir / folder;
if (utils::io::directory_exists(script_dir.generic_string()))
{
load_scripts_from_folder(root_dir, script_dir);
}
};
const std::filesystem::path base_dir = "scripts";
load(base_dir);
const auto* map_name = game::Dvar_FindVar("mapname");
if (game::environment::is_sp())
{
const std::filesystem::path game_folder = "sp";
load(base_dir / game_folder);
load(base_dir / game_folder / map_name->current.string);
}
else
{
const std::filesystem::path game_folder = "mp";
load(base_dir / game_folder);
load(base_dir / game_folder / map_name->current.string);
const auto* game_type = game::Dvar_FindVar("g_gametype");
load(base_dir / game_folder / game_type->current.string);
}
}
int db_is_x_asset_default(game::XAssetType type, const char* name) int db_is_x_asset_default(game::XAssetType type, const char* name)
{ {
if (loaded_scripts.contains(name)) if (loaded_scripts.contains(name))
@ -260,22 +218,12 @@ namespace gsc
{ {
utils::hook::invoke<void>(0x1403CCB10); utils::hook::invoke<void>(0x1403CCB10);
for (const auto& path : filesystem::get_search_paths()) clear();
{
load_scripts(path);
}
}
int g_scr_load_script_and_label_stub(game::ScriptFunctions* functions)
{
const auto result = utils::hook::invoke<int>(0x140349790, functions);
for (const auto& path : filesystem::get_search_paths()) for (const auto& path : filesystem::get_search_paths())
{ {
load_scripts(path); load_scripts(path);
} }
return result;
} }
void db_get_raw_buffer_stub(const game::RawFile* rawfile, char* buf, const int size) void db_get_raw_buffer_stub(const game::RawFile* rawfile, char* buf, const int size)
@ -302,26 +250,7 @@ namespace gsc
utils::hook::invoke<void>(0x1403D2CA0); utils::hook::invoke<void>(0x1403D2CA0);
} }
void scr_load_level_singleplayer_stub() void scr_load_level_stub()
{
for (auto& function_handle : main_handles)
{
console::info("Executing '%s::main'\n", function_handle.first.data());
const auto thread = game::Scr_ExecThread(static_cast<int>(function_handle.second), 0);
game::RemoveRefToObject(thread);
}
utils::hook::invoke<void>(0x1403401B0);
for (auto& function_handle : init_handles)
{
console::info("Executing '%s::init'\n", function_handle.first.data());
const auto thread = game::Scr_ExecThread(static_cast<int>(function_handle.second), 0);
game::RemoveRefToObject(thread);
}
}
void scr_load_level_multiplayer_stub()
{ {
utils::hook::invoke<void>(0x1403CDC60); utils::hook::invoke<void>(0x1403CDC60);
@ -416,35 +345,31 @@ namespace gsc
utils::hook::call(SELECT_VALUE(0x14032D1E0, 0x1403CCED9), scr_begin_load_scripts_stub); // GScr_LoadScripts utils::hook::call(SELECT_VALUE(0x14032D1E0, 0x1403CCED9), scr_begin_load_scripts_stub); // GScr_LoadScripts
utils::hook::call(SELECT_VALUE(0x14032D345, 0x1403CD08D), scr_end_load_scripts_stub); // GScr_LoadScripts utils::hook::call(SELECT_VALUE(0x14032D345, 0x1403CD08D), scr_end_load_scripts_stub); // GScr_LoadScripts
// ProcessScript
utils::hook::call(SELECT_VALUE(0x1403DC887, 0x1404378D7), find_script);
utils::hook::call(SELECT_VALUE(0x1403DC897, 0x1404378E7), db_is_x_asset_default);
dvars::com_developer_script = game::Dvar_RegisterBool("developer_script", false, game::DVAR_FLAG_NONE, "Enable developer script comments"); dvars::com_developer_script = game::Dvar_RegisterBool("developer_script", false, game::DVAR_FLAG_NONE, "Enable developer script comments");
scripting::on_shutdown([](const int clear_scripts, const int post_shutdown) -> void
{
if (clear_scripts && post_shutdown)
{
clear();
}
});
if (game::environment::is_sp()) if (game::environment::is_sp())
{ {
utils::hook::call(0x14034996F, g_scr_load_script_and_label_stub); return;
utils::hook::call(0x140316591, scr_load_level_singleplayer_stub);
} }
else
{ // ProcessScript
utils::hook::call(0x1404378D7, find_script);
utils::hook::call(0x1404378E7, db_is_x_asset_default);
// GScr_LoadScripts // GScr_LoadScripts
utils::hook::call(0x1403CD009, gscr_load_game_type_script_stub); utils::hook::call(0x1403CD009, gscr_load_game_type_script_stub);
// Exec script handles // Exec script handles
utils::hook::call(0x14039F64E, g_load_structs_stub); utils::hook::call(0x14039F64E, g_load_structs_stub);
utils::hook::call(0x14039F653, scr_load_level_multiplayer_stub); utils::hook::call(0x14039F653, scr_load_level_stub);
scripting::on_shutdown([](int free_scripts)
{
if (free_scripts)
{
clear();
} }
});
} }
}; };
} }

View File

@ -1,157 +0,0 @@
#include <std_include.hpp>
#include "loader/component_loader.hpp"
#include "game/game.hpp"
#include "game/dvars.hpp"
#include "mods.hpp"
#include <utils/hook.hpp>
namespace mods
{
namespace
{
utils::hook::detour sys_create_file_hook;
void db_build_os_path_from_source(const char* zone_name, game::FF_DIR source, unsigned int size, char* filename)
{
char user_map[MAX_PATH]{};
switch (source)
{
case game::FFD_DEFAULT:
(void)sprintf_s(filename, size, "%s\\%s.ff", std::filesystem::current_path().string().c_str(), zone_name);
break;
case game::FFD_MOD_DIR:
assert(mods::is_using_mods());
(void)sprintf_s(filename, size, "%s\\%s\\%s.ff", std::filesystem::current_path().string().c_str(), (*dvars::fs_gameDirVar)->current.string, zone_name);
break;
case game::FFD_USER_MAP:
strncpy_s(user_map, zone_name, _TRUNCATE);
(void)sprintf_s(filename, size, "%s\\%s\\%s\\%s.ff", std::filesystem::current_path().string().c_str(), "usermaps", user_map, zone_name);
break;
default:
assert(false && "inconceivable");
break;
}
}
game::Sys_File sys_create_file_stub(const char* dir, const char* filename)
{
auto result = sys_create_file_hook.invoke<game::Sys_File>(dir, filename);
if (result.handle != INVALID_HANDLE_VALUE)
{
return result;
}
if (!is_using_mods())
{
return result;
}
// .ff extension was added previously
if (!std::strcmp(filename, "mod.ff") && mods::db_mod_file_exists())
{
char file_path[MAX_PATH]{};
db_build_os_path_from_source("mod", game::FFD_MOD_DIR, sizeof(file_path), file_path);
result.handle = game::Sys_OpenFileReliable(file_path);
}
return result;
}
void db_load_x_assets_stub(game::XZoneInfo* zone_info, unsigned int zone_count, game::DBSyncMode sync_mode)
{
std::vector<game::XZoneInfo> zones(zone_info, zone_info + zone_count);
if (db_mod_file_exists())
{
zones.emplace_back("mod", game::DB_ZONE_COMMON | game::DB_ZONE_CUSTOM, 0);
}
game::DB_LoadXAssets(zones.data(), static_cast<unsigned int>(zones.size()), sync_mode);
}
const auto skip_extra_zones_stub = utils::hook::assemble([](utils::hook::assembler& a)
{
const auto skip = a.newLabel();
const auto original = a.newLabel();
a.pushad64();
a.test(ebp, game::DB_ZONE_CUSTOM); // allocFlags
a.jnz(skip);
a.bind(original);
a.popad64();
a.mov(rdx, 0x140835F28);
a.mov(rcx, rsi);
a.call_aligned(strcmp);
a.jmp(0x1403217C0);
a.bind(skip);
a.popad64();
a.mov(r15d, 0x80);
a.not_(r15d);
a.and_(ebp, r15d);
a.jmp(0x1403217F6);
});
}
bool is_using_mods()
{
return (*dvars::fs_gameDirVar) && *(*dvars::fs_gameDirVar)->current.string;
}
bool db_mod_file_exists()
{
if (!*(*dvars::fs_gameDirVar)->current.string)
{
return false;
}
char filename[MAX_PATH]{};
db_build_os_path_from_source("mod", game::FFD_MOD_DIR, sizeof(filename), filename);
if (auto zone_file = game::Sys_OpenFileReliable(filename); zone_file != INVALID_HANDLE_VALUE)
{
::CloseHandle(zone_file);
return true;
}
return false;
}
class component final : public component_interface
{
public:
static_assert(sizeof(game::Sys_File) == 8);
void post_unpack() override
{
dvars::fs_gameDirVar = reinterpret_cast<game::dvar_t**>(SELECT_VALUE(0x145856D38, 0x147876000));
// Remove DVAR_INIT from fs_game
utils::hook::set<std::uint32_t>(SELECT_VALUE(0x14041C085 + 2, 0x1404DDA45 + 2), SELECT_VALUE(game::DVAR_FLAG_NONE, game::DVAR_FLAG_SERVERINFO));
if (game::environment::is_sp())
{
return;
}
// Don't load eng_ + patch_ with loadzone
utils::hook::nop(0x1403217B1, 15);
utils::hook::jump(0x1403217B1, skip_extra_zones_stub, true);
// Add custom zone paths
sys_create_file_hook.create(game::Sys_CreateFile, sys_create_file_stub);
// Load mod.ff
utils::hook::call(0x1405E7113, db_load_x_assets_stub); // R_LoadGraphicsAssets According to myself but I don't remember where I got it from
}
};
}
REGISTER_COMPONENT(mods::component)

View File

@ -1,7 +0,0 @@
#pragma once
namespace mods
{
bool is_using_mods();
bool db_mod_file_exists();
}

View File

@ -20,7 +20,7 @@ namespace network
return callbacks; return callbacks;
} }
bool handle_command(game::netadr_s* address, const char* command, game::msg_t* message) bool handle_command(game::netadr_t* address, const char* command, game::msg_t* message)
{ {
const auto cmd_string = utils::string::to_lower(command); const auto cmd_string = utils::string::to_lower(command);
auto& callbacks = get_callbacks(); auto& callbacks = get_callbacks();
@ -61,7 +61,7 @@ namespace network
a.jmp(0x1402C64EE); a.jmp(0x1402C64EE);
} }
int net_compare_base_address(const game::netadr_s* a1, const game::netadr_s* a2) int net_compare_base_address(const game::netadr_t* a1, const game::netadr_t* a2)
{ {
if (a1->type == a2->type) if (a1->type == a2->type)
{ {
@ -83,12 +83,12 @@ namespace network
return false; return false;
} }
int net_compare_address(const game::netadr_s* a1, const game::netadr_s* a2) int net_compare_address(const game::netadr_t* a1, const game::netadr_t* a2)
{ {
return net_compare_base_address(a1, a2) && a1->port == a2->port; return net_compare_base_address(a1, a2) && a1->port == a2->port;
} }
void reconnect_migrated_client(game::mp::client_t*, game::netadr_s* from, const int, const int, const char*, const char*, bool) void reconnect_migrated_client(game::mp::client_t*, game::netadr_t* from, const int, const int, const char*, const char*, bool)
{ {
// This happens when a client tries to rejoin after being recently disconnected, OR by a duplicated guid // This happens when a client tries to rejoin after being recently disconnected, OR by a duplicated guid
// We don't want this to do anything. It decides to crash seemingly randomly // We don't want this to do anything. It decides to crash seemingly randomly
@ -107,14 +107,14 @@ namespace network
get_callbacks()[utils::string::to_lower(command)] = callback; get_callbacks()[utils::string::to_lower(command)] = callback;
} }
int dw_send_to_stub(const int size, const char* src, game::netadr_s* addr) int dw_send_to_stub(const int size, const char* src, game::netadr_t* addr)
{ {
sockaddr s = {}; sockaddr s = {};
game::NetadrToSockadr(addr, &s); game::NetadrToSockadr(addr, &s);
return sendto(*game::query_socket, src, size, 0, &s, 16) >= 0; return sendto(*game::query_socket, src, size, 0, &s, 16) >= 0;
} }
void send(const game::netadr_s& address, const std::string& command, const std::string& data, const char separator) void send(const game::netadr_t& address, const std::string& command, const std::string& data, const char separator)
{ {
std::string packet = "\xFF\xFF\xFF\xFF"; std::string packet = "\xFF\xFF\xFF\xFF";
packet.append(command); packet.append(command);
@ -124,7 +124,7 @@ namespace network
send_data(address, packet); send_data(address, packet);
} }
void send_data(const game::netadr_s& address, const std::string& data) void send_data(const game::netadr_t& address, const std::string& data)
{ {
if (address.type == game::NA_LOOPBACK) if (address.type == game::NA_LOOPBACK)
{ {
@ -136,12 +136,12 @@ namespace network
} }
} }
bool are_addresses_equal(const game::netadr_s& a, const game::netadr_s& b) bool are_addresses_equal(const game::netadr_t& a, const game::netadr_t& b)
{ {
return net_compare_address(&a, &b); return net_compare_address(&a, &b);
} }
const char* net_adr_to_string(const game::netadr_s& a) const char* net_adr_to_string(const game::netadr_t& a)
{ {
if (a.type == game::NA_LOOPBACK) if (a.type == game::NA_LOOPBACK)
{ {
@ -286,7 +286,7 @@ namespace network
if (!game::environment::is_dedi()) if (!game::environment::is_dedi())
{ {
// we need this on the client for RCon // we need this on the client for RCon
on("print", [](const game::netadr_s& address, const std::string& message) on("print", [](const game::netadr_t& address, const std::string& message)
{ {
if (address != party::get_target()) if (address != party::get_target())
{ {

View File

@ -2,23 +2,23 @@
namespace network namespace network
{ {
using callback = std::function<void(const game::netadr_s&, const std::string&)>; using callback = std::function<void(const game::netadr_t&, const std::string&)>;
void on(const std::string& command, const callback& callback); void on(const std::string& command, const callback& callback);
void send(const game::netadr_s& address, const std::string& command, const std::string& data = {}, char separator = ' '); void send(const game::netadr_t& address, const std::string& command, const std::string& data = {}, char separator = ' ');
void send_data(const game::netadr_s& address, const std::string& data); void send_data(const game::netadr_t& address, const std::string& data);
bool are_addresses_equal(const game::netadr_s& a, const game::netadr_s& b); bool are_addresses_equal(const game::netadr_t& a, const game::netadr_t& b);
const char* net_adr_to_string(const game::netadr_s& a); const char* net_adr_to_string(const game::netadr_t& a);
} }
inline bool operator==(const game::netadr_s& a, const game::netadr_s& b) inline bool operator==(const game::netadr_t& a, const game::netadr_t& b)
{ {
return network::are_addresses_equal(a, b); // return network::are_addresses_equal(a, b); //
} }
inline bool operator!=(const game::netadr_s& a, const game::netadr_s& b) inline bool operator!=(const game::netadr_t& a, const game::netadr_t& b)
{ {
return !(a == b); // return !(a == b); //
} }
@ -26,20 +26,20 @@ inline bool operator!=(const game::netadr_s& a, const game::netadr_s& b)
namespace std namespace std
{ {
template <> template <>
struct equal_to<game::netadr_s> struct equal_to<game::netadr_t>
{ {
using result_type = bool; using result_type = bool;
bool operator()(const game::netadr_s& lhs, const game::netadr_s& rhs) const bool operator()(const game::netadr_t& lhs, const game::netadr_t& rhs) const
{ {
return network::are_addresses_equal(lhs, rhs); return network::are_addresses_equal(lhs, rhs);
} }
}; };
template <> template <>
struct hash<game::netadr_s> struct hash<game::netadr_t>
{ {
size_t operator()(const game::netadr_s& x) const noexcept size_t operator()(const game::netadr_t& x) const noexcept
{ {
return hash<uint32_t>()(*reinterpret_cast<const uint32_t*>(&x.ip[0])) ^ hash<uint16_t>()(x.port); return hash<uint32_t>()(*reinterpret_cast<const uint32_t*>(&x.ip[0])) ^ hash<uint16_t>()(x.port);
} }

View File

@ -61,7 +61,7 @@ namespace notifies
scheduler::once([params, message, client_num] scheduler::once([params, message, client_num]
{ {
const auto* guid = game::SV_GetGuid(client_num); const auto* guid = game::SV_GetGuid(client_num);
const auto* name = game::mp::svs_clients[client_num].name; const auto* name = game::mp::svs->clients[client_num].name;
game_log::g_log_printf("%s;%s;%i;%s;%s\n", game_log::g_log_printf("%s;%s;%i;%s;%s\n",
params.get(0), params.get(0),
@ -126,7 +126,7 @@ namespace notifies
a.lea(eax, dword_ptr(r15, -0x17)); a.lea(eax, dword_ptr(r15, -0x17));
a.mov(dword_ptr(rbp, 0x60), r15d); a.mov(dword_ptr(rbp, 0x60), r15d);
a.jmp(SELECT_VALUE(0x1403DF5B3, 0x14043A593)); a.jmp(0x14043A593);
a.bind(replace); a.bind(replace);
@ -174,22 +174,22 @@ namespace notifies
public: public:
void post_unpack() override void post_unpack() override
{ {
utils::hook::jump(SELECT_VALUE(0x1403DF5A4, 0x14043A584), utils::hook::assemble(vm_execute_stub), true);
scripting::on_shutdown([](const int clear_scripts, const int post_shutdown) -> void
{
if (clear_scripts && post_shutdown)
{
vm_execute_hooks.clear();
}
});
if (game::environment::is_sp()) if (game::environment::is_sp())
{ {
return; return;
} }
utils::hook::call(0x1404724DD, client_command_stub); utils::hook::call(0x1404724DD, client_command_stub);
utils::hook::jump(0x14043A584, utils::hook::assemble(vm_execute_stub), true);
scripting::on_shutdown([](const bool free_scripts)
{
if (free_scripts)
{
vm_execute_hooks.clear();
}
});
} }
}; };
} }

View File

@ -26,7 +26,7 @@ namespace party
{ {
struct struct
{ {
game::netadr_s host{}; game::netadr_t host{};
std::string challenge{}; std::string challenge{};
bool hostDefined{false}; bool hostDefined{false};
} connect_state; } connect_state;
@ -37,7 +37,7 @@ namespace party
int sv_maxclients; int sv_maxclients;
void connect_to_party(const game::netadr_s& target, const std::string& mapname, const std::string& gametype) void connect_to_party(const game::netadr_t& target, const std::string& mapname, const std::string& gametype)
{ {
if (game::environment::is_sp()) if (game::environment::is_sp())
{ {
@ -58,7 +58,7 @@ namespace party
// CL_ConnectFromParty // CL_ConnectFromParty
char session_info[0x100] = {}; char session_info[0x100] = {};
reinterpret_cast<void(*)(int, char*, const game::netadr_s*, const char*, const char*)>(0x1402C5700)( reinterpret_cast<void(*)(int, char*, const game::netadr_t*, const char*, const char*)>(0x1402C5700)(
0, session_info, &target, mapname.data(), gametype.data()); 0, session_info, &target, mapname.data(), gametype.data());
} }
@ -81,26 +81,6 @@ namespace party
a.mov(ecx, 2); a.mov(ecx, 2);
a.jmp(0x1402C617D); a.jmp(0x1402C617D);
}); });
utils::info_string get_info()
{
utils::info_string info;
info.set("gamename", "IW6");
info.set("hostname", dvars::get_string("sv_hostname"));
info.set("gametype", dvars::get_string("g_gametype"));
info.set("sv_motd", dvars::get_string("sv_motd"));
info.set("xuid", utils::string::va("%llX", steam::SteamUser()->GetSteamID().bits));
info.set("mapname", dvars::get_string("mapname"));
info.set("isPrivate", dvars::get_string("g_password").empty() ? "0" : "1");
info.set("clients", std::to_string(get_client_count()));
info.set("bots", std::to_string(get_bot_count()));
info.set("sv_maxclients", std::to_string(*game::mp::svs_clientCount));
info.set("protocol", std::to_string(PROTOCOL));
info.set("shortversion", SHORTVERSION);
return info;
}
} }
void switch_gamemode_if_necessary(const std::string& gametype) void switch_gamemode_if_necessary(const std::string& gametype)
@ -140,9 +120,9 @@ namespace party
int get_client_count() int get_client_count()
{ {
auto count = 0; auto count = 0;
for (auto i = 0; i < *game::mp::svs_clientCount; ++i) for (auto i = 0; i < game::mp::svs->clientCount; ++i)
{ {
if (game::mp::svs_clients[i].header.state >= game::CS_CONNECTED) if (game::mp::svs->clients[i].header.state >= game::CS_CONNECTED)
{ {
++count; ++count;
} }
@ -154,10 +134,10 @@ namespace party
int get_bot_count() int get_bot_count()
{ {
auto count = 0; auto count = 0;
for (auto i = 0; i < *game::mp::svs_clientCount; ++i) for (auto i = 0; i < game::mp::svs->clientCount; ++i)
{ {
if (game::mp::svs_clients[i].header.state >= game::CS_CONNECTED && if (game::mp::svs->clients[i].header.state >= game::CS_CONNECTED &&
game::mp::svs_clients[i].testClient != game::TC_NONE) game::mp::svs->clients[i].testClient != game::TC_NONE)
{ {
++count; ++count;
} }
@ -166,7 +146,7 @@ namespace party
return count; return count;
} }
game::netadr_s& get_target() game::netadr_t& get_target()
{ {
return connect_state.host; return connect_state.host;
} }
@ -178,7 +158,7 @@ namespace party
int get_client_num_from_name(const std::string& name) int get_client_num_from_name(const std::string& name)
{ {
for (auto i = 0; !name.empty() && i < *game::mp::svs_clientCount; ++i) for (auto i = 0; !name.empty() && i < game::mp::svs->clientCount; ++i)
{ {
if (game::mp::g_entities[i].client) if (game::mp::g_entities[i].client)
{ {
@ -195,7 +175,7 @@ namespace party
return -1; return -1;
} }
void connect(const game::netadr_s& target) void connect(const game::netadr_t& target)
{ {
if (game::environment::is_sp()) if (game::environment::is_sp())
{ {
@ -272,7 +252,7 @@ namespace party
return; return;
} }
game::netadr_s target{}; game::netadr_t target{};
if (game::NET_StringToAdr(params[1], &target)) if (game::NET_StringToAdr(params[1], &target))
{ {
connect(target); connect(target);
@ -303,7 +283,7 @@ namespace party
} }
const auto client_num = atoi(params.get(1)); const auto client_num = atoi(params.get(1));
if (client_num < 0 || client_num >= *game::mp::svs_clientCount) if (client_num < 0 || client_num >= game::mp::svs->clientCount)
{ {
return; return;
} }
@ -340,7 +320,7 @@ namespace party
const std::string name = params.get(1); const std::string name = params.get(1);
if (name == "all"s) if (name == "all"s)
{ {
for (auto i = 0; i < *game::mp::svs_clientCount; ++i) for (auto i = 0; i < game::mp::svs->clientCount; ++i)
{ {
scheduler::once([i, reason] scheduler::once([i, reason]
{ {
@ -351,7 +331,7 @@ namespace party
} }
const auto client_num = get_client_num_from_name(name); const auto client_num = get_client_num_from_name(name);
if (client_num < 0 || client_num >= *game::mp::svs_clientCount) if (client_num < 0 || client_num >= game::mp::svs->clientCount)
{ {
return; return;
} }
@ -380,7 +360,7 @@ namespace party
const auto message = params.join(2); const auto message = params.join(2);
const auto* const name = game::Dvar_FindVar("sv_sayName")->current.string; const auto* const name = game::Dvar_FindVar("sv_sayName")->current.string;
game::SV_GameSendServerCommand(client_num, game::SV_CMD_CAN_IGNORE, utils::string::va("%c \"%s: %s\"", 84, name, message.data())); game::SV_GameSendServerCommand(client_num, 0, utils::string::va("%c \"%s: %s\"", 84, name, message.data()));
console::info("%s -> %i: %s\n", name, client_num, message.data()); console::info("%s -> %i: %s\n", name, client_num, message.data());
}); });
@ -394,7 +374,7 @@ namespace party
const auto client_num = atoi(params.get(1)); const auto client_num = atoi(params.get(1));
const auto message = params.join(2); const auto message = params.join(2);
game::SV_GameSendServerCommand(client_num, game::SV_CMD_CAN_IGNORE, utils::string::va("%c \"%s\"", 84, message.data())); game::SV_GameSendServerCommand(client_num, 0, utils::string::va("%c \"%s\"", 84, message.data()));
console::info("%i: %s\n", client_num, message.data()); console::info("%i: %s\n", client_num, message.data());
}); });
@ -408,7 +388,7 @@ namespace party
const auto message = params.join(1); const auto message = params.join(1);
const auto* const name = game::Dvar_FindVar("sv_sayName")->current.string; const auto* const name = game::Dvar_FindVar("sv_sayName")->current.string;
game::SV_GameSendServerCommand(-1, game::SV_CMD_CAN_IGNORE, utils::string::va("%c \"%s: %s\"", 84, name, message.data())); game::SV_GameSendServerCommand(-1, 0, utils::string::va("%c \"%s: %s\"", 84, name, message.data()));
console::info("%s: %s\n", name, message.data()); console::info("%s: %s\n", name, message.data());
}); });
@ -421,67 +401,36 @@ namespace party
const auto message = params.join(1); const auto message = params.join(1);
game::SV_GameSendServerCommand(-1, game::SV_CMD_CAN_IGNORE, utils::string::va("%c \"%s\"", 84, message.data())); game::SV_GameSendServerCommand(-1, 0, utils::string::va("%c \"%s\"", 84, message.data()));
console::info("%s\n", message.data()); console::info("%s\n", message.data());
}); });
network::on("getInfo", [](const game::netadr_s& target, const std::string& data) network::on("getInfo", [](const game::netadr_t& target, const std::string& data)
{ {
utils::info_string info = get_info(); utils::info_string info;
info.set("challenge", data); info.set("challenge", data);
info.set("gamename", "IW6");
info.set("hostname", dvars::get_string("sv_hostname"));
info.set("gametype", dvars::get_string("g_gametype"));
info.set("sv_motd", dvars::get_string("sv_motd"));
info.set("xuid", utils::string::va("%llX", steam::SteamUser()->GetSteamID().bits));
info.set("mapname", dvars::get_string("mapname"));
info.set("isPrivate", dvars::get_string("g_password").empty() ? "0" : "1");
info.set("clients", std::to_string(get_client_count()));
info.set("bots", std::to_string(get_bot_count()));
info.set("sv_maxclients", std::to_string(game::mp::svs->clientCount));
info.set("protocol", std::to_string(PROTOCOL));
info.set("shortversion", SHORTVERSION);
network::send(target, "infoResponse", info.build(), '\n'); network::send(target, "infoResponse", info.build(), '\n');
}); });
network::on("getStatus", [](const game::netadr_s& target, const std::string& data)
{
std::string player_list;
utils::info_string info = get_info();
info.set("challenge", data);
const auto* sv_running = game::Dvar_FindVar("sv_running");
if (!sv_running || !sv_running->current.enabled)
{
return;
}
for (auto i = 0; i < game::Dvar_FindVar("sv_maxclients")->current.integer; ++i)
{
auto* client = &game::mp::svs_clients[i];
auto* self = &game::mp::g_entities[i];
if (client->header.state < game::CS_ACTIVE)
{
continue;
}
if (!self || !self->client)
{
continue;
}
if (game::SV_BotIsBot(i))
{
continue;
}
const auto score = game::G_GetClientScore(i);
const auto ping = game::mp::svs_clients[i].ping;
const std::string name = game::mp::svs_clients[i].name;
player_list.append(std::format("{} {} \"{}\"\n", score, ping, name));
}
network::send(target, "statusResponse", info.build() + "\n"s + player_list + "\n"s, '\n');
});
if (game::environment::is_dedi()) if (game::environment::is_dedi())
{ {
return; return;
} }
network::on("infoResponse", [](const game::netadr_s& target, const std::string& data) network::on("infoResponse", [](const game::netadr_t& target, const std::string& data)
{ {
const utils::info_string info(data); const utils::info_string info(data);
server_list::handle_info_response(target, info); server_list::handle_info_response(target, info);

View File

@ -7,7 +7,7 @@ namespace party
void reset_connect_state(); void reset_connect_state();
void connect(const game::netadr_s& target); void connect(const game::netadr_t& target);
void map_restart(); void map_restart();
[[nodiscard]] int server_client_count(); [[nodiscard]] int server_client_count();
@ -15,5 +15,5 @@ namespace party
[[nodiscard]] int get_client_count(); [[nodiscard]] int get_client_count();
[[nodiscard]] int get_bot_count(); [[nodiscard]] int get_bot_count();
[[nodiscard]] game::netadr_s& get_target(); [[nodiscard]] game::netadr_t& get_target();
} }

View File

@ -150,7 +150,7 @@ namespace patches
return 0; return 0;
} }
game::Font_s* get_chat_font_handle() game::Font_t* get_chat_font_handle()
{ {
return game::R_RegisterFont("fonts/bigFont"); return game::R_RegisterFont("fonts/bigFont");
} }
@ -187,11 +187,11 @@ namespace patches
} }
utils::hook::detour cmd_lui_notify_server_hook; utils::hook::detour cmd_lui_notify_server_hook;
void cmd_lui_notify_server_stub(game::mp::gentity_s* ent) void cmd_lui_notify_server_stub(game::mp::gentity_t* ent)
{ {
command::params_sv params{}; command::params_sv params{};
const auto menu_id = atoi(params.get(1)); const auto menu_id = atoi(params.get(1));
const auto client = &game::mp::svs_clients[ent->s.clientNum]; const auto client = &game::mp::svs->clients[ent->s.clientNum];
// 9 => "end_game" // 9 => "end_game"
if (menu_id == 9 && client->header.netchan.remoteAddress.type != game::NA_LOOPBACK) if (menu_id == 9 && client->header.netchan.remoteAddress.type != game::NA_LOOPBACK)

View File

@ -14,11 +14,11 @@ namespace rcon
namespace namespace
{ {
bool is_redirecting_ = false; bool is_redirecting_ = false;
game::netadr_s redirect_target_ = {}; game::netadr_t redirect_target_ = {};
std::string redirect_buffer = {}; std::string redirect_buffer = {};
std::recursive_mutex redirect_lock; std::recursive_mutex redirect_lock;
void setup_redirect(const game::netadr_s& target) void setup_redirect(const game::netadr_t& target)
{ {
std::lock_guard<std::recursive_mutex> $(redirect_lock); std::lock_guard<std::recursive_mutex> $(redirect_lock);
@ -50,7 +50,7 @@ namespace rcon
for (int i = 0; i < sv_maxclients->current.integer; i++) for (int i = 0; i < sv_maxclients->current.integer; i++)
{ {
const auto client = &game::mp::svs_clients[i]; const auto client = &game::mp::svs->clients[i];
auto self = &game::mp::g_entities[i]; auto self = &game::mp::g_entities[i];
char clean_name[32]{}; char clean_name[32]{};
@ -92,7 +92,7 @@ namespace rcon
if (*reinterpret_cast<std::int32_t*>(0x1419E1AE0) >= 5) //clientUIActive.connectionState >= CA_CONNECTED if (*reinterpret_cast<std::int32_t*>(0x1419E1AE0) >= 5) //clientUIActive.connectionState >= CA_CONNECTED
{ {
const auto target = *reinterpret_cast<game::netadr_s*>(0x141CB535C); const auto target = *reinterpret_cast<game::netadr_t*>(0x141CB535C);
const auto buffer = password + " " + data; const auto buffer = password + " " + data;
network::send(target, "rcon", buffer); network::send(target, "rcon", buffer);
} }
@ -170,7 +170,7 @@ namespace rcon
} }
else else
{ {
network::on("rcon", [](const game::netadr_s& addr, const std::string& data) network::on("rcon", [](const game::netadr_t& addr, const std::string& data)
{ {
const auto pos = data.find_first_of(" "); const auto pos = data.find_first_of(" ");
if (pos == std::string::npos) if (pos == std::string::npos)

View File

@ -34,7 +34,7 @@ namespace scripting
std::unordered_map<unsigned int, std::string> canonical_string_table; std::unordered_map<unsigned int, std::string> canonical_string_table;
std::vector<std::function<void(int, int)>> shutdown_callbacks; std::vector<std::function<void(int)>> shutdown_callbacks;
std::vector<std::function<void()>> init_callbacks; std::vector<std::function<void()>> init_callbacks;
void scr_load_level_stub() void scr_load_level_stub()
@ -47,9 +47,9 @@ namespace scripting
} }
} }
void g_shutdown_game_stub(const int clear_scripts) void g_shutdown_game_stub(const int free_scripts)
{ {
if (clear_scripts) if (free_scripts)
{ {
script_function_table_sort.clear(); script_function_table_sort.clear();
script_function_table.clear(); script_function_table.clear();
@ -59,15 +59,10 @@ namespace scripting
for (const auto& callback : shutdown_callbacks) for (const auto& callback : shutdown_callbacks)
{ {
callback(clear_scripts ,false); callback(free_scripts);
} }
g_shutdown_game_hook.invoke<void>(clear_scripts); return g_shutdown_game_hook.invoke<void>(free_scripts);
for (const auto& callback : shutdown_callbacks)
{
callback(clear_scripts, true);
}
} }
void process_script_stub(const char* filename) void process_script_stub(const char* filename)
@ -170,7 +165,7 @@ namespace scripting
return find_token(id); return find_token(id);
} }
void on_shutdown(const std::function<void(int, int)>& callback) void on_shutdown(const std::function<void(int)>& callback)
{ {
shutdown_callbacks.push_back(callback); shutdown_callbacks.push_back(callback);
} }

View File

@ -8,7 +8,7 @@ namespace scripting
extern std::string current_file; extern std::string current_file;
void on_shutdown(const std::function<void(int, int)>& callback); void on_shutdown(const std::function<void(int)>& callback);
void on_init(const std::function<void()>& callback); void on_init(const std::function<void()>& callback);
std::optional<std::string> get_canonical_string(unsigned int id); std::optional<std::string> get_canonical_string(unsigned int id);

View File

@ -33,14 +33,14 @@ namespace server_list
std::string map_name; std::string map_name;
std::string game_type; std::string game_type;
char in_game; char in_game;
game::netadr_s address; game::netadr_t address;
}; };
struct struct
{ {
game::netadr_s address{}; game::netadr_t address{};
volatile bool requesting = false; volatile bool requesting = false;
std::unordered_map<game::netadr_s, int> queued_servers{}; std::unordered_map<game::netadr_t, int> queued_servers{};
} master_state; } master_state;
volatile bool update_server_list = false; volatile bool update_server_list = false;
@ -307,12 +307,12 @@ namespace server_list
} }
} }
bool get_master_server(game::netadr_s& address) bool get_master_server(game::netadr_t& address)
{ {
return game::NET_StringToAdr("server.alterware.dev:20810", &address); return game::NET_StringToAdr("server.alterware.dev:20810", &address);
} }
void handle_info_response(const game::netadr_s& address, const utils::info_string& info) void handle_info_response(const game::netadr_t& address, const utils::info_string& info)
{ {
int start_time{}; int start_time{};
const auto now = game::Sys_Milliseconds(); const auto now = game::Sys_Milliseconds();
@ -436,7 +436,7 @@ namespace server_list
scheduler::loop(do_frame_work, scheduler::pipeline::main); scheduler::loop(do_frame_work, scheduler::pipeline::main);
network::on("getServersResponse", [](const game::netadr_s& target, const std::string& data) network::on("getServersResponse", [](const game::netadr_t& target, const std::string& data)
{ {
{ {
std::lock_guard<std::mutex> _(mutex); std::lock_guard<std::mutex> _(mutex);
@ -469,7 +469,7 @@ namespace server_list
break; break;
} }
game::netadr_s address{}; game::netadr_t address{};
address.type = game::NA_IP; address.type = game::NA_IP;
address.localNetID = game::NS_CLIENT1; address.localNetID = game::NS_CLIENT1;
std::memcpy(&address.ip[0], data.data() + i + 0, 4); std::memcpy(&address.ip[0], data.data() + i + 0, 4);

View File

@ -3,8 +3,8 @@
namespace server_list namespace server_list
{ {
bool get_master_server(game::netadr_s& address); bool get_master_server(game::netadr_t& address);
void handle_info_response(const game::netadr_s& address, const utils::info_string& info); void handle_info_response(const game::netadr_t& address, const utils::info_string& info);
bool sl_key_event(int key, int down); bool sl_key_event(int key, int down);
} }

View File

@ -50,8 +50,8 @@ namespace slowmotion
for (auto i = 0; i < game::Dvar_FindVar("sv_maxclients")->current.integer; i++) for (auto i = 0; i < game::Dvar_FindVar("sv_maxclients")->current.integer; i++)
{ {
auto* client = &game::mp::svs_clients[i]; auto* client = &game::mp::svs->clients[i];
client->nextSnapshotTime = *game::mp::serverTime - 1; client->nextSnapshotTime = game::mp::svs->time - 1;
} }
} }
} }

View File

@ -46,9 +46,7 @@ namespace dvars
game::dvar_t* cg_legacyCrashHandling = nullptr; game::dvar_t* cg_legacyCrashHandling = nullptr;
game::dvar_t* com_developer_script = nullptr; game::dvar_t* com_developer_script = nullptr;
game::dvar_t** com_developer = nullptr; game::dvar_t** com_developer;
game::dvar_t** fs_gameDirVar = nullptr;
std::string dvar_get_vector_domain(const int components, const game::dvar_limits& domain) std::string dvar_get_vector_domain(const int components, const game::dvar_limits& domain)
{ {

View File

@ -47,8 +47,6 @@ namespace dvars
extern game::dvar_t* com_developer_script; extern game::dvar_t* com_developer_script;
extern game::dvar_t** com_developer; extern game::dvar_t** com_developer;
extern game::dvar_t** fs_gameDirVar;
std::string dvar_get_vector_domain(int components, const game::dvar_limits& domain); std::string dvar_get_vector_domain(int components, const game::dvar_limits& domain);
std::string dvar_get_domain(game::dvar_type type, const game::dvar_limits& domain); std::string dvar_get_domain(game::dvar_type type, const game::dvar_limits& domain);
} }

View File

@ -25,13 +25,6 @@ namespace game
return sv_cmd_args->argv[sv_cmd_args->nesting][index]; return sv_cmd_args->argv[sv_cmd_args->nesting][index];
} }
HANDLE Sys_OpenFileReliable(const char* filename)
{
return ::CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, nullptr,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, nullptr);
}
namespace environment namespace environment
{ {
launcher::mode mode = launcher::mode::none; launcher::mode mode = launcher::mode::none;

View File

@ -63,8 +63,6 @@ namespace game
[[nodiscard]] int SV_Cmd_Argc(); [[nodiscard]] int SV_Cmd_Argc();
[[nodiscard]] const char* SV_Cmd_Argv(int index); [[nodiscard]] const char* SV_Cmd_Argv(int index);
[[nodiscard]] HANDLE Sys_OpenFileReliable(const char* filename);
[[nodiscard]] bool is_headless(); [[nodiscard]] bool is_headless();
void show_error(const std::string& text, const std::string& title = "Error"); void show_error(const std::string& text, const std::string& title = "Error");

View File

@ -47,12 +47,6 @@ namespace game
PMF_UNK3 = 0x4000, PMF_UNK3 = 0x4000,
}; };
enum svscmd_type
{
SV_CMD_CAN_IGNORE,
SV_CMD_RELIABLE,
};
enum XAssetType enum XAssetType
{ {
ASSET_TYPE_PHYSPRESET = 0x0, ASSET_TYPE_PHYSPRESET = 0x0,
@ -133,19 +127,6 @@ namespace game
DB_LOAD_SYNC_SKIP_ALWAYS_LOADED = 0x5, DB_LOAD_SYNC_SKIP_ALWAYS_LOADED = 0x5,
}; };
enum
{
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 = 0x80,
};
enum enum
{ {
THREAD_CONTEXT_MAIN = 0x0, THREAD_CONTEXT_MAIN = 0x0,
@ -200,7 +181,7 @@ namespace game
static_assert(sizeof(db_internal_state) == 0x20); static_assert(sizeof(db_internal_state) == 0x20);
struct db_z_stream_s struct db_z_stream_t
{ {
unsigned char* next_in; unsigned char* next_in;
unsigned int avail_in; unsigned int avail_in;
@ -235,7 +216,7 @@ namespace game
unsigned char* start_in; unsigned char* start_in;
_OVERLAPPED overlapped; _OVERLAPPED overlapped;
unsigned int readError; unsigned int readError;
db_z_stream_s stream; db_z_stream_t stream;
int readingResident; int readingResident;
}; };
@ -811,6 +792,22 @@ namespace game
enum ConfigString enum ConfigString
{ {
CS_TIMESCALE = 0xA,
CS_VISIONSET_NORMAL = 0x49C,
CS_VISIONSET_NIGHT = 0x49D,
CS_VISIONSET_MISSILECAM = 0x49E,
CS_VISIONSET_THERMAL = 0x49F,
CS_VISIONSET_PAIN = 0x4A0,
CS_VISIONSET_POST_APPLY = 0x4A1,
CS_VISIONSET_FIRST = CS_VISIONSET_NORMAL,
CS_VISIONSET_LAST = CS_VISIONSET_POST_APPLY,
CS_VISIONSET_COUNT = CS_VISIONSET_POST_APPLY - CS_VISIONSET_NORMAL + 1
// many of the indices below are incorrect
/*
CS_FIRST = 0x0, CS_FIRST = 0x0,
CS_SERVERINFO = 0x0, CS_SERVERINFO = 0x0,
CS_SYSTEMINFO = 0x1, CS_SYSTEMINFO = 0x1,
@ -882,7 +879,8 @@ namespace game
CS_MP_ANIMS_LAST = 0xD21, CS_MP_ANIMS_LAST = 0xD21,
CS_ITEMS = 0xD22, CS_ITEMS = 0xD22,
CS_LEADERBOARDS = 0xD23, CS_LEADERBOARDS = 0xD23,
MAX_CONFIGSTRINGS = 0xD24, MAX_CONFIGSTRINGS = 0xD24
*/
}; };
enum LiveClientDropType enum LiveClientDropType
@ -1083,7 +1081,7 @@ namespace game
float t1; float t1;
}; };
struct Font_s struct Font_t
{ {
const char* fontName; const char* fontName;
int pixelHeight; int pixelHeight;
@ -1125,7 +1123,6 @@ namespace game
DVAR_FLAG_LATCHED = 0x2, DVAR_FLAG_LATCHED = 0x2,
DVAR_FLAG_CHEAT = 0x4, DVAR_FLAG_CHEAT = 0x4,
DVAR_FLAG_REPLICATED = 0x8, DVAR_FLAG_REPLICATED = 0x8,
DVAR_FLAG_SERVERINFO = 0x400,
DVAR_FLAG_WRITE = 0x800, DVAR_FLAG_WRITE = 0x800,
DVAR_FLAG_READ = 0x2000, DVAR_FLAG_READ = 0x2000,
}; };
@ -1202,9 +1199,9 @@ namespace game
const char** argv[8]; const char** argv[8];
}; };
struct cmd_function_s struct cmd_function_t
{ {
cmd_function_s* next; cmd_function_t* next;
const char* name; const char* name;
void (__cdecl* function)(); void (__cdecl* function)();
}; };
@ -1255,7 +1252,7 @@ namespace game
WEAPON_HAND_DEFAULT = 0x0, WEAPON_HAND_DEFAULT = 0x0,
}; };
struct usercmd_s struct usercmd_t
{ {
int serverTime; int serverTime;
unsigned int buttons; unsigned int buttons;
@ -1309,6 +1306,16 @@ namespace game
vec2_t corridorSpeeds; vec2_t corridorSpeeds;
}; };
struct ClientArchiveData
{
int serverTime;
vec3_t origin;
vec3_t velocity;
int bobCycle;
int movementDir;
PlayerVehicleState playerVehStateClientArchive;
};
struct PlayerActiveWeaponState struct PlayerActiveWeaponState
{ {
int weapAnim; int weapAnim;
@ -1331,7 +1338,7 @@ namespace game
bool hybridScope; bool hybridScope;
}; };
struct compressedAnimData_s struct compressedAnimData_t
{ {
int flags; int flags;
int animRate; int animRate;
@ -1350,7 +1357,7 @@ namespace game
int flags; int flags;
int startTime; int startTime;
float startPosition[3]; float startPosition[3];
compressedAnimData_s compressedAnimData; compressedAnimData_t compressedAnimData;
}; };
struct SlideState struct SlideState
@ -1359,7 +1366,7 @@ namespace game
int noFricTime; int noFricTime;
}; };
struct SprintState_s struct SprintState_t
{ {
int sprintButtonUpRequired; int sprintButtonUpRequired;
int sprintDelay; int sprintDelay;
@ -1418,7 +1425,7 @@ namespace game
NS_INVALID_NETSRC = 0x4, NS_INVALID_NETSRC = 0x4,
}; };
struct netadr_s struct netadr_t
{ {
netadrtype_t type; netadrtype_t type;
unsigned char ip[4]; unsigned char ip[4];
@ -1431,18 +1438,26 @@ namespace game
{ {
int overflowed; int overflowed;
int readOnly; int readOnly;
char* data; const char* data;
char* splitData; const char* splitData;
int maxsize; int maxsize;
int cursize; int cursize;
int splitSize; int splitSize;
int readcount; int readcount;
int bit; int bit;
int lastEntityRef; int lastEntityRef;
netsrc_t targetLocalNetID;
int useZlib; int useZlib;
}; };
struct gameState_t
{
int stringOffsets[3524];
char stringData[131'072];
int dataCount;
};
static_assert(sizeof(game::gameState_t) == 145'172);
struct HsvColor struct HsvColor
{ {
unsigned char h; unsigned char h;
@ -1483,7 +1498,7 @@ namespace game
unsigned int rgba; unsigned int rgba;
}; };
struct hudelem_s struct hudelem_t
{ {
he_type_t type; he_type_t type;
float x; float x;
@ -1529,9 +1544,9 @@ namespace game
int flags; int flags;
}; };
struct game_hudelem_s struct game_hudelem_t
{ {
hudelem_s elem; hudelem_t elem;
int clientNum; int clientNum;
int team; int team;
int archived; int archived;
@ -1573,13 +1588,6 @@ namespace game
VAR_TOTAL_COUNT = 0x1B, VAR_TOTAL_COUNT = 0x1B,
}; };
struct ScriptFunctions
{
int maxSize;
int count;
int* address;
};
struct VariableStackBuffer struct VariableStackBuffer
{ {
const char* pos; const char* pos;
@ -1966,7 +1974,7 @@ namespace game
FxWorld *fxWorld; FxWorld *fxWorld;
GfxWorld *gfxWorld; GfxWorld *gfxWorld;
GfxLightDef *lightDef;*/ GfxLightDef *lightDef;*/
Font_s* font; Font_t* font;
/*MenuList *menuList; /*MenuList *menuList;
menuDef_t *menu; menuDef_t *menu;
AnimationClass *animClass; AnimationClass *animClass;
@ -1979,8 +1987,8 @@ namespace game
SurfaceFxTable *surfaceFx;*/ SurfaceFxTable *surfaceFx;*/
RawFile* rawfile; RawFile* rawfile;
ScriptFile* scriptfile; ScriptFile* scriptfile;
StringTable* stringTable; /*StringTable *stringTable;
/*LeaderboardDef *leaderboardDef; LeaderboardDef *leaderboardDef;
StructuredDataDefSet *structuredDataDefSet; StructuredDataDefSet *structuredDataDefSet;
TracerDef *tracerDef; TracerDef *tracerDef;
VehicleDef *vehDef; VehicleDef *vehDef;
@ -2042,36 +2050,24 @@ namespace game
const void* weapCompleteDef; const void* weapCompleteDef;
}; };
enum FF_DIR
{
FFD_DEFAULT = 0x0,
FFD_MOD_DIR = 0x1,
FFD_USER_MAP = 0x2,
};
struct Sys_File
{
HANDLE handle;
};
namespace sp namespace sp
{ {
// very shit structures for the moment cuz i cba mapping the whole thing out right now... // very shit structures for the moment cuz i cba mapping the whole thing out right now...
struct gclient_s struct gclient_t
{ {
char __0x00[0xB6DC]; char __0x00[0xB6DC];
int flags; int flags;
}; };
struct gentity_s struct gentity_t
{ {
char __0x00[0x110]; char __0x00[0x110];
gclient_s* client; gclient_t* client;
char __0x118[0x4C]; char __0x118[0x4C];
int flags; int flags;
}; };
struct playerState_s struct playerState_t
{ {
}; };
@ -2088,7 +2084,7 @@ namespace game
namespace mp namespace mp
{ {
#pragma pack(push, 4) #pragma pack(push, 4)
struct playerState_s struct playerState_t
{ {
int commandTime; int commandTime;
int pm_type; int pm_type;
@ -2138,9 +2134,11 @@ namespace game
int clientNum; int clientNum;
int viewmodelIndex; int viewmodelIndex;
vec3_t viewangles; vec3_t viewangles;
char _0x190[0xAC]; char _0x190[0x58];
int viewlocked_entNum;
char _0x1EC[0x50];
int locationSelectionInfo; int locationSelectionInfo;
SprintState_s sprintState; SprintState_t sprintState;
float holdBreathScale; float holdBreathScale;
int holdBreathTimer; int holdBreathTimer;
float moveSpeedScaleMultiplier; float moveSpeedScaleMultiplier;
@ -2170,14 +2168,11 @@ namespace game
vec3_t weapLockedPos; vec3_t weapLockedPos;
int weaponIdleTime; int weaponIdleTime;
int lastStowedWeapon; int lastStowedWeapon;
char __0x638[0x2CE8]; char __0x638[0x2CEC];
}; };
#pragma pack(pop)
struct ClientCustomizationInfo static_assert(sizeof(playerState_t) == 0x3328);
{ #pragma pack(pop)
unsigned int modelIndex[3];
};
struct ScoreInfo struct ScoreInfo
{ {
@ -2193,6 +2188,140 @@ namespace game
unsigned short adrenaline; unsigned short adrenaline;
}; };
struct ScoreboardInfo
{
int teamScores[2];
ScoreInfo clientScores[18];
};
struct clSnapshot_t
{
mp::playerState_t ps;
ScoreboardInfo scores;
int valid;
int snapFlags;
int serverTime;
int messageNum;
int deltaNum;
int ping;
int cmdNum;
int numEntities;
int numClients;
int parseEntitiesIndex;
int parseClientsIndex;
int parseOmnvarsIdx;
int numAgents;
int parseAgentsIndex;
int scriptablesParseCount;
int scriptablesParseIndex;
int serverCommandNum;
};
static_assert(sizeof(clSnapshot_t) == 0x34B8);
struct clientActive_t
{
char usingAds;
char padding1[3];
int timeoutcount;
clSnapshot_t snap;
int oldSnapServerTime;
int oldServerTime;
int extrapolatedSnapshot;
char alwaysFalse;
char padding2[3];
int serverTime;
int oldFrameServerTime;
int serverTimeDelta;
int newSnapshots;
int serverId;
char mapname[64];
int mapcrc;
int parseEntitiesIndex;
int parseClientsIndex;
int parseOmnvarsIdx;
int mouseDx[2];
int mouseDy[2];
int mouseIndex;
char stanceHeld;
char padding3[3];
int stance;
int stancePosition;
int stanceTime;
char wasSprinting;
char padding4[3];
int cgameUserCmdWeapon;
int cgameUserCmdOffHand;
int cgameUserCmdAlternate;
float cgameFOVSensitivityScale;
float cgameMaxPitchSpeed;
float cgameMaxYawSpeed;
vec3_t cgameKickAngles;
vec3_t cgameOrigin;
vec3_t cgameVelocity;
PlayerVehicleState cgamePlayerVehState;
int cgameBobCycle;
int cgameMovementDir;
int cgameExtraButtons;
int cgamePredictedDataServerTime;
vec3_t clViewangles;
char _361C[12];
usercmd_t cmds[128];
int cmdNumber;
ClientArchiveData clientArchive[256];
int clientArchiveIndex;
int packetBackupCount;
int packetBackupMask;
int parseEntitiesCount;
int parseClientsCount;
int parseOmnvarsCount;
// missing fields
};
struct clientStatic_t
{
int quit;
int hunkUsersStarted;
char servername[256];
int rendererStarted;
int soundStarted;
int inUpdateSound;
int uiStarted;
int frametime;
int frametime_base;
int realtime;
char _0x124[0x80DBC];
gameState_t gameState;
// missing fields
};
struct clientConnection_t
{
int qport;
int clientNum;
netadr_t serverAddress;
int connectLastSendTime;
int connectPacketCount;
char serverMessage[256];
int challenge;
int checksumFeed;
int reliableSequence;
int reliableAcknowledge;
char reliableCommands[128][1024];
int serverMessageSequence;
int serverCommandSequence;
int lastExecutedServerCommand;
char serverCommands[128][1024];
char isServerRestarting;
char padding[3];
// missing fields
};
struct ClientCustomizationInfo
{
unsigned int modelIndex[3];
};
union OmnvarValue union OmnvarValue
{ {
bool enabled; bool enabled;
@ -2218,51 +2347,58 @@ namespace game
TEAM_NUM_TEAMS = 0x4, TEAM_NUM_TEAMS = 0x4,
}; };
struct clientState_s struct clientState_t
{ {
int clientIndex; int clientIndex;
team_t team; team_t team;
int modelindex; int modelindex;
int dualWielding; int dualWielding;
char _0x10[0x30]; char _0x10[0x30];
char name[0x10]; char name[16];
int rank; int rank;
int prestige; int prestige;
char _0x00[0x10];
int nameplateFriendlyIndex; int nameplateFriendlyIndex;
int nameplateEnemyIndex; int nameplateEnemyIndex;
unsigned int perks[2]; unsigned int perks[2];
char _0x78[0x80]; char _0x68[0x40];
char clanAbbrev[8];
char _0xB0[0x28];
}; };
static_assert(sizeof(clientState_t) == 0xD8);
struct clientSession_t struct clientSession_t
{ {
int sessionState; int sessionState;
int forceSpectatorClient; int forceSpectatorClient;
int killCamEntity; int killCamEntity;
int isInKillcam; int isInKillcam;
char __0x332C[0x14]; char _0x10[0x10];
usercmd_s cmd; usercmd_t cmd;
usercmd_s oldcmd; usercmd_t oldcmd;
int localClient; int localClient;
char __0x33C4[0x24]; char _0x9C[0x34];
float moveSpeedScaleMultiplier; float moveSpeedScaleMultiplier;
int viewmodelIndex; int viewmodelIndex;
int noSpectate; int noSpectate;
clientState_s cs; clientState_t cs;
ScoreInfo scores; ScoreInfo scores;
char __pad[0x1B0]; char _0x1E6[0x1C0];
}; };
struct gclient_s static_assert(sizeof(clientSession_t) == 0x388);
struct gclient_t
{ {
playerState_s ps; playerState_t ps;
clientSession_t sess; clientSession_t sess;
int flags; int flags;
int spectatorClient; int spectatorClient;
char __0x36B4[0x3B0]; char _0x36B8[0x3B0];
}; };
static_assert(sizeof(gclient_t) == 0x3A68);
struct LerpEntityState struct LerpEntityState
{ {
int entFlags; int entFlags;
@ -2297,6 +2433,8 @@ namespace game
char _0xD8[0x30]; char _0xD8[0x30];
}; };
static_assert(sizeof(EntityState) == 0x108);
struct EntityShared struct EntityShared
{ {
char _0x108[0x38]; char _0x108[0x38];
@ -2305,11 +2443,18 @@ namespace game
char _0x14C[0xC]; char _0x14C[0xC];
}; };
struct gentity_s struct centity_t
{
char _0x0[0x238];
};
static_assert(sizeof(centity_t) == 0x238);
struct gentity_t
{ {
EntityState s; EntityState s;
EntityShared r; EntityShared r;
gclient_s* client; gclient_t* client;
char _0x170[0x50]; char _0x170[0x50];
int flags; int flags;
char _0x1C4[0x18]; char _0x1C4[0x18];
@ -2318,21 +2463,232 @@ namespace game
char _0x1E4[0x10C]; char _0x1E4[0x10C];
}; };
struct snapshot_s struct snapshot_t
{ {
char _0x0[0x3C78]; playerState_t ps;
ScoreboardInfo scores;
OmnvarData omnvars[256];
int snapFlags;
int ping; int ping;
int serverTime; int serverTime;
int numEntities; int numEntities;
int numClients; int numClients;
// missing fields
}; };
struct cg_s enum DemoType
{ {
playerState_s ps; DEMO_TYPE_NONE = 0x0,
char _0x3324[0x64]; DEMO_TYPE_CLIENT = 0x1,
snapshot_s* snap; DEMO_TYPE_SERVER = 0x2
snapshot_s* nextSnap; // theres alot after this cba rn };
struct characterInfo_t
{
char _0x0[0x5D8];
};
static_assert(sizeof(characterInfo_t) == 0x5D8);
struct clientInfo_t
{
char _0x0[0x70];
};
static_assert(sizeof(clientInfo_t) == 0x70);
struct bgs_t
{
char _0x0[0x459F0];
characterInfo_t characterinfo[42];
clientInfo_t clientinfo[18];
};
static_assert(sizeof(bgs_t) == 0x55740);
struct visionSetVarsBase_t
{
int filmEnable;
float filmBrightness;
float filmContrast;
float filmDesaturation;
float filmDesaturationDark;
float filmInvert;
vec3_t filmLightTint;
vec3_t filmMediumTint;
vec3_t filmDarkTint;
int charPrimaryUseTweaks;
float charPrimaryDiffuseScale;
float charPrimarySpecularScale;
vec3_t charLightAmbient;
int viewModelPrimaryUseTweaks;
float viewModelPrimaryDiffuseScale;
float viewModelPrimarySpecularScale;
vec3_t viewModelLightAmbient;
float primaryLightOverride;
int materialBloomHQEnable;
float materialBloomHQHaziness;
float materialBloomHQGamma;
float materialBloomHQDesaturation;
float materialBloomIntensity;
float materialBloomRadius;
float materialBloomPinch;
float materialBloomLuminanceCutoff;
float materialBloomDesaturation;
int volumeLightScatter;
float volumeLightScatterLinearAtten;
float volumeLightScatterQuadraticAtten;
float volumeLightScatterAngularAtten;
float volumeLightScatterDepthAttenNear;
float volumeLightScatterDepthAttenFar;
float volumeLightScatterBackgroundDistance;
vec3_t volumeLightScatterColor;
float ssaoStrength;
float ssaoPower;
float ssaoBlurRadius;
int glareEnable;
float glareNormalStart;
float glareNormalEnd;
float glareNormalPower;
float glareNormalAmount;
float glareMirrorStart;
float glareMirrorEnd;
float glareMirrorPower;
float glareMirrorAmount;
float rimLightPitch;
float rimLightHeading;
float rimLightDiffuseIntensity;
float rimLightSpecIntensity;
float rimLightBias;
float rimLightPower;
vec3_t rimLightColor;
int overrideExistingMask;
float unlitSurfaceHDRScalar;
float litSurfaceHDRScalar;
float hdrSkyIntensity;
vec3_t hdrSkyColorTint;
};
static_assert(sizeof(visionSetVarsBase_t) == 0x12C);
struct visionSetVars_t
{
visionSetVarsBase_t baseclass_0;
void* _0x12C[3];
};
static_assert(sizeof(visionSetVars_t) == 0x148);
struct interpolationVisionSetVars_t
{
visionSetVarsBase_t baseclass_0;
void* _0x12C[0x2F];
};
static_assert(sizeof(interpolationVisionSetVars_t) == 0x2A8);
struct visionSetLerpData_t
{
int timeStart;
int timeDuration;
int style;
};
struct GfxFog
{
char _0x0[0x38];
int startTime;
int finishTime;
int color;
float density;
int sunColor;
};
struct ClientVisionSetData
{
visionSetVars_t visionSetPreLoaded[4];
char visionSetPreLoadedName[4][64];
int visionSetPreLoadedUsedTime[4];
interpolationVisionSetVars_t visionSetFrom[6];
interpolationVisionSetVars_t visionSetTo[6];
interpolationVisionSetVars_t visionSetCurrent[6];
interpolationVisionSetVars_t visionSetPrevious;
visionSetLerpData_t visionSetLerpData[6];
char visionName[6][64];
char visionBlendActive[6];
char thermalVisionActive;
char remoteMissileCam;
char painVisionActive;
float painVisionLerp;
int postApplyLerpTimeStart;
int postApplyLerpTimeDuration;
float postApplyLerpStart;
float postApplyLerpDest;
float postApplyLerpCurrent;
GfxFog lastClientFog;
int scriptFogActive;
int scriptFogLerpStartTime;
int scriptFogLerpEndTime;
};
static_assert(sizeof(ClientVisionSetData) == 0x3AF0);
struct cpose_t
{
char _0x0[0x90];
};
static_assert(sizeof(cpose_t) == 0x90);
struct cg_t
{
playerState_t ps;
char _0x3324[0x38];
int clientNum;
int localClientNum;
DemoType demoType;
char _0x336C[0x1C];
snapshot_t* snap;
snapshot_t* nextSnap;
char _0x3398[0xA66F8];
vec3_t refdefViewAngles;
char _0xA9A9C[0x8CC4];
int clientSideVisionSetsEnabled;
int voiceTime;
Weapon weaponSelect;
char _0xB276C[0x2C10];
int inKillCam;
char _0xB5380[0x148];
bgs_t bgs;
cpose_t viewModelPose;
cpose_t viewModelPoseLeftHand;
ClientVisionSetData cvsData;
int stagedVisionStateTo;
int stagedVisionStateFrom;
int stagedVisionStateEndTime;
int stagedVisionStateStartTime;
// missing fields
};
struct cgs_t
{
int viewX;
int viewY;
int viewWidth;
int viewHeight;
float viewAspect;
float _0x14;
int serverCommandSequence;
int processedSnapshotNum;
int localServer;
char gametype[32];
char szHostName[256];
int hardcore;
int maxclients;
int privateClients;
char mapname[64];
int gameEndTime;
// missing fields
}; };
struct netProfilePacket_t struct netProfilePacket_t
@ -2367,7 +2723,7 @@ namespace game
netsrc_t sock; netsrc_t sock;
int dropped; int dropped;
int incomingSequence; int incomingSequence;
netadr_s remoteAddress; netadr_t remoteAddress;
int fragmentSequence; int fragmentSequence;
int fragmentLength; int fragmentLength;
char* fragmentBuffer; char* fragmentBuffer;
@ -2382,7 +2738,7 @@ namespace game
struct __declspec(align(8)) clientHeader_t struct __declspec(align(8)) clientHeader_t
{ {
int state; clientstate_t state;
int sendAsActive; int sendAsActive;
int deltaMessage; int deltaMessage;
int rateDelayed; int rateDelayed;
@ -2416,8 +2772,11 @@ namespace game
int reliableAcknowledge; int reliableAcknowledge;
int reliableSent; int reliableSent;
int messageAcknowledge; int messageAcknowledge;
char _0xC30[0x41238]; int largeCommandSequence;
gentity_s* gentity; int gamestateMessageNum;
int challenge;
char _0xC3C[0x4122C];
gentity_t* gentity;
char name[16]; char name[16];
int lastPacketTime; int lastPacketTime;
int lastConnectTime; int lastConnectTime;
@ -2439,6 +2798,8 @@ namespace game
char _0x41E94[0x416A0]; char _0x41E94[0x416A0];
}; };
static_assert(sizeof(client_t) == 0x83570);
struct XZone struct XZone
{ {
char name[64]; char name[64];
@ -2450,7 +2811,7 @@ namespace game
struct missileFireParms struct missileFireParms
{ {
gentity_s* target; gentity_t* target;
float targetPosOrOffset[3]; float targetPosOrOffset[3];
float autoDetonateTime; float autoDetonateTime;
bool lockon; bool lockon;
@ -2458,14 +2819,23 @@ namespace game
}; };
static_assert(sizeof(missileFireParms) == 0x20); static_assert(sizeof(missileFireParms) == 0x20);
struct serverStatic_t
{
char _0x0[0x1681D00];
int time;
int loopbackProcessStopTime;
int snapFlagServerBit;
int clientCount;
client_t clients[18];
// missing fields
};
} }
static_assert(sizeof(mp::client_t) == 0x83570); union playerState_t
union playerState_s
{ {
sp::playerState_s* sp; sp::playerState_t* sp;
mp::playerState_s* mp; mp::playerState_t* mp;
}; };
enum GfxDrawSceneMethod enum GfxDrawSceneMethod
@ -2496,7 +2866,7 @@ namespace game
TECHNIQUE_NONE = 0x137, TECHNIQUE_NONE = 0x137,
}; };
struct GfxDrawMethod_s struct GfxDrawMethod_t
{ {
int drawScene; int drawScene;
int baseTechType; int baseTechType;
@ -2548,8 +2918,8 @@ namespace game
struct pmove_t struct pmove_t
{ {
void* ps; void* ps;
usercmd_s cmd; usercmd_t cmd;
usercmd_s oldcmd; usercmd_t oldcmd;
int tracemask; int tracemask;
int numtouch; int numtouch;
int touchents[32]; int touchents[32];

View File

@ -8,12 +8,12 @@ namespace game
* Functions * Functions
**************************************************************/ **************************************************************/
WEAK symbol<void(unsigned int id)> AddRefToObject{0x1403D7A10, 0x1404326D0}; WEAK symbol<void(unsigned int id)> AddRefToObject{0, 0x1404326D0};
WEAK symbol<void(int type, VariableUnion u)> AddRefToValue{0x1403D7740, 0x1404326E0}; WEAK symbol<void(int type, VariableUnion u)> AddRefToValue{0x1403D7740, 0x1404326E0};
WEAK symbol<unsigned int(unsigned int id)> AllocThread{0, 0x1404329B0}; WEAK symbol<unsigned int(unsigned int id)> AllocThread{0, 0x1404329B0};
WEAK symbol<ObjectVariableValue*(unsigned int* index)> AllocVariable{0x1403D7A70, 0x140432A10}; WEAK symbol<ObjectVariableValue*(unsigned int* index)> AllocVariable{0x1403D7A70, 0x140432A10};
WEAK symbol<void(int type, VariableUnion u)> RemoveRefToValue{0x1403D90F0, 0x1404340C0}; WEAK symbol<void(int type, VariableUnion u)> RemoveRefToValue{0x1403D90F0, 0x1404340C0};
WEAK symbol<void(unsigned int id)> RemoveRefToObject{0x1403D8FE0, 0x140433FB0}; WEAK symbol<void(unsigned int id)> RemoveRefToObject{0, 0x140433FB0};
WEAK symbol<void(unsigned int parentId, unsigned int index)> RemoveVariableValue{0x1403D91C0, 0x140434190}; WEAK symbol<void(unsigned int parentId, unsigned int index)> RemoveVariableValue{0x1403D91C0, 0x140434190};
WEAK symbol<void(void*, void*)> AimAssist_AddToTargetList{0, 0x140139D80}; WEAK symbol<void(void*, void*)> AimAssist_AddToTargetList{0, 0x140139D80};
@ -39,9 +39,9 @@ namespace game
WEAK symbol<bool()> CL_IsCgameInitialized{0x140234DA0, 0x1402B9A70}; WEAK symbol<bool()> CL_IsCgameInitialized{0x140234DA0, 0x1402B9A70};
WEAK symbol<void(int localClientNum, const char* message)> CG_GameMessage{0x1401F2E20, 0x140271320}; WEAK symbol<void(int localClientNum, const char* message)> CG_GameMessage{0x1401F2E20, 0x140271320};
WEAK symbol<void(int localClientNum, mp::cg_s* cg, const char* dvar, const char* value)> CG_SetClientDvarFromServer{0x0, 0x14028A2C0}; WEAK symbol<void(int localClientNum, mp::cg_t* cg, const char* dvar, const char* value)> CG_SetClientDvarFromServer{0x0, 0x14028A2C0};
WEAK symbol<void(const char* cmdName, void (), cmd_function_s* allocedCmd)> Cmd_AddCommandInternal{0x1403B3570, 0x1403F7070}; WEAK symbol<void(const char* cmdName, void (), cmd_function_t* allocedCmd)> Cmd_AddCommandInternal{0x1403B3570, 0x1403F7070};
WEAK symbol<void(int localClientNum, int controllerIndex, const char* text)> Cmd_ExecuteSingleCommand{0x1403B3B10, 0x1403F7680}; WEAK symbol<void(int localClientNum, int controllerIndex, const char* text)> Cmd_ExecuteSingleCommand{0x1403B3B10, 0x1403F7680};
WEAK symbol<void (XAssetType type, void (__cdecl *func)(XAssetHeader, void*), void* inData, bool includeOverride)> DB_EnumXAssets_FastFile{0x140271F50, 0x14031EF90}; WEAK symbol<void (XAssetType type, void (__cdecl *func)(XAssetHeader, void*), void* inData, bool includeOverride)> DB_EnumXAssets_FastFile{0x140271F50, 0x14031EF90};
@ -54,11 +54,11 @@ namespace game
WEAK symbol<XAssetHeader(XAssetType type, const char* name, int allowCreateDefault)> DB_FindXAssetHeader{0x140272300, 0x14031F3A0}; WEAK symbol<XAssetHeader(XAssetType type, const char* name, int allowCreateDefault)> DB_FindXAssetHeader{0x140272300, 0x14031F3A0};
WEAK symbol<int(XAssetType type, const char* name)> DB_XAssetExists{0x140276200, 0x1403245E0}; WEAK symbol<int(XAssetType type, const char* name)> DB_XAssetExists{0x140276200, 0x1403245E0};
WEAK symbol<int(XAssetType type, const char* name)> DB_IsXAssetDefault{0x140273480 , 0x1403204D0}; WEAK symbol<int(XAssetType type, const char* name)> DB_IsXAssetDefault{0x140273480 , 0x1403204D0};
WEAK symbol<int(const RawFile* rawfile)> DB_GetRawFileLen{0x140272E80, 0x14031FF80}; WEAK symbol<int(const RawFile* rawfile)> DB_GetRawFileLen{0x0140272E80, 0x14031FF80};
WEAK symbol<void(const RawFile* rawfile, char* buf, int size)> DB_GetRawBuffer{0x140272D50, 0x14031FE50}; WEAK symbol<void(const RawFile* rawfile, char* buf, int size)> DB_GetRawBuffer{0x140272D50, 0x14031FE50};
WEAK symbol<int(const char* zoneName)> DB_IsLocalized{0x140273210, 0x140320360}; WEAK symbol<int(const char* zoneName)> DB_IsLocalized{0x140273210, 0x140320360};
WEAK symbol<void*(unsigned int size, unsigned int alignment, unsigned int type, PMem_Source source)> PMem_AllocFromSource_NoDebug{0x140430B80, 0x1404F46C0}; WEAK symbol<void*(unsigned int size, unsigned int alignment, unsigned int type, PMem_Source source)> PMem_AllocFromSource_NoDebug{0x0140430B80, 0x001404F46C0};
WEAK symbol<void(const char* name, PMem_Direction allocDir)> PMem_Free{0x140430EC0 , 0x1404F4A30}; WEAK symbol<void(const char* name, PMem_Direction allocDir)> PMem_Free{0x140430EC0 , 0x1404F4A30};
WEAK symbol<void*(unsigned int size)> Hunk_AllocateTempMemoryHighInternal{0x140423C70, 0x1404E4E20}; WEAK symbol<void*(unsigned int size)> Hunk_AllocateTempMemoryHighInternal{0x140423C70, 0x1404E4E20};
@ -94,18 +94,17 @@ namespace game
WEAK symbol<void(const char *path, const char *dir)> FS_AddLocalizedGameDirectory{0x14041A2F0, 0x1404DC760}; WEAK symbol<void(const char *path, const char *dir)> FS_AddLocalizedGameDirectory{0x14041A2F0, 0x1404DC760};
WEAK symbol<Weapon(const char* pickupName, int model)> G_FindItem{0x140462490, 0x14021B7E0}; WEAK symbol<Weapon(const char* pickupName, int model)> G_FindItem{0x140462490, 0x14021B7E0};
WEAK symbol<int(playerState_s* ps, Weapon weapon, int dualWield, int startInAltMode, int usedBefore)> G_GivePlayerWeapon{0x140359E20, 0x1403DA5E0}; WEAK symbol<int(playerState_t* ps, Weapon weapon, int dualWield, int startInAltMode, int usedBefore)> G_GivePlayerWeapon{0x140359E20, 0x1403DA5E0};
WEAK symbol<Weapon(const char* name)> G_GetWeaponForName{0x140359890, 0x1403DA060}; WEAK symbol<Weapon(const char* name)> G_GetWeaponForName{0x140359890, 0x1403DA060};
WEAK symbol<void()> G_Glass_Update{0x14030E680, 0x140397450}; WEAK symbol<void()> G_Glass_Update{0x14030E680, 0x140397450};
WEAK symbol<void (playerState_s* ps, Weapon weapon, int hadWeapon)> G_InitializeAmmo{0x140311F00, 0x14039AEA0}; WEAK symbol<void (playerState_t* ps, Weapon weapon, int hadWeapon)> G_InitializeAmmo{0x140311F00, 0x14039AEA0};
WEAK symbol<void(int clientNum, Weapon weapon)> G_SelectWeapon{0x14035A200, 0x1403DA880}; WEAK symbol<void(int clientNum, Weapon weapon)> G_SelectWeapon{0x14035A200, 0x1403DA880};
WEAK symbol<int(playerState_s* ps, Weapon weapon)> G_TakePlayerWeapon{0x14035A350, 0x1403DA9C0}; WEAK symbol<int(playerState_t* ps, Weapon weapon)> G_TakePlayerWeapon{0x14035A350, 0x1403DA9C0};
WEAK symbol<unsigned int (const char* name, /*ConfigString*/ unsigned int start, unsigned int max, int create, WEAK symbol<unsigned int (const char* name, /*ConfigString*/ unsigned int start, unsigned int max, int create,
const char* errormsg)> G_FindConfigstringIndex{0x0, 0x140161F90}; const char* errormsg)> G_FindConfigstringIndex{0x0, 0x140161F90};
WEAK symbol<int(int server_time)> G_RunFrame{0x0, 0x1403A05E0}; WEAK symbol<int(int server_time)> G_RunFrame{0x0, 0x1403A05E0};
WEAK symbol<int(int clientNun)> G_GetClientScore{0x0, 0x14039EF60};
WEAK symbol<game_hudelem_s*(int clientNum, int teamNum)> HudElem_Alloc{0x0, 0x1403997E0}; WEAK symbol<game_hudelem_t*(int clientNum, int teamNum)> HudElem_Alloc{0x0, 0x1403997E0};
WEAK symbol<char*(char* string)> I_CleanStr{0x140432460, 0x1404F63C0}; WEAK symbol<char*(char* string)> I_CleanStr{0x140432460, 0x1404F63C0};
@ -133,9 +132,8 @@ namespace game
WEAK symbol<StructuredDataDef*(const char* filename, unsigned int maxSize)>StructuredDataDef_GetAsset{0, 0x1404E6560}; WEAK symbol<StructuredDataDef*(const char* filename, unsigned int maxSize)>StructuredDataDef_GetAsset{0, 0x1404E6560};
WEAK symbol<StringTable*(const char* fileName, const StringTable** tablePtr)>StringTable_GetAsset{0, 0x1404E6170}; WEAK symbol<StringTable*(const char* fileName, const StringTable** tablePtr)>StringTable_GetAsset{0, 0x1404E6170};
WEAK symbol<const char*(const StringTable* table, int row, int column)> StringTable_GetColumnValueForRow{0, 0x1404E61A0}; WEAK symbol<const char*(const StringTable* table, const int row, const int column)> StringTable_GetColumnValueForRow{0, 0x1404E61A0};
WEAK symbol<int(const StringTable* table, int comparisonColumn, const char* value)> StringTable_LookupRowNumForValue{0, 0x1404E6260}; WEAK symbol<int(const StringTable* table, const int comparisonColumn, const char* value)> StringTable_LookupRowNumForValue{0, 0x1404E6260};
WEAK symbol<int(const char* string)> StringTable_HashString{0x1404259A0, 0x1404E6320};
WEAK symbol<void(int localClientNum, const char* menuName, int isPopup, int isModal, unsigned int isExclusive)> LUI_OpenMenu{0x1403FD460, 0x1404B3610}; WEAK symbol<void(int localClientNum, const char* menuName, int isPopup, int isModal, unsigned int isExclusive)> LUI_OpenMenu{0x1403FD460, 0x1404B3610};
// Made up name, replaced by ScopedCriticalSection on Black Ops 3 // Made up name, replaced by ScopedCriticalSection on Black Ops 3
@ -146,18 +144,18 @@ namespace game
WEAK symbol<Material*(const char* material)> Material_RegisterHandle{0x140523D90, 0x1405F0E20}; WEAK symbol<Material*(const char* material)> Material_RegisterHandle{0x140523D90, 0x1405F0E20};
WEAK symbol<void(netsrc_t, netadr_s*, const char*)> NET_OutOfBandPrint{0, 0x14041D5C0}; WEAK symbol<void(netsrc_t, netadr_t*, const char*)> NET_OutOfBandPrint{0, 0x14041D5C0};
WEAK symbol<void(netsrc_t sock, int length, const void* data, const netadr_s* to)> NET_SendLoopPacket{0, 0x14041D780}; WEAK symbol<void(netsrc_t sock, int length, const void* data, const netadr_t* to)> NET_SendLoopPacket{0, 0x14041D780};
WEAK symbol<bool(const char* s, netadr_s* a)> NET_StringToAdr{0, 0x14041D870}; WEAK symbol<bool(const char* s, netadr_t* a)> NET_StringToAdr{0, 0x14041D870};
WEAK symbol<void(netadr_s*, sockaddr*)> NetadrToSockadr{0, 0x1404E53D0}; WEAK symbol<void(netadr_t*, sockaddr*)> NetadrToSockadr{0, 0x1404E53D0};
WEAK symbol<void(float x, float y, float width, float height, float s0, float t0, float s1, float t1, WEAK symbol<void(float x, float y, float width, float height, float s0, float t0, float s1, float t1,
float* color, Material* material)> R_AddCmdDrawStretchPic{0x140234460, 0x140600BE0}; float* color, Material* material)> R_AddCmdDrawStretchPic{0x140234460, 0x140600BE0};
WEAK symbol<void(const char*, int, Font_s*, float, float, float, float, float, float*, int)> R_AddCmdDrawText{0x140533E40, 0x140601070}; WEAK symbol<void(const char*, int, Font_t*, float, float, float, float, float, float*, int)> R_AddCmdDrawText{0x140533E40, 0x140601070};
WEAK symbol<void(const char*, int, Font_s*, float, float, float, float, float, const float*, int, int, char)> R_AddCmdDrawTextWithCursor{0x140534170, 0x1406013A0}; WEAK symbol<void(const char*, int, Font_t*, float, float, float, float, float, const float*, int, int, char)> R_AddCmdDrawTextWithCursor{0x140534170, 0x1406013A0};
WEAK symbol<Font_s*(const char* font)> R_RegisterFont{0x1405130B0, 0x1405DFAC0}; WEAK symbol<Font_t*(const char* font)> R_RegisterFont{0x1405130B0, 0x1405DFAC0};
WEAK symbol<void()> R_SyncRenderThread{0x140535AF0, 0x140602D30}; WEAK symbol<void()> R_SyncRenderThread{0x140535AF0, 0x140602D30};
WEAK symbol<int(const char* text, int maxChars, Font_s* font)> R_TextWidth{0x140513390, 0x1405DFDB0}; WEAK symbol<int(const char* text, int maxChars, Font_t* font)> R_TextWidth{0x140513390, 0x1405DFDB0};
WEAK symbol<ScreenPlacement*()> ScrPlace_GetViewPlacement{0x14024D150, 0x1402F6D40}; WEAK symbol<ScreenPlacement*()> ScrPlace_GetViewPlacement{0x14024D150, 0x1402F6D40};
@ -165,17 +163,13 @@ namespace game
WEAK symbol<unsigned int(unsigned int parentId, unsigned int name)> FindVariable{0x1403D84F0, 0x1404334A0}; WEAK symbol<unsigned int(unsigned int parentId, unsigned int name)> FindVariable{0x1403D84F0, 0x1404334A0};
WEAK symbol<unsigned int(int entnum, unsigned int classnum)> FindEntityId{0, 0x1404333A0}; WEAK symbol<unsigned int(int entnum, unsigned int classnum)> FindEntityId{0, 0x1404333A0};
WEAK symbol<unsigned int(unsigned int parentId, unsigned int id)> GetVariableName{0x1403D8E90, 0x140433E60}; WEAK symbol<unsigned int(unsigned int parentId, unsigned int id)> GetVariableName{0x1403D8E90, 0x140433E60};
WEAK symbol<void(VariableValue* result, unsigned int classnum, int entnum, int offset)> GetEntityFieldValue{0x1403DC810, 0x140437860}; WEAK symbol<void (VariableValue* result, unsigned int classnum, int entnum, int offset)> GetEntityFieldValue{0x1403DC810, 0x140437860};
WEAK symbol<const float*(const float* v)> Scr_AllocVector{0x1403D9AF0, 0x140434A10}; WEAK symbol<const float*(const float* v)> Scr_AllocVector{0x1403D9AF0, 0x140434A10};
WEAK symbol<const char*(unsigned int index)> Scr_GetString{0x1403DE200, 0x140439160}; WEAK symbol<const char*(unsigned int index)> Scr_GetString{0, 0x140439160};
WEAK symbol<unsigned int(unsigned int index)> Scr_GetConstString{0x1403DDAC0, 0x140438AD0};
WEAK symbol<unsigned int(unsigned int index)> Scr_GetConstIString{0x1403DD8A0, 0x1404388B0};
WEAK symbol<void(int value)> Scr_AddInt{0x0, 0x140437E70}; WEAK symbol<void(int value)> Scr_AddInt{0x0, 0x140437E70};
WEAK symbol<void(const char* value)> Scr_AddString{0x0, 0x1404381D0}; WEAK symbol<void(const char* value)> Scr_AddString{0x0, 0x1404381D0};
WEAK symbol<int(unsigned int index)> Scr_GetInt{0x1403DDEB0, 0x140438E10}; WEAK symbol<int(unsigned int index)> Scr_GetInt{0x0, 0x140438E10};
WEAK symbol<float(unsigned int index)> Scr_GetFloat{0x1403DDD50, 0x140438D60}; WEAK symbol<float(unsigned int index)> Scr_GetFloat{0, 0x140438D60};
WEAK symbol<void(unsigned int index, float* vectorValue)> Scr_GetVector{0x1403DE470, 0x1404393D0};
WEAK symbol<unsigned int(unsigned int index)> Scr_GetObject{0x1403DDF70, 0x140438ED0};
WEAK symbol<unsigned int()> Scr_GetNumParam{0x1403DDF60, 0x140438EC0}; WEAK symbol<unsigned int()> Scr_GetNumParam{0x1403DDF60, 0x140438EC0};
WEAK symbol<void()> Scr_ClearOutParams{0x1403DD500, 0x140438600}; WEAK symbol<void()> Scr_ClearOutParams{0x1403DD500, 0x140438600};
WEAK symbol<scr_entref_t(unsigned int entId)> Scr_GetEntityIdRef{0x1403DBDC0, 0x140436E10}; WEAK symbol<scr_entref_t(unsigned int entId)> Scr_GetEntityIdRef{0x1403DBDC0, 0x140436E10};
@ -184,16 +178,15 @@ namespace game
WEAK symbol<void(unsigned int id, unsigned int stringValue, unsigned int paramcount)> Scr_NotifyId{0x1403DE730, 0x140439700}; WEAK symbol<void(unsigned int id, unsigned int stringValue, unsigned int paramcount)> Scr_NotifyId{0x1403DE730, 0x140439700};
WEAK symbol<void(unsigned int stringValue, unsigned int paramcount)> Scr_NotifyLevel{0x0, 0x1404397D0}; WEAK symbol<void(unsigned int stringValue, unsigned int paramcount)> Scr_NotifyLevel{0x0, 0x1404397D0};
WEAK symbol<unsigned int(int entnum, unsigned int classnum)> Scr_GetEntityId{0x0, 0x140436D60}; WEAK symbol<unsigned int(int entnum, unsigned int classnum)> Scr_GetEntityId{0x0, 0x140436D60};
WEAK symbol<bool(VariableValue* value)> Scr_CastString{0x1403D9BA0, 0x140434AC0}; WEAK symbol<bool(VariableValue* value)> Scr_CastString{0x0, 0x140434AC0};
WEAK symbol<unsigned __int16(int handle, unsigned int paramcount)> Scr_ExecThread{0x1403DD600, 0x1404386E0}; WEAK symbol<unsigned __int16(int handle, unsigned int paramcount)> Scr_ExecThread{0x1403DD600, 0x1404386E0};
WEAK symbol<unsigned int(const char* name)> Scr_LoadScript{0x1403D3C50, 0x14042EAA0}; WEAK symbol<unsigned int(const char* name)> Scr_LoadScript{0x1403D3C50, 0x14042EAA0};
WEAK symbol<unsigned int(const char* script, unsigned int name)> Scr_GetFunctionHandle{0x1403D3AD0 , 0x14042E920}; WEAK symbol<unsigned int(const char* script, unsigned int name)> Scr_GetFunctionHandle{0x1403D3AD0 , 0x14042E920};
WEAK symbol<unsigned int(void* func, int type, unsigned int name)> Scr_RegisterFunction{0x1403D3530, 0x14042E330}; WEAK symbol<unsigned int(void* func, int type, unsigned int name)> Scr_RegisterFunction{0x1403D3530, 0x14042E330};
WEAK symbol<unsigned int(const char** pName, int* type)> Scr_GetFunction{0x14034A950, 0x1403CD9F0}; WEAK symbol<void()> Scr_ErrorInternal{0x0, 0x140438660};
WEAK symbol<void()> Scr_ErrorInternal{0x1403DD580 , 0x140438660};
WEAK symbol<int(unsigned int)> GetObjectType{0x1403D8D30, 0x140433CF0}; WEAK symbol<int(unsigned int)> GetObjectType{0x0, 0x140433CF0};
WEAK symbol<unsigned int(unsigned int localId, const char* pos, unsigned int paramcount)> VM_Execute{0, 0x14043A280}; WEAK symbol<unsigned int(unsigned int localId, const char* pos, unsigned int paramcount)> VM_Execute{0, 0x14043A280};
@ -210,29 +203,29 @@ namespace game
WEAK symbol<void()> SV_Cmd_EndTokenizedString{0, 0x1403F8110}; WEAK symbol<void()> SV_Cmd_EndTokenizedString{0, 0x1403F8110};
WEAK symbol<void()> SV_MatchEnd{0x0, 0x14047A090}; WEAK symbol<void()> SV_MatchEnd{0x0, 0x14047A090};
WEAK symbol<void(netadr_s* from)> SV_DirectConnect{0, 0x140471390}; WEAK symbol<void(netadr_t* from)> SV_DirectConnect{0, 0x140471390};
WEAK symbol<void(int, int, const char*)> SV_GameSendServerCommand{0x140490F40, 0x1404758C0};
WEAK symbol<bool()> SV_Loaded{0x140491820, 0x1404770C0}; WEAK symbol<bool()> SV_Loaded{0x140491820, 0x1404770C0};
WEAK symbol<void(int localClientNum, const char* map, bool mapIsPreloaded)> SV_StartMap{0, 0x140470170}; WEAK symbol<void(int localClientNum, const char* map, bool mapIsPreloaded)> SV_StartMap{0, 0x140470170};
WEAK symbol<void(int localClientNum, const char* map, bool mapIsPreloaded, bool migrate)> SV_StartMapForParty{0, 0x1404702F0}; WEAK symbol<void(int localClientNum, const char* map, bool mapIsPreloaded, bool migrate)> SV_StartMapForParty{0, 0x1404702F0};
WEAK symbol<mp::gentity_s*(const char*, unsigned int, unsigned int, unsigned int)> SV_AddBot{0, 0x140470920}; WEAK symbol<mp::gentity_t*(const char*, unsigned int, unsigned int, unsigned int)> SV_AddBot{0, 0x140470920};
WEAK symbol<bool(int clientNum)> SV_BotIsBot{0, 0x140461340}; WEAK symbol<bool(int clientNum)> SV_BotIsBot{0, 0x140461340};
WEAK symbol<const char*()> SV_BotGetRandomName{0, 0x140460B80}; WEAK symbol<const char*()> SV_BotGetRandomName{0, 0x140460B80};
WEAK symbol<void(mp::gentity_s*)> SV_SpawnTestClient{0, 0x1404740A0}; WEAK symbol<void(mp::gentity_t*)> SV_SpawnTestClient{0, 0x1404740A0};
WEAK symbol<void(mp::client_t*, const char*, int)> SV_ExecuteClientCommand{0, 0x140472430}; WEAK symbol<void(mp::client_t*, const char*, int)> SV_ExecuteClientCommand{0, 0x140472430};
WEAK symbol<void()> SV_FastRestart{0x14048B890, 0x14046F440}; WEAK symbol<void()> SV_FastRestart{0x14048B890, 0x14046F440};
WEAK symbol<playerState_s*(int num)> SV_GetPlayerstateForClientNum{0x140490F80, 0x140475A10}; WEAK symbol<playerState_t*(int num)> SV_GetPlayerstateForClientNum{0x140490F80, 0x140475A10};
WEAK symbol<const char*(int clientNum)> SV_GetGuid{0, 0x140475990}; WEAK symbol<const char*(int clientNum)> SV_GetGuid{0, 0x140475990};
WEAK symbol<void(int clientNum, const char* reason)> SV_KickClientNum{0, 0x14046F730}; WEAK symbol<void(int clientNum, const char* reason)> SV_KickClientNum{0, 0x14046F730};
WEAK symbol<void(int index, const char* string)> SV_SetConfigstring{0, 0x140477450}; WEAK symbol<void(int index, const char* string)> SV_SetConfigstring{0, 0x140477450};
WEAK symbol<void(int clientNum, svscmd_type type, const char* text)> SV_GameSendServerCommand{0x140490F40, 0x1404758C0};
WEAK symbol<void(const char* error, ...)> Sys_Error{0x14043AC20, 0x1404FF510}; WEAK symbol<void(const char* error, ...)> Sys_Error{0x14043AC20, 0x1404FF510};
WEAK symbol<bool()> Sys_IsDatabaseReady2{0x1403C2D40, 0x140423920}; WEAK symbol<bool()> Sys_IsDatabaseReady2{0x1403C2D40, 0x140423920};
WEAK symbol<int()> Sys_Milliseconds{0x14043D2A0, 0x140501CA0}; WEAK symbol<int()> Sys_Milliseconds{0x14043D2A0, 0x140501CA0};
WEAK symbol<void()> Sys_ShowConsole{0x14043E650, 0x140503130}; WEAK symbol<void()> Sys_ShowConsole{0x14043E650, 0x140503130};
WEAK symbol<bool(int, void const*, const netadr_s*)> Sys_SendPacket{0x14043D000, 0x140501A00}; WEAK symbol<bool(int, void const*, const netadr_t*)> Sys_SendPacket{0x14043D000, 0x140501A00};
WEAK symbol<void*(int valueIndex)> Sys_GetValue{0x1403C2C30, 0x1404237D0}; WEAK symbol<void*(int valueIndex)> Sys_GetValue{0x1403C2C30, 0x1404237D0};
WEAK symbol<bool()> Sys_IsMainThread{0x1478FC470, 0x140423950}; WEAK symbol<bool()> Sys_IsMainThread{0x1478FC470, 0x140423950};
WEAK symbol<HANDLE(Sys_Folder folder, const char* baseFilename)> Sys_CreateFile{0x140434B10, 0x1404F8FD0}; WEAK symbol<HANDLE(Sys_Folder folder, const char* baseFilename)> Sys_CreateFile{0x140434B10, 0x1404F8FD0};
@ -253,8 +246,6 @@ namespace game
WEAK symbol<void(void* ps)> Jump_ClearState{0x0, 0x140213120}; WEAK symbol<void(void* ps)> Jump_ClearState{0x0, 0x140213120};
WEAK symbol<void(unsigned __int64 markPos)> LargeLocalResetToMark{0x140423B50, 0x1404E4D00};
WEAK symbol<void*(jmp_buf* Buf, int Value)> longjmp{0x14062E030, 0x140738060}; WEAK symbol<void*(jmp_buf* Buf, int Value)> longjmp{0x14062E030, 0x140738060};
WEAK symbol<int (jmp_buf* Buf)> _setjmp{0x14062F030, 0x140739060}; WEAK symbol<int (jmp_buf* Buf)> _setjmp{0x14062F030, 0x140739060};
@ -266,7 +257,7 @@ namespace game
WEAK symbol<CmdArgs> cmd_args{0x144CE7F70, 0x144518480}; WEAK symbol<CmdArgs> cmd_args{0x144CE7F70, 0x144518480};
WEAK symbol<CmdArgs> sv_cmd_args{0x144CE8020, 0x144518530}; WEAK symbol<CmdArgs> sv_cmd_args{0x144CE8020, 0x144518530};
WEAK symbol<cmd_function_s*> cmd_functions{0x144CE80C8, 0x1445185D8}; WEAK symbol<cmd_function_t*> cmd_functions{0x144CE80C8, 0x1445185D8};
WEAK symbol<int> dvarCount{0x1458CBA3C, 0x1478EADF4}; WEAK symbol<int> dvarCount{0x1458CBA3C, 0x1478EADF4};
WEAK symbol<dvar_t*> sortedDvars{0x1458CBA60, 0x1478EAE10}; WEAK symbol<dvar_t*> sortedDvars{0x1458CBA60, 0x1478EAE10};
@ -309,30 +300,31 @@ namespace game
WEAK symbol<DWORD> threadIds{0x144DE6640, 0x1446B4960}; WEAK symbol<DWORD> threadIds{0x144DE6640, 0x1446B4960};
WEAK symbol<GfxDrawMethod_s> gfxDrawMethod{0x145F525A8, 0x1480350D8}; WEAK symbol<GfxDrawMethod_t> gfxDrawMethod{0x145F525A8, 0x1480350D8};
namespace sp namespace sp
{ {
WEAK symbol<gentity_s> g_entities{0x143C91600, 0}; WEAK symbol<gentity_t> g_entities{0x143C91600, 0};
WEAK symbol<XZone> g_zones_0{0x1434892D8, 0}; WEAK symbol<XZone> g_zones_0{0x1434892D8, 0};
} }
namespace mp namespace mp
{ {
WEAK symbol<cg_s> cgArray{0, 0x14176EC00}; WEAK symbol<cg_t> cg{0, 0x14176EC00};
WEAK symbol<cgs_t> cgs{0, 0x14187EB80};
WEAK symbol<clientActive_t> cl{0, 0x1419E1C70};
WEAK symbol<clientConnection_t> clc{0, 0x141CB5350};
WEAK symbol<clientStatic_t> cls{0, 0x141D1AB60};
WEAK symbol<serverStatic_t> svs{0, 0x144DF9580};
WEAK symbol<gentity_s> g_entities{0, 0x14427A0E0}; WEAK symbol<gentity_t> g_entities{0, 0x14427A0E0};
WEAK symbol<centity_t> centities{0, 0x141887350};
WEAK symbol<int> svs_clientCount{0, 0x14647B28C};
WEAK symbol<client_t> svs_clients{0, 0x14647B290};
WEAK symbol<std::uint32_t> sv_serverId_value{0, 0x144DF9478};
WEAK symbol<int> gameTime{0, 0x1443F4B6C};
WEAK symbol<int> serverTime{0, 0x14647B280};
WEAK symbol<XZone> g_zones_0{0, 0x143A46498}; WEAK symbol<XZone> g_zones_0{0, 0x143A46498};
WEAK symbol<connstate_t> connstate{0, 0x1419E1AE0};
WEAK symbol<int> gameTime{0, 0x1443F4B6C};
WEAK symbol<std::uint32_t> sv_serverId_value{0, 0x144DF9478};
} }
namespace hks namespace hks

View File

@ -4,6 +4,7 @@
#include "loader/component_loader.hpp" #include "loader/component_loader.hpp"
#include "game/game.hpp" #include "game/game.hpp"
#include "utils/command_line.hpp"
#include <utils/flags.hpp> #include <utils/flags.hpp>
#include <utils/io.hpp> #include <utils/io.hpp>
#include <utils/string.hpp> #include <utils/string.hpp>
@ -165,11 +166,26 @@ FARPROC load_binary(const launcher::mode mode)
} }
std::string data; std::string data;
if (!utils::io::read_file(binary, &data))
{
// Check the first argument to see if the current directory needs to changed
// Required when the game is used to open a file (like a demo file)
const auto& args = utils::command_line::get_args();
if (!args.empty())
{
const auto& binary_dir = args.front();
if (binary_dir.filename().string().ends_with("iw6-mod.exe"))
{
std::filesystem::current_path(binary_dir.parent_path());
}
}
if (!utils::io::read_file(binary, &data)) if (!utils::io::read_file(binary, &data))
{ {
throw std::runtime_error( throw std::runtime_error(
"Failed to read game binary! Please select the correct path in the launcher settings."); "Failed to read game binary! Please select the correct path in the launcher settings.");
} }
}
#ifdef INJECT_HOST_AS_LIB #ifdef INJECT_HOST_AS_LIB
return loader.load_library(binary); return loader.load_library(binary);

View File

@ -5,9 +5,7 @@
#define BINARY_PAYLOAD_SIZE 0x0B500000 #define BINARY_PAYLOAD_SIZE 0x0B500000
// Decide whether to load the game as lib or to inject it // Decide whether to load the game as lib or to inject it
#if 1
#define INJECT_HOST_AS_LIB #define INJECT_HOST_AS_LIB
#endif
#pragma warning(push) #pragma warning(push)
#pragma warning(disable: 4100) #pragma warning(disable: 4100)

View File

@ -0,0 +1,35 @@
#include "command_line.hpp"
#include "nt.hpp"
#include <shellapi.h>
#include <winrt/Windows.Foundation.h>
namespace utils::command_line
{
template <typename type, typename deleter>
constexpr std::unique_ptr<type, deleter> make_unique_ptr(type* ptr, deleter&& del)
{
return std::unique_ptr<type, deleter&&>(ptr, std::forward<deleter>(del));
}
const std::vector<std::filesystem::path>& get_args()
{
static const auto args = []()
{
auto argc = 0;
const auto cmd_line = winrt::check_pointer(::GetCommandLineW());
const auto up = make_unique_ptr(winrt::check_pointer(::CommandLineToArgvW(cmd_line, &argc)), ::LocalFree);
const auto argv = up.get();
std::vector<std::filesystem::path> vec(argc);
std::transform(argv, argv + argc, vec.begin(), [](const auto* path)
{
return std::filesystem::path(path);
});
return vec;
}();
return args;
}
}

View File

@ -0,0 +1,9 @@
#pragma once
#include <filesystem>
#include <vector>
namespace utils::command_line
{
[[nodiscard]] const std::vector<std::filesystem::path>& get_args();
}

View File

@ -109,6 +109,86 @@ namespace utils::compression
result.resize(length); result.resize(length);
return result; return result;
} }
std::vector<std::uint8_t> decompress(std::span<const std::uint8_t> input, std::size_t exp_output_size, double growth_rate)
{
auto decompress_internal = [](std::uint8_t* output, uLong* output_size, const std::uint8_t* input, uLong* input_size)
{
return uncompress2(
reinterpret_cast<Bytef*>(output), output_size,
reinterpret_cast<const Bytef*>(input), input_size
);
};
auto output_size = static_cast<uLong>(std::max(exp_output_size, std::size_t(256)));
std::vector<std::uint8_t> output(output_size);
auto input_size = static_cast<uLong>(input.size());
auto status = decompress_internal(output.data(), &output_size, input.data(), &input_size);
if (status == Z_BUF_ERROR)
{
const auto decompression_ratio = (input_size / static_cast<double>(output.size())) - 0.04;
output_size = static_cast<uLong>(std::max(input.size() / decompression_ratio, static_cast<double>(output_size)));
output.resize(output_size);
input_size = static_cast<uLong>(input.size());
status = decompress_internal(output.data(), &output_size, input.data(), &input_size);
}
for (growth_rate = std::max(growth_rate, 1.0); status == Z_BUF_ERROR;)
{
output_size = 4 + static_cast<uLong>(growth_rate * output.size());
output.resize(output_size);
input_size = static_cast<uLong>(input.size());
status = decompress_internal(output.data(), &output_size, input.data(), &input_size);
}
if (status != Z_OK)
{
output.clear();
return output;
}
output.resize(output_size);
return output;
}
std::vector<std::uint8_t> compress(std::span<const std::uint8_t> input, std::size_t exp_output_size, double growth_rate)
{
auto compress_internal = [](std::uint8_t* output, uLong* output_size, const std::uint8_t* input, uLong input_size)
{
return compress2(
reinterpret_cast<Bytef*>(output), output_size,
reinterpret_cast<const Bytef*>(input), input_size,
Z_BEST_COMPRESSION
);
};
auto output_size = static_cast<uLong>(std::max(exp_output_size, std::size_t(256)));
std::vector<std::uint8_t> output(output_size);
const auto input_size = static_cast<uLong>(input.size());
auto status = compress_internal(output.data(), &output_size, input.data(), input_size);
for (growth_rate = std::max(growth_rate, 1.0); status == Z_BUF_ERROR;)
{
output_size = 4 + static_cast<uLong>(growth_rate * output.size());
output.resize(output_size);
status = compress_internal(output.data(), &output_size, input.data(), input_size);
}
if (status != Z_OK)
{
output.clear();
return output;
}
output.resize(output_size);
return output;
}
} }
namespace zip namespace zip

View File

@ -1,7 +1,9 @@
#pragma once #pragma once
#include <span>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include <vector>
#define CHUNK 16384u #define CHUNK 16384u
@ -11,6 +13,9 @@ namespace utils::compression
{ {
std::string compress(const std::string& data); std::string compress(const std::string& data);
std::string decompress(const std::string& data); std::string decompress(const std::string& data);
std::vector<std::uint8_t> compress(std::span<const std::uint8_t> input, std::size_t exp_output_size, double growth_rate = 2.0);
std::vector<std::uint8_t> decompress(std::span<const std::uint8_t> input, std::size_t exp_output_size, double growth_rate = 2.0);
} }
namespace zip namespace zip

View File

@ -1,25 +0,0 @@
#include "properties.hpp"
#include <gsl/gsl>
#include <ShlObj.h>
namespace utils::properties
{
std::filesystem::path get_appdata_path()
{
PWSTR path;
if (!SUCCEEDED(SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, nullptr, &path)))
{
throw std::runtime_error("Failed to read APPDATA path!");
}
auto _ = gsl::finally([&path]
{
CoTaskMemFree(path);
});
static auto appdata = std::filesystem::path(path) / "alterware";
return appdata;
}
}

View File

@ -1,7 +0,0 @@
#pragma once
#include <filesystem>
namespace utils::properties
{
std::filesystem::path get_appdata_path();
}

View File

@ -115,13 +115,13 @@ namespace utils::string
void strip(const char* in, char* out, size_t max) void strip(const char* in, char* out, size_t max)
{ {
if (!in || !out) return; if (!in || !out || !max) return;
max--; max--;
auto current = 0u; auto current = 0u;
while (*in != 0 && current < max) while (*in != 0 && current < max)
{ {
const auto color_index = (*(in + 1) - 48) >= 0xC ? 7 : (*(in + 1) - 48); const auto color_index = (static_cast<size_t>(*(in + 1) - 48)) >= 0xC ? 7 : (*(in + 1) - 48);
if (*in == '^' && (color_index != 7 || *(in + 1) == '7')) if (*in == '^' && (color_index != 7 || *(in + 1) == '7'))
{ {
@ -140,6 +140,32 @@ namespace utils::string
*out = '\0'; *out = '\0';
} }
std::string strip(std::string_view sv, bool strip_default_color)
{
std::string in(sv);
for (std::size_t i = 0; i + 1 < in.size();)
{
if (in[i] == '^' && static_cast<std::size_t>(in[i + 1] - '0') < 0xC)
{
if (in[i + 1] != '7' || strip_default_color)
{
in.erase(in.begin() + i, in.begin() + i + 2);
}
else
{
i += 2;
}
}
else
{
i += 1;
}
}
return in;
}
std::string convert(const std::wstring& wstr) std::string convert(const std::wstring& wstr)
{ {
std::string result; std::string result;

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "memory.hpp" #include "memory.hpp"
#include <cstdint> #include <cstdint>
#include <span>
template <class Type, size_t n> template <class Type, size_t n>
constexpr auto ARRAY_COUNT(Type(&)[n]) { return n; } constexpr auto ARRAY_COUNT(Type(&)[n]) { return n; }
@ -91,6 +92,7 @@ namespace utils::string
std::string get_clipboard_data(); std::string get_clipboard_data();
void strip(const char* in, char* out, size_t max); void strip(const char* in, char* out, size_t max);
std::string strip(std::string_view sv, bool strip_default_color = false);
std::string convert(const std::wstring& wstr); std::string convert(const std::wstring& wstr);
std::wstring convert(const std::string& str); std::wstring convert(const std::string& str);