def watch(self): ov11 = self.rom_data.binaries['overlay/overlay_0011.bin'] self.register_exec( ov11.symbols['GroundMainLoop'].begin_absolute + 0x3C, self.hook__ground_start) self.register_exec( ov11.symbols['GroundMainLoop'].begin_absolute + 0x210, self.hook__ground_quit) self.register_exec( ov11.symbols['GroundMainLoop'].begin_absolute + 0x598, self.hook__ground_map_change) self.register_exec(ov11.symbols['SsbLoad1'].begin_absolute, self.hook__ssb_load) self.register_exec(ov11.symbols['SsbLoad2'].begin_absolute, self.hook__ssb_load) self.register_exec( ov11.symbols['StationLoadHanger'].begin_absolute + 0xC0, self.hook__ssx_load) self.register_exec( ov11.symbols['ScriptStationLoadTalk'].begin_absolute, self.hook__talk_load) threadsafe_emu( self.emu_thread, lambda: self.emu_thread.emu.memory.register_write( self.pnt_unionall_load_addr, self.hook__write_unionall_address, 4))
def _queue_variable_write(self, var_id: int, offset: int, value: int): threadsafe_emu( self.emu_thread, lambda: GameVariable.write(self.emu_thread.emu.memory, self. rom_data, var_id, offset, value)) # Also update the cached values for var in self._variable_cache.keys(): if var.id == var_id: self._variable_cache[var][offset] = value break
def uninit(self): notebook: Gtk.Notebook = self.builder.get_object('variables_notebook') for _ in range(0, notebook.get_n_pages()): # TODO: Do the children need to be destroyed? notebook.remove_page(0) threadsafe_emu( self.emu_thread, lambda: self.emu_thread.emu.memory.register_exec( self.rom_data.binaries['arm9.bin'].functions[ 'SaveScriptVariableValue'].begin_absolute, None)) threadsafe_emu( self.emu_thread, lambda: self.emu_thread.emu.memory.register_exec( self.rom_data.binaries['arm9.bin'].functions[ 'SaveScriptVariableValueWithOffset'].begin_absolute, None))
def deserialize(self, state: dict): """Load a saved state back from a dict""" self._running = state['running'] self._load_ssb_for = state['load_ssb_for'] self._loaded_ssb_files = [ SsbFileInRam(fn_and_hash[0], hng, fn_and_hash[1]) if fn_and_hash is not None else None for hng, fn_and_hash in enumerate(state['ssbs']) ] # - Load SSB file hashes from ground state file, if the hashes don't match on reload with the saved # files, mark them as not up to date in RAM and show warning for affected files. were_invalid = [] for f in self._loaded_ssb_files: if f is not None and f.hash != self.ssb_file_manager.hash_for( f.file_name): were_invalid.append(f.file_name) if len(were_invalid) > 0: n = '\n' md = self.context.message_dialog_cls( )(None, Gtk.DialogFlags.DESTROY_WITH_PARENT, Gtk.MessageType.WARNING, Gtk.ButtonsType.OK, f"Some SSB script files that are loaded in RAM were changed. You can not debug " f"these files, until they are reloaded:\n{n.join(were_invalid)}", title="Warning!") md.set_position(Gtk.WindowPosition.CENTER) # Some timing issues here. def run_and_destroy(): md.run() md.destroy() GLib.idle_add(lambda: run_and_destroy()) for ssb in self._loaded_ssb_files: if ssb is not None: self.ssb_file_manager.open_in_ground_engine(ssb.file_name) if ssb.file_name in were_invalid: self.ssb_file_manager.mark_invalid(ssb.file_name) self._loaded_ssx_files = [ SsxFileInRam(fn, hng) if fn is not None else None for hng, fn in enumerate(state['ssxs']) ] # Also update the load address for unionall threadsafe_emu( self.emu_thread, lambda: self.unionall_load_addr.set( self.emu_thread.emu.memory.unsigned.read_long( self.pnt_unionall_load_addr)))
def init(self, rom_data: Pmd2Data): if not self.emu_thread: return self.rom_data = rom_data self.var_form_elements = [ None for _ in range(0, len(rom_data.script_data.game_variables)) ] notebook: Gtk.Notebook = self.builder.get_object('variables_notebook') # Build the GTK form for category, items in self.CATEGORIES.items(): tab_label = Gtk.Label.new(category) tab_label.show() sw: Gtk.ScrolledWindow = Gtk.ScrolledWindow.new() page_grid: Gtk.Grid = Gtk.Grid.new() page_grid.set_margin_bottom(5) page_grid.set_margin_left(5) page_grid.set_margin_top(5) page_grid.set_margin_right(5) sw.add(page_grid) notebook.append_page(sw, tab_label) row = 0 for item in items: var: Pmd2ScriptGameVar = rom_data.script_data.game_variables__by_name[ item] self.var_form_elements[var.id] = [ None for _ in range(0, var.nbvalues) ] label: Gtk.Label = Gtk.Label.new(item) label.set_valign(Gtk.Align.START) label.set_markup(f'<b>{item}</b>') label.set_halign(Gtk.Align.START) label.set_margin_top(8) label.set_margin_bottom(4) page_grid.attach(label, 0, row, 1, 1) if var.nbvalues == 1: page_grid.attach( self.create_var_form_element(var, 0, no_label=True), 0, row + 1, 1, 1) elif var.name.startswith( 'SCENARIO_' ) and var.nbvalues == 2 and var.type == GameVariableType.UINT8: sub_box: Gtk.Box = Gtk.Box.new(Gtk.Orientation.VERTICAL, 5) sub_box.set_margin_bottom(2) page_grid.attach(sub_box, 0, row + 1, 1, 1) sub_box.pack_start( self.create_var_form_element(var, 0, label='Scenario'), True, True, 0) sub_box.pack_start( self.create_var_form_element(var, 1, label='Level'), True, True, 0) elif var.type == GameVariableType.BIT: sub_grid: Gtk.Grid = Gtk.Grid.new() sub_grid.set_margin_bottom(2) page_grid.attach(sub_grid, 0, row + 1, 1, 1) for i in range(0, var.nbvalues): x = i % 3 y = math.floor(i / 3) sub_grid.attach(self.create_var_form_element(var, i), x, y, 1, 1) else: sub_box: Gtk.Box = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0) sub_box.set_margin_bottom(2) page_grid.attach(sub_box, 0, row + 1, 1, 1) for i in range(0, var.nbvalues): sub_box.pack_start( self.create_var_form_element(var, i), True, True, 0) row += 2 notebook.show_all() self.sync() threadsafe_emu( self.emu_thread, lambda: self.emu_thread.emu.memory.register_exec( self.rom_data.binaries['arm9.bin'].functions[ 'SaveScriptVariableValue'].begin_absolute, self. hook__variable_set)) threadsafe_emu( self.emu_thread, lambda: self.emu_thread.emu.memory.register_exec( self.rom_data.binaries['arm9.bin'].functions[ 'SaveScriptVariableValueWithOffset'].begin_absolute, self. hook__variable_set_with_offset))
def debug_dungeon_skip(self, value: bool): self._debug_dungeon_skip = value if self.rom_data and (not self.ground_engine_state or not self.ground_engine_state.running): threadsafe_emu(self.emu_thread, lambda: self._set_dungeon_debug_skip())
def register_write(self, pnt, cb): threadsafe_emu( self.emu_thread, lambda: self.emu_thread.emu.memory.register_write(pnt, cb))
def pnt(self): return threadsafe_emu( self.emu_thread, lambda: self.emu_thread.emu.memory.unsigned.read_long(self.pnt_to_block_start) )