Files
2026-05-27 23:29:53 +01:00

120 lines
4.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# game-server — Wave C-2 enhanced (delta)
## ADDED Requirements
### Requirement: Anti-Cheat Validator
`@suaveplan/game-server` SHALL expose an `AntiCheatValidator<TMove, TAction>`
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<TData>` 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<TState>` 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`.