Протокол AiControl
Проекты FOnline могут предоставлять клиент разработки автоматизированным QA-агентам, локальным инструментам или MCP-адаптеру, не превращая команды отдельной игры в часть Engine. Эта страница определяет такую переиспользуемую границу. Точный машинный контракт находится в сгенерированном справочнике протокола AiControl, а запускаемый пример транспорта — в Examples/AiControlSample.
Контракт имеет статус experimental. Закрепляйте ревизию Engine, отдельно версионируйте проектное наблюдение и считайте каждый listener чувствительной с точки зрения безопасности функцией разработки.
Решение по интеграции
Полная интеграция сохраняет видимыми четыре границы:
- Переиспользуйте только принадлежащие Engine UTF-8 newline-delimited TCP
envelope, общие методы и ошибки, ограничения размера, очереди и истории,
авторизацию, sequence id принятых команд и терминальный жизненный цикл
command_completed. - Оставляйте роли приложений и включение native listener, поля наблюдения и
schemaVersion, имена и семантику действий, расширения событий, имена инструментов и пространства имён MCP, рецепты запуска, политику агента и redaction policy во встраивающем проекте. Last Frontier и TLA являются отдельными проектными примерами; схема ни одного из них не становится поведением Engine. - Извлекайте команды через безопасную точку передачи в цикле проектного клиента и обычные аутентифицированные gameplay paths. Игровой сервер остаётся авторитетным; AI-адаптер не создаёт второй канал authority.
- Разделяйте уровни свидетельств. Пример протокола доказывает только framing, bounds, authorization и жизненный цикл команд; это не доказательство runtime FOnline. Отдельно доказывайте настоящий native client bridge с реальным клиентом, server rejection и authority behavior, а также исключение listener из shipping release artifacts.
За что отвечает Engine
Репозиторий Engine отвечает за:
- конверт UTF-8 JSON over TCP с одним сообщением на строку;
- методы
auth,ping,status,observe,eventsиact; - общие формы request/result/error и коды ошибок;
- требования к ограниченным размеру строки, очереди команд и истории событий;
- sequence id принятых команд и терминальное событие
command_completed; - политику безопасности с loopback по умолчанию;
- эталонный клиент на стандартной библиотеке, пример протокола, сгенерированный контракт, сфокусированные тесты и политику compatibility diff.
Это контракт протокола и интеграции, а не listener в основном runtime FOnline. Эталонный сервер намеренно заменяет цикл проектного клиента.
За что отвечает проект
Каждый встраиваемый проект отвечает за:
- наличие native listener и роли приложения, в которые он компилируется;
- исключение из shipping-сборок на этапе компиляции и runtime-настройку включения;
- поля наблюдения,
schemaVersion, критерии готовности, проекции сущностей и политику сокрытия информации; - имена действий, семантику параметров, обычную игровую валидацию, отмену и сообщения об ошибках;
- типы событий, кроме
command_completed; - имена MCP-инструментов, рецепты запуска, реестры endpoint, память, политики агентов, prompts и отчёты;
- интеграционные native/script-тесты настоящего проектного клиента.
Last Frontier и TLA имеют клиентские bridges, но различаются наблюдениями, каталогами действий, QA-командами и пространствами имён MCP. Эти поверхности подтверждают общий конверт, но не являются поведением Engine или шаблонами для копирования без изменений.
Архитектура
Обычная интеграция включает четыре зоны ответственности:
- Проектное native-расширение владеет ограниченным TCP listener, отдельной для каждого соединения авторизацией, разбором конвертов и потокобезопасными очередями.
- Цикл проектного клиента публикует неизменяемые снимки наблюдения и извлекает принятые команды в безопасной точке жизненного цикла script/native.
- Обработчики проектных действий вызывают обычное поведение клиента или аутентифицированные игровые RPC. Игровой сервер остаётся авторитетным и сохраняет server authority.
- Необязательный адаптер преобразует проектные наблюдения и действия в семантические MCP-инструменты. Wire-контракт при этом не меняется.
Поток listener не должен хранить или изменять script-объекты, сущности, узлы GUI либо состояние Engine. Передавайте через ограниченную очередь простые скопированные значения. Роли и жизненный цикл расширений описаны в NativeExtensions.md, владение потоками скриптов — в Жизненном цикле скриптов и конкурентности, а native/script handles — в Nullability.md.
Wire-протокол
Bridge использует последовательный request/response-протокол поверх потока байтов TCP. Каждое сообщение — один объект JSON в UTF-8, завершённый LF. JSON payload до LF не должен превышать 1 МиБ. Клиент отправляет один запрос и получает соответствующий ответ до повторного использования соединения; multiplexing не входит в контракт.
Конверт по форме похож на JSON-RPC и использует jsonrpc: "2.0", однако bridge
не заявляет полную поддержку JSON-RPC 2.0: notifications, batches, discovery и
все стандартные правила валидации не гарантируются.
Запрос:
{"jsonrpc":"2.0","id":1,"method":"observe","params":{}}
Успешный ответ:
{"jsonrpc":"2.0","id":1,"result":{"observationSeq":4,"observation":{"schemaVersion":1}}}
Ответ с ошибкой:
{"jsonrpc":"2.0","id":1,"error":{"code":-32001,"message":"Unauthorized"}}
Ответ должен повторять id запроса и содержать ровно одно из полей result или
error. Таблица кодов ошибок и точные правила framing принадлежат
справочнику wire-контракта.
Авторизация
Авторизация действует в пределах соединения. Если настроен token, до успешной
аутентификации разрешён только метод auth. Неверный token возвращает
{"authorized":false} и оставляет то же соединение неавторизованным; следующая
попытка может завершиться успешно. Новое соединение всегда начинает с нового
состояния авторизации.
Пустой token может быть удобен для listener разработки, доступного только через loopback. Он никогда не должен разрешать listener, привязанный за пределами loopback.
Методы
Шесть методов протокола намеренно образуют небольшую поверхность:
| Метод | Назначение |
|---|---|
auth |
Авторизовать текущее соединение общим token. |
ping |
Подтвердить доступность транспорта, но не готовность игры. |
status |
Получить состояние listener, заполнение ограниченных очереди/истории, sequence наблюдения и последнюю ошибку bridge. |
observe |
Прочитать последнее полное проектное наблюдение. |
events |
Запросить сохранённые временные события после исключающего sequence cursor. |
act |
Поставить одну проектную команду в очередь и вернуть её sequence. |
Точные формы параметров и результатов приведены в справочнике методов.
Наблюдения и события
observe возвращает конверт с одним проектным объектом:
{
"observationSeq": 4,
"observation": {
"schemaVersion": 1,
"ready": true,
"availableActions": ["move"]
}
}
observationSeq меняется при замене опубликованного снимка. Это не event cursor.
Проект должен публиковать полную внутренне согласованную копию; клиентам не
следует объединять поля из двух снимков.
events использует afterSeq как исключающий cursor и возвращает сохранённые
записи по возрастанию. Ответ также содержит latestSeq, даже если более новых
сохранённых событий нет. История событий ограничена: медленный адаптер может
пропустить старые события и должен синхронизироваться через observe, а не
рассчитывать на бесконечный журнал.
Жизненный цикл команды
Запрос act обязан содержать непустой проектный type команды. Протокол также
стандартизирует необязательные вспомогательные поля targetId, itemId,
auxId, x, y, screenX, screenY, intArg, stringArg и append.
Единицы измерения и смысл принадлежат проекту; проект может использовать
вложенную схему конкретного действия вместо принудительной передачи каждой
операции через эти поля.
Принятие в очередь — только первый этап:
{"jsonrpc":"2.0","id":7,"result":{"accepted":true,"commandSeq":12}}
После выполнения команды в цикле владельца клиент добавляет связанное терминальное событие:
{
"seq": 38,
"event": {
"type": "command_completed",
"commandSeq": 12,
"success": true,
"message": "moved"
}
}
Каждая принятая команда должна в итоге завершиться, включая неизвестные, отклонённые игрой, отменённые и прерванные при shutdown команды. Сохраняйте сообщения о завершении достаточно стабильными для диагностики, но для поведения, от которого зависит ветвление адаптера, используйте явные проектные поля событий.
Если очередь команд заполнена, act возвращает -32002; уже поставленные
команды нельзя перезаписывать или молча отбрасывать. Адаптеру следует дождаться
прогресса, обновить status/events и повторять команду только тогда, когда
повтор безопасен для соответствующего проектного действия.
Граница безопасности
Listener AiControl является поверхностью удалённого управления, даже если его планирует вызывать локальный тестовый процесс. Соблюдайте все правила:
- По умолчанию функция должна быть выключена.
- Для удалённой работы требуется непустой token.
- По умолчанию привязывайтесь к loopback. Перед привязкой к любому non-loopback-адресу требуйте явное разрешение оператора и непустой token.
- Считайте token и payload открытым текстом. В протоколе нет TLS, защиты от повторов, идентификации пользователя и authorization scopes. Предпочитайте loopback; в иных случаях создайте независимо аутентифицированный зашифрованный туннель.
- Читайте token из хранилища секретов или переменной окружения. Не помещайте его в командные строки, committed-конфигурации, логи, снимки экрана, fixtures или отчёты.
- Исключайте listener и путь удалённых команд из production-клиентов на этапе компиляции. Одна runtime-настройка оставляет поверхность безопасности и эвристик антивируса в бинарном файле.
- Ограничивайте размер строки, число ожидающих команд, сохранённых событий, размер наблюдения и число наблюдаемых сущностей.
- По умолчанию предоставляйте действия, эквивалентные возможностям игрока. Инструменты администратора и подготовки держите в отдельной явной проектной политике и фиксируйте их применение в свидетельствах QA.
- Скрывайте секреты, скрытое состояние сервера, приватное состояние других игроков и данные, которые обычный клиент не должен знать.
Общий token — минимальный барьер для локальной разработки, а не универсальная система безопасности. Не публикуйте этот TCP endpoint напрямую в LAN или интернете.
Native-интеграция проекта
Когда настоящему клиенту FOnline нужен bridge, используйте проектное native-расширение:
- Добавьте проектную опцию CMake, которая включает всю реализацию listener и по умолчанию соответствует политике разработки проекта. Принудительно выключайте её во всех release/package workflows.
- Храните в native bridge только простые скопированные значения команд, событий, статуса и наблюдений. Защитите все общие контейнеры явными locks и положительными пределами.
- Запускайтесь после готовности клиентского/script-модуля владельца. До создания потока listener отклоняйте небезопасные настройки host, port, token и capacity.
- Выполняйте parsing и enqueue в потоке listener. Извлекайте команды и публикуйте снимки из клиентского цикла через узкие экспортированные методы.
- При teardown прекратите принимать команды, закройте активный socket, разбудите поток, выполните join, завершите ошибкой все принятые незаконченные команды, отмените регистрацию callbacks и освободите проектное состояние до исчезновения client engine.
- Логи должны быть редкими и не содержать секретов. Сообщайте о сбоях
протокола через
status.lastErrorи проектную диагностику, не копируя произвольные payload.
Для эталонного контракта достаточно одного активного клиентского соединения. Проект может поддерживать больше, но тогда самостоятельно отвечает за изоляцию авторизации, event cursors, сериализацию записи, fan-out наблюдений и пределы нагрузки. Клиенты не должны зависеть от такого расширения.
Engine пока не предоставляет вспомогательный native listener. Его продвижение
потребует владельца основного runtime, кроссплатформенных socket-тестов,
доказательств корректных shutdown и thread safety, стабильной конфигурационной
поверхности и отдельного security review. Не описывайте проектную реализацию
SourceExt как встроенное поведение Engine.
Интеграция MCP-адаптера
Эталонный клиент BuildTools/ai_control_client.py — небольшая транспортная
библиотека и диагностический CLI. MCP-адаптер должен соблюдать те же правила,
но оставаться проектным:
- Подключайтесь к явно заданному endpoint и один раз авторизуйтесь для каждого соединения.
- Вызовите
statusиobserve; проверьте проектныйschemaVersionнаблюдения до публикации инструментов. - Преобразуйте в семантические инструменты только актуальные
availableActionsи видимые сущности. Не заставляйте модель синтезировать сырые объекты команд, когда typed tool может сначала их проверить. - Ведите независимый event cursor для каждого endpoint. Связывайте каждую
принятую команду с
command_completedи задайте timeouts/cancellation. - Отделяйте запуск процессов, выбор endpoint, screenshots, logs, memory и политику прохождения игры от wire-клиента.
- Включайте в отчёты версию bridge, версию проектной схемы, ревизии Engine/проекта и идентичность endpoint, но никогда не включайте token.
Не публикуйте инструменты Last Frontier lf_* или TLA tla_* как общие методы
FOnline. Небольшой проект может предоставлять только observe, move и
interact; крупной игре могут понадобиться диалоги, инвентари, бой, группы и
проектная QA-подготовка. Оба варианта используют один конверт.
Проверка
Запустите нейтральное к проекту доказательство из корня Engine:
python Examples\AiControlSample\run_protocol_smoke.py
python BuildTools\tests\test_ai_control_protocol.py
python BuildTools\tests\test_docs_ai_control_protocol.py
python BuildTools\docs_ai_control_protocol.py --check
Smoke-тест запускает временный loopback listener и проверяет отклонение неверного token, отдельную для соединения авторизацию, liveness, поля status, начальное наблюдение, неверные параметры, неизвестные методы, принятие действия, асинхронное завершение, обновлённое наблюдение и исключающие event cursors. Сфокусированные тесты malformed peer также отклоняют несовпадающие id, неоднозначные ответы, неверный JSON и слишком длинные строки.
Этот пример — не доказательство runtime FOnline. Проектная интеграция также обязана:
- собрать каждую native-роль, включающую или исключающую bridge;
- запустить настоящий клиент и доказать публикацию наблюдений вместе с извлечением команд в клиентском цикле;
- проверить типичные успешные действия обычного gameplay и отказы сервера;
- проверить reconnect, переполнение очереди, rollover событий, shutdown во время принятой команды и очистку процессов;
- исследовать release-артефакты и доказать, что listener не может запуститься, а проектная реализация удалённых команд отсутствует.
Для продолжительных многопроцессных сценариев объединяйте проектные проверки с набором для тестирования gameplay, а не добавляйте управление процессами в протокол.
Сопровождение
BuildTools/AiControlProtocol.json — канонический структурированный контракт.
Изменяйте его в одном change с любыми правками framing, методов, ошибок, общих
полей, безопасности, интеграции или проверки. Затем выполните:
python BuildTools\docs_ai_control_protocol.py --write
python BuildTools\docs_helper_cli.py --write
python BuildTools\docs_contract_diff.py --baseline-git-ref origin/master --allow-missing-baseline --write --enforce
python BuildTools\docs_public_api.py --write
Протокол AiControl — восемнадцатый сгенерированный домен совместимости. Удаление
или ограничение baseline-public-контракта либо снижение стабильности требует
записи в Docs/contract-change-dispositions.json по правилам
управления изменениями сгенерированных контрактов.
Изменения проектной схемы наблюдений/действий принадлежат проектной документации
и тестам, если общий конверт не меняется.
Когда Last Frontier, TLA или другой сопровождаемый проект меняет bridge, повторно проверяйте полный входящий диапазон проекта. Продвигайте только поведение, подтверждённое хотя бы одним независимым артефактом Engine и review; сохраняйте игровые схемы, имена MCP-инструментов и политику QA у проектов- владельцев.