Hook modding Journal - RedBrumbler/BMBFCustomSabers GitHub Wiki

You use MAKE_HOOK_OFFSETLESS(function name, return type, Il2CppObject* self, any other function parameters) to hook to a function. if you are hooking to a static method you do not need the Il2CppObject* self parameter in the MAKE_HOOK function. after this you use {} to tell the code what to do when this specific function gets called.

example:

MAKE_HOOK_OFFSETLESS(RawScore, void, Il2CppObject* noteCutInfo, int* beforeCutRawScore, int* afterCutRawScore, int* cutDistanceRawScore) {
    RawScore(noteCutInfo, beforeCutRawScore, afterCutRawScore, cutDistanceRawScore);
    if(NoHud) return;
    Accuracy_RawScore(noteCutInfo, beforeCutRawScore, afterCutRawScore, cutDistanceRawScore);
}

A good practice for the function name parameter is to use the convention namespace_class_method. if there is no namespace just use class_method. This will make your code easier to read for others and also easier to understand and call those methods.

by default hooking a method makes the code not run that it originally would have run, so it's needed to if you hook a method to also add the original method into your defined code, that way it will still actually run (don't worry this will not create a loop of it constantly calling the hook), that's why you see the RawScore added there after making the hook.


To get a value from a class there are 2 ways to do so, and it needs (at least it's good practice to do that) to be prefixed with either RET_UNLESS or CRASH_UNLESS, which do exactly as they say, they return unless the value gets dereferenced (RET), or crash the mod/game unless the value gets dereferenced (CRASH).

next you get the value and dereference it with GetFieldValue(class, valuename);

Il2CppObject* Level = RET_UNLESS(GetFieldValue(self, "_level"));

this will get a field value from the self class, called _level, a field value is basically like int x;

you can also use GetPropertyValue<TYPE>(object, propertyname), like so

Il2CppString* LevelID = RET_UNLESS(GetPropertyValue<Il2CppString*>(Level, "levelID"));

this will get a property value from the Level object called LevelID, a property value is basically like int x {get; set;}


the type to use for objects that are not native cpp is Il2CppObject* (you use pointer because you need to refer to a specific instance of something, like the specific level that's stored somewhere, so oyu point to the value in the class in unity, from your own code.), this applies to gameObjects, or any other types that you may not actually have available to you in c++ code.


to call methods from specific namespaces you add the namespace:: "modifier" in front of the method. for example to do stuff with the standard string format you use std:string and that will make the c++ code use the string as defined in the std namespace, else it may use it as defined in another namespace.


The setup and the load methods need to be prefixed with extern "C" so that the naming convvention they follow is that of the C language which will allow bmbf to call those methods for modding.


After setting up all the hooks with MAKE_HOOK_OFFSETLESS you need to then actually install those hooks. this is done in the load method after a call to il2cpp_functions::Init();. After the call to this method you want to call INSTALL_HOOK_OFFSETLESS for all the hooks you made, and use the following way of calling it:

INSTALL_HOOK_OFFSETLESS(function name, il2cpp_utils::FindMethodUnsafe(namespace, class, method, number of parameters the method has));

if the method has no namespace just put in an empty string there: ""

⚠️ **GitHub.com Fallback** ⚠️