С 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, отвечу в комментариях.

