Skip to content

Instantly share code, notes, and snippets.

@21Joakim
Created January 27, 2025 19:41
Show Gist options
  • Select an option

  • Save 21Joakim/480f2bae588df54d2f34faba8b2861bc to your computer and use it in GitHub Desktop.

Select an option

Save 21Joakim/480f2bae588df54d2f34faba8b2861bc to your computer and use it in GitHub Desktop.
Example of how to use ReplicateConVar to enable bhop on a per player basis.
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Attributes.Registration;
using CounterStrikeSharp.API.Modules.Commands;
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
using CounterStrikeSharp.API.Modules.Cvars;
// Example of how to use ReplicateConVar
// to enable bhop on a per player basis.
public class BhopPlugin : BasePlugin
{
// The signature is for Linux (this has not been tested on Windows)
private static readonly MemoryFunctionVoid<CCSPlayer_MovementServices, IntPtr> CCSPlayer_MovementServices_ProcessMovement =
new("55 48 89 E5 41 57 41 56 41 55 41 54 49 89 FC 53 48 83 EC ? 48 8B 7F 30");
public override string ModuleName => "BhopPlugin";
public override string ModuleVersion => "0.0.1";
private readonly bool[] _bhopEnabled = new bool[64];
private readonly ConVar? _autobunnyhopping = ConVar.Find("sv_autobunnyhopping");
private readonly ConVar? _enablebunnyhopping = ConVar.Find("sv_enablebunnyhopping");
public override void Load(bool hotReload)
{
CCSPlayer_MovementServices_ProcessMovement.Hook(ProcessMovementPre, HookMode.Pre);
CCSPlayer_MovementServices_ProcessMovement.Hook(ProcessMovementPost, HookMode.Post);
}
public override void Unload(bool hotReload)
{
CCSPlayer_MovementServices_ProcessMovement.Unhook(ProcessMovementPre, HookMode.Pre);
CCSPlayer_MovementServices_ProcessMovement.Unhook(ProcessMovementPost, HookMode.Post);
}
[ConsoleCommand("bhop")]
public void BhopCommand(CCSPlayerController? player, CommandInfo command)
{
CCSPlayerPawn? pawn = player?.PlayerPawn.Value;
if (player == null || pawn == null)
{
command.ReplyToCommand("Only a player can run this command");
return;
}
bool enabled = !_bhopEnabled[player.Slot];
_bhopEnabled[player.Slot] = enabled;
player.ReplicateConVar("sv_autobunnyhopping", Convert.ToString(enabled));
player.ReplicateConVar("sv_enablebunnyhopping", Convert.ToString(enabled));
command.ReplyToCommand($"Bhop has been {(enabled ? "enabled" : "disabled")}");
}
public int? GetSlot(CCSPlayer_MovementServices? movementServices)
{
uint? index = movementServices?.Pawn.Value?.Controller.Value?.Index;
if (index == null)
{
return null;
}
return (int) index.Value - 1;
}
public bool IsBhopEnabled(CCSPlayer_MovementServices movementServices)
{
int? slot = GetSlot(movementServices);
if (slot == null)
{
return false;
}
return _bhopEnabled[slot.Value];
}
private bool _wasAutobunnyhoppingChanged = false;
private bool _wasEnablebunnyhoppingChanged = false;
public HookResult ProcessMovementPre(DynamicHook hook)
{
if (_autobunnyhopping == null || _enablebunnyhopping == null)
{
return HookResult.Continue;
}
_wasAutobunnyhoppingChanged = false;
_wasEnablebunnyhoppingChanged = false;
CCSPlayer_MovementServices movementServices = hook.GetParam<CCSPlayer_MovementServices>(0);
if (!IsBhopEnabled(movementServices))
{
return HookResult.Continue;
}
if (!_autobunnyhopping.GetPrimitiveValue<bool>())
{
_autobunnyhopping.SetValue(true);
_wasAutobunnyhoppingChanged = true;
}
if (!_enablebunnyhopping.GetPrimitiveValue<bool>())
{
_enablebunnyhopping.SetValue(true);
_wasEnablebunnyhoppingChanged = true;
}
return HookResult.Continue;
}
public HookResult ProcessMovementPost(DynamicHook hook)
{
if (_autobunnyhopping == null || _enablebunnyhopping == null)
{
return HookResult.Continue;
}
if (_wasAutobunnyhoppingChanged)
{
_autobunnyhopping.SetValue(false);
_wasAutobunnyhoppingChanged = false;
}
if (_wasEnablebunnyhoppingChanged)
{
_enablebunnyhopping.SetValue(false);
_wasEnablebunnyhoppingChanged = false;
}
return HookResult.Continue;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment