The GameInstance on server is not the same as the GameInstance on client.
They might be of the same class, with same variables, but they do not share memory (=variables values).
Collision has to be handled on server-side, and should also be handled properly on client-sides for smoothness. Thus you have to synchronize (replicate) the variables you want. Using “Run on server” events is the right idea. But not in GameInstance.
GameInstance cannot replicate. Each machine has its own, local, gameinstance and you cannot use replicated variables or functions (RPCs) on them.
Furthermore, there is only one GameInstance on server, for all the players, so it wouldn’t be practical for your use-case. How would you handle if PlayerA and PlayerB can access different areas, but there’s only one game instance on server.
Your best place for this kind of variables is probably the PlayerState. Each player has a player state, on server, which replicates to every client. It’s the class where everybody knows about everybody, where you have variables like the “player name” and “score” so you can see everyone in a leaderboard (for example). As such it would make sense to also put the level/rank there.
So now let’s say you have custom playerstate class with this “Level” variable, and you need to populate it. That’s where a RunOnServer event can come into play.
This is roughly what happens when player joins a server :
- PlayerA connects to server
- PlayerStateA is created (on server)
- All world information is replicated from server to PlayerA (including PlayerStateA)
- PlayerStateA is created (on client) using replicated information
So what you can do is :
- Wait for the player state to be created on client
- Grab the Level from client’s GameInstance
- Send it to server via RPC (Run on server event)
- Set the value on server
- Let the value replicate automatically to all clients
So, something like this (for a naive approach)
Then, whenever you need to test collision, grab the player state of the colliding player and check what you want.
Do note however that this approach is not really viable if your multiplayer needs to be somewhat secure. You cannot trust the client with whatever data (eg. level/rank) he sends to the server.
For proper security the server should retrieve player’s level directly from the database and assign it to the player state. No client-to-server RPC required here. However to implement it can be a bit tedious.
OSS (online subsystems) are supposedly designed to facilitate this sort of mechanism, where the player logs in via OSS, then connects to server via OSS, then server also gets player information via OSS, and all this is abstracted through interfaces which you can either implement or use plugins for. You might want to delve into this rabbit hole.
If not, you can also try to wrap up something yourself.
Clearly you already have a login server and a database.
What you can do is something like this :
-
When player logs in to retrieve his level, generate a token (on the login server), and store it to associate the token with this player. Send the token to the player
-
On the client, store the token (along with the level) in GameInstance
-
In the PlayerState graph above, instead of sending Level via RPC, send the token instead
-
On gameserver-side, contact the login server with the token, and retrieve the true player level
This way the player cannot cheat by simply sending “level=99” with a forged RPC.
Of course there are many more concerns when it comes to security/stability, which is why a fully fledged and tested OSS implementation is probably recommended, but at least I hope you get the main idea.