Player ID, Replication & Client Side checking for a turn based game


So I’m making a TCG game similar to Magic: the Gathering or Hearthstone. I have a custom player state, game state, and player controller class. I’m pulling out my hair trying to figure out how to randomize which player goes first, and to allow the player whos turn it is, to advance the game and end their turn. I’ve ended up with some kind of race condition or something.

In my GameState, I have an array containing the “Player Order.” Index 0 represents the first player to go, index 1 represents the 2nd player to go. The int within the array represents the player’s ID (taken from gamestate itself). It uses the “get player state from index” function to search the general player array class and find matching ID’s.

In my player controller, I have some client side checks to see if the “active player ID” is the same as the game states. If it is, then I can call a server function to move the game forward a phase (main phase → combat → end turn for example).

However, sometimes the player controller function fails, and I have mismatched values. I have been printing the values to the screen every time it fails, I often get this result:

On one instance of the client:

Active Player ID:552 (the one we need to progress the game) red text

Current Player ID: 553 (the player controllers) green text

On the other instance of the client:

Active Player ID:553 (the one we need to progress the game) red text

Current Player ID: 552 (the player controllers) green text

Both of these clients cannot progress the game, because the “active player” is not equal to the player attempting to call the function. But the ID’s for both of them are correct on the OTHER client’s information…


Other times it works perfectly as if there was no problem at all. Note that I am testing this using PIE, on a dedicated server with 2 players. And from these, I assumed that my logic for progressing the game was correct.

This is super frustrating as I cannot consistently reproduce this error. It seems like some kind of race condition (or else I don’t fully grasp replication).

Would really appreciate any help on this issue! Thanks.

Where is the SosGameState > Generate Player Order executed on? Is it executed on Server only or do the Clients execute it. That type of code looks like it belongs in GameMode instead of GameState, as it seems like a Server only thing to figure out who should be active.

EDIT: If it’s executed on Client, then both clients could end up shuffling to different states. Just because you try to set Active Player Index on a client, doesn’t mean the server will agree to it and replicate it to everyone else.

EDIT2: The only thing your cilent should be able to do is tell the server they finished their turn. Let the server decide if the active player should switch. So I’d disagree with the idea of having the client check for active player to let the server know what should be done.

Generate Player Order is executed once both players have the boolean “isReady” active. I have this behind a has authority switch so it only executes on the server and not the players.

I have the clients trying to notify the server that they have ended their turn (or advance the state). The thing is that I dont want to spam the server with these “end turn attempts” if the player mashes the space bar during other players turns: that’s why I had the check on the client side. Check if I am the active player first, and if I am, then let me progress the turn.

Hope that makes sense.

Oh hmm. I was expecting something like an RPC Replicating Functions in Blueprints | Unreal Engine Documentation

Just for further debugging, you could consider adding in print logs for OnRep_Notify (Related blueprint doc: Replicating Variables in Blueprints | Unreal Engine Documentation) to see when the clients are being replicated the value or they are even replicated the value at all.
I also noticed that you didn’t seem to be logging out what the server says is the active player, only what the clients are saying. Could you check that also, since its what the server has that’s most important.

Solved the issue. I was stupidly accessing the wrong array which was why the data was incorrect. Derp. Wasn’t an issue with any of the code in here. That’s what happens when you code on a lack of sleep.