From 348d8b4c4d6a902941b1da01e42d737bab9196ec Mon Sep 17 00:00:00 2001 From: neon <> Date: Mon, 23 Sep 2019 17:25:44 +0200 Subject: [PATCH] Discord: does it work like this? --- Discord_UNLOZE/scripting/Discord_UNLOZE.sp | 779 +++++++++++++++++++++ 1 file changed, 779 insertions(+) create mode 100644 Discord_UNLOZE/scripting/Discord_UNLOZE.sp diff --git a/Discord_UNLOZE/scripting/Discord_UNLOZE.sp b/Discord_UNLOZE/scripting/Discord_UNLOZE.sp new file mode 100644 index 00000000..714579b7 --- /dev/null +++ b/Discord_UNLOZE/scripting/Discord_UNLOZE.sp @@ -0,0 +1,779 @@ +#pragma semicolon 1 + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#tryinclude +#tryinclude +#tryinclude + +#pragma newdecls required + +Regex g_Regex_Clyde = null; + +ArrayList g_arrQueuedMessages = null; + +Handle g_hDataTimer = null; +Handle g_hReplaceConfigFile = null; + +UserMsg g_umSayText2 = INVALID_MESSAGE_ID; + +bool g_bLoadedLate; +bool g_bProcessingData; +bool g_bGotReplaceFile; +bool g_bTeamChat; + +char g_sReplacePath[PLATFORM_MAX_PATH]; +char g_sAvatarURL[MAXPLAYERS + 1][128]; + +int g_iRatelimitRemaining = 5; +int g_iRatelimitReset; + +int g_iLastReportID; + +public Plugin myinfo = +{ + name = "Discord core", + author = "Obus and Neon", + description = "", + version = "1.3.0", + url = "" +} + +public APLRes AskPluginLoad2(Handle hThis, bool bLate, char[] sError, int err_max) +{ + g_bLoadedLate = bLate; + + return APLRes_Success; +} + +public void OnPluginStart() +{ + char sRegexErr[32]; + RegexError RegexErr; + + g_Regex_Clyde = CompileRegex(".*(clyde).*", PCRE_CASELESS, sRegexErr, sizeof(sRegexErr), RegexErr); + + if (RegexErr != REGEX_ERROR_NONE) + LogError("Could not compile \"Clyde\" regex (err: %s)", sRegexErr); + + g_hReplaceConfigFile = CreateKeyValues("AutoReplace"); + BuildPath(Path_SM, g_sReplacePath, sizeof(g_sReplacePath), "configs/custom-chatcolorsreplace.cfg"); + + if (FileToKeyValues(g_hReplaceConfigFile, g_sReplacePath)) + g_bGotReplaceFile = true; + + g_arrQueuedMessages = CreateArray(ByteCountToCells(1024)); + + g_hDataTimer = CreateTimer(0.333, Timer_DataProcessor, INVALID_HANDLE, TIMER_REPEAT); + + g_umSayText2 = GetUserMessageId("SayText2"); + + if (g_umSayText2 == INVALID_MESSAGE_ID) + SetFailState("This game doesn't support SayText2 user messages."); + + HookUserMessage(g_umSayText2, Hook_UserMessage, false); + + if (g_bLoadedLate) + { + for (int i = 1; i <= MaxClients; i++) + { + if (!IsClientAuthorized(i)) + continue; + + static char sAuthID32[32]; + + GetClientAuthId(i, AuthId_Steam2, sAuthID32, sizeof(sAuthID32)); + OnClientAuthorized(i, sAuthID32); + } + } + + AddCommandListener(CommandListener_SmChat, "sm_chat"); + + RegServerCmd("sm_printtoadminchat", Command_PrintToAdminChat, "Discord Integration"); + RegServerCmd("sm_printtoallchat", Command_PrintToAllChat, "Discord Integration"); +} + +public void OnPluginEnd() +{ + delete g_arrQueuedMessages; + delete g_hDataTimer; + + UnhookUserMessage(g_umSayText2, Hook_UserMessage, false); +} + +public void OnClientAuthorized(int client, const char[] sAuthID32) +{ + if (IsFakeClient(client)) + return; + + char sAuthID64[32]; + + if (!Steam32IDtoSteam64ID(sAuthID32, sAuthID64, sizeof(sAuthID64))) + return; + + static char sRequest[256]; + + FormatEx(sRequest, sizeof(sRequest), "http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key=%s&steamids=%s&format=vdf", STEAM_API_KEY, sAuthID64); + + Handle hRequest = SteamWorks_CreateHTTPRequest(k_EHTTPMethodGET, sRequest); + + if (!hRequest || + !SteamWorks_SetHTTPRequestContextValue(hRequest, client) || + !SteamWorks_SetHTTPCallbacks(hRequest, OnTransferComplete) || + !SteamWorks_SendHTTPRequest(hRequest)) + { + delete hRequest; + } +} + +public Action Command_PrintToAdminChat(int args) +{ + char sArgs[1024]; + char sArgs2[1024]; + + GetCmdArg(1, sArgs, sizeof(sArgs)); + GetCmdArg(2, sArgs2, sizeof(sArgs2)); + + for(int i = 0; i < MAXPLAYERS; i++) + { + if (IsValidClient(i)) + { + bool bAdmin = CheckCommandAccess(i, "", ADMFLAG_GENERIC, true); + if (bAdmin) + CPrintToChat(i, "{azure}[DISCORD](ADMINS) %s: {white}%s", sArgs, sArgs2); + } + } + return Plugin_Handled; +} + +public Action Command_PrintToAllChat(int args) +{ + char sArgs[1024]; + char sArgs2[1024]; + + GetCmdArg(1, sArgs, sizeof(sArgs)); + GetCmdArg(2, sArgs2, sizeof(sArgs2)); + + CPrintToChatAll("{azure}[DISCORD](ALL) %s: {white}%s", sArgs, sArgs2); + + return Plugin_Handled; +} + +public Action Timer_DataProcessor(Handle hThis) +{ + if (!g_bProcessingData) + return; + + if (g_iRatelimitRemaining == 0 && GetTime() < g_iRatelimitReset) + return; + + //PrintToServer("[Timer_DataProcessor] Array Length #1: %d", g_arrQueuedMessages.Length); + + char sContent[1024]; + g_arrQueuedMessages.GetString(0, sContent, sizeof(sContent)); + g_arrQueuedMessages.Erase(0); + + char sURL[128]; + g_arrQueuedMessages.GetString(0, sURL, sizeof(sURL)); + g_arrQueuedMessages.Erase(0); + + if (g_arrQueuedMessages.Length == 0) + g_bProcessingData = false; + + //PrintToServer("[Timer_DataProcessor] Array Length #2: %d", g_arrQueuedMessages.Length); + + //PrintToServer("%s | %s", sURL, sContent); + + Handle hRequest = SteamWorks_CreateHTTPRequest(k_EHTTPMethodPOST, sURL); + + JSONObject RequestJSON = view_as(json_load(sContent)); + + if (!hRequest || + !SteamWorks_SetHTTPRequestContextValue(hRequest, RequestJSON) || + !SteamWorks_SetHTTPCallbacks(hRequest, OnHTTPRequestCompleted) || + !SteamWorks_SetHTTPRequestRawPostBody(hRequest, "application/json", sContent, strlen(sContent)) || + !SteamWorks_SetHTTPRequestNetworkActivityTimeout(hRequest, 10) || + !SteamWorks_SendHTTPRequest(hRequest)) + { + LogError("Discord SteamWorks_CreateHTTPRequest failed."); + + delete RequestJSON; + delete hRequest; + + return; + } +} +public Action Hook_UserMessage(UserMsg msg_id, Handle bf, const players[], int playersNum, bool reliable, bool init) +{ + char sMessageName[32]; + char sMessageSender[64]; + int iAuthor = BfReadByte(bf); + bool bIsChat = view_as(BfReadByte(bf)); if (bIsChat) bIsChat=false; //fucking compiler shut the fuck up REEEEEE + BfReadString(bf, sMessageName, sizeof(sMessageName), false); + BfReadString(bf, sMessageSender, sizeof(sMessageSender), false); + + if (iAuthor <= 0 || iAuthor > MaxClients) + return; + + if (strlen(sMessageName) == 0 || strlen(sMessageSender) == 0) + return; + + if (strcmp(sMessageName, "#Cstrike_Name_Change") == 0) + return; + + if (sMessageName[13] == 'C' || sMessageName[13] == 'T' || sMessageName[13] == 'S') + g_bTeamChat = true; + else + g_bTeamChat = false; +} + +stock bool Steam32IDtoSteam64ID(const char[] sSteam32ID, char[] sSteam64ID, int Size) +{ + if (strlen(sSteam32ID) < 11 || strncmp(sSteam32ID[0], "STEAM_0:", 8) || strcmp(sSteam32ID, "STEAM_ID_PENDING") == 0) + { + sSteam64ID[0] = 0; + return false; + } + + int iUpper = 765611979; + int isSteam64ID = StringToInt(sSteam32ID[10]) * 2 + 60265728 + sSteam32ID[8] - 48; + + int iDiv = isSteam64ID / 100000000; + int iIdx = 9 - (iDiv ? (iDiv / 10 + 1) : 0); + iUpper += iDiv; + + IntToString(isSteam64ID, sSteam64ID[iIdx], Size - iIdx); + iIdx = sSteam64ID[9]; + IntToString(iUpper, sSteam64ID, Size); + sSteam64ID[9] = iIdx; + + return true; +} + +stock void Discord_MakeStringSafe(const char[] sOrigin, char[] sOut, int iOutSize) +{ + int iDataLen = strlen(sOrigin); + int iCurIndex; + + for (int i = 0; i < iDataLen && iCurIndex < iOutSize; i++) + { + if (sOrigin[i] < 0x20 && sOrigin[i] != 0x0) + { + //sOut[iCurIndex] = 0x20; + //iCurIndex++; + continue; + } + + switch (sOrigin[i]) + { + // case '"': + // { + // strcopy(sOut[iCurIndex], iOutSize, "\\u0022"); + // iCurIndex += 6; + + // continue; + // } + // case '\\': + // { + // strcopy(sOut[iCurIndex], iOutSize, "\\u005C"); + // iCurIndex += 6; + + // continue; + // } + case '@': + { + strcopy(sOut[iCurIndex], iOutSize, "@​"); //@ + zero-width space + iCurIndex += 4; + + continue; + } + case '`': + { + strcopy(sOut[iCurIndex], iOutSize, "\\`"); + iCurIndex += 2; + + continue; + } + case '_': + { + strcopy(sOut[iCurIndex], iOutSize, "\\_"); + iCurIndex += 2; + + continue; + } + case '~': + { + strcopy(sOut[iCurIndex], iOutSize, "\\~"); + iCurIndex += 2; + + continue; + } + default: + { + sOut[iCurIndex] = sOrigin[i]; + iCurIndex++; + } + } + } +} + +stock int OnTransferComplete(Handle hRequest, bool bFailure, bool bRequestSuccessful, EHTTPStatusCode eStatusCode, int client) +{ + if (bFailure || !bRequestSuccessful || eStatusCode != k_EHTTPStatusCode200OK) + { + if (eStatusCode != k_EHTTPStatusCode429TooManyRequests) + { + LogError("SteamAPI HTTP Response failed: %d", eStatusCode); + } + + delete hRequest; + return; + } + + int iBodyLength; + SteamWorks_GetHTTPResponseBodySize(hRequest, iBodyLength); + + char[] sData = new char[iBodyLength]; + SteamWorks_GetHTTPResponseBodyData(hRequest, sData, iBodyLength); + + delete hRequest; + + APIWebResponse(sData, client); +} + +stock void APIWebResponse(const char[] sData, int client) +{ + KeyValues kvResponse = new KeyValues("SteamAPIResponse"); + + if (!kvResponse.ImportFromString(sData, "SteamAPIResponse")) + { + //LogError("kvResponse.ImportFromString(\"SteamAPIResponse\") in APIWebResponse failed."); + + delete kvResponse; + return; + } + + if (!kvResponse.JumpToKey("players")) + { + //LogError("kvResponse.JumpToKey(\"players\") in APIWebResponse failed."); + + delete kvResponse; + return; + } + + if (!kvResponse.GotoFirstSubKey()) + { + //LogError("kvResponse.GotoFirstSubKey() in APIWebResponse failed."); + + delete kvResponse; + return; + } + + kvResponse.GetString("avatarfull", g_sAvatarURL[client], sizeof(g_sAvatarURL[])); + + delete kvResponse; +} + +stock void HTTPPostJSON(const char[] sURL, const char[] sText) +{ + // if (g_iRatelimitRemaining > 0 && !g_bProcessingData && GetTime() < g_iRatelimitReset) + // { + Handle hRequest = SteamWorks_CreateHTTPRequest(k_EHTTPMethodPOST, sURL); + + JSONObject RequestJSON = view_as(json_load(sText)); + + if (!hRequest || + !SteamWorks_SetHTTPRequestContextValue(hRequest, RequestJSON) || + !SteamWorks_SetHTTPCallbacks(hRequest, OnHTTPRequestCompleted) || + !SteamWorks_SetHTTPRequestRawPostBody(hRequest, "application/json", sText, strlen(sText)) || + !SteamWorks_SetHTTPRequestNetworkActivityTimeout(hRequest, 15) || + !SteamWorks_SendHTTPRequest(hRequest)) + { + LogError("Discord SteamWorks_CreateHTTPRequest failed."); + + delete RequestJSON; + delete hRequest; + + return; + } + // } + // else + // { + // g_arrQueuedMessages.PushString(sText); + // g_arrQueuedMessages.PushString(sURL); + // g_bProcessingData = true; + // } + + //delete hRequest; +} + +stock void Discord_POST(const char[] sURL, char[] sText, bool bUsingUsername=false, char[] sUsername=NULL_STRING, bool bUsingAvatar=false, char[] sAvatarURL=NULL_STRING, bool bSafe=true, bool bTimestamp=true) +{ + //PrintToServer("[Discord_POST] Called with text: %s", sText); + + JSONRootNode hJSONRoot = new JSONObject(); + + char sSafeText[4096]; + char sFinal[4096]; + + if (bUsingUsername) + { + TrimString(sUsername); + + if (g_Regex_Clyde.Match(sUsername) > 0 || strlen(sUsername) < 2) + (view_as(hJSONRoot)).SetString("username", "Invalid Name"); + else + (view_as(hJSONRoot)).SetString("username", sUsername); + } + + if (bUsingAvatar) + (view_as(hJSONRoot)).SetString("avatar_url", sAvatarURL); + + if (bSafe) + { + Discord_MakeStringSafe(sText, sSafeText, sizeof(sSafeText)); + } + else + { + Format(sSafeText, sizeof(sSafeText), "%s", sText); + } + + if (bTimestamp) + { + int iTime = GetTime(); + char sTime[32]; + FormatTime(sTime, sizeof(sTime), "%r", iTime); + Format(sSafeText, sizeof(sSafeText), "[ *%s* ] %s", sTime, sText); + } + + (view_as(hJSONRoot)).SetString("content", sSafeText); + (view_as(hJSONRoot)).ToString(sFinal, sizeof(sFinal), 0); + + //hJSONRoot.DumpToServer(); + + delete hJSONRoot; + + if ((g_iRatelimitRemaining > 0 || GetTime() >= g_iRatelimitReset) && !g_bProcessingData) + { + //PrintToServer("[Discord_POST] Have allowances and not processing data"); + + Handle hRequest = SteamWorks_CreateHTTPRequest(k_EHTTPMethodPOST, sURL); + + JSONObject RequestJSON = view_as(json_load(sFinal)); + + if (!hRequest || + !SteamWorks_SetHTTPRequestContextValue(hRequest, RequestJSON) || + !SteamWorks_SetHTTPCallbacks(hRequest, OnHTTPRequestCompleted) || + !SteamWorks_SetHTTPRequestRawPostBody(hRequest, "application/json", sFinal, strlen(sFinal)) || + !SteamWorks_SetHTTPRequestNetworkActivityTimeout(hRequest, 10) || + !SteamWorks_SendHTTPRequest(hRequest)) + { + LogError("Discord SteamWorks_CreateHTTPRequest failed."); + + delete RequestJSON; + delete hRequest; + + return; + } + } + else + { + //PrintToServer("[Discord_POST] Have allowances? [%s] | Is processing data? [%s]", g_iRatelimitRemaining > 0 ? "YES":"NO", g_bProcessingData?"YES":"NO"); + g_arrQueuedMessages.PushString(sFinal); + g_arrQueuedMessages.PushString(sURL); + g_bProcessingData = true; + } + + //delete hRequest; //nonono +} + +public int OnHTTPRequestCompleted(Handle hRequest, bool bFailure, bool bRequestSuccessful, EHTTPStatusCode eStatusCode, JSONObject RequestJSON) +{ + if (bFailure || !bRequestSuccessful || (eStatusCode != k_EHTTPStatusCode200OK && eStatusCode != k_EHTTPStatusCode204NoContent)) + { + if (eStatusCode != k_EHTTPStatusCode429TooManyRequests) + LogError("Discord HTTP request failed: %d", eStatusCode); + + if (eStatusCode == k_EHTTPStatusCode400BadRequest) + { + char sData[2048]; + + (view_as(RequestJSON)).ToString(sData, sizeof(sData), 0); + + LogError("Malformed request? Dumping request data:\n%s", sData); + } + else if (eStatusCode == k_EHTTPStatusCode429TooManyRequests) + { + g_iRatelimitRemaining = 0; + g_iRatelimitReset = GetTime() + 5; + } + + delete RequestJSON; + delete hRequest; + + return; + } + + static int iLastRatelimitRemaining = 0; + static int iLastRatelimitReset = 0; + char sTmp[32]; + bool bHeaderExists = SteamWorks_GetHTTPResponseHeaderValue(hRequest, "x-ratelimit-remaining", sTmp, sizeof(sTmp)); + + if (!bHeaderExists) + LogError("x-ratelimit-remaining header value could not be retrieved"); + + int iRatelimitRemaining = StringToInt(sTmp); + + bHeaderExists = SteamWorks_GetHTTPResponseHeaderValue(hRequest, "x-ratelimit-reset", sTmp, sizeof(sTmp)); + + if (!bHeaderExists) + LogError("x-ratelimit-reset header value could not be retrieved"); + + int iRatelimitReset = StringToInt(sTmp); + + if (iRatelimitRemaining < iLastRatelimitRemaining || iRatelimitReset >= iLastRatelimitReset) //don't be fooled by different completion times + { + g_iRatelimitRemaining = iRatelimitRemaining; + g_iRatelimitReset = iRatelimitReset; + } + + //PrintToServer("limit: %d | remaining: %d || reset %d - now %d", g_iRatelimitLimit, g_iRatelimitRemaining, g_iRatelimitReset, GetTime()); + + delete RequestJSON; + delete hRequest; +} + +stock bool IsValidClient(int client) +{ + return (client > 0 && client <= MaxClients && IsClientInGame(client)); +} + +public Action OnLogAction(Handle hSource, Identity ident, int client, int target, const char[] sMsg) +{ + if (client <= 0) + return; + + if ((StrContains(sMsg, "sm_psay", false)!= -1) || (StrContains(sMsg, "sm_chat", false)!= -1)) + return;// dont log sm_psay and sm_chat + + char sFinal[256]; + char sCurrentMap[32]; + char sClientName[64]; + + GetCurrentMap(sCurrentMap, sizeof(sCurrentMap)); + Format(sFinal, sizeof(sFinal), "[ %s ]```%s```", sCurrentMap, sMsg); + + GetClientName(client, sClientName, sizeof(sClientName)); + + if (g_sAvatarURL[client][0] != '\0') + Discord_POST(DISCORD_ADMINLOGS_WEBHOOKURL, sFinal, true, sClientName, true, g_sAvatarURL[client], false); + else + Discord_POST(DISCORD_ADMINLOGS_WEBHOOKURL, sFinal, true, sClientName, false, "", false); + + return; +} + +public Action CommandListener_SmChat(int client, const char[] sCommand, int argc) +{ + if (client <= 0) + return Plugin_Continue; + + char sText[256]; + char sUsername[32]; + + GetCmdArgString(sText, sizeof(sText)); + GetClientName(client, sUsername, sizeof(sUsername)); + + if (g_sAvatarURL[client][0] != '\0') + Discord_POST(DISCORD_ADMINCHAT_WEBHOOKURL, sText, true, sUsername, true, g_sAvatarURL[client]); + else + Discord_POST(DISCORD_ADMINCHAT_WEBHOOKURL, sText, true, sUsername); + + return Plugin_Continue; +} + +public Action OnClientSayCommand(int client, const char[] sCommand, const char[] sArgs) +{ + if (client <= 0 || !IsClientInGame(client) || BaseComm_IsClientGagged(client)) + return Plugin_Continue; + + char sFinal[256]; + char sUsername[MAX_NAME_LENGTH]; + + GetClientName(client, sUsername, sizeof(sUsername)); + + if (strcmp(sCommand, "say_team") == 0) + { + if (sArgs[0] == '@') + { + bool bAdmin = CheckCommandAccess(client, "", ADMFLAG_GENERIC, true); + Format(sFinal, sizeof(sFinal), "%s%s", bAdmin ? "" : "To Admins: ", sArgs[1]); + if (g_sAvatarURL[client][0] != '\0') + Discord_POST(DISCORD_ADMINCHAT_WEBHOOKURL, sFinal, true, sUsername, true, g_sAvatarURL[client]); + else + Discord_POST(DISCORD_ADMINCHAT_WEBHOOKURL, sFinal, true, sUsername); + + if (!bAdmin) + { + //g_iReplyTargetSerial = GetClientSerial(client); + //g_iReplyType = REPLYTYPE_CHAT; + } + + return Plugin_Continue; + } + + char sTeamName[32]; + + GetTeamName(GetClientTeam(client), sTeamName, sizeof(sTeamName)); + Format(sFinal, sizeof(sFinal), "(%s) ", sTeamName); + } + + return Plugin_Continue; +} + +public void CallAdmin_OnReportPost(int client, int target, const char[] reason) +{ + char sClientName[MAX_NAME_LENGTH]; + char sClientID[21]; + + char sTargetName[MAX_NAME_LENGTH]; + char sTargetID[21]; + + char sServerIP[16]; + int serverPort; + char sServerName[128]; + + CallAdmin_GetHostIP(sServerIP, sizeof(sServerIP)); + serverPort = CallAdmin_GetHostPort(); + CallAdmin_GetHostName(sServerName, sizeof(sServerName)); + + // Reporter wasn't a real client (initiated by a module) + if (client == REPORTER_CONSOLE) + { + strcopy(sClientName, sizeof(sClientName), "Server/Console"); + strcopy(sClientID, sizeof(sClientID), "Server/Console"); + } + else + { + GetClientName(client, sClientName, sizeof(sClientName)); + GetClientAuthId(client, AuthId_Steam2, sClientID, sizeof(sClientID)); + } + + GetClientName(target, sTargetName, sizeof(sTargetName)); + GetClientAuthId(target, AuthId_Steam2, sTargetID, sizeof(sTargetID)); + + g_iLastReportID = CallAdmin_GetReportID(); + + char currentMap[64]; + GetCurrentMap(currentMap, sizeof(currentMap)); + + char sMessage[4096]; + Format(sMessage, sizeof(sMessage), "@here\n```%s - Tick: %d``````New report on server: %s (%s:%d)\nReportID: %d\nReporter: %s (%s)\nTarget: %s (%s)\nReason: %s\nJoin Server: steam://connect/%s:%d\nwhen in game, type !calladmin_handle %d or /calladmin_handle %d in chat to handle this report```", currentMap, GetGameTickCount(), sServerName, sServerIP, serverPort, g_iLastReportID, sClientName, sClientID, sTargetName, sTargetID, reason, sServerIP, serverPort, g_iLastReportID, g_iLastReportID); + + char sUsername[MAX_NAME_LENGTH]; + GetClientName(client, sUsername, sizeof(sUsername)); + + if (g_sAvatarURL[client][0] != '\0') + Discord_POST(DISCORD_CALLADMIN_WEBHOOKURL, sMessage, true, sUsername, true, g_sAvatarURL[client], false); + else + Discord_POST(DISCORD_CALLADMIN_WEBHOOKURL, sMessage, true, sUsername, false, "", false); +} + +public void CallAdmin_OnReportHandled(int client, int id) +{ + if (id != g_iLastReportID) + { + return; + } + + char sMessage[1024]; + Format(sMessage, sizeof(sMessage), "```Last report (%d) was handled by: %N```", g_iLastReportID, client); + + char sUsername[MAX_NAME_LENGTH]; + GetClientName(client, sUsername, sizeof(sUsername)); + + if (g_sAvatarURL[client][0] != '\0') + Discord_POST(DISCORD_CALLADMIN_WEBHOOKURL, sMessage, true, sUsername, true, g_sAvatarURL[client], false); + else + Discord_POST(DISCORD_CALLADMIN_WEBHOOKURL, sMessage, true, sUsername, false, "", false); +} + +public void AntiBhopCheat_OnClientDetected(int client, char[] sReason, char[] sStats) +{ + char sUsername[MAX_NAME_LENGTH]; + GetClientName(client, sUsername, sizeof(sUsername)); + + char currentMap[64]; + GetCurrentMap(currentMap, sizeof(currentMap)); + + char sMessage[4096]; + Format(sMessage, sizeof(sMessage), "```%s - Tick: %d``````%s\n%s```", currentMap, GetGameTickCount(), sReason, sStats); + + if (g_sAvatarURL[client][0] != '\0') + Discord_POST(DISCORD_ANTIBHOPCHEAT_WEBHOOKURL, sMessage, true, sUsername, true, g_sAvatarURL[client], false); + else + Discord_POST(DISCORD_ANTIBHOPCHEAT_WEBHOOKURL, sMessage, true, sUsername, false, "", false); +} + +public void EW_OnClientRestricted(int client, int target, int length) +{ + char sUsername[MAX_NAME_LENGTH]; + GetClientName(target, sUsername, sizeof(sUsername)); + + char currentMap[64]; + GetCurrentMap(currentMap, sizeof(currentMap)); + + char sMessageTmp[4096]; + + if (length == -1) + { + Format(sMessageTmp, sizeof(sMessageTmp), "%L got temporarily restricted by %L", target, client); + } + else if (length == 0) + { + Format(sMessageTmp, sizeof(sMessageTmp), "%L got PERMANENTLY restricted by %L", target, client); + } + else + { + Format(sMessageTmp, sizeof(sMessageTmp), "%L got restricted by %L for %d minutes", target, client, length); + } + + + char sMessage[4096]; + Format(sMessage, sizeof(sMessage), "```%s - Tick: %d``````%s```", currentMap, GetGameTickCount(), sMessageTmp); + + if (g_sAvatarURL[target][0] != '\0') + Discord_POST(DISCORD_ENTWATCH_WEBHOOKURL, sMessage, true, sUsername, true, g_sAvatarURL[target], false); + else + Discord_POST(DISCORD_ENTWATCH_WEBHOOKURL, sMessage, true, sUsername, false, "", false); +} + + +public void EW_OnClientUnrestricted(int client, int target) +{ + char sUsername[MAX_NAME_LENGTH]; + GetClientName(target, sUsername, sizeof(sUsername)); + + char currentMap[64]; + GetCurrentMap(currentMap, sizeof(currentMap)); + + char sMessageTmp[4096]; + Format(sMessageTmp, sizeof(sMessageTmp), "%L got unrestricted by %L", target, client); + + char sMessage[4096]; + Format(sMessage, sizeof(sMessage), "```%s - Tick: %d``````%s```", currentMap, GetGameTickCount(), sMessageTmp); + + if (g_sAvatarURL[target][0] != '\0') + Discord_POST(DISCORD_ENTWATCH_WEBHOOKURL, sMessage, true, sUsername, true, g_sAvatarURL[target], false); + else + Discord_POST(DISCORD_ENTWATCH_WEBHOOKURL, sMessage, true, sUsername, false, "", false); +}