Files
mtgodot-poc/.agents/skills/metin2-40250-parity-audit/scripts/audit_sequence_table.py
T
shenleiandClaude Opus 5 55f733fda6 audit: phase 0 tooling for file-by-file 40250 porting
- refroot.py: one reference-root resolver (MT_40250_SOURCE, then manifest)
  used by every audit script; missing tree or fingerprint input is an error
- port_map.py: per-function inventory of active 40250 units plus the
  40250 Python root, status/queue/init/show/check, 40250: tag scan
- manifest: fix 18 wrong reference paths (Python UI now points at the
  40250 Client/Eternexus/root, not the m2dev assets/root), drop 2 deleted
  implementation files, move 64 prose test entries to evidence.commands
- first port-map entry: PythonPlayerEventHandler.cpp
- roadmap replaced by a batch/unit queue

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 17:17:49 +09:00

69 lines
2.3 KiB
Python

#!/usr/bin/env python3
"""Verify the classic sequence table against the 40250 Windows source.
The client-side table is protocol data, not a generated random table. Compare
the complete byte array and report the digest so a copied prefix or reordered
tail cannot be mistaken for parity.
"""
from __future__ import annotations
import argparse
import hashlib
import json
import re
from pathlib import Path
import refroot # script directory is on sys.path when run directly
def read_array(path: Path, symbol: str) -> bytes:
text = path.read_text(errors="replace")
match = re.search(
rf"{re.escape(symbol)}\s*(?:\[[^\]]+\])?\s*=\s*\{{(?P<body>.*?)\}}\s*;",
text,
re.S,
)
if not match:
raise ValueError(f"cannot find {symbol} in {path}")
values = [int(token, 0) for token in re.findall(r"0x[0-9a-fA-F]+|\b\d+\b", match.group("body"))]
if any(value < 0 or value > 255 for value in values):
raise ValueError(f"out-of-range byte in {path}")
return bytes(values)
def digest(data: bytes) -> str:
return hashlib.sha256(data).hexdigest()
def main() -> int:
parser = argparse.ArgumentParser()
default_root = Path(__file__).resolve().parents[4]
parser.add_argument("--repo-root", type=Path, default=default_root)
args = parser.parse_args()
root = args.repo_root.resolve()
reference = refroot.reference_root(root) / "EterLib/NetStream.cpp"
current = root / "extension/src/net/classic/sequence_table.h"
try:
ref = read_array(reference, "s_bSequenceTable")
cur = read_array(current, "SEQUENCE_TABLE")
except (OSError, ValueError) as exc:
print(json.dumps({"status": "ERROR", "error": str(exc)}, indent=2, sort_keys=True))
return 2
first_difference = next((i for i, pair in enumerate(zip(ref, cur)) if pair[0] != pair[1]), None)
equal = len(ref) == len(cur) and first_difference is None
result = {
"status": "PASS" if equal else "FAIL",
"reference": {"length": len(ref), "sha256": digest(ref)},
"current": {"length": len(cur), "sha256": digest(cur)},
"first_difference": first_difference,
}
print(json.dumps(result, indent=2, sort_keys=True))
return 0 if equal else 1
if __name__ == "__main__":
raise SystemExit(main())