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')))
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."))
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
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()
def _get_empty_scene(self) -> Ssa: with open(os.path.join(data_dir(), 'empty.ssx'), 'rb') as f: return FileType.SSA.deserialize(f.read())
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