the directory containing the BP is cooked (added in the packaging option list)
this code works in editor but not in packaged game
the same code works well on a skeletal mesh (even in packaged game)
i get this error in the (packaged) :
LogUObjectGlobals:Warning: Failed to find object ‘AnimBlueprint /Game/mixamo/Heidi/IcloneAnimBP.IcloneAnimBP’
i have tried to package without the pak option and i can see the asset file in the package:
So the BP is cooked, the file is there, but it can’t be loaded in packaged game, while a skeletal mesh in the same directory is correctly loaded.
Is there something special with animation blueprint as a packaged object ?
Sorry if this is no bug but i checked everything i could and can’t see a reason for it not to load, considering it has been cooked and the code works in PIE.
Are you working within 4.8.2? If so, are did you obtain the engine from the Epic Games Launcher or through GitHub? Are you able to reproduce this in any project/template or a specific one? Are all dynamically loaded animation blueprints causing this problem? Please provide the exact reproduction steps in order to verify this bug within the engine.
I am using 4.8.2 from the launcher (i don’t use github).
Here are the repro steps that work on my computer:
create a 3rd person c++ project (i called it ReproAnimBP)
modify the code like this:
in ReproAnimBP.h, replace #include “EngineMinimal.h” by #include “Engine.h” (just so we can use GEngine to print some message on screen)
Thank you so much for noticing this issue with the Unreal Engine. I have verified and reported this bug to our Developers. The report is referenced as: UE-19239. If you happen to have any further questions or concerns, please feel free to reply back and I will assist you further.
In a packaged (or ‘cooked’) game, dynamic loading of non-cooked content is not supported. For content to be referenced by code you would need to use the FObjectFinder in your classes constructor instead of a plain old LoadObject(). For example:
Thanks for you answer but (if i understand correctly) this is precisely what i do not want to do
My concern is that i will have a lot of objects to load and i want to manage them from the windows directories/editor and not from the code, that’s why i want to keep the constructor as free as possible from any reference to those objects and use dynamic loading.
I might have tens of such objects and don’t want to change my code/recompile each time i add a new one. Of course, in the final version, the path will be a variable constructed at runtime from the directory structure. In the future, those objects might even be some optional content to be added later on, so everything should be manageable without touching the code. At least that’s my goal.
In a dream world, i prepare the assets and the code knows where to search them, list them and loads them dynamically.
This seems to work well for all objects but not for anim blueprints, hence this ticket.
Also, in my main project (initial post), i specifically declared the directory to be cooked in the packaging options and double checked the presence of the asset file in the package. Does that not ensure that all objects in the directory are cooked and ready for the packaged game ?
Of course i am no expert and could have misunderstood something, i stay open to suggestions
One thing i did not study yet is the whole ObjectLibrary thing, which i definitely should have a serious look at.
If other assets are being correctly cooked (and therefore loaded) then it does indeed sound like something specific to AnimBPs. I’ll log an issue to investigate this! Thanks for all the info!
After some more investigation, this is because UBlueprints (and derived classes, like UAnimBlueprints) are not loaded outside the editor. They are deemed to be editor-only constructs and their generated classes should be used in cooked games rather than the UBlueprint itself.
For reference, loading is controlled by UBlueprint::NeedsLoadForClient() and UBlueprint::NeedsLoadForServer().
Funny, the question you point is a question i posted, i didn’t make the connection
I might try to play again with bDontLoadBlueprintOutsideEditor just for the fun of trying, but i don’t feel confident enough to leave the main road for long.
Ok, thanks for the info, no good news for me, but oh well.
At least i now know for sure that i shouldn’t try to make it work this way. I’m gonna try my luck with the object libraries, otherwise i’ll rethink some other strategy.
Thanks for your time and the info, you guys are doing a great job with ue4 !
Just in case anyone bumps into this problem, here is some working code to dynamically load animation blueprint.
The trick is simple: never ever use blueprint, instead, use the class Luke.
// get the blueprint class reference from the editor
FString AnimClassStringTest = "Class'/Game/mixamo/Heidi/IcloneAnimBP.IcloneAnimBP_C'";
// load the class
UClass* AnimationClass = LoadObject<UClass>(NULL, *AnimClassStringTest);
if (!AnimationClass) return;
// assign the anim blueprint class to your skeletal mesh component
Skeletal3DMeshComponent->SetAnimInstanceClass(AnimationClass);
And this is it
Now if you want to your animation state through variables, here is the bonus.
Code a class inheriting from UAnimInstance to store all your BP variables (here i created the UYagCharacterAnimInstance class that contains the AnimTest integer).
Your animBP (here IcloneAnimBP) should be created in the editor inheriting from your own anim instance class (here UYagCharacterAnimInstance) instead of UAnimInstance
Then:
// Assign the skeletal mesh component instance to your own instance
UYagCharacterAnimInstance* AnimationBPInstance = Cast<UYagCharacterAnimInstance>(Skeletal3DMeshComponent->GetAnimInstance());
if (!AnimationBPInstance) return;
// You can now modify your variable (provided your anim BP, inheriting from your own anim instance class, knows how to handle this variable)
AnimationBPInstance->AnimTest = 42;
// This value will be passed to your anim BP and can some state modification, etc.
As always, it might not be the best way to do this but it works.
All this is done in the PostInitializeComponents function in my code but can be put anywhere else, the point is it’s not in the constructor and is entirely dynamic.