CS:GO GSI使ってAIM力管理ツールみたいのを作りたかった

この記事はkstmアドベントカレンダー9日目の記事として書きました.

はじめに

こんばんは.今年もこの季節がやってきました.チキチキアドベントカレンダー用にナンカツクルチャレンジのお時間です.

さて、本題に入ります.普段いろんなFPSをテキトーにゆるーくプレイしてるんですが,対人戦に入る前にAIM練習をするんですよ.で、その時の練習の結果を保存して,前練習した時との差を見たりとか出来たら良いなって思ったわけです.

と、いうことで今回はCS:GOのAIM練習データを保存するような”何か”を作ろうと思います.

CS:GO GSI(Game State Integration)について

起動中のCS:GOのステータスを取得出来るシステムです.公式がこの機能を提供してくれています.

f:id:hoshi_cpp:20171208173950p:plain
おおまかなしくみ

HTTPサーバー建てるとゲームクライアントがそのサーバーにデータを送ってくれるような形になっています. ちなみにどんなデータが送られてくるかというと,

  "weapons": {
"weapon_0": {
"name": "weapon_knife_t",
"paintkit": "default",
"type": "Knife",
"state": "holstered"
},
"weapon_1": {
"name": "weapon_elite",
"paintkit": "default",
"type": "Pistol",
"ammo_clip": 30,
"ammo_clip_max": 30,
"ammo_reserve": 120,
"state": "holstered"
},
"weapon_2": {
"name": "weapon_mac10",
"paintkit": "default",
"type": "Submachine Gun",
"ammo_clip": 30,
"ammo_clip_max": 30,
"ammo_reserve": 100,
"state": "active"
}
},
"match_stats": {
"kills": 0,
"assists": 0,
"deaths": 0,
"mvps": 0,
"score": 0
}

どんな武器持ってるかー とか残弾数いくつとかKDスコアとかも吐いてくれます.
ちなみに,キルした時とかラウンドが変わる時とかのイベントが起きた時のみ送られてきます.それでは実際にコード書いて動かしてみたいと思います.


やること

どんなデータが欲しいか,サーバーのアドレス・ポートなどの設定を書いたコンフィグファイルを設置する
HTTPサーバーの中の処理を書く
 まずはコンフィグファイルから

"AIMrensyu"{   

    "uri" "http://127.0.0.1:3000"   
    "timeout" "5.0"
    "buffer"  "0.1"
    "throttle" "0.5"
    "heartbeat" "60.0"

    "data"    {   "provider"            "1" 
                      "map"                  "1"
                      "round"               "1"    
                      "player_id"           "1"     
                      "player_state"        "1"    
                      "player_weapons"      "1"
                      "player_match_stats"  "1"    
                  }
}

URIとかはお好きにどうぞ.もちろんローカルである必要はないです.これをローカルのcfgフォルダに設置しておきます

次にサーバーの処理書いていきます.残念なことに何発撃ったとかは取得できないようなので(私が確認した限りでは取得できそうにありませんでした)K/Dを表示していく処理を書いていきます.

# -*- coding: utf-8 -*-
from http.server import BaseHTTPRequestHandler, HTTPServer
import time
import json


class GSIServer(HTTPServer):
    def init_state(self):
        self.kill = 0
        self.death = 0
        self.hskill = 0


class GSIRequestHandler(BaseHTTPRequestHandler):
    def do_POST(self):
        length = int(self.headers['Content-Length'])
        body = self.rfile.read(length).decode('utf-8')

        self.display_kd(json.loads(body))

        self.send_header('Content-type', 'text/html')
        self.send_response(200)
        self.end_headers()

    def display_kd(self, payload):
        self.kill, self.death = self.get_player_state(payload)
        print("K:{}".format(self.kill))
        print("D:{}".format(self.death))

    def get_player_state(self, payload):
        if 'player' in payload and 'match_stats' in payload['player']:
            match_stats = payload['player']['match_stats']
            return match_stats['kills'], match_stats['deaths']



server = GSIServer(('localhost', 3000), GSIRequestHandler)

server.init_state()


try:
    server.serve_forever()
except (KeyboardInterrupt, SystemExit):
    pass

server.server_close()

BaseRequestHandler継承して,GSIのJSONをパースするように書いています.

大変申し訳ないのですが,不慮の事故(HDD整理してたら間違えてCS:GO消してしまった… あともう眠い)により今回はここまでです.
これを拡張していってトレーニングに役立つツール作っていきたいですね.

余談

ゲーム映像のキャプチャで人気ツールのPlaysTVなんかは試合中のK/Dイベントを映像と一緒に保存してくれるような機能があるんですが,PlaysTVもGSIを使ってイベントを取得しています.
こういうゲーム内のイベントが簡単に取れると色々便利なツール作れそうですよね.

あと,今回大してGSIの仕様を確認せずに作り始めたんですが,どうにもGSIじゃ正確に命中率とか計るのは厳しそうです.
パケットみて射撃だったり命中のイベントを抽出したりってことを考えたほうが良いかもしれません.出来るかどうかわからんけど