示例#1
0
    def _runOppaiProcess(self, command):
        log.debug("oppai ~> running {}".format(command))
        process = subprocess.run(command, shell=True, stdout=subprocess.PIPE)
        try:
            output = json.loads(process.stdout.decode("utf-8",
                                                      errors="ignore"))
            if "code" not in output or "errstr" not in output:
                raise OppaiError("No code in json output")
            if output["code"] != 200:
                raise OppaiError("oppai error {}: {}".format(
                    output["code"], output["errstr"]))
            if "pp" not in output or "stars" not in output:
                raise OppaiError("No pp/stars entry in oppai json output")
            pp = output["pp"]

            stars = output["stars"]
            if (self.gameMode == gameModes.STD):
                mod = "difficulty_{}".format(
                    scoreUtils.readableMods(self.mods & 80))
                if (mod == "difficulty_HR" or mod == "difficulty_DT"):
                    diff = glob.db.fetch(
                        "SELECT {} FROM beatmaps WHERE beatmap_md5 = '{}'".
                        format(mod, self.beatmap.fileMD5))[mod]
                    if (diff == 0):
                        glob.db.execute(
                            "UPDATE beatmaps SET {} = {} WHERE beatmap_md5 = '{}'"
                            .format(mod, round(stars, 5),
                                    self.beatmap.fileMD5))
            log.debug("oppai ~> full output: {}".format(output))
            log.debug("oppai ~> pp: {}, stars: {}".format(pp, stars))
        except (json.JSONDecodeError, IndexError, OppaiError) as e:
            raise OppaiError(e)
        return pp, stars
示例#2
0
def recalcFirstPlaces(userID):

    c = glob.db.fetch("select * from user_first_places WHERE userid = %s",
                      [userID])

    fs = glob.db.fetchAll(
        "SELECT o.pp pp, o.mods mods,	beatmap_id, difficulty_std stars, difficulty_hr starsHR, difficulty_dt starsDT, hit_length length FROM (SELECT scores.* from scores JOIN users ON scores.userid = users.id WHERE privileges > 2 AND completed = 3 AND play_mode = 0) o LEFT JOIN (SELECT scores.* from scores JOIN users ON scores.userid = users.id WHERE privileges > 2 AND completed = 3 AND play_mode = 0) b on o.beatmap_md5 = b.beatmap_md5 AND o.pp < b.pp JOIN beatmaps ON o.beatmap_md5 = beatmaps.beatmap_md5 WHERE b.pp is NULL AND o.userid = %s AND o.play_mode = 0 AND o.completed = 3 AND o.pp > 40",
        [userID])

    if fs is None:
        return

    fvalue = 0
    for f in fs:
        mod = scoreUtils.readableMods(int(f["mods"]) & 80)
        stars = f["stars"]
        if (mod == "HR" or mod == "DT"):
            if (f["stars{}".format(mod)] <= 0):
                log.error("stars <= 0 beatmap: {}".format(f["beatmap_id"]))
            else:
                stars = f["stars{}".format(mod)]

        cv = addModsBonus(stars, f["mods"], f["pp"])**4.45 / 800
        fvalue += cv * lengthBonusMultiplier(f["length"])

    fvalue = round(fvalue)

    if c is None:
        glob.db.execute(
            "INSERT INTO user_first_places(userid,value) VALUES(%s,%s)",
            [userID, fvalue])
    else:
        glob.db.execute(
            "UPDATE user_first_places SET value = %s WHERE userID = %s",
            [fvalue, userID])
示例#3
0
	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))
示例#4
0
def handle(userToken, packetData):
    # Get usertoken data
    userID = userToken.userID
    username = userToken.username

    # Make sure we are not banned
    #if userUtils.isBanned(userID):
    #	userToken.enqueue(serverPackets.loginBanned())
    #	return

    # Send restricted message if needed
    #if userToken.restricted:
    #	userToken.checkRestricted(True)

    # Change action packet
    packetData = clientPackets.userActionChange(packetData)

    # If we are not in spectate status but we're spectating someone, stop spectating
    '''
if userToken.spectating != 0 and userToken.actionID != actions.WATCHING and userToken.actionID != actions.IDLE and userToken.actionID != actions.AFK:
	userToken.stopSpectating()

# If we are not in multiplayer but we are in a match, part match
if userToken.matchID != -1 and userToken.actionID != actions.MULTIPLAYING and userToken.actionID != actions.MULTIPLAYER and userToken.actionID != actions.AFK:
	userToken.partMatch()
		'''

    # Update cached stats if relax status changed
    if packetData["actionMods"] & 128 != userToken.relax:
        userToken.relax = packetData["actionMods"] & 128
        notifs = userUtils.checkAkatsukiNotifications(userID)
        if packetData["actionMods"] & 128:
            if not notifs:
                userToken.enqueue(
                    serverPackets.notification("You've switched to Relax!"))
            userToken.rxupdateCachedStats()
        else:
            if not notifs:
                userToken.enqueue(
                    serverPackets.notification("You've switched to Regular!"))
            userToken.updateCachedStats()

    # Update cached stats if our pp changed if we've just submitted a score or we've changed gameMode
    if (userToken.actionID == actions.PLAYING or userToken.actionID
            == actions.MULTIPLAYING) or (userToken.pp != userUtils.getPP(
                userID, userToken.gameMode)) or (userToken.gameMode !=
                                                 packetData["gameMode"]):
        if packetData["actionMods"] & 128:
            userToken.rxupdateCachedStats()
        else:
            userToken.updateCachedStats()

    # Update cached stats if we've changed gamemode
    if userToken.gameMode != packetData["gameMode"]:
        userToken.gameMode = packetData["gameMode"]
        if packetData["actionMods"] & 128:
            userToken.rxupdateCachedStats()
        else:
            userToken.updateCachedStats()

    # Always update action id, text, md5 and beatmapID
    userToken.actionID = packetData["actionID"]
    userToken.actionText = packetData[
        "actionText"] + " +" + scoreUtils.readableMods(
            int(packetData["actionMods"]))
    userToken.actionMd5 = packetData["actionMd5"]
    userToken.actionMods = packetData["actionMods"]
    userToken.beatmapID = packetData["beatmapID"]

    # Enqueue our new user panel and stats to us and our spectators
    recipients = [userToken]
    if len(userToken.spectators) > 0:
        for i in userToken.spectators:
            if i in glob.tokens.tokens:
                recipients.append(glob.tokens.tokens[i])

    for i in recipients:
        if i is not None:
            # Force our own packet
            force = True if i == userToken else False
            i.enqueue(serverPackets.userPanel(userID, force))
            i.enqueue(serverPackets.userStats(userID, force))

    # Console output
    log.info("{} changed action: {} [{}][{}][{}].".format(
        username, str(userToken.actionID), userToken.actionText,
        userToken.actionMd5, userToken.beatmapID))
示例#5
0
    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)

            mapsHelper.cacheMap(mapFile, self.beatmap)

            # Base command
            command = fixPath("{path}/oppai {mapFile}".format(
                path=self.OPPAI_FOLDER, mapFile=mapFile))

            # Use only mods supported by oppai.
            modsFixed = self.mods & 14303
            command += " scorev{ver}".format(
                ver=scoreUtils.scoreType(self.mods))
            # Add params if needed
            if not self.tillerino:
                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 = round(temp_pp, 2)
            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(round(pp, 2))
                self.pp = pp_list

            # 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
            consoleHelper.printRippoppaiMessage("Calculated pp: {}".format(
                self.pp))
        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))
示例#6
0
    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