雪降って地固まる

Dota 2に関する内容を中心に扱います

Dota 2 Game State Integrationで遊んでみよう #3 実際に製作する

何を作るかに悩んだ末、観戦を助けるツールを作ってみることにしました。
実際に動いている様子:

映像は映像はBorderless WindowにしてあるDotaクライアントをSkyWay ScreenShareでキャプチャーしたもの、音声はPlay sound in DesktopでDotaから出力されたものをそのまま聞く形で利用しています。

便利な点

  • ブラウザのウィンドウで観戦ができる(リサイズなどが便利)
  • プレイヤーのDotabuff/Opendotaページをすぐに開ける
  • 全員のアイテムやBuyback statusを同時に表示できる

観戦時のGSIデータについて

  • 観戦・リプレイ・Broadcastで同じデータ構造のデータが送られてくる
  • 建造物、ヒーローの座標、Roshanのリスポーン時間などのデータは取得できない
    • roshan_stateはalive, respawn_base, respawn_variableの3種類なのでrespawn_baseの段階ではリスポーンまでの残り時間を計算することができない
    • これらのデータは大会の試合であればWeb APIGetLiveLeagueGamesを使用して取得できる。更新頻度は20秒に1度

データ形式

生データ

{
    "provider": {
        "name": "Dota 2",
        "appid": 570,
        "version": 44,
        "timestamp": 1479620832
    },
    "map": {
        "name": "dota",
        "matchid": 2790650572,
        "game_time": 2177,
        "clock_time": 1450,
        "daytime": true,
        "nightstalker_night": false,
        "game_state": "DOTA_GAMERULES_STATE_GAME_IN_PROGRESS",
        "win_team": "none",
        "customgamename": "",
        "radiant_ward_purchase_cooldown": 0,
        "dire_ward_purchase_cooldown": 0,
        "roshan_state": "respawn_base",
        "roshan_state_end_seconds": 88
    },
    "player": {
        "team2": {
            "player0": {
                "steamid": "76561198091503033",
                "name": "!",
                "activity": "playing",
                "kills": 0,
                "deaths": 3,
                "assists": 2,
                "last_hits": 55,
                "denies": 5,
                "kill_streak": 0,
                "team_name": "radiant",
                "gold": 125,
                "gold_reliable": 35,
                "gold_unreliable": 90,
                "gpm": 242,
                "xpm": 255,
                "net_worth": 3760,
                "hero_damage": 2898,
                "support_gold_spent": 1240,
                "wards_purchased": 14,
                "wards_placed": 4,
                "wards_destroyed": 2,
                "runes_activated": 1,
                "camps_stacked": 0
            }, ...
        },
        "team3": { ... }
    },
    "hero": {
        "team2": {
            "player0": {
                "id": 64,
                "name": "npc_dota_hero_jakiro",
                "level": 11,
                "alive": true,
                "respawn_seconds": 0,
                "buyback_cost": 643,
                "buyback_cooldown": 0,
                "health": 1160,
                "max_health": 1160,
                "health_percent": 100,
                "mana": 972,
                "max_mana": 972,
                "mana_percent": 100,
                "silenced": false,
                "stunned": false,
                "disarmed": false,
                "magicimmune": false,
                "hexed": false,
                "muted": false,
                "break": false,
                "has_debuff": false,
                "selected_unit": false
            },
        },
        "team3": { ... }
    },
    "abilities": {
        "team2": {
            "player0": {
                "ability0": {
                    "name": "jakiro_dual_breath",
                    "level": 2,
                    "can_cast": true,
                    "passive": false,
                    "ability_active": true,
                    "cooldown": 0,
                    "ultimate": false
                },
                ...,
                "attributes": {
                    "level": 0
                }
            },
            "player1": {
                "ability0": {
                    "name": "ember_spirit_searing_chains",
                    "level": 4,
                    "can_cast": true,
                    "passive": false,
                    "ability_active": true,
                    "cooldown": 0,
                    "ultimate": false
                }, ...
            }, ...

        },
        "team3": { ... }
    },
    "items": {
        "team2": {
            "player0": {
                "slot0": {
                    "name": "item_arcane_boots",
                    "can_cast": false,
                    "cooldown": 37,
                    "passive": false
                },
                ...,
                "stash0": {
                    "name": "empty"
                },
                ...
            }, ...
        },
        "team3": { ... }
    }
}

ソースコード

https://github.com/yukidaruma/dota2-spectating-helper

インストールはreadmeを参照してください。問題を発見された場合、コメントまたはIssuesでお知らせください。