refactor: move game-specific import logic into profiles; unblock Tomie import

- Add app/games: GameProfile base, registry, ReaderHooks and renpy/naninovel/
  tomie profiles. pipeline, preflight, detect and mods dispatch via the registry
- Move tomie_* converter modules to app/games/tomie and split out reader hooks,
  import, mod validation and known defects
- Tolerate the 31 authoring defects of the pinned Tomie build as report
  warnings (exact list, per-script counts); any new defect still blocks import
- Frontend: runtime registry (runtimes.ts) with lazy Tomie launcher
- Add profile/registry tests and docs/GAME_PROFILES.md; update IMPORT.md

Full media export of the original Tomie build is not yet verified.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
mrleo1nidandClaude Sonnet 5.5 committed 2026-10-25 11:35:23 +03:00
1 parent bbbcc6a5d8
commit 12ec82c7e6
30 files changed
+700 -196

No files matched your search

+5 -26
View File
@@ -7,6 +7,7 @@ from uuid import NAMESPACE_URL, uuid4, uuid5
from app.blobs import BLOB_ID_RE
from app.converter.locales import walk
from app.converter.pipeline import anchors
from app.games.registry import for_runtime
from app.pgvn import expression, statements
from app.translation import file_json, put_json
@@ -111,8 +112,8 @@ def validate(doc, manifest):
body(n.get("body"), depth + 1)
if op == "exec":
statements(n.get("code"))
if op == "nani_command" and game.get("runtime") != "tomie/1":
raise ValueError("Исходные команды Naninovel требуют плеер Tomie")
if op == "nani_command" and not for_runtime(game.get("runtime")):
raise ValueError("Исходные команды Naninovel требуют отдельный плеер игры")
for path, module in scripts.items():
check_path(path)
@@ -134,30 +135,8 @@ def validate(doc, manifest):
raise ValueError("Точка входа не найдена")
if any(t not in names for t in targets):
raise ValueError("Переход на отсутствующую метку")
if game.get("runtime") == "tomie/1":
from app.converter.tomie_format import unpack_modules
from app.converter.tomie_validation import validate_runtime
native = unpack_modules(scripts)
issues = validate_runtime({"scripts": native})
if issues:
raise ValueError(issues[0].message + " (" + issues[0].location + ")")
config = game.get("tomie")
if not isinstance(config, dict) or not isinstance(config.get("defaults"), dict) or not isinstance(config.get("function_data"), dict):
raise ValueError("Отсутствуют исходные настройки Tomie")
start = config.get("start", {})
script = native.get(start.get("script"))
if script is None or start.get("label", "") not in script["labels"]:
raise ValueError("Точка входа Tomie не найдена")
media = config.get("media")
if not isinstance(media, dict):
raise ValueError("Не найден индекс медиа Tomie")
for collection in ("backgrounds", "characters", "textures", "videos", "audio", "fonts"):
if not isinstance(media.get(collection), dict):
raise ValueError("Некорректный индекс медиа Tomie: " + collection)
for entry in media[collection].values():
path = entry.get("file") if isinstance(entry, dict) else entry
if not isinstance(path, str) or path not in manifest["files"]:
raise ValueError("Отсутствует медиа Tomie: " + str(path))
if profile := for_runtime(game.get("runtime")):
profile.validate_mod(game, scripts, manifest)
files = manifest["files"]
for path, entry in files.items():
check_path(path)