PCSX2 / pcsx2

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

[Feature Request]: New pnach code type for pointer reading in conditionals #10606

Open SlyCooperReloadCoded opened 9 months ago

SlyCooperReloadCoded commented 9 months ago

Description

I'm proposing a new pnach code type be implemented, which would be a fusion of the 6 type and the E type, capable of reading values at a pointer for use in conditionals. I'll be referring to as F type for this feature suggestion. It would look something like this:

patch=1,EE,F0AAAAAA,extended,00000LLL patch=1,EE,VVVVVVVV,extended,C00T00NN patch=1,EE,0000OOOO,extended,00000000

A = Base address L = Number of lines below to execute, like how E and D codes already do it V = Value to check for C = Condition, like how E and D do it - 0 = equal to, 1 = not equal to, etc. T = Type, such as 1 byte, 2 bytes, or 4 bytes N = Number of offsets O = Offset to follow

This would be expandable like E and D:

patch=1,EE,F0AAAAAA,extended,00000LLL patch=1,EE,VVVVVVVV,extended,C00T0003 patch=1,EE,0000OOOO,extended,0000OOOO patch=1,EE,0000OOOO,extended,00000000

Reason

Due to many PS2 games having various levels of moddability, different methods of obfuscation, or difficult filesystems, it simply might not be possible for some modders or modding communities to "just create a game patch for it" or "make a custom build that can do it". The community's skill and speed of progression are also important factors. Sly Cooper modding has this issue - there are no data archives, instead data is read from a list of sectors stored in the executable, and all the data is in proprietary formats. I've been told that the code is also not in the easiest language to read, and has had all debug symbols stripped out. Our only entry point is memory through pnach. We've dealt with this by writing specific-use-case Assembly and inserting it into codecaves. While this does work, it not only has the potential to massively inflate the line count of the pnach, but also increases the level of technical knowledge that beginners would need to create similar modifications, which hurts us as this one feature would eliminate the need to write a large percentage of the Assembly we write, and remove a massive learning curve for beginners, some of which are already familiar with writing pnach cheats.

While this would not be useful for a large percentage of game modders, it would be invaluable to those who could, and it seems odd that - while pnach is based on PS2 Patch Format - it has a pointer writing type but not a pointer reading type. This wouldn't have necessarily been useful when the format was created, but it absolutely would be nowadays with easier access to system memory and an overall increased interest in game modding.

Examples

I'll be using Sly 2: Band of Thieves as an example game.

The pointer shown in this image points to the struct for the black bars overlay the game uses during cutscenes. image

By default, the game looks normal, but if you set that to 2, they enable: image

If I wanted to create a pnach that enables that if I hold R1 and press Select, I'd do the following:

patch=1,EE,E10300FF,extended,002DFC11 // 0x2DFC11 checks if R1 is held, global address patch=1,EE,E10200FE,extended,002DFC02 // 0x2DFC02 checks if Select is held, global address patch=1,EE,602E1E60,extended,00000002 // Pointer to the struct of these black bars patch=1,EE,00020001,extended,00000064

This has been possible for a very long time. However, what if I wanted to check if these cutscene bars are enabled, and if they are, set health to 1? Well, since E and D only support single line, that's not possible. However, if F type existed, it would look like this:

patch=1,EE,F02E1E60,extended,00000003 // Checks if value at 0x2E1E60 with offset of 0x64 is equal to 2 patch=1,EE,00000002,extended,00020001 patch=1,EE,00000064,extended,00000000 patch=1,EE,203D4AB0,extended,00000001 // Sets health to 1

Currently, the only way to do this is write Assembly that reads this pointer, copies its value to a global position in memory, compile this Assembly into bytes, and insert it into a codecave using a pnach. So much effort would be saved with this F type, and you wouldn't have to understand Assembly to accomplish it.

RibShark commented 4 months ago

+1 for this, would be very useful to make sure patches only run at the right places!

SlyCooperReloadCoded commented 4 months ago

It should be noted that a 32-bit single-line conditional type also does not exist. This would implement two things at once.