Basic working dedicated server support
This commit is contained in:
parent
59586e18e6
commit
55f12e3313
@ -79,24 +79,24 @@ namespace auth
|
||||
static auto key = utils::cryptography::ecc::generate_key(512, get_key_entropy());
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
bool is_second_instance()
|
||||
{
|
||||
static const auto is_first = []
|
||||
bool is_second_instance()
|
||||
{
|
||||
static utils::nt::handle<> mutex = CreateMutexA(nullptr, FALSE, "boiii_mutex");
|
||||
return mutex && GetLastError() != ERROR_ALREADY_EXISTS;
|
||||
}();
|
||||
static const auto is_first = []
|
||||
{
|
||||
static utils::nt::handle<> mutex = CreateMutexA(nullptr, FALSE, "boiii_mutex");
|
||||
return mutex && GetLastError() != ERROR_ALREADY_EXISTS;
|
||||
}();
|
||||
|
||||
return !is_first;
|
||||
return !is_first;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t get_guid()
|
||||
{
|
||||
static const auto guid = []() -> uint64_t
|
||||
{
|
||||
if (is_second_instance())
|
||||
if (game::is_server() || is_second_instance())
|
||||
{
|
||||
return 0x110000100000000 | (::utils::cryptography::random::get_integer() & ~0x80000000);
|
||||
}
|
||||
@ -112,10 +112,55 @@ namespace auth
|
||||
void post_unpack() override
|
||||
{
|
||||
// Patch steam id bit check
|
||||
utils::hook::jump(0x141E19D7D_g, 0x141E19DCB_g);
|
||||
utils::hook::jump(0x141EB2D06_g, 0x141EB2D46_g);
|
||||
utils::hook::jump(0x141EB2E3D_g, 0x141EB2E82_g);
|
||||
utils::hook::jump(0x141EB3CC5_g, 0x141EB3D06_g);
|
||||
std::vector<std::pair<size_t, size_t>> patches{};
|
||||
const auto p = [&patches](const size_t a, const size_t b)
|
||||
{
|
||||
patches.emplace_back(a, b);
|
||||
};
|
||||
|
||||
if (game::is_server())
|
||||
{
|
||||
p(0x1404747C6_g, 0x140474806_g);
|
||||
p(0x140474A24_g, 0x140474A68_g);
|
||||
p(0x140474A85_g, 0x140474AC6_g);
|
||||
p(0x140457ED0_g, 0x140457F26_g);
|
||||
p(0x140473DD8_g, 0x140473E19_g);
|
||||
p(0x1404743D5_g, 0x140474423_g);
|
||||
p(0x1404744FD_g, 0x140474553_g);
|
||||
p(0x14047462D_g, 0x140474677_g);
|
||||
p(0x140475057_g, 0x14047509F_g); // ?
|
||||
p(0x140475672_g, 0x1404756B5_g);
|
||||
p(0x140477322_g, 0x140477365_g); // ?
|
||||
}
|
||||
else
|
||||
{
|
||||
p(0x141E19D7D_g, 0x141E19DCB_g);
|
||||
p(0x141EB2D06_g, 0x141EB2D46_g);
|
||||
p(0x141EB2E3D_g, 0x141EB2E82_g);
|
||||
p(0x141EB3CC5_g, 0x141EB3D06_g);
|
||||
p(0x141E19B60_g, 0x141E19BB6_g);
|
||||
//
|
||||
p(0x141EB0F78_g, 0x141EB0FB9_g);
|
||||
p(0x141EB1038_g, 0x141EB1079_g);
|
||||
p(0x141EB25B5_g, 0x141EB2603_g);
|
||||
p(0x141EB26DD_g, 0x141EB2733_g);
|
||||
p(0x141EB280D_g, 0x141EB2857_g);
|
||||
|
||||
p(0x141EB2B7A_g, 0x141EB2B8A_g);
|
||||
p(0x141EB2B91_g, 0x141EB2BC3_g);
|
||||
|
||||
p(0x141EB31C7_g, 0x141EB31D7_g);
|
||||
p(0x141EB31DE_g, 0x141EB320F_g);
|
||||
|
||||
p(0x141EB5407_g, 0x141EB544F_g); // ?
|
||||
p(0x141EB5A22_g, 0x141EB5A65_g);
|
||||
p(0x141EB7562_g, 0x141EB75A5_g); // ?
|
||||
}
|
||||
|
||||
for (const auto& patch : patches)
|
||||
{
|
||||
utils::hook::jump(patch.first, patch.second);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
|
||||
#include "game/game.hpp"
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
|
||||
namespace dedicated
|
||||
@ -13,6 +15,9 @@ namespace dedicated
|
||||
{
|
||||
void post_unpack() override
|
||||
{
|
||||
// Ignore "bad stats"
|
||||
utils::hook::set<uint8_t>(0x14052D523_g, 0xEB);
|
||||
utils::hook::nop(0x14052D4E4_g, 2);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -476,17 +476,20 @@ namespace demonware
|
||||
{
|
||||
server_thread = utils::thread::create_named_thread("Demonware", server_main);
|
||||
|
||||
|
||||
utils::hook::set<uint8_t>(game::select(0x14293E829, 0x1407D5879), 0x0); // CURLOPT_SSL_VERIFYPEER
|
||||
utils::hook::set<uint8_t>(game::select(0x15F3CCFED, 0x1407D5865), 0xAF); // CURLOPT_SSL_VERIFYHOST
|
||||
|
||||
utils::hook::copy_string(game::select(0x1430B96E0, 0x140EE4C68), "http://prod.umbrella.demonware.net");
|
||||
|
||||
if (game::is_server())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
utils::hook::set<uint8_t>(0x14293E829_g, 0x0); // CURLOPT_SSL_VERIFYPEER
|
||||
utils::hook::set<uint8_t>(0x15F3CCFED_g, 0xAF); // CURLOPT_SSL_VERIFYHOST
|
||||
utils::hook::set<uint8_t>(0x1430B9810_g, 0x0); // HTTPS -> HTTP
|
||||
|
||||
utils::hook::copy_string(0x1430B96E0_g, "http://prod.umbrella.demonware.net");
|
||||
utils::hook::copy_string(0x1430B9BE0_g, "http://prod.uno.demonware.net/v1.0");
|
||||
|
||||
utils::hook::set<uint8_t>(0x1430B9810_g, 0x0); // HTTPS -> HTTP
|
||||
utils::hook::copy_string(0x1430B93C8_g, "http://%s:%d/auth/");
|
||||
|
||||
utils::hook::set<uint32_t>(0x141EC4B50_g, 0xC3D08948); // Skip publisher file signature stuff
|
||||
|
60
src/client/component/getinfo.cpp
Normal file
60
src/client/component/getinfo.cpp
Normal file
@ -0,0 +1,60 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
|
||||
#include "game/game.hpp"
|
||||
#include "steam/steam.hpp"
|
||||
|
||||
#include "network.hpp"
|
||||
|
||||
#include <utils/string.hpp>
|
||||
#include <utils/info_string.hpp>
|
||||
|
||||
#include <version.hpp>
|
||||
|
||||
namespace getinfo
|
||||
{
|
||||
namespace
|
||||
{
|
||||
std::string get_dvar_string(const char* dvar_name)
|
||||
{
|
||||
const auto dvar = game::Dvar_FindVar(dvar_name);
|
||||
if (!dvar)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
return game::Dvar_GetString(dvar);
|
||||
}
|
||||
}
|
||||
|
||||
struct component final : generic_component
|
||||
{
|
||||
void post_unpack() override
|
||||
{
|
||||
network::on("getInfo", [](const game::netadr_t& target, const network::data_view& data)
|
||||
{
|
||||
utils::info_string info{};
|
||||
info.set("challenge", std::string(data.begin(), data.end()));
|
||||
info.set("gamename", "T7");
|
||||
info.set("hostname", get_dvar_string("sv_hostname"));
|
||||
info.set("gametype", get_dvar_string("g_gametype"));
|
||||
//info.set("sv_motd", get_dvar_string("sv_motd"));
|
||||
info.set("xuid", utils::string::va("%llX", steam::SteamUser()->GetSteamID().bits));
|
||||
info.set("mapname", get_dvar_string("mapname"));
|
||||
//info.set("isPrivate", get_dvar_string("g_password").empty() ? "0" : "1");
|
||||
//info.set("clients", utils::string::va("%i", get_client_count()));
|
||||
//info.set("bots", utils::string::va("%i", get_bot_count()));
|
||||
//info.set("sv_maxclients", utils::string::va("%i", *game::mp::svs_numclients));
|
||||
info.set("protocol", utils::string::va("%i", 1/*PROTOCOL*/));
|
||||
info.set("playmode", utils::string::va("%i", game::Com_SessionMode_GetMode()));
|
||||
//info.set("sv_running", utils::string::va("%i", get_dvar_bool("sv_running")));
|
||||
info.set("dedicated", utils::string::va("%i", game::is_server() ? 1 : 0));
|
||||
info.set("shortversion", SHORTVERSION);
|
||||
|
||||
network::send(target, "infoResponse", info.build(), '\n');
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
REGISTER_COMPONENT(getinfo::component)
|
@ -39,11 +39,13 @@ namespace network
|
||||
|
||||
void handle_command_stub(utils::hook::assembler& a)
|
||||
{
|
||||
const auto sv = game::is_server();
|
||||
|
||||
a.pushad64();
|
||||
|
||||
a.mov(r8, r12); // msg
|
||||
a.mov(rdx, rcx); // command
|
||||
a.mov(rcx, r15); // address
|
||||
a.mov(rdx, rcx); // command
|
||||
a.mov(r8, sv ? r15 : r12); // msg
|
||||
a.mov(rcx, sv ? r14 : r15); // address
|
||||
|
||||
a.call_aligned(handle_command);
|
||||
|
||||
@ -51,7 +53,7 @@ namespace network
|
||||
|
||||
a.popad64();
|
||||
|
||||
a.jmp(0x14134D14B_g);
|
||||
a.ret();
|
||||
}
|
||||
|
||||
bool socket_set_blocking(const SOCKET s, const bool blocking)
|
||||
@ -210,24 +212,21 @@ namespace network
|
||||
return 2;
|
||||
}
|
||||
|
||||
struct component final : client_component
|
||||
struct component final : generic_component
|
||||
{
|
||||
void post_unpack() override
|
||||
{
|
||||
//utils::hook::jump(0x14143CAB0_g, ret2); // patch dwGetConnectionStatus
|
||||
//utils::hook::jump(0x14233307E_g, 0x1423330C7_g);
|
||||
utils::hook::nop(game::select(0x142332E76, 0x140596DF6), 4); // don't increment data pointer to optionally skip socket byte
|
||||
utils::hook::call(game::select(0x142332E43, 0x140596DC3), read_socket_byte_stub); // optionally read socket byte
|
||||
utils::hook::call(game::select(0x142332E81, 0x140596E01), verify_checksum_stub); // skip checksum verification
|
||||
utils::hook::set<uint8_t>(game::select(0x14233305E, 0x140596F2E), 0); // don't add checksum to packet
|
||||
|
||||
utils::hook::nop(0x142332E76_g, 4); // don't increment data pointer to optionally skip socket byte
|
||||
utils::hook::call(0x142332E43_g, read_socket_byte_stub); // optionally read socket byte
|
||||
utils::hook::call(0x142332E81_g, verify_checksum_stub); // skip checksum verification
|
||||
utils::hook::set<uint8_t>(0x14233305E_g, 0); // don't add checksum to packet
|
||||
|
||||
utils::hook::set<uint32_t>(0x14134C6E0_g, 5); // set initial connection state to challenging
|
||||
utils::hook::set<uint32_t>(game::select(0x14134C6E0, 0x14018E574), 5); // set initial connection state to challenging
|
||||
|
||||
// intercept command handling
|
||||
utils::hook::jump(0x14134D146_g, utils::hook::assemble(handle_command_stub));
|
||||
utils::hook::call(game::select(0x14134D146, 0x14018EED0), utils::hook::assemble(handle_command_stub));
|
||||
|
||||
utils::hook::set<uint8_t>(0x14224E90D_g, 0xEB); // don't kick clients without dw handle
|
||||
utils::hook::set<uint8_t>(game::select(0x14224E90D, 0x1405315F9), 0xEB); // don't kick clients without dw handle
|
||||
|
||||
// TODO: Fix that
|
||||
scheduler::once(create_ip_socket, scheduler::main);
|
||||
|
@ -1,20 +1,16 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
#include "game/game.hpp"
|
||||
#include "steam/steam.hpp"
|
||||
|
||||
#include "party.hpp"
|
||||
#include "network.hpp"
|
||||
#include "scheduler.hpp"
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/string.hpp>
|
||||
#include <utils/info_string.hpp>
|
||||
#include <utils/cryptography.hpp>
|
||||
#include <utils/concurrency.hpp>
|
||||
|
||||
#include <version.hpp>
|
||||
|
||||
namespace party
|
||||
{
|
||||
namespace
|
||||
@ -186,17 +182,6 @@ namespace party
|
||||
connect_host = target;
|
||||
query_server(target, handle_connect_query_response);
|
||||
}
|
||||
|
||||
std::string get_dvar_string(const char* dvar_name)
|
||||
{
|
||||
const auto dvar = game::Dvar_FindVar(dvar_name);
|
||||
if (!dvar)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
return game::Dvar_GetString(dvar);
|
||||
}
|
||||
}
|
||||
|
||||
void query_server(const game::netadr_t& host, query_callback callback)
|
||||
@ -221,32 +206,8 @@ namespace party
|
||||
{
|
||||
void post_unpack() override
|
||||
{
|
||||
utils::hook::jump(0x141E19B60_g, 0x141E19BB6_g); // patch steam id validity check
|
||||
utils::hook::jump(0x141EE6030_g, connect_stub);
|
||||
|
||||
network::on("getInfo", [](const game::netadr_t& target, const network::data_view& data)
|
||||
{
|
||||
utils::info_string info{};
|
||||
info.set("challenge", std::string(data.begin(), data.end()));
|
||||
info.set("gamename", "T7");
|
||||
info.set("hostname", get_dvar_string("sv_hostname"));
|
||||
info.set("gametype", get_dvar_string("g_gametype"));
|
||||
//info.set("sv_motd", get_dvar_string("sv_motd"));
|
||||
info.set("xuid", utils::string::va("%llX", steam::SteamUser()->GetSteamID().bits));
|
||||
info.set("mapname", get_dvar_string("mapname"));
|
||||
//info.set("isPrivate", get_dvar_string("g_password").empty() ? "0" : "1");
|
||||
//info.set("clients", utils::string::va("%i", get_client_count()));
|
||||
//info.set("bots", utils::string::va("%i", get_bot_count()));
|
||||
//info.set("sv_maxclients", utils::string::va("%i", *game::mp::svs_numclients));
|
||||
info.set("protocol", utils::string::va("%i", 1/*PROTOCOL*/));
|
||||
info.set("playmode", utils::string::va("%i", game::Com_SessionMode_GetMode()));
|
||||
//info.set("sv_running", utils::string::va("%i", get_dvar_bool("sv_running")));
|
||||
//info.set("dedicated", utils::string::va("%i", get_dvar_bool("dedicated")));
|
||||
info.set("shortversion", SHORTVERSION);
|
||||
|
||||
network::send(target, "infoResponse", info.build(), '\n');
|
||||
});
|
||||
|
||||
network::on("infoResponse", [](const game::netadr_t& target, const network::data_view& data)
|
||||
{
|
||||
bool found_query = false;
|
||||
|
@ -75,8 +75,8 @@ namespace scheduler
|
||||
{
|
||||
new_callbacks_.access([&](task_list& new_tasks)
|
||||
{
|
||||
tasks.insert(tasks.end(), std::move_iterator<task_list::iterator>(new_tasks.begin()),
|
||||
std::move_iterator<task_list::iterator>(new_tasks.end()));
|
||||
tasks.insert(tasks.end(), std::move_iterator(new_tasks.begin()),
|
||||
std::move_iterator(new_tasks.end()));
|
||||
new_tasks = {};
|
||||
});
|
||||
});
|
||||
@ -167,10 +167,13 @@ namespace scheduler
|
||||
{
|
||||
if (!game::is_server())
|
||||
{
|
||||
r_end_frame_hook.create(0x142273560_g, r_end_frame_stub); // some func called before R_EndFrame, maybe SND_EndFrame?
|
||||
g_run_frame_hook.create(0x14065C360_g, server_frame_stub); // GlassSv_Update
|
||||
main_frame_hook.create(0x1420F9860_g, main_frame_stub); // Com_Frame_Try_Block_Function
|
||||
r_end_frame_hook.create(0x142273560_g, r_end_frame_stub);
|
||||
// some func called before R_EndFrame, maybe SND_EndFrame?
|
||||
}
|
||||
|
||||
//g_run_frame_hook.create(0x14065C360_g, server_frame_stub); // GlassSv_Update
|
||||
main_frame_hook.create(game::select(0x1420F9860, 0x1405020E0), main_frame_stub);
|
||||
// Com_Frame_Try_Block_Function
|
||||
}
|
||||
|
||||
void pre_destroy() override
|
||||
|
@ -9,7 +9,7 @@ namespace game
|
||||
{
|
||||
const utils::nt::library& get_host_library()
|
||||
{
|
||||
static auto host_library = []
|
||||
static const auto host_library = []
|
||||
{
|
||||
utils::nt::library host{};
|
||||
if (!host || host == utils::nt::library::get_by_address(get_base))
|
||||
@ -26,13 +26,13 @@ namespace game
|
||||
|
||||
size_t get_base()
|
||||
{
|
||||
static auto base = reinterpret_cast<size_t>(get_host_library().get_ptr());
|
||||
static const auto base = reinterpret_cast<size_t>(get_host_library().get_ptr());
|
||||
return base;
|
||||
}
|
||||
|
||||
bool is_server()
|
||||
{
|
||||
static auto server = get_host_library().get_optional_header()->CheckSum == 0x14C28B4;
|
||||
static const auto server = get_host_library().get_optional_header()->CheckSum == 0x14C28B4;
|
||||
return server;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "structs.hpp"
|
||||
|
||||
namespace game
|
||||
{
|
||||
size_t get_base();
|
||||
@ -9,12 +7,16 @@ namespace game
|
||||
|
||||
inline size_t relocate(const size_t val)
|
||||
{
|
||||
if (!val) return 0;
|
||||
|
||||
const auto base = get_base();
|
||||
return base + (val - 0x140000000);
|
||||
}
|
||||
|
||||
inline size_t derelocate(const size_t val)
|
||||
{
|
||||
if (!val) return 0;
|
||||
|
||||
const auto base = get_base();
|
||||
return (val - base) + 0x140000000;
|
||||
}
|
||||
@ -24,6 +26,16 @@ namespace game
|
||||
return derelocate(reinterpret_cast<size_t>(val));
|
||||
}
|
||||
|
||||
inline size_t select(const size_t client_val, const size_t server_val)
|
||||
{
|
||||
return relocate(is_server() ? server_val : client_val);
|
||||
}
|
||||
|
||||
inline size_t select(const void* client_val, const void* server_val)
|
||||
{
|
||||
return select(reinterpret_cast<size_t>(client_val), reinterpret_cast<size_t>(server_val));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class symbol
|
||||
{
|
||||
@ -33,9 +45,15 @@ namespace game
|
||||
{
|
||||
}
|
||||
|
||||
symbol(const size_t address, const size_t server_address)
|
||||
: address_(address)
|
||||
, server_address_(server_address)
|
||||
{
|
||||
}
|
||||
|
||||
T* get() const
|
||||
{
|
||||
return reinterpret_cast<T*>(relocate(this->address_));
|
||||
return reinterpret_cast<T*>(select(this->address_, this->server_address_));
|
||||
}
|
||||
|
||||
operator T*() const
|
||||
@ -49,7 +67,8 @@ namespace game
|
||||
}
|
||||
|
||||
private:
|
||||
size_t address_;
|
||||
size_t address_{};
|
||||
size_t server_address_{};
|
||||
};
|
||||
}
|
||||
|
||||
@ -58,4 +77,5 @@ inline size_t operator"" _g(const size_t val)
|
||||
return game::relocate(val);
|
||||
}
|
||||
|
||||
#include "structs.hpp"
|
||||
#include "symbols.hpp"
|
||||
|
@ -828,7 +828,7 @@ namespace game
|
||||
JOIN_RESPONSE_COUNT = 0x1E,
|
||||
};
|
||||
|
||||
typedef void (*joinCompleteCallback)(const int, JoinResult);
|
||||
typedef void (*joinCompleteCallback)(int, JoinResult);
|
||||
|
||||
struct AgreementStatus
|
||||
{
|
||||
|
@ -6,6 +6,6 @@ namespace game
|
||||
{
|
||||
eModes Com_SessionMode_GetMode()
|
||||
{
|
||||
return eModes(*reinterpret_cast<uint32_t*>(0x1568EF7F4_g) << 28 >> 28);
|
||||
return eModes(*reinterpret_cast<uint32_t*>(game::select(0x1568EF7F4, 0x14948DB04)) << 28 >> 28);
|
||||
}
|
||||
}
|
||||
|
@ -40,12 +40,11 @@ namespace game
|
||||
WEAK symbol<bool(uint64_t, int*, bool)> Live_GetConnectivityInformation{0x141E0C410};
|
||||
|
||||
// MSG
|
||||
WEAK symbol<uint8_t(msg_t* msg)> MSG_ReadByte{0x142155EB0};
|
||||
WEAK symbol<uint8_t(msg_t* msg)> MSG_ReadByte{0x142155EB0, 0x14050D1B0};
|
||||
|
||||
// NET
|
||||
WEAK symbol<bool(netsrc_t sock, int length, const void* data, const netadr_t* to)> NET_SendPacket{0x142332F70};
|
||||
WEAK symbol<bool(char const*, netadr_t*)> NET_StringToAdr{0x1421731E0};
|
||||
WEAK symbol<bool(netadr_t*, char const*)> NetAdr_InitFromString{0x142332F70};
|
||||
WEAK symbol<bool(netsrc_t sock, int length, const void* data, const netadr_t* to)> NET_SendPacket{0x142332F70, 0x140596E40};
|
||||
WEAK symbol<bool(char const*, netadr_t*)> NET_StringToAdr{0x1421731E0, 0x140515110};
|
||||
|
||||
// Sys
|
||||
WEAK symbol<int()> Sys_Milliseconds{0x142333430};
|
||||
@ -53,11 +52,11 @@ namespace game
|
||||
WEAK symbol<TLSData*()> Sys_GetTLS{0x142184210};
|
||||
|
||||
// Dvar
|
||||
WEAK symbol<const dvar_t*(const char* dvarName)> Dvar_FindVar{0x1422BD730};
|
||||
WEAK symbol<const dvar_t*(const char* dvarName)> Dvar_FindVar{0x1422BD730, 0x140575540};
|
||||
WEAK symbol<unsigned int(const char* str)> Dvar_GenerateHash{0x14133DBF0};
|
||||
WEAK symbol<dvar_t*(unsigned int hash)> Dvar_FindMalleableVar{0x1422BD6A0};
|
||||
WEAK symbol<const char*(const dvar_t* dvar)> Dvar_GetDebugName{0x1422BDCB0};
|
||||
WEAK symbol<const char*(const dvar_t* dvar)> Dvar_GetString{0x1422BFFF0};
|
||||
WEAK symbol<const char*(const dvar_t* dvar)> Dvar_GetString{0x1422BFFF0, 0x140575E30};
|
||||
WEAK symbol<void(const char* dvarName, const char* string, bool createIfMissing)> Dvar_SetFromStringByName{
|
||||
0x1422C7F60
|
||||
};
|
||||
@ -76,7 +75,7 @@ namespace game
|
||||
WEAK symbol<cmd_function_s> cmd_functions{0x15689FF58};
|
||||
WEAK symbol<CmdArgs> sv_cmd_args{0x15689CE30};
|
||||
|
||||
WEAK symbol<SOCKET> ip_socket{0x157E77818};
|
||||
WEAK symbol<SOCKET> ip_socket{0x157E77818, 0x14A640988};
|
||||
|
||||
WEAK symbol<Join> s_join{0x15574C640};
|
||||
|
||||
|
@ -7,9 +7,12 @@
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/nt.hpp>
|
||||
#include <utils/io.hpp>
|
||||
#include <utils/flags.hpp>
|
||||
|
||||
#include <steam/steam.hpp>
|
||||
|
||||
#include "game/game.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
volatile bool g_call_tls_callbacks = false;
|
||||
@ -55,6 +58,12 @@ namespace
|
||||
return steam::SteamAPI_RestartAppIfNecessary();
|
||||
}
|
||||
|
||||
BOOL set_process_dpi_aware_stub()
|
||||
{
|
||||
component_loader::post_unpack();
|
||||
return SetProcessDPIAware();
|
||||
}
|
||||
|
||||
void patch_imports()
|
||||
{
|
||||
patch_steam_import("SteamAPI_RegisterCallback", steam::SteamAPI_RegisterCallback);
|
||||
@ -74,7 +83,9 @@ namespace
|
||||
//patch_steam_import("SteamAPI_Shutdown", steam::SteamAPI_Shutdown);
|
||||
g_original_import = patch_steam_import("SteamAPI_RestartAppIfNecessary", restart_app_if_necessary_stub);
|
||||
|
||||
utils::hook::set(utils::nt::library{}.get_iat_entry("kernel32.dll", "ExitProcess"), exit_hook);
|
||||
const utils::nt::library game{};
|
||||
utils::hook::set(game.get_iat_entry("kernel32.dll", "ExitProcess"), exit_hook);
|
||||
utils::hook::set(game.get_iat_entry("user32.dll", "SetProcessDPIAware"), set_process_dpi_aware_stub);
|
||||
}
|
||||
|
||||
void remove_crash_file()
|
||||
@ -163,7 +174,6 @@ namespace
|
||||
{
|
||||
if (handle_process_runner())
|
||||
{
|
||||
TerminateProcess(GetCurrentProcess(), 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -186,7 +196,7 @@ namespace
|
||||
|
||||
const auto client_binary = "BlackOps3.exe"s;
|
||||
const auto server_binary = "BlackOps3_UnrankedDedicatedServer.exe"s;
|
||||
const auto has_server = utils::io::file_exists(server_binary);
|
||||
const auto has_server = !utils::io::file_exists(client_binary) || utils::flags::has_flag("dedicated");
|
||||
|
||||
if (!component_loader::activate(has_server))
|
||||
{
|
||||
@ -199,6 +209,11 @@ namespace
|
||||
throw std::runtime_error("Unable to load binary into memory");
|
||||
}
|
||||
|
||||
if (has_server != game::is_server())
|
||||
{
|
||||
throw std::runtime_error("Bad binary loaded into memory");
|
||||
}
|
||||
|
||||
patch_imports();
|
||||
|
||||
if (!component_loader::post_load())
|
||||
|
Loading…
Reference in New Issue
Block a user