С 2022 года я в одиночку поддерживаю сервер World of Warcraft 3.3.5a на открытом ядре AzerothCore. Расскажу, как я закрывал главную проблему небольшого сервера ботами-компаньонами и на какие грабли при этом наступил. Если вы работаете с AzerothCore или TrinityCore, часть историй может сэкономить вам пару вечеров.

Задача: пустые очереди

Поиск подземелий (LFG) в WotLK рассчитан на тысячи игроков онлайн. На небольшом сервере очередь на героик может висеть часами: нет танка, нет хила, а то и вообще никого. Игрок заходит вечером, ждёт и уходит.

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

Основа: mod-playerbots

Писать всё с нуля я не стал. Для AzerothCore есть модуль mod-playerbots. Он заводит ботов на отдельных аккаунтах, сам их прокачивает и экипирует. Боты умеют вести себя в подземельях, рейдах и на полях боя.

Я работаю с собственным форком. Главные изменения — поведение ботов в очереди подземелий и на арене, ребаланс и перевод фраз ботов на русский. Сервер русскоязычный, и английские реплики в чате группы смотрелись чужеродно.

Как настраивается пул ботов

Модуль держит пул «случайных ботов». В конфиге задаются минимальная и максимальная численность пула и распределение по уровневым диапазонам: сколько ботов держать на 15–19 уровнях, сколько на 20–29 и так далее до 80-го.

Первая неочевидная вещь: сумма квот по диапазонам должна совпадать с максимальной численностью пула. Если изменить количество ботов и не пересчитать диапазоны, распределение по уровням поедет. Я поймал это, когда сокращал пул с 1550 ботов до 50.

Сейчас у меня 50 ботов, из них 15 — на 80-м уровне, остальные поровну по диапазонам. Перекос к капу сделан намеренно: на 80-м больше всего героиков и рейдов, и боты нужнее всего именно там.

Почему всего 50, если железо позволяет больше? Сервер работает на Xeon со 128 ГБ памяти и NVMe, и тысяча с лишним ботов его не роняла. Но при небольшом онлайне слишком много ботов размывает мир: в чате и на аукционе их становится больше, чем людей. Задача ботов — закрывать дыры в группах, а не изображать население.

Грабли №1: часть группы не телепортируется в подземелье

Симптом: группа собралась, игрок телепортировался внутрь, а часть ботов осталась снаружи.

Причина — в проверках состояния персонажа перед телепортом LFG. Ядро не телепортирует персонажа, если тот падает или находится в прыжке. Для живого игрока это разумно. Но бот в момент сбора группы мог прыгать, преследуя цель, и телепорт для него тихо не срабатывал: ни ошибки, ни записи в логе.

Решение: для ботов проверка падения и прыжка при телепорте LFG пропускается. Игроков это не касается, у них поведение осталось оригинальным.

Грабли №2: падение сервера при роспуске группы

Симптом: периодические падения worldserver, стек ведёт в функцию роспуска группы.

Причина — обращение к уже несуществующему объекту при роспуске групп, созданных для Battlefield, то есть внешних PvP-зон вроде Озера Ледяных Оков. У таких групп свой жизненный цикл, и в момент роспуска код обращался к тому, чего уже не было. С живыми игроками это случалось редко. Боты, которые постоянно вступают в группы и выходят из них, сделали редкий баг регулярным.

Решение — добавить проверку существования объекта перед обращением.

Попутно всплыли и другие гонки, например при применении аур питомцев. Общий вывод: боты — бесплатный нагрузочный тест. Групповых операций они совершают на порядки больше, чем люди, и вытаскивают баги, которые годами спали в ядре.

Грабли №3: сервер читал чужие конфиги

Самая коварная история. Боты в ней сыграли роль индикатора.

У меня две сборки ядра: тестовая и боевая, в разных каталогах. Главный конфиг сервера явно передаётся при запуске, поэтому база данных и порты всегда были правильными. Но путь к каталогу конфигов модулей вшивается в исполняемый файл при сборке. Однажды на прод уехал файл, собранный в тестовом дереве. Сервер начал читать конфиги модулей тестового реалма.

Внешне всё работало, только:

  • ботов стало 50 вместо 1550;

  • автозаполнение очередей подземелий и арены ботами выключилось;

  • модули, которых нет в тестовой сборке, молча работали на значениях по умолчанию. Например, сменился множитель опыта.

Так продолжалось около двух с половиной суток, пока я не заметил, что онлайн подозрительно мал.

Теперь перед выкатом на прод скрипт сначала проверяет, из какой сборки взят новый исполняемый файл: читает вшитый в него путь к конфигам и сравнивает с боевым. Если путь не совпадает, выкат останавливается. Дополнительно скрипт сохраняет копию старой версии и сам откатывает её, если сервер упал или не ответил за отведённое время.

Бот как соперник на арене 1х1

На сервере есть рейтинговая арена один на один. Проблема та же, что с подземельями: соперника нет. Поэтому если живой противник не нашёлся за 15 секунд, против игрока выходит бот. Ожидание ограничено, и арена превращается из «очереди на вечер» в режим, куда можно зайти на пять минут.

Итоги

  • mod-playerbots — рабочая основа, но для продакшена его придётся дорабатывать.

  • Боты — лучший бесплатный нагрузочный тест: редкие гонки и обращения к удалённым объектам они вытаскивают за дни.

  • Проверяйте, из какой сборки взят выкатываемый файл. Путь к конфигам модулей вшит в него намертво, а явно указанный конфиг переопределяет только главный файл.

  • Сумма квот по уровням должна совпадать с размером пула ботов.

  • Больше ботов — не всегда лучше. На небольшом сервере их задача — закрывать дыры в группах, а не создавать массовку.

Всё это работает на моём сервере Valor (valor.su). Если есть вопросы по AzerothCore или playerbots, отвечу в комментариях.