Compare commits

...

4 Commits

Author SHA1 Message Date
6239fb8a10
maint: update Premake5 2025-04-11 11:25:07 +02:00
5a4f180986
fix: remove _s poison 2025-02-06 12:55:05 +01:00
547948a324
fix(dedicated): remove loreless patch 2025-02-03 20:49:48 +01:00
6217a48a0d
maint: update 2025-01-30 13:22:45 +01:00
35 changed files with 602 additions and 308 deletions

2
deps/GSL vendored

@ -1 +1 @@
Subproject commit 355982daf6c54ccb11bef8a1c511be2622dec402
Subproject commit 3325bbd33d24d1f8f5a0f69e782c92ad5a39a68e

2
deps/asmjit vendored

@ -1 +1 @@
Subproject commit cfc9f813cc6ccda63cad872edb32b38e0662bedb
Subproject commit e8c8e2e48a1a38154c8e8864eb3bc61db80a1e31

2
deps/gsc-tool vendored

@ -1 +1 @@
Subproject commit e4cb6a7819726d9ea33cd6a52f0dcd9382258b47
Subproject commit 2d9781ce0ce9e8551eaf040d7761fd986f33cfdc

2
deps/libtomcrypt vendored

@ -1 +1 @@
Subproject commit 2e9f2b5e44dd498dba60e5175c6c7effa5ff3728
Subproject commit a6b9aff7aab857fe1b491710a5c5b9e2be49cb08

2
deps/libtommath vendored

@ -1 +1 @@
Subproject commit 5809141a3a6ec1bf3443c927c02b955e19224016
Subproject commit e823b0c34cea291bdb94d672731e1c1f08525557

2
deps/minhook vendored

@ -1 +1 @@
Subproject commit c1a7c3843bd1a5fe3eb779b64c0d823bca3dc339
Subproject commit c3fcafdc10146beb5919319d0683e44e3c30d537

2
deps/rapidjson vendored

@ -1 +1 @@
Subproject commit d621dc9e9c77f81e5c8a35b8dcc16dcd63351321
Subproject commit 24b5e7a8b27f42fa16b96fc70aade9106cf7102f

2
deps/zlib vendored

@ -1 +1 @@
Subproject commit ef24c4c7502169f016dcd2a26923dbaf3216748c
Subproject commit 5a82f71ed1dfc0bec044d9702463dbdf84ea3b71

View File

@ -259,7 +259,7 @@ filter "configurations:Release"
buildoptions {"/GL"}
linkoptions {"/IGNORE:4702", "/LTCG"}
defines {"NDEBUG"}
flags {"FatalCompileWarnings"}
fatalwarnings {"All"}
filter {}
filter "configurations:Debug"

View File

@ -30,8 +30,7 @@ namespace binding
if (value && value < get_num_keys())
{
const auto len = sprintf_s(&buffer[bytes_used], (buffer_size_align - bytes_used),
"bind %s \"%s\"\n", key_button, game::command_whitelist[value]);
const auto len = game::Com_sprintf(&buffer[bytes_used], (buffer_size_align - bytes_used), "bind %s \"%s\"\n", key_button, game::command_whitelist[value]);
if (len < 0)
{
@ -45,8 +44,7 @@ namespace binding
value -= get_num_keys();
if (static_cast<size_t>(value) < custom_binds.size() && !custom_binds[value].empty())
{
const auto len = sprintf_s(&buffer[bytes_used], (buffer_size_align - bytes_used),
"bind %s \"%s\"\n", key_button, custom_binds[value].data());
const auto len = game::Com_sprintf(&buffer[bytes_used], (buffer_size_align - bytes_used), "bind %s \"%s\"\n", key_button, custom_binds[value].data());
if (len < 0)
{

View File

@ -62,7 +62,6 @@ namespace bots
return;
}
// SV_BotGetRandomName
const auto* const bot_name = game::SV_BotGetRandomName();
const auto* bot_ent = game::SV_AddBot(bot_name);
if (bot_ent)

View File

@ -1,14 +1,13 @@
#include <std_include.hpp>
#include "loader/component_loader.hpp"
#include "game/game.hpp"
#include "game/engine/sv_game.hpp"
#include "game/dvars.hpp"
#include "command.hpp"
#include "console.hpp"
#include "game_console.hpp"
#include "scheduler.hpp"
#include "fastfiles.hpp"
#include "game_console.hpp"
#include <utils/hook.hpp>
#include <utils/string.hpp>
@ -236,15 +235,13 @@ namespace command
{
if (!dvars::sv_cheats->current.enabled)
{
game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE,
"f \"Cheats are not enabled on this server\"");
game::engine::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, "f \"Cheats are not enabled on this server\"");
return false;
}
if (ent->health < 1)
{
game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE,
"f \"You must be alive to use this command\"");
game::engine::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, "f \"You must be alive to use this command\"");
return false;
}
@ -582,8 +579,7 @@ namespace command
ent->flags ^= game::FL_GODMODE;
game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE,
utils::string::va("f \"godmode %s\"", (ent->flags & game::FL_GODMODE) ? "^2on" : "^1off"));
game::engine::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, utils::string::va("f \"godmode %s\"", (ent->flags & game::FL_GODMODE) ? "^2on" : "^1off"));
});
add_sv("demigod", [](game::mp::gentity_s* ent, const params_sv&)
@ -593,8 +589,7 @@ namespace command
ent->flags ^= game::FL_DEMI_GODMODE;
game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE,
utils::string::va("f \"demigod mode %s\"", (ent->flags & game::FL_DEMI_GODMODE) ? "^2on" : "^1off"));
game::engine::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, utils::string::va("f \"demigod mode %s\"", (ent->flags & game::FL_DEMI_GODMODE) ? "^2on" : "^1off"));
});
add_sv("notarget", [](game::mp::gentity_s* ent, const params_sv&)
@ -604,8 +599,7 @@ namespace command
ent->flags ^= game::FL_NOTARGET;
game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE,
utils::string::va("f \"notarget %s\"", (ent->flags & game::FL_NOTARGET) ? "^2on" : "^1off"));
game::engine::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, utils::string::va("f \"notarget %s\"", (ent->flags & game::FL_NOTARGET) ? "^2on" : "^1off"));
});
add_sv("noclip", [](game::mp::gentity_s* ent, const params_sv&)
@ -615,8 +609,7 @@ namespace command
ent->client->flags ^= 1;
game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE,
utils::string::va("f \"noclip %s\"", ent->client->flags & 1 ? "^2on" : "^1off"));
game::engine::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, utils::string::va("f \"noclip %s\"", ent->client->flags & 1 ? "^2on" : "^1off"));
});
add_sv("ufo", [](game::mp::gentity_s* ent, const params_sv&)
@ -626,8 +619,7 @@ namespace command
ent->client->flags ^= 2;
game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE,
utils::string::va("f \"ufo %s\"", ent->client->flags & 2 ? "^2on" : "^1off"));
game::engine::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, utils::string::va("f \"ufo %s\"", ent->client->flags & 2 ? "^2on" : "^1off"));
});
add_sv("give", [](game::mp::gentity_s* ent, const params_sv& params)
@ -637,8 +629,7 @@ namespace command
if (params.size() < 2)
{
game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE,
"f \"You did not specify a weapon name\"");
game::engine::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, "f \"You did not specify a weapon name\"");
return;
}
@ -661,8 +652,7 @@ namespace command
if (params.size() < 2)
{
game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE,
"f \"You did not specify a weapon name\"");
game::engine::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, "f \"You did not specify a weapon name\"");
return;
}

View File

@ -42,7 +42,7 @@ namespace console
{
static thread_local char buffer[0x1000];
const auto count = vsnprintf_s(buffer, _TRUNCATE, message, *ap);
const auto count = vsnprintf(buffer, sizeof(buffer), message, *ap);
if (count < 0) return {};
return {buffer, static_cast<size_t>(count)};
@ -84,15 +84,14 @@ namespace console
void print_stub(const char* fmt, ...)
{
char buffer[4096]{};
va_list ap;
va_start(ap, fmt);
char buffer[4096]{};
const auto res = vsnprintf_s(buffer, _TRUNCATE, fmt, ap);
(void)res;
print_message(buffer);
[[maybe_unused]] const auto res = vsnprintf(buffer, sizeof(buffer), fmt, ap);
va_end(ap);
print_message(buffer);
}
void append_text(const char* text)

View File

@ -1,13 +1,16 @@
#include <std_include.hpp>
#include "loader/component_loader.hpp"
#include "game/game.hpp"
#include "game/engine/sv_game.hpp"
#include "command.hpp"
#include "console.hpp"
#include "dvars.hpp"
#include "network.hpp"
#include "scheduler.hpp"
#include "server_list.hpp"
#include "network.hpp"
#include "command.hpp"
#include "dvars.hpp"
#include "component/gsc/script_extension.hpp"
#include <utils/hook.hpp>
#include <utils/string.hpp>
@ -16,9 +19,6 @@ namespace dedicated
{
namespace
{
utils::hook::detour gscr_set_dynamic_dvar_hook;
utils::hook::detour com_quit_f_hook;
const game::dvar_t* sv_lanOnly;
void init_dedicated_server()
@ -99,8 +99,7 @@ namespace dedicated
for (const auto& command : queue)
{
game::Cbuf_AddText(0, command.data());
game::Cbuf_AddText(0, "\n");
command::execute(command);
}
}
@ -109,49 +108,53 @@ namespace dedicated
std::this_thread::sleep_for(1ms);
}
void gscr_set_dynamic_dvar()
void sv_kill_server_f()
{
auto s = game::Scr_GetString(0);
auto* dvar = game::Dvar_FindVar(s);
if (dvar && !std::strncmp("scr_", dvar->name, 4))
game::Com_Shutdown("EXE_SERVERKILLED");
}
void start_map(const std::string& map_name)
{
if (game::Live_SyncOnlineDataFlags(0) > 32)
{
scheduler::once([map_name]()
{
command::execute(std::format("map {}", map_name), false);
}, scheduler::pipeline::main, 1s);
return;
}
gscr_set_dynamic_dvar_hook.invoke<void>();
if (!game::SV_MapExists(map_name.c_str()))
{
console::info("Map '%s' doesn't exist.\n", map_name.c_str());
return;
}
void kill_server()
auto* current_mapname = game::Dvar_FindVar("mapname");
if (current_mapname && utils::string::to_lower(current_mapname->current.string) == utils::string::to_lower(map_name) && (game::SV_Loaded() && !game::VirtualLobby_Loaded()))
{
for (auto i = 0; i < *game::mp::svs_numclients; ++i)
{
if (game::mp::svs_clients[i].header.state >= 3)
{
game::SV_GameSendServerCommand(i, game::SV_CMD_CAN_IGNORE,
utils::string::va("r \"%s\"", "EXE_ENDOFGAME"));
}
console::info("Restarting map: %s\n", map_name.c_str());
command::execute("map_restart", false);
return;
}
com_quit_f_hook.invoke<void>();
console::info("Starting map: %s\n", map_name.c_str());
auto* gametype = game::Dvar_FindVar("g_gametype");
if (gametype && gametype->current.string)
{
command::execute(utils::string::va("ui_gametype %s", gametype->current.string), true);
}
void sys_error_stub(const char* msg, ...)
command::execute(utils::string::va("ui_mapname %s", map_name.c_str()), true);
game::SV_StartMapForParty(0, map_name.c_str(), false, false);
}
void gscr_is_using_match_rules_data_stub()
{
char buffer[2048]{};
va_list ap;
va_start(ap, msg);
vsnprintf_s(buffer, _TRUNCATE, msg, ap);
va_end(ap);
scheduler::once([]
{
command::execute("map_rotate");
}, scheduler::main, 3s);
game::Com_Error(game::ERR_DROP, "%s", buffer);
game::Scr_AddInt(0);
}
}
@ -190,12 +193,12 @@ namespace dedicated
// Don't allow sv_hostname to be changed by the game
dvars::disable::set_string("sv_hostname");
// Stop crashing from sys_errors
utils::hook::jump(0x1404D6260, sys_error_stub);
// Hook R_SyncGpu
utils::hook::jump(0x1405A7630, sync_gpu_stub);
// Make GScr_IsUsingMatchRulesData return 0 so the game doesn't override the cfg
gsc::override_function("isusingmatchrulesdata", gscr_is_using_match_rules_data_stub);
utils::hook::jump(0x14020C6B0, init_dedicated_server);
// delay startup commands until the initialization is done
@ -205,9 +208,6 @@ namespace dedicated
utils::hook::call(0x1403CEC35, execute_console_command);
utils::hook::nop(0x1403CEC4B, 5);
// patch GScr_SetDynamicDvar to behave better
gscr_set_dynamic_dvar_hook.create(0x140312D00, &gscr_set_dynamic_dvar);
utils::hook::nop(0x1404AE6AE, 5); // don't load config file
utils::hook::nop(0x1403AF719, 5); // ^
utils::hook::set<uint8_t>(0x1403D2490, 0xC3); // don't save config file
@ -306,7 +306,7 @@ namespace dedicated
console::info("==================================\n");
// remove disconnect command
game::Cmd_RemoveCommand(reinterpret_cast<const char*>(751));
game::Cmd_RemoveCommand(751);
execute_startup_command_queue();
execute_console_command_queue();
@ -317,8 +317,38 @@ namespace dedicated
command::add("heartbeat", send_heartbeat);
}, scheduler::pipeline::main, 1s);
command::add("killserver", kill_server);
com_quit_f_hook.create(0x1403D08C0, &kill_server);
command::add("killserver", sv_kill_server_f);
command::add("map", [](const command::params& argument)
{
if (argument.size() != 2)
{
return;
}
start_map(argument[1]);
});
command::add("map_restart", []()
{
if (!game::SV_Loaded() || game::VirtualLobby_Loaded())
{
return;
}
*reinterpret_cast<int*>(0x1488692B0) = 1; // sv_map_restart
*reinterpret_cast<int*>(0x1488692B4) = 1; // sv_loadScripts
*reinterpret_cast<int*>(0x1488692B8) = 0; // sv_migrate
reinterpret_cast<void(*)(int)>(0x140437460)(0); // SV_CheckLoadGame
});
command::add("fast_restart", []()
{
if (game::SV_Loaded() && !game::VirtualLobby_Loaded())
{
game::SV_FastRestart(0);
}
});
}
};
}

View File

@ -348,15 +348,14 @@ namespace demonware
return;
}
char buffer[2048];
char buffer[2048]{};
va_list ap;
va_start(ap, msg);
vsnprintf_s(buffer, _TRUNCATE, msg, ap);
printf("%s: %s\n", function, buffer);
vsnprintf(buffer, sizeof(buffer), msg, ap);
va_end(ap);
printf("%s: %s\n", function, buffer);
}
void startup_dw()

View File

@ -1,7 +1,7 @@
#include <std_include.hpp>
#include "loader/component_loader.hpp"
#include "game/game.hpp"
#include "game/engine/sv_game.hpp"
#include "game/dvars.hpp"
#include "console.hpp"
@ -130,7 +130,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* command = utils::string::va("q %s \"%s\"", dvar, value);
game::SV_GameSendServerCommand(entity_num, game::SV_CMD_RELIABLE, command);
game::engine::SV_GameSendServerCommand(static_cast<char>(entity_num), game::SV_CMD_RELIABLE, command);
}
const auto player_cmd_set_client_dvar = utils::hook::assemble([](utils::hook::assembler& a)

View File

@ -64,20 +64,22 @@ namespace filesystem
void startup()
{
register_path("s1");
const auto base = std::filesystem::current_path();
register_path(base / "s1");
register_path(get_binary_directory() + "\\data");
if (get_binary_directory() != std::filesystem::current_path())
if (get_binary_directory() != base)
{
register_path(std::filesystem::current_path() / "data");
register_path(base / "data");
}
// game's search paths
register_path("devraw");
register_path("devraw_shared");
register_path("raw_shared");
register_path("raw");
register_path("main");
register_path(base / "devraw");
register_path(base / "devraw_shared");
register_path(base / "raw_shared");
register_path(base / "raw");
register_path(base / "main");
}
void check_for_startup()

View File

@ -63,7 +63,7 @@ namespace game_console
void clear()
{
strncpy_s(con.buffer, "", sizeof(con.buffer));
game::I_strncpyz(con.buffer, "", sizeof(con.buffer));
con.cursor = 0;
fixed_input = "";
@ -249,7 +249,7 @@ namespace game_console
dvars::con_inputDvarInactiveValueColor->current.vector, offset);
}
strncpy_s(con.globals.auto_complete_choice, matches[0].data(), 64);
game::I_strncpyz(con.globals.auto_complete_choice, matches[0].data(), 64);
con.globals.may_auto_complete = true;
}
else if (matches.size() > 1)
@ -274,7 +274,7 @@ namespace game_console
}
}
strncpy_s(con.globals.auto_complete_choice, matches[0].data(), 64);
game::I_strncpyz(con.globals.auto_complete_choice, matches[0].data(), 64);
con.globals.may_auto_complete = true;
}
}
@ -365,11 +365,11 @@ namespace game_console
void print_internal(const char* fmt, ...)
{
char va_buffer[0x200]{};
char va_buffer[1024]{};
va_list ap;
va_start(ap, fmt);
vsprintf_s(va_buffer, fmt, ap);
vsnprintf(va_buffer, sizeof(va_buffer), fmt, ap);
va_end(ap);
const auto formatted = std::string(va_buffer);
@ -425,7 +425,7 @@ namespace game_console
con.buffer[1] = '\0';
}
strncat_s(con.buffer, con.globals.auto_complete_choice, 64);
game::I_strncat(con.buffer, sizeof(con.buffer), con.globals.auto_complete_choice);
con.cursor = static_cast<int>(std::string(con.buffer).length());
if (con.cursor != 254)
@ -550,7 +550,7 @@ namespace game_console
if (history_index != -1)
{
strncpy_s(con.buffer, history.at(history_index).c_str(), sizeof(con.buffer));
game::I_strncpyz(con.buffer, history.at(history_index).c_str(), sizeof(con.buffer));
con.cursor = static_cast<int>(strlen(con.buffer));
}
}
@ -565,7 +565,7 @@ namespace game_console
if (history_index != -1)
{
strncpy_s(con.buffer, history.at(history_index).c_str(), sizeof(con.buffer));
game::I_strncpyz(con.buffer, history.at(history_index).c_str(), sizeof(con.buffer));
con.cursor = static_cast<int>(strlen(con.buffer));
}
}
@ -720,7 +720,7 @@ namespace game_console
con.output_visible = false;
con.display_line_offset = 0;
con.line_count = 0;
strncpy_s(con.buffer, "", sizeof(con.buffer));
game::I_strncpyz(con.buffer, "", sizeof(con.buffer));
con.globals.x = 0.0f;
con.globals.y = 0.0f;
@ -728,7 +728,7 @@ namespace game_console
con.globals.font_height = 0.0f;
con.globals.may_auto_complete = false;
con.globals.info_line_count = 0;
strncpy_s(con.globals.auto_complete_choice, "", 64);
game::I_strncpyz(con.globals.auto_complete_choice, "", 64);
// add clear command
command::add("clear", [&]()

View File

@ -10,7 +10,6 @@
#include "gsc/script_extension.hpp"
#include <utils/hook.hpp>
#include <utils/io.hpp>
#include <utils/string.hpp>
@ -23,7 +22,7 @@ namespace game_log
char buf[1024]{};
std::size_t out_chars = 0;
for (auto i = 0u; i < game::Scr_GetNumParam(); ++i)
for (std::uint32_t i = 0; i < game::Scr_GetNumParam(); ++i)
{
const auto* value = game::Scr_GetString(i);
const auto len = std::strlen(value);
@ -34,7 +33,7 @@ namespace game_log
break;
}
strncat_s(buf, value, _TRUNCATE);
game::I_strncat(buf, sizeof(buf), value);
}
g_log_printf("%s", buf);
@ -53,18 +52,11 @@ namespace game_log
va_list ap;
va_start(ap, fmt);
vsnprintf_s(buffer, _TRUNCATE, fmt, ap);
vsnprintf(buffer, sizeof(buffer), fmt, ap);
va_end(ap);
const auto time = *game::level_time / 1000;
utils::io::write_file(log, utils::string::va("%3i:%i%i %s",
time / 60,
time % 60 / 10,
time % 60 % 10,
buffer
), true);
utils::io::write_file(log, utils::string::va("%3i:%i%i %s", time / 60, time % 60 / 10, time % 60 % 10, buffer), true);
}
class component final : public component_interface

View File

@ -419,7 +419,7 @@ namespace gsc
public:
void post_load() override
{
gsc_ctx = std::make_unique<xsk::gsc::s1_pc::context>();
gsc_ctx = std::make_unique<xsk::gsc::s1_pc::context>(xsk::gsc::instance::server);
}
void post_unpack() override

View File

@ -2,7 +2,6 @@
#include "loader/component_loader.hpp"
#include "game/game.hpp"
#include "party.hpp"
#include "console.hpp"
#include <utils/hook.hpp>
@ -11,57 +10,15 @@ namespace logger
{
namespace
{
utils::hook::detour com_error_hook;
game::dvar_t* logger_dev = nullptr;
void print_error(const char* msg, ...)
{
char buffer[2048]{};
va_list ap;
va_start(ap, msg);
vsnprintf_s(buffer, _TRUNCATE, msg, ap);
va_end(ap);
console::error("%s", buffer);
}
void print_com_error(int, const char* msg, ...)
{
char buffer[2048]{};
va_list ap;
va_start(ap, msg);
vsnprintf_s(buffer, _TRUNCATE, msg, ap);
va_end(ap);
console::error("%s", buffer);
}
void com_error_stub(const int error, const char* msg, ...)
{
char buffer[2048]{};
va_list ap;
va_start(ap, msg);
vsnprintf_s(buffer, _TRUNCATE, msg, ap);
va_end(ap);
console::error("Error: %s\n", buffer);
party::clear_sv_motd(); // clear sv_motd on error if it exists
com_error_hook.invoke<void>(error, "%s", buffer);
}
void print_warning(const char* msg, ...)
{
char buffer[2048]{};
va_list ap;
va_start(ap, msg);
vsnprintf_s(buffer, _TRUNCATE, msg, ap);
vsnprintf(buffer, sizeof(buffer), msg, ap);
va_end(ap);
console::warn("%s", buffer);
@ -73,7 +30,7 @@ namespace logger
va_list ap;
va_start(ap, msg);
vsnprintf_s(buffer, _TRUNCATE, msg, ap);
vsnprintf(buffer, sizeof(buffer), msg, ap);
va_end(ap);
console::info("%s", buffer);
@ -90,7 +47,7 @@ namespace logger
va_list ap;
va_start(ap, msg);
vsnprintf_s(buffer, _TRUNCATE, msg, ap);
vsnprintf(buffer, sizeof(buffer), msg, ap);
va_end(ap);
console::info("%s", buffer);
@ -157,13 +114,6 @@ namespace logger
utils::hook::jump(0x140701A1C, print);
}
if (!game::environment::is_sp())
{
utils::hook::call(0x1404D8543, print_com_error);
}
com_error_hook.create(game::Com_Error, com_error_stub);
logger_dev = game::Dvar_RegisterBool("logger_dev", false, game::DVAR_FLAG_SAVED);
}
};

View File

@ -29,7 +29,7 @@ namespace lui
{
if (params.size() <= 1)
{
console::info("usage: lui_open <name>\n");
console::info("USAGE: %s <name>\n", params.get(0));
return;
}
@ -40,7 +40,7 @@ namespace lui
{
if (params.size() <= 1)
{
console::info("usage: lui_open_popup <name>\n");
console::info("USAGE: %s <name>\n", params.get(0));
return;
}

View File

@ -1,6 +1,7 @@
#include <std_include.hpp>
#include "loader/component_loader.hpp"
#include "game/game.hpp"
#include "game/engine/sv_game.hpp"
#include "game/dvars.hpp"
#include "party.hpp"
@ -159,7 +160,7 @@ namespace party
if (game::mp::g_entities[i].client)
{
char client_name[16] = {0};
strncpy_s(client_name, game::mp::g_entities[i].client->name, sizeof(client_name));
game::I_strncpyz(client_name, game::mp::g_entities[i].client->name, sizeof(client_name));
game::I_CleanStr(client_name);
if (client_name == name)
@ -226,64 +227,6 @@ namespace party
network::send(target, "getInfo", connect_state.challenge);
}
void start_map(const std::string& mapname)
{
if (game::Live_SyncOnlineDataFlags(0) > 32)
{
scheduler::once([=]()
{
command::execute("map " + mapname, false);
}, scheduler::pipeline::main, 1s);
}
else
{
if (!game::SV_MapExists(mapname.data()))
{
console::info("Map '%s' doesn't exist.\n", mapname.data());
return;
}
auto* current_mapname = game::Dvar_FindVar("mapname");
if (current_mapname && utils::string::to_lower(current_mapname->current.string) ==
utils::string::to_lower(mapname) && (game::SV_Loaded() && !game::VirtualLobby_Loaded()))
{
console::info("Restarting map: %s\n", mapname.data());
command::execute("map_restart", false);
return;
}
if (!game::environment::is_dedi())
{
if (game::SV_Loaded())
{
const auto* args = "Leave";
game::UI_RunMenuScript(0, &args);
}
perform_game_initialization();
}
console::info("Starting map: %s\n", mapname.data());
auto* gametype = game::Dvar_FindVar("g_gametype");
if (gametype && gametype->current.string)
{
command::execute(utils::string::va("ui_gametype %s", gametype->current.string), true);
}
command::execute(utils::string::va("ui_mapname %s", mapname.data()), true);
/*auto* maxclients = game::Dvar_FindVar("sv_maxclients");
if (maxclients)
{
command::execute(utils::string::va("ui_maxclients %i", maxclients->current.integer), true);
command::execute(utils::string::va("party_maxplayers %i", maxclients->current.integer), true);
}*/
const auto* args = "StartServer";
game::UI_RunMenuScript(0, &args);
}
}
int server_client_count()
{
return sv_maxclients;
@ -314,36 +257,6 @@ namespace party
// enable custom kick reason in GScr_KickPlayer
utils::hook::set<uint8_t>(0x14032ED80, 0xEB);
command::add("map", [](const command::params& argument)
{
if (argument.size() != 2)
{
return;
}
start_map(argument[1]);
});
command::add("map_restart", []()
{
if (!game::SV_Loaded() || game::VirtualLobby_Loaded())
{
return;
}
*reinterpret_cast<int*>(0x1488692B0) = 1; // sv_map_restart
*reinterpret_cast<int*>(0x1488692B4) = 1; // sv_loadScripts
*reinterpret_cast<int*>(0x1488692B8) = 0; // sv_migrate
reinterpret_cast<void(*)(int)>(0x140437460)(0); // SV_CheckLoadGame
});
command::add("fast_restart", []()
{
if (game::SV_Loaded() && !game::VirtualLobby_Loaded())
{
game::SV_FastRestart(0);
}
});
command::add("reconnect", [](const command::params& argument)
{
if (!connect_state.hostDefined)
@ -442,7 +355,7 @@ namespace party
{
scheduler::once([i, reason]
{
game::SV_KickClientNum(i, reason.data());
game::SV_KickClientNum(i, reason.c_str());
}, scheduler::pipeline::server);
}
return;
@ -456,7 +369,7 @@ namespace party
scheduler::once([client_num, reason]()
{
game::SV_KickClientNum(client_num, reason.data());
game::SV_KickClientNum(client_num, reason.c_str());
}, scheduler::pipeline::server);
});
@ -476,9 +389,8 @@ namespace party
const auto message = params.join(2);
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()));
printf("%s -> %i: %s\n", name, client_num, message.data());
game::engine::SV_GameSendServerCommand(static_cast<char>(client_num), game::SV_CMD_CAN_IGNORE, utils::string::va("%c \"%s: %s\"", 84, name, message.c_str()));
printf("%s -> %i: %s\n", name, client_num, message.c_str());
});
command::add("tellraw", [](const command::params& params)
@ -491,9 +403,8 @@ namespace party
const auto client_num = atoi(params.get(1));
const auto message = params.join(2);
game::SV_GameSendServerCommand(client_num, game::SV_CMD_CAN_IGNORE,
utils::string::va("%c \"%s\"", 84, message.data()));
printf("%i: %s\n", client_num, message.data());
game::engine::SV_GameSendServerCommand(static_cast<char>(client_num), game::SV_CMD_CAN_IGNORE, utils::string::va("%c \"%s\"", 84, message.c_str()));
printf("%i: %s\n", client_num, message.c_str());
});
command::add("say", [](const command::params& params)
@ -506,9 +417,8 @@ namespace party
const auto message = params.join(1);
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()));
printf("%s: %s\n", name, message.data());
game::engine::SV_GameSendServerCommand(-1, game::SV_CMD_CAN_IGNORE, utils::string::va("%c \"%s: %s\"", 84, name, message.c_str()));
printf("%s: %s\n", name, message.c_str());
});
command::add("sayraw", [](const command::params& params)
@ -520,8 +430,7 @@ namespace party
const auto message = params.join(1);
game::SV_GameSendServerCommand(-1, game::SV_CMD_CAN_IGNORE,
utils::string::va("%c \"%s\"", 84, message.data()));
game::engine::SV_GameSendServerCommand(-1, game::SV_CMD_CAN_IGNORE, utils::string::va("%c \"%s\"", 84, message.c_str()));
printf("%s\n", message.data());
});

View File

@ -5,7 +5,6 @@ namespace party
void reset_connect_state();
void connect(const game::netadr_s& target);
void start_map(const std::string& mapname);
void clear_sv_motd();
int server_client_count();

View File

@ -1,6 +1,7 @@
#include <std_include.hpp>
#include "loader/component_loader.hpp"
#include "game/game.hpp"
#include "game/engine/sv_game.hpp"
#include "game/dvars.hpp"
#include "command.hpp"
@ -19,6 +20,8 @@ namespace patches
{
namespace
{
utils::hook::detour com_quit_f_hook;
utils::hook::detour sv_shutdown_hook;
utils::hook::detour live_get_local_client_name_hook;
const char* live_get_local_client_name()
@ -115,7 +118,7 @@ namespace patches
char* db_read_raw_file_stub(const char* filename, char* buf, const int size)
{
std::string file_name = filename;
if (file_name.find(".cfg") == std::string::npos)
if (!file_name.ends_with(".cfg"))
{
file_name.append(".cfg");
}
@ -124,6 +127,7 @@ namespace patches
if (file.exists())
{
snprintf(buf, size, "%s\n", file.get_buffer().data());
buf[size - 1] = '\0';
return buf;
}
@ -178,13 +182,27 @@ namespace patches
const auto client = &game::mp::svs_clients[ent->s.number];
// 22 => "end_game"
if (menu_id == 22 && client->header.remoteAddress.type != game::NA_LOOPBACK)
if (menu_id == 22 && client->header.netchan.remoteAddress.type != game::NA_LOOPBACK)
{
return;
}
cmd_lui_notify_server_hook.invoke<void>(ent);
}
void sv_shutdown_stub(const char* finalmsg)
{
console::info("----- Server Shutdown -----\n");
sv_shutdown_hook.invoke<void>(finalmsg);
}
void com_quit_f_stub()
{
console::info("quitting...\n");
com_quit_f_hook.invoke<void>();
}
}
class component final : public component_interface
@ -239,6 +257,10 @@ namespace patches
static void patch_mp()
{
// Bypass Arxan function
utils::hook::nop(0x14043E120, 9);
utils::hook::jump(0x14043E120, game::engine::SV_GameSendServerCommand);
// Use name dvar
live_get_local_client_name_hook.create(0x1404D47F0, &live_get_local_client_name);
@ -306,8 +328,14 @@ namespace patches
game::Dvar_RegisterInt("scr_game_spectatetype", 1, 0, 99, game::DVAR_FLAG_REPLICATED);
// Disable Com_Error in NET_SendPacket
utils::hook::nop(0x1404D8543, 5);
// Prevent clients from ending the game as non host by sending 'end_game' lui notification
cmd_lui_notify_server_hook.create(0x1402E9390, cmd_lui_notify_server_stub);
com_quit_f_hook.create(0x1403D08C0, com_quit_f_stub);
sv_shutdown_hook.create(0x140440170, sv_shutdown_stub);
}
static void patch_sp()

View File

@ -86,7 +86,7 @@ namespace rcon
}
char clean_name[32]{};
strncpy_s(clean_name, client->name, _TRUNCATE);
game::I_strncpyz(clean_name, client->name, sizeof(clean_name));
game::I_CleanStr(clean_name);
buffer.append(utils::string::va("%3i %5i %3s %s %32s %16s %21s %5i\n",
@ -96,8 +96,8 @@ namespace rcon
(client->header.state == 2) ? "CNCT" : (client->header.state == 1) ? "ZMBI" : utils::string::va("%4i", game::SV_GetClientPing(i)),
game::SV_GetGuid(i),
clean_name,
network::net_adr_to_string(client->header.remoteAddress),
client->header.remoteAddress.port)
network::net_adr_to_string(client->header.netchan.remoteAddress),
client->header.netchan.remoteAddress.port)
);
}

View File

@ -84,6 +84,36 @@ namespace security
ui_replace_directive_hook.invoke<void>(local_client_num, src_string, dst_string, dst_buffer_size);
}
int hud_elem_set_enum_string_stub(char* string, const char* format, ...)
{
va_list ap;
va_start(ap, format);
const auto len = vsnprintf(string, 0x800, format, ap);
va_end(ap);
return len;
}
int sv_add_bot_stub(char* string, const char* format, ...)
{
va_list ap;
va_start(ap, format);
const auto len = vsnprintf(string, 0x400, format, ap);
va_end(ap);
return len;
}
int sv_add_test_client_stub(char* string, const char* format, ...)
{
va_list ap;
va_start(ap, format);
const auto len = vsnprintf(string, 0x400, format, ap);
va_end(ap);
return len;
}
}
class component final : public component_interface
@ -91,11 +121,18 @@ namespace security
public:
void post_unpack() override
{
// sprinf
utils::hook::call(SELECT_VALUE(0x1402203DF, 0x1402F0BAF), hud_elem_set_enum_string_stub);
if (game::environment::is_sp()) return;
// Patch vulnerability in PlayerCards_SetCachedPlayerData
utils::hook::call(0x1401BB909, set_cached_playerdata_stub);
// sprinf
utils::hook::call(0x140439075, sv_add_bot_stub);
utils::hook::call(0x14043932A, sv_add_test_client_stub);
// Patch entity overflow
utils::hook::jump(0x14044DE3A, assemble(remap_cached_entities_stub), true);

View File

@ -26,6 +26,8 @@ namespace steam_proxy
ownership_state state_;
utils::binary_resource runner_file(RUNNER, "s1-mod-runner.exe");
bool is_disabled() { return true; }
}
class component final : public component_interface
@ -33,7 +35,7 @@ namespace steam_proxy
public:
void post_load() override
{
if (game::environment::is_dedi())
if (game::environment::is_dedi() || is_disabled())
{
return;
}

View File

@ -206,6 +206,27 @@ namespace ui_scripting
setup_functions();
lua["print"] = function(reinterpret_cast<game::hks::lua_function>(0x14007CB70));
lua["directoryexists"] = [](const std::string& string)
{
return utils::io::directory_exists(string);
};
lua["listfiles"] = [](const std::string& string)
{
return utils::io::list_files(string);
};
lua["directoryisempty"] = [](const std::string& string)
{
return utils::io::directory_is_empty(string);
};
lua["fileexists"] = [](const std::string& string)
{
return utils::io::file_exists(string);
};
lua["table"]["unpack"] = lua["unpack"];
lua["luiglobals"] = lua;

View File

@ -0,0 +1,181 @@
#include <std_include.hpp>
#include <game/game.hpp>
#include "sv_game.hpp"
#include <component/console.hpp>
#include <utils/string.hpp>
namespace game::engine
{
char* SV_ExpandNewlines(char* in)
{
static char string[1024];
unsigned int l = 0;
while (*in && l < sizeof(string) - 3)
{
if (*in == '\n')
{
string[l++] = '\\';
string[l++] = 'n';
}
else
{
if (*in != '\x14' && *in != '\x15')
{
string[l++] = *in;
}
}
++in;
}
string[l] = '\0';
return string;
}
void SV_CullIgnorableServerCommands(mp::client_t* client)
{
int to = client->reliableSent + 1;
for (int from = to; from <= client->reliableSequence; ++from)
{
int from_index = from & 0x7F;
assert(client->netBuf.reliableCommandInfo[from_index].time >= 0);
if (client->netBuf.reliableCommandInfo[from_index].type)
{
int to_index = to & 0x7F;
if (to_index != from_index)
{
client->netBuf.reliableCommandInfo[to_index] = client->netBuf.reliableCommandInfo[from_index];
}
++to;
}
}
client->reliableSequence = to - 1;
}
void SV_DelayDropClient(mp::client_t* drop, const char* reason)
{
assert(drop);
assert(reason);
assert(drop->header.state != mp::CS_FREE);
if (drop->header.state == mp::CS_ZOMBIE)
{
#ifdef _DEBUG
console::info("(drop->dropReason) = %s", drop->dropReason);
#endif
}
else if (!drop->dropReason)
{
drop->dropReason = reason;
}
}
void SV_AddServerCommand(mp::client_t* client, svscmd_type type, const char* cmd)
{
static_assert(offsetof(mp::client_t, netBuf.reliableCommandInfo[0].cmd) == 0xC44);
if (client->testClient == TC_BOT)
{
return;
}
if (client->reliableSequence - client->reliableAcknowledge < 64 && client->header.state == mp::CS_ACTIVE || (SV_CullIgnorableServerCommands(client), type))
{
int len = static_cast<int>(std::strlen(cmd)) + 1;
int to = SV_CanReplaceServerCommand(client, reinterpret_cast<const unsigned char*>(cmd), len);
if (to < 0)
{
++client->reliableSequence;
}
else
{
int from = to + 1;
while (from <= client->reliableSequence)
{
client->netBuf.reliableCommandInfo[to & 0x7F] = client->netBuf.reliableCommandInfo[from & 0x7F];
++from;
++to;
}
}
if (client->reliableSequence - client->reliableAcknowledge == 129)
{
#ifdef _DEBUG
console::info("===== pending server commands =====\n");
int i = 0;
for (i = client->reliableAcknowledge + 1; i <= client->reliableSequence; ++i)
{
console::info("cmd %5d: %8d: %s\n", i, client->netBuf.reliableCommandInfo[i & 0x7F].time, client->netBuf.reliableCommandInfo[i & 0x7F].cmd);
}
console::info("cmd %5d: %8d: %s\n", i, *game::mp::serverTime, cmd);
#endif
NET_OutOfBandPrint(NS_SERVER, &client->header.netchan.remoteAddress, "disconnect");
SV_DelayDropClient(client, "EXE_SERVERCOMMANDOVERFLOW");
type = SV_CMD_RELIABLE;
cmd = utils::string::va("%c \"EXE_SERVERCOMMANDOVERFLOW\"", 'r');
}
int index = client->reliableSequence & 0x7F;
MSG_WriteReliableCommandToBuffer(cmd, client->netBuf.reliableCommandInfo[index].cmd, sizeof(client->netBuf.reliableCommandInfo[index].cmd));
client->netBuf.reliableCommandInfo[index].time = *game::mp::serverTime;
client->netBuf.reliableCommandInfo[index].type = type;
}
}
void SV_SendServerCommand(mp::client_t* cl, svscmd_type type, const char* fmt, ...)
{
mp::client_t* client;
int j, len;
va_list va;
const auto server_command_buf_large = std::make_unique<char[]>(0x20000);
va_start(va, fmt);
len = vsnprintf(server_command_buf_large.get(), 0x20000, fmt, va);
va_end(va);
assert(len >= 0);
if (cl)
{
SV_AddServerCommand(cl, type, server_command_buf_large.get());
return;
}
if (environment::is_dedi() && !std::strncmp(server_command_buf_large.get(), "print", 5))
{
console::info("broadcast: %s\n", SV_ExpandNewlines(server_command_buf_large.get()));
}
const auto* sv_maxclients = Dvar_FindVar("sv_maxclients");
for (j = 0, client = mp::svs_clients; j < sv_maxclients->current.integer; j++, client++)
{
if (client->header.state < mp::CS_CLIENTLOADING)
{
continue;
}
SV_AddServerCommand(client, type, server_command_buf_large.get());
}
}
void SV_GameSendServerCommand(char clientNum, svscmd_type type, const char* text)
{
[[maybe_unused]] const auto* sv_maxclients = Dvar_FindVar("sv_maxclients");
if (clientNum == -1)
{
SV_SendServerCommand(nullptr, type, "%s", text);
return;
}
assert(sv_maxclients->current.integer >= 1 && sv_maxclients->current.integer <= 18);
assert(static_cast<unsigned>(clientNum) < sv_maxclients->current.unsignedInt);
SV_SendServerCommand(&mp::svs_clients[clientNum], type, "%s", text);
}
}

View File

@ -0,0 +1,7 @@
#pragma once
namespace game::engine
{
void SV_SendServerCommand(mp::client_t* cl, svscmd_type type, const char* fmt, ...);
void SV_GameSendServerCommand(char clientNum, svscmd_type type, const char* text);
}

View File

@ -855,10 +855,11 @@ namespace game
int readcount;
int bit;
int lastEntityRef;
netsrc_t targetLocalNetID;
int useZlib;
};
static_assert(sizeof(msg_t) == 0x38);
enum errorParm
{
ERR_FATAL = 0,
@ -1416,8 +1417,44 @@ namespace game
static_assert(sizeof(pml_t) == 0x130);
struct netProfilePacket_t
{
int iTime;
int iSize;
int bFragment;
};
struct netProfileStream_t
{
netProfilePacket_t packets[60];
int iCurrPacket;
int iBytesPerSecond;
int iLastBPSCalcTime;
int iCountedPackets;
int iCountedFragments;
int iFragmentPercentage;
int iLargestPacket;
int iSmallestPacket;
};
struct netProfileInfo_t
{
netProfileStream_t send;
netProfileStream_t recieve;
};
namespace mp
{
enum
{
CS_FREE = 0x0,
CS_ZOMBIE = 0x1,
CS_RECONNECTING = 0x2,
CS_CONNECTED = 0x3,
CS_CLIENTLOADING = 0x4,
CS_ACTIVE = 0x5,
};
struct cachedSnapshot_t
{
int archivedFrame;
@ -1470,33 +1507,141 @@ namespace game
{
};
struct netchan_t
{
int outgoingSequence;
netsrc_t sock;
int dropped;
int incomingSequence;
netadr_s remoteAddress;
int fragmentSequence;
int fragmentLength;
char* fragmentBuffer;
int fragmentBufferSize;
int unsentFragments;
int unsentFragmentStart;
int unsentLength;
char* unsentBuffer;
int unsentBufferSize;
netProfileInfo_t prof;
};
struct clientHeader_t
{
int state;
char __pad0[36];
netadr_s remoteAddress;
}; // size = ?
int sendAsActive;
int deltaMessage;
int rateDelayed;
int hasAckedBaselineData;
int hugeSnapshotSent;
netchan_t netchan;
float predictedOrigin[3];
int predictedOriginServerTime;
int migrationState;
unsigned int predictedVehicleSplineId;
int predictedVehicleTargetEntity;
float predictedVehicleOrigin[3];
int predictedVehicleServerTime;
int ackedMessage[32];
unsigned int ackedMessageCount;
int sentMessage[32];
int wasKillcam[32];
unsigned int sendMessageCount;
bool overrideDeltaMessage;
int overrideSequenceNumber;
int sequenceResume;
int isInKillcam;
};
struct svscmd_info_t
{
int time;
int type;
char cmd[1024];
};
static_assert(sizeof(svscmd_info_t) == 0x408);
struct client_net_buffers_t
{
svscmd_info_t reliableCommandInfo[128];
char netchanOutgoingBuffer[131072];
char netchanIncomingBuffer[2048];
};
struct usercmd_s
{
int serverTime;
unsigned int buttons;
int angles[3];
Weapon weapon;
Weapon offHand;
char forwardmove;
char rightmove;
unsigned __int16 airburstMarkDistance;
__int16 meleeChargeEnt;
unsigned __int8 meleeChargeDist;
char selectedLoc[2];
unsigned __int8 selectedLocAngle;
char remoteControlAngles[2];
char remoteControlMove[3];
unsigned int sightedClientsMask;
unsigned __int16 spawnTraceEntIndex;
unsigned int sightedSpawnsMask[2];
unsigned int partialSightedSpawnsMask[2];
};
static_assert(sizeof(usercmd_s) == 0x44);
struct client_t
{
clientHeader_t header;
char __pad0[3044];
const char* dropReason;
char userinfo[0x400];
int reliableSequence;
int reliableAcknowledge;
char __pad1[265864];
int reliableSent;
int messageAcknowledge;
int largeCommandSequence;
int gamestateMessageNum;
int challenge;
client_net_buffers_t netBuf;
int cumulThinkTime;
int beginCmdIndex;
int currCmdIndex;
usercmd_s lastUsercmd;
usercmd_s cmds[8];
int lastClientCommand;
gentity_s* gentity; // 268976
char name[32]; // 268984
char __pad2[8];
char name[32];
int lastPacketTime;
int lastConnectTime;
int nextSnapshotTime; // 269024
char __pad3[544];
char __pad3[532];
int pureAuthentic;
unsigned int streamSyncWaitBits;
unsigned int streamSyncWaitTimeout;
LiveClientDropType liveDropRequest; // 269572
char __pad4[24];
TestClientType testClient; // 269600
char __pad5[391700];
}; // size = 661304
static_assert(offsetof(client_t, header.netchan.unsentFragments) == 0x54);
static_assert(offsetof(client_t, header.migrationState) == 0x660);
static_assert(offsetof(client_t, userinfo) == 0x820);
static_assert(offsetof(client_t, reliableSequence) == 0xC20);
static_assert(offsetof(client_t, reliableAcknowledge) == 0xC24);
static_assert(offsetof(client_t, reliableSent) == 0xC28);
static_assert(offsetof(client_t, messageAcknowledge) == 0xC2C);
static_assert(offsetof(client_t, largeCommandSequence) == 0xC30);
static_assert(offsetof(client_t, lastUsercmd) == 0x41848);
static_assert(offsetof(client_t, lastClientCommand) == 0x41AAC);
static_assert(offsetof(client_t, gentity) == 0x41AB0);
static_assert(offsetof(client_t, name) == 0x41AB8);
static_assert(offsetof(client_t, lastPacketTime) == 0x41AD8);
static_assert(offsetof(client_t, nextSnapshotTime) == 0x41AE0);
static_assert(offsetof(client_t, pureAuthentic) == 0x41CF8);
static_assert(offsetof(client_t, liveDropRequest) == 0x41D04);
static_assert(offsetof(client_t, testClient) == 0x41D20);
static_assert(sizeof(client_t) == 0xA1738);
@ -1508,7 +1653,9 @@ namespace game
{
char __pad[56135];
int flags; // 56136
};
}; // Incomplete
static_assert(offsetof(gclient_s, flags) == 56136);
struct gentity_s
{

View File

@ -23,12 +23,14 @@ namespace game
WEAK symbol<CodPlayMode()> Com_GetCurrentCoDPlayMode{0, 0x1404C9690};
WEAK symbol<void(float, float, int)> Com_SetSlowMotion{0, 0x1403D19B0};
WEAK symbol<void()> Com_Quit_f{0x1402F9390, 0x1403D08C0};
WEAK symbol<void(const char* finalmsg)> Com_Shutdown{0x0, 0x1403D1BF0};
WEAK symbol<void(const char* cmdName, void (), cmd_function_s* allocedCmd)> Cmd_AddCommandInternal{0x1402EDDB0, 0x1403AF2C0};
WEAK symbol<void(int localClientNum, int controllerIndex, const char* text)> Cmd_ExecuteSingleCommand{0x1402EE350, 0x1403AF900};
WEAK symbol<void(const char*)> Cmd_RemoveCommand{0x1402EE910, 0x1403AFEF0};
WEAK symbol<void(int index)> Cmd_RemoveCommand{0x1402EE910, 0x1403AFEF0};
WEAK symbol<void(const char* text_in)> Cmd_TokenizeString{0x1402EEA30, 0x1403B0020};
WEAK symbol<void()> Cmd_EndTokenizeString{0x1402EE000, 0x1403AF5B0};
WEAK symbol<int(char* dest, int size, const char* fmt, ...)> Com_sprintf{0x140378E30, 0x1404C97B0};
WEAK symbol<void(const char* message)> Conbuf_AppendText{0x14038F220, 0x1404D9040};
@ -184,7 +186,7 @@ namespace game
WEAK symbol<void(mp::client_t* client)> SV_DropClient{0, 0x140438A30};
WEAK symbol<void(mp::client_t*, const char*, int)> SV_ExecuteClientCommand{0, 0x15121D8E6};
WEAK symbol<void(int localClientNum)> SV_FastRestart{0, 0x1404374E0};
WEAK symbol<void(int clientNum, svscmd_type type, const char* text)> SV_GameSendServerCommand{0x1403F3A70, 0x14043E120};
WEAK symbol<int(mp::client_t* client, const unsigned char* cmd, int cmdSize)> SV_CanReplaceServerCommand{0x0, 0x140441A00};
WEAK symbol<const char*(int clientNum)> SV_GetGuid{0, 0x14043E1E0};
WEAK symbol<int(int clientNum)> SV_GetClientPing{0, 0x14043E1C0};
WEAK symbol<playerState_s*(int num)> SV_GetPlayerstateForClientNum{0x1403F3AB0, 0x14043E260};
@ -220,6 +222,9 @@ namespace game
WEAK symbol<void(unsigned __int64 markPos)> LargeLocalResetToMark{0x140369C40, 0x1404B6790};
WEAK symbol<void(char* dest, const char* src, int destsize)> I_strncpyz{0x1403793B0, 0x1404C9E60};
WEAK symbol<void(char* dest, int size, const char* src)> I_strncat{0x1403792E0, 0x1404C9D90};
WEAK symbol<void(const char* pszCommand, char* pszBuffer, int iBufferSize)> MSG_WriteReliableCommandToBuffer{0x0, 0x1403E1090};
WEAK symbol<void*(jmp_buf* Buf, int Value)> longjmp{0x14059C5C0, 0x1406FD930};
WEAK symbol<int(jmp_buf* Buf)> _setjmp{0x14059CD00, 0x1406FE070};

View File

@ -64,9 +64,7 @@ LONG WINAPI exception_handler(PEXCEPTION_POINTERS exception_info)
&exception_information, nullptr, nullptr))
{
char buf[4096]{};
sprintf_s(buf, "An exception 0x%08X occurred at location 0x%p\n",
exception_info->ExceptionRecord->ExceptionCode,
exception_info->ExceptionRecord->ExceptionAddress);
sprintf_s(buf, "An exception 0x%08X occurred at location 0x%p\n", exception_info->ExceptionRecord->ExceptionCode, exception_info->ExceptionRecord->ExceptionAddress);
game::show_error(buf);
}

View File

@ -54,6 +54,7 @@
#include <functional>
#include <iostream>
#include <map>
#include <memory>
#include <mutex>
#include <optional>
#include <queue>