Холст
Текстовые блоки, панели, полоски прогресса, изображения, круги на земле и маршруты со стрелками поверх игровой картинки. Рантайм сам рисует их каждый кадр и не меняет состояние игры, поэтому это безопасно и в многопользовательской игре; работать можно через Python, HTTP или напрямую через общую память.
Внешняя программа может рисовать поверх игровой картинки текстовые блоки, панели, полоски прогресса, изображения, круги на земле и маршруты по земле (со стрелкой) — рантайм сам отрисовывает их каждый кадр. Подходит для собственного HUD, вспомогательных линий, подсказок, учебных пометок, информационных плашек для стрима.
Холст или визуальные функции JASS
| Холст (эта страница) | Визуальные функции JASS | |
|---|---|---|
| Кто рисует | Сам рантайм | Сама игра (всплывающий текст, эффекты, панели, диалог с портретом…) |
| Многопользовательская игра | Безопасно: рисуется только на вашем экране, игровые объекты не создаются, состояние игры не меняется | Только одиночная игра |
| Оформление | Свободное: любые шрифты (включая китайские), скруглённые углы, полупрозрачность, рамки, любые цвета, локальные изображения | Родной стиль игры |
| Привязка | К юниту, к координатам мира, к позиции на экране; круги на земле повторяют рельеф | Зависит от функции |
| Затраты | Замер: 0.2 ~ 0.35 ms за кадр (9 элементов) | Около 13 ms на вызов |
Оба пути можно совмещать: эффекты в родном стиле игры — через JASS, собственные панели, вспомогательные линии и подсказки — через холст.
Python
c = g.canvas # при первом обращении рантайм ставит хук отрисовки (около 0.1 s)
c.text("title", "Привет, это холст", screen=(40, 110), color=(255, 220, 80),
bg=(0, 0, 0, 170), border="#C49C40", size=22, bold=True)
c.panel("status", "Компаньон · Светик", ["Настроение: радость", "Убийств: 12"], screen=(16, 330))
c.bar("hp", 0.62, unit=hero, lift=260, width=100, height=12, color=(80, 220, 80), text="62%") # следует за юнитом
c.text("tag", "Босс готовит ульту!", unit=boss, lift=320, color=(255, 80, 80), size=22, bold=True)
c.circle("danger", (x, y), 300, color=(255, 60, 60), fill=(255, 60, 60, 60), width=3) # опасная зона на земле
c.circle("aura", hero, 450, color=(80, 200, 255, 220)) # круг, следующий за юнитом
c.path("route", [(x1, y1), (x2, y2), (x3, y3)], color=(255, 220, 0), width=5, arrow=True)
c.image("icon", "icon.png", screen=(40, 170), width=64, height=64)
c.remove("danger"); c.hide("tag"); c.clear() # clear убирает только то, что нарисовали вы
c.expire("tag", 5) # исчезнет сам через 5 s
with c.batch(): ... # много изменений разом — одна запись в общую память
c.stats() # drawnFrames растёт = отрисовка действительно идёт
Каждый элемент обозначается ключом key: повторная отрисовка с тем же key — это обновление.
Кликабельность: добавьте текстовому блоку или панели clickable=True (цвет при наведении задаётся через hover=) — при клике в поток событий приходит ui.click, ev.key равен этому key, а сам клик по элементу до игры не доходит. Готовые кнопки, карточки выбора, горячие клавиши и клики по земле — в разделе Интерфейс и ввод.
Позиция (у каждого элемента одна):
screen=(x, y): пиксели экрана, отрицательные значения отсчитываются от правого / нижнего края;center=True— выравнивание по центру;frac=(0.5, 0.1): доли экрана;world=(x, y): координаты мира;unit=юнит: следовать за юнитом. Текст и полоски в мире и над юнитом привязываются к точке серединой нижнего края,liftподнимает их выше.
Элементы в мире и над юнитами по умолчанию не заходят на нижнюю панель управления и шар дня и ночи вверху (over_ui=True — рисовать поверх них). Цвет можно задать как (r, g, b), (r, g, b, a), "#RRGGBB" или "#RRGGBBAA".
| Метод | Что рисует | Основные параметры |
|---|---|---|
text(key, текст, ...) | Текстовый блок, несколько строк — через \n | color, bg фон (не задан — прозрачный), border, size, bold, shadow, width (перенос по этой ширине), radius скругление углов |
panel(key, заголовок, [строки...], ...) | Панель (тёмный полупрозрачный фон, золотая рамка) | Как у text |
bar(key, 0..1, ...) | Полоска прогресса: здоровье, перезарядка, произнесение | width, height, color, bg, border, text |
image(key, путь, ...) | Локальное изображение (png / jpg / bmp / gif) | width, height (не заданы — исходный размер) |
circle(key, юнит или точка, радиус, ...) | Круг на земле, повторяет рельеф | color цвет линии, fill заливка (с прозрачностью), width толщина линии |
path(key, [точки...], ...) | Ломаная на земле | color, width, arrow стрелка на конце; точки — координаты или юниты |
HTTP (любой язык)
Бэкенд Farsight (слушает только локальный адрес):
POST /api/instances/20/canvas
{"set": [
{"key": "banner", "kind": "text", "text": "Холст из HTTP", "frac": [0.5, 0.12], "center": true,
"color": "#FFDC50", "bg": [0, 0, 0, 180]},
{"key": "hp", "kind": "bar", "value": 0.8, "unit": 596125988, "lift": 260, "text": "80%"},
{"key": "zone", "kind": "circle", "center": 596125988, "radius": 600, "color": [255, 200, 0], "width": 4},
{"key": "route", "kind": "path", "points": [[-4587, -9092], [-5387, -8792]], "color": "#50C8FF"}
],
"remove": ["old"], "clear": false}
GET /api/instances/20/canvas какие элементы сейчас нарисованы + сколько кадров отрисовано
kind — это имя метода в Python, имена параметров те же; юнит задаётся адресом addr из снимка.
Напрямую через общую память
Можно обойтись без Python и Farsight: один раз отправьте семантическую команду canvas_enable (код операции W3P 73), и рантайм создаст блок общей памяти Local\War3Canvas_<pid>: заголовок 64 байта + 256 записей × 112 байт + пул текста / точек на 64 KB. Запись идёт по seqlock (номер становится нечётным → записываются элементы и пул → номер становится чётным); рантайм читает блок раз в кадр, а если попадает на наполовину записанные данные, повторяет предыдущий кадр. Обратно он записывает число отрисованных кадров, число элементов и счётчик сбоев. Эталонная реализация на Python — sdk/python/w3canvas.py, структуры описаны в заголовочном файле протокола, см. Протокол W3P.
Несколько программ рисуют одновременно
Моды, Farsight, MCP и шлюз могут одновременно рисовать в одной и той же игре, а холст всего один. Правило: каждая программа трогает только свои элементы.
- перед записью взять именованную блокировку, прочитать текущие элементы, оставить чужие, заменить свои и записать всё обратно;
- каждый элемент помнит, кто его нарисовал (идентификатор процесса + порядковый номер внутри процесса); если нарисовавшая его программа завершилась, элемент попутно убирается при следующей записи, кто бы её ни делал, а его кнопки больше не перехватывают клики;
- номера элементов выдаёт общий счётчик, так что они не совпадают.
Python SDK уже так и работает, и clear() тоже убирает только свои элементы. Если пишете в общую память напрямую, следуйте этим правилам, иначе затрёте чужое. Подробности о раскладке памяти — см. Протокол W3P.
Замеры и замечания
- Замер 2026-09-25 (1920×1080, скорость 2×): 9 элементов — 0.27 ~ 0.34 ms за кадр, около 63 кадров в секунду, 0 сбоев; запись 9 элементов — 6 ms; когда герой двигается, круг, текст и полоска здоровья, привязанные к юниту, не отстают. Текстура перерисовывается, только когда меняется содержимое; при простом перемещении перерисовки нет.
- Холст рисуется после интерфейса игры и перед указателем мыши: он перекрывает собственные полоски здоровья игры, юнитов и интерфейс, а указатель мыши рисуется поверх него. Нижнюю панель управления и шар дня и ночи он обходит, но собственные панели карты не обходит (таблицу лидеров и таймер в правом верхнем углу) — свои панели в правый верхний угол не ставьте.
- Вне матча (в главном меню, на экране итогов) элементы, привязанные к координатам мира и к юнитам, не рисуются, а привязанные к позиции на экране рисуются как обычно.
- Круг на земле строится так: каждая из 64 точек окружности отдельно проецируется на землю, поэтому на неровном рельефе форма круга следует за ним. Так и должно быть: круг нарисован на настоящей поверхности.
- При первом включении нужно поставить хук и прогреть шрифты — около 1 секунды; в это время текстовые элементы не рисуются, а круги и линии рисуются.
- Если при отрисовке случился хотя бы один сбой, до конца сеанса холст больше не рисует (та же защита, что у облачков над головой), а
faultsвstats()становится 1. - Текст, пути к изображениям и точки — всего 64 KB, не больше 256 элементов; путь к изображению должен быть локальным путём, доступным процессу игры.
Панель состояния ИИ-компаньона нарисована именно на холсте: полоска здоровья, текущее занятие, настроение, число убийств и лечений.