Netdex / twinject

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

Keys do not work; Z, X and C are all active in the GUI #9

Closed Boii1 closed 6 years ago

Boii1 commented 6 years ago

Touhou 8 v1.00d TWinJect v0.05 (Release)

None of the hotkeys activate on keyDown/keyPress.

Injection: OK EXCEPTION_BREAKPOINT DEBUG: DllMain injected DEBUG: DllMain: Debugger attached DEBUG: Detours: Hooked LoadLibraryA DEBUG: Detours: Hooked sub_410A70 DEBUG: Detours: Hooked first stage sub_447A37 DEBUG: D3D9: Found Direct3DCreate9 at addr 1695102048 DEBUG: Detours: Hooked Direct3DCreate9 DEBUG: D3D9: Feeding fake IDirect3D9 DEBUG: Error 10 (object not found) in function enum EResult __thiscall SysAudioHook::CMMDeviceClient::EraseAudioClientInVector(struct IAudioClient *)

DEBUG: DI8Init: Hooking second stage DirectInputCreate DEBUG: Detours: Hooked second stage DirectInput8Create DEBUG: DI8Create: Feeding fake DirectInput

Boii1 commented 6 years ago

Apparently won't work on the English version.

Netdex commented 6 years ago

Some English patches affect things like the order some modules are loaded, or change some code that twinject needs to hook onto. All my testing is done with the untouched Japanese versions, so I can only guarantee twinject's functionality with them. Also make a note that twinject 0.0.5 was released last year, and many changes were made to twinject since then. I haven't built a release in a while, but I'm currently working on connecting AppVeyor to the releases page so you should see some more up to date releases sometime soon.

Boii1 commented 6 years ago

Appreciate the comment, I have been messing around with it a bit and it seemed to have worked for a bit although it's good to hear that you will be releasing them sometimes soon. Being that the sources are still out there, I managed to build one of them. Though, it hadn't been able to work properly, the GUI shows it's injected however shows that the keys Z, X and C are all active and input from the arrow keys are not shown. I assume that it's reading from a different point than what was intended as to why those three were shown pressed. Theoretically it's just attempting to read from the memory at a misaligned point. Although, it wouldn't really matter as the English versions may have extra memory built into it which would basically make the use of realignment impossible. Anyways, I had been wondering which version you are on, and where to get any of the Toho games as fuzzy2.com doesn't exist anymore (I think they went to .net with a different tree setup), you can't get them from his site, unless I've been mistaken. I've seen other links but mainly they are tampered in some manner or simply aren't of the right versions. I'll keep looking for them. I'll also be hoping for some releases when you're able to. 😉

Netdex commented 6 years ago

Hmmm, I just tried the gensokyo.org English patch of th08 v1.00d and it worked fine. If you're using thcrap then it definitely won't work, because it does some fiddly magic that twinject doesn't like.

So if you enter a stage then enable the bot (press G) does it do anything? Or does it stay completely still? And if you show debug visualizations while in a stage (press H), does it show anything?

There are also a few settings that should be checked, for example make sure DirectInput isn't disabled in custom.exe, and make sure you have the enbconvertor d3d8->d3d9 patch. Also make sure you don't have a controller plugged in, because for some reason that messes things up.

As for the original games, the links I've used some seven or so odd years ago seem to all be dead. However I've tried several English patches of Imperishable Night and they seem to work fine (as long as they are v1.00d). In fact, even the one from a certain shrine that shall not be named worked as well.

I've integrated the GitHub releases with the CI I'm using, so now some releases are available under this repository.

Boii1 commented 6 years ago

I think the issue was the controller because it seems to work now. It however does not register any keys pressed by the player. Also, I noticed that in twinject.ini it has this line env=th=th08. Does the env stand for envelop with the number corresponding after the second th, meaning you can envelop this bot into other games? I've only been wondering that as because you were working on support for other games (as I recall, could have been an older project of yours). As for the buttons, they work now. However, they cannot be toggled.

EDIT: It really enjoys the bottom right corner, the down and right arrow keys are always pressed. No idea if it's intended or not. Figured out the italicized.

Netdex commented 6 years ago

The env setting actually stands for "environment", as in the _putenv call in twinject.cpp that tells twinhook what game version to load (don't worry, there's no way anyone could have guessed this). As of writing this twinject supports th07, th08, th10, and th15, although to varying levels of support (there's a chart in README.MD, so far th10 is the most supported). You can see which games are supported by looking at th_init in twinhook.cpp.

It's definitely not supposed to enjoy the bottom right corner (it's supposed to enjoy dodging bullets and not dying). The only reason I can think of why it would do this is if you enable the bot (press G) before you are in the stage and able to move, because it does a bit of calibration by moving the player around (so make sure you only press G after the stage starts and you are able to move). It should print a message in the debug console along the lines of "calibrated player vel...", you should get something along the lines of 4.5 2.0 depending on the player you chose.

EDIT: Also,

-- CONTROLS --
G - Enable bot
B - Disable bot
H - Display debug graphics
N - Hide debug graphics 

Don't ask me why, but I made the enable/disable keys different (because key down detection was a lot easier than key press detection). Of course I've written code since then that fixes that problem, but I never got around to changing the keyboard shortcuts.

Boii1 commented 6 years ago

Ah, well I had assumed as it had something to do with the general compatibility with the other Toho games. I had tried it on TH15 before knowing that, just a lucky guess of what to do. The bot was activated once in the game though. No idea why it would differ.

Aside from this with the keypress, if you wanted to you could always use a boolean, and if you did keypress, you don't really need it as keyup is just as sufficient. I mean it doesn't trigger keypress until the keyup is in fact triggered. I haven't really looked into your source code too much, only some minor things that I was fixated on. Why not use an if else statement with the boolean so you don't have that many keys, even if it's still keydown.

Try something like this maybe? (Yes I know it looks simplistic, I haven't been into attachment so I don't have it off the top of my head, also it's in Java here, I'm not too adept with C++, mainly a bit of simple pointer manipulation...) //Controls boolean botBool, debugBool = false; if (myKeyCode = 'B') {(botBool = false ? startBot() && botBool = true : stopBot() && botBool = false)} if (myKeyCode = 'D') {(debugBool = false ? showDebug() && debugBool = true : hideDebug() && debugBool = false)}

Netdex commented 6 years ago

I'm sorry if I'm misunderstanding, but I'm a bit confused. I'll explain to you the current way keyboard input is handled so we're on the same page (also for my own documentation in case I forget).

So first we use th_di8_hook to hook DirectInput8Create, so that when the game calls it, it will call our custom function at th_di8_hook::DirectInput8Create_Hook. DirectInput8Create initializes the DirectInput interface, and returns a COM object that controls the interface. We return our own fake interface called a DirectInput8Wrapper, which is essentially the same as a DirectInput8 instance except there is additional code at DirectInputDevice8Wrapper::GetDeviceState. The game uses GetDeviceState to poll the current state of the keyboard to see which keys are pressed, so we hook this and add our own code to control the inputs we send to the game.

In control/th_player::onTick, we use GetDeviceState to get the current state of the keyboard for managing keyboard inputs related to controlling the bot (we have to get the actual inputs, not the inputs the game sees because those are modified, so we access the original DirectInputDevice8 instead of the wrapper) . If all's good, then we call control/th_player::handleInput, which has the code that controls the bot and visualization state. Unfortunately the problem is that GetDeviceState returns keyboard state, not keyup and keydown events. If we used something like

if key_state at DIK_B is pressed then
    enabled = !enabled

It would toggle the bot at every frame that the key is pressed, since it's polled every frame.

If you look carefully at th_player::onTick you might see a line with kpd.tick(diKeys, press);, which populates some array called press. kpd is an instance of info/keypress_detect, which basically takes keyboard state at a frame and compares it to the last frame to see if it has changed. If it has, then that constitutes a keyboard press. The press array stores when keys have changed rather than are pressed. This is a relatively new addition, so I haven't used it much yet.

However, with kpd, we can replace the code in th_player::handleInput with this:

if (press[DIK_G])
    setEnable(!enabled);
if (press[DIK_D])
    render = !render;

Of course, you may wonder why I haven't done this yet? Mostly because I forgot. I'll make sure to change it in a future commit.