forked from alterware/iw6-mod
Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
deafda9061 | |||
61f0374d10 | |||
9052daab5c | |||
a299874dd2 | |||
27d5985574 | |||
b60692f0d7 | |||
6f2c293970 |
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -29,9 +29,6 @@
|
||||
[submodule "deps/udis86"]
|
||||
path = deps/udis86
|
||||
url = https://github.com/vmt/udis86.git
|
||||
[submodule "deps/WinToast"]
|
||||
path = deps/WinToast
|
||||
url = https://github.com/mohabouje/WinToast.git
|
||||
[submodule "deps/zlib"]
|
||||
path = deps/zlib
|
||||
url = https://github.com/madler/zlib.git
|
||||
|
2
deps/GSL
vendored
2
deps/GSL
vendored
@ -1 +1 @@
|
||||
Subproject commit 272463043ef3e442f6c80a530d3dd38ee6781381
|
||||
Subproject commit 3325bbd33d24d1f8f5a0f69e782c92ad5a39a68e
|
1
deps/WinToast
vendored
1
deps/WinToast
vendored
@ -1 +0,0 @@
|
||||
Subproject commit a78ce469b456c06103b3b30d4bd37e7bb80da30c
|
2
deps/asmjit
vendored
2
deps/asmjit
vendored
@ -1 +1 @@
|
||||
Subproject commit cfc9f813cc6ccda63cad872edb32b38e0662bedb
|
||||
Subproject commit e8c8e2e48a1a38154c8e8864eb3bc61db80a1e31
|
2
deps/gsc-tool
vendored
2
deps/gsc-tool
vendored
@ -1 +1 @@
|
||||
Subproject commit e4cb6a7819726d9ea33cd6a52f0dcd9382258b47
|
||||
Subproject commit 2d9781ce0ce9e8551eaf040d7761fd986f33cfdc
|
2
deps/libtomcrypt
vendored
2
deps/libtomcrypt
vendored
@ -1 +1 @@
|
||||
Subproject commit c900951dab1bb94bab803fc57688dac18e3b71f9
|
||||
Subproject commit a6b9aff7aab857fe1b491710a5c5b9e2be49cb08
|
2
deps/libtommath
vendored
2
deps/libtommath
vendored
@ -1 +1 @@
|
||||
Subproject commit 5809141a3a6ec1bf3443c927c02b955e19224016
|
||||
Subproject commit e823b0c34cea291bdb94d672731e1c1f08525557
|
2
deps/minhook
vendored
2
deps/minhook
vendored
@ -1 +1 @@
|
||||
Subproject commit c1a7c3843bd1a5fe3eb779b64c0d823bca3dc339
|
||||
Subproject commit c3fcafdc10146beb5919319d0683e44e3c30d537
|
32
deps/premake/wintoast.lua
vendored
32
deps/premake/wintoast.lua
vendored
@ -1,32 +0,0 @@
|
||||
wintoast = {
|
||||
source = path.join(dependencies.basePath, "WinToast"),
|
||||
}
|
||||
|
||||
function wintoast.import()
|
||||
links { "WinToast" }
|
||||
wintoast.includes()
|
||||
end
|
||||
|
||||
function wintoast.includes()
|
||||
includedirs {
|
||||
path.join(wintoast.source, "include"),
|
||||
}
|
||||
end
|
||||
|
||||
function wintoast.project()
|
||||
project "WinToast"
|
||||
language "C++"
|
||||
|
||||
wintoast.includes()
|
||||
rapidjson.import();
|
||||
|
||||
files {
|
||||
path.join(wintoast.source, "include/wintoastlib.h"),
|
||||
path.join(wintoast.source, "src/wintoastlib.cpp"),
|
||||
}
|
||||
|
||||
warnings "Off"
|
||||
kind "StaticLib"
|
||||
end
|
||||
|
||||
table.insert(dependencies, wintoast)
|
2
deps/rapidjson
vendored
2
deps/rapidjson
vendored
@ -1 +1 @@
|
||||
Subproject commit d621dc9e9c77f81e5c8a35b8dcc16dcd63351321
|
||||
Subproject commit 24b5e7a8b27f42fa16b96fc70aade9106cf7102f
|
2
deps/zlib
vendored
2
deps/zlib
vendored
@ -1 +1 @@
|
||||
Subproject commit ef24c4c7502169f016dcd2a26923dbaf3216748c
|
||||
Subproject commit 5a82f71ed1dfc0bec044d9702463dbdf84ea3b71
|
@ -268,7 +268,7 @@ filter "configurations:Release"
|
||||
buildoptions {"/GL"}
|
||||
linkoptions {"/IGNORE:4702", "/LTCG"}
|
||||
defines {"NDEBUG"}
|
||||
flags {"FatalCompileWarnings"}
|
||||
fatalwarnings {"All"}
|
||||
filter {}
|
||||
|
||||
filter "configurations:Debug"
|
||||
|
@ -25,9 +25,7 @@ namespace binding
|
||||
|
||||
if (value && value < 100)
|
||||
{
|
||||
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)
|
||||
{
|
||||
return bytes_used;
|
||||
@ -40,9 +38,7 @@ namespace binding
|
||||
value -= 100;
|
||||
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)
|
||||
{
|
||||
return bytes_used;
|
||||
|
@ -13,6 +13,8 @@
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/string.hpp>
|
||||
|
||||
#define ALLOW_CUSTOM_BOT_NAMES
|
||||
|
||||
namespace bots
|
||||
{
|
||||
namespace
|
||||
|
@ -107,7 +107,7 @@ namespace colors
|
||||
|
||||
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)
|
||||
{
|
||||
game::I_strncpyz(dest, "UnnamedAgent", size);
|
||||
|
@ -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 len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
print_message(buffer);
|
||||
}
|
||||
|
||||
void append_text(const char* text)
|
||||
|
@ -198,25 +198,6 @@ namespace dedicated
|
||||
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()
|
||||
{
|
||||
command::add("map", [](const command::params& params)
|
||||
@ -364,9 +345,6 @@ namespace dedicated
|
||||
utils::hook::nop(0x1404F8BE1, 2); // ^
|
||||
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
|
||||
utils::hook::set<uint64_t>(0x1404FA6BD, 0x80000000);
|
||||
utils::hook::set<uint64_t>(0x1404FA76F, 0x80000000);
|
||||
|
@ -222,7 +222,7 @@ namespace demonware
|
||||
va_list ap;
|
||||
va_start(ap, msg);
|
||||
|
||||
vsnprintf_s(buffer, _TRUNCATE, msg, ap);
|
||||
vsnprintf(buffer, sizeof(buffer), msg, ap);
|
||||
printf("%s: %s\n", function, buffer);
|
||||
|
||||
va_end(ap);
|
||||
|
@ -112,23 +112,24 @@ namespace dvar_cheats
|
||||
|
||||
void cg_set_client_dvar_from_server(const int local_client_num, game::mp::cg_s* cg, const char* dvar_id, const char* value)
|
||||
{
|
||||
if (dvar_id == "cg_fov"s || dvar_id == "com_maxfps"s)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto* dvar = game::Dvar_FindVar(dvar_id);
|
||||
if (dvar)
|
||||
{
|
||||
// If we send as string, it can't be set with source SERVERCMD because the game only allows that source on real server cmd dvars.
|
||||
// Just use external instead as if it was being set by the console
|
||||
game::Dvar_SetFromStringByNameFromSource(dvar_id, value, game::DvarSetSource::DVAR_SOURCE_EXTERNAL);
|
||||
}
|
||||
else
|
||||
|
||||
if (!dvar)
|
||||
{
|
||||
// Not a dvar name, assume it is an id and the game will handle normally
|
||||
game::CG_SetClientDvarFromServer(local_client_num, cg, dvar_id, value);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dvar && ((dvar->flags & game::DVAR_FLAG_SAVED) != 0))
|
||||
{
|
||||
console::info("Not allowing server to override archive dvar '%s'\n", dvar->name);
|
||||
return;
|
||||
}
|
||||
|
||||
// If we send as string, it can't be set with source SERVERCMD because the game only allows that source on real server cmd dvars.
|
||||
// Just use external instead as if it was being set by the console
|
||||
game::Dvar_SetFromStringByNameFromSource(dvar_id, value, game::DVAR_SOURCE_EXTERNAL);
|
||||
}
|
||||
|
||||
void set_client_dvar_by_string(const int entity_num, const char* value)
|
||||
|
@ -7,10 +7,10 @@
|
||||
#include "console.hpp"
|
||||
#include "fastfiles.hpp"
|
||||
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/memory.hpp>
|
||||
#include <utils/io.hpp>
|
||||
#include <utils/memory.hpp>
|
||||
#include <utils/string.hpp>
|
||||
|
||||
namespace fastfiles
|
||||
{
|
||||
@ -32,6 +32,12 @@ namespace fastfiles
|
||||
return;
|
||||
}
|
||||
|
||||
const auto out_name = std::format("gsc_dump/{}.gscbin", name);
|
||||
if (utils::io::file_exists(out_name))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::string buffer;
|
||||
buffer.append(header.scriptfile->name, std::strlen(header.scriptfile->name) + 1);
|
||||
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(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);
|
||||
|
||||
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)
|
||||
{
|
||||
@ -58,6 +90,11 @@ namespace fastfiles
|
||||
dump_gsc_script(name, result);
|
||||
}
|
||||
|
||||
if (type == game::ASSET_TYPE_STRINGTABLE)
|
||||
{
|
||||
dump_csv_table(name, result);
|
||||
}
|
||||
|
||||
if (diff > 100)
|
||||
{
|
||||
console::print(
|
||||
@ -110,14 +147,11 @@ namespace fastfiles
|
||||
|
||||
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_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(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)
|
||||
{
|
||||
game::DB_EnumXAssets_FastFile(game::ASSET_TYPE_MATERIAL, [](const game::XAssetHeader header, void*)
|
||||
@ -132,6 +166,10 @@ namespace fastfiles
|
||||
if (!game::environment::is_sp())
|
||||
{
|
||||
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
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -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(), 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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -364,11 +364,11 @@ namespace game_console
|
||||
|
||||
void print_internal(const char* fmt, ...)
|
||||
{
|
||||
char va_buffer[0x200] = { 0 };
|
||||
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);
|
||||
@ -424,7 +424,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)
|
||||
@ -549,7 +549,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));
|
||||
}
|
||||
}
|
||||
@ -564,7 +564,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));
|
||||
}
|
||||
}
|
||||
@ -721,7 +721,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;
|
||||
@ -729,7 +729,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, "", sizeof(con.globals.auto_complete_choice));
|
||||
game::I_strncpyz(con.globals.auto_complete_choice, "", sizeof(con.globals.auto_complete_choice));
|
||||
|
||||
// add clear command
|
||||
command::add("clear", [&]()
|
||||
|
@ -3,12 +3,10 @@
|
||||
#include "game/game.hpp"
|
||||
#include "game/dvars.hpp"
|
||||
|
||||
#include "scheduler.hpp"
|
||||
#include "scripting.hpp"
|
||||
#include "console.hpp"
|
||||
#include "game_log.hpp"
|
||||
|
||||
#include "gsc/script_extension.hpp"
|
||||
#include "scheduler.hpp"
|
||||
#include "scripting.hpp"
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/io.hpp>
|
||||
@ -23,7 +21,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 +32,7 @@ namespace game_log
|
||||
break;
|
||||
}
|
||||
|
||||
strncat_s(buf, value, _TRUNCATE);
|
||||
game::I_strncat(buf, sizeof(buf), value);
|
||||
}
|
||||
|
||||
g_log_printf("%s", buf);
|
||||
@ -49,22 +47,15 @@ namespace game_log
|
||||
return;
|
||||
}
|
||||
|
||||
char buffer[0x400]{};
|
||||
char buffer[1024]{};
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
|
||||
vsprintf_s(buffer, 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
|
||||
|
@ -113,6 +113,26 @@ namespace gsc
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool player_cmd_set_client_dvar_is_valid_name(const char* dvar_name)
|
||||
{
|
||||
if (!game::Dvar_IsValidName(dvar_name))
|
||||
{
|
||||
scr_error(va("%s is an invalid dvar name", dvar_name));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void player_cmd_set_client_dvar_server_dvar()
|
||||
{
|
||||
scr_error("server dvar cannot be set as a client dvar");
|
||||
}
|
||||
|
||||
void player_cmd_set_client_dvar_non_writable_dvar()
|
||||
{
|
||||
scr_error("non-writable dvar cannot be set as a client dvar");
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int scr_get_object(unsigned int index)
|
||||
@ -300,6 +320,13 @@ namespace gsc
|
||||
utils::hook::jump(SELECT_VALUE(0x1403DE150, 0x1404390B0), scr_get_pointer_type);
|
||||
utils::hook::jump(SELECT_VALUE(0x1403DE320, 0x140439280), scr_get_type);
|
||||
utils::hook::jump(SELECT_VALUE(0x1403DE390, 0x1404392F0), scr_get_type_name);
|
||||
|
||||
if (game::environment::is_mp())
|
||||
{
|
||||
utils::hook::call(0x14038A4F7, player_cmd_set_client_dvar_is_valid_name);
|
||||
utils::hook::call(0x14038A52F, player_cmd_set_client_dvar_server_dvar);
|
||||
utils::hook::call(0x14038A53A, player_cmd_set_client_dvar_non_writable_dvar);
|
||||
}
|
||||
}
|
||||
|
||||
void pre_destroy() override
|
||||
|
@ -347,7 +347,7 @@ namespace gsc
|
||||
build = static_cast<xsk::gsc::build>(static_cast<unsigned int>(build) | static_cast<unsigned int>(xsk::gsc::build::dev_blocks));
|
||||
}
|
||||
|
||||
gsc_ctx->init(build, []([[maybe_unused]] auto const* ctx, const auto& included_path) -> std::pair<xsk::gsc::buffer, std::vector<std::uint8_t>>
|
||||
gsc_ctx->init(build, []([[maybe_unused]] const auto* ctx, const auto& included_path) -> std::pair<xsk::gsc::buffer, std::vector<std::uint8_t>>
|
||||
{
|
||||
const auto script_name = std::filesystem::path(included_path).replace_extension().string();
|
||||
|
||||
@ -403,7 +403,7 @@ namespace gsc
|
||||
public:
|
||||
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
|
||||
|
@ -10,43 +10,15 @@ namespace logger
|
||||
{
|
||||
namespace
|
||||
{
|
||||
utils::hook::detour com_error_hook;
|
||||
|
||||
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, ...)
|
||||
{
|
||||
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);
|
||||
@ -58,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);
|
||||
@ -75,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);
|
||||
@ -141,17 +113,10 @@ namespace logger
|
||||
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
|
||||
utils::hook::jump(SELECT_VALUE(0x1406283A4, 0x140732184), print);
|
||||
|
||||
logger_dev = game::Dvar_RegisterBool("logger_dev", false, game::DVAR_FLAG_SAVED, "Print dev stuff");
|
||||
logger_dev = game::Dvar_RegisterBool("logger_dev", false, game::DVAR_FLAG_NONE, "Print dev stuff");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -16,24 +16,24 @@ namespace mods
|
||||
{
|
||||
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, const game::FF_DIR source, const 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);
|
||||
(void)game::Com_sprintf(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);
|
||||
(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;
|
||||
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;
|
||||
default:
|
||||
assert(false && "inconceivable");
|
||||
@ -41,9 +41,9 @@ namespace mods
|
||||
}
|
||||
}
|
||||
|
||||
game::Sys_File sys_create_file_stub(const char* dir, const char* filename)
|
||||
game::Sys_File sys_create_file_stub(game::Sys_Folder folder, const char* base_filename)
|
||||
{
|
||||
auto result = sys_create_file_hook.invoke<game::Sys_File>(dir, filename);
|
||||
auto result = sys_create_file_hook.invoke<game::Sys_File>(folder, base_filename);
|
||||
|
||||
if (result.handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
@ -56,7 +56,7 @@ namespace mods
|
||||
}
|
||||
|
||||
// .ff extension was added previously
|
||||
if (!std::strcmp(filename, "mod.ff") && mods::db_mod_file_exists())
|
||||
if (!std::strcmp(base_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);
|
||||
|
@ -181,18 +181,21 @@ namespace party
|
||||
{
|
||||
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};
|
||||
strncpy_s(client_name, game::mp::g_entities[i].client->sess.cs.name, sizeof(client_name));
|
||||
game::I_CleanStr(client_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (client_name == name)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
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);
|
||||
|
||||
if (client_name == name)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -73,8 +73,10 @@ namespace patches
|
||||
if (exec_params.size() == 2)
|
||||
{
|
||||
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");
|
||||
}
|
||||
|
||||
const auto file = filesystem::file(file_name);
|
||||
if (file.exists())
|
||||
@ -164,11 +166,11 @@ namespace patches
|
||||
game::AimAssist_AddToTargetList(a1, a2);
|
||||
}
|
||||
|
||||
game::dvar_t* register_cg_fov_stub(const char* name, float value, float min, float /*max*/,
|
||||
game::dvar_t* register_cg_fov_stub(const char* name, const float value, const float min, [[maybe_unused]] const float max,
|
||||
const unsigned int flags,
|
||||
const char* description)
|
||||
{
|
||||
return game::Dvar_RegisterFloat(name, value, min, 160, flags | 1, description);
|
||||
return game::Dvar_RegisterFloat(name, value, min, 160, flags, description);
|
||||
}
|
||||
|
||||
void bsp_sys_error_stub(const char* error, const char* arg1)
|
||||
@ -295,6 +297,8 @@ namespace patches
|
||||
utils::hook::nop(0x1404758C0, 16);
|
||||
utils::hook::jump(0x1404758C0, game::engine::SV_GameSendServerCommand, true);
|
||||
|
||||
utils::hook::call(0x140477399, game::engine::SV_SendServerCommand);
|
||||
|
||||
// Register dvars
|
||||
com_register_dvars_hook.create(0x140413A90, &com_register_dvars_stub);
|
||||
|
||||
@ -366,6 +370,9 @@ namespace patches
|
||||
utils::hook::nop(0x1403A1A0F, 1);
|
||||
// ^^
|
||||
utils::hook::nop(0x1403A072F, 5); // LiveStorage_RecordMovementInMatchdata
|
||||
|
||||
// Disable Com_Error in NET_SendPacket
|
||||
utils::hook::nop(0x140501AE3, 5);
|
||||
}
|
||||
|
||||
static void patch_sp()
|
||||
|
@ -59,7 +59,7 @@ namespace rcon
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
buffer.append(utils::string::va("%3i %5i %3s %s %32s %16s %21s %5i\n",
|
||||
|
@ -46,12 +46,11 @@ namespace renderer
|
||||
return;
|
||||
}
|
||||
|
||||
dvars::r_fullbright = game::Dvar_RegisterBool("r_fullbright", false, game::DvarFlags::DVAR_FLAG_SAVED,
|
||||
dvars::r_fullbright = game::Dvar_RegisterBool("r_fullbright", false, game::DVAR_FLAG_CHEAT,
|
||||
"Toggles rendering without lighting");
|
||||
|
||||
r_init_draw_method_hook.create(SELECT_VALUE(0x1404FF600, 0x1405CB470), &r_init_draw_method_stub);
|
||||
r_update_front_end_dvar_options_hook.create(
|
||||
SELECT_VALUE(0x140535FF0, 0x140603240), &r_update_front_end_dvar_options_stub);
|
||||
r_update_front_end_dvar_options_hook.create(SELECT_VALUE(0x140535FF0, 0x140603240), &r_update_front_end_dvar_options_stub);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -61,6 +61,42 @@ 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);
|
||||
|
||||
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
|
||||
@ -68,11 +104,18 @@ namespace security
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
// sprinf
|
||||
utils::hook::call(SELECT_VALUE(0x140310D0F, 0x140399B0F), hud_elem_set_enum_string_stub);
|
||||
|
||||
if (game::environment::is_sp()) return;
|
||||
|
||||
// Patch vulnerability in PlayerCards_SetCachedPlayerData
|
||||
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
|
||||
utils::hook::call(0x14047A29A, sv_execute_client_message_stub);
|
||||
|
||||
|
@ -26,6 +26,8 @@ namespace steam_proxy
|
||||
ownership_state state_;
|
||||
|
||||
utils::binary_resource runner_file(RUNNER, "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;
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ namespace dvars
|
||||
game::dvar_t* g_rocketPushbackScale = nullptr;
|
||||
game::dvar_t* g_enableElevators = 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* bg_surfacePenetration = nullptr;
|
||||
|
@ -24,6 +24,7 @@ namespace dvars
|
||||
extern game::dvar_t* g_rocketPushbackScale;
|
||||
extern game::dvar_t* g_enableElevators;
|
||||
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* bg_surfacePenetration;
|
||||
|
@ -136,7 +136,7 @@ namespace game::engine
|
||||
const auto server_command_buf_large = std::make_unique<char[]>(0x20000);
|
||||
|
||||
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);
|
||||
|
||||
assert(len >= 0);
|
||||
@ -178,4 +178,29 @@ namespace game::engine
|
||||
assert(static_cast<unsigned>(clientNum) < sv_maxclients->current.unsignedInt);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,5 +2,7 @@
|
||||
|
||||
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_ReconnectClients(int savepersist);
|
||||
}
|
||||
|
@ -990,6 +990,27 @@ namespace game
|
||||
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
|
||||
{
|
||||
unsigned int name;
|
||||
@ -1160,6 +1181,7 @@ namespace game
|
||||
DVAR_FLAG_LATCHED = 0x2,
|
||||
DVAR_FLAG_CHEAT = 0x4,
|
||||
DVAR_FLAG_REPLICATED = 0x8,
|
||||
DVAR_FLAG_SCRIPTINFO = 0x10,
|
||||
DVAR_FLAG_INTERNAL = 0x80,
|
||||
DVAR_FLAG_EXTERNAL = 0x100,
|
||||
DVAR_FLAG_SERVERINFO = 0x400,
|
||||
|
@ -30,6 +30,8 @@ namespace game
|
||||
WEAK symbol<void(float, float, int)> Com_SetSlowMotion{0, 0x1404158C0};
|
||||
WEAK symbol<void(const char* text_in)> Com_TokenizeString{0x1403B4150, 0x1403F7CC0};
|
||||
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};
|
||||
|
||||
@ -89,6 +91,7 @@ namespace game
|
||||
WEAK symbol<void(const char*, const char*, DvarSetSource)> Dvar_SetFromStringByNameFromSource{0x14042D000, 0x1404F00B0};
|
||||
WEAK symbol<void()> Dvar_Sort{0x14042DEF0, 0x1404F1210};
|
||||
WEAK symbol<const char*(dvar_t* dvar, DvarValue value)> Dvar_ValueToString{0x14042E710, 0x1404F1A30};
|
||||
WEAK symbol<bool(const char* dvarName)> Dvar_IsValidName{0x0, 0x1404ED0E0};
|
||||
|
||||
WEAK symbol<long long (const char* qpath, char** buffer)> FS_ReadFile{0x14041D0B0, 0x1404DE900};
|
||||
WEAK symbol<void(void* buffer)> FS_FreeFile{0x14041D0A0, 0x1404DE8F0};
|
||||
@ -113,10 +116,10 @@ namespace game
|
||||
|
||||
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, 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,
|
||||
uint32_t imageFlags, DXGI_FORMAT imageFormat, const char* name, const void* initData)>
|
||||
Image_Setup{0x140517910, 0x1405E4380};
|
||||
uint32_t imageFlags, DXGI_FORMAT imageFormat, const char* name, const void* initData)> Image_Setup{0x140517910, 0x1405E4380};
|
||||
|
||||
WEAK symbol<const char*(int, int, int)> Key_KeynumToString{0x14023D9A0, 0x1402C40E0};
|
||||
|
||||
@ -220,6 +223,10 @@ namespace game
|
||||
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, 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<bool(int clientNum)> SV_BotIsBot{0, 0x140461340};
|
||||
@ -344,6 +351,8 @@ namespace game
|
||||
WEAK symbol<int> serverTime{0, 0x14647B280};
|
||||
|
||||
WEAK symbol<XZone> g_zones_0{0, 0x143A46498};
|
||||
|
||||
WEAK symbol<int> s_launchDataAvailable{0x0, 0x1445CE354};
|
||||
}
|
||||
|
||||
namespace hks
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -67,6 +67,14 @@ namespace utils::string
|
||||
return std::equal(substring.rbegin(), substring.rend(), text.rbegin());
|
||||
}
|
||||
|
||||
bool compare(const std::string& lhs, const std::string& rhs)
|
||||
{
|
||||
return std::ranges::equal(lhs, rhs, [](const unsigned char a, const unsigned char b)
|
||||
{
|
||||
return std::tolower(a) == std::tolower(b);
|
||||
});
|
||||
}
|
||||
|
||||
bool is_numeric(const std::string& text)
|
||||
{
|
||||
return std::to_string(atoi(text.data())) == text;
|
||||
|
@ -22,78 +22,79 @@ namespace utils::string
|
||||
++this->current_buffer_ %= ARRAY_COUNT(this->string_pool_);
|
||||
auto entry = &this->string_pool_[this->current_buffer_];
|
||||
|
||||
if (!entry->size || !entry->buffer)
|
||||
if (!entry->size_ || !entry->buffer_)
|
||||
{
|
||||
throw std::runtime_error("String pool not initialized");
|
||||
}
|
||||
|
||||
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) return nullptr; // Error
|
||||
|
||||
entry->double_size();
|
||||
}
|
||||
|
||||
return entry->buffer;
|
||||
return entry->buffer_;
|
||||
}
|
||||
|
||||
private:
|
||||
class entry final
|
||||
{
|
||||
public:
|
||||
explicit entry(const size_t _size = MinBufferSize) : size(_size), buffer(nullptr)
|
||||
explicit entry(const size_t size = MinBufferSize) : size_(size), buffer_(nullptr)
|
||||
{
|
||||
if (this->size < MinBufferSize) this->size = MinBufferSize;
|
||||
this->size_ = std::max<size_t>(this->size_, MinBufferSize);
|
||||
this->allocate();
|
||||
}
|
||||
|
||||
~entry()
|
||||
{
|
||||
if (this->buffer) memory::get_allocator()->free(this->buffer);
|
||||
this->size = 0;
|
||||
this->buffer = nullptr;
|
||||
if (this->buffer_) memory::get_allocator()->free(this->buffer_);
|
||||
this->size_ = 0;
|
||||
this->buffer_ = nullptr;
|
||||
}
|
||||
|
||||
void allocate()
|
||||
{
|
||||
if (this->buffer) memory::get_allocator()->free(this->buffer);
|
||||
this->buffer = memory::get_allocator()->allocate_array<char>(this->size + 1);
|
||||
if (this->buffer_) memory::get_allocator()->free(this->buffer_);
|
||||
this->buffer_ = memory::get_allocator()->allocate_array<char>(this->size_ + 1);
|
||||
}
|
||||
|
||||
void double_size()
|
||||
{
|
||||
this->size *= 2;
|
||||
this->size_ *= 2;
|
||||
this->allocate();
|
||||
}
|
||||
|
||||
size_t size;
|
||||
char* buffer;
|
||||
size_t size_;
|
||||
char* buffer_;
|
||||
};
|
||||
|
||||
size_t current_buffer_;
|
||||
entry string_pool_[Buffers];
|
||||
};
|
||||
|
||||
const char* va(const char* fmt, ...);
|
||||
[[nodiscard]] const char* va(const char* fmt, ...);
|
||||
|
||||
std::vector<std::string> split(const std::string& s, char delim);
|
||||
[[nodiscard]] std::vector<std::string> split(const std::string& s, char delim);
|
||||
|
||||
std::string to_lower(const std::string& text);
|
||||
std::string to_upper(const std::string& text);
|
||||
bool starts_with(const std::string& text, const std::string& substring);
|
||||
bool ends_with(const std::string& text, const std::string& substring);
|
||||
bool is_numeric(const std::string& text);
|
||||
[[nodiscard]] std::string to_lower(const std::string& text);
|
||||
[[nodiscard]] std::string to_upper(const std::string& text);
|
||||
[[nodiscard]] bool starts_with(const std::string& text, const std::string& substring);
|
||||
[[nodiscard]] bool ends_with(const std::string& text, const std::string& substring);
|
||||
[[nodiscard]] bool compare(const std::string& lhs, const std::string& rhs);
|
||||
[[nodiscard]] bool is_numeric(const std::string& text);
|
||||
|
||||
std::string dump_hex(const std::string& data, const std::string& separator = " ");
|
||||
[[nodiscard]] std::string dump_hex(const std::string& data, const std::string& separator = " ");
|
||||
|
||||
std::string get_clipboard_data();
|
||||
[[nodiscard]] std::string get_clipboard_data();
|
||||
|
||||
void strip(const char* in, char* out, size_t max);
|
||||
|
||||
std::string convert(const std::wstring& wstr);
|
||||
std::wstring convert(const std::string& str);
|
||||
[[nodiscard]] std::string convert(const std::wstring& wstr);
|
||||
[[nodiscard]] std::wstring convert(const std::string& str);
|
||||
|
||||
std::string replace(std::string str, const std::string& from, const std::string& to);
|
||||
[[nodiscard]] std::string replace(std::string str, const std::string& from, const std::string& to);
|
||||
}
|
||||
|
@ -1,109 +0,0 @@
|
||||
#include "toast.hpp"
|
||||
#include "string.hpp"
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 6387)
|
||||
#include <wintoastlib.h>
|
||||
#pragma warning(pop)
|
||||
|
||||
namespace utils
|
||||
{
|
||||
namespace
|
||||
{
|
||||
bool initialize()
|
||||
{
|
||||
static bool initialized = false;
|
||||
static bool success = false;
|
||||
if (initialized)
|
||||
{
|
||||
return success;
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
auto* instance = WinToastLib::WinToast::instance();
|
||||
if (!instance)
|
||||
{
|
||||
success = false;
|
||||
return success;
|
||||
}
|
||||
|
||||
instance->setAppName(L"iw6-mod");
|
||||
instance->setAppUserModelId(
|
||||
WinToastLib::WinToast::configureAUMI(L"AlterWare", L"iw6-mod", L"", L"20201212"));
|
||||
|
||||
WinToastLib::WinToast::WinToastError error;
|
||||
success = instance->initialize(&error);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
class toast_handler : public WinToastLib::IWinToastHandler
|
||||
{
|
||||
public:
|
||||
void toastActivated() const override
|
||||
{
|
||||
}
|
||||
|
||||
void toastActivated(const int /*actionIndex*/) const override
|
||||
{
|
||||
}
|
||||
|
||||
void toastFailed() const override
|
||||
{
|
||||
}
|
||||
|
||||
void toastDismissed(WinToastDismissalReason /*state*/) const override
|
||||
{
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
toast::toast(const int64_t id)
|
||||
: id_(id)
|
||||
{
|
||||
}
|
||||
|
||||
toast::operator bool() const
|
||||
{
|
||||
return this->id_ >= 0;
|
||||
}
|
||||
|
||||
void toast::hide() const
|
||||
{
|
||||
if (this->operator bool())
|
||||
{
|
||||
WinToastLib::WinToast::instance()->hideToast(this->id_);
|
||||
}
|
||||
}
|
||||
|
||||
toast toast::show(const std::string& title, const std::string& text)
|
||||
{
|
||||
if (!initialize())
|
||||
{
|
||||
return toast{-1};
|
||||
}
|
||||
|
||||
WinToastLib::WinToastTemplate toast_template(WinToastLib::WinToastTemplate::Text02);
|
||||
toast_template.setTextField(string::convert(title), WinToastLib::WinToastTemplate::FirstLine);
|
||||
toast_template.setTextField(string::convert(text), WinToastLib::WinToastTemplate::SecondLine);
|
||||
toast_template.setDuration(WinToastLib::WinToastTemplate::Long);
|
||||
|
||||
return toast{WinToastLib::WinToast::instance()->showToast(toast_template, new toast_handler())};
|
||||
}
|
||||
|
||||
toast toast::show(const std::string& title, const std::string& text, const std::string& image)
|
||||
{
|
||||
if (!initialize())
|
||||
{
|
||||
return {-1};
|
||||
}
|
||||
|
||||
WinToastLib::WinToastTemplate toast_template(WinToastLib::WinToastTemplate::ImageAndText02);
|
||||
toast_template.setTextField(string::convert(title), WinToastLib::WinToastTemplate::FirstLine);
|
||||
toast_template.setTextField(string::convert(text), WinToastLib::WinToastTemplate::SecondLine);
|
||||
toast_template.setDuration(WinToastLib::WinToastTemplate::Long);
|
||||
toast_template.setImagePath(string::convert(image));
|
||||
|
||||
return {WinToastLib::WinToast::instance()->showToast(toast_template, new toast_handler())};
|
||||
}
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
namespace utils
|
||||
{
|
||||
class toast
|
||||
{
|
||||
public:
|
||||
static toast show(const std::string& title, const std::string& text);
|
||||
static toast show(const std::string& title, const std::string& text, const std::string& image);
|
||||
|
||||
operator bool() const;
|
||||
void hide() const;
|
||||
|
||||
private:
|
||||
toast(int64_t id);
|
||||
int64_t id_;
|
||||
};
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user