Execute event locally for client, but also replicate it?

Hello! In my top-down game, I have the aiming defined inside the player controller (from a hit result.) However, in a networked game, the other players do not see the pawn rotating. The only exception is of course the server, and everyone can see the server’s pawn’s rotating perfectly fine, but no one (including the server) can see the clients rotating except for themselves. What I did to fix this is the following:

UpdateRotation1 is called from the player controller ([click here for more details][2].) The issue that I face with this is that the rotation is handled by the server if I execute it like this. Correct me if I’m wrong, but this means that if there is an unreliable connection between the server and the client, there might be some lag when the player tries aiming since the aiming is executed from the pawn, to the server, and then back again to the pawn.

My question therefore is: Is there a way to execute the event locally for the pawn, and then simultaneously execute that event on the server and the other clients? This way it will always be reliable and latency-free for the player performing the actual aiming, but it will not be for the other players (as it should be.)

Thank you!

So this first “mistake” is, to perform this in the PlayerController.

The PlayerController only exists on Server and the owning Client. So if we both are Clients, we would only know about our own PlayerControllers, and the Server knows about them, but I don’t know about yours and other way round.

So with this, a “Multicast” on the PlayerController couldn’t work, cause there are no instances on the other clients to perform the call on.

Moving it into the PlayerCharacter is correct, as you now have an instance of the Actor on all Clients and the “Multicast” can actually execute on the other clients.

To kill the latency for the Local Client (The one that is in control of the PlayerCharacter), you simply call the Event for him directly, without the “Multicast”.

So it would be:

  1. Client Presses button to perform hit with Start/End Trace Vector etc
  2. Client checks if the HitResult is ok and turns to that point (or what ever you are doing there)
  3. Client tells the Server to perform the same trace (don’t pass the HitResult, as this opens up a way to cheat!), by passing the Start/End Trace Vector etc
  4. Server also checks if the HitResult is ok (and maybe keeps in mind that things could have moved in that time)
  5. Depending on the Servers result, he multicasts the Rotation or does (maybe) nothing, cause the HitResult didn’T hit stuff

That’s a pseudo code for a working solution. I think you’ll manage to create code from it :stuck_out_tongue:

For more information on Networking: My Network Compendium: http://cedric.bnslv.de/unreal-engine-4-network-compendium-released/


pass the player id, from the playercontroller. if you retrieve if from the player character on the replicate on all, it will retrieve the same Id as the source. so you are better off checking it from the controller. enjoy

You don’t need the ID for this. Simply do “IsLocallyControlled”. This will return a boolean indicating if the Pawn is controlled by the Local Client or if it’s just a “puppet” on the other clients.

I would also try to not replicate (call RPCs) on the Event Tick.

Ahh, I see! Thanks for the solution! :slight_smile:
Can’t believe it didn’t occur to me to just not replicate one of the events… Hahaha

true, could have used the isLocallyControlled.
and yeah, the screenshot was an example. placed on the first place I could find.

Would you mind answering a question of mine though? Even though the player controller does not exist in the other clients, shouldn’t the rotation still be replicated because the rotation is being applied on the pawn, which IS replicated? Or does replication work by having separate instances created on the server, and in those instances since the playercontroller doesn’t exist, the rotation change never occurs? Thanks!

my understanding is that if the class dont exist on all other clients, the functions implemented on them wont either, so calling a target self like in your question would target the controller of that other client, making him rotate instead of the original initiator.