Документация Расширения игры

Холст

Текстовые блоки, панели, полоски прогресса, изображения, круги на земле и маршруты со стрелками поверх игровой картинки. Рантайм сам рисует их каждый кадр и не меняет состояние игры, поэтому это безопасно и в многопользовательской игре; работать можно через 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, текст, ...)Текстовый блок, несколько строк — через \ncolor, 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 элементов; путь к изображению должен быть локальным путём, доступным процессу игры.

Панель состояния ИИ-компаньона нарисована именно на холсте: полоска здоровья, текущее занятие, настроение, число убийств и лечений.