Example #1
0
def check_cache(zip_list):
    """Check to see if any zipfiles are invalid, and if so extract the cache."""
    global copy_process
    from BEE2_config import GEN_OPTS

    LOGGER.info('Checking cache...')

    cache_packs = GEN_OPTS.get_int('General', 'cache_pack_count')

    # We need to match the number of packages too, to account for removed ones.
    cache_stale = (len(packageLoader.packages) == cache_packs) or any(
        pack.is_stale()
        for pack in
        packageLoader.packages.values()
    )

    if not cache_stale:
        # We've already done the copying..
        LOGGER.info('Cache is still fresh, skipping extraction')
        done_callback()
        return

    copy_process = multiprocessing.Process(
        target=do_copy,
        args=(zip_list, currently_done),
    )
    copy_process.daemon = True
    LOGGER.info('Starting background extraction process!')
    copy_process.start()
    TK_ROOT.after(UPDATE_INTERVAL, update)
Example #2
0
def check_cache(zip_list):
    """Check to see if any zipfiles are invalid, and if so extract the cache."""
    global copy_process
    from BEE2_config import GEN_OPTS

    LOGGER.info('Checking cache...')

    cache_packs = GEN_OPTS.get_int('General', 'cache_pack_count')

    # We need to match the number of packages too, to account for removed ones.
    cache_stale = (len(packageLoader.packages) == cache_packs) or any(
        pack.is_stale() for pack in packageLoader.packages.values())

    if not cache_stale:
        # We've already done the copying..
        LOGGER.info('Cache is still fresh, skipping extraction')
        done_callback()
        return

    copy_process = multiprocessing.Process(
        target=do_copy,
        args=(zip_list, currently_done),
    )
    copy_process.daemon = True
    LOGGER.info('Starting background extraction process!')
    copy_process.start()
    TK_ROOT.after(UPDATE_INTERVAL, update)
Example #3
0
def load_backup(zip_file):
    """Load in a backup file."""
    maps = []
    puzzles = [
        file[:-4]  # Strip extension
        for file in zip_names(zip_file) if file.endswith('.p2c')
    ]
    # Each P2C init requires reading in the properties file, so this may take
    # some time. Use a loading screen.
    reading_loader.set_length('READ', len(puzzles))
    LOGGER.info('Loading {} maps..', len(puzzles))
    with reading_loader:
        for file in puzzles:
            new_map = P2C.from_file(file, zip_file)
            maps.append(new_map)
            LOGGER.debug(
                'Loading {} map "{}"',
                'coop' if new_map.is_coop else 'sp',
                new_map.title,
            )
            reading_loader.step('READ')
    LOGGER.info('Done!')

    # It takes a while before the detail headers update positions,
    # so delay a refresh call.
    TK_ROOT.after(500, UI['game_details'].refresh)

    return maps
Example #4
0
def start_copying(zip_list):
    global copy_process
    copy_process = multiprocessing.Process(
        target=do_copy,
        args=(zip_list, currently_done),
    )
    copy_process.daemon = True
    LOGGER.info('Starting background process!')
    copy_process.start()
    TK_ROOT.after(UPDATE_INTERVAL, update)
Example #5
0
    def fx_blockable(sound: str) -> None:
        """Play a sound effect.

        This waits for a certain amount of time between retriggering sounds
        so they don't overlap.
        """
        global _play_repeat_sfx
        if play_sound and _play_repeat_sfx:
            fx(sound)
            _play_repeat_sfx = False
            TK_ROOT.after(75, _reset_fx_blockable)
Example #6
0
    def fx_blockable(sound):
        """Play a sound effect.

        This waits for a certain amount of time between retriggering sounds
        so they don't overlap.
        """
        global _play_repeat_sfx
        if play_sound and _play_repeat_sfx:
            fx(sound)
            _play_repeat_sfx = False
            TK_ROOT.after(75, _reset_fx_blockable)
        def play_sample(self, e=None):
            pass
            """Play a sample of music.

            If music is being played it will be stopped instead.
            """
            if self.cur_file is None:
                return

            if self.sample is not None:
                self.stop()
                return

            try:
                sound = pyglet.media.load(self.cur_file, streaming=False)
            # AVbin raises it's own error if the file isn't found..
            except (FileNotFoundError, pyglet.media.MediaFormatException):
                self.stop_callback()
                LOGGER.error('Sound sample not found: "{}"', self.cur_file)
                return  # Abort if music isn't found..

            self.sample = sound.play()
            self.after = TK_ROOT.after(
                int(sound.duration * 1000),
                self._finished,
            )
            self.start_callback()
Example #8
0
        def play_sample(self, e=None):
            pass
            """Play a sample of music.

            If music is being played it will be stopped instead.
            """
            if self.cur_file is None:
                return

            if self.sample is not None:
                self.stop()
                return

            try:
                sound = pyglet.media.load(self.cur_file, streaming=False)
            # AVbin raises it's own error if the file isn't found..
            except (FileNotFoundError, pyglet.media.MediaFormatException):
                self.stop_callback()
                LOGGER.error('Sound sample not found: "{}"', self.cur_file)
                return  # Abort if music isn't found..

            self.sample = sound.play()
            self.after = TK_ROOT.after(
                int(sound.duration * 1000),
                self._finished,
            )
            self.start_callback()
Example #9
0
def flash_count():
    """Flash the counter between 0 and 100 when on."""
    should_cont = False

    for var in (count_brush, count_entity, count_overlay):
        if not var.should_flash:
            continue  # Abort when it shouldn't be flashing

        if var.get() == 0:
            var.set(100)
        else:
            var.set(0)

        should_cont = True

    if should_cont:
        TK_ROOT.after(750, flash_count)
Example #10
0
def flash_count():
    """Flash the counter between 0 and 100 when on."""
    should_cont = False

    for var in (count_brush, count_entity, count_overlay):
        if not var.should_flash:
            continue  # Abort when it shouldn't be flashing

        if var.get() == 0:
            var.set(100)
        else:
            var.set(0)

        should_cont = True

    if should_cont:
        TK_ROOT.after(750, flash_count)
Example #11
0
def update():
    """Check the progress of the copying until it's done.
    """
    progress_var.set(1000 * currently_done.value / res_count, )
    export_btn_text.set('Extracting Resources ({!s}/{!s})...'.format(
        currently_done.value,
        res_count,
    ))
    if not copy_process.is_alive():
        # We've finished copying
        export_btn_text.set('Export...')
        update_modtimes()
        done_callback()
    else:
        # Coninuously tell TK to re-run this, so we update
        # without deadlocking the CPU
        TK_ROOT.after(UPDATE_INTERVAL, update)
Example #12
0
        def play_sample(self, e=None):
            pass
            """Play a sample of music.

            If music is being played it will be stopped instead.
            """
            if self.cur_file is None:
                return

            if self.sample is not None:
                self.stop()
                return

            with self.system:
                try:
                    file = self.system[self.cur_file]
                except (KeyError, FileNotFoundError):
                    self.stop_callback()
                    LOGGER.error('Sound sample not found: "{}"', self.cur_file)
                    return  # Abort if music isn't found..

            # TODO: Pyglet doesn't support direct streams, so we have to
            # TODO: extract sounds to disk first.

            fsystem = self.system.get_system(file)
            if isinstance(fsystem, RawFileSystem):
                # Special case, it's directly lying on the disk -
                # We can just pass that along.
                disk_filename = os.path.join(fsystem.path, file.path)
                LOGGER.info('Directly playing sample "{}"...', disk_filename)
            else:
                # In a filesystem, we need to extract it.
                # SAMPLE_WRITE_PATH + the appropriate extension.
                disk_filename = str(SAMPLE_WRITE_PATH.with_suffix(os.path.splitext(self.cur_file)[1]))
                LOGGER.info('Extracting music sample to "{}"...', disk_filename)
                with self.system.get_system(file), file.open_bin() as fsrc:
                    with open(disk_filename, 'wb') as fdest:
                        shutil.copyfileobj(fsrc, fdest)

            try:
                sound = pyglet.media.load(disk_filename, streaming=False)  # type: Source
            except MediaFormatException:
                self.stop_callback()
                LOGGER.exception('Sound sample not valid: "{}"', self.cur_file)
                return  # Abort if music isn't found..

            if self.start_time:
                try:
                    sound.seek(self.start_time)
                except CannotSeekException:
                    LOGGER.exception('Cannot seek in "{}"!', self.cur_file)

            self.sample = sound.play()
            self.after = TK_ROOT.after(
                int(sound.duration * 1000),
                self._finished,
            )
            self.start_callback()
Example #13
0
        def play_sample(self, e=None):
            pass
            """Play a sample of music.

            If music is being played it will be stopped instead.
            """
            if self.cur_file is None:
                return

            if self.sample is not None:
                self.stop()
                return

            with self.system:
                try:
                    file = self.system[self.cur_file]
                except (KeyError, FileNotFoundError):
                    self.stop_callback()
                    LOGGER.error('Sound sample not found: "{}"', self.cur_file)
                    return  # Abort if music isn't found..

            # TODO: Pyglet doesn't support direct streams, so we have to
            # TODO: extract sounds to disk first.

            fsystem = self.system.get_system(file)
            if isinstance(fsystem, RawFileSystem):
                # Special case, it's directly lying on the disk -
                # We can just pass that along.
                disk_filename = os.path.join(fsystem.path, file.path)
            else:
                # In a filesystem, we need to extract it.
                # SAMPLE_WRITE_PATH + the appropriate extension.
                disk_filename = SAMPLE_WRITE_PATH.with_suffix(
                    os.path.splitext(self.cur_file)[1])
                with self.system.get_system(file), file.open_bin() as fsrc:
                    with open(disk_filename, 'wb') as fdest:
                        shutil.copyfileobj(fsrc, fdest)

            try:
                sound = pyglet.media.load(disk_filename,
                                          streaming=False)  # type: Source
            except MediaFormatException:
                self.stop_callback()
                LOGGER.exception('Sound sample not valid: "{}"', self.cur_file)
                return  # Abort if music isn't found..

            if self.start_time:
                try:
                    sound.seek(self.start_time)
                except CannotSeekException:
                    LOGGER.exception('Cannot seek in "{}"!', self.cur_file)

            self.sample = sound.play()
            self.after = TK_ROOT.after(
                int(sound.duration * 1000),
                self._finished,
            )
            self.start_callback()
Example #14
0
        def play_sample(self, e: Event = None) -> None:
            pass
            """Play a sample of music.

            If music is being played it will be stopped instead.
            """
            if self.cur_file is None:
                return

            if self.sample is not None:
                self.stop()
                return

            self._close_handles()

            with self.system:
                try:
                    file = self.system[self.cur_file]
                except (KeyError, FileNotFoundError):
                    self.stop_callback()
                    LOGGER.error('Sound sample not found: "{}"', self.cur_file)
                    return  # Abort if music isn't found..

                child_sys = self.system.get_system(file)
                # Special case raw filesystems - Pyglet is more efficient
                # if it can just open the file itself.
                if isinstance(child_sys, RawFileSystem):
                    load_path = os.path.join(child_sys.path, file.path)
                    self._cur_sys = self._handle = None
                    LOGGER.debug('Loading music directly from {!r}', load_path)
                else:
                    # Use the file objects directly.
                    load_path = self.cur_file
                    self._cur_sys = child_sys
                    self._cur_sys.open_ref()
                    self._handle = file.open_bin()
                    LOGGER.debug('Loading music via {!r}', self._handle)
                try:
                    sound = pyglet.media.load(load_path, self._handle)
                except (MediaDecodeException, MediaFormatException):
                    self.stop_callback()
                    LOGGER.exception('Sound sample not valid: "{}"',
                                     self.cur_file)
                    return  # Abort if music isn't found..

            if self.start_time:
                try:
                    sound.seek(self.start_time)
                except CannotSeekException:
                    LOGGER.exception('Cannot seek in "{}"!', self.cur_file)

            self.sample = sound.play()
            self.after = TK_ROOT.after(
                int(sound.duration * 1000),
                self._finished,
            )
            self.start_callback()
Example #15
0
 def enter_handler(e):
     """Schedule showing the tooltip."""
     nonlocal event_id
     if targ_widget.tooltip_text:
         if hasattr(targ_widget, 'instate'):
             if not targ_widget.instate(('!disabled',)):
                 return
         event_id = TK_ROOT.after(
             delay,
             after_complete,
         )
Example #16
0
 def enter_handler(event: tk.Event):
     """Schedule showing the tooltip."""
     nonlocal event_id
     if targ_widget.tooltip_text:
         if check_disabled and not targ_widget.instate(('!disabled',)):
             return
         event_id = TK_ROOT.after(
             delay,
             after_complete,
             event.x_root, event.y_root,
         )
Example #17
0
def update():
    """Check the progress of the copying until it's done.
    """
    progress_var.set(
        1000 * currently_done.value / res_count,
    )
    export_btn_text.set(
        'Extracting Resources ({!s}/{!s})...'.format(
            currently_done.value,
            res_count,
        )
    )
    if not copy_process.is_alive():
        # We've finished copying
        export_btn_text.set(
            'Export...'
        )
        done_callback()
    else:
        # Coninuously tell TK to re-run this, so we update
        # without deadlocking the CPU
        TK_ROOT.after(UPDATE_INTERVAL, update)
Example #18
0
 def enter_handler(event):
     """Schedule showing the tooltip."""
     nonlocal event_id
     # noinspection PyUnresolvedReferences, PyProtectedMember
     if targ_widget._bee2_tooltip_text or targ_widget._bee2_tooltip_img is not None:
         # We know it has this method from above!
         # noinspection PyUnresolvedReferences
         if check_disabled and not targ_widget.instate(('!disabled',)):
             return
         event_id = TK_ROOT.after(
             delay,
             after_complete,
             event.x_root, event.y_root,
         )
Example #19
0
 def enter_handler(event):
     """Schedule showing the tooltip."""
     nonlocal event_id
     # noinspection PyUnresolvedReferences, PyProtectedMember
     if targ_widget._bee2_tooltip_text or targ_widget._bee2_tooltip_img is not None:
         # We know it has this method from above!
         # noinspection PyUnresolvedReferences
         if check_disabled and not targ_widget.instate(('!disabled', )):
             return
         event_id = TK_ROOT.after(
             delay,
             after_complete,
             event.x_root,
             event.y_root,
         )
Example #20
0
        def play_sample(self, e=None):
            pass
            """Play a sample of music.

            If music is being played it will be stopped instead.
            """
            if self.cur_file is None:
                return

            if self.sample is not None:
                self.stop()
                return

            try:
                file = self.system[self.cur_file]
            except KeyError:
                self.stop_callback()
                LOGGER.error('Sound sample not found: "{}"', self.cur_file)
                return  # Abort if music isn't found..

            # TODO: Pyglet doesn't support direct streams, so we have to
            # TODO: extract sounds to disk first.
            with self.system.get_system(file), file.open_bin() as fsrc, open(
                    SAMPLE_WRITE_PATH + os.path.splitext(self.cur_file)[1],
                    'wb',
            ) as fdest:
                shutil.copyfileobj(fsrc, fdest)

            try:
                sound = pyglet.media.load(fdest.name, streaming=False)
            except pyglet.media.MediaFormatException:
                self.stop_callback()
                LOGGER.exception('Sound sample not valid: "{}"', self.cur_file)
                return  # Abort if music isn't found..

            self.sample = sound.play()
            self.after = TK_ROOT.after(
                int(sound.duration * 1000),
                self._finished,
            )
            self.start_callback()
Example #21
0
 def block_fx():
     """Block fx_blockable() for a short time."""
     global _play_repeat_sfx
     _play_repeat_sfx = False
     TK_ROOT.after(50, _reset_fx_blockable)
Example #22
0
if __name__ == '__main__':
    utils.init_logging()
    LOGGER = utils.getLogger('BEE2')
    init(True, log_level='DEBUG')

    # Generate a bunch of log messages to test the window.
    def errors():
        # Use a generator to easily run these functions with a delay.
        yield LOGGER.info('Info Message')
        yield LOGGER.critical('Critical Message')
        yield LOGGER.warning('Warning')

        try:
            raise ValueError('An error')
        except ValueError:
            yield LOGGER.exception('Error message')

        yield LOGGER.warning('Post-Exception warning')
        yield LOGGER.info('Info')
        yield LOGGER.debug('Debug Message')

    err_iterator = errors()

    def next_error():
        # Use False since functions return None usually
        if next(err_iterator, False) is not False:
            TK_ROOT.after(1000, next_error)

    TK_ROOT.after(1000, next_error)
    TK_ROOT.mainloop()
Example #23
0
 def next_error():
     # Use False since functions return None usually
     if next(err_iterator, False) is not False:
         TK_ROOT.after(1000, next_error)
Example #24
0
    toolbar_frame.grid(row=0, column=0, columnspan=3, sticky='W')

    ui_new_backup()


@atexit.register
def deinit():
    """When shutting down, we need to close the backup zipfile."""
    for name in ('backup_zip', 'unsaved_file'):
        obj = BACKUPS[name]
        if obj is not None:
            obj.close()


if __name__ == '__main__':
    # Run this standalone.

    init_application()

    TK_ROOT.deiconify()

    def fix_details():
        # It takes a while before the detail headers update positions,
        # so delay a refresh call.
        TK_ROOT.update_idletasks()
        UI['game_details'].refresh()

    TK_ROOT.after(500, fix_details)

    TK_ROOT.mainloop()
Example #25
0
        width=11,
    ).grid(row=0, column=2)

    ttk.Button(
        toolbar_frame,
        text='.. As',
        command=ui_save_backup_as,
        width=5,
    ).grid(row=0, column=3)

    toolbar_frame.grid(row=0, column=0, columnspan=3, sticky='W')

    ui_new_backup()


if __name__ == '__main__':
    # Run this standalone.

    init_application()

    TK_ROOT.deiconify()

    def fix_details():
        # It takes a while before the detail headers update positions,
        # so delay a refresh call.
        TK_ROOT.update_idletasks()
        UI['game_details'].refresh()
    TK_ROOT.after(500, fix_details)

    TK_ROOT.mainloop()
Example #26
0
 def block_fx():
     """Block fx_blockable() for a short time."""
     global _play_repeat_sfx
     _play_repeat_sfx = False
     TK_ROOT.after(50, _reset_fx_blockable)
Example #27
0
 def next_error():
     # Use False since functions return None usually
     if next(err_iterator, False) is not False:
         TK_ROOT.after(1000, next_error)
Example #28
0
if __name__ == '__main__':
    utils.init_logging()
    init(True, log_level=logging.DEBUG)

    # Generate a bunch of log messages to test the window.
    def errors():
        # Use a generator to easily run these functions with a delay.
        yield LOGGER.info('Info Message')
        yield LOGGER.critical('Critical Message')
        yield LOGGER.warning('Warning')

        try:
            raise ValueError('An error')
        except ValueError:
            yield LOGGER.exception('Error message')

        yield LOGGER.warning('Post-Exception warning')
        yield LOGGER.info('Info')
        yield LOGGER.debug('Debug Message')

    err_iterator = errors()

    def next_error():
        # Use False since functions return None usually
        if next(err_iterator, False) is not False:
            TK_ROOT.after(1000, next_error)

    TK_ROOT.after(1000, next_error)
    TK_ROOT.mainloop()