Animations references not followed during cooking?

Hello !

All my content is loaded dynamically (my game starts with an empty map) so i’m not relying on maps for cooking.

Instead, i put all my meshes (skeletal and static) in a specific directory and i add this directory to the list of directories to be cooked (in “project settings/packaging” options).

It seems that for each object, all the references are recursively followed until everything related to the object is cooked (material, textures, etc.). Works great.

Unfortunately, the animations seem to be an exception here, they are never cooked if they are not in the directory specificaly marked for cooking.

The repro step should look something like that:

  • create a skeletal mesh with its and animations
  • do not spawn it on the map, so it’s not cooked by default
  • put it in a directory, let’s call it A
  • put the and animations in a different directoty, let’s call it B
    -in the "project setting/packaging "section, add A only to the list of additionnal directories to cook (do not add B).
  • package the game

On my computer, the skeletal mesh is cooked and packaged but the animations are not so it seems that the references to the animations through the are not followed by the cooking process (whereas every other properties are).

Yet, if i open the skeletal mesh with the reference viewer, i can see the animations are referenced and linked to the skeletal mesh through the , as expected.
But they are no cooked nor added to the release of the game.

Is this intended ?

Thanks

Cedric

Hey ,

I think part of the problem here is that animations reference skeletons and not the other way around.

The reference viewer is a great way to visualize this, but you can get a good sense of what assets the is dependent on by attempting to use the migrate feature (Right Click>Asset Actions>Migrate).

If you’re spawning from code, I may have to get a second opinion on this, but anytime you reference an asset from a code/BP class (even just assigning an animation to a skeletal mesh), it should be included as a reference. Can you expand on how you’re dynamically spawning your actors?

-.

Hey ,

Thanks for the answer, here is a quick summary of what i do (the full code is more complex because i use several types of animations + retargeted anims with several different skeletons).

First i get the dir:

FStringAssetReference SkeletonRef = FStringAssetReference(Skeletal3DMesh->);

Then the absolute path for content dir:

FString ContentDir = FPaths::GameContentDir();
ContentDir = IFileManager::Get().ConvertToAbsolutePathForExternalAppForRead(*ContentDir);

Then i transform the ref into a path:

FString BaseReplace = "/Game/";
FString SearchDir = FPaths::GetPath(SkeletonRef.ToString()).Replace(*BaseReplace, *ContentDir, ESearchCase::CaseSensitive);

I define the animation file name (animation is a parameter variable of the function doing all this):

FileToSearch = AnimationName + ".uasset";

Then i look for the file:

IFileManager::Get().FindFilesRecursive(FoundAnimationDirs, *SearchDir, *FileToSearch, true, false, false);

which i transform into a ref:

FString FoundDir = FPaths::GetPath(FoundAnimationDirs[0]);
FString FoundDirRef = FoundDir.Replace(*ContentDir, *BaseReplace, ESearchCase::CaseSensitive);
FString AnimationRef = "AnimSequence'" + FoundDirRef + "/" + AnimationName + "." + AnimationName + "'";

Finally i load the anim:

UAnimSequence* ThisAnimSequence;
ThisAnimSequence = LoadObject<UAnimSequence>(NULL, *AnimationRef);

Which i use in another function that wraps the PlayAnimation function:

Skeletal3DMeshComponent->PlayAnimation(NewAnimSequence, true);
Skeletal3DMeshComponent->SetPlayRate(NewPlayRate);

So in a word, i retrieve and load the animation asset from a name. The only constraint is that the animations has to be in the same (or sub) dir than the (because i use the dir to start searching the anim files)

All this is happening in a class inheriting from AActor.

In the editor, i create a BP inheriting from this class but nothing is done in the BP (i mean no visual scripting)

Then, in my PlayerController class, i declare the class in the constructor:

static ConstructorHelpers::FObjectFinder<UClass> BP_YagCharacterClassFinder(TEXT("Class'/Game/YagGameClasses/character/BP_YagCharacter.BP_YagCharacter_C'"));
BP_YagCharacter = BP_YagCharacterClassFinder.Object;

And use it when i need to spawn the actor (in a dedicated PC server function):

AYagCharacter* SpawnedCharacter= GetWorld()->SpawnActor<AYagCharacter>(BP_YagCharacter, ActorLocation, ActorRotation, SpawnParams);

In short:
AActor → my actor class (doing all the animation finding and loading hereabove) → becomes a BP in the editor → spawned by the PC

Do you see in this long chain a possible link between the animations and the skeletal mesh from the UE4 cooker stand point ?

Cheers

Cedric

Hey ,

I gave you all the details but my answer was to long for a comment, so i posted it as an answer.

Please let me know if you need any more info.

Cheers

Cedric

Hey Cedric, just to clarify, where is most of this code (other than the obvious lines like the one with ConstructorHelpers) happening in your project? Does most of this happen at runtime or at compile time?

Hey ,

Everything happens 100% at runtime (except for the constructor part as you mentionned).

My game isn’t really a game, it’s a rpg gaming table where players can throw dice and play with figurines.

So the spawning happens when the “players” use the UI to spawn a figurine and all the loading business happens when they choose an animation for their figurine.

The maps starts completely empty and is populated as the gamers spawn objects and figurines.

The code i described is all in functions called by users at runtime.

Cedric

Thats what I was expecting but I wanted to be sure. From my limited knowledge when it comes to packaging, I’m fairly sure that these references aren’t seen by the cooker due to being set at runtime. When you set stuff like this up through blueprints, it’s all there and visible to the engine as to what animations need to be included but that isn’t true in this case. You’ll need to add that directory manually if you want to do it this way.

Have a nice day!

I thought so. No big deal, thanks for the info and have a great day.

Cheers

Cedric