def cacheMap(mapFile, _beatmap): # Check if we have to download the .osu file download = False if not os.path.isfile(mapFile): # .osu file doesn't exist. We must download it download = True else: # File exists, check md5 if generalUtils.fileMd5(mapFile) != _beatmap.fileMD5 or not isBeatmap( mapFile): # MD5 don't match, redownload .osu file download = True # Download .osu file if needed if download: log.debug("maps ~> Downloading {} osu file".format(_beatmap.beatmapID)) # Get .osu file from osu servers fileContent = osuapiHelper.getOsuFileFromID(_beatmap.beatmapID) # Make sure osu servers returned something if fileContent is None or not isBeatmap(content=fileContent): raise exceptions.osuApiFailException("maps") # Delete old .osu file if it exists if os.path.isfile(mapFile): os.remove(mapFile) # Save .osu file with open(mapFile, "wb+") as f: f.write(fileContent) else: # Map file is already in folder log.debug("maps ~> Beatmap found in cache!")
def shouldDownloadMap(mapFile, _beatmap): # Check if we have to download the .osu file if not os.path.isfile(mapFile): # .osu file doesn't exist. We must download it return True else: # File exists, check md5 if generalUtils.fileMd5(mapFile) != _beatmap.checksum or not isBeatmap( mapFile): # MD5 don't match, redownload .osu file return True # File exists and md5 matches. There's no need to download it again. return False
def getPP(self, tillerino=False, stars=False): """ Calculate total pp value with oppai and return it return -- total pp """ # Set variables self.pp = 0 try: # Build .osu map file path mapFile = "{path}/maps/{map}".format(path=self.OPPAI_FOLDER, map=self.map) try: # Check if we have to download the .osu file download = False if not os.path.isfile(mapFile): # .osu file doesn't exist. We must download it if glob.debug: consoleHelper.printColored( "[!] {} doesn't exist".format(mapFile), bcolors.YELLOW) download = True else: # File exists, check md5 if generalUtils.fileMd5(mapFile) != self.beatmap.fileMD5: # MD5 don't match, redownload .osu file if glob.debug: consoleHelper.printColored( "[!] Beatmaps md5 don't match", bcolors.YELLOW) download = True # Download .osu file if needed if download: if glob.debug: consoleHelper.printRippoppaiMessage( "Downloading {} from osu! servers...".format( self.beatmap.beatmapID)) # Get .osu file from osu servers fileContent = osuapiHelper.getOsuFileFromID( self.beatmap.beatmapID) # Make sure osu servers returned something if fileContent is None: raise exceptions.osuApiFailException(MODULE_NAME) # Delete old .osu file if it exists if os.path.isfile(mapFile): os.remove(mapFile) # Save .osu file with open(mapFile, "wb+") as f: f.write(fileContent.encode("latin-1")) else: # Map file is already in folder if glob.debug: consoleHelper.printRippoppaiMessage( "Found beatmap file {}".format(mapFile)) except exceptions.osuApiFailException: pass # Base command command = fixPath("{path}/oppai {mapFile}".format( path=self.OPPAI_FOLDER, mapFile=mapFile)) # Use only mods supported by oppai. modsFixed = self.mods & 5979 # Add params if needed 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 tillerino: command += " tillerino" if stars: command += " stars" # Debug output if glob.debug: consoleHelper.printRippoppaiMessage( "Executing {}".format(command)) # oppai output process = subprocess.run(command, shell=True, stdout=subprocess.PIPE) output = process.stdout.decode("utf-8") # Get standard or tillerino output sep = "\n" if UNIX else "\r\n" if output == ['']: # This happens if mode not supported or something self.pp = 0 self.stars = None return self.pp output = output.split(sep) # get rid of pesky warnings!!! try: float(output[0]) except ValueError: del output[0] if tillerino: # Get tillerino output (multiple lines) if stars: self.pp = output[:-2] self.stars = float(output[-2]) else: self.pp = output.split( sep)[: -1] # -1 because there's an empty line at the end else: # Get standard output (:l to remove (/r)/n at the end) l = -1 if UNIX else -2 if stars: self.pp = float(output[len(output) - 2][:l - 1]) else: self.pp = float(output[len(output) - 2][:l]) # Debug output if glob.debug: consoleHelper.printRippoppaiMessage("Calculated pp: {}".format( self.pp)) finally: return self.pp
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 = "{path}/maps/{map}".format(path=self.OPPAI_FOLDER, map=self.map) log.debug("oppai ~> Map file: {}".format(mapFile)) try: # Check if we have to download the .osu file download = False if not os.path.isfile(mapFile): # .osu file doesn't exist. We must download it if glob.debug: consoleHelper.printColored("[!] {} doesn't exist".format(mapFile), bcolors.YELLOW) download = True else: # File exists, check md5 if generalUtils.fileMd5(mapFile) != self.beatmap.fileMD5: # MD5 don't match, redownload .osu file if glob.debug: consoleHelper.printColored("[!] Beatmaps md5 don't match", bcolors.YELLOW) download = True # Download .osu file if needed if download: log.debug("oppai ~> Downloading {} osu file".format(self.beatmap.beatmapID)) # Get .osu file from osu servers fileContent = osuapiHelper.getOsuFileFromID(self.beatmap.beatmapID) # Make sure osu servers returned something if fileContent is None: raise exceptions.osuApiFailException(MODULE_NAME) # Delete old .osu file if it exists if os.path.isfile(mapFile): os.remove(mapFile) # Save .osu file with open(mapFile, "wb+") as f: f.write(fileContent.encode("utf-8")) else: # Map file is already in folder log.debug("oppai ~> Beatmap found in cache!") except exceptions.osuApiFailException: log.error("oppai ~> osu!api error!") pass # Parse beatmap log.debug("oppai ~> About to parse beatmap") pyoppai.parse( mapFile, self._oppai_beatmap, self._oppai_buffer, self.BUFSIZE, False, self.OPPAI_FOLDER # /oppai_cache ) self.checkOppaiErrors() log.debug("oppai ~> Beatmap parsed with no errors") # Create diffcalc context and calculate difficulty log.debug("oppai ~> About to calculate difficulty") # Use only mods supported by oppai modsFixed = self.mods & 5979 if modsFixed > 0: pyoppai.apply_mods(self._oppai_beatmap, modsFixed) self._oppai_diffcalc_ctx = pyoppai.new_d_calc_ctx(self._oppai_ctx) diff_stars, diff_aim, diff_speed, _, _, _, _ = pyoppai.d_calc(self._oppai_diffcalc_ctx, self._oppai_beatmap) self.checkOppaiErrors() log.debug("oppai ~> Difficulty calculated with no errors. {}*, {} aim, {} speed".format(diff_stars, diff_aim, diff_speed)) # Calculate pp log.debug("oppai ~> About to calculate PP") if not self.tillerino: _, total_pp, aim_pp, speed_pp, acc_pp = pyoppai.pp_calc_acc(self._oppai_ctx, diff_aim, diff_speed, self._oppai_beatmap, self.acc if self.acc > 0 else 100, modsFixed, self.combo if self.combo > 0 else 0xFFFF, self.misses) self.checkOppaiErrors() log.debug("oppai ~> PP Calculated with no errors. {}pp, {} aim pp, {} speed pp, {} acc pp".format( total_pp, aim_pp, speed_pp, acc_pp )) self.pp = total_pp else: pp_list = [] for acc in [100, 99, 98, 95]: log.debug("oppai ~> Calculating PP with acc {}%".format(acc)) _, total_pp, aim_pp, speed_pp, acc_pp = pyoppai.pp_calc_acc(self._oppai_ctx, diff_aim, diff_speed, self._oppai_beatmap, acc, modsFixed) self.checkOppaiErrors() pp_list.append(total_pp) log.debug("oppai ~> PP Calculated with no errors. {}pp, {} aim pp, {} speed pp, {} acc pp".format( total_pp, aim_pp, speed_pp, acc_pp )) self.pp = pp_list self.stars = diff_stars log.debug("oppai ~> Calculated PP: {}".format(self.pp)) except OppaiError: log.error("oppai ~> pyoppai error!") self.pp = 0 except Exception as e: log.error("oppai ~> Unhandled exception: {}".format(str(e))) raise e finally: log.debug("oppai ~> Shutting down and returning {}pp".format(self.pp)) return self.pp