def calculate_pp(self): try: # Cache beatmap mapFile = mapsHelper.cachedMapPath(self.beatmap.beatmapID) mapsHelper.cacheMap(mapFile, self.beatmap) # TODO: Sanizite mods # Gamemode check if self.score and self.score.gameMode != gameModes.CTB: raise exceptions.unsupportedGameModeException() # Accuracy check if self.accuracy > 1: raise ValueError("Accuracy must be between 0 and 1") # Calculate difficulty calcBeatmap = CalcBeatmap(mapFile) difficulty = Difficulty(beatmap=calcBeatmap, mods=self.mods) # Calculate pp if self.tillerino: results = [] for acc in [1, 0.99, 0.98, 0.95]: results.append(ppCalc.calculate_pp( diff=difficulty, accuracy=acc, combo=self.combo if self.combo >= 0 else calcBeatmap.max_combo, miss=self.misses )) self.pp = results else: self.pp = ppCalc.calculate_pp( diff=difficulty, accuracy=self.accuracy, combo=self.combo if self.combo >= 0 else calcBeatmap.max_combo, miss=self.misses ) except exceptions.osuApiFailException: log.error("cicciobello ~> osu!api error!") self.pp = 0 except exceptions.unsupportedGameModeException: log.error("cicciobello ~> Unsupported gamemode") self.pp = 0 except Exception as e: log.error("cicciobello ~> Unhandled exception: {}".format(str(e))) self.pp = 0 raise finally: log.debug("cicciobello ~> Shutting down, pp = {}".format(self.pp))
def asyncGet(self): statusCode = 400 data = {"message": "unknown error"} try: # Check arguments if not requestsManager.checkArguments(self.request.arguments, ["b"]): raise exceptions.invalidArgumentsException(self.MODULE_NAME) # Get beatmap ID and make sure it's a valid number beatmapId = self.get_argument("b") if not beatmapId.isdigit(): raise exceptions.invalidArgumentsException(self.MODULE_NAME) # Get mods if "m" in self.request.arguments: modsEnum = self.get_argument("m") if not modsEnum.isdigit(): raise exceptions.invalidArgumentsException( self.MODULE_NAME) modsEnum = int(modsEnum) else: modsEnum = 0 # Get game mode if "g" in self.request.arguments: gameMode = self.get_argument("g") if not gameMode.isdigit(): raise exceptions.invalidArgumentsException( self.MODULE_NAME) gameMode = int(gameMode) else: gameMode = 0 # Get acc if "a" in self.request.arguments: accuracy = self.get_argument("a") try: accuracy = float(accuracy) except ValueError: raise exceptions.invalidArgumentsException( self.MODULE_NAME) else: accuracy = None # Print message log.info("Requested pp for beatmap {}".format(beatmapId)) # Get beatmap md5 from osuapi # TODO: Move this to beatmap object osuapiData = osuapiHelper.osuApiRequest("get_beatmaps", "b={}".format(beatmapId)) if osuapiData is None or "file_md5" not in osuapiData or "beatmapset_id" not in osuapiData: raise exceptions.invalidBeatmapException(self.MODULE_NAME) beatmapMd5 = osuapiData["file_md5"] beatmapSetID = osuapiData["beatmapset_id"] # Create beatmap object bmap = beatmap.beatmap(beatmapMd5, beatmapSetID) # Check beatmap length # TODO: Why do we do this? if bmap.hit_length > 900: raise exceptions.beatmapTooLongException(self.MODULE_NAME) if gameMode == gameModes.STD and bmap.starsStd == 0: # Mode Specific beatmap, auto detect game mode if bmap.starsTaiko > 0: gameMode = gameModes.TAIKO if bmap.starsCtb > 0: gameMode = gameModes.CTB if bmap.starsMania > 0: gameMode = gameModes.MANIA # Calculate pp if gameMode in (gameModes.STD, gameModes.TAIKO): # osu!standard and osu!taiko oppai = ez.Ez(bmap, mods_=modsEnum, tillerino=accuracy is None, acc=accuracy, gameMode=gameMode) bmap.starsStd = oppai.stars returnPP = oppai.pp elif gameMode == gameModes.CTB: # osu!catch ciccio = cicciobello.Cicciobello(bmap, mods_=modsEnum, tillerino=accuracy is None, accuracy=accuracy) bmap.starsStd = ciccio.stars returnPP = ciccio.pp else: raise exceptions.unsupportedGameModeException() # Data to return data = { "song_name": bmap.songName, "pp": [x for x in returnPP] if type(returnPP) is list else returnPP, "game_mode": gameMode, "length": bmap.hit_length, "stars": bmap.starsStd if bmap.starsStd is not None else bmap.difficultyrating, "ar": bmap.diff_approach, "bpm": bmap.bpm, } # Set status code and message statusCode = 200 data["message"] = "ok" except exceptions.invalidArgumentsException: # Set error and message statusCode = 400 data["message"] = "missing required arguments" except exceptions.invalidBeatmapException: statusCode = 400 data["message"] = "beatmap not found" except exceptions.beatmapTooLongException: statusCode = 400 data["message"] = "requested beatmap is too long" except exceptions.unsupportedGameModeException: statusCode = 400 data["message"] = "Unsupported gamemode" finally: # Add status code to data data["status"] = statusCode # Debug output log.debug(str(data)) # Send response self.write(json.dumps(data)) self.set_header("Content-Type", "application/json") self.set_status(statusCode)
def calculatePP(self): """ Calculate total pp value with oppai and return it return -- total pp """ # Set variables self.pp = None try: # Build .osu map file path mapFile = mapsHelper.cachedMapPath(self.beatmap.beatmapID) log.debug("oppai ~> Map file: {}".format(mapFile)) mapsHelper.cacheMap(mapFile, self.beatmap) # Use only mods supported by oppai modsFixed = self.mods & 5983 # Check gamemode if self.gameMode != gameModes.STD and self.gameMode != gameModes.TAIKO: raise exceptions.unsupportedGameModeException() command = "./pp/oppai-ng/oppai {}".format(mapFile) if not self.tillerino: # force acc only for non-tillerino calculation # acc is set for each subprocess if calculating tillerino-like pp sets if self.acc > 0: command += " {acc:.2f}%".format(acc=self.acc) if self.mods > 0: command += " +{mods}".format(mods=scoreUtils.readableMods(modsFixed)) if self.combo >= 0: command += " {combo}x".format(combo=self.combo) if self.misses > 0: command += " {misses}xm".format(misses=self.misses) if self.gameMode == gameModes.TAIKO: command += " -taiko" command += " -ojson" # Calculate pp if not self.tillerino: # self.pp, self.stars = self._runOppaiProcess(command) temp_pp, self.stars = self._runOppaiProcess(command) if (self.gameMode == gameModes.TAIKO and self.beatmap.starsStd > 0 and temp_pp > 800) or \ self.stars > 50: # Invalidate pp for bugged taiko converteds and bugged inf pp std maps self.pp = 0 else: self.pp = temp_pp else: pp_list = [] for acc in [100, 99, 98, 95]: temp_command = command temp_command += " {acc:.2f}%".format(acc=acc) pp, self.stars = self._runOppaiProcess(temp_command) # If this is a broken converted, set all pp to 0 and break the loop if self.gameMode == gameModes.TAIKO and self.beatmap.starsStd > 0 and pp > 800: pp_list = [0, 0, 0, 0] break pp_list.append(pp) self.pp = pp_list log.debug("oppai ~> Calculated PP: {}, stars: {}".format(self.pp, self.stars)) except OppaiError: log.error("oppai ~> oppai-ng error!") self.pp = 0 except exceptions.osuApiFailException: log.error("oppai ~> osu!api error!") self.pp = 0 except exceptions.unsupportedGameModeException: log.error("oppai ~> Unsupported gamemode") self.pp = 0 except Exception as e: log.error("oppai ~> Unhandled exception: {}".format(str(e))) self.pp = 0 raise finally: log.debug("oppai ~> Shutting down, pp = {}".format(self.pp))
def asyncGet(self): statusCode = 400 data = {"message": "unknown error"} try: # Check arguments if not requestsManager.checkArguments(self.request.arguments, ["b"]): raise exceptions.invalidArgumentsException(MODULE_NAME) # Get beatmap ID and make sure it's a valid number beatmapID = self.get_argument("b") if not beatmapID.isdigit(): raise exceptions.invalidArgumentsException(MODULE_NAME) # Get mods if "m" in self.request.arguments: modsEnum = self.get_argument("m") if not modsEnum.isdigit(): raise exceptions.invalidArgumentsException(MODULE_NAME) modsEnum = int(modsEnum) else: modsEnum = 0 # Get game mode if "g" in self.request.arguments: gameMode = self.get_argument("g") if not gameMode.isdigit(): raise exceptions.invalidArgumentsException(MODULE_NAME) gameMode = int(gameMode) else: gameMode = 0 # Get acc if "a" in self.request.arguments: accuracy = self.get_argument("a") try: accuracy = float(accuracy) except ValueError: raise exceptions.invalidArgumentsException(MODULE_NAME) else: accuracy = None # Print message log.info("Requested pp for beatmap {}".format(beatmapID)) # Get beatmap md5 from osuapi # TODO: Move this to beatmap object osuapiData = osuapiHelper.osuApiRequest("get_beatmaps", "b={}".format(beatmapID)) if int(beatmapID) > 100000000: raise exceptions.ppCustomBeatmap(MODULE_NAME) if osuapiData is None or "file_md5" not in osuapiData or "beatmapset_id" not in osuapiData: raise exceptions.invalidBeatmapException(MODULE_NAME) beatmapMd5 = osuapiData["file_md5"] beatmapSetID = osuapiData["beatmapset_id"] # Create beatmap object bmap = beatmap.beatmap(beatmapMd5, beatmapSetID) # Check beatmap length if bmap.hitLength > 900: raise exceptions.beatmapTooLongException(MODULE_NAME) returnPP = [] if gameMode == gameModes.STD and bmap.starsStd == 0: # Mode Specific beatmap, auto detect game mode if bmap.starsTaiko > 0: gameMode = gameModes.TAIKO if bmap.starsCtb > 0: gameMode = gameModes.CTB if bmap.starsMania > 0: gameMode = gameModes.MANIA # Calculate pp if gameMode in (gameModes.STD, gameModes.TAIKO): # Std pp if accuracy is None and modsEnum == 0: # Generic acc/nomod # Get cached pp values cachedPP = bmap.getCachedTillerinoPP() if (modsEnum & mods.RELAX): cachedPP = [0, 0, 0, 0] elif (modsEnum & mods.RELAX2): cachedPP = [0, 0, 0, 0] if cachedPP != [0, 0, 0, 0]: log.debug("Got cached pp.") returnPP = cachedPP else: log.debug( "Cached pp not found. Calculating pp with oppai..." ) # Cached pp not found, calculate them if gameMode == gameModes.STD and (modsEnum & mods.RELAX): oppai = relaxoppai.oppai(bmap, mods=modsEnum, tillerino=True) elif gameMode == gameModes.STD and (modsEnum & mods.RELAX2): oppai = relax2oppai.oppai(bmap, mods=modsEnum, tillerino=True) else: oppai = rippoppai.oppai(bmap, mods=modsEnum, tillerino=True) returnPP = oppai.pp bmap.starsStd = oppai.stars if not (modsEnum & mods.RELAX) or (modsEnum & mods.RELAX2): # Cache values in DB log.debug("Saving cached pp...") if type(returnPP) == list and len(returnPP) == 4: bmap.saveCachedTillerinoPP(returnPP) else: # Specific accuracy/mods, calculate pp # Create oppai instance log.debug( "Specific request ({}%/{}). Calculating pp with oppai..." .format(accuracy, modsEnum)) if gameMode == gameModes.STD and (modsEnum & mods.RELAX): oppai = relaxoppai.oppai(bmap, mods=modsEnum, tillerino=True) elif gameMode == gameModes.STD and (modsEnum & mods.RELAX2): oppai = relax2oppai.oppai(bmap, mods=modsEnum, tillerino=True) else: oppai = rippoppai.oppai(bmap, mods=modsEnum, tillerino=True) bmap.starsStd = oppai.stars if accuracy is not None: returnPP = calculatePPFromAcc(oppai, accuracy) else: returnPP = oppai.pp else: raise exceptions.unsupportedGameModeException() # Data to return data = { "song_name": bmap.songName, "pp": [x for x in returnPP] if type(returnPP) is list else returnPP, "length": bmap.hitLength, "stars": bmap.starsStd, "ar": bmap.AR, "bpm": bmap.bpm, } # Set status code and message statusCode = 200 data["message"] = "ok" except exceptions.invalidArgumentsException: # Set error and message statusCode = 400 data["message"] = "missing required arguments" except exceptions.ppCustomBeatmap: statusCode = 400 data[ "message"] = "Custom map does not supported pp calculating yet" except exceptions.invalidBeatmapException: statusCode = 400 data["message"] = "beatmap not found" except exceptions.beatmapTooLongException: statusCode = 400 data["message"] = "requested beatmap is too long" except exceptions.unsupportedGameModeException: statusCode = 400 data["message"] = "Unsupported gamemode" finally: # Add status code to data data["status"] = statusCode # Debug output log.debug(str(data)) # Send response #self.clear() self.write(json.dumps(data)) self.set_header("Content-Type", "application/json") self.set_status(statusCode)
def calculatePP(self): """ Calculate total pp value with oppai and return it return -- total pp """ # Set variables self.pp = None ez = None try: # Build .osu map file path mapFile = mapsHelper.cachedMapPath(self.beatmap.beatmapID) mapsHelper.cacheMap(mapFile, self.beatmap) # Use only mods supported by oppai modsFixed = self.mods & 5983 # Check gamemode if self.gameMode not in (gameModes.STD, gameModes.TAIKO): raise exceptions.unsupportedGameModeException() ez = oppai.ezpp_new() if self.misses > 0: oppai.ezpp_set_nmiss(ez, self.misses) if self.combo >= 0: oppai.ezpp_set_combo(ez, self.combo) if self.gameMode == gameModes.TAIKO: oppai.ezpp_set_mode_override(ez, gameModes.TAIKO) if not self.tillerino: if self.acc > 0: oppai.ezpp_set_accuracy_percent(ez, self.acc) if self.mods > mods.NOMOD: oppai.ezpp_set_mods(ez, modsFixed) relax = (self.mods & mods.RELAX) > 0 autopilot = (self.mods & mods.RELAX2) > 0 if relax or autopilot: oppai.ezpp_set_relax_version(ez, 1) if relax: oppai.ezpp_set_relax(ez, 1) elif autopilot: oppai.ezpp_set_autopilot(ez, 1) if not self.tillerino: oppai.ezpp_dup(ez, mapFile) temp_pp = oppai.ezpp_pp(ez) self.stars = oppai.ezpp_stars(ez) if (self.gameMode == gameModes.TAIKO and self.beatmap.starsStd > 0 and temp_pp > 800) or \ self.stars > 50: # Invalidate pp for bugged taiko converteds and bugged inf pp std maps self.pp = 0 else: self.pp = temp_pp else: with open(mapFile, "r") as f: data = f.read() oppai.ezpp_data_dup(ez, data, len(data.encode())) pp_list = [] self.stars = oppai.ezpp_stars(ez) oppai.ezpp_set_autocalc(ez, 1) for acc in (100, 99, 98, 95): oppai.ezpp_set_accuracy_percent(ez, acc) pp = oppai.ezpp_pp(ez) # If this is a broken converted, set all pp to 0 and break the loop if self.gameMode == gameModes.TAIKO and self.beatmap.starsStd > 0 and pp > 800: pp_list = [0, 0, 0, 0] break pp_list.append(pp) self.pp = pp_list log.debug("oppai ~> Calculated PP: {}, stars: {}".format( self.pp, self.stars)) except exceptions.osuApiFailException: log.error("oppai ~> osu!api error!") self.pp = 0 except exceptions.unsupportedGameModeException: log.error("oppai ~> Unsupported gamemode") self.pp = 0 except Exception as e: log.error("oppai ~> Unhandled exception: {}".format(str(e))) self.pp = 0 raise finally: if ez is not None: oppai.ezpp_free(ez) log.debug("oppai ~> Shutting down, pp = {}".format(self.pp))
def _calculatePP(self): log.debug(f"ezPeace ~> object dict: {self.__dict__}") """ Calculate total pp value with peace and return it return -- total pp """ # Set variables self.pp = None peace = None try: # Check gamemode if self.gameMode not in (gameModes.STD, gameModes.TAIKO, gameModes.CTB, gameModes.MANIA): raise exceptions.unsupportedGameModeException() # Build .osu map file path mapFile = "{path}/{map}".format( path=self.GAME_FOLDER[self.gameMode], map=self.map) mapsHelper.cacheMap(mapFile, self.beatmap) beatmap = Beatmap(mapFile) peace = Calculator() # Not so readeable part starts here... peace.set_mode(self.gameMode) if self.misses > 0: peace.set_miss(self.misses) if self.combo >= 0: peace.set_combo(self.combo) if not self.tillerino: if self.acc > 0: peace.set_acc(self.acc) if self.score and self.gameMode == gameModes.MANIA: peace.set_score(self.score.score) if self.mods > mods.NOMOD: peace.set_mods(self.mods) if not self.tillerino: peace_calculations = peace.calculate(beatmap) temp_pp = round(peace_calculations.pp, 5) self.stars = peace_calculations.attrs_dict['stars'] if (self.gameMode == gameModes.TAIKO and self.beatmap.starsStd > 0 and temp_pp > 800) or \ self.stars > 50 or \ self.gameMode == gameModes.MANIA and self.mods & mods.SCOREV2 > 0: # Invalidate pp for bugged taiko converteds and bugged inf pp std maps self.pp = 0 else: self.pp = temp_pp else: pp_list = [] peace_calculations = peace.calculate(beatmap) self.stars = peace_calculations.attrs_dict['stars'] if self.acc and self.acc > 0: peace.set_acc(self.acc) peace_calculations = peace.calculate(beatmap) self.pp = peace_calculations.pp else: for acc in (100, 99, 98, 95): peace.set_acc(acc) peace_calculations = peace.calculate(beatmap) pp = round(peace_calculations.pp, 5) # If this is a broken converted, set all pp to 0 and break the loop if self.gameMode == gameModes.TAIKO and self.beatmap.starsStd > 0 and pp > 800 or \ self.gameMode == gameModes.MANIA and self.mods & mods.SCOREV2 > 0: pp_list = [0, 0, 0, 0] break pp_list.append(pp) self.pp = pp_list log.debug("peace ~> Calculated PP: {}, stars: {}".format( self.pp, self.stars)) except exceptions.osuApiFailException: log.error("peace ~> osu!api error!") self.pp = 0 except exceptions.unsupportedGameModeException: log.error("peace ~> Unsupported gamemode") self.pp = 0 except Exception as e: log.error("peace ~> Unhandled exception: {}".format(str(e))) self.pp = 0 raise finally: log.debug("peace ~> Shutting down, pp = {}".format(self.pp))
def _calculatePP(self): """ Calculate total pp value with peace and return it return -- total pp """ # Set variables self.pp = None peace = None try: # Check gamemode if self.gameMode not in (gameModes.STD, gameModes.TAIKO, gameModes.CTB, gameModes.MANIA): raise exceptions.unsupportedGameModeException() # Build .osu map file path mapFile = "{path}/maps/{map}".format( path=self.GAME_FOLDER[self.gameMode], map=self.map) mapsHelper.cacheMap(mapFile, self.beatmap) rosu = Calculator(mapFile) score_params = ScoreParams() # Not so readeable part starts here... if self.misses > 0: score_params.nMisses = self.misses if self.combo >= 0: score_params.combo = self.combo if not self.tillerino: if self.acc > 0: score_params.acc = self.acc if self.score and self.gameMode == gameModes.MANIA: score_params.score = self.score.score if self.mods > mods.NOMOD: score_params.mods = self.mods [rosu_calculations] = rosu.calculate(score_params) if not self.tillerino: if rosu_calculations.mode != self.score.gameMode: self.pp = 0 else: temp_pp = round(rosu_calculations.pp, 5) self.stars = rosu_calculations.stars if (self.gameMode == gameModes.TAIKO and self.beatmap.starsStd > 0 and temp_pp > 800) or \ self.stars > 50 or \ self.gameMode == gameModes.MANIA and self.mods & mods.SCOREV2 > 0: # Invalidate pp for bugged taiko converteds and bugged inf pp std maps self.pp = 0 else: self.pp = temp_pp else: if rosu_calculations.mode != self.score.gameMode: self.pp = [0, 0, 0, 0] else: pp_list = [] self.stars = rosu_calculations.stars if self.acc and self.acc > 0: score_params.acc = self.acc [rosu_calculations] = rosu.calculate(score_params) self.pp = rosu_calculations.pp else: # ik that can be a better way, but i don't wanna do something "NICE" to this odd code for acc in (100, 99, 98, 95): score_params.acc = self.acc [rosu_calculations] = rosu.calculate(score_params) pp = round(rosu_calculations.pp, 5) # If this is a broken converted, set all pp to 0 and break the loop if self.gameMode == gameModes.TAIKO and self.beatmap.starsStd > 0 and pp > 800 or \ self.gameMode == gameModes.MANIA and self.mods & mods.SCOREV2 > 0: pp_list = [0, 0, 0, 0] break pp_list.append(pp) self.pp = pp_list log.debug("rosu ~> Calculated PP: {}, stars: {}".format( self.pp, self.stars)) except exceptions.osuApiFailException: log.error("rosu ~> osu!api error!") self.pp = 0 except exceptions.unsupportedGameModeException: log.error("rosu ~> Unsupported gamemode") self.pp = 0 except Exception as e: log.error("rosu ~> Unhandled exception: {}".format(str(e))) self.pp = 0 raise finally: log.debug("rosu ~> Shutting down, pp = {}".format(self.pp))