mirror of
https://github.com/diamante0018/BlackOpsPlugin.git
synced 2025-07-05 10:41:48 +00:00
Fix crash
This commit is contained in:
46
src/client/component/ban.cpp
Normal file
46
src/client/component/ban.cpp
Normal file
@ -0,0 +1,46 @@
|
||||
#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)
|
96
src/client/component/bots.cpp
Normal file
96
src/client/component/bots.cpp
Normal file
@ -0,0 +1,96 @@
|
||||
#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() {
|
||||
const auto* path = game::Dvar_FindVar("fs_homepath")->current.string;
|
||||
std::filesystem::current_path(path);
|
||||
|
||||
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() {
|
||||
if (bot_names.empty()) {
|
||||
load_bot_data();
|
||||
}
|
||||
|
||||
if (!bot_names.empty()) {
|
||||
static 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* xuid, int protocol,
|
||||
int port) {
|
||||
// Default
|
||||
auto clan_tag = "3arc"s;
|
||||
for (const auto& [bot_name, tag] : bot_names) {
|
||||
if (bot_name == name) {
|
||||
clan_tag = tag;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return _snprintf_s(buf, 0x400, _TRUNCATE, connect_string, name,
|
||||
clan_tag.data(), xuid, protocol, port);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
class component final : public component_interface {
|
||||
public:
|
||||
void post_unpack() override {
|
||||
if (game::current == game::gamemode::zombies)
|
||||
return;
|
||||
|
||||
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)
|
135
src/client/component/chat.cpp
Normal file
135
src/client/component/chat.cpp
Normal file
@ -0,0 +1,135 @@
|
||||
#include <std_include.hpp>
|
||||
|
||||
#include "../loader/component_loader.hpp"
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/string.hpp>
|
||||
|
||||
#include "command.hpp"
|
||||
|
||||
namespace chat {
|
||||
namespace {
|
||||
std::mutex chat_mutex;
|
||||
std::unordered_set<std::uint64_t> mute_list{};
|
||||
|
||||
void mute_player(const game::client_s* client) {
|
||||
std::unique_lock<std::mutex> _(chat_mutex);
|
||||
|
||||
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) {
|
||||
std::unique_lock<std::mutex> _(chat_mutex);
|
||||
|
||||
mute_list.erase(client->xuid);
|
||||
|
||||
game::SV_GameSendServerCommand(
|
||||
client->gentity->entnum, game::SV_CMD_CAN_IGNORE,
|
||||
utils::string::va("%c \"You were unmuted\"", 0x65));
|
||||
}
|
||||
|
||||
void client_command(int client_number) {
|
||||
char buf[1024] = {0};
|
||||
|
||||
if (game::g_entities[client_number].client == nullptr) {
|
||||
// Not in game
|
||||
return;
|
||||
}
|
||||
|
||||
game::SV_Cmd_ArgvBuffer(0, buf, sizeof(buf));
|
||||
|
||||
std::unique_lock<std::mutex> _(chat_mutex);
|
||||
if (utils::string::starts_with(buf, "say") &&
|
||||
mute_list.contains(game::svs_clients[client_number].xuid)) {
|
||||
game::SV_GameSendServerCommand(
|
||||
client_number, game::SV_CMD_CAN_IGNORE,
|
||||
utils::string::va("%c \"You are muted\"", 0x65));
|
||||
return;
|
||||
}
|
||||
|
||||
game::ClientCommand(client_number);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
class component final : public component_interface {
|
||||
public:
|
||||
void post_unpack() override {
|
||||
utils::hook::call(SELECT(0x58DA1C, 0x4FB3BD), client_command);
|
||||
|
||||
add_chat_commands();
|
||||
}
|
||||
|
||||
private:
|
||||
static void add_chat_commands() {
|
||||
command::add("sayAs", [](const command::params& params) {
|
||||
if (params.size() < 3) {
|
||||
game::Com_Printf(game::CON_CHANNEL_DONT_FILTER,
|
||||
"Usage: sayAs <client number> <message>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto* client = game::SV_GetPlayerByNum();
|
||||
|
||||
if (client == nullptr)
|
||||
return;
|
||||
|
||||
auto* const gentity = client->gentity;
|
||||
assert(gentity != nullptr);
|
||||
|
||||
if (gentity->client == nullptr)
|
||||
return;
|
||||
|
||||
const auto message = params.join(2);
|
||||
game::G_Say(gentity, nullptr, 0, message.data());
|
||||
});
|
||||
|
||||
command::add("mutePlayer", [](const command::params& params) {
|
||||
if (params.size() < 2) {
|
||||
game::Com_Printf(game::CON_CHANNEL_DONT_FILTER,
|
||||
"Usage: mutePlayer <client number>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto* client = game::SV_GetPlayerByNum();
|
||||
|
||||
if (client == nullptr)
|
||||
return;
|
||||
|
||||
assert(client->gentity != nullptr);
|
||||
|
||||
if (client->gentity->client == nullptr)
|
||||
return;
|
||||
|
||||
mute_player(client);
|
||||
});
|
||||
|
||||
command::add("unmutePlayer", [](const command::params& params) {
|
||||
if (params.size() < 2) {
|
||||
game::Com_Printf(game::CON_CHANNEL_DONT_FILTER,
|
||||
"Usage: unmutePlayer <client number>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto* client = game::SV_GetPlayerByNum();
|
||||
|
||||
if (client == nullptr)
|
||||
return;
|
||||
|
||||
assert(client->gentity != nullptr);
|
||||
|
||||
if (client->gentity->client == nullptr)
|
||||
return;
|
||||
|
||||
unmute_player(client);
|
||||
});
|
||||
}
|
||||
};
|
||||
} // namespace chat
|
||||
|
||||
REGISTER_COMPONENT(chat::component)
|
125
src/client/component/command.cpp
Normal file
125
src/client/component/command.cpp
Normal file
@ -0,0 +1,125 @@
|
||||
#include <std_include.hpp>
|
||||
|
||||
#include "../loader/component_loader.hpp"
|
||||
|
||||
#include <utils/string.hpp>
|
||||
#include <utils/nt.hpp>
|
||||
|
||||
#include "command.hpp"
|
||||
|
||||
constexpr auto CMD_MAX_NESTING = 8;
|
||||
|
||||
namespace command {
|
||||
std::unordered_map<std::string, std::function<void(params&)>> handlers;
|
||||
|
||||
namespace {
|
||||
void cmd_vstr_f(const params& params) {
|
||||
if (params.size() < 2) {
|
||||
game::Com_Printf(game::CON_CHANNEL_DONT_FILTER,
|
||||
"vstr <variablename> : execute a variable command\n");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto* dvar_name = params.get(1);
|
||||
const auto* dvar = game::Dvar_FindVar(dvar_name);
|
||||
|
||||
if (dvar == nullptr) {
|
||||
game::Com_Printf(game::CON_CHANNEL_DONT_FILTER, "%s doesn't exist\n",
|
||||
dvar_name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dvar->type == game::DVAR_TYPE_STRING ||
|
||||
dvar->type == game::DVAR_TYPE_ENUM) {
|
||||
execute(dvar->current.string);
|
||||
} else {
|
||||
game::Com_Printf(game::CON_CHANNEL_DONT_FILTER,
|
||||
"%s is not a string-based dvar\n", dvar->name);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void main_handler() {
|
||||
params params = {};
|
||||
|
||||
const auto command = utils::string::to_lower(params[0]);
|
||||
|
||||
if (const auto got = handlers.find(command); got != handlers.end()) {
|
||||
got->second(params);
|
||||
}
|
||||
}
|
||||
|
||||
params::params() : nesting_(game::sv_cmd_args->nesting) {
|
||||
assert(game::sv_cmd_args->nesting < CMD_MAX_NESTING);
|
||||
}
|
||||
|
||||
int params::size() const { return game::sv_cmd_args->argc[this->nesting_]; }
|
||||
|
||||
const char* params::get(const int index) const {
|
||||
if (index >= this->size()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return game::sv_cmd_args->argv[this->nesting_][index];
|
||||
}
|
||||
|
||||
std::string params::join(const int index) const {
|
||||
std::string result = {};
|
||||
|
||||
for (auto i = index; i < this->size(); i++) {
|
||||
if (i > index)
|
||||
result.append(" ");
|
||||
result.append(this->get(i));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void add_raw(const char* name, void (*callback)()) {
|
||||
game::Cmd_AddCommandInternal(
|
||||
name, callback,
|
||||
utils::memory::get_allocator()->allocate<game::cmd_function_t>());
|
||||
}
|
||||
|
||||
void add(const char* name, const std::function<void(const params&)>& callback) {
|
||||
const auto command = utils::string::to_lower(name);
|
||||
|
||||
if (!handlers.contains(command)) {
|
||||
add_raw(name, main_handler);
|
||||
}
|
||||
|
||||
handlers[command] = callback;
|
||||
}
|
||||
|
||||
void execute(std::string command, const bool sync) {
|
||||
command += "\n";
|
||||
|
||||
if (sync) {
|
||||
game::Cmd_ExecuteSingleCommand(game::LOCAL_CLIENT_0, 0, command.data());
|
||||
} else {
|
||||
game::Cbuf_AddText(game::LOCAL_CLIENT_0, command.data());
|
||||
}
|
||||
}
|
||||
|
||||
class component final : public component_interface {
|
||||
public:
|
||||
void post_unpack() override { add_commands_generic(); }
|
||||
|
||||
private:
|
||||
static void add_commands_generic() {
|
||||
add("properQuit", [](const params&) { utils::nt::raise_hard_exception(); });
|
||||
|
||||
add("echo", [](const params& params) {
|
||||
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, "\n");
|
||||
});
|
||||
|
||||
game::Cmd_RemoveCommand("vstr");
|
||||
add("vstr", cmd_vstr_f);
|
||||
}
|
||||
};
|
||||
} // namespace command
|
||||
|
||||
REGISTER_COMPONENT(command::component)
|
22
src/client/component/command.hpp
Normal file
22
src/client/component/command.hpp
Normal file
@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
namespace command {
|
||||
class params {
|
||||
public:
|
||||
params();
|
||||
|
||||
int size() const;
|
||||
const char* get(int index) const;
|
||||
std::string join(int index) const;
|
||||
|
||||
const char* operator[](const int index) const { return this->get(index); }
|
||||
|
||||
private:
|
||||
int nesting_;
|
||||
};
|
||||
|
||||
void add_raw(const char* name, void (*callback)());
|
||||
void add(const char* name, const std::function<void(const params&)>& callback);
|
||||
|
||||
void execute(std::string command, bool sync = false);
|
||||
} // namespace command
|
30
src/client/component/gameplay.cpp
Normal file
30
src/client/component/gameplay.cpp
Normal file
@ -0,0 +1,30 @@
|
||||
#include <std_include.hpp>
|
||||
|
||||
#include "../loader/component_loader.hpp"
|
||||
#include <utils/hook.hpp>
|
||||
|
||||
namespace gameplay {
|
||||
namespace {
|
||||
game::dvar_s** player_sustainAmmo = nullptr;
|
||||
|
||||
utils::hook::detour pm_weapon_use_ammo_hook;
|
||||
|
||||
void pm_weapon_use_ammo_stub(void* ps, int wp, int amount) {
|
||||
if (!(*player_sustainAmmo)->current.enabled) {
|
||||
pm_weapon_use_ammo_hook.invoke<void>(ps, wp, amount);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
class component final : public component_interface {
|
||||
public:
|
||||
void post_unpack() override {
|
||||
if (game::environment::t5zm()) {
|
||||
player_sustainAmmo = reinterpret_cast<game::dvar_s**>(0xBCD250);
|
||||
pm_weapon_use_ammo_hook.create(0x6979B0, &pm_weapon_use_ammo_stub);
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace gameplay
|
||||
|
||||
REGISTER_COMPONENT(gameplay::component)
|
13
src/client/dllmain.cpp
Normal file
13
src/client/dllmain.cpp
Normal file
@ -0,0 +1,13 @@
|
||||
#include "std_include.hpp"
|
||||
#include "loader/component_loader.hpp"
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE /*module_*/, DWORD ul_reason_for_call,
|
||||
LPVOID /*reserved_*/) {
|
||||
if (ul_reason_for_call == DLL_PROCESS_ATTACH) {
|
||||
component_loader::post_unpack();
|
||||
} else if (ul_reason_for_call == DLL_PROCESS_DETACH) {
|
||||
component_loader::pre_destroy();
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
13
src/client/game/game.cpp
Normal file
13
src/client/game/game.cpp
Normal file
@ -0,0 +1,13 @@
|
||||
#include <std_include.hpp>
|
||||
|
||||
namespace game {
|
||||
gamemode current = reinterpret_cast<const char*>(0xA6840C) == "multiplayer"s
|
||||
? gamemode::multiplayer
|
||||
: gamemode::zombies;
|
||||
|
||||
namespace environment {
|
||||
bool t5mp() { return current == gamemode::multiplayer; }
|
||||
|
||||
bool t5zm() { return current == gamemode::zombies; }
|
||||
} // namespace environment
|
||||
} // namespace game
|
40
src/client/game/game.hpp
Normal file
40
src/client/game/game.hpp
Normal file
@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#define SELECT(mp, zm) (game::environment::t5mp() ? mp : zm)
|
||||
|
||||
namespace game {
|
||||
enum gamemode { none, multiplayer, zombies };
|
||||
|
||||
extern gamemode current;
|
||||
|
||||
namespace environment {
|
||||
bool t5mp();
|
||||
bool t5zm();
|
||||
} // namespace environment
|
||||
|
||||
template <typename T> class symbol {
|
||||
public:
|
||||
symbol(const size_t t5mp, const size_t t5zm)
|
||||
: t5mp_(reinterpret_cast<T*>(t5mp)), t5zm_(reinterpret_cast<T*>(t5zm)) {}
|
||||
|
||||
T* get() const {
|
||||
if (environment::t5mp()) {
|
||||
|
||||
return t5mp_;
|
||||
}
|
||||
|
||||
return t5zm_;
|
||||
}
|
||||
|
||||
operator T*() const { return this->get(); }
|
||||
|
||||
T* operator->() const { return this->get(); }
|
||||
|
||||
private:
|
||||
T* t5mp_;
|
||||
T* t5zm_;
|
||||
};
|
||||
|
||||
} // namespace game
|
||||
|
||||
#include "symbols.hpp"
|
498
src/client/game/structs.hpp
Normal file
498
src/client/game/structs.hpp
Normal file
@ -0,0 +1,498 @@
|
||||
#pragma once
|
||||
|
||||
namespace game {
|
||||
typedef float vec_t;
|
||||
typedef vec_t vec2_t[2];
|
||||
typedef vec_t vec3_t[3];
|
||||
typedef vec_t vec4_t[4];
|
||||
|
||||
enum FsListBehavior_e { FS_LIST_PURE_ONLY = 0x0, FS_LIST_ALL = 0x1 };
|
||||
|
||||
enum svscmd_type { SV_CMD_CAN_IGNORE, SV_CMD_RELIABLE };
|
||||
|
||||
typedef enum {
|
||||
ERR_FATAL = 0x0,
|
||||
ERR_DROP = 0x1,
|
||||
ERR_SERVERDISCONNECT = 0x2,
|
||||
ERR_DISCONNECT = 0x3,
|
||||
ERR_SCRIPT = 0x4,
|
||||
ERR_SCRIPT_DROP = 0x5,
|
||||
ERR_LOCALIZATION = 0x6
|
||||
} errorParm_t;
|
||||
|
||||
typedef enum {
|
||||
LOCAL_CLIENT_INVALID = -1,
|
||||
LOCAL_CLIENT_0 = 0,
|
||||
LOCAL_CLIENT_1 = 1,
|
||||
LOCAL_CLIENT_2 = 2,
|
||||
LOCAL_CLIENT_3 = 3,
|
||||
LOCAL_CLIENT_LAST = 3,
|
||||
LOCAL_CLIENT_COUNT = 4
|
||||
} LocalClientNum_t;
|
||||
|
||||
typedef enum {
|
||||
CON_CHANNEL_DONT_FILTER = 0x0,
|
||||
CON_CHANNEL_ERROR = 0x1,
|
||||
CON_CHANNEL_GAMENOTIFY = 0x2,
|
||||
CON_CHANNEL_BOLDGAME = 0x3,
|
||||
CON_CHANNEL_SUBTITLE = 0x4,
|
||||
CON_CHANNEL_OBITUARY = 0x5,
|
||||
CON_CHANNEL_LOGFILEONLY = 0x6,
|
||||
CON_CHANNEL_CONSOLEONLY = 0x7,
|
||||
CON_CHANNEL_GFX = 0x8,
|
||||
CON_CHANNEL_SOUND = 0x9,
|
||||
CON_CHANNEL_FILES = 0xA,
|
||||
CON_CHANNEL_DEVGUI = 0xB,
|
||||
CON_CHANNEL_PROFILE = 0xC,
|
||||
CON_CHANNEL_UI = 0xD,
|
||||
CON_CHANNEL_CLIENT = 0xE,
|
||||
CON_CHANNEL_SERVER = 0xF,
|
||||
CON_CHANNEL_SYSTEM = 0x10,
|
||||
CON_CHANNEL_PLAYERWEAP = 0x11,
|
||||
CON_CHANNEL_AI = 0x12,
|
||||
CON_CHANNEL_ANIM = 0x13,
|
||||
CON_CHANNEL_PHYS = 0x14,
|
||||
CON_CHANNEL_FX = 0x15,
|
||||
CON_CHANNEL_LEADERBOARDS = 0x16,
|
||||
CON_CHANNEL_LIVE = 0x17,
|
||||
CON_CHANNEL_PARSERSCRIPT = 0x18,
|
||||
CON_CHANNEL_SCRIPT = 0x19,
|
||||
CON_CHANNEL_SPAWNSYSTEM = 0x1A,
|
||||
CON_CHANNEL_COOPINFO = 0x1B,
|
||||
CON_CHANNEL_SERVERDEMO = 0x1C,
|
||||
CON_CHANNEL_DDL = 0x1D,
|
||||
CON_CHANNEL_NETWORK = 0x1E,
|
||||
CON_CHANNEL_SCHEDULER = 0x1F,
|
||||
CON_FIRST_DEBUG_CHANNEL = 0x1F,
|
||||
CON_CHANNEL_TASK = 0x20,
|
||||
CON_CHANNEL_SPU = 0x21,
|
||||
CON_BUILTIN_CHANNEL_COUNT = 0x22
|
||||
} conChannel_t;
|
||||
|
||||
typedef enum {
|
||||
CON_DEST_CONSOLE = 0,
|
||||
CON_DEST_MINICON = 1,
|
||||
CON_DEST_ERROR = 2,
|
||||
CON_DEST_GAME_FIRST = 3,
|
||||
CON_DEST_GAME1 = 3,
|
||||
CON_DEST_GAME2 = 4,
|
||||
CON_DEST_GAME3 = 5,
|
||||
CON_DEST_GAME_LAST = 5,
|
||||
CON_DEST_COUNT = 6
|
||||
} print_msg_dest_t;
|
||||
|
||||
typedef enum {
|
||||
NS_CLIENT1 = 0x0,
|
||||
NS_SERVER = 0x1,
|
||||
NS_MAXCLIENTS = 0x1,
|
||||
NS_PACKET = 0x2
|
||||
} netsrc_t;
|
||||
|
||||
typedef enum { CS_MOTD = 11, CS_TIMESCALE = 14 } ConfigString;
|
||||
|
||||
typedef enum {
|
||||
FS_READ = 0,
|
||||
FS_WRITE = 1,
|
||||
FS_APPEND = 2,
|
||||
FS_APPEND_SYNC = 3
|
||||
} fsMode_t;
|
||||
|
||||
struct PrintChannel {
|
||||
char name[32];
|
||||
bool allowScript;
|
||||
};
|
||||
|
||||
static_assert(sizeof(PrintChannel) == 33);
|
||||
|
||||
struct PrintChannelGlob {
|
||||
PrintChannel openChannels[256];
|
||||
unsigned int filters[6][8];
|
||||
};
|
||||
|
||||
struct usercmd_s {
|
||||
int serverTime;
|
||||
int button_bits[2];
|
||||
int angles[3];
|
||||
unsigned __int16 weapon;
|
||||
unsigned __int16 offHandIndex;
|
||||
unsigned __int16 lastWeaponAltModeSwitch;
|
||||
char forwardmove;
|
||||
char rightmove;
|
||||
char upmove;
|
||||
char pitchmove;
|
||||
char yawmove;
|
||||
float meleeChargeYaw;
|
||||
unsigned char meleeChargeDist;
|
||||
float rollmove;
|
||||
char selectedLocation[2];
|
||||
unsigned char selectedYaw;
|
||||
};
|
||||
|
||||
static_assert(sizeof(usercmd_s) == 52);
|
||||
|
||||
struct cmd_function_t {
|
||||
cmd_function_t* next;
|
||||
const char* name;
|
||||
const char* autoCompleteDir;
|
||||
const char* autoCompleteExt;
|
||||
void(__cdecl* function)();
|
||||
bool consoleAccess;
|
||||
};
|
||||
|
||||
static_assert(sizeof(cmd_function_t) == 24);
|
||||
|
||||
struct CmdArgs {
|
||||
int nesting;
|
||||
int localClientNum[8];
|
||||
int controllerIndex[8];
|
||||
void* itemDef[8];
|
||||
int argshift[8];
|
||||
int argc[8];
|
||||
const char** argv[8];
|
||||
char textPool[8192];
|
||||
const char* argvPool[512];
|
||||
int usedTextPool[8];
|
||||
int totalUsedArgvPool;
|
||||
int totalUsedTextPool;
|
||||
};
|
||||
|
||||
static_assert(sizeof(CmdArgs) == 10476);
|
||||
|
||||
typedef enum {
|
||||
NA_BOT = 0x0,
|
||||
NA_BAD = 0x1,
|
||||
NA_LOOPBACK = 0x2,
|
||||
NA_BROADCAST = 0x3,
|
||||
NA_IP = 0x4
|
||||
} netadrtype_t;
|
||||
|
||||
struct netadr_s // Confirm nigga
|
||||
{
|
||||
netadrtype_t type;
|
||||
unsigned char ip[4];
|
||||
unsigned __int16 port;
|
||||
int addrHandleIndex;
|
||||
};
|
||||
|
||||
static_assert(sizeof(netadr_s) == 16);
|
||||
|
||||
struct msg_t {
|
||||
int overflowed;
|
||||
int readOnly;
|
||||
unsigned char* data;
|
||||
unsigned char* splitData;
|
||||
int maxsize;
|
||||
int cursize;
|
||||
int splitSize;
|
||||
int readcount;
|
||||
int bit;
|
||||
int lastEntityRef;
|
||||
int flush;
|
||||
netsrc_t targetLocalNetID;
|
||||
};
|
||||
|
||||
static_assert(sizeof(msg_t) == 48);
|
||||
|
||||
typedef enum {
|
||||
SCRIPTINSTANCE_SERVER,
|
||||
SCRIPTINSTANCE_CLIENT,
|
||||
SCRIPT_INSTANCE_MAX
|
||||
} scriptInstance_t;
|
||||
|
||||
enum dvar_flags : unsigned __int16 {
|
||||
DVAR_ARCHIVE = 0x1,
|
||||
DVAR_WRITEPROTECTED = 0x10,
|
||||
DVAR_READONLY = 0x40,
|
||||
DVAR_CHEAT = 0x80,
|
||||
DVAR_CODINFO = 0x100,
|
||||
};
|
||||
|
||||
typedef enum : char {
|
||||
DVAR_TYPE_BOOL = 0x0,
|
||||
DVAR_TYPE_FLOAT = 0x1,
|
||||
DVAR_TYPE_FLOAT_2 = 0x2,
|
||||
DVAR_TYPE_FLOAT_3 = 0x3,
|
||||
DVAR_TYPE_FLOAT_4 = 0x4,
|
||||
DVAR_TYPE_INT = 0x5,
|
||||
DVAR_TYPE_ENUM = 0x6,
|
||||
DVAR_TYPE_STRING = 0x7,
|
||||
DVAR_TYPE_COLOR = 0x8,
|
||||
DVAR_TYPE_INT64 = 0x9,
|
||||
DVAR_TYPE_LINEAR_COLOR_RGB = 0xA,
|
||||
DVAR_TYPE_COLOR_XYZ = 0xB,
|
||||
DVAR_TYPE_COUNT = 0xC,
|
||||
} dvarType_t;
|
||||
|
||||
union DvarValue {
|
||||
bool enabled;
|
||||
int integer;
|
||||
unsigned int unsignedInt;
|
||||
__int64 integer64;
|
||||
unsigned __int64 unsignedInt64;
|
||||
float value;
|
||||
float vector[4];
|
||||
const char* string;
|
||||
unsigned char color[4];
|
||||
};
|
||||
|
||||
struct enum_limit {
|
||||
int stringCount;
|
||||
const char** strings;
|
||||
};
|
||||
|
||||
struct int_limit {
|
||||
int min;
|
||||
int max;
|
||||
};
|
||||
|
||||
struct int64_limit {
|
||||
__int64 min;
|
||||
__int64 max;
|
||||
};
|
||||
|
||||
struct float_limit {
|
||||
float min;
|
||||
float max;
|
||||
};
|
||||
|
||||
union DvarLimits {
|
||||
enum_limit enumeration;
|
||||
int_limit integer;
|
||||
float_limit value;
|
||||
float_limit vector;
|
||||
};
|
||||
|
||||
typedef struct dvar_s {
|
||||
const char* name;
|
||||
const char* description;
|
||||
long hash;
|
||||
unsigned int flags;
|
||||
dvarType_t type;
|
||||
bool modified;
|
||||
bool loadedFromSaveGame;
|
||||
DvarValue current;
|
||||
DvarValue latched;
|
||||
DvarValue reset;
|
||||
DvarValue saved;
|
||||
DvarLimits domain;
|
||||
dvar_s* hashNext;
|
||||
} dvar_t;
|
||||
|
||||
static_assert(sizeof(dvar_s) == 104);
|
||||
|
||||
enum playerFlag {
|
||||
PLAYER_FLAG_NOCLIP = 1 << 0,
|
||||
PLAYER_FLAG_UFO = 1 << 1,
|
||||
PLAYER_FLAG_FROZEN = 1 << 2,
|
||||
};
|
||||
|
||||
struct playerState_s {
|
||||
int commandTime;
|
||||
int pm_type;
|
||||
int bobCycle;
|
||||
int pm_flags;
|
||||
int weapFlags;
|
||||
int otherFlags;
|
||||
int pm_time;
|
||||
};
|
||||
|
||||
struct pmove_t {
|
||||
playerState_s* ps;
|
||||
};
|
||||
|
||||
struct gclient_s {
|
||||
char __pad0[10396];
|
||||
int flags;
|
||||
char __pad1[320];
|
||||
};
|
||||
|
||||
static_assert(sizeof(gclient_s) == 10720);
|
||||
|
||||
enum entityFlag {
|
||||
FL_GODMODE = 1,
|
||||
FL_DEMI_GODMODE = 2,
|
||||
FL_NOTARGET = 4,
|
||||
FL_NO_KNOCKBACK = 8,
|
||||
FL_DROPPED_ITEM = 16,
|
||||
FL_NO_BOTS = 32,
|
||||
FL_NO_HUMANS = 64,
|
||||
FL_TOGGLE = 128,
|
||||
FL_SOFTACTIVATE = 256,
|
||||
FL_LOW_PRIORITY_USEABLE = 512,
|
||||
FL_NO_HEADCHECK = 1024,
|
||||
FL_DYNAMICPATH = 2048,
|
||||
FL_SUPPORTS_LINKTO = 4096,
|
||||
FL_NO_AUTO_ANIM_UPDATE = 8192,
|
||||
FL_GRENADE_TOUCH_DAMAGE = 16384,
|
||||
FL_GRENADE_MARTYRDOM = 32768,
|
||||
FL_MISSILE_DESTABILIZED = 65536,
|
||||
FL_STABLE_MISSILES = 131072,
|
||||
FL_REPEAT_ANIM_UPDATE = 262144,
|
||||
FL_VEHICLE_TARGET = 524288,
|
||||
FL_GROUND_ENT = 1048576,
|
||||
FL_CURSOR_HINT = 2097152,
|
||||
FL_USE_TURRET = 4194304,
|
||||
FL_MISSILE_ATTRACTOR = 8388608,
|
||||
FL_TARGET = 16777216,
|
||||
FL_WEAPON_BEING_GRABBED = 33554432,
|
||||
FL_OBSTACLE = 67108864,
|
||||
FL_DODGE_LEFT = 134217728,
|
||||
FL_DODGE_RIGHT = 268435456,
|
||||
FL_BADPLACE_VOLUME = 536870912,
|
||||
FL_AUTO_BLOCKPATHS = 1073741824
|
||||
};
|
||||
|
||||
enum playerStateFlag { PMF_PRONE = 0x1, PMF_DUCKED = 0x2, PMF_MANTLE = 0x4 };
|
||||
|
||||
struct gentity_s {
|
||||
int entnum;
|
||||
char __pad0[320];
|
||||
gclient_s* client;
|
||||
char __pad1[44];
|
||||
int flags;
|
||||
char __pad2[384];
|
||||
};
|
||||
|
||||
static_assert(sizeof(gentity_s) == 760);
|
||||
|
||||
struct netProfilePacket_t {
|
||||
int iTime;
|
||||
int iSize;
|
||||
int bFragment;
|
||||
};
|
||||
|
||||
struct netProfileStream_t {
|
||||
netProfilePacket_t packets[60];
|
||||
int iCurrPacket;
|
||||
int iBytesPerSecond;
|
||||
int iLastBPSCalcTime;
|
||||
int iCountedPackets;
|
||||
int iCountedFragments;
|
||||
int iFragmentPercentage;
|
||||
int iLargestPacket;
|
||||
int iSmallestPacket;
|
||||
};
|
||||
|
||||
struct netProfileInfo_t {
|
||||
netProfileStream_t send;
|
||||
netProfileStream_t recieve;
|
||||
};
|
||||
|
||||
static_assert(sizeof(netProfileInfo_t) == 1504);
|
||||
|
||||
struct netchan_t {
|
||||
int outgoingSequence;
|
||||
netsrc_t sock;
|
||||
int dropped;
|
||||
int incomingSequence;
|
||||
netadr_s remoteAddress;
|
||||
int qport;
|
||||
int fragmentSequence;
|
||||
int fragmentLength;
|
||||
unsigned char* fragmentBuffer;
|
||||
int fragmentBufferSize;
|
||||
int unsentFragments;
|
||||
int unsentFragmentStart;
|
||||
int unsentLength;
|
||||
unsigned char* unsentBuffer;
|
||||
int unsentBufferSize;
|
||||
int reliable_fragments;
|
||||
unsigned char fragment_send_count[128];
|
||||
unsigned int fragment_ack[4];
|
||||
int lowest_send_count;
|
||||
netProfileInfo_t prof;
|
||||
};
|
||||
|
||||
static_assert(sizeof(netchan_t) == 1728);
|
||||
|
||||
struct MantleState {
|
||||
float yaw;
|
||||
int timer;
|
||||
int transIndex;
|
||||
int flags;
|
||||
};
|
||||
|
||||
enum ViewLockTypes {
|
||||
PLAYERVIEWLOCK_NONE = 0,
|
||||
PLAYERVIEWLOCK_FULL = 1,
|
||||
PLAYERVIEWLOCK_WEAPONJITTER = 2,
|
||||
PLAYERVIEWLOCKCOUNT = 3
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
PM_NORMAL = 0,
|
||||
PM_NORMAL_LINKED = 1,
|
||||
PM_NOCLIP = 2,
|
||||
PM_UFO = 3,
|
||||
PM_SPECTATOR = 4,
|
||||
PM_INTERMISSION = 5,
|
||||
PM_LASTSTAND = 6,
|
||||
PM_REVIVEE = 7,
|
||||
PM_LASTSTAND_TRANSITION = 8,
|
||||
PM_DEAD = 9,
|
||||
PM_DEAD_LINKED = 10
|
||||
} pmtype_t;
|
||||
|
||||
enum clientState_t {
|
||||
CS_FREE = 0,
|
||||
CS_ZOMBIE = 1,
|
||||
CS_RECONNECTING = 2,
|
||||
CS_CONNECTED = 3,
|
||||
CS_CLIENTLOADING = 4,
|
||||
CS_ACTIVE = 5
|
||||
};
|
||||
|
||||
struct PredictedVehicleInfo {
|
||||
bool inVehicle;
|
||||
vec3_t origin;
|
||||
vec3_t angles;
|
||||
vec3_t tVel;
|
||||
vec3_t aVel;
|
||||
};
|
||||
|
||||
static_assert(sizeof(PredictedVehicleInfo) == 52);
|
||||
|
||||
struct clientHeader_t {
|
||||
clientState_t state;
|
||||
int sendAsActive;
|
||||
int deltaMessage;
|
||||
int rateDealyed;
|
||||
netchan_t netchan;
|
||||
vec3_t predictedOrigin;
|
||||
int predictedOriginServerTime;
|
||||
PredictedVehicleInfo vehicle;
|
||||
};
|
||||
|
||||
static_assert(sizeof(clientHeader_t) == 1812);
|
||||
|
||||
struct svscmd_info_t {
|
||||
const char* cmd;
|
||||
int time;
|
||||
int type;
|
||||
};
|
||||
|
||||
struct client_s {
|
||||
clientHeader_t header;
|
||||
const char* dropReason; // 1812
|
||||
char userinfo[1024]; // 1816
|
||||
char reliableCommandBuffer[16384]; // 2840
|
||||
int reliableCommandBufferNext; // 19224
|
||||
svscmd_info_t reliableCommandInfo[128]; // 19228
|
||||
int reliableSequence; // 20764
|
||||
int reliableAcknowledge; // 20768
|
||||
int reliableSent; // 20772
|
||||
int messageAcknowledge; // 20776
|
||||
int gamestateMessageNum; // 20780
|
||||
int challenge; // 20784
|
||||
usercmd_s lastUsercmd; // 20788
|
||||
int lastClientCommand; // 20840
|
||||
char lastClientCommandString[1024]; // 20844
|
||||
gentity_s* gentity; // 21868
|
||||
char name[32]; // 21872
|
||||
char clanAbbrev[5]; // 21904
|
||||
unsigned __int64 xuid; // 21912
|
||||
unsigned char __pad0[0x76D48];
|
||||
};
|
||||
|
||||
static_assert(sizeof(client_s) == 0x7C2E8);
|
||||
} // namespace game
|
77
src/client/game/symbols.hpp
Normal file
77
src/client/game/symbols.hpp
Normal file
@ -0,0 +1,77 @@
|
||||
#pragma once
|
||||
|
||||
#define WEAK __declspec(selectany)
|
||||
|
||||
namespace game {
|
||||
WEAK symbol<void(errorParm_t, const char*, ...)> Com_Error{0x627380, 0x651D90};
|
||||
WEAK symbol<void(conChannel_t, const char*, ...)> Com_Printf{0x4126C0,
|
||||
0x43BF30};
|
||||
WEAK symbol<void(conChannel_t, const char*, ...)> Com_DPrintf{0x4E3FA0,
|
||||
0x60F7F0};
|
||||
WEAK symbol<void(conChannel_t, const char*, ...)> Com_PrintError{0x568B90,
|
||||
0x5DFC40};
|
||||
|
||||
WEAK symbol<void(LocalClientNum_t, const char* text)> Cbuf_AddText{0x56EF70,
|
||||
0x49B930};
|
||||
WEAK symbol<void(LocalClientNum_t, const char* text)> Cbuf_InsertText{0x695E10,
|
||||
0x5B3EB0};
|
||||
WEAK symbol<void(LocalClientNum_t, int controllerIndex, const char* text)>
|
||||
Cmd_ExecuteSingleCommand{0x50B470, 0x829AD0};
|
||||
|
||||
WEAK symbol<void(client_s*, svscmd_type, const char*, ...)>
|
||||
SV_SendServerCommand{0x588B10, 0x6106E0};
|
||||
WEAK symbol<void(int, svscmd_type, const char*)> SV_GameSendServerCommand{
|
||||
0x6B8730, 0x543CF0};
|
||||
WEAK symbol<void(int, char*, int)> SV_Cmd_ArgvBuffer{0x462CB0, 0x4DF5A0};
|
||||
WEAK symbol<void(client_s*, const char*)> SV_DelayDropClient{0x4A8DC0,
|
||||
0x4A2EB0};
|
||||
WEAK symbol<client_s*()> SV_GetPlayerByName{0x875180, 0x87C350};
|
||||
WEAK symbol<client_s*()> SV_GetPlayerByNum{0x875260, 0x87C430};
|
||||
|
||||
WEAK symbol<bool(netsrc_t, netadr_s, const char*)> NET_OutOfBandPrint{0x560BB0,
|
||||
0x472850};
|
||||
WEAK symbol<const char*(netadr_s)> NET_AdrToString{0x49F970, 0x40D790};
|
||||
|
||||
WEAK symbol<const dvar_s*(const char*)> Dvar_FindVar{0x512F70, 0x5AE810};
|
||||
WEAK symbol<const char*(const dvar_s*)> Dvar_DisplayableValue{0x681DD0,
|
||||
0x5B56F0};
|
||||
WEAK symbol<const char*(const dvar_s*)> Dvar_DisplayableLatchedValue{0x4AE1A0,
|
||||
0x675850};
|
||||
WEAK symbol<const dvar_s*(const char*, const char*, unsigned __int16,
|
||||
const char*)>
|
||||
Dvar_RegisterString{0x4E3410, 0x59B3B0};
|
||||
WEAK symbol<const dvar_s*(const char*, float, float, float, unsigned __int16,
|
||||
const char*)>
|
||||
Dvar_RegisterFloat{0x670020, 0x679020};
|
||||
WEAK symbol<const dvar_s*(const char*, bool, unsigned __int16, const char*)>
|
||||
Dvar_RegisterBool{0x5A5350, 0x45BB20};
|
||||
WEAK symbol<const dvar_s*(const char*, int, int, int, unsigned __int16,
|
||||
const char*)>
|
||||
Dvar_RegisterInt{0x58D900, 0x651910};
|
||||
|
||||
WEAK symbol<void(const char*, void(), cmd_function_t*)> Cmd_AddCommandInternal{
|
||||
0x6AD580, 0x661400};
|
||||
WEAK symbol<void(const char* cmdName)> Cmd_RemoveCommand{0x527EA0, 0x5F1A90};
|
||||
WEAK symbol<cmd_function_t*(const char*)> Cmd_FindCommand{0x445B60, 0x479DD0};
|
||||
|
||||
WEAK symbol<char*(char*)> I_CleanStr{0x4B0700, 0x0};
|
||||
|
||||
WEAK symbol<char*(int)> ConcatArgs{0x5D5F10, 0x4FB210};
|
||||
WEAK symbol<void(int)> ClientCommand{0x63DB70, 0x4AF770};
|
||||
WEAK symbol<void(gentity_s*, gentity_s*, int, const char*)> G_Say{0x51BBD0,
|
||||
0x49A790};
|
||||
|
||||
WEAK symbol<void(gentity_s*, unsigned __int16, unsigned int)> Scr_Notify{
|
||||
0x458D30, 0x0};
|
||||
WEAK symbol<void(int, scriptInstance_t)> Scr_AddInt{0x49F830, 0x0};
|
||||
WEAK symbol<void(const float*, scriptInstance_t)> Scr_AddVector{0x532EF0, 0x0};
|
||||
|
||||
WEAK symbol<int(const playerState_s*)> PM_GetEffectiveStance{0x659590, 0x0};
|
||||
|
||||
WEAK symbol<CmdArgs> sv_cmd_args{0x355BD88, 0x243D208};
|
||||
WEAK symbol<int> dvarCount{0x385BE74, 0x261CBD4};
|
||||
WEAK symbol<dvar_t*> sortedDvars{0x385BE88, 0x261CBE8};
|
||||
WEAK symbol<client_s> svs_clients{0x372D11C, 0x286D01C};
|
||||
WEAK symbol<gentity_s> g_entities{0x32E5640, 0x1A796F8};
|
||||
WEAK symbol<int> level_time{0x3443F4C, 0xC2078C};
|
||||
} // namespace game
|
21
src/client/loader/component_interface.hpp
Normal file
21
src/client/loader/component_interface.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
class component_interface {
|
||||
public:
|
||||
virtual ~component_interface() {}
|
||||
|
||||
virtual void post_start() {}
|
||||
|
||||
virtual void post_load() {}
|
||||
|
||||
virtual void pre_destroy() {}
|
||||
|
||||
virtual void post_unpack() {}
|
||||
|
||||
virtual void* load_import([[maybe_unused]] const std::string& library,
|
||||
[[maybe_unused]] const std::string& function) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual bool is_supported() { return true; }
|
||||
};
|
111
src/client/loader/component_loader.cpp
Normal file
111
src/client/loader/component_loader.cpp
Normal file
@ -0,0 +1,111 @@
|
||||
#include <std_include.hpp>
|
||||
#include "component_loader.hpp"
|
||||
|
||||
void component_loader::register_component(
|
||||
std::unique_ptr<component_interface>&& component_) {
|
||||
get_components().push_back(std::move(component_));
|
||||
}
|
||||
|
||||
bool component_loader::post_start() {
|
||||
static auto handled = false;
|
||||
if (handled)
|
||||
return true;
|
||||
handled = true;
|
||||
|
||||
try {
|
||||
for (const auto& component_ : get_components()) {
|
||||
component_->post_start();
|
||||
}
|
||||
} catch (premature_shutdown_trigger&) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool component_loader::post_load() {
|
||||
static auto handled = false;
|
||||
if (handled)
|
||||
return true;
|
||||
handled = true;
|
||||
|
||||
clean();
|
||||
|
||||
try {
|
||||
for (const auto& component_ : get_components()) {
|
||||
component_->post_load();
|
||||
}
|
||||
} catch (premature_shutdown_trigger&) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void component_loader::post_unpack() {
|
||||
static auto handled = false;
|
||||
if (handled)
|
||||
return;
|
||||
handled = true;
|
||||
|
||||
for (const auto& component_ : get_components()) {
|
||||
component_->post_unpack();
|
||||
}
|
||||
}
|
||||
|
||||
void component_loader::pre_destroy() {
|
||||
static auto handled = false;
|
||||
if (handled)
|
||||
return;
|
||||
handled = true;
|
||||
|
||||
for (const auto& component_ : get_components()) {
|
||||
component_->pre_destroy();
|
||||
}
|
||||
}
|
||||
|
||||
void component_loader::clean() {
|
||||
auto& components = get_components();
|
||||
for (auto i = components.begin(); i != components.end();) {
|
||||
if (!(*i)->is_supported()) {
|
||||
(*i)->pre_destroy();
|
||||
i = components.erase(i);
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void* component_loader::load_import(const std::string& library,
|
||||
const std::string& function) {
|
||||
void* function_ptr = nullptr;
|
||||
|
||||
for (const auto& component_ : get_components()) {
|
||||
auto* const component_function_ptr =
|
||||
component_->load_import(library, function);
|
||||
if (component_function_ptr) {
|
||||
function_ptr = component_function_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
return function_ptr;
|
||||
}
|
||||
|
||||
void component_loader::trigger_premature_shutdown() {
|
||||
throw premature_shutdown_trigger();
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<component_interface>>&
|
||||
component_loader::get_components() {
|
||||
using component_vector = std::vector<std::unique_ptr<component_interface>>;
|
||||
using component_vector_container =
|
||||
std::unique_ptr<component_vector, std::function<void(component_vector*)>>;
|
||||
|
||||
static component_vector_container components(
|
||||
new component_vector, [](component_vector* component_vector) {
|
||||
pre_destroy();
|
||||
delete component_vector;
|
||||
});
|
||||
|
||||
return *components;
|
||||
}
|
51
src/client/loader/component_loader.hpp
Normal file
51
src/client/loader/component_loader.hpp
Normal file
@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
#include "component_interface.hpp"
|
||||
|
||||
class component_loader final {
|
||||
public:
|
||||
class premature_shutdown_trigger final : public std::exception {
|
||||
[[nodiscard]] const char* what() const noexcept override {
|
||||
return "Premature shutdown requested";
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> class installer final {
|
||||
static_assert(std::is_base_of<component_interface, T>::value,
|
||||
"component has invalid base class");
|
||||
|
||||
public:
|
||||
installer() { register_component(std::make_unique<T>()); }
|
||||
};
|
||||
|
||||
template <typename T> static T* get() {
|
||||
for (const auto& component_ : get_components()) {
|
||||
if (typeid(*component_.get()) == typeid(T)) {
|
||||
return reinterpret_cast<T*>(component_.get());
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void
|
||||
register_component(std::unique_ptr<component_interface>&& component);
|
||||
|
||||
static bool post_start();
|
||||
static bool post_load();
|
||||
static void post_unpack();
|
||||
static void pre_destroy();
|
||||
static void clean();
|
||||
|
||||
static void* load_import(const std::string& library,
|
||||
const std::string& function);
|
||||
|
||||
static void trigger_premature_shutdown();
|
||||
|
||||
private:
|
||||
static std::vector<std::unique_ptr<component_interface>>& get_components();
|
||||
};
|
||||
|
||||
#define REGISTER_COMPONENT(name) \
|
||||
namespace { \
|
||||
static component_loader::installer<name> __component; \
|
||||
}
|
1
src/client/std_include.cpp
Normal file
1
src/client/std_include.cpp
Normal file
@ -0,0 +1 @@
|
||||
#include "std_include.hpp"
|
35
src/client/std_include.hpp
Normal file
35
src/client/std_include.hpp
Normal file
@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#define BINARY_PAYLOAD_SIZE 0x0A000000
|
||||
#define TLS_PAYLOAD_SIZE 0x2000
|
||||
|
||||
#define DLL_EXPORT extern "C" __declspec(dllexport)
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#pragma warning(disable : 26812)
|
||||
|
||||
#include <rapidjson/document.h>
|
||||
#include <rapidjson/prettywriter.h>
|
||||
#include <rapidjson/stringbuffer.h>
|
||||
|
||||
#pragma comment(lib, "ntdll.lib")
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
// clang-format off
|
||||
#include "game/structs.hpp"
|
||||
#include "game/game.hpp"
|
||||
// clang-format on
|
Reference in New Issue
Block a user