Download

Saving and loading asset UProperties

Hello,
I’ve been trying some thing with unreal and I’m struggling on one.
I wrote a bit of code to make an editor plugin that generates custom actors asset (.uasset).
I have used this tutorial code for instance : https://docs.unrealengine.com/en-US/…art/index.html

I’m saving everything using these lines code:



AMyActor* myActor = NewObject<AMyActor>(Package, ObjectUName, RF_Public | RF_Standalone);
myActor->FloatSpeed = 15.f;

...] Creating a mesh and other things

Package->MarkPackageDirty();
bool bSaved = UPackage::SavePackage(
            Package, 
            myActor, 
            EObjectFlags::RF_Public | EObjectFlags::RF_Standalone /*| RF_ClassDefaultObject *//*| RF_NeedPostLoadSubobjects*/,  saved
            *PackageFileName, 
            GError, nullptr, true, true, SAVE_NoError);


It seems that the export works as I can vizualize my properties values (as you can see below, floatspeed = 15), I can’t load them though.
When I create a new asset from my new file, everything is zero’d (by the constructor it seems ?). I would like to keep my values.

I’ve tried ‘official’ classes : StaticMeshActor for instance, but same here, I can’t make the asset remember its staticMesh ! Same goes if I use a Factory instead of SavePackage.

I guess I have missed something ? Do you have any idea ?

Thanks;

You don’t show there how you create the actual package object.
This is an example that works as expected for me:



void FMagicNodeEditor::CreateNewScriptAsset() {
    IAssetTools &AssetTools = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools").Get();

    FString PackageName = FString(TEXT("/Game/"));
    FString AssetName = FString(TEXT("NewMagicNode"));
    AssetTools.CreateUniqueAssetName(PackageName,AssetName,PackageName,AssetName);

    UPackage* Package = CreatePackage(nullptr,*PackageName);
    UPackage* OuterPack = Package->GetOutermost();

    auto ScriptFactory = NewObject<UMGC_ScriptFactory>();
    UObject* NewScript = ScriptFactory->FactoryCreateNew(UMagicNodeScript::StaticClass(),OuterPack,*AssetName,RF_Standalone|RF_Public,nullptr,GWarn);

    FAssetRegistryModule::AssetCreated(NewScript);
    NewScript->MarkPackageDirty();
    NewScript->PostEditChange();
    NewScript->AddToRoot();

    Package->SetDirtyFlag(true);
}


Oh sorry.
Here is the code :
Concerning the “+ ObjectName”, I’ve tried without it, it doesn’t change anything.



    FString ObjectName = TEXT("MyObject");

    // Create Package
    FString pathPackage = TEXT("/Game/MyStaticMeshes");
    FString absolutePathPackage = FPaths::ProjectContentDir() + "/MyStaticMeshes";
    FPackageName::RegisterMountPoint(*pathPackage, *absolutePathPackage);
    pathPackage += "/" + ObjectName;

    UPackage * Package = CreatePackage(nullptr, *pathPackage);
    Package->FullyLoad();

    FName ObjectUName = MakeUniqueObjectName(Package, AMyActor::StaticClass(), FName(*ObjectName));

    AMyActor* myActor = NewObject<AMyActor>(Package, ObjectUName, RF_Public | RF_Standalone);


I don’t really catch the use of the OuterPack in your code.
I have tried the AddToRoot() but it doesn’t help here :confused: I already had the PostEditChange & Dirty methods too.
But it still initializes to 0. Isn’t it a constructor problem ? (I only have a basic empty constructor)

Your code could work for creating an asset but you don’t modify any UProperty before saving it, do you ?
My asset is successfully created, and I can import it, the problem is the values of my properties that are reinitialized !

You are saving object to /Game/MyStaticMeshes/ObjectName when you should specify it as /Game/MyStaticMeshes/PackageName.ObjectName

Oh ok I see, thanks for your answers.
I now understand the example when we load “/Shapes/shapeName.shapeName” as a mesh
Yet my problem is still here. FloatSpeed still equals to 0 when I create a new actor from my freshly created asset.
I have tried your code too, it does the same for me: creating the asset.
I can see the value by hovering in the contentBrowser but it still doesn’t initialize the UObject with it.

I just added this in FactoryCreateNew():



UObject* UMyFactoryOOO::FactoryCreateNew(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn)
{
    //Create the editor asset
    AMyActor* obj = NewObject<AMyActor>(InParent, InClass, InName, Flags);
    obj->FloatSpeed = 19.f;
    return obj;
}


and the associated code : (The log prints 19 as intended).


    
    IAssetTools &AssetTools = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools").Get();

    FString PackageName = FString(TEXT("/Game/"));
    FString AssetName = FString(TEXT("NewMagicNode"));
    AssetTools.CreateUniqueAssetName(PackageName, AssetName, PackageName, AssetName);

    UPackage* Package = CreatePackage(nullptr, *PackageName);
    UPackage* OuterPack = Package->GetOutermost();

    auto MyActorFactory = NewObject<UMyFactoryOOO>();
    UObject* NewActor = MyActorFactory->FactoryCreateNew(AMyActor::StaticClass(), OuterPack, *AssetName, RF_Standalone | RF_Public, nullptr, GWarn);

    FAssetRegistryModule::AssetCreated(NewActor);
    NewActor->MarkPackageDirty();
    NewActor->PostEditChange();
    NewActor->AddToRoot();

    Package->SetDirtyFlag(true);

    UE_LOG(LogTemp, Warning, TEXT("Here floatspeed %f"), (Cast<AMyActor>(NewActor))->FloatSpeed);

    return;


But the result is the same after dragging it in the scene:
floatingactor.png

After the pack is created you should be able to *GetMutableDefault<YourClass>() *and set default values.

Thanks for the help. It seems that was not the solution though.
I have simplified my code into this :



    FString ObjectName = TEXT("MyObject");

    // Create Package
    IAssetTools &AssetTools = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools").Get();

    FString PackageName = FString(TEXT("/Game/MyStaticMeshes/"));
    AssetTools.CreateUniqueAssetName(PackageName, ObjectName, PackageName, ObjectName);

    UPackage* Package = CreatePackage(nullptr, *PackageName);
    UPackage* OuterPack = Package->GetOutermost();
    Package->FullyLoad();

    AMyActor* myDefaultActor = GetMutableDefault<AMyActor>();
    myDefaultActor->FloatSpeed = 21.f;

    AMyActor* myActor = NewObject<AMyActor>(OuterPack, *ObjectName, RF_Public | RF_Standalone, myDefaultActor, true);

    FAssetRegistryModule::AssetCreated(myActor);

    myActor->MarkPackageDirty(); // I have tried setDirtyFlag here too
    myActor->PostEditChange();
    myActor->AddToRoot();

    FString PackageFileName = FPackageName::LongPackageNameToFilename(PackageName, FPackageName::GetAssetPackageExtension());

    bool bSaved = UPackage::SavePackage(
        Package,
        myActor,  
        EObjectFlags::RF_Public | EObjectFlags::RF_Standalone, 
        *PackageFileName, 
        GError, nullptr, true, true, SAVE_NoError);

    UE_LOG(LogTemp, Warning, TEXT("floatspeed = %f"), myActor->FloatSpeed); // prints 21
    UE_LOG(LogTemp, Warning, TEXT("floatspeed DEFAULT = %f"), GetMutableDefault<AMyActor>()->FloatSpeed); // prints 21


But I still have the same problem. When I drag my new asset in the scene, floatspeed equals 0 !
I’m a little bit surprised to struggle on that as it seems to be quite a basic feature.

I have no idea why you create yet another Actor fron NewObject and then you overwrite the package again with that new object.

There’s no reason to do that:
AMyActor* myActor = NewObject<AMyActor>()

Neither reason to use SavePackage() function.
​​​​​
​​​​​​​Also you use GetDefault() while you’re object’s default doesn’t even exist yet because you haven’t used a factory to add any to the created package.