← Капитанский журнал

Плагины, которые могут исчезнуть бесследно — разделение manifest/definition/core/ui

Как мы спроектировали систему плагинов, где ни одна часть кода не знает ни одного плагина по имени — и почему это важно.

Tinker Dice в основе своей — игровой движок, который ничего не знает об играх. Он знает плагины. И вся система построена так, чтобы он никогда, ни при каких обстоятельствах не знал, какие плагины существуют.

Это не случайность. Это ограничение, которое мы ввели рано: ни в одном месте проекта — ни в движке, ни на сервере, ни в редакторе — не должно быть упоминания какого-либо конкретного плагина. Ни if (pluginId === 'cards'), ни захардкоженных импортов, ни особых случаев. Каждый плагин живёт в своей папке под shared/plugins/{pluginId}/, самодостаточный и заменяемый.

Каждый плагин — это четыре файла:

  • core.ts — рантайм-логика. Хэндлеры, исполняемые на сервере. Это мир движка.
  • definition.ts — спецификация для AI. Параметры, типы, ноды редактора. Так AI знает, что плагин умеет.
  • manifest.ts — документация для AI. Описания, возможности, примеры. Так AI рассказывает о плагине.
  • ui-widget.tsx — React-компоненты для отображения данных плагина в UI. Это мир игрока.

Разделение на четыре файла соответствует четырём разным аудиториям: движок, AI-дизайнер, база знаний AI и человек-игрок. Каждый файл принадлежит своей зоне ответственности, и ни один не просачивается в другие.

Плата за это — жёсткая простота остальной кодовой базы. Движок загружает плагины по конвенции, а не по имени. Можно удалить папку плагина, переименовать его или заменить — и ничего больше не сломается. Редактор не знает про карты, ходы или голосования. Он знает про плагины — в общем виде.

Это тот вид ограничений, который кажется избыточным до того момента, когда нужно удалить или отрефакторить плагин. А тогда он кажется предусмотрительностью.