Retrying an F6 Hook?

Started by biolizard89, October 10, 2011, 01:35:50 AM

Previous topic - Next topic

biolizard89

I'm working with a game whose ASM is in a different location each boot.  F6 codes work fine, but I have to apply them via USB Gecko after the ASM is loaded.  Problem is, the ASM isn't loaded when the game starts, so the F6 code doesn't hook when the game starts, and gives up.  Is there any way to periodically retry an F6 hook until the hook is successful, after which point the F6 will stop re-searching?

Thanks.

biolizard89

Hmm, so you're using a button activator to initiate the F6 search?  I considered that, but two issues: (a) it requires the user to do something instead of it being automatic, and (b) the pad data moves around in this game too, so dealing with button activators is quite difficult.  Is there no way to handle retrying F6 searches automatically?

Y.S.

It could be done by overwriting the "searched but not found" status in an F6 code using 4E code type.
Like this:
4E000018 00000000
38000002 00FF0100
10000002 00000000
E0000000 80008000
F60000NN XXXXYYYY

This method is not tested but I think it's worth giving it a try.

Quote(If) Search, Set Pointer
F60000NN XXXXYYYY
ZZZZZZZZ ZZZZZZZZ
ZZZZZZZZ ZZZZZZZZ

Creates an if (so this code requires an endif), then searches for the NN lines of Z values between XXXX0000 and YYYY0000 (or, if XXXX is 8000, between 80003000 and YYYY0000).
To prevent this code from causing game lag, it will only search the first time it is read by the code handler (the result is saved to the code and reused).
If the Z values are found, set po to the starting address of the values (SSSSSSSS) and replace the F6 line with F60003NN SSSSSSSS.
If the Z values are not found, then set code execution status to false and replace the F6 line with F60001NN XXXXYYYY.

QuotePut next code's location into the Pointer Address
4E00XXXX 00000000

XXXX is a signed 16bits value : 0xFFFF=-1
po will hold the address at which the next line of code is stored + XXXX

Pseudo Code
No pseudo code available.

Examples
4E000000 00000000 = po points to next code's first 32bits.

4E000004 00000000 = po points to next code's second 32bits.

dcx2

Stuff asked for something like this once.  http://wiird.l0nk.org/forum/index.php/topic,8730.msg72854.html#msg72854

F6000001 XXXXYYYY
ZZZZZZZZ WWWWWWWW
# use PO to do stuff here...
E0000000 00000000 # terminate everything, but DO NOT RESET PO
32000000 ZZZZZZZZ # if [po] != ZZZZZZZZ
4E00QQQQ 00000000 # reload po with address of F6 code
A8000000 FFC00001 # this is true once every 64 frames, or about 1 second @ 60 FPS
16000000 00000008 # rewrite F6 line
F6000001 XXXXYYYY # rewrite everything in case the hook moved
E0000000 80008000 # terminator and reset po

The only issue is that you have to manually count QQQQ to make sure it points the po at the F6 line.

In the event that the F6 code fails the first time, the po will be 80000000.  As long as [80000000] != ZZZZZZZZ, then this will re-try the F6 code once per second-ish.

If the F6 find it, the 32 code will skip the reset.  If the hook moves, the 32 code will reset the F6 code and it will search again.

biolizard89

#4
@Y.S. and dcx2: wow, that's brilliant!  I'll try this out, hopefully it works for me.

EDIT: Yes, it works!  Code released, thanks for the help!

daijoda

Quote from: dcx2 on October 10, 2011, 03:16:36 AM
A8000000 FFC00001 # this is true once every 64 frames, or about 1 second @ 60 FPS
I'm not sure I understand this... When the counter has reached 0x40, why would that make the statement true?

0x0001 and not(0xFFC0)
= 0000000000000001 and not(1111111111000000)
= 0000000000000001 and 0000000000111111
= 0000000000000001

but 0x40 = 0000000001000000

dcx2

Masking with not(0xFFC0) means that only the lower six bits will be compared to 0001.  This means 0001 matches, 0041 matches, 0081 matches, 00C1 matches, 0101 matches, etc.  Every 0x40 frames it will be true.  The only issue is that this "delay" is only adjustable by powers-of-2.  You can't get 1.5-ish seconds, only 1-ish or 2-ish (or 4-ish, 0.5-ish, etc)

daijoda

Oh.. does that mean if I mask with not(0xFFF8) only the lower 3 bits will be compared? And if I mask with not(0xFFFE), only one bit will be compared? What about those masks for button activators, such as, not(0xF3FF) for 0x0C00?

dcx2

@biolizard, good to see your code is working. ^_^  I looked at it a little bit, and there may be some room for optimization using C0 codes.  You can also remove the dependency on Gecko Registers using a bl trick in ASM or gosub code type.

---

@daijoda, you seem to have a good grasp on how the mask operand works.  Only bits with 0 will be looked at.

The mask works basically the same for button activators.  Except activators don't count up, so it's not really useful for this "modulus" style usage.

daijoda

I'm surprised that's the case. Now I'm confused, lol, why do people say it's better to use as button activator this form:
28_______ F3FF0C00

than this form?
28_______ 00000C00

The first compares only 2 bits for buttons A and B, while the second compares all bits for all buttons...

dcx2

This is somewhat off-topic for this thread, so if you have more questions you should post in the codetypes explanation thread or make a new one dedicated to your question.

Consider a button activator which makes you moon jump when you press A.  Also, for this hypothetical game, holding Z will make you run.  If you use a mask of all 0's, then you won't be able to moon jump when you're running.  The mask allows you to press other buttons (e.g. run) while still activating the code.

Deathwolf

Actually it won't work for C0 codes right? I tried it but it's not possible to debug C0 codes... anyway this is offtopic
lolz

daijoda


biolizard89

Quote from: dcx2 on October 10, 2011, 06:50:02 PM
@biolizard, good to see your code is working. ^_^  I looked at it a little bit, and there may be some room for optimization using C0 codes.  You can also remove the dependency on Gecko Registers using a bl trick in ASM or gosub code type.

---

@daijoda, you seem to have a good grasp on how the mask operand works.  Only bits with 0 will be looked at.

The mask works basically the same for button activators.  Except activators don't count up, so it's not really useful for this "modulus" style usage.
Thanks dcx2!  Agreed, there are a lot of things I'd like to optimize; removing the dependency on Gecko Registers is one of them.  I'm intending to integrate the code with GeckoTunnel at some point; I'll do some fairly heavy cleanup for that release.  I released what I had now since it's useful without GeckoTunnel, and because my priorities for GeckoTunnel are with other features, so the 3D code may not be integrated into GT for a while.  Anyway, yeah, it's not what I would call "final," and I'll definitely be changing a lot of it to reduce the hacky-ness of it.