ReplayDojo
Dota 2
Разработчикам

Что находится внутри файла реплея Dota 2

Формат .dem Dota 2 для разработчиков: загрузка и сжатие реплеев, данные сущностей и боевого журнала, доступные парсеры и подводные камни обработки.

Обновлено · 8 мин чтения

Карта, распадающаяся на сетку точек выборки с одной жёлтой траекторией

Открыв .dem, вы не найдёте видеокадров. В файле находятся сетевые сообщения, которые игровой сервер отправлял во время матча. Чтобы прочитать реплей, нужно воспроизвести этот поток в модели игровых сущностей. Именно это делает клиент при просмотре и парсер, когда вам нужны данные. Здесь собран наш опыт создания обработки ReplayDojo, которая превращает ID матча в 3D-реплей в браузере.

Как получить файл

Valve раздаёт реплеи со своих кластеров по URL, который составляется из трёх значений:

ID матча общедоступен. Кластер и соль нигде в пользовательском интерфейсе не показываются. Обычно их получают через эндпоинт матча OpenDota, который возвращает готовый replay_url для известных ему матчей. Если OpenDota недоступна, полный URL Valve уже содержит всё необходимое, поэтому наш импортёр принимает такие ссылки напрямую как запасной вариант. Ссылка перестаёт работать, когда Valve удаляет реплей — обычно через неделю-две после матча.

http://replay<cluster>.valve.net/570/<match_id>_<replay_salt>.dem.bz2

Что содержит .dem

Файл представляет собой последовательность сообщений, перед каждым из которых указана его длина. Большинство сообщений — Protocol Buffers. Почти все полезные данные приходятся на два вида.

Packet entities — дельта-обновления всех сетевых сущностей: героев, крипов, строений, вардов, предметов, а также ресурсов игроков и команд, где хранятся золото, общая ценность, добивания и подобные показатели. Схемы, или send tables, встроены в начало файла. Поэтому парсер, созданный позже, может декодировать реплей старого патча.

Боевой журнал (combat log) — отдельная запись для каждого случая урона, лечения, использования способности или предмета, модификатора, смерти, изменения золота или опыта. В записи указаны атакующий, цель и источник воздействия (inflictor). Отсюда получают сведения об убийствах, помощи и о том, кто забрал Рошана.

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

Парсеры

Скорее всего, писать декодер сущностей самостоятельно вам не понадобится. Из открытых решений мы хорошо знакомы со следующими.

manta (Go), поддерживается Dotabuff. Быстрый низкоуровневый парсер: вы регистрируете обработчики сообщений и изменений сущностей. Мы используем его для координат, состояния и данных героев в каждом срезе.

clarity (Java) — зрелый парсер с хорошей поддержкой боевого журнала. Для реплеев патча 7.40 и новее нужна clarity 4.0.1 или более новая версия.

Есть и парсеры на Rust и Python. Прежде чем брать один за основу, проверьте дату последнего обновления: каждый крупный патч может менять схемы сущностей или типы сообщений.

От сущностей к координатам

Позиция героя разделена на индекс ячейки и смещение внутри неё, поэтому мировые координаты восстанавливаются из обеих частей. Обновления сущностей приходят неравномерно: стоящий на месте герой ничего не отправляет, а герой в драке обновляется каждый тик. Для воспроизведения мы приводим данные каждого юнита к фиксированной частоте 15 отсчётов в секунду. Позиции, направление взгляда и состояние анимации сохраняются ключевыми кадрами в компактный бинарный файл, а медленнее меняющиеся показатели — золото, предметы, способности, перезарядки — записываются в JSON с шагом две секунды. Для 45-минутного матча получается несколько мегабайт, которые браузер загружает за секунду-две.

Затем убийства, башни, Рошан и драки один раз сводятся в единый индекс событий. Из него читают лента убийств, шкала времени, таблица счёта и камера, поэтому везде отображаются одинаковые числа.

С какими проблемами мы столкнулись

Игровое время не совпадает со временем реплея. Файл начинается в лобби, задолго до стартового сигнала, а во время пауз тики продолжают идти. Отсчитывайте время от тика начала игры и вычитайте паузы, иначе все часы будут ошибаться на минуты.

Не каждая смерть — убийство. После смерти с Aegis или Reincarnation герой через несколько секунд возрождается на том же месте. Денай героя — смерть от союзника. Если считать такие случаи обычными убийствами, счёт не сойдётся с таблицей.

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

Внутренние имена: сущности используют имена движка, оставшиеся с тех времён, когда герои назывались иначе. npc_dota_hero_furion — это Nature’s Prophet, windrunner — Windranger, а имена классов предметов не всегда совпадают с их ключами. Поддерживайте таблицу соответствий.

Вставьте ID матча Dota 2 и смотрите реплей в 3D — бесплатно, прямо в браузере.

Открыть матч

Другие руководства