fix hook compatability with plutonium

This commit is contained in:
6arelyFuture 2022-08-27 20:25:31 +02:00
parent 798e0e780c
commit 314a3424ea
Signed by: Future
GPG Key ID: FA77F074E98D98A5
12 changed files with 57 additions and 243 deletions

3
.gitmodules vendored
View File

@ -4,9 +4,6 @@
[submodule "deps/minhook"] [submodule "deps/minhook"]
path = deps/minhook path = deps/minhook
url = https://github.com/TsudaKageyu/minhook.git url = https://github.com/TsudaKageyu/minhook.git
[submodule "deps/rapidjson"]
path = deps/rapidjson
url = https://github.com/Tencent/rapidjson.git
[submodule "deps/asmjit"] [submodule "deps/asmjit"]
path = deps/asmjit path = deps/asmjit
url = https://github.com/asmjit/asmjit.git url = https://github.com/asmjit/asmjit.git

View File

@ -1,19 +0,0 @@
rapidjson = {
source = path.join(dependencies.basePath, "rapidjson"),
}
function rapidjson.import()
rapidjson.includes()
end
function rapidjson.includes()
includedirs {
path.join(rapidjson.source, "include"),
}
end
function rapidjson.project()
end
table.insert(dependencies, rapidjson)

1
deps/rapidjson vendored

@ -1 +0,0 @@
Subproject commit 27c3a8dc0e2c9218fe94986d249a12b5ed838f1d

View File

@ -1,46 +0,0 @@
#include <std_include.hpp>
#include "../loader/component_loader.hpp"
#include <utils/hook.hpp>
namespace ban {
namespace {
const game::dvar_t* sv_discord = nullptr;
const game::dvar_t* sv_clanWebsite = nullptr;
bool out_of_band_print_hk(game::netsrc_t src, game::netadr_s to,
const char* msg) {
// Proof of concept patch. Please ignore
if (msg != "error\nPATCH_BANNED_FROM_SERVER"s) {
return game::NET_OutOfBandPrint(src, to, msg);
}
const auto error_msg =
std::format("error\nPermanently banned\nDiscord: {}\nWebsite: {}",
sv_discord->current.string, sv_clanWebsite->current.string);
return game::NET_OutOfBandPrint(src, to, error_msg.data());
}
} // namespace
class component final : public component_interface {
public:
void post_unpack() override {
if (game::current == game::gamemode::zombies)
return;
sv_discord = game::Dvar_RegisterString(
"sv_discord", "https://www.discord.gg/", game::DVAR_ARCHIVE,
"Discord invitation link");
sv_clanWebsite =
game::Dvar_RegisterString("sv_clanWebsite", "https://www.google.com/",
game::DVAR_ARCHIVE, "Website link");
utils::hook::call(0x48B7E2, out_of_band_print_hk);
}
};
} // namespace ban
REGISTER_COMPONENT(ban::component)

View File

@ -1,98 +0,0 @@
#include <std_include.hpp>
#include "../loader/component_loader.hpp"
#include <utils/hook.hpp>
#include <utils/io.hpp>
namespace bots {
namespace {
using bot_entry = std::pair<std::string, std::string>;
std::vector<bot_entry> bot_names;
utils::hook::detour sv_bot_name_random_hook;
// Json file is expected to contain a key for the bot's name. Value should be a
// string for the clantag
void load_bot_data() {
if (!utils::io::file_exists("bots/bots.json")) {
game::Com_Printf(game::CON_CHANNEL_SERVER, "bots.json was not found\n");
return;
}
rapidjson::Document obj;
const rapidjson::ParseResult result =
obj.Parse(utils::io::read_file("bots/bots.json").data());
if (!result || !obj.IsObject()) {
game::Com_Printf(game::CON_CHANNEL_SERVER,
"Failed to parse ban file. Empty?\n");
return;
}
for (rapidjson::Value::ConstMemberIterator itr = obj.MemberBegin();
itr != obj.MemberEnd(); ++itr) {
if (itr->value.GetType() == rapidjson::Type::kStringType) {
bot_names.emplace_back(
std::make_pair(itr->name.GetString(), itr->value.GetString()));
}
}
}
const char* sv_bot_name_random_stub() {
static auto loaded = false;
if (bot_names.empty() && !loaded) {
load_bot_data();
loaded = true;
}
if (!bot_names.empty()) {
static std::size_t bot_id = 0;
bot_id %= bot_names.size();
const auto& entry = bot_names.at(bot_id++);
return entry.first.data();
}
return sv_bot_name_random_hook.invoke<const char*>();
}
int build_connect_string(char* buf, const char* connect_string,
const char* name, const char* bd_online_user_id,
int protocol, int qport) {
// Default
auto clan_tag = "3arc"s;
for (const auto& [bot_name, tag] : bot_names) {
if (bot_name == name) {
// Found their clantag
clan_tag = tag;
break;
}
}
return _snprintf_s(buf, 0x400, _TRUNCATE, connect_string, name,
clan_tag.data(), bd_online_user_id, protocol, qport);
}
} // namespace
class component final : public component_interface {
public:
void post_unpack() override {
if (game::current == game::gamemode::zombies)
return;
// Add custom clantag
utils::hook::set<const char*>(
0x6B6294,
"connect "
"\"\\cg_predictItems\\1\\cl_punkbuster\\0\\cl_"
"anonymous\\0\\color\\4\\head\\default\\"
" model\\multi\\snaps\\20\\rate\\5000\\name\\%s\\clanAbbrev\\%"
"s\\bdOnlineUserID\\%s\\protocol\\%d\\qport\\%d\"");
sv_bot_name_random_hook.create(0x49ED80, &sv_bot_name_random_stub);
utils::hook::call(0x6B6299, build_connect_string);
}
};
} // namespace bots
REGISTER_COMPONENT(bots::component)

View File

@ -1,41 +1,36 @@
#include <std_include.hpp> #include <std_include.hpp>
#include "../loader/component_loader.hpp" #include "../loader/component_loader.hpp"
#include <utils/hook.hpp> #include <utils/hook.hpp>
#include <utils/string.hpp> #include <utils/string.hpp>
#include <utils/concurrency.hpp>
#include "command.hpp" #include "command.hpp"
namespace chat { namespace chat {
namespace { namespace {
std::mutex chat_mutex; utils::hook::detour client_command_hook;
std::unordered_set<std::uint64_t> mute_list{};
using client_list = std::unordered_set<std::uint64_t>;
utils::concurrency::container<client_list> mute_list;
void mute_player(const game::client_s* client) { void mute_player(const game::client_s* client) {
std::unique_lock<std::mutex> _(chat_mutex); const auto xuid = client->xuid;
mute_list.access([&](client_list& clients) { clients.insert(xuid); });
if (mute_list.contains(client->xuid)) {
game::SV_GameSendServerCommand(
-1, game::SV_CMD_CAN_IGNORE,
utils::string::va("%c \"%s is already muted\"", 0x65, client->name));
return;
}
mute_list.insert(client->xuid);
} }
void unmute_player(const game::client_s* client) { void unmute_player(const game::client_s* client) {
std::unique_lock<std::mutex> _(chat_mutex);
mute_list.erase(client->xuid); const auto xuid = client->xuid;
mute_list.access([&](client_list& clients) { clients.erase(xuid); });
game::SV_GameSendServerCommand( game::SV_GameSendServerCommand(
client->gentity->entnum, game::SV_CMD_CAN_IGNORE, client->gentity->entnum, game::SV_CMD_CAN_IGNORE,
utils::string::va("%c \"You were unmuted\"", 0x65)); utils::string::va("%c \"You were unmuted\"", 0x65));
} }
void client_command(int client_number) { void client_command_stub(const int client_number) {
char buf[1024] = {0}; char buf[1024]{};
if (game::g_entities[client_number].client == nullptr) { if (game::g_entities[client_number].client == nullptr) {
// Not in game // Not in game
@ -44,30 +39,36 @@ void client_command(int client_number) {
game::SV_Cmd_ArgvBuffer(0, buf, sizeof(buf)); game::SV_Cmd_ArgvBuffer(0, buf, sizeof(buf));
std::unique_lock<std::mutex> _(chat_mutex); if (utils::string::starts_with(buf, "say")) {
if (utils::string::starts_with(buf, "say") && const auto is_muted =
mute_list.contains(game::svs_clients[client_number].xuid)) { mute_list.access<bool>([&](const client_list& clients) {
return clients.contains(game::svs_clients[client_number].xuid);
});
if (is_muted) {
game::SV_GameSendServerCommand( game::SV_GameSendServerCommand(
client_number, game::SV_CMD_CAN_IGNORE, client_number, game::SV_CMD_CAN_IGNORE,
utils::string::va("%c \"You are muted\"", 0x65)); utils::string::va("%c \"You are muted\"", 0x65));
return; return;
} }
}
game::ClientCommand(client_number); client_command_hook.invoke<void>(client_number);
} }
} // namespace } // namespace
class component final : public component_interface { class component final : public component_interface {
public: public:
void post_unpack() override { void post_unpack() override {
utils::hook::call(SELECT_VALUE(0x58DA1C, 0x4FB3BD), client_command); client_command_hook.create(SELECT_VALUE(0x63DB70, 0x4AF770),
client_command_stub);
add_chat_commands(); add_chat_commands();
} }
private: private:
static void add_chat_commands() { static void add_chat_commands() {
command::add("sayAs", [](const command::params& params) { command::add("sayAs", [](const command::params_sv& params) {
if (params.size() < 3) { if (params.size() < 3) {
game::Com_Printf(game::CON_CHANNEL_DONT_FILTER, game::Com_Printf(game::CON_CHANNEL_DONT_FILTER,
"Usage: sayAs <client number> <message>\n"); "Usage: sayAs <client number> <message>\n");
@ -89,7 +90,7 @@ private:
game::G_Say(gentity, nullptr, 0, message.data()); game::G_Say(gentity, nullptr, 0, message.data());
}); });
command::add("mutePlayer", [](const command::params& params) { command::add("mutePlayer", [](const command::params_sv& params) {
if (params.size() < 2) { if (params.size() < 2) {
game::Com_Printf(game::CON_CHANNEL_DONT_FILTER, game::Com_Printf(game::CON_CHANNEL_DONT_FILTER,
"Usage: mutePlayer <client number>\n"); "Usage: mutePlayer <client number>\n");
@ -109,7 +110,7 @@ private:
mute_player(client); mute_player(client);
}); });
command::add("unmutePlayer", [](const command::params& params) { command::add("unmutePlayer", [](const command::params_sv& params) {
if (params.size() < 2) { if (params.size() < 2) {
game::Com_Printf(game::CON_CHANNEL_DONT_FILTER, game::Com_Printf(game::CON_CHANNEL_DONT_FILTER,
"Usage: unmutePlayer <client number>\n"); "Usage: unmutePlayer <client number>\n");

View File

@ -1,5 +1,4 @@
#include <std_include.hpp> #include <std_include.hpp>
#include "../loader/component_loader.hpp" #include "../loader/component_loader.hpp"
#include <utils/string.hpp> #include <utils/string.hpp>
@ -10,11 +9,11 @@
constexpr auto CMD_MAX_NESTING = 8; constexpr auto CMD_MAX_NESTING = 8;
namespace command { namespace command {
std::unordered_map<std::string, std::function<void(params&)>> handlers; std::unordered_map<std::string, std::function<void(const params_sv&)>> handlers;
namespace { namespace {
void cmd_vstr_f() { void cmd_vstr_f() {
const params params; const params_sv params;
if (params.size() < 2) { if (params.size() < 2) {
game::Com_Printf(game::CON_CHANNEL_DONT_FILTER, game::Com_Printf(game::CON_CHANNEL_DONT_FILTER,
@ -43,7 +42,7 @@ void cmd_vstr_f() {
} // namespace } // namespace
void main_handler() { void main_handler() {
params params = {}; params_sv params = {};
const auto command = utils::string::to_lower(params[0]); const auto command = utils::string::to_lower(params[0]);
@ -52,13 +51,13 @@ void main_handler() {
} }
} }
params::params() : nesting_(game::sv_cmd_args->nesting) { params_sv::params_sv() : nesting_(game::sv_cmd_args->nesting) {
assert(game::sv_cmd_args->nesting < CMD_MAX_NESTING); assert(game::sv_cmd_args->nesting < CMD_MAX_NESTING);
} }
int params::size() const { return game::sv_cmd_args->argc[this->nesting_]; } int params_sv::size() const { return game::sv_cmd_args->argc[this->nesting_]; }
const char* params::get(const int index) const { const char* params_sv::get(const int index) const {
if (index >= this->size()) { if (index >= this->size()) {
return ""; return "";
} }
@ -66,10 +65,10 @@ const char* params::get(const int index) const {
return game::sv_cmd_args->argv[this->nesting_][index]; return game::sv_cmd_args->argv[this->nesting_][index];
} }
std::string params::join(const int index) const { std::string params_sv::join(const int index) const {
std::string result = {}; std::string result = {};
for (auto i = index; i < this->size(); i++) { for (auto i = index; i < this->size(); ++i) {
if (i > index) if (i > index)
result.append(" "); result.append(" ");
result.append(this->get(i)); result.append(this->get(i));
@ -83,7 +82,8 @@ void add_raw(const char* name, void (*callback)()) {
utils::memory::get_allocator()->allocate<game::cmd_function_s>()); utils::memory::get_allocator()->allocate<game::cmd_function_s>());
} }
void add(const char* name, const std::function<void(const params&)>& callback) { void add(const char* name,
const std::function<void(const params_sv&)>& callback) {
const auto command = utils::string::to_lower(name); const auto command = utils::string::to_lower(name);
if (!handlers.contains(command)) { if (!handlers.contains(command)) {
@ -109,9 +109,10 @@ public:
private: private:
static void add_commands_generic() { static void add_commands_generic() {
add("properQuit", [](const params&) { utils::nt::raise_hard_exception(); }); add("properQuit",
[](const params_sv&) { utils::nt::raise_hard_exception(); });
add("echo", [](const params& params) { add("echo", [](const params_sv& params) {
for (auto i = 1; i < params.size(); i++) { for (auto i = 1; i < params.size(); i++) {
game::Com_Printf(game::CON_CHANNEL_DONT_FILTER, "%s ", params.get(i)); game::Com_Printf(game::CON_CHANNEL_DONT_FILTER, "%s ", params.get(i));
} }

View File

@ -1,13 +1,14 @@
#pragma once #pragma once
namespace command { namespace command {
class params {
public:
params();
int size() const; class params_sv {
const char* get(int index) const; public:
std::string join(int index) const; params_sv();
[[nodiscard]] int size() const;
[[nodiscard]] const char* get(int index) const;
[[nodiscard]] std::string join(int index) const;
const char* operator[](const int index) const { return this->get(index); } const char* operator[](const int index) const { return this->get(index); }
@ -16,7 +17,8 @@ private:
}; };
void add_raw(const char* name, void (*callback)()); void add_raw(const char* name, void (*callback)());
void add(const char* name, const std::function<void(const params&)>& callback); void add(const char* name,
const std::function<void(const params_sv&)>& callback);
void execute(std::string command, bool sync = false); void execute(std::string command, bool sync = false);
} // namespace command } // namespace command

View File

@ -1,6 +1,6 @@
#include <std_include.hpp> #include <std_include.hpp>
#include "../loader/component_loader.hpp" #include "../loader/component_loader.hpp"
#include <utils/hook.hpp> #include <utils/hook.hpp>
namespace gameplay { namespace gameplay {

View File

@ -1,21 +0,0 @@
#include <std_include.hpp>
#include "../loader/component_loader.hpp"
#include <utils/hook.hpp>
namespace gsc_patches {
namespace {
void g_log_printf(const char* fmt) { game::G_LogPrintf("%s", fmt); }
} // namespace
class component final : public component_interface {
public:
void post_unpack() override {
if (game::environment::is_mp()) {
utils::hook::call(0x8426D3, g_log_printf);
}
}
};
} // namespace gsc_patches
REGISTER_COMPONENT(gsc_patches::component)

View File

@ -49,8 +49,9 @@ WEAK symbol<const dvar_s*(const char*, int, int, int, unsigned __int16,
const char*)> const char*)>
Dvar_RegisterInt{0x58D900, 0x651910}; Dvar_RegisterInt{0x58D900, 0x651910};
WEAK symbol<void(const char*, void(), cmd_function_s*)> Cmd_AddCommandInternal{ WEAK symbol<void(const char* cmdName, void (*function)(),
0x6AD580, 0x661400}; cmd_function_s* allocedCmd)>
Cmd_AddCommandInternal{0x6AD580, 0x661400};
WEAK symbol<void(const char* cmdName)> Cmd_RemoveCommand{0x527EA0, 0x5F1A90}; WEAK symbol<void(const char* cmdName)> Cmd_RemoveCommand{0x527EA0, 0x5F1A90};
WEAK symbol<cmd_function_s*(const char*)> Cmd_FindCommand{0x445B60, 0x479DD0}; WEAK symbol<cmd_function_s*(const char*)> Cmd_FindCommand{0x445B60, 0x479DD0};
@ -71,6 +72,7 @@ WEAK symbol<void(const float*, scriptInstance_t)> Scr_AddVector{0x532EF0, 0x0};
WEAK symbol<int(const playerState_s*)> PM_GetEffectiveStance{0x659590, 0x0}; WEAK symbol<int(const playerState_s*)> PM_GetEffectiveStance{0x659590, 0x0};
WEAK symbol<CmdArgs> sv_cmd_args{0x355BD88, 0x243D208}; WEAK symbol<CmdArgs> sv_cmd_args{0x355BD88, 0x243D208};
WEAK symbol<int> dvarCount{0x385BE74, 0x261CBD4}; WEAK symbol<int> dvarCount{0x385BE74, 0x261CBD4};
WEAK symbol<dvar_t*> sortedDvars{0x385BE88, 0x261CBE8}; WEAK symbol<dvar_t*> sortedDvars{0x385BE88, 0x261CBE8};
WEAK symbol<client_s> svs_clients{0x372D11C, 0x286D01C}; WEAK symbol<client_s> svs_clients{0x372D11C, 0x286D01C};

View File

@ -18,10 +18,6 @@
#pragma warning(disable : 26812) #pragma warning(disable : 26812)
#include <rapidjson/document.h>
#include <rapidjson/prettywriter.h>
#include <rapidjson/stringbuffer.h>
#pragma comment(lib, "ntdll.lib") #pragma comment(lib, "ntdll.lib")
using namespace std::literals; using namespace std::literals;