Newer
Older
PixelPaintWar / apps / client / src / scenes / game / application / time / PongSampleEstimator.ts
/**
 * PongSampleEstimator
 * PONGペイロードからRTTと時計差分を推定する
 * 不正値や過大RTTサンプルを除外して品質を担保する
 */
import type { PongPayload } from "@repo/shared";

/** PONGサンプル推定結果の型 */
export type PongSample = {
  rttMs: number;
  offsetMs: number;
};

/** PONGサンプル推定の設定値 */
export type PongSampleEstimatorConfig = {
  maxAcceptedRttMs: number;
};

/** PONGサンプル推定の既定設定 */
export const DEFAULT_PONG_SAMPLE_ESTIMATOR_CONFIG: PongSampleEstimatorConfig = {
  maxAcceptedRttMs: 1000,
};

/** PONGから同期サンプルを推定する */
export class PongSampleEstimator {
  private readonly config: PongSampleEstimatorConfig;

  constructor(config: Partial<PongSampleEstimatorConfig> = {}) {
    this.config = {
      ...DEFAULT_PONG_SAMPLE_ESTIMATOR_CONFIG,
      ...config,
    };
  }

  /** PONG受信情報からRTTとoffsetを推定して返す */
  public estimate(
    payload: PongPayload,
    receivedAtMs: number,
  ): PongSample | null {
    const measuredRttMs = receivedAtMs - payload.clientTime;
    if (measuredRttMs < 0 || measuredRttMs > this.config.maxAcceptedRttMs) {
      return null;
    }

    const estimatedOneWayMs = measuredRttMs / 2;
    const measuredOffsetMs =
      payload.serverTime - (payload.clientTime + estimatedOneWayMs);

    return {
      rttMs: measuredRttMs,
      offsetMs: measuredOffsetMs,
    };
  }
}