In a Blueprint type object, is there any way to execute the Async Load Asset?
The problem is that if I run it I have an error called World Context Object, it is normal, since it does not know in which context it has to be executed.
In my C++ object (extends Uobject) I have set: UCLASS(Blueprintable, BlueprintType, Abstract, Meta = (ShowWorldContextPin))
but it seems that for the Async Load Asset it does not have a pin.
How can I pass the “context” to the “Async Load Asset” in a Blueprint of object type? Is this another limitation of the engine? Do I have to do Async manually in C++?..
-Note: I do not do it from C++ since Async does not have a return and if I wanted to return I have to use TFuture and the problems arise again in the return…
-Note: Yes, “Async Load Asset” works correctly in an Actor since it has its own context. I don’t want it in an Actor. It is an object that contains only “data”, it does not need to be of type Actor since the use of data would not make sense and would be bad practices. (Yes, everything works in an Actor, but I’m not going to do bad practices).
What I have come up with as a correct solution in the BLueprint Object is:
1 - I execute the function normally
2 - I disconnect the entire part of the “Async Load Asset” onwards
3 - In an Actor, Component, Controller or in the level… put the entire part of the “Async Load Asset” in which you are going to implement it.
That is the correct use that I should make if I do not have context and that is what I am going to do.
The problem I see with this is that the entire “Asyn Load Asset” part from now on is too long. I just wanted to write it “just once.” “Write it once and use it everywhere”, I don’t like doing boilerplate. Anything that saves me time in the future is time that I don’t need to dedicate to it. The problem is that if I need to modify something, I will have to modify it for each zone where I have implemented it… that’s exactly what I don’t want.
Even if the solution is correct, I’m looking one step further. That’s why I’m looking for how to pass the context to the Blueprint of type Object.
Final solution: I will put it in the Game Instance is the best way.
I wanted to have an object with data, but now that I think about it GameInstance has context and above all persists the data.
You have one other possible solution (since you can’t always just jam functionality on the game instance):
Your class can override UObject::GetWorld so that it returns the world that is relevant to your object. This is one of those weird cases where you shouldn’t call Super:: in your implementation. If you do the engine treats it as if you didn’t override it and the blueprint won’t think that self/this is a valid input for WorldContext pins.
One implementation of this that I’ve seen (but don’t really like) is for your class to have a WorldContext member variable that is set before calling blueprint implementable functions. Then the override of GetWorld can just return that value.
It has a number of limitations (and like I said I don’t really like it as a solution that much) but it is very direct.
As you say, I like it and I don’t like it.
I really like to pass a current “context” to the object of where I am? Yeah.
Is it really necessary? Yeah.
Will it work well if I use callbacks in the future? Don’t know.
Will it work for any context? Don’t know.
Will I have context conflicts in the future? Don’t know.
Furthermore, the problem is not the class itself. The problem is the “Async Load Asset” (ALA) node/method, it does not have a context pin to overwrite it, even if the class that inherits from UObject passes it a context and it overwrites the “context” of the UObject itself, the node “ ALA” itself does not have or is not available to change the context. “ALA” needs a pin to establish context. I hope they put it up one day.
Now, as I said, if you have to do the “ALA” manually, you have to use TFuture and we’re getting into bigger words. That is, if it predicts wrong for some reason unknown to me, I will have headaches.
For now the Game Instance fulfills its purpose without problems.
It is a shame since you could have objects full of data (which is what they are for) and use them at a specific moment anywhere.
But as I said I have found two solutions:
Blueprint Object (Inheriting from a C++ Object)
Put the async part from now on inside the Actor, Component, Controller, level… or others in the place where the object is called.
Directly put it in the GameInstance
There may be more solutions, but I have no problem with those two for now.
I’m totally with you there. Other nodes & functions have markup/support that allows that context pin to show up in cases like yours so that a context can be passed in manually. It’s unfortunate they didn’t apply that functionality to this one.
But the source is available, so fourth/fifth options is to duplicate that functionality to work the way you want or to make local engine modifications (if you’re working with a source build of the engine).
And that’s great, my response was not meant to make it sound like you’d done anything wrong or that you should change anything. Only to provide you with some non-obvious information about how the engine works that you may want to consider that allows you to create the objects you want and get around the problems inherent in the async node. How you get a context that the GetWorld override returns isn’t that important. Only that it’s overridden and returns something that can be a context, that’s why all those other types Actor, Component and the like all work. They override that function.