- 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>
51 lines
2.1 KiB
Python
51 lines
2.1 KiB
Python
"""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
|