When a client first loads into a multiplayer game, some actors like GameState have not fully replicated yet. So if you try to access the PlayerArray in GameState on the client, you get access violation errors. So I’m wondering what is the best way to detect when the GameState has been fully replicated to the client? Ideally I’d like to have some event called so I can have the client’s PlayerController respond, like update a UI for example. The only way I can think to do it is to have a check constantly running on Tick. I want to avoid doing that as I don’t like using Tick and prefer to use an event driven approach.
Well, multiple ways I’d try to do this. First you can make a multicast GameState event “I’mHere”, in which you can GetPlayerController(0) - CastTo(MyPlayerPC) and call “GStateIsHere” event, and do your thing.
Another idea is when the GameMode fires the OnPostLogin event, you call the RepToClient PlayerController event “ThisYouNeed”, and pass the GameState’s reference. If I guess well, the GameState already exists immediately on the client too, but its reference is not replicated to the client yet, that’s why you get None.
Is it clear this way?
The trouble is that the game state does in fact exist on the client. I believe it exists pretty much immediately. However it isn’t fully replicated from what I can tell. This means that all though you can access the GameState, you can’t access some of its properties right away, like the PlayerArray as it is still None. If I throw a small Delay in then all is fine. But Delay is a super hack that doesn’t fly in the real world.
The point I’m trying to make is that there is really nothing the server to tell the client as the client literally just has to wait for this data to arrive.
The “best” (of all the bad options) I’ve come up with is to run a timer on 0.1 interval checking the PlayerArray. Once it is not None, then the timer kills itself so there is no further overhead. In practice the timer ticks maybe two or three times.
Ahh! A fellow delay-hater! Did you try the first idea? It might be just in time. Especially if you put it in GameState like BeginPlay - Siwtch Has Authority (Remote) - (PlayerController’s)StateIsHere event.
But if you need exact information from the GameState, that you need at the very start, then you can Send those information through an event to the PlayerController after OnPostLogin.
This is how I get MyNumber to the PlayerController very fast at the start (note that MyNumber is set at both the client and the server because normal replication is not fast enough.)
(InitialSetup is called by the GameMode, so it runs only on server)
Did you ever find a good solution to this? I’ve been struggling with it for a while.
Can you specify your case a bit, that why do you need immediately the game state at the client? (BTW my answer still could be the solution.
I have a hud that initializes OnPostLogin, that hud contains player frames for all the connected players (name, health, etc…) The player frams populate their information from each PlayerState, which it grabs from GameState. So if GameState has not yet replicated, it does not show any player frames. Adding delays fixes the issue, but again, that’s a huge hack.
I’ve thought about having a multicast event called in GameState that gets called OnPostLogin, then loops on the client PlayerStates array until it has the same count as the number of players in the game. This again feels like a hack. Ultimately I just need to be notified every time a new PlayerState is added to the array in GameState and has finished replicating to the client.
For what it’s worth, I encountered a similar (same?) issue as the OP, and it took me a while to realize that the GameState was initializing MUCH later at the Client (in CPU time) than at the Server.
So I ended up doing exactly what CrimsomHawk suggested which was to NOTIFY At BeginPlay() of your PlayerState (specifically, the LOCAL one) those other classes in your project that need to know it’s ready.
RepNotify is your friend here.
There are also several overrideable functions in GameStateBase that can be used to notify when replication has completed.
I had the same problem and was able to manage it without delays. From what I learned, player states are one of the last things to be constructed and begin on client side. I used ticks in my custom player state to check each tick if that state was ready to be consumed. Ticks were then disabled once PS was valid. Server side the states were ready in 0 ticks. Client side it took 2 ticks usually when playing via LAN. Not sure if this is the best way but seems to work.