NorthstarLauncher/NorthstarDedicatedTest/dedicated.cpp

250 lines
6.6 KiB
C++

#include "pch.h"
#include "dedicated.h"
#include "hookutils.h"
#include "tier0.h"
#include "gameutils.h"
bool IsDedicated()
{
return CommandLine()->CheckParm("-dedicated");
}
// CDedidcatedExports defs
struct CDedicatedExports; // forward declare
typedef void (*DedicatedSys_PrintfType)(CDedicatedExports* dedicated, char* msg);
typedef void (*DedicatedRunServerType)(CDedicatedExports* dedicated);
// would've liked to just do this as a class but have not been able to get it to work
struct CDedicatedExports
{
void* vtable; // because it's easier, we just set this to &this, since CDedicatedExports has no props we care about other than funcs
char unused[56];
DedicatedSys_PrintfType Sys_Printf;
DedicatedRunServerType RunServer;
};
void Sys_Printf(CDedicatedExports* dedicated, char* msg)
{
spdlog::info("[DEDICATED PRINT] {}", msg);
}
typedef bool (*CEngine__FrameType)(void* engineSelf);
typedef void(*CHostState__InitType)(CHostState* self);
void RunServer(CDedicatedExports* dedicated)
{
Sys_Printf(dedicated, (char*)"CDedicatedExports::RunServer(): starting");
// init hoststate, if we don't do this, we get a crash later on
CHostState__InitType CHostState__Init = (CHostState__InitType)((char*)GetModuleHandleA("engine.dll") + 0x16E110);
CHostState__Init(g_pHostState);
// set host state to allow us to enter CHostState::FrameUpdate, with the state HS_NEW_GAME
g_pHostState->m_iNextState = HostState_t::HS_NEW_GAME;
strncpy(g_pHostState->m_levelName, CommandLine()->ParmValue("+map", "mp_lobby"), sizeof(g_pHostState->m_levelName)); // set map to load into
spdlog::info(CommandLine()->GetCmdLine());
while (g_pEngine->m_nQuitting == EngineQuitState::QUIT_NOTQUITTING)
{
g_pEngine->Frame();
spdlog::info("g_pEngine->Frame() on map {} took {}ms", g_pHostState->m_levelName, g_pEngine->GetFrameTime());
Sleep(50);
}
}
void InitialiseDedicated(HMODULE engineAddress)
{
if (!IsDedicated())
return;
spdlog::info("InitialiseDedicated");
{
// Host_Init
// prevent a particle init that relies on client dll
char* ptr = (char*)engineAddress + 0x156799;
TempReadWrite rw(ptr);
*ptr = (char)0x90;
*(ptr + 1) = (char)0x90;
*(ptr + 2) = (char)0x90;
*(ptr + 3) = (char)0x90;
*(ptr + 4) = (char)0x90;
}
{
// CModAppSystemGroup::Create
// force the engine into dedicated mode by changing the first comparison to IsServerOnly to an assignment
char* ptr = (char*)engineAddress + 0x1C4EBD;
TempReadWrite rw(ptr);
// cmp => mov
*(ptr + 1) = (char)0xC6;
*(ptr + 2) = (char)0x87;
// 00 => 01
*((char*)ptr + 7) = (char)0x01;
}
{
// Some init that i'm not sure of that crashes
char* ptr = (char*)engineAddress + 0x156A63;
TempReadWrite rw(ptr);
// nop the call to it
*ptr = (char)0x90;
*(ptr + 1) = (char)0x90;
*(ptr + 2) = (char)0x90;
*(ptr + 3) = (char)0x90;
*(ptr + 4) = (char)0x90;
}
{
// runframeserver
char* ptr = (char*)engineAddress + 0x159819;
TempReadWrite rw(ptr);
// nop some access violations
*ptr = (char)0x90;
*(ptr + 1) = (char)0x90;
*(ptr + 2) = (char)0x90;
*(ptr + 3) = (char)0x90;
*(ptr + 4) = (char)0x90;
*(ptr + 5) = (char)0x90;
*(ptr + 6) = (char)0x90;
*(ptr + 7) = (char)0x90;
*(ptr + 8) = (char)0x90;
*(ptr + 9) = (char)0x90;
*(ptr + 10) = (char)0x90;
*(ptr + 11) = (char)0x90;
*(ptr + 12) = (char)0x90;
*(ptr + 13) = (char)0x90;
*(ptr + 14) = (char)0x90;
*(ptr + 15) = (char)0x90;
*(ptr + 16) = (char)0x90;
}
{
// HostState_State_NewGame
char* ptr = (char*)engineAddress + 0x156B4C;
TempReadWrite rw(ptr);
// nop some access violations
*ptr = (char)0x90;
*(ptr + 1) = (char)0x90;
*(ptr + 2) = (char)0x90;
*(ptr + 3) = (char)0x90;
*(ptr + 4) = (char)0x90;
*(ptr + 5) = (char)0x90;
*(ptr + 6) = (char)0x90;
*(ptr + 7) = (char)0x90;
*(ptr + 8) = (char)0x90;
*(ptr + 9) = (char)0x90;
*(ptr + 10) = (char)0x90;
*(ptr + 11) = (char)0x90;
*(ptr + 12) = (char)0x90;
*(ptr + 13) = (char)0x90;
*(ptr + 14) = (char)0x90;
*(ptr + 15) = (char)0x90;
*(ptr + 16) = (char)0x90;
*(ptr + 17) = (char)0x90;
*(ptr + 18) = (char)0x90;
*(ptr + 19) = (char)0x90;
*(ptr + 20) = (char)0x90;
*(ptr + 21) = (char)0x90;
}
{
// HostState_State_NewGame
char* ptr = (char*)engineAddress + 0xB934C;
TempReadWrite rw(ptr);
// nop an access violation
*ptr = (char)0x90;
*(ptr + 1) = (char)0x90;
*(ptr + 2) = (char)0x90;
*(ptr + 3) = (char)0x90;
*(ptr + 4) = (char)0x90;
*(ptr + 5) = (char)0x90;
*(ptr + 6) = (char)0x90;
*(ptr + 7) = (char)0x90;
*(ptr + 8) = (char)0x90;
}
{
// CEngineAPI::Connect
char* ptr = (char*)engineAddress + 0x1C4D7D;
TempReadWrite rw(ptr);
// remove call to Shader_Connect
*ptr = 0x90;
*(ptr + 1) = (char)0x90;
*(ptr + 2) = (char)0x90;
*(ptr + 3) = (char)0x90;
*(ptr + 4) = (char)0x90;
}
// not currently using this because it's for nopping renderthread/gamewindow stuff i.e. very hard
//{
// // CEngineAPI::Init
// char* ptr = (char*)engineAddress + 0x1C60CE;
// TempReadWrite rw(ptr);
//
// // remove call to something or other that reads video settings
// *ptr = 0x90;
// *(ptr + 1) = (char)0x90;
// *(ptr + 2) = (char)0x90;
// *(ptr + 3) = (char)0x90;
// *(ptr + 4) = (char)0x90;
//}
{
// some inputsystem bullshit
char* ptr = (char*)engineAddress + 0x1CEE28;
TempReadWrite rw(ptr);
// nop an accessviolation: temp because we still create game window atm
*ptr = (char)0x90;
*(ptr + 1) = (char)0x90;
*(ptr + 2) = (char)0x90;
}
CDedicatedExports* dedicatedExports = new CDedicatedExports;
dedicatedExports->vtable = dedicatedExports;
dedicatedExports->Sys_Printf = Sys_Printf;
dedicatedExports->RunServer = RunServer;
CDedicatedExports** exports = (CDedicatedExports**)((char*)engineAddress + 0x13F0B668);
*exports = dedicatedExports;
// extra potential patches:
// nop engine.dll+1c67d1 and +1c67d8 to skip videomode creategamewindow
// also look into launcher.dll+d381, seems to cause renderthread to get made
// this crashes HARD if no window which makes sense tbh
// also look into materialsystem + 5B344 since it seems to be the base of all the renderthread stuff
// add cmdline args that are good for dedi
CommandLine()->AppendParm("-nomenuvid", 0);
CommandLine()->AppendParm("-nosound", 0);
CommandLine()->AppendParm("+host_preload_shaders", "0");
}
typedef void(*Tier0_InitOriginType)();
Tier0_InitOriginType Tier0_InitOrigin;
void Tier0_InitOriginHook()
{
if (!IsDedicated())
Tier0_InitOrigin();
}
void InitialiseDedicatedOrigin(HMODULE baseAddress)
{
HookEnabler hook;
ENABLER_CREATEHOOK(hook, GetProcAddress(GetModuleHandleA("tier0.dll"), "Tier0_InitOrigin"), &Tier0_InitOriginHook, reinterpret_cast<LPVOID*>(&Tier0_InitOrigin));
}