Enhanced Input stops working when AIController is used

  • Unreal Engine 5.5.4
  • C++ / 2D adventure game
  • Enhanced Input

If the player pawn is possessed by an AI Controller then enhanced input stops delivering any events to the actual player controller.


Code is here:

Not sure what I can try next.

My options are to try to re-order things to have the binding happen after the possess. Not sure that can work as the function SetupPlayerInputComponent is called by the engine at some early point in the life-cycle of the player character, not controlled by me.

Or to just dump enhanced input and use touch and mouse manually. Probably going to go with this approach tbh.

I’m not familiar with the 2D adventure game.

Is it possible that the mapping context is added to the character instead of the player controller?

1 Like

The InputMappingContext is definitely being added to the character. That’s what I thought was the place you are supposed to do it.

Here in the doc, it says that is the correct place to do it.

Here’s my source code, with the input actually working (as I have rolled back the AI possess):

The doc says you can do it dynamically, so I suppose there’s nothing to stop from doing it later after the AIController has possessed the Player Character.

The main issue I faced with this was the actual binding of the action, which is done in the Player Character’s SetupPlayerInputComponent method. I tried a few ways to call this method after the AI Controller had done it’s possess, but could not get a valid UInputComponent reference.

Yea Ok. So fundamentally one pawn can only be possessed by one controller. When you possess the player pawn with an AI controller the player controller automatically unposseses(?) the pawn. In that case your player controller has no longer any pawn that controls. This is why you can’t get UInputComponent.

Keyboard events propagate from the controller down to the pawn. Check Input Processing Procedure here.

I am not sure what are you trying to achieve here but try to keep the player having a pawn even if it is an ObserverPawn and if you want pawn independent inputs add the mapping context to the Player Controller.

P.S.
I can’t seem to find the line where you actually try to get UInputComponent and receive the error. The code snippet might be relevant :wink:

Got it. This is super helpful. Thanks heaps. Especially that insight that the events are propagating down.

On that page you linked it has this, which looks very promising. Maybe doing it in PawnClientRestart will cause the binding to be done [again] after the possess. I’ll try it out and report back.

Once you have populated an Input Mapping Context, you can add it to the Local Player associated with the Pawn’s Player Controller . Do this by overriding the PawnClientRestart function and adding a code block like this:

// Make sure that we have a valid PlayerController.
 if (APlayerController* PC = Cast<APlayerController>(GetController()))
 {
    // Get the Enhanced Input Local Player Subsystem from the Local Player related to our Player Controller.
    if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PC->GetLocalPlayer()))
    {
        // PawnClientRestart can run more than once in an Actor's lifetime, so start by clearing out any leftover mappings.
        Subsystem->ClearAllMappings();

        // Add each mapping context, along with their priority values. Higher values take priority over lower values.
        Subsystem->AddMappingContext(MyInputMappingContext, MyInt32Priority);
    }
 }

Using PawnClientRestart does help somewhat because with that change the EnhancedInput system is now in effect in the player character. Yay!

That has enabled me to narrow it down to one line of code. Predictably, its when the AIController possessed the player character.

NO POSSESS

Without the call to possess, my input bindings work and I get a call to the HandlePointAndClickInput function where I show a debug text on screen WalkToLocation. So it gets the location, but I don’t have an AIController to walk the character over the nav mesh. Ba-bow.

WITH POSSESS

Current situation (as checked into Github) is that when this line of code runs, the binding to the input action stops working:

	AdventureAIController->Possess(PlayerCharacter);

This is from the tutorial. (done in blueprints)

And the Enhanced input is there, its firing and I can see that from the ShowDebug EnhancedInput that I’m running from the console (the yellow text) but its not firing the binding to HandlePointAndClickInput any more.

I’m following this tutorial here:

and translating into C++ as I go. I can’t understand Blueprints - too much spaghetti.

What I don’t understand is the lifecycle of these things. This is a screenshot of my debug trace. Why is there no PawnRestartClient when the possess happens?

The first call to AAdventureAIController::OnPossess happens because the Class Defaults for the character are used to instantiate the AI controller into the scene:

Without that there’s no AI controller. But the hover text for Auto Possess AI says

…which seems to imply that is should be possessed? Which implication is shored up by the OnPossess debug output.

So why the different behaviour when I call this line of code?

As I previously stated - you wont be able to directly control a pawn that is possessed by someone else. You should either:

  1. Move all input handling in the controller and give some kind of “orders” to the character, that are later executed by the AI.
  2. Make an observer pawn (the incorporeal camera) for the player and put the input handling there. (again with some kind of orders)
  3. Don’t use AI controller at all. The player controllers are supposed to represent “network connections”, AI controllers are supposed to replace players and mimic their behavior (like bots in multiplayer game) You don’t need it anyway.

Take your time and reconsider your approach towards your character control. Don’t be afraid to use BPs if nothing else, they don’t need compiling. :wink:

1 Like

OK, I have fixed the issue and I now have:

  • Enhanced Input working
  • AI control of the player character

Credit is due to @dZh0 for the bones of the solution. Taking that knowledge that if the AI controller was possessing the Pawn then it would not receive Enhanced Inputs (or any inputs actually) I realised that I needed to have the input and AI on separate pawns.

Solution:

  • Create a separate APawn subclass which I called Puck
  • Either move the Input to Puck or move the AI to Puck.

The latter approach would have meant that I would have had to do a messy hack inside Tick to match the position of the APlayerCharacter to the Puck.

So I added the Enhanced input binding to the Puck class. Some details:

  • Create a C++ class Puck inheriting from APawn
    • In Puck.h create UPROPERTY slots for the InputMappingContext and InputAction:
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Inputs)
	UInputAction* PointAndClickInput = nullptr;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Inputs)
	UInputMappingContext* InputMappingContext = nullptr;
  • In Puck.cpp use PawnClientRestart to bind the InputMappingContext

    • And SetupPlayerInputComponent to bind the PointAndClickInput
  • Create Blueprint class from Puck

  • In the BP_Puck blueprint class defaults:

    • Set Pawn > Auto Possess Player to Player 0
    • Set the InputAction and InputMappingContext

I won’t detail it here but I forward the PointAndClickInput fired binding to the controller via a delegate binding, which the main player controller subscribes to immediately after it spawns the Puck into the scene.

I would mark @dZh0 post above as a solution, but it seems I’ve not marked my original post as a question. Thanks for the the above though, as with those insights I’ve got a fix working.

1 Like