예제 #1
0
 def get_dummy_tileset(self) -> [Dma, Image.Image]:
     with open(os.path.join(data_dir(), 'fixed_floor', 'dummy.dma'),
               'rb') as f:
         dma = FileType.DMA.deserialize(f.read())
     return (dma,
             Image.open(os.path.join(data_dir(), 'fixed_floor',
                                     'dummy.png')))
예제 #2
0
 def import_sprite(self, dir_fn: str) -> bytes:
     with tempfile.TemporaryDirectory() as tmp_path:
         tmp_path = os.path.join(tmp_path, 'tmp.wan')
         AsyncTaskRunner.instance().run_task(self._run_gfxcrunch([dir_fn, tmp_path]))
         self._run_window()
         if self.status == GfxcrunchStatus.SUCCESS:
             with open(tmp_path, 'rb') as f:
                 return f.read()
         else:
             raise RuntimeError(_("The gfxcrunch process failed."))
예제 #3
0
    def import_a_sprite__wan(self) -> Optional[bytes]:
        dialog = Gtk.FileChooserNative.new(_("Import WAN sprite..."),
                                           MainController.window(),
                                           Gtk.FileChooserAction.OPEN, None,
                                           None)

        response = dialog.run()
        fn = dialog.get_filename()
        dialog.destroy()

        if response == Gtk.ResponseType.ACCEPT:
            fn = add_extension_if_missing(fn, 'wan')
            with open(fn, 'rb') as f:
                return f.read()
        return None
예제 #4
0
    def import_a_sprite__wan(self) -> bytes:
        dialog = Gtk.FileChooserNative.new(
            _("Import WAN sprite..."),
            MainController.window(),
            Gtk.FileChooserAction.OPEN,
            None, None
        )

        response = dialog.run()
        fn = dialog.get_filename()
        dialog.destroy()

        if response == Gtk.ResponseType.ACCEPT:
            if '.' not in fn:
                fn += '.wan'
            with open(fn, 'rb') as f:
                return f.read()
예제 #5
0
 def _get_empty_scene(self) -> Ssa:
     with open(os.path.join(data_dir(), 'empty.ssx'), 'rb') as f:
         return FileType.SSA.deserialize(f.read())
예제 #6
0
    def apply(self, patch: Union[Pmd2Patch, Pmd2SimplePatch],
              binaries: Dict[str, Pmd2Binary], patch_file_dir: str, stub_path: str, game_id: str):
        try:
            with tempfile.TemporaryDirectory() as tmp:
                shutil.copytree(patch_file_dir, tmp, dirs_exist_ok=True)

                # Build ASM file to run
                asm_entrypoint = ''

                # First read in  stub
                with open(os.path.join(tmp, stub_path)) as f:
                    asm_entrypoint += f.read() + '\n'

                if isinstance(patch, Pmd2SimplePatch):
                    for replace in patch.string_replacements:
                        fn = os.path.join(tmp, replace.filename)
                        game = None
                        for game_candidate in replace.games:
                            if game_candidate.game_id == game_id:
                                game = game_candidate
                        if game is not None:
                            with open(os.path.join(tmp, fn), 'r') as f:
                                new_content = replace.regexp.sub(game.replace, f.read())
                            with open(os.path.join(tmp, fn), 'w') as f:
                                f.write(new_content)

                    # If it's a simple patch just output and re-import all binaries.
                    for binary_name, binary in binaries.items():
                        binary_path = os.path.join(tmp, binary_name.split('/')[-1])
                        # Write binary to tmp dir
                        with open(binary_path, 'wb') as f:
                            try:
                                f.write(get_binary_from_rom_ppmdu(self.rom, binary))
                            except ValueError as err:
                                if binary_name.split('/')[-1] == 'overlay_0036.bin':
                                    continue  # We ignore if End's extra overlay is missing.
                                raise err
                    # For simple patches we also output the overlay table as y9.bin:
                    binary_path = os.path.join(tmp, Y9_BIN)
                    # Write binary to tmp dir
                    with open(binary_path, 'wb') as f:
                        f.write(self.rom.arm9OverlayTable)

                # Then include other includes
                for include in patch.includes:
                    asm_entrypoint += f'.include "{os.path.join(tmp, include.filename)}"\n'

                # Build binary blocks
                if isinstance(patch, Pmd2Patch):
                    for open_bin in patch.open_bins:
                        binary = binaries[open_bin.filepath]
                        binary_path = os.path.join(tmp, open_bin.filepath.split('/')[-1])
                        os.makedirs(os.path.dirname(binary_path), exist_ok=True)
                        # Write binary to tmp dir
                        with open(binary_path, 'wb') as f:
                            f.write(get_binary_from_rom_ppmdu(self.rom, binary))
                        asm_entrypoint += f'.open "{binary_path}", 0x{binary.loadaddress:0x}\n'
                        for include in open_bin.includes:
                            asm_entrypoint += f'.include "{os.path.join(tmp, include.filename)}"\n'
                        asm_entrypoint += '.close\n'

                # Write final asm file
                with open_utf8(os.path.join(tmp, ASM_ENTRYPOINT_FN), 'w') as f:
                    f.write(asm_entrypoint)

                # Run armips
                original_cwd = os.getcwd()
                os.chdir(tmp)
                try:
                    prefix = ""
                    # Under Windows, try to load from SkyTemple _resources dir first.
                    if sys.platform.startswith('win') and os.path.exists(os.path.join(get_resources_dir(), 'armips.exe')):
                        prefix = os.path.join(get_resources_dir(), '')
                    result = subprocess.Popen([f'{prefix}armips', ASM_ENTRYPOINT_FN],
                                              stdout=subprocess.PIPE,
                                              stderr=subprocess.STDOUT)
                    retcode = result.wait()
                except FileNotFoundError as ex:
                    raise ArmipsNotInstalledError(_("ARMIPS could not be found. Make sure, that "
                                                    "'armips' is inside your system's PATH.")) from ex
                finally:
                    # Restore cwd
                    os.chdir(original_cwd)

                if retcode != 0:
                    raise PatchError(_("ARMIPS reported an error while applying the patch."),
                                     str(result.stdout.read(), 'utf-8'), str(result.stderr.read(), 'utf-8') if result.stderr else '')

                # Load the binaries back into the ROM
                opened_binaries = {}
                if isinstance(patch, Pmd2SimplePatch):
                    # Read in all binaries again
                    opened_binaries = binaries
                    # Also read in arm9OverlayTable
                    binary_path = os.path.join(tmp, Y9_BIN)
                    with open(binary_path, 'rb') as f:
                        self.rom.arm9OverlayTable = f.read()
                else:
                    # Read opened binaries again
                    for open_bin in patch.open_bins:
                        opened_binaries[open_bin.filepath] = binaries[open_bin.filepath]
                for binary_name, binary in opened_binaries.items():
                    binary_path = os.path.join(tmp, binary_name.split('/')[-1])
                    with open(binary_path, 'rb') as f:
                        try:
                            set_binary_in_rom_ppmdu(self.rom, binary, f.read())
                        except ValueError as err:
                            if binary_name.split('/')[-1] == 'overlay_0036.bin':
                                continue  # We ignore if End's extra overlay is missing.
                            raise err

        except (PatchError, ArmipsNotInstalledError):
            raise
        except BaseException as ex:
            raise RuntimeError(f(_("Error while applying the patch: {ex}"))) from ex