Compare commits

..

5 Commits

Author SHA1 Message Date
9052daab5c
maint: update Premake5 2025-04-11 11:10:05 +02:00
a299874dd2
fix: remove _s poison 2025-02-06 12:34:59 +01:00
27d5985574
fix noob team 2025-02-03 20:02:50 +01:00
b60692f0d7
feat: more arxan patches 2025-01-30 13:14:21 +01:00
6f2c293970
chore: update deps 2025-01-29 13:25:42 +01:00
33 changed files with 219 additions and 141 deletions

2
deps/GSL vendored

@ -1 +1 @@
Subproject commit 272463043ef3e442f6c80a530d3dd38ee6781381 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 c900951dab1bb94bab803fc57688dac18e3b71f9 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

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

View File

@ -25,9 +25,7 @@ namespace binding
if (value && value < 100) if (value && value < 100)
{ {
const auto len = sprintf_s(&buffer[bytes_used], (buffer_size_align - bytes_used), const auto len = game::Com_sprintf(&buffer[bytes_used], (buffer_size_align - bytes_used), "bind %s \"%s\"\n", key_button, game::command_whitelist[value]);
"bind %s \"%s\"\n", key_button, game::command_whitelist[value]);
if (len < 0) if (len < 0)
{ {
return bytes_used; return bytes_used;
@ -40,9 +38,7 @@ namespace binding
value -= 100; value -= 100;
if (static_cast<size_t>(value) < custom_binds.size() && !custom_binds[value].empty()) 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), const auto len = game::Com_sprintf(&buffer[bytes_used], (buffer_size_align - bytes_used), "bind %s \"%s\"\n", key_button, custom_binds[value].data());
"bind %s \"%s\"\n", key_button, custom_binds[value].data());
if (len < 0) if (len < 0)
{ {
return bytes_used; return bytes_used;

View File

@ -107,7 +107,7 @@ namespace colors
int com_sprintf_stub(char* dest, int size, const char* fmt, const char* name) int com_sprintf_stub(char* dest, int size, const char* fmt, const char* name)
{ {
const auto len = sprintf_s(dest, size, fmt, name); const auto len = game::Com_sprintf(dest, size, fmt, name);
if (len < 0) if (len < 0)
{ {
game::I_strncpyz(dest, "UnnamedAgent", size); game::I_strncpyz(dest, "UnnamedAgent", size);

View File

@ -84,15 +84,14 @@ namespace console
void print_stub(const char* fmt, ...) void print_stub(const char* fmt, ...)
{ {
char buffer[4096]{};
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
[[maybe_unused]] const auto len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
char buffer[4096]{};
const auto res = vsnprintf_s(buffer, _TRUNCATE, fmt, ap);
(void)res;
print_message(buffer);
va_end(ap); va_end(ap);
print_message(buffer);
} }
void append_text(const char* text) void append_text(const char* text)

View File

@ -198,25 +198,6 @@ namespace dedicated
return hwnd; return hwnd;
} }
void sys_error_stub(const char* msg, ...)
{
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::pipeline::main, 3s);
game::Com_Error(game::ERR_DROP, "%s", buffer);
}
void add_commands() void add_commands()
{ {
command::add("map", [](const command::params& params) command::add("map", [](const command::params& params)
@ -364,9 +345,6 @@ namespace dedicated
utils::hook::nop(0x1404F8BE1, 2); // ^ utils::hook::nop(0x1404F8BE1, 2); // ^
utils::hook::set<uint8_t>(0x140328660, 0xC3); // Disable image pak file loading utils::hook::set<uint8_t>(0x140328660, 0xC3); // Disable image pak file loading
// Stop crashing from sys_errors
utils::hook::jump(0x1404FF510, sys_error_stub);
// Reduce min required memory // Reduce min required memory
utils::hook::set<uint64_t>(0x1404FA6BD, 0x80000000); utils::hook::set<uint64_t>(0x1404FA6BD, 0x80000000);
utils::hook::set<uint64_t>(0x1404FA76F, 0x80000000); utils::hook::set<uint64_t>(0x1404FA76F, 0x80000000);

View File

@ -222,7 +222,7 @@ namespace demonware
va_list ap; va_list ap;
va_start(ap, msg); va_start(ap, msg);
vsnprintf_s(buffer, _TRUNCATE, msg, ap); vsnprintf(buffer, sizeof(buffer), msg, ap);
printf("%s: %s\n", function, buffer); printf("%s: %s\n", function, buffer);
va_end(ap); va_end(ap);

View File

@ -7,10 +7,10 @@
#include "console.hpp" #include "console.hpp"
#include "fastfiles.hpp" #include "fastfiles.hpp"
#include <utils/hook.hpp> #include <utils/hook.hpp>
#include <utils/memory.hpp>
#include <utils/io.hpp> #include <utils/io.hpp>
#include <utils/memory.hpp>
#include <utils/string.hpp>
namespace fastfiles namespace fastfiles
{ {
@ -32,6 +32,12 @@ namespace fastfiles
return; return;
} }
const auto out_name = std::format("gsc_dump/{}.gscbin", name);
if (utils::io::file_exists(out_name))
{
return;
}
std::string buffer; std::string buffer;
buffer.append(header.scriptfile->name, std::strlen(header.scriptfile->name) + 1); buffer.append(header.scriptfile->name, std::strlen(header.scriptfile->name) + 1);
buffer.append(reinterpret_cast<char*>(&header.scriptfile->compressedLen), 4); buffer.append(reinterpret_cast<char*>(&header.scriptfile->compressedLen), 4);
@ -40,12 +46,38 @@ namespace fastfiles
buffer.append(header.scriptfile->buffer, header.scriptfile->compressedLen); buffer.append(header.scriptfile->buffer, header.scriptfile->compressedLen);
buffer.append(reinterpret_cast<char*>(header.scriptfile->bytecode), header.scriptfile->bytecodeLen); buffer.append(reinterpret_cast<char*>(header.scriptfile->bytecode), header.scriptfile->bytecodeLen);
const auto out_name = std::format("gsc_dump/{}.gscbin", name);
utils::io::write_file(out_name, buffer); utils::io::write_file(out_name, buffer);
console::info("Dumped %s\n", out_name.data()); console::info("Dumped %s\n", out_name.c_str());
} }
void dump_csv_table(const std::string& name, game::XAssetHeader header)
{
if (!dvars::g_dump_string_tables->current.enabled)
{
return;
}
const auto out_name = std::format("csv_dump/{}.csv", name);
if (utils::io::file_exists(out_name))
{
return;
}
std::string buffer;
for (auto row = 0; row < header.stringTable->rowCount; row++)
{
for (auto column = 0; column < header.stringTable->columnCount; column++)
{
const auto* string = header.stringTable->values[(row * header.stringTable->columnCount) + column].string;
buffer.append(utils::string::va("%s%s", string ? string : "", (column == header.stringTable->columnCount - 1) ? "\n" : ","));
}
}
utils::io::write_file(out_name, buffer);
console::info("Dumped %s\n", out_name.c_str());
}
game::XAssetHeader db_find_x_asset_header_stub(game::XAssetType type, const char* name, int allow_create_default) game::XAssetHeader db_find_x_asset_header_stub(game::XAssetType type, const char* name, int allow_create_default)
{ {
@ -58,6 +90,11 @@ namespace fastfiles
dump_gsc_script(name, result); dump_gsc_script(name, result);
} }
if (type == game::ASSET_TYPE_STRINGTABLE)
{
dump_csv_table(name, result);
}
if (diff > 100) if (diff > 100)
{ {
console::print( console::print(
@ -110,14 +147,11 @@ namespace fastfiles
db_find_x_asset_header_hook.create(game::DB_FindXAssetHeader, db_find_x_asset_header_stub); db_find_x_asset_header_hook.create(game::DB_FindXAssetHeader, db_find_x_asset_header_stub);
dvars::g_dump_scripts = game::Dvar_RegisterBool("g_dumpScripts", false, game::DVAR_FLAG_NONE, "Dump GSC scripts to binary format"); dvars::g_dump_scripts = game::Dvar_RegisterBool("g_dumpScripts", false, game::DVAR_FLAG_NONE, "Dump GSC scripts to binary format");
dvars::g_dump_string_tables = game::Dvar_RegisterBool("g_dumpStringTables", false, game::DVAR_FLAG_NONE, "Dump CSV files");
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
utils::hook::set<uint8_t>(0x1402FBF23, 0xEB); // DB_LoadXFile
utils::hook::nop(0x1402FC445, 2); // DB_SetFileLoadCompressor
command::add("materiallist", [](const command::params& params) command::add("materiallist", [](const command::params& params)
{ {
game::DB_EnumXAssets_FastFile(game::ASSET_TYPE_MATERIAL, [](const game::XAssetHeader header, void*) game::DB_EnumXAssets_FastFile(game::ASSET_TYPE_MATERIAL, [](const game::XAssetHeader header, void*)
@ -132,6 +166,10 @@ namespace fastfiles
if (!game::environment::is_sp()) if (!game::environment::is_sp())
{ {
reallocate_asset_pool(game::ASSET_TYPE_WEAPON, 320); reallocate_asset_pool(game::ASSET_TYPE_WEAPON, 320);
// Allow loading of unsigned fastfiles
utils::hook::set<uint8_t>(0x1402FBF23, 0xEB); // DB_LoadXFile
utils::hook::nop(0x1402FC445, 2); // DB_SetFileLoadCompressor
} }
} }
}; };

View File

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

View File

@ -3,12 +3,10 @@
#include "game/game.hpp" #include "game/game.hpp"
#include "game/dvars.hpp" #include "game/dvars.hpp"
#include "scheduler.hpp"
#include "scripting.hpp"
#include "console.hpp" #include "console.hpp"
#include "game_log.hpp" #include "game_log.hpp"
#include "scheduler.hpp"
#include "gsc/script_extension.hpp" #include "scripting.hpp"
#include <utils/hook.hpp> #include <utils/hook.hpp>
#include <utils/io.hpp> #include <utils/io.hpp>
@ -23,7 +21,7 @@ namespace game_log
char buf[1024]{}; char buf[1024]{};
std::size_t out_chars = 0; 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* value = game::Scr_GetString(i);
const auto len = std::strlen(value); const auto len = std::strlen(value);
@ -34,7 +32,7 @@ namespace game_log
break; break;
} }
strncat_s(buf, value, _TRUNCATE); game::I_strncat(buf, sizeof(buf), value);
} }
g_log_printf("%s", buf); g_log_printf("%s", buf);
@ -49,22 +47,15 @@ namespace game_log
return; return;
} }
char buffer[0x400]{}; char buffer[1024]{};
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
vsnprintf(buffer, sizeof(buffer), fmt, ap);
vsprintf_s(buffer, fmt, ap);
va_end(ap); va_end(ap);
const auto time = *game::level_time / 1000; const auto time = *game::level_time / 1000;
utils::io::write_file(log, utils::string::va("%3i:%i%i %s", utils::io::write_file(log, utils::string::va("%3i:%i%i %s", time / 60, time % 60 / 10, time % 60 % 10, buffer), true);
time / 60,
time % 60 / 10,
time % 60 % 10,
buffer
), true);
} }
class component final : public component_interface class component final : public component_interface

View File

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

View File

@ -10,43 +10,15 @@ namespace logger
{ {
namespace namespace
{ {
utils::hook::detour com_error_hook;
const game::dvar_t* logger_dev = nullptr; const game::dvar_t* logger_dev = nullptr;
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);
com_error_hook.invoke<void>(error, "%s", buffer);
}
void print_warning(const char* msg, ...) void print_warning(const char* msg, ...)
{ {
char buffer[2048]{}; char buffer[2048]{};
va_list ap; va_list ap;
va_start(ap, msg); va_start(ap, msg);
vsnprintf_s(buffer, _TRUNCATE, msg, ap); vsnprintf(buffer, sizeof(buffer), msg, ap);
va_end(ap); va_end(ap);
console::warn("%s", buffer); console::warn("%s", buffer);
@ -58,7 +30,7 @@ namespace logger
va_list ap; va_list ap;
va_start(ap, msg); va_start(ap, msg);
vsnprintf_s(buffer, _TRUNCATE, msg, ap); vsnprintf(buffer, sizeof(buffer), msg, ap);
va_end(ap); va_end(ap);
console::info("%s", buffer); console::info("%s", buffer);
@ -75,7 +47,7 @@ namespace logger
va_list ap; va_list ap;
va_start(ap, msg); va_start(ap, msg);
vsnprintf_s(buffer, _TRUNCATE, msg, ap); vsnprintf(buffer, sizeof(buffer), msg, ap);
va_end(ap); va_end(ap);
console::info("%s", buffer); console::info("%s", buffer);
@ -141,13 +113,6 @@ namespace logger
sub_1401DAA40(); sub_1401DAA40();
} }
if (!game::environment::is_sp())
{
utils::hook::call(0x140501AE3, print_com_error);
}
com_error_hook.create(game::Com_Error, com_error_stub);
// Make havok script's print function actually print // Make havok script's print function actually print
utils::hook::jump(SELECT_VALUE(0x1406283A4, 0x140732184), print); utils::hook::jump(SELECT_VALUE(0x1406283A4, 0x140732184), print);

View File

@ -16,24 +16,24 @@ namespace mods
{ {
utils::hook::detour sys_create_file_hook; 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) void db_build_os_path_from_source(const char* zone_name, game::FF_DIR source, int size, char* filename)
{ {
char user_map[MAX_PATH]{}; char user_map[MAX_PATH]{};
switch (source) switch (source)
{ {
case game::FFD_DEFAULT: case game::FFD_DEFAULT:
(void)sprintf_s(filename, size, "%s\\%s.ff", std::filesystem::current_path().string().c_str(), zone_name); (void)game::Com_sprintf(filename, size, "%s\\%s.ff", std::filesystem::current_path().string().c_str(), zone_name);
break; break;
case game::FFD_MOD_DIR: case game::FFD_MOD_DIR:
assert(mods::is_using_mods()); 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); (void)game::Com_sprintf(filename, size, "%s\\%s\\%s.ff", std::filesystem::current_path().string().c_str(), (*dvars::fs_gameDirVar)->current.string, zone_name);
break; break;
case game::FFD_USER_MAP: case game::FFD_USER_MAP:
strncpy_s(user_map, zone_name, _TRUNCATE); game::I_strncpyz(user_map, zone_name, sizeof(user_map));
(void)sprintf_s(filename, size, "%s\\%s\\%s\\%s.ff", std::filesystem::current_path().string().c_str(), "usermaps", user_map, zone_name); (void)game::Com_sprintf(filename, size, "%s\\%s\\%s\\%s.ff", std::filesystem::current_path().string().c_str(), "usermaps", user_map, zone_name);
break; break;
default: default:
assert(false && "inconceivable"); assert(false && "inconceivable");

View File

@ -181,10 +181,13 @@ namespace party
{ {
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)
{ {
char client_name[16] = {0}; continue;
strncpy_s(client_name, game::mp::g_entities[i].client->sess.cs.name, sizeof(client_name)); }
char client_name[16]{};
game::I_strncpyz(client_name, game::mp::g_entities[i].client->sess.cs.name, sizeof(client_name));
game::I_CleanStr(client_name); game::I_CleanStr(client_name);
if (client_name == name) if (client_name == name)
@ -192,7 +195,7 @@ namespace party
return i; return i;
} }
} }
}
return -1; return -1;
} }

View File

@ -73,8 +73,10 @@ namespace patches
if (exec_params.size() == 2) if (exec_params.size() == 2)
{ {
std::string file_name = exec_params.get(1); std::string file_name = exec_params.get(1);
if (file_name.find(".cfg") == std::string::npos) if (!file_name.ends_with(".cfg"))
{
file_name.append(".cfg"); file_name.append(".cfg");
}
const auto file = filesystem::file(file_name); const auto file = filesystem::file(file_name);
if (file.exists()) if (file.exists())
@ -295,6 +297,8 @@ namespace patches
utils::hook::nop(0x1404758C0, 16); utils::hook::nop(0x1404758C0, 16);
utils::hook::jump(0x1404758C0, game::engine::SV_GameSendServerCommand, true); utils::hook::jump(0x1404758C0, game::engine::SV_GameSendServerCommand, true);
utils::hook::call(0x140477399, game::engine::SV_SendServerCommand);
// Register dvars // Register dvars
com_register_dvars_hook.create(0x140413A90, &com_register_dvars_stub); com_register_dvars_hook.create(0x140413A90, &com_register_dvars_stub);
@ -366,6 +370,9 @@ namespace patches
utils::hook::nop(0x1403A1A0F, 1); utils::hook::nop(0x1403A1A0F, 1);
// ^^ // ^^
utils::hook::nop(0x1403A072F, 5); // LiveStorage_RecordMovementInMatchdata utils::hook::nop(0x1403A072F, 5); // LiveStorage_RecordMovementInMatchdata
// Disable Com_Error in NET_SendPacket
utils::hook::nop(0x140501AE3, 5);
} }
static void patch_sp() static void patch_sp()

View File

@ -59,7 +59,7 @@ namespace rcon
} }
char clean_name[32]{}; char clean_name[32]{};
strncpy_s(clean_name, self->client->sess.cs.name, sizeof(clean_name)); game::I_strncpyz(clean_name, self->client->sess.cs.name, sizeof(clean_name));
game::I_CleanStr(clean_name); game::I_CleanStr(clean_name);
buffer.append(utils::string::va("%3i %5i %3s %s %32s %16s %21s %5i\n", buffer.append(utils::string::va("%3i %5i %3s %s %32s %16s %21s %5i\n",

View File

@ -61,6 +61,42 @@ namespace security
ui_replace_directive_hook.invoke<void>(local_client_num, src_string, dst_string, dst_buffer_size); 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);
string[0x800 - 1] = '\0';
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);
string[0x400 - 1] = '\0';
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);
string[0x400 - 1] = '\0';
return len;
}
} }
class component final : public component_interface class component final : public component_interface
@ -68,11 +104,18 @@ namespace security
public: public:
void post_unpack() override void post_unpack() override
{ {
// sprinf
utils::hook::call(SELECT_VALUE(0x140310D0F, 0x140399B0F), hud_elem_set_enum_string_stub);
if (game::environment::is_sp()) return; if (game::environment::is_sp()) return;
// Patch vulnerability in PlayerCards_SetCachedPlayerData // Patch vulnerability in PlayerCards_SetCachedPlayerData
utils::hook::call(0x140287C5C, set_cached_playerdata_stub); utils::hook::call(0x140287C5C, set_cached_playerdata_stub);
// sprinf
utils::hook::call(0x140470A88, sv_add_bot_stub);
utils::hook::call(0x140470F68, sv_add_test_client_stub);
// It is possible to make the server hang if left unchecked // It is possible to make the server hang if left unchecked
utils::hook::call(0x14047A29A, sv_execute_client_message_stub); utils::hook::call(0x14047A29A, sv_execute_client_message_stub);

View File

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

View File

@ -25,6 +25,7 @@ namespace dvars
game::dvar_t* g_rocketPushbackScale = nullptr; game::dvar_t* g_rocketPushbackScale = nullptr;
game::dvar_t* g_enableElevators = nullptr; game::dvar_t* g_enableElevators = nullptr;
game::dvar_t* g_dump_scripts = nullptr; game::dvar_t* g_dump_scripts = nullptr;
game::dvar_t* g_dump_string_tables = nullptr;
game::dvar_t* g_log = nullptr; game::dvar_t* g_log = nullptr;
game::dvar_t* bg_surfacePenetration = nullptr; game::dvar_t* bg_surfacePenetration = nullptr;

View File

@ -24,6 +24,7 @@ namespace dvars
extern game::dvar_t* g_rocketPushbackScale; extern game::dvar_t* g_rocketPushbackScale;
extern game::dvar_t* g_enableElevators; extern game::dvar_t* g_enableElevators;
extern game::dvar_t* g_dump_scripts; extern game::dvar_t* g_dump_scripts;
extern game::dvar_t* g_dump_string_tables;
extern game::dvar_t* g_log; extern game::dvar_t* g_log;
extern game::dvar_t* bg_surfacePenetration; extern game::dvar_t* bg_surfacePenetration;

View File

@ -136,7 +136,7 @@ namespace game::engine
const auto server_command_buf_large = std::make_unique<char[]>(0x20000); const auto server_command_buf_large = std::make_unique<char[]>(0x20000);
va_start(va, fmt); va_start(va, fmt);
len = vsnprintf_s(server_command_buf_large.get(), 0x20000, _TRUNCATE, fmt, va); len = vsnprintf(server_command_buf_large.get(), 0x20000, fmt, va);
va_end(va); va_end(va);
assert(len >= 0); assert(len >= 0);
@ -178,4 +178,29 @@ namespace game::engine
assert(static_cast<unsigned>(clientNum) < sv_maxclients->current.unsignedInt); assert(static_cast<unsigned>(clientNum) < sv_maxclients->current.unsignedInt);
SV_SendServerCommand(&mp::svs_clients[clientNum], type, "%s", text); SV_SendServerCommand(&mp::svs_clients[clientNum], type, "%s", text);
} }
void SV_ReconnectClients(int savepersist)
{
const auto* sv_maxclients = Dvar_FindVar("sv_maxclients");
for (int i = 0; i < sv_maxclients->current.integer; ++i)
{
mp::client_t* client = &mp::svs_clients[i];
if (client->header.state < CS_CONNECTED)
{
continue;
}
SV_AddServerCommand(client, SV_CMD_RELIABLE, utils::string::va("%c", savepersist != 0 ? 107 : 118));
const char* denied = ClientConnect(i, client->scriptId);
if (denied)
{
SV_DropClient(client, denied, true);
console::info("SV_MapRestart_f: dropped client %i - denied!\n", i);
}
else if (client->header.state == CS_ACTIVE)
{
SV_ClientEnterWorld(client, &client->lastUsercmd);
}
}
}
} }

View File

@ -2,5 +2,7 @@
namespace game::engine namespace game::engine
{ {
void SV_SendServerCommand(mp::client_t* cl, svscmd_type type, const char* fmt, ...);
void SV_GameSendServerCommand(int clientNum, svscmd_type type, const char* text); void SV_GameSendServerCommand(int clientNum, svscmd_type type, const char* text);
void SV_ReconnectClients(int savepersist);
} }

View File

@ -990,6 +990,27 @@ namespace game
LOOKUP_ERROR_COUNT = 0x5, LOOKUP_ERROR_COUNT = 0x5,
}; };
struct ComStreamSyncModel
{
unsigned __int16 modelIndex;
unsigned __int8 alternateIndex;
};
static_assert(sizeof(ComStreamSyncModel) == 4);
struct ComStreamedSyncModelList
{
unsigned int modelCount;
ComStreamSyncModel models[18];
};
static_assert(sizeof(ComStreamedSyncModelList) == 0x4C);
struct ComStreamedSyncSwapBuffer
{
ComStreamedSyncModelList modelLists[2];
};
struct StructuredDataEnumEntry struct StructuredDataEnumEntry
{ {
unsigned int name; unsigned int name;

View File

@ -30,6 +30,8 @@ namespace game
WEAK symbol<void(float, float, int)> Com_SetSlowMotion{0, 0x1404158C0}; WEAK symbol<void(float, float, int)> Com_SetSlowMotion{0, 0x1404158C0};
WEAK symbol<void(const char* text_in)> Com_TokenizeString{0x1403B4150, 0x1403F7CC0}; WEAK symbol<void(const char* text_in)> Com_TokenizeString{0x1403B4150, 0x1403F7CC0};
WEAK symbol<void()> Com_EndTokenizeString{0x1403B37C0, 0x1403F7330}; WEAK symbol<void()> Com_EndTokenizeString{0x1403B37C0, 0x1403F7330};
WEAK symbol<void()> Com_StreamSync_UpdateLaunchData{0x0, 0x140411B50};
WEAK symbol<int(char* dest, int size, const char* fmt, ...)> Com_sprintf{0x140432310, 0x1404F6260};
WEAK symbol<void(const char* message)> Conbuf_AppendText{0x14043DDE0, 0x1405028C0}; WEAK symbol<void(const char* message)> Conbuf_AppendText{0x14043DDE0, 0x1405028C0};
@ -113,10 +115,10 @@ namespace game
WEAK symbol<char*(char* string)> I_CleanStr{0x140432460, 0x1404F63C0}; WEAK symbol<char*(char* string)> I_CleanStr{0x140432460, 0x1404F63C0};
WEAK symbol<void(char* dest, const char* src, int destsize)> I_strncpyz{0x140432810, 0x1404F67A0}; WEAK symbol<void(char* dest, const char* src, int destsize)> I_strncpyz{0x140432810, 0x1404F67A0};
WEAK symbol<void(char* dest, int size, const char* src)> I_strncat{0x140432740, 0x1404F66D0};
WEAK symbol<char*(GfxImage* image, uint32_t width, uint32_t height, uint32_t depth, uint32_t mipCount, WEAK symbol<char*(GfxImage* image, uint32_t width, uint32_t height, uint32_t depth, uint32_t mipCount,
uint32_t imageFlags, DXGI_FORMAT imageFormat, const char* name, const void* initData)> uint32_t imageFlags, DXGI_FORMAT imageFormat, const char* name, const void* initData)> Image_Setup{0x140517910, 0x1405E4380};
Image_Setup{0x140517910, 0x1405E4380};
WEAK symbol<const char*(int, int, int)> Key_KeynumToString{0x14023D9A0, 0x1402C40E0}; WEAK symbol<const char*(int, int, int)> Key_KeynumToString{0x14023D9A0, 0x1402C40E0};
@ -220,6 +222,10 @@ namespace game
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<void(mp::client_t* cl, int isReconnectingClient)> SV_StreamSync_ClientConnect{0x0, 0x140488080};
WEAK symbol<const char*(int clientNum, unsigned __int16 scriptPersId)> ClientConnect{0x0, 0x140387630};
WEAK symbol<void(mp::client_t* client, usercmd_s* cmd)> SV_ClientEnterWorld{0x0, 0x1404710F0};
WEAK symbol<void(mp::client_t* drop, const char* reason, bool tellThem)> SV_DropClient{0x0, 0x140472110};
WEAK symbol<mp::gentity_s*(const char*, unsigned int, unsigned int, unsigned int)> SV_AddBot{0, 0x140470920}; WEAK symbol<mp::gentity_s*(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};
@ -344,6 +350,8 @@ namespace game
WEAK symbol<int> serverTime{0, 0x14647B280}; WEAK symbol<int> serverTime{0, 0x14647B280};
WEAK symbol<XZone> g_zones_0{0, 0x143A46498}; WEAK symbol<XZone> g_zones_0{0, 0x143A46498};
WEAK symbol<int> s_launchDataAvailable{0x0, 0x1445CE354};
} }
namespace hks namespace hks

View File

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

View File

@ -29,7 +29,7 @@ namespace utils::string
while (true) while (true)
{ {
const int res = vsnprintf_s(entry->buffer, entry->size, _TRUNCATE, format, ap); const int res = vsnprintf(entry->buffer, entry->size, format, ap);
if (res > 0) break; // Success if (res > 0) break; // Success
if (res == 0) return nullptr; // Error if (res == 0) return nullptr; // Error