Prepare dedicated server support
This commit is contained in:
parent
f4a4a95674
commit
3a6f973473
@ -696,9 +696,8 @@ namespace arxan
|
||||
return zw_terminate_process_hook.invoke<NTSTATUS>(process_handle, exit_status);
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
struct component final : component_interface
|
||||
{
|
||||
public:
|
||||
void post_load() override
|
||||
{
|
||||
auto* dll_characteristics = &utils::nt::library().get_optional_header()->DllCharacteristics;
|
||||
|
@ -107,9 +107,8 @@ namespace auth
|
||||
return guid;
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
struct component final : client_component_interface
|
||||
{
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
// Patch steam id bit check
|
||||
|
@ -41,9 +41,8 @@ namespace bots
|
||||
}
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
struct component final : client_component_interface
|
||||
{
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
utils::hook::jump(0x141653B70_g, get_bot_name);
|
||||
|
@ -27,9 +27,8 @@ namespace branding
|
||||
}
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
struct component final : client_component_interface
|
||||
{
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
scheduler::loop(draw_branding, scheduler::renderer);
|
||||
|
@ -30,9 +30,8 @@ namespace colors
|
||||
utils::hook::copy(g_color_table + index * 4, color_float, sizeof(color_float));
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
struct component final : client_component_interface
|
||||
{
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
patch_color<1>(255, 49, 49); // 1 - Red
|
||||
|
@ -46,9 +46,8 @@ namespace command
|
||||
}
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
struct component final : client_component_interface
|
||||
{
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
// Disable whitelist
|
||||
|
@ -193,9 +193,8 @@ namespace console
|
||||
}
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
struct component final : client_component_interface
|
||||
{
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
utils::hook::set<uint8_t>(0x14133D2FE_g, 0xEB); // Always enable ingame console
|
||||
|
@ -9,9 +9,8 @@ namespace dedicated
|
||||
{
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
struct component final : server_component_interface
|
||||
{
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
}
|
||||
|
@ -441,9 +441,8 @@ namespace demonware
|
||||
}
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
struct component final : component_interface
|
||||
{
|
||||
public:
|
||||
component()
|
||||
{
|
||||
udp_servers.create<stun_server>("stun.us.demonware.net");
|
||||
@ -477,6 +476,11 @@ namespace demonware
|
||||
{
|
||||
server_thread = utils::thread::create_named_thread("Demonware", server_main);
|
||||
|
||||
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
|
||||
@ -489,7 +493,7 @@ namespace demonware
|
||||
utils::hook::call(0x141EC458C_g, get_ffotd_name); // Return unlocalized ffotd name
|
||||
utils::hook::set<uint64_t>(0x141F04550_g, 0xC300000001B8); // Kill LPC_File_SafeWrite
|
||||
utils::hook::set<uint64_t>(0x141F03180_g, 0xC300000001B8); // Kill LPC_DeleteStale
|
||||
|
||||
|
||||
utils::hook::set<uint8_t>(0x141E0AAAB_g, 0xEB); // Release un-handled reportReward spamming loop
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,7 @@ namespace discord
|
||||
}
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
class component final : public client_component_interface
|
||||
{
|
||||
public:
|
||||
void post_load() override
|
||||
|
@ -193,9 +193,8 @@ namespace exception
|
||||
}
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
struct component final : component_interface
|
||||
{
|
||||
public:
|
||||
component()
|
||||
{
|
||||
main_thread_id = GetCurrentThreadId();
|
||||
|
@ -29,9 +29,8 @@ namespace icon
|
||||
}
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
struct component final : component_interface
|
||||
{
|
||||
public:
|
||||
void post_load() override
|
||||
{
|
||||
load_icon_a_hook.create(LoadIconA, load_icon_a_stub);
|
||||
|
@ -14,7 +14,8 @@ namespace loot
|
||||
utils::hook::detour liveinventory_getitemquantity_hook;
|
||||
utils::hook::detour liveinventory_areextraslotspurchased_hook;
|
||||
|
||||
int loot_getitemquantity_stub(const game::ControllerIndex_t /*controller_index*/, const game::eModes mode, const int /*item_id*/)
|
||||
int loot_getitemquantity_stub(const game::ControllerIndex_t /*controller_index*/, const game::eModes mode,
|
||||
const int /*item_id*/)
|
||||
{
|
||||
if (mode == game::eModes::MODE_ZOMBIES)
|
||||
{
|
||||
@ -27,7 +28,8 @@ namespace loot
|
||||
int liveinventory_getitemquantity_stub(const game::ControllerIndex_t controller_index, const int item_id)
|
||||
{
|
||||
// Item id's for extra CaC slots, CWL camo's and paid specialist outfits
|
||||
if (item_id == 99003 || item_id >= 99018 && item_id <= 99021 || item_id == 99025 || item_id >= 90047 && item_id <= 90064)
|
||||
if (item_id == 99003 || item_id >= 99018 && item_id <= 99021 || item_id == 99025 || item_id >= 90047 &&
|
||||
item_id <= 90064)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
@ -47,9 +49,8 @@ namespace loot
|
||||
}
|
||||
};
|
||||
|
||||
class component final : public component_interface
|
||||
struct component final : client_component_interface
|
||||
{
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
scheduler::once(set_dvars_on_startup, scheduler::pipeline::main);
|
||||
|
@ -210,9 +210,8 @@ namespace network
|
||||
return 2;
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
struct component final : client_component_interface
|
||||
{
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
//utils::hook::jump(0x14143CAB0_g, ret2); // patch dwGetConnectionStatus
|
||||
|
@ -217,9 +217,8 @@ namespace party
|
||||
network::send(host, "getInfo", challenge);
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
struct component final : client_component_interface
|
||||
{
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
utils::hook::jump(0x141E19B60_g, 0x141E19BB6_g); // patch steam id validity check
|
||||
|
@ -149,9 +149,8 @@ namespace scheduler
|
||||
}, type, delay);
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
struct component final : component_interface
|
||||
{
|
||||
public:
|
||||
void post_load() override
|
||||
{
|
||||
thread = utils::thread::create_named_thread("Async Scheduler", []()
|
||||
@ -166,9 +165,12 @@ namespace scheduler
|
||||
|
||||
void post_unpack() override
|
||||
{
|
||||
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
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
void pre_destroy() override
|
||||
|
@ -165,9 +165,8 @@ namespace splash
|
||||
}
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
struct component final : client_component_interface
|
||||
{
|
||||
public:
|
||||
component()
|
||||
{
|
||||
enable_dpi_awareness();
|
||||
|
@ -53,7 +53,7 @@ namespace steam_proxy
|
||||
{
|
||||
std::string name = utils::string::va("CLIENTENGINE_INTERFACE_VERSION%03i", i);
|
||||
auto* const temp_client_engine = steam_client_module
|
||||
.invoke<void*>("CreateInterface", name.data(), nullptr);
|
||||
.invoke<void*>("CreateInterface", name.data(), nullptr);
|
||||
if (temp_client_engine) return temp_client_engine;
|
||||
}
|
||||
|
||||
@ -76,7 +76,7 @@ namespace steam_proxy
|
||||
|
||||
steam_pipe = steam_client_module.invoke<void*>("Steam_CreateSteamPipe");
|
||||
global_user = steam_client_module.invoke<void*>(
|
||||
"Steam_ConnectToGlobalUser", steam_pipe);
|
||||
"Steam_ConnectToGlobalUser", steam_pipe);
|
||||
|
||||
client_user = client_engine.invoke<void*>(8, global_user, steam_pipe);
|
||||
client_utils = client_engine.invoke<void*>(14, steam_pipe);
|
||||
@ -205,9 +205,8 @@ namespace steam_proxy
|
||||
}
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
struct component final : component_interface
|
||||
{
|
||||
public:
|
||||
void post_load() override
|
||||
{
|
||||
load_client();
|
||||
@ -312,7 +311,7 @@ namespace steam_proxy
|
||||
}
|
||||
|
||||
void access_subscribed_items(
|
||||
const std::function<void(const subscribed_item_map&)>& callback)
|
||||
const std::function<void(const subscribed_item_map&)>& callback)
|
||||
{
|
||||
subscribed_items.access(callback);
|
||||
}
|
||||
|
@ -5,18 +5,33 @@
|
||||
|
||||
namespace game
|
||||
{
|
||||
namespace
|
||||
{
|
||||
const utils::nt::library& get_host_library()
|
||||
{
|
||||
static auto host = []
|
||||
{
|
||||
utils::nt::library host{};
|
||||
if (!host || host == utils::nt::library::get_by_address(get_base))
|
||||
{
|
||||
throw std::runtime_error("Invalid host application");
|
||||
}
|
||||
|
||||
return host;
|
||||
}();
|
||||
return host;
|
||||
}
|
||||
}
|
||||
|
||||
size_t get_base()
|
||||
{
|
||||
static auto base = []
|
||||
{
|
||||
const utils::nt::library host{};
|
||||
if (!host || host == utils::nt::library::get_by_address(get_base))
|
||||
{
|
||||
throw std::runtime_error("Invalid host application");
|
||||
}
|
||||
|
||||
return reinterpret_cast<size_t>(host.get_ptr());
|
||||
}();
|
||||
static 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;
|
||||
return server;
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
namespace game
|
||||
{
|
||||
size_t get_base();
|
||||
bool is_server();
|
||||
|
||||
inline size_t relocate(const size_t val)
|
||||
{
|
||||
|
@ -10,9 +10,17 @@ enum class component_priority
|
||||
arxan,
|
||||
};
|
||||
|
||||
class component_interface
|
||||
enum class component_type
|
||||
{
|
||||
public:
|
||||
client,
|
||||
server,
|
||||
any,
|
||||
};
|
||||
|
||||
struct component_interface
|
||||
{
|
||||
static constexpr component_type type = component_type::any;
|
||||
|
||||
virtual ~component_interface() = default;
|
||||
|
||||
virtual void post_load()
|
||||
@ -32,3 +40,13 @@ public:
|
||||
return component_priority::min;
|
||||
}
|
||||
};
|
||||
|
||||
struct client_component_interface : component_interface
|
||||
{
|
||||
static constexpr component_type type = component_type::client;
|
||||
};
|
||||
|
||||
struct server_component_interface : component_interface
|
||||
{
|
||||
static constexpr component_type type = component_type::server;
|
||||
};
|
||||
|
@ -23,9 +23,9 @@ namespace component_loader
|
||||
return *components;
|
||||
}
|
||||
|
||||
std::vector<registration_functor>& get_registration_functors()
|
||||
std::vector<std::pair<registration_functor, component_type>>& get_registration_functors()
|
||||
{
|
||||
static std::vector<registration_functor> functors;
|
||||
static std::vector<std::pair<registration_functor, component_type>> functors;
|
||||
return functors;
|
||||
}
|
||||
|
||||
@ -42,25 +42,28 @@ namespace component_loader
|
||||
}
|
||||
}
|
||||
|
||||
void register_component(registration_functor functor)
|
||||
void register_component(registration_functor functor, component_type type)
|
||||
{
|
||||
if (!get_components().empty())
|
||||
{
|
||||
throw std::runtime_error("Registration is too late");
|
||||
}
|
||||
|
||||
get_registration_functors().push_back(std::move(functor));
|
||||
get_registration_functors().emplace_back(std::move(functor), type);
|
||||
}
|
||||
|
||||
bool activate()
|
||||
bool activate(bool server)
|
||||
{
|
||||
static auto res = []
|
||||
static auto res = [server]
|
||||
{
|
||||
try
|
||||
{
|
||||
for (auto& functor : get_registration_functors())
|
||||
{
|
||||
activate_component(functor());
|
||||
if (functor.second == component_type::any || server == (functor.second == component_type::server))
|
||||
{
|
||||
activate_component(functor.first());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (premature_shutdown_trigger&)
|
||||
|
@ -5,9 +5,9 @@ namespace component_loader
|
||||
{
|
||||
using registration_functor = std::function<std::unique_ptr<component_interface>()>;
|
||||
|
||||
void register_component(registration_functor functor);
|
||||
void register_component(registration_functor functor, component_type type);
|
||||
|
||||
bool activate();
|
||||
bool activate(bool server);
|
||||
bool post_load();
|
||||
void post_unpack();
|
||||
void pre_destroy();
|
||||
@ -33,7 +33,7 @@ namespace component_loader
|
||||
register_component([]
|
||||
{
|
||||
return std::make_unique<T>();
|
||||
});
|
||||
}, T::type);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
@ -100,7 +100,7 @@ namespace loader
|
||||
|
||||
auto* rel_info = offset_pointer<uint16_t*>(relocation, sizeof(IMAGE_BASE_RELOCATION));
|
||||
const auto* rel_info_end = offset_pointer<uint16_t*>(
|
||||
rel_info, relocation->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION));
|
||||
rel_info, relocation->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION));
|
||||
|
||||
for (; rel_info < rel_info_end; ++rel_info)
|
||||
{
|
||||
|
@ -28,7 +28,8 @@ namespace
|
||||
const auto game_entry = game.get_iat_entry("steam_api64.dll", func);
|
||||
if (!game_entry)
|
||||
{
|
||||
throw std::runtime_error("Import '" + func + "' not found!");
|
||||
//throw std::runtime_error("Import '" + func + "' not found!");
|
||||
return {nullptr, nullptr};
|
||||
}
|
||||
|
||||
const auto original_import = game_entry;
|
||||
@ -183,12 +184,16 @@ namespace
|
||||
{
|
||||
remove_crash_file();
|
||||
|
||||
if (!component_loader::activate())
|
||||
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);
|
||||
|
||||
if (!component_loader::activate(has_server))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
entry_point = load_process("BlackOps3.exe");
|
||||
entry_point = load_process(has_server ? server_binary : client_binary);
|
||||
if (!entry_point)
|
||||
{
|
||||
throw std::runtime_error("Unable to load binary into memory");
|
||||
|
@ -3,51 +3,42 @@
|
||||
#include "nt.hpp"
|
||||
|
||||
#include <shellapi.h>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "finally.hpp"
|
||||
|
||||
namespace utils::flags
|
||||
{
|
||||
void parse_flags(std::vector<std::string>& flags)
|
||||
std::unordered_set<std::string> parse_flags()
|
||||
{
|
||||
int num_args;
|
||||
int num_args{};
|
||||
auto* const argv = CommandLineToArgvW(GetCommandLineW(), &num_args);
|
||||
|
||||
flags.clear();
|
||||
|
||||
if (argv)
|
||||
const auto _ = finally([&argv]
|
||||
{
|
||||
for (auto i = 0; i < num_args; ++i)
|
||||
if (argv)
|
||||
{
|
||||
std::wstring wide_flag(argv[i]);
|
||||
if (wide_flag[0] == L'-')
|
||||
{
|
||||
wide_flag.erase(wide_flag.begin());
|
||||
flags.emplace_back(string::convert(wide_flag));
|
||||
}
|
||||
LocalFree(argv);
|
||||
}
|
||||
});
|
||||
|
||||
LocalFree(argv);
|
||||
std::unordered_set<std::string> flags{};
|
||||
|
||||
for (auto i = 0; i < num_args && argv; ++i)
|
||||
{
|
||||
std::wstring wide_flag(argv[i]);
|
||||
if (wide_flag[0] == L'-')
|
||||
{
|
||||
wide_flag.erase(wide_flag.begin());
|
||||
flags.emplace(string::to_lower(string::convert(wide_flag)));
|
||||
}
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
bool has_flag(const std::string& flag)
|
||||
{
|
||||
static auto parsed = false;
|
||||
static std::vector<std::string> enabled_flags;
|
||||
|
||||
if (!parsed)
|
||||
{
|
||||
parse_flags(enabled_flags);
|
||||
parsed = true;
|
||||
}
|
||||
|
||||
for (const auto& entry : enabled_flags)
|
||||
{
|
||||
if (string::to_lower(entry) == string::to_lower(flag))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
static const auto enabled_flags = parse_flags();
|
||||
return enabled_flags.contains(string::to_lower(flag));
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user