#pragma semicolon 1 #include #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; int g_iAdminAFKTime; ConVar g_cvAdminAFKTime; 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 OnAllPluginsLoaded() { if((g_cvAdminAFKTime = FindConVar("sm_admin_afk_time")) == INVALID_HANDLE) SetFailState("Failed to find sm_admin_afk_time cvar."); else g_iAdminAFKTime = g_cvAdminAFKTime.IntValue; HookConVarChange(g_cvAdminAFKTime, OnAdminAFKTimeChanged); } public void OnAdminAFKTimeChanged(ConVar convar, const char[] oldValue, const char[] newValue) { g_iAdminAFKTime = g_cvAdminAFKTime.IntValue; } 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, "{green}(DISCORD ADMINS) %s: {yellow}%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)); bool ActiveAdmins = false; for (int i = 1; i <= MaxClients; i++) { if (IsClientInGame(i) && (CheckCommandAccess(i, "", ADMFLAG_GENERIC, true)) && GetClientIdleTime(i) < g_iAdminAFKTime) { ActiveAdmins = true; break; } } char sMessage[4096]; if(ActiveAdmins) Format(sMessage, sizeof(sMessage), "```***ACTIVE ADMINS IN-GAME***``````\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); else Format(sMessage, sizeof(sMessage), "@here ```***NO ACTIVE ADMINS IN-GAME***``````\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); }