Background loading

    The ResourceInteractiveLoader class allows you to load a resource in stages. Every time the method poll is called, a new stage is loaded, and control is returned to the caller. Each stage is generally a sub-resource that is loaded by the main resource. For example, if you’re loading a scene that loads 10 images, each image will be one stage.

    Usage is generally as follows

    This method will give you a ResourceInteractiveLoader that you will use to manage the load operation.

    Polling

    1. Error ResourceInteractiveLoader::poll();

    Use this method to advance the progress of the load. Each call to poll will load the next stage of your resource. Keep in mind that each stage is one entire “atomic” resource, such as an image, or a mesh, so it will take several frames to load.

    Returns OK on no errors, ERR_FILE_EOF when loading is finished. Any other return value means there was an error and loading has stopped.

    To query the progress of the load, use the following methods:

    1. int ResourceInteractiveLoader::get_stage_count() const;
    2. int ResourceInteractiveLoader::get_stage() const;

    get_stage_count returns the total number of stages to load. get_stage returns the current stage being loaded.

    Forcing completion (optional)

    1. Error ResourceInteractiveLoader::wait();

    Use this method if you need to load the entire resource in the current frame, without any more steps.

    1. Ref<Resource> ResourceInteractiveLoader::get_resource();

    This example demonstrates how to load a new scene. Consider it in the context of the Singletons (AutoLoad) example.

    First, we set up some variables and initialize the current_scene with the main scene of the game:

    The function goto_scene is called from the game when the scene needs to be switched. It requests an interactive loader, and calls set_process(true) to start polling the loader in the _process callback. It also starts a “loading” animation, which could show a progress bar or loading screen.

    1. func goto_scene(path): # Game requests to switch to this scene.
    2. loader = ResourceLoader.load_interactive(path)
    3. if loader == null: # Check for errors.
    4. show_error()
    5. return
    6. set_process(true)
    7. current_scene.queue_free() # Get rid of the old scene.
    8. # Start your "loading..." animation.
    9. get_node("animation").play("loading")
    10. wait_frames = 1

    _process is where the loader is polled. is called, and then we deal with the return value from that call. OK means keep polling, ERR_FILE_EOF means loading is done, anything else means there was an error. Also note we skip one frame (via wait_frames, set on the goto_scene function) to allow the loading screen to show up.

    Note how we use OS.get_ticks_msec to control how long we block the thread. Some stages might load fast, which means we might be able to cram more than one call to poll in one frame; some might take way more than your value for time_max, so keep in mind we won’t have precise control over the timings.

    1. func _process(time):
    2. if loader == null:
    3. # no need to process anymore
    4. set_process(false)
    5. return
    6. # Wait for frames to let the "loading" animation show up.
    7. if wait_frames > 0:
    8. wait_frames -= 1
    9. return
    10. var t = OS.get_ticks_msec()
    11. # Use "time_max" to control for how long we block this thread.
    12. while OS.get_ticks_msec() < t + time_max:
    13. # Poll your loader.
    14. var err = loader.poll()
    15. if err == ERR_FILE_EOF: # Finished loading.
    16. var resource = loader.get_resource()
    17. loader = null
    18. set_new_scene(resource)
    19. break
    20. update_progress()
    21. else: # Error during loading.
    22. loader = null
    23. break

    Some extra helper functions. update_progress updates a progress bar, or can also update a paused animation (the animation represents the entire load process from beginning to end). set_new_scene puts the newly loaded scene on the tree. Because it’s a scene being loaded, instance() needs to be called on the resource obtained from the loader.

    1. func update_progress():
    2. var progress = float(loader.get_stage()) / loader.get_stage_count()
    3. # Update your progress bar?
    4. get_node("progress").set_progress(progress)
    5. # ...or update a progress animation?
    6. var length = get_node("animation").get_current_animation_length()
    7. # Call this on a paused animation. Use "true" as the second argument to
    8. # force the animation to update.
    9. get_node("animation").seek(progress * length, true)
    10. func set_new_scene(scene_resource):
    11. current_scene = scene_resource.instance()
    12. get_node("/root").add_child(current_scene)

    ResourceInteractiveLoader can be used from multiple threads. A couple of things to keep in mind if you attempt it:

    Use a semaphore

    While your thread waits for the main thread to request a new resource, use a Semaphore to sleep (instead of a busy loop or anything similar).

    You can find an example class for loading resources in threads here: . Usage is as follows:

    1. func start()

    Call after you instance the class to start the thread.

    Queue a resource. Use optional argument “p_in_front” to put it in front of the queue.

    1. func cancel_resource(path)

    Remove a resource from the queue, discarding any loading done.

    1. func is_ready(path)

    Returns true if a resource is fully loaded and ready to be retrieved.

    1. func get_progress(path)

    Get the progress of a resource. Returns -1 if there was an error (for example if the resource is not in the queue), or a number between 0.0 and 1.0 with the progress of the load. Use mostly for cosmetic purposes (updating progress bars, etc), use is_ready to find out if a resource is actually ready.

    1. func get_resource(path)

    Returns the fully loaded resource, or null on error. If the resource is not fully loaded (is_ready returns ), it will block your thread and finish the load. If the resource is not on the queue, it will call ResourceLoader::load to load it normally and return it.

    Example:

    Note: this code, in its current form, is not tested in real world scenarios. If you run into any issues, ask for help in one of .