def __init__( self, filename: str, *, in_conf_folder: bool=True, auto_load: bool=True, ) -> None: """Initialise the config file. `filename` is the name of the config file, in the `root` directory. If `auto_load` is true, this file will immediately be read and parsed. If in_conf_folder is set, The folder is relative to the 'config/' folder in the BEE2 folder. """ super().__init__() self.has_changed = False if filename is not None: if in_conf_folder: self.filename = utils.conf_location('config/' + filename) else: self.filename = filename self.writer = AtomicWriter(self.filename) self.has_changed = False if auto_load: self.load() else: self.filename = self.writer = None
def __init__( self, filename: str, *, in_conf_folder: bool = True, auto_load: bool = True, ) -> None: """Initialise the config file. `filename` is the name of the config file, in the `root` directory. If `auto_load` is true, this file will immediately be read and parsed. If in_conf_folder is set, The folder is relative to the 'config/' folder in the BEE2 folder. """ super().__init__() self.has_changed = False if filename is not None: if in_conf_folder: self.filename = utils.conf_location('config/' + filename) else: self.filename = filename self.writer = AtomicWriter(self.filename) self.has_changed = False if auto_load: self.load() else: self.filename = self.writer = None
def __init__( self, filename: Optional[str], *, in_conf_folder: bool = True, auto_load: bool = True, ) -> None: """Initialise the config file. `filename` is the name of the config file, in the `root` directory. If `auto_load` is true, this file will immediately be read and parsed. If in_conf_folder is set, The folder is relative to the 'config/' folder in the BEE2 folder. """ super().__init__() self.has_changed = Event() self._file_lock = Lock() if filename is not None: if in_conf_folder: self.filename = utils.conf_location('config') / filename else: self.filename = Path(filename) if auto_load: self.load() else: self.filename = None
def read_settings() -> None: """Read and apply the settings from disk.""" try: file = open(utils.conf_location('config/config.vdf'), encoding='utf8') except FileNotFoundError: return with file: props = Property.parse(file) apply_settings(props)
def write_settings() -> None: """Write the settings to disk.""" props = get_curr_settings() props.name = None with AtomicWriter( str(utils.conf_location('config/config.vdf')), is_bytes=False, ) as file: for line in props.export(): file.write(line)
def export(exp_data: ExportData) -> None: """Export the quotepack.""" if exp_data.selected is None: return # No quote pack! try: voice = QuotePack.by_id(exp_data.selected) # type: QuotePack except KeyError: raise Exception("Selected voice ({}) doesn't exist?".format( exp_data.selected)) from None vbsp_config = exp_data.vbsp_conf # type: Property # We want to strip 'trans' sections from the voice pack, since # they're not useful. for prop in voice.config: if prop.name == 'quotes': vbsp_config.append(QuotePack.strip_quote_data(prop)) else: vbsp_config.append(prop.copy()) # Set values in vbsp_config, so flags can determine which voiceline # is selected. options = vbsp_config.ensure_exists('Options') options['voice_pack'] = voice.id options['voice_char'] = ','.join(voice.chars) if voice.cave_skin is not None: options['cave_port_skin'] = str(voice.cave_skin) if voice.studio is not None: options['voice_studio_inst'] = voice.studio options['voice_studio_actor'] = voice.studio_actor options['voice_studio_inter_chance'] = str(voice.inter_chance) options['voice_studio_cam_loc'] = voice.cam_loc.join(' ') options['voice_studio_cam_pitch'] = str(voice.cam_pitch) options['voice_studio_cam_yaw'] = str(voice.cam_yaw) options['voice_studio_should_shoot'] = srctools.bool_as_int( voice.turret_hate) # Copy the config files for this voiceline.. for prefix, pretty in [('', 'normal'), ('mid_', 'MidChamber'), ('resp_', 'Responses')]: path = utils.conf_location('config/voice/') / (prefix.upper() + voice.id + '.cfg') LOGGER.info('Voice conf path: {}', path) if path.is_file(): shutil.copy( str(path), exp_data.game.abs_path( 'bin/bee2/{}voice.cfg'.format(prefix))) LOGGER.info('Written "{}voice.cfg"', prefix) else: LOGGER.info('No {} voice config!', pretty)
def write_settings() -> None: """Write the settings to disk.""" props = get_curr_settings(is_palette=False) with atomic_write( utils.conf_location('config/config.vdf'), encoding='utf8', overwrite=True, ) as file: for prop in props: for line in prop.export(): file.write(line)
def read_settings() -> None: """Read and apply the settings from disk.""" path = utils.conf_location('config/config.vdf') try: file = path.open(encoding='utf8') except FileNotFoundError: return try: with file: props = Property.parse(file) except KeyValError: LOGGER.warning('Cannot parse config.vdf!', exc_info=True) # Try and move to a backup name, if not don't worry about it. try: path.replace(path.with_suffix('.err.vdf')) except IOError: pass apply_settings(props)
from app import TK_ROOT from srctools.filesys import FileSystemChain, FileSystem, RawFileSystem import srctools.logger import utils __all__ = [ 'SamplePlayer', 'pyglet_version', 'play_sound', 'fx', 'fx_blockable', 'block_fx', ] LOGGER = srctools.logger.get_logger(__name__) SAMPLE_WRITE_PATH = utils.conf_location('music_sample/music') play_sound = True # Nursery to hold sound-related tasks. We can cancel this to shutdown sound logic. _nursery: trio.Nursery | None = None SOUNDS: dict[str, str] = { 'select': 'rollover', 'add': 'increment', 'config': 'reconfig', 'subtract': 'decrement', 'connect': 'connection_made', 'disconnect': 'connection_destroyed', 'expand': 'extrude', 'delete': 'collapse', 'error': 'error', 'contract': 'carve',
'SamplePlayer', 'avbin_version', 'pyglet_version', 'initiallised', 'load_snd', 'play_sound', 'fx', 'fx_blockable', 'block_fx', ] LOGGER = srctools.logger.get_logger(__name__) play_sound = True SAMPLE_WRITE_PATH = utils.conf_location('config/music_sample/temp') # This starts holding the filenames, but then caches the actual sound object. SOUNDS = { 'select': 'rollover', 'add': 'increment', 'config': 'reconfig', 'subtract': 'decrement', 'connect': 'connection_made', 'disconnect': 'connection_destroyed', 'expand': 'extrude', 'delete': 'collapse', 'error': 'error', 'contract': 'carve', 'raise_1': 'panel_raise_01', 'raise_2': 'panel_raise_02',
from srctools.filesys import RawFileSystem, FileSystemChain import srctools.logger __all__ = [ 'SOUNDS', 'SamplePlayer', 'avbin_version', 'pyglet_version', 'initiallised', 'load_snd', 'play_sound', 'fx', 'fx_blockable', 'block_fx', ] LOGGER = srctools.logger.get_logger(__name__) play_sound = True SAMPLE_WRITE_PATH = utils.conf_location('config/music_sample/temp') # This starts holding the filenames, but then caches the actual sound object. SOUNDS = { 'select': 'rollover', 'add': 'increment', 'config': 'reconfig', 'subtract': 'decrement', 'connect': 'connection_made', 'disconnect': 'connection_destroyed', 'expand': 'extrude', 'delete': 'collapse', 'error': 'error', 'contract': 'carve', 'raise_1': 'panel_raise_01', 'raise_2': 'panel_raise_02',
import os import shutil import zipfile import random import utils import srctools.logger import BEE2_config from srctools import Property, NoKeyError, KeyValError from typing import List, Tuple, Optional LOGGER = srctools.logger.get_logger(__name__) PAL_DIR = utils.conf_location('palettes/') PAL_EXT = '.bee2_palette' pal_list = [] # type: List[Palette] # Allow translating the names of the built-in palettes DEFAULT_PALETTES = { # i18n: Last exported items 'LAST_EXPORT': _('<Last Export>'), # i18n: Empty palette name 'EMPTY': _('Blank'), # i18n: BEEmod 1 palette. 'BEEMOD': _('BEEMod'), # i18n: Default items merged together
'PETI': _('Bendy'), } PLAYER_MODEL_ORDER = ['PETI', 'SP', 'ATLAS', 'PBODY'] PLAYER_MODELS_REV = {value: key for key, value in PLAYER_MODELS.items()} COMPILE_CFG = ConfigFile('compile.cfg') COMPILE_CFG.set_defaults(COMPILE_DEFAULTS) window = None UI = {} # type: Dict[str, Widget] chosen_thumb = StringVar( value=COMPILE_CFG.get_val('Screenshot', 'Type', 'AUTO')) tk_screenshot = None # The preview image shown # Location we copy custom screenshots to SCREENSHOT_LOC = str(utils.conf_location('screenshot.jpg')) VOICE_PRIORITY_VAR = IntVar( value=COMPILE_CFG.get_bool('General', 'use_voice_priority', True)) player_model_var = StringVar(value=PLAYER_MODELS.get( COMPILE_CFG.get_val('General', 'player_model', 'PETI'), PLAYER_MODELS['PETI'], )) start_in_elev = IntVar(value=COMPILE_CFG.get_bool('General', 'spawn_elev')) cust_file_loc = COMPILE_CFG.get_val('Screenshot', 'Loc', '') cust_file_loc_var = StringVar(value='') packfile_dump_enable = IntVar( value=COMPILE_CFG.get_bool('General', 'packfile_dump_enable'))
def modify(conf: ConfigFile, game_folder: Path) -> None: """Modify the map's screenshot.""" mod_type = conf.get_val('Screenshot', 'type', 'PETI').lower() if mod_type == 'cust': LOGGER.info('Using custom screenshot!') scr_loc = str(utils.conf_location('screenshot.jpg')) elif mod_type == 'auto': LOGGER.info('Using automatic screenshot!') scr_loc = None # The automatic screenshots are found at this location: auto_path = os.path.join(game_folder, 'screenshots') # We need to find the most recent one. If it's named # "previewcomplete", we want to ignore it - it's a flag # to indicate the map was playtested correctly. try: screens = [ os.path.join(auto_path, path) for path in os.listdir(auto_path) ] except FileNotFoundError: # The screenshot folder doesn't exist! screens = [] screens.sort( key=os.path.getmtime, reverse=True, # Go from most recent to least ) playtested = False for scr_shot in screens: filename = os.path.basename(scr_shot) if filename.startswith('bee2_playtest_flag'): # Previewcomplete is a flag to indicate the map's # been playtested. It must be newer than the screenshot playtested = True continue elif filename.startswith('bee2_screenshot'): continue # Ignore other screenshots # We have a screenshot. Check to see if it's # not too old. (Old is > 2 hours) date = datetime.fromtimestamp(os.path.getmtime(scr_shot)) diff = datetime.now() - date if diff.total_seconds() > 2 * 3600: LOGGER.info( 'Screenshot "{scr}" too old ({diff!s})', scr=scr_shot, diff=diff, ) continue # If we got here, it's a good screenshot! LOGGER.info('Chosen "{}"', scr_shot) LOGGER.info('Map Playtested: {}', playtested) scr_loc = scr_shot break else: # If we get to the end, we failed to find an automatic # screenshot! LOGGER.info('No Auto Screenshot found!') mod_type = 'peti' # Suppress the "None not found" error if conf.get_bool('Screenshot', 'del_old'): LOGGER.info('Cleaning up screenshots...') # Clean up this folder - otherwise users will get thousands of # pics in there! for screen in screens: if screen != scr_loc and os.path.isfile(screen): os.remove(screen) LOGGER.info('Done!') else: # PeTI type, or something else scr_loc = None if scr_loc is not None and os.path.isfile(scr_loc): # We should use a screenshot! for screen in find(): LOGGER.info('Replacing "{}"...', screen) # Allow us to edit the file... utils.unset_readonly(screen) shutil.copy(scr_loc, screen) # Make the screenshot readonly, so P2 can't replace it. # Then it'll use our own utils.set_readonly(screen) else: if mod_type != 'peti': # Error if we were looking for a screenshot LOGGER.warning('"{}" not found!', scr_loc) LOGGER.info('Using PeTI screenshot!') for screen in find(): # Make the screenshot writeable, so P2 will replace it LOGGER.info('Making "{}" replaceable...', screen) utils.unset_readonly(screen)
import os import shutil import zipfile import random import utils import srctools.logger import BEE2_config from srctools import Property, NoKeyError from typing import List, Tuple, Optional LOGGER = srctools.logger.get_logger(__name__) PAL_DIR = utils.conf_location('palettes/') PAL_EXT = '.bee2_palette' pal_list = [] # type: List[Palette] # Allow translating the names of the built-in palettes DEFAULT_PALETTES = { # i18n: Last exported items 'LAST_EXPORT': _('<Last Export>'), # i18n: Empty palette name 'EMPTY': _('Blank'), # i18n: BEEmod 1 palette. 'BEEMOD': _('BEEMod'), # i18n: Default items merged together 'P2_COLLAPSED': _('Portal 2 Collapsed'),