Feedback: Allow Input System generated C# class to use an existing Input Actions Asset instance

When using the generated C# class, we only get one constructor and it looks something like this:

public partial class @MyActionsAsset: IInputActionCollection2, IDisposable
{
    public InputActionAsset asset { get; }
    public @MyActionsAsset()
    {
         asset = InputActionAsset.FromJson("/* huge json blob here */");
         // A series of field assignments here, e.g.
        // Player
        m_Player = asset.FindActionMap("Player", throwIfNotFound: true);
        m_Player_Move = m_Player.FindAction("Move", throwIfNotFound: true);
        // etc....

This is inflexible, as it always creates its own self-contained instance of the InputActionsAsset. I propose adding a second constructor to the generated C# class that allows you to pass in an existing input actions asset. Like so:

public partial class @MyActionsAsset: IInputActionCollection2, IDisposable
{
    public InputActionAsset asset { get; }
    public @MyActionsAsset(InputActionAsset existingAssetInstance)
    {
         ValidateAssetConformsToJson(existingAssetInstance);
         asset = existingAssetInstance;
         // A series of field assignments here, e.g.
        // Player
        m_Player = asset.FindActionMap("Player", throwIfNotFound: true);
        m_Player_Move = m_Player.FindAction("Move", throwIfNotFound: true);
        // etc....

The generated code can validate that the asset conforms to the generated structure, while still allowing the user to use an existing asset instance. This unlocks the ability to attach the ease of use of the generated code api to inflexible existing InputActionAsset instances such as those created by PlayerInput instances and those used by the InputSystemUIInputModule. Being able to use the same instance in more places will unlock broader centralized handling for controlling the enabled state for action maps and actions as well as centralized runtime rebinding, and ease of use for PlayerInputManager/PlayerInput setups. It could also be used with the Project-Wide Actions asset.

2 Likes

I think it could be done even simpler than a second constructor by just providing an optional argument. I also think ValidateAssetConformsToJson(existingAssetInstance); is not required as the following lines will throw if the supplied asset does not contain required actions (the side effect is that it might contain extra actions, but I don’t think that is a problem)

I would suggest doing

public @MyActionsAsset(InputActionAsset existingAsset = null)
{
     asset = existingAsset != null ? existingAsset : InputActionAsset.FromJson("/* huge json blob here */");

or something similar.

Looking at the code, it could be implemented by modifying the 103 and 105 in InputActionCodeGenerator.cs like so

writer.WriteLine($"public @{options.className}(InputActionAsset existingAsset = null)");
writer.BeginBlock();
writer.WriteLine($"asset = existingAsset != null ? existingAsset : InputActionAsset.FromJson(@\"{asset.ToJson().Replace("\"", "\"\"")}\");");
1 Like