I’ve set up a HUD that is supposed to be added to the viewport as soon as the game starts which right now is immediately after the project is run. For the server, everything works great. This is my player controller event graph
The elements in the HUD look to display variables that exist on the pawn. But when a client connects, it seems to take a while for the pawn to actually be spawned. By “a while”, I simply mean the pawn does not yet exist when this is executed which is why I have the “switch has authority” in there, because if I try to run it for the client too I get flooded with errors.
Unfortunately, I don’t see a good way to handle this. A few months ago I was researching a similar issue and someone referenced a function available in the gamemode called “OnPostLogin” which I thought helped somehow but now I don’t recall what it was supposed to do. I thought it might mean “The client has finished its initialization and has a pawn”, so I tried the following:
OnPostLogin is called when the Client has a valid PlayerController.
This is not about the PlayerPawn.
Your SwitchHasAuthority completely blocks off the Client, since you only call this on the Server.
What you need to do, is calling it as Remote AND* Authority*, but as Authority, you need to make sure it’s the Server’s PlayerController.
Clients only have one PlayerController anyway. You can do that by simply using the function IsLocalPlayerController + a branch.
Another way would be using the OnPostLogin Event and using a “RunOnOwningClient” RPC on the PlayerController.
Oh, they are in the pawn, not in the controller.
Luckily you can easily forward from your pawns to your controller using some interface or casting approach.
This doesn’t solve anything from the remote client perspective though. The pawn is still not valid at the time that this runs so every HUD element that initializes by trying to get the player pawn causes errors. I could potentially rectify this by doing a EventBeginPlay on the player pawn to initialize the HUD elements but that’s a bit of a backwards way to go about it I think. Overall, it might be the only choice if there’s no way to detect a valid pawn.
If you need the Pawn Reference inside of the HUD Widget to be valid, yoi either spawn the HUD in the Pawn, like you said, or, which is better, simply use ‘IsValid’ on the Pawn Reference and only use the reference if it’s Valid.
But that leads me back to the same problem of needing to essentially running a loop on Pawn–>IsValid and every time I do that it tells me it’s an infinite loop.
So this is pretty much what shows up in each of my HUD elements
The editor ends telling me it’s an infinite loop which is incorrect but I guess it runs through enough iterations that it triggers it.
I was able to hack together some awful script that used the Event Tick to check over and over if the GUI had been initialized and if it didn’t keep trying. This got around the infinite loop error but it’s SO MESSY. Plus I like to avoid Event Tick if I can.
This is why I was looking for some kind of event that would tell me exactly when a pawn exists.
Well, if you need the Pawn on Construct, then you need the Pawn to initialize the HUD creation.
So use the Pawns BeginPlay. But that doesn’t solve the death of a Pawn. If you happen to destroy him, the reference will be NULL again.
So you need to fill that variable when the Player gets created.
You could create a reference Variable in the HUD and create the HUD when the PlayerController is ready.
Then, when the Pawn gets created/possessed, you use its BeginPlay to tell the PlayerController to fill the Variable in the HUD.
Or you just get the HUD reference and fill it yourself from inside of the Pawns BeginPlay. Doesn’t matter.
In the HUD you just use an IsValid on the Reference for your bindings. So you don’t get Accessed None errors until the Player gets spawned.
It’s strange because I feel like this should be a fairly common thing every person who creates a networked game with UMG needs to deal with and it just feels so … messy!
Ok, so the Player Controller spawns the GUI, but I’ll need to remove the “Event Construct” nodes since the references wont be available then.
In the Pawn, I should use a “Get Controller” to get a reference to my Player Controller (that works, right?) and inform it that the Pawn is ready.
From there, I get each HUD element and call an initialize function to set up the references for the Pawn.
And in the meantime, the HUD elements will check for the Pawn’s validity before attempting to access it.
I’ll give this a try tonight. Thanks for your responses.
So I tried this out. So far … not good. Then I read through your document - a few good things in there I didn’t know! Will be referencing it in the future. Unfortunately, right now it doesn’t seem to help me.
I currently have this on my Pawn
Just as a test. I would have expected this to be called 4 times, twice for the server and twice for the client and for each pair there should be a “I am locally controlled” and a “I am NOT locally controlled”. Instead…
So the client is always returning false for “Is Locally Controlled”. I did some research and some people suggested that when “Event BeginPlay” is called on the pawn, this is not yet set up internally. To test this, I added a 2 second delay immediately after the Event BeginPlay. The result…
So it would seem that even in “Event BeginPlay”, the pawn isn’t yet fully set up. So where can I actually call this stuff when I can be sure that things are actually done loading? Because I’m not going to just put a 2 second delay in and call it a “solution”. I feel like this is something everyone has had to deal with so why does it seem like I’m the only one struggling with it?
I would simply think your Pawn isn’t possessed when the BeginPlay gets called. So the “IsLocallyControlled” will return false, because there is no Controller yet.
So what’s the right way to do this? The pawn doesnt exist when the controller is created, the pawn isn’t possessed when it is created … how can I ensure this is ready? This is so frustrating.
This is the source of an absolutely massive amount of frustration. And it’s not even like I’m doing something crazy - this is something literally every single person who uses UMG with networking needs to deal with. Why does it seem like no one knows what’s going on?
The creation of the HUD isn’t the issue. Right now I’m creating it on the controller. The problem is the HUD relies on variables from the Pawn and trying to get the controller and pawn in sync is apparently a MASSIVE headache. I’m losing sleep over this. Seriously. I just want to continue with this project and I’m hung up on such a stupid part.
Edit: Sorry if I’m kinda coming off as snippy. I’m very upset
OK. I think I found another way to go about this. I didn’t think I’d have to do this but now that I’ve done it this way… it makes more sense.
I focused primarily on the GameMode. I set the default pawn to be null.
In the GameMode I used the Event OnPostLogin to spawn an actor of my character pawn. I then cast the “new player” pin to my player controller and assigned to it the spawned pawn.
Then I used the pin from the spawned pawn to assign my reference to the player controller.
Then I told the controller to possess the pawn and initialize the HUD. Seems to be working so far.
Well yeah, using the OnPostLogin is a valid solution. I always spawn my Pawns by hand instead of using the GameMode. Just to have more control about it.
“OnPostLogin”->“Spawn Pawn and Possess Server Side”->“RunOnOwningClient RPC to ‘NewPlayer’ PlayerController that tells the Client to Spawn the HUD”.
Other idea would be using the “OnPossessed” Events of the Pawn Class. Though that might only run on the Server, but you could do a Client RPC again.
This is exactly what I tried last night. In the controller, I create the HUD widget and save off a reference to it. For some reason on the client the created HUD widget would not return a valid reference. It’s like it couldn’t create it for the client for some reason. Just to be clear we’re talking about the same process here…
In GameMode:
[OnPostLogin] –> [Authority? Needed here?] –> [Cast “New Player” to MyPlayerController] –> [Spawn MyCharacter Actor] –> [Save MyCharacter reference in MyPlayerController] –> [Save MyPlayerController reference in MyCharacter] –> [MyPlayerController possess MyCharacter] –> [Call “InitializeHud” in MyPlayerController]
In MyPlayerController:
[InitializeHUD (Run On Owning Client)] –> [Create HUD Widget] –> [Save HUD reference]
I’m getting a little confused here in terms of variable replication as well. I’m not good at keeping a lot in my brain at the same time so trying to keep in mind who knows what when for each actor doesn’t work very well. In GameMode, do I need to specify authority for the OnPostLogin? Your document states that the GameMode only exists on the server so I don’t think Authority should be needed there. I’m pretty sure I will need to have the MyCharacter reference in MyPlayerController replicated though. If the GameMode is setting that reference on the server and the HUD (which only exists on the client) needs to access it, I will need to replicate it. I don’t think I need to replicate the MyPlayerController reference on MyCharacter though.
One thing that’s been confusing me too is the methods of obtaining a player controller and pawn. On page 39 of your document you mention the use of “GetPlayerController(0)” which I was previously told never to use in a multiplayer environment. But your document seems to indicate that as long as it’s not being run on a dedicated server, it will return the player controller being used for that client (or listen server “client”).
So I’m not sure what the best practice is here. In my GameMode, I have the absolute correct PlayerController and Character for each connecting player. I tell the controller who the player is and vice versa. Now, in the HUD I will also need to get a reference to MyCharacter. Should I go about this by referencing the PlayerController’s reference? Or should I look to do a “GetPlayerController”->“Get Controlled Pawn”? It should give me the same reference either way but I’m almost tempted to say the first method is better because it ensures consistency. On the other hand, if something goes wrong with that reference, everything will break since it relies on it. Although I guess in that case the real problem is the reference not being available.
GameMode only exists on the Server, ergo no Authority Check needed.
Possessing should give the Controller, on Server and Client side, the “ControlledPawn”, so you don’t need to save it.
From the Pawn side, you can do “GetController”, which should also work on Clients.
To get the correct Client Controller on a Client, you just need GetPlayerController0. Clients only have their own, so that’s fine.
You could also call “GetController” on the Pawn, but if the Pawn isn’t controlled, that will be null. GetPlayerController0 will give you the correct
PlayerController as long as its up and valid.
So normally, there is no need to replicate Pawn/Controller references.
You could check out my “Ballbump” Game. I think I got some HUD spawning when a new player joins. Maybe that helps:
I confirmed the GameMode code is executed once for the server and once for the client. But the InitializeHUD custom event that is set to run on owning client doesn’t run for the client. Is it possible that the client does not own its own player controller? I don’t know how I would fix it if it was.
I’m downloading the ball bump project now to take a look at how that’s setup.
Edit: Ok … so turns out I needed to make the InitializeHUD event reliable. I guess that makes sense. I’m not sure why it was consistently not working when it wasn’t ticked off though. The HUD elements aren’t working quite yet but at least that code is executing. One step closer.
Edit2: GetControlledPawn in my HUD isn’t returning a valid value on the client. I added a .2 second delay in my controller before it sets up the client’s HUD and that seemed to be long enough to allow the value to propagate. I don’t like that as a solution but I think it’s the best I’m gonna get for now.
Edit3: And… everything works! I did have one more hiccup. In my InitializeHUD that was running only on the owning client, I was saving a reference to my HUD. But, since it runs only on the owning client, the server doesn’t set that reference. I had code in place where the server would update a value and tell the HUD to refresh which I needed to change into a “Run on owning client” RPC before getting the HUD reference. I could just have the server save the HUD reference but I don’t really need to.
As of right now, everything is working just as it should. All my implemented features are functional. Time to make some more and break everything
Thank you so much for your help on this. It’s frustrating coming home after a long day of work and trying to relax with a project just to be stopped over and over. It makes my little free time much less fulfilling.