mrleo1nidandClaude Sonnet 5.5 3923ee72fb feat: generator interpreter for Python that waits for the player (Ren'Py)
Python containing renpy.input, narrator("..."), character calls, renpy.say,
renpy.pause, renpy.display_menu, renpy.with_statement or renpy.call_screen now
runs through loops, try, functions, methods and expressions.

Player
- python.ts: execG/evalG/callG run only the code that may wait (mayBlock);
  everything else stays on the synchronous fast path. A waiting call returns a
  BlockingCall; outside the generator interpreter it is an explicit error. The
  interpreter scope is set aside while the player decides
- engine: drives the generator and answers requests (dialogue, text input with
  length/allow/exclude, pause, choice menu, transition, call screen)
- renpy.show/hide/scene, transitions and transforms as Python values,
  Character(...) objects, Borders, set_tag_attributes

Converter
- blocking_names() lists game functions that may wait, transitively, and ships
  them as game.json "blocking"; character calls are allowed
- hide screen of an unknown screen is harmless; images defined by a parenthesised
  expression are supported

Hooked now passes the strict compatibility check (with Tomie and Twisted-Thoughts).
Tests: waiting.py fixture run through the generator interpreter; blocking-name analysis.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 14:22:38 +03:00

PGames — локальная библиотека игр в браузере

Домашний сервер для коллекции игр, которые играются прямо в браузере: визуальные новеллы, игры-«песочницы» с открытым миром, текстовые квесты и другие. Вы загружаете архив или папку с игрой, сервер распознаёт движок, переводит сценарии и ассеты в собственный формат PGVN (JSON-скрипты, WebP, Opus, WebM) и удаляет исходники; играть можно во встроенном плеере, без установки. У каждой игры может быть несколько версий (форков) от разных пользователей; версии делят общие ассеты, поэтому форк почти не занимает места. Есть редактор модов и переводов, ревизии и слияние.

Каждый движок и каждая особенная игра подключаются профилем (см. docs/GAME_PROFILES.md):

Движок Состояние
Ren'Py основной: сценарии, Python-песочница, ATL, экраны
Unity + Naninovel (в том числе Tomie) импорт скомпилированных сценариев
GameMaker (песочницы вроде FF692) планируется: загрузчик data.win и виртуальная машина GML
QSP (Quest Soft Player) планируется: текстовые квесты .qsp
Unity (без Naninovel), Godot, RPG Maker пока отклоняются при загрузке

Игры других движков отклоняются на входе: неподдерживаемое никогда не «импортируется наполовину».

Подробности устройства — в docs/ARCHITECTURE.md.

Пакетный импорт коллекции, строгая проверка совместимости и текущие ограничения Naninovel описаны в docs/IMPORT.md.

Профили игр (отдельный конвейер для игр с особенностями) — в docs/GAME_PROFILES.md.

Редактор модов, слияние, перенос на новую версию, ревизии и сборщик мусора — в docs/MODDING.md.

Установка на VM

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 распакованными, архивировать их не нужно. Подключите папку к контейнеру (только чтение) и запустите импорт:

docker compose run --rm -v /srv/games:/games:ro backend \
    python -m app.import_dir "/games/Some-Game" --title "Some Game"

Папка не изменяется, сконвертированная копия попадает в библиотеку как обычная загрузка. Проверить, насколько хорошо конвертер понимает игру, не трогая медиа (минуты вместо часов), можно сухим прогоном:

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 — логи бэкенда и воркера.

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.

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.

Пока не поддерживается: в экранах — input, imagemap, mousearea, drag, side, в ATL — function, time, contains, matrixcolor и шейдеры, в Python — специальные методы кроме __init__/__str__/__repr__, генераторы, with, системные модули (os, socket, …) и картинки, которые игра вычисляет своими функциями. Такие места перечислены в отчёте конвертации у версии и останавливают импорт. Игры-«песочницы» на renpy.ui.* и im.* пока не играбельны.

S
Description
No description provided
Readme
1.9 MiB
0 Stars 1 Watchers 0 Forks
Languages
TypeScript 46.8%
Python 38.3%
JavaScript 11.1%
CSS 3.5%
Batchfile 0.2%