Отладка и производительность
Почему тик медленный, почему команда не сработала, почему игра стоит. Ищите по симптомам, а затем подтверждайте встроенными скриптами проверки в реальной игре.
Смотрите на квитанцию
Квитанция каждой команды — информация из первых рук:
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 игровые секунды после гибели.