Notice me, Senpy!

Всем ку. Исправлял тут кривущий русификатор для DDLC Blue Skies, и я задолбался помимо машинного перевода вылавливать сами багули, которые тянутся еще с оригинала DDLC.

Я очень привык к быстрому линтеру Ruff для обычных проверок проектов на Python, а никакого нормального линтера для Ren'Py я не нашел, кроме расширения Ren'Py Language, которое по сути... просто раскрашивает код.

В итоге психанул и набросал свой семантический линтер — Senpy (semantic + renpy / senpai + renpy).

В чем вообще разница между Ren'Py Language и Senpy?

Если коротко: Ren'Py Language следит за тем, чтобы у вас стояли нужные пробелы и двоеточия. Если вы напишете идеально отформатированный, но абсолютно нерабочий бред — он довольно промолчит. Senpy понимает, как устроен Ren'Py под капотом, и ищет грабли, которые сломают игру живому игроку:

  1. Сохранения и откат (Rollback):
  2. Обычный плагин: спокойно пропустит $ my_var = 1 посреди сюжета.
  3. Senpy: сразу даст по рукам (RPY104/105). Потому что переменная без верхнеуровневого default намертво ломает сейвы игроков после любого патча, а перезапись константы из define ломает механику отката назад.
  4. Экраны (Screen Language) и лаги UI:
  5. Обычный плагин: видит питоновский цикл или мутацию внутри screen и думает: «ну код как код».
  6. Senpy: знает, что Ren'Py оценивает экраны предиктивно наперед. Если пихнуть $ gold -= 10 или for i in range() прямо в тело экрана, интерфейс начнет дико фризить, а переменные будут мутировать сами по себе без клика игрока (RPY201, RPY205). Плюс находит кнопки без action (RPY203), на которые игрок жмет как в пустоту.
  7. Сюжетные дыры в меню: Если в развилке menu вы в одном выборе дали игроку $ has_key = True, а во втором забыли — Senpy предупредит (RPY401), что когда игрок пойдет по второй ветке, на следующем if has_key игра гарантированно вылетит с NameError.
  8. Ассеты (звуки и спрайты):Senpy реально сканирует папки и даже заглядывает внутрь .rpa архивов. Опечатались в имени звука или атрибуте спрайта — он не просто скажет «не найдено», а ещё и заботливо предложит опечатку: did you mean 'natsuki 5k'?

Что получилось на реальном проекте:

Вдохновлялся скоростью Ruff, поэтому движок новеллы для анализа не поднимаю — только быстрый гибридный парсер (AST + регулярки).

Натравил его на весь сценарий Blue Skies: 77 000 строк кода он перелопачивает за 3.9 секунды.

Киллер-фичи из коробки:

  • Авто-декомпиляция .rpyc: если закинули чужой мод, где часть файлов осталась только в скомпилированном виде — он сам предложит на лету распаковать их во временную песочницу через unrpyc и проверит проект целиком. То есть теперь не надо каждый раз раскомпилировать .rpyc.
  • Генератор дефолтов (--generate-defaults): если проект старый и там 50 переменных созданы на лету через $ без default, линтер с этим флагом сгенерирует готовый файл senpy_defaults.rpy с правильными начальными значениями (числа, строки, списки), чтобы спасти сохранения игроков.
  • Автофикс (--fix): если забыли закрыть тег {b} или {color} в диалоге — сам найдет закрывающую кавычку реплики и аккуратно вставит {/b} на место.
  • VS Code Extension (.vsix): собрал нормальный плагин с LSP, чтобы ошибки и подсказки светились прямо во время набора текста. В официальный маркетплейс Microsoft заливать не стал, ибо регистрация через Azure у мелкомягких — это отдельный цирк с конями, готовый .vsix лежит в релизах на GitHub.
  • --tsundere режим: чисто по фану зашил режим, где ошибки выдаются как реплики злой аниме-девочки, которая поливает тебя за то, что ты забыл объявить переменные или сломал механику отката.

Ставится в терминале за 5 секунд:

pip install senpy-linter

запускать просто в корне с .rpy или .rpyc командой senpy (как на примере выше)

Исходники и плагин для VS Code лежат тут: https://github.com/Xilleet/senpy

Прогоните на своих модах или новеллах на renpy, чисто ради интереса. Если наткнетесь на баги — пишите в Issues на гитхабе, буду допиливать.

22