mirror of
https://github.com/Jylpah/blitz-tools.git
synced 2026-10-21 02:07:06 +02:00
Merge pull request #16 from Jylpah/stable-tank_wr
tank WR as player performance measure, improved help
This commit is contained in:
2 files changed
+157
-12
No files matched your search
+155
-10
@@ -33,6 +33,7 @@ RE_SRC_IS_DB = re.compile(r'^DB:')
|
||||
# 1st function = for forming stat_id, 2nd for DB stats query, 3rd for WG API stats query
|
||||
STAT_FUNC = {
|
||||
'tank_tier': [ 'get_stat_id_tank_tier', 'get_db_tank_tier_stats', 'get_wg_tank_tier_stats' ],
|
||||
'tank': [ 'get_stat_id_tank', 'get_db_tank_stats', 'get_wg_tank_stats' ],
|
||||
'player': [ 'get_stat_id_player', 'get_db_player_stats', 'get_wg_player_stats' ]
|
||||
}
|
||||
|
||||
@@ -125,15 +126,15 @@ class BattleCategorizationList():
|
||||
_categorizations = {
|
||||
'total' : [ 'TOTAL', 'total' ],
|
||||
'battle_result' : [ 'Result', 'category', [ 'Loss', 'Win', 'Draw']],
|
||||
'battle_type' : [ 'Battle Type', 'category', ['Encounter', 'Supremacy']],
|
||||
'battle_type' : [ 'Battle Type', 'category', [ 'Encounter', 'Supremacy']],
|
||||
'tank_tier' : [ 'Tank Tier', 'number' ],
|
||||
'top_tier' : [ 'Tier', 'category', ['Bottom tier', 'Top tier']],
|
||||
'top_tier' : [ 'Tier', 'category', [ 'Bottom tier', 'Top tier']],
|
||||
'room_type' : [ 'Battle Mode', 'category', _BATTLE_MODES ],
|
||||
'mastery_badge' : [ 'Battle Medal', 'category', ['-', '3rd Class', '2nd Class', '1st Class', 'Mastery' ]],
|
||||
'team_result' : [ 'Team Result', 'string' ],
|
||||
'player_wins' : [ 'Player WR', 'bucket', [ 0, .35, .45, .50, .55, .65], '%' ],
|
||||
'player_battles' : [ 'Player Battles', 'bucket', [ 0, 500, 1000, 2500, 5e3, 10e3, 15e3, 25e3], 'int' ],
|
||||
'player_damage_dealt' : [ 'Player Avg Dmg', 'bucket', [ 0, 500, 1000, 1250, 1500, 1750, 2000, 2500], 'int' ],
|
||||
'player_battles' : [ 'Player Battles','bucket', [ 0, 500, 1000, 2500, 5e3, 10e3, 15e3, 25e3], 'int' ],
|
||||
'player_damage_dealt' : [ 'Player Avg Dmg','bucket', [ 0, 500, 1000, 1250, 1500, 1750, 2000, 2500], 'int' ],
|
||||
'map_name' : [ 'Map', 'string' ],
|
||||
'tank_name' : [ 'Tank', 'string' ],
|
||||
'player_name' : [ 'Player', 'string' ],
|
||||
@@ -206,7 +207,35 @@ class BattleCategorizationList():
|
||||
except Exception as err:
|
||||
bu.error(exception=err)
|
||||
return None
|
||||
|
||||
|
||||
|
||||
@classmethod
|
||||
def help(cls):
|
||||
for cat in cls.get_categorizations_all():
|
||||
try:
|
||||
ctitle = cls.get_categorization_title(cat)
|
||||
ctype = cls.get_categorization_type(cat)
|
||||
cparams = cls.get_categorization_params(cat)
|
||||
|
||||
if ctype == 'number':
|
||||
cat_tmp = BattleNumberCategorization(cat, ctitle)
|
||||
elif ctype == 'string':
|
||||
cat_tmp = BattleStringCategorization(cat, ctitle)
|
||||
elif ctype == 'category':
|
||||
cat_tmp = BattleClassCategorization(cat, ctitle, cparams[0])
|
||||
elif ctype == 'bucket':
|
||||
cat_tmp = BattleBucketCategorization(cat, ctitle, cparams[0], cparams[1])
|
||||
else:
|
||||
cat_tmp = BattleTotals(ctitle)
|
||||
|
||||
cat_tmp.help()
|
||||
|
||||
except KeyError as err:
|
||||
bu.error('BattleCategorizationList(): Key not found: Category: ' + cat, exception=err)
|
||||
except Exception as err:
|
||||
bu.error('BattleCategorizationList()', exception=err)
|
||||
|
||||
|
||||
|
||||
def __init__(self, args : argparse.Namespace):
|
||||
self.urls = collections.OrderedDict()
|
||||
@@ -328,6 +357,12 @@ class BattleCategorization():
|
||||
"""Get category. Must be implemented in the child classes"""
|
||||
return 'NONE'
|
||||
|
||||
|
||||
def help(self):
|
||||
"""Help"""
|
||||
FORMAT = '\t{:<15s}\t{}. Options:'
|
||||
print(FORMAT.format(self.category_key, self.title), end=' ')
|
||||
|
||||
|
||||
def record_result(self, result: dict):
|
||||
try:
|
||||
@@ -392,6 +427,10 @@ class BattleTotals(BattleCategorization):
|
||||
def get_categories(self) -> str:
|
||||
return [ self.TOTAL ]
|
||||
|
||||
def help(self):
|
||||
super().help()
|
||||
print('-')
|
||||
|
||||
|
||||
class BattleClassCategorization(BattleCategorization):
|
||||
"""Class for categorization by fixed classes with ID (int)"""
|
||||
@@ -401,6 +440,14 @@ class BattleClassCategorization(BattleCategorization):
|
||||
self.category_labels = classes
|
||||
|
||||
|
||||
def help(self):
|
||||
super().help()
|
||||
labels = list()
|
||||
for ndx in range(0, len(self.category_labels)):
|
||||
labels.append(str(ndx) + '=' + self.category_labels[ndx])
|
||||
print(', '.join(labels))
|
||||
|
||||
|
||||
def get_category(self, result: dict) -> str:
|
||||
"""Get category"""
|
||||
cat_id = -1
|
||||
@@ -441,6 +488,11 @@ class BattleStringCategorization(BattleCategorization):
|
||||
bu.error('Category: ' + self.category_key, exception=err)
|
||||
return None
|
||||
|
||||
|
||||
def help(self):
|
||||
super().help()
|
||||
print(self.title + ' name')
|
||||
|
||||
|
||||
class BattleNumberCategorization(BattleCategorization):
|
||||
"""Class for categorization by number"""
|
||||
@@ -465,6 +517,11 @@ class BattleNumberCategorization(BattleCategorization):
|
||||
return None
|
||||
|
||||
|
||||
def help(self):
|
||||
super().help()
|
||||
print('INTEGER')
|
||||
|
||||
|
||||
class BattleBucketCategorization(BattleCategorization):
|
||||
"""Class for categorization by buckets based on value"""
|
||||
|
||||
@@ -477,6 +534,14 @@ class BattleBucketCategorization(BattleCategorization):
|
||||
except Exception as err:
|
||||
bu.error('BattleBucketCategorization()', exception=err)
|
||||
|
||||
|
||||
def help(self):
|
||||
super().help()
|
||||
labels = list()
|
||||
for ndx in range(0, len(self.category_labels)):
|
||||
labels.append(str(ndx) + '=' + self.category_labels[ndx])
|
||||
print(', '.join(labels))
|
||||
|
||||
def get_category(self, result: dict) -> str:
|
||||
"""Get category"""
|
||||
cat_id = -1
|
||||
@@ -1126,7 +1191,7 @@ async def help_extended(db : motor.motor_asyncio.AsyncIOMotorDatabase = None, pa
|
||||
|
||||
# Filter usage
|
||||
print('\n-------------------------------------------------------------------')
|
||||
print('| Filter usage |')
|
||||
print('| DB Filter usage |')
|
||||
print('-------------------------------------------------------------------')
|
||||
|
||||
print("Syntax: --filters '{ \"replay.param\": VALUE, \"replay.param2\": { \"$MONGO_OPERATOR\" : VALUE }, ... }'")
|
||||
@@ -1145,6 +1210,12 @@ async def help_extended(db : motor.motor_asyncio.AsyncIOMotorDatabase = None, pa
|
||||
except Exception as err:
|
||||
bu.error(exception=err)
|
||||
|
||||
print('\n-------------------------------------------------------------------')
|
||||
print('| Filter usage |')
|
||||
print('-------------------------------------------------------------------')
|
||||
BattleCategorizationList.help()
|
||||
|
||||
|
||||
## move the class PlayerHistogram?
|
||||
def set_histogram_buckets(json: dict):
|
||||
global histogram_fields
|
||||
@@ -1421,8 +1492,10 @@ async def stat_worker(queue : asyncio.Queue, workerID: int, args : argparse.Name
|
||||
# no DB stats found, trying WG AP
|
||||
if (stats[stat_id] == None):
|
||||
stats[pruned_stat_id] = await stat_wg_func(pruned_stat_id)
|
||||
stat_id_remap[stat_id] = pruned_stat_id
|
||||
stat_id_remap[stat_id] = pruned_stat_id
|
||||
del stats[stat_id]
|
||||
bu.debug('get_wg_' + args.stat_func + '_stats returned: account_id=' + str(get_account_id_f_stat_id(pruned_stat_id)) + ': ' + str(stats[pruned_stat_id]), workerID)
|
||||
|
||||
|
||||
except KeyError as err:
|
||||
bu.error('Key not found', err, id=workerID)
|
||||
@@ -1448,6 +1521,65 @@ async def stat_worker(queue : asyncio.Queue, workerID: int, args : argparse.Name
|
||||
# bu.debug('Returning stats & exiting')
|
||||
return (stats, stat_id_remap)
|
||||
|
||||
|
||||
## player stat functions: tank
|
||||
async def get_wg_tank_stats(stat_id_str: str, cache_only = False) -> dict:
|
||||
"""Get player stats from WG. Returns WR per tier of tank_id"""
|
||||
try:
|
||||
(account_id, tank_id) = str2ints(stat_id_str)
|
||||
|
||||
# 'battles' must always be there
|
||||
hist_stats = [ 'all.' + x for x in histogram_fields.keys() ]
|
||||
hist_stats.append('tank_id')
|
||||
|
||||
player_stats = await wg.get_player_tank_stats(account_id, [ tank_id ], hist_stats, cache_only = cache_only)
|
||||
#bu.debug('account_id: ' + str(account_id) + ' ' + str(player_stats))
|
||||
|
||||
return await tank_stats_helper(player_stats)
|
||||
|
||||
except KeyError as err:
|
||||
bu.error('account_id: ' + str(account_id) + ' tank_id:' + str(tank_id) +' : Key not found', err)
|
||||
except Exception as err:
|
||||
bu.error(exception=err)
|
||||
return None
|
||||
|
||||
|
||||
async def get_db_tank_stats(db : motor.motor_asyncio.AsyncIOMotorDatabase, stat_id_str: str) -> dict:
|
||||
"""Get player stats from MongoDB (you are very unlikely to have it, unless you have set it up)"""
|
||||
if db == None:
|
||||
return None
|
||||
try:
|
||||
dbc = db[DB_C_TANK_STATS]
|
||||
( account_id, tank_id, battletime ) = str2ints(stat_id_str)
|
||||
time_buffer = 2*7*24*3600
|
||||
|
||||
hist_stats = [ 'all.' + x for x in histogram_fields.keys() ]
|
||||
hist_stats.append('tank_id')
|
||||
hist_stats.append('account_id')
|
||||
hist_stats.append('last_battle_time')
|
||||
project = dict()
|
||||
for stat in hist_stats:
|
||||
project[stat] = True
|
||||
project['_id'] = False
|
||||
|
||||
cursor = dbc.find({ '$and': [ { 'account_id': account_id }, { 'last_battle_time': { '$gte': battletime - time_buffer }}, { 'tank_id' : tank_id } ] }, projection=project).sort('last_battle_time',-1).limit(1)
|
||||
|
||||
# pipeline = [ { '$match': { '$and': [ { 'account_id': account_id }, { 'last_battle_time': { '$lte': battletime + time_buffer }}, { 'tank_id' : tank_id } ]}},
|
||||
# { '$sort': { 'last_battle_time': -1 }},
|
||||
# { '$group': { '_id': '$tank_id', 'doc': { '$first': '$$ROOT' }}},
|
||||
# { '$replaceRoot': { 'newRoot': '$doc' }},
|
||||
# { '$project': { '_id': 0 }} ]
|
||||
|
||||
# cursor = dbc.aggregate(pipeline, allowDiskUse=True)
|
||||
#cursor = dbc.aggregate(pipeline)
|
||||
|
||||
return await tank_stats_helper(await cursor.to_list(1))
|
||||
|
||||
except Exception as err:
|
||||
bu.error('account_id: ' + str(account_id) + ' Error', err)
|
||||
return None
|
||||
|
||||
|
||||
## player stat functions: tank_tier
|
||||
async def get_wg_tank_tier_stats(stat_id_str: str, cache_only = False) -> dict:
|
||||
"""Get player stats from WG. Returns WR per tier of tank_id"""
|
||||
@@ -1890,17 +2022,30 @@ def get_stat_id(account_id: int, tank_id: int, battletime: int) -> str:
|
||||
|
||||
|
||||
def get_stat_id_tank_tier(stat_id_str: str) -> str:
|
||||
"""Return stat_id = account_id:tank_tier"""
|
||||
"""Return stat_id = account_id:tank_tier:battletime"""
|
||||
try:
|
||||
stat_id = str2ints(stat_id_str)
|
||||
tank_tier = wg.get_tank_tier(stat_id[1])
|
||||
account_id = stat_id[0]
|
||||
tank_tier = wg.get_tank_tier(stat_id[1])
|
||||
battle_time = (stat_id[2] // BATTLE_TIME_BUCKET) * BATTLE_TIME_BUCKET
|
||||
return ':'.join(map(str, [stat_id[0],tank_tier, battle_time ]))
|
||||
return ':'.join(map(str, [account_id, tank_tier, battle_time ]))
|
||||
except Exception as err:
|
||||
bu.error('Stats_id: ' + stat_id_str, exception=err)
|
||||
return None
|
||||
|
||||
|
||||
def get_stat_id_tank(stat_id_str: str) -> str:
|
||||
"""Return stat_id = account_id:tank_id:battletime"""
|
||||
try:
|
||||
stat_id = str2ints(stat_id_str)
|
||||
account_id = stat_id[0]
|
||||
tank_id = stat_id[1]
|
||||
battle_time = (stat_id[2] // BATTLE_TIME_BUCKET) * BATTLE_TIME_BUCKET
|
||||
return ':'.join(map(str, [account_id, tank_id, battle_time ]))
|
||||
except Exception as err:
|
||||
bu.error('Stats_id: ' + stat_id_str, exception=err)
|
||||
return None
|
||||
|
||||
def get_stat_id_player(stat_id_str: str) -> str:
|
||||
"""Return stat_id = account_id:battletime"""
|
||||
try:
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
"karelia": "Rockfield",
|
||||
"karieri": "Copperfield",
|
||||
"lake": "Mirage",
|
||||
"lumber": "Horrorstadt",
|
||||
"lumber": "Alpenstadt",
|
||||
"lumber_01": "Alpenstadt - Town",
|
||||
"malinovka": "Winter Malinovka",
|
||||
"medvedkovo": "Dead Rail",
|
||||
@@ -51,4 +51,4 @@
|
||||
"skit": "Naval Frontier",
|
||||
"test": "World of Ducks",
|
||||
"tutorial": "Proving Grounds"
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user