Problem with replication of sub-objects when changing inventories.

Hello! I’ve been searching about this problem I have but I couldn’t find anything, so I decided to ask here. Thanks in advance!

I have an Inventory which is an ActorComponent, and it has a TArray of UItem (UObject). The replication works almost fine, but there is an error when an item change its inventory.

I don’t see any gameplay problems, I can move items from one inventory to another, everything looks fine, and that’s probably because it seems that the error is not thrown by the server (I might be wrong) but the Client.
The error I’m getting is: LogNetTraffic: Error: UActorChannel::ReadContentBlockHeader: Sub-object not in parent actor.

I did some debug and I found that the ‘OuterPrivate’ of the UItem is not changing in the client. The server has the updated OuterPrivate.
When the item changes from one inventory to another, I use the Rename method with the new Outer.

// This is in the Inventory.cpp when adding an item.
Item->Rename(*Item->GetName(), this);

The only solution I found is that instead of changing the outer, I could duplicate the object. That ‘seems to work’ but I don’t like that solution.

UItem* NewItem = DuplicateObject<UItem>(Item, this);

This is the relevant code:

Inventory.h

class UInventory : public UActorComponent

public:
  UPROPERTY(Replicated, BlueprintReadWrite, ReplicatedUsing = OnRep_Items)
  TArray<class UItem*> Items; 

  virtual bool ReplicateSubobjects(class UActorChannel *Channel, class FOutBunch *Bunch, FReplicationFlags *RepFlags) override;
  ...

Inventory.cpp

void UInventory::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
	Super::GetLifetimeReplicatedProps(OutLifetimeProps);
	DOREPLIFETIME_CONDITION_NOTIFY(UInventory, Items, COND_None, REPNOTIFY_Always);
}

bool UInventory::ReplicateSubobjects(UActorChannel* Channel, FOutBunch* Bunch, FReplicationFlags* RepFlags)
{
	bool WroteSomething = Super::ReplicateSubobjects(Channel, Bunch, RepFlags);

	for (int32 Index = 0; Index != Items.Num(); ++Index)
	{
		UItem* Item = Items[Index];
		if (!IsValid(Item)) continue;
		WroteSomething |= Channel->ReplicateSubobject(Item, *Bunch, *RepFlags);
	}
	return WroteSomething;
}

UItem.h

class UItem : public UObject

public:
  UPROPERTY(Replicated, BlueprintReadOnly, Category = "Item", Meta = (ExposeOnSpawn = "true"))
  UItemData* Data;
  UPROPERTY(Replicated, EditDefaultsOnly, BlueprintReadOnly, ReplicatedUsing = OnRep_OnChanged, Category = "Item")
  int Quantity = 1;
  UPROPERTY(Replicated, EditDefaultsOnly, BlueprintReadOnly, ReplicatedUsing = OnRep_OnChanged, Category = "Item")
  int RequiredLevel = 0;
  ...

  virtual bool IsSupportedForNetworking() const override;
  virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;

UItem.cpp

bool UItem::IsSupportedForNetworking() const
{
	return true;
}

void UItem::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
	Super::GetLifetimeReplicatedProps(OutLifetimeProps);

	DOREPLIFETIME(UItem, Data);
	DOREPLIFETIME(UItem, Quantity);
	DOREPLIFETIME(UItem, RequiredLevel);
}

Thank you!

Hey.
I’m facing the exact same issue with my version of inventory, clients don’t seem to update with the proper OuterPrivate, and it starts giving me issues when I grab an item whose OuterPrivate was the actor itself, because when I grab the item I destroy the actor after adding the item to my inventory so the fact the OuterPrivate becomes a null pointer it starts messing up with my inventory.

Did you ever find a solution for this?

Thanks in advance