ImmersiveRPG / GodotAsyncLoader

A Godot plugin to load, instance, and add scenes asynchronously using a background thread.
https://godotengine.org/asset-library/asset/1376
MIT License
37 stars 4 forks source link

Move thread setup out of AutoLoad _enter_tree #12

Closed workhorsy closed 2 years ago

workhorsy commented 2 years ago

Having threads start inside AutoLoad can lead to crashes. This is because the main loop (and signal system) isn't loaded yet, and we have to poll for its existence like so:

func _enter_tree() -> void:
    _thread = Thread.new()
    var err = _thread.start(self, "_run_thread", 0, Thread.PRIORITY_LOW)
    assert(err == OK)

func _run_thread(_arg : int) -> void:
    # Wait for main loop to initialize
    var is_waiting_for_main_loop_to_load := true
    while is_waiting_for_main_loop_to_load:
        var loop = self.get_tree()
        if loop != null:
            is_waiting_for_main_loop_to_load = false

        if is_waiting_for_main_loop_to_load:
            print("Still waiting for main loop to initialize ...")
            OS.delay_msec(100)

    # Do actual thread stuff here ...

Also, setting up the plugin like this, is annoying and not obvious to users:

const GROUPS := [
    "terrain",
    "building",
]

func _ready() -> void:
    AsyncLoader._sleep_msec = 100
    AsyncLoader.set_groups(GROUPS)

So we can replace both of these with a start function that does setup and starts threads:

const GROUPS := [
    "terrain",
    "structure",
]
const SLEEP_MSEC := 100

func _ready() -> void:
    AsyncLoader.start(GROUPS, SLEEP_MSEC)