Пример #1
0
 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)
Пример #2
0
    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
Пример #3
0
    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)
Пример #4
0
    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)
Пример #5
0
    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
Пример #6
0
    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
Пример #7
0
 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()
Пример #8
0
    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)
Пример #9
0
 def load_backgrounds(self):
     with Constants.fopen('config/backgrounds.yaml', 'r', encoding='utf-8') as bgs:
         self.backgrounds = Constants.yaml_load(bgs)