Сделать мозг
Пакет .oabrain для одного места компьютера: папка, все ключи манифеста, теги, уровни, полный обзор, где выполняется скрипт, бюджеты и что бывает, когда он останавливается.
Эта глава кратко пересказывает docs/brains/oabrain-standard.md, docs/brains/authoring.md и docs/playing-with-brains.md. Нормативный текст — в этих документах.
Что такое мозг
Собственный компьютерный игрок движка остаётся игроком по умолчанию и остаётся в движке. Мозг играет за одно место компьютера, и только за то, на которое его поставил игрок. Пустой id мозга — это и есть встроенный игрок. Место без мозга, мозг, который не подходит, и мозг, который остановился, — во всех этих случаях играет тот же встроенный игрок. Classic написан на Lua и играет так же, как этот игрок. Это документация встроенного игрока, а не замена ему.
Скрипт выполняет только машина, которая размещает компьютерного игрока, поэтому другим игрокам ничего устанавливать не нужно. Их машины отражают юниты этого места. При воспроизведении записи скрипт не выполняется. Мозг — это исходный код Lua и данные. У него нет нативного кода, файлов, сети и часов. Полный обзор — флаг в манифесте. Мозг может его установить и играть с ним в сетевой игре, а место показывает этот флаг.
Пакет
Мозг — это один файл .oabrain или папка, в которую он распаковывается. Манифест — тот же строгий YAML, что и профиль мода: один документ, одно отображение верхнего уровня, без якорей и блочных скаляров. В корне пакета лежит oabrain.yaml. Каждый файл рядом с ним должен быть одним из перечисленных ниже. Файл вне этого списка отклоняется.
my-brain.oabrainфайл, который получает игрок├─ oabrain.yamlобязательно манифест, не больше 256 КиБ├─ brain.luaвходной скрипт. Имя по умолчанию — brain.lua. entry называет другое, и этот файл должен быть в пакете├─ lua/дополнительный исходный код Lua. require читает только эти файлы. Каждая часть имени — строчные буквы, цифры и _├─ nets/сеть, которую называет манифест: nets/ и имя на .oann├─ data/одна таблица данных на глубине одной папки: .csv, .tdf, .json или .txt├─ icon.pngизображение, только если его называет icon. Без этого ключа файл не входит в список├─ README.mdзаметка в корне. Игра её не загружает└─ LICENSEлицензия в корне. Имя licence и readme во вложенной папке в список не входятПри сравнении регистр букв ASCII не учитывается, кроме случаев, когда стандарт требует совпадения байтов. brain.lua не входит в список, если entry называет другой файл. Один файл Lua — не больше 1 МиБ. Значок — квадратный PNG, каждая сторона не больше 256 пикселей, размер не больше 256 КиБ. OA устанавливает мозг в Brains/, в папку с id из манифеста.
Манифест
Парсер собирает все нарушенные правила и при любом нарушении оставляет манифест без изменений. Ключ, которого нет в стандарте, отклоняется. Ключу профиля место в моде. Ключ мутатора отклоняется как ключ мутатора. Версию берите в кавычки, потому что 1.0 без кавычек — это число, а звёздочку — потому что звёздочка без кавычек — это псевдоним YAML.
| Ключ | Обязательно | Что делает |
|---|---|---|
oabrain | да | Формат. Целое число 1. 1.0 и 1 в кавычках отклоняются. |
id | да | Строчные буквы, kebab-case, от 1 до 64 байт. Без дефиса в начале и в конце и без двойного дефиса. Имя папки в Brains/. |
name | да | От 1 до 64 байт, без управляющих символов. Название, которое видят игроки. |
version | да | В кавычках, от одной до трёх частей, как версия мутатора, например "2.0". Простое число отклоняется. 2, 2.0 и 2.0.0 считаются равными. |
author | да | Отображение. name обязателен, от 1 до 128 байт. email необязателен. |
description | да | Обязательно, от 1 до 2 000 байт. Перевод строки допустим. Любой другой управляющий символ отклоняется. Первая строка, обрезанная до 200 байт, — это краткое описание. |
homepage | нет | Адрес http или https. |
icon | нет | Только icon.png, изображение в корне пакета. Всё остальное отклоняется. |
tags | да | От 1 до 4 из девяти тегов ниже, без повторов. |
works-with | да | От 1 до 32 условий, без повторов id. Звёздочка означает любой мод и основную игру и тогда должна быть единственной записью. ta-3.1c означает основную игру без мода. Любой другой id — это мод, с необязательным диапазоном версий. |
requires | нет | Только engine и expansions. engine — диапазон, в кавычках, если начинается со знака «больше». expansions — от 1 до 16 id комплектов. Мозг не может требовать мутатор. |
levels | да | От 1 до 6 уровней. Каждое отображение — ровно id, name и difficulty. |
fullAwareness | нет | true или false. Если нет, то false. true в кавычках отклоняется. |
networks | нет | От 1 до 16, каждая — ровно id, file и sha256. file — это nets/ и имя на .oann. sha256 — 64 шестнадцатеричные цифры в нижнем регистре, в кавычках. |
options | нет | Не больше 16, по правилам параметров мутатора. Переключатель — true или false, число — число, выбор — его текст. Их читает me.options. |
strings | нет | Не больше 16 языков. Язык может содержать name, description, options, labels и levels. |
entry | нет | Файл Lua в корне пакета, имя из строчных букв, цифр и _. Если не указан — brain.lua. |
Девять тегов
Тег — один из этих девяти, сравнение побайтовое. Больше четырёх тегов, когда общее правило тегов уже пройдено, — отдельная ошибка. Тег не из этих девяти отклоняется.
| Ключ |
|---|
classic |
economy |
rush |
turtle |
air |
naval |
learned |
teaching |
experimental |
Уровни и сложность
levels — это список из 1–6 отображений. Каждое — ровно id, name и difficulty, все обязательны. id — kebab-case строчными буквами длиной от 1 до 32 байт, без повторов. name — от 1 до 64 байт без управляющих символов. difficulty — easy, medium или hard, побайтово.
Эти три имени соответствуют значениям 0, 1 и 2. Место, на котором выбран уровень, использует это значение для правил дохода — ту же сложность, что игра уже использует.
Полный обзор
fullAwareness — true или false. Если нет, то false. Мозг с этим флагом видит юниты, которые место в тумане войны не увидело бы, как и встроенный компьютерный игрок, и его проверкам площадок не нужен размещающий игрок. Флаг разрешён в сетевой игре. Библиотека показывает Видит все юниты на карте, как и компьютер самой Total Annihilation. Флаг принадлежит самому манифесту. Он не выдаётся по id пакета и не входит в то, что дано только Classic.
Где выполняется мозг
Пакет нужен только машине, которая размещает компьютерного игрока, и только эта машина выполняет скрипт. Место — это компьютерный игрок этой машины. Место человека отклоняется. game.mode — skirmish, campaign или network.
| Ситуация | Что выполняется |
|---|---|
| Схватка | Каждое место компьютера, за которое играет эта машина, если игрок поставил на него мозг. Пустой id — это встроенный компьютерный игрок. |
| Миссия кампании | Место в кампании следует мозгу по умолчанию, который выбрал игрок. Миссия этот выбор не игнорирует. |
| Сетевая игра | Мозг выполняет машина, которой принадлежит место компьютера, включая полный обзор. Другие машины — нет. |
| Сохранённая игра, загруженная позже | Сохранение записывает мозг каждого места. Что происходит, если пакета нет или версия отличается, описано в стандарте. |
| Воспроизведение записи | Запись хранит текст brains. Воспроизведение применяет записанные пакеты. Оно не сажает мозг на место и не вызывает его хуки. |
| Deathmatch или турнир | Запуск не создаёт мест компьютера. |
Мозг, который играет за место, не входит в хеш симуляции. Два матча, которые отличаются только тем, какой мозг сидит на месте, дают один и тот же хеш состояния матча. Значения доработок ai.* мода входят в профиль мода, который покрывает этот хеш, поэтому они всё равно доходят до каждой машины.
Бюджеты среды выполнения
Мозг выполняется как Lua в одной песочнице. Два мозга не делят модулей, глобальных переменных и бюджетов. У скрипта нет файлов, часов, окружения, процессов и сети. Каждый чанк загружается как текст. pcall и xpcall не могут продлить исчерпанную фазу. Ход — это один вызов за счёт банка инструкций в точке контроллера места, после обхода юнитов. Приказы, отданные хуком, вступают в силу на следующем тике.
| Бюджет | Значение |
|---|---|
| Инструкции в load, fits, start, save и report | 50,000,000 |
| Инструкции, которые добавляет один тик | 2,000,000 |
| Сколько тиков может хранить банк, включая текущий | 30, поэтому начальный баланс — 60 000 000 |
| Память Lua | 64 МиБ (67 108 864 байт). Между фазами не сбрасывается. |
| Память сетей | 64 МиБ, отдельно от предела Lua |
| Реальное время фазы, которая не является ходом, в миллисекундах | 10,000 |
| Реальное время одного хода, в миллисекундах | 250 |
| Одна строка, в байтах | 65,536 |
Когда мозг даёт сбой
Мозг останавливается из-за ошибки в хуке или таймере, исчерпанного лимита инструкций, предохранителя реального времени, предела памяти Lua, строки длиннее 65 536 байт или загрузки, которую отклоняет место. Неудачный ход закрывает песочницу и очищает хуки до того, как этот ход вернёт управление. Неудачный ход всё равно считается сыгранным. На следующем тике приказов хуков нет, поэтому его берёт встроенный компьютерный игрок. У мозга, который отклонён, не смог запуститься или не подходит, хуков нет вовсе, поэтому этот игрок играет с самого начала. Уведомление использует название из манифеста и причину, обрезанную до 160 байт:
- `{brain} stopped ({reason}); the engine plays this seat on`
- `{brain} could not start ({reason}); the engine plays this seat`
- `{brain} does not fit this game ({reason}); the engine plays this seat`
Если у места нет собственной причины, причина — the brain could not be seated. Побеждённого игрока просто перестают вызывать. Песочница закрывается вместе с матчем.