stats.json fix with auto backup

This commit is contained in:
Ayush Saini 2022-05-08 15:27:08 +05:30
parent a2c7b303d0
commit db5782b6f1

View file

@ -1,12 +1,12 @@
damage_data = {} damage_data = {}
#Don't touch the above line # Don't touch the above line
""" """
mystats module for BombSquad version 1.5.29 mystats module for BombSquad version 1.5.29
Provides functionality for dumping player stats to disk between rounds. Provides functionality for dumping player stats to disk between rounds.
""" """
ranks=[] ranks = []
top3Name=[] top3Name = []
import threading,json,os,urllib.request,ba,_ba,setting import threading, json, os, urllib.request, ba, _ba, setting
from ba._activity import Activity from ba._activity import Activity
from ba._music import setmusic, MusicType from ba._music import setmusic, MusicType
# False-positive from pylint due to our class-generics-filter. # False-positive from pylint due to our class-generics-filter.
@ -19,10 +19,11 @@ from ba._activitytypes import *
import urllib.request import urllib.request
import custom_hooks import custom_hooks
import datetime import datetime
#variables
# variables
our_settings = setting.get_settings_data() our_settings = setting.get_settings_data()
# where our stats file and pretty html output will go # where our stats file and pretty html output will go
base_path = os.path.join(_ba.env()['python_directory_user'],"stats" + os.sep) base_path = os.path.join(_ba.env()['python_directory_user'], "stats" + os.sep)
statsfile = base_path + 'stats.json' statsfile = base_path + 'stats.json'
htmlfile = base_path + 'stats_page.html' htmlfile = base_path + 'stats_page.html'
table_style = "{width:100%;border: 3px solid black;border-spacing: 5px;border-collapse:collapse;text-align:center;background-color:#fff}" table_style = "{width:100%;border: 3px solid black;border-spacing: 5px;border-collapse:collapse;text-align:center;background-color:#fff}"
@ -46,7 +47,7 @@ html_start = f'''<!DOCTYPE html>
<th><b>Games Played</b></th> <th><b>Games Played</b></th>
</tr> </tr>
''' '''
statsDefault={ statsDefault = {
"pb-IF4VAk4a": { "pb-IF4VAk4a": {
"rank": 65, "rank": 65,
"name": "pb-IF4VAk4a", "name": "pb-IF4VAk4a",
@ -63,22 +64,28 @@ statsDefault={
} }
# <th><b>Total Damage</b></th> #removed this line as it isn't crt data # <th><b>Total Damage</b></th> #removed this line as it isn't crt data
#useful functions # useful functions
seasonStartDate=None seasonStartDate = None
import shutil,os import shutil, os
def get_all_stats(): def get_all_stats():
global seasonStartDate global seasonStartDate
if os.path.exists(statsfile): if os.path.exists(statsfile):
renameFile=False renameFile = False
with open(statsfile, 'r',encoding='utf8') as f: with open(statsfile, 'r', encoding='utf8') as f:
jsonData=json.loads(f.read())
try: try:
stats=jsonData["stats"] jsonData = json.loads(f.read())
except:
f=open(statsfile+".backup",encoding='utf-8')
jsonData=json.load(f)
try:
stats = jsonData["stats"]
seasonStartDate=datetime.datetime.strptime(jsonData["startDate"],"%d-%m-%Y") seasonStartDate = datetime.datetime.strptime(jsonData["startDate"], "%d-%m-%Y")
if (datetime.datetime.now()-seasonStartDate).days >=our_settings["statsResetAfterDays"]: if (datetime.datetime.now() - seasonStartDate).days >= our_settings["statsResetAfterDays"]:
backupStatsFile() backupStatsFile()
seasonStartDate=datetime.datetime.now() seasonStartDate = datetime.datetime.now()
return statsDefault return statsDefault
return stats return stats
except OSError as e: except OSError as e:
@ -87,30 +94,33 @@ def get_all_stats():
else: else:
return {} return {}
def backupStatsFile():
shutil.copy(statsfile,statsfile.replace(".json","")+str(seasonStartDate)+".json")
def backupStatsFile():
shutil.copy(statsfile, statsfile.replace(".json", "") + str(seasonStartDate) + ".json")
def dump_stats(s: dict): def dump_stats(s: dict):
global seasonStartDate global seasonStartDate
if seasonStartDate ==None: if seasonStartDate == None:
seasonStartDate=datetime.datetime.now() seasonStartDate = datetime.datetime.now()
s={"startDate":seasonStartDate.strftime("%d-%m-%Y") , "stats":s} s = {"startDate": seasonStartDate.strftime("%d-%m-%Y"), "stats": s}
if os.path.exists(statsfile): if os.path.exists(statsfile):
with open(statsfile, 'w',encoding='utf8') as f: shutil.copyfile(statsfile,statsfile+".backup")
f.write(json.dumps(s, indent=4,ensure_ascii=False)) with open(statsfile, 'w', encoding='utf8') as f:
f.write(json.dumps(s, indent=4, ensure_ascii=False))
f.close() f.close()
else: print('Stats file not found!') else:
print('Stats file not found!')
def get_stats_by_id(ID: str): def get_stats_by_id(ID: str):
a = get_all_stats() a = get_all_stats()
if ID in a: if ID in a:
return a[ID] return a[ID]
else: else:
return None return None
def refreshStats(): def refreshStats():
# lastly, write a pretty html version. # lastly, write a pretty html version.
# our stats url could point at something like this... # our stats url could point at something like this...
@ -120,11 +130,11 @@ def refreshStats():
entries = [(a['scores'], a['kills'], a['deaths'], a['games'], a['name'], a['aid']) for a in pStats.values()] entries = [(a['scores'], a['kills'], a['deaths'], a['games'], a['name'], a['aid']) for a in pStats.values()]
# this gives us a list of kills/names sorted high-to-low # this gives us a list of kills/names sorted high-to-low
entries.sort(key=lambda x:x[1] or 0,reverse=True) entries.sort(key=lambda x: x[1] or 0, reverse=True)
rank = 0 rank = 0
toppers = {} toppers = {}
toppersIDs=[] toppersIDs = []
_ranks=[] _ranks = []
for entry in entries: for entry in entries:
if True: if True:
rank += 1 rank += 1
@ -135,7 +145,7 @@ def refreshStats():
name = str(entry[4]) name = str(entry[4])
aid = str(entry[5]) aid = str(entry[5])
if rank < 6: toppersIDs.append(aid) if rank < 6: toppersIDs.append(aid)
#The below kd and avg_score will not be added to website's html document, it will be only added in stats.json # The below kd and avg_score will not be added to website's html document, it will be only added in stats.json
try: try:
kd = str(float(kills) / float(deaths)) kd = str(float(kills) / float(deaths))
kd_int = kd.split('.')[0] kd_int = kd.split('.')[0]
@ -153,39 +163,39 @@ def refreshStats():
if damage_data and aid in damage_data: if damage_data and aid in damage_data:
dmg = damage_data[aid] dmg = damage_data[aid]
dmg = str(str(dmg).split('.')[0] + '.' + str(dmg).split('.')[1][:3]) dmg = str(str(dmg).split('.')[0] + '.' + str(dmg).split('.')[1][:3])
else: dmg = 0 else:
dmg = 0
_ranks.append(aid) _ranks.append(aid)
pStats[str(aid)]["rank"] = int(rank) pStats[str(aid)]["rank"] = int(rank)
pStats[str(aid)]["scores"] = int(scores) pStats[str(aid)]["scores"] = int(scores)
pStats[str(aid)]["total_damage"] += float(dmg) #not working properly pStats[str(aid)]["total_damage"] += float(dmg) # not working properly
pStats[str(aid)]["games"] = int(games) pStats[str(aid)]["games"] = int(games)
pStats[str(aid)]["kills"] = int(kills) pStats[str(aid)]["kills"] = int(kills)
pStats[str(aid)]["deaths"] = int(deaths) pStats[str(aid)]["deaths"] = int(deaths)
pStats[str(aid)]["kd"] = float(p_kd) pStats[str(aid)]["kd"] = float(p_kd)
pStats[str(aid)]["avg_score"] = float(p_avg_score) pStats[str(aid)]["avg_score"] = float(p_avg_score)
# if rank < 201: # if rank < 201:
# #<td>{str(dmg)}</td> #removed this line as it isn't crt data # #<td>{str(dmg)}</td> #removed this line as it isn't crt data
# f.write(f''' # f.write(f'''
# <tr> # <tr>
# <td>{str(rank)}</td> # <td>{str(rank)}</td>
# <td style="text-align:center">{str(name)}</td> # <td style="text-align:center">{str(name)}</td>
# <td>{str(scores)}</td> # <td>{str(scores)}</td>
# <td>{str(kills)}</td> # <td>{str(kills)}</td>
# <td>{str(deaths)}</td> # <td>{str(deaths)}</td>
# <td>{str(games)}</td> # <td>{str(games)}</td>
# </tr>''') # </tr>''')
# f.write(''' # f.write('''
# </table> # </table>
# </body> # </body>
# </html>''') # </html>''')
# f.close() # f.close()
global ranks global ranks
ranks=_ranks ranks = _ranks
dump_stats(pStats) dump_stats(pStats)
updateTop3Names(toppersIDs[0:3]) updateTop3Names(toppersIDs[0:3])
@ -193,6 +203,7 @@ def refreshStats():
from playersData import pdata from playersData import pdata
pdata.update_toppers(toppersIDs) pdata.update_toppers(toppersIDs)
def update(score_set): def update(score_set):
""" """
Given a Session's ScoreSet, tallies per-account kills Given a Session's ScoreSet, tallies per-account kills
@ -201,7 +212,6 @@ def update(score_set):
""" """
# look at score-set entries to tally per-account kills for this round # look at score-set entries to tally per-account kills for this round
account_kills = {} account_kills = {}
account_deaths = {} account_deaths = {}
account_scores = {} account_scores = {}
@ -224,6 +234,7 @@ def update(score_set):
if account_scores: if account_scores:
UpdateThread(account_kills, account_deaths, account_scores).start() UpdateThread(account_kills, account_deaths, account_scores).start()
class UpdateThread(threading.Thread): class UpdateThread(threading.Thread):
def __init__(self, account_kills, account_deaths, account_scores): def __init__(self, account_kills, account_deaths, account_scores):
threading.Thread.__init__(self) threading.Thread.__init__(self)
@ -235,9 +246,9 @@ class UpdateThread(threading.Thread):
# pull our existing stats from disk # pull our existing stats from disk
import datetime import datetime
try: try:
stats=get_all_stats() stats = get_all_stats()
except: except:
stats={} stats = {}
# now add this batch of kills to our persistant stats # now add this batch of kills to our persistant stats
for account_id, kill_count in self._account_kills.items(): for account_id, kill_count in self._account_kills.items():
@ -248,8 +259,6 @@ class UpdateThread(threading.Thread):
# though it may be smart to refresh it periodically since # though it may be smart to refresh it periodically since
# it may change) # it may change)
stats[account_id] = {'rank': 0, stats[account_id] = {'rank': 0,
'name': "deafult name", 'name': "deafult name",
'scores': 0, 'scores': 0,
@ -259,22 +268,22 @@ class UpdateThread(threading.Thread):
'games': 0, 'games': 0,
'kd': 0, 'kd': 0,
'avg_score': 0, 'avg_score': 0,
'last_seen':str(datetime.datetime.now()), 'last_seen': str(datetime.datetime.now()),
'aid': str(account_id)} 'aid': str(account_id)}
#Temporary codes to change 'name_html' to 'name' # Temporary codes to change 'name_html' to 'name'
# if 'name_html' in stats[account_id]: # if 'name_html' in stats[account_id]:
# stats[account_id].pop('name_html') # stats[account_id].pop('name_html')
# stats[account_id]['name'] = 'default' # stats[account_id]['name'] = 'default'
url="http://bombsquadgame.com/bsAccountInfo?buildNumber=20258&accountID="+account_id url = "http://bombsquadgame.com/bsAccountInfo?buildNumber=20258&accountID=" + account_id
data=urllib.request.urlopen(url) data = urllib.request.urlopen(url)
if data is not None: if data is not None:
try: try:
name=json.loads(data.read())["profileDisplayString"] name = json.loads(data.read())["profileDisplayString"]
except ValueError: except ValueError:
stats[account_id]['name']= "???" stats[account_id]['name'] = "???"
else: else:
stats[account_id]['name']= name stats[account_id]['name'] = name
# now increment their kills whether they were already there or not # now increment their kills whether they were already there or not
@ -292,32 +301,31 @@ class UpdateThread(threading.Thread):
# aaand that's it! There IS no step 27! # aaand that's it! There IS no step 27!
now = datetime.now() now = datetime.now()
update_time = now.strftime("%S:%M:%H - %d %b %y") update_time = now.strftime("%S:%M:%H - %d %b %y")
#print(f"Added {str(len(self._account_kills))} account's stats entries. || {str(update_time)}") # print(f"Added {str(len(self._account_kills))} account's stats entries. || {str(update_time)}")
refreshStats() refreshStats()
def getRank(acc_id): def getRank(acc_id):
global ranks global ranks
if ranks==[]: if ranks == []:
refreshStats() refreshStats()
if acc_id in ranks: if acc_id in ranks:
return ranks.index(acc_id)+1 return ranks.index(acc_id) + 1
def updateTop3Names(ids): def updateTop3Names(ids):
global top3Name global top3Name
names=[] names = []
for id in ids: for id in ids:
url="http://bombsquadgame.com/bsAccountInfo?buildNumber=20258&accountID="+id url = "http://bombsquadgame.com/bsAccountInfo?buildNumber=20258&accountID=" + id
data=urllib.request.urlopen(url) data = urllib.request.urlopen(url)
if data is not None: if data is not None:
try: try:
name=json.loads(data.read())["profileDisplayString"] name = json.loads(data.read())["profileDisplayString"]
except ValueError: except ValueError:
names.append("???") names.append("???")
else: else:
names.append(name) names.append(name)
top3Name=names top3Name = names