initial commit: change in oryx is only outcommenting KickClient. Change in oryx-scroll is changing the message send to the native

This commit is contained in:
jenz 2022-06-11 23:02:43 +02:00
parent 153f1c28ce
commit 2c5820dd3d
7 changed files with 4751 additions and 0 deletions

View File

@ -0,0 +1,38 @@
#if defined _tas_included
#endinput
#endif
#define _tas_included
native bool TAS_InEditMode(int client);
native bool TAS_IsPaused(int client);
native ArrayList TAS_GetRunHandle(int client);
native int TAS_GetCurrentFrame(int client);
forward void OnTASPauseChanged(int client, bool paused);
forward void OnTASFrameRecorded(int client, int frame);
public SharedPlugin __pl_tas =
{
name = "tas",
file = "bTimes-tas.smx",
#if defined REQUIRE_PLUGIN
required = 1,
#else
required = 0,
#endif
};
#if !defined REQUIRE_PLUGIN
public void __pl_tas_SetNTVOptional()
{
MarkNativeAsOptional("TAS_InEditMode");
MarkNativeAsOptional("TAS_IsPaused");
MarkNativeAsOptional("TAS_GetRunHandle");
MarkNativeAsOptional("TAS_GetCurrentFrame");
}
#endif

View File

@ -0,0 +1,89 @@
#if defined _btimes_timer_included
#endinput
#endif
#define _btimes_timer_included
enum styleConfig
{
String:Name[32],
String:Name_Short[32],
bool:Enabled,
bool:TempEnabled,
bool:AllowType[2],
bool:Freestyle,
bool:Freestyle_Unrestrict,
bool:Freestyle_EzHop,
bool:Freestyle_Auto,
bool:Auto,
bool:EzHop,
Float:Gravity,
Float:RunSpeed,
Float:MaxVel,
Float:MinFps,
bool:CalcSync,
bool:Prevent_Left,
bool:Prevent_Right,
bool:Prevent_Back,
bool:Prevent_Forward,
bool:Require_Left,
bool:Require_Right,
bool:Require_Back,
bool:Require_Forward,
bool:Hud_Style,
bool:Hud_Strafes,
bool:Hud_Jumps,
bool:Count_Left_Strafe,
bool:Count_Right_Strafe,
bool:Count_Back_Strafe,
bool:Count_Forward_Strafe,
bool:Ghost_Use[2],
bool:Ghost_Save[2],
Float:PreSpeed,
Float:SlowedSpeed,
bool:Special,
String:Special_Key[32],
bool:GunJump,
String:GunJump_Weapon[64],
bool:UnrealPhys,
AirAcceleration,
bool:EnableBunnyhopping,
StyleConfig
};
/*
* Gets a client's style (Normal, Sideways, etc..).
*
* @param client Client index
*
* @return The client's style.
*/
native int GetClientStyle(int client);
/*
* Gets the complete configuration for a specified style.
*
* @param Style The style to get a configuration for.
* @param Properties The buffer to store all the style properties, (properties are listed in the StyleConfig enum)
*
* @return True if the style exists, false otherwise.
*/
native bool Style_GetConfig(int Style, any Properties[StyleConfig]);
public SharedPlugin __pl_btimes_timer =
{
name = "timer",
file = "bTimes-timer.smx",
#if defined REQUIRE_PLUGIN
required = 1
#else
required = 0
#endif
};
#if !defined REQUIRE_PLUGIN
public void __pl_btimes_timer_SetNTVOptional()
{
MarkNativeAsOptional("GetClientStyle");
MarkNativeAsOptional("Style_GetConfig");
}
#endif

View File

@ -0,0 +1,484 @@
// code by Dr!fter https://forums.alliedmods.net/showthread.php?t=180114
#if defined _dhooks_included
#endinput
#endif
#define _dhooks_included
enum ObjectValueType
{
ObjectValueType_Int = 0,
ObjectValueType_Bool,
ObjectValueType_Ehandle,
ObjectValueType_Float,
ObjectValueType_CBaseEntityPtr,
ObjectValueType_IntPtr,
ObjectValueType_BoolPtr,
ObjectValueType_EhandlePtr,
ObjectValueType_FloatPtr,
ObjectValueType_Vector,
ObjectValueType_VectorPtr,
ObjectValueType_CharPtr,
ObjectValueType_String
};
enum ListenType
{
ListenType_Created,
ListenType_Deleted
};
enum ReturnType
{
ReturnType_Unknown,
ReturnType_Void,
ReturnType_Int,
ReturnType_Bool,
ReturnType_Float,
ReturnType_String, //Note this is a string_t
ReturnType_StringPtr, //Note this is a string_t *
ReturnType_CharPtr,
ReturnType_Vector,
ReturnType_VectorPtr,
ReturnType_CBaseEntity,
ReturnType_Edict
};
enum HookParamType
{
HookParamType_Unknown,
HookParamType_Int,
HookParamType_Bool,
HookParamType_Float,
HookParamType_String, //Note this is a string_t
HookParamType_StringPtr, //Note this is a string_t *
HookParamType_CharPtr,
HookParamType_VectorPtr,
HookParamType_CBaseEntity,
HookParamType_ObjectPtr,
HookParamType_Edict,
HookParamType_Object
};
enum ThisPointerType
{
ThisPointer_Ignore,
ThisPointer_CBaseEntity,
ThisPointer_Address
};
enum HookType
{
HookType_Entity,
HookType_GameRules,
HookType_Raw
};
enum MRESReturn
{
MRES_ChangedHandled = -2, // Use changed values and return MRES_Handled
MRES_ChangedOverride, // Use changed values and return MRES_Override
MRES_Ignored, // plugin didn't take any action
MRES_Handled, // plugin did something, but real function should still be called
MRES_Override, // call real function, but use my return value
MRES_Supercede // skip real function; use my return value
};
enum DHookPassFlag
{
DHookPass_ByVal = (1<<0),
DHookPass_ByRef = (1<<1)
};
typeset ListenCB
{
//Deleted
function void (int entity);
//Created
function void (int entity, const char[] classname);
};
typeset DHookRemovalCB
{
function void (int hookid);
};
typeset DHookCallback
{
//Function Example: void Ham::Test() with this pointer ignore
function MRESReturn ();
//Function Example: void Ham::Test() with this pointer passed
function MRESReturn (int pThis);
//Function Example: void Ham::Test(int cake) with this pointer ignore
function MRESReturn (Handle hParams);
//Function Example: void Ham::Test(int cake) with this pointer passed
function MRESReturn (int pThis, Handle hParams);
//Function Example: int Ham::Test() with this pointer ignore
function MRESReturn (Handle hReturn);
//Function Example: int Ham::Test() with this pointer passed
function MRESReturn (int pThis, Handle hReturn);
//Function Example: int Ham::Test(int cake) with this pointer ignore
function MRESReturn (Handle hReturn, Handle hParams);
//Function Example: int Ham::Test(int cake) with this pointer passed
function MRESReturn (int pThis, Handle hReturn, Handle hParams);
//Address NOW
//Function Example: void Ham::Test() with this pointer passed
function MRESReturn (Address pThis);
//Function Example: void Ham::Test(int cake) with this pointer passed
function MRESReturn (Address pThis, Handle hParams);
//Function Example: int Ham::Test() with this pointer passed
function MRESReturn (Address pThis, Handle hReturn);
//Function Example: int Ham::Test(int cake) with this pointer passed
function MRESReturn (Address pThis, Handle hReturn, Handle hParams);
};
/* Adds an entity listener hook
*
* @param type Type of listener to add
* @param callback Callback to use
*
* @noreturn
*/
native void DHookAddEntityListener(ListenType type, ListenCB callback);
/* Removes an entity listener hook
*
* @param type Type of listener to remove
* @param callback Callback this listener was using
*
* @return True if one was removed false otherwise.
*/
native bool DHookRemoveEntityListener(ListenType type, ListenCB callback);
/* Creates a hook
*
* @param offset vtable offset for function to hook
* @param hooktype Type of hook
* @param returntype Type type of return
* @param thistype Type of this pointer or ignore (ignore can be used if not needed)
* @param callback Callback function
*
* @return Returns setup handle for the hook or INVALID_HANDLE.
*/
native Handle DHookCreate(int offset, HookType hooktype, ReturnType returntype, ThisPointerType thistype, DHookCallback callback);
/* Adds param to a hook setup
*
* @param setup Setup handle to add the param to.
* @param type Param type
* @param size Used for Objects (not Object ptr) to define the size of the object.
* @param flag Used to change the pass type.
*
* @error Invalid setup handle or too many params added (request upping the max in thread)
* @noreturn
*/
native void DHookAddParam(Handle setup, HookParamType type, int size=-1, DHookPassFlag flag=DHookPass_ByVal);
//native DHookAddParam(Handle:setup, HookParamType:type);
/* Hook entity
*
* @param setup Setup handle to use to add the hook.
* @param post True to make the hook a post hook. (If you need to change the retunr value or need the return value use a post hook! If you need to change params and return use a pre and post hook!)
* @param entity Entity index to hook on.
* @param removalcb Callback for when the hook is removed (Entity hooks are auto-removed on entity destroyed and will call this callback)
*
* @error Invalid setup handle, invalid entity or invalid hook type.
* @return -1 on fail a hookid on success
*/
native int DHookEntity(Handle setup, bool post, int entity, DHookRemovalCB removalcb=INVALID_FUNCTION);
/* Hook gamerules
*
* @param setup Setup handle to use to add the hook.
* @param post True to make the hook a post hook. (If you need to change the retunr value or need the return value use a post hook! If you need to change params and return use a pre and post hook!)
* @param removalcb Callback for when the hook is removed (Game rules hooks are auto-removed on map end and will call this callback)
*
* @error Invalid setup handle, failing to get gamerules pointer or invalid hook type.
* @return -1 on fail a hookid on success
*/
native int DHookGamerules(Handle setup, bool post, DHookRemovalCB removalcb=INVALID_FUNCTION);
/* Hook a raw pointer
*
* @param setup Setup handle to use to add the hook.
* @param post True to make the hook a post hook. (If you need to change the retunr value or need the return value use a post hook! If you need to change params and return use a pre and post hook!)
* @param addr This pointer address.
* @param removalcb Callback for when the hook is removed (Entity hooks are auto-removed on entity destroyed and will call this callback)
*
* @error Invalid setup handle, invalid address or invalid hook type.
* @return -1 on fail a hookid on success
*/
native int DHookRaw(Handle setup, bool post, Address addr, DHookRemovalCB removalcb=INVALID_FUNCTION);
/* Remove hook by hook id
*
* @param hookid Hook id to remove
*
* @return true on success false otherwise
* @note This will not fire the removal callback!
*/
native bool DHookRemoveHookID(int hookid);
/* Get param value (Only use for: int, entity, bool or float param types)
*
* @param hParams Handle to params structure
* @param num Param number to get. (Example if the function has 2 params and you need the value of the first param num would be 1. 0 Will return the number of params stored)
*
* @error Invalid handle. Invalid param number. Invalid param type.
* @return value if num greater than 0. If 0 returns paramcount.
*/
native any DHookGetParam(Handle hParams, int num);
/* Get vector param value
*
* @param hParams Handle to params structure
* @param num Param number to get. (Example if the function has 2 params and you need the value of the first param num would be 1.)
* @param vec Vector buffer to store result.
*
* @error Invalid handle. Invalid param number. Invalid param type.
* @noreturn
*/
native void DHookGetParamVector(Handle hParams, int num, float vec[3]);
/* Get string param value
*
* @param hParams Handle to params structure
* @param num Param number to get. (Example if the function has 2 params and you need the value of the first param num would be 1.)
* @param buffer String buffer to store result
* @param size Buffer size
*
* @error Invalid handle. Invalid param number. Invalid param type.
* @noreturn
*/
native void DHookGetParamString(Handle hParams, int num, char[] buffer, int size);
/* Set param value (Only use for: int, entity, bool or float param types)
*
* @param hParams Handle to params structure
* @params num Param number to set (Example if the function has 2 params and you need to set the value of the first param num would be 1.)
* @param value Value to set it as (only pass int, bool, float or entity index)
*
* @error Invalid handle. Invalid param number. Invalid param type.
* @noreturn
*/
native void DHookSetParam(Handle hParams, int num, any value);
/* Set vector param value
*
* @param hParams Handle to params structure
* @params num Param number to set (Example if the function has 2 params and you need to set the value of the first param num would be 1.)
* @param vec Value to set vector as.
*
* @error Invalid handle. Invalid param number. Invalid param type.
* @noreturn
*/
native void DHookSetParamVector(Handle hParams, int num, float vec[3]);
/* Set string param value
*
* @param hParams Handle to params structure
* @params num Param number to set (Example if the function has 2 params and you need to set the value of the first param num would be 1.)
* @param value Value to set string as.
*
* @error Invalid handle. Invalid param number. Invalid param type.
* @noreturn
*/
native void DHookSetParamString(Handle hParams, int num, char[] value);
/* Get return value (Only use for: int, entity, bool or float return types)
*
* @param hReturn Handle to return structure
*
* @error Invalid Handle, invalid type.
* @return Returns default value if prehook returns actual value if post hook.
*/
native any DHookGetReturn(Handle hReturn);
/* Get return vector value
*
* @param hReturn Handle to return structure
* @param vec Vector buffer to store result in. (In pre hooks will be default value (0.0,0.0,0.0))
*
* @error Invalid Handle, invalid type.
* @noreturn
*/
native void DHookGetReturnVector(Handle hReturn, float vec[3]);
/* Get return string value
*
* @param hReturn Handle to return structure
* @param buffer String buffer to store result in. (In pre hooks will be default value "")
* @param size String buffer size
*
* @error Invalid Handle, invalid type.
* @noreturn
*/
native void DHookGetReturnString(Handle hReturn, char[] buffer, int size);
/* Set return value (Only use for: int, entity, bool or float return types)
*
* @param hReturn Handle to return structure
* @param value Value to set return as
*
* @error Invalid Handle, invalid type.
* @noreturn
*/
native void DHookSetReturn(Handle hReturn, any value);
/* Set return vector value
*
* @param hReturn Handle to return structure
* @param vec Value to set return vector as
*
* @error Invalid Handle, invalid type.
* @noreturn
*/
native void DHookSetReturnVector(Handle hReturn, float vec[3]);
/* Set return string value
*
* @param hReturn Handle to return structure
* @param value Value to set return string as
*
* @error Invalid Handle, invalid type.
* @noreturn
*/
native void DHookSetReturnString(Handle hReturn, char[] value);
//WE SHOULD WRAP THESE AROUND STOCKS FOR NON PTR AS WE SUPPORT BOTH WITH THESE NATIVE'S
/* Gets an objects variable value
*
* @param hParams Handle to params structure
* @param num Param number to get.
* @param offset Offset within the object to the var to get.
* @param type Type of var it is
*
* @error Invalid handle. Invalid param number. Invalid param type. Invalid Object type.
* @return Value of the objects var. If EHANDLE type or entity returns entity index.
*/
native any DHookGetParamObjectPtrVar(Handle hParams, int num, int offset, ObjectValueType type);
/* Sets an objects variable value
*
* @param hParams Handle to params structure
* @param num Param number to set.
* @param offset Offset within the object to the var to set.
* @param type Type of var it is
* @param value The value to set the var to.
*
* @error Invalid handle. Invalid param number. Invalid param type. Invalid Object type.
* @noreturn
*/
native void DHookSetParamObjectPtrVar(Handle hParams, int num, int offset, ObjectValueType type, any value);
/* Gets an objects vector variable value
*
* @param hParams Handle to params structure
* @param num Param number to get.
* @param offset Offset within the object to the var to get.
* @param type Type of var it is
* @param buffer Buffer to store the result vector
*
* @error Invalid handle. Invalid param number. Invalid param type. Invalid Object type.
* @noreturn
*/
native void DHookGetParamObjectPtrVarVector(Handle hParams, int num, int offset, ObjectValueType type, float buffer[3]);
/* Sets an objects vector variable value
*
* @param hParams Handle to params structure
* @param num Param number to set.
* @param offset Offset within the object to the var to set.
* @param type Type of var it is
* @param value The value to set the vector var to.
*
* @error Invalid handle. Invalid param number. Invalid param type. Invalid Object type.
* @noreturn
*/
native void DHookSetParamObjectPtrVarVector(Handle hParams, int num, int offset, ObjectValueType type, float value[3]);
/* Gets an objects string variable value
*
* @param hParams Handle to params structure
* @param num Param number to get.
* @param offset Offset within the object to the var to get.
* @param type Type of var it is
* @param buffer Buffer to store the result vector
* @param size Size of the buffer
*
* @error Invalid handle. Invalid param number. Invalid param type. Invalid Object type.
* @noreturn
*/
native void DHookGetParamObjectPtrString(Handle hParams, int num, int offset, ObjectValueType type, char[] buffer, int size);
/* Checks if a pointer param is null
*
* @param hParams Handle to params structure
* @param num Param number to check.
*
* @error Non pointer param
* @return True if null false otherwise.
*/
native bool DHookIsNullParam(Handle hParams, int num);
public Extension __ext_dhooks =
{
name = "dhooks",
file = "dhooks.ext",
#if defined AUTOLOAD_EXTENSIONS
autoload = 1,
#else
autoload = 0,
#endif
#if defined REQUIRE_EXTENSIONS
required = 1,
#else
required = 0,
#endif
};
#if !defined REQUIRE_EXTENSIONS
public void __ext_dhooks_SetNTVOptional()
{
MarkNativeAsOptional("DHookAddEntityListener");
MarkNativeAsOptional("DHookRemoveEntityListener");
MarkNativeAsOptional("DHookCreate");
MarkNativeAsOptional("DHookAddParam");
MarkNativeAsOptional("DHookEntity");
MarkNativeAsOptional("DHookGamerules");
MarkNativeAsOptional("DHookRaw");
MarkNativeAsOptional("DHookRemoveHookID");
MarkNativeAsOptional("DHookGetParam");
MarkNativeAsOptional("DHookGetParamVector");
MarkNativeAsOptional("DHookGetParamString");
MarkNativeAsOptional("DHookSetParam");
MarkNativeAsOptional("DHookSetParamVector");
MarkNativeAsOptional("DHookSetParamString");
MarkNativeAsOptional("DHookGetReturn");
MarkNativeAsOptional("DHookGetReturnVector");
MarkNativeAsOptional("DHookGetReturnString");
MarkNativeAsOptional("DHookSetReturn");
MarkNativeAsOptional("DHookSetReturnVector");
MarkNativeAsOptional("DHookSetReturnString");
MarkNativeAsOptional("DHookGetParamObjectPtrVar");
MarkNativeAsOptional("DHookSetParamObjectPtrVar");
MarkNativeAsOptional("DHookGetParamObjectPtrVarVector");
MarkNativeAsOptional("DHookSetParamObjectPtrVarVector");
MarkNativeAsOptional("DHookIsNullParam");
MarkNativeAsOptional("DHookGetParamObjectPtrString");
}
#endif

View File

@ -0,0 +1,156 @@
/* Oryx AC: collects and analyzes statistics to find some cheaters in CS:S, CS:GO, and TF2 bunnyhop.
* Copyright (C) 2018 Nolan O.
* Copyright (C) 2018 shavit.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#if defined _oryx_included
#endinput
#endif
#define _oryx_included
#define ORYX_VERSION "1.3.1"
/**
* List of current detection descriptions:
*
* "Acute TR formatter"
* "+left/right bypasser"
* "Prestrafe tool"
* "Average strafe too close to 0"
* "Too many perfect strafes"
* "Movement config"
* "Unsynchronised movement"
* "Invalid wish velocity"
* "Script on scroll"
* "Hyperscroll"
*/
enum
{
TRIGGER_LOW, // Reachable by skilled players occasionally. Not always necessary before a med detect.
TRIGGER_MEDIUM, // Reachable by skilled players by unlikely chance.
TRIGGER_HIGH, // Only theoretically reachable by the aligning of stars by the gods.
TRIGGER_HIGH_NOKICK, // This should really only be used for a follow up definitive detection.
TRIGGER_DEFINITIVE, // Non-skill-based detection type. 100% sure detection.
TRIGGER_TEST // Allows you to develop new detections on live servers with minimal side effects.
};
/**
* Called when Oryx gets triggered on a client.
*
* @param client Client entity index.
* @param level Level of detection as defined in the above enum.
* @param cheat Short description or name of the cheat being detected. 32 cells char array.
* @return Plugin_Continue to do nothing. Plugin_Changed to modify values. Plugin_Handled to abort kicks. Plugin_Stop to completely ignore the trigger.
*/
forward Action Oryx_OnTrigger(int client, int &level, char[] cheat);
/**
* Call to activate Oryx's trigger procedure (logging, kicking, admin notifications, etc..).
*
* @param client Client entity index.
* @param level Level of detection as defined in the above enum.
* @param cheat Short description or name of the cheat being detected.
* @return Return value of the Oryx_OnTrigger forward.
*/
native Action Oryx_Trigger(int client, int level, const char[] cheat);
/**
* Prints a message to admins' chat.
*
* @param format Formatting rules.
* @param any Variable number of format parameters.
* @noreturn
*/
native void Oryx_PrintToAdmins(const char[] format, any ...);
/**
* Prints a message to admins' console.
*
* @param format Formatting rules.
* @param any Variable number of format parameters.
* @noreturn
*/
native void Oryx_PrintToAdminsConsole(const char[] format, any ...);
/**
* Logs an entry to Oryx's log file.
*
* @param format Formatting rules.
* @param any Variable number of format parameters.
* @noreturn
*/
native void Oryx_LogMessage(const char[] format, any ...);
/**
* Checks if f1 is inbetween a specified threshold of f12.
*
* @param f1 First value.
* @param f2 Second value.
* @param frac Used as a threshold of f2 for f1 to be within.
* @return True if the test passed.
*/
native bool Oryx_WithinThreshold(float f1, float f2, float threshold);
/**
* Checks if the player has permissions to bypass Oryx.
* Will return false if `oryx_allow_bypass` is set to 0.
* With bhoptimer or bTimes v1.8.3, will return true for styles with the `oryx_bypass` special flag.
* For bTimes2, will return true if the player is in edit mode (rewind/fastforward etc).
*
* @param client Client index.
* @return True if the player can bypass the anticheat.
*/
native bool Oryx_CanBypass(int client);
/**
* A tiny function to veify if the player fits gameplay.
*
* @param client Client entity index.
* @param watrer Check for water level?
* @return True if the test passed.
*/
stock bool IsLegalMoveType(int client, bool water = true)
{
MoveType iMoveType = GetEntityMoveType(client);
return (!water || GetEntProp(client, Prop_Data, "m_nWaterLevel") < 2) &&
(GetEntityFlags(client) & FL_ATCONTROLS) == 0 &&
(iMoveType == MOVETYPE_WALK || iMoveType == MOVETYPE_ISOMETRIC || iMoveType == MOVETYPE_LADDER);
}
public SharedPlugin __pl_oryx =
{
name = "oryx",
file = "oryx.smx",
#if defined REQUIRE_PLUGIN
required = 1
#else
required = 0
#endif
};
#if !defined REQUIRE_PLUGIN
public void __pl_oryx_SetNTVOptional()
{
MarkNativeAsOptional("Oryx_CanBypass");
MarkNativeAsOptional("Oryx_LogMessage");
MarkNativeAsOptional("Oryx_PrintToAdmins");
MarkNativeAsOptional("Oryx_PrintToAdminsConsole");
MarkNativeAsOptional("Oryx_Trigger");
MarkNativeAsOptional("Oryx_WithinThreshold");
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,690 @@
/* Oryx AC: collects and analyzes statistics to find some cheaters in CS:S, CS:GO, and TF2 bunnyhop.
* Copyright (C) 2018 shavit.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
// This module is a complete rewrite, and doesn't work like the simple one written by Rusty. //'
#include <sourcemod>
#include <sdktools>
#include <oryx>
#undef REQUIRE_PLUGIN
#include <shavit>
#pragma newdecls required
#pragma semicolon 1
// Some features from my old anticheat.
#define DESC1 "Scripted jumps (havg)" // 91%+ perf over sample size
#define DESC2 "Scripted jumps (havgp)" // 87%+ perf, consistent scrolls
#define DESC3 "Scripted jumps (patt1)" // 85%+ perf, very consistent scrolls
#define DESC4 "Scripted jumps (patt2)" // 80%+ perf, inhumanly consistent scrolls
#define DESC5 "Scripted jumps (wpatt1)" // 75%+ perf, inhumanly consistent scrolls
#define DESC6 "Scripted jumps (wpatt2)" // 85%+ perf, obviously randomized scrolls
#define DESC7 "Scripted jumps (nobf)" // 40%+ perf, no scrolls before touching the ground
#define DESC8 "Scripted jumps (bf-af)" // 55%+ perf, same number of scrolls before and after touching the ground
#define DESC9 "Scripted jumps (noaf)" // 40%+ perf, no scrolls after leaving the ground
#define DESC10 "Scroll macro (highn)" // scrolls per jump are 17+, either high perf% (80%+) or consistent scrolls
// ORYX exclusive:
#define DESC11 "Scroll cheat (interval)" // interval between scrolls is consistent (<=2, and is over 3/4 of the jumps)
// TODO: Implement this:
#define DESC12 "Scroll cheat (ticks)" // average ticks on ground are inhuman
// Decrease this to make the scroll anticheat more sensitive.
// Samples will be taken from the last X jumps' data.
// If the number is too high, logs might be cut off due to the scroll patterns being too long.
#define SAMPLE_SIZE_MIN 45
#define SAMPLE_SIZE_MAX 55
// Amount of ticks between jumps to not count one.
#define TICKS_NOT_COUNT_JUMP 8
// Maximum airtime per jump in ticks before we stop measuring. This is to prevent low-gravity style bans and players spamming their scroll wheel while falling to purposely make the anti-cheat ban them.
#define TICKS_NOT_COUNT_AIR 135
// Fill scroll stats array with junk data.
// #define DEBUG_SCROLL 50
public Plugin myinfo =
{
name = "ORYX scroll module",
author = "shavit",
description = "Advanced bunnyhop script/macro detection.",
version = ORYX_VERSION,
url = "https://github.com/shavitush/Oryx-AC"
}
ConVar sv_autobunnyhopping = null;
bool gB_AutoBunnyhopping = false;
bool gB_Shavit = false;
int gI_SampleSize = 50;
enum
{
StatsArray_Scrolls,
StatsArray_BeforeGround,
StatsArray_AfterGround,
StatsArray_AverageTicks,
StatsArray_PerfectJump,
STATSARRAY_SIZE
}
enum
{
State_Nothing,
State_Landing,
State_Jumping,
State_Pressing,
State_Releasing
}
// 5 cells:
// Scrolls before this jump.
// Scrolls before touching ground (33 units from ground).
// Scrolls after leaving ground (33 units from ground).
// Average ticks between each scroll input.
// Is it a perfect jump?
ArrayList gA_JumpStats[MAXPLAYERS+1];
any gA_StatsArray[MAXPLAYERS+1][STATSARRAY_SIZE];
int gI_GroundTicks[MAXPLAYERS+1];
int gI_ReleaseTick[MAXPLAYERS+1];
int gI_AirTicks[MAXPLAYERS+1];
bool gB_PreviousGround[MAXPLAYERS+1] = { true, ... }; // Initialized as trues to prevent the first data being wrong.
int gI_PreviousButtons[MAXPLAYERS+1];
int gI_CurrentJump[MAXPLAYERS+1];
char gS_LogPath[PLATFORM_MAX_PATH];
public void OnPluginStart()
{
sv_autobunnyhopping = FindConVar("sv_autobunnyhopping");
if(sv_autobunnyhopping != null)
{
sv_autobunnyhopping.AddChangeHook(OnAutoBunnyhoppingChanged);
}
for(int i = 1; i <= MaxClients; i++)
{
if(IsClientInGame(i))
{
OnClientPutInServer(i);
}
}
RegConsoleCmd("scroll_stats", Command_PrintScrollStats, "Print the scroll stat buffer for a given player.");
LoadTranslations("common.phrases");
gB_Shavit = LibraryExists("shavit");
BuildPath(Path_SM, gS_LogPath, PLATFORM_MAX_PATH, "logs/oryx-ac-scroll.log");
}
public void OnMapStart()
{
gI_SampleSize = GetRandomInt(SAMPLE_SIZE_MIN, SAMPLE_SIZE_MAX);
}
public void OnClientPutInServer(int client)
{
gA_JumpStats[client] = new ArrayList(STATSARRAY_SIZE);
gI_CurrentJump[client] = 0;
ResetStatsArray(client);
#if defined DEBUG_SCROLL
gA_JumpStats[client].Resize(DEBUG_SCROLL);
for(int i = 0; i < DEBUG_SCROLL; i++)
{
int scrolls = GetRandomInt(7, 15);
int before = GetRandomInt(0, scrolls);
int after = scrolls - before;
gA_JumpStats[client].Set(i, scrolls, StatsArray_Scrolls);
gA_JumpStats[client].Set(i, before, StatsArray_BeforeGround);
gA_JumpStats[client].Set(i, after, StatsArray_AfterGround);
gA_JumpStats[client].Set(i, GetRandomInt(1, 2), StatsArray_AverageTicks);
}
#endif
}
public void OnClientDisconnect(int client)
{
delete gA_JumpStats[client];
}
public void OnLibraryAdded(const char[] name)
{
if(StrEqual(name, "shavit"))
{
gB_Shavit = true;
}
}
public void OnLibraryRemoved(const char[] name)
{
if(StrEqual(name, "shavit"))
{
gB_Shavit = false;
}
}
public void OnAutoBunnyhoppingChanged(ConVar convar, const char[] oldValue, const char[] newValue)
{
gB_AutoBunnyhopping = view_as<bool>(StringToInt(newValue));
}
public void OnConfigsExecuted()
{
if(sv_autobunnyhopping != null)
{
gB_AutoBunnyhopping = sv_autobunnyhopping.BoolValue;
}
}
public Action Command_PrintScrollStats(int client, int args)
{
if(args < 1)
{
ReplyToCommand(client, "Usage: scroll_stats <target>");
return Plugin_Handled;
}
char[] sArgs = new char[MAX_TARGET_LENGTH];
GetCmdArgString(sArgs, MAX_TARGET_LENGTH);
int target = FindTarget(client, sArgs);
if(target == -1)
{
return Plugin_Handled;
}
if(GetSampledJumps(target) == 0)
{
ReplyToCommand(client, "\x03%N\x01 does not have recorded jump stats.", target);
return Plugin_Handled;
}
char[] sScrollStats = new char[300];
GetScrollStatsFormatted(target, sScrollStats, 300);
ReplyToCommand(client, "Scroll stats for %N: %s", target, sScrollStats);
return Plugin_Handled;
}
void GetScrollStatsFormatted(int client, char[] buffer, int maxlength)
{
FormatEx(buffer, maxlength, "%d%% perfs, %d sampled jumps: {", GetPerfectJumps(client), GetSampledJumps(client));
int iSize = gA_JumpStats[client].Length;
int iEnd = (iSize >= gI_SampleSize)? (iSize - gI_SampleSize):0;
for(int i = iSize - 1; i >= iEnd; i--)
{
Format(buffer, maxlength, "%s %d,", buffer, gA_JumpStats[client].Get(i, StatsArray_Scrolls));
}
// Beautify the text output so that the jumps are separated inside the curly braces, without irrelevant commas.
int iPos = strlen(buffer) - 1;
if(buffer[iPos] == ',')
{
buffer[iPos] = ' ';
}
StrCat(buffer, maxlength, "}");
}
int GetSampledJumps(int client)
{
if(gA_JumpStats[client] == null)
{
return 0;
}
int iSize = gA_JumpStats[client].Length;
int iEnd = (iSize >= gI_SampleSize)? (iSize - gI_SampleSize):0;
return (iSize - iEnd);
}
int GetPerfectJumps(int client)
{
int iPerfs = 0;
int iSize = gA_JumpStats[client].Length;
int iEnd = (iSize >= gI_SampleSize)? (iSize - gI_SampleSize):0;
int iTotalJumps = (iSize - iEnd);
for(int i = iSize - 1; i >= iEnd; i--)
{
if(view_as<bool>(gA_JumpStats[client].Get(i, StatsArray_PerfectJump)))
{
iPerfs++;
}
}
if(iTotalJumps == 0) // Don't throw a divide-by-zero error.
{
return 0;
}
return RoundToZero((float(iPerfs) / iTotalJumps) * 100);
}
public Action OnPlayerRunCmd(int client, int &buttons)
{
if(gB_Shavit || !IsPlayerAlive(client) || IsFakeClient(client))
{
return Plugin_Continue;
}
return SetupMove(client, buttons);
}
public Action Shavit_OnUserCmdPre(int client, int &buttons, int &impulse, float vel[3], float angles[3], TimerStatus status, int track, int style, int mouse[2])
{
// Ignore autobhop styles.
if(Shavit_GetStyleSettingBool(style, "autobhop"))
{
return Plugin_Continue;
}
return SetupMove(client, buttons);
}
void ResetStatsArray(int client)
{
for(int i = 0; i < STATSARRAY_SIZE; i++)
{
gA_StatsArray[client][i] = 0;
}
gI_ReleaseTick[client] = GetGameTickCount();
gI_AirTicks[client] = 0;
}
public bool TRFilter_NoPlayers(int entity, int mask, any data)
{
return (entity != view_as<int>(data) || (entity < 1 || entity > MaxClients));
}
float GetGroundDistance(int client)
{
if(GetEntPropEnt(client, Prop_Send, "m_hGroundEntity") == 0)
{
return 0.0;
}
float fPosition[3];
GetClientAbsOrigin(client, fPosition);
TR_TraceRayFilter(fPosition, view_as<float>({90.0, 0.0, 0.0}), MASK_PLAYERSOLID, RayType_Infinite, TRFilter_NoPlayers, client);
float fGroundPosition[3];
if(TR_DidHit() && TR_GetEndPosition(fGroundPosition))
{
return GetVectorDistance(fPosition, fGroundPosition);
}
return 0.0;
}
Action SetupMove(int client, int buttons)
{
if((sv_autobunnyhopping != null && gB_AutoBunnyhopping) || Oryx_CanBypass(client))
{
return Plugin_Continue;
}
bool bOnGround = ((GetEntityFlags(client) & FL_ONGROUND) > 0 || GetEntProp(client, Prop_Send, "m_nWaterLevel") >= 2);
if(bOnGround)
{
gI_GroundTicks[client]++;
}
float fAbsVelocity[3];
GetEntPropVector(client, Prop_Data, "m_vecAbsVelocity", fAbsVelocity);
float fSpeed = (SquareRoot(Pow(fAbsVelocity[0], 2.0) + Pow(fAbsVelocity[1], 2.0)));
// Player isn't really playing but is just trying to make the anticheat go nuts.
if(fSpeed > 225.0 && IsLegalMoveType(client, false))
{
CollectJumpStats(client, bOnGround, buttons, fAbsVelocity[2]);
}
else
{
ResetStatsArray(client);
}
gB_PreviousGround[client] = bOnGround;
gI_PreviousButtons[client] = buttons;
return Plugin_Continue;
}
void CollectJumpStats(int client, bool bOnGround, int buttons, float fAbsVelocityZ)
{
// States
int iGroundState = State_Nothing;
int iButtonState = State_Nothing;
if(bOnGround && !gB_PreviousGround[client])
{
iGroundState = State_Landing;
}
else if(!bOnGround && gB_PreviousGround[client])
{
iGroundState = State_Jumping;
}
if((buttons & IN_JUMP) > 0 && (gI_PreviousButtons[client] & IN_JUMP) == 0)
{
iButtonState = State_Pressing;
}
else if((buttons & IN_JUMP) == 0 && (gI_PreviousButtons[client] & IN_JUMP) > 0)
{
iButtonState = State_Releasing;
}
int iTicks = GetGameTickCount();
if(iButtonState == State_Pressing)
{
gA_StatsArray[client][StatsArray_Scrolls]++;
gA_StatsArray[client][StatsArray_AverageTicks] += (iTicks - gI_ReleaseTick[client]);
if(bOnGround)
{
if((buttons & IN_JUMP) > 0)
{
gA_StatsArray[client][StatsArray_PerfectJump] = !gB_PreviousGround[client];
}
}
else
{
float fDistance = GetGroundDistance(client);
if(fDistance < 33.0)
{
if(fAbsVelocityZ > 0.0 && gI_CurrentJump[client] > 1)
{
// 'Inject' data into the previous recorded jump.
int iJump = (gI_CurrentJump[client] - 1);
int iAfter = gA_JumpStats[client].Get(iJump, StatsArray_AfterGround);
gA_JumpStats[client].Set(iJump, iAfter + 1, StatsArray_AfterGround);
}
else if(fAbsVelocityZ < 0.0)
{
gA_StatsArray[client][StatsArray_BeforeGround]++;
}
}
}
}
else if(iButtonState == State_Releasing)
{
gI_ReleaseTick[client] = iTicks;
}
if(!bOnGround && gI_AirTicks[client]++ > TICKS_NOT_COUNT_AIR)
{
ResetStatsArray(client);
return;
}
if(iGroundState == State_Landing)
{
int iScrolls = gA_StatsArray[client][StatsArray_Scrolls];
if(iScrolls == 0)
{
ResetStatsArray(client);
return;
}
if(gI_GroundTicks[client] < TICKS_NOT_COUNT_JUMP)
{
int iJump = gI_CurrentJump[client];
gA_JumpStats[client].Resize(iJump + 1);
gA_JumpStats[client].Set(iJump, iScrolls, StatsArray_Scrolls);
gA_JumpStats[client].Set(iJump, gA_StatsArray[client][StatsArray_BeforeGround], StatsArray_BeforeGround);
gA_JumpStats[client].Set(iJump, 0, StatsArray_AfterGround);
gA_JumpStats[client].Set(iJump, (gA_StatsArray[client][StatsArray_AverageTicks] / iScrolls), StatsArray_AverageTicks);
gA_JumpStats[client].Set(iJump, gA_StatsArray[client][StatsArray_PerfectJump], StatsArray_PerfectJump);
#if defined DEBUG
PrintToChat(client, "{ %d, %d, %d, %d, %d, %d }", gA_StatsArray[client][StatsArray_Scrolls],
gA_StatsArray[client][StatsArray_BeforeGround],
(iJump > 0)? gA_JumpStats[client].Get(iJump - 1, gA_StatsArray[client][StatsArray_AfterGround]):0,
gA_StatsArray[client][StatsArray_GroundTicks],
(gA_StatsArray[client][StatsArray_AverageTicks] / iScrolls),
gA_StatsArray[client][StatsArray_PerfectJump]);
#endif
gI_CurrentJump[client]++;
}
gI_GroundTicks[client] = 0;
ResetStatsArray(client);
}
else if(iGroundState == State_Jumping && gI_CurrentJump[client] >= gI_SampleSize)
{
AnalyzeStats(client);
}
}
int Min(int a, int b)
{
return (a < b)? a:b;
}
int Max(int a, int b)
{
return (a > b)? a:b;
}
int Abs(int num)
{
return (num < 0)? -num:num;
}
void AnalyzeStats(int client)
{
int iPerfs = GetPerfectJumps(client);
// "Pattern analysis"
int iVeryHighNumber = 0;
int iSameAsNext = 0;
int iCloseToNext = 0;
int iBadIntervals = 0;
int iLowBefores = 0;
int iLowAfters = 0;
int iSameBeforeAfter = 0;
for(int i = (gI_CurrentJump[client] - gI_SampleSize); i < gI_CurrentJump[client] - 1; i++)
{
// TODO: Cache iNextScrolls for the next time this code is ran. I'm tired and can't really think right now..
int iCurrentScrolls = gA_JumpStats[client].Get(i, StatsArray_Scrolls);
int iTicks = gA_JumpStats[client].Get(i, StatsArray_AverageTicks);
int iBefores = gA_JumpStats[client].Get(i, StatsArray_BeforeGround);
int iAfters = gA_JumpStats[client].Get(i, StatsArray_AfterGround);
if(i != gI_SampleSize - 1)
{
int iNextScrolls = gA_JumpStats[client].Get(i + 1, StatsArray_Scrolls);
if(iCurrentScrolls == iNextScrolls)
{
iSameAsNext++;
}
if(Abs(Max(iCurrentScrolls, iNextScrolls) - Min(iCurrentScrolls, iNextScrolls)) <= 2)
{
iCloseToNext++;
}
}
if(iCurrentScrolls >= 17)
{
iVeryHighNumber++;
}
if(iTicks <= 2)
{
iBadIntervals++;
}
if(iBefores <= 1)
{
iLowBefores++;
}
if(iAfters <= 1)
{
iLowAfters++;
}
if(iBefores == iAfters)
{
iSameBeforeAfter++;
}
}
float fIntervals = (float(iBadIntervals) / gI_SampleSize);
bool bTriggered = true;
char[] sScrollStats = new char[300];
GetScrollStatsFormatted(client, sScrollStats, 300);
char stats_desc[1024];
// Ugly code below, I know.
if(iPerfs >= 91)
{
LogToFileEx(gS_LogPath, "%L - (" ... DESC1 ... "): %s", client, sScrollStats);
Format(stats_desc, sizeof(stats_desc), "%s :\n%s", DESC1, sScrollStats);
Oryx_Trigger(client, TRIGGER_DEFINITIVE, stats_desc);
}
else if(iPerfs >= 87 && (iSameAsNext >= 13 || iCloseToNext >= 18))
{
LogToFileEx(gS_LogPath, "%L - (" ... DESC2 ... "): %s", client, sScrollStats);
Format(stats_desc, sizeof(stats_desc), "%s :\n%s", DESC2, sScrollStats);
Oryx_Trigger(client, TRIGGER_DEFINITIVE, stats_desc);
}
else if(iPerfs >= 85 && iSameAsNext >= 13)
{
LogToFileEx(gS_LogPath, "%L - (" ... DESC3 ... "): %s", client, sScrollStats);
Format(stats_desc, sizeof(stats_desc), "%s :\n%s", DESC3, sScrollStats);
Oryx_Trigger(client, TRIGGER_DEFINITIVE, stats_desc);
}
else if(iPerfs >= 80 && iSameAsNext >= 15)
{
LogToFileEx(gS_LogPath, "%L - (" ... DESC4 ... "): %s", client, sScrollStats);
Format(stats_desc, sizeof(stats_desc), "%s :\n%s", DESC4, sScrollStats);
Oryx_Trigger(client, TRIGGER_HIGH, stats_desc);
}
else if(iPerfs >= 75 && iVeryHighNumber >= 4 && iSameAsNext >= 3 && iCloseToNext >= 10)
{
LogToFileEx(gS_LogPath, "%L - (" ... DESC5 ... "): %s", client, sScrollStats);
Format(stats_desc, sizeof(stats_desc), "%s :\n%s", DESC5, sScrollStats);
Oryx_Trigger(client, TRIGGER_HIGH, stats_desc);
}
else if(iPerfs >= 85 && iCloseToNext >= 16)
{
LogToFileEx(gS_LogPath, "%L - (" ... DESC6 ... "): %s", client, sScrollStats);
Format(stats_desc, sizeof(stats_desc), "%s :\n%s", DESC6, sScrollStats);
Oryx_Trigger(client, TRIGGER_HIGH, stats_desc);
}
else if(iPerfs >= 40 && iLowBefores >= 45)
{
LogToFileEx(gS_LogPath, "%L - (" ... DESC7 ... ") (%d): %s", client, iLowBefores, sScrollStats);
Format(stats_desc, sizeof(stats_desc), "%s (%d):\n%s", DESC7, iLowBefores, sScrollStats);
Oryx_Trigger(client, TRIGGER_MEDIUM, stats_desc);
}
else if(iPerfs >= 55 && iSameBeforeAfter >= 25)
{
LogToFileEx(gS_LogPath, "%L - (" ... DESC8 ... ") (bf %d | af %d | bfaf %d): %s", client, iLowBefores, iLowAfters, iSameBeforeAfter, sScrollStats);
Format(stats_desc, sizeof(stats_desc), "%s :\n(bf %d | af %d | bfaf %d): %s", DESC8, iLowBefores, iLowAfters, iSameBeforeAfter, sScrollStats);
Oryx_Trigger(client, TRIGGER_HIGH_NOKICK, stats_desc);
}
else if(iPerfs >= 40 && iLowAfters >= 45)
{
LogToFileEx(gS_LogPath, "%L - (" ... DESC9 ... ") (%d): %s", client, iLowAfters, sScrollStats);
Format(stats_desc, sizeof(stats_desc), "%s :\n(%d): %s", DESC9, iLowAfters, sScrollStats);
Oryx_Trigger(client, TRIGGER_LOW, stats_desc);
}
else if(iVeryHighNumber >= 15 && (iCloseToNext >= 13 || iPerfs >= 80))
{
LogToFileEx(gS_LogPath, "%L - (" ... DESC10 ... "): %s", client, sScrollStats);
Format(stats_desc, sizeof(stats_desc), "%s :\n%s", DESC10, sScrollStats);
Oryx_Trigger(client, TRIGGER_HIGH, stats_desc);
}
else if(fIntervals > 0.75)
{
LogToFileEx(gS_LogPath, "%L - (" ... DESC11 ... ", intervals: %.2f): %s", client, fIntervals, sScrollStats);
Format(stats_desc, sizeof(stats_desc), "%s :\nintervals: %.2f: %s", DESC11, fIntervals, sScrollStats);
Oryx_Trigger(client, TRIGGER_MEDIUM, stats_desc);
}
else
{
bTriggered = false;
}
if(bTriggered)
{
// Hard reset stats after logging, to prevent spam.
ResetStatsArray(client);
gI_CurrentJump[client] = 0;
gA_JumpStats[client].Clear();
}
}

View File

@ -0,0 +1,414 @@
/* Oryx AC: collects and analyzes statistics to find some cheaters in CS:S, CS:GO, and TF2 bunnyhop.
* Copyright (C) 2018 Nolan O.
* Copyright (C) 2018 shavit.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <sourcemod>
#include <sdktools>
#include <oryx>
#undef REQUIRE_PLUGIN
#include <shavit>
#include <bTimes-tas>
#include <bTimes-timer_hack>
#pragma newdecls required
#pragma semicolon 1
enum
{
Timer_None,
Timer_Shavit,
Timer_Blacky2,
Timer_Blacky183
}
int gI_Timer = Timer_None;
char gS_SpecialString[128];
ConVar gCV_AllowBypass = null;
EngineVersion gEV_Type = Engine_Unknown;
Handle gH_Forwards_OnTrigger = null;
char gS_LogPath[PLATFORM_MAX_PATH];
char gS_BeepSound[PLATFORM_MAX_PATH];
bool gB_NoSound = false;
bool gB_Testing[MAXPLAYERS+1];
bool gB_Locked[MAXPLAYERS+1];
public Plugin myinfo =
{
name = "ORYX bunnyhop anti-cheat",
author = "Rusty, shavit",
description = "Cheat detection interface.",
version = ORYX_VERSION,
url = "https://github.com/shavitush/Oryx-AC"
}
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
{
CreateNative("Oryx_CanBypass", Native_CanBypass);
CreateNative("Oryx_Trigger", Native_OryxTrigger);
CreateNative("Oryx_WithinThreshold", Native_WithinThreshold);
CreateNative("Oryx_PrintToAdmins", Native_PrintToAdmins);
CreateNative("Oryx_PrintToAdminsConsole", Native_PrintToAdminsConsole);
CreateNative("Oryx_LogMessage", Native_LogMessage);
// registers library, check "bool LibraryExists(const char[] name)" in order to use with other plugins
RegPluginLibrary("oryx");
return APLRes_Success;
}
public void OnAllPluginsLoaded()
{
// workaround
if(gI_Timer == Timer_None &&
GetFeatureStatus(FeatureType_Native, "GetClientStyle") == FeatureStatus_Available &&
GetFeatureStatus(FeatureType_Native, "Style_GetConfig") == FeatureStatus_Available)
{
gI_Timer = Timer_Blacky183;
}
}
public void OnPluginStart()
{
gH_Forwards_OnTrigger = CreateGlobalForward("Oryx_OnTrigger", ET_Event, Param_Cell, Param_CellByRef, Param_String);
gEV_Type = GetEngineVersion();
gCV_AllowBypass = CreateConVar("oryx_allow_bypass", "1", "Allow specific styles to bypass Oryx? Refer to README.md for information.", 0, true, 0.0, true, 1.0);
CreateConVar("oryx_version", ORYX_VERSION, "Plugin version.", (FCVAR_NOTIFY | FCVAR_DONTRECORD));
RegAdminCmd("sm_otest", Command_OryxTest, ADMFLAG_BAN, "Enables the TRIGGER_TEST detection level.");
RegAdminCmd("sm_lock", Command_LockPlayer, ADMFLAG_BAN, "Disables movement for a player.");
LoadTranslations("common.phrases");
BuildPath(Path_SM, gS_LogPath, PLATFORM_MAX_PATH, "logs/oryx-ac.log");
if(LibraryExists("shavit"))
{
gI_Timer = Timer_Shavit;
}
else if(LibraryExists("tas"))
{
gI_Timer = Timer_Blacky2;
}
}
public void OnLibraryAdded(const char[] name)
{
if(StrEqual(name, "shavit"))
{
gI_Timer = Timer_Shavit;
}
else if(StrEqual(name, "tas"))
{
gI_Timer = Timer_Blacky2;
}
}
public void OnLibraryRemoved(const char[] name)
{
if((StrEqual(name, "shavit") && gI_Timer == Timer_Shavit) ||
(StrEqual(name, "tas") && gI_Timer == Timer_Blacky2))
{
gI_Timer = Timer_None;
}
}
public void OnMapStart()
{
// Beep sounds.
Handle hConfig = LoadGameConfigFile("funcommands.games");
if(hConfig == null)
{
SetFailState("Unable to load game config funcommands.games");
return;
}
if(GameConfGetKeyValue(hConfig, "SoundBeep", gS_BeepSound, PLATFORM_MAX_PATH))
{
PrecacheSound(gS_BeepSound, true);
}
delete hConfig;
}
public void OnClientPutInServer(int client)
{
gB_Locked[client] = false;
gB_Testing[client] = false;
}
public Action Command_OryxTest(int client, int args)
{
gB_Testing[client] = !gB_Testing[client];
ReplyToCommand(client, "Testing is %s.", (gB_Testing[client])? "on":"off");
return Plugin_Handled;
}
public Action Command_LockPlayer(int client, int args)
{
if(args < 1)
{
ReplyToCommand(client, "Usage: sm_lock <target>");
return Plugin_Handled;
}
char[] sArgs = new char[MAX_TARGET_LENGTH];
GetCmdArgString(sArgs, MAX_TARGET_LENGTH);
int target = FindTarget(client, sArgs);
if(target == -1)
{
return Plugin_Handled;
}
gB_Locked[target] = !gB_Locked[target];
ReplyToCommand(client, "Player has been %s.", (gB_Locked[target])? "locked":"unlocked");
PrintToChat(target, "An admin has %s your ability to move!", (gB_Locked[target])? "locked":"unlocked");
return Plugin_Handled;
}
public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3])
{
// Movement is locked, don't allow anything.
if(gB_Locked[client])
{
buttons = 0;
vel[0] = 0.0;
vel[1] = 0.0;
impulse = 0;
return Plugin_Changed;
}
return Plugin_Continue;
}
public int Native_CanBypass(Handle plugin, int numParams)
{
if(!gCV_AllowBypass.BoolValue)
{
return false;
}
int client = GetNativeCell(1);
switch(gI_Timer)
{
case Timer_Shavit:
{
Shavit_GetStyleStrings(Shavit_GetBhopStyle(client), sSpecialString, gS_SpecialString, 128);
if(StrContains(gS_SpecialString, "oryx_bypass", false) != -1)
{
return true;
}
}
case Timer_Blacky2:
{
return TAS_InEditMode(client);
}
case Timer_Blacky183:
{
any styleconfig[StyleConfig];
Style_GetConfig(GetClientStyle(client), styleconfig);
if(StrContains(styleconfig[Special_Key], "oryx_bypass", false) != -1)
{
return true;
}
}
}
return false;
}
public int Native_OryxTrigger(Handle plugin, int numParams)
{
int client = GetNativeCell(1);
int level = GetNativeCell(2);
char[] sLevel = new char[16];
char[] sCheatDescription = new char[32];
GetNativeString(3, sCheatDescription, 32);
Action result = Plugin_Continue;
Call_StartForward(gH_Forwards_OnTrigger);
Call_PushCell(client);
Call_PushCellRef(level);
Call_PushStringEx(sCheatDescription, 32, SM_PARAM_STRING_COPY, SM_PARAM_COPYBACK);
Call_Finish(result);
if(result == Plugin_Stop)
{
return view_as<int>(Plugin_Stop);
}
if(level == TRIGGER_LOW)
{
strcopy(sLevel, 16, "LOW");
gB_NoSound = true; // Don't play the annoying beep sound for LOW detections.
}
else if(level == TRIGGER_MEDIUM)
{
strcopy(sLevel, 16, "MEDIUM");
}
else if(level == TRIGGER_HIGH)
{
strcopy(sLevel, 16, "HIGH");
if(result != Plugin_Handled)
{
//KickClient(client, "[ORYX] %s", sCheatDescription);
}
}
else if(level == TRIGGER_HIGH_NOKICK)
{
strcopy(sLevel, 16, "HIGH-NOKICK");
}
else if(level == TRIGGER_DEFINITIVE)
{
strcopy(sLevel, 16, "DEFINITIVE");
if(result != Plugin_Handled)
{
//KickClient(client, "[ORYX] %s", sCheatDescription);
}
}
else if(level == TRIGGER_TEST)
{
char[] sBuffer = new char[128];
Format(sBuffer, 128, "(\x03%N\x01) - %s | Level: \x04TESTING", client, sCheatDescription);
for(int i = 1; i <= MaxClients; i++)
{
if(gB_Testing[i] && IsClientInGame(i))
{
PrintToChat(i, "%s", sBuffer);
}
}
return view_as<int>(result);
}
char[] sAuth = new char[32];
GetClientAuthId(client, AuthId_Steam3, sAuth, 32);
char[] sBuffer = new char[128];
Format(sBuffer, 128, "\x03%N\x01 - \x05%s\x01 Cheat: %s | Level: %s", client, sAuth, sCheatDescription, sLevel);
Oryx_PrintToAdmins("%s", sBuffer);
LogToFileEx(gS_LogPath, "%L - Cheat: %s | Level: %s", client, sCheatDescription, sLevel);
return view_as<int>(result);
}
public int Native_WithinThreshold(Handle plugin, int numParams)
{
float f1 = GetNativeCell(1);
float f2 = GetNativeCell(2);
float threshold = GetNativeCell(3);
return view_as<int>(FloatAbs(f1 - f2) <= threshold);
}
public int Native_PrintToAdmins(Handle plugin, int numParams)
{
static int iWritten = 0; // Useless?
char[] sBuffer = new char[300];
FormatNativeString(0, 1, 2, 300, iWritten, sBuffer);
for(int i = 1; i <= MaxClients; i++)
{
if(CheckCommandAccess(i, "oryx_admin", ADMFLAG_GENERIC))
{
PrintToChat(i, "%s\x04[ORYX]\x01 %s", (gEV_Type == Engine_CSGO)? " ":"", sBuffer);
if(!gB_NoSound)
{
if(gEV_Type == Engine_CSS || gEV_Type == Engine_TF2)
{
EmitSoundToClient(i, gS_BeepSound);
}
else
{
ClientCommand(i, "play */%s", gS_BeepSound);
}
}
}
}
gB_NoSound = false;
}
public int Native_PrintToAdminsConsole(Handle plugin, int numParams)
{
static int iWritten = 0; // Useless?
char[] sBuffer = new char[300];
FormatNativeString(0, 1, 2, 300, iWritten, sBuffer);
for(int i = 1; i <= MaxClients; i++)
{
if(CheckCommandAccess(i, "oryx_admin", ADMFLAG_GENERIC))
{
PrintToConsole(i, "[ORYX] %s", sBuffer);
}
}
}
public int Native_LogMessage(Handle plugin, int numParams)
{
char[] sPlugin = new char[32];
if(!GetPluginInfo(plugin, PlInfo_Name, sPlugin, 32))
{
GetPluginFilename(plugin, sPlugin, 32);
}
static int iWritten = 0; // Useless?
char[] sBuffer = new char[300];
FormatNativeString(0, 1, 2, 300, iWritten, sBuffer);
LogToFileEx(gS_LogPath, "[%s] %s", sPlugin, sBuffer);
}