xan1242 / NFS-XtendedInput

NFS (Black Box, MW & newer) - XInput Plugin
MIT License
112 stars 7 forks source link

(Feature-ish request) Hash texture names at compile time? #23

Closed TorutheRedFox closed 2 years ago

TorutheRedFox commented 2 years ago

This would speed things up a bit I think (along with the implementation of this into the TPK tool so you don't have to do it manually in the INI)

dunno how to implement the algorithm into a macro though, but thankfully C++ 11 has our backs and allows us to just write constant expressions which have the same end result as a macro while having more flexibility as you no longer need hacks to do recursion (which has to be fixed length too)

here's a quick matching implementation of it (you can also make a non-constexpr copy of it for runtime computation of hashes, could be useful in giving the different controllers string names in the INI without needing to rewrite much maybe?)

constexpr unsigned int BIN_HASH(const char* string)
{
    char* _string = ((char*)string);
    int result = -1;

    while (*_string != 0) {
        result = result * 0x21 + (unsigned int)(*_string);
        _string = _string + 1;
    }

    return (unsigned int)result;
}
TorutheRedFox commented 2 years ago

i.e. rather than

#define PS4_DPAD_UP_HASH 0x52FB3FD2

you'd have

#define PS4_DPAD_UP_HASH BIN_HASH("PS4_DPAD_UP")

and it'd expand to 0x52FB3FD2 at compile time

xan1242 commented 2 years ago

Hmmm that would be useful to do during compile time. Good idea!

I wasn't very familiar with constexpr, to be perfectly honest with you, but I could implement this.

I currently use the ripped bStringHash function but this appears to be the exact same thing anyways, so if you want to, you may submit a PR for this.

Or I'll do it myself, your choice.

TorutheRedFox commented 2 years ago

it's a version of bStringHash I decompiled with Ghidra then manually cleaned up to remove redundancy and make it more readable

xan1242 commented 2 years ago

Ah alright.

Feel free to replace bStringHash with it and turned into this! I'd gladly accept this change!

TorutheRedFox commented 2 years ago

FYI I'm working on making the hash macros use this instead I'll open a PR once I'm done

TorutheRedFox commented 2 years ago

Opened pull request at https://github.com/xan1242/NFS-XtendedInput/pull/24

I haven't tested it with ProStreet as I don't have the game installed rn so be sure to do that before merging

xan1242 commented 2 years ago

With 0995a41 I'm considering this implemented, closing.

xan1242 commented 2 years ago

Nuh-uh, after further snooping, constexpr doesn't do its job that I thought it did. Reverting all changes.

xan1242 commented 2 years ago

image

Proof here: IDA shows this in GetAppropriateButtonTex function. This is not right and it should NOT happen.

xan1242 commented 2 years ago

image

It should look a little something like this.

Runtime calculations should NEVER occur like in the picture I showed before this one.

For now I'll stick to compiler macros until a better solution arrives.

TorutheRedFox commented 2 years ago

hmmm

that's odd

TorutheRedFox commented 2 years ago

I'll look into what's causing this and if it can be fixed

otherwise, time to make that macro then :D

xan1242 commented 2 years ago

I've tested with Carbon but that doesn't have a barring on this, this is the compiler's doing.

xan1242 commented 2 years ago

There isn't a way to make this a "macro" per se, from what I've read. Maybe I could be wrong, but constexpr is the way to go.

xan1242 commented 2 years ago

The solution is to convert the hash macros into enums instead. That way it'll actually get processed by the compiler.

I'll make the implementation myself.

TorutheRedFox commented 2 years ago

I think I fixed it with a dirty hack?

TorutheRedFox commented 2 years ago
// compile time hasher thanks to C++11
// I tried making a macro version but failed xdddd
// P.S. it causes IntelliSense to freak out in some cases, but it still compiles
static constexpr int __HASH(char* string)
{
    if (string == NULL) // sanity check
        return 0;

    char* _string = ((char*)string);
    int result = -1;

    while (*_string != 0) { // loop through each char until string terminator is reached
        result = result * 0x21 + (unsigned int)(*_string);
        _string = _string + 1;
    }

    return result;
}

template <int V> static constexpr int _HASH = V;

#define HASH(str) _HASH<__HASH(str)>

it seems to work, as I don't see any instances of the source strings in the output binary now

TorutheRedFox commented 2 years ago

tested ingame and yeah it works

xan1242 commented 2 years ago

Result is OK in this case as well. Either way would work (enums or templates).

xan1242 commented 2 years ago

implemented in 666286e, closing