Network game and replication

Hello,

I am doing a network game and I need information about replication. (I have already read unreal documentation about this subject but it is very theoric)

How can I do if client1 do something, to make it replicated on client2 ?
For example, if the client1 press a button in a UI that change is skin, he will be the only one that see his player with a new skin. So, how can I do to make the client2 see the client1 with is new skin ?

Sorry for my mistakes but I am not english, I do my best to be understandable.
Thank you very much in advance for your answers !
Kind regards

When a client does something, he is the only one who knows about it (except for CHARACTERmovement).

A client can tell the server to do it but cannot tell another client.

So for client A to tell client B something,
Client A has to tell Server to tell Client B.

Only the Server can tell other clients to do something.

The most common two ways to do this:
Client A tells Server to set SomeVariable. SomeVariable is Replicated, so the server updates that variable on any Clients that are Relevant, as fast as the Server thinks it needs to tell them.
OR,
Client A tells Server to run an event (Server RPC). The server runs this function which calls another RPC (Multicast) which runs on the Server and all clients. this event happens on all machines Almost immediately. If you have several these happening every tick it will take too much network bandwidth and slow down the game making it laggy. But this is how you should do it for occasiional (not constant) things that all machines need to do at the same time immediately.

RepNotify happens when the server changes a variable and a client comes into relevant range (which could be much later than the first two options) Use this to guarantee that a client who joined the session late or entered a room after an effect happened still sees the effect turned on or off.

When I read your answer I had many ideas to solve my problem but I tested them and that doesn’t work…
In fact, my problem is :

  • client 1 think he is “BP_player” in my game (BP_player is my character) and he thinks that the other client are “BP_player1”
  • client 2 think he is “BP_player” in my game and he thinks that the other client are “BP_player1”

So, even if I do a run on server event, a multicast or anything else I can’t say that this client will have this skin, because if I say that BP_player will have skin one and BP_player1 skin 2, then each player will have skin 1 and see the enemi as skin2…
So have you an idea of how I can do to assign a skin to a specific player ?
Thank you for you answer, it helps me to understand multiplayer better.

I had this same problem until i realized that PlayerControllers are not replicated. So each machine had its own Player 0, Player 1, etc. Which are not the same objects as te Player 0, Player1, etc. on the other machines.

Pawns replicate and Playerstates replicate, but Playercontrollers do not, even though they own the connections that communicate with the server.

So Player 0 on machine A is not the same object as Player 0 on machine B, even if one of them is the server.

So what to do?
In your Playercontroller you can send a Server RPC containing the number of which skin you want, and it multicasts to all machines saying this guy chooses that skin but it gets it all wrong.

I dont know what is the right way but what I did that works is the following:

  • In Playercontroller I send Server RPC with a PlayerID parameter which is from the PlayerController → Playerstate → PlayerId variable.
  • Also in Playercontroller that Server RPC Loops over all the Playercontrollers (because server has all playercontrollers but clients only have playercontrollers of their machine) until it finds a match between the parameter playerid and one of the playercontroller–> playerstate–>playerids. When it finds the match, it sets the skin on that playercontroller’s controlled pawn (you must pass in a parametef to tell it which skin also).
  • Do a multicast on the controlled Pawn passing which skin it should have. then on each majine the multicast received should run the set material function.

Thank you for your answer ! I am understanding the objectiv of what you said but there is still some point that I didn’t understand.
You speak about sending a server RPC, I think I am mixing this notion with the Run on server option…
I have try to follow your instructions but it is quite… I am not sure I understood well what you said because in what I have done I don’t use the id that i passed in the parameters for the event…
This is a screenshot :

:

You’ve got it right - Server RPC means the same thing as Run On Server. It’s just another name for it.

Oh wow - don’t do that on a Tick event! Just do it when the player does the action to change skin! Sending replicated events (RPCs) will flood your network bandwidth if you do them every tick, because Tick happens many more times per second than network updates do.
But you got the rest of it right for sending the Server RPC.

Now in your Server RPC event handler, called change_skin,
GetAllActorsOfClass should be of yoru PlayerController class.
Then the Array Element coming out of the Foreach loop will be a playercontroller and you can pull a wire out of it to get its playerState which has the Player Id, and you can test if == to the Player Id that comes out of the change_skin event, instead of what you have connected to the == node right now (erase that part).

Erase everything else in your screenshot for now and let’s just go partway.
After Branch on that == is true, pull another wire out of the Array element to make a Get Controlled Pawn node, cast to the Pawn class you made, and from there pull out another wire and get the Component that you want to set the skin on (probably the skeletal mesh), and Set Material on that.

Once you get that working server side, we will move on to getting the other computers to see the skin change.

I recommend eXi’s pdf for network.

Thank you for this pdf, I will read it !

Thank you for you answer ! So, I send you my new blueprint thanks to your explainations : I knew that the event tick is not a good option, but the problem is that my game is working like that : - When you open the game you have a “choose skin” menu where you select your skin by clicking a button. When you click the button, it save the skin you have choose in a game instance. - Then, it load the test_map and you should appear in it with the correct skin.

So my question is, do I have to do an event tick that test if a variable in game instance is set, so that the player choose the skin and if it is the case change the skin (only if I haven’t do it already) ? But as you said it will do the test at each frame so I am not sure it is a good way to do it… Or is there any better solution ? I can’t do the skin change at event begin play due to the fact that when the game begin the player haven’t yet set the variable “skin” in the game instance…

Just do it when the player sets the skin. You must have an event somewhere for that or it wouldnt happen at all

Ok, so I added the event. It is called when I open the test_level (so after choosing the skin).

All right excellent! That looks like how I think it will work. Does it work on the Server when you do it that way? If so then we can move on to getting it to work on the Clients if it doesn’t already.

Ok, so for the moment it is not working :confused: I explain what happen :

  1. Game begin, player 1 choose skin 1, player 2 choose skin 2.
  2. Player 1 and player 2 see their skins correctly (at this point there is no server, each player is alone in his map)
  3. Now, player 1 decide to host the game. So he appears in a new map and become the server. (His skin is still correct)
  4. Player 2 decide to join an hosted game, and then he appears in the same map as player 1. But his skin change and become the basic skin (skin 0)

So, in fact

-Player 1 see player 2 with default skin (skin 0) instead of skin2.

-Player 1 see himself with correct skin (skin 1)

-Player 2 see player 1 with default skin (skin 0) instead of skin1

-Player 2 see himself with default skin (skin 0) instead of skin2.

So it is quite strange… I am not sure why player 2 can’t see himself correctly when he arrives in the host game…

EDIT : I change something in the player Controller :
I put the “change skin” event in “Multicast” event instead of run on server event.
It change something but there is still one problem :

  • Player 1 see himself with the correct skin (skin1)

  • Player 2 see himself with the correct skin (skin2)

  • Player 1 see player 2 with default skin (skin0)

  • Player 2 see player 1 with default skin (skin0)

Some screens :
-Player controller skin is the same as previously
-I send you my menu (where i change skin) and the level blueprint where i call the event.

Oh. All my advice assumes that the clients have all joined the host before any skins are applied.
When i got this working on my project then i was able to let the clients choose their skins before joining but then they had to store their choice in the game instance and then tell the server to apply their choice again after joining (the game instance remembers thinggs on its own machine even after opening a level, whereas pawns do not survive the process unless the level was streamed in, or maybe if it was seamless travel).

In my project it was supposed to load skin 2 times :

-after choosing the skin when he appears alone in his map

-after joining

Because the event is called in the event begin play of the map so it was “supposed” to work.
But i will try to apply the skin just after joining and see what happened. I will tell you.
I have done what you said exactly : just set skin when player join the game and not before but is is not working…

EDIT : I have done a test :
I added 2 print string in the player_controller to know why it does nothing for the client.
(Screen below)

When the server create the party he said :

Server : Setting following mesh

Server : “Name of the correct skin”

So, that is normal. And when the player 2 enter, server said nothing for him. Even the simple string “setting following mesh”. So it seems that the player 2 will not have the skin because he didn’t execute the event for him…
I tried to add a new print string before calling the run on server event and the client 2 display this string. So i have no idea why the run on server event is not executed when client 2 call it.

If i change the event run on server into a multicast event, then the player 2 display :
Client 1 : Setting following mesh
Client 1 : “Name of the correct skin”
But the player1 still can not see the player 2 with is correct skin and player 2 still can not see the player 1 with is correct skin.

I this point I don’t know what to say but you are almost there!
You just need to choose an event that will automatically fire after the player joins and call that change_skin server RPC from there.

In my game I did something even weirder but I think you shouldn’t have to and it would be harder to make it work: I had the server send out Client RPCs to all the playercontrollers, to ask them what their skins were, and they responded back with the skin and their Player ID, and did the change_skin on the server from there. I did it that way when the server opens the level, but like I said that sounds like it’s adding another step that you probably don’t need.

Ok, i will try to find a solution. But for the moment can you explain me what you said about the mutlicast server to make the client see the server skin and things like that ?

So what I did in my game is that when the player joins the server, then that will fire an event on their playerclass or their default pawn, like beginplay for example, because when you Open Level or Join Session it opens a level and destroys the pawn and controller they had (but keeps the underlying player connection object I think), then creates new ones once the level is loaded, and this fires their constructors and beginplay events.

So you go to where the player is just beginning to function, and have it send a Server RPC with its desired skin (which it told the GameInstance to remember because GameInstance is not destroyed on the client machine between levels like player controllers and pawns are) and its Player ID from the playerstate it has on the client machine which should be the same as the one on the Server’s version of the same player’s player state.

From there the server receives the Server RPC and just relays the Skin and PlayerID into a MultiCast. Then that MultiCast is received by the Server and all the Clients, and they all get the skin and Player ID to match to, and they look for the Pawn which has the Player State which has the matching ID, and when they find it, then they apply the skin that was passed to them in the Multicast. This will happen on all the machines.

So then the only problem is that if somebody else joins the session later, they missed all those multicasts from before, so really every player who joins will need to not only tell the server to multicast their chosen skin to everyone, but ALSO repeat everyone else’s skin choices back to him so they get set on his computer too.

So, I have changed many things in my project :

When the game begin, there is no default pawn class. When you decide to create or join a party, then the default pawn class change to “BP_player” and you arrive in a new map called “test”.

Ok, that all. So, I tryied what you said but i am not sure of what I understood.
I put my blueprints below :
My BP_player where I call the event ‘applyskin’. Apply skin is a run on server event that is in the player controller

Here we are in the player controller. It is the content of ‘apply skin’ event. It calls a multicast event.

And there is the content of the multicast event.

At this point, nothing is working. I explain myself, the id given by the bp_player and the id with which we try to see if it is equal is never matching…
The id that i pass in bp_player is 0. The id that i try to verify if it match is 370…

I am totally lost at this point

Hmm that sounds just like what I thought would work. Try replacing [Get PlayerController: 0]
with [Get Controller] having Self node plugged into Target.

I recommend you put a breakpoint on apply_skin and examine the Id and Mesh pins on it and the multicast call after doing one Step Over during play.
The reason for this is I want to check that one machine isn’t overwriting those settings with its own blank ones somehow, AND I want to see whether you really can send a SkeletalMesh over a network RPC. I don’t know if you can. If you can’t (and you can find out by debugging as I described), then I suggest replacing the Mesh pin with a simple integer pin, and use the integer inside the multicast, on a Select node or an Array Get in order to pick out which Mesh. So one mesh will be #0, another mesh/skin will be #1, Another is #2, etc. Try that way if you find that skeletal meshes themselves can’t make it across an RPC.