WoT の戦績データ Dossier ファイルに関するメモです。

ファイルの場所

%AppData%\Wargaming.net\WorldOfTanks\dossier_cache に作成されます。

ファイル名

ファイル名は以下のように、英数字列に “=” を付加したものに拡張子 “.dat” が付いた形式となっています。

O5XXIYLTNFQTCLJSFZWG6Z3JNYXHOYLSM5QW22LOM4XG4ZLUHIZDAMBRGY5UG2DJOJUW2ZLOHNIGYYLZMVZECY3DN52W45A=.dat

拡張子を除いた部分は、Base32 でエンコードした文字列で、 上記の例をデコードすると下記のようになります。

wotasia1-2.login.wargaming.net:20016;Chirimen;PlayerAccount

ファイル名は scripts/client/account_helpers/DossierCache.py で作成されています。 ログインサーバ、アカウント名、アカウントクラスを ‘;’ (セミコロン) で連結したものになっています。

class DossierCache(object):

    def __init__(self, accountName, accountClassName):
        self.__account = None
        self.__syncController = None
        p = os.path
        prefsFilePath = unicode(BigWorld.wg_getPreferencesFilePath(), 'utf-8', errors='ignore')
        self.__cacheDir = p.join(p.dirname(prefsFilePath), 'dossier_cache')
        self.__cacheFileName = p.join(self.__cacheDir, '%s.dat' % base64.b32encode('%s;%s;%s' % (str(BigWorld.server()), accountName, accountClassName)))

データ

Dossier ファイル内のデータは Python のオブジェクトを cPickle でシリアライズしたものです。 ファイルの入出力やシリアライズ・復元は scripts/client/account_helpers/DossierCache.py で行っています。

cPickle でシリアライズされたオブジェクトを復元できます (pickle でも可)

import os
import cPickle
from pprint import pprint

dir = '(AppDataの場所)/Wargaming.net/WorldOfTanks/dossier_cache'
file = '(Dossierファイル).dat'

with open(os.path.join(dir, file), 'r') as f:
    data = cPickle.load(f)
    pprint(data)

cPickle で復元されたオブジェクトは、 バージョンと中身で構成されていて、 さらに中身は Dossier データの辞書のリストになっています。 Dossier データの辞書は、 キーが dpssierType の種別と ownerID のタプル、 値が changeTime と dossierCompDescr のタプルになっています。

{
    version,
    [
        { ( dossierType, ownerID ): ( changeTime, dossierCompDescr ) },
        ...
    ]
}

dossierType

dossier の種別を表します。 scripts/common/constants.py で定義されている クラス DOSSIER_TYPE の属性のいずれかの値をとります。 車輌戦績であれば DOSSIER_TYPE.VEHICLE (=2) です。

ownerID

全アイテム間で固有の値となるように決められたIDです。 アイテム種別 (itemTypeID) と国 (nationID)、アイテム識別番号 (itemID) をエンコードしたものです。 itemTypeID や nationID が異なる場合には itemID は重複する場合があります。

ownerID は compactDescr として scripts/common/items/__init__.py の makeIntCompactDescrByID によってエンコード、 parseIntCompactDescr によってデコードされます。

def makeIntCompactDescrByID(itemTypeName, nationID, itemID):
    itemTypeID = ITEM_TYPES[itemTypeName]
    if itemTypeID <= 15:
        header = itemTypeID + (nationID << 4)
        return (itemID << 8) + header
    if itemTypeID <= 255:
        header = 0 + (nationID << 4)
        return (itemTypeID << 24) + (itemID << 8) + header
def parseIntCompactDescr(compactDescr):
    itemTypeID = compactDescr & 15
    if itemTypeID == 0:
        itemTypeID = compactDescr >> 24 & 255
    return (itemTypeID, compactDescr >> 4 & 15, compactDescr >> 8 & 65535)

ownerID は32bit長の整数で、itemTypeID の大きさに応じて以下のように2種類のフォーマットになっています。

itemTypeID が 15 以下の場合:

 0           4           8           12          16          20          24          28       31
|--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
|itemTypeID | nationID  |                  itemID(16)                   |           0           |

itemTypeID が 16 以上の場合:

 0           4           8           12          16          20          24          28       31
|--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
|     0     | nationID  |                  itemID(16)                   |      itemTypeID       |

itemTypeID

  • 値域 [1, 15] (4bit長) または [16, 255] (8bit長)
  • 15 以下と 16以上で ownerID のフォーマットが異なる
  • 名称との対応表は scripts/common/items/__init__.py の ITEM_TYPE_NAMES から生成される
  • ‘vehicle’ の場合は 1

nationID

  • 値域 [0, 15] (4bit長)
  • 名称との対応表は scripts/common/nations.py の NAMES から生成される
  • ‘ussr’ は 0, ‘germany’ は 1, ‘italy’ は 10

itemID

  • 値域 [0, 65535] (16bit長)
  • itemTypeID と nationID の組み合わせに対して固有の値となるように ID が定義されている
  • 例えば itemTypeID=1 (vehicle) かつ nationID=0 (ussr) であれば ソ連車輌の ID と解釈される
  • ソ連車輌の ID は scripts/item_defs/vehicles/ussr/list.xml で定義される

itemTypeID + nationID * 16 + itemID * 256 (itemTypsID <= 15 の場合)

itemTypeID * 2^24 + nationID * 16 + itemID * 256 (itemTypsID <= 15 の場合)

changeTime

dossier データの更新時刻です。 POSIX タイムスタンプの形式なので、 Python の datetime.fromtimestamp で datetime オブジェクトに変換できます。

from datetime import datetime
print datetime.fromtimestamp(changeTime)

dossierCompDescr

パックされたバイナリデータです。 リトルエンディアンです。

データ形式のバージョン (2バイト)、ブロックデータ長のリスト (4バイト×ブロック数)、ブロックデータ本体 から構成されています。

データ形式のバージョン VEHICLE_DOSSIER_VERSION は WoT 1.0.1.1 では 101 ですが、 車輌の戦績が更新された時点のデータ形式が残るので、 ファイル中には新旧のデータ形式が混在することになります。 VEHICLE_DOSSIER_VERSION は scripts/common/dossiers2/custom/updaters.py で定義されています。

ブロック数は車輌 dossier のバージョンによって異なります。 各車輌 dossier のバージョンに対するブロックのリストが scripts/common/dossiers2/custom/updaters.py の関数 __updateFromVehicleDossierXX (XX は車輌 dossier のバージョン) 内の変数 blocksLayout で定義されているので、 blocksLayout の長さをカウントすることでブロック数を得ることができます。

手元の dossier ファイルで確認したところ、 バージョン 77 で 19、 バージョン 94 で 34、 バージョン 101 では 42 でした。

ブロックデータには StaticDossierBlockDescr, DictDossierBlockDescr, ListDossierBlockDescr, BinarySetDossierBlockDescr の4種類があります。

StaticDossierBlockDescr

あらかじめ決められた順序で固定長のデータをパックしたブロックです。 格納されるデータはプログラム内で静的に決まっています。 戦闘数や獲得経験値などが格納されます。

固定長のブロックですが、データが存在しない場合のブロック長は 0 になります。

DictDossierBlockDescr

キーと値のセットを格納する可変長のブロックです。

ListDossierBlockDescr

固定長の要素を複数格納可能な可変長のブロックです。

エンブレムや迷彩のデータが格納されます。

BinarySetDossierBlockDescr

ビットデータを格納するブロックです。

一回のみ取得可能な実績のリストが格納されます。