After a client joins when is it safe for a client to send an RPC to the server?

Using a listen server setup. Trying to send some data (player color) from the client to the server, so then the server can replicate it back out to all other players via replicated variable.

Currently, my customization system works great in game. Players can join and then chose their colour (and a ton of other customization things) and all other players can see these changes happening. Works great. I am saving these customizations via Save game, so after they quite the game, next time the player joins a game, their player will automatically set up to have the same customizations when they join.

So I have that save data, and I am trying to apply it on the client’s character when that character is automatically spawned on join. But in OnBeginPlay, when I try and send an RPC from that client → server saying “these are my customizations I want to have immediately!” that RPC just never makes it to the server. However, if I put a DELAY 1.0s node before calling the RPC everything works fine (or if I manually trigger the RPC some other way any time after the 1.0s)

It seems that I am just trying to send data to the server, before the connection/something is all setup? Is there a better entry point to do this? Or some other issue that is causing this that I am just not aware of? Looking at the logs from the OnBeginPlay on my Client’s player, it does log this warning:

ogNet: Warning: UNetDriver::ProcessRemoteFunction: No owning connection for actor BP_Character_C_1. Function S_RPCTest will not be processed.

But I’m not sure how I resolve that

Additionally, I have tried using the “Event Receive Controller Changed” event, to wait for the server to assign the controller to the client/player, to ensure that the “connection is ready to go”, but I get even weirder issues there. In the below test I am not calling my RPC until both OnBeginPlay AND OnControllerChanged is called on the locally controlled actor, to ensure the Actor is ready to have visual changes happen AND the controller signaling it’s net-ready. But the lines marked with * leave me very confused.

Server Starts
Server Char0 OnControllerChanged called
Server Char0 OnBeginPlay called
Server Char0 Set Initial Customization Data, since server is the owner of Char0 player (success visually we see this working)

Client Starts
Server Char1 OnBeginPlay called
Server Char1 OnControllerChanged called
Server Char1 Does NOT set data, because server is not the owner/controller of Character1, the client is
Visually, we see Char0 on client window with the correct data

Client Char0 OnControllerChanged called (irrelevant, since Character0 is the server's player, we don't care about that as the client?)
Client Char0 OnBeginPlay called
*Client Char0 IS locally controlled??? But thats the servers player? (IsLocallyControlled and IsLocalPlayerController = true)
Client Char0 Set Initial Customization Data (RPC never makes it to the server still, but it shouldn't have been sent anyways since this is not our player!)
Client Char1 OnBeginPlay called
**Client Char1 OnControllerChanged NEVER gets called, and so never sends data to the server.

No more logs
Visually, the client sees both players with the correct data
The server sees themselves with the correct data, but NOT the clients character (missing customization data)

So I’m just very confused. What is the proper way to send client data to the server, so the server can have that as soon as possible after the client has connected/joined? Anyone have any advice or things for me to try? Seems like just “leaving a delay before calling the rpc” is a nasty hack that I’m worried won’t actually work in all network conditions.

Edit: Regarding the IsLocallyControlled confusion above, in OnBegnPlay, I found this thread from 10 years ago that says IsLocallyControlled is not yet setup properly in OnBeginPlay yet… assuming that is still the case. Is Locally Controlled returns True for remote players? - #3 by Ryan_Gerleve


This is my super simple example, happening on the player pawn (which is basically the Third Person demo character). S_RPC that is sent from the client-> server never shows up in the log. If I add a delay in the EventBeginPlay of 1.0, S_RPC does get called. What is the proper way to do this, that doesn’t rely on a delay? How can I know the actor is net-ready and can send off RPCs properly (and nothing behind the scenes is still being resolved on the network/setup?)

try setting a bool IsInit by the server on repnotify and then in the repnotify event the client should be ready.

i havent had the problem you have though, what i always do is have my playercontroller spawn its own pawn (rather than gamemode defaults) so i can pass through any variables i need set, duing this should ensure the player is set and therefore IsLocallyControlled should work

Thank you for the reply. Yes, I considered using a variable on the server and wait for it to reach the client to know “things are good to go” when I receive it but seems like a messy workaround. Might be what I do for now though I guess!

Right now I am using the default “out of the box” setup for spawning players, but I do need to fix that up soon anyways to get a proper login/join game flow, and perhaps by doing that this whole issue will disappear anyways. Like you say controlling the spawn manually might be a solution

Begin play firing doesn’t mean that the controller has possessed the pawn or that possession has been replicated down to you.

For things like this I tend to lean on Timers when working with BP.
Also I use rep notify vars. The onrep function it creates is used to apply the changes.


1 Like

I implemented these solutions and thought it was all working, but this problem showed up again today. Pulling my hair out now!

My current setup is:
[Server] OnPostLogin. When client has joined, send a RPC from server->client telling that client “isServerReady”.
[Client] Player Pawn OnBeginPlay, delay 1s, then check “isServerReady”. If true send an RPC from client->server with initial data to be applied. If false, delay 1s and check again (looping until it finally works).

Client receives the 'isServerReady" rpc just fine, and IS TRYING to send the RPC back to the server but THIS RPC NEVER ARRIVES. Logs don’t show anything at all, no “no valid connection” or any error.

I checked that the pawn is owned by the local controller. But also tried to just route this event through the locally controlled player controller, same issue.

Does the event need to be set to reliable?
Is there some other condition I need to wait for “before it’s safe”?
Is there any way to further confirm with logs if the RPC is being sent, or being received but just… wrong? I have a log string before and after the client calls the “Send RPC” which are being logged so the code is being reached. Just nothing on the server.

I noticed if I add a delay 5s in the PostLogin function to delay telling the client “isServerReady” things work. But I am not sure it works in all net conditions so I don’t want to rely on random delays.

I’m at my wits end and any advice would be greatly appreciated! :slight_smile:
Really would like a proper solution instead of just adding more delays and hoping it works in all cases!

Edit: Marking these RPCs as reliable seems to make things work? So I wonder if the network (during startup) just is too full, and those first RPCs (which were not marked as reliable) are being dropped? Hmmm

On Post Login is too early to RPC the client. It’s when the client “connects” to the server and a controller has been created. Replication hasn’t started yet.

When the client does get its controller then handle the code / check-ins etc.

1 Like

Thanks for the reply.

The RPC from the server->client from OnPostLogin is consistently working though. So that doesn’t seem to be “too early” as far as the connection being valid. Too early in that “the server isn’t done setting everything up” though, is that what you mean? And if so, is there a place that IS not too early for that?

It’s just when I try and respond to that rpc, and send back a response from client->server, that just fails silently.

If I mark the RPC reliable things work though. Which is interesting, and I’m not sure why that would resolve things. But it’s at least different behavior that might help narrow things down.

When the client does get its controller then handle the code / check-ins etc.

What is the entry point for doing this?
OnBeginPlay on the controller? (No, too early? because things are not “settled”?)
OnPossess? (No, server only unless I send an RPC from here to client?)
OnControllerChanged on the player pawn? (logged this, this is already happening before trying to send the failing rpc from client->server)

Before sending the response RPC back from client->server, I did log out that the client is the controller/owner of the actor at that point. But the RPC still fails

my guess is at this stage of the game ‘everything’ is replicating (Defaults values, initialization etc ) so a non-reliable just gets dropped.

something like this makes perfect sense to be Reliable anyway.

you can use RecievedControllerChanged on the pawn as youve said but personally what i do is use a load screen widget that the player has to click on

1 Like

Your getting lucky. Go into PIE advanced settings and turn on network emulation. Use a 100/100 ping w/1% loss.

On Post Login is when the “Server” creates a controller and it has has Initialized on the “Server”. There’s no guarantee the server has even sent you the client a controller yet, much less you character class. Characters are spawned after the controller, then possession takes place.

Generally 2-3 ticks after OnPost Login is roughly “when” the server is sending you the controller, then Character.


If a regular RPC isn’t getting through there’s a choke. Typically this due to not enough bandwidth. Bump it up a bit.

Reliable means its just going to keep resending until received. Wasted bandwidth. Reliable RPC’s can negate other gameplay relevant RPC’s (movement etc) from being sent if there isn’t enough bandwidth at net flush tick.


Begin Play is 100% when you get the class loaded. A short delay after that is a good option.

Personally I use a loading pawn as the GM’s default pawn. It’s bare bones, no mesh. It’s job is to fire back to the controller when the level has loaded enough to spawn the real character class. This is when I send cosmetics etc.

1 Like

Thanks. This is what my thought process was too, which could explain the why. Perhaps I need to consider a smarter replication strategy, to delay some less important things from initializing immediately anyways.

I actually tried waiting for RecievedControllerChanged on the client to fire first and then sending my RPC back from client->server, and it didnt resolve my issue. I’ll do some more sanity checking here, if you’re sure is supposed to work from here, then I guess my bandwidth must just be getting choked.

@Rev0verDrive
Thanks for the comprehensive answer. I very much appreciate it. Sounds like I am doing things mostly almost right then, but just the RPC is being dropped, which was making me think I was doing something wrong.

Do you know if there is way to log/confirm if the things are getting dropped due to bandwidth limits? (other than just increasing the limits and seeing if it doesn’t happen anymore?)

when the level has loaded enough

What is the exact criteria for “loaded enough”? Or are you just doing a short delay (because I was doing a short delay, and it wasn’t working, but maybe bandwidth is saturated so maybe my entry point isn’t wrong, but want to confirm!)
You’re doing:
Sever spawn loading pawn
client gets the pawn, OnBeginPlay (?), send RPC back to server saying “loaded enough, spawn my real character with these cosmetics”
Server gets RPC, spawns real character
Client gets real character?

if you mean without being Reliable then just make it Reliable, there are literally few things more important than a player joining and its a one time event. this is literally what Reliable is for :slight_smile:

this is the eternal question isnt it, thats why i use a loadscreen to manage player joining. that way you can have a global system behind it that decides when the game is loaded. I async load most assets so i just have a list of assets i need loaded and wait for them.

delays are never the answer, i guess you could have a looping delay with checks but still very inelegant

1 Like

Off the top of my head in BP no. C++ you can log anything.

I do specific checks to determine if the landscape and other large assets are loaded at the spawn point.

When checks clear I call an event on the controller.
This specific event is where you would pass cosmetics etc up to the GM.

Controller event executes on the server. It calls an event in the GM to spawn and replace the current pawn.

The action of loading the real character class is in itself telling the server the client is ready.


If you want a vid tutorial on the process I can whip one up tomorrow.

1 Like

Thank you. This is info enough and seems like a clean elegant solution! Will give it a shot

1 Like