def __init__(self, area_id, server, parameters): """ Parameters ---------- area_id: int The area ID. server: server.TsuserverDR The server this area belongs to. parameters: dict Area parameters as specified in the loaded area list. """ self.clients = set() self.invite_list = {} self.id = area_id self.server = server self.music_looper = None self.next_message_time = 0 self.hp_def = 10 self.hp_pro = 10 self.doc = 'No document.' self.status = 'IDLE' self.judgelog = [] self.shoutlog = [] self.current_music = '' self.current_music_player = '' self.evi_list = EvidenceList() self.is_recording = False self.recorded_messages = [] self.owned = False self.ic_lock = False self.is_locked = False self.is_gmlocked = False self.is_modlocked = False self.bleeds_to = set() self.blood_smeared = False self.lights = True self.last_ic_messages = list() self.parties = set() self.dicelog = list() self._in_zone = None self.name = parameters['area'] self.background = parameters['background'] self.bg_lock = parameters['bglock'] self.evidence_mod = parameters['evidence_mod'] self.locking_allowed = parameters['locking_allowed'] self.iniswap_allowed = parameters['iniswap_allowed'] self.rp_getarea_allowed = parameters['rp_getarea_allowed'] self.rp_getareas_allowed = parameters['rp_getareas_allowed'] self.rollp_allowed = parameters['rollp_allowed'] self.reachable_areas = parameters['reachable_areas'] self.change_reachability_allowed = parameters[ 'change_reachability_allowed'] self.default_change_reachability_allowed = parameters[ 'change_reachability_allowed'] self.gm_iclock_allowed = parameters['gm_iclock_allowed'] self.afk_delay = parameters['afk_delay'] self.afk_sendto = parameters['afk_sendto'] self.lobby_area = parameters['lobby_area'] self.private_area = parameters['private_area'] self.scream_range = parameters['scream_range'] self.restricted_chars = parameters['restricted_chars'] self.default_description = parameters['default_description'] self.has_lights = parameters['has_lights'] self.cbg_allowed = parameters['cbg_allowed'] self.song_switch_allowed = parameters['song_switch_allowed'] self.bullet = parameters['bullet'] # Store the current description separately from the default description self.description = self.default_description # Have a background backup in order to restore temporary background changes self.background_backup = self.background # Fix comma-separated entries self.reachable_areas = Constants.fix_and_setify( self.reachable_areas) self.scream_range = Constants.fix_and_setify(self.scream_range) self.restricted_chars = Constants.fix_and_setify( self.restricted_chars) self.default_reachable_areas = self.reachable_areas.copy() self.staffset_reachable_areas = self.reachable_areas.copy() if '<ALL>' not in self.reachable_areas: self.reachable_areas.add(self.name) # Safety feature, yay sets # Make sure only characters that exist are part of the restricted char set try: for char_name in self.restricted_chars: self.server.char_list.index(char_name) except ValueError: info = ( 'Area `{}` has a character `{}` not in the character list of the server ' 'listed as a restricted character. Please make sure this character exists ' 'and try again.'.format(self.name, char_name)) raise AreaError(info)
def validate_contents(self, contents, extra_parameters=None): if extra_parameters is None: extra_parameters = dict() server_character_list = extra_parameters.get('server_character_list', None) server_default_area_description = extra_parameters.get( 'server_default_area_description', '') default_area_parameters = { 'afk_delay': 0, 'afk_sendto': 0, 'background_tod': dict(), 'bglock': False, 'bullet': True, 'cbg_allowed': False, 'change_reachability_allowed': True, 'default_description': server_default_area_description, 'evidence_mod': 'FFA', 'gm_iclock_allowed': True, 'has_lights': True, 'iniswap_allowed': False, 'global_allowed': True, '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, } current_area_id = 0 area_parameters = list() temp_area_names = set() found_uncheckable_restricted_chars = False # Create the areas for item in contents: # 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) # Prevent reserved area names (it has a special meaning) reserved_names = { '<ALL>', '<REACHABLE_AREAS>', } for name in reserved_names: if item['area'] == name: info = ( 'An area in your area list is called "{name}". This is a reserved ' 'name, so it is not a valid area name. Please change its name and try ' 'again.') raise AreaError(info) # 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 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 unset optional parameters for param in default_area_parameters: if param not in item: item[param] = default_area_parameters[param] # 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) # Check and fix background tods if needed, as YAML parses this as a list of if item['background_tod'] != dict(): raw_background_tod_map = item['background_tod'] if not isinstance(raw_background_tod_map, dict): info = ( f'Expected background TOD for area {item["area"]} be ' f'one dictionary, found it was of type ' f'{type(raw_background_tod_map).__name__}: {raw_background_tod_map}' ) raise AreaError(info) new_background_tod = dict() if not isinstance(raw_background_tod_map, dict): info = ( f'Expected background TOD for area {item["area"]} be a dictionary, ' f'found it was of type {type(raw_background_tod_map).__name__}: ' f'{raw_background_tod_map}') raise AreaError(info) for (key, value) in raw_background_tod_map.items(): tod_name = str(key) tod_background = str(value) if not tod_name.strip(): info = ( f'TOD name `{tod_name}` invalid for area {item["area"]}. ' f'Make sure the TOD name has non-space characters and try ' f'again.') raise AreaError(info) if ' ' in tod_name: info = ( f'TOD name `{tod_name}` invalid for area {item["area"]}. ' f'Make sure the TOD name has no space characters and try ' f'again.') raise AreaError(info) if '|' in tod_name: info = ( f'TOD name `{tod_name}` contains invalid character |.' f'Make sure the TOD name does not have that character and ' f'try again.') raise AreaError(info) if '|' in tod_background: info = ( f'TOD background `{tod_background}` contains invalid ' f'character |. Make sure the TOD name does not have that ' f'character and try again.') raise AreaError(tod_background) new_background_tod[tod_name] = tod_background item['background_tod'] = new_background_tod area_parameters.append(item.copy()) temp_area_names.add(item['area']) current_area_id += 1 # Check if a reachable area is not an area name # Can only be done once all areas are created for area_item in area_parameters: name = area_item['area'] reachable_areas = Constants.fix_and_setify( area_item['reachable_areas']) scream_range = Constants.fix_and_setify(area_item['scream_range']) restricted_chars = Constants.fix_and_setify( area_item['restricted_chars']) if reachable_areas == {'<ALL>'}: reachable_areas = temp_area_names.copy() if scream_range == {'<ALL>'}: scream_range = temp_area_names.copy() elif scream_range == {'<REACHABLE_AREAS>'}: scream_range = reachable_areas.copy() area_item['reachable_areas'] = reachable_areas area_item['scream_range'] = scream_range area_item['restricted_chars'] = restricted_chars # Make sure no weird areas were set as reachable by players or by screams unrecognized_areas = reachable_areas - temp_area_names if unrecognized_areas: info = ( f'Area {name} has unrecognized areas {unrecognized_areas} defined as ' f'areas a player can reach to. Please rename the affected areas and try ' f'again.') raise AreaError(info) unrecognized_areas = scream_range - temp_area_names if unrecognized_areas: info = ( f'Area {name} has unrecognized areas {unrecognized_areas} defined as ' f'areas screams can reach to. Please rename the affected areas and try ' f'again.') raise AreaError(info) # Make sure only characters that exist are part of the restricted char set if server_character_list is not None: unrecognized_characters = restricted_chars - set( server_character_list) if unrecognized_characters: info = ( f'Area {name} has unrecognized characters {unrecognized_characters} ' f'defined as restricted characters. Please make sure the characters ' f'exist and try again.') raise AreaError(info) elif restricted_chars: found_uncheckable_restricted_chars = True if found_uncheckable_restricted_chars: info = ( 'WARNING: Some areas provided default restricted characters. However, no ' 'server character list was provided, so no checks whether restricted ' 'characters were in the character list of the server were performed.' ) print(info) return area_parameters