Один рантайм, один протокол — игра становится программируемой средой
W3 Runtime внедряется в оригинальную игру и в игровом потоке собирает состояние мира, исполняет команды и сообщает результаты. Вашему ИИ достаточно сказать «что сделать» — общение идёт по версионированному протоколу общей памяти.
Нижний слой не знает о верхнем
В интерфейсном слое нет ни строчки логики «атаковать или нет»; мозги не импортируют друг друга и зависят только от SDK. На этом держится Арена: платформе нужны лишь «интерфейсный слой + судья», а подключить можно чей угодно мозг.
Вся карта — каждые 50 ms
Рантайм собирает данные за один проход в игровом потоке и выкладывает их в общую память; клиенты читают напрямую и больше не стоят в очереди к игровому потоку. Один сбор — в медиане 0.5 ~ 0.9 ms (100 ~ 120 юнитов), время по этапам всегда записано в заголовке блока мира.
Игроки ×16
Золото, древесина, пища и лимит, всего добыто, раса
Юниты ×1024
Тип, владелец, координаты, здоровье и мана, текущий приказ и цель, кого юнит на самом деле атакует, уровень, опыт, очки навыков, видимость для каждого игрока
Подробности юнитов ×256
12 способностей (уровень, оставшаяся перезарядка), 8 баффов, 6 ячеек инвентаря; герои в приоритете
Производство ×128
Тренировка / исследование / строительство / улучшение: очередь, общая длительность, прошедшее время, не застряло ли
Предметы на земле ×256
Тип, позиция, прочность; подбор или использование порождает событие
Деревья ×4096
Позиции и здоровье разрушаемых объектов, обновление каждые 2 секунды
Карта
Сетка проходимости и застройки с клеткой 128, игровая область, стартовые точки; рассчитывается за несколько секунд в начале матча
Время
Игровые часы движка, время суток, скорость игры, идёт ли матч
Как исполнить — решает рантайм
Добыча, отступление, применение способностей… Всё это «приказать юниту», но внутри движка пути совершенно разные. Весь этот опыт собран в рантайме: вы говорите, что сделать, он исполняет проверенным рецептом и в том же кадре возвращает квитанцию с приказом до и после.
- Одна отправка — одна пачка, исполняется в одном кадре
- Квитанция на каждую команду: код статуса + код причины движка + время выполнения
- Очередь через Shift, точки маршрута, постройка нескольких зданий подряд
- Запросы: счётчики технологий, выполнимость, видимость, остаток золота, цель атаки компьютерного противника
Дело никогда не было в межпроцессном взаимодействии
Чтение и запись общей памяти занимают наносекунды, снимок читается ≈ за 0.05 ms. Старый канал был медленным, потому что каждый запрос захватывал общую для всей машины блокировку и ждал, пока игра в следующий раз заберёт сообщение (раз в кадр, 16 ~ 33 ms). Эталонный мозг тратил на это ожидание 93% реального времени.
- Захватить общий для всей машины мьютекс
- Отправить сообщение игровому потоку
- Ждать, пока игра заберёт сообщение (раз в кадр)
- Дождаться события завершения, отпустить блокировку
При 6 процессах пропускная способность упиралась примерно в 88 запросов/с.
- У каждого клиента собственная полоса: один писатель, один читатель, без блокировок
- Исполнение происходит в диспетчеризации событий игрового потока (сотни раз в секунду); когда отправок нет, накладные расходы — несколько сравнений целых чисел
- 16 команд за одну отправку исполняются в одной диспетчеризации; на каждый проход — бюджет 4 ms
- У каждой команды есть дедлайн: после снятия с паузы просроченные команды не выполняются
В квитанции каждой команды указано время выполнения, а заголовок полосы хранит самую медленную команду и длительность последнего прохода — сразу видно, где тормозит.
| Уровень | Канал | Задержка | Кто использует | Статус |
|---|---|---|---|---|
| 0 | Push-снимок + поток событий | чтение ≈ 0.4 ms; новая копия каждые 50 ms (можно до 16 ms) | Все боты | Проверено в игре |
| 1 | Быстрая полоса | ≈ 1 кадр; при 6 процессах медиана 0.06 ms, пропускная способность ≈ 3000 команд/с | SDK по умолчанию | Проверено в игре |
| 2 | Канал управления | 20 ~ 40 ms | Резервный путь, немногие операции с интерфейсом | Проверено в игре |
| 3 | Шлюз (WebSocket / JSON) | уровень 1 + ≈ 1 ms | Любые языки, страницы в браузере, LLM (MCP), другая машина | Проверено в игре |
Замеры (тестовый экземпляр 1.27, 2026-09-23 / 24)
Инженерная заметка: первые 3 минуты матча каждая команда была в 1000 раз медленнее
Когда к каждой команде добавили время выполнения, выяснилось: в первые минуты матча каждая команда в пачке, начиная со второй, занимала 4 ~ 10 ms, а примерно на 180-й секунде игрового времени внезапно ускорялась до нескольких микросекунд. Встроенный в рантайм сэмплер игрового потока собрал 1700 сэмплов — 93% пришлись на собственную функцию логирования рантайма: каждая строка синхронно открывала и закрывала файл лога, а в начале матча строка пишется на каждый приказ движка. После того как отладочный лог по умолчанию выключили, а запись логов сделали асинхронной, даже команды на 14-й секунде матча занимают всего 4 ~ 8 µs.
Мы верим измеренным числам, а не догадкам.
У каждой полосы есть роль
Проверка владения и фильтрация по обзору выполняются в рантайме: слой исполнения движка сам не проверяет, кому принадлежит юнит, и восполнить это можно только здесь. Бой двух ИИ — это две полосы player в одном матче.
| Роль | Что видит | Что может |
|---|---|---|
| player | Всё своё + враги и нейтралы в пределах обзора (честный режим) | Командовать только своими юнитами Игроки, ваш бот |
| observer | Вся карта | Приказывать нельзя; можно делать запросы, управлять камерой, читать HUD Режиссура, комментаторы, разбор матчей |
Не гадать и не падать
1.24 ~ 1.28 построены на одном движке — это подходит под схему «один рантайм + несколько профилей». 1.29+ и Reforged — другой движок, автоматическую совместимость с ними мы не обещаем.
- Определение Читаем ресурс версии и хэш файла Game.dll, выбираем профиль
- Таблица символов Рецепты ссылаются на имена символов, а не на числа; у каждого символа указаны соглашение о вызове и форма аргументов
- Резерв по сигнатурам На неизвестной версии ищем по байтовой сигнатуре начала функции; используем, только если совпадение единственное
- Самопроверка при запуске Каждый символ проверяется без побочных эффектов; не прошедшие проверку возможности помечаются недоступными
- Список возможностей Если SDK видит, что возможность недоступна, вызов выбрасывает понятную ошибку, а не тихо возвращает 0
Баг в одном боте не должен ронять всю игру
Поэтому каждый ИИ работает в отдельном процессе: нулевой указатель внутри процесса игры — это падение всего матча, а если упал отдельный процесс, останавливается только одна сторона.
| Механизм | Как сделано | Статус |
|---|---|---|
| Не ронять игру | Все вызовы в игру защищены обработкой исключений; бюджет 4 ms на проход (таймер высокой точности) | Есть |
| Клиенты не мешают друг другу | У каждого клиента своя полоса и своя квота; зависший клиент не блокирует остальных | Есть |
| Просроченное не выполняется | У каждой команды есть дедлайн; просроченные только помечаются и не выполняются, после паузы не воспроизводятся | Есть |
| Наблюдаемость | Время выполнения каждой команды; время каждого сбора по этапам записано в заголовке блока мира | Есть |
| Переподключение | SDK автоматически переподключается при смене матча или процесса | Частично |
| Предохранители возможностей | Возможность отказала N раз подряд → помечается недоступной, отправляется событие, остальные работают как обычно | В планах |
Делайте в игре что-то своё
Семантические команды позволяют ИИ действовать как игрок; слой расширений позволяет менять то, что игрок видит и переживает: рисовать собственный интерфейс, который можно нажимать, и вызывать все функции, доступные авторам карт. Эти два пути разделены по тому, безопасны ли они в многопользовательской игре.
- Текстовые блоки, панели, индикаторы прогресса, изображения, круги по рельефу, маршруты со стрелками
- Привязка к юниту, мировым координатам или позиции на экране; любые шрифты (включая китайские), скругления, полупрозрачность, любые цвета
- Рисует сам рантайм: игровые объекты не создаются, состояние игры не меняется
- В Python — одна строка на элемент; также через HTTP или прямой записью в общую память
- Кнопки и карточки выбора нажимаются и подсвечиваются при наведении; рисуются под указателем мыши, а клик по ним до игры не доходит
- Создание юнитов, изменение характеристик, эффекты, панели, диалоги, звук, камера, туман войны, погода…
- Консоль Farsight, командная строка, HTTP, Python — один и тот же синтаксис скриптов
- Частые эффекты — одной строкой: всплывающий текст, линии, круги радиуса, диалог с портретом, полноэкранный фильтр
- В многопользовательской игре разрешены только функции чтения — чтобы не было рассинхронизации
| Холст | Визуальные функции JASS | |
|---|---|---|
| Кто рисует | Сам рантайм | Сама игра |
| Многопользовательская игра | Безопасно: рисуется только на вашем экране | Только одиночная игра |
| Стиль | Любой: шрифты, скругления, полупрозрачность, изображения | Родной стиль игры |
| Привязка | Юнит / мировые координаты / позиция на экране | Зависит от функции |
| Стоимость | 0.2 ~ 0.35 ms за кадр | ≈ 13 ms на вызов |
Действия игрока сразу попадают в поток событий
Рантайм напрямую сообщает о действиях игрока: какую нарисованную кнопку он нажал, какую горячую клавишу, куда кликнул на земле, кого выбрал, какую способность применил, что написал в чат. Собственные триггерные события игры (вход в область, кнопки диалогов, стрелки) по-прежнему можно ловить пустым триггером: только зарегистрировать событие, без условий и действий, и считать, сколько раз он сработал.