Author SHA1 Message Date
Jylpah 5f84ec4724 Merge branch 'dev-datetime-cats' into merge-master-dev-datetime 2021-05-03 19:08:42 +03:00
Jylpah 36fb53f0e7 convert_tank_names(): Fix tank key sorting 2021-04-29 00:09:40 +03:00
Jylpah b19a2169a7 Update 7.9 2021-04-29 00:09:04 +03:00
Jylpah 67aeaddf36 get_db_player_stats(): Fix aggregation 2021-04-27 10:26:30 +03:00
Jylpah 763f205175 Update 7.9 2021-04-27 10:24:01 +03:00
Jylpah d97c0cabd8 Update analyze_wotb_replays.py 2021-04-17 14:34:05 +03:00
Jylpah e6ff2f438d save_XXX_stats() funcs 2021-04-17 14:33:59 +03:00
Jylpah f4f153a175 stat_worker(): fix bug introduced in earlier commit 2021-04-15 09:15:00 +03:00
Jylpah 829e03f644 get_db_tank_stats(): optimize find() for index 2021-04-14 21:02:43 +03:00
Jylpah 53b2f62817 mk_readerQ_item(): add _id param 2021-04-09 12:08:14 +03:00
Jylpah 804a4a6483 update 7.8 2021-04-05 15:34:34 +03:00
Jylpah 47a1f96c4e Update 7.8 2021-04-05 14:39:38 +03:00
Jylpah 170e6a287d Update analyze_wotb_replays.py 2021-02-22 22:06:52 +02:00
Jylpah 4e9032d7ba Merge pull request #26 from Jylpah/master
Backport extract_tankopedia.py tank strings fix
2021-02-16 12:07:25 +02:00
Jylpah 9c0949748e Update analyze_wotb_replays.py 2021-02-13 17:08:51 +02:00
Jylpah 5b2ef816f5 Update analyze_wotb_replays.py 2021-02-10 23:25:53 +02:00
Jylpah 448b91a866 Update analyze_wotb_replays.py 2021-02-10 21:42:49 +02:00
Jylpah cddc7dd947 --fields, datetime fields/categorizations 2021-02-09 01:02:59 +02:00
6 changed files with 758 additions and 241 deletions

No files matched your search

+529 -202
View File
File diff suppressed because it is too large. Load diff
+55 -17
View File
@@ -22,6 +22,11 @@ _log_level = NORMAL
LOG = False
LOGGER = None
MODE_TANK_STATS = 'tank_stats'
MODE_PLAYER_STATS = 'player_stats'
MODE_PLAYER_ACHIEVEMENTS= 'player_achievements'
MODE_TANKOPEDIA = 'tankopedia'
# Progress display
_progress_N = 100
_progress_i = 0
@@ -418,12 +423,14 @@ def set_progress_bar(heading: str, max_value: int, step: int = None, slow: bool
return
def set_counter(heading: str):
def set_counter(heading: str, step = None):
global _progress_obj, _progress_i
_progress_i = 0
if _progress_obj != None:
finish_progress_bar()
_progress_obj = Counter(heading)
_progress_obj = Counter(heading + ': ')
if step != None:
set_progress_step(step)
return
@@ -649,8 +656,6 @@ class StatsNotFound(Exception):
pass
# -----------------------------------------------------------
# Class WG
# -----------------------------------------------------------
@@ -686,7 +691,7 @@ class WG:
# WHERE account_id = {} AND stat = {}
# AND date >= {} LIMIT 1;"""
# TANK_STATS
SQL_TANK_STATS_TBL = 'tank_stats'
SQL_TANK_STATS_CREATE_TBL = 'CREATE TABLE IF NOT EXISTS ' + SQL_TANK_STATS_TBL + \
@@ -700,6 +705,7 @@ class WG:
SQL_TANK_STATS_UPDATE = 'REPLACE INTO ' + SQL_TANK_STATS_TBL + '(account_id, tank_id, update_time, stats) VALUES(?,?,?,?)'
# PLAYER_STATS
SQL_PLAYER_STATS_TBL = 'player_stats'
SQL_PLAYER_STATS_CREATE_TBL = 'CREATE TABLE IF NOT EXISTS ' + SQL_PLAYER_STATS_TBL + \
@@ -713,6 +719,7 @@ class WG:
SQL_PLAYER_STATS_CACHED = 'SELECT * FROM ' + SQL_PLAYER_STATS_TBL + ' WHERE account_id = ? AND update_time > ?'
# PLAYER_ACHIEVEMENTS
SQL_PLAYER_ACHIEVEMENTS_TBL = 'player_achievements'
SQL_PLAYER_ACHIEVEMENTS_CREATE_TBL = 'CREATE TABLE IF NOT EXISTS ' + SQL_PLAYER_ACHIEVEMENTS_TBL + \
@@ -720,11 +727,12 @@ class WG:
update_time INTEGER NOT NULL,
stats TEXT)"""
SQL_PLAYER_ACHIEVEMENTS_COUNT = 'SELECT COUNT(*) FROM ' + SQL_PLAYER_ACHIEVEMENTS_TBL
SQL_PLAYER_ACHIEVEMENTS_CACHED = 'SELECT * FROM ' + SQL_PLAYER_ACHIEVEMENTS_TBL + ' WHERE account_id = ? AND update_time > ?'
SQL_PLAYER_ACHIEVEMENTS_UPDATE = 'REPLACE INTO ' + SQL_PLAYER_ACHIEVEMENTS_TBL + '(account_id, update_time, stats) VALUES(?,?,?)'
SQL_PLAYER_ACHIEVEMENTS_COUNT = 'SELECT COUNT(*) FROM ' + SQL_PLAYER_ACHIEVEMENTS_TBL
SQL_TABLES = [ SQL_PLAYER_STATS_TBL, SQL_TANK_STATS_TBL, SQL_PLAYER_ACHIEVEMENTS_TBL ]
@@ -1261,7 +1269,7 @@ class WG:
# debug('JSON Response received: ' + str(json_data))
stats = json_data['data'][str(account_id)]
if cache:
await self.put_2_statsQ('tank_stats', [account_id, tank_ids], stats)
await self.save_tank_stats(account_id, tank_ids, stats)
return stats
except Exception as err:
error(exception=err)
@@ -1294,7 +1302,7 @@ class WG:
# debug('JSON Response received: ' + str(json_data))
stats = json_data['data'][str(account_id)]
if cache:
await self.put_2_statsQ('player_stats', [account_id], stats)
await self.save_player_stats(account_id, stats)
return stats
except Exception as err:
error(exception=err)
@@ -1333,7 +1341,7 @@ class WG:
for account_id in json_data['data'].keys():
stats[account_id] = json_data['data'][account_id]
if cache:
await self.put_2_statsQ('player_achievements', [int(account_id)], json_data['data'][account_id])
await self.save_player_achievements(int(account_id), json_data['data'][account_id])
return stats
except Exception as err:
error(exception=err)
@@ -1440,7 +1448,7 @@ class WG:
return None
async def put_2_statsQ(self, statsType: str, key: list, stats: list):
async def save_stats(self, statsType: str, key: list, stats: list):
"""Save stats to a async queue to be saved by the stat_saver -task"""
if self.statsQ == None:
return False
@@ -1449,6 +1457,30 @@ class WG:
return True
async def save_player_stats(self, account_id: int, stats: dict):
try:
await self.save_stats(MODE_PLAYER_STATS, [int(account_id)], stats)
except Exception as err:
error(exception=err)
return None
async def save_player_achievements(self, account_id: int, stats: dict):
try:
await self.save_stats(MODE_PLAYER_ACHIEVEMENTS, [int(account_id)], stats)
except Exception as err:
error(exception=err)
return None
async def save_tank_stats(self, account_id: int, tank_ids: list, stats: dict):
try:
await self.save_stats(MODE_TANK_STATS, [int(account_id), tank_ids], stats)
except Exception as err:
error(exception=err)
return None
async def stat_saver(self):
"""Async task for saving stats into cache in background"""
@@ -1464,8 +1496,13 @@ class WG:
await self.cache.commit()
if is_debug():
async with self.cache.execute(WG.SQL_PLAYER_STATS_COUNT) as cursor:
debug('Cache contains: ' + str((await cursor.fetchone())[0]) + ' player stat records' )
async with self.cache.execute(WG.SQL_PLAYER_ACHIEVEMENTS_COUNT) as cursor:
debug('Cache contains: ' + str((await cursor.fetchone())[0]) + ' player achievement records' )
async with self.cache.execute(WG.SQL_TANK_STATS_COUNT) as cursor:
debug('Cache contains: ' + str((await cursor.fetchone())[0]) + ' cached player tank stat records' )
debug('Cache contains: ' + str((await cursor.fetchone())[0]) + ' player tank stat records' )
except Exception as err:
error(exception=err)
sys.exit(1)
@@ -1474,19 +1511,20 @@ class WG:
try:
stats = await self.statsQ.get()
stats_type = stats[0]
stat_type = stats[0]
key = stats[1]
stats_data = stats[2]
update_time = stats[3]
if stats_type == 'tank_stats':
#debug('stat_type: ' + stat_type + ', key: ' + str(key))
if stat_type == MODE_TANK_STATS:
await self.store_tank_stats(key, stats_data, update_time)
elif stats_type == 'player_stats':
elif stat_type == MODE_PLAYER_STATS:
await self.store_player_stats(key, stats_data, update_time)
elif stats_type == 'player_achievements':
elif stat_type == MODE_PLAYER_ACHIEVEMENTS:
await self.store_player_achievements(key, stats_data, update_time)
else:
error('Function to saves stats type \'' + stats_type + '\' is not implemented yet')
error('Function to saves stats type \'' + stat_type + '\' is not implemented yet')
except asyncio.CancelledError:
# this is an eternal loop that will wait until cancelled
@@ -1521,7 +1559,7 @@ class WG:
for stat in stats_data:
tank_id = stat['tank_id']
await self.cache.execute(WG.SQL_TANK_STATS_UPDATE, (account_id, tank_id, update_time, json.dumps(stat)))
tank_ids.remove(tank_id)
tank_ids.discard(tank_id)
# no stats found => Add None to mark that
for tank_id in tank_ids:
await self.cache.execute(WG.SQL_TANK_STATS_UPDATE, (account_id, tank_id, update_time, None))
+8 -6
View File
@@ -115,13 +115,12 @@ async def extract_tanks(blitz_app_base : str, nation: str):
for data in tankList['root'].keys():
tank_xml = tankList['root'][data]
tank = dict()
tank['tank_id'] = await get_tank_id(nation, int(tank_xml['id']))
tank['userStr'] = tank_xml['userString']
tank['nation'] = nation
tank['tier'] = int(tank_xml['level'])
#debug(tank_xml['price'])
tank['is_premium'] = issubclass(type(tank_xml['price']), dict)
tank['nation'] = nation
tank['tank_id'] = await get_tank_id(nation, int(tank_xml['id']))
tank['tier'] = int(tank_xml['level'])
tank['type'] = await get_tank_type(tank_xml['tags'])
tank['userStr'] = tank_xml['userString']
#bu.debug('Reading tank string: ' + tank['userStr'], force=True)
tanks.append(tank)
except Exception as err:
@@ -165,7 +164,10 @@ async def convert_tank_names(tanklist : list, tank_strs: dict) -> dict:
tank['name'] = tank_strs[tank['userStr']]
#userStrs[tank['userStr'].split(':')[1]] = tank['name']
tank.pop('userStr', None)
tankopedia[str(tank['tank_id'])] = tank
tank_tmp = collections.OrderedDict()
for key in sorted(tank.keys()):
tank_tmp[key] = tank[key]
tankopedia[str(tank['tank_id'])] = tank_tmp
for tank_str in tank_strs:
skip = False
+3
View File
@@ -48,6 +48,9 @@
"rift": "Hellas",
"rock": "Mayan Ruins",
"rudniki": "Mines",
"rudniki_01": "Mines - Hill",
"rudniki_02": "Mines - Village",
"rudniki_03": "Mines - Center",
"savanna": "Oasis Palms",
"skit": "Naval Frontier",
"test": "World of Ducks",
+2
View File
@@ -2,6 +2,8 @@
| Release | Date | Notes | Inaccurate? |
|:-------:|:--------:|-------------|-----|
| 7.9 | 2021-04-27 | Mines rework, new tutorial, colorblind mode, JgPz E100 legendary camo | |
| 7.8 | 2021-03-24 | Mid-tier balance changes, Grille line new consumables | |
| 7.7 | 2021-02-24 | Czechoslovakian medium tanks | |
| 7.6 | 2021-01-27 | AMC 13 90, TOG II buffs, free replay camera | |
| 7.5 | 2020-12-09 | ATGM removal, Batchat, Kpz70, T-2020 buff | |
+161 -16
View File
@@ -1,7 +1,7 @@
{
"status": "ok",
"meta": {
"count": 476
"count": 489
},
"data": {
"1": {
@@ -414,7 +414,7 @@
},
"1649": {
"is_premium": true,
"name": "Helsing H0",
"name": "Helsing",
"nation": "other",
"tank_id": 1649,
"tier": 7,
@@ -894,7 +894,7 @@
},
"3937": {
"is_premium": false,
"name": "Ho-Ri Type 3",
"name": "Ho-Ri Type III",
"nation": "japan",
"tank_id": 3937,
"tier": 10,
@@ -2262,7 +2262,7 @@
},
"12321": {
"is_premium": true,
"name": "T6E1",
"name": "T6E1 Grizzly",
"nation": "usa",
"tank_id": 12321,
"tier": 4,
@@ -2614,7 +2614,7 @@
},
"17473": {
"is_premium": true,
"name": "AMX 13 90 Defender",
"name": "AMX Defender",
"nation": "france",
"tank_id": 17473,
"tier": 8,
@@ -2628,6 +2628,14 @@
"tier": 8,
"type": "AT-SPG"
},
"17729": {
"is_premium": true,
"name": "Somua SM",
"nation": "france",
"tank_id": 17729,
"tier": 8,
"type": "heavyTank"
},
"17745": {
"is_premium": true,
"name": "FV217 Badger",
@@ -2972,6 +2980,14 @@
"tier": 8,
"type": "mediumTank"
},
"20817": {
"is_premium": true,
"name": "Explorer",
"nation": "uk",
"tank_id": 20817,
"tier": 6,
"type": "mediumTank"
},
"20993": {
"is_premium": true,
"name": "T-2020",
@@ -3084,6 +3100,14 @@
"tier": 10,
"type": "heavyTank"
},
"22305": {
"is_premium": true,
"name": "AE Phase I",
"nation": "usa",
"tank_id": 22305,
"tier": 9,
"type": "heavyTank"
},
"22529": {
"is_premium": true,
"name": "LT-432",
@@ -3108,6 +3132,22 @@
"tier": 6,
"type": "heavyTank"
},
"22817": {
"is_premium": true,
"name": "M-VI-Yoh",
"nation": "usa",
"tank_id": 22817,
"tier": 10,
"type": "heavyTank"
},
"23057": {
"is_premium": true,
"name": "Kunze Panzer",
"nation": "germany",
"tank_id": 23057,
"tier": 7,
"type": "lightTank"
},
"51201": {
"is_premium": true,
"name": "KV-220 Beta-Test",
@@ -3598,7 +3638,7 @@
},
"63585": {
"is_premium": true,
"name": "Kuro Mori Mine",
"name": "Tiger Kuromorimine SP",
"nation": "japan",
"tank_id": 63585,
"tier": 6,
@@ -3606,7 +3646,7 @@
},
"63601": {
"is_premium": true,
"name": "T6 Dracula",
"name": "Dracula",
"nation": "other",
"tank_id": 63601,
"tier": 7,
@@ -3614,7 +3654,7 @@
},
"63841": {
"is_premium": true,
"name": "Panzer IV Anko Special",
"name": "Panzer IV Ankou Special",
"nation": "japan",
"tank_id": 63841,
"tier": 5,
@@ -3713,7 +3753,7 @@
"name": "Pz.Kpfw. II",
"nation": "germany",
"tank_id": 64785,
"tier": 2,
"tier": 1,
"type": "lightTank"
},
"64801": {
@@ -3811,6 +3851,70 @@
"tank_id": 65377,
"tier": 5,
"type": "mediumTank"
},
"7041": {
"is_premium": true,
"name": "Turbo",
"nation": "european",
"tank_id": 7041,
"tier": 6,
"type": "mediumTank"
},
"17985": {
"is_premium": true,
"name": "Bretagne Panther",
"nation": "france",
"tank_id": 17985,
"tier": 6,
"type": "mediumTank"
},
"21537": {
"is_premium": true,
"name": "Sherman Easy 8",
"nation": "usa",
"tank_id": 21537,
"tier": 6,
"type": "mediumTank"
},
"22017": {
"is_premium": true,
"name": "T-34-85",
"nation": "ussr",
"tank_id": 22017,
"tier": 6,
"type": "mediumTank"
},
"22289": {
"is_premium": true,
"name": "Tiger I",
"nation": "germany",
"tank_id": 22289,
"tier": 6,
"type": "heavyTank"
},
"22785": {
"is_premium": true,
"name": "Triumphant",
"nation": "ussr",
"tank_id": 22785,
"tier": 6,
"type": "mediumTank"
},
"23313": {
"is_premium": true,
"name": "Kampfpanzer 50 t",
"nation": "germany",
"tank_id": 23313,
"tier": 10,
"type": "mediumTank"
},
"23841": {
"is_premium": true,
"name": "Super Hellcat",
"nation": "usa",
"tank_id": 23841,
"tier": 7,
"type": "AT-SPG"
}
},
"userStr": {
@@ -3858,10 +3962,12 @@
"A124_T54E2_Custom": "T54E2 Shark",
"A124_T54E2_Custom_short": "T54E2 Shark",
"A124_T54E2_short": "T54E2",
"A125_AEP_1": "AE Phase I",
"A125_AEP_1_short": "AE Phase I",
"A68_T28D": "T28 Defender",
"A68_T28D_short": "T28 Defender",
"A77_T6M": "T6E1",
"A77_T6M_short": "T6E1",
"A77_T6M": "T6E1 Grizzly",
"A77_T6M_short": "T6E1 Grizzly",
"A94_T37": "T37",
"A95_T95E6": "T95E6",
"A95_T95E6_short": "T95E6",
@@ -3911,6 +4017,7 @@
"AMX_dracula_Custom_short": "Dracula Two-faced",
"AMX_dracula_short": "Dracula",
"AOI-1490": "Continental AOI-1490",
"AOSI_1490-1": "Continental AOSI-1490-1",
"AOS_895": "AOS-895",
"APCNR": "Pzgr. 41 HK",
"APCNR.erz": "Pzgr. 41 StK",
@@ -4098,6 +4205,7 @@
"Continental_AOS-895-1_short": "Continental\\nAOS-895-1",
"Continental_AOS-895-3": "AN/GRC-8",
"Continental_AOS-895-3_short": "AN/GRC-8",
"Continental_AOSI-1195-5": "Continental AOSI-1195-5",
"Continental_AOSI-895-5": "Continental AOSI-895-5",
"Continental_AOSI-895-5_short": "Continental\\nAOSI-895-5",
"Continental_AOSI_895_5_Prem": "Continental AOSI-895-5",
@@ -4236,6 +4344,10 @@
"F82_AMX_M4_Mle1949_Ter_Custom": "AMX M4 54 Firebird",
"F82_AMX_M4_Mle1949_Ter_Custom_short": "AMX M4 54 Firebird",
"F82_AMX_M4_Mle1949_Ter_short": "AMX M4 mle. 54",
"F84_Somua_SM": "Somua SM",
"F84_Somua_SM_Custom": "Somua Grenadier",
"F84_Somua_SM_Custom_short": "Somua Grenadier",
"F84_Somua_SM_short": "Somua SM",
"FCM50t_fwhite": "FCM 50 t Titi",
"FCM50t_fwhite_short": "FCM 50 t Titi",
"FCM50t_liliam": "FCM 50 t Zizou",
@@ -4309,6 +4421,8 @@
"G136_Tiger_131_short": "Tiger 131",
"G138_VK16801P": "VK 168.01 (P)",
"G138_VK16801P_short": "VK 168.01 (P)",
"G147_mPanzer_64": "Kunze Panzer",
"G147_mPanzer_64_short": "Kunze Panzer",
"G20_Marder_II": "Marder II",
"G20_Marder_II_short": "Marder II",
"GAZ-11": "GAZ-11",
@@ -4351,6 +4465,8 @@
"GB19_Sherman_Firefly_short": "Sherman Firefly",
"GB20_Crusader": "Crusader",
"GB20_Crusader_short": "Crusader",
"GB21_A27BP": "Explorer",
"GB21_A27BP_short": "Explorer",
"GB21_Cromwell": "Cromwell",
"GB21_Cromwell_short": "Cromwell",
"GB22_Comet": "Comet",
@@ -4701,6 +4817,8 @@
"M-5-400F_Bis": "M-5-400F Bis",
"M-50T": "M-50T",
"M-50TD": "M-50TD",
"M-6-Y": "M-VI-Yoh",
"M-6-Y_short": "M-VI-Yoh",
"M-80": "M-80",
"M103": "M103",
"M10_Wolverine": "M10 Wolverine",
@@ -4746,8 +4864,8 @@
"M48A1_short": "M48 Patton",
"M4A2E4": "M4A2E4 Sherman",
"M4A2E4_short": "M4A2E4",
"M4A3E8TU": "M4A3E8 Sherman",
"M4A3E8TU_short": "M4A3E8",
"M4A3E8TU": "Sherman Easy 8",
"M4A3E8TU_short": "Sherman Easy 8",
"M4A3E8_BP": "Rudolph",
"M4A3E8_BP_short": "Rudolph",
"M4A3E8_Sherman": "M4A3E8 Sherman",
@@ -4792,6 +4910,7 @@
"MB517": "MB 517",
"MB_837_Aa": "MB 837 Aa",
"MB_837_Ea": "MB 837 Ea",
"MB_837_K": "MB 837 K",
"MS-1": "MS-1",
"MT-5-1": "MT-5-1",
"MT25": "MT-25",
@@ -4879,6 +4998,7 @@
"Maybach_HL_234_TRM_P45_1": "Maybach HL 234 TRM P45",
"Maybach_HL_235": "Maybach HL 235",
"Maybach_HL_295": "Maybach HL 295",
"Maybach_HL_295_003_Somua": "Maybach HL 295.003 \\\"Somua\\\"",
"Maybach_HL_295_F": "Maybach HL 295 F",
"Maybach_HL_295_FA": "Maybach HL 295 F",
"Maybach_HL_45P": "Maybach HL 45 P",
@@ -4907,6 +5027,7 @@
"Nuffield_liberty_MKII": "Nuffield Liberty Mk. II",
"Nuffield_liberty_MKIV": "Nuffield Liberty Mk. III",
"Nuffield_liberty_MKV": "Nuffield Liberty Mk. V",
"Nuffield_liberty_MKV_BP": "Nuffield Liberty Mk. VB",
"OQF_17pdr_Gun_Mk_IV_SH_SH": "OQF 17-pdr Gun Mk. IV SH-SH",
"OQF_17pdr_Gun_Mk_VII": "OQF 17-pdr Gun Mk. VII",
"OQF_17pdr_Gun_Mk_VIIG": "OQF 17-pdr Gun Mk. VII G",
@@ -5200,6 +5321,8 @@
"R109_T54S": "T-54 ltwt.",
"R109_T54S_short": "T-54 ltwt.",
"R110_Object_260": "Object 260",
"R110_Object_260_Custom": "Object 260 Pike",
"R110_Object_260_Custom_short": "Object 260 Pike",
"R110_Object_260_short": "Obj. 260",
"R111_ISU130": "ISU-130",
"R111_ISU130_short": "ISU-130",
@@ -5401,8 +5524,8 @@
"Skoda_AHK": "Škoda AHK",
"Skoda_T-11": "Škoda T-11",
"Skoda_T-15": "Škoda T-15",
"Skoda_V12_19_8_liter_450": "Škoda V12 19.8 liter (450)",
"Skoda_V12_19_8_liter_500": "Škoda V12 19.8 liter (500)",
"Skoda_V12_19_8_liter_450": "Škoda V12 mod. 1",
"Skoda_V12_19_8_liter_500": "Škoda V12 mod. 2",
"Skoda_V16_diesel_600": "Škoda 16 cylinder diesel (600)",
"Skoda_V16_diesel_660": "Škoda 16 cylinder diesel (660)",
"Slpprj_m43": "Slpprj m/43",
@@ -5806,6 +5929,28 @@
"chinaNY_short": "#other_vehicles:chinaNY_short",
"skin_121B_Gold_dragon_Custom": "121B Invincible",
"skin_121B_Gold_dragon_Custom_short": "121B Invincible",
"turret_IS-2Sh": "IS-2Sh"
"turret_IS-2Sh": "IS-2Sh",
"A130_Super_Hellcat": "Super Hellcat",
"A130_Super_Hellcat_short": "Super Hellcat",
"Cz13_T-27_Custom": "Škoda T 27 Rampant",
"Cz13_T-27_Custom_short": "Škoda T 27 Rampant",
"F113_PzV_FR": "Bretagne Panther",
"F113_PzV_FR_short": "Bretagne Panther",
"G144_Kpz_50t": "Kampfpanzer 50 t",
"G144_Kpz_50t_short": "Kampfpanzer 50 t",
"JagdPz_E100_Custom": "Jagdpanzer Mighty",
"JagdPz_E100_Custom_short": "Jg.Pz. Mighty",
"MB_837_F": "MB 837 F",
"Maybach_HL_230_TRM_P30_FR": "Maybach HL 230 TRM P30 fr.",
"Object_907_Custom": "Object 907 Ruthless",
"Object_907_Custom_short": "Object 907 Ruthless",
"S07_Strv74BP": "Turbo",
"S07_Strv74BP_Custom": "Turbo",
"S07_Strv74BP_Custom_short": "Turbo",
"S07_Strv74BP_short": "Turbo",
"T34_85BP": "Triumphant",
"T34_85BP_short": "Triumphant",
"V-2-34M_BP": "V-2-34M B",
"Wright_Continental_R_975_C4_858": "Wright Continental\\nR-975-C4 (858)"
}
}