PCSX2 / pcsx2

PCSX2 - The Playstation 2 Emulator
https://pcsx2.net
GNU General Public License v3.0
11.68k stars 1.61k forks source link

[BUG]: Monster Hunter games: bounce calculation inaccuracy #10519

Open 2Tie opened 9 months ago

2Tie commented 9 months ago

Describe the Bug

Certain interactions between player attacks hitting monsters behave differently between hardware and PCSX2 (for example, a blue weapon hitting basarios's back will bounce on hardware but not on emulator). After investigating with the debugger, my (and the mh community's) working theory is that the root cause of the divergence involves how floats are converted in part of the damage calculation. This difference does affect battle flow to a nontrivial degree (it also occurs against the final boss monster), as well as resource management.

Reproduction Steps

In MHG, equip a melee weapon with blue sharpness, and attack a basarios when submerged. Attack timing window and weapon type is irrelevant for this example chosen. On PCSX2, the attack connects and completes, while on hardware the attack bounces.

This is a commentated walkthrough of what I found to be the relevant bits of the damage function in MHG in this example interaction, but a mostly reduced version of it would be something like the following, with nops added as needed:

lwcl f26, 0x3fa00000 ;load constant 1.25 into f26
lbu v0, 0x14
mctl v0, f0
cvt.s.W f1, f0 ;load and convert int 20 into a float
lui v0, 0x42c8
mtcl v0, f0 ;load constant 100 into f0
div.S f0, f1, f0 ;divide converted 20 by constant 100, put result in f0
mul.S f26, f26, f0 ;multiply the initial constant (1.25) by the new value (~0.20), ideally resulting in 0.25 in f26
lui v0, 0x3e80
mtcl v0, f0 ;load 0.25 into f0
c.lt.S f26, f0 ;compare if f26 is less than constant 0.25
bclt ;branch if so!

where the comparison branch happens on hardware but not pcsx2... but i haven't the resources to test this minimal case on hardware to see what the actual binary value in f26 should be. With a breakpoint at 0x4DFD24, the c.lt.S f26, f00 where f00 is the 0.25 constant, pcsx2 lists f26 to be 0.250000 on hit and the bounce doesn't happen.

This is just the easiest to reproduce and demonstrate version of this bug; there's also a version where hitstop is triggered on emulator while it isn't on hardware which is the same as the above reduced code but the int is 80 and the constant for the comparison is 1.0 (0x3f80) instead of 0.25 - again theorized by us to be pcsx2 hitting the comparison thresholds exactly instead of being just below them.

Expected Behavior

The emulator behaviour should match console; in this case, both should bounce in the example interaction.

PCSX2 Revision

v1.7.5370

Operating System

Windows 10 (64bit)

If Linux - Specify Distro

No response

CPU

Ryzen 5 1600 six core 3.20GHz

GPU

Nvidia GTX 1070 Ti FE

GS Settings

No response

Emulation Settings

No response

GS Window Screenshots

No response

Logs & Dumps

No response

refractionpcsx2 commented 9 months ago

Does the behaviour work any better if you set EE clamping to full?

2Tie commented 9 months ago

no. with EE clamping set to full, the blue basarios test still doesn't bounce, and debugger reports 0.25 in f26 at the breakpoint. Here's a savestate for the test situation, the basarios is buried right in front of the player: SLPM-65869 (29396A53).08.p2s.zip

AmyRoxwell commented 9 months ago

Could you please provide a memcard with a weapon with blue sharpness? Not only for easier testing purposes but for not becoming incompatible with future versions of the emulator like savestates.

Mrlinkwii commented 5 months ago

the savestate provided is invalid , can you please post a memorycard @2Tie image

AmyRoxwell commented 5 months ago

Due to 2Tie being busy atm, here is a video and a memory card on how 2 recreate it on MH2DOS (If the basarios quest doesnt show up just reboot the game and try again)

You want to hit the head of the basarios, be careful of not hitting the neck where it bounces:

The quest in question: Screenshot_04_20_2024-13

The video: https://www.youtube.com/watch?v=QOUwADqW0OE

The memory card: OwO Firstcard.ps2.zip

2Tie commented 5 months ago

here's the test save - Continue, load up Adam, go to Single Mode, talk to the chief, pick 5 Star quests, here's the quest you'll be looking for image if not present in the list, you may need to restart the system or clear a quest to reroll the available quests. once in the quest, basarios will be in area 2. the character is already set up to have blue sharp lance. the save: Mcd001_converted_converted.zip

2Tie commented 1 week ago

turns out it wasn't the 0.20 1.25 multiplication that was causing the bug as i anticipated earlier - instead it was a different aspect of the gist that multiplied the 0.20 by 1.0 and it rounded down to 0.1999999, causing that value 1.25 to be less than 0.25.

here's a minimal reproduceable example i've written and tested:

   li $v0, 0x14
   mtc1 $v0, $f0
   cvt.s.W $f1, $f0 //f1 is 20.0
   li $v0, 0x64
   mtc1 $v0, $f0
   cvt.s.W $f2, $f0 //f2 is 100.0
   nop
   div.S $f2, $f1, $f2 //20.0 / 100.0 into f2, this will be 0x3E4CCCCD on either machine
   nop
   lui $v0, 0x3f80
   mtc1 $v0, $f0 //load 1.0 into $f0
   mul.S $f1, $f0, $f2 //multiply! $f1 will be 0x3E4CCCCD on emulator, while on hardware it becomes 0x3E4CCCCC

and here is an .elf i've made with ps2sdk to run the above code and print the resulting value to the screen. I haven't yet tested if every irrational float will be rounded down like this, but it seems values that can be perfectly represented (like 1.25) aren't altered.