cleanup and more

This commit is contained in:
quaK 2022-10-18 06:39:26 +03:00
parent a9ddb83380
commit b131b28075
18 changed files with 515 additions and 259 deletions

View File

@ -8,6 +8,7 @@
#include "console.hpp" #include "console.hpp"
#include "game_console.hpp" #include "game_console.hpp"
#include "scheduler.hpp" #include "scheduler.hpp"
#include "dvars.hpp"
#include <utils/hook.hpp> #include <utils/hook.hpp>
#include <utils/string.hpp> #include <utils/string.hpp>
@ -107,6 +108,47 @@ namespace command
parsed = true; parsed = true;
} }
void parse_startup_variables()
{
auto& com_num_console_lines = *reinterpret_cast<int*>(0x6006DB0_b);
auto* com_console_lines = reinterpret_cast<char**>(0x6006DC0_b);
for (int i = 0; i < com_num_console_lines; i++)
{
game::Cmd_TokenizeString(com_console_lines[i]);
// only +set dvar value
if (game::Cmd_Argc() >= 3 && (game::Cmd_Argv(0) == "set"s || game::Cmd_Argv(0) == "seta"s))
{
const std::string& dvar_name = game::Cmd_Argv(1);
const std::string& value = game::Cmd_Argv(2);
const auto* dvar = game::Dvar_FindVar(dvar_name.data());
if (dvar)
{
game::Dvar_SetCommand(dvar_name.data(), value.data());
}
else
{
dvars::callback::on_register(dvar_name, [dvar_name, value]()
{
game::Dvar_SetCommand(dvar_name.data(), value.data());
});
}
}
game::Cmd_EndTokenizeString();
}
}
void parse_commandline()
{
parse_command_line();
parse_startup_variables();
parse_commandline_hook.invoke<void>();
}
game::dvar_t* dvar_command_stub() game::dvar_t* dvar_command_stub()
{ {
const params args; const params args;
@ -324,6 +366,8 @@ namespace command
client_command_mp_hook.create(0xB105D0_b, &client_command_mp); client_command_mp_hook.create(0xB105D0_b, &client_command_mp);
client_command_sp_hook.create(0x483130_b, &client_command_sp); client_command_sp_hook.create(0x483130_b, &client_command_sp);
parse_commandline_hook.create(0xF2F67B_b, parse_commandline);
add_commands(); add_commands();
} }

View File

@ -2,6 +2,7 @@
#include "loader/component_loader.hpp" #include "loader/component_loader.hpp"
#include "game/game.hpp" #include "game/game.hpp"
#include "game/dvars.hpp"
#include "dvars.hpp" #include "dvars.hpp"
#include "command.hpp" #include "command.hpp"
@ -10,13 +11,41 @@
#include <utils/hook.hpp> #include <utils/hook.hpp>
#include <utils/string.hpp> #include <utils/string.hpp>
#include <utils/flags.hpp>
#include "game/dvars.hpp"
namespace dedicated namespace dedicated
{ {
namespace namespace
{ {
std::vector<std::string>& get_startup_command_queue()
{
static std::vector<std::string> startup_command_queue;
return startup_command_queue;
}
void execute_startup_command(int client, int /*controllerIndex*/, const char* command)
{
if (game::Live_SyncOnlineDataFlags(0) == 0)
{
game::Cbuf_ExecuteBufferInternal(0, 0, command, game::Cmd_ExecuteSingleCommand);
}
else
{
get_startup_command_queue().emplace_back(command);
}
}
void execute_startup_command_queue()
{
const auto queue = get_startup_command_queue();
get_startup_command_queue().clear();
for (const auto& command : queue)
{
game::Cbuf_ExecuteBufferInternal(0, 0, command.data(), game::Cmd_ExecuteSingleCommand);
}
}
bool party_is_server_dedicated_stub() bool party_is_server_dedicated_stub()
{ {
return true; return true;
@ -27,10 +56,13 @@ namespace dedicated
std::this_thread::sleep_for(1ms); std::this_thread::sleep_for(1ms);
} }
void gscr_is_using_match_rules_data_stub()
{
game::Scr_AddInt(0);
}
void init_dedicated_server() void init_dedicated_server()
{ {
printf("init called...\n");
// R_RegisterDvars // R_RegisterDvars
utils::hook::invoke<void>(0xDF62C0_b); utils::hook::invoke<void>(0xDF62C0_b);
@ -53,7 +85,6 @@ namespace dedicated
{ {
if (handle == *reinterpret_cast<HANDLE*>(0x8B1BC98_b)) if (handle == *reinterpret_cast<HANDLE*>(0x8B1BC98_b))
{ {
//printf("not waiting for mutex\n");
return 0; return 0;
} }
@ -62,7 +93,6 @@ namespace dedicated
void initialize() void initialize()
{ {
//command::execute("exec default_xboxlive.cfg", true);
command::execute("onlinegame 1", true); command::execute("onlinegame 1", true);
command::execute("xblive_privatematch 1", true); command::execute("xblive_privatematch 1", true);
} }
@ -76,7 +106,7 @@ namespace dedicated
{ {
if (function == "WaitForSingleObject") if (function == "WaitForSingleObject")
{ {
return wait_for_single_object_stub; // return wait_for_single_object_stub;
} }
} }
@ -109,95 +139,44 @@ namespace dedicated
// Disable load for renderer // Disable load for renderer
dvars::override::register_bool("r_loadForRenderer", false, game::DVAR_FLAG_READ); dvars::override::register_bool("r_loadForRenderer", false, game::DVAR_FLAG_READ);
// Preload game mode fastfiles on launch
//dvars::override::register_bool("fastfilePreloadGamemode", true, game::DVAR_FLAG_NONE);
dvars::override::register_bool("intro", false, game::DVAR_FLAG_READ); dvars::override::register_bool("intro", false, game::DVAR_FLAG_READ);
// Is party dedicated // Is party dedicated
utils::hook::jump(0x5DFC10_b, party_is_server_dedicated_stub); utils::hook::jump(0x5DFC10_b, party_is_server_dedicated_stub);
// Make GScr_IsUsingMatchRulesData return 0 so the game doesn't override the cfg
utils::hook::jump(0xB53950_b, gscr_is_using_match_rules_data_stub);
// Hook R_SyncGpu // Hook R_SyncGpu
utils::hook::jump(0xE08AE0_b, sync_gpu_stub, true); utils::hook::jump(0xE08AE0_b, sync_gpu_stub, true);
utils::hook::jump(0x341B60_b, init_dedicated_server, true); utils::hook::jump(0x341B60_b, init_dedicated_server, true);
// delay startup commands until the initialization is done
utils::hook::call(0xB8D20F_b, execute_startup_command);
utils::hook::nop(0xCDD5D3_b, 5); // don't load config file utils::hook::nop(0xCDD5D3_b, 5); // don't load config file
utils::hook::nop(0xB7CE46_b, 5); // ^ utils::hook::nop(0xB7CE46_b, 5); // ^
utils::hook::set<uint8_t>(0xBB0930_b, 0xC3); // don't save config file utils::hook::set<uint8_t>(0xBB0930_b, 0xC3); // don't save config file
utils::hook::set<uint8_t>(0x9D49C0_b, 0xC3); // disable self-registration // done utils::hook::set<uint8_t>(0x9D49C0_b, 0xC3); // disable self-registration
utils::hook::set(0xC93120_b, 0xC3C033); // init sound system (1) // done SND_InitDriver utils::hook::set<uint8_t>(0xE574E0_b, 0xC3); // render thread
utils::hook::set<uint8_t>(0xD597C0_b, 0xC3); // init sound system (2) // done Voice_Init utils::hook::set<uint8_t>(0x3471A0_b, 0xC3); // called from Com_Frame, seems to do renderer stuff
utils::hook::set<uint8_t>(0xE574E0_b, 0xC3); // render thread // done RB_RenderThread utils::hook::set<uint8_t>(0x9AA9A0_b, 0xC3); // CL_CheckForResend, which tries to connect to the local server constantly
utils::hook::set<uint8_t>(0x3471A0_b, 0xC3); // called from Com_Frame, seems to do renderer stuff // done CL_Screen_Update utils::hook::set<uint8_t>(0xD2EBB0_b, 0xC3); // recommended settings check
utils::hook::set<uint8_t>(0x9AA9A0_b, 0xC3); // CL_CheckForResend, which tries to connect to the local server constantly // done CL_MainMP_CheckForResend
//utils::hook::set<uint8_t>(0x67ADCE_b, 0x00); // r_loadForRenderer default to 0 // done via dvar override
//utils::hook::set<uint8_t>(0xD2EBB0_b, 0xC3); // recommended settings check // done
//utils::hook::set<uint8_t>(0x5BE850_b, 0xC3); // some mixer-related function called on shutdown // not needed, only called from Voice_Init
//utils::hook::set<uint8_t>(0x4DEA50_b, 0xC3); // dont load ui gametype stuff // don't add this for now
utils::hook::nop(0xC5007B_b, 6); // unknown check in SV_ExecuteClientMessage // done // sound initialization
utils::hook::nop(0xC4F407_b, 3); // allow first slot to be occupied // done utils::hook::nop(0xC93213_b, 5); // snd stream thread
utils::hook::nop(0x3429A7_b, 2); // properly shut down dedicated servers // done utils::hook::set<uint8_t>(0xC93206_b, 0); // snd_active
utils::hook::nop(0x34296F_b, 2); // ^ // done utils::hook::set<uint8_t>(0xD597C0_b, 0xC3); // init voice system
utils::hook::nop(0x3429CD_b, 5); // don't shutdown renderer // done ( maybe need to add R_ShutdownWorld to this too? )
//utils::hook::set<uint8_t>(0xAA290_b, 0xC3); // something to do with blendShapeVertsView // not a thing in iw7 utils::hook::nop(0xC5007B_b, 6); // unknown check in SV_ExecuteClientMessage
//utils::hook::nop(0x70465D_b, 8); // sound thing // dunno if needed utils::hook::nop(0xC4F407_b, 3); // allow first slot to be occupied
utils::hook::nop(0x3429A7_b, 2); // properly shut down dedicated servers
utils::hook::nop(0x34296F_b, 2); // ^
utils::hook::set<uint8_t>(0xE08360_b, 0xC3); // don't shutdown renderer
//utils::hook::set<uint8_t>(0x1D8A20_b, 0xC3); // cpu detection stuff? // can't find utils::hook::set<uint8_t>(0xC5A200_b, 0xC3); // disable host migration
//utils::hook::set<uint8_t>(0x690F30_b, 0xC3); // gfx stuff during fastfile loading // not there
//utils::hook::set<uint8_t>(0x690E00_b, 0xC3); // ^
//utils::hook::set<uint8_t>(0x690ED0_b, 0xC3); // ^
//utils::hook::set<uint8_t>(0x39B980_b, 0xC3); // ^
//utils::hook::set<uint8_t>(0x690E50_b, 0xC3); // ^
//utils::hook::set<uint8_t>(0xDD26E0_b, 0xC3); // directx stuff // done
//utils::hook::set<uint8_t>(0xE00FC0_b, 0xC3); // ^
//utils::hook::set<uint8_t>(0x6CE390_b, 0xC3); // ^ - mutex // not done
//utils::hook::set<uint8_t>(0x681ED0_b, 0xC3); // ^
//utils::hook::set<uint8_t>(0x0A3CD0_b, 0xC3); // rendering stuff // not done
//utils::hook::set<uint8_t>(0x682150_b, 0xC3); // ^
//utils::hook::set<uint8_t>(0x682260_b, 0xC3); // ^
//utils::hook::set<uint8_t>(0x6829C0_b, 0xC3); // ^
//utils::hook::set<uint8_t>(0x6834A0_b, 0xC3); // ^
//utils::hook::set<uint8_t>(0x683B40_b, 0xC3); // ^
// shaders
//utils::hook::set<uint8_t>(0x5F0610_b, 0xC3); // ^ // done
//utils::hook::set<uint8_t>(0x5F0580_b, 0xC3); // ^ // done
//utils::hook::set<uint8_t>(0xE51020_b, 0xC3); // ^ - mutex // done
//utils::hook::set<uint8_t>(0x5BFD10_b, 0xC3); // idk // not done
//utils::hook::set<uint8_t>(0xDD4430_b, 0xC3); // ^ // R_ReleaseBuffer
//utils::hook::set<uint8_t>(0xE08360_b, 0xC3); // R_Shutdown
//utils::hook::set<uint8_t>(0x652BA0_b, 0xC3); // shutdown stuff // not done
//utils::hook::set<uint8_t>(0x687DF0_b, 0xC3); // ^ // not done
//utils::hook::set<uint8_t>(0x686DE0_b, 0xC3); // ^ // not done
// utils::hook::set<uint8_t>(0x1404B67E0, 0xC3); // sound crashes (H1 - questionable, function looks way different)
utils::hook::set<uint8_t>(0xC5A200_b, 0xC3); // disable host migration // done SV_MigrationStart
//utils::hook::set<uint8_t>(0xBB66B0_b, 0xC3); // render synchronization lock // done
//utils::hook::set<uint8_t>(0xBB64A0_b, 0xC3); // render synchronization unlock // done
//utils::hook::set<uint8_t>(0x615359_b, 0xEB); // LUI: Unable to start the LUI system due to errors in main.lua // done
//utils::hook::set<uint8_t>(0x27AAC5_b, 0xEB); // LUI: Unable to start the LUI system due to errors in depot.lua // no
//utils::hook::set<uint8_t>(0x27AADC_b, 0xEB); // ^
//utils::hook::nop(0xCFDA7E_b, 5); // Disable sound pak file loading // done
//utils::hook::nop(0xCFDA97_b, 2); // ^ // done
//utils::hook::set<uint8_t>(0x3A0BA0_b, 0xC3); // Disable image pak file loading // not done
// Reduce min required memory
//utils::hook::set<uint64_t>(0x5B7F37_b, 0x80000000); // not done
//utils::hook::set<uint8_t>(0x399E10_b, 0xC3); // some loop // not done
//utils::hook::set<uint8_t>(0x1D48B0_b, 0xC3); // related to shader caching / techsets / fastfilesc // not done
//utils::hook::set<uint8_t>(0x3A1940_b, 0xC3); // DB_ReadPackedLoadedSounds // not done
// iw7 patches // iw7 patches
utils::hook::set(0xE06060_b, 0xC3C033); //utils::hook::set<uint8_t>(0xE06060_b, 0xC3); // directx utils::hook::set(0xE06060_b, 0xC3C033); //utils::hook::set<uint8_t>(0xE06060_b, 0xC3); // directx
@ -230,6 +209,8 @@ namespace dedicated
utils::hook::set(0xDD42E0_b, 0xC3C033); // ^ utils::hook::set(0xDD42E0_b, 0xC3C033); // ^
utils::hook::set(0xDD4280_b, 0xC3C033); // ^ utils::hook::set(0xDD4280_b, 0xC3C033); // ^
utils::hook::set(0xDD4230_b, 0xC3C033); // ^
// r_loadForRenderer // r_loadForRenderer
//utils::hook::set<uint8_t>(0xE114A0_b, 0xC3); // ^ //utils::hook::set<uint8_t>(0xE114A0_b, 0xC3); // ^
//utils::hook::set<uint8_t>(0xE11380_b, 0xC3); // ^ //utils::hook::set<uint8_t>(0xE11380_b, 0xC3); // ^
@ -249,26 +230,69 @@ namespace dedicated
// R_LoadWorld // R_LoadWorld
utils::hook::set<uint8_t>(0xDD14C0_b, 0xC3); utils::hook::set<uint8_t>(0xDD14C0_b, 0xC3);
// vls shit // something to do with vls?
utils::hook::set<uint8_t>(0xD02CB0_b, 0xC3); utils::hook::set<uint8_t>(0xD02CB0_b, 0xC3);
// renderer
//utils::hook::set<uint8_t>(0xDD4370_b, 0xC3);
// image stream (pak) // image stream (pak)
utils::hook::set<uint8_t>(0xA7DB10_b, 0xC3); // DB_CreateGfxImageStreamInternal utils::hook::set<uint8_t>(0xA7DB10_b, 0xC3); // DB_CreateGfxImageStreamInternal
// sound stream (sabl, sabs) // sound stream (sabl, sabs)
//utils::hook::nop(0xCFDC03_b, 2); //utils::hook::nop(0xCFDC03_b, 2);
command::add("startserver", []() // set game mode
scheduler::once([]()
{
if (utils::flags::has_flag("cpMode") || utils::flags::has_flag("zombies"))
{
game::Com_GameMode_SetDesiredGameMode(game::GAME_MODE_CP);
}
else
{
game::Com_GameMode_SetDesiredGameMode(game::GAME_MODE_MP);
}
}, scheduler::pipeline::main);
// initialization
scheduler::on_game_initialized([]()
{ {
initialize(); initialize();
console::info("==================================\n"); console::info("==================================\n");
console::info("Server started!\n"); console::info("Server started!\n");
console::info("==================================\n"); console::info("==================================\n");
});
// remove disconnect command
game::Cmd_RemoveCommand("disconnect");
execute_startup_command_queue();
}, scheduler::pipeline::main, 1s);
// dedicated info
scheduler::loop([]()
{
auto* sv_running = game::Dvar_FindVar("sv_running");
if (!sv_running || !sv_running->current.enabled)
{
console::set_title("IW7-Mod Dedicated Server");
return;
}
auto* const sv_hostname = game::Dvar_FindVar("sv_hostname");
auto* const mapname = game::Dvar_FindVar("mapname");
if (!sv_hostname || !mapname)
{
return;
}
std::string cleaned_hostname;
cleaned_hostname.resize(static_cast<int>(strlen(sv_hostname->current.string) + 1));
utils::string::strip(sv_hostname->current.string, cleaned_hostname.data(),
static_cast<int>(strlen(sv_hostname->current.string)) + 1);
console::set_title(utils::string::va("%s on %s", cleaned_hostname.data(), mapname->current.string));
}, scheduler::pipeline::main, 1s);
} }
}; };
} }

View File

@ -6,6 +6,7 @@
#include "game/dvars.hpp" #include "game/dvars.hpp"
#include <utils/hook.hpp> #include <utils/hook.hpp>
#include <utils/string.hpp>
namespace dvars namespace dvars
{ {
@ -358,7 +359,7 @@ namespace dvars
if (dvar) if (dvar)
{ {
if (name) if (name && !utils::string::is_numeric(name))
{ {
dvars::dvar_set_name(dvar, name); dvars::dvar_set_name(dvar, name);
} }

View File

@ -0,0 +1,29 @@
#include <std_include.hpp>
#include "loader/component_loader.hpp"
#include "filesystem.hpp"
#include "game/game.hpp"
#include "dvars.hpp"
#include <utils/hook.hpp>
#include <utils/string.hpp>
namespace filesystem
{
namespace
{
}
class component final : public component_interface
{
public:
void post_unpack() override
{
dvars::override::register_string("fs_basegame", "iw7-mod", 2048);
}
};
}
REGISTER_COMPONENT(filesystem::component)

View File

@ -0,0 +1,6 @@
#pragma once
namespace filesystem
{
}

View File

@ -6,6 +6,8 @@
#include "game/game.hpp" #include "game/game.hpp"
#include "game/dvars.hpp" #include "game/dvars.hpp"
#include "dvars.hpp"
#include <utils/nt.hpp> #include <utils/nt.hpp>
#include <utils/hook.hpp> #include <utils/hook.hpp>
#include <utils/flags.hpp> #include <utils/flags.hpp>
@ -18,7 +20,7 @@ namespace gameplay
void stuck_in_client_stub(void* entity) void stuck_in_client_stub(void* entity)
{ {
if (dvars::g_playerEjection->current.enabled) if (dvars::bg_playerEjection->current.enabled)
{ {
stuck_in_client_hook.invoke<void>(entity); stuck_in_client_hook.invoke<void>(entity);
} }
@ -51,20 +53,52 @@ namespace gameplay
}); });
} }
void* g_gravity_stub() int get_gravity()
{
return static_cast<int>(game::BG_GetGravity());
}
void* bg_gravity_stub()
{ {
return utils::hook::assemble([](utils::hook::assembler& a) return utils::hook::assemble([](utils::hook::assembler& a)
{ {
a.mov(rax, qword_ptr(reinterpret_cast<int64_t>(&dvars::g_gravity))); // do moveSpeedScaleMultiplier first (xmm0)
a.mov(eax, dword_ptr(rax, 0x10));
a.mov(dword_ptr(rdi, 0x78), eax);
a.call(0xBB3030_b); a.call(0xBB3030_b);
a.mov(ptr(rdi, 0x32C), eax); a.mov(ptr(rdi, 0x32C), eax);
// get bg_gravity as int
a.pushad64();
a.push(rdi);
a.call_aligned(get_gravity);
a.pop(rdi);
a.mov(dword_ptr(rdi, 0x78), eax);
a.popad64();
a.jmp(0xAFA342_b); a.jmp(0xAFA342_b);
}); });
} }
void* g_speed_stub()
{
return utils::hook::assemble([](utils::hook::assembler& a)
{
// original code
a.add(eax, ptr(rdi, 0x1FD0));
a.push(rax);
a.push(eax);
a.mov(rax, qword_ptr(reinterpret_cast<int64_t>(&*reinterpret_cast<game::dvar_t**>(0x3C98330_b))));
a.mov(eax, dword_ptr(rax, 0x10));
a.mov(dword_ptr(rdi, 0x7C), eax);
a.pop(rax);
a.pop(eax);
a.jmp(0xAFB1EC_b);
});
}
} }
class component final : public component_interface class component final : public component_interface
@ -72,17 +106,23 @@ namespace gameplay
public: public:
void post_unpack() override void post_unpack() override
{ {
// Implement bounces // Implement ejection dvar
dvars::bg_playerEjection = game::Dvar_RegisterBool("bg_playerEjection", true, game::DVAR_FLAG_REPLICATED, "Flag whether player ejection is on or off");
stuck_in_client_hook.create(0xAFD9B0_b, stuck_in_client_stub);
// Implement bounces dvar
dvars::bg_bounces = game::Dvar_RegisterBool("bg_bounces", false, game::DVAR_FLAG_REPLICATED, "Enables bounces"); dvars::bg_bounces = game::Dvar_RegisterBool("bg_bounces", false, game::DVAR_FLAG_REPLICATED, "Enables bounces");
utils::hook::jump(0x70FBB7_b, bg_bounces_stub(), true); utils::hook::jump(0x70FBB7_b, bg_bounces_stub(), true);
// Implement gravity dvar // Modify gravity dvar
dvars::g_gravity = game::Dvar_RegisterInt("g_gravity", 800, 0, 1000, game::DVAR_FLAG_REPLICATED, "Game gravity in inches per second squared"); dvars::override::register_float("bg_gravity", 800, 0, 1000, 0xC0 | game::DVAR_FLAG_REPLICATED);
utils::hook::nop(0xAFA330_b, 13); utils::hook::nop(0xAFA330_b, 18);
utils::hook::jump(0xAFA330_b, g_gravity_stub(), true); utils::hook::jump(0xAFA330_b, bg_gravity_stub(), true);
dvars::g_playerEjection = game::Dvar_RegisterBool("g_playerEjection", true, game::DVAR_FLAG_REPLICATED, "Flag whether player ejection is on or off"); // Modify speed dvar
stuck_in_client_hook.create(0xAFD9B0_b, stuck_in_client_stub); dvars::override::register_int("g_speed", 190, 0x80000000, 0x7FFFFFFF, 0xC0 | game::DVAR_FLAG_REPLICATED);
utils::hook::nop(0xAFB1DF_b, 13);
utils::hook::jump(0xAFB1DF_b, g_speed_stub(), true);
} }
}; };
} }

View File

@ -0,0 +1,181 @@
#include <std_include.hpp>
#include "loader/component_loader.hpp"
#include "command.hpp"
#include "scheduler.hpp"
#include <utils/hook.hpp>
#include <utils/string.hpp>
#include "game/game.hpp"
#include <game/dvars.hpp>
namespace map_rotation
{
namespace
{
DWORD previous_priority{};
void set_dvar(const std::string& dvar, const std::string& value)
{
command::execute(utils::string::va("%s \"%s\"", dvar.data(), value.data()), true);
}
void set_gametype(const std::string& gametype)
{
set_dvar("g_gametype", gametype);
}
void launch_map(const std::string& mapname)
{
command::execute(utils::string::va("map %s", mapname.data()), false);
}
void launch_default_map()
{
auto* mapname = game::Dvar_FindVar("mapname");
if (mapname && mapname->current.string && strlen(mapname->current.string) &&
mapname->current.string != "mp_frontend"s &&
mapname->current.string != "cp_frontend"s)
{
launch_map(mapname->current.string);
}
else
{
launch_map(game::Com_GameMode_GetActiveGameMode() == game::GAME_MODE_CP ? "cp_zmb" : "mp_frontier");
}
}
std::string load_current_map_rotation()
{
auto* rotation = game::Dvar_FindVar("sv_mapRotationCurrent");
if (!strlen(rotation->current.string))
{
rotation = game::Dvar_FindVar("sv_mapRotation");
set_dvar("sv_mapRotationCurrent", rotation->current.string);
}
return rotation->current.string;
}
std::vector<std::string> parse_current_map_rotation()
{
const auto rotation = load_current_map_rotation();
return utils::string::split(rotation, ' ');
}
void store_new_rotation(const std::vector<std::string>& elements, const size_t index)
{
std::string value{};
for (auto i = index; i < elements.size(); ++i)
{
if (i != index)
{
value.push_back(' ');
}
value.append(elements[i]);
}
set_dvar("sv_mapRotationCurrent", value);
}
void change_process_priority()
{
auto* const dvar = game::Dvar_FindVar("sv_autoPriority");
if (dvar && dvar->current.enabled)
{
scheduler::on_game_initialized([]()
{
//printf("=======================setting OLD priority=======================\n");
SetPriorityClass(GetCurrentProcess(), previous_priority);
}, scheduler::pipeline::main, 1s);
previous_priority = GetPriorityClass(GetCurrentProcess());
//printf("=======================setting NEW priority=======================\n");
SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
}
}
void perform_map_rotation()
{
if (game::Live_SyncOnlineDataFlags(0) != 0)
{
scheduler::on_game_initialized(perform_map_rotation, scheduler::pipeline::main, 1s);
return;
}
const auto rotation = parse_current_map_rotation();
for (size_t i = 0; !rotation.empty() && i < (rotation.size() - 1); i += 2)
{
const auto& key = rotation[i];
const auto& value = rotation[i + 1];
if (key == "gametype")
{
set_gametype(value);
}
else if (key == "map")
{
store_new_rotation(rotation, i + 2);
change_process_priority();
if (!game::SV_MapExists(value.data()))
{
printf("map_rotation: '%s' map doesn't exist!\n", value.data());
launch_default_map();
return;
}
launch_map(value);
return;
}
else
{
printf("Invalid map rotation key: %s\n", key.data());
}
}
launch_default_map();
}
void trigger_map_rotation()
{
scheduler::schedule([]()
{
if (game::CL_IsGameClientActive(0))
{
return scheduler::cond_continue;
}
command::execute("map_rotate", false);
return scheduler::cond_end;
}, scheduler::pipeline::main, 1s);
}
}
class component final : public component_interface
{
public:
void post_unpack() override
{
if (!game::environment::is_dedi())
{
return;
}
scheduler::once([]()
{
game::Dvar_RegisterString("sv_mapRotation", "", game::DVAR_FLAG_NONE, "");
game::Dvar_RegisterString("sv_mapRotationCurrent", "", game::DVAR_FLAG_NONE, "");
game::Dvar_RegisterString("sv_autoPriority", "", game::DVAR_FLAG_NONE, "Lowers the process priority during map changes to not cause lags on other servers.");
}, scheduler::pipeline::main);
command::add("map_rotate", &perform_map_rotation);
// Hook GScr_ExitLevel
utils::hook::jump(0xB52E50_b, &trigger_map_rotation, true);
previous_priority = GetPriorityClass(GetCurrentProcess());
}
};
}
REGISTER_COMPONENT(map_rotation::component)

View File

@ -26,7 +26,6 @@ namespace network
bool handle_command(game::netadr_s* address, const char* command, game::msg_t* message) bool handle_command(game::netadr_s* address, const char* command, game::msg_t* message)
{ {
printf("hamdle_cmd: %s\n", command);
const auto cmd_string = utils::string::to_lower(command); const auto cmd_string = utils::string::to_lower(command);
auto& callbacks = get_callbacks(); auto& callbacks = get_callbacks();
const auto handler = callbacks.find(cmd_string); const auto handler = callbacks.find(cmd_string);
@ -51,7 +50,6 @@ namespace network
utils::hook::detour cl_dispatch_connectionless_packet_hook; utils::hook::detour cl_dispatch_connectionless_packet_hook;
bool cl_dispatch_connectionless_packet_stub(int client_num, game::netadr_s* from, game::msg_t* msg, int time) bool cl_dispatch_connectionless_packet_stub(int client_num, game::netadr_s* from, game::msg_t* msg, int time)
{ {
printf("connectionless packet: type: %d, adr: %s\n", from->type, net_adr_to_string(*from));
if (handle_command(from, game::Cmd_Argv(0), msg)) if (handle_command(from, game::Cmd_Argv(0), msg))
{ {
return true; return true;
@ -62,16 +60,8 @@ namespace network
int dw_send_to_stub(const int length, const char* data, game::netadr_s* to) int dw_send_to_stub(const int length, const char* data, game::netadr_s* to)
{ {
if (!*game::query_socket || *game::query_socket == INVALID_SOCKET)
{
printf("query socket is not initialized\n");
}
sockaddr s = {}; sockaddr s = {};
game::NetadrToSockadr(to, &s); game::NetadrToSockadr(to, &s);
if (to->type == game::NA_IP)
{
//printf("sendto: size: %i\n", length);
}
return sendto(*game::query_socket, data, length, 0, &s, sizeof(sockaddr)); return sendto(*game::query_socket, data, length, 0, &s, sizeof(sockaddr));
} }
@ -97,10 +87,6 @@ namespace network
return -2; return -2;
} }
sockadr_to_netadr(&s, from); sockadr_to_netadr(&s, from);
if (from->type == game::NA_IP)
{
//printf("recv: size: %i\n", ret);
}
datalen = ret; datalen = ret;
if (!datalen) if (!datalen)
{ {
@ -165,27 +151,23 @@ namespace network
if (sock == INVALID_SOCKET) if (sock == INVALID_SOCKET)
{ {
console::warn("WARNING: UDP_OpenSocket: socket\n");
return 0; return 0;
} }
u_long arg = 1; u_long arg = 1;
if (ioctlsocket(sock, FIONBIO, &arg) == SOCKET_ERROR) if (ioctlsocket(sock, FIONBIO, &arg) == SOCKET_ERROR)
{ {
console::warn("WARNING: UDP_OpenSocket: ioctl FIONBIO\n");
return 0; return 0;
} }
char optval[4] = { 1, 0, 0, 0 }; char optval[4] = { 1, 0, 0, 0 };
if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, optval, sizeof(optval)) == SOCKET_ERROR) if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, optval, sizeof(optval)) == SOCKET_ERROR)
{ {
console::warn("WARNING: UDP_OpenSocket: setsockopt SO_BROADCAST\n");
return 0; return 0;
} }
if (bind(sock, reinterpret_cast<sockaddr*>(&address), sizeof(address)) == SOCKET_ERROR) if (bind(sock, reinterpret_cast<sockaddr*>(&address), sizeof(address)) == SOCKET_ERROR)
{ {
console::warn("WARNING: UDP_OpenSocket: bind\n");
closesocket(sock); closesocket(sock);
return 0; return 0;
} }
@ -215,7 +197,6 @@ namespace network
return; return;
} }
printf("net_port: %d\n", port_diff);
game::Dvar_SetInt(net_port, net_port->current.integer + port_diff); game::Dvar_SetInt(net_port, net_port->current.integer + port_diff);
} }
@ -230,11 +211,6 @@ namespace network
return PROTOCOL; return PROTOCOL;
} }
int dw_get_addr_handle_connection_task_status_stub()
{
return 1; // TASK_COMPLETE
}
void reconnect_migratated_client(void*, game::netadr_s* from, const int, const int, const char*, void reconnect_migratated_client(void*, game::netadr_s* from, const int, const int, const char*,
const char*, bool) const char*, bool)
{ {
@ -271,7 +247,6 @@ namespace network
} }
else else
{ {
printf("send_data: type: %d, data: %s, size: %i\n", address.type, data.data(), size);
game::Sys_SendPacket(size, data.data(), &address); game::Sys_SendPacket(size, data.data(), &address);
} }
} }
@ -341,13 +316,6 @@ namespace network
utils::hook::jump(0xC4F200_b, 0xC4F1AB_b); utils::hook::jump(0xC4F200_b, 0xC4F1AB_b);
utils::hook::jump(0xC4F2F6_b, 0xC4F399_b); utils::hook::jump(0xC4F2F6_b, 0xC4F399_b);
// disable xuid verification
//utils::hook::set<uint8_t>(0x_b, 0xEB);
// disable xuid verification
//utils::hook::nop(0x_b, 2);
//utils::hook::set<uint8_t>(0x_b, 0xEB);
// ignore configstring mismatch // ignore configstring mismatch
utils::hook::set<uint8_t>(0x9B6F91_b, 0xEB); utils::hook::set<uint8_t>(0x9B6F91_b, 0xEB);
@ -378,54 +346,19 @@ namespace network
utils::hook::set<int>(0xBB4E22_b, max_packet_size); utils::hook::set<int>(0xBB4E22_b, max_packet_size);
utils::hook::set<int>(0xBB4F31_b, max_packet_size); utils::hook::set<int>(0xBB4F31_b, max_packet_size);
// increase cl_maxpackets
dvars::override::register_int("cl_maxpackets", 1000, 1, 1000, game::DVAR_FLAG_SAVED);
// increase snaps
//dvars::override::register_int("sv_remote_client_snapshot_msec", 33, 33, 100, game::DVAR_FLAG_NONE);
dvars::override::register_float("cl_timeout", 3600.0f, 0.0f, 3600.0f, game::DVAR_FLAG_NONE);
dvars::override::register_float("cl_connectTimeout", 3600.0f, 0.0f, 3600.0f, game::DVAR_FLAG_NONE);
dvars::override::register_int("sv_timeout", 1800, 0, 1800, game::DVAR_FLAG_NONE); // no work
dvars::override::register_int("sv_connectTimeout", 1800, 0, 1800, game::DVAR_FLAG_NONE); // ^
//dvars::override::register_int("sv_zombietime", 1800, 0, 1800, game::DVAR_FLAG_NONE); // ^
dvars::override::register_int("pt_connectTimeout", 60000, 0, 60000, game::DVAR_FLAG_READ);
dvars::override::register_int("ds_serverConnectTimeout", 60000, 0, -1, game::DVAR_FLAG_READ);
dvars::override::register_int("dw_addrHandleTimeout", -1, 0, -1, game::DVAR_FLAG_READ);
// ignore built in "print" oob command and add in our own // ignore built in "print" oob command and add in our own
//utils::hook::set<uint8_t>(0x9B0326_b, 0xEB); utils::hook::set<uint8_t>(0x9B0326_b, 0xEB);
//network::on("print", [](const game::netadr_s&, const std::string_view& data) network::on("print", [](const game::netadr_s&, const std::string_view& data)
//{ {
// const std::string message{ data }; const std::string message{ data };
// console::info(message.data()); console::info(message.data());
//}); });
// initialize query_socket // initialize query_socket
utils::hook::jump(0xD57C7E_b, net_init_stub); utils::hook::jump(0xD57C7E_b, net_init_stub);
// use our own protocol version // use our own protocol version
utils::hook::jump(0xCE8290_b, get_protocol_version_stub); utils::hook::jump(0xCE8290_b, get_protocol_version_stub);
//utils::hook::set<uint8_t>(0x4030F0_b, 0xC3);
//utils::hook::nop(0x9B014B_b, 2);
// don't establish secure conenction pt2
/*utils::hook::nop(0xC572A2_b, 2);
utils::hook::nop(0xC72980_b, 2);
utils::hook::nop(0xC73512_b, 2);
utils::hook::nop(0xC739C9_b, 2);
utils::hook::set<uint8_t>(0xCFD928_b, 0xEB);*/
//utils::hook::jump(0xD93390_b, dw_get_addr_handle_connection_task_status_stub);
#ifdef DEBUG
//dvars::override::register_bool("frontEndSceneEnabled", false, game::DVAR_FLAG_READ);
#endif
} }
}; };
} }

View File

@ -31,13 +31,10 @@ namespace party
void perform_game_initialization() void perform_game_initialization()
{ {
command::execute("onlinegame 1", true); command::execute("onlinegame 1", true);
//command::execute("exec default_xboxlive.cfg", true);
command::execute("xblive_privatematch 1", true); command::execute("xblive_privatematch 1", true);
//command::execute("xstopparty 0", true); //command::execute("xstartprivateparty", true);
//command::execute("xstartprivateparty 0", true); command::execute("xstartprivatematch", true);
command::execute("xstartprivatematch 0", true);
command::execute("uploadstats", true); command::execute("uploadstats", true);
//command::execute("entitlements_delay 0", true);
} }
void connect_to_party(const game::netadr_s& target, const std::string& mapname, const std::string& gametype, int sv_maxclients) void connect_to_party(const game::netadr_s& target, const std::string& mapname, const std::string& gametype, int sv_maxclients)
@ -50,26 +47,11 @@ namespace party
if (game::Live_SyncOnlineDataFlags(0) != 0) if (game::Live_SyncOnlineDataFlags(0) != 0)
{ {
// initialize the game after onlinedataflags is 32 (workaround) scheduler::once([=]()
if (game::Live_SyncOnlineDataFlags(0) == 32)
{ {
scheduler::once([=]() connect_to_party(target, mapname, gametype, sv_maxclients);
{ }, scheduler::pipeline::main, 1s);
command::execute("xstartprivateparty", true); return;
command::execute("disconnect", true); // 32 -> 0
connect_to_party(target, mapname, gametype, sv_maxclients);
}, scheduler::pipeline::main, 1s);
return;
}
else
{
scheduler::once([=]()
{
connect_to_party(target, mapname, gametype, sv_maxclients);
}, scheduler::pipeline::main, 1s);
return;
}
} }
const auto ui_maxclients = game::Dvar_FindVar("ui_maxclients"); const auto ui_maxclients = game::Dvar_FindVar("ui_maxclients");
@ -85,6 +67,28 @@ namespace party
game::CL_MainMP_ConnectAndPreloadMap(0, reinterpret_cast<void*>(session_info), &target, mapname.data(), gametype.data()); game::CL_MainMP_ConnectAndPreloadMap(0, reinterpret_cast<void*>(session_info), &target, mapname.data(), gametype.data());
} }
void start_map_for_party()
{
auto* mapname = game::Dvar_FindVar("ui_mapname");
auto* gametype = game::Dvar_FindVar("ui_gametype");
auto* clients = game::Dvar_FindVar("ui_maxclients");
auto* private_clients = game::Dvar_FindVar("ui_privateClients");
auto* hardcore = game::Dvar_FindVar("ui_hardcore");
//utils::hook::invoke<void>(0x9D8900_b, game::Party_GetActiveParty(), true);
utils::hook::invoke<void>(0xE4DDC0_b); // Sys_WaitWorkerCmds
utils::hook::invoke<void>(0xBAFFD0_b, ""); // Com_ShutdownInternal
game::SV_CmdsMP_StartMapForParty(
mapname->current.string,
gametype->current.string,
clients->current.integer,
private_clients->current.integer,
hardcore->current.enabled,
false,
false);
}
std::string get_dvar_string(const std::string& dvar) std::string get_dvar_string(const std::string& dvar)
{ {
auto* dvar_value = game::Dvar_FindVar(dvar.data()); auto* dvar_value = game::Dvar_FindVar(dvar.data());
@ -119,53 +123,40 @@ namespace party
} }
} }
void start_map_for_party() void start_map(const std::string& mapname, bool dev)
{
auto* mapname = game::Dvar_FindVar("ui_mapname");
auto* gametype = game::Dvar_FindVar("ui_gametype");
auto* clients = game::Dvar_FindVar("ui_maxclients");
auto* private_clients = game::Dvar_FindVar("ui_privateClients");
auto* hardcore = game::Dvar_FindVar("ui_hardcore");
//utils::hook::invoke<void>(0x9D8900_b, game::Party_GetActiveParty(), true);
utils::hook::invoke<void>(0xE4DDC0_b); // Sys_WaitWorkerCmds
utils::hook::invoke<void>(0xBAFFD0_b, ""); // Com_ShutdownInternal
game::SV_CmdsMP_StartMapForParty(
mapname->current.string,
gametype->current.string,
clients->current.integer,
private_clients->current.integer,
hardcore->current.enabled,
false,
false);
}
bool start_map(const std::string& mapname, bool dev)
{ {
if (game::Com_GameMode_GetActiveGameMode() == game::GAME_MODE_SP) if (game::Com_GameMode_GetActiveGameMode() == game::GAME_MODE_SP)
{ {
console::info("Starting sp map: %s\n", mapname.data()); console::info("Starting sp map: %s\n", mapname.data());
command::execute(utils::string::va("spmap %s", mapname.data()), false); command::execute(utils::string::va("spmap %s", mapname.data()), false);
return true; return;
}
if (game::Live_SyncOnlineDataFlags(0) != 0)
{
scheduler::once([=]()
{
start_map(mapname, dev);
}, scheduler::pipeline::main, 1s);
return;
} }
if (mapname.empty()) if (mapname.empty())
{ {
console::error("No map specified.\n"); console::error("No map specified.\n");
return false; return;
} }
if (!game::SV_MapExists(mapname.data())) if (!game::SV_MapExists(mapname.data()))
{ {
console::error("Map \"%s\" doesn't exist.\n", mapname.data()); console::error("Map \"%s\" doesn't exist.\n", mapname.data());
return false; return;
} }
if (!game::Com_GameMode_SupportsMap(mapname.data())) if (!game::Com_GameMode_SupportsMap(mapname.data()))
{ {
console::error("Cannot load map \"%s\" in current game mode.\n", mapname.data()); console::error("Cannot load map \"%s\" in current game mode.\n", mapname.data());
return false; return;
} }
auto* current_mapname = game::Dvar_FindVar("mapname"); auto* current_mapname = game::Dvar_FindVar("mapname");
@ -177,17 +168,22 @@ namespace party
{ {
console::info("Restarting map: %s\n", mapname.data()); console::info("Restarting map: %s\n", mapname.data());
command::execute("map_restart", false); command::execute("map_restart", false);
return true; return;
} }
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); command::execute(utils::string::va("ui_mapname %s", mapname.data()), true);
console::info("Starting map: %s\n", mapname.data());
perform_game_initialization(); perform_game_initialization();
game::Cbuf_AddCall(0, start_map_for_party); console::info("Starting map: %s\n", mapname.data());
return true;
start_map_for_party();
return;
} }
int get_client_num_by_name(const std::string& name) int get_client_num_by_name(const std::string& name)
@ -209,8 +205,6 @@ namespace party
{ {
//command::execute("lui_open_popup popup_acceptinginvite", false); //command::execute("lui_open_popup popup_acceptinginvite", false);
printf("connect called...\n");
connect_state.host = target; connect_state.host = target;
connect_state.challenge = utils::cryptography::random::get_challenge(); connect_state.challenge = utils::cryptography::random::get_challenge();
connect_state.hostDefined = true; connect_state.hostDefined = true;
@ -227,7 +221,6 @@ namespace party
//} //}
game::Com_SetLocalizedErrorMessage(error.data(), "MENU_NOTICE"); game::Com_SetLocalizedErrorMessage(error.data(), "MENU_NOTICE");
//*reinterpret_cast<int*>(0x0) = 1;
} }
@ -236,16 +229,6 @@ namespace party
public: public:
void post_unpack() override void post_unpack() override
{ {
command::add("live", []()
{
console::info("%d\n", game::Live_SyncOnlineDataFlags(0));
});
command::add("connstate", []()
{
console::info("%d\n", game::clientUIActives[0].connectionState);
});
static const char* a1 = "map_sp"; static const char* a1 = "map_sp";
static const char* a2 = "map_restart_sp"; static const char* a2 = "map_restart_sp";
static const char* a3 = "fast_restart_sp"; static const char* a3 = "fast_restart_sp";
@ -265,6 +248,7 @@ namespace party
utils::hook::set(0x1BBA700_b + 24, a3); utils::hook::set(0x1BBA700_b + 24, a3);
utils::hook::set(0x1BBA700_b + 56, a3); utils::hook::set(0x1BBA700_b + 56, a3);
// need to fix this, currently it will disconnect everyone from the server when a new map is rotated
command::add("map", [](const command::params& args) command::add("map", [](const command::params& args)
{ {
if (args.size() != 2) if (args.size() != 2)
@ -297,6 +281,7 @@ namespace party
start_map(args.get(1), true); start_map(args.get(1), true);
}); });
// need to fix this, currently game will freeze in loadingnewmap command
command::add("map_restart", []() command::add("map_restart", []()
{ {
if (!game::SV_Loaded() || game::Com_FrontEnd_IsInFrontEnd()) if (!game::SV_Loaded() || game::Com_FrontEnd_IsInFrontEnd())
@ -351,8 +336,6 @@ namespace party
network::on("getInfo", [](const game::netadr_s& target, const std::string_view& data) network::on("getInfo", [](const game::netadr_s& target, const std::string_view& data)
{ {
printf("getInfo called...\n");
utils::info_string info{}; utils::info_string info{};
info.set("challenge", std::string{ data }); info.set("challenge", std::string{ data });
info.set("gamename", "IW7"); info.set("gamename", "IW7");
@ -375,8 +358,6 @@ namespace party
network::on("infoResponse", [](const game::netadr_s& target, const std::string_view& data) network::on("infoResponse", [](const game::netadr_s& target, const std::string_view& data)
{ {
printf("infoResponse called...\n");
const utils::info_string info{ data }; const utils::info_string info{ data };
//server_list::handle_info_response(target, info); //server_list::handle_info_response(target, info);

View File

@ -8,7 +8,7 @@ namespace party
void reset_connect_state(); void reset_connect_state();
void connect(const game::netadr_s& target); void connect(const game::netadr_s& target);
bool start_map(const std::string& mapname, bool dev = false); void start_map(const std::string& mapname, bool dev = false);
void clear_sv_motd(); void clear_sv_motd();
game::netadr_s get_state_host(); game::netadr_s get_state_host();

View File

@ -63,7 +63,11 @@ namespace patches
bool com_game_mode_supports_feature_stub(game::Com_GameMode_Feature feature) bool com_game_mode_supports_feature_stub(game::Com_GameMode_Feature feature)
{ {
if (feature == game::FEATURE_TIMESCALE) if (feature == game::FEATURE_GRAVITY)
{
return true;
}
else if (feature == game::FEATURE_TIMESCALE)
{ {
return true; return true;
} }

View File

@ -26,9 +26,10 @@ namespace dvars
game::dvar_t* r_fullbright = nullptr; game::dvar_t* r_fullbright = nullptr;
game::dvar_t* bg_bounces = nullptr; game::dvar_t* bg_bounces = nullptr;
game::dvar_t* g_gravity = nullptr; game::dvar_t* bg_gravity = nullptr;
game::dvar_t* bg_playerEjection = nullptr;
game::dvar_t* g_playerEjection = nullptr; game::dvar_t* g_speed = nullptr;
std::string dvar_get_vector_domain(const int components, const game::DvarLimits& domain) std::string dvar_get_vector_domain(const int components, const game::DvarLimits& domain)
{ {
@ -138,7 +139,7 @@ namespace dvars
} }
} }
std::unordered_map<const game::dvar_t*, const char*> dvar_names; std::unordered_map<const game::dvar_t*, std::string> dvar_names;
std::string dvar_get_name(const game::dvar_t* dvar) std::string dvar_get_name(const game::dvar_t* dvar)
{ {
@ -151,12 +152,12 @@ namespace dvars
return ""; return "";
} }
void dvar_set_name(const game::dvar_t* dvar, const char* name) void dvar_set_name(const game::dvar_t* dvar, const std::string& name)
{ {
dvar_names[dvar] = name; dvar_names[dvar] = name;
} }
std::unordered_map<const game::dvar_t*, const char*> dvar_descriptions; std::unordered_map<const game::dvar_t*, std::string> dvar_descriptions;
std::string dvar_get_description(const game::dvar_t* dvar) std::string dvar_get_description(const game::dvar_t* dvar)
{ {
@ -169,7 +170,7 @@ namespace dvars
return ""; return "";
} }
void dvar_set_description(const game::dvar_t* dvar, const char* description) void dvar_set_description(const game::dvar_t* dvar, const std::string& description)
{ {
dvar_descriptions[dvar] = description; dvar_descriptions[dvar] = description;
} }

View File

@ -22,14 +22,12 @@ namespace dvars
extern game::dvar_t* r_fullbright; extern game::dvar_t* r_fullbright;
extern game::dvar_t* bg_bounces; extern game::dvar_t* bg_bounces;
extern game::dvar_t* g_gravity; extern game::dvar_t* bg_playerEjection;
extern game::dvar_t* g_playerEjection;
std::string dvar_get_vector_domain(const int components, const game::DvarLimits& domain); std::string dvar_get_vector_domain(const int components, const game::DvarLimits& domain);
std::string dvar_get_domain(const game::DvarType type, const game::DvarLimits& domain); std::string dvar_get_domain(const game::DvarType type, const game::DvarLimits& domain);
std::string dvar_get_name(const game::dvar_t* dvar); std::string dvar_get_name(const game::dvar_t* dvar);
std::string dvar_get_description(const game::dvar_t* dvar); std::string dvar_get_description(const game::dvar_t* dvar);
void dvar_set_name(const game::dvar_t* dvar, const char* name); void dvar_set_name(const game::dvar_t* dvar, const std::string& name);
void dvar_set_description(const game::dvar_t* dvar, const char* description); void dvar_set_description(const game::dvar_t* dvar, const std::string& description);
} }

View File

@ -24,6 +24,7 @@ namespace game
enum Com_GameMode_Feature : std::int32_t enum Com_GameMode_Feature : std::int32_t
{ {
FEATURE_GRAVITY = 33,
FEATURE_TIMESCALE = 69, FEATURE_TIMESCALE = 69,
}; };

View File

@ -8,6 +8,8 @@ namespace game
* Functions * Functions
**************************************************************/ **************************************************************/
WEAK symbol<float()> BG_GetGravity{ 0x68DD0 };
WEAK symbol<void(errorParm code, const char* message, ...)> Com_Error{ 0xB8D830 }; WEAK symbol<void(errorParm code, const char* message, ...)> Com_Error{ 0xB8D830 };
WEAK symbol<void()> Com_Quit_f{ 0xBADC90 }; WEAK symbol<void()> Com_Quit_f{ 0xBADC90 };
@ -33,6 +35,8 @@ namespace game
WEAK symbol<void(int localClientNum, const char* text)> Cbuf_AddText{ 0xB7C290 }; WEAK symbol<void(int localClientNum, const char* text)> Cbuf_AddText{ 0xB7C290 };
WEAK symbol<void(int localClientNum, void(*))> Cbuf_AddCall{ 0xB7C220 }; WEAK symbol<void(int localClientNum, void(*))> Cbuf_AddCall{ 0xB7C220 };
WEAK symbol<void(int localClientNum, int controllerIndex, const char* buffer)> Cbuf_ExecuteBuffer{ 0xB7C3B0 };
WEAK symbol<void(int localClientNum, int controllerIndex, const char* buffer, void(int, int, const char*))> Cbuf_ExecuteBufferInternal{ 0xB7C3C0 };
WEAK symbol<void(int localClientNum, const char* msg, int flags)> CG_Utils_GameMessage{ 0x1D7FC0 }; WEAK symbol<void(int localClientNum, const char* msg, int flags)> CG_Utils_GameMessage{ 0x1D7FC0 };
WEAK symbol<void(int localClientNum, const char* msg, int flags)> CG_Utils_BoldGameMessage{ 0x1D7F10 }; WEAK symbol<void(int localClientNum, const char* msg, int flags)> CG_Utils_BoldGameMessage{ 0x1D7F10 };
@ -132,6 +136,9 @@ namespace game
WEAK symbol<int(int length, void const* data, const netadr_s* to)> Sys_SendPacket{ 0xD57DE0 }; WEAK symbol<int(int length, void const* data, const netadr_s* to)> Sys_SendPacket{ 0xD57DE0 };
WEAK symbol<int(netadr_s* net_from, msg_t* net_message)> Sys_GetPacket{ 0xD57D50 }; WEAK symbol<int(netadr_s* net_from, msg_t* net_message)> Sys_GetPacket{ 0xD57D50 };
WEAK symbol<void(int)> Scr_AddInt{ 0xC0A580 };
WEAK symbol<int()> Scr_GetInt{ 0xC0B950 };
WEAK symbol<ScreenPlacement* ()> ScrPlace_GetViewPlacement{ 0x9E4090 }; WEAK symbol<ScreenPlacement* ()> ScrPlace_GetViewPlacement{ 0x9E4090 };
WEAK symbol<void(const char* string)> SV_Cmd_TokenizeString{ 0xB7DD00 }; WEAK symbol<void(const char* string)> SV_Cmd_TokenizeString{ 0xB7DD00 };

View File

@ -103,7 +103,7 @@
using namespace std::literals; using namespace std::literals;
#ifdef DEBUG #ifdef DEBUG
#define DW_DEBUG //#define DW_DEBUG
#endif #endif
#define __FILENAME__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__) #define __FILENAME__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)

View File

@ -65,6 +65,11 @@ namespace utils::string
return std::equal(substring.rbegin(), substring.rend(), text.rbegin()); return std::equal(substring.rbegin(), substring.rend(), text.rbegin());
} }
bool is_numeric(const std::string& text)
{
return std::to_string(atoi(text.data())) == text;
}
std::string dump_hex(const std::string& data, const std::string& separator) std::string dump_hex(const std::string& data, const std::string& separator)
{ {
std::string result; std::string result;

View File

@ -86,6 +86,7 @@ namespace utils::string
std::string to_upper(std::string text); std::string to_upper(std::string text);
bool starts_with(const std::string& text, const std::string& substring); bool starts_with(const std::string& text, const std::string& substring);
bool ends_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);
std::string dump_hex(const std::string& data, const std::string& separator = " "); std::string dump_hex(const std::string& data, const std::string& separator = " ");