Merge pull request #159 from diamante0018/feature/mute-player

[Chat] Mute player (prevents them from using the chat)
This commit is contained in:
Dss0 2022-02-14 16:41:19 +01:00 committed by GitHub
commit b86e725b3e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 148 additions and 4 deletions

View File

@ -8,17 +8,35 @@ namespace Components
bool Chat::SendChat;
std::mutex Chat::AccessMutex;
std::unordered_set<std::uint64_t> Chat::MuteList;
const char* Chat::EvaluateSay(char* text, Game::gentity_t* player)
{
SendChat = true;
Chat::SendChat = true;
if (text[1] == '/')
{
SendChat = false;
Chat::SendChat = false;
text[1] = text[0];
++text;
}
std::unique_lock<std::mutex> lock(Chat::AccessMutex);
if (Chat::MuteList.find(Game::svs_clients[player->s.number].steamID) != Chat::MuteList.end())
{
lock.unlock();
Chat::SendChat = false;
Game::SV_GameSendServerCommand(player->s.number, 0,
Utils::String::VA("%c \"You are muted\"", 0x65));
}
// Test whether the lock is still locked
if (lock.owns_lock())
{
lock.unlock();
}
TextRenderer::StripMaterialTextIcons(text, text, strlen(text) + 1);
Game::Scr_AddEntity(player);
@ -194,9 +212,113 @@ namespace Components
}
}
void Chat::MuteClient(const Game::client_t* client)
{
std::unique_lock<std::mutex> lock(Chat::AccessMutex);
if (Chat::MuteList.find(client->steamID) == Chat::MuteList.end())
{
Chat::MuteList.insert(client->steamID);
lock.unlock();
Logger::Print("%s was muted\n", client->name);
Game::SV_GameSendServerCommand(client->gentity->s.number, 0,
Utils::String::VA("%c \"You were muted\"", 0x65));
return;
}
lock.unlock();
Logger::Print("%s is already muted\n", client->name);
Game::SV_GameSendServerCommand(-1, 0,
Utils::String::VA("%c \"%s is already muted\"", 0x65, client->name));
}
void Chat::UnmuteClient(const Game::client_t* client)
{
Chat::UnmuteInternal(client->steamID);
Logger::Print("%s was unmuted\n", client->name);
Game::SV_GameSendServerCommand(client->gentity->s.number, 0,
Utils::String::VA("%c \"You were unmuted\"", 0x65));
}
void Chat::UnmuteInternal(const std::uint64_t id, bool everyone)
{
std::unique_lock<std::mutex> lock(Chat::AccessMutex);
if (everyone)
Chat::MuteList.clear();
else
Chat::MuteList.erase(id);
}
void Chat::AddChatCommands()
{
Command::AddSV("muteClient", [](Command::Params* params)
{
if (!Dvar::Var("sv_running").get<bool>())
{
Logger::Print("Server is not running.\n");
return;
}
const auto* cmd = params->get(0);
if (params->length() < 2)
{
Logger::Print("Usage: %s <client number> : prevent the player from using the chat\n", cmd);
return;
}
const auto* client = Game::SV_GetPlayerByNum();
if (client != nullptr)
{
Chat::MuteClient(client);
}
});
Command::AddSV("unmute", [](Command::Params* params)
{
if (!Dvar::Var("sv_running").get<bool>())
{
Logger::Print("Server is not running.\n");
return;
}
const auto* cmd = params->get(0);
if (params->length() < 2)
{
Logger::Print("Usage: %s <client number or guid>\n%s all = unmute everyone\n", cmd, cmd);
return;
}
const auto* client = Game::SV_GetPlayerByNum();
if (client != nullptr)
{
Chat::UnmuteClient(client);
return;
}
if (params->get(1) == "all"s)
{
Logger::Print("All players were unmuted\n");
Chat::UnmuteInternal(0, true);
}
else
{
const auto steamId = std::strtoull(params->get(1), nullptr, 16);
Chat::UnmuteInternal(steamId);
}
});
}
Chat::Chat()
{
cg_chatWidth = Dvar::Register<int>("cg_chatWidth", 52, 1, INT_MAX, Game::DVAR_FLAG_SAVED, "The normalized maximum width of a chat message");
Dvar::OnInit([]
{
cg_chatWidth = Dvar::Register<int>("cg_chatWidth", 52, 1, std::numeric_limits<int>::max(), Game::DVAR_FLAG_SAVED, "The normalized maximum width of a chat message");
Chat::AddChatCommands();
});
// Intercept chat sending
Utils::Hook(0x4D000B, PreSayStub, HOOK_CALL).install()->quick();
@ -206,4 +328,9 @@ namespace Components
// Change logic that does word splitting with new lines for chat messages to support fonticons
Utils::Hook(0x592E10, CG_AddToTeamChat_Stub, HOOK_JUMP).install()->quick();
}
Chat::~Chat()
{
Chat::MuteList.clear();
}
}

View File

@ -7,6 +7,7 @@ namespace Components
static constexpr auto FONT_ICON_CHAT_WIDTH_CALCULATION_MULTIPLIER = 2.0f;
public:
Chat();
~Chat();
private:
static Game::dvar_t** cg_chatHeight;
@ -15,6 +16,9 @@ namespace Components
static bool SendChat;
static std::mutex AccessMutex;
static std::unordered_set<std::uint64_t> MuteList;
static const char* EvaluateSay(char* text, Game::gentity_t* player);
static void PreSayStub();
@ -23,5 +27,10 @@ namespace Components
static void CheckChatLineEnd(const char*& inputBuffer, char*& lineBuffer, float& len, int chatHeight, float chatWidth, char*& lastSpacePos, char*& lastFontIconPos, int lastColor);
static void CG_AddToTeamChat(const char* text);
static void CG_AddToTeamChat_Stub();
static void MuteClient(const Game::client_t* client);
static void UnmuteClient(const Game::client_t* client);
static void UnmuteInternal(const std::uint64_t id, bool everyone = false);
static void AddChatCommands();
};
}

View File

@ -323,6 +323,8 @@ namespace Game
SV_SetConfigstring_t SV_SetConfigstring = SV_SetConfigstring_t(0x4982E0);
SV_Loaded_t SV_Loaded = SV_Loaded_t(0x4EE3E0);
SV_ClientThink_t SV_ClientThink = SV_ClientThink_t(0x44ADD0);
SV_GetPlayerByName_t SV_GetPlayerByName = SV_GetPlayerByName_t(0x6242B0);
SV_GetPlayerByNum_t SV_GetPlayerByNum = SV_GetPlayerByNum_t(0x624390);
Sys_Error_t Sys_Error = Sys_Error_t(0x4E0200);
Sys_FreeFileList_t Sys_FreeFileList = Sys_FreeFileList_t(0x4D8580);

View File

@ -774,9 +774,15 @@ namespace Game
typedef bool(__cdecl * SV_Loaded_t)();
extern SV_Loaded_t SV_Loaded;
typedef void(__cdecl* SV_ClientThink_t)(client_s*, usercmd_s*);
typedef void(__cdecl * SV_ClientThink_t)(client_s*, usercmd_s*);
extern SV_ClientThink_t SV_ClientThink;
typedef client_t*(__cdecl * SV_GetPlayerByName_t)();
extern SV_GetPlayerByName_t SV_GetPlayerByName;
typedef client_t*(__cdecl * SV_GetPlayerByNum_t)();
extern SV_GetPlayerByNum_t SV_GetPlayerByNum;
typedef int(__cdecl * Sys_Error_t)(int, char *, ...);
extern Sys_Error_t Sys_Error;