This repository has been archived on 2022-02-23. You can view files and clone it, but cannot push or open issues or pull requests.
lets/objects/rxscore.pyx
2018-12-09 00:15:56 -05:00

275 lines
8.6 KiB
Cython

import time
from objects import beatmap
from common.constants import gameModes
from common.log import logUtils as log
from common.ripple import userUtils
from constants import rankedStatuses
from common.ripple import scoreUtils
from objects import glob
from pp import rippoppai
from pp import rxoppai
from pp import wifipiano2
from pp import cicciobello
class score:
PP_CALCULATORS = {
gameModes.STD: rxoppai.oppai,
gameModes.TAIKO: rippoppai.oppai,
gameModes.CTB: cicciobello.Cicciobello,
gameModes.MANIA: wifipiano2.piano
}
__slots__ = ["scoreID", "playerName", "score", "maxCombo", "c50", "c100", "c300", "cMiss", "cKatu", "cGeki",
"fullCombo", "mods", "playerUserID","rank","date", "hasReplay", "fileMd5", "passed", "playDateTime",
"gameMode", "completed", "accuracy", "pp", "oldPersonalBest", "rankedScoreIncrease"]
def __init__(self, scoreID = None, rank = None, setData = True):
"""
Initialize a (empty) score object.
scoreID -- score ID, used to get score data from db. Optional.
rank -- score rank. Optional
setData -- if True, set score data from db using scoreID. Optional.
"""
self.scoreID = 0
self.playerName = "nospe"
self.score = 0
self.maxCombo = 0
self.c50 = 0
self.c100 = 0
self.c300 = 0
self.cMiss = 0
self.cKatu = 0
self.cGeki = 0
self.fullCombo = False
self.mods = 0
self.playerUserID = 0
self.rank = rank # can be empty string too
self.date = 0
self.hasReplay = 0
self.fileMd5 = None
self.passed = False
self.playDateTime = 0
self.gameMode = 0
self.completed = 0
self.accuracy = 0.00
self.pp = 0.00
self.oldPersonalBest = 0
self.rankedScoreIncrease = 0
if scoreID is not None and setData == True:
self.setDataFromDB(scoreID, rank)
def calculateAccuracy(self):
"""
Calculate and set accuracy for that score
"""
if self.gameMode == 0:
# std
totalPoints = self.c50*50+self.c100*100+self.c300*300
totalHits = self.c300+self.c100+self.c50+self.cMiss
if totalHits == 0:
self.accuracy = 1
else:
self.accuracy = totalPoints/(totalHits*300)
elif self.gameMode == 1:
# taiko
totalPoints = (self.c100*50)+(self.c300*100)
totalHits = self.cMiss+self.c100+self.c300
if totalHits == 0:
self.accuracy = 1
else:
self.accuracy = totalPoints / (totalHits * 100)
elif self.gameMode == 2:
# ctb
fruits = self.c300+self.c100+self.c50
totalFruits = fruits+self.cMiss+self.cKatu
if totalFruits == 0:
self.accuracy = 1
else:
self.accuracy = fruits / totalFruits
elif self.gameMode == 3:
# mania
totalPoints = self.c50*50+self.c100*100+self.cKatu*200+self.c300*300+self.cGeki*300
totalHits = self.cMiss+self.c50+self.c100+self.c300+self.cGeki+self.cKatu
self.accuracy = totalPoints / (totalHits * 300)
else:
# unknown gamemode
self.accuracy = 0
def setRank(self, rank):
"""
Force a score rank
rank -- new score rank
"""
self.rank = rank
def setDataFromDB(self, scoreID, rank = None):
"""
Set this object's score data from db
Sets playerUserID too
scoreID -- score ID
rank -- rank in scoreboard. Optional.
"""
data = glob.db.fetch("SELECT scores_relax.*, users.username FROM scores_relax LEFT JOIN users ON users.id = scores_relax.userid WHERE scores_relax.id = %s LIMIT 1", [scoreID])
if data is not None:
self.setDataFromDict(data, rank)
def setDataFromDict(self, data, rank = None):
"""
Set this object's score data from dictionary
Doesn't set playerUserID
data -- score dictionarty
rank -- rank in scoreboard. Optional.
"""
#print(str(data))
self.scoreID = data["id"]
if "username" in data:
self.playerName = userUtils.getClan(data["userid"])
else:
self.playerName = userUtils.getUsername(data["userid"])
self.playerUserID = data["userid"]
self.score = data["score"]
self.maxCombo = data["max_combo"]
self.gameMode = data["play_mode"]
self.c50 = data["50_count"]
self.c100 = data["100_count"]
self.c300 = data["300_count"]
self.cMiss = data["misses_count"]
self.cKatu = data["katus_count"]
self.cGeki = data["gekis_count"]
self.fullCombo = True if data["full_combo"] == 1 else False
self.mods = data["mods"]
self.rank = rank if rank is not None else ""
self.date = data["time"]
self.fileMd5 = data["beatmap_md5"]
self.completed = data["completed"]
#if "pp" in data:
self.pp = data["pp"]
self.calculateAccuracy()
def setDataFromScoreData(self, scoreData):
"""
Set this object's score data from scoreData list (submit modular)
scoreData -- scoreData list
"""
if len(scoreData) >= 16:
self.fileMd5 = scoreData[0]
self.playerName = scoreData[1].strip()
# %s%s%s = scoreData[2]
self.c300 = int(scoreData[3])
self.c100 = int(scoreData[4])
self.c50 = int(scoreData[5])
self.cGeki = int(scoreData[6])
self.cKatu = int(scoreData[7])
self.cMiss = int(scoreData[8])
self.score = int(scoreData[9])
self.maxCombo = int(scoreData[10])
self.fullCombo = True if scoreData[11] == 'True' else False
#self.rank = scoreData[12]
self.mods = int(scoreData[13])
self.passed = True if scoreData[14] == 'True' else False
self.gameMode = int(scoreData[15])
#self.playDateTime = int(scoreData[16])
self.playDateTime = int(time.time())
self.calculateAccuracy()
#osuVersion = scoreData[17]
self.calculatePP()
# Set completed status
self.setCompletedStatus()
def getData(self, pp=True):
"""Return score row relative to this score for getscores"""
return "{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|1\n".format(
self.scoreID,
self.playerName,
int(self.pp) if pp else self.score,
self.maxCombo,
self.c50,
self.c100,
self.c300,
self.cMiss,
self.cKatu,
self.cGeki,
self.fullCombo,
self.mods,
self.playerUserID,
self.rank,
self.date)
def setCompletedStatus(self):
"""
Set this score completed status and rankedScoreIncrease
"""
self.completed = 0
if self.passed == True and scoreUtils.isRankable(self.mods):
# Get userID
userID = userUtils.getID(self.playerName)
# Make sure we don't have another score identical to this one
duplicate = glob.db.fetch("SELECT id FROM scores_relax WHERE userid = %s AND beatmap_md5 = %s AND play_mode = %s AND time = %s AND score = %s LIMIT 1", [userID, self.fileMd5, self.gameMode, self.date, self.score])
if duplicate is not None:
# Found same score in db. Don't save this score.
self.completed = -1
return
# No duplicates found.
# Get right "completed" value
personalBest = glob.db.fetch("SELECT id, pp, score FROM scores_relax WHERE userid = %s AND beatmap_md5 = %s AND play_mode = %s AND completed = 3 LIMIT 1", [userID, self.fileMd5, self.gameMode])
if personalBest is None:
# This is our first score on this map, so it's our best score
self.completed = 3
self.rankedScoreIncrease = self.score
self.oldPersonalBest = 0
else:
# Compare personal best's score with current score
if self.pp > personalBest["pp"]:
# New best score
self.completed = 3
self.rankedScoreIncrease = self.score-personalBest["score"]
self.oldPersonalBest = personalBest["id"]
else:
self.completed = 2
self.rankedScoreIncrease = 0
self.oldPersonalBest = 0
log.info("Completed status: {}".format(self.completed))
def saveScoreInDB(self):
"""
Save this score in DB (if passed and mods are valid)
"""
# Add this score
if self.completed >= 2:
query = "INSERT INTO scores_relax (id, beatmap_md5, userid, score, max_combo, full_combo, mods, 300_count, 100_count, 50_count, katus_count, gekis_count, misses_count, time, play_mode, completed, accuracy, pp) VALUES (NULL, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s);"
self.scoreID = int(glob.db.execute(query, [self.fileMd5, userUtils.getID(self.playerName), self.score, self.maxCombo, 1 if self.fullCombo == True else 0, self.mods, self.c300, self.c100, self.c50, self.cKatu, self.cGeki, self.cMiss, self.playDateTime, self.gameMode, self.completed, self.accuracy * 100, self.pp]))
# Set old personal best to completed = 2
if self.oldPersonalBest != 0:
glob.db.execute("UPDATE scores_relax SET completed = 2 WHERE id = %s", [self.oldPersonalBest])
def calculatePP(self, b = None):
"""
Calculate this score's pp value if completed == 3
"""
# Create beatmap object
if b is None:
b = beatmap.beatmap(self.fileMd5, 0)
# Calculate pp
if b.rankedStatus >= rankedStatuses.RANKED and b.rankedStatus != rankedStatuses.LOVED and b.rankedStatus != rankedStatuses.UNKNOWN \
and scoreUtils.isRankable(self.mods) and self.passed and self.gameMode in score.PP_CALCULATORS:
calculator = score.PP_CALCULATORS[self.gameMode](b, self)
self.pp = calculator.pp
else:
self.pp = 0