///|
/// desync_demo:证明分叉检测真的会响。
///
///   moon run examples/desync_demo
///
/// 先跑一局正常的,确认「没有分叉」不是靠什么都不检查;再让 P1 在第 100 帧
/// 「本地执行 A、发出去的是 B」,看检测器能否在正确的帧上报出来。
///
/// 现实里对应的是序列化 bug、两端版本不一致、漏同步了某个字段。注意不能
/// 直接去改内存里的状态——回滚会从快照恢复重放,把它洗掉。
const FRAMES : Int32 = 300

///|
const CORRUPT_AT : Int32 = 100

///|
fn main {
  // 100ms 延迟 + 50ms 抖动的链路,两条场景用同一组参数。
  let spec = @scene.LinkSpec::new(6, 3, 0, 0)
  println("desync_demo:分叉检测器自证")
  println("")
  let clean = @scene.run_link(spec, FRAMES, 0)
  println("场景 A · 正常对局")
  println(
    "  分叉帧 = \{frame_or_dash(clean.first_divergence)},一致 = \{clean.synced}",
  )
  println(
    "  校验失配 = \{clean.mismatches},回滚 = \{clean.p0_rollbacks}/\{clean.p1_rollbacks}",
  )
  println("")
  let broken = @scene.run_link(spec, FRAMES, CORRUPT_AT)
  println(
    "场景 B · 第 \{CORRUPT_AT} 帧 P1 发出去的输入与本地执行的输入不一致",
  )
  println(
    "  分叉帧 = \{frame_or_dash(broken.first_divergence)}(从这一帧起两端世界不同)",
  )
  println("  P0 hash  = \{broken.hash0}")
  println("  P1 hash  = \{broken.hash1}")
  println(
    "  校验失配 = \{broken.mismatches}(P1 发出的 Checksum 与 P0 的历史哈希不符)",
  )
  println("  一致 = \{broken.synced}")
  println("")
  if clean.synced && !broken.synced && broken.first_divergence > 0 {
    println(
      "结论:正常局不报警,篡改后在同一帧上被两端同时发现——检测是可用的。",
    )
  } else {
    println(
      "失败:检测器没能区分正常与异常,这本身就是一个 bug。",
    )
  }
}

///|
fn frame_or_dash(frame : Int32) -> String {
  if frame == 0 {
    "-"
  } else {
    frame.to_string()
  }
}