So, I had to spend a few long months away from my project (based on 4.8 at the moment).
First thing I try to do when I came back is switching to Unreal Engine 4.9, and it blew up on me.
UnrealHeaderTool choked on my headers. I have several UObject or AActor classes that have arrays of weak pointers, exposed to blueprints at a property. pointers are weak to avoid reference cycles
This worked for me at 4.8, but fails for 4.9: the error I get is Type ‘TArray’ is not supported by blueprint. This seem to mean that Blueprint system won’t accept an array of weak pointers anymore.
Switching to arrays of raw pointers is not an option because of reference cycles
dropping exposure to blue prints is not an option either, as I am setting several relationships at the editor, and using them in blueprint code
Does anybody know how I can go about this?
_
_
_
Technical Details:
My affected classes look like:
UCLASS(Blueprintable)
class MY_API UMyClass : public UMyParent
{
GENERATED_UCLASS_BODY()
//UnrealHeaderTool fails for this
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Blah)
TArray< TWeakObjectPtr<AMyActor> > Actors;
//rest of the class
}
The error I get looks like:
F:/path/to/MyClass.h(19) : Type 'TArray' is not supported by blueprint. MyClass.Actors
UnrealHeaderTool seems to work if I change to a TArray of raw pointers. i.e.:
//UnrealHeaderTool can handle this, but I don't want to leave weak pointers
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Blah)
TArray< AMyActor * > Actors;
//UnrealHeaderTool can handle this but breaks my maps
UPROPERTY()
TArray< TWeakObjectPtr<AMyActor> > Actors;
But I can’t use it.
[Edited syntax for readability]
[Edit II: ] when I wrote “breaks my maps”, I meant “breaks my blueprints”. My Level Blueprints are just one more thing that breaks. Silly me.
This doesn’t work in my case. When I tried it, many objects won’t get destroyed because of the aforementioned reference cycle (thus, implementing Destroyed() didn’t help)
Dead weak pointers were never an issue because I always checked if they were valid.
What aforementioned reference cycle? when you delete item from array it is not exist in memory anymore, there is not invalid or valid pointer, there no pointer at all, there for reference don’t exist. UE4 is full of cycle references (for example Pawn knows which Controller possessing it and Controller knows what Pawn it is possessing), and none of them use weak pointers they clean after themselves (or possibly via UPROPERTY() becuase it also involved with GC). Btw on UObjects pointers, you can use IsValidLowLevel
“Aforementioned Reference Cycle” is the cycle I get when I do not use Weak Pointers in my previous code, as explained in my question. This reference cycle prevents items from being garbage collected, thus they are not destroyed. That’s why I originally did as in the documentation
When I use weak pointers, there is no reference cycle, therefore objects get destroyed, therefore weak pointers got invalidated, and that’s when I removed them. This statement is contingent upon there being no reference cycles.
As to the pawn and controller case, their cycle is broken at the actor’s EndPlay(), that calls the Pawn’s EndPlay(), that detaches from the controller. They don’t have an issue because each pawn has the life cycle of the actor.
Ah you use UObject on UMyClass, then you have BeginDestroy()
Again i never seen weak pointer or shared pointer used on UObjects i only see them outside of UObjects and Slate is full of them, and as i know UPROPERTY() is enough for GC to be aware of refrence
BeginDestroy() doesn’t get called either, because the Garbage collector doesn’t go through reference cycles.
I use WeakPointers on both UObjects and AActors, as stated in my question. If you want to see an example from Epic, you can search for TWeakObjectPtr in Strategy Game Example. I do similar things in my code.