Open torbenvanassche opened 3 months ago
Here is one example of how I might handle this situation. You could probably combine this with signals that you create yourself to do whatever you need to do
extends Node
var thread:Thread = Thread.new()
@onready var sprite_2d:Sprite2D= $"../Sprite2D" as Sprite2D
@onready var mona_lisa:Sprite2D = $"../mona_lisa" as Sprite2D
func _ready():
thread.start(thread_func)
func thread_func():
var mona_lisa_texture = load("res://mona.png")
var i = 0
var j = 10000
while i != 30000000: # LONG WHILE LOOP TO SIMULATE LOADING TIME
i += 1
if i % j == 0:
print(i)
call_deferred("done")
return mona_lisa_texture
func _process(delta):
sprite_2d.position.x += 2
func done():
print("All finished, destroying thread objects")
mona_lisa.texture = thread.wait_to_finish()
As this has bothered me before, I am thinking of maybe making this my first actual code contribution? I mean it does not look to hard to do. 🤞
Okay the issue with your proposal is: you assume ResourceLoader can only load one Resource at a time, but there can be multiple requests simultaneously and there's no good way of only sending the signal to the object that created the load request with the current class structure.
It would be possible to emit an unspecific signal too, that then could be used to issue to check in on the resources on the script side.
The cleanest implementation of your proposal would be to return a ThreadLoadStatus object as a return type for the threaded resource get function instead of an error. This resource could then hold a reference to the loaded object and also emit a signal when the loading is done.
This however would be a breaking change and the Godot Team strongly dislikes those.
This would need a greater discussion before someone can work on it.
Okay the issue with your proposal is: you assume ResourceLoader can only load one Resource at a time, but there can be multiple requests simultaneously and there's no good way of only sending the signal to the object that created the load request with the current class structure.
It would be possible to emit an unspecific signal too, that then could be used to issue to check in on the resources on the script side.
The cleanest implementation of your proposal would be to return a ThreadLoadStatus object as a return type for the threaded resource get function instead of an error. This resource could then hold a reference to the loaded object and also emit a signal when the loading is done.
This however would be a breaking change and the Godot Team strongly dislikes those.
This would need a greater discussion before someone can work on it.
Funny how a seemingly small addition can be rather difficult to implement, but I totally see the problem with breaking changes. I think this could be solved with a signal on the ResourceLoader like ResourceLoader.signal_resource_ready
that emits a signal in the form of signal signal_resource_ready(loaded_resource: Node)
. Not sure if that is viable but it is the first thing that comes to mind to make it fully backwards compatible and work additively.
This would require people to handle the inner checks of what they are loading manually but I think that is a reasonable trade-off.
Not sure if that is viable but it is the first thing that comes to mind to make it fully backwards compatible and work additively.
Okay, try to write code that starts a threaded get request, awaits it being and then adds the loaded node as a child.
Keep in mind that multiple resources can be requested at the same time and you can't really tell in what order they will be done and how many times this signal is emitted while you wait for the correct response.
Not sure if that is viable but it is the first thing that comes to mind to make it fully backwards compatible and work additively.
Okay, try to write code that starts a threaded get request, awaits it being and then adds the loaded node as a child.
Keep in mind that multiple resources can be requested at the same time and you can't really tell in what order they will be done and how many times this signal is emitted while you wait for the correct response.
iMO, the whole point of multi threading is that you shouldn't care about when something is done. It should be a set-and-forget type deal where the thread takes care of doing everything it needs. If order of operations is important, then semaphore and mutexes should be used somehow.
I digress though.
This is just a thought, haven't actually tested this or thought it through all the way but what if you created an ID and a signal when you created a thread and passed that ID to the thread. Then When the thread finished, you could return that ID and use the ID to fire the signal associated with that thread. That ID/signal would somehow be used to determine what has finished loading.
I envision using a dictionary in some way with this as well.
Describe the project you are working on
I am working on a project where i want to have adjacent rooms load into memory when you enter a room. For this I am using the
ResourceLoader.load_threaded_request
. This allows me to dynamically load the nodes I need and clean up the ones I don't.Describe the problem or limitation you are having in your project
The problem is that there is no way of knowing when something has finished loading, other than manually checking. The only way this is currently possible is by periodically checking the status of
ResourceLoader.load_threaded_get_status
. This makes it a little tricky to manage the data and its loading.Describe the feature / enhancement and how it helps to overcome the problem or limitation
Having a signal would prevent the need for the periodic check, I would just be able to connect the signal to add the node directly, rather than polling every X seconds to see if the asset is ready, then instantiating it if it is.
Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams
In terms of how it works on the engine side, I have little insight to offer. However, as a user I could see the following work:
Where you can then have
signal load_threaded_finished(data: Variant)
so you can work with the data you receive directlyIf this enhancement will not be used often, can it be worked around with a few lines of script?
I wrote some code that works around the issue with a
Timer
but as I mentioned above, this is not optimal:Is there a reason why this should be core and not an add-on in the asset library?
I think this could be useful, not just for me, but for a lot of things in the engine as a whole. Personally, I feel this is something that should exist and I was surprised that it doesn't yet.