Using SpawnActor and other BP nodes
SpawnActor nodes and some others aren’t available by default in UObject child classes.
This is caused by the default implementation of GetWorld
. You need to override it, and make sure the default implementation never gets called.
Important: Your GetWorld
code should not call Super::GetWorld()
. The default implementation will make BP’s think you don’t have it correctly implemented.
UObjects by default don’t have a valid reference to a world. You need some way of referencing one in your GetWorld
. For example, if you always pass an Outer object which is an Actor (since actors always have a world), the following implementation works well:
const AActor* Outer = Cast<AActor>(GetOuter());
if(Outer)
{
return Outer->GetWorld();
}
return nullptr;
Custom serialization
The class loading logic below might not work for actors or actor components. Example code from TCFX on Unreal Source Discord.
/** Serialize objects array */
//First need to remove any invalid object from the array
if (Ar.IsSaving())
{
MyObjects.RemoveAll([](UObject* Obj)
{
return (Obj == nullptr || Obj->IsPendingKill());
});
}
//Serialize array num;
const int32 ArrayNum = MyObjects.Num();
Ar << ArrayNum;
if (Ar.IsSaving())
{
for (UObject* Object : MyObjects)
{
FString ObjectClassName = Object->GetClass()->GetFName().ToString();
Ar << ObjectClassName;
Obj->Serialize(Ar);
}
}
if (Ar.IsLoading())
{
MyObjects.Reserve(ArrayNum);
for (int32 Index=0; Index < ArrayNum; ++Index)
{
FString ObjectClassName;
Ar << ObjectClassName;
if (!ObjectClassName.IsEmpty())
{
UClass* FoundClass = FindObject<UClass>(ANY_PACKAGE, *ObjectClassName);
if (FoundClass)
{
UObject* Obj = StaticAllocateObject(FoundClass, GetTransientPackage(), NAME_None, EObjectFlags::RF_NoFlags, EInternalObjectFlags::None, false);
if (Obj)
{
Obj->Serialize(Ar);
MyObjects.Add(Obj);
}
}
}
}
}