882 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			SourcePawn
		
	
	
	
	
	
			
		
		
	
	
			882 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			SourcePawn
		
	
	
	
	
	
#pragma semicolon 1
 | 
						||
 | 
						||
#include <basecomm>
 | 
						||
#include <sourcemod>
 | 
						||
#include <SteamWorks>
 | 
						||
#include <regex>
 | 
						||
#include <smjansson>
 | 
						||
#include <multicolors>
 | 
						||
#include <sdktools>
 | 
						||
#include <AFKManager>
 | 
						||
#include <AutoRecorder>
 | 
						||
 | 
						||
#include <SteamAPI.secret>
 | 
						||
#include <Discord.secret>
 | 
						||
 | 
						||
#tryinclude <AntiBhopCheat>
 | 
						||
#tryinclude <calladmin>
 | 
						||
#tryinclude <oryx>
 | 
						||
#tryinclude <entWatch_restrictions>
 | 
						||
#tryinclude <jenz_ban_detector>
 | 
						||
 | 
						||
#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 Plugin_Handled;
 | 
						||
 | 
						||
    if (g_iRatelimitRemaining == 0 && GetTime() < g_iRatelimitReset)
 | 
						||
        return Plugin_Handled;
 | 
						||
 | 
						||
    //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<JSONObject>(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 Plugin_Handled;
 | 
						||
    }
 | 
						||
    return Plugin_Handled;
 | 
						||
}
 | 
						||
 | 
						||
public Action Hook_UserMessage(UserMsg msg_id, Handle bf, const int[] players, int playersNum, bool reliable, bool init)
 | 
						||
{
 | 
						||
    char sMessageName[32];
 | 
						||
    char sMessageSender[64];
 | 
						||
    int iAuthor = BfReadByte(bf);
 | 
						||
    bool bIsChat = view_as<bool>(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 Plugin_Handled;
 | 
						||
 | 
						||
    if (strlen(sMessageName) == 0 || strlen(sMessageSender) == 0)
 | 
						||
        return Plugin_Handled;
 | 
						||
 | 
						||
    if (strcmp(sMessageName, "#Cstrike_Name_Change") == 0)
 | 
						||
        return Plugin_Handled;
 | 
						||
 | 
						||
    if (sMessageName[13] == 'C' || sMessageName[13] == 'T' || sMessageName[13] == 'S')
 | 
						||
        g_bTeamChat = true;
 | 
						||
    else
 | 
						||
        g_bTeamChat = false;
 | 
						||
    return Plugin_Handled;
 | 
						||
}
 | 
						||
 | 
						||
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 0;
 | 
						||
    }
 | 
						||
 | 
						||
    int iBodyLength;
 | 
						||
    SteamWorks_GetHTTPResponseBodySize(hRequest, iBodyLength);
 | 
						||
 | 
						||
    char[] sData = new char[iBodyLength];
 | 
						||
    SteamWorks_GetHTTPResponseBodyData(hRequest, sData, iBodyLength);
 | 
						||
 | 
						||
    delete hRequest;
 | 
						||
 | 
						||
    APIWebResponse(sData, client);
 | 
						||
    return 0;
 | 
						||
}
 | 
						||
 | 
						||
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<JSONObject>(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<JSONObject>(hJSONRoot)).SetString("username", "Invalid Name");
 | 
						||
		else
 | 
						||
			(view_as<JSONObject>(hJSONRoot)).SetString("username", sUsername);
 | 
						||
	}
 | 
						||
 | 
						||
	if (bUsingAvatar)
 | 
						||
		(view_as<JSONObject>(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<JSONObject>(hJSONRoot)).SetString("content", sSafeText);
 | 
						||
	(view_as<JSONObject>(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<JSONObject>(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<JSONRootNode>(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 0;
 | 
						||
    }
 | 
						||
 | 
						||
    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;
 | 
						||
    return 0;
 | 
						||
}
 | 
						||
 | 
						||
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 Plugin_Handled;
 | 
						||
 | 
						||
    if ((StrContains(sMsg, "sm_psay", false)!= -1) || (StrContains(sMsg, "sm_chat", false)!= -1))
 | 
						||
        return Plugin_Handled;// dont log sm_psay and sm_chat
 | 
						||
 | 
						||
    char sFinal[256];
 | 
						||
    char sCurrentMap[32];
 | 
						||
    char sDemoInfo[64];
 | 
						||
    char sClientName[64];
 | 
						||
 | 
						||
    GetCurrentMap(sCurrentMap, sizeof(sCurrentMap));
 | 
						||
 | 
						||
    if (IsDemoRecording())
 | 
						||
        Format(sDemoInfo, sizeof(sDemoInfo), "Demo: %d @ Tick: %d", GetDemoRecordingNumber(), GetDemoRecordingTick());
 | 
						||
    else
 | 
						||
        Format(sDemoInfo, sizeof(sDemoInfo), "Not recording");
 | 
						||
 | 
						||
    Format(sFinal, sizeof(sFinal), "[ %s ][ %s ]```%s```", sCurrentMap, sDemoInfo, 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 Plugin_Handled;
 | 
						||
}
 | 
						||
 | 
						||
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 BanDetectorPost(int client, const char[] detected_sourceban)
 | 
						||
{
 | 
						||
    char sClientName[MAX_NAME_LENGTH];
 | 
						||
    char sClientID[21];
 | 
						||
    GetClientName(client, sClientName, sizeof(sClientName));
 | 
						||
    GetClientAuthId(client, AuthId_Steam2, sClientID, sizeof(sClientID));
 | 
						||
    char currentMap[64];
 | 
						||
    GetCurrentMap(currentMap, sizeof(currentMap));
 | 
						||
    char sMessage[1900];
 | 
						||
    char sAuthID64[32];
 | 
						||
    if (!Steam32IDtoSteam64ID(sClientID, sAuthID64, sizeof(sAuthID64)))
 | 
						||
        return;
 | 
						||
 | 
						||
    Format(sMessage, sizeof(sMessage), "https://steamcommunity.com/profiles/%s\nName: %s\nSteamID: %s\nClient is ban avoiding the ban: https://bans.unloze.com/index.php?p=banlist&searchText=%s&Submit=Search ", sAuthID64, sClientName, sClientID, detected_sourceban);
 | 
						||
    if (g_sAvatarURL[client][0] != '\0')
 | 
						||
        Discord_POST(DISCORD_BAN_DETECTOR, sMessage, true, sClientName, true, g_sAvatarURL[client], false);
 | 
						||
    else
 | 
						||
        Discord_POST(DISCORD_BAN_DETECTOR, sMessage, true, sClientName, false, "", false);
 | 
						||
}
 | 
						||
 | 
						||
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[1900];
 | 
						||
	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[1900];
 | 
						||
	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 Action Oryx_OnTrigger(int client, int &level, char[] cheat)
 | 
						||
{
 | 
						||
    char sUsername[MAX_NAME_LENGTH];
 | 
						||
    GetClientName(client, sUsername, sizeof(sUsername));
 | 
						||
 | 
						||
    char currentMap[64];
 | 
						||
    GetCurrentMap(currentMap, sizeof(currentMap));
 | 
						||
 | 
						||
    char sAuthID[32];
 | 
						||
    GetClientAuthId(client, AuthId_Steam2, sAuthID, sizeof(sAuthID), false);
 | 
						||
    char sMessage[1900];
 | 
						||
    Format(sMessage, sizeof(sMessage), "```%s - Tick: %d``````NAME: %N\nSTEAMID: %s\nTRIGGER LEVEL: %i\n%s```", currentMap, GetGameTickCount(), client, sAuthID, level, cheat);
 | 
						||
 | 
						||
    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);
 | 
						||
 | 
						||
    return Plugin_Continue;
 | 
						||
}
 | 
						||
*/
 | 
						||
public void AntiBhopCheat_OnClientDetected(int client, char[] sReason, char[] sStats)
 | 
						||
{
 | 
						||
	char sCurrentMap[64];
 | 
						||
	GetCurrentMap(sCurrentMap, sizeof(sCurrentMap));
 | 
						||
 | 
						||
	char sDemoInfo[64];
 | 
						||
	if (IsDemoRecording())
 | 
						||
		Format(sDemoInfo, sizeof(sDemoInfo), "Demo: %d @ Tick: %d", GetDemoRecordingNumber(), GetDemoRecordingTick());
 | 
						||
	else
 | 
						||
		Format(sDemoInfo, sizeof(sDemoInfo), "Not recording");
 | 
						||
 | 
						||
	char sTrimmedStats[1792]; // 128 x 14
 | 
						||
	strcopy(sTrimmedStats, sizeof(sTrimmedStats), sStats);
 | 
						||
 | 
						||
	char sMessage[1920]; // 128 x 15
 | 
						||
	Format(sMessage, sizeof(sMessage), "[ %s ][ %s ]```%s\n%s```", sCurrentMap, sDemoInfo, sReason, sTrimmedStats);
 | 
						||
 | 
						||
	char sUsername[MAX_NAME_LENGTH];
 | 
						||
	GetClientName(client, sUsername, sizeof(sUsername));
 | 
						||
 | 
						||
	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 sCurrentMap[64];
 | 
						||
	GetCurrentMap(sCurrentMap, sizeof(sCurrentMap));
 | 
						||
 | 
						||
	char sDemoInfo[64];
 | 
						||
	if (IsDemoRecording())
 | 
						||
		Format(sDemoInfo, sizeof(sDemoInfo), "Demo: %d @ Tick: %d", GetDemoRecordingNumber(), GetDemoRecordingTick());
 | 
						||
	else
 | 
						||
		Format(sDemoInfo, sizeof(sDemoInfo), "Not recording");
 | 
						||
 | 
						||
	char sMessageTemp[1280]; // 128 x 10
 | 
						||
	if (length == -1)
 | 
						||
		Format(sMessageTemp, sizeof(sMessageTemp), "%L got temporarily restricted by %L", target, client);
 | 
						||
	else if (length == 0)
 | 
						||
		Format(sMessageTemp, sizeof(sMessageTemp), "%L got permanently restricted by %L", target, client);
 | 
						||
	else
 | 
						||
		Format(sMessageTemp, sizeof(sMessageTemp), "%L got restricted by %L for %d minutes", target, client, length);
 | 
						||
 | 
						||
	char sMessage[1920]; // 128 x 15
 | 
						||
	Format(sMessage, sizeof(sMessage), "[ %s ][ %s ]```%s```", sCurrentMap, sDemoInfo, sMessageTemp);
 | 
						||
 | 
						||
	char sUsername[MAX_NAME_LENGTH];
 | 
						||
	GetClientName(client, sUsername, sizeof(sUsername));
 | 
						||
 | 
						||
	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 sCurrentMap[64];
 | 
						||
	GetCurrentMap(sCurrentMap, sizeof(sCurrentMap));
 | 
						||
 | 
						||
	char sDemoInfo[64];
 | 
						||
	if (IsDemoRecording())
 | 
						||
		Format(sDemoInfo, sizeof(sDemoInfo), "Demo: %d @ Tick: %d", GetDemoRecordingNumber(), GetDemoRecordingTick());
 | 
						||
	else
 | 
						||
		Format(sDemoInfo, sizeof(sDemoInfo), "Not recording");
 | 
						||
 | 
						||
	char sMessageTemp[1280]; // 128 x 10
 | 
						||
	Format(sMessageTemp, sizeof(sMessageTemp), "%L got unrestricted by %L", target, client);
 | 
						||
 | 
						||
	char sMessage[1920]; // 128 x 15
 | 
						||
	Format(sMessage, sizeof(sMessage), "[ %s ][ %s ]```%s```", sCurrentMap, sDemoInfo, sMessageTemp);
 | 
						||
 | 
						||
	char sUsername[MAX_NAME_LENGTH];
 | 
						||
	GetClientName(client, sUsername, sizeof(sUsername));
 | 
						||
 | 
						||
	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);
 | 
						||
}
 |