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:
1 parent
bbbcc6a5d8
commit
12ec82c7e6
30 files changed
+700
-196
No files matched your search
@@ -0,0 +1,50 @@
|
||||
"""Game profiles: everything specific to one engine or one concrete game build.
|
||||
|
||||
The shared pipeline (upload, queue, storage, mods, player shell) only talks to
|
||||
this interface. A game that needs its own importer, validator or runtime adds a
|
||||
profile in ``app/games`` and registers it; nothing else has to change.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from app.converter.pipeline import Result
|
||||
|
||||
Progress = Callable[[str], None]
|
||||
|
||||
|
||||
class GameProfile:
|
||||
"""Base class. Subclasses override what differs from a plain engine import."""
|
||||
|
||||
#: Stable identifier stored in reports, e.g. ``renpy`` or ``tomie/expansion-1.3801``.
|
||||
id: str = ""
|
||||
#: Engine family from ``compatibility.detect`` this profile applies to.
|
||||
engine: str = ""
|
||||
#: ``game.json`` ``runtime`` value for games played by a dedicated player (None = shared player).
|
||||
runtime: str | None = None
|
||||
#: True for profiles pinned to one concrete build; they win over the engine's generic profile.
|
||||
specific: bool = False
|
||||
#: True when ``pipeline.convert_archive`` itself performs the conversion (Ren'Py).
|
||||
converts_in_pipeline: bool = False
|
||||
|
||||
def claims(self, root: Path) -> bool:
|
||||
"""Whether this profile recognises the game at ``root`` (cheap, no media decoding)."""
|
||||
return True
|
||||
|
||||
def inspect(self, root: Path, work: Path | None = None) -> dict[str, Any]:
|
||||
"""Read-only compatibility check; raise ``CompatibilityError`` to refuse the game."""
|
||||
raise NotImplementedError
|
||||
|
||||
def convert(self, root: Path, work: Path, progress: Progress) -> Result:
|
||||
"""Full import into a PGVN package."""
|
||||
raise NotImplementedError
|
||||
|
||||
def validate_mod(self, game: dict[str, Any], scripts: dict[str, Any], manifest: dict[str, Any]) -> None:
|
||||
"""Extra checks for edited mods of games using this profile; raise ``ValueError``."""
|
||||
|
||||
def unity_hooks(self) -> Any | None:
|
||||
"""Hooks for the shared Unity/Naninovel reader (see ``app.games.hooks``)."""
|
||||
return None
|
||||
Reference in new issue
Block a user