Документация Руководства

Отладка и производительность

Почему тик медленный, почему команда не сработала, почему игра стоит. Ищите по симптомам, а затем подтверждайте встроенными скриптами проверки в реальной игре.

Смотрите на квитанцию

Квитанция каждой команды — информация из первых рук:

r = g.cast(hero, "blizzard", x=tx, y=ty)
if not r:
    print(r.reason, r.verdict)     # rejected(…) и код причины
print(r.exec_us, r.engine_us)      # сколько микросекунд команда выполнялась в игровом потоке / сколько из них заняла сама функция приказа движка

Обычно команда занимает в игровом потоке от нескольких до нескольких сотен микросекунд. После завершения блока пачки в g.last_receipts лежат квитанции всех команд этой пачки.

Смотрите прямо в игре

g.say(unit, "Отходим")          # над юнитом появляется облачко чата (на игру не влияет)
g.message("Начинаем крипинг")   # строка в области сообщений внизу слева (видна только на этом компьютере)

Вывод print появляется в терминале, где запущен бот. Печатайте ключевые решения каждого тика и добавьте облачка над юнитами — так разобраться гораздо быстрее, чем читая код.

Тик слишком медленный

Сначала проверьте, не ваш ли это случай:

ПричинаРешение
Команды отправляются по одной, и каждая ждёт кадрОберните их в with g.batch(): — десятки команд ждут только один раз
g.visible() / g.can_do() вызываются по одному (каждый вызов идёт через быструю полосу и ждёт кадр)Видимость берите из снимка через u.visible_to(); выполнимость спрашивайте пачкой через g.can_do_many([...])
sleep или ожидание внутри on_tickЗапомните игровое время и проверьте условие на следующем тике
Дорогие вычисления каждый тик (поиск пути, сканирование всей карты)Кэшируйте результат и пересчитывайте раз в несколько тиков. У g.grid() встроенный кэш на 2 секунды, уровни технологий в g.stats() кэшируются на 5 секунд

Игра стоит / бот не дожидается начала матча

СимптомСкорее всего
Бесконечное «ожидание матча»Неверный номер экземпляра; или окно игры свёрнуто — пока оно свёрнуто, симуляция стоит (часы не идут)
Игра идёт, а на приказы бота нет реакцииПриказы идут чужим юнитам (квитанция not_owner); или бот подключён как observer (forbidden)
Команды возвращают heldЮнита держит слой с более высоким приоритетом (рефлекторный слой эталонного мозга, ручной приказ из консоли), команда не отправлена
На паузе команды всё равно проходятЭто нормально: на паузе часы движка стоят, но диспетчеризация событий работает и команды выполняются как обычно

Подключиться и посмотреть статус

python -m openwar3 status --inst 5

Выводит состояние подключения: pid игры, период публикации мира и время каждого сбора, счётчики быстрой полосы, идёт ли матч, число юнитов, игровые часы.

Скрипты проверки в реальной игре

Запустите тестовый экземпляр и по пунктам проверьте, что возможности SDK работают на вашей машине:

python tools/sdk_live_check.py --inst 20                 # всё
python tools/sdk_live_check.py --inst 20 --only prod     # только один раздел

Разделы: пачки, время, производство, очередь приказов, боевые характеристики, поиск пути, честный режим. Каждый раздел отдаёт команды в настоящем матче, считывает результат и печатает число пройденных проверок.

Для офлайн-тестов игра не нужна:

python tools/run_tests.py

Частые «вроде бы баги»

  • Квитанция на строительство — «принята», а фундамента всё нет: точку в лесу движок тоже сразу принимает, а срывается всё, когда рабочий дойдёт до места. Используйте build_near: он следит за результатом и на время заносит неудачные точки в чёрный список.
  • Квитанция на способность — «принята», а способность не применилась: её прервали или не хватило маны. На следующем тике после применения проверьте по g.cooldown(), началась ли перезарядка.
  • Приказ атаки принят, а бойцы бьют кого-то другого: для атаки конкретной цели используйте g.attack(боец, враг) (семантика правого клика). Сырой приказ атаки на цель меняет только приказ, но не запоминает цель — и юнит пойдёт бить кого-то рядом.
  • Не сходится число рабочих: рабочих внутри рудника нет в снимке.
  • Погибшего героя не удаётся натренировать: герой уникален, нужен g.revive(алтарь); воскрешение требует пищи и доступно лишь примерно через 3 игровые секунды после гибели.