maint: update
This commit is contained in:
parent
4dd9eb2419
commit
6217a48a0d
2
deps/gsc-tool
vendored
2
deps/gsc-tool
vendored
@ -1 +1 @@
|
|||||||
Subproject commit e4cb6a7819726d9ea33cd6a52f0dcd9382258b47
|
Subproject commit 616595f8e0dd62d6d57ed7a4ef7635a4c65e5dde
|
2
deps/libtomcrypt
vendored
2
deps/libtomcrypt
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 2e9f2b5e44dd498dba60e5175c6c7effa5ff3728
|
Subproject commit 54f0456559c8f64b93273a7c71c88a46550eed4e
|
@ -62,7 +62,6 @@ namespace bots
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// SV_BotGetRandomName
|
|
||||||
const auto* const bot_name = game::SV_BotGetRandomName();
|
const auto* const bot_name = game::SV_BotGetRandomName();
|
||||||
const auto* bot_ent = game::SV_AddBot(bot_name);
|
const auto* bot_ent = game::SV_AddBot(bot_name);
|
||||||
if (bot_ent)
|
if (bot_ent)
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
#include <std_include.hpp>
|
#include <std_include.hpp>
|
||||||
#include "loader/component_loader.hpp"
|
#include "loader/component_loader.hpp"
|
||||||
|
|
||||||
#include "game/game.hpp"
|
#include "game/game.hpp"
|
||||||
|
#include "game/engine/sv_game.hpp"
|
||||||
#include "game/dvars.hpp"
|
#include "game/dvars.hpp"
|
||||||
|
|
||||||
#include "command.hpp"
|
#include "command.hpp"
|
||||||
#include "console.hpp"
|
#include "console.hpp"
|
||||||
#include "game_console.hpp"
|
|
||||||
#include "scheduler.hpp"
|
|
||||||
#include "fastfiles.hpp"
|
#include "fastfiles.hpp"
|
||||||
|
#include "game_console.hpp"
|
||||||
|
|
||||||
#include <utils/hook.hpp>
|
#include <utils/hook.hpp>
|
||||||
#include <utils/string.hpp>
|
#include <utils/string.hpp>
|
||||||
@ -236,15 +235,13 @@ namespace command
|
|||||||
{
|
{
|
||||||
if (!dvars::sv_cheats->current.enabled)
|
if (!dvars::sv_cheats->current.enabled)
|
||||||
{
|
{
|
||||||
game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE,
|
game::engine::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, "f \"Cheats are not enabled on this server\"");
|
||||||
"f \"Cheats are not enabled on this server\"");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ent->health < 1)
|
if (ent->health < 1)
|
||||||
{
|
{
|
||||||
game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE,
|
game::engine::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, "f \"You must be alive to use this command\"");
|
||||||
"f \"You must be alive to use this command\"");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -582,8 +579,7 @@ namespace command
|
|||||||
|
|
||||||
ent->flags ^= game::FL_GODMODE;
|
ent->flags ^= game::FL_GODMODE;
|
||||||
|
|
||||||
game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE,
|
game::engine::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, utils::string::va("f \"godmode %s\"", (ent->flags & game::FL_GODMODE) ? "^2on" : "^1off"));
|
||||||
utils::string::va("f \"godmode %s\"", (ent->flags & game::FL_GODMODE) ? "^2on" : "^1off"));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
add_sv("demigod", [](game::mp::gentity_s* ent, const params_sv&)
|
add_sv("demigod", [](game::mp::gentity_s* ent, const params_sv&)
|
||||||
@ -593,8 +589,7 @@ namespace command
|
|||||||
|
|
||||||
ent->flags ^= game::FL_DEMI_GODMODE;
|
ent->flags ^= game::FL_DEMI_GODMODE;
|
||||||
|
|
||||||
game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE,
|
game::engine::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, utils::string::va("f \"demigod mode %s\"", (ent->flags & game::FL_DEMI_GODMODE) ? "^2on" : "^1off"));
|
||||||
utils::string::va("f \"demigod mode %s\"", (ent->flags & game::FL_DEMI_GODMODE) ? "^2on" : "^1off"));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
add_sv("notarget", [](game::mp::gentity_s* ent, const params_sv&)
|
add_sv("notarget", [](game::mp::gentity_s* ent, const params_sv&)
|
||||||
@ -604,8 +599,7 @@ namespace command
|
|||||||
|
|
||||||
ent->flags ^= game::FL_NOTARGET;
|
ent->flags ^= game::FL_NOTARGET;
|
||||||
|
|
||||||
game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE,
|
game::engine::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, utils::string::va("f \"notarget %s\"", (ent->flags & game::FL_NOTARGET) ? "^2on" : "^1off"));
|
||||||
utils::string::va("f \"notarget %s\"", (ent->flags & game::FL_NOTARGET) ? "^2on" : "^1off"));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
add_sv("noclip", [](game::mp::gentity_s* ent, const params_sv&)
|
add_sv("noclip", [](game::mp::gentity_s* ent, const params_sv&)
|
||||||
@ -615,8 +609,7 @@ namespace command
|
|||||||
|
|
||||||
ent->client->flags ^= 1;
|
ent->client->flags ^= 1;
|
||||||
|
|
||||||
game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE,
|
game::engine::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, utils::string::va("f \"noclip %s\"", ent->client->flags & 1 ? "^2on" : "^1off"));
|
||||||
utils::string::va("f \"noclip %s\"", ent->client->flags & 1 ? "^2on" : "^1off"));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
add_sv("ufo", [](game::mp::gentity_s* ent, const params_sv&)
|
add_sv("ufo", [](game::mp::gentity_s* ent, const params_sv&)
|
||||||
@ -626,8 +619,7 @@ namespace command
|
|||||||
|
|
||||||
ent->client->flags ^= 2;
|
ent->client->flags ^= 2;
|
||||||
|
|
||||||
game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE,
|
game::engine::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, utils::string::va("f \"ufo %s\"", ent->client->flags & 2 ? "^2on" : "^1off"));
|
||||||
utils::string::va("f \"ufo %s\"", ent->client->flags & 2 ? "^2on" : "^1off"));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
add_sv("give", [](game::mp::gentity_s* ent, const params_sv& params)
|
add_sv("give", [](game::mp::gentity_s* ent, const params_sv& params)
|
||||||
@ -637,8 +629,7 @@ namespace command
|
|||||||
|
|
||||||
if (params.size() < 2)
|
if (params.size() < 2)
|
||||||
{
|
{
|
||||||
game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE,
|
game::engine::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, "f \"You did not specify a weapon name\"");
|
||||||
"f \"You did not specify a weapon name\"");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -661,8 +652,7 @@ namespace command
|
|||||||
|
|
||||||
if (params.size() < 2)
|
if (params.size() < 2)
|
||||||
{
|
{
|
||||||
game::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE,
|
game::engine::SV_GameSendServerCommand(ent->s.number, game::SV_CMD_RELIABLE, "f \"You did not specify a weapon name\"");
|
||||||
"f \"You did not specify a weapon name\"");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include <std_include.hpp>
|
#include <std_include.hpp>
|
||||||
#include "loader/component_loader.hpp"
|
#include "loader/component_loader.hpp"
|
||||||
#include "game/game.hpp"
|
#include "game/game.hpp"
|
||||||
|
#include "game/engine/sv_game.hpp"
|
||||||
|
|
||||||
#include "console.hpp"
|
#include "console.hpp"
|
||||||
#include "scheduler.hpp"
|
#include "scheduler.hpp"
|
||||||
@ -99,8 +100,7 @@ namespace dedicated
|
|||||||
|
|
||||||
for (const auto& command : queue)
|
for (const auto& command : queue)
|
||||||
{
|
{
|
||||||
game::Cbuf_AddText(0, command.data());
|
command::execute(command);
|
||||||
game::Cbuf_AddText(0, "\n");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,36 +123,10 @@ namespace dedicated
|
|||||||
|
|
||||||
void kill_server()
|
void kill_server()
|
||||||
{
|
{
|
||||||
for (auto i = 0; i < *game::mp::svs_numclients; ++i)
|
game::engine::SV_GameSendServerCommand(-1, game::SV_CMD_CAN_IGNORE, utils::string::va("r \"%s\"", "EXE_ENDOFGAME"));
|
||||||
{
|
|
||||||
if (game::mp::svs_clients[i].header.state >= 3)
|
|
||||||
{
|
|
||||||
game::SV_GameSendServerCommand(i, game::SV_CMD_CAN_IGNORE,
|
|
||||||
utils::string::va("r \"%s\"", "EXE_ENDOFGAME"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
com_quit_f_hook.invoke<void>();
|
com_quit_f_hook.invoke<void>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void sys_error_stub(const char* msg, ...)
|
|
||||||
{
|
|
||||||
char buffer[2048]{};
|
|
||||||
|
|
||||||
va_list ap;
|
|
||||||
va_start(ap, msg);
|
|
||||||
|
|
||||||
vsnprintf_s(buffer, _TRUNCATE, msg, ap);
|
|
||||||
|
|
||||||
va_end(ap);
|
|
||||||
|
|
||||||
scheduler::once([]
|
|
||||||
{
|
|
||||||
command::execute("map_rotate");
|
|
||||||
}, scheduler::main, 3s);
|
|
||||||
|
|
||||||
game::Com_Error(game::ERR_DROP, "%s", buffer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void initialize()
|
void initialize()
|
||||||
@ -190,8 +164,6 @@ namespace dedicated
|
|||||||
// Don't allow sv_hostname to be changed by the game
|
// Don't allow sv_hostname to be changed by the game
|
||||||
dvars::disable::set_string("sv_hostname");
|
dvars::disable::set_string("sv_hostname");
|
||||||
|
|
||||||
// Stop crashing from sys_errors
|
|
||||||
utils::hook::jump(0x1404D6260, sys_error_stub);
|
|
||||||
|
|
||||||
// Hook R_SyncGpu
|
// Hook R_SyncGpu
|
||||||
utils::hook::jump(0x1405A7630, sync_gpu_stub);
|
utils::hook::jump(0x1405A7630, sync_gpu_stub);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#include <std_include.hpp>
|
#include <std_include.hpp>
|
||||||
#include "loader/component_loader.hpp"
|
#include "loader/component_loader.hpp"
|
||||||
|
|
||||||
#include "game/game.hpp"
|
#include "game/game.hpp"
|
||||||
|
#include "game/engine/sv_game.hpp"
|
||||||
#include "game/dvars.hpp"
|
#include "game/dvars.hpp"
|
||||||
|
|
||||||
#include "console.hpp"
|
#include "console.hpp"
|
||||||
@ -130,7 +130,7 @@ namespace dvar_cheats
|
|||||||
const auto* dvar = game::Scr_GetString(0); // grab the original dvar again since it's never stored on stack
|
const auto* dvar = game::Scr_GetString(0); // grab the original dvar again since it's never stored on stack
|
||||||
const auto* command = utils::string::va("q %s \"%s\"", dvar, value);
|
const auto* command = utils::string::va("q %s \"%s\"", dvar, value);
|
||||||
|
|
||||||
game::SV_GameSendServerCommand(entity_num, game::SV_CMD_RELIABLE, command);
|
game::engine::SV_GameSendServerCommand(static_cast<char>(entity_num), game::SV_CMD_RELIABLE, command);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto player_cmd_set_client_dvar = utils::hook::assemble([](utils::hook::assembler& a)
|
const auto player_cmd_set_client_dvar = utils::hook::assemble([](utils::hook::assembler& a)
|
||||||
|
@ -64,20 +64,22 @@ namespace filesystem
|
|||||||
|
|
||||||
void startup()
|
void startup()
|
||||||
{
|
{
|
||||||
register_path("s1");
|
const auto base = std::filesystem::current_path();
|
||||||
|
|
||||||
|
register_path(base / "s1");
|
||||||
register_path(get_binary_directory() + "\\data");
|
register_path(get_binary_directory() + "\\data");
|
||||||
|
|
||||||
if (get_binary_directory() != std::filesystem::current_path())
|
if (get_binary_directory() != base)
|
||||||
{
|
{
|
||||||
register_path(std::filesystem::current_path() / "data");
|
register_path(base / "data");
|
||||||
}
|
}
|
||||||
|
|
||||||
// game's search paths
|
// game's search paths
|
||||||
register_path("devraw");
|
register_path(base / "devraw");
|
||||||
register_path("devraw_shared");
|
register_path(base / "devraw_shared");
|
||||||
register_path("raw_shared");
|
register_path(base / "raw_shared");
|
||||||
register_path("raw");
|
register_path(base / "raw");
|
||||||
register_path("main");
|
register_path(base / "main");
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_for_startup()
|
void check_for_startup()
|
||||||
|
@ -419,7 +419,7 @@ namespace gsc
|
|||||||
public:
|
public:
|
||||||
void post_load() override
|
void post_load() override
|
||||||
{
|
{
|
||||||
gsc_ctx = std::make_unique<xsk::gsc::s1_pc::context>();
|
gsc_ctx = std::make_unique<xsk::gsc::s1_pc::context>(xsk::gsc::instance::server);
|
||||||
}
|
}
|
||||||
|
|
||||||
void post_unpack() override
|
void post_unpack() override
|
||||||
|
@ -29,7 +29,7 @@ namespace lui
|
|||||||
{
|
{
|
||||||
if (params.size() <= 1)
|
if (params.size() <= 1)
|
||||||
{
|
{
|
||||||
console::info("usage: lui_open <name>\n");
|
console::info("USAGE: %s <name>\n", params.get(0));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ namespace lui
|
|||||||
{
|
{
|
||||||
if (params.size() <= 1)
|
if (params.size() <= 1)
|
||||||
{
|
{
|
||||||
console::info("usage: lui_open_popup <name>\n");
|
console::info("USAGE: %s <name>\n", params.get(0));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include <std_include.hpp>
|
#include <std_include.hpp>
|
||||||
#include "loader/component_loader.hpp"
|
#include "loader/component_loader.hpp"
|
||||||
#include "game/game.hpp"
|
#include "game/game.hpp"
|
||||||
|
#include "game/engine/sv_game.hpp"
|
||||||
#include "game/dvars.hpp"
|
#include "game/dvars.hpp"
|
||||||
|
|
||||||
#include "party.hpp"
|
#include "party.hpp"
|
||||||
@ -442,7 +443,7 @@ namespace party
|
|||||||
{
|
{
|
||||||
scheduler::once([i, reason]
|
scheduler::once([i, reason]
|
||||||
{
|
{
|
||||||
game::SV_KickClientNum(i, reason.data());
|
game::SV_KickClientNum(i, reason.c_str());
|
||||||
}, scheduler::pipeline::server);
|
}, scheduler::pipeline::server);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -456,7 +457,7 @@ namespace party
|
|||||||
|
|
||||||
scheduler::once([client_num, reason]()
|
scheduler::once([client_num, reason]()
|
||||||
{
|
{
|
||||||
game::SV_KickClientNum(client_num, reason.data());
|
game::SV_KickClientNum(client_num, reason.c_str());
|
||||||
}, scheduler::pipeline::server);
|
}, scheduler::pipeline::server);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -476,9 +477,8 @@ namespace party
|
|||||||
const auto message = params.join(2);
|
const auto message = params.join(2);
|
||||||
const auto* const name = game::Dvar_FindVar("sv_sayName")->current.string;
|
const auto* const name = game::Dvar_FindVar("sv_sayName")->current.string;
|
||||||
|
|
||||||
game::SV_GameSendServerCommand(client_num, game::SV_CMD_CAN_IGNORE,
|
game::engine::SV_GameSendServerCommand(static_cast<char>(client_num), game::SV_CMD_CAN_IGNORE, utils::string::va("%c \"%s: %s\"", 84, name, message.c_str()));
|
||||||
utils::string::va("%c \"%s: %s\"", 84, name, message.data()));
|
printf("%s -> %i: %s\n", name, client_num, message.c_str());
|
||||||
printf("%s -> %i: %s\n", name, client_num, message.data());
|
|
||||||
});
|
});
|
||||||
|
|
||||||
command::add("tellraw", [](const command::params& params)
|
command::add("tellraw", [](const command::params& params)
|
||||||
@ -491,9 +491,8 @@ namespace party
|
|||||||
const auto client_num = atoi(params.get(1));
|
const auto client_num = atoi(params.get(1));
|
||||||
const auto message = params.join(2);
|
const auto message = params.join(2);
|
||||||
|
|
||||||
game::SV_GameSendServerCommand(client_num, game::SV_CMD_CAN_IGNORE,
|
game::engine::SV_GameSendServerCommand(static_cast<char>(client_num), game::SV_CMD_CAN_IGNORE, utils::string::va("%c \"%s\"", 84, message.c_str()));
|
||||||
utils::string::va("%c \"%s\"", 84, message.data()));
|
printf("%i: %s\n", client_num, message.c_str());
|
||||||
printf("%i: %s\n", client_num, message.data());
|
|
||||||
});
|
});
|
||||||
|
|
||||||
command::add("say", [](const command::params& params)
|
command::add("say", [](const command::params& params)
|
||||||
@ -506,9 +505,8 @@ namespace party
|
|||||||
const auto message = params.join(1);
|
const auto message = params.join(1);
|
||||||
const auto* const name = game::Dvar_FindVar("sv_sayName")->current.string;
|
const auto* const name = game::Dvar_FindVar("sv_sayName")->current.string;
|
||||||
|
|
||||||
game::SV_GameSendServerCommand(
|
game::engine::SV_GameSendServerCommand(-1, game::SV_CMD_CAN_IGNORE, utils::string::va("%c \"%s: %s\"", 84, name, message.c_str()));
|
||||||
-1, game::SV_CMD_CAN_IGNORE, utils::string::va("%c \"%s: %s\"", 84, name, message.data()));
|
printf("%s: %s\n", name, message.c_str());
|
||||||
printf("%s: %s\n", name, message.data());
|
|
||||||
});
|
});
|
||||||
|
|
||||||
command::add("sayraw", [](const command::params& params)
|
command::add("sayraw", [](const command::params& params)
|
||||||
@ -520,8 +518,7 @@ namespace party
|
|||||||
|
|
||||||
const auto message = params.join(1);
|
const auto message = params.join(1);
|
||||||
|
|
||||||
game::SV_GameSendServerCommand(-1, game::SV_CMD_CAN_IGNORE,
|
game::engine::SV_GameSendServerCommand(-1, game::SV_CMD_CAN_IGNORE, utils::string::va("%c \"%s\"", 84, message.c_str()));
|
||||||
utils::string::va("%c \"%s\"", 84, message.data()));
|
|
||||||
printf("%s\n", message.data());
|
printf("%s\n", message.data());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include <std_include.hpp>
|
#include <std_include.hpp>
|
||||||
#include "loader/component_loader.hpp"
|
#include "loader/component_loader.hpp"
|
||||||
#include "game/game.hpp"
|
#include "game/game.hpp"
|
||||||
|
#include "game/engine/sv_game.hpp"
|
||||||
#include "game/dvars.hpp"
|
#include "game/dvars.hpp"
|
||||||
|
|
||||||
#include "command.hpp"
|
#include "command.hpp"
|
||||||
@ -178,7 +179,7 @@ namespace patches
|
|||||||
const auto client = &game::mp::svs_clients[ent->s.number];
|
const auto client = &game::mp::svs_clients[ent->s.number];
|
||||||
|
|
||||||
// 22 => "end_game"
|
// 22 => "end_game"
|
||||||
if (menu_id == 22 && client->header.remoteAddress.type != game::NA_LOOPBACK)
|
if (menu_id == 22 && client->header.netchan.remoteAddress.type != game::NA_LOOPBACK)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -239,6 +240,10 @@ namespace patches
|
|||||||
|
|
||||||
static void patch_mp()
|
static void patch_mp()
|
||||||
{
|
{
|
||||||
|
// Bypass Arxan function
|
||||||
|
utils::hook::nop(0x14043E120, 9);
|
||||||
|
utils::hook::jump(0x14043E120, game::engine::SV_GameSendServerCommand);
|
||||||
|
|
||||||
// Use name dvar
|
// Use name dvar
|
||||||
live_get_local_client_name_hook.create(0x1404D47F0, &live_get_local_client_name);
|
live_get_local_client_name_hook.create(0x1404D47F0, &live_get_local_client_name);
|
||||||
|
|
||||||
|
@ -96,8 +96,8 @@ namespace rcon
|
|||||||
(client->header.state == 2) ? "CNCT" : (client->header.state == 1) ? "ZMBI" : utils::string::va("%4i", game::SV_GetClientPing(i)),
|
(client->header.state == 2) ? "CNCT" : (client->header.state == 1) ? "ZMBI" : utils::string::va("%4i", game::SV_GetClientPing(i)),
|
||||||
game::SV_GetGuid(i),
|
game::SV_GetGuid(i),
|
||||||
clean_name,
|
clean_name,
|
||||||
network::net_adr_to_string(client->header.remoteAddress),
|
network::net_adr_to_string(client->header.netchan.remoteAddress),
|
||||||
client->header.remoteAddress.port)
|
client->header.netchan.remoteAddress.port)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,6 +206,27 @@ namespace ui_scripting
|
|||||||
setup_functions();
|
setup_functions();
|
||||||
|
|
||||||
lua["print"] = function(reinterpret_cast<game::hks::lua_function>(0x14007CB70));
|
lua["print"] = function(reinterpret_cast<game::hks::lua_function>(0x14007CB70));
|
||||||
|
|
||||||
|
lua["directoryexists"] = [](const std::string& string)
|
||||||
|
{
|
||||||
|
return utils::io::directory_exists(string);
|
||||||
|
};
|
||||||
|
|
||||||
|
lua["listfiles"] = [](const std::string& string)
|
||||||
|
{
|
||||||
|
return utils::io::list_files(string);
|
||||||
|
};
|
||||||
|
|
||||||
|
lua["directoryisempty"] = [](const std::string& string)
|
||||||
|
{
|
||||||
|
return utils::io::directory_is_empty(string);
|
||||||
|
};
|
||||||
|
|
||||||
|
lua["fileexists"] = [](const std::string& string)
|
||||||
|
{
|
||||||
|
return utils::io::file_exists(string);
|
||||||
|
};
|
||||||
|
|
||||||
lua["table"]["unpack"] = lua["unpack"];
|
lua["table"]["unpack"] = lua["unpack"];
|
||||||
lua["luiglobals"] = lua;
|
lua["luiglobals"] = lua;
|
||||||
|
|
||||||
|
181
src/client/game/engine/sv_game.cpp
Normal file
181
src/client/game/engine/sv_game.cpp
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include <game/game.hpp>
|
||||||
|
|
||||||
|
#include "sv_game.hpp"
|
||||||
|
|
||||||
|
#include <component/console.hpp>
|
||||||
|
|
||||||
|
#include <utils/string.hpp>
|
||||||
|
|
||||||
|
namespace game::engine
|
||||||
|
{
|
||||||
|
char* SV_ExpandNewlines(char* in)
|
||||||
|
{
|
||||||
|
static char string[1024];
|
||||||
|
|
||||||
|
unsigned int l = 0;
|
||||||
|
while (*in && l < sizeof(string) - 3)
|
||||||
|
{
|
||||||
|
if (*in == '\n')
|
||||||
|
{
|
||||||
|
string[l++] = '\\';
|
||||||
|
string[l++] = 'n';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (*in != '\x14' && *in != '\x15')
|
||||||
|
{
|
||||||
|
string[l++] = *in;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
++in;
|
||||||
|
}
|
||||||
|
|
||||||
|
string[l] = '\0';
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SV_CullIgnorableServerCommands(mp::client_t* client)
|
||||||
|
{
|
||||||
|
int to = client->reliableSent + 1;
|
||||||
|
for (int from = to; from <= client->reliableSequence; ++from)
|
||||||
|
{
|
||||||
|
int from_index = from & 0x7F;
|
||||||
|
assert(client->netBuf.reliableCommandInfo[from_index].time >= 0);
|
||||||
|
if (client->netBuf.reliableCommandInfo[from_index].type)
|
||||||
|
{
|
||||||
|
int to_index = to & 0x7F;
|
||||||
|
if (to_index != from_index)
|
||||||
|
{
|
||||||
|
client->netBuf.reliableCommandInfo[to_index] = client->netBuf.reliableCommandInfo[from_index];
|
||||||
|
}
|
||||||
|
|
||||||
|
++to;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
client->reliableSequence = to - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SV_DelayDropClient(mp::client_t* drop, const char* reason)
|
||||||
|
{
|
||||||
|
assert(drop);
|
||||||
|
assert(reason);
|
||||||
|
assert(drop->header.state != mp::CS_FREE);
|
||||||
|
if (drop->header.state == mp::CS_ZOMBIE)
|
||||||
|
{
|
||||||
|
#ifdef _DEBUG
|
||||||
|
console::info("(drop->dropReason) = %s", drop->dropReason);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if (!drop->dropReason)
|
||||||
|
{
|
||||||
|
drop->dropReason = reason;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SV_AddServerCommand(mp::client_t* client, svscmd_type type, const char* cmd)
|
||||||
|
{
|
||||||
|
static_assert(offsetof(mp::client_t, netBuf.reliableCommandInfo[0].cmd) == 0xC44);
|
||||||
|
|
||||||
|
if (client->testClient == TC_BOT)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (client->reliableSequence - client->reliableAcknowledge < 64 && client->header.state == mp::CS_ACTIVE || (SV_CullIgnorableServerCommands(client), type))
|
||||||
|
{
|
||||||
|
int len = static_cast<int>(std::strlen(cmd)) + 1;
|
||||||
|
int to = SV_CanReplaceServerCommand(client, reinterpret_cast<const unsigned char*>(cmd), len);
|
||||||
|
if (to < 0)
|
||||||
|
{
|
||||||
|
++client->reliableSequence;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int from = to + 1;
|
||||||
|
while (from <= client->reliableSequence)
|
||||||
|
{
|
||||||
|
client->netBuf.reliableCommandInfo[to & 0x7F] = client->netBuf.reliableCommandInfo[from & 0x7F];
|
||||||
|
++from;
|
||||||
|
++to;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (client->reliableSequence - client->reliableAcknowledge == 129)
|
||||||
|
{
|
||||||
|
#ifdef _DEBUG
|
||||||
|
console::info("===== pending server commands =====\n");
|
||||||
|
int i = 0;
|
||||||
|
for (i = client->reliableAcknowledge + 1; i <= client->reliableSequence; ++i)
|
||||||
|
{
|
||||||
|
console::info("cmd %5d: %8d: %s\n", i, client->netBuf.reliableCommandInfo[i & 0x7F].time, client->netBuf.reliableCommandInfo[i & 0x7F].cmd);
|
||||||
|
}
|
||||||
|
console::info("cmd %5d: %8d: %s\n", i, *game::mp::serverTime, cmd);
|
||||||
|
#endif
|
||||||
|
NET_OutOfBandPrint(NS_SERVER, &client->header.netchan.remoteAddress, "disconnect");
|
||||||
|
SV_DelayDropClient(client, "EXE_SERVERCOMMANDOVERFLOW");
|
||||||
|
type = SV_CMD_RELIABLE;
|
||||||
|
cmd = utils::string::va("%c \"EXE_SERVERCOMMANDOVERFLOW\"", 'r');
|
||||||
|
}
|
||||||
|
|
||||||
|
int index = client->reliableSequence & 0x7F;
|
||||||
|
MSG_WriteReliableCommandToBuffer(cmd, client->netBuf.reliableCommandInfo[index].cmd, sizeof(client->netBuf.reliableCommandInfo[index].cmd));
|
||||||
|
client->netBuf.reliableCommandInfo[index].time = *game::mp::serverTime;
|
||||||
|
client->netBuf.reliableCommandInfo[index].type = type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SV_SendServerCommand(mp::client_t* cl, svscmd_type type, const char* fmt, ...)
|
||||||
|
{
|
||||||
|
mp::client_t* client;
|
||||||
|
int j, len;
|
||||||
|
va_list va;
|
||||||
|
|
||||||
|
const auto server_command_buf_large = std::make_unique<char[]>(0x20000);
|
||||||
|
|
||||||
|
va_start(va, fmt);
|
||||||
|
len = vsnprintf_s(server_command_buf_large.get(), 0x20000, _TRUNCATE, fmt, va);
|
||||||
|
va_end(va);
|
||||||
|
|
||||||
|
assert(len >= 0);
|
||||||
|
|
||||||
|
if (cl)
|
||||||
|
{
|
||||||
|
SV_AddServerCommand(cl, type, server_command_buf_large.get());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (environment::is_dedi() && !std::strncmp(server_command_buf_large.get(), "print", 5))
|
||||||
|
{
|
||||||
|
console::info("broadcast: %s\n", SV_ExpandNewlines(server_command_buf_large.get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto* sv_maxclients = Dvar_FindVar("sv_maxclients");
|
||||||
|
for (j = 0, client = mp::svs_clients; j < sv_maxclients->current.integer; j++, client++)
|
||||||
|
{
|
||||||
|
if (client->header.state < mp::CS_CLIENTLOADING)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
SV_AddServerCommand(client, type, server_command_buf_large.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SV_GameSendServerCommand(char clientNum, svscmd_type type, const char* text)
|
||||||
|
{
|
||||||
|
[[maybe_unused]] const auto* sv_maxclients = Dvar_FindVar("sv_maxclients");
|
||||||
|
|
||||||
|
if (clientNum == -1)
|
||||||
|
{
|
||||||
|
SV_SendServerCommand(nullptr, type, "%s", text);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(sv_maxclients->current.integer >= 1 && sv_maxclients->current.integer <= 18);
|
||||||
|
assert(static_cast<unsigned>(clientNum) < sv_maxclients->current.unsignedInt);
|
||||||
|
SV_SendServerCommand(&mp::svs_clients[clientNum], type, "%s", text);
|
||||||
|
}
|
||||||
|
}
|
7
src/client/game/engine/sv_game.hpp
Normal file
7
src/client/game/engine/sv_game.hpp
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace game::engine
|
||||||
|
{
|
||||||
|
void SV_SendServerCommand(mp::client_t* cl, svscmd_type type, const char* fmt, ...);
|
||||||
|
void SV_GameSendServerCommand(char clientNum, svscmd_type type, const char* text);
|
||||||
|
}
|
@ -855,10 +855,11 @@ namespace game
|
|||||||
int readcount;
|
int readcount;
|
||||||
int bit;
|
int bit;
|
||||||
int lastEntityRef;
|
int lastEntityRef;
|
||||||
netsrc_t targetLocalNetID;
|
|
||||||
int useZlib;
|
int useZlib;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(msg_t) == 0x38);
|
||||||
|
|
||||||
enum errorParm
|
enum errorParm
|
||||||
{
|
{
|
||||||
ERR_FATAL = 0,
|
ERR_FATAL = 0,
|
||||||
@ -1416,8 +1417,44 @@ namespace game
|
|||||||
|
|
||||||
static_assert(sizeof(pml_t) == 0x130);
|
static_assert(sizeof(pml_t) == 0x130);
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
namespace mp
|
namespace mp
|
||||||
{
|
{
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CS_FREE = 0x0,
|
||||||
|
CS_ZOMBIE = 0x1,
|
||||||
|
CS_RECONNECTING = 0x2,
|
||||||
|
CS_CONNECTED = 0x3,
|
||||||
|
CS_CLIENTLOADING = 0x4,
|
||||||
|
CS_ACTIVE = 0x5,
|
||||||
|
};
|
||||||
|
|
||||||
struct cachedSnapshot_t
|
struct cachedSnapshot_t
|
||||||
{
|
{
|
||||||
int archivedFrame;
|
int archivedFrame;
|
||||||
@ -1470,33 +1507,141 @@ namespace game
|
|||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct netchan_t
|
||||||
|
{
|
||||||
|
int outgoingSequence;
|
||||||
|
netsrc_t sock;
|
||||||
|
int dropped;
|
||||||
|
int incomingSequence;
|
||||||
|
netadr_s remoteAddress;
|
||||||
|
int fragmentSequence;
|
||||||
|
int fragmentLength;
|
||||||
|
char* fragmentBuffer;
|
||||||
|
int fragmentBufferSize;
|
||||||
|
int unsentFragments;
|
||||||
|
int unsentFragmentStart;
|
||||||
|
int unsentLength;
|
||||||
|
char* unsentBuffer;
|
||||||
|
int unsentBufferSize;
|
||||||
|
netProfileInfo_t prof;
|
||||||
|
};
|
||||||
|
|
||||||
struct clientHeader_t
|
struct clientHeader_t
|
||||||
{
|
{
|
||||||
int state;
|
int state;
|
||||||
char __pad0[36];
|
int sendAsActive;
|
||||||
netadr_s remoteAddress;
|
int deltaMessage;
|
||||||
}; // size = ?
|
int rateDelayed;
|
||||||
|
int hasAckedBaselineData;
|
||||||
|
int hugeSnapshotSent;
|
||||||
|
netchan_t netchan;
|
||||||
|
float predictedOrigin[3];
|
||||||
|
int predictedOriginServerTime;
|
||||||
|
int migrationState;
|
||||||
|
unsigned int predictedVehicleSplineId;
|
||||||
|
int predictedVehicleTargetEntity;
|
||||||
|
float predictedVehicleOrigin[3];
|
||||||
|
int predictedVehicleServerTime;
|
||||||
|
int ackedMessage[32];
|
||||||
|
unsigned int ackedMessageCount;
|
||||||
|
int sentMessage[32];
|
||||||
|
int wasKillcam[32];
|
||||||
|
unsigned int sendMessageCount;
|
||||||
|
bool overrideDeltaMessage;
|
||||||
|
int overrideSequenceNumber;
|
||||||
|
int sequenceResume;
|
||||||
|
int isInKillcam;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct svscmd_info_t
|
||||||
|
{
|
||||||
|
int time;
|
||||||
|
int type;
|
||||||
|
char cmd[1024];
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(svscmd_info_t) == 0x408);
|
||||||
|
|
||||||
|
struct client_net_buffers_t
|
||||||
|
{
|
||||||
|
svscmd_info_t reliableCommandInfo[128];
|
||||||
|
char netchanOutgoingBuffer[131072];
|
||||||
|
char netchanIncomingBuffer[2048];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct usercmd_s
|
||||||
|
{
|
||||||
|
int serverTime;
|
||||||
|
unsigned int buttons;
|
||||||
|
int angles[3];
|
||||||
|
Weapon weapon;
|
||||||
|
Weapon offHand;
|
||||||
|
char forwardmove;
|
||||||
|
char rightmove;
|
||||||
|
unsigned __int16 airburstMarkDistance;
|
||||||
|
__int16 meleeChargeEnt;
|
||||||
|
unsigned __int8 meleeChargeDist;
|
||||||
|
char selectedLoc[2];
|
||||||
|
unsigned __int8 selectedLocAngle;
|
||||||
|
char remoteControlAngles[2];
|
||||||
|
char remoteControlMove[3];
|
||||||
|
unsigned int sightedClientsMask;
|
||||||
|
unsigned __int16 spawnTraceEntIndex;
|
||||||
|
unsigned int sightedSpawnsMask[2];
|
||||||
|
unsigned int partialSightedSpawnsMask[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(usercmd_s) == 0x44);
|
||||||
|
|
||||||
struct client_t
|
struct client_t
|
||||||
{
|
{
|
||||||
clientHeader_t header;
|
clientHeader_t header;
|
||||||
char __pad0[3044];
|
const char* dropReason;
|
||||||
|
char userinfo[0x400];
|
||||||
int reliableSequence;
|
int reliableSequence;
|
||||||
int reliableAcknowledge;
|
int reliableAcknowledge;
|
||||||
char __pad1[265864];
|
int reliableSent;
|
||||||
|
int messageAcknowledge;
|
||||||
|
int largeCommandSequence;
|
||||||
|
int gamestateMessageNum;
|
||||||
|
int challenge;
|
||||||
|
client_net_buffers_t netBuf;
|
||||||
|
int cumulThinkTime;
|
||||||
|
int beginCmdIndex;
|
||||||
|
int currCmdIndex;
|
||||||
|
usercmd_s lastUsercmd;
|
||||||
|
usercmd_s cmds[8];
|
||||||
|
int lastClientCommand;
|
||||||
gentity_s* gentity; // 268976
|
gentity_s* gentity; // 268976
|
||||||
char name[32]; // 268984
|
char name[32];
|
||||||
char __pad2[8];
|
int lastPacketTime;
|
||||||
|
int lastConnectTime;
|
||||||
int nextSnapshotTime; // 269024
|
int nextSnapshotTime; // 269024
|
||||||
char __pad3[544];
|
char __pad3[532];
|
||||||
|
int pureAuthentic;
|
||||||
|
unsigned int streamSyncWaitBits;
|
||||||
|
unsigned int streamSyncWaitTimeout;
|
||||||
LiveClientDropType liveDropRequest; // 269572
|
LiveClientDropType liveDropRequest; // 269572
|
||||||
char __pad4[24];
|
char __pad4[24];
|
||||||
TestClientType testClient; // 269600
|
TestClientType testClient; // 269600
|
||||||
char __pad5[391700];
|
char __pad5[391700];
|
||||||
}; // size = 661304
|
}; // size = 661304
|
||||||
|
|
||||||
|
static_assert(offsetof(client_t, header.netchan.unsentFragments) == 0x54);
|
||||||
|
static_assert(offsetof(client_t, header.migrationState) == 0x660);
|
||||||
|
static_assert(offsetof(client_t, userinfo) == 0x820);
|
||||||
|
static_assert(offsetof(client_t, reliableSequence) == 0xC20);
|
||||||
|
static_assert(offsetof(client_t, reliableAcknowledge) == 0xC24);
|
||||||
|
static_assert(offsetof(client_t, reliableSent) == 0xC28);
|
||||||
|
static_assert(offsetof(client_t, messageAcknowledge) == 0xC2C);
|
||||||
|
static_assert(offsetof(client_t, largeCommandSequence) == 0xC30);
|
||||||
|
static_assert(offsetof(client_t, lastUsercmd) == 0x41848);
|
||||||
|
static_assert(offsetof(client_t, lastClientCommand) == 0x41AAC);
|
||||||
static_assert(offsetof(client_t, gentity) == 0x41AB0);
|
static_assert(offsetof(client_t, gentity) == 0x41AB0);
|
||||||
|
static_assert(offsetof(client_t, name) == 0x41AB8);
|
||||||
|
static_assert(offsetof(client_t, lastPacketTime) == 0x41AD8);
|
||||||
static_assert(offsetof(client_t, nextSnapshotTime) == 0x41AE0);
|
static_assert(offsetof(client_t, nextSnapshotTime) == 0x41AE0);
|
||||||
|
static_assert(offsetof(client_t, pureAuthentic) == 0x41CF8);
|
||||||
static_assert(offsetof(client_t, liveDropRequest) == 0x41D04);
|
static_assert(offsetof(client_t, liveDropRequest) == 0x41D04);
|
||||||
static_assert(offsetof(client_t, testClient) == 0x41D20);
|
static_assert(offsetof(client_t, testClient) == 0x41D20);
|
||||||
static_assert(sizeof(client_t) == 0xA1738);
|
static_assert(sizeof(client_t) == 0xA1738);
|
||||||
@ -1508,7 +1653,9 @@ namespace game
|
|||||||
{
|
{
|
||||||
char __pad[56135];
|
char __pad[56135];
|
||||||
int flags; // 56136
|
int flags; // 56136
|
||||||
};
|
}; // Incomplete
|
||||||
|
|
||||||
|
static_assert(offsetof(gclient_s, flags) == 56136);
|
||||||
|
|
||||||
struct gentity_s
|
struct gentity_s
|
||||||
{
|
{
|
||||||
|
@ -184,7 +184,7 @@ namespace game
|
|||||||
WEAK symbol<void(mp::client_t* client)> SV_DropClient{0, 0x140438A30};
|
WEAK symbol<void(mp::client_t* client)> SV_DropClient{0, 0x140438A30};
|
||||||
WEAK symbol<void(mp::client_t*, const char*, int)> SV_ExecuteClientCommand{0, 0x15121D8E6};
|
WEAK symbol<void(mp::client_t*, const char*, int)> SV_ExecuteClientCommand{0, 0x15121D8E6};
|
||||||
WEAK symbol<void(int localClientNum)> SV_FastRestart{0, 0x1404374E0};
|
WEAK symbol<void(int localClientNum)> SV_FastRestart{0, 0x1404374E0};
|
||||||
WEAK symbol<void(int clientNum, svscmd_type type, const char* text)> SV_GameSendServerCommand{0x1403F3A70, 0x14043E120};
|
WEAK symbol<int(mp::client_t* client, const unsigned char* cmd, int cmdSize)> SV_CanReplaceServerCommand{0x0, 0x140441A00};
|
||||||
WEAK symbol<const char*(int clientNum)> SV_GetGuid{0, 0x14043E1E0};
|
WEAK symbol<const char*(int clientNum)> SV_GetGuid{0, 0x14043E1E0};
|
||||||
WEAK symbol<int(int clientNum)> SV_GetClientPing{0, 0x14043E1C0};
|
WEAK symbol<int(int clientNum)> SV_GetClientPing{0, 0x14043E1C0};
|
||||||
WEAK symbol<playerState_s*(int num)> SV_GetPlayerstateForClientNum{0x1403F3AB0, 0x14043E260};
|
WEAK symbol<playerState_s*(int num)> SV_GetPlayerstateForClientNum{0x1403F3AB0, 0x14043E260};
|
||||||
@ -221,6 +221,8 @@ namespace game
|
|||||||
|
|
||||||
WEAK symbol<void(char* dest, const char* src, int destsize)> I_strncpyz{0x1403793B0, 0x1404C9E60};
|
WEAK symbol<void(char* dest, const char* src, int destsize)> I_strncpyz{0x1403793B0, 0x1404C9E60};
|
||||||
|
|
||||||
|
WEAK symbol<void(const char* pszCommand, char* pszBuffer, int iBufferSize)> MSG_WriteReliableCommandToBuffer{0x0, 0x1403E1090};
|
||||||
|
|
||||||
WEAK symbol<void*(jmp_buf* Buf, int Value)> longjmp{0x14059C5C0, 0x1406FD930};
|
WEAK symbol<void*(jmp_buf* Buf, int Value)> longjmp{0x14059C5C0, 0x1406FD930};
|
||||||
WEAK symbol<int(jmp_buf* Buf)> _setjmp{0x14059CD00, 0x1406FE070};
|
WEAK symbol<int(jmp_buf* Buf)> _setjmp{0x14059CD00, 0x1406FE070};
|
||||||
|
|
||||||
|
@ -54,6 +54,7 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user