class SendPrivateMessage(BanchoPacket, type=Packets.OSU_SEND_PRIVATE_MESSAGE): msg: osuTypes.message async def handle(self, p: Player) -> None: if p.silenced: log(f'{p} tried to send a dm while silenced.', Ansi.YELLOW) return msg = self.msg.msg target = self.msg.target # allow this to get from sql - players can receive # messages offline, due to the mail system. B) if not (t := await glob.players.get(name=target, sql=True)): log(f'{p} tried to write to non-existent user {target}.', Ansi.YELLOW) return if t.pm_private and p.id not in t.friends: p.enqueue(packets.userDMBlocked(target)) log(f'{p} tried to message {t}, but they are blocking dms.') return if t.silenced: # if target is silenced, inform player. p.enqueue(packets.targetSilenced(target)) log(f'{p} tried to message {t}, but they are silenced.') return msg = f'{msg[:2045]}...' if msg[2048:] else msg if t.status.action == Action.Afk and t.away_msg: # send away message if target is afk and has one set. await p.send(t, t.away_msg) if t is glob.bot: # may have a command in the message. cmd = (msg.startswith(glob.config.command_prefix) and await commands.process_commands(p, t, msg)) if cmd: # command triggered, send response if any. if 'resp' in cmd: await p.send(t, cmd['resp']) else: # no commands triggered. if match := regexes.now_playing.match(msg): # user is /np'ing a map. # save it to their player instance # so we can use this elsewhere owo.. p.last_np = await Beatmap.from_bid(int(match['bid'])) if p.last_np: if match['mods']: # [1:] to remove leading whitespace mods = Mods.from_np(match['mods'][1:]) else: mods = Mods.NOMOD if mods not in p.last_np.pp_cache: await p.last_np.cache_pp(mods) # since this is a DM to the bot, we should # send back a list of general PP values. # TODO: !acc and !mods in commands to # modify these values :P _msg = [p.last_np.embed] if mods: _msg.append(f'+{mods!r}') msg = f"{' '.join(_msg)}: " + ' | '.join([ f'{acc}%: {pp:.2f}pp' for acc, pp in zip((90, 95, 98, 99, 100), p.last_np.pp_cache[mods]) ]) else: msg = 'Could not find map.' await p.send(t, msg)
class SendPrivateMessage(ClientPacket, type=ClientPacketType.SEND_PRIVATE_MESSAGE): msg = osuTypes.message async def handle(self, p: Player) -> None: if p.silenced: log(f'{p} tried to send a dm while silenced.', Ansi.YELLOW) return msg = self.msg.msg target = self.msg.target if not (t := await glob.players.get_by_name(target)): log(f'{p} tried to write to non-existant user {target}.', Ansi.YELLOW) return if t.pm_private and p.id not in t.friends: p.enqueue(packets.userPMBlocked(target)) log(f'{p} tried to message {t}, but they are blocking dms.') return if t.silenced: p.enqueue(packets.targetSilenced(target)) log(f'{p} tried to message {t}, but they are silenced.') return msg = f'{msg[:2045]}...' if msg[2048:] else msg client, client_id = p.name, p.id if t.status.action == Action.Afk and t.away_msg: # send away message if target is afk and has one set. p.enqueue( packets.sendMessage(client, t.away_msg, target, client_id)) if t.id == 1: # target is the bot, check if message is a command. cmd = msg.startswith(glob.config.command_prefix) \ and await commands.process_commands(p, t, msg) if cmd and 'resp' in cmd: # command triggered and there is a response to send. p.enqueue( packets.sendMessage(t.name, cmd['resp'], client, t.id)) else: # no commands triggered. if match := regexes.now_playing.match(msg): # user is /np'ing a map. # save it to their player instance # so we can use this elsewhere owo.. p.last_np = await Beatmap.from_bid(int(match['bid'])) if p.last_np: if match['mods']: # [1:] to remove leading whitespace mods = Mods.from_np(match['mods'][1:]) else: mods = Mods.NOMOD if mods not in p.last_np.pp_cache: await p.last_np.cache_pp(mods) # since this is a DM to the bot, we should # send back a list of general PP values. # TODO: !acc and !mods in commands to # modify these values :P _msg = [p.last_np.embed] if mods: _msg.append(f'{mods!r}') msg = f"{' '.join(_msg)}: " + ' | '.join( f'{acc}%: {pp:.2f}pp' for acc, pp in zip((90, 95, 98, 99, 100 ), p.last_np.pp_cache[mods])) else: msg = 'Could not find map.' p.enqueue(packets.sendMessage(t.name, msg, client, t.id))
class SendPrivateMessage(BanchoPacket, type=Packets.OSU_SEND_PRIVATE_MESSAGE): msg: osuTypes.message async def handle(self, p: Player) -> None: if p.silenced: log(f'{p} tried to send a dm while silenced.', Ansi.LYELLOW) return # remove leading/trailing whitespace msg = self.msg.msg.strip() t_name = self.msg.target # allow this to get from sql - players can receive # messages offline, due to the mail system. B) if not (t := await glob.players.get_ensure(name=t_name)): log(f'{p} tried to write to non-existent user {t_name}.', Ansi.LYELLOW) return if t.pm_private and p.id not in t.friends: p.enqueue(packets.userDMBlocked(t_name)) log(f'{p} tried to message {t}, but they are blocking dms.') return if t.silenced: # if target is silenced, inform player. p.enqueue(packets.targetSilenced(t_name)) log(f'{p} tried to message {t}, but they are silenced.') return # limit message length to 2k chars # perhaps this could be dangerous with !py..? if len(msg) > 2000: msg = f'{msg[:2000]}... (truncated)' p.enqueue( packets.notification('Your message was truncated\n' '(exceeded 2000 characters).')) if t.status.action == Action.Afk and t.away_msg: # send away message if target is afk and has one set. p.send(t.away_msg, sender=t) if t is glob.bot: # may have a command in the message. cmd = (msg.startswith(glob.config.command_prefix) and await commands.process_commands(p, t, msg)) if cmd: # command triggered, send response if any. if 'resp' in cmd: p.send(cmd['resp'], sender=t) else: # no commands triggered. if match := regexes.now_playing.match(msg): # user is /np'ing a map. # save it to their player instance # so we can use this elsewhere owo.. bmap = await Beatmap.from_bid(int(match['bid'])) if bmap: # parse mode_vn int from regex if match['mode_vn'] is not None: mode_vn = { 'Taiko': 1, 'CatchTheBeat': 2, 'osu!mania': 3 }[match['mode_vn']] else: # use beatmap mode if not specified mode_vn = bmap.mode.as_vanilla p.last_np = { 'bmap': bmap, 'mode_vn': mode_vn, 'timeout': time.time() + 300 # 5mins } # calc pp if possible if not glob.oppai_built: msg = 'No oppai-ng binary was found at startup.' elif mode_vn not in (0, 1): msg = 'PP not yet supported for that mode.' else: if match['mods'] is not None: # [1:] to remove leading whitespace mods = Mods.from_np(match['mods'][1:], mode_vn) else: mods = Mods.NOMOD if mods not in bmap.pp_cache: await bmap.cache_pp(mods) # since this is a DM to the bot, we should # send back a list of general PP values. _msg = [bmap.embed] if mods: _msg.append(f'+{mods!r}') msg = f"{' '.join(_msg)}: " + ' | '.join([ f'{acc}%: {pp:.2f}pp' for acc, pp in zip((90, 95, 98, 99, 100), bmap.pp_cache[mods]) ]) else: msg = 'Could not find map.' # time out their previous /np p.last_np['timeout'] = 0 p.send(msg, sender=t)
return client, msg, target, client_id = pr.read(osuTypes.message) if not (t := glob.players.get_by_name(target)): printlog(f'{p} tried to write to non-existant user {target}.', Ansi.YELLOW) return if t.pm_private and p.id not in t.friends: p.enqueue(packets.userPMBlocked(target)) printlog(f'{p} tried to message {t}, but they are blocking dms.') return if t.silenced: p.enqueue(packets.targetSilenced(target)) printlog(f'{p} tried to message {t}, but they are silenced.') return msg = f'{msg[:2045]}...' if msg[2048:] else msg client, client_id = p.name, p.id if t.status.action == Action.Afk and t.away_msg: # Send away message if target is afk and has one set. p.enqueue(packets.sendMessage(client, t.away_msg, target, client_id)) if t.id == 1: # Target is Aika, check if message is a command. cmd = msg.startswith(glob.config.command_prefix) \ and commands.process_commands(p, t, msg)