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じゃ正確に命中率とか計るのは厳しそうです.
パケットみて射撃だったり命中のイベントを抽出したりってことを考えたほうが良いかもしれません.出来るかどうかわからんけど

Riot Games API Match-V3のマッチリスト取得でちょっと詰まった

そこまで詰まったわけではないけど,一応備忘録としてメモ

Match-V3のマッチリスト取得APIを試しに叩いてみた.
こいつはQueueタイプ(試合の種類, ランクとかノーマルとか)や, シーズンとかでフィルタリングすることが出来る.

Riot Developer Portal

を参考に,試しにシーズン7のランクの戦績を引っ張ろうとして queue=4 season=9と指定してAPIを叩いてみても404を返され上手く行かない.

はて?と思って今度はフィルタリング無しでAPI叩いてみると, 普通に取得できる. ここで,queueが4ではなく420となっていることに気づいた.
Game Constantsのページを下の方までスクロールしてみると,TEAM_BUILDER_RANKED_SOLO
っていう項目があって, これが420という値になっているではないか.
なるほど, 新しいランクのシステムはチームビルダーのシステム使ってるからこうなるのね…。

単純にソロランクって指定してもエラー吐くから, まあ色々面倒くさいっていう話でした.

Riot Games API AccountIDについて

コード書いてて気になって調べたので自分用を兼ねてメモを・・・

以前Riot Games APIを叩いた時は,サモナー固有の情報を引っ張ってくるにはSummonerIDがあれば良かった(と思う).こいつは,サモナー特有に割り当てられているIDのようなもので,サモナー名を変えても一貫してそのサモナーのデータにアクセスすることが出来るというもの.
しかし最近になって見てみると,Match-V3のマッチリスト取得API叩こうとしたらAccountIDというものが必要であることに気づいた.
なんじゃこりゃ~ってなったので,調べたものをここに載せておく(間違ってたらごめんね

過去に我々(Riot Games)は混乱を防ぐのと,データに一貫性を持たせるために,summonerIDを通してデータにアクセス出来るようにした.

しかしながら,将来的にAPIを更に柔軟に,他のゲーム(LOL以外のゲーム)にも対応できるようにする必要が出てきた.
つまり,APIが複数のゲームをサポートするような将来では,サモナーという概念は他のゲームには無いかもしれない.複数ゲームに渡って一貫性のあるものである必要があり,将来的に複数ゲームのサポートを準備する必要があるので,この機会(恐らくRiot Games APIのアップデートのこと)アカウントIDを公にすることを決めた.従って,V3のAPIでは可能な限りAccountIDを使う.


パッと訳したところこんな感じ.
要は将来的にRiotがLoL以外の他ゲームをリリースしても大丈夫なようにAccountIDというものを公開したっていうことみたい. CHAMPION-MASTERY-V3とかAccountIDじゃなくてSummonerIDが求められるので,両方必要っぽいですね.
Riotが別ゲーを用意しているってのは聞いたことがありましたが,どうやら準備しているようだね.ちょっと驚き.

話が逸れましたが,色々V3アップデートによって一新されてて分からないこともあるので,これから調べていきたい.

参考

Riot Games API V3 - Riot Developer Community

 

OpenCV2.4.8 でヒストグラム平坦化(C++)

正しく動いてるかわからないけどそれっぽい結果は出た。
結果画像とかはその内貼っつける(試した画像が他人の顔写真の為)
以下ソースコード
変数名とか色々ガバガバ/適当だけど気にしないで

#include <iostream>
#include "opencv2/opencv.hpp"
 
using namespace cv;
using namespace std;
 
int main(){
 
    Mat input_image = imread("input.jpg", 1);
    Mat output_image;
    vector<Mat> planes(3);
    vector<Mat> output_planes(3);
    vector<Mat> rgb;
 
    if(!input_image.data){
        cout << "input is empty!" << endl;
        return -1;

    }
 
    /*RGBの分割 デフォルトでBGRの順番*/
    split(input_image, planes);
     
    equalizeHist(planes[0], output_planes[0]);
    equalizeHist(planes[1], output_planes[1]);
    equalizeHist(planes[2], output_planes[2]);
     
    rgb.push_back( output_planes[0] );
    rgb.push_back( output_planes[1] );
    rgb.push_back( output_planes[2] );
 
    merge(rgb, output_image);   
 
    imshow("Input", input_image);
    imshow("Output", output_image);
    waitKey(0);
     
    return 0;
 
 
}

Ubuntuでディスプレイのバックライトの明るさが暗すぎる時の対処法メモ(レッツノート CF-SX3)

画面が暗いっていうか黒かった。

1,rootに化ける

2, /sys/class/backlight/intel_backlight/max_brightnessの値を見てみる。

 cat /sys/class/backlight/intel_backlight/max_brightness

3, /sys/class/backlight/intel_backlight/brightness にmaxより少し小さいぐらいの値を入れる
    大体900ぐらいを入れた。

    echo 900 > /sys/class/backlight/intel_backlight/brightness

 

なぜかsudoではできなった。なんでだろう?