def net_cmd_ee(self, args): """Edits a piece of evidence. EE#<id: int>#<name: string>#<description: string>#<image: string>#% """ if not self.client.is_checked: return if not self.validate_net_cmd(args, self.ArgType.INT, self.ArgType.STR_OR_EMPTY, self.ArgType.STR_OR_EMPTY, self.ArgType.STR_OR_EMPTY): return elif len(args) < 4: return evi = (args[1], args[2], args[3], 'all') self.client.area.evi_list.edit_evidence( self.client, self.client.evi_list[int(args[0])], evi) self.client.area.add_to_evidlog(self.client, 'edited evidence') database.log_room('evidence.edit', self.client, self.client.area) self.client.area.broadcast_evidence_list()
def ooc_cmd_undisemvowel(client, arg): """ Give back the freedom of vowels to a user. Usage: /undisemvowel <id> """ if len(arg) == 0: raise ArgumentError('You must specify a target.') try: targets = client.server.client_manager.get_targets( client, TargetType.ID, int(arg), False) except: raise ArgumentError( 'You must specify a target. Use /undisemvowel <id>.') if targets: for c in targets: database.log_room('undisemvowel', client, client.area, target=c) c.disemvowel = False client.send_ooc(f'Undisemvowelled {len(targets)} existing client(s).') else: client.send_ooc('No targets found.')
def ooc_cmd_bglock(client, arg): """ Toggle whether or not non-moderators are allowed to change the background of a room. Usage: /bglock """ if len(arg) != 0: raise ArgumentError('This command has no arguments.') # XXX: Okay, what? if client.area.bg_lock == "true": client.area.bg_lock = "false" else: client.area.bg_lock = "true" client.area.broadcast_ooc( '{} [{}] has set the background lock to {}.'.format( client.char_name, client.id, client.area.bg_lock)) database.log_room('bglock', client, client.area, message=client.area.bg_lock)
def net_cmd_pe(self, args): """Adds a piece of evidence. PE#<name: string>#<description: string>#<image: string>#% :param args: """ if not self.client.is_checked: return if not self.validate_net_cmd(args, self.ArgType.STR_OR_EMPTY, self.ArgType.STR_OR_EMPTY, self.ArgType.STR_OR_EMPTY): return if len(args) < 3: return # evi = Evidence(args[0], args[1], args[2], self.client.pos) self.client.area.evi_list.add_evidence(self.client, args[0], args[1], args[2], 'all') self.client.area.add_to_evidlog(self.client, 'added evidence') database.log_room('evidence.add', self.client, self.client.area) self.client.area.broadcast_evidence_list()
def ooc_cmd_invite(client, arg): """ Allow a particular user to join a locked or spectator-only area. Usage: /invite <id> """ if not arg: raise ClientError('You must specify a target. Use /invite <id>') elif client.area.is_locked == client.area.Locked.FREE: raise ClientError('Area isn\'t locked.') try: c = client.server.client_manager.get_targets(client, TargetType.ID, int(arg), False)[0] client.area.invite_list[c.id] = None client.send_ooc('{} is invited to your area.'.format( c.char_name)) c.send_ooc( f'You were invited and given access to {client.area.name}.') database.log_room('invite', client, client.area, target=c) except: raise ClientError('You must specify a target. Use /invite <id>')
def ooc_cmd_unblockwtce(client, arg): """ Allow a user to use WT/CE again. Usage: /unblockwtce <id> """ if len(arg) == 0: raise ArgumentError( 'You must specify a target. Use /unblockwtce <id>.') try: targets = client.server.client_manager.get_targets( client, TargetType.ID, int(arg), False) except: raise ArgumentError('You must enter a number. Use /unblockwtce <id>.') if not targets: raise ArgumentError('Target not found. Use /unblockwtce <id>.') for target in targets: target.can_wtce = True target.send_ooc('A moderator unblocked you from using judge signs.') database.log_room('unblockwtce', client, client.area, target=target) client.send_ooc('unblockwtce\'d {}.'.format(targets[0].char_name))
def ooc_cmd_blockdj(client, arg): """ Prevent a user from changing music. Usage: /blockdj <id> """ if len(arg) == 0: raise ArgumentError('You must specify a target. Use /blockdj <id>.') try: targets = client.server.client_manager.get_targets( client, TargetType.ID, int(arg), False) except: raise ArgumentError('You must enter a number. Use /blockdj <id>.') if not targets: raise ArgumentError('Target not found. Use /blockdj <id>.') for target in targets: target.is_dj = False target.send_ooc('A moderator muted you from changing the music.') database.log_room('blockdj', client, client.area, target=target) target.area.remove_jukebox_vote(target, True) client.send_ooc('blockdj\'d {}.'.format(targets[0].char_name))
def ooc_cmd_blockwtce(client, arg): """ Prevent a user from using Witness Testimony/Cross Examination buttons as a judge. Usage: /blockwtce <id> """ if len(arg) == 0: raise ArgumentError('You must specify a target. Use /blockwtce <id>.') try: targets = client.server.client_manager.get_targets( client, TargetType.ID, int(arg), False) except: raise ArgumentError('You must enter a number. Use /blockwtce <id>.') if not targets: raise ArgumentError('Target not found. Use /blockwtce <id>.') for target in targets: target.can_wtce = False target.send_ooc('A moderator blocked you from using judge signs.') database.log_room('blockwtce', client, client.area, target=target) client.send_ooc('blockwtce\'d {}.'.format(targets[0].char_name))
def ooc_cmd_hubstatus(client, arg: str) -> None: """ Changes a hub and all it's subareas to specified status. Usage: /hubstatus <idle|rp|casing|looking-for-players|lfp|recess|gaming> """ if 'CM' not in client.area.evidence_mod: raise ClientError('You can\'t change the status of this area') if client.area.is_hub and not client in client.area.owners: raise ClientError('Must be CM.') else: try: client.area.hub_status(arg) client.area.broadcast_ooc('{} changed status to {}.'.format( client.char_name, client.area.status)) for sub in client.area.subareas: sub.broadcast_ooc('{} changed status to {}.'.format( client.char_name, client.area.status)) database.log_room('hubstatus', client, client.area, message=arg) except AreaError: raise
def ooc_cmd_rollp(client, arg): """ Roll a die privately. Usage: /roll [max value] [rolls] """ roll_max = 11037 if len(arg) != 0: try: val = list(map(int, arg.split(' '))) if not 1 <= val[0] <= roll_max: raise ArgumentError( f'Roll value must be between 1 and {roll_max}.') except ValueError: raise ArgumentError( 'Wrong argument. Use /rollp [<max>] [<num of rolls>]') else: val = [6] if len(val) == 1: val.append(1) if len(val) > 2: raise ArgumentError( 'Too many arguments. Use /rollp [<max>] [<num of rolls>]') if val[1] > 20 or val[1] < 1: raise ArgumentError('Num of rolls must be between 1 and 20') roll = '' for _ in range(val[1]): roll += str(random.randint(1, val[0])) + ', ' roll = roll[:-2] if val[1] > 1: roll = '(' + roll + ')' if client.showname != 0: client.send_ooc('{} ({}) rolled {} out of {}.'.format(client.showname, client.char_name, roll, val[0])) client.area.broadcast_ooc('{}({}) rolled in secret.'.format(client.showname, client.char_name)) else: client.send_ooc('{} rolled {} out of {}.'.format(client.char_name, roll, val[0])) client.area.broadcast_ooc('{} rolled in secret.'.format(client.char_name)) for c in client.area.owners: c.send_ooc('[{}]{} secretly rolled {} out of {}.'.format(client.area.abbreviation, client.char_name, roll, val[0])) database.log_room('rollp', client, client.area, message=f'{roll} out of {val[0]}')
def ooc_cmd_area_kick(client, arg): """ Remove a user from the current area and move them to another area. Usage: /area_kick <id> [destination] """ if client.area.is_locked == client.area.Locked.FREE: raise ClientError('Area isn\'t locked.') if not arg: raise ClientError( 'You must specify a target. Use /area_kick <id> [destination #]') arg = arg.split(' ') targets = client.server.client_manager.get_targets(client, TargetType.ID, int(arg[0]), False) if targets: try: for c in targets: if len(arg) == 1: area = client.server.area_manager.get_area_by_id(int(0)) output = 0 else: try: area = client.server.area_manager.get_area_by_id( int(arg[1])) output = arg[1] except AreaError: raise client.send_ooc( "Attempting to kick {} to area {}.".format( c.char_name, output)) c.change_area(area) c.send_ooc( f"You were kicked from the area to area {output}.") database.log_room('area_kick', client, client.area, target=c, message=output) if client.area.is_locked != client.area.Locked.FREE: client.area.invite_list.pop(c.id) except AreaError: raise except ClientError: raise else: client.send_ooc("No targets found.")
def ooc_cmd_removelink(client, arg): """ Remove a specific HTML link from data. Usage: /removelink <choice> """ links_list = client.server.misc_data if len(arg) == 0: raise ArgumentError('You must specify a link to delete.') arg = arg.lower() if arg in links_list: try: del links_list[arg] client.server.save_miscdata() client.send_ooc(f'Deleted link "{arg}".') database.log_room('link.delete', client, client.area, message=arg) except: raise ClientError('Error, link has not been deleted.') else: raise ArgumentError('Link not found. Use /link to see possible choices.')
def ooc_cmd_evidence_mod(client, arg): """ Change the evidence privilege mode. Refer to the documentation for more information on the function of each mode. Usage: /evidence_mod <FFA|Mods|CM|HiddenCM> """ if not arg or arg == client.area.evidence_mod: client.send_ooc( f'current evidence mod: {client.area.evidence_mod}') elif arg in ['FFA', 'Mods', 'CM', 'HiddenCM']: if client.area.evidence_mod == 'HiddenCM': for i in range(len(client.area.evi_list.evidences)): client.area.evi_list.evidences[i].pos = 'all' client.area.evidence_mod = arg client.send_ooc( f'current evidence mod: {client.area.evidence_mod}') database.log_room('evidence_mod', client, client.area, message=arg) else: raise ArgumentError( 'Wrong Argument. Use /evidence_mod <MOD>. Possible values: FFA, CM, Mods, HiddenCM' )
def change_character(self, char_id, force=False): """ Change the client's character or force the character selection screen to appear for the client. :param char_id: character ID to switch to :param force: whether or not the client is forced to switch to another character if the target character is not available (Default value = False) """ # If it's -1, we want to be the spectator character. if char_id != -1: if not self.server.is_valid_char_id(char_id): raise ClientError('Invalid character ID.') if len(self.charcurse) > 0: if not char_id in self.charcurse: raise ClientError('Character not available.') force = True if not self.area.is_char_available(char_id): if force: for client in self.area.clients: if client.char_id == char_id: client.char_select() else: raise ClientError('Character not available.') old_char = self.char_name self.char_id = char_id self.pos = '' self.area.shadow_status[self.char_id] = [self.ipid, self.hdid] self.send_command('PV', self.id, 'CID', self.char_id) self.area.send_command('CharsCheck', *self.get_available_char_list()) new_char = self.char_name database.log_room('char.change', self, self.area, message={ 'from': old_char, 'to': new_char })
def ooc_cmd_bglock(client, arg: str) -> None: """ Toggle whether or not non-moderators are allowed to change the background of a room. Usage: /bglock """ if client not in client.area.owners and not client.is_mod: raise ClientError('You must be a CM.') if len(arg) != 0: raise ArgumentError('This command has no arguments.') # XXX: Okay, what? if client.area.bg_lock == True: client.area.bg_lock = False else: client.area.bg_lock = True client.area.broadcast_ooc( '{} [{}] has set the background lock to {}.'.format( client.char_name, client.id, client.area.bg_lock)) database.log_room('bglock', client, client.area, message=client.area.bg_lock)
def ooc_cmd_bg(client, arg: str) -> None: """ Set the background of a room. Usage: /bg <background> """ if len(arg) == 0: client.send_ooc(f'Current background is "{client.area.background}".') return if not client.is_mod and client.area.bg_lock == True: raise AreaError("This area's background is locked") try: client.area.change_background(arg) except AreaError: msg = 'custom/' msg += arg try: client.area.change_cbackground(msg) except AreaError: raise client.area.broadcast_ooc( f'{client.char_name} changed the background to {arg}.') database.log_room('bg', client, client.area, message=arg)
def ooc_cmd_jukebox_skip(client, arg): """ Skip the current track. Usage: /jukebox_skip """ if len(arg) != 0: raise ArgumentError('This command has no arguments.') if not client.area.jukebox: raise ClientError('This area does not have a jukebox.') if len(client.area.jukebox_votes) == 0: raise ClientError( 'There is no song playing right now, skipping is pointless.') client.area.start_jukebox() if len(client.area.jukebox_votes) == 1: client.area.broadcast_ooc( '{} [{}] has forced a skip, restarting the only jukebox song.'. format(client.char_name, client.id)) else: client.area.broadcast_ooc( '{} [{}] has forced a skip to the next jukebox song.'.format( client.char_name, client.id)) database.log_room('jukebox_skip', client, client.area)
def ooc_cmd_link(client, arg): """ Show a requested HTML link, a list of links or add/set a link. Usage: /link [choice] Mod usage: /link [choice]: <link> """ links_list = client.server.misc_data max = 10 if len(arg) == 0: msg = 'Links available (use /link <option>):\n' msg += "\n".join(links_list) client.send_ooc(msg) # bit sloppy but shrug elif ':' in arg: if client.is_mod: args = arg.split(': ') args[0] = args[0].lower() args[0] = args[0].strip(' ') if args[0] in links_list: try: client.server.misc_data[args[0]] = args[1] client.server.save_miscdata() client.send_ooc(f'{args[0]} set!') database.log_room(f'link.set "{args[0]}"', client, client.area, message=args[1]) except: raise ArgumentError('Input error, link not set.\nUse /link <choice>: [link]') else: if len(links_list) < max: if args[0].isspace() or args[0] == "": raise ArgumentError('You must enter a link name.') else: try: client.server.misc_data[args[0]] = args[1] client.server.save_miscdata() client.send_ooc(f'Link "{args[0]}" created and set!') database.log_room(f'link.create "{args[0]}"', client, client.area, message=args[1]) except: raise ArgumentError('Input error, link not set.\nUse /link <choice>: [link]') else: raise ClientError('Link list is full!') else: raise ClientError('You must be authorized to do that.') else: arg = arg.lower() choice = arg.capitalize() if arg in links_list: try: if arg == 'update': client.send_ooc('Latest {}: {}'.format(choice, client.server.misc_data[arg])) else: client.send_ooc('{}: {}'.format(choice, client.server.misc_data[arg])) database.log_room('link.request', client, client.area, message=arg) except: raise ClientError('Link has not been set!') else: raise ArgumentError('Link not found. Use /link to see possible choices.')
def ooc_cmd_hubplay(client, arg): """ Play a track. Usage: /play <name> """ if client not in client.area.owners and not client.is_mod: if client.area.sub: if not client in client.area.hub.owners: raise ClientError('You must be a CM.') else: raise ClientError('You must be a CM.') if not client.area.is_hub and not client.area.sub: raise ClientError('Must be in hub.') if len(arg) == 0: raise ArgumentError('Not enough arguments. Use /hubplay <name>.') elif len(arg) > 0: custom = False try: name, length, mod, custom = client.server.get_song_data(arg, client.client.area) except: name = arg length = -1 client.send_ooc('Track not found in area\'s music list, playing directly without length.') if custom: name = f'custom/{arg}' if client.area.is_hub: for sub in client.area.subareas: sub.play_music(name, client.char_id, length) sub.add_music_playing(client, arg) database.log_room('hubplay', client, sub, message=name) return elif client.area.sub: for sub in client.area.hub.subareas: sub.play_music(name, client.char_id, length) sub.add_music_playing(client, arg) database.log_room('hubplay', client, sub, message=name) return
def ooc_cmd_gimp(client, arg): """ Replace every message from a user in IC chat with a message from gimp.yaml. Usage: /disemvowel <id> """ if len(arg) == 0: raise ArgumentError('You must specify a target.') try: targets = client.server.client_manager.get_targets( client, TargetType.ID, int(arg), False) except: raise ArgumentError('You must specify a target. Use /gimp <id>.') if targets: for c in targets: if c.gimp: database.log_room('ungimp', client, client.area, target=c) c.gimp = False client.send_ooc(f'Ungimped {c.char_name}.') else: database.log_room('gimp', client, client.area, target=c) c.gimp = True client.send_ooc(f'Gimped {c.char_name}.') else: client.send_ooc('No targets found.')
def ooc_cmd_roll(client, arg): """ Roll a die. The result is shown publicly. Usage: /roll [max value] [rolls] """ roll_max = 11037 if len(arg) != 0: try: val = list(map(int, arg.split(' '))) if not 1 <= val[0] <= roll_max: raise ArgumentError( f'Roll value must be between 1 and {roll_max}.') except ValueError: raise ArgumentError( 'Wrong argument. Use /roll [<max>] [<num of rolls>]') else: val = [6] if len(val) == 1: val.append(1) if len(val) > 2: raise ArgumentError( 'Too many arguments. Use /roll [<max>] [<num of rolls>]') if val[1] > 20 or val[1] < 1: raise ArgumentError('Num of rolls must be between 1 and 20') roll = '' for _ in range(val[1]): roll += str(random.randint(1, val[0])) + ', ' roll = roll[:-2] if val[1] > 1: roll = '(' + roll + ')' client.area.broadcast_ooc('{} rolled {} out of {}.'.format( client.char_name, roll, val[0])) database.log_room('roll', client, client.area, message=f'{roll} out of {val[0]}')
def net_cmd_mc(self, args): """Play music. MC#<song_name:int>#<???:int>#% """ if not self.client.is_checked: return try: called_function = 'ooc_cmd_area' getattr(commands, called_function)(self.client, args[0]) except AreaError: if self.client.is_muted: # Checks to see if the client has been muted by a mod self.client.send_ooc('You are muted by a moderator.') return if not self.client.is_dj: self.client.send_ooc('You were blockdj\'d by a moderator.') return if self.client.area.cannot_ic_interact(self.client): self.client.send_ooc( "You are not on the area's invite list, and thus, you cannot change music!" ) return if not self.validate_net_cmd(args, self.ArgType.STR, self.ArgType.INT): if not self.validate_net_cmd(args, self.ArgType.STR, self.ArgType.INT, self.ArgType.STR_OR_EMPTY): if not self.validate_net_cmd( args, self.ArgType.STR, self.ArgType.INT, self.ArgType.STR_OR_EMPTY, self.ArgType.INT): if not self.validate_net_cmd( args, self.ArgType.STR, self.ArgType.INT, self.ArgType.STR_OR_EMPTY, self.ArgType.INT, self.ArgType.INT): return if args[1] != self.client.char_id: return if self.client.change_music_cd(): if (len(self.client.area.clients) != 1): self.client.send_ooc( f'You changed the song too many times. Please try again after {int(self.client.change_music_cd())} seconds.' ) return try: if args[0] == "~stop.mp3" or self.server.get_song_is_category( self.server.music_list, args[0]): name, length = "~stop.mp3", 0 else: name, length = self.server.get_song_data( self.server.music_list, args[0]) # Showname info showname = '' if len(args) > 2: showname = args[2] if len( showname ) > 0 and not self.client.area.showname_changes_allowed: self.client.send_ooc( "Showname changes are forbidden in this area!") return # Effects info effects = 0 if len(args) > 3: effects = int(args[3]) # Jukebox check if self.client.area.jukebox: self.client.area.add_jukebox_vote(self.client, name, length, showname) database.log_room('jukebox.vote', self.client, self.client.area, message=name) else: self.client.area.play_music(name, self.client.char_id, length, showname, effects) self.client.area.add_music_playing(self.client, name, showname) database.log_room('music', self.client, self.client.area, message=name) except ServerError: self.client.send_ooc( 'Error: song {} isn\'t recognized by server!'.format( args[0])) except ClientError as ex: self.client.send_ooc(ex)
def net_cmd_ct(self, args): """OOC Message CT#<name:string>#<message:string>#% """ if not self.client.is_checked: return if self.client.is_ooc_muted: # Checks to see if the client has been muted by a mod self.client.send_ooc('You are muted by a moderator.') return if not self.validate_net_cmd( args, self.ArgType.STR, self.ArgType.STR, needs_auth=False): return if self.client.name != args[0] and self.client.fake_name != args[0]: if self.client.is_valid_name(args[0]): self.client.name = args[0] self.client.fake_name = args[0] else: self.client.fake_name = args[0] if self.client.name == '': self.client.send_ooc( 'You must insert a name with at least one letter') return if len(self.client.name) > 30: self.client.send_ooc( 'Your OOC name is too long! Limit it to 30 characters.') return for c in self.client.name: if unicodedata.category(c) == 'Cf': self.client.send_ooc( 'You cannot use format characters in your name!') return if self.client.name.startswith( self.server.config['hostname']) or self.client.name.startswith( '<dollar>G') or self.client.name.startswith('<dollar>M'): self.client.send_ooc('That name is reserved!') return max_char = 0 try: max_char = int(self.server.config['max_chars']) except: max_char = 256 if len(args[1]) > max_char: return if args[1].startswith(' /'): self.client.send_ooc( 'Your message was not sent for safety reasons: you left a space before that slash.' ) return if args[1].startswith('/'): spl = args[1][1:].split(' ', 1) cmd = spl[0].lower() arg = '' if len(spl) == 2: arg = spl[1][:256] try: called_function = f'ooc_cmd_{cmd}' if not hasattr(commands, called_function): self.client.send_ooc('Invalid command.') else: getattr(commands, called_function)(self.client, arg) except (ClientError, AreaError, ArgumentError, ServerError) as ex: self.client.send_ooc(ex) except Exception as ex: self.client.send_ooc( 'An internal error occurred. Please check the server log.') logger.exception('Exception while running a command') else: args[1] = self.dezalgo(args[1]) if self.client.shaken: args[1] = self.client.shake_message(args[1]) if self.client.disemvowel: args[1] = self.client.disemvowel_message(args[1]) self.client.area.send_command('CT', self.client.name, args[1]) self.client.area.send_owner_command( 'CT', '[' + self.client.area.abbreviation + ']' + self.client.name, args[1]) database.log_room('ooc', self.client, self.client.area, message=args[1])
def new_client(self, client): """Add a client to the area.""" self.clients.add(client) self.server.area_manager.send_arup_players() if client.char_id != -1: database.log_room('area.join', client, self)
def net_cmd_mc(self, args): """Play music. MC#<song_name:int>#<???:int>#% """ if not self.client.is_checked: return if not self.client.permission: self.client.send_ooc('You need permission to use a web client, please ask staff.') return try: area = self.server.area_manager.get_area_by_name(args[0], self.client) self.client.change_area(area) except AreaError: try: area = self.client.area.get_sub(args[0]) self.client.change_area(area) except AreaError: try: if self.client.area.sub: area = self.client.area.hub.get_sub(args[0]) self.client.change_area(area) else: area = self.server.area_manager.get_area_by_name(args[0], self.client) self.client.change_area(area) except AreaError: if self.client.is_muted: # Checks to see if the client has been muted by a mod self.client.send_ooc( 'You are muted by a moderator.') return if not self.client.is_dj: self.client.send_ooc( "You were blockdj'd by a moderator.") return if self.client.area.cannot_ic_interact(self.client): self.client.send_ooc("You are not on the area's invite list, and thus, you cannot change music!") return if not self.client.area.allowmusic and self.client not in self.client.area.owners: self.client.send_ooc('The CM has disallowed music changes, ask them to change the music.') return if not self.validate_net_cmd(args, ArgType.STR, ArgType.INT): if not self.validate_net_cmd(args, ArgType.STR, ArgType.INT, ArgType.STR_OR_EMPTY): if not self.validate_net_cmd(args, ArgType.STR, ArgType.INT, ArgType.STR_OR_EMPTY, ArgType.INT): if not self.validate_net_cmd(args, ArgType.STR, ArgType.INT, ArgType.STR_OR_EMPTY, ArgType.INT, ArgType.INT): return if args[1] != self.client.char_id: return if self.client.change_music_cd(): self.client.send_ooc( 'You changed song too many times. Please try again after {} seconds.' .format(int(self.client.change_music_cd()))) return try: if args[0] == "~stop.mp3": name, length, mod, custom = args[0], 0, -1, False else: name, length, mod, custom = self.server.get_song_data(args[0], self.client.area) if not mod == -1: if not self.client.is_mod: self.client.send_host_message("This song is reserved for moderators.") return if self.client.area.jukebox: showname = '' if len(args) > 2: showname = args[2] if len( showname ) > 0 and not self.client.area.showname_changes_allowed: self.client.send_ooc( "Showname changes are forbidden in this area!") return self.client.area.add_jukebox_vote(self.client, name, length, showname) database.log_room('jukebox.vote', self.client, self.client.area, message=name) else: if len(args) > 2: showname = args[2] if len( showname ) > 0 and not self.client.area.showname_changes_allowed: self.client.send_ooc( "Showname changes are forbidden in this area!") return # Effects info effects = 0 if custom: nname = name name = 'custom/' name += nname if len(args) > 3: effects = int(args[3]) self.client.area.play_music_shownamed( name, self.client.char_id, showname, length, effects) self.client.area.add_music_playing_shownamed( self.client, showname, name) else: self.client.area.play_music(name, self.client.char_id, length) self.client.area.add_music_playing(self.client, name) database.log_room('music', self.client, self.client.area, message=name) if self.client.afk: self.client.server.client_manager.toggle_afk(self.client) if self.client.afktime: self.client.afktime.cancel() if self.server.config['afk_delay'] > 0: self.client.afktime = asyncio.get_event_loop().call_later(self.client.server.config['afk_delay'], lambda: client.server.client_manager.toggle_afk(self.client)) except ServerError: return except ClientError as ex: self.client.send_ooc(ex) except ClientError as ex: self.client.send_ooc(ex) except ClientError as ex: self.client.send_ooc(ex)
def net_cmd_ct(self, args): """OOC Message CT#<name:string>#<message:string>#% """ if not self.client.is_checked: return if self.client.is_ooc_muted: # Checks to see if the client has been muted by a mod self.client.send_ooc('You are muted by a moderator.') if self.client.char_id == -1: #Checks if the user is a spectator self.client.send_ooc("Spectators can't use OOC chat.") return if not self.client.permission: self.client.send_ooc('You need permission to use a web client, please ask staff.') return if not self.validate_net_cmd(args, ArgType.STR, ArgType.STR): return if self.client.name != args[0] and self.client.fake_name != args[0]: if self.client.is_valid_name(args[0]): self.client.name = args[0] self.client.fake_name = args[0] else: self.client.fake_name = args[0] if self.client.name == '': self.client.send_ooc( 'You must insert a name with at least one letter') return if len(self.client.name) > 30: self.client.send_ooc( 'Your OOC name is too long! Limit it to 30 characters.') return for c in self.client.name: if unicodedata.category(c) == 'Cf': self.client.send_ooc( 'You cannot use format characters in your name!') return if self.client.name.startswith(self.server.config['hostname']) or self.client.name.startswith('<dollar>G') or self.client.name.startswith('<dollar>M'): self.client.send_ooc('That name is reserved!') return if args[1].startswith(' /'): self.client.send_ooc( 'Your message was not sent for safety reasons: you left a space before that slash.' ) return if args[1].startswith('.'): self.client.send_ooc( 'Your message was not sent for safety reasons: you left a dot before that message.' ) return if len(args[1]) > 300: self.client.send_ooc( 'That message is too long!.' ) return if not args[1].startswith('/') and self.client.ooc_delay != None: if self.client.ooc_delay > time.perf_counter(): self.client.send_ooc('You are trying to send messages too fast!') return if self.client.afk: self.client.server.client_manager.toggle_afk(self.client) if self.client.afktime: self.client.afktime.cancel() if self.server.config['afk_delay'] > 0: self.client.afktime = asyncio.get_event_loop().call_later(self.client.server.config['afk_delay'], lambda: self.client.server.client_manager.toggle_afk(self.client)) if args[1].startswith('/'): spl = args[1][1:].split(' ', 1) cmd = spl[0].lower() arg = '' if len(spl) == 2: arg = spl[1][:256] try: called_function = f'ooc_cmd_{cmd}' if cmd == 'help' and arg != '': self.client.send_ooc(commands.help(f'ooc_cmd_{arg}')) else: getattr(commands, called_function)(self.client, arg) except AttributeError: print('Attribute error with ' + called_function) self.client.send_ooc('Invalid command.') except (ClientError, AreaError, ArgumentError, ServerError) as ex: self.client.send_ooc(ex) except Exception as ex: self.client.send_ooc('An internal error occurred. Please check the server log.') logger.exception('Exception while running a command') else: args[1] = self.dezalgo(args[1]) if self.client.shaken: args[1] = self.client.shake_message(args[1]) if self.client.disemvowel: args[1] = self.client.disemvowel_message(args[1]) self.client.ooc_delay = (time.perf_counter() + self.server.config['ooc_delay']) self.client.area.send_command('CT', self.client.name, args[1]) self.client.area.send_owner_command('CT', '[' + self.client.area.abbreviation + ']' + self.client.name, args[1]) database.log_room('ooc', self.client, self.client.area, message=args[1])
def ooc_cmd_timer(client, arg): """ Manage a countdown timer in the current area. Note that timer of ID 0 is global. All other timer IDs are local to the area (valid IDs are 1 - 4). Usage: /timer <id> [+/-][time] Set the timer's time, optionally adding or subtracting time. If the timer had not been previously set up, it will be shown paused. /timer <id> start /timer <id> <pause|stop> /timer <id> hide """ arg = arg.split() if len(arg) < 1: msg = 'Currently active timers:' # Global timer timer = client.server.area_manager.timer if timer.set: if timer.started: msg += f'\nTimer 0 is at {timer.target - arrow.get()}' else: msg += f'\nTimer 0 is at {timer.static}' # Area timers for timer_id, timer in enumerate(client.area.timers): if timer.set: if timer.started: msg += f'\nTimer {timer_id+1} is at {timer.target - arrow.get()}' else: msg += f'\nTimer {timer_id+1} is at {timer.static}' client.send_ooc(msg) return # TI packet specification: # TI#TimerID#Type#Value#% # TimerID = from 0 to 4 (5 possible timers total) # Type 0 = start/resume/sync timer at time # Type 1 = pause timer at time # Type 2 = show timer # Type 3 = hide timer # Value = Time to set on the timer try: timer_id = int(arg[0]) except: raise ArgumentError('Invalid ID. Usage: /timer <id>') if timer_id < 0 or timer_id > 4: raise ArgumentError('Invalid ID. Usage: /timer <id>') if timer_id == 0: timer = client.server.area_manager.timer else: timer = client.area.timers[timer_id-1] if len(arg) < 2: if timer.set: if timer.started: client.send_ooc(f'Timer {timer_id} is at {timer.target - arrow.get()}') else: client.send_ooc(f'Timer {timer_id} is at {timer.static}') else: client.send_ooc(f'Timer {timer_id} is unset.') return if client not in client.area.owners and not client.is_mod: raise ArgumentError('Only CMs or mods can modify timers. Usage: /timer <id>') if timer_id == 0 and not client.is_mod: raise ArgumentError('Only mods can set the global timer. Usage: /timer <id>') duration = pytimeparse.parse(''.join(arg[1:])) if duration is not None: if timer.set: if timer.started: if not (arg[1] == '+' or duration < 0): timer.target = arrow.get() timer.target = timer.target.shift(seconds=duration) timer.static = timer.target - arrow.get() else: if not (arg[1] == '+' or duration < 0): timer.static = datetime.timedelta(0) timer.static += datetime.timedelta(seconds=duration) else: timer.static = datetime.timedelta(seconds=abs(duration)) timer.set = True if timer_id == 0: client.server.send_all_cmd_pred('TI', timer_id, 2) else: client.area.send_command('TI', timer_id, 2) if not timer.set: raise ArgumentError(f'Timer {timer_id} is not set in this area.') elif arg[1] == 'start': timer.target = timer.static + arrow.get() timer.started = True client.send_ooc(f'Starting timer {timer_id}.') database.log_room('timer.start', client, client.area, message=str(timer_id)) elif arg[1] in ('pause', 'stop'): timer.static = timer.target - arrow.get() timer.started = False client.send_ooc(f'Stopping timer {timer_id}.') database.log_room('timer.stop', client, client.area, message=str(timer_id)) elif arg[1] in ('unset', 'hide'): timer.set = False timer.started = False timer.static = None timer.target = None client.send_ooc(f'Timer {timer_id} unset and hidden.') database.log_room('timer.hide', client, client.area, message=str(timer_id)) if timer_id == 0: client.server.send_all_cmd_pred('TI', timer_id, 3) else: client.area.send_command('TI', timer_id, 3) # Send static time if applicable if timer.set: s = int(not timer.started) static_time = int(timer.static.total_seconds()) * 1000 if timer_id == 0: client.server.send_all_cmd_pred('TI', timer_id, s, static_time) else: client.area.send_command('TI', timer_id, s, static_time) client.send_ooc(f'Timer {timer_id} is at {timer.static}') target = client.area if timer_id == 0: target = client.server.area_manager def timer_expired(): if timer.schedule: timer.schedule.cancel() # Area was destroyed at some point if target is None or timer is None: return target.broadcast_ooc(f'Timer {timer_id} has expired.') timer.static = datetime.timedelta(0) timer.started = False database.log_room('timer.expired', None, target, message=str(timer_id)) if timer.schedule: timer.schedule.cancel() if timer.started: timer.schedule = asyncio.get_event_loop().call_later( int(timer.static.total_seconds()), timer_expired)
def musiclist_shuffle(self, client, track=-1): client = client index = 0 for item in client.area.cmusic_list: if 'songs' in item: for song in item['songs']: index += 1 else: index += 1 if index == 0: client.send_ooc('Area musiclist empty.') return else: music_set = set(range(index)) trackid = random.choice(tuple(music_set)) while trackid == track: trackid = random.choice(tuple(music_set)) index = 0 for item in client.area.cmusic_list: if 'songs' in item: for song in item['songs']: if index == trackid: if song['length'] <= 5: client.send_ooc( 'Track seems to have too little or no length, shuffle canceled.' ) return self.play_music_shownamed( song['name'], client.char_id, 'Custom Shuffle') self.music_looper = asyncio.get_event_loop( ).call_later( song['length'], lambda: self.musiclist_shuffle( client, trackid)) self.add_music_playing(client, song['name']) database.log_room('play', client, self, message=song['name']) return else: index += 1 else: if index == trackid: if item['length'] <= 5: client.send_ooc( 'Track seems to have too little or no length, shuffle canceled.' ) return self.play_music_shownamed(item['name'], client.char_id, 'Custom Shuffle') self.music_looper = asyncio.get_event_loop( ).call_later( item['length'], lambda: self.musiclist_shuffle( client, trackid)) self.add_music_playing(client, item['name']) database.log_room('play', client, self, message=item['name']) return else: index += 1
def music_shuffle(self, arg, client, track=-1): """ Shuffles through tracks randomly, either from entire music list or specific category. """ arg = arg client = client if len(arg) != 0: index = 0 for item in self.server.music_list: if item['category'] == arg: for song in item['songs']: index += 1 if index == 0: client.send_ooc('Category/music not found.') return else: music_set = set(range(index)) trackid = random.choice(tuple(music_set)) while trackid == track: trackid = random.choice(tuple(music_set)) index = 0 for item in self.server.music_list: if item['category'] == arg: for song in item['songs']: if index == trackid: self.play_music_shownamed( song['name'], client.char_id, '{} Shuffle'.format(arg)) self.music_looper = asyncio.get_event_loop( ).call_later( song['length'], lambda: self.music_shuffle( arg, client, trackid)) self.add_music_playing( client, song['name']) database.log_room('play', client, self, message=song['name']) return else: index += 1 else: index = 0 for item in self.server.music_list: for song in item['songs']: index += 1 if index == 0: client.send_ooc('Category/music not found.') return else: music_set = set(range(index)) trackid = random.choice(tuple(music_set)) while trackid == track: trackid = random.choice(tuple(music_set)) index = 0 for item in self.server.music_list: for song in item['songs']: if index == trackid: self.play_music_shownamed( song['name'], client.char_id, 'Random Shuffle') self.music_looper = asyncio.get_event_loop( ).call_later( song['length'], lambda: self.music_shuffle( arg, client, trackid)) self.add_music_playing(client, song['name']) database.log_room('play', client, self, message=song['name']) return else: index += 1
def new_client(self, client): """Add a client to the area.""" self.clients.add(client) lobby = self.server.area_manager.default_area() if self == lobby: for area in self.server.area_manager.areas: if area.is_hub: area.sub_arup_players() for sub in area.subareas: if sub.is_restricted and len(sub.clients) > 0: sub.conn_arup_players() if client.char_id != -1: database.log_room('area.join', client, self) if client.ambiance != self.ambiance: client.ambiance = self.ambiance client.send_command( "MC", self.ambiance, -1, "", 1, 1, int(MusicEffect.FADE_OUT), ) if self.loop: client.send_command( "MC", 'None', -1, "", 0, 0, int(MusicEffect.FADE_OUT), ) client.current_music = self.current_music else: if client.current_music != self.current_music: client.send_command( "MC", self.current_music, -1, "", 1, 0, int(MusicEffect.FADE_OUT), ) client.current_music = self.current_music if self.desc != '': client.send_ooc(self.desc) # Update the timers timer = self.server.area_manager.timer if timer.set: s = int(not timer.started) current_time = timer.static if timer.started: current_time = timer.target - arrow.get() int_time = int(current_time.total_seconds()) * 1000 # Unhide the timer client.send_command('TI', 0, 2) # Start the timer client.send_command('TI', 0, s, int_time) else: # Stop the timer client.send_command('TI', 0, 3, 0) # Hide the timer client.send_command('TI', 0, 1) for timer_id, timer in enumerate(self.timers): # Send static time if applicable if timer.set: s = int(not timer.started) current_time = timer.static if timer.started: current_time = timer.target - arrow.get() int_time = int(current_time.total_seconds()) * 1000 # Start the timer client.send_command('TI', timer_id + 1, s, int_time) # Unhide the timer client.send_command('TI', timer_id + 1, 2) client.send_ooc(f'Timer {timer_id+1} is at {current_time}') else: # Stop the timer client.send_command('TI', timer_id + 1, 1, 0) # Hide the timer client.send_command('TI', timer_id + 1, 3)