SOURCEPAWN 926
Example sourcepawn By siosios on 14th August 2025 01:51:04 PM
  1. /*
  2.     SourceMod Anti-Cheat
  3.     Copyright (C) 2011-2016 SMAC Development Team
  4.     Copyright (C) 2007-2011 CodingDirect LLC
  5.  
  6.     This program is free software: you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation, either version 3 of the License, or
  9.     (at your option) any later version.
  10.  
  11.     This program is distributed in the hope that it will be useful,
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.     GNU General Public License for more details.
  15.  
  16.     You should have received a copy of the GNU General Public License
  17.     along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #pragma semicolon 1
  20. #pragma newdecls required
  21.  
  22. /* SM Includes */
  23. #include <sourcemod>
  24. #include <sdktools>
  25. #include <smac>
  26. #include <colors>
  27.  
  28. /* Plugin Info */
  29. public Plugin myinfo =
  30. {
  31.     name =          "SourceMod Anti-Cheat",
  32.     author =        SMAC_AUTHOR,
  33.     description =   "Open source anti-cheat plugin for SourceMod",
  34.     version =       SMAC_VERSION,
  35.     url =           SMAC_URL
  36. };
  37.  
  38. /* Globals */
  39. #define SOURCEBANS_AVAILABLE()      (GetFeatureStatus(FeatureType_Native, "SBBanPlayer") == FeatureStatus_Available) // Depreciated in SB++, leaving in for legacy/compatibility!
  40. #define SBPP_AVAILABLE()            (GetFeatureStatus(FeatureType_Native, "SBPP_BanPlayer") == FeatureStatus_Available)
  41. #define SOURCEIRC_AVAILABLE()       (GetFeatureStatus(FeatureType_Native, "IRC_MsgFlaggedChannels") == FeatureStatus_Available)
  42. #define IRCRELAY_AVAILABLE()        (GetFeatureStatus(FeatureType_Native, "IRC_Broadcast") == FeatureStatus_Available)
  43.  
  44. enum IrcChannel
  45. {
  46.     IrcChannel_Public  = 1,
  47.     IrcChannel_Private = 2,
  48.     IrcChannel_Both    = 3
  49. }
  50.  
  51. native void SBBanPlayer(int client,int target,int time, char[] reason); // Depreciated in SB++, leaving in for legacy/compatibility!
  52. native void SBPP_BanPlayer(int client,int target,int time, char[] reason);
  53. native any IRC_MsgFlaggedChannels(const char[] flag, const char[] format, any ...);
  54. native any IRC_Broadcast(IrcChannel type, const char[] format, any ...);
  55.  
  56. GameType g_Game = Game_Unknown;
  57. ConVar g_hCvarVersion = null;
  58. ConVar g_hCvarWelcomeMsg = null;
  59. ConVar g_hCvarBanDuration = null;
  60. ConVar g_hCvarLogVerbose = null;
  61. ConVar g_hCvarIrcMode = null;
  62. char g_sLogPath[PLATFORM_MAX_PATH];
  63.  
  64. /* Plugin Functions */
  65. public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
  66. {
  67.     // Detect game.
  68.     char sGame[64];
  69.     GetGameFolderName(sGame, sizeof(sGame));
  70.     EngineVersion iEngine = GetEngineVersion();
  71.  
  72.     /*
  73.         Notes: Removed GMOD support as SourceMod doesn't support Gmod anymore.
  74.  
  75.         Todo: Figure out which EngineVersion INSMod, FoF, HL2CTF, HIDDEN and ZPS use
  76.         from https://sm.alliedmods.net/new-api/halflife/EngineVersion
  77.  
  78.         Those could be switched over too. Also, is cstrike_beta even still a thing?
  79.     */
  80.  
  81.     if (iEngine == Engine_TF2)
  82.     {
  83.         g_Game = Game_TF2;
  84.     }
  85.     else if (iEngine == Engine_CSS)
  86.     {
  87.         g_Game = Game_CSS;
  88.     }
  89.     else if (iEngine == Engine_CSGO)
  90.     {
  91.         g_Game = Game_CSGO;
  92.     }
  93.     else if (iEngine == Engine_DODS)
  94.     {
  95.         g_Game = Game_DODS;
  96.     }
  97.     else if (iEngine == Engine_Left4Dead)
  98.     {
  99.         g_Game = Game_L4D;
  100.     }
  101.     else if (iEngine == Engine_Left4Dead2)
  102.     {
  103.         g_Game = Game_L4D2;
  104.     }
  105.     else if (iEngine == Engine_HL2DM)
  106.     {
  107.         g_Game = Game_HL2DM;
  108.     }
  109.     else if (iEngine == Engine_NuclearDawn)
  110.     {
  111.         g_Game = Game_ND;
  112.     }
  113.     else if (iEngine == Engine_Insurgency)
  114.     {    
  115.         g_Game = Game_INS;
  116.     }
  117.     else if (iEngine ==  Engine_BlackMesa)
  118.     {
  119.         g_Game = Game_BM;
  120.     }
  121.     else if (iEngine == Engine_SDK2013)
  122.     {
  123.         if (StrEqual(sGame, "fof"))
  124.         {        
  125.             g_Game = Game_FOF;
  126.         }
  127.         else if (StrEqual(sGame, "zps"))
  128.         {
  129.             g_Game = Game_ZPS;
  130.         }
  131.         else if (StrEqual(sGame, "zps"))
  132.         {
  133.             g_Game = Game_ZMR;
  134.         }
  135.         else
  136.         {
  137.             g_Game = Game_Unknown;
  138.         }
  139.     }
  140.     else if (iEngine == Engine_SourceSDK2006)
  141.     {
  142.         if (StrEqual(sGame, "hl2ctf"))
  143.         {        
  144.             g_Game = Game_HL2CTF;
  145.         }
  146.         else if (StrEqual(sGame, "hidden"))
  147.         {
  148.             g_Game = Game_HIDDEN;
  149.         }
  150.         else
  151.         {
  152.             g_Game = Game_Unknown;
  153.         }
  154.     }
  155.     else if (iEngine == Engine_Unknown)
  156.     {
  157.         g_Game = Game_Unknown;
  158.     }
  159.     else
  160.     {
  161.         g_Game = Game_Unknown;
  162.     }
  163.    
  164.     // Path used for logging.
  165.     BuildPath(Path_SM, g_sLogPath, sizeof(g_sLogPath), "logs/SMAC.log");
  166.  
  167.     // Optional dependencies.
  168.     MarkNativeAsOptional("SBBanPlayer");
  169.     MarkNativeAsOptional("SBPP_BanPlayer");
  170.     MarkNativeAsOptional("IRC_MsgFlaggedChannels");
  171.     MarkNativeAsOptional("IRC_Broadcast");
  172.  
  173.     API_Init();
  174.     RegPluginLibrary("smac");
  175.  
  176.     return APLRes_Success;
  177. }
  178.  
  179. public void OnPluginStart()
  180. {
  181.     LoadTranslations("smac.phrases");
  182.  
  183.     // Convars.
  184.     g_hCvarVersion = CreateConVar("smac_version", SMAC_VERSION, "SourceMod Anti-Cheat", FCVAR_NOTIFY|FCVAR_DONTRECORD);
  185.     OnVersionChanged(g_hCvarVersion, "", "");
  186.     g_hCvarVersion.AddChangeHook(OnVersionChanged);
  187.  
  188.     g_hCvarWelcomeMsg = CreateConVar("smac_welcomemsg", "0", "Display a message saying that your server is protected.", 0, true, 0.0, true, 1.0);
  189.     g_hCvarBanDuration = CreateConVar("smac_ban_duration", "0", "The duration in minutes used for automatic bans. (0 = Permanent)", 0, true, 0.0);
  190.     g_hCvarLogVerbose = CreateConVar("smac_log_verbose", "0", "Include extra information about a client being logged.", 0, true, 0.0, true, 1.0);
  191.     g_hCvarIrcMode = CreateConVar("smac_irc_mode", "1", "Which messages should be sent to IRC plugins. (1 = Admin notices, 2 = Mimic log)", 0, true, 1.0, true, 2.0);
  192.  
  193.     // Commands.
  194.     RegAdminCmd("smac_status", Command_Status, ADMFLAG_GENERIC, "View the server's player status.");
  195. }
  196.  
  197. public void OnAllPluginsLoaded()
  198. {
  199.     // Don't clutter the config if they aren't using IRC anyway.
  200.     if (!SOURCEIRC_AVAILABLE() && !IRCRELAY_AVAILABLE())
  201.     {
  202.         g_hCvarVersion.Flags |= FCVAR_DONTRECORD;
  203.     }
  204.  
  205.     // Wait for other modules to create their convars.
  206.     AutoExecConfig(true, "smac");
  207.  
  208.     PrintToServer("SourceMod Anti-Cheat %s has been successfully loaded.", SMAC_VERSION);
  209. }
  210.  
  211. public void OnVersionChanged(ConVar convar, char[] oldValue, char[] newValue)
  212. {
  213.     if (!StrEqual(newValue, SMAC_VERSION))
  214.     {
  215.         convar.SetString(SMAC_VERSION, false, false);
  216.     }
  217. }
  218.  
  219. public void OnClientPutInServer(int client)
  220. {
  221.     if (g_hCvarWelcomeMsg.BoolValue)
  222.     {
  223.         CreateTimer(10.0, Timer_WelcomeMsg, GetClientSerial(client), TIMER_FLAG_NO_MAPCHANGE);
  224.     }
  225. }
  226.  
  227. public Action Timer_WelcomeMsg(Handle timer, any serial)
  228. {
  229.     int client = GetClientFromSerial(serial);
  230.  
  231.     if (IS_CLIENT(client) && IsClientInGame(client))
  232.     {
  233.         CPrintToChat(client, "%t%t", "SMAC_Tag", "SMAC_WelcomeMsg");
  234.     }
  235.  
  236.     return Plugin_Stop;
  237. }
  238.  
  239. public Action Command_Status(int client, int args)
  240. {
  241.     PrintToConsole(client, "%s  %-40s %s", "UserID", "AuthID", "Name");
  242.  
  243.     char sAuthID[MAX_AUTHID_LENGTH];
  244.  
  245.     for (int i = 1; i <= MaxClients; i++)
  246.     {
  247.         if (!IsClientConnected(i))
  248.         {
  249.             continue;
  250.         }
  251.        
  252.         if (!GetClientAuthId(i, AuthId_Steam2, sAuthID, sizeof(sAuthID), true))
  253.         {
  254.             if (GetClientAuthId(i, AuthId_Steam2, sAuthID, sizeof(sAuthID), false))
  255.             {
  256.                 Format(sAuthID, sizeof(sAuthID), "%s (Not Validated)", sAuthID);
  257.             }
  258.             else
  259.             {
  260.                 strcopy(sAuthID, sizeof(sAuthID), "Unknown");
  261.             }
  262.         }
  263.  
  264.         PrintToConsole(client, "%6d  %-40s %N", GetClientUserId(i), sAuthID, i);
  265.     }
  266.  
  267.     return Plugin_Handled;
  268. }
  269.  
  270. void SMAC_RelayToIRC(const char[] format, any ...)
  271. {
  272.     char sBuffer[256];
  273.     SetGlobalTransTarget(LANG_SERVER);
  274.     VFormat(sBuffer, sizeof(sBuffer), format, 2);
  275.  
  276.     if (SOURCEIRC_AVAILABLE())
  277.     {
  278.         IRC_MsgFlaggedChannels("ticket", sBuffer);
  279.     }
  280.     if (IRCRELAY_AVAILABLE())
  281.     {
  282.         IRC_Broadcast(IrcChannel_Private, sBuffer);
  283.     }
  284. }
  285.  
  286. /* API - Natives & Forwards */
  287.  
  288. Handle g_OnCheatDetected = INVALID_HANDLE;
  289.  
  290. void API_Init()
  291. {
  292.     CreateNative("SMAC_GetGameType",        Native_GetGameType);
  293.     CreateNative("SMAC_Log",                Native_Log);
  294.     CreateNative("SMAC_LogAction",          Native_LogAction);
  295.     CreateNative("SMAC_Ban",                Native_Ban);
  296.     CreateNative("SMAC_PrintAdminNotice",   Native_PrintAdminNotice);
  297.     CreateNative("SMAC_CreateConVar",       Native_CreateConVar);
  298.     CreateNative("SMAC_CheatDetected",      Native_CheatDetected);
  299.  
  300.     g_OnCheatDetected = CreateGlobalForward("SMAC_OnCheatDetected", ET_Event, Param_Cell, Param_String, Param_Cell, Param_Cell);
  301. }
  302.  
  303. // native GameType:SMAC_GetGameType();
  304. public any Native_GetGameType(Handle plugin, int numParams)
  305. {
  306.     return view_as<GameType>(g_Game);
  307. }
  308.  
  309. // native SMAC_Log(const String:format[], any:...);
  310. public any Native_Log(Handle plugin, int numParams)
  311. {
  312.     char sFilename[64], sBuffer[256];
  313.     GetPluginBasename(plugin, sFilename, sizeof(sFilename));
  314.     FormatNativeString(0, 1, 2, sizeof(sBuffer), _, sBuffer);
  315.     LogToFileEx(g_sLogPath, "[%s] %s", sFilename, sBuffer);
  316.  
  317.     // Relay log to IRC.
  318.     if (GetConVarInt(g_hCvarIrcMode) == 2)
  319.     {
  320.         SMAC_RelayToIRC("[%s] %s", sFilename, sBuffer);
  321.     }
  322. }
  323.  
  324. // native SMAC_LogAction(client, const String:format[], any:...);
  325. public any Native_LogAction(Handle plugin, int numParams)
  326. {
  327.     int client = GetNativeCell(1);
  328.  
  329.     if (!IS_CLIENT(client) || !IsClientConnected(client))
  330.     {
  331.         ThrowNativeError(SP_ERROR_INDEX, "Client index %i is invalid", client);
  332.     }
  333.  
  334.     char sAuthID[MAX_AUTHID_LENGTH];
  335.     if (!GetClientAuthId(client, AuthId_Steam2, sAuthID, sizeof(sAuthID), true))
  336.     {
  337.         if (GetClientAuthId(client, AuthId_Steam2, sAuthID, sizeof(sAuthID), false))
  338.         {
  339.             Format(sAuthID, sizeof(sAuthID), "%s (Not Validated)", sAuthID);
  340.         }
  341.         else
  342.         {
  343.             strcopy(sAuthID, sizeof(sAuthID), "Unknown");
  344.         }
  345.     }
  346.  
  347.     char sIP[17];
  348.     if (!GetClientIP(client, sIP, sizeof(sIP)))
  349.     {
  350.         strcopy(sIP, sizeof(sIP), "Unknown");
  351.     }
  352.  
  353.     char sVersion[16], sFilename[64], sBuffer[512];
  354.     GetPluginInfo(plugin, PlInfo_Version, sVersion, sizeof(sVersion));
  355.     GetPluginBasename(plugin, sFilename, sizeof(sFilename));
  356.     FormatNativeString(0, 2, 3, sizeof(sBuffer), _, sBuffer);
  357.  
  358.     // Verbose client logging.
  359.     if (GetConVarBool(g_hCvarLogVerbose) && IsClientInGame(client))
  360.     {
  361.         char sMap[MAX_MAPNAME_LENGTH], sWeapon[32];
  362.         float vOrigin[3], vAngles[3];
  363.         int iTeam, iLatency;
  364.  
  365.         GetCurrentMap(sMap, sizeof(sMap));
  366.         GetClientAbsOrigin(client, vOrigin);
  367.         GetClientEyeAngles(client, vAngles);
  368.         GetClientWeapon(client, sWeapon, sizeof(sWeapon));
  369.         iTeam = GetClientTeam(client);
  370.         iLatency = RoundToNearest(GetClientAvgLatency(client, NetFlow_Outgoing) * 1000.0);
  371.  
  372.         LogToFileEx(g_sLogPath,
  373.         "[%s | %s] %N (ID: %s | IP: %s) %s\n\tMap: %s | Origin: %.0f %.0f %.0f | Angles: %.0f %.0f %.0f | Weapon: %s | Team: %i | Latency: %ims",
  374.             sFilename,
  375.             sVersion,
  376.             client,
  377.             sAuthID,
  378.             sIP,
  379.             sBuffer,
  380.             sMap,
  381.             vOrigin[0], vOrigin[1], vOrigin[2],
  382.             vAngles[0], vAngles[1], vAngles[2],
  383.             sWeapon,
  384.             iTeam,
  385.             iLatency);
  386.     }
  387.     else
  388.     {
  389.         LogToFileEx(g_sLogPath, "[%s | %s] %N (ID: %s | IP: %s) %s", sFilename, sVersion, client, sAuthID, sIP, sBuffer);
  390.     }
  391.  
  392.     // Relay minimal log to IRC.
  393.     if (GetConVarInt(g_hCvarIrcMode) == 2)
  394.     {
  395.         SMAC_RelayToIRC("[%s | %s] %N (ID: %s | IP: %s) %s", sFilename, sVersion, client, sAuthID, sIP, sBuffer);
  396.     }
  397. }
  398.  
  399. // native SMAC_Ban(client, const String:reason[], any:...);
  400. public any Native_Ban(Handle plugin, int numParams)
  401. {
  402.     char sVersion[16], sReason[256];
  403.     int client = GetNativeCell(1);
  404.     int duration = g_hCvarBanDuration.IntValue;
  405.  
  406.     GetPluginInfo(plugin, PlInfo_Version, sVersion, sizeof(sVersion));
  407.     FormatNativeString(0, 2, 3, sizeof(sReason), _, sReason);
  408.     Format(sReason, sizeof(sReason), "SMAC %s: %s", sVersion, sReason);
  409.  
  410.     if (SBPP_AVAILABLE())
  411.     {
  412.         SBPP_BanPlayer(0, client, duration, sReason);
  413.     }
  414.     else if (SOURCEBANS_AVAILABLE())
  415.     {
  416.         SBBanPlayer(0, client, duration, sReason);
  417.     }
  418.     else
  419.     {
  420.         char sKickMsg[256];
  421.         FormatEx(sKickMsg, sizeof(sKickMsg), "%T", "SMAC_Banned", client);
  422.         BanClient(client, duration, BANFLAG_AUTO, sReason, sKickMsg, "SMAC");
  423.     }
  424.  
  425.     if(IsClientConnected(client))
  426.     {
  427.         KickClient(client, sReason);
  428.     }
  429. }
  430.  
  431. // native SMAC_PrintAdminNotice(const String:format[], any:...);
  432. public any Native_PrintAdminNotice(Handle plugin, int numParams)
  433. {
  434.     char sBuffer[192];
  435.  
  436.     for (int i = 1; i <= MaxClients; i++)
  437.     {
  438.         if (IsClientInGame(i) && CheckCommandAccess(i, "smac_admin_notices", ADMFLAG_GENERIC, true))
  439.         {
  440.             SetGlobalTransTarget(i);
  441.             FormatNativeString(0, 1, 2, sizeof(sBuffer), _, sBuffer);
  442.             CPrintToChat(i, "%t%s", "SMAC_Tag", sBuffer);
  443.         }
  444.     }
  445.  
  446.     // Relay admin notice to IRC.
  447.     if (g_hCvarIrcMode.IntValue == 1)
  448.     {
  449.         SetGlobalTransTarget(LANG_SERVER);
  450.         FormatNativeString(0, 1, 2, sizeof(sBuffer), _, sBuffer);
  451.         Format(sBuffer, sizeof(sBuffer), "%t%s", "SMAC_Tag", sBuffer);
  452.         CRemoveTags(sBuffer, sizeof(sBuffer));
  453.         SMAC_RelayToIRC(sBuffer);
  454.     }
  455. }
  456.  
  457. // native Handle:SMAC_CreateConVar(const String:name[], const String:defaultValue[], const String:description[]="", flags=0, bool:hasMin=false, Float:min=0.0, bool:hasMax=false, Float:max=0.0);
  458. public any Native_CreateConVar(Handle plugin, int numParams)
  459. {
  460.     char name[64], defaultValue[16], description[192];
  461.     GetNativeString(1, name, sizeof(name));
  462.     GetNativeString(2, defaultValue, sizeof(defaultValue));
  463.     GetNativeString(3, description, sizeof(description));
  464.  
  465.     int flags = GetNativeCell(4);
  466.     bool hasMin = view_as<bool>(GetNativeCell(5));
  467.     float min = view_as<float>(GetNativeCell(6));
  468.     bool hasMax = view_as<bool>(GetNativeCell(7));
  469.     float max = view_as<float>(GetNativeCell(8));
  470.  
  471.     char sFilename[64];
  472.     GetPluginBasename(plugin, sFilename, sizeof(sFilename));
  473.     Format(description, sizeof(description), "[%s] %s", sFilename, description);
  474.  
  475.     return CreateConVar(name, defaultValue, description, flags, hasMin, min, hasMax, max);
  476. }
  477.  
  478. // native Action:SMAC_CheatDetected(client, DetectionType:type = Detection_Unknown, Handle:info = INVALID_HANDLE);
  479. public int Native_CheatDetected(Handle plugin, int numParams)
  480. {
  481.     int client = GetNativeCell(1);
  482.  
  483.     if (!IS_CLIENT(client) || !IsClientConnected(client))
  484.     {
  485.         ThrowNativeError(SP_ERROR_INDEX, "Client index %i is invalid", client);
  486.     }
  487.  
  488.     // Block duplicate detections.
  489.     if (IsClientInKickQueue(client))
  490.     {
  491.         return view_as<int>(Plugin_Handled);
  492.     }
  493.  
  494.     char sFilename[64];
  495.     GetPluginBasename(plugin, sFilename, sizeof(sFilename));
  496.  
  497.     DetectionType type = Detection_Unknown;
  498.     Handle info = INVALID_HANDLE;
  499.  
  500.     if (numParams == 3)
  501.     {
  502.         // caller is using newer cheat detected native
  503.         type = view_as<DetectionType>(GetNativeCell(2));
  504.         info = view_as<Handle>(GetNativeCell(3));
  505.     }
  506.  
  507.     // forward Action:SMAC_OnCheatDetected(client, const String:module[], DetectionType:type, Handle:info);
  508.     Action result = Plugin_Continue;
  509.     Call_StartForward(g_OnCheatDetected);
  510.     Call_PushCell(client);
  511.     Call_PushString(sFilename);
  512.     Call_PushCell(type);
  513.     Call_PushCell(info);
  514.     Call_Finish(result);
  515.  
  516.     return view_as<int>(result);
  517. }

N/U PasteBin is for source code and general debugging text.

Login or Register to edit, delete and keep track of your pastes and more.

Raw Paste

Login or Register to edit or fork this paste. It's free.