Enhanced Input System
This page is a work in progress. |
Unreal Engine 5 introduces the Enhanced Input System which assits games in handling user input. Satisfactory extends this system to allow for automatic detection of mod keybinds in the game’s settings menu and automatic integration with the base game’s contexts.
The Unreal Engine documentation provides a good overview of the system, and you should read that page first, but there are a few extra steps required to interface correctly with Satisfactory’s version of the system.
Introduction
The Enhanced Input System differs from Unreal’s previous input system in that it is data-driven. Actions that the player can take are defined in Input Action data assets, and Input Mapping Context data assets group actions into situations with information on how they are triggered.
During gameplay, multiple Input Mapping Contexts are dynamically added or removed to process the player’s input and determine which Input Actions to fire based on actual keyboard and mouse input.
For example, the base game has controls for walking around and driving a train.
Walking forwards and throttling the speed up on a train are generally both bound to the W key,
so how does the game know what to do when the player presses W?
The Enhanced Input System decides by looking at which Mapping Contexts are in play and what their priorities are.
Separate Input Actions exist for walking as a player and throttling trains.
The walking action is included in Mapping Context MC_PlayerMovement
and the train throttle action is included in MC_Trains
.
The MC_Trains
context is only applied to the player when they enter a train and is removed when they exit it.
When the player presses W, the Enhanced Input System checks the contexts in order of priority.
If MC_Trains
is active, the throttle action is fired,
but if MC_PlayerMovement
is active, the walking action is fired instead.
In the real game, there are many more contexts and actions at play, and it could be the case that the player movement context is actually removed while the player is in a vehicle. Regardless, hopefully this example gives you an idea of how the system works.
Organization
The existing structure of the Enhanced Input System lends itself well to
storing Input Action assets in folders with their contexts.
Base-game input actions and contexts are mostly stored in /FactoryGame/Inputs/
and /FactoryGame/Interface/UI/Inputs/
.
You can take inspiration on how your mod should organize its contexts from looking at those folders.
Input Actions
Input Action assets can be created in Blueprint via
Create Advanced Asset
> Input
> Input Action
in a content browser window.
The Unreal documentation explains how to create them in C++.
Note that Input Actions do not have any definition about what key they are bound to - that information is set by the context they are in.
The "Action Description" text will appear to the user when they hover over the binding in the settings menu. "Consume Input" should be set to false unless you have a good reason to set it otherwise, since this means it will prevent any other bindings on this key from taking effect if the relevant Context the Action is in has higher priority.
Standard 'key presses' usually have a Value Type of Digital (bool)
and have Triggers on Pressed
and Released
with a threshold of 0.5
.
Look at the base game’s input actions for other examples.
Input Mapping Contexts
Satisfactory adds additional functionality to Input Mapping Contexts that are used instead of some of Unreal’s fields.
Your Input Mapping Contexts should be of type FGInputMappingContext
and NOT InputMappingContext
.
Note that in order to create one in Blueprint you must use
Create Advanced Asset
> Miscellaneous
> Data Asset
and search for FGInputMappingContext
.
Alternatively, you can copy an existing mapping context and blank it out for your own use,
for example, you can copy one from the base game or from ExampleMod.
The Unreal documentation explains how to create them in C++,
but you need to adapt it to use the aforementioned Satisfactory-specific parent class.
Again, make sure that you are using |
Input Mapping Contexts should have all of the relevant Input Actions provided in the Mapping field, which is also where you are allowed to assign default key bindings for each action. For each Input Action you list, you must:
-
Enable "Is Player Mappable" (unless you don’t want it to be edited by the user, but 99% of the time you do)
-
Under "Player Mappable Options":
-
Provide a "Name", otherwise the bind will not be user editable and attempting to look up its display name will fail.
-
Set a "Display Name", which is the text that will appear to users when they view or search for the action in the settings menu.
-
Note: the "Display Category" field here is ignored by Satisfactory.
Satisfactory adds its own custom fields to Input Mapping Contexts that appear in the "Mapping" category.
-
The "Display Name" is the name of the section heading the Actions will be grouped under in the settings menu. This should usually be your mod’s user friendly name.
-
"Menu Priority" presumably allows for reordering categories, but is
0.0
for all base-game Contexts and has not been tested. -
"Parent Context" is described in detail below.
Once an input action is added to a Context and the Context is properly formatted with a Display Name it will appear in the settings menu. You do not need to register your actions nor contexts anywhere else.
If your mod has relatively few key binds you will probably only have one or two contexts for your mod: one that will be applied when the player is moving about as normal and one for when they are in the user interface.
Parent Context
Parent Contexts are a feature provided by Satisfactory for usage by mods. We can’t add our own Actions to the existing Contexts that are shipped with the base game, but we can instead specify a Parent Context for our own Contexts. When the Context we specified as a parent is applied by the game, our context will also be applied, and vice versa when the parent context is removed.
If you want the context to be available:
-
All the time, even when in interaction widgets such as the inventory, use
MC_PlayerController
. Be careful with this! If you use this context, you should not have Consume Input enabled for the listed actions because it will block other keybinds from working. -
Whenever the player can interact with buildings and their held equipment, use
MC_PlayerActions
-
Whenever the player is in a building interaction widget, use
MC_UserInterfaceBase
-
Whenever the player is in their inventory, use
MC_Window
-
In a special condition, such as when the build gun is open in a certian mode, look at the existing contexts to see which is the best choice
-
In an even more specific condition, then you may wish to use manual mapping context registration instead.
Responding to Input Actions in Code
It is suggested that your code respond to input actions in either an actor (such as a Subsystems), a widget, or a custom actor component on the player character or controller attached via Simple Construction Script (SCS) Hooks.
On some actors, such as Subsystems, you may need to call Player Controller instance > EnableInput for them to process user input.
Blueprint
In order to create the Blueprint event node for responding to an input action, you may have to turn off "Context Sensitive" in the blueprint action selector for it to appear in the search results.
Type the name of the input action to create the Event node for responding to it.
C++
The Unreal documentation explains how to handle responding to Input Actions in C++,
except it assumes we have control over the player controller, which modders do not.
Thankfully Coffee Stain has created a delegate AFGCharacterPlayer::OnPlayerInputInitialized
which mods can bind to.
Each time SetupPlayerInputComponent
is called
the delegate will be called, giving you a chance to register your custom inputs.
Reading Input Action Information
In order to retrieve the name(s) of the key(s) bound to an action for display to the user,
call the FGInputLibrary function Get Input Action Name as Text
on a Player Controller instance passing in the Name given to the action in its Mapping Context.
This will automatically handle multi-key binds and display them in a combined format like Left Alt + Q
.
Note that if the mapping context is not registered at call time you will get back UNKNOWN_KEY()
.
If you need to retrieve the exact key structures involved in an input action,
call the FGInputLibrary function Get Current Mapping for Action
on a Player Controller instance passing in the Name given to the action in its Mapping Context.
Be sure to check the boolean return value for success/failure status.
Manual Mapping Context Registration
The primary method of registering your Contexts is usually via the Parent Context system, however, is is possible to manually manage the registration of your context.
You can get a reference to the EnhancedInputLocalPlayerSubsystem via a Get node on a player controller instance.
From there, you can call AFGPlayerController::SetMappingContextBound
to control when your context is applied.
You should not use Add Mapping Context or Remove Mapping Context because those do not interact with Satisfactory’s parent context system, meaning your contexts cannot be extended as described in the[Parent Context section.
Handling Input in User Interfaces
Sometimes a modded user interface requires extra Actions to be bound while it is active. An example of this is the Workbench UI in the base game, which binds the spacebar to holding down the craft button.
Create a Context and Actions for use when the widget is open.
As long as your modded interface widget extends Widget Usable Base, context management is handled for you.
Simply specify the MC_UserInterfaceBase context and your own custom context
in the widget’s mInputMappingContexts
field
and enable mInputGateDelayOpen
.
An example of this can be found in Widget_InputExample
in the ExampleMod.
If you override the Destruct method in your widget, make sure to call the parent implementation or the widget will not properly unregister the input contexts! |
If your interface does not extend Widget Usable base you will have to
manually manage context registration,
handle your input in a subsystem instead,
or have the context always registered via parent context MC_PlayerController
and decide based on additional conditions whether to handle the input or not.
Debugging
Unfortunately the very useful showdebug enhancedinput
console command
described in the
Unreal documentation
is not available in shipping builds.
However, the command showdebug INPUT
is available and displays a reduced set of information,
such as which mapping contexts are currently bound.