This is the AMP version of this page.
If you want to load the real page instead, click this text.

Solved Storing address of a class, then using it later on crashes the game

Status
Not open for further replies.

ThePerplexedOne

Platinian
I've got a button on my menu to add 1k currency each time it is pressed:

C++:
        case 5:
            if(playerDataManager) {
                AddGem(playerDataManager, 1000, nullptr, nullptr);
            }
            break;

To get `playerDataManager`, I hook the `Initialize` function:

C++:
void(*old_PlayerDataManager_Initialize)(void *instance);
void PlayerDataManager_Initialize(void *instance) {
    old_PlayerDataManager_Initialize(instance);
    playerDataManager = instance;
    //AddGem(instance, 100000, nullptr, nullptr);
}

C++:
HOOK("0xE0A634", PlayerDataManager_Initialize, old_PlayerDataManager_Initialize);

And then I also get the `AddGem` function:

C++:
AddGem = (void(*)(void*, u_long, void*, void*))getAbsoluteAddress(targetLibName, 0xE0D2DC);

This only works if I call `AddGem` from inside my hooked function. If I store the address and reference it later, it crashes the game.
 
Maybe u can read this, he explained somewhere there
 

Hooking "Update" and then toggling inside there is just a workaround for the issue I'm having. Unless I'm missing something?
 
It's probably due to IL2CPP garbage collecting the object and deleting it if it detects that no Managed code is using it. You can use the IL2CPP API functions il2cpp_gchandle_new and il2cpp_gchandle_free to make sure it doesn't get garbage collected. Here's an example:

C++:
#include <cstdint>

void* playerDataManager = nullptr;
uint32_t playerDataManager_gcHandle = -1;

// Make sure to get the addresses or offsets of these functions.
void* (*il2cpp_domain_get)(); // Gets the current IL2CPP domain and returns it. Use it for il2cpp_thread_attach.
void* (*il2cpp_thread_attach)(void* domain); // Attaches the current thread to the IL2CPP domain and returns the thread object. Use it for il2cpp_thread_detach. Do not call in a hooked function.
void (*il2cpp_thread_detach)(void* thread); // Detaches the current thread from the IL2CPP domain. Do not call in a hooked function.
uint32_t (*il2cpp_gchandle_new)(void* object, bool weak); // Prevents the object from being garbage collected and returns the handle for it. Use the return value for il2cpp_gchandle_free.
void (*il2cpp_gchandle_free)(uint32_t gchandle); // Allows the object to be garbage collected. Call with the gchandle received from il2cpp_gchandle_new

void (*old_PlayerDataManager_Initialize)(void* instance);

void PlayerDataManager_Initialize(void* instance) {
    old_PlayerDataManager_Initialize(instance);
    
    if (instance) { // check for nullptr
        if (playerDataManager_gchandle != -1) // make sure the handle is valid
            il2cpp_gchandle_free(playerDataManager_gchandle); // a new PlayerDataManager is being initialized, get rid of the old one.
        
        playerDataManager_gchandle = il2cpp_gchandle_new(instance, false); // create a new handle so that the object doesn't get deleted
        playerDataManager = instance;
    }
}

void ButtonClicked() {
    void* thread = il2cpp_thread_attach(il2cpp_domain_get());
    
    AddGem(playerDataManager, 1000, nullptr, nullptr);
    
    il2cpp_thread_detach(thread);
}
If possible, try to post a link to the game so I can try to help.
 

This is huge information, thank you so much! I will try this and see what happens :)
 

It actually worked! Thank you so much, you've saved me so much headache :D
 
Status
Not open for further replies.