def reload(self): with Constants.fopen('config/characters.yaml', 'r') as chars: self.char_list = Constants.yaml_load(chars) with Constants.fopen('config/music.yaml', 'r') as music: self.music_list = Constants.yaml_load(music) self.build_music_pages_ao1() self.build_music_list_ao2() with Constants.fopen('config/backgrounds.yaml', 'r') as bgs: self.backgrounds = Constants.yaml_load(bgs)
def validate(self, file_name, extra_parameters=None): """ Attempt to open the YAML file, parse its contents, then validate Parameters ---------- file_name : str File to open. extra_parameters : dict Any extra parameters to pass to the validator when it wants to modify the contents. Structure of the dict depends on the class implementing validate_contents. Returns ------- contents : Iterable Contents of the YAML file. """ with Constants.fopen(file_name, disallow_parent_folder=True, mode='r', encoding='utf-8') as file: contents = Constants.yaml_load(file) contents = self.validate_contents(contents, extra_parameters=extra_parameters) return contents
def load_config(self): with Constants.fopen('config/config.yaml', 'r', encoding='utf-8') as cfg: self.config = Constants.yaml_load(cfg) self.config['motd'] = self.config['motd'].replace('\\n', ' \n') for i in range(1, 8): daily_gmpass = '******'.format(i) if daily_gmpass not in self.config or not self.config[daily_gmpass]: self.config[daily_gmpass] = None # Default values to fill in config.yaml if not present defaults_for_tags = { 'discord_link': None, 'max_numdice': 20, 'max_numfaces': 11037, 'max_modifier_length': 12, 'max_acceptable_term': 22074, 'def_numdice': 1, 'def_numfaces': 6, 'def_modifier': '', 'blackout_background': 'Blackout_HD', 'default_area_description': 'No description.', 'party_lights_timeout': 10, 'showname_max_length': 30, 'sneak_handicap': 5, 'spectator_name': 'SPECTATOR', 'music_change_floodguard': { 'times_per_interval': 1, 'interval_length': 0, 'mute_length': 0 } } for (tag, value) in defaults_for_tags.items(): if tag not in self.config: self.config[tag] = value # Check that all passwords were generated and that they are unique passwords = [ 'guardpass', 'modpass', 'cmpass', 'gmpass', 'gmpass1', 'gmpass2', 'gmpass3', 'gmpass4', 'gmpass5', 'gmpass6', 'gmpass7' ] for password_type in passwords: if password_type not in self.config: info = ( 'Password "{}" not defined in server/config.yaml. Please make sure it is ' 'set and try again.'.format(password_type)) raise ServerError(info) for (i, password1) in enumerate(passwords): for (j, password2) in enumerate(passwords): if i != j and self.config[password1] == self.config[ password2] != None: info = ( 'Passwords "{}" and "{}" in server/config.yaml match. ' 'Please change them so they are different and try again.' .format(password1, password2)) raise ServerError(info)
def load_iniswaps(self): try: with Constants.fopen('config/iniswaps.yaml', 'r', encoding='utf-8') as iniswaps: self.allowed_iniswaps = Constants.yaml_load(iniswaps) except Exception as ex: message = 'WARNING: Error loading config/iniswaps.yaml. Will assume empty values.\n' message += '{}: {}'.format(type(ex).__name__, ex) logger.log_pdebug(message)
def load_music(self, music_list_file='config/music.yaml', server_music_list=True): with Constants.fopen(music_list_file, 'r', encoding='utf-8') as music: music_list = Constants.yaml_load(music) if server_music_list: self.music_list = music_list self.build_music_pages_ao1() self.build_music_list_ao2(music_list=music_list) return music_list
def load_areas(self, area_list_file='config/areas.yaml'): """ Load an area list. Parameters ---------- area_list_file: str, optional Location of the area list to load. Defaults to 'config/areas.yaml'. Raises ------ AreaError If any one of the following conditions are met: * An area has no 'area' or no 'background' tag. * An area uses the deprecated 'sound_proof' tag. * Two areas have the same name. * An area parameter was left deliberately blank as opposed to fully erased. * An area has a passage to an undefined area. FileNotFound If the area list could not be found. """ self.area_names = set() current_area_id = 0 temp_areas = list() temp_area_names = set() temp_reachable_area_names = set() # Check if valid area list file with Constants.fopen(area_list_file, 'r') as chars: areas = Constants.yaml_load(chars) def_param = { 'afk_delay': 0, 'afk_sendto': 0, 'bglock': False, 'bullet': True, 'cbg_allowed': False, 'change_reachability_allowed': True, 'default_description': self.server.config['default_area_description'], 'evidence_mod': 'FFA', 'gm_iclock_allowed': True, 'has_lights': True, 'iniswap_allowed': False, 'lobby_area': False, 'locking_allowed': False, 'private_area': False, 'reachable_areas': '<ALL>', 'restricted_chars': '', 'rollp_allowed': True, 'rp_getarea_allowed': True, 'rp_getareas_allowed': True, 'scream_range': '', 'song_switch_allowed': False, } # Create the areas for item in areas: # Check required parameters if 'area' not in item: info = 'Area {} has no name.'.format(current_area_id) raise AreaError(info) if 'background' not in item: info = 'Area {} has no background.'.format(item['area']) raise AreaError(info) # Check unset optional parameters for param in def_param: if param not in item: item[param] = def_param[param] # Prevent names that may be interpreted as a directory with . or .. # This prevents sending the client an entry to their music list which may be read as # including a relative directory if False: # Constants.includes_relative_directories(item['area']): info = ( f'Area {item["area"]} could be interpreted as referencing the current or ' f'parent directories, so it is invalid. Please rename the area and try ' f'again.') raise AreaError(info) # Check use of backwards incompatible parameters if 'sound_proof' in item: info = ( 'The sound_proof property was defined for area {}. ' 'Support for sound_proof was removed in favor of scream_range. ' 'Please replace the sound_proof tag with scream_range in ' 'your area list and try again.'.format(item['area'])) raise AreaError(info) # Avoid having areas with the same name if item['area'] in temp_area_names: info = ( 'Two areas have the same name in area list: {}. ' 'Please rename the duplicated areas and try again.'.format( item['area'])) raise AreaError(info) # Check if any of the items were interpreted as Python Nones (maybe due to empty lines) for parameter in item: if item[parameter] is None: info = ( 'Parameter {} is manually undefined for area {}. This can be the case ' 'due to having an empty parameter line in your area list. ' 'Please fix or remove the parameter from the area definition and try ' 'again.'.format(parameter, item['area'])) raise AreaError(info) temp_areas.append(self.Area(current_area_id, self.server, item)) temp_area_names.add(item['area']) temp_reachable_area_names |= temp_areas[-1].reachable_areas current_area_id += 1 # Check if a reachable area is not an area name # Can only be done once all areas are created unrecognized_areas = temp_reachable_area_names - temp_area_names - { '<ALL>' } if unrecognized_areas != set(): info = ( 'The following areas were defined as reachable areas of some areas in the ' 'area list file, but were not actually defined as areas: {}. Please rename the ' 'affected areas and try again.'.format(unrecognized_areas)) raise AreaError(info) # Only once all areas have been created, actually set the corresponding values # Helps avoiding junk area lists if there was an error # But first, remove all zones backup_zones = self.server.zone_manager.get_zones() for (zone_id, zone) in backup_zones.items(): self.server.zone_manager.delete_zone(zone_id) for client in zone.get_watchers(): client.send_ooc('Your zone has been automatically deleted.') old_areas = self.areas self.areas = temp_areas self.area_names = temp_area_names # And cancel all existing day cycles for client in self.server.client_manager.clients: try: client.server.tasker.remove_task(client, ['as_day_cycle']) except KeyError: pass # And remove all global IC and global IC prefixes for client in self.server.client_manager.clients: if client.multi_ic: client.send_ooc( 'Due to an area list reload, your global IC was turned off. You ' 'may turn it on again manually.') client.multi_ic = None if client.multi_ic_pre: client.send_ooc( 'Due to an area list reload, your global IC prefix was removed. ' 'You may set it again manually.') client.multi_ic_pre = '' # If the default area ID is now past the number of available areas, reset it back to zero if self.server.default_area >= len(self.areas): self.server.default_area = 0 for area in old_areas: # Decide whether the area still exists or not try: new_area = self.get_area_by_name(area.name) remains = True except AreaError: new_area = self.default_area() remains = False # Move existing clients to new corresponding area (or to default area if their previous # area no longer exists). for client in area.clients.copy(): # Check if current char is available if new_area.is_char_available(client.char_id): new_char_id = client.char_id else: try: new_char_id = new_area.get_rand_avail_char_id() except AreaError: new_char_id = -1 if remains: message = 'Area list reload. Moving you to the new {}.' else: message = ( 'Area list reload. Your previous area no longer exists. Moving you ' 'to the server default area {}.') client.send_ooc(message.format(new_area.name)) client.change_area(new_area, ignore_checks=True, change_to=new_char_id, ignore_notifications=True) # Move parties (independently) for party in area.parties.copy(): party.area = new_area new_area.add_party(party) # Update the server's area list only once everything is successful self.server.old_area_list = self.server.area_list self.server.area_list = area_list_file
def load_characters(self): with Constants.fopen('config/characters.yaml', 'r', encoding='utf-8') as chars: self.char_list = Constants.yaml_load(chars) self.build_char_pages_ao1()
def load_config(self): with Constants.fopen('config/config.yaml', 'r', encoding='utf-8') as cfg: self.config = Constants.yaml_load(cfg) self.config['motd'] = self.config['motd'].replace('\\n', ' \n') self.all_passwords = list() # Mandatory passwords must be present in the configuration file. If they are not, # a server error will be raised. mandatory_passwords = ['modpass', 'cmpass', 'gmpass'] for password in mandatory_passwords: if not (password not in self.config or not str(self.config[password])): self.all_passwords.append(self.config[password]) else: err = (f'Password "{password}" is not defined in server/config.yaml. Please ' f'make sure it is set and try again.') raise ServerError(err) # Daily (and guard) passwords are handled differently. They may optionally be left # blank or be not available. What this means is the server does not want a daily # password for that day (or a guard password) optional_passwords = ['guardpass'] + [f'gmpass{i}' for i in range(1, 8)] for password in optional_passwords: if not (password not in self.config or not str(self.config[password])): self.all_passwords.append(self.config[password]) else: self.config[password] = None # Default values to fill in config.yaml if not present defaults_for_tags = { 'utc_offset': 'local', 'discord_link': None, 'max_numdice': 20, 'max_numfaces': 11037, 'max_modifier_length': 12, 'max_acceptable_term': 22074, 'def_numdice': 1, 'def_numfaces': 6, 'def_modifier': '', 'blackout_background': 'Blackout_HD', 'default_area_description': 'No description.', 'party_lights_timeout': 10, 'show_ms2-prober': True, 'showname_max_length': 30, 'sneak_handicap': 5, 'spectator_name': 'SPECTATOR', 'music_change_floodguard': {'times_per_interval': 1, 'interval_length': 0, 'mute_length': 0}} for (tag, value) in defaults_for_tags.items(): if tag not in self.config: self.config[tag] = value # Check that all passwords were generated are unique passwords = ['guardpass', 'modpass', 'cmpass', 'gmpass', 'gmpass1', 'gmpass2', 'gmpass3', 'gmpass4', 'gmpass5', 'gmpass6', 'gmpass7'] for (i, password1) in enumerate(passwords): for (j, password2) in enumerate(passwords): if i != j and self.config[password1] == self.config[password2] != None: info = ('Passwords "{}" and "{}" in server/config.yaml match. ' 'Please change them so they are different and try again.' .format(password1, password2)) raise ServerError(info)
def load_backgrounds(self): with Constants.fopen('config/backgrounds.yaml', 'r', encoding='utf-8') as bgs: self.backgrounds = Constants.yaml_load(bgs)