Initial Commit
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
# Wave C-2 — game-server enhanced: anti-cheat + interest management + lag compensation
|
||||
|
||||
## Why
|
||||
|
||||
The `@suaveplan/game-server` package's Wave A–B foundation (core / engine /
|
||||
state / network / matchmaking / performance) is in place. The next layer —
|
||||
the `enhanced/` family — adds server-authoritative safeguards and
|
||||
broadcast-scope optimisations needed for any open-world multiplayer game.
|
||||
|
||||
Wave C-2 ships the three foundational `enhanced/` modules that are entirely
|
||||
self-contained from a dependency standpoint and underpin the rest of the
|
||||
`enhanced/` tree (anti-cheat consumed by leaderboard/persistence; interest
|
||||
management by state-sync; lag compensation by replay/state-sync):
|
||||
|
||||
- `enhanced/anti-cheat/anti-cheat-validator/` — server-authoritative move /
|
||||
action validator with movement, rate-limit, and custom-action rules;
|
||||
player-violation history; punishment escalation FSM.
|
||||
- `enhanced/interest-management/interest-manager/` — area-of-interest
|
||||
manager: circular/rectangular/custom zones, per-player view-distance
|
||||
culling, priority-weighted entity visibility, visibility-change deltas.
|
||||
- `enhanced/lag-compensation/lag-compensator/` — server-side state-rewind +
|
||||
RTT-aware hit validation: per-entity bounded snapshot ring buffer,
|
||||
per-player RTT statistics (avg/min/max/jitter), interpolated state
|
||||
lookups, clamped compensation.
|
||||
|
||||
## What Changes
|
||||
|
||||
Add three feature modules under `packages/gaming/games/game-server/src/enhanced/`,
|
||||
each as a self-contained `5-files-per-feature` directory:
|
||||
|
||||
- `anti-cheat/anti-cheat-validator/{anti-cheat-validator.ts,.test.ts,.types.ts,.md,index.ts}`
|
||||
- `interest-management/interest-manager/{interest-manager.ts,.test.ts,.types.ts,.md,index.ts}`
|
||||
- `lag-compensation/lag-compensator/{lag-compensator.ts,.test.ts,.types.ts,.md,index.ts}`
|
||||
|
||||
Behaviour shift versus the upstream `main` implementation:
|
||||
|
||||
- Inject `Clock` (and where ids are minted, `IdGenerator`) from
|
||||
`@suaveplan/types` rather than reading `Date.now`/`Math.random` directly.
|
||||
- Replace ad-hoc `Logger` dependency + `EventEmitter` inheritance with a
|
||||
pluggable listener registry (no `@suaveplan/events` runtime dep) and OTel
|
||||
metrics for observability.
|
||||
- Throw `GameServerError` via the package-wide `GAME_SERVER_CODES` registry
|
||||
on invalid input or out-of-bounds operations instead of silently
|
||||
returning sentinel values.
|
||||
- Validate all caller-supplied configuration with Zod at the boundary.
|
||||
|
||||
Extend `GAME_SERVER_CODES` with the following new codes (appended, no
|
||||
re-order):
|
||||
|
||||
- `CHEAT_DETECTED`
|
||||
- `INVALID_VALIDATION_RULE`
|
||||
- `INVALID_ANTI_CHEAT_CONFIG`
|
||||
- `INTEREST_REGION_INVALID`
|
||||
- `INVALID_INTEREST_CONFIG`
|
||||
- `INTEREST_PLAYER_NOT_REGISTERED`
|
||||
- `LAG_COMPENSATION_HISTORY_EXCEEDED`
|
||||
- `INVALID_LAG_COMPENSATION_CONFIG`
|
||||
- `LAG_COMPENSATION_ENTITY_NOT_TRACKED`
|
||||
|
||||
Extend `package.json` `exports` map additively with subpath exports for the
|
||||
three new feature modules.
|
||||
|
||||
## Impact
|
||||
|
||||
- Affected specs: `game-server` (new requirements for enhanced anti-cheat,
|
||||
interest management, lag compensation).
|
||||
- Affected code: `packages/gaming/games/game-server/src/enhanced/**` (new),
|
||||
`packages/gaming/games/game-server/src/errors/game-server-error.ts`
|
||||
(new codes appended), `packages/gaming/games/game-server/package.json`
|
||||
(additive subpath exports), `packages/gaming/games/game-server/src/index.ts`
|
||||
(re-exports for the three new modules).
|
||||
- Out of scope: all other `enhanced/*` subtrees (leaderboard, persistence,
|
||||
replay, tournament, service-discovery, state-sync, timing) — owned by
|
||||
Wave C-3/C-4. The orchestrator `src/index.ts` is updated only to add the
|
||||
three Wave C-2 re-exports.
|
||||
@@ -0,0 +1,119 @@
|
||||
# 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`.
|
||||
@@ -0,0 +1,95 @@
|
||||
# Tasks — game-server enhanced anti-cheat + interest + lag
|
||||
|
||||
## 1. Error codes
|
||||
|
||||
- [x] 1.1 Append `CHEAT_DETECTED`, `INVALID_VALIDATION_RULE`,
|
||||
`INVALID_ANTI_CHEAT_CONFIG`, `INTEREST_REGION_INVALID`,
|
||||
`INVALID_INTEREST_CONFIG`, `INTEREST_PLAYER_NOT_REGISTERED`,
|
||||
`LAG_COMPENSATION_HISTORY_EXCEEDED`,
|
||||
`INVALID_LAG_COMPENSATION_CONFIG`,
|
||||
`LAG_COMPENSATION_ENTITY_NOT_TRACKED` to `GAME_SERVER_CODES`.
|
||||
|
||||
## 2. Anti-cheat validator
|
||||
|
||||
- [x] 2.1 `src/enhanced/anti-cheat/anti-cheat-validator/anti-cheat-validator.types.ts`
|
||||
— Zod schemas for `AntiCheatConfig`, `MovementData`, `ActionData`,
|
||||
`RateLimitConfig`, `MovementConfig`, `PunishmentThresholds`; types
|
||||
for `Violation`, `ValidationResult`, `PlayerViolationHistory`,
|
||||
`AntiCheatStats`, `AntiCheatEventMap`, `ActionValidator`,
|
||||
`ValidationContext`.
|
||||
- [x] 2.2 `anti-cheat-validator.ts` — `AntiCheatValidator` class with
|
||||
injected `Clock` + `IdGenerator`, OTel counter + histogram, listener
|
||||
registry. Public surface: `registerValidator`, `validateMovement`,
|
||||
`validateAction`, `checkRateLimit`, `getPlayerHistory`,
|
||||
`flagPlayer`/`unflagPlayer`, `banPlayer`/`isPlayerBanned`, `setTick`,
|
||||
`getStats`/`resetStats`, `clearPlayer`, `dispose`, `on`/`off`.
|
||||
- [x] 2.3 `anti-cheat-validator.test.ts` — full coverage: movement ok /
|
||||
speed-hack / teleport / timing anomaly / vertical-speed cap; rate
|
||||
limit windowing; custom action validator success + failure +
|
||||
throwing; ban-status auto-escalation; auto-flag threshold; stats
|
||||
and disposal.
|
||||
- [x] 2.4 `anti-cheat-validator.md` — Purpose / Features / Usage Basic /
|
||||
Usage Advanced / API Reference / Implementation Notes (≥200 words).
|
||||
- [x] 2.5 `index.ts` — named re-exports only.
|
||||
|
||||
## 3. Interest manager
|
||||
|
||||
- [x] 3.1 `interest-manager.types.ts` — Zod schema for
|
||||
`InterestManagerConfig`; types for `Vector3`, zone discriminated
|
||||
union (`CircularZone` | `RectangularZone` | `CustomZone`),
|
||||
`TrackedEntity`, `PlayerSubscription`, `EntityVisibility`,
|
||||
`VisibilityChange`, `InterestStats`, `InterestEventMap`.
|
||||
- [x] 3.2 `interest-manager.ts` — `InterestManager` class with injected
|
||||
`Clock`, OTel histogram + counter. Public surface: `registerZone`,
|
||||
`unregisterZone`, `updateEntity`, `removeEntity`, `registerPlayer`,
|
||||
`updatePlayerPosition`, `unregisterPlayer`, `subscribeToZone`,
|
||||
`unsubscribeFromZone`, `getVisibleEntities`,
|
||||
`calculateVisibilityChanges`, `isInZone`, `getZonesAtPoint`,
|
||||
`getZone`/`getAllZones`/`getEntity`, `start`/`stop`, `getStats`,
|
||||
`dispose`, `on`/`off`. No timer side-effects in constructor.
|
||||
- [x] 3.3 `interest-manager.test.ts` — full coverage: zone register /
|
||||
unregister / sweep; entity add/move/remove; player register /
|
||||
view-distance cap; subscribe/unsubscribe; visibility enter/exit
|
||||
deltas; rectangular vs circular vs custom zone containment;
|
||||
stats; dispose.
|
||||
- [x] 3.4 `interest-manager.md`.
|
||||
- [x] 3.5 `index.ts`.
|
||||
|
||||
## 4. Lag compensator
|
||||
|
||||
- [x] 4.1 `lag-compensator.types.ts` — Zod schema for
|
||||
`LagCompensatorConfig`; types for `PlayerLatency`,
|
||||
`CompensatedState`, `HitValidationRequest`, `HitValidationResult`,
|
||||
`LagCompensatorStats`, `LagCompensatorEventMap`,
|
||||
`StateSnapshot`.
|
||||
- [x] 4.2 `lag-compensator.ts` — `LagCompensator` class with injected
|
||||
`Clock`, bounded ring buffer per entity. Public surface:
|
||||
`recordState`, `updateRtt`, `getPlayerLatency`, `getStateAtTime`,
|
||||
`validateHit`, `getTrackedEntities`, `clearEntityHistory`,
|
||||
`removePlayer`, `getStats`/`resetStats`, `dispose`, `on`/`off`.
|
||||
- [x] 4.3 `lag-compensator.test.ts` — full coverage: state recording +
|
||||
pruning; RTT sample windowing; latency statistics; exact-match /
|
||||
before-only / after-only / interpolated lookups; max-compensation
|
||||
clamp; hit validation valid + invalid + missing-state; events;
|
||||
stats reset; dispose.
|
||||
- [x] 4.4 `lag-compensator.md`.
|
||||
- [x] 4.5 `index.ts`.
|
||||
|
||||
## 5. Wiring
|
||||
|
||||
- [x] 5.1 Add subpath exports for the three new modules to
|
||||
`package.json`.
|
||||
- [x] 5.2 Add new module re-exports to `src/index.ts` (Wave C-2 block).
|
||||
|
||||
## 6. Verification
|
||||
|
||||
- [x] 6.1 `bunx turbo lint typecheck test --filter=@suaveplan/game-server` — green.
|
||||
- [x] 6.2 `bunx turbo test:coverage --filter=@suaveplan/game-server` — 100/100/100/100.
|
||||
- [x] 6.3 No `from "vitest"` / `from "bun:test"` in `src/`.
|
||||
- [x] 6.4 No `biome-ignore` / `TODO` / `FIXME` / `XXX` in `src/`.
|
||||
|
||||
## 7. Archive
|
||||
|
||||
- [ ] 7.1 Fold the spec delta into `openspec/specs/game-server/spec.md` and
|
||||
move the change folder to `openspec/archive/<yyyy-mm-dd>-game-server-enhanced-anti-cheat-lag/`
|
||||
after merge.
|
||||
Reference in New Issue
Block a user