puchik / godot-extras

LOD and optimization C++ addons and shaders for Godot 4 and Godot 3
137 stars 14 forks source link

Multilod Crashes on load #3

Closed TokisanGames closed 3 years ago

TokisanGames commented 3 years ago

I've experimented with Multilod a bit. I have a tree with a mesh as LOD0 and a billboard as LOD1. When it works, it does so just fine. However on two separate occasions, I've come back to my project on a subsequent day, it loads in the editor but when I run the game it crashes almost instantly on startup. I have to disable the plugin to run my game. Running the game through various versions 3.2.1, 3.2.3, 3.2.4rc all exhibit the same symptom.

When it happened the first time, I stopped using it for a while to focus on other things. 1-2 weeks later I came back, got the new version, and again am experiencing the same thing. It was fine last night. I haven't changed anything with the multilod or the object and have been working on other things. Now all of a sudden it isn't fine.

When I run godot 3.2.4rc through the MSVC debugger it shows lod.dll throws an exception error in nativescript. Though my game takes about 25 seconds to load, including to get the scene actually using multilod to _ready(). However the game crashes with this exception error within the first second of loading.

image

Win 10/64 Latest master, and the previous commit

puchik commented 3 years ago

That looks like it's trying to access/delete an object that doesn't exist. Is there any additional error message? I'm not sure why it's asking to destroy the variant/object after the function call, either.

What happens if you try to run it with multithreading disabled?

By "previous commit" do you mean you don't have the update from about a week ago? I changed the way some references work so that could help.

It looks like the line you posted can be tracked back to void Node::_propagate_enter_tree() { // this needs to happen to all children before any enter_tree and NOTIFICATION_READY in node.cpp. Are you calling any functions on the lod manager on game load? Otherwise it is probably the _ready function of either the manager or an object. Are you using any of the other lod types or just the node one? (lod.gdns)

Is there any chance your scene does not have a camera when the lod object is loading? Or possibly they are at the same level but in an order that causes the object to load before the camera? It tries to load FOV from a camera when starting up (my bad, I will add a null check in the upcoming version). It also tries to call a function on the manager in _ready, which may not be initialized (yet another thing requiring a null check).

TokisanGames commented 3 years ago

There are no errors. The editor remains open. The game engine starts, prints the engine and GLES version. a gamewindow opens for a split second, then it disappears. The game scenes all have a camera.

I'm currently in single-safe thread model. If I switch to multithreaded the gamewindow stays open for about twice as long, a whole second. The same exception is thrown at the same point.

I have experienced this on two commits: f0b9e8e81a41afa514a1fc45fcdb7d29dce330a9 and an earlier one, probably 24f75465b578472e92a762a39fab6b56d0ed30f2.

The setup is mostly default. It's just a tree w/ 2 lods. This is the only multilod object I'm using. image

I'm not accessing multilod by code at the moment, but I am instancing the above TreeLOD scene by code and placing them in the editor. When the game starts, the trees are already in the scene. They are not being instanced and generated on the fly. I currently have 875 of them, but if I reduce to 20 I get the same results.

It's plausible that the multilod loads before the camera. This is a very large godot project (a small ARPG), so who knows? The camera is higher in the tree than the multilod objects. It loads all scenes and all assets using the ResourceInteractiveLoader. Neither the camera, nor the multilod nodes are displayed on screen, or even attached to the tree until all the scenes and assets are loaded.

Once the first level starts, it's attached to the tree. The player camera and multilod are attached to the tree at the same time, as they are underneath the loaded orphan scene that is getting attached.

All of this scene connecting stuff happens 25s after the initial start, because the scenes are loading in the background. But when Multilod doesn't work, the game dies within 1 second after the initial start. Long before any multilod asset or camera is even attached to the scene tree. Long before the scene that contains the multilod has even finished loading. During this time, the only thing on screen is a 2D loading scene with control nodes. This setup worked fine with multilod the other day, so if it's dying because it's looking for a camera, it apparently doesn't do that all the time.

Thanks for taking a look at this.

puchik commented 3 years ago

Thanks for the report and many details, it's good to hear about use in a big project!

The crash might be inconsistent due to thread timing differences between runs (and even between machines). Maybe _ready runs when the node and its children are ready but not when it's inside a tree?... Ah debugging multi threaded things is fun.

By disabling multi threading I meant on the LOD manager itself. If you open the LOD manager scene in the addons folder there is a setting to turn it off, in which case it will iterate the array piece by piece over multiple frames in the main thread. Godot has no debugging for threads so this might help us see an actual error message.

If you try changing the manager settings, you could also try setting the tick speed to a very large number (to prevent the thread itself from running immediately) and we can see if the thread crashes it or the _ready function.

Apparently a singleton/autoload is able to run before any other scenes or nodes, which would explain it working in random tests but breaking in a real game that switches scenes and loads resources. It would also explain it breaking immediately (i.e. the manager, which is loaded before everything else, causes the crash).

It sounds like I can add some null checks and methods to attempt to retrieve the wanted objects to fix this. Might end up being a quick fix when I get time in the coming days. Right now I'm wrapping up something new for the multimesh LOD.

TokisanGames commented 3 years ago

Thanks for the report and many details, it's good to hear about use in a big project!

I'm testing it. We'll see.

By disabling multi threading I meant on the LOD manager itself.

I disabled multithreading there, and also set tickspeed to 2 and 200. Nothing produced different results.

Apparently a singleton/autoload is able to run before any other scenes or nodes,

Yes, I've noticed this and had difficulties with it on other plugins. You might have to add in a flag that says don't start doing anything until the scene tree is up, or until a Multilod node is actually in the tree.

Right now I'm wrapping up something new for the multimesh LOD.

No problem. I am testing other methods and workarounds. Thanks for checking it out.

puchik commented 3 years ago

I can't test your exact case, but I just put out an update that I think may fix your crashes. Try it out.

puchik commented 3 years ago

If you tried out the new one and had some weird issues, those are now also fixed. A couple lines broke it initially.

TokisanGames commented 3 years ago

Great, thanks. I'll check it out later this week and report back.

TokisanGames commented 3 years ago

In the old version, I don't even have to have any assets connected to the lod.gdns script. Just as long as the plugin is enabled, it crashes the game on start. I tested to make sure it still wasn't working. Then I put in the new version and my game was able to start right away without any LOD assets. Then I put my LOD tree back in and it doesn't crash so far.

However it doesn't actually check LOD all the time. I have a scene with your LOD cube and my trees in it. If I run the scene individually, the scenes and cube will switch LODs. If I run the whole game, which loads the scene via ResourceInteractiveLoader, then connect it to the tree, LODs aren't processed.

I do recall it changing and working fine before, but I don't recall if those tests were the scene only or the whole game. It's possible I didn't even notice it wasn't changing when running the whole game. I only noticed when it started crashing on load. So this is probably a separate issue.

Regarding the crashing, I'll leave it enabled and keep testing to see if it starts crashing the game as it did before and will let you know. Thanks.

puchik commented 3 years ago

So in this newest version, loading the objects via ResourceInteractiveLoader results on those objects not being processed? Can you make a minimal reproduction project? I have a suspicion why but it would be easier to test if the solution works with your case. If you make a new issue that would be great.

TokisanGames commented 3 years ago

Yes, multilod under my implementation with ResourceInteractiveLoader does nothing. It may have nothing to do with RIL and just the process of connecting to the scene tree. If I had to guess I would bet that you're connecting to the active camera, then assuming it won't ever change. So when I connect a new scene and change the camera, you're still connected to the old one. I'll set up a new issue at some point.

In the meantime, this new version of the plugin has continued to load and operate without crashing. Thanks for your help.

puchik commented 3 years ago

Oh I see, yes that is probably the case. I will add some methods to reset the camera when possible. Thanks for reporting the issue and helping make this better.

TokisanGames commented 3 years ago

I haven't been testing this plugin for a while, but I'm starting to now as I have a bunch of assets with LODs. I'm going to be creating a more realistic landscape w/ tons of rocks, trees, and foliage and hope to use this plugin extensively.

Today I had an instance where the game was crashing on load again, with no messages. Turns out I had mistakenly added the multimesh.gdns instead of the lod.gdns. But I had to go through and delete all the nodes, then go through the process of adding them back in until I found the one causing the crash.

It would be helpful if you could put in a lot more checks to check everything before you use it. e.g. If this isn't an MMI, print an error then return nothing but don't die. And maybe put in a debug mode with a level of detail in the LOD manager that prints everything it's doing (level 1) and the objects its working on (level 2) so we don't have to guess.

Also I like the hide @ 1% feature. I was curious about what would happen with my small single lod rocks. I'm glad to see they disappear.

puchik commented 3 years ago

Hey, I'm glad things are starting to work out and that you're finding it useful. That debugging functionality is a pretty good idea and relatively simple. I just pushed an update that adds support for it. 👍