Why is the parameter of a Server function with value NULL?

Hello, i’m trying to send my inventory from the client to the server using the ServerSetInventory(AInventory * Inventory) function, but when it runs on the server the Inventory variable is NULL with the following warning log:

LogNetPackageMap:Warning: Could not find Object for: NetGUID <1, Inventory_2> (and IsNetGUIDAuthority())
LogNetPackageMap:Warning: Unable to resolve static NetGUID <1> from Path: Inventory_2
LogNetPackageMap:Warning: InternalLoadObject unable to resolve reference from NetGUID <1> (received full path: 1)

At first i was getting constantly the log:

LogNet:Warning: Actor Inventory / Inventory_0 has no root component in AActor::IsNetRelevantFor. (Make bAlwaysRelevant=true?)

I added a RootComponent (although i don’t know why it needs since it’s a NotPlaceable item and should only exists virtually in the character) and the warning stopped showing, but it didn’t solve the problem. I added bAlwaysRelevant = true; and bNetUseOwnerRelevancy = true; and set the owner, but it did not do anything. Do you have any idea how to solve this?

My first question would be is who calls SpawnActor on the AInventory class you have setup? The server should make this class, attach it to some replicating AActor (like APlayerController) and then let it replicate down to the client.

The client will know that this object has been created/sent via

Header

UPROPERTY(ReplicatedUsing=OnRep_Inventory)
AMyInventory* PlayerInventoryVar;

UFUNCTION()
virtual void OnRep_WorldInventory();

CPP

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

	DOREPLIFETIME_CONDITION( AMyPlayerController, PlayerInventoryVar, COND_OwnerOnly );

   // more code here
}

You could initialize this in AMyPlayerController::Possess(APawn* Pawn)

if (Role == ROLE_Authority && PlayerInventoryVar == nullptr)
{
    FActorSpawnParameters SpawnInfo;
    SpawnInfo.Owner = this;
    PlayerInventoryVar= GetWorld()->SpawnActor<AMyInventory>(SpawnInfo);
}

Now you have a server initiated spawning of an object, the lack of this before is probably the cause of your warnings above.

Then use the ServerDoWorkOnInventory() RPCs to modify/use/manipulate your inventories, making it server authoritative.

Thank you for your answer :slight_smile: I wanted to make my code as much client-side as possible, so i was spawning the inventory in the client and sending it to the server to replicate to other clients, but i’m guessing i can’t do that :stuck_out_tongue: What you are saying is that i can use the ServerSetInventory() to update the server from the client but the original instance must be spawned from the server?

Yes that is the procedure that i’m trying to do to replicate. I’m calling ServerSetInventory to set the new value on the server so it’s replicated to the other clients, the only thing i was missing was that i need to create the object in the server to be able to do that comunication. I though you could spawn it in the client and could set the value in the server even if it’s value was null. Thank you for the help :slight_smile:

Correct. Clients can’t tell servers about objects they don’t know about. An object can be created on the server, given to a client, then used as a reference when talking back and forth.

Additionally, replication only goes one way “server->client”. You can’t set member variable A on the client and expect it to just be set on the server. The typical pattern is to call an RPC “ServerSetMyVar(newVal)”, have the server set it there, then make the member variable set to replicate to other clients.

Or you can do “for all clients, ClientDoSomeWork()” inside the server call as well. But that is more heavy handed and also brings in the caveat that the object must exist and be relevant for all the other clients.