예제 #1
0
def parse_item_folder(
    folders_to_parse: set[str],
    filesystem: FileSystem,
    pak_id: str,
) -> dict[str, ItemVariant]:
    """Parse through the data in item/ folders.

    folders is a dict, with the keys set to the folder names we want.
    The values will be filled in with itemVariant values
    """
    folders: dict[str, ItemVariant] = {}
    for fold in folders_to_parse:
        prop_path = 'items/' + fold + '/properties.txt'
        editor_path = 'items/' + fold + '/editoritems.txt'
        config_path = 'items/' + fold + '/vbsp_config.cfg'

        first_item: EditorItem | None = None
        extra_items: list[EditorItem] = []
        try:
            props = filesystem.read_prop(prop_path).find_key('Properties')
            f = filesystem[editor_path].open_str()
        except FileNotFoundError as err:
            raise IOError('"' + pak_id + ':items/' + fold + '" not valid! '
                          'Folder likely missing! ') from err
        with f:
            tok = Tokenizer(f, editor_path)
            for tok_type, tok_value in tok:
                if tok_type is Token.STRING:
                    if tok_value.casefold() != 'item':
                        raise tok.error('Unknown item option "{}"!', tok_value)
                    if first_item is None:
                        first_item = EditorItem.parse_one(tok)
                    else:
                        extra_items.append(EditorItem.parse_one(tok))
                elif tok_type is not Token.NEWLINE:
                    raise tok.error(tok_type)

        if first_item is None:
            raise ValueError(f'"{pak_id}:items/{fold}/editoritems.txt has no '
                             '"Item" block!')

        try:
            editor_vmf = VMF.parse(
                filesystem.read_prop(editor_path[:-3] + 'vmf'))
        except FileNotFoundError:
            pass
        else:
            editoritems_vmf.load(first_item, editor_vmf)
        first_item.generate_collisions()

        # extra_items is any extra blocks (offset catchers, extent items).
        # These must not have a palette section - it'll override any the user
        # chooses.
        for extra_item in extra_items:
            extra_item.generate_collisions()
            for subtype in extra_item.subtypes:
                if subtype.pal_pos is not None:
                    LOGGER.warning(
                        f'"{pak_id}:items/{fold}/editoritems.txt has '
                        f'palette set for extra item blocks. Deleting.')
                    subtype.pal_icon = subtype.pal_pos = subtype.pal_name = None

        # In files this is specified as PNG, but it's always really VTF.
        try:
            all_icon = FSPath(props['all_icon']).with_suffix('.vtf')
        except LookupError:
            all_icon = None

        folders[fold] = ItemVariant(
            editoritems=first_item,
            editor_extra=extra_items,

            # Add the folder the item definition comes from,
            # so we can trace it later for debug messages.
            source=f'<{pak_id}>/items/{fold}',
            pak_id=pak_id,
            vbsp_config=lazy_conf.BLANK,
            authors=sep_values(props['authors', '']),
            tags=sep_values(props['tags', '']),
            desc=desc_parse(props, f'{pak_id}:{prop_path}', pak_id),
            ent_count=props['ent_count', ''],
            url=props['infoURL', None],
            icons={
                prop.name: img.Handle.parse(
                    prop,
                    pak_id,
                    64,
                    64,
                    subfolder='items',
                )
                for prop in props.find_children('icon')
            },
            all_name=props['all_name', None],
            all_icon=all_icon,
        )

        if Item.log_ent_count and not folders[fold].ent_count:
            LOGGER.warning(
                '"{id}:{path}" has missing entity count!',
                id=pak_id,
                path=prop_path,
            )

        # If we have one of the grouping icon definitions but not both required
        # ones then notify the author.
        has_name = folders[fold].all_name is not None
        has_icon = folders[fold].all_icon is not None
        if (has_name or has_icon or 'all'
                in folders[fold].icons) and (not has_name or not has_icon):
            LOGGER.warning(
                'Warning: "{id}:{path}" has incomplete grouping icon '
                'definition!',
                id=pak_id,
                path=prop_path,
            )
        folders[fold].vbsp_config = lazy_conf.from_file(
            utils.PackagePath(pak_id, config_path),
            missing_ok=True,
            source=folders[fold].source,
        )
    return folders
예제 #2
0
파일: item.py 프로젝트: seagemgames/BEE2.4
def parse_item_folder(
    folders_to_parse: Set[str],
    filesystem: FileSystem,
    pak_id: str,
) -> Dict[str, ItemVariant]:
    """Parse through the data in item/ folders.

    folders is a dict, with the keys set to the folder names we want.
    The values will be filled in with itemVariant values
    """
    folders: Dict[str, ItemVariant] = {}
    for fold in folders_to_parse:
        prop_path = 'items/' + fold + '/properties.txt'
        editor_path = 'items/' + fold + '/editoritems.txt'
        config_path = 'items/' + fold + '/vbsp_config.cfg'

        first_item: Optional[Item] = None
        extra_items: List[EditorItem] = []
        with filesystem:
            try:
                props = filesystem.read_prop(prop_path).find_key('Properties')
                f = filesystem[editor_path].open_str()
            except FileNotFoundError as err:
                raise IOError('"' + pak_id + ':items/' + fold + '" not valid!'
                              'Folder likely missing! ') from err
            with f:
                tok = Tokenizer(f, editor_path)
                for tok_type, tok_value in tok:
                    if tok_type is Token.STRING:
                        if tok_value.casefold() != 'item':
                            raise tok.error('Unknown item option "{}"!',
                                            tok_value)
                        if first_item is None:
                            first_item = EditorItem.parse_one(tok)
                        else:
                            extra_items.append(EditorItem.parse_one(tok))
                    elif tok_type is not Token.NEWLINE:
                        raise tok.error(tok_type)

        if first_item is None:
            raise ValueError('"{}:items/{}/editoritems.txt has no '
                             '"Item" block!'.format(pak_id, fold))

        # extra_items is any extra blocks (offset catchers, extent items).
        # These must not have a palette section - it'll override any the user
        # chooses.
        for extra_item in extra_items:
            for subtype in extra_item.subtypes:
                if subtype.pal_pos is not None:
                    LOGGER.warning(
                        '"{}:items/{}/editoritems.txt has palette set for extra'
                        ' item blocks. Deleting.'.format(pak_id, fold))
                    subtype.pal_icon = subtype.pal_pos = subtype.pal_name = None

        try:
            all_icon = FSPath(props['all_icon'])
        except LookupError:
            all_icon = None

        folders[fold] = ItemVariant(
            editoritems=first_item,
            editor_extra=extra_items,

            # Add the folder the item definition comes from,
            # so we can trace it later for debug messages.
            source='<{}>/items/{}'.format(pak_id, fold),
            vbsp_config=Property(None, []),
            authors=sep_values(props['authors', '']),
            tags=sep_values(props['tags', '']),
            desc=desc_parse(props, pak_id + ':' + prop_path),
            ent_count=props['ent_count', ''],
            url=props['infoURL', None],
            icons={p.name: p.value
                   for p in props['icon', []]},
            all_name=props['all_name', None],
            all_icon=all_icon,
        )

        if Item.log_ent_count and not folders[fold].ent_count:
            LOGGER.warning(
                '"{id}:{path}" has missing entity count!',
                id=pak_id,
                path=prop_path,
            )

        # If we have at least 1, but not all of the grouping icon
        # definitions then notify the author.
        num_group_parts = ((folders[fold].all_name is not None) +
                           (folders[fold].all_icon is not None) +
                           ('all' in folders[fold].icons))
        if 0 < num_group_parts < 3:
            LOGGER.warning(
                'Warning: "{id}:{path}" has incomplete grouping icon '
                'definition!',
                id=pak_id,
                path=prop_path,
            )
        try:
            with filesystem:
                folders[fold].vbsp_config = conf = filesystem.read_prop(
                    config_path, )
        except FileNotFoundError:
            folders[fold].vbsp_config = conf = Property(None, [])

        set_cond_source(conf, folders[fold].source)
    return folders
예제 #3
0
    async def modify(self, pak_id: str, props: Property,
                     source: str) -> ItemVariant:
        """Apply a config to this item variant.

        This produces a copy with various modifications - switching
        out palette or instance values, changing the config, etc.
        """
        vbsp_config: lazy_conf.LazyConf
        if 'config' in props:
            # Item.parse() has resolved this to the actual config.
            vbsp_config = get_config(
                props,
                'items',
                pak_id,
            )
        else:
            vbsp_config = self.vbsp_config

        if 'replace' in props:
            # Replace property values in the config via regex.
            vbsp_config = lazy_conf.replace(
                vbsp_config,
                [(re.compile(prop.real_name, re.IGNORECASE), prop.value)
                 for prop in props.find_children('Replace')])

        vbsp_config = lazy_conf.concat(
            vbsp_config,
            get_config(
                props,
                'items',
                pak_id,
                prop_name='append',
            ))

        if 'description' in props:
            desc = desc_parse(props, source, pak_id)
        else:
            desc = self.desc.copy()

        if 'appenddesc' in props:
            desc = tkMarkdown.join(
                desc,
                desc_parse(props, source, pak_id, prop_name='appenddesc'),
            )

        if 'authors' in props:
            authors = sep_values(props['authors', ''])
        else:
            authors = self.authors

        if 'tags' in props:
            tags = sep_values(props['tags', ''])
        else:
            tags = self.tags.copy()

        variant = ItemVariant(
            pak_id,
            self.editor,
            vbsp_config,
            self.editor_extra.copy(),
            authors=authors,
            tags=tags,
            desc=desc,
            icons=self.icons.copy(),
            ent_count=props['ent_count', self.ent_count],
            url=props['url', self.url],
            all_name=self.all_name,
            all_icon=self.all_icon,
            source=f'{source} from {self.source}',
        )
        [variant.editor] = variant._modify_editoritems(
            props,
            [variant.editor],
            pak_id,
            source,
            is_extra=False,
        )

        if 'extra' in props:
            variant.editor_extra = variant._modify_editoritems(
                props.find_key('extra'),
                variant.editor_extra,
                pak_id,
                source,
                is_extra=True)

        return variant
예제 #4
0
파일: item.py 프로젝트: seagemgames/BEE2.4
    def modify(self, fsys: FileSystem, props: Property,
               source: str) -> 'ItemVariant':
        """Apply a config to this item variant.

        This produces a copy with various modifications - switching
        out palette or instance values, changing the config, etc.
        """
        if 'config' in props:
            # Item.parse() has resolved this to the actual config.
            vbsp_config = get_config(
                props,
                fsys,
                'items',
                pak_id=fsys.path,
            )
        else:
            vbsp_config = self.vbsp_config.copy()

        if 'replace' in props:
            # Replace property values in the config via regex.
            replace_vals = [(re.compile(prop.real_name,
                                        re.IGNORECASE), prop.value)
                            for prop in props.find_children('Replace')]
            for prop in vbsp_config.iter_tree():
                for regex, sub in replace_vals:
                    prop.name = regex.sub(sub, prop.real_name)
                    prop.value = regex.sub(sub, prop.value)

        vbsp_config += list(
            get_config(
                props,
                fsys,
                'items',
                prop_name='append',
                pak_id=fsys.path,
            ))

        if 'description' in props:
            desc = desc_parse(props, source)
        else:
            desc = self.desc.copy()

        if 'appenddesc' in props:
            desc = tkMarkdown.join(
                desc,
                desc_parse(props, source, prop_name='appenddesc'),
            )

        if 'authors' in props:
            authors = sep_values(props['authors', ''])
        else:
            authors = self.authors

        if 'tags' in props:
            tags = sep_values(props['tags', ''])
        else:
            tags = self.tags.copy()

        variant = ItemVariant(
            self.editor,
            vbsp_config,
            self.editor_extra.copy(),
            authors=authors,
            tags=tags,
            desc=desc,
            icons=self.icons.copy(),
            ent_count=props['ent_count', self.ent_count],
            url=props['url', self.url],
            all_name=self.all_name,
            all_icon=self.all_icon,
            source='{} from {}'.format(source, self.source),
        )
        [variant.editor] = variant._modify_editoritems(
            props,
            [variant.editor],
            source,
            is_extra=False,
        )

        if 'extra' in props:
            variant.editor_extra = variant._modify_editoritems(
                props.find_key('extra'),
                variant.editor_extra,
                source,
                is_extra=True)

        return variant