Download

GetController() returns nullptr while GetPlayerController() works properly

I’m writing an ACharacter derived class.

Calling GetController() in either BeginPlay() or overidden EndPlay() methods returns a nullptr, while calling GetWorld()->GetFirstPlayerController() properly returns the controller of my character.

GetController() works ok in all other methods called during the life of my character.

Why can’t I simply get my pawn’s controller using GetController() if APlayerController is a child of AController? Isn’t it true that an upcasted APlayerController will give me the AController possessing my character?

Makes perfect sense. Your Character doesn’t have a Controller at Character::BeginPlay, you can only get your Characters Controller after OnPossessed(). When you get Endplay() the Character most likely has been Unpossessed, so no Controller there either.
“GetWorld()->GetFirstPlayerController()” is giving you the login Controller, this Controller may or may not have a Character possessed, depends on when you call it.

So the controller I get from GetWorld()->GetFirstPlayerController() and GetController() is not the same object? Does that mean my character is being possessed by 2 controllers at the same time? If so, what is the difference between the login Controller and the Controller I’m receiving from GetController()?

I assume you are using a 1P/3P standard FPS template for your project, some things are handled automatically and you get some initial setup done. When you start(login) you get a PlayerController and a PlayerState object, at this point there is no Character but as the PlayerController(child of Controller) handles the UI you can do login widget etc.
At some point the Gamemode spawns your Character and runs BeginPlay, again you have no Controller set here yet. Soon after the Character(Pawn) is possessed by your PlayerController and you can access it with GetController().

So for a standalone game you have one Controller that is a PlayerController but if you try to get it from inside the Character you need to do that after the Character is possessed, only then will the Character have the Controller property set.

Everything is perfectly clear to me now. Thank you!

@FrostyElkArne

Great posts, thanks for sharing. So summing up… Even though Player-Controller is a child of Controller (and so is non-null at login etc), Controller can still be null from the POV of Character, unless Character is Possessed… Makes sense… But when you’re coding its easy to assume that Possession has already taken place, leading to timing glitches. I’m dealing with one right now where sometimes Possess isn’t done executing on Server. So critical setup code from the Client is failing silently, as the Client doesn’t OWN the Pawn / Character actor yet, so Run-On-Server requests automatically get rejected… Interesting… Adding a test using the info here will help…

If you have time, could you also clarify these please, as the docs don’t really help. Thanks in advance

IsLocalController vs IsLocalPlayerController vs IsLocallyControlled

The documentation is mostly a collection of header comments, better is to actually take some time to read the engine code for the functions. As you get into networking/multiplayer with controllers things get even more complex. The best networking documentation i know is this one : Multiplayer Network Compendium – Cedric Neukirchen

No worries… eXi’s doc is popular. But its more a quick reference guide than something that can help you with specific questions.
I plan to dive into the source in the next year or two. But to be honest I’m a bit reluctant as C++ always eats into precious dev time.

IsLocalController and IsLocalPlayerController do the same thing when the target is a PlayerController but if it is an AiController then IsLocalPlayerController always returns false.

IsLocallyControlled is used on Possessed pawns and it simply calls IsLocalController. If Un-possessed it always returns false.