LimmeDev's picture
Initial MANIFOLD upload - CS2 cheat detection training
454ecdd verified
from __future__ import annotations
import numpy as np
from dataclasses import dataclass, field
from typing import Optional, Dict, Any, Set, Tuple
from enum import Enum
class CheatType(Enum):
AIMBOT = "aimbot"
WALLHACK = "wallhack"
TRIGGERBOT = "triggerbot"
class TogglePattern(Enum):
ALWAYS = "always"
CLUTCH_ONLY = "clutch_only"
LOSING_ONLY = "losing_only"
RANDOM = "random"
@dataclass
class HumanizationConfig:
"""Cheater's attempt to appear legit - but leaves artifacts."""
reaction_delay_ms: Tuple[float, float] = (0.0, 20.0)
aim_smoothing: Tuple[float, float] = (0.0, 0.2)
random_miss_rate: Tuple[float, float] = (0.0, 0.05)
fov_degrees: Tuple[float, float] = (90.0, 180.0)
noise_amplitude: Tuple[float, float] = (0.0, 0.0)
prefire_suppression: float = 0.0
check_delay_ms: Tuple[float, float] = (0.0, 0.0)
def sample(self, rng: np.random.Generator) -> Dict[str, float]:
"""Sample concrete values from ranges."""
return {
"reaction_delay_ms": rng.uniform(*self.reaction_delay_ms),
"aim_smoothing": rng.uniform(*self.aim_smoothing),
"random_miss_rate": rng.uniform(*self.random_miss_rate),
"fov_degrees": rng.uniform(*self.fov_degrees),
"noise_amplitude": rng.uniform(*self.noise_amplitude),
"prefire_suppression": self.prefire_suppression,
"check_delay_ms": rng.uniform(*self.check_delay_ms) if self.check_delay_ms[1] > 0 else 0.0,
}
CHEAT_PROFILES: Dict[str, Dict[str, Any]] = {
"blatant_rage": {
"intensity": (0.8, 1.0),
"toggle_pattern": TogglePattern.ALWAYS,
"cheat_types": {CheatType.AIMBOT, CheatType.WALLHACK, CheatType.TRIGGERBOT},
"humanization": HumanizationConfig(
reaction_delay_ms=(0.0, 20.0),
aim_smoothing=(0.0, 0.2),
random_miss_rate=(0.0, 0.05),
fov_degrees=(90.0, 180.0),
),
"base_skill_multiplier": (0.3, 0.5),
},
"obvious": {
"intensity": (0.5, 0.8),
"toggle_pattern": TogglePattern.ALWAYS,
"cheat_types": {CheatType.AIMBOT, CheatType.TRIGGERBOT},
"humanization": HumanizationConfig(
reaction_delay_ms=(30.0, 80.0),
aim_smoothing=(0.2, 0.5),
random_miss_rate=(0.05, 0.10),
fov_degrees=(30.0, 60.0),
),
"base_skill_multiplier": (0.4, 0.6),
},
"closet_moderate": {
"intensity": (0.3, 0.5),
"toggle_pattern": TogglePattern.CLUTCH_ONLY,
"cheat_types": {CheatType.AIMBOT},
"humanization": HumanizationConfig(
reaction_delay_ms=(80.0, 150.0),
aim_smoothing=(0.5, 0.8),
random_miss_rate=(0.10, 0.18),
fov_degrees=(10.0, 25.0),
),
"base_skill_multiplier": (0.5, 0.7),
},
"closet_subtle": {
"intensity": (0.15, 0.35),
"toggle_pattern": TogglePattern.LOSING_ONLY,
"cheat_types": {CheatType.AIMBOT, CheatType.TRIGGERBOT},
"humanization": HumanizationConfig(
reaction_delay_ms=(150.0, 250.0),
aim_smoothing=(0.8, 0.95),
random_miss_rate=(0.15, 0.25),
fov_degrees=(3.0, 10.0),
noise_amplitude=(0.5, 1.5),
),
"base_skill_multiplier": (0.6, 0.8),
},
"wallhack_only": {
"intensity": (0.4, 0.7),
"toggle_pattern": TogglePattern.ALWAYS,
"cheat_types": {CheatType.WALLHACK},
"humanization": HumanizationConfig(
prefire_suppression=0.7,
check_delay_ms=(500.0, 1500.0),
),
"base_skill_multiplier": (0.7, 0.9),
},
}
@dataclass
class CheatConfig:
"""Configuration for a specific cheater."""
profile_name: str
cheat_types: Set[CheatType]
intensity: float
toggle_pattern: TogglePattern
humanization: Dict[str, float]
base_skill_multiplier: float
@classmethod
def from_profile(
cls,
profile_name: str,
seed: Optional[int] = None,
) -> CheatConfig:
"""Create config from predefined profile."""
if profile_name not in CHEAT_PROFILES:
raise ValueError(f"Unknown profile: {profile_name}. Valid: {list(CHEAT_PROFILES.keys())}")
rng = np.random.default_rng(seed)
profile = CHEAT_PROFILES[profile_name]
intensity = rng.uniform(*profile["intensity"])
base_skill_mult = rng.uniform(*profile["base_skill_multiplier"])
humanization = profile["humanization"].sample(rng)
return cls(
profile_name=profile_name,
cheat_types=profile["cheat_types"].copy(),
intensity=intensity,
toggle_pattern=profile["toggle_pattern"],
humanization=humanization,
base_skill_multiplier=base_skill_mult,
)
@dataclass
class CheatBehavior:
"""Runtime cheat behavior with toggle logic."""
config: CheatConfig
is_active: bool = True
rounds_since_toggle: int = 0
@classmethod
def from_profile(cls, profile_name: str, seed: Optional[int] = None) -> CheatBehavior:
config = CheatConfig.from_profile(profile_name, seed)
return cls(config=config)
@property
def toggle_pattern(self) -> TogglePattern:
return self.config.toggle_pattern
def should_activate(
self,
is_clutch: bool = False,
is_losing: bool = False,
round_number: int = 0,
rng: Optional[np.random.Generator] = None,
) -> bool:
"""Determine if cheat should be active this round."""
pattern = self.config.toggle_pattern
if pattern == TogglePattern.ALWAYS:
return True
elif pattern == TogglePattern.CLUTCH_ONLY:
return is_clutch
elif pattern == TogglePattern.LOSING_ONLY:
return is_losing
elif pattern == TogglePattern.RANDOM:
if rng is None:
rng = np.random.default_rng()
return rng.random() < 0.5
return True
def get_aim_modification(self, target_angle: float, current_angle: float) -> float:
"""Calculate aim correction from cheat."""
if CheatType.AIMBOT not in self.config.cheat_types:
return 0.0
if not self.is_active:
return 0.0
angle_diff = target_angle - current_angle
fov_limit = self.config.humanization["fov_degrees"]
if abs(angle_diff) > fov_limit:
return 0.0
smoothing = self.config.humanization["aim_smoothing"]
intensity = self.config.intensity
# Smoothed correction
correction = angle_diff * (1.0 - smoothing) * intensity
# Add humanization noise
noise_amp = self.config.humanization.get("noise_amplitude", 0.0)
if noise_amp > 0:
correction += np.random.normal(0, noise_amp)
return correction
def get_reaction_delay(self) -> float:
"""Get reaction delay in ms."""
return self.config.humanization["reaction_delay_ms"]
def should_miss_intentionally(self, rng: Optional[np.random.Generator] = None) -> bool:
"""Check if should intentionally miss (humanization)."""
if rng is None:
rng = np.random.default_rng()
miss_rate = self.config.humanization["random_miss_rate"]
return rng.random() < miss_rate