Converter - screens.py parses the screen language: containers (fixed, frame, vbox, hbox, grid, vpgrid, viewport, button, has), widgets (text, textbutton, imagebutton, add, bar ...), if/for/use/transclude, default, python, key, timer, on, inline ATL, conditional properties, and decompiled forms (unparenthesised operators, glued property values, comma separated actions) - style statements, call/show/hide screen operators and Python-level renpy.show_screen are translated; only screens the game shows are audited, unused stock screens no longer block an import; undefined screens do - ATL values may be computed at run time and transforms take parameters (at blink(0.2, 0.3)); blur property Player - screens.ts builds the DOM from the IR and rebuilds it on state changes; buttons with idle/hover/selected/insensitive states, tooltips, sounds, modal screens, timers and keys that survive re-rendering, saved with the save file - Actions: Jump, Call, Return, SetVariable, Toggle*, SetScreenVariable, Show, Hide, ToggleScreen, Function, Play, Notify, If, Language, ShowMenu, OpenURL ... - Crop/LiveCrop/Solid/Frame/Transform/DynamicDisplayable values, crop property, globals(), renpy.variant/change_language/seen_image, transition stubs Tests: screen parser and runtime (linkedom DOM), screens fixture compiled from tests/fixtures/screens.rpy. Docs: docs/SCREENS.md. Twisted-Thoughts now passes the strict compatibility check. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
137 lines
8.4 KiB
Markdown
137 lines
8.4 KiB
Markdown
# PGames — локальная библиотека визуальных новелл
|
||
|
||
Загружаете архив с игрой на Ren'Py или Unity-игру на Naninovel (включая
|
||
отдельный адаптер Tomie) — сервер распаковывает его, переводит
|
||
скрипты и ассеты в собственный формат **PGVN** (JSON-скрипты, WebP, Opus, WebM)
|
||
и удаляет исходники. Игры других движков отклоняются на входе. Играете в браузере во встроенном плеере. У каждой игры
|
||
может быть несколько версий (форков) от разных пользователей; версии делят
|
||
общие ассеты, поэтому форк почти не занимает места.
|
||
|
||
Подробности устройства — в [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md).
|
||
|
||
Пакетный импорт коллекции, строгая проверка совместимости и текущие ограничения
|
||
Naninovel описаны в [docs/IMPORT.md](docs/IMPORT.md).
|
||
|
||
Профили игр (отдельный конвейер для игр с особенностями) —
|
||
в [docs/GAME_PROFILES.md](docs/GAME_PROFILES.md).
|
||
|
||
Редактор модов, слияние, перенос на новую версию, ревизии и сборщик мусора —
|
||
в [docs/MODDING.md](docs/MODDING.md).
|
||
|
||
## Установка на VM
|
||
|
||
```bash
|
||
git clone <repo> pgames && cd pgames
|
||
cp .env.example .env
|
||
# обязательно поменяйте SECRET_KEY (openssl rand -hex 32) и пароли
|
||
docker compose up -d --build
|
||
```
|
||
|
||
Приложение слушает `http://<IP VM>:8080` (порт — `HTTP_PORT` в `.env`).
|
||
Caddy на хосте Proxmox:
|
||
|
||
```
|
||
games.example.lan {
|
||
reverse_proxy 192.168.1.50:8080
|
||
}
|
||
```
|
||
|
||
Если в браузере сайт открывается по HTTPS через Caddy, оставьте
|
||
`COOKIE_SECURE=true`; при доступе напрямую по HTTP поставьте `false`, иначе
|
||
браузер не сохранит сессию.
|
||
|
||
## Первый вход
|
||
|
||
Логин `admin` / пароль из `ADMIN_PASSWORD` (по умолчанию `admin`). Сразу после
|
||
входа нужно задать свой логин и пароль.
|
||
|
||
Регистрации нет: пользователей создаёт админ в разделе «Пользователи».
|
||
Сервер генерирует пароль и показывает его один раз — передайте его человеку,
|
||
при первом входе он задаст свой. Права настраиваются через роли
|
||
(«Роли»): `admin`, `moderator`, `player` плюс свои.
|
||
|
||
## Импорт уже распакованных игр
|
||
|
||
Если игры уже лежат на VM распакованными, архивировать их не нужно.
|
||
Подключите папку к контейнеру (только чтение) и запустите импорт:
|
||
|
||
```bash
|
||
docker compose run --rm -v /srv/games:/games:ro backend \
|
||
python -m app.import_dir "/games/Some-Game" --title "Some Game"
|
||
```
|
||
|
||
Папка не изменяется, сконвертированная копия попадает в библиотеку как
|
||
обычная загрузка. Проверить, насколько хорошо конвертер понимает игру,
|
||
не трогая медиа (минуты вместо часов), можно сухим прогоном:
|
||
|
||
```bash
|
||
docker compose run --rm -v /srv/games:/games:ro backend \
|
||
python -W ignore -m app.converter.analyze "/games/Some-Game"
|
||
```
|
||
|
||
## Данные и бэкап
|
||
|
||
* `./data/blobs` — сконвертированные игры (неизменяемые файлы по sha256);
|
||
* том `db` — PostgreSQL (пользователи, игры, версии, сохранения).
|
||
|
||
Для бэкапа достаточно `pg_dump` и копии `data/blobs`.
|
||
|
||
## Разработка
|
||
|
||
На Windows тестовый стенд поднимается одной командой: `start-test.bat`.
|
||
Он запускает отдельный compose-проект `pgames-test` на http://localhost:8090
|
||
(свой `.env.test`, данные в `data-test\`), генерирует тестовую игру
|
||
`data-test\sample.zip` и открывает браузер. `start-test.bat stop` — остановить,
|
||
`reset` — удалить стенд вместе с данными, `logs` — логи бэкенда и воркера.
|
||
|
||
```bash
|
||
cd backend && pip install -r requirements-dev.txt ruff && ruff check . && python -m pytest
|
||
cd frontend && npm install && npm run dev # проксирует /api на :8000
|
||
cd frontend && npm run typecheck && npm test
|
||
python -m tests.make_sample sample.zip # тестовая игра (из backend/)
|
||
```
|
||
|
||
Тесты конвертера требуют `ffmpeg` в `PATH`. Те же проверки (ruff, pytest,
|
||
`tsc`, тесты и сборка фронтенда) выполняет GitHub Actions
|
||
(`.github/workflows/ci.yml`); `mypy` запускается там как справочная проверка.
|
||
|
||
Каталоги `data/` и `data-test/` содержат библиотеку и тестовый стенд (гигабайты),
|
||
они в `.gitignore` — не добавляйте их в коммиты и в образы Docker.
|
||
|
||
Вход ограничен по числу неудачных попыток: 8 ошибок за 15 минут по IP или по
|
||
логину блокируют вход на оставшееся время (ответ 429 с `Retry-After`). Счётчик
|
||
хранится в памяти процесса и сбрасывается при перезапуске backend.
|
||
|
||
## Что поддерживает конвертер Ren'Py
|
||
|
||
`label`, реплики (в т.ч. атрибуты, `extend`, `centered`, NVL), `scene/show/hide`
|
||
с `at`/`as`/`behind`/`zorder`/`with`, переходы (`dissolve`, `fade`,
|
||
`Fade(...)`, `vpunch`, wipe/slide…), `menu` с условиями и `set`, `if/elif/else`,
|
||
`while`, `jump/call/return` (включая `expression`), `$`/`python:`/`init python:`
|
||
(подмножество Python: переменные, выражения, списки/словари, циклы),
|
||
`define/default`, `Character(...)`, `image` (файлы, цвета, `Transform`, `im.*`,
|
||
`Composite`, `ConditionSwitch`, `Movie`, покадровые ATL-анимации с `pause`/`repeat`),
|
||
`layeredimage` (always/attribute/group/if), `transform` со статическими
|
||
свойствами, `Shake`, `camera`, вложенные метки и именованные `menu`,
|
||
`call label(args)` и метки с параметрами, `play/queue/stop/voice` и свои
|
||
каналы (`register_channel`), `pause`, `.rpa`, `.rpyc` (через unrpyc),
|
||
автоопределение картинок из `images/`, GUI-текстбокс и шрифты игры.
|
||
|
||
Для Naninovel/Tomie см. [docs/IMPORT.md](docs/IMPORT.md).
|
||
|
||
Python игры выполняется в песочнице плеера: свои `def` и `class` (наследование,
|
||
`super()`, свойства, замыкания, `lambda`, `*args`/`**kwargs`), `try`/`except`/
|
||
`finally`, `raise`, `assert`, `for`/`while … else`, comprehension. ATL: движение
|
||
(`linear`/`ease`/`easein`/`easeout`), `pause`, `repeat`, `parallel`, `choice`,
|
||
`block`, `on show`/`on hide`, вызов других transform.
|
||
|
||
Экраны игры (`screen`, `call screen`, `show screen`) и их действия — см.
|
||
[docs/SCREENS.md](docs/SCREENS.md).
|
||
|
||
Пока **не** поддерживается: в экранах — `input`, `imagemap`, `mousearea`, `drag`, `side`, в ATL —
|
||
`function`, `time`, `contains`, `matrixcolor` и шейдеры,
|
||
в Python — специальные методы кроме `__init__`/`__str__`/`__repr__`, генераторы,
|
||
`with`, системные модули (`os`, `socket`, …) и картинки, которые игра вычисляет
|
||
своими функциями. Такие места перечислены в отчёте конвертации у версии и
|
||
останавливают импорт. Игры-«песочницы» на `renpy.ui.*` и `im.*` пока не играбельны.
|