Accessing game state from client

So I’m trying to use GameState as a class for managing resources. As it is both client and server, I make server-only events in the replicated character, which call functions inside game state. The problem seems to be that, according to the debugger, the functions are being run in the client, and so any functionality I have are also client-only.

My solution will probably be to keep data in GameState while moving functionality to character RPCs, but before I embark on this exhausting rework, I just want to confirm that there is no way to call a server-side function in game state from the client.

Thanks in advance :slight_smile:

2 Likes

Clients can only do “Run on Server” RPC’s from Actors that the Client already own.

The Server owns the GameState therefore you can’t make any use of “Run on Server” events.

The GameState should only be used in conjunction with the GameMode class to replicate variables or make Multicast RPC’s to the clients.
GameMode is used for server internal logic and GameState is used to let the clients see what the server is doing.

You might have the wrong perception of what Replication is.
Replication is when the Server has spawned an Actor and it is “mirrored” onto the Clients.

Clients have no control on replication but they can make “Run on Owner” Events ONLY on the Actors and it’s Components that the Client already is the net-owner of.

If a Client spawns an Actor even if it is replicated nothing happens because the Client can’t Replicate anything. RPC’s also won’t work at all.

If the server already has all the information it needs (which it often does) then it will work fine with replicating everything through the GameState but if the Client needs to make an “Run on Server” event you have several options.

Use the PlayerController, PlayerState or Possessed Character Actor.

You can also let the Server Spawn a new Actor per player and use that. To ensure every player gets an Actor each you can Spawn on BeginPlay of the PlayerController when having Authority (Server side). It is important while spawning this Actor to set the PlayerController as the Owner of the new Actor otherwise “Run on Server” RPC’s won’t work.

Alternatively you can add a replicated Component to any of the Above Actors as it will inherit the ownership from it’s parent Actor.

Note that if you use the PlayerController or Components attached to the PlayerController you will not be able to use Multicast RPC’s or replicate any variables for other clients to receive because the PlayerController replication mode is set to “Only Relevant to Owner”.

8 Likes

Thanks for such a detailed, well thought out reply Garner!

And thanks for filling in some gaps in my understanding.

For anyone facing a similar issue, as I mentioned in my first post, I broke my logic into data and functionality, with the data component attached to the game state and its data-storing variables replicated (and therefore accessible to the client), and the another actor component attached to the character so that server functionality can be run successfully.

1 Like

I am watching this topic to see if I can learn a bit because I am working with Lyra’s custom games modes. So, thank you for this explanation.

It is true game states can be used to update HUD information to all clients? In the case of available resources in the game session, perhaps game state can get all connected players and update their HUDd regularly.

This the video that I am using as descriptive reference for replicated actors. I also followed his complete multiplayer modules and it worked very well.

3 Likes

Yes that should work just fine.

1 Like

GameMode actually has an overridable function PostLogin, which you can use to generate an array of all player controllers connected. You can then keep any variables in the controllers updated in tick. If you don’t need this to happen throughout the game, you could set a bool in the controller ie bHUDActive, which you can set inside the controller and check for inside the GameMode tick mentioned above.

1 Like

Thank you for the detailed explanation. I’ll try that postlogin option.

I appreciated your help.

Don’t forget the super call. Gets me every time :smiley:

1 Like

What does super call means?

If you’re using C++, any virtual function you override from a parent class needs a super call in the cpp definition. If you’re using BP only, don’t worry about it. Just choose PostLogin in the overridable functions list and get stuck in.

1 Like

The GameState should only be used for information that is the same across all users. If the information is unique per player and it should be visible to other players then PlayerState should be used. If the information is only relevant between the server and the client then the PlayerController should be used.

There is generally two ways of handling updating UI. Event based or tick / immediate / polling. Personally I prefer event based as it has a lot less overhead and is easier to debug.

If you need to display Replicated variables then use OnRep rather than RPC’s since RPC’s (even the reliable ones) can be missed.

1 Like

Super is a shorthand for the name of the parent class. This is a Unreal thing but if you know C# it is the same as the base Keyword.

1 Like

Just to tack on to Garner’s response, you can also override OnPossess inside the controller and store a reference wherever you like, whether it be in GameState, GameMode, or other player controllers. More flexible than GameMode’s PostLogin.

1 Like

I would never bother making an array that I now have to manage, but rather use GetPlayerControllerIterator

1 Like

Thanks for clarifying.

That explains one of my issues. I’ve noticed that in my work in progress co-op
Horde mode. All wave numbers were replicated correctly to both host and client players, except wave #2 was missed on client once. Not sure if it happens all the times. I need to run more play tests. I don’t have my computer here, but I guess I used Run on server + multicast.

Thanks for this explanation.

Depends what you want to do with it :slight_smile: Mine is an array of a custom player controller classes so I don’t have to cast every time I need to use its members.

1 Like