UE4SS-RE / RE-UE4SS

Injectable LUA scripting system, SDK generator, live property editor and other dumping utilities for UE4/5 games
http://docs.ue4ss.com/
MIT License
1.38k stars 188 forks source link

[Question] PalWorld: The function HookedLoadMap Crashed #584

Closed AnnznnA closed 4 months ago

AnnznnA commented 5 months ago

[Game and UE version] palworld v0.3.2 -UE5.1.1

[Description] I tried to develop a lua mod based on ue4ss-lua-doc,and it works without crash,but when I re-enter the world ,it will crash and this is report

:UE4SS!RC::Unreal::HookedLoadMap() [D:\a\RE-UE4SS\RE-UE4SS\deps\first\Unreal\src\Hooks.cpp:433]

I developed with the zDEV-ue4ss v3.0.1 version

so I am tring to make HookedLoadMap:0 in the ue4ss-setting.ini and it still Appear Is there the same problem as me?:D

AnnznnA commented 5 months ago

At first I turned off the 'RegisterLoadMapPostHook' Seems to solve the problem but it still seems to be there

Buckminsterfullerene02 commented 4 months ago

What happens if you try the latest experimental version?

AnnznnA commented 4 months ago

What happens if you try the latest experimental version?

The setting of 'HookedLoadMap' have taken effect,this solves my problem,but in fact, we need this HookedLoadMap。

And I think this bug was originally caused by the game PalWorld, he reconstructed a lot of objects and caused a reference error when he re-entered the world,you need re-enter the game to solve, I didn't find any problems in the source of ue4ss, according to the dmp file, the input parameters of HookedLoadMap are caused by invalid values of the crash, and I don't have the source code of palword, I can only locate it through testing at the moment.

Using Lua mod to call the Blueprint function of some Palworld's built-in Blueprint objects can cause these problems, which can be avoided by packaging a new Blueprint function into the pakfile and load by BPModLoader yourself.

I can give some examples of test results

--- will not crash when re-enter the world,I am not using the BP object and it is safe
RegisterKeyBind(Key.NINE, {ModifierKey.SHIFT }, function()
    ExecuteInGameThread(function()
        FindFirstOf("APalCharacter"):RequestJump()
    end)
end)

--- will crash when re-enter the world,I am not using the BP object and it is safe
RegisterKeyBind(Key.NINE, {ModifierKey.SHIFT }, function()
    ExecuteInGameThread(function()
        FindFirstOf("BP_OtomoPalHolderComponent_C"):InactivateAllOtomo()
    end)
end)

this is just an example, and it is actually developed to target a specific palcharacter object,I don't know if it's because Lua calls Blueprint objects, but that's how I've tested it so far. I could have avoided him by packaging my own Blueprint scripts with ue-pak, but hopefully Lua will work because he's just awesome, fast and hot-reloadable Perhaps as a non-game developer with no experience, there are some things to keep in mind about whether or not to take Blueprint objects

UE4SS commented 4 months ago

I can give some examples of test results

--- will not crash when re-enter the world,I am not using the BP object and it is safe
RegisterKeyBind(Key.NINE, {ModifierKey.SHIFT }, function()
    ExecuteInGameThread(function()
        FindFirstOf("APalCharacter"):RequestJump()
    end)
end)

--- will crash when re-enter the world,I am not using the BP object and it is safe
RegisterKeyBind(Key.NINE, {ModifierKey.SHIFT }, function()
    ExecuteInGameThread(function()
        FindFirstOf("BP_OtomoPalHolderComponent_C"):InactivateAllOtomo()
    end)
end)

I haven't looked into your particular problem, but I thought I'd comment on this code. I also realize that this is test code, but I still think it's worth pointing something out so that people that look at this later can learn from it.

There's an assumption that FindFirstOf will return you the correct instance. There may be multiple objects of the same class in memory, and FindFirstOf only gets the first of the specified class it finds, which means it might be an outdated object scheduled for GC, or just otherwise not the correct object if the game spawns multiple instances of the same class for whatever reason. The use of FindFirstOf should be avoided whenever possible for that reason.

An alternative is using FindAllOf and iterating each result and performing whatever necessary code to find which object is the one you actually want. Another, better, alternative is to find a UFunction that has a reference to your object as a param and that executes at your desired occasion and then hooking it with RegisterHook.

AnnznnA commented 4 months ago

I can give some examples of test results

--- will not crash when re-enter the world,I am not using the BP object and it is safe
RegisterKeyBind(Key.NINE, {ModifierKey.SHIFT }, function()
    ExecuteInGameThread(function()
        FindFirstOf("APalCharacter"):RequestJump()
    end)
end)

--- will crash when re-enter the world,I am not using the BP object and it is safe
RegisterKeyBind(Key.NINE, {ModifierKey.SHIFT }, function()
    ExecuteInGameThread(function()
        FindFirstOf("BP_OtomoPalHolderComponent_C"):InactivateAllOtomo()
    end)
end)

I haven't looked into your particular problem, but I thought I'd comment on this code. I also realize that this is test code, but I still think it's worth pointing something out so that people that look at this later can learn from it.

There's an assumption that FindFirstOf will return you the correct instance. There may be multiple objects of the same class in memory, and FindFirstOf only gets the first of the specified class it finds, which means it might be an outdated object scheduled for GC, or just otherwise not the correct object if the game spawns multiple instances of the same class for whatever reason. The use of FindFirstOf should be avoided whenever possible for that reason.

An alternative is using FindAllOf and iterating each result and performing whatever necessary code to find which object is the one you actually want. Another, better, alternative is to find a UFunction that has a reference to your object as a param and that executes at your desired occasion and then hooking it with RegisterHook.

Thks for your nice advice,and perhaps my expression was not clear enough.I believe and have tested the application of Lua interfaces, such as "Register Hook", "FindAllOf","FindObject","NotifyOnNewObject", They all have the opportunity to obtain the UE object I want。

For this specific game test code, I can guarantee that there is only one instance of these objects in the memory during game runtime, so I chose "FindFirstOf " as a simpler method and gave an example,and the function is actived and can use。

Even if FindFirstOf returns an empty reference or an exception reference, in the first case, the Lua interpreter will give me a prompt indicating an empty reference exception, and it will not report an error. UE4SS has taken care of this maintenance. If there is an error when calling a game function with an exception reference, it is also due to the source game not handling the error reference of its internal function properly, It is cause. However,These are all traceable

In fact, this is not the problem I encountered. I called the test function once in the game through the Key-Binding regiser, and then did not execute any lua scripts again. ReEntering to the game world [which is not a Restart for this game] caused the problem. During this process

·Obtained an instance within the game ·Called the callable function of this instance ·Entering the world again in the game, the game will execute and construct a series of functions or objects, causing a crash

Actually, I have already located the possible occurrences through HookLoadMap, When HookLoadMap is enabled, ue4ss will get illegal input parameters and crash when re-enter the game world. As a Hook function, the illegal input parameter provider comes from the game,And the game PalWorld will trigger hookloadmap when re-enter the game world. I don't know why only calling a function of an object inside the game can cause this situation. Of course, I haven't replicated it in other UE games except PalWorld

UE4SS commented 4 months ago

I can confirm that when joining a world, regardless if the above code has been executed, it will get stuck and crash inside the games LoadMap function. What's confusing is that LoadMap succeeds during startup when the main menu is loaded, and if they had changed LoadMap significantly, you'd think it would crash immediately when you start the game.

AnnznnA commented 4 months ago

I can confirm that when joining a world, regardless if the above code has been executed, it will get stuck and crash inside the games LoadMap function. What's confusing is that LoadMap succeeds during startup when the main menu is loaded, and if they had changed LoadMap significantly, you'd think it would crash immediately when you start the game.

Yeah,And joining the world for the first time,it will not. Afrer I once use some function from some game objects like "BP_OtomoPalHolderComponent_C:InactivateAllOtomo",Exit the world and reload, this will crash.

Essentially, LoadMaps are executed within the game, but the second execution can cause the game to crash, and the top of the reporting stack does not come from ue4ss, which may be difficult to debug

UE4SS commented 4 months ago

Can you try turning off CheatManagerEnablerMod and ConsoleEnablerMod and let me know if it still crashes ? I might be having a different problem than you and this will tell me if that's the case.

UE4SS commented 4 months ago

This might not be related but I want to point out that in your test code above, the non-crashing call to FindFirstOf is looking for the wrong class. It should be PalCharacter, not APalCharacter.

AnnznnA commented 4 months ago

This might not be related but I want to point out that in your test code above, the non-crashing call to FindFirstOf is looking for the wrong class. It should be PalCharacter, not APalCharacter.

I'm sorry that I temporarily wrote my code on issues. It should indeed be PalCharacter, and A only indicates that it is an Actor object.  And for the two mods you mentioned, they were turned off during my testing, I only use LineTraceMod to log game character info.  this is my mod.txt

CheatManagerEnablerMod : 0
ActorDumperMod : 0
ConsoleCommandsMod : 0
ConsoleEnablerMod : 0
SplitScreenMod : 0
LineTraceMod : 1
BPModLoaderMod : 1
BPML_GenericFunctions : 0
jsbLuaProfilerMod : 0
UE4SS commented 4 months ago

In that case, I'm unable to reproduce the problem. I can go back and fourth between the main menu and my save without any problems, even after executing your test code.

AnnznnA commented 4 months ago

In that case, I'm unable to reproduce the problem. I can go back and fourth between the main menu and my save without any problems, even after executing your test code.

Seems this issue has been solved? But I still have this problem. Whether your save is new or not is a question that has something to do with the amount of time you play Can you try to replace the InactivateAllOtomo by ActivateCurrentOtomoNearThePlayer,These two functions are called at the time of release and revocation, respectively。

RegisterKeyBind(Key.NINE, {ModifierKey.SHIFT }, function()
    ExecuteInGameThread(function()
        FindFirstOf("BP_OtomoPalHolderComponent_C"):ActivateCurrentOtomoNearThePlayer()
    end)
end)

thks

UE4SS commented 4 months ago

In that case, I'm unable to reproduce the problem. I can go back and fourth between the main menu and my save without any problems, even after executing your test code.

Seems this issue has been solved? But I still have this problem. Whether your save is new or not is a question that has something to do with the amount of time you play Can you try to replace the InactivateAllOtomo by ActivateCurrentOtomoNearThePlayer,These two functions are called at the time of release and revocation, respectively。

RegisterKeyBind(Key.NINE, {ModifierKey.SHIFT }, function()
    ExecuteInGameThread(function()
        FindFirstOf("BP_OtomoPalHolderComponent_C"):ActivateCurrentOtomoNearThePlayer()
    end)
end)

thks

I'm not able to cause a crash with this code either, using experimental release 137-g6867a08.

AnnznnA commented 4 months ago

g3320fc1 will crash in this game with my code. I choose [137-g6867a08] to make it soved。 I don't know if this was accidental or solved the problem, but at least my speculation is wrong.

This made the probability of the problem occurring extremely low, but I still reproduced it using the code currently being developed


local _currentHolder = nil
function GetOtomoPalHolder()
    if _currentHolder == nil then
        _currentHolder = FindFirstOf("BP_OtomoPalHolderComponent_C")
    end
    return _currentHolder
end

RegisterHook("/Script/Engine.PlayerController:ClientRestart", function (Context) 
    _currentHolder = nil
end)

RegisterKeyBind(Key.NINE, {ModifierKey.SHIFT }, function()
    ExecuteInGameThread(function()
        local CharacterContainer = GetOtomoPalHolder().CharacterContainer.SlotArray
        local begin = GetOtomoPalHolder().SelectedOtomoSlotID
        CharacterContainer:ForEach(function (index,value)
            GetOtomoPalHolder().ActivatedOtomoSlotID = -1
            GetOtomoPalHolder().SelectedOtomoSlotID = begin
            GetOtomoPalHolder():InactivateCurrentOtomo()
            GetOtomoPalHolder():ActivateCurrentOtomoNearThePlayer()
            begin =  GetOtomoPalHolder():GetNextOtomoSlotID()
        end)
        GetOtomoPalHolder().SelectedOtomoSlotID = begin
        GetOtomoPalHolder().ActivatedOtomoSlotID = begin
    end)
end)

it weren't for the inevitable event, this problem couldn't be attributed to UE4SS. If possible, have you found any unreasonable aspects of this development method? Of course, I think this is entirely my problem. If it's really troublesome, you can close this issue. I still appreciate your response 👍 I will provide the test video results of this code

Test.zip



UE4SS commented 4 months ago

Is a .dmp file not generated ? With a .dmp file, I can debug the problem without reproducing the crash myself.

As far as your code is concerned: If I'm looking at it right, you're iterating an array and executing identical code for each iteration, you're not using the index nor the value of the array element, meaning that the ForEach loop doesn't actually achieve anything other than slowing the code down.

AnnznnA commented 4 months ago

UE4SS did not generate any dmp files, Only the dmp file of the game client is available here.

I used the GetNextOtomoSlotID()method from within the game to replace the iterative index in this code, in order to ensure that the generation order follows the desired effect; Currently, what I am more concerned about is whether this encoding method is the root cause of the crash.

Then I can only upload the crash dmp file of the client

UECC-Windows-95689DF14BC739408DCD35A3046C13BE_0000.zip

UE4SS commented 4 months ago

Unfortunately that dmp file is not useful for us. Because I can't reproduce the problem, and because there's no viable dmp file, I'm unable to help any further. This might be a game specific problem, but I don't know.

AnnznnA commented 4 months ago

I understand that debugging UE4SS requires one's own dmp file, and I have also solved the problem in z-dev in this way. For this issue, I also believe that it was not caused by UE4SS. This is indeed a problem caused by the game, and I would like to see if anyone has already solved this issue. I will continue to follow up and if possible I solve this problem, I can share the solution with all Palworld developers. From the dmp file on the client side, the root cause is not ue4ss, which is consistent with my judgment

QQ截图20240722134118