[UE4] Can't save object with references to Spine in it Search this topic… Post a reply

Hey everyone

I’m trying to make a tool that automatically creates the actor type I need and populates it with the spine atlas and skeleton data that is selected in the content browser. I have to do this over and over so making it faster would be really nice.

I set up an editor utility widget to run my script, which seems to work, but I can’t save the object it creates:

I also get a crash if I try to open the object.

I guess I’ll start pasting code in the hope that someone spots what the problem is.

I have SpinePlugin and SpineEditorPlugin in my module dependencies.

This is how I attach the spine components:


UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Spine")
    USpineSkeletonDataAsset * SpineSkeleton;

UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Spine")
    USpineAtlasAsset * SpineAtlas;



ASpineActor::ASpineActor(const class FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
{
    PrimaryActorTick.bCanEverTick = true;
    SpineSkeletonRenderer = NewObject<USpineSkeletonRendererComponent>(this, FName(TEXT("SpineSkeletonRenderer")));
    SpineSkeletonAnimation = NewObject<USpineSkeletonAnimationComponent>(this, FName(TEXT("SpineSkeletonAnimation")));

    SpineSkeletonAnimation->SkeletonData = SpineSkeleton;
    SpineSkeletonAnimation->Atlas = SpineAtlas;
}

And this is the script I wrote to create and save the actor: ASpineActor * UPAndBEditorUtilityWidget::CreateSpineBlueprint(){ // Assign s - Pastebin.com

I’ve made a bit of progress and now the asset is created, the right stuff is populated and it can be saved without the warning.

Unfortunately the asset still throws an assertion on opening, which without the debugger is fatal:

AssetSelection.cpp (133):


if ( !ActorInfo.SharedWorld )
{
    ActorInfo.SharedWorld = CurrentActor->GetWorld();
    check(ActorInfo.SharedWorld);
}

CurrentActor is definitely valid, but I can’t inspect ActorInfo for whatever reason. It seems reasonable to assume that there is no current world. Keep in mind that this is a blueprint in the content browser being opened.

Any idea what’s probably causing it?

Content browsers don’t initialize any world context.
Only when you open an editor tool with a viewport or play in editor then a pointer to a world is set, unless you override the GetWorld() function an asset will always return nullptr while instances should return the world they are spawned in.

I realised my mistake and switched to a UBlueprint and CreateBlueprint(), which is giving me what I wanted.

The next step I believe is to load the CDO and make the changes I want to make programmatically. However what I’ve tried isn’t making any changes:


ASpineActor * CDO = ASpineActor::StaticClass()->GetDefaultObject<ASpineActor>();
    CDO->SpineSkeletonAnimation->SkeletonData = SpineSkeleton;
    CDO->SpineSkeletonAnimation->Atlas = SpineAtlas;
    CDO->SaveConfig();
    Blueprint->ReloadConfig();

Any suggestions? I know you’re the king of UBlueprints Bruno. :smiley:

Edit: and what happens if I use GetDefaultSubobjectByName(FName(“SpineSkeletonAnimation”) instead? Will it change that component’s defaults for every single blueprint instance that uses it, or just the one attached to this blueprint?

In Property Transfer plugin there’s these functions I wrote for this:



template<typename T>
T* GetBlueprintCDO(UBlueprint* Blueprint) {

    if (Blueprint == nullptr) {return nullptr;}

    const UClass* BlueprintClass = Blueprint->GeneratedClass;

    return Cast<T>(BlueprintClass->ClassDefaultObject);

}




UBlueprint* FPropertyTransferManager::GetBlueprintFromOBJ(UObject* OBJ) {

    UBlueprint* BP = nullptr;

    if (OBJ)
    {
        BP = Cast<UBlueprint>(OBJ);

        if (BP == nullptr) {
            BP = Cast<UBlueprint>(OBJ->GetClass()->ClassGeneratedBy);
        }
    }

    return BP;
}


That’s handy, let me give it a go. Cheers!

Edit: that worked. You are amazing Bruno. That should be in the engine.

Btw you usually have to call ->Modify() on the CDO before you make changes to a UBlueprint* asset…
Or use helper methods such as:



FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(myBlueprint);


Ah yeah, thank you. The SaveConfig() and Reload() was working but that seems better.