How do I get Enhanced Input Local Player Subsystem without accessing Player Controller in C++?

Hello,
I’ve been searching for some time and seen quite a lot of topics about how to get UEnhancedInputLocalPlayerSubsystem, but they all seem to involve PlayerController in some way (or at least getting the current UWorld).
Now, I might be totally misunderstanding something, but this is what I’ve got and what I’m planning to do.
I am making a main menu where the player will be able to change key mappings. I’ve done this in BP first, but now I want to do it in C++.
In BP it was more or less straightforward: simply get Enhanced Input Local Player Subsystem and then do the remapping there - there was no need to reference any World or LocalPlayer.
In c++ however, in order to get UEnhancedInputLocalPlayerSubsystem, all the solutions that I’ve seen require a reference to the ULocalPlayer, which in turn requires referencing a UWorld.

Now, in C++ file (UMyGameUserSettings.h/cpp - derived from UGameUserSettings) I don’t have any reference to the LocalPlayer or any World - these are just user settings, which are supposed to work globally in any world, I really don’t get it. Even if I wanted to, how am I supposed to get UWorld or LocalPlayer in UserSettings?

Hello!
Firstly, I want to stress that your title mentions the “Player Controller”, but as you correctly point out in your post’s body, it’s actually from the “Local Player” that you can get the UEnhancedInputLocalPlayerSubsystem.

As its name indicates, it’s a child class of ULocalPlayerSubsystem.

Next: The LocalPlayer is not tied to a specific PlayerController, it’s just that for most use cases people are fine with accessing it this way, I guess..

And it’s not tied to the world either!

For instance, quickly looking at UE’s source code, the Game Instance also contains a reference to the local players, and since the game instance is a singleton (that persists between level transitions), you could absolutely access it from your settings class, or from anywhere else.

Example code:
EDIT: Do not use, it’s unfortunately not reusable. The TL;DR is use a GameInstanceSubsystem or a LocalPlayerSubsystem, or plug into a lifecycle function from a custom LocalPlayer or PlayerController class.

ULocalPlayer* NewLocalPlayer = GetGameInstance().GetLocalPlayerByIndex(LocalUserNum);

@Altrue thanks for the suggestion.
The problem is that my IDE (Rider) says GetGameInstance() is ‘unresolved symbol’.
It seems there was a missing GetWorld() in front:

ULocalPlayer* NewLocalPlayer = GetWorld()->GetGameInstance()->GetLocalPlayerByIndex(0);

But now the problem is that no World is found (I made some checks and GetWorld() is a nullptr). Actually, this would be a bit weird that I needed a World to get a GameInstance (which shouldn’t be tied to any World, I guess) - your solution seemed sensible, but GetGameInstance() on its own (without GetWorld() ) isn’t recognized.

My apologies, I took a random example from SocialManager.cpp (from the OnlineFramework), and they do in fact implement their own GetGameInstance function, so this wasn’t a good example on its own.

Anyway, since the question turns out to not be as trivial as I expected, it’s time to take a step back and do something that I should have done from the get go, which is: Are you asking the right question?

See.. The thing with architectural issues for frameworks as experienced as UE is, when you’re encountering weird difficulties and it feels like the engine is fighting you on this.. It’s often because you’re accidentally pushing against inevitable constraints.

For instance, it doesn’t make sense to worry about accessing the EnhancedInputSubsystem for a “main menu”, if you don’t have a way to display that main menu. You won’t be able to push the widgets to it, if you don’t have a reference to the viewport. And which class represents the ui?.. AHUD! Which is a responsibility of the PlayerController.

So really, by trying to go around the Player Controller.. All you’re doing is taking the risk of accessing the game instance too early.

Rather, you should make sure that your “main menu” input settings are read in a location that ensures that everything is ready for you. For instance, inside a PlayerController virtual function like PostInitializeComponents() (which can spawn the default hud class, so you know it’s good for that sort of stuff if you wait until after the Super::PostInitializeComponents())

Or inside a child class of AHUD itself. This way, you can have multiple HUD subclasses to swap between different UIs.. Some games do it this way.

Or, perhaps even better, read the settings from inside a child class of the LocalPlayer itself! After all, EPIC is clearly telling us with the EnhancedInput subsystem, that it’s a business for the LocalPlayer.. So why not lean into it, and have your own code reside in an override of ULocalPlayer::PlayerAdded?

..And if you really want to know how to access the GameInstance without going through the world:

First option: Create your own GameInstanceSubsystem. From there you can easily get a reference to the GameInstance, and you know for a fact that such a subsystem is spawned when the GameInstance is ready.. However, there is no guarantee that you won’t be too early to get a reference to the LocalPlayer!

Second option: Use GEngine. There are various functions there to get the LocalPlayer from weird references, like using a UPendingNetGame or a UGameViewportClient.. Pretty unorthodox way to go about it though. If you manage to get a hold of the WorldList, you can iterate on it (outside of the editor it should only have one or two UWorld instances in it, all valid) and find the reference to the GameInstance that they share.. But again, you’re fighting the UE framework by doing this, which is usually a red flag that you’re doing things out-of-order and therefore may run into references that are not yet ready.

Ok, your points about fighting the engine seem sensible. The problem sort of is that I simply wanted to separate the Settings (specifically key mappings, here) from everything else. Sure, I will need those settings when I have the UI (main menu, etc.), but I wanted to have the logic behind it separated into another class, where I don’t have access to UI elements, World, etc., in order to have my Menu class less cluttered and dealing with UI things only.

The second thing is, I might need those settings (key mappings) somewhere else as well, which is again a good reason to have it separated. Well, if it can’t be done, I’ll put it in the Player Controller probably, or HUD, but I still think my points make sense.

When it comes to your suggested solutions, the first one, with the custom GameInstanceSubsystem seems sensible. But won’t I have to face the same problems anyway (like not being able to access a World)?

You can have the logic be separated, but you will have to trigger some kind of initialization function when you finally get a reference to your local player. (In order to store the reference to the subsystem & start working on it) So there is still some level of dependency initially, but afterwards you’re in the clear.

I am absolutely NOT saying that your point doesn’t make sense, on paper it’s a sensible demand since there is no reason that the keybinds would absolutely need other instances, since they are merely settings…

..Which makes me realise something! Maybe you could try and parse the keybinding file directly, instead of waiting for the input subsystem.. That could be an option if the format isn’t too complicated.

About the GameInstanceSubsystem, you don’t actually need a world, right? If I understand correctly, you need a reference to the EnhancedInputLocalPlayerSubsystem, which “merely” requires a reference to the LocalPlayer.. Which the GameInstance creates and stores, so that should be fine.. But as stipulated above, there is still some risk of querying the GameInstance too early when the LocalPlayer isn’t instanced yet. I don’t know how likely this risk actually is.