From 6999694f8999422e1645a9fbe3eb4b13910cdb67 Mon Sep 17 00:00:00 2001 From: Martin Michelsen Date: Sun, 8 Jun 2025 16:18:29 -0700 Subject: [PATCH] rewrite 6xE4 logic --- src/CommandFormats.hh | 11 +- src/ReceiveSubcommands.cc | 35 +- .../EnemyDamageSyncWIP.3___.patch.s | 463 +++++++++--------- .../EnemyDamageSyncWIP.4___.patch.s | 266 ++++++++++ .../EnemyDamageSyncWIP.59NL.patch.s | 327 +++++-------- ...ersionDetectWithPatchFunctionsXB.x86.inc.s | 54 -- .../System/VersionDetectXB.x86.s | 10 +- .../WriteCallToCodeMulti-59NL.x86.inc.s | 12 +- .../System/WriteCodeBlocksXB.x86.inc.s | 79 +-- system/client-functions/notes.txt | 10 +- 10 files changed, 728 insertions(+), 539 deletions(-) create mode 100644 system/client-functions/EnemyDamageSyncWIP/EnemyDamageSyncWIP.4___.patch.s delete mode 100644 system/client-functions/System/VersionDetectWithPatchFunctionsXB.x86.inc.s diff --git a/src/CommandFormats.hh b/src/CommandFormats.hh index b242b10a..82b776d4 100644 --- a/src/CommandFormats.hh +++ b/src/CommandFormats.hh @@ -7434,14 +7434,13 @@ struct G_RejectBattleStartRequest_Ep3_6xB4x53 { // XB v3: PSOXBCharacterFile::Character // 6xE4: Increment enemy damage threshold -// This command increments or decrements the minimum amount of damage an enemy -// has sustained. This threshold is used to mitigate the effects of damage -// cancellation due to the original game's 6x0A implementation. +// This command increments or decrements the amount of damage an enemy has +// sustained. This replaces the use of total_damage in 6x0A to update enemy HP. -struct G_IncrementEnemyDamageThreshold_Extension_6xE4 { - G_EntityIDHeader header = {0xE4, sizeof(G_IncrementEnemyDamageThreshold_Extension_6xE4) / 4, 0x0000}; +struct G_IncrementEnemyDamage_Extension_6xE4 { + G_EntityIDHeader header = {0xE4, sizeof(G_IncrementEnemyDamage_Extension_6xE4) / 4, 0x0000}; le_int16_t hit_amount = 0; le_uint16_t total_damage_before_hit = 0; le_uint16_t current_hp_before_hit = 0; le_uint16_t max_hp = 0; -} __packed_ws__(G_IncrementEnemyDamageThreshold_Extension_6xE4, 0x0C); +} __packed_ws__(G_IncrementEnemyDamage_Extension_6xE4, 0x0C); diff --git a/src/ReceiveSubcommands.cc b/src/ReceiveSubcommands.cc index cff1c093..a56abc17 100644 --- a/src/ReceiveSubcommands.cc +++ b/src/ReceiveSubcommands.cc @@ -320,6 +320,10 @@ static asio::awaitable on_invalid(shared_ptr c, SubcommandMessage& co_return; } +static asio::awaitable on_debug_info(shared_ptr, SubcommandMessage&) { + co_return; +} + static asio::awaitable on_forward_check_game_loading(shared_ptr c, SubcommandMessage& msg) { auto l = c->require_lobby(); if (l->is_game() && l->any_client_loading()) { @@ -3475,6 +3479,33 @@ static asio::awaitable on_update_enemy_state(shared_ptr c, Subcomm } } +static asio::awaitable on_incr_enemy_damage(shared_ptr c, SubcommandMessage& msg) { + auto& cmd = msg.check_size_t(); + + if (command_is_private(msg.command)) { + co_return; + } + auto l = c->require_lobby(); + if (!l->is_game()) { + co_return; + } + if (cmd.header.entity_id < 0x1000 || cmd.header.entity_id >= 0x4000) { + throw runtime_error("6xE4 received for non-enemy entity"); + } + auto ene_st = l->map_state->enemy_state_for_index(c->version(), c->floor, cmd.header.entity_id & 0x0FFF); + + c->log.info_f("E-{:03X} damage incremented by {}; before hit, damage was {} (cmd) or {} (ene_st) and HP was {}/{}", + ene_st->e_id, + cmd.hit_amount.load(), + ene_st->total_damage, + cmd.total_damage_before_hit.load(), + cmd.current_hp_before_hit.load(), + cmd.max_hp.load()); + ene_st->total_damage = std::min(ene_st->total_damage + cmd.hit_amount, cmd.max_hp); + + co_await forward_subcommand_with_entity_id_transcode_t(c, msg); +} + static asio::awaitable on_set_enemy_low_game_flags_ultimate(shared_ptr c, SubcommandMessage& msg) { auto& cmd = msg.check_size_t(); @@ -5406,7 +5437,7 @@ const SubcommandDefinition subcommand_definitions[0x100] = { /* 6xE1 */ {NONE, NONE, 0xE1, on_quest_F95F_result_bb}, /* 6xE2 */ {NONE, NONE, 0xE2, on_quest_F960_result_bb}, /* 6xE3 */ {NONE, NONE, 0xE3, on_invalid}, - /* 6xE4 */ {NONE, NONE, 0xE4, forward_subcommand_with_entity_id_transcode_t}, // Extended subcommand; see CommandFormats.hh + /* 6xE4 */ {NONE, NONE, 0xE4, on_incr_enemy_damage}, // Extended subcommand; see CommandFormats.hh /* 6xE5 */ {NONE, NONE, 0xE5, on_invalid}, /* 6xE6 */ {NONE, NONE, 0xE6, on_invalid}, /* 6xE7 */ {NONE, NONE, 0xE7, on_invalid}, @@ -5433,7 +5464,7 @@ const SubcommandDefinition subcommand_definitions[0x100] = { /* 6xFC */ {NONE, NONE, 0xFC, on_invalid}, /* 6xFD */ {NONE, NONE, 0xFD, on_invalid}, /* 6xFE */ {NONE, NONE, 0xFE, on_invalid}, - /* 6xFF */ {NONE, NONE, 0xFF, on_invalid}, + /* 6xFF */ {NONE, NONE, 0xFF, on_debug_info}, // Extended subcommand with no format; used for debugging patches }; asio::awaitable on_subcommand_multi(shared_ptr c, Channel::Message& msg) { diff --git a/system/client-functions/EnemyDamageSyncWIP/EnemyDamageSyncWIP.3___.patch.s b/system/client-functions/EnemyDamageSyncWIP/EnemyDamageSyncWIP.3___.patch.s index 55422ce3..e88ee609 100644 --- a/system/client-functions/EnemyDamageSyncWIP/EnemyDamageSyncWIP.3___.patch.s +++ b/system/client-functions/EnemyDamageSyncWIP/EnemyDamageSyncWIP.3___.patch.s @@ -18,10 +18,19 @@ start: - # Change class_flags check to read only low 16 bits - .data + # Don't allow 6x0A to set total_damage; we'll do it with 6xE4 instead + .data .data 4 - lhz r0, [r28 + 0x2E6] + .address + nop + + + + # Enemy state setup debug hook + .data + .data 4 + .address + bl debug_hook1 @@ -29,19 +38,7 @@ start: .data .data 8 .data 0x00E40006 # subcommand=0xE4, flags=6 - .data 0x800041C0 # on_6xE4 - - - - # Hooks in 6x0A handler - .data - .data 4 - .address - bl on_handle_6x0A_set_total_damage - .data - .data 4 - .address - bl on_handle_6x0A_call_object_update_handler + .data 0x800041C0 # handle_6xE4 @@ -49,90 +46,82 @@ start: .data .data 4 .address - bl on_TObjectV8047c128_add_hp + bl on_TObjectV8047c128_add_hp_with_sync - # subtract_hp callsites in TObjectV8047c128_subtract_hp_if_in_state_2 + # subtract_hp callsites in TObjectV8047c128_subtract_hp_if_not_in_state_2 .data .data 4 .address - bl on_TObjectV8047c128_subtract_hp + bl on_TObjectV8047c128_subtract_hp_with_sync # subtract_hp callsites in TObjectV8047c128_v18_handle_hit_special_effects .data .data 4 .address - bl on_TObjectV8047c128_subtract_hp + bl on_TObjectV8047c128_subtract_hp_with_sync .data .data 4 .address - bl on_TObjectV8047c128_subtract_hp + bl on_TObjectV8047c128_subtract_hp_with_sync .data .data 4 .address - bl on_TObjectV8047c128_subtract_hp + bl on_TObjectV8047c128_subtract_hp_with_sync .data .data 4 .address - bl on_TObjectV8047c128_subtract_hp + bl on_TObjectV8047c128_subtract_hp_with_sync .data .data 4 .address - bl on_TObjectV8047c128_subtract_hp + bl on_TObjectV8047c128_subtract_hp_with_sync .data .data 4 .address - bl on_TObjectV8047c128_subtract_hp + bl on_TObjectV8047c128_subtract_hp_with_sync .data .data 4 .address - bl on_TObjectV8047c128_subtract_hp + bl on_TObjectV8047c128_subtract_hp_with_sync .data .data 4 .address - bl on_TObjectV8047c128_subtract_hp + bl on_TObjectV8047c128_subtract_hp_with_sync # subtract_hp callsites in TObjectV8047c128_v17_accept_hit .data .data 4 .address - bl on_TObjectV8047c128_subtract_hp + bl on_TObjectV8047c128_subtract_hp_with_sync .data .data 4 .address - bl on_TObjectV8047c128_subtract_hp + bl on_TObjectV8047c128_subtract_hp_with_sync .data .data 4 .address - bl on_TObjectV8047c128_subtract_hp + bl on_TObjectV8047c128_subtract_hp_with_sync .data .data 4 .address - bl on_TObjectV8047c128_subtract_hp + bl on_TObjectV8047c128_subtract_hp_with_sync .data .data 4 .address - bl on_TObjectV8047c128_subtract_hp + bl on_TObjectV8047c128_subtract_hp_with_sync .data .data 4 .address - bl on_TObjectV8047c128_subtract_hp + bl on_TObjectV8047c128_subtract_hp_with_sync .data .data 4 .address - bl on_TObjectV8047c128_subtract_hp + bl on_TObjectV8047c128_subtract_hp_with_sync # subtract_hp callsites in TObjectV8047c128_v16 .data .data 4 .address - bl on_TObjectV8047c128_subtract_hp - - - - # subtract_hp callsites in TObjectV8047c128_v23_give_poison_damage - .data - .data 4 - .address - bl on_TObjectV8047c128_subtract_hp_without_sync + bl on_TObjectV8047c128_subtract_hp_with_sync @@ -140,206 +129,242 @@ start: .deltaof code_start, code_end .address 0x800041C0 code_start: -on_6xE4: # (G_6xE4* cmd @ r3) -> void - mflr r0 - stw [r1 + 4], r0 - stwu [r1 - 0x20], r1 - stw [r1 + 8], r3 - li r4, 2 - lhbrx r3, [r3 + r4] - bl get_enemy_entity +handle_6xE4: # [std] (G_IncrementEnemyDamage_Extension_6xE4* cmd @ r3) -> void + mflr r0 + stw [r1 + 4], r0 + stwu [r1 - 0x20], r1 + stw [r1 + 0x08], r31 + stw [r1 + 0x0C], r30 + mr r31, r3 - cmplwi r3, 0 - beq on_6xE4_skip + li r3, 2 + lhbrx r3, [r31 + r3] + cmplwi r3, 0x1000 + blt handle_6xE4_return + cmplwi r3, 0x1B50 + bge handle_6xE4_return + bl state_for_enemy # auto* st = state_for_enemy(cmd->header.entity_id); - lwz r4, [r1 + 8] - li r5, 4 - lhbrx r6, [r4 + r5] - extsh r6, r6 - lhz r7, [r3 + 0x2E4] - add r6, r6, r7 - lhz r7, [r3 + 0x2B8] - cmp r6, r7 - bgt on_6xE4_use_r7 - li r7, 0 - cmp r6, r7 - blt on_6xE4_use_r7 - sth [r3 + 0x2E4], r6 - b on_6xE4_skip -on_6xE4_use_r7: - sth [r3 + 0x2E4], r7 + lhz r4, [r3 + 6] # st->total_damage + li r5, 0x04 + lhbrx r5, [r31 + r5] # cmd->hit_amount + add r4, r4, r5 # st->total_damage + cmd->hit_amount + li r5, 0x0A + lhbrx r5, [r31 + r5] # cmd->max_hp + cmp r4, r5 + blt handle_6xE4_damage_less_than_max_hp -on_6xE4_skip: - addi r1, r1, 0x20 - lwz r0, [r1 + 4] - mtlr r0 + sth [r3 + 6], r5 # st->total_damage = cmd->max_hp; + li r4, 0x0C + bl send_debug_info # TODO: Remove this when no longer necessary + lwz r4, [r3] + andi. r0, r4, 0x800 + bne handle_6xE4_return + ori r4, r4, 0x800 + stw [r3], r4 # st->game_flags |= 0x800; + + # Send 6x0A with dead flag + stw [r1 + 0x14], r4 + li r6, 0x12 + sthbrx [r1 + r6], r5 + lhz r6, [r31 + 2] + oris r6, r6, 0x0A03 + stw [r1 + 0x0C], r6 + andi. r6, r6, 0xFF0F + sth [r1 + 0x10], r6 + addi r3, r1, 0x0C + bl send_and_handle_60 + b handle_6xE4_return + +handle_6xE4_damage_less_than_max_hp: + cmpwi r4, 0 + bge handle_6xE4_damage_nonnegative + li r4, 0 +handle_6xE4_damage_nonnegative: + sth [r3 + 6], r4 # st->total_damage = std::max(st->total_damage + cmd->hit_amount, 0); + li r4, 0x0C + mr r30, r3 + bl send_debug_info + + li r3, 2 + lhbrx r3, [r31 + r3] + bl get_enemy_entity + cmplwi r3, 0 + beq handle_6xE4_return + mr r4, r30 + lwz r12, [r3 + 0x18] + lwz r12, [r12 + 0x140] + mtctr r12 + bctrl + +handle_6xE4_return: + lwz r30, [r1 + 0x0C] + lwz r31, [r1 + 0x08] + addi r1, r1, 0x20 + lwz r0, [r1 + 4] + mtlr r0 blr -on_handle_6x0A_set_total_damage: # (G_6x0A* cmd @ r30) -> int16_t @ r3 - # Nonstandard convention (patched callsite is not a call or return); must - # save and restore r0 - mflr r4 - stw [r1 + 0x04], r4 - stwu [r1 - 0x20], r1 - stw [r1 + 0x08], r0 - - lhz r3, [r30 + 2] - bl get_enemy_entity - - cmplwi r3, 0 - beq on_handle_6x0A_set_total_damage_not_loaded - - lhz r4, [r3 + 0x2E4] - lhz r5, [r3 + 0x2B8] - lhz r3, [r30 + 6] - cmp r3, r5 - bgt on_handle_6x0A_set_total_damage_use_r5 - cmp r3, r4 - blt on_handle_6x0A_set_total_damage_use_r4 - b on_handle_6x0A_set_total_damage_return -on_handle_6x0A_set_total_damage_use_r4: - mr r3, r4 - b on_handle_6x0A_set_total_damage_return -on_handle_6x0A_set_total_damage_use_r5: - mr r3, r5 - b on_handle_6x0A_set_total_damage_return - -on_handle_6x0A_set_total_damage_not_loaded: - lhz r3, [r30 + 6] - -on_handle_6x0A_set_total_damage_return: - lwz r0, [r1 + 0x08] - addi r1, r1, 0x20 - lwz r4, [r1 + 4] - mtlr r4 +state_for_enemy: # [/r4] (uint16_t entity_id @ r3) -> EnemyState* @ r3 + # return &enemy_states[entity_id & 0x0FFF]; + lwz r4, [r13 - ] + andi. r3, r3, 0x0FFF + mulli r3, r3, 0x0C + add r3, r3, r4 blr -on_handle_6x0A_call_object_update_handler: # (TObjectV8047c128* this @ r3, EnemyState* ene_st @ r4, void (*vfn)(TObjectV8047c128* this @ r3, EnemyState* ene_st @ r4) @ r12) -> void - mflr r0 - stw [r1 + 4], r0 - stwu [r1 - 0x20], r1 - stw [r1 + 0x08], r3 - stw [r1 + 0x0C], r4 - stw [r1 + 0x10], r12 +on_TObjectV8047c128_add_hp_with_sync: # [std] (TObjectV8047c128* ene @ r3, int16_t amount @ r4) -> void + li r5, 1 + b on_add_or_subtract_hp +on_TObjectV8047c128_subtract_hp_with_sync: # [std] (TObjectV8047c128* ene @ r3, int16_t amount @ r4) -> void + li r5, 0 +on_add_or_subtract_hp: # [std] (TObjectV8047c128* ene @ r3, int16_t amount @ r4, bool is_add @ r5) -> void + lhz r0, [r3 + 0x1C] + cmplwi r0, 0x1000 + blt on_add_or_subtract_hp_skip_send + cmplwi r0, 0x1B50 + bge on_add_or_subtract_hp_skip_send - lwz r5, [r3 + 0x30] - lwz r7, [r4] - or r5, r5, r7 - andi. r5, r5, 0x0800 - bne on_handle_6x0A_call_object_update_handler_return - lhz r5, [r4 + 6] - lhz r6, [r3 + 0x2B8] - cmp r5, r6 - blt on_handle_6x0A_call_object_update_handler_return + lwz r11, [r13 - ] + cmplwi r11, 0 + beq on_add_or_subtract_hp_skip_send - ori r7, r7, 0x0800 - stw [r4], r7 + mflr r0 + stw [r1 + 4], r0 + stwu [r1 - 0x20], r1 + stw [r1 + 0x14], r29 + stw [r1 + 0x18], r30 + stw [r1 + 0x1C], r31 + mr r29, r3 + mr r30, r4 + mr r31, r5 - lwz r11, [r13 - ] - cmplwi r11, 0 - beq on_handle_6x0A_call_object_update_handler_return + lhz r3, [r29 + 0x1C] + bl state_for_enemy # EnemyState* st = state_for_enemy(ene->entity_id); - addi r10, r1, 0x14 - li r9, 0x1C - lhbrx r5, [r3 + r9] - oris r5, r5, 0x0A03 - stw [r10], r5 - lhz r5, [r3 + 0x2C] - li r9, 4 - sthbrx [r10 + r9], r5 - lhz r5, [r4 + 6] - li r9, 6 - sthbrx [r10 + r9], r5 - lwz r5, [r4] - stw [r10 + 8], r5 - mr r3, r11 - mr r4, r10 - li r5, 0x0C - bl send_60 + mr r5, r30 + cmplwi r31, 0 + beq on_add_or_subtract_hp_skip_negate_amount + neg r5, r5 +on_add_or_subtract_hp_skip_negate_amount: -on_handle_6x0A_call_object_update_handler_return: - lwz r3, [r1 + 0x08] - lwz r4, [r1 + 0x0C] - lwz r12, [r1 + 0x10] - mtctr r12 - addi r1, r1, 0x20 - lwz r0, [r1 + 4] - mtlr r0 + li r4, 0x1C + lhbrx r4, [r29 + r4] + oris r4, r4, 0xE403 + stw [r1 + 0x08], r4 + li r4, 0x0C + sthbrx [r1 + r4], r5 + li r4, 6 + lhbrx r4, [r3 + r4] + sth [r1 + 0x0E], r4 + li r4, 0x32C + lhbrx r4, [r29 + r4] + sth [r1 + 0x10], r4 + li r4, 0x2B8 + lhbrx r4, [r29 + r4] + sth [r1 + 0x12], r4 + mr r3, r11 + addi r4, r1, 0x08 + li r5, 0x0C + bl send_60 + +on_add_or_subtract_hp_tail_call: + mr r3, r29 + mr r4, r30 + mr r5, r31 + lwz r31, [r1 + 0x1C] + lwz r30, [r1 + 0x18] + lwz r29, [r1 + 0x14] + addi r1, r1, 0x20 + lwz r0, [r1 + 4] + mtlr r0 + +on_add_or_subtract_hp_skip_send: + cmplwi r5, 0 + beq on_add_or_subtract_hp_tail_call_subtract_hp + b TObjectV8047c128_add_hp +on_add_or_subtract_hp_tail_call_subtract_hp: + b TObjectV8047c128_subtract_hp + + + +# TODO: Remove this when no longer necessary +debug_hook1: + mflr r0 + stw [r1 + 4], r0 + stwu [r1 - 0x20], r1 + mr r6, r3 + mr r7, r4 + mr r3, r4 + li r4, 0x0C + li r5, -1 + bl send_debug_info + mr r3, r6 + mr r4, r7 + addi r1, r1, 0x20 + lwz r0, [r1 + 4] + mtlr r0 + mtctr r12 bctr -on_TObjectV8047c128_subtract_hp_without_sync: # (TObjectV8047c128* this @ r3, int16_t amount @ r4) - li r5, 2 - b on_TObjectV8047c128_hp_change -on_TObjectV8047c128_add_hp: # (TObjectV8047c128* this @ r3, int16_t amount @ r4) - li r5, 1 - b on_TObjectV8047c128_hp_change -on_TObjectV8047c128_subtract_hp: # (TObjectV8047c128* this @ r3, int16_t amount @ r4) - li r5, 0 +send_debug_info: # (void* data @ r3, uint32_t size @ r4, uint16_t what @ r5) -> void + mflr r0 + stw [r1 + 0x04], r0 + stw [r1 - 0x04], r3 + stw [r1 - 0x08], r4 + stw [r1 - 0x0C], r5 + stw [r1 - 0x10], r6 + stw [r1 - 0x14], r7 + stw [r1 - 0x18], r8 + stw [r1 - 0x1C], r9 + stw [r1 - 0x20], r10 + stw [r1 - 0x24], r11 + stw [r1 - 0x28], r12 + subi r6, r1, 0x40 + sub r6, r6, r4 + stw [r6], r1 + mr r1, r6 -on_TObjectV8047c128_hp_change: # (TObjectV8047c128* this @ r3, int16_t amount @ r4, uint8_t flags @ r5) - lhz r7, [r3 + 0x1C] - cmplwi r7, 0x1000 - blt on_TObjectV8047c128_hp_change_skip_send - cmplwi r7, 0x4000 - bge on_TObjectV8047c128_hp_change_skip_send + rlwinm r6, r4, 14, 8, 15 + addis r6, r6, 1 + oris r6, r6, 0xFF00 + rlwinm r5, r5, 0, 16, 31 + or r5, r5, r6 + stw [r1 + 0x08], r5 + li r6, 0 + subi r3, r3, 4 + addi r7, r1, 0x08 + rlwinm r0, r4, 30, 24, 31 + mtctr r0 +copy_again: + lwzu r0, [r3 + 4] + stwu [r7 + 4], r0 + bdnz copy_again - mflr r0 - stw [r1 + 4], r0 - stwu [r1 - 0x20], r1 - stw [r1 + 0x08], r3 - stw [r1 + 0x0C], r4 - stw [r1 + 0x10], r5 + addi r3, r1, 0x08 + bl send_and_handle_60 - mr r7, r3 - addi r3, r1, 0x10 - li r8, 0x1C - lhbrx r6, [r7 + r8] - oris r6, r6, 0xE403 - stw [r3], r6 # cmd.header - andi. r0, r5, 1 - beq on_TObjectV8047c128_hp_change_skip_negate - neg r4, r4 -on_TObjectV8047c128_hp_change_skip_negate: - li r8, 4 - sthbrx [r3 + r8], r4 # cmd.hit_amount - lhz r4, [r7 + 0x2E4] - li r8, 6 - sthbrx [r3 + r8], r4 # cmd.total_damage_before_hit - lhz r4, [r7 + 0x32C] - li r8, 8 - sthbrx [r3 + r8], r4 # cmd.current_hp_before_hit - lhz r4, [r7 + 0x2B8] - li r8, 0x0A - sthbrx [r3 + r8], r4 # cmd.max_hp - - andi. r0, r5, 2 - bne on_TObjectV8047c128_hp_change_local_only - bl send_and_handle_60 - b on_TObjectV8047c128_hp_change_send_done -on_TObjectV8047c128_hp_change_local_only: - bl on_6xE4 -on_TObjectV8047c128_hp_change_send_done: - - lwz r3, [r1 + 0x08] - lwz r4, [r1 + 0x0C] - lwz r5, [r1 + 0x10] - addi r1, r1, 0x20 - lwz r0, [r1 + 4] - mtlr r0 - -on_TObjectV8047c128_hp_change_skip_send: - andi. r0, r5, 1 - bne on_TObjectV8047c128_hp_change_b_to_add - b TObjectV8047c128_subtract_hp -on_TObjectV8047c128_hp_change_b_to_add: - b TObjectV8047c128_add_hp + lwz r1, [r1] + lwz r3, [r1 - 0x04] + lwz r4, [r1 - 0x08] + lwz r5, [r1 - 0x0C] + lwz r6, [r1 - 0x10] + lwz r7, [r1 - 0x14] + lwz r8, [r1 - 0x18] + lwz r9, [r1 - 0x1C] + lwz r10, [r1 - 0x20] + lwz r11, [r1 - 0x24] + lwz r12, [r1 - 0x28] + lwz r0, [r1 + 0x04] + mtlr r0 + blr diff --git a/system/client-functions/EnemyDamageSyncWIP/EnemyDamageSyncWIP.4___.patch.s b/system/client-functions/EnemyDamageSyncWIP/EnemyDamageSyncWIP.4___.patch.s new file mode 100644 index 00000000..d5221bb1 --- /dev/null +++ b/system/client-functions/EnemyDamageSyncWIP/EnemyDamageSyncWIP.4___.patch.s @@ -0,0 +1,266 @@ +.meta hide_from_patches_menu +.meta name="DMC" +.meta description="Mitigates effects\nof enemy health\ndesync" + +.versions 4OJB 4OJD 4OJU 4OED 4OEU 4OPD 4OPU + +entry_ptr: +reloc0: + .offsetof start + +write_call_to_code_multi: + .include WriteCallToCodeMultiXB + + + +start: + call write_static_patches + call write_incr_hp_with_sync + ret + + + + # Write TObjectV004434c8::incr_hp_with_sync +write_incr_hp_with_sync: + push 5 + push # v17 inlined callsite + 5 + push 5 + push # TObjectV004434c8::subtract_hp_if_not_in_state_2 + D + push 5 + push # TObjectV004434c8::v18_accept_hit (presumably Resta) - this is add_hp, not subtract_hp! + push 5 + push # TObjectV004434c8::v18_accept_hit cases 0 and 4 + push 5 + push # TObjectV004434c8::v18_accept_hit case 1 + push 5 + push # TObjectV004434c8::v18_accept_hit case 2 + push 5 + push # TObjectV004434c8::v18_accept_hit case 3 + push 5 + push # TObjectV004434c8::v18_accept_hit case 0x13 + push 5 + push # TObjectV004434c8::v18_accept_hit case 0x15 + push 5 + push # TObjectV004434c8::v19_handle_hit_special_effects case 1 + push 5 + push # TObjectV004434c8::v19_handle_hit_special_effects case 1 + push 5 + push # TObjectV004434c8::v19_handle_hit_special_effects case 6 + push 5 + push # TObjectV004434c8::v19_handle_hit_special_effects case 9 + push 5 + push # TObjectV004434c8::v19_handle_hit_special_effects case 0x0A + push 5 + push # TObjectV004434c8::v19_handle_hit_special_effects case 0x0D + push 15 + call +4 + .deltaof on_add_or_subtract_hp_start, on_add_or_subtract_hp_end + pop eax + push dword [eax] + call on_add_or_subtract_hp_end + +on_add_or_subtract_hp_start: # (TObjectV004434c8* this @ eax, int16_t amount @ cx) -> bool @ eax + # Check if callsite is subtract_hp_if_not_in_state_2 + + push eax + push ecx + push ebx + movzx edx, word [eax + 0x1C] # ene->entity_id + cmp edx, 0x1000 + jl on_add_or_subtract_hp_skip_send + cmp edx, 0x1B50 + jge on_add_or_subtract_hp_skip_send + + and edx, 0x0FFF + imul edx, edx, 0x0C + add edx, [] # eax = state_for_enemy(cmd->header.entity_id) + + sub esp, 0x0C + mov word [esp], 0x03E4 + mov bx, [eax + 0x1C] + mov [esp + 0x02], bx # cmd.entity_id + cmp dword [esp + 0x18], # Check if callsite is add_hp + jne on_add_or_subtract_hp_skip_negate_amount + neg cx +on_add_or_subtract_hp_skip_negate_amount: + mov [esp + 0x04], cx # cmd.hit_amount + mov bx, [edx + 6] + mov [esp + 0x06], bx # cmd.total_damage_before_hit + mov bx, [eax + 0x0330] + mov [esp + 0x08], bx # cmd.current_hp + mov bx, [eax + 0x02BC] + mov [esp + 0x0A], bx # cmd.max_hp + + mov ecx, esp + mov ebx, [] # root_protocol + test ebx, ebx + jz on_add_or_subtract_hp_skip_send + mov eax, 0x0C + # Can't just `call ` here because this code is relocated at apply time + mov edx, + call edx # send_60(root_protocol, &out_cmd, sizeof(out_cmd)) + add esp, 0x0C + +on_add_or_subtract_hp_skip_send: + mov edx, # subtract_hp + mov eax, # add_hp + cmp dword [esp + 0x0C], # Check if callsite is add_hp + cmove edx, eax + pop ebx + pop ecx + pop eax + jmp edx + +on_add_or_subtract_hp_end: + call write_call_to_code_multi + ret + + + +write_static_patches: + .include WriteCodeBlocksXB + + # Don't let 6x0A handler overwrite total_damage + .data + .data 5 + nop + nop + nop + nop + nop + + .data + .data 8 + .data 0x000600E4 # subcommand=0xE4, flags=6 + .addrof handle_6xE4 + + .data + .deltaof handle_91_replacement, handle_6xE4_end + .address +handle_91_replacement: # [std] (S_91* cmd @ [esp + 4]) -> void + ret 4 +handle_6xE4: # [std] (G_6xE4* cmd @ [esp + 4]) -> void + push ebx + push esi + push edi + mov ebx, [esp + 0x10] # cmd + movzx eax, word [ebx + 2] + cmp eax, 0x1000 + jl handle_6xE4_return + cmp eax, 0x1B50 + jge handle_6xE4_return + + and eax, 0x0FFF + imul eax, eax, 0x0C + add eax, [] # eax = state_for_enemy(cmd->header.entity_id) + + movzx edx, word [eax + 0x06] # st.total_damage + movsx esi, word [ebx + 0x04] # cmd->hit_amount + movzx edi, word [ebx + 0x0A] # cmd->max_hp + add edx, esi # st.total_damage + cmd->hit_amount + cmp edx, edi + jl handle_6xE4_damage_less_than_max_hp + mov [eax + 0x06], di # st.total_damage = cmd->max_hp; + mov edx, [eax] + test edx, 0x800 + jnz handle_6xE4_return + or edx, 0x800 + mov [eax], edx + push edx # out_cmd.flags + sub esp, 8 + mov word [esp], 0x030A # out_cmd.header.{subcommand,size} + mov si, [ebx + 2] + mov [esp + 2], si # out_cmd.header.entity_id + and si, 0x0FFF + mov [esp + 4], si # out_cmd.entity_index + mov [esp + 6], di # out_cmd.total_damage + + mov ecx, esp + push ecx # For handle_60 later + mov ebx, [] # root_protocol + test ebx, ebx + jz handle_6xE4_root_protocol_missing + mov eax, 0x0C + call # send_60(root_protocol, &out_cmd, sizeof(out_cmd)) +handle_6xE4_root_protocol_missing: + mov dword [], 1 + call # handle_60(&out_cmd) + mov dword [], 0 + + add esp, 0x10 + jmp handle_6xE4_return + +handle_6xE4_damage_less_than_max_hp: + xor edi, edi + cmp edx, edx + cmovl edx, edi + mov [eax + 0x06], dx # st.total_damage = std::max(st.total_damage + cmd->hit_amount, 0); + + mov esi, eax # esi = ene_st + movzx di, word [ebx + 2] + call # auto* ene = get_enemy_entity(cmd->header.entity_id); + test eax, eax + jz handle_6xE4_return + mov ecx, eax + push esi + mov edx, [ecx] + call [edx + 0x138] # ene->vtable[0x4E](ene, &st); + +handle_6xE4_return: + pop edi + pop esi + pop ebx + ret +handle_6xE4_end: + + + + # Rewrite TObjectV004434c8::subtract_hp_if_not_in_state_2 + .data + .deltaof on_subtract_hp_if_not_in_state_2_start, on_subtract_hp_if_not_in_state_2_end + .address +on_subtract_hp_if_not_in_state_2_start: # (TObjectV004434c8* this @ eax, int16_t amount @ cx) -> bool @ eax + cmp word [eax + 0x328], 2 + jne on_subtract_hp_if_not_in_state_2_do_subtract + xor eax, eax + ret +on_subtract_hp_if_not_in_state_2_do_subtract: + call -1 # Overwritten by write_call_to_code_multi later + ret +on_subtract_hp_if_not_in_state_2_end: + + + + # Inlined callsite of subtract_hp in TObjectV004434c8::v17 + .data + .deltaof v17_subtract_hp_inlined_callsite_start, v17_subtract_hp_inlined_callsite_end + .address +v17_subtract_hp_inlined_callsite_start: + # This must assemble to exactly 0x1A bytes. There is a vfn call shortly after + # this, and fortunately it appears eax, ecx, and edx are not used before + # then, so we don't have to save any registers here; we just have to move the + # args into the right places. + mov cx, ax + mov eax, edi + call -1 # Overwritten by write_call_to_code_multi later + jmp v17_subtract_hp_inlined_callsite_end + int 3 + int 3 + int 3 + int 3 + int 3 + int 3 + int 3 + int 3 + int 3 + int 3 + int 3 + int 3 + int 3 + int 3 +v17_subtract_hp_inlined_callsite_end: + + + + .data 0x00000000 + .data 0x00000000 diff --git a/system/client-functions/EnemyDamageSyncWIP/EnemyDamageSyncWIP.59NL.patch.s b/system/client-functions/EnemyDamageSyncWIP/EnemyDamageSyncWIP.59NL.patch.s index f6e0fa83..57b1c7e5 100644 --- a/system/client-functions/EnemyDamageSyncWIP/EnemyDamageSyncWIP.59NL.patch.s +++ b/system/client-functions/EnemyDamageSyncWIP/EnemyDamageSyncWIP.59NL.patch.s @@ -13,100 +13,88 @@ write_address_of_code: start: - # Change class_flags check to read only low 16 bits - # This is annoying since the opcode we need is one byte longer than the - # original, so we have to write a call to allocated code here, sigh - push 6 - push 0x00773448 - push 1 - call +4 - .deltaof class_flags_check_start, class_flags_check_end - pop eax - push dword [eax] - call class_flags_check_end -class_flags_check_start: - movzx eax, word [esi + 0x2E8] - ret -class_flags_check_end: - call write_call_to_code_multi - - - # Replace 6x09 with 6xE4 in subcommand handler table mov dword [0x00A0FC30], 0x000600E4 # subcommand=0xE4, flags=6 push 0x00A0FC34 call +4 - .deltaof on_6xE4_start, on_6xE4_end + .deltaof handle_6xE4_start, handle_6xE4_end pop eax push dword [eax] - call on_6xE4_end -on_6xE4_start: # (G_6xE4* cmd @ [esp + 4]) - mov edx, [esp + 4] - movzx eax, word [edx + 2] - .include GetEnemyEntity-59NL # eax = get_enemy_entity(cmd->header.entity_id) + call handle_6xE4_end + +handle_6xE4_start: # (G_6xE4* cmd @ [esp + 4]) -> void + push ebx + push esi + push edi + mov ebx, [esp + 0x10] # cmd + movzx eax, word [ebx + 2] + cmp eax, 0x1000 + jl handle_6xE4_return + cmp eax, 0x1B50 + jge handle_6xE4_return + + and eax, 0x0FFF + imul eax, eax, 0x0C + add eax, [0x00AB02B8] # eax = state_for_enemy(cmd->header.entity_id) + + movzx edx, word [eax + 0x06] # st.total_damage + movsx esi, word [ebx + 0x04] # cmd->hit_amount + movzx edi, word [ebx + 0x0A] # cmd->max_hp + add edx, esi # st.total_damage + cmd->hit_amount + cmp edx, edi + jl handle_6xE4_damage_less_than_max_hp + mov [eax + 0x06], di # st.total_damage = cmd->max_hp; + mov edx, [eax] + test edx, 0x800 + jnz handle_6xE4_return + or edx, 0x800 + mov [eax], edx + push edx # out_cmd.flags + sub esp, 8 + mov word [esp], 0x030A # out_cmd.header.{subcommand,size} + mov si, [ebx + 2] + mov [esp + 2], si # out_cmd.header.entity_id + and si, 0x0FFF + mov [esp + 4], si # out_cmd.entity_index + mov [esp + 6], di # out_cmd.total_damage + mov ecx, esp + mov edx, 0x008003E0 + call edx # send_and_handle_60(&out_cmd); + add esp, 0x0C + jmp handle_6xE4_return + +handle_6xE4_damage_less_than_max_hp: + xor edi, edi + cmp edx, edx + cmovl edx, edi + mov [eax + 0x06], dx # st.total_damage = std::max(st.total_damage + cmd->hit_amount, 0); + + mov edx, eax # edx = ene_st + movzx eax, word [ebx + 2] + .include GetEnemyEntity-59NL # auto* ene = get_enemy_entity(cmd->header.entity_id); test eax, eax - je on_6xE4_no_entity - movzx ecx, word [eax + 0x2EA] - movzx edx, word [edx + 4] - add ecx, edx - xor edx, edx - cmp ecx, 0 - cmovl ecx, edx - movzx edx, word [eax + 0x2BC] - cmp ecx, edx - cmovg ecx, edx - mov [eax + 0x2EA], cx -on_6xE4_no_entity: + jz handle_6xE4_return + mov ecx, eax + push edx + mov edx, [ecx] + call [edx + 0x148] # ene->vtable[0x52](ene, &st); + +handle_6xE4_return: + pop edi + pop esi + pop ebx ret -on_6xE4_end: + +handle_6xE4_end: call write_address_of_code - # Write TObjectV00b441c0::add_hp_with_sync + # Write TObjectV00b441c0::incr_hp_with_sync push 5 - push 0x00774448 # TObjectV00b441c0::v18_accept_hit (presumably Resta) - push 1 - call +4 - .deltaof TObjectV00b441c0_add_hp_with_sync_start, TObjectV00b441c0_add_hp_with_sync_end - pop eax - push dword [eax] - call TObjectV00b441c0_add_hp_with_sync_end -TObjectV00b441c0_add_hp_with_sync_start: # (TObjectV00b441c0* this @ ecx, int16_t amount @ [esp + 4]) -> bool @ eax - mov ax, [ecx + 0x1C] - cmp ax, 0x1000 - jl TObjectV00b441c0_add_hp_with_sync_skip_send - cmp ax, 0x4000 - jge TObjectV00b441c0_add_hp_with_sync_skip_send - sub esp, 0x0C - mov word [esp], 0x03E4 - mov [esp + 0x02], ax # cmd.header.entity_id = this->entity_id - mov ax, [esp + 0x10] - neg ax - mov [esp + 0x04], ax # cmd.hit_amount = -amount - mov ax, [ecx + 0x2EA] - mov [esp + 0x06], ax # cmd.total_damage_before_hit = this->total_damage - mov ax, [ecx + 0x334] - mov [esp + 0x08], ax # cmd.current_hp_before_hit = this->current_hp - mov ax, [ecx + 0x2BC] - mov [esp + 0x0A], ax # cmd.max_hp = this->max_hp - push ecx - lea ecx, [esp + 4] - mov eax, 0x008003E0 - call eax # send_and_handle_60(void* data @ ecx) - pop ecx - add esp, 0x0C -TObjectV00b441c0_add_hp_with_sync_skip_send: - mov eax, 0x007773D4 # TObjectV00b441c0::add_hp - jmp eax -TObjectV00b441c0_add_hp_with_sync_end: - call write_call_to_code_multi - - - - # Write TObjectV00b441c0::subtract_hp_with_sync + push 0x00774448 # TObjectV00b441c0::v18_accept_hit (presumably Resta) - this is add_hp, not subtract_hp! push 5 - push 0x00777287 # TObjectV00b441c0::subtract_hp_if_in_state_2 + push 0x00777287 # TObjectV00b441c0::subtract_hp_if_not_in_state_2 push 5 push 0x00776CD6 # TObjectV00b441c0::v19_handle_hit_special_effects push 5 @@ -139,147 +127,66 @@ TObjectV00b441c0_add_hp_with_sync_end: push 0x00773EFA # TObjectV00b441c0::v18_accept_hit push 5 push 0x00773937 # TObjectV00b441c0::v17 - push 17 + push 18 call +4 - .deltaof TObjectV00b441c0_subtract_hp_with_sync_start, TObjectV00b441c0_subtract_hp_with_sync_end + .deltaof on_add_or_subtract_hp_start, on_add_or_subtract_hp_end pop eax push dword [eax] - call TObjectV00b441c0_subtract_hp_with_sync_end -TObjectV00b441c0_subtract_hp_with_sync_start: # (TObjectV00b441c0* this @ ecx, int16_t amount @ [esp + 4]) -> bool @ eax - mov ax, [ecx + 0x1C] - cmp ax, 0x1000 - jl TObjectV00b441c0_subtract_hp_with_sync_skip_send - cmp ax, 0x4000 - jge TObjectV00b441c0_subtract_hp_with_sync_skip_send + call on_add_or_subtract_hp_end + +on_add_or_subtract_hp_start: # (TObjectV00b441c0* this @ ecx, int16_t amount @ [esp + 4]) -> bool @ eax + movzx eax, word [ecx + 0x1C] # ene->entity_id + cmp eax, 0x1000 + jl on_add_or_subtract_hp_skip_send + cmp eax, 0x1B50 + jge on_add_or_subtract_hp_skip_send + + and eax, 0x0FFF + imul eax, eax, 0x0C + add eax, [0x00AB02B8] # eax = state_for_enemy(cmd->header.entity_id) + sub esp, 0x0C mov word [esp], 0x03E4 - mov [esp + 0x02], ax # cmd.header.entity_id = this->entity_id - mov ax, [esp + 0x10] - mov [esp + 0x04], ax # cmd.hit_amount = amount - mov ax, [ecx + 0x2EA] - mov [esp + 0x06], ax # cmd.total_damage_before_hit = this->total_damage - mov ax, [ecx + 0x334] - mov [esp + 0x08], ax # cmd.current_hp_before_hit = this->current_hp - mov ax, [ecx + 0x2BC] - mov [esp + 0x0A], ax # cmd.max_hp = this->max_hp + mov dx, [ecx + 0x1C] + mov [esp + 0x02], dx # cmd.entity_id + mov dx, [esp + 0x10] + cmp dword [esp + 0x0C], 0x0077444D # Check if callsite is add_hp + jne on_add_or_subtract_hp_skip_negate_amount + neg dx +on_add_or_subtract_hp_skip_negate_amount: + mov [esp + 0x04], dx # cmd.hit_amount + mov dx, [eax + 6] + mov [esp + 0x06], dx # cmd.total_damage_before_hit + mov dx, [ecx + 0x0334] + mov [esp + 0x08], dx # cmd.current_hp + mov dx, [ecx + 0x02BC] + mov [esp + 0x0A], dx # cmd.max_hp + mov edx, esp push ecx - lea ecx, [esp + 4] - mov eax, 0x008003E0 - call eax # send_and_handle_60(void* data @ ecx) - pop ecx - add esp, 0x0C -TObjectV00b441c0_subtract_hp_with_sync_skip_send: - mov eax, 0x00777414 # TObjectV00b441c0::subtract_hp - jmp eax -TObjectV00b441c0_subtract_hp_with_sync_end: - call write_call_to_code_multi - - - - # Write TObjectV00b441c0::subtract_hp_without_sync - push 5 - push 0x00777CBD # TObjectV00b441c0::v25_give_poison_damage - push 1 - call +4 - .deltaof TObjectV00b441c0_subtract_hp_without_sync_start, TObjectV00b441c0_subtract_hp_without_sync_end - pop eax - push dword [eax] - call TObjectV00b441c0_subtract_hp_without_sync_end -TObjectV00b441c0_subtract_hp_without_sync_start: # (TObjectV00b441c0* this @ ecx, int16_t amount @ [esp + 4]) -> bool @ eax - movzx edx, word [ecx + 0x2EA] - movsx eax, word [esp + 2] - add edx, eax - movzx eax, word [ecx + 0x2BC] - cmp edx, eax - cmovg edx, eax - mov [ecx + 0x2EA], dx - mov eax, 0x00777414 # TObjectV00b441c0::subtract_hp - jmp eax -TObjectV00b441c0_subtract_hp_without_sync_end: - call write_call_to_code_multi - - - - # Write handle_6x0A_update_total_damage_hook - push 5 - push 0x0078781F - push 1 - call +4 - .deltaof handle_6x0A_update_total_damage_hook_start, handle_6x0A_update_total_damage_hook_end - pop eax - push dword [eax] - call handle_6x0A_update_total_damage_hook_end -handle_6x0A_update_total_damage_hook_start: # (G_6x0A* cmd @ eax, int16_t cmd_total_damage @ cx) -> void - # Nonstandard calling convention: - # Caller-save: ecx, ebx - # Callee-save: eax, edx, ebp, esi, edi - push eax - movzx eax, word [eax + 2] - .include GetEnemyEntity-59NL # eax = get_enemy_entity(cmd->header.entity_id) - test eax, eax - jz handle_6x0A_update_total_damage_hook_no_entity - mov ebx, [eax + 0x2EA] - cmp ecx, ebx - cmovl ecx, ebx - mov ebx, [eax + 0x2BC] - cmp ecx, ebx - cmovg ecx, ebx -handle_6x0A_update_total_damage_hook_no_entity: - mov [esp + 0x0E], cx # ene_st.total_damage = cx - pop eax - ret -handle_6x0A_update_total_damage_hook_end: - call write_call_to_code_multi - - - - # Write handle_6x0A_call_object_update_vfn - push 6 - push 0x007878CC - push 1 - call +4 - .deltaof handle_6x0A_call_object_update_vfn_start, handle_6x0A_call_object_update_vfn_end - pop eax - push dword [eax] - call handle_6x0A_call_object_update_vfn_end -handle_6x0A_call_object_update_vfn_start: # (TObjectV00b441c0* this @ ecx, EnemyState* ene_st @ [esp + 4]) -> void - # Standard calling conventions - push dword [edx + 0x148] # vfn to call at end (which we do via ret) - push ecx - test dword [ecx + 0x30], 0x800 # this->game_flags & 0x800 - jnz handle_6x0A_call_object_update_vfn_tail_call - mov edx, [esp + 0x0C] - test dword [edx], 0x800 # ene_st->flags & 0x800 - jnz handle_6x0A_call_object_update_vfn_tail_call - mov ax, [edx + 6] - cmp ax, [ecx + 0x2BC] # ene_st->total_damage >= ene->max_hp - jl handle_6x0A_call_object_update_vfn_tail_call - or dword [edx], 0x800 # ene_st->game_flags |= 0x800 (set dead flag) - mov eax, [0x00AAB284] - test eax, eax - jz handle_6x0A_call_object_update_vfn_tail_call - push dword [edx] # cmd.game_flags = ene_st->game_flags - sub esp, 8 - mov ax, [edx + 6] - mov [esp + 0x06], ax # cmd.total_damage = ene_st->total_damage - mov ax, [ecx + 0x2C] - mov [esp + 0x04], ax # cmd.enemy_index = this->enemy_index - mov ax, [ecx + 0x1C] - mov [esp + 0x02], ax # cmd.header.entity_id = this->entity_id - mov word [esp], 0x030A # cmd.header.subommand = 0x0A, cmd.header.size = 0x03 push 0x0C - lea ecx, [esp + 4] - push ecx + push edx mov ecx, [0x00AAB284] - mov eax, 0x007D3F38 - call eax # send_60(TGameProtocol* this @ ecx, void* data @ [esp + 4], uint32_t size @ [esp + 8]) - add esp, 0x0C -handle_6x0A_call_object_update_vfn_tail_call: + mov edx, 0x007D3F38 + call edx # send_60(root_protocol, &cmd, sizeof(cmd)); pop ecx - ret -handle_6x0A_call_object_update_vfn_end: + add esp, 0x0C + +on_add_or_subtract_hp_skip_send: + mov eax, 0x00777414 # subtract_hp + mov edx, 0x007773D4 # add_hp + cmp dword [esp], 0x0077444D # Check if callsite is add_hp + cmove eax, edx + jmp eax + +on_add_or_subtract_hp_end: call write_call_to_code_multi + # Don't let 6x0A handler overwrite total_damage + mov byte [0x0078781F], 0x90 + mov dword [0x00787820], 0x90909090 + + + ret diff --git a/system/client-functions/System/VersionDetectWithPatchFunctionsXB.x86.inc.s b/system/client-functions/System/VersionDetectWithPatchFunctionsXB.x86.inc.s deleted file mode 100644 index ce4f8188..00000000 --- a/system/client-functions/System/VersionDetectWithPatchFunctionsXB.x86.inc.s +++ /dev/null @@ -1,54 +0,0 @@ -# Returns the client specific_version in eax and the address of the -# MmSetAddressProtect function pointer in edx, which is immediately followed by -# the MmQueryAddressProtect function pointer. - -start: - mov ecx, 0x61657244 - - # JP beta - mov eax, 0x344F4A42 - mov edx, 0x00400578 - cmp [0x0043D460], ecx - je done - - # JP disc - mov eax, 0x344F4A44 - mov edx, 0x00400918 - cmp [0x0043D7D0], ecx - je done - - # JP title update - mov eax, 0x344F4A55 - mov edx, 0x00403E3C - cmp [0x00440FE0], ecx - je done - - # US disc - mov eax, 0x344F4544 - mov edx, 0x00404518 - cmp [0x0044174C], ecx - je done - - # US title update - mov eax, 0x344F4555 - mov edx, 0x00403E3C - cmp [0x00440FEC], ecx - je done - - # EU disc - mov eax, 0x344F5044 - mov edx, 0x00404538 - cmp [0x00441768], ecx - je done - - # EU title update - mov eax, 0x344F5055 - mov edx, 0x0040491C - cmp [0x00441AF8], ecx - je done - - # Unknown version - mov eax, 0x344F0000 - xor edx, edx - -done: diff --git a/system/client-functions/System/VersionDetectXB.x86.s b/system/client-functions/System/VersionDetectXB.x86.s index a4d75216..7608f4bb 100644 --- a/system/client-functions/System/VersionDetectXB.x86.s +++ b/system/client-functions/System/VersionDetectXB.x86.s @@ -14,5 +14,13 @@ reloc0: .offsetof start start: - .include VersionDetectWithPatchFunctionsXB + .include GetVersionInfoXB + + test eax, eax + jz version_not_found + mov eax, [eax] + ret + +version_not_found: + mov eax, 0x344F0000 ret diff --git a/system/client-functions/System/WriteCallToCodeMulti-59NL.x86.inc.s b/system/client-functions/System/WriteCallToCodeMulti-59NL.x86.inc.s index 3f47779c..fc785016 100644 --- a/system/client-functions/System/WriteCallToCodeMulti-59NL.x86.inc.s +++ b/system/client-functions/System/WriteCallToCodeMulti-59NL.x86.inc.s @@ -1,10 +1,10 @@ # This file defines the following function: -# write_call_to_code( -# const void* patch_code, -# size_t patch_code_size, -# size_t call_count, -# void* call_opcode_address, -# ssize_t call_opcode_bytes, +# void [/std] write_call_to_code( +# const void* patch_code @ [esp + 0x04], +# size_t patch_code_size @ [esp + 0x08], +# size_t call_count @ [esp + 0x0C], +# void* call_opcode_address @ [esp + 0x10], +# ssize_t call_opcode_bytes @ [esp + 0x14], # ...); # This function allocates memory for patch_code, copies patch_code to that # memory, then writes a call or jmp opcode to call_opcode_address that calls diff --git a/system/client-functions/System/WriteCodeBlocksXB.x86.inc.s b/system/client-functions/System/WriteCodeBlocksXB.x86.inc.s index c6ab123e..f20b1987 100644 --- a/system/client-functions/System/WriteCodeBlocksXB.x86.inc.s +++ b/system/client-functions/System/WriteCodeBlocksXB.x86.inc.s @@ -1,56 +1,57 @@ start: - .include VersionDetectWithPatchFunctionsXB - - xor eax, eax - cmp edx, 0 - jne can_patch + .include GetVersionInfoXB + test eax, eax + jnz can_patch ret -can_patch: - push esi - push edi - push ebx - mov edi, edx # edi = ptr to useful kernel function ptrs - jmp get_patch_data_ptr +can_patch: + push esi + push edi + push ebx + mov edi, eax # edi = ptr to version info struct + jmp get_patch_data_ptr get_patch_data_ptr_ret: - pop ebx # ebx = patch header + pop ebx # ebx = patch header apply_next_patch: - cmp dword [ebx + 4], 0 - jne copy_code_and_apply_again - pop ebx - pop edi - pop esi - mov eax, 1 + cmp dword [ebx + 4], 0 + jne copy_code_and_apply_again + pop ebx + pop edi + pop esi + mov eax, 1 ret copy_code_and_apply_again: - push dword [ebx] # dest addr - call [edi + 4] # MmQueryAddressProtect - mov esi, eax # esi = prev protection flags + push dword [ebx] # dest addr + mov ecx, [edi + 0x0C] + call [ecx] # MmQueryAddressProtect + mov esi, eax # esi = prev protection flags - push 4 # new protection flags - push dword [ebx + 4] # size - push dword [ebx] # base address - call [edi] # MmSetAddressProtect + push 4 # new protection flags + push dword [ebx + 4] # size + push dword [ebx] # base address + mov ecx, [edi + 0x08] + call [ecx] # MmSetAddressProtect - xor ecx, ecx # ecx = offset - mov edx, [ebx] # edx = dest addr + xor ecx, ecx # ecx = offset + mov edx, [ebx] # edx = dest addr copy_next_byte: - mov al, [ebx + ecx + 8] # copy one byte to dest - mov [edx + ecx], al - inc ecx # offset++ - cmp [ebx + 4], ecx # check if all bytes have been copied - jne copy_next_byte + mov al, [ebx + ecx + 8] # copy one byte to dest + mov [edx + ecx], al + inc ecx # offset++ + cmp [ebx + 4], ecx # check if all bytes have been copied + jne copy_next_byte - push esi # new protection flags - push dword [ebx + 4] # size - push dword [ebx] # base address - lea ebx, [ebx + ecx + 8] # advance to next block - call [edi] # MmSetAddressProtect - jmp apply_next_patch + push esi # new protection flags + push dword [ebx + 4] # size + push dword [ebx] # base address + lea ebx, [ebx + ecx + 8] # advance to next block + mov ecx, [edi + 0x08] + call [ecx] # MmSetAddressProtect + jmp apply_next_patch get_patch_data_ptr: - call get_patch_data_ptr_ret + call get_patch_data_ptr_ret first_patch_header: diff --git a/system/client-functions/notes.txt b/system/client-functions/notes.txt index da94847b..0aaf344f 100644 --- a/system/client-functions/notes.txt +++ b/system/client-functions/notes.txt @@ -1,8 +1,7 @@ Used regions in PSO GC: - 80004000-80004194 (0194) ExtendedItemInfo (AR code uses 80005000 due to conflict with q8853x) 800041A0-800041B8 (0018) UnsellableRares -800041C0-???????? (????) EnemyDamageSync +800041C0-???????? (TODO) EnemyDamageSync 8000B088-8000B0E0 (0058) BugFixes 8000B0E0-8000B254 (0174) q8853x send_function_call handler 8000B5C8-8000B5DC (0014) BugFixes @@ -27,3 +26,10 @@ Used regions in PSO GC: 8000D9A0-8000D9B8 (0018) BugFixes 8000DFA0-8000DFE0 (0040) DrawDistance 8000E1E0-8000E1FC (001C) BugFixes + +Used regions in PSO XB (40EU): +002DB550-002DB600 (B0) handle_0E => EnemyHPBars, FlickeringStatusIcons +002DC970-002DCA70 (100) handle_91 => EnemyDamageSync + +Potentially available regions in PSO XB: +002BFDB0-002BFE40 (90) handle_03_phase2 (replace handler in table with do_nothing, or just prepend with ret)