Запускаю цикл заметок о работе с частью Steam API используя dota2-api. Это не будет документацией в чистом виде, это будет своего рода сборник рецептов. Писать буду на русском и английском языках. В вики на гитхабе будут просто ссылки на эти записи.
Как и любой разработчик, я считаю свой код простым, понятным и «быстро усваиваемым» для других. Эти самые «другие» зачастую считают ровно наоборот. На основе таких противоречий и возникают разного рода «гайды», «мануалы» и «рецепты».
Я не буду расписывать процесс установки dota2-api. Он один и тот же для любого пакета, который ставится через composer. Про то, как получить ключ к API, написано по ссылке — #. Единственным важным моментом является то, что если вы планируете хранить обычные игры (а не турнирные), то надо в БД убрать внешний ключ между таблицами leagues
и matches
(поле leagueid
). Иначе матчи просто не сохранятся. Если же вы сохраняете какие-то турнирные матчи, то вначале должны сохранить список турниров в таблицу leagues
.
Начнем с простого — загрузка данных о прошедшем матче. Тут нужен только match_id
. Узнать его можно в клиенте игры. Возьмем какой-то случайный матч из «паблика» — 2472644644.
require_once 'vendor/autoload.php'; use Dota2Api\Api; Api::init('YOUR_API_KEY', array('localhost', 'root', 'password', 'db_name', '')); $mapper = new Dota2Api\Mappers\MatchMapperWeb(2472644644); /* @var Dota2Api\Models\Match */ $match = $mapper->load(); |
Вроде бы все просто. Но, нет. API не всегда возвращает данные про игру. Может вернуть и пустой результат. В таком случае, надо попробовать загрузить еще раз или даже сделать несколько попыток:
Тут и далее фрагменты кода являются продолжением уже написанных фрагментов (то есть,
$match
уже определен ранее).
$retries = 3; if (is_null($match) && $retries !== 0) { $match = $mapper->load(); $retries--; } if (is_null($match)) { echo 'API is truly down'. exit 1; } |
В таком варианте, будет 3 попытки загрузить данные про игру. Если после них $match
по-прежнему будет пустым, то, видимо, API упал всерьез и надолго. Посмотрим, как вывести информацию по игре, когда она уже доступна в $match
(объект класса Dota2Api\Models\Match
). Во всех моделях есть метод get
для получения значений полей.
$durationInSeconds = $match->get('duration'); echo gmdate('H:i:s', $durationInSeconds); // '00:50:10' echo $match->get('start_time'); // '2016-06-30 19:46:07' echo $match->get('radiant_score').' - '.$match->get('dire_score'); // '57 - 47' echo $match->get('game_mode'); // 2 echo $match->get('lobby_type'); // 7 echo $match->get('radiant_win'); // 1 echo $match->get('cluster'); // 181 |
game_mode
, lobby_type
и cluster
выглядят не очень понятно — просто какие-то цифры. Для их «трактовки» есть классы из Dota2Api\Data
:
lobbies = new Dota2Api\Data\Lobbies(); $lobbies->parse(); $matchLobbyType = $match->get('lobby_type'); echo $lobbies->getFieldById($matchLobbyType, 'name'); // 'Ranked' $mods = new Dota2Api\Data\Mods(); $mods->parse(); $matchGameMode = $match->get('game_mode'); echo $mods->getFieldById($matchGameMode, 'name'); // 'Captain Mode' $regions= new Dota2Api\Data\Regions(); $regions->parse(); $matchRegion = $match->get('cluster'); echo $regions->getFieldById($matchRegion, 'name'); // 'Russia' |
Таким относительно не хитрым образом мы получили время начала матча, его продолжительность, счет, тип, ранг и регион, где он был проведен. Но, матч — это в первую очередь игроки. О них и поговорим. Как известно, на «классической» карте в одной игре 10 игроков (1х1 solomid — исключение, которое не рассматриваем):
/* @var Dota2Api\Models\Slot[] */ $slots = $match->getAllSlots(); foreach($slots as $player_slot => $slot) { // some code for $slot processing } print_r(array_keys($slots)); // [0, 1, 2, 3, 4, 128, 129, 130, 131, 132] $firstSlot = $slots[0]; echo 'KDA: ' . $firstSlot->get('kills') . '/' . $firstSlot->get('deaths') . '/' . $firstSlot->get('assists') . "\n"; // 'KDA: 16/6/8' echo $firstSlot->get('level'); // 25 echo $firstSlot->get('last_hits'); // 432 echo $firstSlot->get('denies'); // 14 echo $firstSlot->get('gold_per_min'); // 692 echo $firstSlot->get('xp_per_min'); // 646 echo $firstSlot->get('hero_id'); // 1 |
Тут стоит обратить внимание на индексы массива слотов — они идут не подряд. То есть, обходить этот массив имеет смысл только циклом foreach
. В объектах класса Dota2Api\Models\Slot
почти все поля с данными самодостаточны. Отличаются только поля hero_id
, account_id
и item_*
. Первое — это идентификатор героя, на котором играл участник матча. Второе — идентификатор игрока. Третья группа (item_0 - item_5
) — это инвентарь. Ниже показано, как получить человекопонятные данные на их основе:
$heroes = new Dota2Api\Data\Heroes(); $heroes->parse(); $heroId = $firstSlot->get('hero_id'); echo $heroes->getFieldById($heroId, 'localized_name'); // 'Anti-Mage' echo $heroes->getImgUrlById($heroId); // 'http://media.steampowered.com/apps/dota2/images/heroes/antimage_eg.png' echo $heroes->getImgUrlById($heroId, false); // 'http://media.steampowered.com/apps/dota2/images/heroes/antimage_lg.png' $items = new Dota2Api\Data\Items(); $items->parse(); $firstItem = $firstSlot->get('item_0'); $items->getFieldById($firstItem, 'name'); // 'bfury' echo $items->getImgUrlById($firstItem); // 'http://media.steampowered.com/apps/dota2/images/items/bfury_eg.png' - small image echo $items->getImgUrlById($firstItem, false); // 'http://media.steampowered.com/apps/dota2/images/items/bfury_lg.png' - big image |
С инвентарем и героем все ясно, а вот как быть с игроком? Увы, данные по игроку (его ник, steamid, profile_url) доступны в другом API. Один важный момент — в настройках профиля игрока можно скрыть свою «историю матчей» от других. API тогда вместо реального account_id
будет возвращать значение 4294967295
. Оно доступно как константа в Dota2Api\Models\Player::ANONYMOUS
:
if ($firstSlot->get('account_id') == Dota2Api\Models\Player::ANONYMOUS) { echo 'Anonymous player'; } |
У всех героев есть набор уникальных способностей. И у каждого игрока своя логика при выборе раскачки героя. Эти данные (на каком уровне какая способность была прокачана) тоже есть в объектах класса Slot
:
$abilities = new Dota2Api\Data\Abilities(); $abilities->parse(); $buildDetails = $firstSlot->getAbilitiesUpgrade(); foreach($buildDetails as $level) { echo $level['level'] . ' ' . $abilities->getFieldById($level['ability'], 'name') . ' ' . $level['time'] . "\n"; } |
С $level['time']
надо быть осторожным. Отсчет ведется от начала матча. То есть, время пиков и банов тоже считалось. Вот и получается, что способность на первом уровне игрок выбрал на 12-й минуте (по версии API).
Рассматриваемый матч игрался в CM-режиме и в нем была фаза пико-банов. Как можно узнать, кого же выбирали игроки и в какой очередности?
$picksBans = $match->getAllPicksBans(); foreach($picksBans as $order) { $team = $order['team'] == 0 ? 'radiant' : 'dire'; $state = $order['is_pick'] == 1 ? 'pick' : 'ban'; echo $team .' '.$state.' '.$heroes->getFieldById($order['hero_id'], 'localized_name')."\n"; } /* Output: dire ban Lifestealer radiant ban Nature's Prophet dire ban Invoker radiant ban Sven dire pick Elder Titan radiant pick Lion radiant pick Axe dire pick Disruptor radiant ban Windranger dire ban Warlock radiant ban Slark dire ban Silencer radiant pick Anti-Mage dire pick Beastmaster radiant pick Death Prophet dire pick Weaver radiant ban Queen of Pain dire ban Zeus dire pick Viper radiant pick Winter Wyvern */ |
Мы разобрали, какие данные про игру можно получить из API и как их вывести пользователю в читаемом виде. Каждый раз обращаться к API за данными слишком долго. Лучше сохранять их в БД и брать уже оттуда:
$dbMapper = new Dota2Api\Mappers\MatchMapperDb(); $dbMapper->save($match); // save to db /* @var Dota2Api\Models\Match */ $matchFromDb = $dbMapper->load($match->get('match_id')); // load from db |
Из $matchFromDb
данные берутся точно так же, как и из матчей, полученных из API.
Формат вывода данных ограничивается только вашей фантазией (в крайнем случае, всегда можно подсмотреть, как сделано у dota2statistic.com или dotabuff.com).
Сборник рецептов по dota2-api
- Работа с dota2-api от версии 2.2.1 и старше
- Загружаем сразу много матчей используя dota2-api
- Работа с командами в dota2-api
- Работа с турнирами в dota2-api
- Работа с игроками в dota2-api
Оставить комментарий