Hello UE4 Community, I need some help working through the flow of a multiplayer game and player instances.
I have created a project that goes like this:
Main Menu goes to Multiplayer Server Browser (All within the same map). When a user creates a new server, or joins a server. The game opens the Lobby map. And when all the players have joined the lobby map, the host hits play and all players are moved into MP_Map. This all works great.
Now I’m having a hard time trying to wrap my head around how to store the player values such as “name”. Because I want this value to be easy accessible from any point or state in the game. So I need to pass this variable to my MainMenu map, to my lobby map, and to my MP_Map. I think this is where I have trouble. I try to store the name in the ‘game instance’ class.
When the MainMenu/Start map opens it checks the saved game slot for a player saved game. It loads that information in (or creates a new one) and saves that data to a variable I have attached to “game instance” class. When the user loads into the Lobby Map, I try to take that variable from my game instance and add it too my player pawn class ‘on construct’ node. And this is how I want to access other players in the game… But this is where things go wrong. It works well on each client by itself meaning that they can see their own player names. But I cannot get the player names of others connected to the game. Infact the game thinks they all have the same name. I’m sure what I’m doing is not the prefered way to do this so I’m hoping maybe someone could point me in the right direction as to how to attach a player name to basically a “controller” that I can access through different states/maps on the game. Does any of this make sense? Thanks.
I did not try game state but I will. More specifically do you mean to store my local player name in the game state instead of game instance? Geez how did I forget about game state! Lets hope that does the trick. I assume game state stays alive between maps loading?
I think it should(I read something about it when I trace code about map changing), but even if it’s not you can still get around that as you can save player name in a config/save(which most games do) and query them when player joins again.
So unfortunately due to an oversight that actually didn’t work out for me. I’m guessing my flow is all wrong but I’m not sure how else to handle this. When I packaged my project and ran it on 2 separate machines the intended results did not happen. Unlike running from the editor.
So when the lobby map loads. It loads it default player class. And on that player class is where I’m trying to assign the ‘player name’ on construct by loading the player save. This way when any of the clients ‘get all actors’ of user class, and iterate them in a loop and grab the player name. But what happens is all the player names are the name of your client and not all the clients/host. So maybe this isn’t the right way to handle this. But otherwise I have no idea how to assign a player id to each connected client then access that value between levels (key part here).
I think, if there are no names assigned, think back on games like say quake1, they can just all be player1 or something similar(if their c_var never changed).
So essentially when you have the default player class, you need to also be albe to check the saved state and apply it upon client start up.
Once this is done, player name can be sent to gamestate where change level should be kept the same.(or doesn’t matter since client already know what their name is, they can always sent again upon level change.)
the flow should be something like this:
1.client start, loads whatever name var, save to a temp playerstate
2.connect(which reloads local lobby level) - ps. at this point I don’t know if playerstate gets destroyed or not.
3.upon post login call a event to owning client, which sends over player name to be saved in player state.
4.when actual level started, you spawn your actual pawn bp with names that are replicated on server.
5.any time you need to show scoreboard, use the gamestate + playerstate(which replicated automatically) and pull info from that.
playerstate actually have a unique id that you can get to identify different players.
Now, the missing part where I’m not entirely sure is what owns playerstate, it seems that either gamemode or gamestate owns it.
And I am not sure if playerstate would survive through level change, but could be easily tested if you implemented it and and change level on server( clients should automatically transferred to that level as well.)
This is good topic and I might actually test it out this weekend and see what actually gets carried over when level changed, or in your case, the pawn is changed, maybe even gamemode(ie. lobby mode and actual game mode. )
So last night I tried this:
From the Lobby GameMode -> Get all actors of player class -> Loop and call an event on that player class (runs on owning client) that sets the Player Name (replicated) variable from Load Game. In game- each client properly see’s his own name (which I couldn’t do before) and the client can also see the host name in the lobby list. But client can’t see other client names and host doesn’t see any client names whatsoever. But I feel like this is the closest I have got so far.
You mention ‘player state’ which I’ve seen referenced a few times in answers and on the forums here but, maybe I’m missing something but I don’t see player state in my game mode settings. Only Hud, Player, Game State, Controller. No player state. Maybe I should mention I’m strictly using blueprints (for now, anyway)
I found out that GameState has a built in ‘Players Array’ but GameState seems to only run on clients. And when I loop and print the players array to console it prints each player twice for some reason. I don’t understand that.
GameMode executes on server. GameState executes on client. So far the only class that seems to ‘stay’ alive between levels is game instance which I may go back and start trying a few things in there.
Sorry most of this is just rambling as I’m not sitting infront of the project right now. I appreciate your tips! I’ll probably report back later this evening when I get a little further along or figure out a solution! Also if you attempt to try this keep me updated
There is a tiny pull down/expand triangle when you edit game mode blueprint where you can specify player state. The reason why you only see yourself and server correct is when you “set name” for the player, it has to be a replicated variable that gets set on server side. As replication only happens one way from server to client. I’ll put a simpler list just to let you know what should be happen.(host would always be correct so I’ll just list the client side)
server starts
server(gamemode) gets PostLogin event(which gives you a player controller), call owning client event to get player name set by client(can be from file or anything that you can retrive.)
on client(Player controller), call run on server event to set names on both owning pawn(if you have over the head text) and playerstate(which I assume sends to gamemode only exist on server).
on server(Player controller), call event on possessed pawn and set replicated float text, call gamemode to set player state names(which should be replicated var as well).
to clarify:
GameMode only exist on server
GameState replicated to everyone, and you should only change it on server. Anything replicated should only be changed on server.
No worry, it’s pretty confusing in the beginning, but once you gets it, it will be easier for you to plan out things.
Welp I stopped for a week to fix a critical bug. And I started trying to figure this out without much luck but I feel like I’m so close. The big issue I have though is trying to load the Player Save from the client to update the host… I have accomplished this by using built in methods… IE the Player array from GameState and the player state. I can use Player State → Player Name and assign it to my Player array in game state and display this in the lobby and each game instance/session displays the proper names. The problem is you cannot set player name from blueprints. But as soon as I try to load my player save, it only loads the player save from the host because I cannot figure out how to load the player save from the client… I’ve tried everything from events that only fire on owning client, ect.ect. I’ve tried so many different things that I cannot even remember what I’ve tried, lol… And apparently nobody else has tried to do this in blueprint yet because I haven’t seen any resources online.
true, the default player name set function isn’t exposed in blueprint, but you can still use any string variable you can think of and make is replicated. Personally I think it’s weird why it’s not exposed, but can’t bother too much about it since it’s just a string anyway.