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 set_artifact_layer_active_patch(addresses: Prime1DolVersion, layer_id: int, active: bool, ) -> List[assembler.BaseInstruction]: # g_GameState->StateForWorld(0x39F2DE28)->GetLayerState()->SetLayerActive(templeAreaIndex, artifactLayer, true) result = [] for_another_world = [ # Get the LayerState via the CGameState lwz(r3, addresses.game_state_pointer - addresses.sda13_base, r13), # get g_GameState # r4 already have the asset id bl(addresses.state_for_world), # CGameState::StateForWorld lwz(r3, 0x14, r3), # worldState->layerState ] result.extend([ # Get the LayerState of current world. We'll overwrite if it's another world, it's just 1 instruction bigger lwz(r3, 0x8c8, r31), # mgr->worldLayerState # Tallon Overworld asset id custom_ppc.load_unsigned_32bit(r4, 0x39f2de28), # Load current asset id in r5 lwz(r5, 0x850, r31), # mgr->world lwz(r5, 0x8, r5), # world->mlvlId cmpw(0, r4, r5), # compare asset ids beq(4 + assembler.byte_count(for_another_world), relative=True), *for_another_world, lwz(r3, 0x0, r3), # Set layer li(r4, 16), # Artifact Layer stw(r4, 0x10, r1), # Set layer li(r5, layer_id), # Artifact Layer stw(r5, 0x14, r1), # Make the layer change via SetLayerActive addi(r4, r1, 0x10), addi(r5, r1, 0x14), li(r6, int(active)), bl(addresses.set_layer_active), # CWorldLayerState::SetLayerActive ]) return result
def remote_execution_patch_start() -> List[BaseInstruction]: return_code = remote_execution_patch_end() intro = [ # se(r1tup stack stwu(r1, -(_remote_execution_stack_size - 4), r1), mfspr(r0, LR), stw(r0, _remote_execution_stack_size, r1), stmw(GeneralRegister(32 - _registers_to_save), _remote_execution_stack_size - 4 - _registers_to_save * 4, r1), or_(r31, r3, r3), # return if displayed lbz(r4, 0x2, r31), cmpwi(r4, 0x0), bne((len(return_code) + 1) * 4, relative=True), # clean return if flag is not set *return_code, # set displayed li(r6, 0x0), stb(r6, 0x2, r31), ] num_bytes_to_invalidate = _remote_execution_max_byte_count - assembler.byte_count( intro) # Our loop end condition depends on this value being a multiple of 32, greater than 0 num_bytes_to_invalidate = ((num_bytes_to_invalidate // 32) + 1) * 32 return [ *intro, # fetch the instructions again, since they're being overwritten externally # this clears Dolphin's JIT cache custom_ppc.load_current_address(r30, 8), li(r4, num_bytes_to_invalidate), icbi(4, 30), # invalidate using r30 + r4 cmpwi(r4, 0x0), addi(r4, r4, -32), bne(-3 * 4, relative=True), sync(), isync(), ]