def test_assemble_with_label(): start_address = 0x80085760 + 0x9C patch = [ ppc.bl(8, relative=True), ppc.bl("other"), ppc.nop(), ppc.nop().with_label("other"), ] assembled_bytes = list( assembler.assemble_instructions(start_address, patch)) assert assembled_bytes == [ 0x48, 0x00, 0x00, 0x09, 0x48, 0x00, 0x00, 0x09, 0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, ]
def test_remote_execution_patch_end(): # Run patch = all_prime_dol_patches.remote_execution_patch_end() data = bytes(assembler.assemble_instructions(1000, patch)) # Assert assert data == b"\xbb\xc1\x00\x2c\x80\x01\x00\x38\x7c\x08\x03\xa6\x38\x21\x00\x34\x4e\x80\x00\x20"
def create_remote_execution_body( patch_addresses: StringDisplayPatchAddresses, instructions: List[BaseInstruction]) -> Tuple[int, bytes]: """ Return the address and the bytes for executing the given instructions via remote code execution. """ update_hint_state = patch_addresses.update_hint_state remote_start_instructions = remote_execution_patch_start() remote_start_byte_count = assembler.byte_count(remote_start_instructions) body_address = update_hint_state + remote_start_byte_count body_instructions = list(instructions) body_instructions.extend(remote_execution_patch_end()) body_bytes = bytes( assembler.assemble_instructions(body_address, body_instructions)) if len(body_bytes ) > _remote_execution_max_byte_count - remote_start_byte_count: raise ValueError( f"Received {len(body_instructions)} instructions with total {len(body_bytes)} bytes, " f"but limit is {_remote_execution_max_byte_count - remote_start_byte_count}." ) return body_address, body_bytes
def test_remote_execution_clear_pending_op(): # Run patch = all_prime_dol_patches.remote_execution_clear_pending_op() data = bytes(assembler.assemble_instructions(1000, patch)) # Assert assert data == b'\x38\xc0\x00\x00\x98\xdf\x00\x02'
def export_game(self, patch_data: dict, export_params: GameExportParams, progress_update: status_update_lib.ProgressUpdateCallable) -> None: assert isinstance(export_params, PrimeGameExportParams) input_file = export_params.input_path output_file = export_params.output_path export_params.cache_path.mkdir(parents=True, exist_ok=True) cache_dir = os.fspath(export_params.cache_path) symbols = py_randomprime.symbols_for_file(input_file) new_config = copy.copy(patch_data) has_spoiler = new_config.pop("hasSpoiler") room_rando_mode = new_config.pop("roomRandoMode") new_config["inputIso"] = os.fspath(input_file) new_config["outputIso"] = os.fspath(output_file) new_config["gameConfig"]["updateHintStateReplacement"] = list( assembler.assemble_instructions( symbols["UpdateHintState__13CStateManagerFf"], all_prime_dol_patches.remote_execution_patch(), symbols=symbols) ) new_config["preferences"]["cacheDir"] = cache_dir assets_meta = {} updaters = [progress_update] if export_params.use_echoes_models: assets_path = export_params.asset_cache_path asset_conversion_progress = None if asset_conversion.get_asset_cache_version(assets_path) != asset_conversion.ECHOES_MODELS_VERSION: updaters = status_update_lib.split_progress_update(progress_update, 3) asset_conversion_progress = updaters[1] from randovania.games.prime2.exporter.game_exporter import extract_and_backup_iso extract_and_backup_iso(export_params.echoes_input_path, export_params.echoes_contents_path, export_params.echoes_backup_path, updaters[0]) assets_meta = asset_conversion.convert_prime2_pickups(assets_path, asset_conversion_progress) new_config["externAssetsDir"] = os.fspath(assets_path) # Replace models adjust_model_names(new_config, assets_meta, export_params.use_echoes_models) patch_as_str = json.dumps(new_config, indent=4, separators=(',', ': ')) if has_spoiler: output_file.with_name(f"{output_file.stem}-patcher.json").write_text(patch_as_str) if room_rando_mode != RoomRandoMode.NONE.value: self.make_room_rando_maps(output_file, f"{output_file.stem}", new_config["levelData"]) os.environ["RUST_BACKTRACE"] = "1" try: py_randomprime.patch_iso_raw( patch_as_str, py_randomprime.ProgressNotifier(lambda percent, msg: updaters[-1](msg, percent)), ) except BaseException as e: if isinstance(e, Exception): raise else: raise RuntimeError(f"randomprime panic: {e}") from e
def write_instructions(self, address_or_symbol: Union[int, str], instructions: List[assembler.BaseInstruction]): address = self.resolve_symbol(address_or_symbol) self.write( address, assembler.assemble_instructions(address, instructions, symbols=self.symbols))
def test_give_item_patch(powerup_address: all_prime_dol_patches.PowerupFunctionsAddresses): # Run patch = all_prime_dol_patches.adjust_item_amount_and_capacity_patch(powerup_address, RandovaniaGame.METROID_PRIME_ECHOES, 10, 5) data = bytes(assembler.assemble_instructions(0x80008020, patch)) # Assert assert data == (b"\x80\x7f\x15\x0c\x38\x80\x00\x0a\x38\xa0\x00\x05\x48\x06\xd8\xc5\x80\x7f\x15\x0c" b"\x38\x80\x00\x0a\x38\xa0\x00\x05\x48\x06\xd7\x25")
def test_call_display_hud_patch(string_display: all_prime_dol_patches.StringDisplayPatchAddresses): # Run patch = all_prime_dol_patches.call_display_hud_patch(string_display) data = bytes(assembler.assemble_instructions(string_display.update_hint_state, patch)) # Assert assert data == (b"\x3c\xa0\x41\x00\x38\xc0\x00\x00\x38\xe0\x00\x01\x39\x20\x00\x09\x90\xa1\x00\x10" b"\x98\xe1\x00\x14\x98\xc1\x00\x15\x98\xc1\x00\x16\x98\xe1\x00\x17\x91\x21\x00\x18" b"\x38\x61\x00\x1c\x3c\x80\x00\x00\x60\x84\x90\x00\x48\x2c\x73\x89\x38\x81\x00\x10" b"\x48\x03\x33\x6d")
def test_remote_execution_patch_start(): # Run patch = all_prime_dol_patches.remote_execution_patch_start() data = bytes(assembler.assemble_instructions(0x80008020, patch)) # Assert assert data == (b'\x94\x21\xff\xcc\x7c\x08\x02\xa6\x90\x01\x00\x38\xbf\xc1\x00\x2c\x7c\x7f\x1b\x78' b'\x88\x9f\x00\x02\x2c\x04\x00\x00\x40\x82\x00\x18\xbb\xc1\x00\x2c\x80\x01\x00\x38' b'\x7c\x08\x03\xa6\x38\x21\x00\x34\x4e\x80\x00\x20\x3f\xc0\x80\x00\x63\xde\x80\x74' b'\x38\x80\x01\x80\x7c\x04\xf7\xac\x2c\x04\x00\x00\x38\x84\xff\xe0\x40\x82\xff\xf4' b'\x7c\x00\x04\xac\x4c\x00\x01\x2c')
def test_composite_bl_double(): target_address = 0x80085760 start_address = 0x80085760 + 0x9C inc = ppc.bl(target_address) comp = custom_ppc.CompositeInstruction((inc, inc)) composite_bytes = list(comp.bytes_for(start_address, symbols={})) assembled_bytes = list( assembler.assemble_instructions(start_address, [inc, inc])) assert composite_bytes == [0x4b, 0xff, 0xff, 0x65, 0x4b, 0xff, 0xff, 0x61] assert composite_bytes == assembled_bytes
def write_instructions(self, address: int, instructions: Iterable[assembler.BaseInstruction]): self.write(address, assembler.assemble_instructions(address, instructions))