Esempio n. 1
0
def get_config(prop_block, zip_file, folder, pak_id='', prop_name='config'):
    """Extract a config file refered 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 is returned.
    Otherwise the value is a filename in the zip which will be parsed.
    """
    prop_block = prop_block.find_key(prop_name, "")
    if prop_block.has_children():
        prop = prop_block.copy()
        prop.name = None
        return prop

    if prop_block.value == '':
        return Property(None, [])

    path = os.path.join(folder, prop_block.value) + '.cfg'
    try:
        with zip_file.open(path) as f:
            return Property.parse(
                f,
                pak_id + ':' + path,
            )
    except KeyError:
        print('"{}:{}" not in zip!'.format(pak_id, path))
        return Property(None, [])
Esempio n. 2
0
 def __init__(
     self,
     style_id,
     selitem_data: 'SelitemData',
     editor,
     config=None,
     base_style=None,
     suggested=None,
     has_video=True,
     corridor_names=utils.EmptyMapping,
 ):
     self.id = style_id
     self.selitem_data = selitem_data
     self.editor = editor
     self.base_style = base_style
     self.bases = []  # Set by setup_style_tree()
     self.suggested = suggested or {}
     self.has_video = has_video
     self.corridor_names = {
         'sp_entry': corridor_names.get('sp_entry', Property('', [])),
         'sp_exit': corridor_names.get('sp_exit', Property('', [])),
         'coop': corridor_names.get('coop', Property('', [])),
     }
     if config is None:
         self.config = Property(None, [])
     else:
         self.config = config
Esempio n. 3
0
def parse_item_folder(folders, zip_file, pak_id):
    for fold in folders:
        prop_path = 'items/' + fold + '/properties.txt'
        editor_path = 'items/' + fold + '/editoritems.txt'
        config_path = 'items/' + fold + '/vbsp_config.cfg'
        try:
            with zip_file.open(prop_path, 'r') as prop_file:
                props = Property.parse(
                    prop_file,
                    pak_id + ':' + prop_path,
                ).find_key('Properties')
            with zip_file.open(editor_path, 'r') as editor_file:
                editor = Property.parse(editor_file,
                                        pak_id + ':' + editor_path)
        except KeyError as err:
            # Opening the files failed!
            raise IOError('"' + pak_id + ':items/' + fold + '" not valid!'
                          'Folder likely missing! ') from err

        editor_iter = Property.find_all(editor, 'Item')
        folders[fold] = {
            'auth': sep_values(props['authors', '']),
            'tags': sep_values(props['tags', '']),
            'desc': list(desc_parse(props)),
            'ent': 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': props['all_icon', None],
            'vbsp': Property(None, []),

            # The first Item block found
            'editor': next(editor_iter),
            # Any extra blocks (offset catchers, extent items)
            'editor_extra': list(editor_iter),
        }

        if LOG_ENT_COUNT and folders[fold]['ent'] == '??':
            print('Warning: "{}:{}" has missing entity count!'.format(
                pak_id,
                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:
            print('Warning: "{}:{}" has incomplete grouping icon '
                  'definition!'.format(pak_id, prop_path))
        try:
            with zip_file.open(config_path, 'r') as vbsp_config:
                folders[fold]['vbsp'] = Property.parse(
                    vbsp_config,
                    pak_id + ':' + config_path,
                )
        except KeyError:
            folders[fold]['vbsp'] = Property(None, [])
Esempio n. 4
0
    def __init__(
        self,
        music_id,
        selitem_data: 'SelitemData',
        config=None,
        inst=None,
        sound=None,
    ):
        self.id = music_id
        self.config = config or Property(None, [])
        self.inst = inst
        self.sound = sound

        self.selitem_data = selitem_data
Esempio n. 5
0
 def __init__(self,
              item_id,
              versions,
              def_version,
              needs_unlock=False,
              all_conf=None,
              unstyled=False,
              glob_desc=(),
              desc_last=False):
     self.id = item_id
     self.versions = versions
     self.def_ver = def_version
     self.def_data = def_version['def_style']
     self.needs_unlock = needs_unlock
     self.all_conf = all_conf or Property(None, [])
     self.unstyled = unstyled
     self.glob_desc = glob_desc
     self.glob_desc_last = desc_last
Esempio n. 6
0
from datetime import datetime
from zipfile import ZipFile
from io import BytesIO

import os
import os.path
import stat
import shutil
import sys
import subprocess

from property_parser import Property
from BSP import BSP, BSP_LUMPS
import utils

CONF = Property('Config')
SCREENSHOT_DIR = os.path.join(
    '..',
    'portal2',  # This is hardcoded into P2, it won't change for mods.
    'puzzles',
    # Then the <random numbers> folder
)
# Locations of resources we need to pack
RES_ROOT = [
    os.path.join('..', loc) for loc in ('bee2', 'bee2_dev', 'portal2_dlc2')
]


def quote(txt):
    return '"' + txt + '"'
Esempio n. 7
0
    def export(
        self,
        style,
        all_items,
        music,
        skybox,
        voice,
        style_vars,
        elevator,
        pack_list,
        editor_sounds,
        should_refresh=False,
    ):
        """Generate the editoritems.txt and vbsp_config.

        - If no backup is present, the original editoritems is backed up
        - We unlock the mandatory items if specified
        -
        """
        print('-' * 20)
        print('Exporting Items and Style for "' + self.name + '"!')
        print('Style =', style)
        print('Music =', music)
        print('Voice =', voice)
        print('Skybox =', skybox)
        print('Elevator = ', elevator)
        print('Style Vars:\n  {')
        for key, val in style_vars.items():
            print('  {} = {!s}'.format(key, val))
        print('  }')
        print(len(pack_list), 'Pack Lists!')
        print(len(editor_sounds), 'Editor Sounds!')
        print('-' * 20)

        # VBSP, VRAD, editoritems
        export_screen.set_length('BACK', len(FILES_TO_BACKUP))
        export_screen.set_length(
            'CONF',
            # VBSP_conf, Editoritems, instances, gameinfo, pack_lists,
            # editor_sounds
            6 +
            # Don't add the voicelines to the progress bar if not selected
            (0 if voice is None else len(VOICE_PATHS)),
        )
        # files in compiler/
        export_screen.set_length('COMP', len(os.listdir('../compiler')))

        if should_refresh:
            export_screen.set_length('RES', extract_packages.res_count)
        else:
            export_screen.skip_stage('RES')

        export_screen.show()
        export_screen.grab_set_global()  # Stop interaction with other windows

        vbsp_config = style.config.copy()

        # Editoritems.txt is composed of a "ItemData" block, holding "Item" and
        # "Renderables" sections.
        editoritems = Property("ItemData", list(style.editor.find_all('Item')))

        for item in sorted(all_items):
            item_block, editor_parts, config_part = all_items[item].export()
            editoritems += item_block
            editoritems += editor_parts
            vbsp_config += config_part

        if voice is not None:
            vbsp_config += voice.config

        if skybox is not None:
            vbsp_config.set_key(
                ('Textures', 'Special', 'Sky'),
                skybox.material,
            )
            vbsp_config += skybox.config

        if style.has_video:
            if elevator is None:
                # Use a randomised video
                vbsp_config.set_key(
                    ('Elevator', 'type'),
                    'RAND',
                )
            elif elevator.id == 'VALVE_BLUESCREEN':
                # This video gets a special script and handling
                vbsp_config.set_key(
                    ('Elevator', 'type'),
                    'BSOD',
                )
            else:
                # Use the particular selected video
                vbsp_config.set_key(
                    ('Elevator', 'type'),
                    'FORCE',
                )
                vbsp_config.set_key(
                    ('Elevator', 'horiz'),
                    elevator.horiz_video,
                )
                vbsp_config.set_key(
                    ('Elevator', 'vert'),
                    elevator.vert_video,
                )
        else:  # No elevator video for this style
            vbsp_config.set_key(
                ('Elevator', 'type'),
                'NONE',
            )

        if music is not None:
            if music.sound is not None:
                vbsp_config.set_key(
                    ('Options', 'music_SoundScript'),
                    music.sound,
                )
            if music.inst is not None:
                vbsp_config.set_key(
                    ('Options', 'music_instance'),
                    music.inst,
                )

            vbsp_config.set_key(('Options', 'music_ID'), music.id)
            vbsp_config += music.config

        if voice is not None:
            vbsp_config.set_key(
                ('Options', 'voice_pack'),
                voice.id,
            )
            vbsp_config.set_key(('Options', 'voice_char'),
                                ','.join(voice.chars))

        vbsp_config.set_key(
            ('Options', 'BEE2_loc'),
            os.path.dirname(
                os.getcwd())  # Go up one dir to our actual location
        )

        vbsp_config.ensure_exists('StyleVars')
        vbsp_config['StyleVars'] += [
            Property(key, utils.bool_as_int(val))
            for key, val in style_vars.items()
        ]

        pack_block = Property('PackList', [])
        # A list of materials which will casue a specific packlist to be used.
        pack_triggers = Property('PackTriggers', [])

        for key, pack in pack_list.items():
            pack_block.append(
                Property(key, [Property('File', file) for file in pack.files]))
            for trigger_mat in pack.trigger_mats:
                pack_triggers.append(
                    Property('Material', [
                        Property('Texture', trigger_mat),
                        Property('PackList', pack.id),
                    ]))
        if pack_triggers.value:
            vbsp_config.append(pack_triggers)

        # If there are multiple of these blocks, merge them together
        # They will end up in this order.
        vbsp_config.merge_children(
            'Textures',
            'Fizzler',
            'Options',
            'StyleVars',
            'Conditions',
            'Voice',
            'PackTriggers',
        )

        for name, file, ext in FILES_TO_BACKUP:
            item_path = self.abs_path(file + ext)
            backup_path = self.abs_path(file + '_original' + ext)
            if os.path.isfile(item_path) and not os.path.isfile(backup_path):
                print('Backing up original ' + name + '!')
                shutil.copy(item_path, backup_path)
            export_screen.step('BACK')

        # This is the connections "heart" icon and "error" icon
        editoritems += style.editor.find_key("Renderables", [])

        # Build a property tree listing all of the instances for each item
        all_instances = Property("AllInstances", [])
        for item in editoritems.find_all("Item"):
            item_prop = Property(item['Type'], [])
            all_instances.append(item_prop)
            for inst_block in item.find_all("Exporting", "instances"):
                for inst in inst_block:
                    item_prop.append(Property('Instance', inst['Name']))

        if style_vars.get('UnlockDefault', False):
            print('Unlocking Items!')
            for item in editoritems.find_all('Item'):
                # If the Unlock Default Items stylevar is enabled, we
                # want to force the corridors and obs room to be
                # deletable and copyable
                # Also add DESIRES_UP, so they place in the correct orientation
                if item['type', ''] in _UNLOCK_ITEMS:
                    editor_section = item.find_key("Editor", [])
                    editor_section['deletable'] = '1'
                    editor_section['copyable'] = '1'
                    editor_section['DesiredFacing'] = 'DESIRES_UP'

        print('Editing Gameinfo!')
        self.edit_gameinfo(True)

        export_screen.step('CONF')

        print('Writing Editoritems!')
        os.makedirs(self.abs_path('portal2_dlc2/scripts/'), exist_ok=True)
        with open(self.abs_path('portal2_dlc2/scripts/editoritems.txt'),
                  'w') as editor_file:
            for line in editoritems.export():
                editor_file.write(line)
        export_screen.step('CONF')

        print('Writing VBSP Config!')
        os.makedirs(self.abs_path('bin/bee2/'), exist_ok=True)
        with open(self.abs_path('bin/bee2/vbsp_config.cfg'), 'w') as vbsp_file:
            for line in vbsp_config.export():
                vbsp_file.write(line)
        export_screen.step('CONF')

        print('Writing instance list!')
        with open(self.abs_path('bin/bee2/instances.cfg'), 'w') as inst_file:
            for line in all_instances.export():
                inst_file.write(line)
        export_screen.step('CONF')

        print('Writing packing list!')
        with open(self.abs_path('bin/bee2/pack_list.cfg'), 'w') as pack_file:
            for line in pack_block.export():
                pack_file.write(line)
        export_screen.step('CONF')

        print('Editing game_sounds!')
        self.add_editor_sounds(editor_sounds.values())
        export_screen.step('CONF')

        if voice is not None:
            for prefix, dest, pretty in VOICE_PATHS:
                path = os.path.join(
                    os.getcwd(),
                    '..',
                    'config',
                    'voice',
                    prefix + voice.id + '.cfg',
                )
                print(path)
                if os.path.isfile(path):
                    shutil.copy(
                        path,
                        self.abs_path('bin/bee2/{}voice.cfg'.format(dest)))
                    print('Written "{}voice.cfg"'.format(dest))
                else:
                    print('No ' + pretty + ' voice config!')
                export_screen.step('CONF')

        print('Copying Custom Compiler!')
        for file in os.listdir('../compiler'):
            print('\t* compiler/{0} -> bin/{0}'.format(file))
            shutil.copy(os.path.join('../compiler', file),
                        self.abs_path('bin/'))
            export_screen.step('COMP')

        if should_refresh:
            print('Copying Resources!')
            self.refresh_cache()

        export_screen.grab_release()
        export_screen.reset()  # Hide loading screen, we're done