mirror of
https://github.com/Jylpah/blitz-tools.git
synced 2026-10-23 19:19:53 +02:00
4 files changed
+550
-108
No files matched your search
@@ -13,3 +13,4 @@ export*
|
||||
*.csv
|
||||
!/stats/*.csv
|
||||
!*.py
|
||||
/.venv
|
||||
+89
-83
@@ -100,7 +100,7 @@ class ThrottledClientSession(aiohttp.ClientSession):
|
||||
|
||||
def get_stats_str(self) -> str:
|
||||
"""Print session statistics"""
|
||||
return f"rate limit: {str(self.rate_limit if self.rate_limit != None else '-')} \
|
||||
return f"rate limit: {str(self.rate_limit if self.rate_limit is not None else '-')} \
|
||||
rate: {0:.1f}.format(self.get_rate()) requests: {str(self._count)}"
|
||||
|
||||
|
||||
@@ -203,7 +203,7 @@ class AsyncLogger():
|
||||
|
||||
async def open(self, logfn: str = None):
|
||||
"""Set logging to file"""
|
||||
if logfn == None:
|
||||
if logfn is None:
|
||||
logfn = 'LOG_' + _randomword(6) + '.log'
|
||||
try:
|
||||
self._file = await aiofiles.open(logfn, mode='a')
|
||||
@@ -216,7 +216,7 @@ class AsyncLogger():
|
||||
|
||||
async def logger(self):
|
||||
"""Async file logger"""
|
||||
if self._file == None:
|
||||
if self._file is None:
|
||||
error('No log file defined')
|
||||
return False
|
||||
while True:
|
||||
@@ -306,7 +306,7 @@ async def set_file_logging(logfn=None, add_timestamp=False):
|
||||
"""Set logging to file"""
|
||||
global LOG, LOGGER
|
||||
LOG = True
|
||||
if logfn == None:
|
||||
if logfn is None:
|
||||
logfn = 'LOG_' + _randomword(6)
|
||||
else:
|
||||
dateTimeObj = datetime.now()
|
||||
@@ -382,7 +382,9 @@ def get_class_from_frame(fr):
|
||||
return None
|
||||
|
||||
|
||||
def _print_log_msg(prefix = 'LOG', msg = '', exception = None, id = None, print_msg : bool = True):
|
||||
def _print_log_msg(prefix: str = 'LOG', msg:str = '',
|
||||
exception: Exception | None = None,
|
||||
id: int|None = None, print_msg : bool = True):
|
||||
# Use empty prefix to determine standard verbose messages
|
||||
if not (print_msg or LOG):
|
||||
return False
|
||||
@@ -392,20 +394,20 @@ def _print_log_msg(prefix = 'LOG', msg = '', exception = None, id = None, print_
|
||||
calframe = inspect.getouterframes(curframe)
|
||||
class_name = get_class_from_frame(curframe)
|
||||
caller = calframe[2].function
|
||||
if class_name != None:
|
||||
prefix = prefix + ': ' + class_name + '.' + caller
|
||||
if class_name is not None:
|
||||
prefix = f'{prefix}: {class_name}.{caller}'
|
||||
else:
|
||||
prefix = prefix + ': ' + caller
|
||||
prefix = prefix + '(): '
|
||||
|
||||
if id != None:
|
||||
prefix = prefix + '[' + str(id) + ']: '
|
||||
if id is not None:
|
||||
prefix = f'{prefix} [ {id}]: '
|
||||
|
||||
exception_msg = ''
|
||||
if (exception != None) and isinstance(exception, Exception):
|
||||
exception_msg = ' : Exception: ' + str(type(exception)) + ' : ' + str(exception)
|
||||
if (exception is not None) and isinstance(exception, Exception):
|
||||
exception_msg = f' : Exception: {type(exception)} : {exception}'
|
||||
|
||||
msg = prefix + msg + exception_msg
|
||||
msg = f'{prefix}{msg}{exception_msg}'
|
||||
if print_msg:
|
||||
print(msg)
|
||||
retval = True
|
||||
@@ -414,8 +416,8 @@ def _print_log_msg(prefix = 'LOG', msg = '', exception = None, id = None, print_
|
||||
return retval
|
||||
|
||||
|
||||
def _log_msg(msg =''):
|
||||
if LOG and (LOGGER != None):
|
||||
def _log_msg(msg :str=''):
|
||||
if LOG and (LOGGER is not None):
|
||||
LOGGER.log(msg)
|
||||
return True
|
||||
return False
|
||||
@@ -438,11 +440,11 @@ def get_progress_step():
|
||||
def set_progress_bar(heading: str, max_value: int, step: int = None, slow: bool = False, id: str = None):
|
||||
global _progress_obj, _progress_N, _progress_i, _progress_id
|
||||
_progress_id = id
|
||||
if step == None:
|
||||
if step is None:
|
||||
_progress_N = int(max_value / 1000) if (max_value > 1000) else 2
|
||||
else:
|
||||
_progress_N = step
|
||||
if _progress_obj != None:
|
||||
if _progress_obj is not None:
|
||||
finish_progress_bar()
|
||||
if slow:
|
||||
_progress_obj = SlowBar(heading, max=max_value)
|
||||
@@ -457,10 +459,10 @@ def set_progress_bar(heading: str, max_value: int, step: int = None, slow: bool
|
||||
def set_counter(heading: str, step = None):
|
||||
global _progress_obj, _progress_i
|
||||
_progress_i = 0
|
||||
if _progress_obj != None:
|
||||
if _progress_obj is not None:
|
||||
finish_progress_bar()
|
||||
_progress_obj = Counter(heading + ': ')
|
||||
if step != None:
|
||||
if step is not None:
|
||||
set_progress_step(step)
|
||||
return
|
||||
|
||||
@@ -472,7 +474,7 @@ def print_progress(force = False, id : str = None) -> bool:
|
||||
_progress_i += 1
|
||||
if ((_progress_i % _progress_N) == 0):
|
||||
if (_log_level > SILENT) and ( force or (_log_level < DEBUG ) ):
|
||||
if (_progress_obj != None):
|
||||
if (_progress_obj is not None):
|
||||
if (_progress_id == id):
|
||||
_progress_obj.next(_progress_N)
|
||||
return True
|
||||
@@ -489,7 +491,7 @@ def finish_progress_bar():
|
||||
global _progress_obj
|
||||
|
||||
# print_nl = True
|
||||
if _progress_obj != None:
|
||||
if _progress_obj is not None:
|
||||
# if isinstance(_progress_obj, Counter):
|
||||
# print_nl = False
|
||||
_progress_obj.finish()
|
||||
@@ -574,7 +576,7 @@ async def open_JSON(filename: str, chk_JSON_func = None) -> dict:
|
||||
try:
|
||||
async with aiofiles.open(filename) as fp:
|
||||
json_data = json.loads(await fp.read())
|
||||
if (chk_JSON_func == None):
|
||||
if (chk_JSON_func is None):
|
||||
debug("JSON file content not checked: " + filename)
|
||||
return json_data
|
||||
elif chk_JSON_func(json_data):
|
||||
@@ -589,10 +591,10 @@ async def open_JSON(filename: str, chk_JSON_func = None) -> dict:
|
||||
|
||||
async def get_url_JSON(session: aiohttp.ClientSession, url: str, chk_JSON_func = None, max_tries = MAX_RETRIES) -> dict:
|
||||
"""Retrieve (GET) an URL and return JSON object"""
|
||||
if session == None:
|
||||
if session is None:
|
||||
error('Session must be initialized first')
|
||||
sys.exit(1)
|
||||
if url == None:
|
||||
if url is None:
|
||||
return None
|
||||
|
||||
# To avoid excessive use of servers
|
||||
@@ -602,7 +604,7 @@ async def get_url_JSON(session: aiohttp.ClientSession, url: str, chk_JSON_func =
|
||||
if resp.status == 200:
|
||||
debug('HTTP request OK')
|
||||
json_resp = await resp.json()
|
||||
if (chk_JSON_func == None) or chk_JSON_func(json_resp):
|
||||
if (chk_JSON_func is None) or chk_JSON_func(json_resp):
|
||||
# debug("Received valid JSON: " + str(json_resp))
|
||||
return json_resp
|
||||
# Sometimes WG API returns JSON error even a retry gives valid JSON
|
||||
@@ -644,14 +646,18 @@ def bld_dict_hierarcy(d : dict, key : str, value) -> dict:
|
||||
return None
|
||||
|
||||
def get_JSON_keypath(keypath: str, key: str):
|
||||
if keypath == None:
|
||||
if keypath is None:
|
||||
return key
|
||||
else:
|
||||
return '.'.join([keypath, key])
|
||||
|
||||
def get_JSON_value(json, key : str = None, keys : list = None, keypath = None):
|
||||
if (keys == None) and (key != None):
|
||||
def get_JSON_value(json, key : str | None = None, keys : list | None = None,
|
||||
keypath : str | None = None):
|
||||
if (keys is None):
|
||||
if key is not None:
|
||||
keys = key.split('.')
|
||||
else:
|
||||
return json
|
||||
if len(keys) == 0:
|
||||
return json
|
||||
key = keys.pop(0)
|
||||
@@ -678,7 +684,7 @@ def sort_dict(d: dict, number: bool = False) -> dict:
|
||||
if number:
|
||||
return dict(sorted(d.items(), key=lambda item: int(item[0])))
|
||||
else:
|
||||
return dict(sorted(d.items(), key=lambda item: item[0]))
|
||||
return dict(sorted(d.items(), key=lambda item: str(item[0])))
|
||||
|
||||
|
||||
# -----------------------------------------------------------
|
||||
@@ -874,7 +880,7 @@ class WG:
|
||||
WG.tanks = self.tanks
|
||||
self.global_rate_limit = global_rate_limit
|
||||
|
||||
if (maps_fn != None):
|
||||
if (maps_fn is not None):
|
||||
if os.path.exists(maps_fn) and os.path.isfile(maps_fn):
|
||||
try:
|
||||
with open(maps_fn, 'rt', encoding='utf8') as f:
|
||||
@@ -883,7 +889,7 @@ class WG:
|
||||
error('Could not read maps file: ' + maps_fn + '\n' + str(err))
|
||||
else:
|
||||
verbose('Could not find maps file: ' + maps_fn)
|
||||
if self.WG_app_id != None:
|
||||
if self.WG_app_id is not None:
|
||||
headers = {'Accept-Encoding': 'gzip, deflate'}
|
||||
if self.global_rate_limit:
|
||||
self.session = ThrottledClientSession(rate_limit=rate_limit, headers=headers)
|
||||
@@ -912,7 +918,7 @@ class WG:
|
||||
async def close(self):
|
||||
# close stats queue
|
||||
try:
|
||||
if self.statsQ != None:
|
||||
if self.statsQ is not None:
|
||||
debug('WG.close(): Waiting for statsQ to finish')
|
||||
await self.statsQ.join()
|
||||
debug('WG.close(): statsQ finished')
|
||||
@@ -921,13 +927,13 @@ class WG:
|
||||
await self.stat_saver_task
|
||||
|
||||
# close cacheDB
|
||||
if self.cache != None:
|
||||
if self.cache is not None:
|
||||
# prune old cache records
|
||||
await self.cleanup_cache()
|
||||
await self.cache.commit()
|
||||
await self.cache.close()
|
||||
|
||||
if self.session != None:
|
||||
if self.session is not None:
|
||||
if self.global_rate_limit:
|
||||
await self.session.close()
|
||||
else:
|
||||
@@ -981,7 +987,7 @@ class WG:
|
||||
@classmethod
|
||||
def chk_JSON(cls, json_obj, check = None) -> bool:
|
||||
try:
|
||||
if (check == None):
|
||||
if (check is None):
|
||||
# nothing to check
|
||||
return True
|
||||
if (check == 'tank_stats'):
|
||||
@@ -1016,16 +1022,16 @@ class WG:
|
||||
@classmethod
|
||||
def chk_JSON_status(cls, json_resp: dict) -> bool:
|
||||
try:
|
||||
if (json_resp == None) or ('status' not in json_resp) or (json_resp['status'] == None):
|
||||
if (json_resp is None) or ('status' not in json_resp) or (json_resp['status'] is None):
|
||||
return False
|
||||
elif (json_resp['status'] == 'ok') and ('data' in json_resp):
|
||||
return True
|
||||
elif json_resp['status'] == 'error':
|
||||
if ('error' in json_resp):
|
||||
error_msg = 'Received an error'
|
||||
if ('message' in json_resp['error']) and (json_resp['error']['message'] != None):
|
||||
if ('message' in json_resp['error']) and (json_resp['error']['message'] is not None):
|
||||
error_msg = error_msg + ': ' + json_resp['error']['message']
|
||||
if ('value' in json_resp['error']) and (json_resp['error']['value'] != None):
|
||||
if ('value' in json_resp['error']) and (json_resp['error']['value'] is not None):
|
||||
error_msg = error_msg + ' Value: ' + json_resp['error']['value']
|
||||
debug(error_msg)
|
||||
return False
|
||||
@@ -1084,7 +1090,7 @@ class WG:
|
||||
try:
|
||||
if cls.chk_JSON_status(json_resp):
|
||||
for acc in json_resp['data']:
|
||||
if json_resp['data'][acc] != None:
|
||||
if json_resp['data'][acc] is not None:
|
||||
return True
|
||||
except KeyError as err:
|
||||
error('Key not found', err)
|
||||
@@ -1110,7 +1116,7 @@ class WG:
|
||||
# Methods --------------------------------------------------
|
||||
def load_tanks(self, tankopedia_fn: str):
|
||||
"""Load tanks from tankopedia JSON"""
|
||||
if tankopedia_fn == None:
|
||||
if tankopedia_fn is None:
|
||||
return False
|
||||
try:
|
||||
with open(tankopedia_fn, 'rt', encoding='utf8') as f:
|
||||
@@ -1118,7 +1124,7 @@ class WG:
|
||||
self.tanks['tankStr'] = dict()
|
||||
p = re.compile('.+_short$')
|
||||
for usr_str in self.tanks['userStr']:
|
||||
if p.match(usr_str) == None:
|
||||
if p.match(usr_str) is None:
|
||||
self.tanks['tankStr'][self.tanks['userStr'][usr_str]] = usr_str
|
||||
self.tanks_by_tier = dict()
|
||||
for tier in range(1,11):
|
||||
@@ -1179,11 +1185,11 @@ class WG:
|
||||
|
||||
def get_url_clan_info(self, server: str, clan_id: int) -> str:
|
||||
try:
|
||||
if server == None:
|
||||
if server is None:
|
||||
return None
|
||||
return self.URL_WG_SERVER[server] + self.URL_WG_CLAN_INFO + self.WG_app_id + '&clan_id=' + str(clan_id)
|
||||
except Exception as err:
|
||||
if (server == None) or (server.lower() not in WG.ACCOUNT_ID_SERVER.keys()):
|
||||
if (server is None) or (server.lower() not in WG.ACCOUNT_ID_SERVER.keys()):
|
||||
error('No server name or invalid server name given: ' + server if (server != None) else '')
|
||||
error('Available servers: ' + ', '.join(WG.ACCOUNT_ID_SERVER.keys()))
|
||||
error(exception=err)
|
||||
@@ -1196,15 +1202,15 @@ class WG:
|
||||
|
||||
def get_url_player_tanks_stats(self, account_id: int, tank_ids: list = [], fields: list = []) -> str:
|
||||
server = self.get_server(account_id)
|
||||
if server == None:
|
||||
if server is None:
|
||||
return None
|
||||
if (tank_ids != None) and (len(tank_ids) > 0):
|
||||
if (tank_ids is not None) and (len(tank_ids) > 0):
|
||||
tank_id_str= '&tank_id=' + '%2C'.join([ str(x) for x in tank_ids])
|
||||
else:
|
||||
# emtpy tank-id list returns all the player's tanks
|
||||
tank_id_str = ''
|
||||
|
||||
if (fields != None) and (len(fields) > 0):
|
||||
if (fields is not None) and (len(fields) > 0):
|
||||
field_str = '&fields=' + '%2C'.join(fields)
|
||||
else:
|
||||
# return all the fields
|
||||
@@ -1216,9 +1222,9 @@ class WG:
|
||||
def get_url_player_stats(self, account_id, fields) -> str:
|
||||
try:
|
||||
server = self.get_server(account_id)
|
||||
if server == None:
|
||||
if server is None:
|
||||
return None
|
||||
if (fields != None) and (len(fields) > 0):
|
||||
if (fields is not None) and (len(fields) > 0):
|
||||
field_str = '&fields=' + '%2C'.join(fields)
|
||||
else:
|
||||
# return all the fields
|
||||
@@ -1226,7 +1232,7 @@ class WG:
|
||||
|
||||
return self.URL_WG_SERVER[server] + self.URL_WG_PLAYER_STATS + self.WG_app_id + '&account_id=' + str(account_id) + field_str
|
||||
except Exception as err:
|
||||
if (server == None):
|
||||
if (server is None):
|
||||
error('Invalid account_id')
|
||||
error(exception=err)
|
||||
return None
|
||||
@@ -1237,10 +1243,10 @@ class WG:
|
||||
# assumming that all account_ids are from the same server. This has to be taken care.
|
||||
server = self.get_server(account_ids[0])
|
||||
|
||||
if server == None:
|
||||
if server is None:
|
||||
return None
|
||||
account_ids_str = '%2C'.join(str(id) for id in account_ids)
|
||||
if (fields != None) and (len(fields) > 0):
|
||||
if (fields is not None) and (len(fields) > 0):
|
||||
field_str = '&fields=' + '%2C'.join(fields)
|
||||
else:
|
||||
# return all the fields
|
||||
@@ -1248,7 +1254,7 @@ class WG:
|
||||
|
||||
return self.URL_WG_SERVER[server] + self.URL_WG_PLAYER_ACHIEVEMENTS + self.WG_app_id + '&account_id=' + account_ids_str + field_str
|
||||
except Exception as err:
|
||||
if (server == None):
|
||||
if (server is None):
|
||||
error('Invalid account_id')
|
||||
error(exception=err)
|
||||
return None
|
||||
@@ -1258,9 +1264,9 @@ class WG:
|
||||
try:
|
||||
return self.URL_WG_SERVER[server] + self.URL_WG_ACCOUNT_ID + self.WG_app_id + '&search=' + urllib.parse.quote(nickname)
|
||||
except Exception as err:
|
||||
if nickname == None or len(nickname) == 0:
|
||||
if nickname is None or len(nickname) == 0:
|
||||
error('No nickname given')
|
||||
if (server == None) or (server.lower() not in WG.ACCOUNT_ID_SERVER.keys()):
|
||||
if (server is None) or (server.lower() not in WG.ACCOUNT_ID_SERVER.keys()):
|
||||
error('No server name or invalid server name given: ' + server if (server != None) else '')
|
||||
error('Available servers: ' + ', '.join(WG.ACCOUNT_ID_SERVER.keys()))
|
||||
error(exception=err)
|
||||
@@ -1308,7 +1314,7 @@ class WG:
|
||||
nick, server = nickname.split('@')
|
||||
debug(nick + ' @ '+ server)
|
||||
server = server.lower()
|
||||
if nick == None or server == None:
|
||||
if nick is None or server is None:
|
||||
raise ValueError('Invalid nickname given: ' + nickname)
|
||||
url = self.get_url_account_id(nick, server)
|
||||
|
||||
@@ -1331,7 +1337,7 @@ class WG:
|
||||
# try cached stats first:
|
||||
if cache:
|
||||
stats = await self.get_cached_tank_stats(account_id, tank_ids, fields)
|
||||
if stats != None:
|
||||
if stats is not None:
|
||||
return stats
|
||||
if cache_only:
|
||||
return None
|
||||
@@ -1339,7 +1345,7 @@ class WG:
|
||||
# Cached stats not found, fetching new ones
|
||||
url = self.get_url_player_tanks_stats(account_id, tank_ids, fields)
|
||||
json_data = await self.get_url_JSON(url, self.chk_JSON_status)
|
||||
if json_data != None:
|
||||
if json_data is not None:
|
||||
# debug('JSON Response received: ' + str(json_data))
|
||||
stats = json_data['data'][str(account_id)]
|
||||
if cache:
|
||||
@@ -1372,7 +1378,7 @@ class WG:
|
||||
# Cached stats not found, fetching new ones
|
||||
url = self.get_url_player_stats(account_id, fields)
|
||||
json_data = await self.get_url_JSON(url, self.chk_JSON_status)
|
||||
if json_data != None:
|
||||
if json_data is not None:
|
||||
# debug('JSON Response received: ' + str(json_data))
|
||||
stats = json_data['data'][str(account_id)]
|
||||
if cache:
|
||||
@@ -1410,7 +1416,7 @@ class WG:
|
||||
# Cached stats not found, fetching new ones
|
||||
url = self.get_url_player_achievements(list(account_ids), fields)
|
||||
json_data = await self.get_url_JSON(url, self.chk_JSON_status)
|
||||
if (json_data != None) and ('data' in json_data):
|
||||
if (json_data is not None) and ('data' in json_data):
|
||||
# debug('JSON Response received: ' + str(json_data))
|
||||
for account_id in json_data['data'].keys():
|
||||
stats[account_id] = json_data['data'][account_id]
|
||||
@@ -1424,7 +1430,7 @@ class WG:
|
||||
|
||||
def merge_player_stats(self, stats1: dict, stats2: dict) -> dict:
|
||||
try:
|
||||
if stats2 == None: return stats1
|
||||
if stats2 is None: return stats1
|
||||
for keyA in stats2:
|
||||
if keyA not in stats1:
|
||||
stats1[keyA] = stats2[keyA]
|
||||
@@ -1438,7 +1444,7 @@ class WG:
|
||||
|
||||
|
||||
def get_tank_data(self, tank_id: int, field: str):
|
||||
if self.tanks == None:
|
||||
if self.tanks is None:
|
||||
return None
|
||||
try:
|
||||
return self.tanks['data'][str(tank_id)][field]
|
||||
@@ -1524,7 +1530,7 @@ class WG:
|
||||
|
||||
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:
|
||||
if self.statsQ is None:
|
||||
return False
|
||||
else:
|
||||
await self.statsQ.put([ statsType, key, stats, NOW() ])
|
||||
@@ -1558,7 +1564,7 @@ class WG:
|
||||
async def stat_saver(self):
|
||||
"""Async task for saving stats into cache in background"""
|
||||
|
||||
if self.statsQ == None:
|
||||
if self.statsQ is None:
|
||||
error('No statsQ defined')
|
||||
return None
|
||||
try:
|
||||
@@ -1612,12 +1618,12 @@ class WG:
|
||||
|
||||
async def cleanup_cache(self, grace_time = CACHE_GRACE_TIME):
|
||||
"""Clean old cache records"""
|
||||
if self.cache == None:
|
||||
if self.cache is None:
|
||||
debug('No active cache')
|
||||
return None
|
||||
for table in WG.SQL_TABLES:
|
||||
async with self.cache.execute(WG.SQL_CHECK_TABLE_EXITS, (table,)) as cursor:
|
||||
if (await cursor.fetchone()) != None:
|
||||
if (await cursor.fetchone()) is not None:
|
||||
debug('Pruning cache table: ' + table)
|
||||
await self.cache.execute(WG.SQL_PRUNE_CACHE.format(table, NOW() - grace_time))
|
||||
await self.cache.commit()
|
||||
@@ -1631,7 +1637,7 @@ class WG:
|
||||
try:
|
||||
account_id = key[0]
|
||||
tank_ids = set(key[1])
|
||||
if stats_data != None:
|
||||
if stats_data is not None:
|
||||
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)))
|
||||
@@ -1653,7 +1659,7 @@ class WG:
|
||||
|
||||
try:
|
||||
account_id = key[0]
|
||||
if stats_data != None:
|
||||
if stats_data is not None:
|
||||
await self.cache.execute(WG.SQL_PLAYER_STATS_UPDATE, (account_id, update_time, json.dumps(stats_data)))
|
||||
else:
|
||||
await self.cache.execute(WG.SQL_PLAYER_STATS_UPDATE, (account_id, update_time, None))
|
||||
@@ -1671,7 +1677,7 @@ class WG:
|
||||
|
||||
try:
|
||||
account_id = key[0]
|
||||
if stats_data != None:
|
||||
if stats_data is not None:
|
||||
await self.cache.execute(WG.SQL_PLAYER_ACHIEVEMENTS_UPDATE, (account_id, update_time, json.dumps(stats_data)))
|
||||
else:
|
||||
await self.cache.execute(WG.SQL_PLAYER_ACHIEVEMENTS_UPDATE, (account_id, update_time, None))
|
||||
@@ -1689,7 +1695,7 @@ class WG:
|
||||
try:
|
||||
# test for cacheDB existence
|
||||
debug('Trying cached stats first')
|
||||
if self.cache == None:
|
||||
if self.cache is None:
|
||||
debug('No cache DB')
|
||||
return None
|
||||
|
||||
@@ -1703,7 +1709,7 @@ class WG:
|
||||
tank_ids = set(tank_ids)
|
||||
async for row in cursor:
|
||||
# debug('account_id: ' + str(account_id) + ': 1')
|
||||
if row[3] == None:
|
||||
if row[3] is None:
|
||||
# None/null stats found in cache
|
||||
# i.e. stats have been requested, but not returned from WG API
|
||||
tank_ids.remove(row[1])
|
||||
@@ -1728,20 +1734,20 @@ class WG:
|
||||
try:
|
||||
# test for cacheDB existence
|
||||
debug('Trying cached stats first')
|
||||
if self.cache == None:
|
||||
if self.cache is None:
|
||||
# debug('No cache DB')
|
||||
raise StatsNotFound('No cache DB in use')
|
||||
|
||||
async with self.cache.execute(WG.SQL_PLAYER_STATS_CACHED, [account_id, NOW() - WG.CACHE_GRACE_TIME] ) as cursor:
|
||||
row = await cursor.fetchone()
|
||||
# debug('account_id: ' + str(account_id) + ': 1')
|
||||
if row == None:
|
||||
if row is None:
|
||||
# no cached stats found, marked with an empty array
|
||||
# debug('No cached stats found')
|
||||
raise StatsNotFound('No cached stats found')
|
||||
|
||||
debug('Cached stats found')
|
||||
if row[2] == None:
|
||||
if row[2] is None:
|
||||
# None/null stats found in cache
|
||||
# i.e. stats have been requested, but not returned from WG API
|
||||
return None
|
||||
@@ -1760,20 +1766,20 @@ class WG:
|
||||
try:
|
||||
# test for cacheDB existence
|
||||
debug('Trying cached stats first')
|
||||
if self.cache == None:
|
||||
if self.cache is None:
|
||||
# debug('No cache DB')
|
||||
raise StatsNotFound('No cache DB in use')
|
||||
|
||||
async with self.cache.execute(WG.SQL_PLAYER_ACHIEVEMENTS_CACHED, [account_id, NOW() - WG.CACHE_GRACE_TIME] ) as cursor:
|
||||
row = await cursor.fetchone()
|
||||
# debug('account_id: ' + str(account_id) + ': 1')
|
||||
if row == None:
|
||||
if row is None:
|
||||
# no cached stats found, marked with an empty array
|
||||
# debug('No cached stats found')
|
||||
raise StatsNotFound('No cached stats found')
|
||||
|
||||
debug('Cached stats found')
|
||||
if row[2] == None:
|
||||
if row[2] is None:
|
||||
# None/null stats found in cache
|
||||
# i.e. stats have been requested, but not returned from WG API
|
||||
return None
|
||||
@@ -1876,7 +1882,7 @@ class WoTinspector:
|
||||
|
||||
async def post_replay(self, data, filename = 'Replay', account_id = 0, title = 'Replay', priv = False, N = None):
|
||||
try:
|
||||
N = N if N != None else self.REPLAY_N
|
||||
N = N if N is not None else self.REPLAY_N
|
||||
self.REPLAY_N += 1
|
||||
|
||||
hash = hashlib.md5()
|
||||
@@ -1885,7 +1891,7 @@ class WoTinspector:
|
||||
|
||||
## Testing if the replay has already been posted
|
||||
json_resp = await self.get_replay_JSON(replay_id)
|
||||
if json_resp != None:
|
||||
if json_resp is not None:
|
||||
debug('Already uploaded: ' + title, id=N)
|
||||
return json_resp
|
||||
|
||||
@@ -1981,7 +1987,7 @@ class WoTinspector:
|
||||
""""Check String for being a valid JSON file"""
|
||||
try:
|
||||
if ('status' in json_resp) and json_resp['status'] == 'ok' and \
|
||||
(get_JSON_value(json_resp, key='data.summary.exp_base') != None) :
|
||||
(get_JSON_value(json_resp, key='data.summary.exp_base') is not None) :
|
||||
debug("JSON check OK")
|
||||
return True
|
||||
except KeyError as err:
|
||||
@@ -2008,7 +2014,7 @@ class BlitzStars:
|
||||
self.session = ThrottledClientSession(rate_limit=rate_limit, headers=headers)
|
||||
|
||||
async def close(self):
|
||||
if self.session != None:
|
||||
if self.session is not None:
|
||||
await self.session.close()
|
||||
|
||||
|
||||
@@ -2066,7 +2072,7 @@ class BlitzStars:
|
||||
async def tank_stats2WG(cls, BS_tank_stats: list) -> list:
|
||||
"""Convert BlitzStars player tank stats to WG API format"""
|
||||
try:
|
||||
if BS_tank_stats == None:
|
||||
if BS_tank_stats is None:
|
||||
return None
|
||||
WG_tank_stats = []
|
||||
for stat in BS_tank_stats:
|
||||
@@ -2108,7 +2114,7 @@ class BlitzStars:
|
||||
# Cached stats not found, fetching new ones
|
||||
url = self.get_url_player_stats(account_id)
|
||||
stats = await get_url_JSON(self.session, url, self.chk_JSON_player_stats)
|
||||
if stats != None:
|
||||
if stats is not None:
|
||||
# debug('JSON Response received: ' + str(json_data))
|
||||
if cache:
|
||||
error('CACHE NOT IMPLEMENTED YET FOR BlitzStars()')
|
||||
@@ -2139,13 +2145,13 @@ class BlitzStars:
|
||||
|
||||
try:
|
||||
# Cached stats not found, fetching new ones
|
||||
if tank_id == None:
|
||||
if tank_id is None:
|
||||
# get stats for all the player's tanks
|
||||
url = self.get_url_player_tanks_stats(account_id)
|
||||
else:
|
||||
url = self.get_url_player_tank_stats(account_id, tank_id)
|
||||
stats = await get_url_JSON(self.session, url, self.chk_JSON_tank_stats)
|
||||
if stats != None:
|
||||
if stats is not None:
|
||||
# debug('JSON Response received: ' + str(json_data))
|
||||
if cache:
|
||||
error('CACHE NOT IMPLEMENTED YET FOR BlitzStars()')
|
||||
|
||||
+33
-18
@@ -4,7 +4,11 @@
|
||||
# Extract tankopedia data in WG API JSON format from Blitz app files (Android APK unzipped)
|
||||
|
||||
from os import path
|
||||
import sys, argparse, json, os, inspect, aiohttp, asyncio, aiofiles, re, logging, time, xmltodict, collections, configparser
|
||||
import aiofiles # type: ignore
|
||||
import xmltodict # type: ignore
|
||||
from asyncio import set_event_loop_policy, run, create_task, get_event_loop_policy
|
||||
import sys, argparse, json, os, inspect, asyncio, re, logging, time, configparser
|
||||
from collections import OrderedDict
|
||||
import blitzutils as bu
|
||||
from blitzutils import WG
|
||||
|
||||
@@ -18,10 +22,10 @@ BLITZAPP_STRINGS='Data/Strings/en.yaml'
|
||||
BLITZAPP_VEHICLES_DIR='Data/XML/item_defs/vehicles/'
|
||||
BLITZAPP_VEHICLE_FILE='list.xml'
|
||||
|
||||
wg = None
|
||||
wg : WG | None = None
|
||||
|
||||
## main() -------------------------------------------------------------
|
||||
async def main(argv):
|
||||
async def main() -> None:
|
||||
global wg
|
||||
# set the directory for the script
|
||||
os.chdir(os.path.dirname(sys.argv[0]))
|
||||
@@ -79,7 +83,7 @@ async def main(argv):
|
||||
# merge old and new tankopedia
|
||||
tanks.update(new_tanks)
|
||||
userStrs.update(new_userStrs)
|
||||
tankopedia = collections.OrderedDict()
|
||||
tankopedia : OrderedDict[str, str| int | dict ]= OrderedDict()
|
||||
tankopedia['status'] = 'ok'
|
||||
tankopedia['meta'] = { "count": len(tanks) }
|
||||
tankopedia['data'] = bu.sort_dict(tanks, number=True)
|
||||
@@ -88,7 +92,7 @@ async def main(argv):
|
||||
bu.verbose_std('New tankopedia \'' + args.tanks + '\' contains ' + str(len(userStrs)) + ' tank strings')
|
||||
await outfile.write(json.dumps(tankopedia, ensure_ascii=False, indent=4, sort_keys=False))
|
||||
|
||||
if args.maps != None:
|
||||
if args.maps is not None:
|
||||
maps = {}
|
||||
if os.path.exists(args.maps):
|
||||
try:
|
||||
@@ -120,7 +124,7 @@ async def extract_tanks(blitz_app_base : str, nation: str):
|
||||
tankList = xmltodict.parse(await f.read())
|
||||
for data in tankList['root'].keys():
|
||||
tank_xml = tankList['root'][data]
|
||||
tank = dict()
|
||||
tank : dict[str, bool | int | str]= dict()
|
||||
tank['is_premium'] = issubclass(type(tank_xml['price']), dict)
|
||||
tank['nation'] = nation
|
||||
tank['tank_id'] = get_tank_id(nation, int(tank_xml['id']))
|
||||
@@ -134,7 +138,7 @@ async def extract_tanks(blitz_app_base : str, nation: str):
|
||||
sys.exit(2)
|
||||
return tanks
|
||||
|
||||
async def read_user_strs(blitz_app_base : str) -> dict:
|
||||
async def read_user_strs(blitz_app_base : str) -> tuple[dict, dict]:
|
||||
"""Read user strings to convert map and tank names"""
|
||||
tank_strs = {}
|
||||
map_strs = {}
|
||||
@@ -147,11 +151,11 @@ async def read_user_strs(blitz_app_base : str) -> dict:
|
||||
|
||||
async for l in f:
|
||||
m = p_tank.match(l)
|
||||
if m != None:
|
||||
if m is not None:
|
||||
tank_strs[m.group(1)] = m.group(2)
|
||||
|
||||
m = p_map.match(l)
|
||||
if m != None and m.group(2) != 'Macragge':
|
||||
if m is not None and m.group(2) != 'Macragge':
|
||||
map_strs[m.group(1)] = m.group(2)
|
||||
|
||||
except Exception as err:
|
||||
@@ -160,20 +164,30 @@ async def read_user_strs(blitz_app_base : str) -> dict:
|
||||
|
||||
return tank_strs, map_strs
|
||||
|
||||
async def convert_tank_names(tanklist : list, tank_strs: dict) -> dict:
|
||||
async def convert_tank_names(tanklist : list, tank_strs: dict) -> tuple[dict, dict]:
|
||||
"""Convert tank names for Tankopedia"""
|
||||
tankopedia = {}
|
||||
userStrs = {}
|
||||
|
||||
bu.debug(f'tank_strs:')
|
||||
for key, value in tank_strs.items():
|
||||
bu.debug(f'{key}: {value}')
|
||||
bu.debug('---------')
|
||||
try:
|
||||
for tank in tanklist:
|
||||
try:
|
||||
bu.debug(f'tank: {tank}')
|
||||
if tank['userStr'] in tank_strs:
|
||||
tank['name'] = tank_strs[tank['userStr']]
|
||||
#userStrs[tank['userStr'].split(':')[1]] = tank['name']
|
||||
else:
|
||||
tank['name'] = tank['userStr'].split(':')[1]
|
||||
tank.pop('userStr', None)
|
||||
tank_tmp = collections.OrderedDict()
|
||||
tank_tmp = OrderedDict()
|
||||
for key in sorted(tank.keys()):
|
||||
tank_tmp[key] = tank[key]
|
||||
tankopedia[str(tank['tank_id'])] = tank_tmp
|
||||
except:
|
||||
bu.error(f'Could not process tank: {tank}')
|
||||
|
||||
for tank_str in tank_strs:
|
||||
skip = False
|
||||
@@ -191,11 +205,11 @@ async def convert_tank_names(tanklist : list, tank_strs: dict) -> dict:
|
||||
userStrs[key] = tank_strs[tank_str]
|
||||
|
||||
# sorting
|
||||
tankopedia_sorted = collections.OrderedDict()
|
||||
tankopedia_sorted = OrderedDict()
|
||||
for tank_id in sorted(tankopedia.keys(), key=int):
|
||||
tankopedia_sorted[str(tank_id)] = tankopedia[str(tank_id)]
|
||||
|
||||
userStrs_sorted = collections.OrderedDict()
|
||||
userStrs_sorted = OrderedDict()
|
||||
for userStr in sorted(userStrs.keys()):
|
||||
userStrs_sorted[userStr] = userStrs[userStr]
|
||||
# bu.debug('Tank strings: ' + str(len(userStrs_sorted)))
|
||||
@@ -208,10 +222,12 @@ async def convert_tank_names(tanklist : list, tank_strs: dict) -> dict:
|
||||
|
||||
|
||||
def get_tank_id(nation: str, tank_id : int) -> int:
|
||||
assert wg is not None, "wg has to be set"
|
||||
return (tank_id << 8) + (wg.NATION_ID[nation] << 4) + 1
|
||||
|
||||
|
||||
def get_tank_type(tagstr : str):
|
||||
assert wg is not None, "wg has to be set"
|
||||
tags = tagstr.split(' ')
|
||||
for t_type in wg.TANK_TYPE:
|
||||
if tags[0] == t_type:
|
||||
@@ -227,7 +243,6 @@ if __name__ == "__main__":
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
if not isinstance(asyncio.get_event_loop_policy(), WindowsSelectorEventLoopPolicy):
|
||||
asyncio.set_event_loop_policy(WindowsSelectorEventLoopPolicy())
|
||||
#asyncio.run(main(sys.argv[1:]), debug=True)
|
||||
asyncio.run(main(sys.argv[1:]))
|
||||
if not isinstance(get_event_loop_policy(), WindowsSelectorEventLoopPolicy):
|
||||
set_event_loop_policy(WindowsSelectorEventLoopPolicy())
|
||||
run(main())
|
||||
+427
-7
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"status": "ok",
|
||||
"meta": {
|
||||
"count": 564
|
||||
"count": 592
|
||||
},
|
||||
"data": {
|
||||
"1": {
|
||||
@@ -788,6 +788,14 @@
|
||||
"tier": 5,
|
||||
"type": "heavyTank"
|
||||
},
|
||||
"3377": {
|
||||
"is_premium": false,
|
||||
"name": "WZ-131",
|
||||
"nation": "china",
|
||||
"tank_id": 3377,
|
||||
"tier": 7,
|
||||
"type": "lightTank"
|
||||
},
|
||||
"3425": {
|
||||
"is_premium": false,
|
||||
"name": "Type 61",
|
||||
@@ -876,6 +884,14 @@
|
||||
"tier": 7,
|
||||
"type": "heavyTank"
|
||||
},
|
||||
"3889": {
|
||||
"is_premium": false,
|
||||
"name": "WZ-132",
|
||||
"nation": "china",
|
||||
"tank_id": 3889,
|
||||
"tier": 8,
|
||||
"type": "lightTank"
|
||||
},
|
||||
"3905": {
|
||||
"is_premium": false,
|
||||
"name": "AMX 50 120",
|
||||
@@ -1092,6 +1108,14 @@
|
||||
"tier": 3,
|
||||
"type": "mediumTank"
|
||||
},
|
||||
"4913": {
|
||||
"is_premium": false,
|
||||
"name": "59-16",
|
||||
"nation": "china",
|
||||
"tank_id": 4913,
|
||||
"tier": 6,
|
||||
"type": "lightTank"
|
||||
},
|
||||
"4929": {
|
||||
"is_premium": false,
|
||||
"name": "AMX 13 90",
|
||||
@@ -2172,6 +2196,14 @@
|
||||
"tier": 6,
|
||||
"type": "lightTank"
|
||||
},
|
||||
"9777": {
|
||||
"is_premium": true,
|
||||
"name": "WZ-114",
|
||||
"nation": "china",
|
||||
"tank_id": 9777,
|
||||
"tier": 9,
|
||||
"type": "heavyTank"
|
||||
},
|
||||
"9793": {
|
||||
"is_premium": false,
|
||||
"name": "Somua SAu 40",
|
||||
@@ -2228,6 +2260,14 @@
|
||||
"tier": 6,
|
||||
"type": "mediumTank"
|
||||
},
|
||||
"10033": {
|
||||
"is_premium": false,
|
||||
"name": "WZ-132A",
|
||||
"nation": "china",
|
||||
"tank_id": 10033,
|
||||
"tier": 9,
|
||||
"type": "lightTank"
|
||||
},
|
||||
"10049": {
|
||||
"is_premium": false,
|
||||
"name": "S35 CA",
|
||||
@@ -2284,6 +2324,14 @@
|
||||
"tier": 4,
|
||||
"type": "AT-SPG"
|
||||
},
|
||||
"10289": {
|
||||
"is_premium": false,
|
||||
"name": "WZ-132-1",
|
||||
"nation": "china",
|
||||
"tank_id": 10289,
|
||||
"tier": 10,
|
||||
"type": "lightTank"
|
||||
},
|
||||
"10353": {
|
||||
"is_premium": true,
|
||||
"name": "Pharaoh",
|
||||
@@ -2293,7 +2341,7 @@
|
||||
"type": "heavyTank"
|
||||
},
|
||||
"10369": {
|
||||
"is_premium": true,
|
||||
"is_premium": false,
|
||||
"name": "Controcarro 3 Minotauro",
|
||||
"nation": "european",
|
||||
"tank_id": 10369,
|
||||
@@ -2324,6 +2372,22 @@
|
||||
"tier": 5,
|
||||
"type": "AT-SPG"
|
||||
},
|
||||
"10545": {
|
||||
"is_premium": true,
|
||||
"name": "Wind",
|
||||
"nation": "china",
|
||||
"tank_id": 10545,
|
||||
"tier": 6,
|
||||
"type": "lightTank"
|
||||
},
|
||||
"10625": {
|
||||
"is_premium": false,
|
||||
"name": "Controcarro 1 Mk. 2",
|
||||
"nation": "european",
|
||||
"tank_id": 10625,
|
||||
"tier": 9,
|
||||
"type": "AT-SPG"
|
||||
},
|
||||
"10753": {
|
||||
"is_premium": false,
|
||||
"name": "ST-I",
|
||||
@@ -2348,6 +2412,14 @@
|
||||
"tier": 10,
|
||||
"type": "heavyTank"
|
||||
},
|
||||
"10801": {
|
||||
"is_premium": true,
|
||||
"name": "Panlong",
|
||||
"nation": "china",
|
||||
"tank_id": 10801,
|
||||
"tier": 6,
|
||||
"type": "AT-SPG"
|
||||
},
|
||||
"10817": {
|
||||
"is_premium": false,
|
||||
"name": "AMX AC mle. 46",
|
||||
@@ -2356,6 +2428,14 @@
|
||||
"tier": 7,
|
||||
"type": "AT-SPG"
|
||||
},
|
||||
"10881": {
|
||||
"is_premium": false,
|
||||
"name": "Semovente Controcarro mod. 1964",
|
||||
"nation": "european",
|
||||
"tank_id": 10881,
|
||||
"tier": 8,
|
||||
"type": "AT-SPG"
|
||||
},
|
||||
"11009": {
|
||||
"is_premium": false,
|
||||
"name": "KV-4",
|
||||
@@ -2388,6 +2468,14 @@
|
||||
"tier": 9,
|
||||
"type": "AT-SPG"
|
||||
},
|
||||
"11137": {
|
||||
"is_premium": false,
|
||||
"name": "Semovente Controcarro mod. 1956",
|
||||
"nation": "european",
|
||||
"tank_id": 11137,
|
||||
"tier": 7,
|
||||
"type": "AT-SPG"
|
||||
},
|
||||
"11265": {
|
||||
"is_premium": true,
|
||||
"name": "T-150",
|
||||
@@ -2412,6 +2500,14 @@
|
||||
"tier": 8,
|
||||
"type": "AT-SPG"
|
||||
},
|
||||
"11393": {
|
||||
"is_premium": false,
|
||||
"name": "Semovente M43 Bassotto",
|
||||
"nation": "european",
|
||||
"tank_id": 11393,
|
||||
"tier": 6,
|
||||
"type": "AT-SPG"
|
||||
},
|
||||
"11521": {
|
||||
"is_premium": false,
|
||||
"name": "IS-8",
|
||||
@@ -2444,6 +2540,14 @@
|
||||
"tier": 6,
|
||||
"type": "AT-SPG"
|
||||
},
|
||||
"11649": {
|
||||
"is_premium": false,
|
||||
"name": "Semovente M41",
|
||||
"nation": "european",
|
||||
"tank_id": 11649,
|
||||
"tier": 5,
|
||||
"type": "AT-SPG"
|
||||
},
|
||||
"11777": {
|
||||
"is_premium": false,
|
||||
"name": "KV-1",
|
||||
@@ -2532,6 +2636,14 @@
|
||||
"tier": 4,
|
||||
"type": "mediumTank"
|
||||
},
|
||||
"12417": {
|
||||
"is_premium": true,
|
||||
"name": "Bisonte C45",
|
||||
"nation": "european",
|
||||
"tank_id": 12417,
|
||||
"tier": 8,
|
||||
"type": "heavyTank"
|
||||
},
|
||||
"12545": {
|
||||
"is_premium": true,
|
||||
"name": "K-91",
|
||||
@@ -2540,6 +2652,14 @@
|
||||
"tier": 9,
|
||||
"type": "heavyTank"
|
||||
},
|
||||
"12673": {
|
||||
"is_premium": true,
|
||||
"name": "Bofors Tornvagn",
|
||||
"nation": "european",
|
||||
"tank_id": 12673,
|
||||
"tier": 8,
|
||||
"type": "heavyTank"
|
||||
},
|
||||
"13073": {
|
||||
"is_premium": true,
|
||||
"name": "Pz.Kpfw. II Ausf. G",
|
||||
@@ -2556,6 +2676,14 @@
|
||||
"tier": 10,
|
||||
"type": "AT-SPG"
|
||||
},
|
||||
"13185": {
|
||||
"is_premium": true,
|
||||
"name": "Vz. 55",
|
||||
"nation": "european",
|
||||
"tank_id": 13185,
|
||||
"tier": 10,
|
||||
"type": "heavyTank"
|
||||
},
|
||||
"13329": {
|
||||
"is_premium": true,
|
||||
"name": "Durchbruchswagen 2",
|
||||
@@ -3140,6 +3268,14 @@
|
||||
"tier": 8,
|
||||
"type": "AT-SPG"
|
||||
},
|
||||
"19521": {
|
||||
"is_premium": true,
|
||||
"name": "Bat-Chat-25CL",
|
||||
"nation": "france",
|
||||
"tank_id": 19521,
|
||||
"tier": 9,
|
||||
"type": "lightTank"
|
||||
},
|
||||
"19537": {
|
||||
"is_premium": false,
|
||||
"name": "Vickers Light 105",
|
||||
@@ -3212,6 +3348,14 @@
|
||||
"tier": 9,
|
||||
"type": "lightTank"
|
||||
},
|
||||
"20033": {
|
||||
"is_premium": true,
|
||||
"name": "Char Futur 4",
|
||||
"nation": "france",
|
||||
"tank_id": 20033,
|
||||
"tier": 9,
|
||||
"type": "mediumTank"
|
||||
},
|
||||
"20049": {
|
||||
"is_premium": false,
|
||||
"name": "FV301",
|
||||
@@ -3750,7 +3894,7 @@
|
||||
},
|
||||
"25361": {
|
||||
"is_premium": true,
|
||||
"name": "Waffenträger Camelot",
|
||||
"name": "Waffenträger Ritter",
|
||||
"nation": "germany",
|
||||
"tank_id": 25361,
|
||||
"tier": 9,
|
||||
@@ -3772,6 +3916,14 @@
|
||||
"tier": 7,
|
||||
"type": "heavyTank"
|
||||
},
|
||||
"25617": {
|
||||
"is_premium": true,
|
||||
"name": "HWK 30",
|
||||
"nation": "germany",
|
||||
"tank_id": 25617,
|
||||
"tier": 8,
|
||||
"type": "lightTank"
|
||||
},
|
||||
"25633": {
|
||||
"is_premium": true,
|
||||
"name": "M-IV-Y",
|
||||
@@ -3780,6 +3932,14 @@
|
||||
"tier": 8,
|
||||
"type": "heavyTank"
|
||||
},
|
||||
"25857": {
|
||||
"is_premium": true,
|
||||
"name": "Object 777 Version II",
|
||||
"nation": "ussr",
|
||||
"tank_id": 25857,
|
||||
"tier": 10,
|
||||
"type": "heavyTank"
|
||||
},
|
||||
"25889": {
|
||||
"is_premium": true,
|
||||
"name": "Ranger",
|
||||
@@ -3788,6 +3948,22 @@
|
||||
"tier": 6,
|
||||
"type": "lightTank"
|
||||
},
|
||||
"26113": {
|
||||
"is_premium": true,
|
||||
"name": "Object 452K",
|
||||
"nation": "ussr",
|
||||
"tank_id": 26113,
|
||||
"tier": 9,
|
||||
"type": "heavyTank"
|
||||
},
|
||||
"26129": {
|
||||
"is_premium": true,
|
||||
"name": "Epsilon",
|
||||
"nation": "germany",
|
||||
"tank_id": 26129,
|
||||
"tier": 6,
|
||||
"type": "AT-SPG"
|
||||
},
|
||||
"26145": {
|
||||
"is_premium": true,
|
||||
"name": "High Score",
|
||||
@@ -3812,6 +3988,54 @@
|
||||
"tier": 8,
|
||||
"type": "mediumTank"
|
||||
},
|
||||
"26913": {
|
||||
"is_premium": true,
|
||||
"name": "Frosty",
|
||||
"nation": "usa",
|
||||
"tank_id": 26913,
|
||||
"tier": 6,
|
||||
"type": "lightTank"
|
||||
},
|
||||
"27169": {
|
||||
"is_premium": true,
|
||||
"name": "Cyborg",
|
||||
"nation": "usa",
|
||||
"tank_id": 27169,
|
||||
"tier": 6,
|
||||
"type": "heavyTank"
|
||||
},
|
||||
"27425": {
|
||||
"is_premium": false,
|
||||
"name": "TL-7-120",
|
||||
"nation": "usa",
|
||||
"tank_id": 27425,
|
||||
"tier": 9,
|
||||
"type": "heavyTank"
|
||||
},
|
||||
"27681": {
|
||||
"is_premium": true,
|
||||
"name": "Pawlack Tank",
|
||||
"nation": "usa",
|
||||
"tank_id": 27681,
|
||||
"tier": 6,
|
||||
"type": "heavyTank"
|
||||
},
|
||||
"27937": {
|
||||
"is_premium": true,
|
||||
"name": "T49 Fearless",
|
||||
"nation": "usa",
|
||||
"tank_id": 27937,
|
||||
"tier": 8,
|
||||
"type": "lightTank"
|
||||
},
|
||||
"28449": {
|
||||
"is_premium": true,
|
||||
"name": "T42",
|
||||
"nation": "usa",
|
||||
"tank_id": 28449,
|
||||
"tier": 7,
|
||||
"type": "mediumTank"
|
||||
},
|
||||
"51201": {
|
||||
"is_premium": true,
|
||||
"name": "KV-220 Beta-Test",
|
||||
@@ -4520,6 +4744,7 @@
|
||||
"userStr": {
|
||||
"1_test": "#germany_vehicles:1_test",
|
||||
"1_test_short": "#germany_vehicles:1_test_short",
|
||||
"85mm_D5T-85BML": "85 mm D-5T-85BML",
|
||||
"8V135-2": "8V135-2",
|
||||
"A-20": "A-20",
|
||||
"A-20_mod_1938": "A-20 mod. 1938",
|
||||
@@ -4532,6 +4757,8 @@
|
||||
"A100_T49": "T49",
|
||||
"A100_T49_Custom": "T49 Hornet",
|
||||
"A100_T49_Custom_short": "T49 Hornet",
|
||||
"A100_T49_Custom_short_v2": "T49 Guanlong",
|
||||
"A100_T49_Custom_v2": "T49 Guanlong",
|
||||
"A100_T49_short": "T49",
|
||||
"A102_T28_concept": "T28 Concept",
|
||||
"A102_T28_concept_Custom": "T28 HTC Independence",
|
||||
@@ -4582,13 +4809,25 @@
|
||||
"A132_T77_Custom": "T77 Cannonball",
|
||||
"A132_T77_Custom_short": "T77 Cannonball",
|
||||
"A132_T77_short": "T77",
|
||||
"A136_T42": "T42",
|
||||
"A136_T42_short": "T42",
|
||||
"A140_ASTRON_REX_105": "ASTRON Rex 105 mm",
|
||||
"A140_ASTRON_REX_105_Custom": "ASTRON Rex Ayame",
|
||||
"A140_ASTRON_REX_105_Custom_short": "ASTRON Rex Ayame",
|
||||
"A140_ASTRON_REX_105_short": "ASTRON Rex",
|
||||
"A141_M-4-Y": "M-IV-Y",
|
||||
"A141_M-4-Y_Custom": "M-IV-Y Stalker",
|
||||
"A141_M-4-Y_Custom_short": "M-IV-Y Stalker",
|
||||
"A141_M-4-Y_short": "M-IV-Y",
|
||||
"A142_Pawlack_Tank": "Pawlack Tank",
|
||||
"A142_Pawlack_Tank_short": "Pawlack Tank",
|
||||
"A146_TL_7_120": "TL-7-120",
|
||||
"A146_TL_7_120_Custom": "TL-7-120 Arachnid",
|
||||
"A146_TL_7_120_Custom_short": "TL-7-120 Arachnid",
|
||||
"A146_TL_7_120_short": "TL-7-120",
|
||||
"A68_T28D": "T28 Defender",
|
||||
"A68_T28D_Custom": "Defender D-Gunner",
|
||||
"A68_T28D_Custom_short": "Defender D-Gunner",
|
||||
"A68_T28D_short": "T28 Defender",
|
||||
"A77_T6M": "T6E1 Grizzly",
|
||||
"A77_T6M_short": "T6E1 Grizzly",
|
||||
@@ -4647,6 +4886,7 @@
|
||||
"AMX_dracula_short": "Dracula",
|
||||
"AOI-1490": "Continental AOI-1490",
|
||||
"AOI-1490A": "Continental AOI-1490-A",
|
||||
"AOI_695": "AOI-695",
|
||||
"AOSI_1490-1": "Continental AOSI-1490-1",
|
||||
"AOS_895": "AOS-895",
|
||||
"APCNR": "Pzgr. 41 HK",
|
||||
@@ -4718,6 +4958,8 @@
|
||||
"Bat_Chatillon25t": "Bat.-Châtillon 25 t",
|
||||
"Bat_Chatillon25t_Custom": "Bat.-Châtillon 25 t Musketeer",
|
||||
"Bat_Chatillon25t_Custom_short": "B-C 25 t Musketeer",
|
||||
"Bat_Chatillon25t_Custom_short_v2": "B-C 25 t Runner",
|
||||
"Bat_Chatillon25t_Custom_v2": "B-C 25 t Runner",
|
||||
"Bat_Chatillon25t_short": "B-C 25 t",
|
||||
"Bedford_Twin-Six": "Bedford Twin-Six",
|
||||
"Berliet_MDP": "Berliet MDP",
|
||||
@@ -4731,6 +4973,7 @@
|
||||
"CH38_WZ113G_FT_Custom": "WZ-113G FT Lucky",
|
||||
"CH38_WZ113G_FT_Custom_short": "WZ-113G FT Lucky",
|
||||
"CKD_AXK": "ČKD AXK",
|
||||
"CKD_AXL": "ČKD AXL",
|
||||
"Cadillac_V8": "3xCadillacV8",
|
||||
"Cannone_da_105_51_M68": "Cannone da 105/51 M68",
|
||||
"Cannone_da_105_51_M68_short": "Cannone da 105/51 M68",
|
||||
@@ -4772,6 +5015,12 @@
|
||||
"Ch12_111_1_2_3_short": "WZ-111 1-4",
|
||||
"Ch14_T34_3": "T-34-3",
|
||||
"Ch14_T34_3_short": "T-34-3",
|
||||
"Ch15_59_16": "59-16",
|
||||
"Ch15_59_16_BP": "Wind",
|
||||
"Ch15_59_16_BP_Custom": "Free Wind",
|
||||
"Ch15_59_16_BP_Custom_short": "Free Wind",
|
||||
"Ch15_59_16_BP_short": "Wind",
|
||||
"Ch16_WZ_131": "WZ-131",
|
||||
"Ch17_WZ131_1_WZ132": "WZ-132",
|
||||
"Ch18_WZ-120": "WZ-120",
|
||||
"Ch19_121": "WZ-121",
|
||||
@@ -4782,6 +5031,8 @@
|
||||
"Ch22_113": "WZ-113",
|
||||
"Ch22_113_Custom": "WZ-113 Bronze Warrior",
|
||||
"Ch22_113_Custom_short": "WZ-113 Bronze Warrior",
|
||||
"Ch22_113_Custom_short_v2": "WZ-113 Nine-Colors",
|
||||
"Ch22_113_Custom_v2": "WZ-113 Nine-Colors",
|
||||
"Ch23_112": "112 Glacial",
|
||||
"Ch24_Type64": "Type 64",
|
||||
"Ch24_Type64_short": "Type 64",
|
||||
@@ -4791,7 +5042,17 @@
|
||||
"Ch26_59_Patton_Custom": "59-Patton Aratinga",
|
||||
"Ch26_59_Patton_Custom_short": "59-Patton Aratinga",
|
||||
"Ch26_59_Patton_short": "59-Patton",
|
||||
"Ch28_WZ_132A": "WZ-132A",
|
||||
"Ch28_WZ_132A_short": "WZ-132A",
|
||||
"Ch29_Type_62C_prot": "WZ-132-1",
|
||||
"Ch29_Type_62C_prot_Custom": "WZ-132-1 Futuro",
|
||||
"Ch29_Type_62C_prot_Custom_short": "WZ-132-1 Futuro",
|
||||
"Ch29_Type_62C_prot_short": "WZ-132-1",
|
||||
"Ch34_WZ-131G_FT": "WZ-131G FT",
|
||||
"Ch34_WZ-131G_FT_BP": "Panlong",
|
||||
"Ch34_WZ-131G_FT_BP_Custom": "Panlong Immortal",
|
||||
"Ch34_WZ-131G_FT_BP_Custom_short": "Panlong Immortal",
|
||||
"Ch34_WZ-131G_FT_BP_short": "Panlong",
|
||||
"Ch34_WZ-131G_FT_short": "WZ-131G FT",
|
||||
"Ch35_T-34-2G_FT": "T-34-2G FT",
|
||||
"Ch35_T-34-2G_FT_short": "T-34-2G FT",
|
||||
@@ -4815,6 +5076,10 @@
|
||||
"Ch42_M41D_short": "M41D",
|
||||
"Ch43_WZ-122_2": "WZ-122 TM",
|
||||
"Ch43_WZ-122_2_short": "WZ-122 TM",
|
||||
"Ch45_WZ_114": "WZ-114",
|
||||
"Ch45_WZ_114_Custom": "WZ-114 Zhulong",
|
||||
"Ch45_WZ_114_Custom_short": "WZ-114 Zhulong",
|
||||
"Ch45_WZ_114_short": "WZ-114",
|
||||
"Ch_LT_vz38": "LT vz. 38",
|
||||
"Ch_LT_vz38_short": "LT vz. 38",
|
||||
"Ch_WZ-112v2": "WZ-112-2",
|
||||
@@ -4823,18 +5088,64 @@
|
||||
"Ch_WZ_112v2_Custom_short": "WZ-112-2 Celestial",
|
||||
"Chassis1_A140_ASTRON_REX_105": "Rex",
|
||||
"Chassis1_A140_ASTRON_REX_105_short": "Rex",
|
||||
"Chassis1_Ch16_WZ_131": "WZ-131",
|
||||
"Chassis1_Ch16_WZ_131_short": "WZ-131",
|
||||
"Chassis1_Ch17_WZ131_1_WZ132": "WZ-131-1",
|
||||
"Chassis1_Ch17_WZ131_1_WZ132_short": "WZ-131-1",
|
||||
"Chassis1_Ch28_WZ_132A": "WZ-132A",
|
||||
"Chassis1_Ch28_WZ_132A_short": "WZ-132A",
|
||||
"Chassis1_Ch29_Type_62C_prot": "WZ-132-1",
|
||||
"Chassis1_Ch29_Type_62C_prot_short": "WZ-132-1",
|
||||
"Chassis1_Ch45_WZ_114": "WZ-114",
|
||||
"Chassis1_Ch45_WZ_114_short": "WZ-114",
|
||||
"Chassis1_F117_Alt_Proto_AMX_30": "AltProto AMX 30",
|
||||
"Chassis1_F117_Alt_Proto_AMX_30_short": "A.P. AMX 30",
|
||||
"Chassis1_GB09_Churchill_VII_BP": "Churchill W",
|
||||
"Chassis1_GB09_Churchill_VII_BP_short": "Churchill W",
|
||||
"Chassis1_It10_P43_bis_BP": "Shadowhunter",
|
||||
"Chassis1_It10_P43_bis_BP_short": "Shadowhunter",
|
||||
"Chassis1_It15_Semovente_M41": "Semovente M41",
|
||||
"Chassis1_It15_Semovente_M41_short": "Semovente M41",
|
||||
"Chassis1_It16_Bassoto": "Semovente M43",
|
||||
"Chassis1_It16_Bassoto_short": "Semovente M43",
|
||||
"Chassis1_It17_Semovente_mod_56": "CC mod. 56",
|
||||
"Chassis1_It17_Semovente_mod_56_short": "CC mod. 56",
|
||||
"Chassis1_It18_Semovente_mod_64": "CC-64 tipo A",
|
||||
"Chassis1_It18_Semovente_mod_64_short": "CC-64 tipo A",
|
||||
"Chassis1_It19_Controcarro_1MK2_Ciclope": "Controcarro 1 Mk. 2 tipo A",
|
||||
"Chassis1_It19_Controcarro_1MK2_Ciclope_short": "CC 1 Mk. 2 tipo A",
|
||||
"Chassis1_It22_Progetto_C45_mod_71": "Bisonte C45",
|
||||
"Chassis1_It22_Progetto_C45_mod_71_short": "Bisonte C45",
|
||||
"Chassis1_M24_Chaffee_BP": "Frosty",
|
||||
"Chassis1_M24_Chaffee_BP_short": "Frosty",
|
||||
"Chassis1_M6E2V2_BP": "Cyborg",
|
||||
"Chassis1_M6E2V2_BP_short": "Cyborg",
|
||||
"Chassis1_Oth34_PanzerMummy": "Royal Tread",
|
||||
"Chassis1_Oth34_PanzerMummy_short": "Royal Tread",
|
||||
"Chassis1_Oth35_PanzerMejai": "Desert Wanderer",
|
||||
"Chassis1_Oth35_PanzerMejai_short": "Desert Wanderer",
|
||||
"Chassis1_R119_Object_777": "Object 777 Version II",
|
||||
"Chassis1_R119_Object_777_short": "Obj. 777 II",
|
||||
"Chassis1_S31_Strv_K": "Stridsvagn KRV",
|
||||
"Chassis1_S31_Strv_K_short": "Stridsvagn KRV",
|
||||
"Chassis1_S32_Bofors_Tornvagn": "Bofors Tornvagn",
|
||||
"Chassis1_S32_Bofors_Tornvagn_short": "Tornvagn",
|
||||
"Chassis2_Ch16_WZ_131": "WZ-131 model 2",
|
||||
"Chassis2_Ch16_WZ_131_short": "WZ-131 model 2",
|
||||
"Chassis2_Ch17_WZ131_1_WZ132": "WZ-132",
|
||||
"Chassis2_Ch17_WZ131_1_WZ132_short": "WZ-132",
|
||||
"Chassis2_Ch28_WZ_132A": "WZ-132B",
|
||||
"Chassis2_Ch28_WZ_132A_short": "WZ-132B",
|
||||
"Chassis2_It15_Semovente_M41": "Semovente M42",
|
||||
"Chassis2_It15_Semovente_M41_short": "Semovente M42",
|
||||
"Chassis2_It16_Bassoto": "Semovente M44",
|
||||
"Chassis2_It16_Bassoto_short": "Semovente M44",
|
||||
"Chassis2_It17_Semovente_mod_56": "CC mod. 57",
|
||||
"Chassis2_It17_Semovente_mod_56_short": "CC mod. 57",
|
||||
"Chassis2_It18_Semovente_mod_64": "CC-64 tipo B",
|
||||
"Chassis2_It18_Semovente_mod_64_short": "CC-64 tipo B",
|
||||
"Chassis2_It19_Controcarro_1MK2_Ciclope": "Controcarro 1 Mk. 2 tipo B",
|
||||
"Chassis2_It19_Controcarro_1MK2_Ciclope_short": "CC 1 Mk. 2 tipo B",
|
||||
"Chi_Ha": "Type 97 Chi-Ha",
|
||||
"Chi_Ha_short": "Chi-Ha",
|
||||
"Chi_He": "Type 1 Chi-He",
|
||||
@@ -4866,16 +5177,20 @@
|
||||
"Continental_AOI-628-2": "Continental AOI-628-2",
|
||||
"Continental_AOI-628-2A": "Continental AOI-628-2A",
|
||||
"Continental_AOI-628-2_short": "Continental\\nAOI-628-2",
|
||||
"Continental_AOI_1490": "Continental AOI-1490",
|
||||
"Continental_AOI_1490M": "Continental AOI-1490-M",
|
||||
"Continental_AOI_1490_1": "Continental AOI-1490-1",
|
||||
"Continental_AOS-895-1": "Continental AOS-895-1",
|
||||
"Continental_AOS-895-1_short": "Continental\\nAOS-895-1",
|
||||
"Continental_AOS-895-3": "AN/GRC-8",
|
||||
"Continental_AOS-895-3M": "Continental AOS-895-3M",
|
||||
"Continental_AOS-895-3V2": "Continental AOS-895-3-2",
|
||||
"Continental_AOS-895-3_short": "AN/GRC-8",
|
||||
"Continental_AOSI-1195-1": "Continental AOSI 1195-1",
|
||||
"Continental_AOSI-1195-1A": "Continental AOSI-1195-1A",
|
||||
"Continental_AOSI-1195-5": "Continental AOSI-1195-5",
|
||||
"Continental_AOSI-895-5": "Continental AOSI-895-5",
|
||||
"Continental_AOSI-895-5FR": "Continental AOSI-895-5",
|
||||
"Continental_AOSI-895-5_short": "Continental\\nAOSI-895-5",
|
||||
"Continental_AOSI_1195_5A": "Continental AOSI-1195-5 Y IV",
|
||||
"Continental_AOSI_895_5_Prem": "Continental AOSI-895-5",
|
||||
@@ -4956,6 +5271,8 @@
|
||||
"Cz15_Skoda_T-45_Custom": "Škoda T 45 Skvělý",
|
||||
"Cz15_Skoda_T-45_Custom_short": "Škoda T 45 Skvělý",
|
||||
"Cz15_Skoda_T-45_short": "Škoda T 45",
|
||||
"Cz17_Vz_55": "Vz. 55",
|
||||
"Cz17_Vz_55_short": "Vz. 55",
|
||||
"D-744": "D-744",
|
||||
"D1": "D1",
|
||||
"D1_short": "D1",
|
||||
@@ -5006,21 +5323,28 @@
|
||||
"E50_Ausf_M_Custom": "E 50 M Roaring",
|
||||
"E50_Ausf_M_Custom_short": "E 50 M Roaring",
|
||||
"E50_Ausf_M_Custom_short_v2": "E 50 M Monster",
|
||||
"E50_Ausf_M_Custom_short_v3": "E 50 M Monster Evo.",
|
||||
"E50_Ausf_M_Custom_v2": "E 50 Ausf. M Monster",
|
||||
"E50_Ausf_M_Custom_v3": "E 50 M Monster Evo.",
|
||||
"E50_Ausf_M_short": "E 50 M",
|
||||
"ELC_AMX": "AMX ELC bis",
|
||||
"ELC_AMX_short": "AMX ELC bis",
|
||||
"E_9": "E-9",
|
||||
"Engine_1_test": "#germany_vehicles:Engine_1_test",
|
||||
"Engine_1_test_short": "#germany_vehicles:Engine_1_test_short",
|
||||
"F01_Vickers_MkF": "Vickers Mk. F",
|
||||
"F01_Vickers_MkF_short": "Vickers Mk. F",
|
||||
"F113_PzV_FR": "Bretagne Panther",
|
||||
"F113_PzV_FR_short": "Bretagne Panther",
|
||||
"F114_Projet_4_1": "Char Futur 4",
|
||||
"F114_Projet_4_1_short": "Char Futur 4",
|
||||
"F116_Bat_Chat_Bourrasque": "Bat.-Châtillon Bourrasque",
|
||||
"F116_Bat_Chat_Bourrasque_Custom": "Bourrasque Noir",
|
||||
"F116_Bat_Chat_Bourrasque_Custom_short": "Bourrasque Noir",
|
||||
"F116_Bat_Chat_Bourrasque_short": "B-C Bourrasque",
|
||||
"F117_Alt_Proto_AMX_30": "AltProto AMX 30",
|
||||
"F117_Alt_Proto_AMX_30_Custom": "A.P. AMX 30 Disruptor",
|
||||
"F117_Alt_Proto_AMX_30_Custom_short": "A.P. AMX 30 Disruptor",
|
||||
"F117_Alt_Proto_AMX_30_short": "A.P. AMX 30",
|
||||
"F19_Lorraine40t": "Lorraine 40 t",
|
||||
"F19_Lorraine40t_Com": "Lorraine 40 t Fearless",
|
||||
@@ -5078,6 +5402,7 @@
|
||||
"Ferdinandstandardketten": "Ferdinand",
|
||||
"Ferdinandturm": "Ferdinand",
|
||||
"Ferdinandvetstaerktketten": "Elefant",
|
||||
"Fiat_V10": "Fiat V-10",
|
||||
"Firefly_GuP": "Firefly Saunders SP",
|
||||
"Firefly_GuP_short": "Firefly Saunders SP",
|
||||
"First_april": "#other_vehicles:First_april",
|
||||
@@ -5107,6 +5432,8 @@
|
||||
"G100_Gtraktor_Krupp": "Großtraktor - Krupp",
|
||||
"G100_Gtraktor_Krupp_short": "Großtraktor",
|
||||
"G103_RU_251": "Spähpanzer Ru 251",
|
||||
"G103_RU_251_Custom": "Ru 251 Breakneck",
|
||||
"G103_RU_251_Custom_short": "Ru 251 Breakneck",
|
||||
"G103_RU_251_short": "Ru 251",
|
||||
"G106_PzKpfwPanther_AusfF": "Panther mit 8,8 cm L/71",
|
||||
"G106_PzKpfwPanther_AusfF_short": "Panther 8,8",
|
||||
@@ -5138,11 +5465,15 @@
|
||||
"G121_Grille_15_L63": "Grille 15",
|
||||
"G121_Grille_15_L63_Custom": "Grille 15 RA1DER",
|
||||
"G121_Grille_15_L63_Custom_short": "Grille 15 RA1DER",
|
||||
"G121_Grille_15_L63_Custom_short_v3": "Grille 15 Förster",
|
||||
"G121_Grille_15_L63_Custom_v3": "Grille 15 Förster",
|
||||
"G121_Grille_15_L63_short": "Grille 15",
|
||||
"G136_Tiger_131": "Tiger 131",
|
||||
"G136_Tiger_131_short": "Tiger 131",
|
||||
"G138_VK16801P": "VK 168.01 (P)",
|
||||
"G138_VK16801P_short": "VK 168.01 (P)",
|
||||
"G140_HWK_30": "HWK 30",
|
||||
"G140_HWK_30_short": "HWK 30",
|
||||
"G142_M48RPz": "M48A2 Räumpanzer",
|
||||
"G142_M48RPz_Custom": "Räumpanzer Rhino",
|
||||
"G142_M48RPz_Custom_short": "Räumpanzer Rhino",
|
||||
@@ -5150,6 +5481,8 @@
|
||||
"G144_Kpz_50t": "Kampfpanzer 50 t",
|
||||
"G144_Kpz_50t_Custom": "Kpz 50 t König",
|
||||
"G144_Kpz_50t_Custom_short": "Kpz 50 t König",
|
||||
"G144_Kpz_50t_Custom_short_v2": "Kpz 50 t Jäger",
|
||||
"G144_Kpz_50t_Custom_v2": "Kpz 50 t Jäger",
|
||||
"G144_Kpz_50t_short": "Kpz 50 t",
|
||||
"G147_mPanzer_64": "Kunze Panzer",
|
||||
"G147_mPanzer_64_Custom": "Kunze Pz. Daredevil",
|
||||
@@ -5347,12 +5680,15 @@
|
||||
"GMC_Allison_V1710-E32_short": "GMC Allison\\nV1710-E32",
|
||||
"GMS-6046B": "GMS 6046B",
|
||||
"GM_6-71_M": "GM 6062 6-71M",
|
||||
"GM_DIESEL_P_V2": "GM Diesel P V2",
|
||||
"GM_X-11": "GM X-11",
|
||||
"GM_X-12": "GM X-12",
|
||||
"GTD": "GTD",
|
||||
"GT_101": "GT 101",
|
||||
"G_E": "G.W. E 100",
|
||||
"G_E-75RT": "Keiler",
|
||||
"G_E-75RT_Custom": "Keiler Exterminator",
|
||||
"G_E-75RT_Custom_short": "Keiler Exterminator",
|
||||
"G_E-75RT_short": "Keiler",
|
||||
"G_E-75TS": "E 75 TS",
|
||||
"G_E-75TS_short": "E 75 TS",
|
||||
@@ -5459,6 +5795,8 @@
|
||||
"IS_4_Custom_short": "IS-4 Skilled",
|
||||
"IS_6_Custom": "IS-6 Legend",
|
||||
"IS_6_Custom_short": "IS-6 Legend",
|
||||
"IS_Custom": "IS Steppe",
|
||||
"IS_Custom_short": "IS Steppe",
|
||||
"Indien_Panzer": "Indien-Panzer",
|
||||
"Indien_Panzer_short": "Indien-Pz.",
|
||||
"It08_Progetto_M40_mod65": "Progetto M40 mod. 65",
|
||||
@@ -5485,12 +5823,28 @@
|
||||
"It14_P44_Pantera_Custom": "P.44 Pantera Furious",
|
||||
"It14_P44_Pantera_Custom_short": "P.44 Pantera Furious",
|
||||
"It14_P44_Pantera_short": "P.44 Pantera",
|
||||
"It15_Semovente_M41": "Semovente M41",
|
||||
"It15_Semovente_M41_short": "Semovente M41",
|
||||
"It16_Bassoto": "Semovente M43 Bassotto",
|
||||
"It16_Bassoto_short": "Bassotto",
|
||||
"It17_Semovente_mod_56": "Semovente Controcarro mod. 1956",
|
||||
"It17_Semovente_mod_56_short": "SMV CC-56",
|
||||
"It18_Semovente_mod_64": "Semovente Controcarro mod. 1964",
|
||||
"It18_Semovente_mod_64_short": "SMV CC-64",
|
||||
"It19_Controcarro_1MK2_Ciclope": "Controcarro 1 Mk. 2",
|
||||
"It19_Controcarro_1MK2_Ciclope_short": "CC 1 Mk. 2",
|
||||
"It20_Car_Comb_45t": "Carro da Combattimento 45t",
|
||||
"It20_Car_Comb_45t_Custom": "Carro 45t Glitch",
|
||||
"It20_Car_Comb_45t_Custom_short": "Carro 45t Glitch",
|
||||
"It20_Car_Comb_45t_short": "Carro 45t",
|
||||
"It21_Controcarro3_Minotauro": "Controcarro 3 Minotauro",
|
||||
"It21_Controcarro3_Minotauro_Custom": "Minotauro Moderno",
|
||||
"It21_Controcarro3_Minotauro_Custom_short": "Minotauro Moderno",
|
||||
"It21_Controcarro3_Minotauro_short": "Minotauro",
|
||||
"It22_Progetto_C45_mod_71": "Bisonte C45",
|
||||
"It22_Progetto_C45_mod_71_Custom": "Bisonte Unbreakable",
|
||||
"It22_Progetto_C45_mod_71_Custom_short": "Bisonte Unbreakable",
|
||||
"It22_Progetto_C45_mod_71_short": "Bisonte C45",
|
||||
"J12_Shinobi": "Shinobi",
|
||||
"J12_Shinobi_short": "Shinobi",
|
||||
"J20_Ho_Ri_type3": "Ho-Ri Type III",
|
||||
@@ -5572,6 +5926,8 @@
|
||||
"KV1": "KV-1",
|
||||
"KV1S_mod_42": "KV-1S mod. 1942",
|
||||
"KV1S_mod_43": "KV-85",
|
||||
"KV1_Custom": "KV-1 Ghost",
|
||||
"KV1_Custom_short": "KV-1 Ghost",
|
||||
"KV1s_bear": "KV-1S Football",
|
||||
"KV1s_bear_short": "KV-1S Football",
|
||||
"KV2": "KV-2",
|
||||
@@ -5607,6 +5963,8 @@
|
||||
"Leopard1": "Leopard 1",
|
||||
"Leopard1_Custom": "Leopard 1 Wild",
|
||||
"Leopard1_Custom_short": "Leopard 1 Wild",
|
||||
"Leopard1_Custom_short_v2": "Leopard 1 Irbis",
|
||||
"Leopard1_Custom_v2": "Leopard 1 Irbis",
|
||||
"Leopard1_short": "Leopard 1",
|
||||
"Leopardketten_Ausf_A": "VK 16.02 Leopard",
|
||||
"Leopardketten_Ausf_B": "VK 16.02 Leopard verstärkteketten",
|
||||
@@ -5618,7 +5976,9 @@
|
||||
"Licoming_0-435t": "Lycoming O-435T",
|
||||
"Lowe": "Löwe",
|
||||
"Lowe_Custom": "Löwe Reliant",
|
||||
"Lowe_Custom_2": "Löwe Colossus",
|
||||
"Lowe_Custom_short": "Löwe Reliant",
|
||||
"Lowe_Custom_short_2": "Löwe Colossus",
|
||||
"Ltraktor": "Leichttraktor",
|
||||
"Ltraktor_short": "L.Tr.",
|
||||
"Luchsketten_Ausf_A": "Luchs",
|
||||
@@ -5644,9 +6004,13 @@
|
||||
"M-5-Y_short": "M-V-Yoh",
|
||||
"M-50T": "M-50T",
|
||||
"M-50TD": "M-50TD",
|
||||
"M-50TV2": "M-50TV2",
|
||||
"M-50TV2K": "M-50TV2K",
|
||||
"M-6-Y": "M-VI-Yoh",
|
||||
"M-6-Y_Custom": "M-VI-Yoh Pride",
|
||||
"M-6-Y_Custom_short": "M-VI-Yoh Pride",
|
||||
"M-6-Y_Custom_short_v2": "M-VI-Yoh Ankylosaurus",
|
||||
"M-6-Y_Custom_v2": "M-VI-Yoh Ankylosaurus",
|
||||
"M-6-Y_short": "M-VI-Yoh",
|
||||
"M-7-Y": "M-VII-Yoh",
|
||||
"M-7-Y_short": "M-VII-Yoh",
|
||||
@@ -5665,6 +6029,10 @@
|
||||
"M22_Locust_short": "Locust",
|
||||
"M24A1": "M24A1",
|
||||
"M24_Chaffee": "M24 Chaffee",
|
||||
"M24_Chaffee_BP": "Frosty",
|
||||
"M24_Chaffee_BP_Custom": "Frosty Jinglebell",
|
||||
"M24_Chaffee_BP_Custom_short": "Frosty Jinglebell",
|
||||
"M24_Chaffee_BP_short": "Frosty",
|
||||
"M24_Chaffee_short": "Chaffee",
|
||||
"M2D27810": "M2D27810",
|
||||
"M2D27812": "M2D27812",
|
||||
@@ -5727,6 +6095,10 @@
|
||||
"M6D2": "M6D2",
|
||||
"M6E2BP": "Magnus",
|
||||
"M6E2BP_short": "Magnus",
|
||||
"M6E2V2_BP": "Cyborg",
|
||||
"M6E2V2_BP_Custom": "Cyborg T-800",
|
||||
"M6E2V2_BP_Custom_short": "Cyborg T-800",
|
||||
"M6E2V2_BP_short": "Cyborg",
|
||||
"M7": "M5A1",
|
||||
"M7D1": "M7D1",
|
||||
"M7_Priest": "M7 Priest",
|
||||
@@ -5743,6 +6115,7 @@
|
||||
"MB-837-Ea-600": "MB 837 Ea 600",
|
||||
"MB-837A": "MTU MB 837 A",
|
||||
"MB-837A_short": "MB 837 A",
|
||||
"MB-837M": "MB 837 M",
|
||||
"MB-838_CAM-500": "MTU MB 838 CaM 500",
|
||||
"MB-838_CAM-500_1": "MTU MB 838 CaM 500A",
|
||||
"MB-838_CAM-500_1_short": "MB 838 CaM 500A",
|
||||
@@ -5765,6 +6138,10 @@
|
||||
"MTLS-1G14": "MTLS-1G14",
|
||||
"MTLS_D1": "MTLS D1",
|
||||
"MTLS_T1": "MTLS T1",
|
||||
"MTU_870": "MTU 870",
|
||||
"MTU_870M": "MTU 870M",
|
||||
"MTU_970": "MTU 970",
|
||||
"MTU_970M": "MTU 970M",
|
||||
"MTU_MB-838_Ca_M-500": "MTU MB 838 CaM 500B",
|
||||
"MT_50_T": "MT-50T",
|
||||
"M_40": "M-40",
|
||||
@@ -5806,6 +6183,7 @@
|
||||
"Maybach_HL_120_TRM_BT": "Maybach HL 120 TRM",
|
||||
"Maybach_HL_120_TRM_C": "Maybach HL 120 TRM V12",
|
||||
"Maybach_HL_120_TRM_R": "Maybach HL 120 TRM R",
|
||||
"Maybach_HL_120_TRM_RBP": "Maybach HL 120 TRM R",
|
||||
"Maybach_HL_120_TR_A": "Maybach HL 120 TRM 112",
|
||||
"Maybach_HL_120_TR_R": "Maybach HL 120 TR R",
|
||||
"Maybach_HL_120_WH": "Dark Soul",
|
||||
@@ -5827,6 +6205,7 @@
|
||||
"Maybach_HL_210_TRM_P30": "Maybach HL 210 TRM P30",
|
||||
"Maybach_HL_210_TRM_P30_A": "Maybach HL 210 TRM P30",
|
||||
"Maybach_HL_210_TRM_P30_short": "Maybach\\nHL 210 TRM P30",
|
||||
"Maybach_HL_210_TRM_P30v2": "Maybach HL 210 TRM P30 V2",
|
||||
"Maybach_HL_210_TRM_P45": "Maybach HL 210 TRM P45",
|
||||
"Maybach_HL_210_TRM_P45TU": "Maybach HL 210 TRM P45",
|
||||
"Maybach_HL_210_TRM_P45_BP": "Maybach HL 210 TRM P45 B",
|
||||
@@ -5841,8 +6220,10 @@
|
||||
"Maybach_HL_230P45_short": "Maybach HL 230\\nP45F",
|
||||
"Maybach_HL_230_F": "Maybach HL 230 F",
|
||||
"Maybach_HL_230_TRM_P30": "Maybach HL 230 TRM P30 pl.",
|
||||
"Maybach_HL_230_TRM_P30V2": "Maybach HL 230 TRM P30 V2",
|
||||
"Maybach_HL_230_TRM_P30_FR": "Maybach HL 230 TRM P30 fr.",
|
||||
"Maybach_HL_230_TRM_P30_short": "Maybach\\nHL 230 TRM P30",
|
||||
"Maybach_HL_230_TRM_P30v3": "Maybach HL 230 TRM P30 V3",
|
||||
"Maybach_HL_230_TRM_P45": "Maybach HL 230 TRM P45",
|
||||
"Maybach_HL_230_TRM_P45A": "Maybach HL 230 TRM P45 A",
|
||||
"Maybach_HL_230_TRM_P45_short": "Maybach HL 230\\nTRM P45",
|
||||
@@ -5892,6 +6273,10 @@
|
||||
"NVSS_T66": "HVSS T66",
|
||||
"NVSS_T80": "HVSS T80",
|
||||
"Nashorn": "Nashorn",
|
||||
"Nashorn_BP": "Epsilon",
|
||||
"Nashorn_BP_Custom": "Epsilon Sagittarius",
|
||||
"Nashorn_BP_Custom_short": "Epsilon Sagittarius",
|
||||
"Nashorn_BP_short": "Epsilon",
|
||||
"Nashorn_short": "Nashorn",
|
||||
"Nuffield_liberty_MKII": "Nuffield Liberty Mk. II",
|
||||
"Nuffield_liberty_MKIV": "Nuffield Liberty Mk. III",
|
||||
@@ -5946,7 +6331,6 @@
|
||||
"Oe_mle._1932A": "HE Shell",
|
||||
"Ordnance_QF_2pdr_AT_Gun_Mk.X": "QF Mk. IX",
|
||||
"Ordnance_QF_2pdr_AT_Gun_Mk.X_short": "QF Mk. IX",
|
||||
"Oth06_Sega_Lupus": "Lupus",
|
||||
"Oth08_WH_Vindicator": "Vindicator Ultramarines",
|
||||
"Oth08_WH_Vindicator_Dark_Angels_Custom": "Vindicator Dark Angels",
|
||||
"Oth08_WH_Vindicator_Dark_Angels_Custom_short": "Vindicator DA",
|
||||
@@ -6201,6 +6585,8 @@
|
||||
"PzVI_Porsche_Turm_short": "Pz.Kpfw. Tiger\\nAusf. E",
|
||||
"PzVI_Standardketten": "Pz.Kpfw. VI H Ausf. H1",
|
||||
"PzVI_Tiger_P": "Tiger (P)",
|
||||
"PzVI_Tiger_P_Custom": "Tiger (P) Sandsturm",
|
||||
"PzVI_Tiger_P_Custom_short": "Tiger (P) Sandsturm",
|
||||
"PzVI_Tiger_P_short": "Tiger (P)",
|
||||
"PzVI_Vetstaerktketten": "Pz.Kpfw. Tiger Ausf. E",
|
||||
"PzVI_skin_gamescom": "Tiger I Gamescom",
|
||||
@@ -6267,6 +6653,8 @@
|
||||
"R115_IS-3_auto": "IS-3 Defender",
|
||||
"R115_IS-3_auto_short": "IS-3 Defender",
|
||||
"R116_ISU122C_Berlin": "ISU-122S",
|
||||
"R119_Object_777": "Object 777 Version II",
|
||||
"R119_Object_777_short": "Obj. 777 II",
|
||||
"R120_T22SR": "T-22 medium",
|
||||
"R120_T22SR_Custom": "T-22 Uncatchable",
|
||||
"R120_T22SR_Custom_short": "T-22 Uncatchable",
|
||||
@@ -6290,6 +6678,8 @@
|
||||
"R146_STG_Custom_short": "STG Guard",
|
||||
"R146_STG_short": "STG",
|
||||
"R149_Object_268_4": "Object 268 Version 4",
|
||||
"R149_Object_268_4_Custom": "Object 268/4 Chronos",
|
||||
"R149_Object_268_4_Custom_short": "Object 268/4 Chronos",
|
||||
"R149_Object_268_4_short": "Object 268/4",
|
||||
"R154_T-34E-43": "T-34 shielded",
|
||||
"R154_T-34E-43_short": "T-34 shielded",
|
||||
@@ -6313,6 +6703,8 @@
|
||||
"R180_Object_274A_Custom": "Object 274a Leshy",
|
||||
"R180_Object_274A_Custom_short": "Object 274a Leshy",
|
||||
"R180_Object_274A_short": "Object 274a",
|
||||
"R181_Object_452K": "Object 452K",
|
||||
"R181_Object_452K_short": "Object 452K",
|
||||
"R43_T-70_57": "T-70/57",
|
||||
"R43_T-70_57_short": "T-70/57",
|
||||
"R63_ST_IBD": "T-2020",
|
||||
@@ -6357,6 +6749,8 @@
|
||||
"Renault_T14": "Renault T14",
|
||||
"Renault_V4": "Renault V4",
|
||||
"RhB_Waffentrager": "Rhm.-Borsig Waffenträger",
|
||||
"RhB_Waffentrager_Custom": "Rhm.-B. WT Tarnkappe",
|
||||
"RhB_Waffentrager_Custom_short": "Rhm.-B. WT Tarnkappe",
|
||||
"RhB_Waffentrager_short": "Rhm.-B. WT",
|
||||
"Rolls_Royce_Griffon": "Rolls-Royce Griffon",
|
||||
"Rolls_Royce_Griffon-Mk2": "Rolls-Royce Griffon A",
|
||||
@@ -6416,7 +6810,13 @@
|
||||
"S26_Lancen_C_Custom_short": "Lansen Moose",
|
||||
"S26_Lancen_C_short": "Lansen C",
|
||||
"S31_Strv_K": "Strv K",
|
||||
"S31_Strv_K_Custom": "Strv K Konung",
|
||||
"S31_Strv_K_Custom_short": "Strv K Konung",
|
||||
"S31_Strv_K_short": "Strv K",
|
||||
"S32_Bofors_Tornvagn": "Bofors Tornvagn",
|
||||
"S32_Bofors_Tornvagn_Custom": "Tornvagn Stegosaurus",
|
||||
"S32_Bofors_Tornvagn_Custom_short": "Tornvagn Stegosaurus",
|
||||
"S32_Bofors_Tornvagn_short": "Tornvagn",
|
||||
"S35_captured": "Pz.Kpfw. S35 739 (f)",
|
||||
"S35_captured_short": "Pz. S35",
|
||||
"SA35_4": "SA35 mle. 4",
|
||||
@@ -6430,15 +6830,21 @@
|
||||
"SOFAM_12_58": "SOFAM 12 58",
|
||||
"SOFAM_8Gxb": "SOFAM 8 Gxb",
|
||||
"SOFAM_8Gxb_A": "SOFAM 8 Gxb",
|
||||
"SPA_15TB": "SPA 15TB",
|
||||
"SPA_17TB": "SPA 17TB",
|
||||
"SPA_242": "SPA 242",
|
||||
"SPA_343": "SPA 343",
|
||||
"SPA_344": "SPA 344",
|
||||
"SPA_mod_15": "SPA mod. 15",
|
||||
"SPA_mod_17": "SPA mod. 17",
|
||||
"STA_1": "STA-1",
|
||||
"STA_1_Rin": "STA-1 Rin",
|
||||
"STA_1_short": "STA-1",
|
||||
"ST_B1": "STB-1",
|
||||
"ST_B1_Custom": "STB-1 Adamant",
|
||||
"ST_B1_Custom_short": "STB-1 Adamant",
|
||||
"ST_B1_Custom_short_v2": "STB-1 Spinosaurus",
|
||||
"ST_B1_Custom_v2": "STB-1 Spinosaurus",
|
||||
"ST_B1_short": "STB-1",
|
||||
"ST_I": "ST-I",
|
||||
"SU-100": "SU-100",
|
||||
@@ -6452,7 +6858,7 @@
|
||||
"SU-152": "SU-152",
|
||||
"SU-152_01": "SU-152",
|
||||
"SU-152_Custom": "SU-152 Taiga",
|
||||
"SU-152_Custom_short": "SU-152 Тaiga",
|
||||
"SU-152_Custom_short": "SU-152 Taiga",
|
||||
"SU-152_mod_1943": "SU-152",
|
||||
"SU-152_mod_1944": "SU-152M",
|
||||
"SU-18": "SU-18",
|
||||
@@ -6660,6 +7066,8 @@
|
||||
"T34_hvy": "T34",
|
||||
"T34_hvy_Custom": "T34 Falcon",
|
||||
"T34_hvy_Custom_short": "T34 Falcon",
|
||||
"T34_hvy_Custom_short_v2": "T34 H-Combat",
|
||||
"T34_hvy_Custom_v2": "T34 H-Combat",
|
||||
"T34_hvy_Freedom": "T34 Independence",
|
||||
"T34_hvy_Freedom_short": "T34 (1776)",
|
||||
"T37": "T37",
|
||||
@@ -6669,6 +7077,8 @@
|
||||
"T42": "T42",
|
||||
"T48": "T48",
|
||||
"T49": "T67",
|
||||
"T49_Fearless": "T49 Fearless",
|
||||
"T49_Fearless_short": "T49 Fearless",
|
||||
"T49_Rocket": "T49 ATM",
|
||||
"T49_Rocket_short": "T49 A",
|
||||
"T51D1": "T51D1",
|
||||
@@ -6677,6 +7087,8 @@
|
||||
"T57_58": "T57 Heavy Tank",
|
||||
"T57_58_Custom": "T57 Heavy Tireless",
|
||||
"T57_58_Custom_short": "T57 Heavy Tireless",
|
||||
"T57_58_Custom_short_v2": "T57 Heavy Ammoel",
|
||||
"T57_58_Custom_v2": "T57 Heavy Ammoel",
|
||||
"T57_58_short": "T57 Heavy",
|
||||
"T62A": "T-62A",
|
||||
"T62A_Custom": "T-62A Fearless",
|
||||
@@ -6703,6 +7115,8 @@
|
||||
"T95": "T95",
|
||||
"T95E2": "T95E2",
|
||||
"T95E2_short": "T95E2",
|
||||
"T95_Custom": "T95 Turtle",
|
||||
"T95_Custom_short": "T95 Turtle",
|
||||
"T99E2": "T99E2",
|
||||
"TD-12": "TD-12",
|
||||
"TD-12S": "TD-12S",
|
||||
@@ -6773,6 +7187,7 @@
|
||||
"V-2-54IS": "V-2-54IS",
|
||||
"V-2-54IS_2": "V-2-54-IS/2",
|
||||
"V-2-54IS_GuP": "V-2-54 GuP",
|
||||
"V-2-54SC": "V-2-54SC",
|
||||
"V-2IS": "V-2IS",
|
||||
"V-2IS_B": "V-2IS",
|
||||
"V-2IS_B_2": "V-2IS-2",
|
||||
@@ -6794,6 +7209,7 @@
|
||||
"V-54-6": "V-54-6",
|
||||
"V-54I": "V-54I",
|
||||
"V-54K": "V-54K",
|
||||
"V-54KML": "V-54K-ML",
|
||||
"V-54K_TU": "V-54K",
|
||||
"V-55": "V-55",
|
||||
"V-55U": "V-14",
|
||||
@@ -6917,8 +7333,10 @@
|
||||
"W_12_5_B": "W12-5B",
|
||||
"W_12_5_P": "W12-5P",
|
||||
"Waffentrager_IV": "Waffenträger auf Pz. IV",
|
||||
"Waffentrager_IV_CL": "Waffenträger Camelot",
|
||||
"Waffentrager_IV_CL_short": "WT Camelot",
|
||||
"Waffentrager_IV_CL": "Waffenträger Ritter",
|
||||
"Waffentrager_IV_CL_short": "WT Ritter",
|
||||
"Waffentrager_IV_Custom": "WT auf Pz. IV Darkwing",
|
||||
"Waffentrager_IV_Custom_short": "WT auf Pz. IV Darkwing",
|
||||
"Waffentrager_IV_short": "WT auf Pz. IV",
|
||||
"Waterspit_1": "Waterspit",
|
||||
"Wespe": "Wespe",
|
||||
@@ -6927,6 +7345,7 @@
|
||||
"Wespeketten_ausf_B": "Wespe verstärkteketten",
|
||||
"Wespeturm": "Wespe",
|
||||
"Wright_Continental_R-975C1": "Wright Continental R-975C1",
|
||||
"Wright_Continental_R-975C1_BP": "Wright Continental R-975C1 B",
|
||||
"Wright_Continental_R-975C1_GuP": "Wright Continental R-975C1 GuP",
|
||||
"Wright_Continental_R-975C1_short": "Wright C. R-975C1",
|
||||
"Wright_Continental_R-975C2": "Wright Continental R-975C2",
|
||||
@@ -6940,6 +7359,7 @@
|
||||
"Wright_Continental_R-975EC2_short": "Wright C. R-975EC2",
|
||||
"Wright_Continental_R_975_C4_858": "Wright Continental\\nR-975-C4 (858)",
|
||||
"Wright_G200_m_781C9GC1": "Wright G200 M781C9GC1",
|
||||
"Wright_G200_m_781C9GC1V2_BP": "Wright G200 M781C9GC1",
|
||||
"Wright_G200_m_781C9GC5": "Wright G200 M781C9GC5",
|
||||
"Wright_G200_m_781C9GC5_short": "Wright G200\\nM781C9GC5",
|
||||
"Wright_G200_m_795C9GC1": "Wright G200 M795C9GC1",
|
||||
|
||||
Reference in new issue
Block a user