hrydgard / ppsspp

A PSP emulator for Android, Windows, Mac and Linux, written in C++. Want to contribute? Join us on Discord at https://discord.gg/5NJB6dD or just send pull requests / issues. For discussion use the forums at forums.ppsspp.org.
https://www.ppsspp.org
Other
11.43k stars 2.19k forks source link

Providing emulator data in plugins #15626

Open ThirteenAG opened 2 years ago

ThirteenAG commented 2 years ago

What should happen

This was partially discussed on discord, here's some features I'd like to see implemented:

Who would this benefit

  1. Unthrottling

Right now it's only possible via pressing(holding) a button, but it's possible to let the game handle it during loading, including not only the initial phase, but during other parts too. E.g.

https://user-images.githubusercontent.com/4904157/175276804-38ae1eb4-0c2c-4477-8d49-7946496703e5.MOV

https://user-images.githubusercontent.com/4904157/175276846-4e94be7d-b5fe-4552-adec-f93b67a06328.MOV

Only thing needed is the ability to send ppsspp a signal from game plugin that unthrottling has to be activated or deactivated. E.g. bool PPSSPP_Unthrottle = true;

  1. Emulator data(settings)

Useful for ultra-widescreen fixes, that mostly needed for mobile phones with non 16:9 display. Currently it's only possible to get this data from the ini file, manually setting the correct values that match the emulator settings. E.g.

int PPSSPP_WIDTH;
int PPSSPP_HEIGHT;
int PPSSPP_AR_SETTING;
...
if (PPSSPP_AR_SETTING == ENUM_STRETCH)
    fAspectRatio = PPSSPP_WIDTH / PPSSPP_HEIGHT;
else
    fAspectRatio = 16/9;
  1. Input data

For example can be used to replace in-game controls, like adding pressure sensitivity for triggers. Or activating in-game cheats with keyboard.

Platform (if relevant)

No response

Games this would be useful in

-

Other emulators or software with a similar feature

I can probably only link this, since I'm not aware of anything like it.

Checklist

ThirteenAG commented 2 years ago

Main question is how to implement this, but I'm not at all familiar with ppsspp internals to suggest anything. In the project linked above, I parse elf files and gather symbol addresses for them, then just write to these addresses externally.

In ppsspp's case, perhaps creating some fake PSP api is possible? Or just allocating some space at a constant address where plugins can access it, and read/write to/from it from emulator.

hrydgard commented 2 years ago

Creating a fake PSP API is absolutely possible, and probably the way to go. Like a PPSSPPServices or EmulatorServices API..

anr2me commented 2 years ago

Btw, with mouse data, will it be possible to tampers the game's camera orientation to make a fluid/free mouse-controlled camera like FPS games on PC?

ThirteenAG commented 2 years ago

Btw, with mouse data, will it be possible to tampers the game's camera orientation to make a fluid/free mouse-controlled camera like FPS games on PC?

Depends on the game, but in GTA VCS I managed to alter PS2 code to read raw input mouse data provided by windows:

https://user-images.githubusercontent.com/4904157/175383493-111ba807-5662-4bdf-84a0-c3e27b365846.mp4

LunaMoo commented 2 years ago

Depends on the game

Not really, it's easy to write your own assembly function to translate any input you can work with into fluid changes in any game even if it never supported that natively and it's also not even limited to camera controls.

My right analog patches were simple examples trying to encourage people showing how easy it is and even included one that controlled acceleration in a racing game, but it never got much interest, maybe because even very simple code ends up long in asm and translated to CWC format ends up as a scarry wall of text. could also be because not many people care about accurate input.

Different input data simply means different math to do to translate it into whatever we want to achieve, most of that math is primary school level. Examples of it are actually in every game with digital controls already as they tend to add various accelerations to change digital into fluid motion, it's the same thing, just the opposite. The idea with more accurate input is to strip the game off all those artificial accelerations and directly translate the input to output(which again, doesn't have to be just camera, anything can be modded as long as it has sense).

hrydgard commented 2 years ago

@LunaMoo I think maybe also we can make your way of making patches more well known in various ways, including maybe putting a tutorial on ppsspp.org and so on, there may be ways to increase interest.

Patches that only ever need to run in an emulator and not on the real hardware could also theoretically be written in easier ways like exposing peek/poke memory and more detailed control inputs to a small Lua host or something, which is what Sony does for game patches in their PS2 emu for re-releases, for example. Though that path is a bit controversial. Yet another alternative would be using our websocket debugger API from any language, though gets tricky to manage.

unknownbrackets commented 2 years ago

Well, it really depends on how you want this to be used.

If you want to change the game's code, an HLE module type API makes sense. This could be like using HEN APIs. You'd call them as functions in code. This could also be used with plugins. The downside is, using a cheat would be problematic because the functions wouldn't be linked.

If you want to patch existing code, it might be better to use the sceIoDevctl style APIs (this is still annoying from cwcheat, though.) The benefit of this is that it doesn't require additional module linkage and can be applied to existing game code in most cases. The downside is that it generally requires pointing at memory and isn't as friendly to use.

If you're wanting to affect the game's memory or apply additional functions from outside or using a scripting language such as Lua, JavaScript, or Python - it makes more sense to potentially use some scripting system. On desktop, it's easy to imagine a script you run that starts up PPSSPP, connects to its API, and does things in the background written in at least Python or JavaScript. Could also imagine something embedded which might be needed for mobile.

I'm definitely not a fan of the static memory-mapped address approach, at least for writing data. I realize that makes sense for hardware and matches older consoles, but it complicates memory handling. The benefit for read data, though, is it's probably easiest to redirect reads to it.

There are several things we could potentially do here:

  1. Allow cwcheat or maybe even armips style patches as "plugins" (different type than prx.)
  2. Expose an module linkage style API, and potentially also allow the same functionality via devctl.
  3. Allow some way via debugger API to schedule a syscall at next opportunity.
  4. Consider exposing a mips encoding hack to do special things?
  5. Consider exposing cwcheats for more than just vibration.
  6. Consider some embedded scripting (maybe exposed via plugins.)
  7. Consider exposing some read-only data at a mapped addresses...

It'd also be good to think about what data we want to expose and accept.

-[Unknown]

LunaMoo commented 2 years ago

I only made like 4 as a proof of concept, polishing a bit more only one for MGSPW(which is customizable enough to work well even with mouse), but my "right analog" cheats currently all work in pretty similar and rather simple way: 1) hook to game code right after it reads input which it writes somewhere in memory, 2) create custom function which loads those values and translate "right analog" data through some basic math to write some useful values - usualy separately different directions(just 1/0 which represents key pressed or not) and a set of values which is calculated for what game works with, usually floating point, potentially modable via user editable options(custom sensitivity or some non-linear function) also separate for each direction and write it for later use, 3) hook to functions that take input to decide whenever key is pressed and instead load our 1/0 from analog being moved in specific direction, 4) hook to functions that translate that input into some action and instead of whatever it used originally load previously generated values we want(for example camera movement acceleration or car acceleration).

Where step 2 requires to figure how the game works and have some idea how we want to mod it, and 3 and 4 requires finding a place in code where input is checked and values are applied, the first easily found by memory breakpoint at location where values of input are stored, the latter follows it, but can also be found via cheat engine pretty easily with some experience in searching for unknown values.

Complexity comes from the fact that even reasonably simple functions writen in assembly takes a lot of space visually, so it would be cool if we could write things in high level, but I have no idea what way would be best. I guess currently it could already be done by using PPSSPP function replacements, but those are hardcoded also it might be nicer to just have a custom syscall that could run some python/lua/js whatever or hook to specific functions via hash, maybe with offset to be able to replace or add after some specific lines of code some of ours. Really dunno what would be most fitting. CWCheat is very useful, but not very readable when storing assembly code, if it could be used for just directing a spot we want to patch or inject our code that could be written in high level that would make it really easy to create new things with a small downside of those things working only in PPSSPP, but if we start going into things like mouse or wheel input then it's a bit outside of real PSP world already:).

ThirteenAG commented 2 years ago

I personally think CWCheat, Pnach and other things like that are a mistake and shouldn't exist to begin with. I just don't see a point in reading a set of symbols only a parser can understand, let alone write them. So it's better to expand existing plugins system(where there are no limiting factors and you're basically free to rewrite the entire game) with new features and then if there's demand for it, make scripting, expose data etc.

LunaMoo commented 2 years ago

Writing assembly means writing 32bit opcodes and that's what CWC basically does, writes 32bit(or less) data per line, it's pretty much same thing all cheating tools do, just simpler than a debug tool with disassembly.

I agree that most of it's "advance" code types are lame, made by people who tried to reinwent programming due to being too lazy to learn ASM, but you're writing cheats by looking at disassembled game code and you can do anything with asm doesn't have any silly limitations of some external systems. Perfectly readable once loaded, I use PPSSPP disassembly myself, but cheating plugins had it's own.

Also most people are happy with just cheats that freeze variables and cheating tools make it way faster than plugins.

unknownbrackets commented 2 years ago

Well, if it's assembly anyway, I'd say we could use a .asm file is a "plugin" or patch, and just automatically run armips on memory. We already pull in armips to encode changes via the debugger and API. It wouldn't be hard to just run it against a file as input. That would be a lot more readable.

We could potentially also add predefined symbols for unlinked HLE funcs (including our custom API) when assembling, so that would solve being able to call functions that aren't defined.

A small downside of prx plugins is that they take up PSP memory space, which isn't unlimited (but can go into kernel memory area, so not a huge deal.) Some of the right analog "plugins" actually just modify assembly, and running armips might be more readable for that scenario too. That said, obviously a prx plugin is more versatile.

It really depends on the goals, as I said before. For example, if someone wanted to create a plugin that automatically looked up text from the game in an AI translation service and translated them (for better or worse), that would be easier using a scripting language. Perhaps similarly with anything else that might already have high-level SDKs for services available (Python or JS is probably better here than Lua.)

-[Unknown]

LunaMoo commented 2 years ago

I played with function replacements while messing around #15640 and it's really fun, if this could be turned into external system with roughtly similar power a lot of fun patches could be done effortlessly. I found it faster to build ppsspp with test hacks than changing game code directly with my custom functions. Changing register values on the fly, calculating stuff without having to find a spot in user memory for all custom code, attaching to exact place in exact function based on it's hash and offset, it's just great. :)

unknownbrackets commented 2 years ago

Well, with the debugger API you can set a breakpoint to get the same effect. There's a sample in this repo: https://github.com/unknownbrackets/ppsspp-api-samples/

-[Unknown]

LunaMoo commented 2 years ago

Is that api feasible for mods that could be shared? Seems like a lot of dependencies.

For figuring stuff up through it might be great, I might have to learn a bit, I saw reading from, but does any of the examples include writing a new value to register? NVM I found it https://github.com/hrydgard/ppsspp/blob/59f3d4b8f5f70cffcaa9388228c492c603433135/Core/Debugger/WebSocket/CPUCoreSubscriber.cpp

Frankly setting everything up for it compared to just pressing ctrl+D in PPSSPP was scaring me off from even trying soo far, but if I could just write myself a few template scripts that I could reuse every time I'm investigating different game I might as well try learning it, hopefully in not soo distant future.

Thanks.

hrydgard commented 2 years ago

So I guess potentially we could reuse a lot of the debug API infrastructure from an internal scripting language, if we want to make a solution that's a bit more practical for deploying this kind of tricks and hacks on mobile and in general..

Lua is my go-to example of an embedded language because it's so extremely easy to integrate, but it has many drawbacks too, it's not a great language. Luau fixes some problems but not really any that we care about. I'm leaning towards no, and I know that unknownbrackets has a special dislike for it :)

Javascript is another logical choice, of course. But embedding a whole node runtime would be overkill. There are a bunch of smaller embedded runtimes implementing JS or various subsets of JS that we could look at, maybe.

Similarly, there are a number of embedded interpreters for various subsets of python too.

Are there any other sensible alternatives?

We could collect a few options and think about it.

LunaMoo commented 2 years ago

I understand the hate for it, but have to mention one more point for lua aside of it's integration in case it's not common knowledge - Cheat Engine is using it from many years, so practically everyone who ever created cheats, trainers or mods on pc with windows knows it already.

unknownbrackets commented 2 years ago

https://bellard.org/quickjs/ seemed promising to me at one point.

If people really like Lua, I'm not that against it. To me, it just seems like a dead end. It's like learning Klingon or something - useful maybe somehow among clubs that want to speak it I guess (is this a thing?), but not practically useful outside that. And even if someone claims Klingon is easy to learn, it's probably not that much easier than say Dutch or Spanish. Except those languages might gain you something in other aspects of life.

But I mean if people really like Klingon or whatever, I'm fine with it being there.

In theory, we could support dll/so files as well, for people who don't want to use whatever language. I don't necessarily want to directly bundle multiple scripting engines, but it'd be nice to give people flexibility. Maybe WASM for cross-platform is better? Not sure, haven't looked into embedding that, maybe it's not a thing.

-[Unknown]

anr2me commented 2 years ago

dll/so files support can be risky isn't? since it can contains malware without anyone knowing what it actually do, compared to readable-scripts.

unknownbrackets commented 2 years ago

Perhaps, but honestly one should be suspicious of anything - js, python, lua, and prx files can all contain malware. I don't think dynamic objects are ideal, but I do think flexibility is good...

-[Unknown]

hrydgard commented 2 years ago

Regarding .so/.dlls, Android will no longer load .so files from non-APK directories, so that's out. Yes, since we have JIT capability still we could write our own .so loader, but still, a lacking solution with regards to cross platform and so on.

WASM is a bit more viable (can be loaded on any platform), although the binaries unless written in very careful "no-std" C/Rust will be much larger than the corresponding few lines of js/python/lua script would be (though maybe not a huge concern).

Could supply scripting engines as WASM perhaps, though we're getting towards the realms of overengineering...

Linblow commented 2 years ago

The following API functions can be useful:

The sceIoDevctl sounds good as it is the most-portable option between PSP and PPSSPP.

LunaMoo commented 2 years ago

I don't think there's a benefit in making things that only exist on PPSSPP to be "most-portable to PSP", since at it's core PPSSPP specific things are not usable on PSP anyway and just add's limitations. For me I know lua and know that many more people into modding scene knows lua than they do PSP SDK which is full of holes and worse learning tool than emulator's source code, but I wouldn't necessary prefer it over python or whatever, if it ment access to automatic translations, voice control, AI computing and whatever we have in modern world which wasn't really a thing 20 years ago.

Features aside as for the returning topic on detecting/blocking memory patches online I'm always saying you'd get better results simply by writing rules and creating community around that mindset. You can't stop people that really want to cheat as even dumb people can just pay someone who's more experienced at it to bypass all your efforts and all it does is stopping casual users from enhancing their experience by mods that you don't whitelist.

Linblow commented 2 years ago

It's not about porting PPSSPP stuff to the PSP. The advantage of sceIoDevctl is there's no need to compile a plugin twice (one for PSP, one for the emu). There is also no need to link to a "PPSSPP plugins" stubs library. When run on the PSP, a plugin will load just fine, and any call to the emulator specific devctl commands will fail, but will work when run in the emu.

From my long time experience with cheaters in the PSP online scene, it's more efficient to detect cheats with software than just telling them not to cheat. Even with rules, or a no-cheat mindset, there's always one guy who will cheat. Even worse, some will use barely noticeable cheats. Of course, a truly motivated individual will find a way to bypass detectors. Still, I believe this is the most effective way.

Both lua, or any scripting language, and that simple approach could be implemented.

unknownbrackets commented 2 years ago

Even if it were a PSP module, you could still use it on a PSP, I suppose, you would just get SCE_KERNEL_ERROR_MODULE_NOT_YET_LINKED for any of the functions. There'd be no problem if they weren't called.

I think we could make any changes to RAM from the windows/similar debugger send messages. I'm not sure this would really stop cheaters, I think there'd just be a "special build" of PPSSPP one person would make that enables cheating. It's a bit like spam, people are only doing these easiest thing now, but even if you block that, they just up the ante. Regardless, doesn't mean memory change monitoring can't be useful.

For Python/JS, it'd be worth considering how dependencies are handled (is it easy to download pip dependencies from embedding?) Maybe I think in Lua too? Not sure if there are libraries for Lua...

-[Unknown]

LunaMoo commented 2 years ago

I think it's pointless, PPSSPP is open source, doesn't even have to create custom builds, if there's a code detecting changes in the memory, we can just break that code, it's done on a daily basis for cheating, if it's open source you don't even need to look for it.

There's like one PSP game with such simple anti-cheat that checks for changes in memory, it's broken by one opcode change, complex anti-cheat for PC games have to hide and obfuscate what they're doing often rightfully blamed for poor performance and even those are easily avoided, the only reason people usually don't casually release their tools for online games is basically the fact that large companies will sue you for their loses in millions of dollars.

Linblow commented 2 years ago

The average user doesn't know how to do that. It's more like one strategy among others to prevent cheating. Think of it as traffic barriers, they increase security and limit damages, but are not bulletproof. Does it mean they are useless and shouldn't be there? Obviously, no.

ThirteenAG commented 2 years ago

I was just thinking about another use case, which would be hooking the game to make save states at certain places, e.g. in GTA after mission completion.