From 0822c76321cd187347d9ccf8f5a934ce78fe4439 Mon Sep 17 00:00:00 2001 From: mrleo1nid <43583385+mrleo1nid@users.noreply.github.com> Date: Mon, 26 Oct 2026 03:05:52 +0300 Subject: [PATCH] feat: build profile for The Only Doe 0.05 that fixes an assignment in a menu condition sleep.rpy tests `... before_sleeping=2` (assignment) in an elif; sleep.rpyc holds the same text, so Ren'Py cannot compile that branch either. Builds can now carry exact-line patches pinned by the SHA-256 of the line and the build fingerprint; this one restores `==2`. Anything else stays strict. Co-Authored-By: Claude Sonnet 5.5 --- backend/app/games/renpy_builds.py | 26 ++++++++++++++++++++++++++ backend/tests/test_game_profiles.py | 19 +++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/backend/app/games/renpy_builds.py b/backend/app/games/renpy_builds.py index 2ea4293..f1fea16 100644 --- a/backend/app/games/renpy_builds.py +++ b/backend/app/games/renpy_builds.py @@ -90,6 +90,18 @@ BUILDS: dict[str, dict] = { }, "defects": {}, }, + "bb19a33af00324fa027a629c052aee885e72f1b7bee7074403a5b9e20c69e2d8": { + "id": "renpy/the-only-doe-0.05", + # One menu branch tests `... before_sleeping=2` (assignment), which Ren'Py cannot compile either: + # sleep.rpyc holds the same text. The port corrects the operator; the digest pins the exact line. + "lines": { + "sleep.rpy": { + "fa092f95dd51401da31285c68c7c4fa9ad9ae4a5dd8c1a1582192f32b1e650cf": + ' elif wake_up_after_sex=="spitroast" and number_of_people_had_sex_with_before_sleeping==2:', + }, + }, + "defects": {}, + }, } @@ -136,6 +148,19 @@ def identify(game_dir: Path) -> str | None: return build["id"] if build else None +def _patch_lines(source: str, patches: dict[str, str]) -> str: + """Replace single lines whose exact text (without the line ending) matches a recorded SHA-256.""" + if not patches: + return source + lines = source.splitlines(keepends=True) + for index, line in enumerate(lines): + text = line.rstrip("\r\n") + replacement = patches.get(hashlib.sha256(text.encode()).hexdigest()) + if replacement is not None: + lines[index] = replacement + line[len(text):] + return "".join(lines) + + def prepare_source(build_id: str | None, relative: str, source: str) -> str: """Adapt verified engine integration blocks, preserving source line numbers. @@ -145,6 +170,7 @@ def prepare_source(build_id: str | None, relative: str, source: str) -> str: from app.converter.rpy_lexer import parse_tree build = next((b for b in BUILDS.values() if b["id"] == build_id), {}) + source = _patch_lines(source, build.get("lines", {}).get(relative.lower(), {})) patches = build.get("blocks", {}).get(relative.lower(), {}) if not patches: return source diff --git a/backend/tests/test_game_profiles.py b/backend/tests/test_game_profiles.py index 692133b..9d851a1 100644 --- a/backend/tests/test_game_profiles.py +++ b/backend/tests/test_game_profiles.py @@ -52,3 +52,22 @@ def test_known_defects_are_waived_only_up_to_the_recorded_count(): assert blocking == [new] and known == [known_issue] same_message_other_script = Issue(code, message, "SomewhereElse:1") assert split_known([same_message_other_script])[0] == [same_message_other_script] + + +def test_known_build_line_patch_requires_the_exact_line(): + import hashlib + + from app.games import renpy_builds + + wrong = ' elif wake_up_after_sex=="spitroast" and number_of_people_had_sex_with_before_sleeping=2:' + fixed = wrong.replace("=2:", "==2:") + assert hashlib.sha256(wrong.encode()).hexdigest() in renpy_builds.BUILDS[ + "bb19a33af00324fa027a629c052aee885e72f1b7bee7074403a5b9e20c69e2d8"]["lines"]["sleep.rpy"] + source = f"label a:\r\n{wrong}\r\n pass\r\n" + assert renpy_builds.prepare_source("renpy/the-only-doe-0.05", "Sleep.rpy", source) == \ + f"label a:\r\n{fixed}\r\n pass\r\n" + # another build, another file, or an edited line stays untouched + assert renpy_builds.prepare_source(None, "sleep.rpy", source) == source + assert renpy_builds.prepare_source("renpy/the-only-doe-0.05", "other.rpy", source) == source + edited = source.replace("spitroast", "other") + assert renpy_builds.prepare_source("renpy/the-only-doe-0.05", "sleep.rpy", edited) == edited