Weird replication behaviour

Hello, today I encountered an odd problem with replication of actor spawn. I managed to fix it but was wondering if there is cleaner solution. To quickly explain:

  • In SetPlayerDefaults my gamemode calls MyCharacter::SpawnInventory
  • SpawnInventory executes on server, spawning an instance of MyWeapon, which has SetReplicates(true) and bOnlyRelevantToOwner = true in constructor. ActorSpawnParameters are set so that character is the owner.
  • Newly spawned weapon is added to MyCharacter’s replicated TArray of MyWeapon pointers
  • Weapon’s OnRecieved(MyCharacter*) sets owner again, sets inistigator and adds prerequisite to it’s PrimaryActorTick so that it ticks after owner
  • Back in game mode I call MyCharacter::SwitchWeapon, which does not switch current weapon, but calls ClientSwitchWeapon (It’s UFUNCTION(Client, Reliable)) since client should always have most up-to-date equiped weapon.
  • ClientSwitchWeapon calls LocalSwitchWeapon, which should change pointer to current weapon. However, the pointer sent from server is null on client, meaning that weapon has not yet been spawned on client, despite character being it’s owner and replication set to true.

And that’s how it goes, I hope it’s understandable. The fix was to add UFUNCTION(Client, Reliable) ClientOnRecieved(MyCharacter*), it can be completely empty, but it forces client to sync and spawn weapon so that function can be called on it. What’s strange is that the pointer to owner character that is valid in OnRecieved (on server) is null on client. Shouldn’t character be already spawned on clients during GameMode::SetPlayerDefaults? Can I somehow force the engine to execute spawn actor before RPCs, even if next RPC is on another object?

It’s better not to force any property replication to avoid messing up prioritization. And sending an RPC that assumes any property as being already replicated is error-prone. I think you could make the weapon set itself as the player’s current weapon as soon as it spawns. Or make you current weapon a UPROPERTY and rely on replication for switching weapons on the client (with ReplicatedUsing).

The current weapon is a UPROPERTY pointer with Replicated and is replicated with COND_SkipOwner (because player has the “authority” over it).
Maybe adding to inventory when weapon spawns is a good idea, but then when i call some client-side function on weapon, forcing it to spawn and execute it the pointer to character is null, so i will have to force character to spawn before it with another client-side function. The best solution over-all would be to know how to force actor spawning update. I tried ForceNetUpdate, FlushNetDormancy with and without SetNetDormancy, even FlushNetDormancy on NetDriver.

I agree with ilookha, the best solution over-all is definitely not to force the replication. The easiest setup is to simply have the server handle important things like this. So adding, switching, dropping, ect. of weapon is just done there and you rely on replication. You can get some better “feel/response time” if you mask some of the delay locally with animations and whatnot, but for first pass I would suggest taking it easy and go with what the engine is good with.

I wanted to clarify something, “since client should always have most up-to-date equipped weapon” is incorrect. Only the server has the most-up-to-date info; it is the authority.

Hope that helps!

Did you ever figure out a good solution for this?