Playerstate wrong on clients

The client’s playercontroller has the wrong playerstate all the time. I bind a button to press “e” and print the controller’s playerstate in playercontroller event graph. in 80% of the cases it goes wrong and many times there are duplicates, which means that client 1 and 2 have the same playerstate, they also get playerstate 0 sometimes. I want it to be PC_0=PS_0,PC_1=PS1,PC_2=PS_2. If I try to run via server with button press E, I always get the correct playerstate for the controller.

Have been trying to understand the problem myself for 2 weeks. So I would be grateful if anyone has any advice. I’m about to give up.

Player controllers only exist on the server and the owning client, so clients don’t know of other client’s player controllers

Player states will never be shared between players, and if the “name” of the player state object is the same, that’s irrelevant, and up to replication order, which might not be the same
All replicated objects have unique identifiers which means that it’s guaranteed that they point to the “same” object, and you can rely on this fact, even if the name of the object is not the same between clients

If you are using an online system such as Steam or EOS, Player States will also have a Unique Player ID, that can help you differentiate between the players
In the engine code, when the unique ID is not available, such as in the case of LAN, the IP and Player name are checked to connect a player state to a player

I’m not 100% sure the player state indices are the same on all clients, but at least according to the code comments they should be

Thanks for the answer! Well explained!

Sounds like I need to use unique id in the future then. But to explain a little better: I start the game with 3 players and run as a listen server, have tested all net modes with same results. I want to use playerstate in a widget to hit the right player to change a variable when a button is pressed so that the number of coins changes. But since the client owns the widget, it becomes difficult to change variables in the playerstate if the client does not have the correct playerstate from the start.

Since I have the HUD that shows the number of coins for an individual player, I know that the playstate that is printed is also registered as right playerstate, and coin changes. Coins: Player1=PS 1 coin, Player2: PS 2 coins… It worked very well with this until I started using the widget.

Should I start using unique ID instead, is that the most common way in a multiplayer game?
Do client knows its uniqe ID?
Do you never use playerstate index in online multiplayer games?

I will probably get some answers to this when I start testing myself with unique ID, will have to redo some. But if you have any answers before that, I’m happy. I’ll get back to you how it goes anyway.

Don’t use any Gets that require an index. e.g. Get Player Controller requires an index.
You should be using Get Controller, then cast to the Player controller class.

Get Controller → Cast → Get PlayerState → cast → store reference


Game State stores a copy of all player states in an array [PlayerArray]. All clients have access to GameState, thus the player array. Therefore any client can look at the replicated copy of any players state.

I tried using player id. I can print it and I get the correct player id if I assume the id is the latest number of the 3 players I have, other players have lower numbers and are in order as it is replicated. . Have the HUD display of players id and if you bind this to playerstate_2 (ie player 3) I seem to find the right player in the widget through the ID. But playercontroller and playestate are wrong when I try to print it. This is a success for me and the only thing that is right, however, I don’t understand how this is possible to be found when everything else varies for each round.

But don’t get much out of it as I can’t extract playerstate from it.
What blueprint code is needed for this?

I have no problems store data linked to playerstate, but big problems getting the right playerstate linked to playercontroller in the client’s widget.

I tried in the widget to do as you say but still get the wrong playerstate. When I open the widget on player e.g. 3 (client 2), playerstate 0-2 can be printed completely randomly after every round I test. It means that my HUD is not updated in the correct place as my HUD has fixed positions. The only thing that currently works and is stable is player ID which seems to work in playerstate. But don’t know yet how to fish playerstate out of it.

What do you mean they’re wrong? On a client’s widget, GetOwningPlayer will return that player’s player controller, and the player state of that controller will always be that client’s player state, and this can never be wrong

Depending on when you initialize your UI, it might be possible that the player’s player state has not replicated yet, so you might have to wait, or keep retrying to get the player state from the controller with a delay (Controller → Get Player State → If not valid delay and Get Player State again, until Player State is valid). Under normal circumstances this should be nearly instant. There are ways to streamline this initialization so you ensure that everything you need is available before you show any UI, but that’s another topic

When a player joins the game mode creates a player controller and a player state. A player state reference is added to the game states player array. These typically should be indexed in the array according to join sort order.

In the controller class you should easily be able to get a specific player state via index with the following code.


In the event they are not correctly sorted (never assume they are) you can set a custom join ID in the game mode as the new player joins.

In the GM create a joins int variable. Default it to 0.

In the PlayerState create a CustomPlayerID int var…set it to replicate.

In the Game Mode use Event OnPostLogin to Set the CustomPlayerID and increment the Joins int.

The CustomerPlayerID will be replicated, thus the GameState Player array will have a copy.


In the controller class create a TMap (Int, Your PS class obj ref)

image

New Function…

When the Game has started, all players are loaded, run the function.

image

You can then reference each player by a unique sorted ID integer.

Sorry if I’m unclear, but I think I need to show better what my problem was. Created a simple widget to show the problem.

In PC:

In widget:

When I press “L” on server:
image

When I press “L” on Client 1:
image

When I press “L” on Client 2:
image

Some examples. Sometimes multiple are playerstate0, and sometimes playerstate1. And sometimes in the correct order and sometimes in reverse. But of course server always keeps 0.

If a playerstate is invalid, you only get a zero, right?

Thanks! You gave me some new ideas how to do it too. Have used a similar method to. A little more complicated than necessary. A small snapshot of how I did many things for display in the HUD.

But as I’m losing more and more self-conceit, I tried to do like you and added my previous one to spawn players. Have used this tutorial:
https://www.youtube.com/watch?v=H0JZnWdY0k8

But didn’t get any better results from them. You are welcome to look at my other answer if I am unclear.

If you read what I wrote… Sort order of the Game State Player Array is NOT guaranteed. It’s all dependent on the work load of the thread.

Player 1 can be literally slotted on Index 1, and player 2 on index 0.

Not seeing the issue using the nodes as suggested. Player States are being assigned properly. Referencing it/them is working exactly as it should.

If the player state is invalid the print will not get called

Like I said, the name of the object which is what you’re seeing with the print is not consistent for player states across clients

it doesn’t matter what that name is, and is completely up to replication order, which can be arbitrary
If you want to test, you can call GetPlayerName on the player state, and it should show you the name of the user connected, which should be, in your case, unique and consistent
Name gets assigned by the online subsystem, so for example it would be your steam or epic username, or your PC’s name plus some other identifier in LAN

Don’t complicate things too much, and in the vast majority of the times you can trust the engine is correct.

Player states also have something called PlayerID (which you can get in BP using GetPlayerId), which is a unique number assigned to each player
I’m sure if you print that it will be consistent every time

Also, something that I’ve noticed and is really important, there was a bug with 5.4 that caused the print string function to not return the correct client string, so all of them printed Client 0 (so much for “trust the engine” huh :sweat_smile:). I think this was fixed in one of the hotfixes, so if you haven’t updated your engine, do that if you can. Otherwise, unfortunately you’ll have to find different ways to differentiate between different client debug prints :frowning:

It’s starting to get into my head what you’re saying. Was a little too late to understand. I think I’m starting to understand. Was able to get the playerstate out correctly now. Just need to rework some code so it will be correct in my HUD.

How I got it right:

Many thanks RevOverDrive! I’ll close the thread when I manage to get my HUD to work with your solution

Make sense its not called.

But when you get off track, you start to lose understanding and you start doing things differently. Have read about bugs earlier so you become a bit thoughtful. Luckily I’m running 5.3.2

Everything flowed so well and crashes for a small thing.

I’m thinking I should move on after your and Rev’s response.

Many thanks Zeaf, I will close the thread when I really also see that my HUD is working as intended.