utopia-rise / godot-kotlin-jvm

Godot Kotlin JVM Module
MIT License
586 stars 39 forks source link

How to free a PackedScene instance? #185

Closed Humberd closed 3 years ago

Humberd commented 3 years ago

Let's say I've manually loaded a scene. How can I free it?

object RootSceneManager : GodotStatic {
    val loginScene = ResourceLoader.load("res://src/main/kotlin/clientjvm/scenes/login/LoginScene.tscn") as PackedScene

    init {
        registerAsSingleton()
    }

    override fun collect() {
        loginScene.free()
    }
}

The problem is that when I do loginScene.free(), then I get this error:

ERROR: MethodBind0<class Node>::call: Condition "!instance" is true. Returned: Variant()
   At: D:\a\godot-kotlin-jvm\godot-kotlin-jvm\core\method_bind.gen.inc:132
ERROR: Godot-JVM: Can't 'free' a reference.
   At: modules\kotlin_jvm\src\transfer_context.cpp:206

On the other hand if I don't free it, then I get this error:

Exception in thread "main" java.lang.UnsatisfiedLinkError: 'void godot.core.GarbageCollector$MemoryBridge.notifyLeak()'
    at godot.core.GarbageCollector$MemoryBridge.notifyLeak(Native Method)
    at godot.core.GarbageCollector.cleanUp(GarbageCollector.kt:296)
Godot-JVM: WARNING: Some JVM godot instances are leaked.
Leaked references:
    [PackedScene:1189]
Humberd commented 3 years ago

How do you catch an exception?

try {
    loginScene.free()
    gameScene.free()
} catch (e: Throwable) {

}

I can't catch this error.

piiertho commented 3 years ago

This exception is at closing of module. PackedScene inherits Reference, it should be free automatically. Maybe a problem with singleton cleaning ? Can you try in a classic object ?

CedNaru commented 3 years ago

Just like in the regular Godot, you can't use free on a Reference. If you try to free a PackedScene in GDScript you are going to get the same error. I think you can't catch it because the error is on the C++ side.

In the case of a reference, you just need to no longer have a variable pointing to it. Just make your variable a var and set it to null in collect. The same way I did in the example in the doc: https://godot-kotl.in/en/latest/advanced/kotlin-singleton/

piiertho commented 3 years ago

Ah, forgot about singleton, assign it to null when cleaning

Humberd commented 3 years ago

@CedNaru I still get the error


var loginScene = ResourceLoader.load("res://src/main/kotlin/clientjvm/scenes/login/LoginScene.tscn") as PackedScene?

override fun collect() {
    loginScene = null
}
ERROR: MethodBind0<class Node>::call: Condition "!instance" is true. Returned: Variant()
   At: D:\a\godot-kotlin-jvm\godot-kotlin-jvm\core\method_bind.gen.inc:132
Godot-JVM: Shutting down JVM ...
CedNaru commented 3 years ago

Ho this is interesting. Maybe it's because it's actually a Resource loaded from the disk so Godot already clean it because it's stored in a cache But the JVM instance still exists and when the JVM tried to unref it when it's closing you get that error because it's already dead. But just speculating, that's only the third issue that I have when dealing with Reference/Resources XD.

CedNaru commented 3 years ago

Just checked the GDScript behavior when you want to free a Reference

image

And yeah I got an error if I try to delete it directly:

image

Leaving that here as a memo. I wasn't sure anymore if it was a behavior we created ourselves or not. But not it's really from Godot.

CedNaru commented 3 years ago

Regarding the C++ error. It's just an error that Godot prints but it's not an exception and doesn't prevent the rest of the code to be executed. So there is nothing to catch in the first place.

CedNaru commented 3 years ago

I can't reproduce the issue I created this singleton image

And the JVM shuts down just fine.

image

Humberd commented 3 years ago

I did this and the problem is gone

private fun clearCurrentScene() {
    if (node != null && GD.isInstanceValid(node)) {
        node.queueFree()
    }
    node = null
}

@CedNaru did you create a node out of it? Because I did.