# game-server — Wave C-2 enhanced (delta) ## ADDED Requirements ### Requirement: Anti-Cheat Validator `@suaveplan/game-server` SHALL expose an `AntiCheatValidator` class for server-authoritative validation of player movement and actions. #### Scenario: Movement under maximum speed is accepted - **WHEN** the validator receives two successive `MovementData` records for a player whose Euclidean distance over the elapsed time is below `movement.maxSpeed × movement.toleranceFactor` - **THEN** `validateMovement` SHALL return `{ valid: true }` - **AND** SHALL record the latest position as the player's reference for subsequent calls. #### Scenario: Teleport above threshold is rejected as `major` - **WHEN** the Euclidean distance exceeds `movement.maxTeleportDistance` - **THEN** `validateMovement` SHALL return a `ValidationResult` whose `violation.type === "teleport"` and `violation.severity === "major"` - **AND** SHALL emit a `violation:detected` event. #### Scenario: Rate limit blocks bursts beyond `maxActions` - **WHEN** more than `maxActions` actions of the matching `actionType` (or `"all"`) arrive inside a rolling `windowMs` - **THEN** `validateAction` SHALL return a `ValidationResult` whose `violation.type === "rate_limit"` - **AND** SHALL emit a `rate_limit:exceeded` event. #### Scenario: Auto-flag triggers at threshold - **WHEN** the player accumulates ≥ `autoFlagThreshold` violations in the trailing 60 seconds - **THEN** the validator SHALL flag the player automatically - **AND** the most recent recorded violation SHALL have `autoFlagged: true`. #### Scenario: Invalid configuration is rejected - **WHEN** caller-supplied `AntiCheatConfig` fails Zod validation - **THEN** the constructor SHALL throw a `GameServerError` with code `GAME_SERVER.INVALID_ANTI_CHEAT_CONFIG`. ### Requirement: Interest Manager `@suaveplan/game-server` SHALL expose an `InterestManager` class that performs area-of-interest culling for broadcast scope reduction. #### Scenario: Entity inside view distance is visible - **WHEN** a player and an entity are within `viewDistance` - **THEN** `getVisibleEntities` SHALL include the entity in its result. #### Scenario: Visibility delta omits unchanged set - **WHEN** `calculateVisibilityChanges` is called twice with no intervening position change - **THEN** the second call SHALL return `null` - **AND** SHALL NOT emit a `visibility:changed` event. #### Scenario: Rectangular zone containment - **WHEN** a 3D point's `(x, y, z)` lies within `±width/2`, `±height/2`, `±depth/2` of a rectangular zone's centre - **THEN** `isInZone` SHALL return `true`. #### Scenario: Custom zone delegates to provided predicate - **WHEN** a `CustomZone` is registered with `containsPoint` - **THEN** `isInZone` SHALL invoke that predicate and return its result. #### Scenario: Invalid configuration is rejected - **WHEN** caller-supplied `InterestManagerConfig` fails Zod validation - **THEN** the constructor SHALL throw `GameServerError` with code `GAME_SERVER.INVALID_INTEREST_CONFIG`. ### Requirement: Lag Compensator `@suaveplan/game-server` SHALL expose a `LagCompensator` class for server-side time-rewind of game state during hit validation. #### Scenario: Bounded history pruning - **WHEN** the number of recorded snapshots for an entity exceeds `maxHistorySize` - **THEN** the oldest snapshots SHALL be evicted - **AND** the count SHALL never grow beyond `maxHistorySize`. #### Scenario: Compensation is clamped - **WHEN** the requested rewind exceeds `maxCompensationMs` - **THEN** the returned `CompensatedState.compensationMs` SHALL equal `maxCompensationMs` - **AND** the returned `CompensatedState.clamped` SHALL be `true`. #### Scenario: Interpolation between snapshots - **WHEN** the rewind timestamp falls between two adjacent snapshots and a `lerp` function is supplied - **THEN** `getStateAtTime` SHALL invoke `lerp` to produce the returned state - **AND** the returned `CompensatedState.interpolated` SHALL be `true`. #### Scenario: Hit validation requires both states - **WHEN** the shooter or the target has no recorded state at the perceived time - **THEN** `validateHit` SHALL return `{ valid: false }` with a `reason` describing the missing side. #### Scenario: Invalid configuration is rejected - **WHEN** caller-supplied `LagCompensatorConfig` fails Zod validation - **THEN** the constructor SHALL throw `GameServerError` with code `GAME_SERVER.INVALID_LAG_COMPENSATION_CONFIG`.