Modules: Combat
Server-authoritative combat systems — cooldowns, hit validation, and anti-cheat (@broblox/combat). Status: Implemented (138 tests).
Purpose
- Multi-charge ability cooldown system with shared cooldown groups.
- Server-authoritative hit validation with bounded lag compensation.
- Anti-cheat pattern detection for suspicious hit sequences.
- Injectable position and raycast providers for line-of-sight checks.
Core rules
- All cooldown state is server-side; clients cannot bypass or manipulate timers.
- Hit validation performs a 6-step chain: rate-limit → lag-check → range → target-lookup → invulnerability → angle → obstruction.
- Bounded lag compensation: hits beyond
maxLagMs (default 200 ms) are rejected.
- Minimum 50 ms between hits (
minHitInterval) to prevent rapid-fire exploits.
- Angle validation: aim must be within ~60° of the target direction.
Data model
CooldownConfig — ability registration: abilityId, durationSeconds, charges, chargeRecoverySeconds, sharedCooldown.
CooldownState — per-player runtime: abilityId, charges, maxCharges, nextChargeAt.
HitIntent — client-submitted: origin, direction, clientTimestamp, targetId, weaponId, maxDistance.
HitValidationResult — server response: valid, hitPosition, hitDistance, reason, serverTimestamp.
Public API
Cooldown module
| Method |
Description |
registerAbility(config) |
Register an ability with cooldown settings |
useAbility(playerId, abilityId) |
Consume a charge (server-authoritative) |
isOnCooldown(playerId, abilityId) |
Check if an ability is on cooldown |
getRemainingCooldown(playerId, abilityId) |
Seconds remaining |
getAvailableCharges(playerId, abilityId) |
Available charges |
resetCooldown(playerId, abilityId) |
Reset a single cooldown |
resetAllCooldowns(playerId) |
Reset all cooldowns for a player |
Hit validation module
| Method |
Description |
configureHitValidation(config) |
Set maxLagMs, maxRange, etc. |
setPositionProvider(provider) |
Inject position source for range checks |
setRaycastProvider(provider) |
Inject raycast for line-of-sight checks |
validateHit(shooterId, intent) |
Core validation — returns HitValidationResult |
setInvulnerable(playerId, bool) |
Toggle invulnerability (e.g. respawn) |
Factory
const combat = createCombatService({
abilities: [{ abilityId: "slash", durationSeconds: 0.8, charges: 3 }],
hitValidation: { maxLagMs: 200, maxRange: 100, checkObstruction: true },
positionProvider: (id) => getPlayerPosition(id),
});
Security
- Server-authoritative — clients send intents only; server validates everything.
- Rate limiting — 50 ms minimum between hits.
- Suspicious pattern tracking — failed hits increment a per-player counter;
SuspiciousHitEvent emitted.
- Invulnerability gating — hits on invulnerable targets immediately rejected.
- Obstruction checks — server-side raycast prevents shooting through walls.
Config
| Key |
Default |
Description |
maxLagMs |
200 |
Maximum allowed client-server time delta |
maxRange |
1000 |
Maximum hit distance |
checkObstruction |
true |
Enable line-of-sight raycast |
logSuspicious |
true |
Log suspicious hits |
Observability
CooldownStartedEvent — charge consumed
CooldownEndedEvent — charge recovered
AbilityRejectedEvent — use attempt denied (on cooldown / no charges)
SuspiciousHitEvent — invalid hit detected (reason, intent details)