Registering keybinds
Mycopunk mods should register controls with UnityEngine.InputSystem. Do not poll the legacy API with calls such as Input.GetKeyDown in Update. An InputAction handles keyboard, mouse, and controller bindings through the same API and only calls your code when the action is performed.
Reference the Input System
Add a reference to the copy of Unity.InputSystem.dll shipped with the game:
<Reference Include="Unity.InputSystem">
<HintPath>C:\path\to\Mycopunk\Mycopunk_Data\Managed\Unity.InputSystem.dll</HintPath>
</Reference>Replace the example with the path to your Mycopunk installation, just as you did for Assembly-CSharp.dll. Do not copy Unity.InputSystem.dll into the plugin folder or include it in a release.
Add this import to the plugin class:
using UnityEngine.InputSystem;One keyboard binding
Create an action map and register an F9 binding like this:
private InputActionMap _controls = null!;
private InputAction _toggleAction = null!;
private void Awake()
{
_controls = new InputActionMap("MyModControls");
_toggleAction = _controls.AddAction(
"toggleMod",
binding: "<Keyboard>/f9"
);
_toggleAction.performed += OnTogglePerformed;
_controls.Enable();
}
private static void OnTogglePerformed(InputAction.CallbackContext _)
{
ToggleMod();
}The binding path has two parts: <Keyboard> selects the device layout and /f9 selects its F9 control. performed runs once when the button press activates the action, so this does not need an Update method.
Multiple actions and controller support
One action can have several bindings. They are alternatives, so any one of them can perform the action. This example registers two actions with keyboard and controller defaults:
private InputActionMap _controls = null!;
private InputAction _toggleHudAction = null!;
private InputAction _nextModeAction = null!;
private void Awake()
{
_controls = new InputActionMap("MyModControls");
_toggleHudAction = _controls.AddAction(
"toggleHud",
InputActionType.Button
);
_toggleHudAction.AddBinding("<Keyboard>/f8");
_toggleHudAction.AddBinding("<Gamepad>/selectButton");
_nextModeAction = _controls.AddAction(
"nextMode",
InputActionType.Button
);
_nextModeAction.AddBinding("<Keyboard>/f9");
_nextModeAction.AddBinding("<Gamepad>/rightShoulder");
_toggleHudAction.performed += OnToggleHud;
_nextModeAction.performed += OnNextMode;
_controls.Enable();
}
private static void OnToggleHud(InputAction.CallbackContext _)
{
Logger.LogInfo("Toggle HUD pressed");
// Toggle your HUD here.
}
private static void OnNextMode(InputAction.CallbackContext _)
{
Logger.LogInfo("Next mode pressed");
// Select the next mode here.
}<Gamepad>/selectButton is the View or Share-style button. <Gamepad>/rightShoulder is the right bumper. These generic paths work across controller brands supported by the Input System.
Some other useful paths are:
<Keyboard>/space
<Keyboard>/leftShift
<Mouse>/middleButton
<Gamepad>/buttonSouth
<Gamepad>/leftStickPress
<Gamepad>/startButtonThere is no single fixed list of every possible binding path because the Input System supports additional device layouts. Unity's device pages list the standard control names:
Turn a listed control name into a binding by adding its device layout. For example, the keyboard control escape becomes <Keyboard>/escape, and the gamepad control leftTrigger becomes <Gamepad>/leftTrigger.
Configurable bindings
Hard-coded defaults are fine for a small test, but released mods should let users change bindings. Binding paths can be stored in the BepInEx configuration:
string keyboardBinding = Config.Bind(
"Keybinds",
"ToggleHudKeyboard",
"<Keyboard>/f8",
"Keyboard binding used to toggle the HUD."
).Value;
string gamepadBinding = Config.Bind(
"Keybinds",
"ToggleHudGamepad",
"<Gamepad>/selectButton",
"Controller binding used to toggle the HUD."
).Value;
_toggleHudAction.AddBinding(keyboardBinding);
_toggleHudAction.AddBinding(gamepadBinding);The user can edit these paths in the mod's .cfg file while the game is closed. The example reads them during Awake, so changes take effect the next time the game starts.
Clean up the actions
Unsubscribe and dispose of the action map when the plugin is destroyed:
private void OnDestroy()
{
_toggleHudAction.performed -= OnToggleHud;
_nextModeAction.performed -= OnNextMode;
_controls.Disable();
_controls.Dispose();
}Disabling the map stops new callbacks. Removing the event handlers and disposing of the map prevents old plugin instances from retaining input callbacks.
Things to check
- Give the action map and actions names specific to your mod.
- Attach callbacks before enabling the map.
- Pick defaults that do not overlap with common game controls.
- Ignore input when your feature should not work, such as while the player is typing or when the required game object does not exist.