async def _with(p: Player, c: Messageable, msg: Sequence[str]) -> str: """Specify custom accuracy & mod combinations with `/np`.""" if isinstance(c, Channel) or c.id != 1: return 'This command can only be used in DM with Aika.' if not p.last_np: return 'Please /np a map first!' # +?<mods> <acc>%? if 1 < len(msg) > 2: return 'Invalid syntax: !with <mods/acc> ...' mods = acc = None for param in (p.strip('+%') for p in msg): if cmyui._isdecimal(param, _float=True): acc = float(param) elif ~len(param) & 1: # len(param) % 2 == 0 mods = Mods.from_str(param) else: return 'Invalid syntax: !with <mods/acc> ...' _msg = [p.last_np.embed] if not mods: mods = Mods.NOMOD _msg.append(repr(mods)) if acc: # they're requesting pp for specified acc value. async with Owoppai(p.last_np.id, acc=acc, mods=mods) as owo: await owo.calc() pp_values = [(owo.acc, owo.pp)] else: # they're requesting pp for general accuracy values. if mods not in p.last_np.pp_cache: # cache await p.last_np.cache_pp(mods) pp_values = zip( (90, 95, 98, 99, 100), p.last_np.pp_cache[mods] ) pp_msg = ' | '.join(f'{acc:.2f}%: {pp:.2f}pp' for acc, pp in pp_values) return f"{' '.join(_msg)}: {pp_msg}"
async def _with(p: 'Player', c: Messageable, msg: Sequence[str]) -> str: """Specify custom accuracy & mod combinations with `/np`.""" if c is not glob.bot: return 'This command can only be used in DM with Aika.' if not p.last_np: return 'Please /np a map first!' # +?<mods> <acc>%? if 1 < len(msg) > 2: return 'Invalid syntax: !with <mods/acc> ...' mods = acc = None for param in (p.strip('+%') for p in msg): if cmyui._isdecimal(param, _float=True): if not 0 <= (acc := float(param)) <= 100: return 'Invalid accuracy.' elif ~len(param) & 1: # len(param) % 2 == 0 mods = Mods.from_str(param)
return data, 'no' if not (r := regexes.osu_ver.match(s[0])): # invalid client version? return packets.userID(-2), 'no' osu_ver = dt(year=int(r['ver'][0:4]), month=int(r['ver'][4:6]), day=int(r['ver'][6:8])) if int(r['ver']) < 20210125: return (packets.versionUpdateForced() + packets.userID(-2)), 'no' if osu_ver < (dt.now() - td(60)): return (packets.versionUpdateForced() + packets.userID(-2)), 'no' if not _isdecimal(s[1], _negative=True): # utc-offset isn't a number (negative inclusive). return packets.userID(-1), 'no' utc_offset = int(s[1]) #display_city = s[2] == '1' # Client hashes contain a few values useful to us. # [0]: md5(osu path) # [1]: adapters (network physical addresses delimited by '.') # [2]: md5(adapters) # [3]: md5(uniqueid) (osu! uninstall id) # [4]: md5(uniqueid2) (disk signature/serial num) client_hashes = s[3].split(':')[:-1] client_hashes.pop(1) # no need for non-md5 adapters if client_hashes in ("f11423b10398dfbd7d460ab49615e997",
# quite a bit faster than using dt.strptime. osu_ver = dt(year=int(r['ver'][0:4]), month=int(r['ver'][4:6]), day=int(r['ver'][6:8])) # disallow the login if their osu! client is older # than two months old, forcing an update re-check. # NOTE: this is disabled on debug since older clients # can sometimes be quite useful when testing. if not glob.config.debug: if osu_ver < (dt.now() - td(60)): return (packets.versionUpdateForced() + packets.userID(-2)), 'no' # ensure utc_offset is a number (negative inclusive). if not _isdecimal(client_info[1], _negative=True): return # invalid request utc_offset = int(client_info[1]) #display_city = client_info[2] == '1' # Client hashes contain a few values useful to us. # [0]: md5(osu path) # [1]: adapters (network physical addresses delimited by '.') # [2]: md5(adapters) # [3]: md5(uniqueid) (osu! uninstall id) # [4]: md5(uniqueid2) (disk signature/serial num) if len(client_hashes := client_info[3].split(':')[:-1]) != 5: return # invalid request client_hashes.pop(1) # no need for non-md5 adapters