Polprzewodnikowy / N64FlashcartMenu

Universal N64 flashcart menu for wide variety of devices
132 stars 10 forks source link

Cheats support (backend only) #94

Closed Polprzewodnikowy closed 5 months ago

Polprzewodnikowy commented 5 months ago

Description

This PR implements cheat support (patcher + engine) with a simple API to provide Action Replay/Game Shark compatible cheats (with exception of cheats that utilize GS button).

API consist of a single pointer to an array of the cheats ended with a double zero entry, For example, if you want to pass these cheats to the patcher:

D01F9B91 0020 // Majora's Mask (USA) Inventory Editor
803FDA3F 0002

Put cheats in a uint32_t array as such (notice last two entries are zeros):

uint32_t cheats[] = {
    0xD01F9B91,
    0x0020,
    0x803FDA3F,
    0x0002,
    0,
    0,
};

And pass this array as a boot parameter: menu->boot_params->cheat_list = cheats;

Motivation and Context

To provide users with ability to run game modifications in a easy way.

How Has This Been Tested?

On a SummerCart64 flashcart + assembly instructions generation verified in ares emulator via GDB.

Screenshots

No screenshots

Types of changes

Checklist:

Signed-off-by: Polprzewodnikowy sc@mateuszfaderewski.pl

parasyte commented 5 months ago

I can provide a bit of context for this.

First, it is not mandatory to start the game through IPL3. Booting through it was done in the original implementation because I could not trust the "boot simulator" in the alt64 menu. Too many games would not start, and the boot emulator had game-specific hacks for some of the ones that did work.

Also, there are games that specifically look at state left by IPL3 for anti-piracy measures. Together, just booting through IPL3 was the best approach at the time. The patches are there to allow the F0/F1 code types to modify the 1 MB executable and bypass the IPL3 checksum failures that they cause.

With custom IPL3s, this practice becomes much less appealing [^1]. The real GS firmware just sets up the minimal state required and jumps to the entrypoint.

Secondly, the watchpoint exception handler in the real GS firmware is incredibly broken. It makes assumptions that only works on games compiled with an older N64 SDK. The games whose enable codes have a 0120 value are a workaround for the incomplete watchpoint protection done by the GS. With a more robust watchpoint handler, those patches are not necessary. The self-modifying code in the GEH is how I decided to address the issue. By rewriting the source register, regardless of which register was used, it should always redirect 0x80000180 writes to 0x80000120. The cheat engine returns to 0x80000120 to run the game's GEH.

And I suppose the last comment is that your analysis of the code is quite accurate. It's a complex beast. As I mentioned on Discord, there are some code types that are unimplemented. But everything else seems to be in order.

[^1]: They probably won't do any integrity checks. You still need to find the entrypoint jump, though.

Polprzewodnikowy commented 5 months ago

Thanks for the info! I've updated the credit annotation. Let me know if you will add license info in your original repository. I don't think it's worth the effort to support cheats in non-retail games without standard IPL3. Libdragon open source IPL3 for example wipes the entire RDRAM as one of the first steps. This would require the menu to detect such ROMs and reimplement loader without this feature. It might be even harder to keep this working as libdragon's bootloader is not set in stone (and probably would never be).

Polprzewodnikowy commented 5 months ago

This PR implements only a way of inserting the cheats into the game. There's still no GUI or loading list from the file as these still need to be implemented in a separate pull request.