LethalCompany InputUtils
Utilities for creating InputActions and having them be accessible in game
Date uploaded | 11 months ago |
Version | 0.4.3 |
Download link | Rune580-LethalCompany_InputUtils-0.4.3.zip |
Downloads | 613666 |
Dependency string | Rune580-LethalCompany_InputUtils-0.4.3 |
This mod requires the following mods to function
BepInEx-BepInExPack
BepInEx pack for Mono Unity games. Preconfigured and ready to use.
Preferred version: 5.4.2100README
LethalCompany InputUtils
Utilities for creating InputActions and having them be accessible in-game. InputActions created through this mod are accessible in-game via the keybinds menu added in update v45.
For feature requests or issues head over to my repo
General Users
This mod is just a dependency for other mods, it doesn't add content, but it allows mods to add keybinds.
Where are my bind overrides stored?
Depends on the version of InputUtils:
- >= 0.4.1
BepInEx/config/controls
- <= 0.4.0
BepInEx/controls
Recommended Install
Use a Mod manager. I won't provide support if a mod manager wasn't used, a mod manager makes it far easier to debug issues since users can just share a modpack code.
Developer Quick-Start
This Api/Mod is still in beta, please keep in mind that stuff may change. Feedback is appreciated.
Download the latest release from either the Thunderstore or the Releases. Extract the zip and add a reference to the dll file of the mod in Visual Studio or Rider.
Initializing Your Binds
- Create a subclass of
LcInputActions
- An instance of this class will contain all
InputAction
s your mod wishes to bind inputs for - Name the class appropriately
- An instance of this class will contain all
- Create InputActions using Attributes and/or at Runtime
public class MyExampleInputClass : LcInputActions
{
[InputAction("<Keyboard>/g", Name = "Explode")]
public InputAction ExplodeKey { get; set; }
[InputAction("<Keyboard>/h", Name = "Another")]
public InputAction AnotherKey { get; set; }
}
Using Attributes
- Create instance properties for all desired
InputActions
- Annotate the instance properties with the
[InputAction(...)]
annotation
[!IMPORTANT]
For actions to be registered to the API, Properties MUST be annotated with[InputAction(...)]
[InputAction("YourkbmPath", Name = "", GamepadPath = "", KbmInteractions = "", GamepadInteractions = "", ActionID = "", ActionType = InputActionType...)]
Required Parameters
kbmPath
: The default bind for Keyboard and Mouse devices
Optional Parameters
-
Name
: The Displayed text in the game keybinds menu -
GamepadPath
: The default bind for Gamepad devices -
KbmInteractions
: Sets the interactions of the kbm binding. See Interactions Docs -
GamepadInteractions
: Sets the interactions of the gamepad binding. See Interactions Docs -
ActionID
: Overrides the generated actionId (Generally you don't want to change this) -
ActionType
: Determines the behavior with which the action triggers. See ActionType Docs
So your Attribute could be written like this:
[InputAction("<Keyboard>/minus", Name = "Explode")]
public InputAction ExplodeKey { get; set; }
Or with any combination of optional parameters:
[InputAction("<Keyboard>/minus", Name = "Explode", GamepadPath = "<Gamepad>/Button North", KbmInteractions = "hold(duration = 5)")]
public InputAction ExplodeKey { get; set; }
[!NOTE] In this case above the Hold Interaction is being used. This keybind triggers after being held for 5 seconds. See Interactions Docs
At Runtime
- Override Method
void CreateInputActions(in InputActionMapBuilder builder)
- Use the builder to create InputActions
- Reference InputAction by calling
Asset["actionId"]
in your class
[!IMPORTANT] Make sure you call
Finish()
after you're done creating each InputAction.
Here's an example usage of the runtime api
public class MyExampleInputClass : LcInputActions
{
public static readonly MyExampleInputClass Instance = new();
public InputAction ExplodeKey => Asset["explodekey"];
public override void CreateInputActions(in InputActionMapBuilder builder)
{
builder.NewActionBinding()
.WithActionId("explodekey")
.WithActionType(InputActionType.Button)
.WithKbmPath("<Keyboard>/j")
.WithBindingName("Explode")
.Finish();
}
}
Referencing Your Binds
To use your InputActions class, you need to instantiate it.
[!IMPORTANT] Do not create more than one instance of your InputActions class. If your class is instantiated more than once, your InputActions are unlikely to work as intended.
The easiest (opinionated) way to do so would be to have a static instance in your plugin class.
[BepInPlugin(...)]
[BepInDependency("com.rune580.LethalCompanyInputUtils", BepInDependency.DependencyFlags.HardDependency)]
public class MyExamplePlugin : BaseUnityPlugin
{
internal static MyExampleInputClass InputActionsInstance = new MyExampleInputClass();
}
You could also opt for instantiating the instance in the InputActions class (Singleton-style).
public class MyExampleInputClass : LcInputActions
{
public static MyExampleInputClass Instance = new();
[InputAction("explodekey", "<Keyboard>/j", "<Gamepad>/Button North", Name = "Explode")]
public InputAction ExplodeKey { get; set; }
}
[!IMPORTANT]
But How Do I Get My Binds String?
You may have noticed that
<keyboard>/yourKey
can be a little confusing for the special buttons. So try this:
- First, arbitrarily set the value to some regular value or just an empty string
- Then, load up your mod and change the keybind to the desired key
- After, look in your
.../BepInEx/controls/YOURMODID.json
file- Find the
{"action":"myaction","origPath":"","path":"<Keyboard>/f8"}]}
- Last, copy that
path:""
from the far right i.e."<Keyboard>/f8"
Using Your Binds
You could then simply reference the instance anywhere you need to have your actions at.
public class MyOtherClassOrMonoBehavior
{
public void DoSomething()
{
MyExamplePlugin.InputActionsInstance.ExplodeKey ...
}
}
or
public class MyOtherClassOrMonoBehavior
{
public void DoSomething()
{
MyExampleInputClass.Instance.ExplodeKey ...
}
}
Best Practices
It is common to see tutorials call InputAction.ReadValue<>()
or InputAction.triggered
from mono-behaviour Update()
functions.
public class MyOtherClassOrMonoBehavior
{
public void Update()
{
DoSomething();
}
public void DoSomething()
{
if (!MyExamplePlugin.InputActionsInstance.ExplodeKey.triggered) return;
//Your executing code here
}
}
This approach is sufficient for 'continuous' actions, e.g. movement.
For 'discrete' actions, it's more appropriate to create event listeners that accept an InputAction.CallbackContext
and subscribe to InputAction.performed
.
public class MyOtherClassOrMonoBehavior
{
public void Awake()
{
SetupKeybindCallbacks();
}
// Name this whatever you like. It needs to be called exactly once, so
public void SetupKeybindCallbacks()
{
MyExamplePlugin.InputActionsInstance.ExplodeKey.performed += OnExplodeKeyPressed;
}
public void OnExplodeKeyPressed(InputAction.CallbackContext explodeConext)
{
if (!explodeConext.performed) return;
// Add more context checks if desired
// Your executing code here
}
}
Using InputUtils as an Optional or Soft Dependency
First make sure to add the [BepInDependency(...)]
attribute to your mods Plugin class, mark it as a SoftDependency
.
If you already have the attribute set as a HardDependency
make sure to replace that.
[BepInPlugin(...)]
[BepInDependency("com.rune580.LethalCompanyInputUtils", BepInDependency.DependencyFlags.SoftDependency)]
public class MyExamplePlugin : BaseUnityPlugin
Create your InputActions class as you would following the guide above. Make a class specifically for when the mod is loaded
internal static class InputUtilsCompat
{
public static bool Enabled =>
BepInEx.Bootstrap.Chainloader.PluginInfos.ContainsKey("com.rune580.LethalCompanyInputUtils");
public static InputAction ExplodeKey =>
MyExampleInputClass.Instance.ExplodeKey;
}
Finally whenever you reference stuff from InputUtilsCompat
, make sure to check its Enabled
Property first.
if (InputUtilsCompat.Enabled)
InputUtilsCompat.ExplodeKey...
Reference Best Practices for details on how to best use the InputAction
[!IMPORTANT]
If your mod uses NetcodePatcher you may need to do additional steps.
This only applies to mods that use InputUtils as a soft-dependency
Please check their Readme for more info. However for a possible fix, replace
var types = Assembly.GetExecutingAssembly().GetTypes();
with
IEnumerable<Type> types; try { types = Assembly.GetExecutingAssembly().GetTypes(); } catch (ReflectionTypeLoadException e) { types = e.Types.Where(t => t != null); }
Next Steps
Check out Unity's documentation for their InputSystem
Build Instructions
Build Script Args
--target=TARGET
- Valid targets:
- Build (default)
- FetchRefs
- Deploy (requires a valid
GAME_DIR
env var) - BuildThunderstore
- BuildNuGet
- Valid targets:
--configuration=MSBUILDCONFIGURATION
- Valid configurations:
- Debug (default)
- Release
- Valid configurations:
Check Build/Build.cs
for the source code of the build script.
Linux
Clone and enter the repo.
git clone https://github.com/Rune580/LethalCompanyInputUtils && cd LethalCompanyInputUtils
Copy and rename .env.example
to .env
.
cp .env.example .env
Edit .env
to fit your needs, a valid installation of Lethal Company is required unless USE_STUBBED_LIBS
is set.
Run ./build.sh to run the default build task.
./build.sh
Windows
Clone the repo.
git clone https://github.com/Rune580/LethalCompanyInputUtils
Enter the cloned repo.
cd LethalCompanyInputUtils
Copy and rename .env.example
to .env
.
cp .env.example .env
Edit .env
to fit your needs, a valid installation of Lethal Company is required unless USE_STUBBED_LIBS
is set.
Run ./build.ps1 to run the default build task.
.\build.ps1
Contact
Discord: @rune
Github: Rune580
Contributors
Thanks to the following contributers:
- @Boxofbiscuits97 for reworking most of the documentation.
- @Lordfirespeed for housekeeping and additional documentation cleanup.
Changelog
All notable changes to this project will be documented here.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[Unreleased]
[0.4.3]
LcInputActions.Asset
now has a public getter.
Fixed issue where binds that were unbound by default would not save/load their new binds after restarting your game.
[0.4.2]
Hotfix for applying migrations when the new file already existed, no longer crashes the mod.
[0.4.1]
Bind overrides have been moved from BepInEx/controls
to BepInEx/config/controls
allowing for bind overrides to be distributed with modpacks.
[0.4.0]
InputActions can now be made at runtime by overriding the method CreateInputActions(...)
and using the provided builder.
[0.3.0]
The only required parameter for the InputActions attribute is now only just the kbmPath, the rest are now optional. Should help improve DX.
[0.2.0]
Interactions for the kbm and gamepad bindings can now be set in the attribute.
[0.1.0]
Initial Beta Release.
CHANGELOG
[0.7.7]
Fixes:
- I also forgot to include Locale with the new build system, this fixes things for real this time.
[0.7.6]
Fixes:
- Forgot to include AssetBundles with new build system, sorry about that.
[0.7.5]
Fixes:
- Delay searching for device layouts until after unity has loaded, fixes a harmless error at startup.
[0.7.4]
Locale:
- Russian translation by @Singularia
Developer Experience Improvements:
Keyboard, Mouse, and Gamepad have generated Enums under the LethalCompanyInputUtils.BindingPathEnums
namespace.
These enums are called KeyboardControl
, MouseControl
, and GamepadControl
respectively.
These enums contain all the keys/buttons that are accepted by Unity's InputSystem.
The docs have been updated to reflect usage of the Enums, you may still use the string input paths if you'd like.
[0.7.3]
Mod Integration:
- LethalConfig - Use TextDropDownConfigItem for the locale option instead of TextInputFieldConfigItem.
[0.7.2]
Mod Integration:
- LobbyCompatibility - Register InputUtils as a client-side mod.
- LethalConfig - Change locale in-game.
[0.7.1]
It wouldn't be an InputUtils update without a hotfix for bug I never noticed.
Fixes:
- Binds actually save instead of gaslighting you into thinking they saved.
[0.7.0]
Highlights:
- Basic locale/lang loading system
- Starting with only
en_US
for now. - Configurable
- Starting with only
- Global controls
- Controls can now be saved globally which allows for Controls to work across Modpacks/Profiles.
- With the addition of Global Controls comes the ability to configure how InputUtils handles Control priority between Local (Modpack/Profile/Manual install) and Global Controls.
- By default both Local and Global Controls are loaded, but with Global Controls having priority.
Internal Changes:
- Better handling of device specific overrides when serializing/deserializing.
[0.6.3]
Fixes:
- Some Keyboard/Mouse binds were being incorrectly recognized as gamepad only binds, this was because I forgot about the existence of lower-case letters. I've studied up on the alphabet to make up for this.
Notes:
- It was brought to my attention that the wording of the previous description could potentially come across as an insult to the vanilla rebind UI, which was not my intention. As such I have updated the description to more accurately provide an overview of the features provided, while also using more neutral wording.
[0.6.2]
Fixes:
- Gamepad only binds now only allow gamepads.
[0.6.1]
Fixes:
- Empty bind paths for InputActions created using the builder now properly resolve.
[0.6.0]
Features:
- Scroll Wheel rebinding support.
- Mouse button glyphs.
[0.5.6]
Allow LcInputAction's to have NonPublic InputActions.
[0.5.5]
Fixes unbinding vanilla keys to no longer cause the UI to be permanently broken.
[0.5.4]
Hotfix for rebind ui breaking due to another oversight on my part.
[0.5.3]
Fix issue with the runtime api causing errors when not defining a gamepad path.
[0.5.2]
Fix vanilla key rebinding being broken when re-opening the rebind UI.
[0.5.1]
Hotfix for broken installs with mod managers, sorry that was my bad.
[0.5.0]
Highlights:
Massive UI Overhaul
- Cleaned up the base game controls to be more organized.
- Added Controller Glyphs for Xbox and DualSense controllers with automatic detection.
- Glyphs only show up in the rebind menu for now, a future update will have them be visible in game.
- Api to request controller glyphs for a control path will be available in a future update.
- Controls added by mods are seperated by mod.
- Controls manually injected into the vanilla ui by mods are available in "Legacy Controls".
Controls can now be unbound.
Controller navigation of the new UI is still a WIP, hoping to improve it in a future update.
[0.4.4]
Text in the remap ui now has auto-scaling size. Remap ui no longer cuts-off the bottom of the controller section. Changed method for determining the BepInPlugin of dependents.
[0.4.3]
LcInputActions.Asset
now has a public getter.
Fixed issue where binds that were unbound by default would not save/load their new binds after restarting your game.
[0.4.2]
Hotfix for applying migrations when the new file already existed, no longer crashes the mod.
[0.4.1]
Bind overrides have been moved from BepInEx/controls
to BepInEx/config/controls
allowing for bind overrides to be distributed with modpacks.
[0.4.0]
InputActions can now be made at runtime by overriding the method CreateInputActions(...)
and using the provided builder.
[0.3.0]
The only required parameter for the InputActions attribute is now only just the kbmPath, the rest are now optional. Should help improve DX.
[0.2.0]
Interactions for the kbm and gamepad bindings can now be set in the attribute.
[0.1.0]
Initial Beta Release.