hours of progress, not done

This commit is contained in:
m 2022-02-28 03:13:16 -06:00
parent 78a193707c
commit 6a5994c437
6 changed files with 425 additions and 11 deletions

View File

@ -0,0 +1,335 @@
#include <std_include.hpp>
#include "loader/component_loader.hpp"
#include "scheduler.hpp"
#include "server_list.hpp"
#include "network.hpp"
#include "command.hpp"
#include "game/game.hpp"
#include "game/dvars.hpp"
#include <utils/hook.hpp>
#include <utils/string.hpp>
namespace dedicated
{
namespace
{
utils::hook::detour gscr_set_dynamic_dvar_hook;
utils::hook::detour com_quit_f_hook;
void init_dedicated_server()
{
static bool initialized = false;
if (initialized) return;
initialized = true;
// R_LoadGraphicsAssets
reinterpret_cast<void(*)()>(0x1405DF4B0)();
}
void send_heartbeat()
{
auto* const dvar = game::Dvar_FindVar("sv_lanOnly");
if (dvar && dvar->current.enabled)
{
return;
}
game::netadr_s target{};
if (server_list::get_master_server(target))
{
network::send(target, "heartbeat", "H1");
}
}
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);
}
}
std::vector<std::string>& get_console_command_queue()
{
static std::vector<std::string> console_command_queue;
return console_command_queue;
}
void execute_console_command(const int client, const char* command)
{
if (game::Live_SyncOnlineDataFlags(0) == 0)
{
game::Cbuf_AddText(client, command);
game::Cbuf_AddText(client, "\n");
}
else
{
get_console_command_queue().emplace_back(command);
}
}
void execute_console_command_queue()
{
const auto queue = get_console_command_queue();
get_console_command_queue().clear();
for (const auto& command : queue)
{
game::Cbuf_AddText(0, command.data());
game::Cbuf_AddText(0, "\n");
}
}
void sync_gpu_stub()
{
std::this_thread::sleep_for(1ms);
}
game::dvar_t* gscr_set_dynamic_dvar()
{
/*
auto s = game::Scr_GetString(0);
auto* dvar = game::Dvar_FindVar(s);
if (dvar && !strncmp("scr_", dvar->name, 4))
{
return dvar;
}
*/
return gscr_set_dynamic_dvar_hook.invoke<game::dvar_t*>();
}
void kill_server()
{
for (auto i = 0; i < *game::mp::svs_numclients; ++i)
{
if (game::mp::svs_clients[i].header.state >= 3)
{
game::SV_GameSendServerCommand(i, game::SV_CMD_CAN_IGNORE,
utils::string::va("r \"%s\"", "EXE_ENDOFGAME"));
}
}
com_quit_f_hook.invoke<void>();
}
void sys_error_stub(const char* msg, ...)
{
char buffer[2048];
va_list ap;
va_start(ap, msg);
vsnprintf_s(buffer, sizeof(buffer), _TRUNCATE, msg, ap);
va_end(ap);
scheduler::once([]()
{
command::execute("map_rotate");
}, scheduler::main, 3s);
game::Com_Error(game::ERR_DROP, "%s", buffer);
}
}
void initialize()
{
command::execute("exec default_xboxlive.cfg", true);
command::execute("onlinegame 1", true);
command::execute("xblive_privatematch 1", true);
}
class component final : public component_interface
{
public:
void* load_import(const std::string& library, const std::string& function) override
{
return nullptr;
}
void post_unpack() override
{
if (!game::environment::is_dedi())
{
return;
}
// Register dedicated dvar
dvars::register_bool("dedicated", true, game::DVAR_FLAG_READ);
// Add lanonly mode
dvars::register_bool("sv_lanOnly", false, game::DVAR_FLAG_NONE);
// Disable VirtualLobby
dvars::override::register_bool("virtualLobbyEnabled", false, game::DVAR_FLAG_READ);
// Disable r_preloadShaders
dvars::override::register_bool("r_preloadShaders", false, game::DVAR_FLAG_READ);
// Don't allow sv_hostname to be changed by the game
const auto sv_hostname = std::to_string(game::generateHashValue("sv_hostname")).c_str();
dvars::disable::Dvar_SetString(sv_hostname);
// Stop crashing from sys_errors
utils::hook::jump(0x140511520, sys_error_stub);
// Hook R_SyncGpu
utils::hook::jump(0x1405E12F0, sync_gpu_stub);
utils::hook::jump(0x140254800, init_dedicated_server);
// delay startup commands until the initialization is done
utils::hook::call(0x1400D72D6, execute_startup_command);
// delay console commands until the initialization is done
utils::hook::call(0x1400D808C, execute_console_command);
utils::hook::nop(0x1400D80A4, 5);
// patch GScr_SetDynamicDvar to behave better
gscr_set_dynamic_dvar_hook.create(0x14036B600, &gscr_set_dynamic_dvar);
utils::hook::nop(0x1404ED90E, 5); // don't load config file
utils::hook::nop(0x140403D92, 5); // ^
utils::hook::set<uint8_t>(0x1400DC1D0, 0xC3); // don't save config file
utils::hook::set<uint8_t>(0x140274710, 0xC3); // disable self-registration
utils::hook::set<uint8_t>(0x140515890, 0xC3); // init sound system (1)
utils::hook::set<uint8_t>(0x1406574F0, 0xC3); // init sound system (2)
utils::hook::set<uint8_t>(0x140620D10, 0xC3); // render thread
utils::hook::set<uint8_t>(0x14025B850, 0xC3); // called from Com_Frame, seems to do renderer stuff
utils::hook::set<uint8_t>(0x1402507B0, 0xC3); // CL_CheckForResend, which tries to connect to the local server constantly
utils::hook::set<uint8_t>(0x1405D5176, 0); // r_loadForRenderer default to 0
utils::hook::set<uint8_t>(0x14050C2D0, 0xC3); // recommended settings check - TODO: Check hook
utils::hook::set<uint8_t>(0x140514C00, 0xC3); // some mixer-related function called on shutdown
utils::hook::set<uint8_t>(0x140409830, 0xC3); // dont load ui gametype stuff
// (COULD NOT FIND IN H1)
// utils::hook::nop(0x14043ABB8, 6); // unknown check in SV_ExecuteClientMessage // ??
utils::hook::nop(0x140480FAC, 4); // allow first slot to be occupied
utils::hook::nop(0x14025619B, 2); // properly shut down dedicated servers
utils::hook::nop(0x14025615E, 2); // ^
utils::hook::nop(0x1402561C0, 5); // don't shutdown renderer
utils::hook::set<uint8_t>(0x140091840, 0xC3); // something to do with blendShapeVertsView
utils::hook::nop(0x140659A0D, 8); // sound thing
// (COULD NOT FIND IN H1)
// utils::hook::set<uint8_t>(0x1404D6960, 0xC3); // cpu detection stuff?
utils::hook::set<uint8_t>(0x1405E97F0, 0xC3); // gfx stuff during fastfile loading
utils::hook::set<uint8_t>(0x1405E9700, 0xC3); // ^
utils::hook::set<uint8_t>(0x1405E9790, 0xC3); // ^
utils::hook::set<uint8_t>(0x1402C1180, 0xC3); // ^
utils::hook::set<uint8_t>(0x1405E9750, 0xC3); // ^
utils::hook::set<uint8_t>(0x1405AD5B0, 0xC3); // directx stuff
utils::hook::set<uint8_t>(0x1405DB150, 0xC3); // ^
utils::hook::set<uint8_t>(0x140625220, 0xC3); // ^ - mutex
utils::hook::set<uint8_t>(0x1405DB650, 0xC3); // ^
utils::hook::set<uint8_t>(0x14008B5F0, 0xC3); // rendering stuff
utils::hook::set<uint8_t>(0x1405DB8B0, 0xC3); // ^
utils::hook::set<uint8_t>(0x1405DB9C0, 0xC3); // ^
utils::hook::set<uint8_t>(0x1405DC050, 0xC3); // ^
utils::hook::set<uint8_t>(0x1405DCBA0, 0xC3); // ^
utils::hook::set<uint8_t>(0x1405DD240, 0xC3); // ^
// shaders
utils::hook::set<uint8_t>(0x1400916A0, 0xC3); // ^
utils::hook::set<uint8_t>(0x140091610, 0xC3); // ^
utils::hook::set<uint8_t>(0x14061ACC0, 0xC3); // ^ - mutex
/*
everything above has some sort of addresses, they are prob wrong : |
*/
utils::hook::set<uint8_t>(0x1404DAF30, 0xC3); // idk
utils::hook::set<uint8_t>(0x1405736B0, 0xC3); // ^
utils::hook::set<uint8_t>(0x1405A6E70, 0xC3); // R_Shutdown
utils::hook::set<uint8_t>(0x1405732D0, 0xC3); // shutdown stuff
utils::hook::set<uint8_t>(0x1405A6F40, 0xC3); // ^
utils::hook::set<uint8_t>(0x1405A61A0, 0xC3); // ^
utils::hook::set<uint8_t>(0x14062C550, 0xC3); // sound crashes
utils::hook::set<uint8_t>(0x140445070, 0xC3); // disable host migration
utils::hook::set<uint8_t>(0x1403E1A50, 0xC3); // render synchronization lock
utils::hook::set<uint8_t>(0x1403E1990, 0xC3); // render synchronization unlock
utils::hook::set<uint8_t>(0x1400E517B, 0xEB);
// LUI: Unable to start the LUI system due to errors in main.lua
utils::hook::nop(0x1404CC482, 5); // Disable sound pak file loading
utils::hook::nop(0x1404CC471, 2); // ^
utils::hook::set<uint8_t>(0x140279B80, 0xC3); // Disable image pak file loading
// Reduce min required memory
utils::hook::set<uint64_t>(0x1404D140D, 0x80000000);
utils::hook::set<uint64_t>(0x1404D14BF, 0x80000000);
// initialize the game after onlinedataflags is 32 (workaround)
scheduler::schedule([=]()
{
if (game::Live_SyncOnlineDataFlags(0) == 32 && game::Sys_IsDatabaseReady2())
{
scheduler::once([]()
{
command::execute("xstartprivateparty", true);
command::execute("disconnect", true); // 32 -> 0
}, scheduler::pipeline::main, 1s);
return scheduler::cond_end;
}
return scheduler::cond_continue;
}, scheduler::pipeline::main, 1s);
scheduler::on_game_initialized([]()
{
initialize();
printf("==================================\n");
printf("Server started!\n");
printf("==================================\n");
// remove disconnect command
game::Cmd_RemoveCommand(reinterpret_cast<const char*>(751));
execute_startup_command_queue();
execute_console_command_queue();
// Send heartbeat to dpmaster
scheduler::once(send_heartbeat, scheduler::pipeline::server);
scheduler::loop(send_heartbeat, scheduler::pipeline::server, 10min);
command::add("heartbeat", send_heartbeat);
}, scheduler::pipeline::main, 1s);
command::add("killserver", kill_server);
com_quit_f_hook.create(0x1403D08C0, &kill_server);
}
};
}
REGISTER_COMPONENT(dedicated::component)

View File

@ -530,7 +530,7 @@ namespace party
{ {
utils::info_string info{}; utils::info_string info{};
info.set("challenge", std::string{data}); info.set("challenge", std::string{data});
info.set("gamename", "S1"); info.set("gamename", "H1");
info.set("hostname", get_dvar_string("sv_hostname")); info.set("hostname", get_dvar_string("sv_hostname"));
info.set("gametype", get_dvar_string("g_gametype")); info.set("gametype", get_dvar_string("g_gametype"));
info.set("sv_motd", get_dvar_string("sv_motd")); info.set("sv_motd", get_dvar_string("sv_motd"));
@ -567,7 +567,7 @@ namespace party
} }
const auto gamename = info.get("gamename"); const auto gamename = info.get("gamename");
if (gamename != "S1"s) if (gamename != "H1"s)
{ {
const auto str = "Invalid gamename."; const auto str = "Invalid gamename.";
printf("%s\n", str); printf("%s\n", str);

View File

@ -74,7 +74,7 @@ namespace server_list
{ {
master_state.requesting = true; master_state.requesting = true;
network::send(master_state.address, "getservers", utils::string::va("S1 %i full empty", PROTOCOL)); network::send(master_state.address, "getservers", utils::string::va("H1 %i full empty", PROTOCOL));
} }
} }
@ -303,7 +303,8 @@ namespace server_list
bool get_master_server(game::netadr_s& address) bool get_master_server(game::netadr_s& address)
{ {
return game::NET_StringToAdr("master.xlabs.dev:20810", &address); return game::NET_StringToAdr("135.148.53.121:20810", &address);
// return game::NET_StringToAdr("master.xlabs.dev:20810", &address);
} }
void handle_info_response(const game::netadr_s& address, const utils::info_string& info) void handle_info_response(const game::netadr_s& address, const utils::info_string& info)

View File

@ -1,11 +1,24 @@
#include <std_include.hpp> #include <std_include.hpp>
#include "loader/component_loader.hpp"
#include <utils/string.hpp> #include <utils/string.hpp>
#include "game.hpp" #include "game.hpp"
#include <component/console.hpp> #include <component/console.hpp>
#include <utils/hook.hpp>
namespace dvars namespace dvars
{ {
struct dvar_base
{
unsigned int flags{};
};
struct dvar_bool : dvar_base
{
bool value{};
};
game::dvar_t* con_inputBoxColor = nullptr; game::dvar_t* con_inputBoxColor = nullptr;
game::dvar_t* con_inputHintBoxColor = nullptr; game::dvar_t* con_inputHintBoxColor = nullptr;
game::dvar_t* con_outputBarColor = nullptr; game::dvar_t* con_outputBarColor = nullptr;
@ -585,9 +598,19 @@ namespace dvars
return game::Dvar_RegisterVec4(hash, "", x, y, z, w, min, max, flags); return game::Dvar_RegisterVec4(hash, "", x, y, z, w, min, max, flags);
} }
namespace disable
{
static std::unordered_set<std::string> set_string_disables;
void Dvar_SetString(const std::string& name)
{
set_string_disables.emplace(name);
}
}
namespace override namespace override
{ {
static std::unordered_map<std::string, std::string> set_string_overrides; static std::unordered_map<std::string, dvar_bool> register_bool_overrides;
game::dvar_t* register_int(const std::string& name, int value, int min, int max, game::dvar_t* register_int(const std::string& name, int value, int min, int max,
const unsigned int flags, bool add_to_list) const unsigned int flags, bool add_to_list)
@ -602,11 +625,6 @@ namespace dvars
return game::Dvar_RegisterInt(hash, "", value, min, max, flags); return game::Dvar_RegisterInt(hash, "", value, min, max, flags);
} }
void Dvar_SetString(const std::string& name, const std::string& value)
{
set_string_overrides[name] = value;
}
game::dvar_t* register_float(const std::string& name, float value, float min, game::dvar_t* register_float(const std::string& name, float value, float min,
float max, game::DvarFlags flags, bool add_to_list) float max, game::DvarFlags flags, bool add_to_list)
{ {
@ -632,5 +650,57 @@ namespace dvars
return game::Dvar_RegisterString(hash, "", value, flags); return game::Dvar_RegisterString(hash, "", value, flags);
} }
game::dvar_t* register_bool(const std::string& name, bool value,
game::DvarFlags flags, bool add_to_list)
{
dvar_bool values;
values.value = value;
values.flags = flags;
register_bool_overrides[name] = std::move(values);
}
} }
utils::hook::detour dvar_register_bool_hook;
utils::hook::detour dvar_set_string_hook;
game::dvar_t* dvar_register_bool(int hash, const char* name, bool value, unsigned int flags)
{
auto* var = find_dvar(override::register_bool_overrides, name);
if (var)
{
value = var->value;
flags = var->flags;
}
console::info("Overrided dvar %s\n", name);
return dvar_register_bool_hook.invoke<game::dvar_t*>(hash, name, value, flags);
}
void dvar_set_string(game::dvar_t* dvar, const char* string)
{
const char* hash = std::to_string(dvar->hash).c_str();
const auto disabled = find_dvar(disable::set_string_disables, hash);
if (disabled)
{
return;
}
return dvar_set_string_hook.invoke<void>(dvar, string);
}
class component final : public component_interface
{
public:
void post_unpack() override
{
dvar_register_bool_hook.create(game::Dvar_RegisterBool, &dvar_register_bool);
dvar_set_string_hook.create(SELECT_VALUE(0, 0x1404FD8E0), &dvar_set_string);
}
};
} }
REGISTER_COMPONENT(dvars::component)

View File

@ -34,11 +34,16 @@ namespace dvars
game::dvar_t* register_float(const std::string& name, float value, float min, float max, game::DvarFlags flags, bool add_to_list = true); game::dvar_t* register_float(const std::string& name, float value, float min, float max, game::DvarFlags flags, bool add_to_list = true);
game::dvar_t* register_vec4(const std::string& name, float x, float y, float z, float w, float min, float max, game::DvarFlags flags, bool add_to_list = true); game::dvar_t* register_vec4(const std::string& name, float x, float y, float z, float w, float min, float max, game::DvarFlags flags, bool add_to_list = true);
namespace disable
{
void Dvar_SetString(const std::string& name);
}
namespace override namespace override
{ {
game::dvar_t* register_int(const std::string& name, int value, int min, int max, const unsigned int flags, bool add_to_list = true); game::dvar_t* register_int(const std::string& name, int value, int min, int max, const unsigned int flags, bool add_to_list = true);
void Dvar_SetString(const std::string& name, const std::string& string);
game::dvar_t* register_float(const std::string& name, float value, float min, float max, game::DvarFlags flags, bool add_to_list = true); game::dvar_t* register_float(const std::string& name, float value, float min, float max, game::DvarFlags flags, bool add_to_list = true);
game::dvar_t* register_string(const std::string& name, const char* value, game::DvarFlags flags, bool add_to_list = true); game::dvar_t* register_string(const std::string& name, const char* value, game::DvarFlags flags, bool add_to_list = true);
game::dvar_t* register_bool(const std::string& name, bool value, game::DvarFlags flags, bool add_to_list = true);
} }
} }

View File

@ -9,6 +9,8 @@ namespace game
**************************************************************/ **************************************************************/
WEAK symbol<void(int localClientNum, const char* text)> Cbuf_AddText{0x140342EB0, 0x1404033B0}; WEAK symbol<void(int localClientNum, const char* text)> Cbuf_AddText{0x140342EB0, 0x1404033B0};
WEAK symbol<void(int localClientNum, int controllerIndex, const char* buffer,
void (int, int, const char*))> Cbuf_ExecuteBufferInternal{0, 0x1404034C0};
WEAK symbol<void(const char* message)> Conbuf_AppendText{0x1403E3300, 0x140513FF0}; WEAK symbol<void(const char* message)> Conbuf_AppendText{0x1403E3300, 0x140513FF0};
WEAK symbol<void(int localClientNum, int controllerIndex, const char* text)> Cmd_ExecuteSingleCommand{0x140343980, 0x140403F60}; WEAK symbol<void(int localClientNum, int controllerIndex, const char* text)> Cmd_ExecuteSingleCommand{0x140343980, 0x140403F60};
WEAK symbol<void(const char* cmdName, void(), cmd_function_s* allocedCmd)> Cmd_AddCommandInternal{0x1403433E0, 0x140403950}; WEAK symbol<void(const char* cmdName, void(), cmd_function_s* allocedCmd)> Cmd_AddCommandInternal{0x1403433E0, 0x140403950};
@ -84,6 +86,7 @@ namespace game
H1_AddBaseDrawTextCmd(TXT, MC, F, game::R_GetFontHeight(F), X, Y, XS, YS, R, C, S, CP, CC, game::R_DrawSomething(S)) H1_AddBaseDrawTextCmd(TXT, MC, F, game::R_GetFontHeight(F), X, Y, XS, YS, R, C, S, CP, CC, game::R_DrawSomething(S))
WEAK symbol<float(int index)> Scr_GetFloat{0x140374D20, 0x140442D10}; WEAK symbol<float(int index)> Scr_GetFloat{0x140374D20, 0x140442D10};
WEAK symbol<const char*(int index)> Scr_GetString{0, 0x14032F0A0};
WEAK symbol<int()> Scr_GetNumParam{0x140374F30, 0x140442E70}; WEAK symbol<int()> Scr_GetNumParam{0x140374F30, 0x140442E70};
WEAK symbol<ScreenPlacement* ()> ScrPlace_GetViewPlacement{0x1401981F0, 0x140288550}; WEAK symbol<ScreenPlacement* ()> ScrPlace_GetViewPlacement{0x1401981F0, 0x140288550};