Page 1 of 1

Shenmue 2 EU Save File Import Function

PostPosted: Sun Oct 25, 2015 6:29 pm
by Sappharad
I wish someone would have done this about 10 years ago, but oh well. Here it is now, a codebreaker code to remove the region check on Save File Import. I really hated having to convert the files, because then when you go back to Shenmue 1 you can't play it anymore without converting back because it you get some obscure error trying to start the game.

Import any S1 Save:
0205AAA4 910B6241
0105AAAA 0000A003

Tested on hardware.

Oh, but I'm sure some of you want to patch this into the game. In 1ST_READ.BIN, make the following changes:
At 04aaa4, Change 426206D1 to 41620B91 at
At 04aaaa, Change 048F to 03A0

To understand how this works, let's look at the relevant game code. This should be interesting if you've ever converted a save by hand:
Code: Select all
H'8c05aaa0: H'2fe6  ./  mov.l R14, @-R15
H'8c05aaa2: H'6ef3  .n  mov R15, R14
H'8c05aaa4: H'6242  Bb  mov.l @R4, R2 //Change to mov.w -> 62 41
H'8c05aaa6: H'd106  ..  mov.l @(H'8c05aac0), R1          (H'45454853) //Change to mov.w -> 91 0B
H'8c05aaa8: H'3210  .2  cmp/eq R1, R2
H'8c05aaaa: H'8f04  ..  bf/s H'8c05aab6 //Change to bra 8c05aab4 -> A0 03
H'8c05aaac: H'e000  ..  mov H'00, R0
H'8c05aaae: H'5241  AR  mov.l @(1, R4), R2
H'8c05aab0: H'9104  ..  mov.w @(H'8c05aabc), R1          (H'010e)
H'8c05aab2: H'3210  .2  cmp/eq R1, R2
H'8c05aab4: H'0029  ).  movt R0
H'8c05aab6: H'6fe3  .o  mov R14, R15
H'8c05aab8: H'000b  ..  rts
H'8c05aaba: H'6ef6  .n  mov.l @R15+, R14
H'8c05aabc: H'010e  ..  mov.l @(R0, R0), R1
H'8c05aabe: H'0009  ..  nop
H'8c05aac0: H'4853  SH  ???
H'8c05aac2: H'4545  EE  ???


At 8c05aaa4, it's loading 4 bytes at the area of your VMU save file with the "SHEE" text in it into register R2.
At 8c05aaa6, it's loading 4 bytes, the hard coded string "SHEE" into R1.
Then it checks if they're the same. If not, it jumps to the end of the method at 8c05aab6, cleans up, and returns. The result goes into R0, and because the value is never set, R0 contains 0, meaning "false". The save file is not compatible.
If they are the same, it continues performing comparisons. It checks for 0E01, the other value you have to change when you convert your save file. If they're equal, R0 is set to 1, (true) and the method returns.

The code simplifies the save file check. Per my comments above, instead of checking 4 bytes, we only check the first two, for SH, since all Shenmue 1 save files have that. (Japan is SHEN, US is SHEU, Europe is SHEE) Then we just skip over the other check completely, so as long as it finds SH, the save file is accepted.


Now I should probably disappear for a few weeks, since I still haven't finished playing MGSV.
Enjoy!

Re: Shenmue 2 EU Save File Import Function

PostPosted: Mon Oct 26, 2015 12:50 am
by Anthony817
Wow, you just keep finding ways to make these games better and better!

Re: Shenmue 2 EU Save File Import Function

PostPosted: Wed Oct 28, 2015 1:24 pm
by Giorgio
This is lovely!
I've been motivated to learn SH-4 assembly code after reading these posts (1, 2) at ASSEMBlergames forums. I always considered it to be something hard, but after further research realized that it is not. Maybe it helps because I also learn an assembly language for a specific microprocessor during a course at my school.

Now, I'd been willing to write something similar for Shenmue I. Because, I don't like it when I save the game from e.g. the NTSC version of Shenmue I, and, when I try to load it from the PAL version, it does not accept it (or vice-versa).

I followed the same logic as the above code for Shenmue II. Here's the code for the 1ST_READ.BIN of Shenmue I PAL:
Code: Select all
H'8c09c726: H'8000  ..  mov.b R0, @(0, R0) ! Address in the BIN file: H'8C726
H'8c09c728: H'6242  Bb  mov.l @R4, R2  ! NEW: H'8c09c728: H'6241  Ab  mov.w @R4, R2
H'8c09c72a: H'd34d  M.  mov.l @(H'8c09c860), R3          (H'45454853) ! NEW: H'8c09c72a: H'9399  ..  mov.w @(H'8c09c860), R3          (H'4853)
H'8c09c72c: H'3230  02  cmp/eq R3, R2
H'8c09c72e: H'8b05  ..  bf H'8c09c73c ! NEW: H'8c09c72e: H'a003  ..  bra H'8c09c738
H'8c09c730: H'5041  AP  mov.l @(1, R4), R0
H'8c09c732: H'918f  ..  mov.w @(H'8c09c854), R1          (H'010e)
H'8c09c734: H'3010  .0  cmp/eq R1, R0
H'8c09c736: H'8b01  ..  bf H'8c09c73c
H'8c09c738: H'000b  ..  rts
H'8c09c73a: H'e001  ..  mov H'01, R0 ! NEW: H'8c09c73a: H'0029  ).  movt R0
H'8c09c73c: H'e000  ..  mov H'00, R0
H'8c09c73e: H'000b  ..  rts
H'8c09c740: H'0009  ..  nop
https://www.onlinedisassembler.com/odaweb/hlwvY6P4/0

However, it still does not accept the save file. Of course, I put the instructions in the .bin file in the Little Endian format. I've tried every possible imaginative way of how to make it work, but still doesn't accept it. I even wrote that code to make it work (but still no luck):

Code: Select all
H'8c09c728: H'6242  Bb  mov.l @R4, R2 ! NEW: H'8c09c728: H'e001  ..  mov H'01, R0
H'8c09c72a: H'd34d  M.  mov.l @(H'8c09c860), R3 ! NEW: H'8c09c72a: H'000b  ..  rts
H'8c09c72c: H'3230  02  cmp/eq R3, R2 ! NEW: H'8c09c72c: H'0009  02  nop

I suspect it is doing some other check somewhere else, that I am not aware of, otherwise it doesn't make sense for me why any of these codes do not work.

Therefore, if you have any ideas on possible solutions, would be great to hear them and learn more about SH-4 and Shenmue's code logic.

Re: Shenmue 2 EU Save File Import Function

PostPosted: Wed Oct 28, 2015 1:26 pm
by shengoro86
This is awesome. Thank you!!!!!

Re: Shenmue 2 EU Save File Import Function

PostPosted: Wed Oct 28, 2015 11:10 pm
by Sappharad
Giorgio wrote: This is lovely!
I've been motivated to learn SH-4 assembly code after reading these posts (1, 2) at ASSEMBlergames forums. I always considered it to be something hard, but after further research realized that it is not. Maybe it helps because I also learn an assembly language for a specific microprocessor during a course at my school.


I was kind of the same way. I learned a random processor's assembly language in college and wrote an emulator for it. After that, I can pretty much read through assembly languages I've never used before and as long as I have a PDF with the instruction set in it, I'm fine. My first time playing with SH-4 assembly was messing with these codes.

Anyway, my advice would be to grab that version of Demul 0.49 with a debugger that I mention in the assembler thread. Put a breakpoint into the code and confirm that R3 and R2 are loading the values you want. ('bp x 8c09c72c') That version doesn't actually work with Shenmue 2, but it does work with Shenmue 1.

When I made my changes, it didn't work the first time because my mov.w instruction was off by 1, grabbing the wrong side of the 4 byte value. I actually figured that out when I disassembled my modified 1ST_READ.BIN again and saw it wasn't what I intended.

Does that help at all?

Re: Shenmue 2 EU Save File Import Function

PostPosted: Thu Nov 12, 2015 3:51 pm
by Giorgio
Thank you. I used Demul 0.49 and its debugger. I set the breakpoint ('bp x 8c09c72c'). Here are the following scenarios and results (always with the PAL GD-ROM's 1ST_READ.BIN modified appropriately, as shown above in my previous post):

1. PAL SAVE FILE:
General registes R2 and R3 are equal (both have the same value, that is '48 53', that is 'HS'). The software loads the save file.

2. NTSC SAVE FILE:
Before reaching the title screen, it shows the TEST screen and it prompts a question if the screen is 60Hz compatible.
When trying to load the save file, the breakpoint is not reached. It shows the message that says that is unable to load the save file.

Therefore, what seems the most logical/possible is that it does another check before it decides if it will do the check to find the "HS" string. What could this first check be about? I do not know. But there is a hunch that is checking about if the save file contains the data that the screen was 50Hz or 60Hz. If that's the case, where is that code of that check in the 1ST_READ.BIN? I don't know and can't think something concrete (as of now on) how to find it.

Image

Re: Shenmue 2 EU Save File Import Function

PostPosted: Thu Nov 12, 2015 9:43 pm
by Sappharad
Giorgio wrote:Therefore, what seems the most logical/possible is that it does another check before it decides if it will do the check to find the "HS" string. What could this first check be about? I do not know.

Yeah, that seems like the most obvious answer to me as well.

The Shenmue 2 save file check was checking two different things though. Both the 4 character game code, and the 0x010E after that. It's possible that the first game checks that, and some additional stuff as well.

One approach you might be able to take is to search RAM for where the save file gets loaded into memory. If it is always loaded to the same spot (no idea), you could search for code that references addresses in the range of memory that the file is loaded to. (You could also do read breakpoints in that region, but without knowing where it looks that may get complicated.) It has to load at least part of the save file from the VMU into memory before it can look at it, so you can count on it being somewhere.