muo.lv: двенадцать лет с игрой, к исходникам которой у меня не было доступа
В августе 2005 года друг предложил сделать частный сервер MuOnline, который конкурировал бы с крупнейшим в Латвии. Программирование взял на себя я. Мы открылись 21 февраля 2006 года, через несколько недель онлайн был 300–400 человек, а проект прожил больше десяти лет и шесть игровых сезонов.

Сайт muo.lv в 2006 году, тестовый сервер. Реквизиты для пожертвований и ники игроков размыты.
Подвох в том, что игровой сервер был закрытым бинарником. Менять его ядро я не мог — поэтому заходил со всех сторон, до которых дотягивался:
- DLL-инъекции с обеих сторон — в игровой клиент для античита и в серверный процесс, чтобы перехватить его сетевой слой;
- прокси перед сервером, через который проходил каждый пакет;
- триггеры в базе данных игры, сохранявшие дополнительную информацию, которую сам сервер не записывал;
- сканирование логов, чтобы реагировать на то, что происходит в игре.
Всё, чем muo.lv отличался от других, было построено вокруг закрытого ядра.

muo.lv во времена Season 6 (скриншот 2011 года): рейтинг персонажей, меню с квестами и рынком, кто сейчас на сайте.
Продуктом был сайт. Около 40 тысяч строк PHP на MS SQL: рынок игроков (именно он переманил к нам игроков конкурента), аукционы вещей и персонажей, биржа кредитов, квесты, рейтинги и графики онлайна, гильдии, личные сообщения, VIP, восстановление аккаунта по телефону, SMS- и PayPal-платежи — и GM-панель примерно на 50 страниц: поиск дюпов, генератор и декодер предметов, логи чата и торговли, баны, перезапуск серверов. У каждого предмета был уникальный серийный номер и история — это убило дюп.
Свой античит (2009). Клиентская DLL перехватывала сетевые вызовы, загрузку библиотек и кадры OpenGL: ловила speedhack сравнением двух часов, блокировала редакторы памяти и внедрённые DLL, оборачивала сетевой протокол своим шифрованием и отправляла отпечаток железа и MD5 файлов клиента.
Прокси перед каждым игровым сервером. Раз сервер не изменить — я поставил перед ним свой man-in-the-middle на C#. Он расшифровывал слой античита, не пускал клиентов с изменёнными файлами, банил по IP и железу, разбирал игровые пакеты, логировал чат, рассылал global-сообщения с сайта и ловил эксплойт в машине крафта, проверяя запрещённые комбинации рецептов до того, как сервер их сохранит.
Ops вручную — до того, как это назвали DevOps. На каждом серверном процессе стоял watchdog-агент: перезапускал упавшее и принимал команды по TCP; около пятнадцати процессов оркестрировались из конфига на сайте. Лаунчер обновлял клиент пофайлово по MD5, загрузка CPU писалась в базу, а кнопка «выкинуть с сайта» вытаскивала зависшего персонажа.
Бот, проводивший ивенты. Сайт ставил команды в очередь в SQL, watchdog вводил их в настоящий игровой клиент с правами администратора. Стейт-машина объявляла PvP-ивент в global-чате, вела обратный отсчёт, телепортировала зарегистрированных игроков в случайные точки арены и находила победителя по логам убийств.
Чему это научило: если не можешь поменять ядро — построй слой вокруг него: прокси, хуки, очереди, триггеры — и делай продукт там.