From 7f6330a61729606f73123c17bdedc06e1ef27984 Mon Sep 17 00:00:00 2001 From: m4ko Date: Fri, 28 Aug 2026 20:33:48 +0200 Subject: [PATCH] Added controller for the native world helper. --- ptlinux/world_fix.py | 66 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 ptlinux/world_fix.py diff --git a/ptlinux/world_fix.py b/ptlinux/world_fix.py new file mode 100644 index 0000000..0b5d7d4 --- /dev/null +++ b/ptlinux/world_fix.py @@ -0,0 +1,66 @@ +"""Exact-profile selection for the post-login V21 world-transition helper.""" + +from __future__ import annotations + +import hashlib +from pathlib import Path + + +V21_BINARY_HASHES = { + "Game.exe": "2bc3edd26c5f6d7ae9bbdc23967c5aefd374bdf934fcdfa2ed42c6442e550837", + "game.dll": "4b4e5c28e2bfdaa8d36c8341fad27becfd03faf63aa8ea874f5d43c5b1961868", +} +WORLD_FIX_HELPER_FILENAME = "pt-world-fix.exe" +# Filled from the reproducible stripped PE after the native helper is built. +WORLD_FIX_HELPER_SHA256 = ( + "d5bdf655f62dae429eff627cf8960f670ec59c12a9759dcd14342786f53e4019" +) + + +class WorldFixError(RuntimeError): + """Raised when an exact client needs a missing or untrusted helper.""" + + +def packaged_world_fix_helper() -> Path: + return Path(__file__).resolve().parent / "native" / WORLD_FIX_HELPER_FILENAME + + +def resolve_world_fix_helper( + game_directory: Path, + *, + helper: Path | None = None, +) -> Path | None: + """Return the verified helper only for the exact publisher V21 pair.""" + + game = game_directory.expanduser().resolve(strict=False) + hashes = { + name: _sha256(game / name) + for name in V21_BINARY_HASHES + if (game / name).is_file() + } + if hashes != V21_BINARY_HASHES: + return None + requested = packaged_world_fix_helper() if helper is None else helper.expanduser() + if requested.is_symlink(): + raise WorldFixError( + "the post-login world-fix helper must not be a symbolic link" + ) + candidate = requested.resolve() + if not candidate.is_file(): + raise WorldFixError( + "the verified post-login world-fix helper is missing; reinstall the launcher" + ) + digest = _sha256(candidate) + if digest != WORLD_FIX_HELPER_SHA256: + raise WorldFixError( + "the post-login world-fix helper failed its launcher integrity check" + ) + return candidate + + +def _sha256(path: Path) -> str: + digest = hashlib.sha256() + with path.open("rb") as handle: + for chunk in iter(lambda: handle.read(1024 * 1024), b""): + digest.update(chunk) + return digest.hexdigest()