I’m sorry for the late reply here.
If it’s not forbidden to use replication on level blueprint variables, and it’s not blocked, it seems like a bug in UE4 4.16.
It’s definitely not forbidden. Level Blueprints are actual blueprints, and are wrapped / managed by an ALevelScriptActor. If you take a look at the constructor, you’ll notice that we do explicitly enable replication and set some other networking state.
We noticed that Level Blueprint references to Actors on that level are invalid after streaming out and streaming back in that level. It happens only in multiplayer on both server and client.
Just so I fully understand the problem, you have some level A that references actors. When the level is Unloaded (unstreamed) and Reloaded (restreamed) those references are broke.
I have a few questions, mostly just for the sake of clarity:
- Are the referenced Actors owned by the streamed level, or another level?
- If they’re owned by another level, is that other level being streamed in / out during the same time frame?
- Are the levels being streamed in and out on the client, server, or both?
After digging into the code I noticed that normally FLinkerLoad::Preload() is called for both Blueprint class object (object of a class “BlueprintGeneratedClass”) and a Blueprint object itself (object of a class “SomeClass_S_C”).
In this case, are you talking about the BP of an actor, or the BP of the level that owns the references?
FLinkerLoad::Preload() is not called for a Blueprint class and FLinkerLoad::FinalizeBlueprint() is never called which in effect doesn’t assign proper Actor* pointers to references in Blueprint.
So, it sounds like in this case FLinkerLoad::Preload is not being called on the Blueprint Class for the Level Script?
When we unload a level we go through and mark all Actors and Subobjects owned by the level as Pending Kill and perform a garbage collection. This system is completely separate from Networking, and if any system has references to these objects they should be properly nulled out regardless of whether or not the references are strong or weak (Strong being a UPROPERTY and weak being something like TWeakObjectPtr).
Aside from that, the networking system generally keeps very few strong references. The few things it will keep a reference too are generally either other networking objects that shouldn’t be level specific. The main exception to this is for UActorChannel where we’ll keep a pointer to the Actor the channel is associated with. Again though, this should get cleared away by the Garbage Collection that happens as a part of unloading the level.
I’ll work on seeing if I can reproduce the issue based on the description you gave. I’m not sure how many others have seen this issue.