Duplicated UObject causes client to disconnect

So I’ve been having this issue for a while now, I know it’s a long one, but I’d appreciate any help I can get.


Little project background:

  1. I have a UDataAsset derived class named UPickupInfo that holds the information needed to spawn an Actor APickup. APickup has a pointer to it’s info and this variable is replicated.

  2. I’ve setup the UObject replication since UPickupInfo has an AActor as an Outer, so APickup implements ReplicateSubobjects(...).

NOTE: UPickupInfo is a child of UInteractableInfo which is a child of UDataAsset. Similarly, APickup is a child of AInteractable. So code below will adhere to this.


This setup works great for UPickupInfo objects that I create runtime using CreateObject<UPickupInfo>(APickupActor, UPickupInfoClass). The problem arises when I try to duplicate a static object that I’ve predefined in the editor using a data asset. I get the following error:

   LogNetTraffic: Error: ReadContentBlockHeader: Stably named sub-object not found. Component: [18]Weapon_0.[22]Basic_Dagger, Actor: Weapon_0
    LogNet: Error: UActorChannel::ReadContentBlockPayload: ReadContentBlockHeader FAILED. Bunch.IsError() == TRUE. Closing connection. RepObj: NULL, Channel: 14
    LogNet: Error: UActorChannel::ReceivedBunch: ReadContentBlockPayload FAILED. Bunch.IsError() == TRUE. Closing connection. RepObj: NULL, Channel: 14

Here’s some code to put things into perspective:

APickup:

UCLASS()
class NADA_API APickup : public AInteractable {
    
    GENERATED_BODY()
public: 
    UPROPERTY(ReplicatedUsing=OnRep_Info, EditAnywhere, BlueprintReadWrite, Category = "Interactable Properties")
    UPickupInfo* Info;
    //SOME OTHER STUFF 
        
};

Spawn function:

bool SpawnItem(int32 TypeID, int32 ItemID)
{
	
	if (HasAuthority()) {
		FTransform SpawnLocAndRotation;
		SpawnLocAndRotation.SetLocation(GetPawn()->GetActorLocation() + FVector(0, 0, 500));

		APickup* SPickup = GetWorld()->SpawnActorDeferred<APickup>(ItemTypes[TypeID], SpawnLocAndRotation, this, this->GetPawn(), ESpawnActorCollisionHandlingMethod::AlwaysSpawn);

		if (SPickup) {

			TArray<UPickupInfo*> Objects;

			TypeLibraries[TypeID]->GetObjects(Objects);

			if (ItemID >= Objects.Num() || ItemID < 0) {
				UE_LOG(LogTemp, Error, TEXT("Invalid ItemID: %d; Please enter a valid item ID!"), ItemID);
				SPickup->Destroy();
				return false;
			}
			UPickupInfo* PickupInfo = DuplicateObject<UPickupInfo>(Objects[ItemID], SPickup, Objects[ItemID]->GetFName());

			if (PickupInfo) {
			
				PickupInfo->IsValid = true;
				
				SPickup->SetOwner(this);
				SPickup->Init(PickupInfo, this);

				SPickup->BaseMesh->SetSimulatePhysics(true);

				SPickup->FinishSpawning(SpawnLocAndRotation);

				return true;
			}
		}
	}
}

If I replace

UPickupInfo* PickupInfo = DuplicateObject<UPickupInfo>(Objects[ItemID], SPickup, Objects[ItemID]->GetFName());

with

UPickupInfo* PickupInfo = CreateObject<UPickupInfo>(SPickup, PickupClass)  

or not duplicate the object in the first place ( just use UPickupInfo* PickupInfo = Objects[ItemID]) the replication works and the client stays connected to the server. However, I can’t just create a new object nor use the object itself because:

  1. I’d have to manually copy all the properties from Objects[ItemID] and since UPickupInfo could be any object of its children this would end up being a nightmare.
  2. PickupInfo is modified in runtime, so I can’t use the static object itself because that would cause the static data asset to be modified as well.

Thank you for taking some of your time to read this and sorry for the bad formatting this is my first time writing a post :slight_smile:

Hello,

So I’ve tried to look at the difference between a newly created UObject and a duplicated one, and I think I figured it out! I just need someone to verify that I’m not doing something stupid here.

After duplicating the UObject, I do the following:

DuplicatedObject->ClearFlags(EObjectFlags::RF_WasLoaded);
DuplicatedObject->ClearFlags(EObjectFlags::RF_LoadCompleted);

I think what’s going on is the following: Since I’m duplicating a UDataAsset from the editor, the RF_WasLoaded and RF_LoadCompleted indicate that this object was loaded from files on disk, so there’s no need to replicate all its attributes. And since the outer is no longer the path to that object (I change it to the owning actor), the client can’t find it, so it disconnects. So by clearing these two flags, the object is being replicated properly.

**I’d appreciate it if someone could validate this. **

1 Like