示例#1
0
    async def parse(cls, data: ParseData) -> ItemConfig:
        """Parse from config files."""
        vers: dict[str, dict[str, lazy_conf.LazyConf]] = {}
        styles: dict[str, lazy_conf.LazyConf]

        all_config = get_config(
            data.info,
            'items',
            pak_id=data.pak_id,
            prop_name='all_conf',
            source=f'<ItemConfig {data.pak_id}:{data.id} all_conf>',
        )

        for ver in data.info.find_all('Version'):
            ver_id = ver['ID', 'VER_DEFAULT']
            vers[ver_id] = styles = {}
            for sty_block in ver.find_all('Styles'):
                for style in sty_block:
                    styles[style.real_name] = lazy_conf.from_file(
                        utils.PackagePath(data.pak_id,
                                          f'items/{style.value}.cfg'),
                        source=
                        f'<ItemConfig {data.pak_id}:{data.id} in "{style.real_name}">',
                    )

        return ItemConfig(
            data.id,
            all_config,
            vers,
        )
示例#2
0
def get_config(
    prop_block: Property,
    folder: str,
    pak_id: str,
    prop_name: str = 'config',
    extension: str = '.cfg',
    source: str = '',
) -> lazy_conf.LazyConf:
    """Lazily extract a config file referred to by the given property block.

    Looks for the prop_name key in the given prop_block.
    If the keyvalue has a value of "", an empty tree is returned.
    If it has children, a copy of them will be returned.
    Otherwise the value is a filename in the zip which will be parsed.

    If source is supplied, set_cond_source() will be run.
    """
    prop_block = prop_block.find_key(prop_name, "")
    if prop_block.has_children():
        prop = prop_block.copy()
        prop.name = ""
        return lazy_conf.raw_prop(prop, source=source)

    if prop_block.value == '':
        return lazy_conf.BLANK

    # Zips must use '/' for the separator, even on Windows!
    path = f'{folder}/{prop_block.value}'
    if len(path) < 3 or path[-4] != '.':
        # Add extension
        path += extension
    return lazy_conf.from_file(utils.PackagePath(pak_id, path), source=source)
示例#3
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
示例#4
0
    async def parse(cls, data: ParseData):
        """Parse a style definition."""
        info = data.info
        selitem_data = SelitemData.parse(info, data.pak_id)
        base = info['base', '']
        has_video = srctools.conv_bool(
            info['has_video', ''],
            not data.is_override,  # Assume no video for override
        )
        vpk_name = info['vpk_name', ''].casefold()

        sugg: dict[str, set[str]] = {
            'quote': set(),
            'music': set(),
            'skybox': set(),
            'elev': set(),
        }
        for prop in info.find_children('suggested'):
            try:
                sugg[prop.name].add(prop.value)
            except KeyError:
                LOGGER.warning('Unknown suggestion types for style {}: {}',
                               data.id, prop.name)

        sugg_tup = (
            sugg['quote'],
            sugg['music'],
            sugg['skybox'],
            sugg['elev'],
        )

        corr_conf = info.find_key('corridors', or_blank=True)
        corridors = {}

        icon_folder = corr_conf['icon_folder', '']

        for group, length in CORRIDOR_COUNTS.items():
            group_prop = corr_conf.find_key(group, or_blank=True)
            for i in range(1, length + 1):
                prop = group_prop.find_key(str(i), '')

                if icon_folder:
                    icon = utils.PackagePath(
                        data.pak_id,
                        'corr/{}/{}/{}.jpg'.format(icon_folder, group, i))
                else:
                    icon = img.PATH_BLANK

                if prop.has_children():
                    corridors[group, i] = CorrDesc(
                        name=prop['name', ''],
                        icon=prop['icon', icon],
                        desc=prop['Desc', ''],
                    )
                else:
                    corridors[group, i] = CorrDesc(
                        name=prop.value,
                        icon=icon,
                        desc='',
                    )

        if base == '':
            base = None
        try:
            folder = 'styles/' + info['folder']
        except LookupError:
            # It's OK for override styles to be missing their 'folder'
            # value.
            if data.is_override:
                items = []
                renderables = {}
                vbsp = lazy_conf.BLANK
            else:
                raise ValueError(
                    f'Style "{data.id}" missing configuration folder!')
        else:
            with data.fsys[folder + '/items.txt'].open_str() as f:
                items, renderables = await trio.to_thread.run_sync(
                    EditorItem.parse, f)
            vbsp = lazy_conf.from_file(
                utils.PackagePath(data.pak_id, folder + '/vbsp_config.cfg'),
                missing_ok=True,
                source=f'Style <{data.id}>',
            )

        return cls(
            style_id=data.id,
            selitem_data=selitem_data,
            items=items,
            renderables=renderables,
            config=vbsp,
            base_style=base,
            suggested=sugg_tup,
            has_video=has_video,
            corridors=corridors,
            vpk_name=vpk_name,
        )