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:
-
I have a
UDataAsset
derived class namedUPickupInfo
that holds the information needed to spawn an ActorAPickup
.APickup
has a pointer to it’s info and this variable is replicated. -
I’ve setup the
UObject
replication sinceUPickupInfo
has anAActor
as an Outer, soAPickup
implementsReplicateSubobjects(...)
.
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:
- I’d have to manually copy all the properties from
Objects[ItemID]
and sinceUPickupInfo
could be any object of its children this would end up being a nightmare. -
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