mirror of
https://github.com/XLabsProject/s1x-client.git
synced 2023-08-02 15:02:12 +02:00
Refactor clientcommand
This commit is contained in:
parent
dfe71ad8f7
commit
62cd7362b0
@ -1,5 +1,7 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
#include "game/game.hpp"
|
||||
#include "steam/steam.hpp"
|
||||
|
||||
#include "auth.hpp"
|
||||
#include "command.hpp"
|
||||
@ -11,9 +13,6 @@
|
||||
#include <utils/info_string.hpp>
|
||||
#include <utils/cryptography.hpp>
|
||||
|
||||
#include "game/game.hpp"
|
||||
#include "steam/steam.hpp"
|
||||
|
||||
namespace auth
|
||||
{
|
||||
namespace
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
#include "game/game.hpp"
|
||||
#include "game/scripting/execution.hpp"
|
||||
|
||||
#include "command.hpp"
|
||||
#include "scheduler.hpp"
|
||||
@ -7,9 +9,6 @@
|
||||
#include "network.hpp"
|
||||
#include "server_list.hpp"
|
||||
|
||||
#include "game/game.hpp"
|
||||
#include "game/scripting/execution.hpp"
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/string.hpp>
|
||||
#include <utils/cryptography.hpp>
|
||||
@ -62,7 +61,7 @@ namespace bots
|
||||
auto* bot_ent = game::SV_AddBot(bot_name);
|
||||
if (bot_ent)
|
||||
{
|
||||
spawn_bot(bot_ent->s.entityNum);
|
||||
spawn_bot(bot_ent->s.number);
|
||||
}
|
||||
else if (can_add()) // workaround since first bot won't ever spawn
|
||||
{
|
||||
|
@ -1,10 +1,9 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
#include "localized_strings.hpp"
|
||||
#include "scheduler.hpp"
|
||||
#include "command.hpp"
|
||||
#include "game/game.hpp"
|
||||
|
||||
#include "localized_strings.hpp"
|
||||
#include "scheduler.hpp"
|
||||
#include "dvars.hpp"
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
|
@ -1,15 +1,16 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
#include "game/game.hpp"
|
||||
#include "game/dvars.hpp"
|
||||
|
||||
#include "command.hpp"
|
||||
#include "console.hpp"
|
||||
#include "game_console.hpp"
|
||||
|
||||
#include "game/game.hpp"
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/string.hpp>
|
||||
#include <utils/memory.hpp>
|
||||
#include "utils/io.hpp"
|
||||
#include <utils/io.hpp>
|
||||
|
||||
namespace command
|
||||
{
|
||||
@ -18,7 +19,7 @@ namespace command
|
||||
utils::hook::detour client_command_hook;
|
||||
|
||||
std::unordered_map<std::string, std::function<void(params&)>> handlers;
|
||||
std::unordered_map<std::string, std::function<void(int, params_sv&)>> handlers_sv;
|
||||
std::unordered_map<std::string, std::function<void(game::mp::gentity_s*, params_sv&)>> handlers_sv;
|
||||
|
||||
void main_handler()
|
||||
{
|
||||
@ -31,17 +32,23 @@ namespace command
|
||||
}
|
||||
}
|
||||
|
||||
void client_command(const int client_num, void* a2)
|
||||
void client_command(const int client_num)
|
||||
{
|
||||
if (game::mp::g_entities[client_num].client == nullptr)
|
||||
{
|
||||
// Client is not fully connected
|
||||
return;
|
||||
}
|
||||
|
||||
params_sv params = {};
|
||||
|
||||
const auto command = utils::string::to_lower(params[0]);
|
||||
if (handlers_sv.find(command) != handlers_sv.end())
|
||||
if (const auto got = handlers_sv.find(command); got != handlers_sv.end())
|
||||
{
|
||||
handlers_sv[command](client_num, params);
|
||||
got->second(&game::mp::g_entities[client_num], params);
|
||||
}
|
||||
|
||||
client_command_hook.invoke<void>(client_num, a2);
|
||||
client_command_hook.invoke<void>(client_num);
|
||||
}
|
||||
|
||||
// Shamelessly stolen from Quake3
|
||||
@ -203,7 +210,7 @@ namespace command
|
||||
});
|
||||
}
|
||||
|
||||
void add_sv(const char* name, std::function<void(int, const params_sv&)> callback)
|
||||
void add_sv(const char* name, std::function<void(game::mp::gentity_s*, const params_sv&)> callback)
|
||||
{
|
||||
// doing this so the sv command would show up in the console
|
||||
add_raw(name, nullptr);
|
||||
@ -214,6 +221,25 @@ namespace command
|
||||
handlers_sv[command] = std::move(callback);
|
||||
}
|
||||
|
||||
bool cheats_ok(const game::mp::gentity_s* ent)
|
||||
{
|
||||
if (!dvars::sv_cheats->current.enabled)
|
||||
{
|
||||
game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE,
|
||||
"f \"Cheats are not enabled on this server\"");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ent->health < 1)
|
||||
{
|
||||
game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE,
|
||||
"f \"You must be alive to use this command\"");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void execute(std::string command, const bool sync)
|
||||
{
|
||||
command += "\n";
|
||||
@ -231,10 +257,10 @@ namespace command
|
||||
void enum_assets(const game::XAssetType type, const std::function<void(game::XAssetHeader)>& callback, const bool includeOverride)
|
||||
{
|
||||
game::DB_EnumXAssets_Internal(type, static_cast<void(*)(game::XAssetHeader, void*)>([](game::XAssetHeader header, void* data)
|
||||
{
|
||||
const auto& cb = *static_cast<const std::function<void(game::XAssetHeader)>*>(data);
|
||||
cb(header);
|
||||
}), &callback, includeOverride);
|
||||
{
|
||||
const auto& cb = *static_cast<const std::function<void(game::XAssetHeader)>*>(data);
|
||||
cb(header);
|
||||
}), &callback, includeOverride);
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
@ -249,9 +275,9 @@ namespace command
|
||||
else
|
||||
{
|
||||
utils::hook::call(0x1403CDF1C, &parse_commandline_stub);
|
||||
|
||||
add_commands_mp();
|
||||
}
|
||||
|
||||
add_commands_generic();
|
||||
}
|
||||
|
||||
@ -260,9 +286,9 @@ namespace command
|
||||
{
|
||||
add("quit", game::Com_Quit_f);
|
||||
add("quit_hard", utils::nt::raise_hard_exception);
|
||||
add("crash", []()
|
||||
add("crash", []
|
||||
{
|
||||
*reinterpret_cast<int*>(1) = 0;
|
||||
*reinterpret_cast<int*>(1) = 0x12345678;
|
||||
});
|
||||
|
||||
add("consoleList", [](const params& params)
|
||||
@ -545,136 +571,98 @@ namespace command
|
||||
{
|
||||
client_command_hook.create(0x1402E98F0, &client_command);
|
||||
|
||||
add_sv("god", [](const int client_num, const params_sv&)
|
||||
add_sv("god", [](game::mp::gentity_s* ent, const params_sv&)
|
||||
{
|
||||
if (!game::Dvar_FindVar("sv_cheats")->current.enabled)
|
||||
{
|
||||
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
||||
"f \"Cheats are not enabled on this server\"");
|
||||
if (!cheats_ok(ent))
|
||||
return;
|
||||
}
|
||||
|
||||
game::mp::g_entities[client_num].flags ^= 1;
|
||||
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
||||
utils::string::va("f \"godmode %s\"",
|
||||
game::mp::g_entities[client_num].flags & 1
|
||||
? "^2on"
|
||||
: "^1off"));
|
||||
ent->flags ^= 1;
|
||||
|
||||
game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE,
|
||||
utils::string::va("f \"godmode %s\"", ent->flags & 1 ? "^2on" : "^1off"));
|
||||
});
|
||||
|
||||
add_sv("demigod", [](const int client_num, const params_sv&)
|
||||
add_sv("demigod", [](game::mp::gentity_s* ent, const params_sv&)
|
||||
{
|
||||
if (!game::Dvar_FindVar("sv_cheats")->current.enabled)
|
||||
{
|
||||
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
||||
"f \"Cheats are not enabled on this server\"");
|
||||
if (!cheats_ok(ent))
|
||||
return;
|
||||
}
|
||||
|
||||
game::mp::g_entities[client_num].flags ^= 2;
|
||||
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
||||
utils::string::va("f \"demigod mode %s\"",
|
||||
game::mp::g_entities[client_num].flags & 2
|
||||
? "^2on"
|
||||
: "^1off"));
|
||||
ent->flags ^= 2;
|
||||
|
||||
game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE,
|
||||
utils::string::va("f \"demigod mode %s\"", ent->flags & 2 ? "^2on" : "^1off"));
|
||||
});
|
||||
|
||||
add_sv("notarget", [](const int client_num, const params_sv&)
|
||||
add_sv("notarget", [](game::mp::gentity_s* ent, const params_sv&)
|
||||
{
|
||||
if (!game::Dvar_FindVar("sv_cheats")->current.enabled)
|
||||
{
|
||||
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
||||
"f \"Cheats are not enabled on this server\"");
|
||||
if (!cheats_ok(ent))
|
||||
return;
|
||||
}
|
||||
|
||||
game::mp::g_entities[client_num].flags ^= 4;
|
||||
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
||||
utils::string::va("f \"notarget %s\"",
|
||||
game::mp::g_entities[client_num].flags & 4
|
||||
? "^2on"
|
||||
: "^1off"));
|
||||
ent->flags ^= 4;
|
||||
|
||||
game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE,
|
||||
utils::string::va("f \"notarget %s\"", ent->flags & 4 ? "^2on" : "^1off"));
|
||||
});
|
||||
|
||||
add_sv("noclip", [](const int client_num, const params_sv&)
|
||||
add_sv("noclip", [](game::mp::gentity_s* ent, const params_sv&)
|
||||
{
|
||||
if (!game::Dvar_FindVar("sv_cheats")->current.enabled)
|
||||
{
|
||||
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
||||
"f \"Cheats are not enabled on this server\"");
|
||||
if (!cheats_ok(ent))
|
||||
return;
|
||||
}
|
||||
|
||||
game::mp::g_entities[client_num].client->flags ^= 1;
|
||||
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
||||
utils::string::va("f \"noclip %s\"",
|
||||
game::mp::g_entities[client_num].client->flags & 1
|
||||
? "^2on"
|
||||
: "^1off"));
|
||||
ent->client->flags ^= 1;
|
||||
|
||||
game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE,
|
||||
utils::string::va("f \"noclip %s\"", ent->client->flags & 1 ? "^2on" : "^1off"));
|
||||
});
|
||||
|
||||
add_sv("ufo", [](const int client_num, const params_sv&)
|
||||
add_sv("ufo", [](game::mp::gentity_s* ent, const params_sv&)
|
||||
{
|
||||
if (!game::Dvar_FindVar("sv_cheats")->current.enabled)
|
||||
{
|
||||
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
||||
"f \"Cheats are not enabled on this server\"");
|
||||
if (!cheats_ok(ent))
|
||||
return;
|
||||
}
|
||||
|
||||
game::mp::g_entities[client_num].client->flags ^= 2;
|
||||
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
||||
utils::string::va("f \"ufo %s\"",
|
||||
game::mp::g_entities[client_num].client->flags & 2
|
||||
? "^2on"
|
||||
: "^1off"));
|
||||
ent->client->flags ^= 2;
|
||||
|
||||
game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE,
|
||||
utils::string::va("f \"ufo %s\"", ent->client->flags & 2 ? "^2on" : "^1off"));
|
||||
});
|
||||
|
||||
add_sv("give", [](const int client_num, const params_sv& params)
|
||||
add_sv("give", [](game::mp::gentity_s* ent, const params_sv& params)
|
||||
{
|
||||
if (!game::Dvar_FindVar("sv_cheats")->current.enabled)
|
||||
{
|
||||
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
||||
"f \"Cheats are not enabled on this server\"");
|
||||
if (!cheats_ok(ent))
|
||||
return;
|
||||
}
|
||||
|
||||
if (params.size() < 2)
|
||||
{
|
||||
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
||||
"f \"You did not specify a weapon name\"");
|
||||
game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE,
|
||||
"f \"You did not specify a weapon name\"");
|
||||
return;
|
||||
}
|
||||
|
||||
auto ps = game::SV_GetPlayerstateForClientNum(client_num);
|
||||
auto ps = game::SV_GetPlayerstateForClientNum(ent->s.number);
|
||||
const auto wp = game::G_GetWeaponForName(params.get(1));
|
||||
if (wp)
|
||||
{
|
||||
if (game::G_GivePlayerWeapon(ps, wp, 0, 0, 0, 0, 0, 0))
|
||||
{
|
||||
game::G_InitializeAmmo(ps, wp, 0);
|
||||
game::G_SelectWeapon(client_num, wp);
|
||||
game::G_SelectWeapon(ent->s.number, wp);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
add_sv("take", [](const int client_num, const params_sv& params)
|
||||
add_sv("take", [](game::mp::gentity_s* ent, const params_sv& params)
|
||||
{
|
||||
if (!game::Dvar_FindVar("sv_cheats")->current.enabled)
|
||||
{
|
||||
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
||||
"f \"Cheats are not enabled on this server\"");
|
||||
if (!cheats_ok(ent))
|
||||
return;
|
||||
}
|
||||
|
||||
if (params.size() < 2)
|
||||
{
|
||||
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
||||
game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE,
|
||||
"f \"You did not specify a weapon name\"");
|
||||
return;
|
||||
}
|
||||
|
||||
auto ps = game::SV_GetPlayerstateForClientNum(client_num);
|
||||
auto ps = game::SV_GetPlayerstateForClientNum(ent->s.number);
|
||||
const auto wp = game::G_GetWeaponForName(params.get(1));
|
||||
if (wp)
|
||||
{
|
||||
|
@ -44,7 +44,7 @@ namespace command
|
||||
void add(const char* name, const std::function<void(const params&)>& callback);
|
||||
void add(const char* name, const std::function<void()>& callback);
|
||||
|
||||
void add_sv(const char* name, std::function<void(int, const params_sv&)> callback);
|
||||
void add_sv(const char* name, std::function<void(game::mp::gentity_s*, const params_sv&)> callback);
|
||||
|
||||
void execute(std::string command, bool sync = false);
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include "loader/component_loader.hpp"
|
||||
|
||||
#include "game/game.hpp"
|
||||
#include "game/dvars.hpp"
|
||||
|
||||
#include "console.hpp"
|
||||
#include "scheduler.hpp"
|
||||
@ -21,7 +22,7 @@ namespace dvar_cheats
|
||||
value->enabled = dvar->current.enabled;
|
||||
}
|
||||
|
||||
// if sv_cheats was enabled and it changes to disabled, we need to reset all cheat dvars
|
||||
// if sv_cheats was enabled and it changes to disabled, we need to reset all cheat dvars
|
||||
else if (dvar->current.enabled && !value->enabled)
|
||||
{
|
||||
for (auto i = 0; i < *game::dvarCount; ++i)
|
||||
@ -63,8 +64,7 @@ namespace dvar_cheats
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto sv_cheats = game::Dvar_FindVar("sv_cheats");
|
||||
if ((dvar->flags & game::DvarFlags::DVAR_FLAG_CHEAT) && (sv_cheats && !sv_cheats->current.enabled))
|
||||
if ((dvar->flags & game::DvarFlags::DVAR_FLAG_CHEAT) && (!dvars::sv_cheats->current.enabled))
|
||||
{
|
||||
console::error("%s is cheat protected\n", dvar->name);
|
||||
return false;
|
||||
@ -179,8 +179,14 @@ namespace dvar_cheats
|
||||
|
||||
scheduler::once([]()
|
||||
{
|
||||
game::Dvar_RegisterBool("sv_cheats", false, game::DvarFlags::DVAR_FLAG_REPLICATED,
|
||||
"Allow cheat commands and dvars on this server");
|
||||
#ifdef _DEBUG
|
||||
constexpr auto value = true;
|
||||
#else
|
||||
constexpr auto value = false;
|
||||
#endif
|
||||
|
||||
dvars::sv_cheats = game::Dvar_RegisterBool("sv_cheats", value, game::DvarFlags::DVAR_FLAG_REPLICATED,
|
||||
"Allow cheat commands and dvars on this server");
|
||||
}, scheduler::pipeline::main);
|
||||
}
|
||||
};
|
||||
|
@ -1,12 +1,12 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
#include "game_console.hpp"
|
||||
#include "game/game.hpp"
|
||||
#include "game/dvars.hpp"
|
||||
|
||||
#include "command.hpp"
|
||||
#include "console.hpp"
|
||||
#include "scheduler.hpp"
|
||||
|
||||
#include "game/game.hpp"
|
||||
#include "game/dvars.hpp"
|
||||
#include "game_console.hpp"
|
||||
|
||||
#include <utils/string.hpp>
|
||||
#include <utils/hook.hpp>
|
||||
|
@ -34,7 +34,7 @@ namespace logfile
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto player = scripting::call("getEntByNum", {ent->s.entityNum});
|
||||
const auto player = scripting::call("getEntByNum", {ent->s.number});
|
||||
|
||||
return scripting::lua::convert(state, player);
|
||||
}
|
||||
@ -162,7 +162,7 @@ namespace logfile
|
||||
scheduler::once([cmd, message, self]()
|
||||
{
|
||||
const scripting::entity level{*game::levelEntityId};
|
||||
const auto player = scripting::call("getEntByNum", {self->s.entityNum}).as<scripting::entity>();
|
||||
const auto player = scripting::call("getEntByNum", {self->s.number}).as<scripting::entity>();
|
||||
|
||||
scripting::notify(level, cmd, {player, message});
|
||||
scripting::notify(player, cmd, {message});
|
||||
|
@ -1,10 +1,12 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
#include "game/game.hpp"
|
||||
|
||||
#include "command.hpp"
|
||||
#include "scheduler.hpp"
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/string.hpp>
|
||||
#include "game/game.hpp"
|
||||
|
||||
namespace map_rotation
|
||||
{
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
#include "game/game.hpp"
|
||||
|
||||
#include "command.hpp"
|
||||
#include "network.hpp"
|
||||
|
@ -1,10 +1,11 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
#include "game/game.hpp"
|
||||
#include "game/dvars.hpp"
|
||||
|
||||
#include "command.hpp"
|
||||
#include "console.hpp"
|
||||
#include "network.hpp"
|
||||
#include "game/game.hpp"
|
||||
#include "game/dvars.hpp"
|
||||
#include "scheduler.hpp"
|
||||
#include "filesystem.hpp"
|
||||
#include "fastfiles.hpp"
|
||||
@ -183,7 +184,7 @@ namespace patches
|
||||
{
|
||||
command::params_sv params{};
|
||||
const auto menu_id = atoi(params.get(1));
|
||||
const auto client = &game::mp::svs_clients[ent->s.entityNum];
|
||||
const auto client = &game::mp::svs_clients[ent->s.number];
|
||||
|
||||
// 22 => "end_game"
|
||||
if (menu_id == 22 && client->header.remoteAddress.type != game::NA_LOOPBACK)
|
||||
|
@ -34,6 +34,8 @@ namespace dvars
|
||||
|
||||
game::dvar_t* cg_legacyCrashHandling = nullptr;
|
||||
|
||||
game::dvar_t* sv_cheats = nullptr;
|
||||
|
||||
std::string dvar_get_vector_domain(const int components, const game::dvar_limits& domain)
|
||||
{
|
||||
if (domain.vector.min == -FLT_MAX)
|
||||
|
@ -33,6 +33,8 @@ namespace dvars
|
||||
|
||||
extern game::dvar_t* cg_legacyCrashHandling;
|
||||
|
||||
extern game::dvar_t* sv_cheats;
|
||||
|
||||
std::string dvar_get_vector_domain(const int components, const game::dvar_limits& domain);
|
||||
std::string dvar_get_domain(const game::dvar_type type, const game::dvar_limits& domain);
|
||||
}
|
||||
|
@ -1407,17 +1407,25 @@ namespace game
|
||||
|
||||
struct EntityState
|
||||
{
|
||||
char entityNum;
|
||||
char number;
|
||||
}; // size = ?
|
||||
|
||||
struct EntHandle
|
||||
{
|
||||
unsigned __int16 number;
|
||||
unsigned __int16 infoIndex;
|
||||
};
|
||||
|
||||
struct gentity_s
|
||||
{
|
||||
EntityState s;
|
||||
char __pad0[343];
|
||||
gclient_s* client;
|
||||
gclient_s* client; // 0x158
|
||||
char __pad1[80];
|
||||
int flags;
|
||||
char __pad2[300];
|
||||
int flags; // 0x1B0
|
||||
char __pad2[0x1c];
|
||||
int health; // 0x1D0
|
||||
char __pad3[0x10C];
|
||||
};
|
||||
|
||||
static_assert(sizeof(gentity_s) == 0x2E0);
|
||||
|
@ -267,6 +267,8 @@ namespace game
|
||||
|
||||
WEAK symbol<GfxDrawMethod_s> gfxDrawMethod{0x14CDFAFE8, 0x14D80FD98};
|
||||
|
||||
WEAK symbol<unsigned int> tls_index{0x14f65dAF0, 0x150085C44};
|
||||
|
||||
namespace mp
|
||||
{
|
||||
WEAK symbol<gentity_s> g_entities{0, 0x144758C70};
|
||||
|
Loading…
Reference in New Issue
Block a user