Exemplo n.º 1
0
def get_pp_infos(beatmap_id):
	BUFSIZE = 2000000

	accuracys = [100, 99, 98, 97]
	mods = [pyoppai.nomod, pyoppai.hr, pyoppai.hd, pyoppai.dt, pyoppai.dt | pyoppai.hd, pyoppai.dt | pyoppai.hr, pyoppai.hd | pyoppai.hr, pyoppai.dt | pyoppai.hr | pyoppai.hd]
	mods_name = ["Nomod", "HR", "HD", "DT", "HDDT", "HRDT", "HDHR", "HRHDDT"]

	pp_results = {}

	ctx = pyoppai.new_ctx()
	buf = pyoppai.new_buffer(BUFSIZE)
	b = pyoppai.new_beatmap(ctx)

	err = pyoppai.err(ctx)
	if err:
		print(err)
		pass
	for accuracy in accuracys:
		i = 0
		for mod in mods:
			pyoppai.parse(constants.Paths.beatmapsDownloadsPermanent + "/" + str(beatmap_id) + ".osu", b, buf, BUFSIZE, False, constants.Paths.beatmapsDownloadsPermanent)
			dctx = pyoppai.new_d_calc_ctx(ctx)
			pyoppai.apply_mods(b, mod)
			stars, aim, speed, _, _, _, _ = pyoppai.d_calc(dctx, b)
			_, pp, _, _, _ = pyoppai.pp_calc_acc(ctx, aim, speed, b, accuracy, mod)

			err = pyoppai.err(ctx)
			if err:
				print(err)
				pass

			pp_results["pp_" + str(accuracy) + "_" + mods_name[i]] = round(pp)
			i += 1

	return pp_results
Exemplo n.º 2
0
async def find_closest_pp(beatmap, args):
    """ Find the accuracy required to get the given amount of pp from this map. """
    if pyoppai is None:
        return None

    ctx, beatmap_ctx = create_ctx(beatmap)

    # Create the difficulty context for calculating
    diff_ctx = pyoppai.new_d_calc_ctx(ctx)
    mods_bitmask = apply_settings(beatmap_ctx, args)
    stars, aim, speed, _, _, _, _ = pyoppai.d_calc(diff_ctx, beatmap_ctx)

    # Define a partial command for easily setting the pp value by 100s count
    def calc(accuracy: float):
        return pyoppai.pp_calc_acc(ctx, aim, speed, beatmap_ctx, accuracy,
                                   mods_bitmask, args.combo, args.misses,
                                   args.score_version)[1]

    # Find the smallest possible value oppai is willing to give
    min_pp = calc(accuracy=0.0)
    if args.pp <= min_pp:
        raise ValueError(
            "The given pp value is too low (oppai gives **{:.02f}pp** at **0% acc**)."
            .format(min_pp))

    # Calculate the max pp value by using 100% acc
    previous_pp = calc(accuracy=100.0)

    if args.pp >= previous_pp:
        raise ValueError(
            "PP value should be below **{:.02f}pp** for this map.".format(
                previous_pp))

    dec = .05
    acc = 100.0 - dec
    while True:
        current_pp = calc(accuracy=acc)

        # Stop when we find a pp value between the current 100 count and the previous one
        if current_pp <= args.pp <= previous_pp:
            break
        else:
            previous_pp = current_pp
            acc -= dec

    # Find the closest pp of our two values, and return the amount of 100s
    closest_pp = min([previous_pp, current_pp], key=lambda v: abs(args.pp - v))
    acc = acc if closest_pp == current_pp else acc + dec
    return ClosestPPStats(round(acc, 2), closest_pp, stars,
                          pyoppai.artist(beatmap_ctx),
                          pyoppai.title(beatmap_ctx),
                          pyoppai.version(beatmap_ctx))
Exemplo n.º 3
0
async def calculate_pp(beatmap_url_or_id, *options):
    """ Return a PPStats namedtuple from this beatmap, or a ClosestPPStats namedtuple
    when [pp_value]pp is given in the options.

    :param beatmap_url_or_id: beatmap_url as str or the id as int
    """
    if pyoppai is None:
        return None

    beatmap = await download_beatmap(beatmap_url_or_id)

    args = parse_options(*options)

    # If the pp arg is given, return using the closest pp function
    if args.pp is not None:
        return await find_closest_pp(beatmap, args)

    ctx, beatmap_ctx = create_ctx(beatmap)

    # Create the difficulty context for calculating
    diff_ctx = pyoppai.new_d_calc_ctx(ctx)
    mods_bitmask = apply_settings(beatmap_ctx, args)
    stars, aim, speed, _, _, _, _ = pyoppai.d_calc(diff_ctx, beatmap_ctx)

    # Calculate using only acc when acc is specified
    if args.acc < 100:
        acc, pp, _, _, _ = pyoppai.pp_calc_acc(ctx, aim, speed, beatmap_ctx,
                                               args.acc, mods_bitmask,
                                               args.combo, args.misses,
                                               args.score_version)
    else:
        acc, pp, _, _, _ = pyoppai.pp_calc(ctx, aim, speed, beatmap_ctx,
                                           mods_bitmask, args.combo,
                                           args.misses, args.c300, args.c100,
                                           args.c50, args.score_version)

    return PPStats(
        pp,
        stars,
        pyoppai.artist(beatmap_ctx),
        pyoppai.title(beatmap_ctx),
        pyoppai.version(beatmap_ctx),
    )
Exemplo n.º 4
0
async def py_oppai(map_id: str,
                   accs=[100],
                   mods=0,
                   misses=0,
                   combo=None,
                   fc=None):
    url = 'https://osu.ppy.sh/osu/{}'.format(map_id)

    # try:
    ctx = pyoppai.new_ctx()
    b = pyoppai.new_beatmap(ctx)

    BUFSIZE = 2000000
    buf = pyoppai.new_buffer(BUFSIZE)

    file_path = 'data/osu/temp/{}.osu'.format(map_id)  # some unique filepath
    await download_file(url,
                        file_path)  # this is the file name that it downloaded
    pyoppai.parse(file_path, b, buf, BUFSIZE, True, 'data/osu/cache/')
    dctx = pyoppai.new_d_calc_ctx(ctx)
    pyoppai.apply_mods(b, mods)

    stars, aim, speed, _, _, _, _ = pyoppai.d_calc(dctx, b)
    cs, od, ar, hp = pyoppai.stats(b)

    if not combo:
        combo = pyoppai.max_combo(b)

    total_pp_list = []
    aim_pp_list = []
    speed_pp_list = []
    acc_pp_list = []

    for acc in accs:
        accurracy, pp, aim_pp, speed_pp, acc_pp = pyoppai.pp_calc_acc(
            ctx, aim, speed, b, acc, mods, combo, misses)
        total_pp_list.append(pp)
        aim_pp_list.append(aim_pp)
        speed_pp_list.append(speed_pp)
        acc_pp_list.append(acc_pp)

    if fc:
        _, fc_pp, _, _, _ = pyoppai.pp_calc_acc(ctx, aim, speed, b, fc, mods,
                                                pyoppai.max_combo(b), 0)
        total_pp_list.append(fc_pp)

    pyoppai_json = {
        'version': pyoppai.version(b),
        'title': pyoppai.title(b),
        'artist': pyoppai.artist(b),
        'creator': pyoppai.creator(b),
        'combo': combo,
        'misses': misses,
        'max_combo': pyoppai.max_combo(b),
        'mode': pyoppai.mode(b),
        'num_objects': pyoppai.num_objects(b),
        'num_circles': pyoppai.num_circles(b),
        'num_sliders': pyoppai.num_sliders(b),
        'num_spinners': pyoppai.num_spinners(b),
        'stars': stars,
        'aim_stars': aim,
        'speed_stars': speed,
        'pp': total_pp_list,  # list
        'aim_pp': aim_pp_list,
        'speed_pp': speed_pp_list,
        'acc_pp': acc_pp_list,
        'acc': accs,  # list
        'cs': cs,
        'od': od,
        'ar': ar,
        'hp': hp
    }

    os.remove(file_path)
    return pyoppai_json
Exemplo n.º 5
0
            data.append(beatmap_info['creator'])
            data.append(beatmap_info['artist'])
            data.append(str(beatmap_info['approved'] == BeatmapStatus.ranked))

            if beatmap_info['mode'] == OsuMode.osu:
                ctx = pyoppai.new_ctx()
                buf = pyoppai.new_buffer(BUFSIZE)
                b = pyoppai.new_beatmap(ctx)
                for accuracy in accuracys:

                    for mod in mods:
                        pyoppai.parse(downloadDirr + "/" + beatmap, b, buf,
                                      BUFSIZE, False, downloadDirr)
                        dctx = pyoppai.new_d_calc_ctx(ctx)
                        pyoppai.apply_mods(b, mod)
                        stars, aim, speed, _, _, _, _ = pyoppai.d_calc(dctx, b)
                        acc, pp, aim_pp, speed_pp, acc_pp = pyoppai.pp_calc_acc(
                            ctx, aim, speed, b, accuracy, mod)
                        try:
                            data.append(round(pp))
                        except OverflowError:  #If pp = infinite
                            data.append(
                                2147483647)  #max sqlite int 4 bytes value

                if pyoppai.err(ctx) != "Could not find General info":
                    try:
                        cursor.execute(
                            "INSERT INTO beatmaps (beatmapId ,songId ,diff_params ,stars ,combo ,bpm ,lenght ,drain ,version ,title ,creator ,artist ,ranked ,PP_100 ,PP_100_HR ,PP_100_HD ,PP_100_DT ,PP_100_DTHD ,PP_100_DTHR ,PP_100_HRHD ,PP_100_DTHRHD ,PP_99 ,PP_99_HR ,PP_99_HD ,PP_99_DT ,PP_99_DTHD ,PP_99_DTHR ,PP_99_HRHD ,PP_99_DTHRHD ,PP_98 ,PP_98_HR ,PP_98_HD ,PP_98_DT ,PP_98_DTHD ,PP_98_DTHR ,PP_98_HRHD ,PP_98_DTHRHD ,PP_97 ,PP_97_HR ,PP_97_HD ,PP_97_DT ,PP_97_DTHD ,PP_97_DTHR ,PP_97_HRHD ,PP_97_DTHRHD) VALUES("
                            + "?," * 44 + " ?)", data)
                        conn.commit()
                    except sqlite3.IntegrityError:
Exemplo n.º 6
0
def main(mod,filepath):

    # if you need to multithread, create one ctx and buffer for each thread
    ctx = pyoppai.new_ctx()

    # parse beatmap ------------------------------------------------------------
    b = pyoppai.new_beatmap(ctx)

    BUFSIZE = 2000000 # should be big enough to hold the .osu file
    buf = pyoppai.new_buffer(BUFSIZE)

    pyoppai.parse(
        filepath,
        b,
        buf,
        BUFSIZE,

        # don't disable caching and use python script's folder for caching
        False,
        os.path.dirname(os.path.realpath(__file__))
    );

    chk(ctx)
    if not mod:
        # diff calc ----------------------------------------------------------------
        dctx = pyoppai.new_d_calc_ctx(ctx)

        stars, aim, speed, _, _, _, _ = pyoppai.d_calc(dctx, b)
        chk(ctx)


        # pp calc ------------------------------------------------------------------
        acc, pp, aim_pp, speed_pp, acc_pp = \
                pyoppai.pp_calc(ctx, aim, speed, b)

        chk(ctx)


        # pp calc (with acc %) -----------------------------------------------------
        acc, pp95, aim_pp, speed_pp, acc_pp = \
            pyoppai.pp_calc_acc(ctx, aim, speed, b, 95.0)

        chk(ctx)

        result=[stars,pp,pp95]
        return (result)
    
    else:
        dctx = pyoppai.new_d_calc_ctx(ctx)
        # mods are a bitmask, same as what the osu! api uses
        mods = pyoppai.dt
        pyoppai.apply_mods(b, mods)

        # mods are map-changing, recompute diff
        stars, aim, speed, _, _, _, _ = pyoppai.d_calc(dctx, b)
        chk(ctx)


        acc, pp, aim_pp, speed_pp, acc_pp = \
                pyoppai.pp_calc(ctx, aim, speed, b, mods)

        chk(ctx)


            # pp calc (with acc %) -----------------------------------------------------
        acc, pp95, aim_pp, speed_pp, acc_pp = \
            pyoppai.pp_calc_acc(ctx, aim, speed, b, 95.0)

        chk(ctx)

        result=[stars,pp,pp95]
        return (result)
Exemplo n.º 7
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 = "{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
Exemplo n.º 8
0
def main():
    if len(sys.argv) != 2:
        print("Usage: " + sys.argv[0] + " file.osu")
        sys.exit(1)

    # if you need to multithread, create one ctx and buffer for each thread
    ctx = pyoppai.new_ctx()

    # parse beatmap ------------------------------------------------------------
    b = pyoppai.new_beatmap(ctx)

    BUFSIZE = 2000000 # should be big enough to hold the .osu file
    buf = pyoppai.new_buffer(BUFSIZE)

    pyoppai.parse(
        sys.argv[1],
        b,
        buf,
        BUFSIZE,

        # don't disable caching and use python script's folder for caching
        False,
        os.path.dirname(os.path.realpath(__file__))
    );

    chk(ctx)

    print("Cache folder: " + os.path.dirname(os.path.realpath(__file__)) + "\n")

    cs, od, ar, hp = pyoppai.stats(b)

    print(
        "%s - %s [%s] (by %s)\n"
        "CS%g OD%g AR%g HP%g\n"
        "%d objects (%d circles, %d sliders, %d spinners)\n"
        "max combo: %d" %
        (
            pyoppai.artist(b),
            pyoppai.title(b),
            pyoppai.version(b),
            pyoppai.creator(b),
            cs, od, ar, hp,
            pyoppai.num_objects(b),
            pyoppai.num_circles(b),
            pyoppai.num_sliders(b),
            pyoppai.num_spinners(b),
            pyoppai.max_combo(b)
        )
    )

    # diff calc ----------------------------------------------------------------
    dctx = pyoppai.new_d_calc_ctx(ctx)

    stars, aim, speed, _, _, _, _ = pyoppai.d_calc(dctx, b)
    chk(ctx)

    print_diff(stars, aim, speed)

    # pp calc ------------------------------------------------------------------
    acc, pp, aim_pp, speed_pp, acc_pp = \
            pyoppai.pp_calc(ctx, aim, speed, b)

    chk(ctx)

    print_pp(acc, pp, aim_pp, speed_pp, acc_pp)

    # pp calc (with acc %) -----------------------------------------------------
    acc, pp, aim_pp, speed_pp, acc_pp = \
        pyoppai.pp_calc_acc(ctx, aim, speed, b, 90.0)

    chk(ctx)

    print_pp(acc, pp, aim_pp, speed_pp, acc_pp)

    # override OD example ------------------------------------------------------
    print("\n----\nIf the map was od10:")
    pyoppai.set_od(b, 10)

    acc, pp, aim_pp, speed_pp, acc_pp = \
            pyoppai.pp_calc(ctx, aim, speed, b)

    chk(ctx)

    print_pp(acc, pp, aim_pp, speed_pp, acc_pp)

    pyoppai.set_od(b, od)

    # override AR example ------------------------------------------------------
    print("\n----\nIf the map was ar11:")
    pyoppai.set_ar(b, 11)

    acc, pp, aim_pp, speed_pp, acc_pp = \
            pyoppai.pp_calc(ctx, aim, speed, b)

    chk(ctx)

    print_pp(acc, pp, aim_pp, speed_pp, acc_pp)

    pyoppai.set_ar(b, ar)

    # override CS example ------------------------------------------------------
    print("\n----\nIf the map was cs6.5:")
    pyoppai.set_cs(b, 6.5)

    # remember that CS is map-changing so difficulty must be recomputed
    stars, aim, speed, _, _, _, _ = pyoppai.d_calc(dctx, b)
    chk(ctx)

    print_diff(stars, aim, speed)

    acc, pp, aim_pp, speed_pp, acc_pp = \
            pyoppai.pp_calc(ctx, aim, speed, b)

    chk(ctx)

    print_pp(acc, pp, aim_pp, speed_pp, acc_pp)

    pyoppai.set_cs(b, cs)

    # mods example -------------------------------------------------------------
    print("\n----\nWith HDHR:")

    # mods are a bitmask, same as what the osu! api uses
    mods = pyoppai.hd | pyoppai.hr
    pyoppai.apply_mods(b, mods)

    # mods are map-changing, recompute diff
    stars, aim, speed, _, _, _, _ = pyoppai.d_calc(dctx, b)
    chk(ctx)

    print_diff(stars, aim, speed)

    acc, pp, aim_pp, speed_pp, acc_pp = \
            pyoppai.pp_calc(ctx, aim, speed, b, mods)

    chk(ctx)

    print_pp(acc, pp, aim_pp, speed_pp, acc_pp)