Netdex / twinject

Automated player and hooking framework for bullet hell games from the Touhou Project
GNU General Public License v3.0
75 stars 14 forks source link

Using `twinject` to tweak bullet and player movement speed? #27

Open vittorioromeo opened 3 years ago

vittorioromeo commented 3 years ago

Hello,

I have an idea in mind for a project. I'd like players to enjoy Touhou at higher refresh rates without changing the actual gameplay speed.

At the moment, increasing or decreasing the FPS in Touhou games also affects the speed of the simulation. So I thought: what is we increase the FPS to, say, 144, and then give the game's update loop a fake time delta that would keep the simulation speed similar to the original one?

For example, assume that the normal time delta in Touhou is 1 for 60FPS. If we raise the FPS to 144, I'd like the time delta to become 0.416 (60 / 144). The game engine currently doesn't do this, and the time delta is always 1 regardless of the FPS.

Do you think twinject could be used to detect and change these values? I'm an experienced C++ developer but I have almost no experience in reverse engineering.

Netdex commented 3 years ago

Hey,

I think that's actually a pretty great idea. It's certainly possible to do this with twinject, with the difficulty depending on how the specific game is implemented. I think most Touhou games do their physics on a frame-by-frame basis, which is useful for keeping replays in sync since they don't run at the frame rate at when they are originally recorded. This means that the physics of the game might be tied to the framerate in mysterious ways, and that they don't necessarily seperate physics from rendering by using a time delta.

You can see an example with Shuusou Gyoku (Seihou Project), which is open-source and shares some similarities with early Touhou Project games. The game routines use frame counting based on the primary game loop keeping frame times of 16 ms. The game's internal compiled language for controlling enemies (ECL) also has an interrupt-based timer which is tied to frame count.

With these considerations in mind, raising the frame rate might require also modifying the stage scripts with proportionally reduced bullet velocities, increasing the time between stages etc. to keep the original gameplay speed.

vittorioromeo commented 3 years ago

Thanks for the quick and detailed reply!


I think most Touhou games do their physics on a frame-by-frame basis [...] they don't necessarily seperate physics from rendering by using a time delta

That's what I assumed, and I have no plans of changing that. My idea was quick and dirty -- force the game to run at 144FPS, and decrease velocities/accelerations while increasing spell delays and stuff like that.


The game routines use frame counting based on the primary game loop keeping frame times of 16 ms. The game's internal compiled language for controlling enemies (ECL) also has an interrupt-based timer which is tied to frame count.

That's honestly pretty discouraging. I was hoping for some sort of global bullet speed multiplier, or some constant time delta which never changes... but it seems that, at least in that project, everything is pretty hard coded. Even with full access to the source it wouldn't be trivial to support 144FPS, and I shudder at the idea of having to do that while reverse engineering.


It's certainly possible to do this with twinject

Could you please share any pointer on where to start? Never hacked on a Touhou game before and I'm pretty lost :)

vittorioromeo commented 3 years ago

OK, I have somewhat good news. I did some research on some Touhou Discord servers and it turns out someone made a 120FPS patch for EOSD: https://joec.moe/touhou/touhou.html

I managed to find the author of the patch and talked to them. They mentioned there is a value in memory which is basically the time delta, a floating point value always set to 1. This can be altered to change the speed of the simulation. Therefore, changing the value to 0.5 with Cheat Engine and increasing FPS to 120 with vpatch results in a somewhat consistent gameplay experience.

However, for some reason not everything uses the time delta value. I have found this value myself in TH12 (address: th12.exe+B2ED0, realaddress: 004B2ED0) and changed it to 0.4166 to enable 144FPS. Most things seem to be affected, including:

Unfortunately, some other thing completely ignore this value:

I discussed with the author of the TH06 patch and they mentioned that they had to tweak some other values manually by using IDA to disassemble the executable. So, in short:

Netdex commented 3 years ago

That's pretty convenient, good find! My best guess is that this time delta value might have been used for some spellcards that manipulate time, like Youmu's slash attack in th07. It was probably a value that could have been manipulated using the stage script. This might also explain why enemy speed/acceleration is ignored, since there usually aren't any enemies during boss spell cards, and the boss movements are scripted anyways. I don't think anything in th12 uses this mechanic too, which is probably why Sanae B's attack wasn't validated for it. All of this is just a theory though of course.

This definitely makes this project tractable though, if those are the only two things that aren't affected by the time delta value. For example, it would be possible to locate the code that does enemy movement physics and hook/patch it to incorporate the time delta value as well.

Deus-nsf commented 2 years ago

Please tell me this is still a thing. I'm dying to be able to play Touhou at a true 120 Hz refreshrate one day...

Deus-nsf commented 2 years ago

Maybe 144 FPS at correct speed is a bit too ambitious and it would possibly lead to too many rounding errors and problems, however 120 FPS, since it's an even multiplier (x2, or rather /2 speed) seems much safer.