Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Resolved How do I load bindings into a generated c# class?

Discussion in 'Input System' started by BGCH, Nov 7, 2021.

  1. BGCH

    BGCH

    Joined:
    Nov 23, 2017
    Posts:
    20
    so the problem is that when I try to load the bindings into the generated class, the new bindings just don't work.
    I am using RebindActionUI from InputSystem samples to change the bindings.
    After the bindings are changed and the game is restarted, the new bindings are displayed correctly
    Save/load code
    upload_2021-11-7_7-26-36.png

    but after line 552 where I try to load the bindings nothing changes (playerActions is a generated class)
     
  2. You don't. This is currently not supported. AFAIK they acknowledged it and they will add the feature in a future version.
    If you take a look at the generated class, you can see that it consists of a direct JSON load (I can't despise this fact enough...).
    Example (sorry, for some reason I had a weak moment and called it
    InputActions
    ):
    Code (CSharp):
    1.    public partial class @InputActions : IInputActionCollection2, IDisposable
    2.     {
    3.         public InputActionAsset asset { get; }
    4.         public @InputActions()
    5.         {
    6.             asset = InputActionAsset.FromJson(@"{
    7.    ""name"": ""InputActions"",
    8.    ""maps"": [
    9. // [...]
    Now, this means, any time you instantiate this class, the inlined JSON will be used. If you feel a little bit adventurous, you can change the asset to have a public setter and set it from outside (meaning whenever you change your
    InputActionAsset
    , you will need to redo this). Or you can make a short
    AssetPostprocessor
    where you can detect when your
    InputActionAsset
    changes and make the code changes automatic. Also you can write an extension method for this class to implement the loading of your JSON.
    So basically change that line to this:
    public InputActionAsset asset { get; set; }
    and create an extension method (this can be absolutely static):
    Code (CSharp):
    1. using UnityEngine.InputSystem;
    2.  
    3. public static class InputActionsExtensions
    4. {
    5.     public static void LoadFromJSON(InputActions ia, string json)
    6.     {
    7.         ia.asset = InputActionAsset.FromJson(json);
    8.     }
    9. }
    In this case.

    Or you can wait until they deliver the new feature which is uncertain, because we asked for it a long time ago. If you don't want to tinker with code, the only way to save/load overrides if you use the
    InputActionAsset
    itself and not the C# accessor class.
     
  3. BGCH

    BGCH

    Joined:
    Nov 23, 2017
    Posts:
    20

    I already tried something before I saw your answer.
    I made a copy of the generated class and changed the constructor class and now my code above works, but obviously this is not a solution to the problem in general, because I have to do this every time I change InputActionAsset.
    upload_2021-11-7_9-7-25.png

    I'm glad to hear that they will fix this, but Is it possible to change the class generation template? this could be a temporary solution
    I have never used AssetPostprocessor
     
  4. In theory, yes. But unfortunately it's not really a template file, it's a
    .cs
    file in the package:
    <project path>\Library\PackageCache\com.unity.inputsystem@1.2.0\ InputSystem\Editor\AssetImporter\InputActionCodeGenerator.cs

    And to change it, first, you need to copy it to the
    Packages
    folder manually. But in this case you lose the ability to automatically update the InputSystem, since you edited it manually.

    Using the AssetPostProcessor is extremely easy. Here is an example I wrote for localization. (The
    OnPostprocessAllAssets
    is the important part from the post there) Obviously you need to check if the changed asset is an
    InputActionAsset
    and then do the stuff (finding the declaration in the file and adding the extra
    set;
    ).
     
  5. BGCH

    BGCH

    Joined:
    Nov 23, 2017
    Posts:
    20

    I managed to get this to work, thank you so much!
    I copied all the needed classes to generate the class and now I can just pass the InputActionAsset instance to the class constructor.

    Code (CSharp):
    1.  private void Awake()
    2.         {
    3.             playerActionsClass = new Actions(InputActionAsseReference);
    4.         }

    I'll leave the code for people who got the same problem

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEditor;
    5. using System;
    6. using System.IO;
    7. using System.Linq;
    8. using System.Text;
    9. using UnityEngine.InputSystem.Utilities;
    10. using UnityEngine.InputSystem;
    11. using System.Reflection;
    12.  
    13. namespace BattleLab
    14. {
    15.     public class InputActionAssetPostprocessor : AssetPostprocessor
    16.     {
    17.         private const string classPath = "Assets/[16]Inputs/actions.cs";
    18.         private const string inputAssetPath = "Assets/[16]Inputs/actions.inputactions";
    19.  
    20.         private const string classFullPath = "***path to your project***/Assets/[16]Inputs/actions.cs";
    21.  
    22.         static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
    23.         {
    24.             foreach (string str in importedAssets)
    25.             {
    26.                 if (str == inputAssetPath)
    27.                 {
    28.                     Debug.Log("Actions Changed");
    29.  
    30.                     string generatedClass = InputActionCodeGenerator.GenerateWrapperCode((InputActionAsset)AssetDatabase.LoadAssetAtPath(inputAssetPath, typeof(InputActionAsset)));
    31.  
    32.                     if (File.Exists(classFullPath))
    33.                     {
    34.                         File.WriteAllText(classFullPath, generatedClass);
    35.                     }
    36.                 }
    37.             }
    38.  
    39.         }
    40.  
    41.         public override int GetPostprocessOrder()
    42.         {
    43.             return (999);
    44.         }
    45.  
    46.     }
    47.     public static class InputActionCodeGenerator
    48.     {
    49.         private const int kSpacesPerIndentLevel = 4;
    50.  
    51.         public struct Options
    52.         {
    53.             public string className { get; set; }
    54.             public string namespaceName { get; set; }
    55.             public string sourceAssetPath { get; set; }
    56.         }
    57.  
    58.         public static string WithAllWhitespaceStripped(this string str)
    59.         {
    60.             var buffer = new StringBuilder();
    61.             foreach (var ch in str)
    62.                 if (!char.IsWhiteSpace(ch))
    63.                     buffer.Append(ch);
    64.             return buffer.ToString();
    65.         }
    66.  
    67.         public static string GenerateWrapperCode(InputActionAsset asset, Options options = default)
    68.         {
    69.             if (asset == null)
    70.                 throw new ArgumentNullException(nameof(asset));
    71.  
    72.             if (string.IsNullOrEmpty(options.sourceAssetPath))
    73.                 options.sourceAssetPath = AssetDatabase.GetAssetPath(asset);
    74.             if (string.IsNullOrEmpty(options.className) && !string.IsNullOrEmpty(asset.name))
    75.                 options.className =
    76.                     CSharpCodeHelpers.MakeTypeName(asset.name);
    77.  
    78.             if (string.IsNullOrEmpty(options.className))
    79.             {
    80.                 if (string.IsNullOrEmpty(options.sourceAssetPath))
    81.                     throw new ArgumentException("options.sourceAssetPath");
    82.                 options.className =
    83.                     CSharpCodeHelpers.MakeTypeName(Path.GetFileNameWithoutExtension(options.sourceAssetPath));
    84.             }
    85.  
    86.             var writer = new Writer
    87.             {
    88.                 buffer = new StringBuilder()
    89.             };
    90.  
    91.             // Header.
    92.             writer.WriteLine(CSharpCodeHelpers.MakeAutoGeneratedCodeHeader("com.unity.inputsystem:InputActionCodeGenerator",
    93.                 InputSystem.version.ToString(),
    94.                 options.sourceAssetPath));
    95.  
    96.             // Usings.
    97.             writer.WriteLine("using System;");
    98.             writer.WriteLine("using System.Collections;");
    99.             writer.WriteLine("using System.Collections.Generic;");
    100.             writer.WriteLine("using UnityEngine.InputSystem;");
    101.             writer.WriteLine("using UnityEngine.InputSystem.Utilities;");
    102.             writer.WriteLine("");
    103.  
    104.             // Begin namespace.
    105.             var haveNamespace = !string.IsNullOrEmpty(options.namespaceName);
    106.             if (haveNamespace)
    107.             {
    108.                 writer.WriteLine($"namespace {options.namespaceName}");
    109.                 writer.BeginBlock();
    110.             }
    111.  
    112.             // Begin class.
    113.             writer.WriteLine($"public partial class @{options.className} : IInputActionCollection2, IDisposable");
    114.             writer.BeginBlock();
    115.  
    116.             writer.WriteLine($"public InputActionAsset asset {{ get; }}");
    117.  
    118.             // Default constructor.
    119.             writer.WriteLine($"public @{options.className}(InputActionAsset actionsAsset = null)");
    120.             writer.BeginBlock();
    121.             writer.WriteLine($"asset = InputActionAsset.FromJson(@\"{asset.ToJson().Replace("\"", "\"\"")}\");");
    122.             writer.WriteLine("if(actionsAsset != null){asset = actionsAsset;}");
    123.  
    124.  
    125.  
    126.             var maps = asset.actionMaps;
    127.             var schemes = asset.controlSchemes;
    128.             foreach (var map in maps)
    129.             {
    130.                 var mapName = CSharpCodeHelpers.MakeIdentifier(map.name);
    131.                 writer.WriteLine($"// {map.name}");
    132.                 writer.WriteLine($"m_{mapName} = asset.FindActionMap(\"{map.name}\", throwIfNotFound: true);");
    133.  
    134.                 foreach (var action in map.actions)
    135.                 {
    136.                     var actionName = CSharpCodeHelpers.MakeIdentifier(action.name);
    137.                     writer.WriteLine($"m_{mapName}_{actionName} = m_{mapName}.FindAction(\"{action.name}\", throwIfNotFound: true);");
    138.                 }
    139.             }
    140.             writer.EndBlock();
    141.             writer.WriteLine();
    142.  
    143.             writer.WriteLine("public void Dispose()");
    144.             writer.BeginBlock();
    145.             writer.WriteLine("UnityEngine.Object.Destroy(asset);");
    146.             writer.EndBlock();
    147.             writer.WriteLine();
    148.  
    149.             writer.WriteLine("public InputBinding? bindingMask");
    150.             writer.BeginBlock();
    151.             writer.WriteLine("get => asset.bindingMask;");
    152.             writer.WriteLine("set => asset.bindingMask = value;");
    153.             writer.EndBlock();
    154.             writer.WriteLine();
    155.  
    156.             writer.WriteLine("public ReadOnlyArray<InputDevice>? devices");
    157.             writer.BeginBlock();
    158.             writer.WriteLine("get => asset.devices;");
    159.             writer.WriteLine("set => asset.devices = value;");
    160.             writer.EndBlock();
    161.             writer.WriteLine();
    162.  
    163.             writer.WriteLine("public ReadOnlyArray<InputControlScheme> controlSchemes => asset.controlSchemes;");
    164.             writer.WriteLine();
    165.  
    166.             writer.WriteLine("public bool Contains(InputAction action)");
    167.             writer.BeginBlock();
    168.             writer.WriteLine("return asset.Contains(action);");
    169.             writer.EndBlock();
    170.             writer.WriteLine();
    171.  
    172.             writer.WriteLine("public IEnumerator<InputAction> GetEnumerator()");
    173.             writer.BeginBlock();
    174.             writer.WriteLine("return asset.GetEnumerator();");
    175.             writer.EndBlock();
    176.             writer.WriteLine();
    177.  
    178.             writer.WriteLine("IEnumerator IEnumerable.GetEnumerator()");
    179.             writer.BeginBlock();
    180.             writer.WriteLine("return GetEnumerator();");
    181.             writer.EndBlock();
    182.             writer.WriteLine();
    183.  
    184.             writer.WriteLine("public void Enable()");
    185.             writer.BeginBlock();
    186.             writer.WriteLine("asset.Enable();");
    187.             writer.EndBlock();
    188.             writer.WriteLine();
    189.  
    190.             writer.WriteLine("public void Disable()");
    191.             writer.BeginBlock();
    192.             writer.WriteLine("asset.Disable();");
    193.             writer.EndBlock();
    194.  
    195.             writer.WriteLine("public IEnumerable<InputBinding> bindings => asset.bindings;");
    196.             writer.WriteLine();
    197.  
    198.             writer.WriteLine("public InputAction FindAction(string actionNameOrId, bool throwIfNotFound = false)");
    199.             writer.BeginBlock();
    200.             writer.WriteLine("return asset.FindAction(actionNameOrId, throwIfNotFound);");
    201.             writer.EndBlock();
    202.  
    203.             writer.WriteLine("public int FindBinding(InputBinding bindingMask, out InputAction action)");
    204.             writer.BeginBlock();
    205.             writer.WriteLine("return asset.FindBinding(bindingMask, out action);");
    206.             writer.EndBlock();
    207.  
    208.             // Action map accessors.
    209.             foreach (var map in maps)
    210.             {
    211.                 writer.WriteLine();
    212.                 writer.WriteLine($"// {map.name}");
    213.  
    214.                 var mapName = CSharpCodeHelpers.MakeIdentifier(map.name);
    215.                 var mapTypeName = CSharpCodeHelpers.MakeTypeName(mapName, "Actions");
    216.  
    217.                 // Caching field for action map.
    218.                 writer.WriteLine($"private readonly InputActionMap m_{mapName};");
    219.                 writer.WriteLine(string.Format("private I{0} m_{0}CallbackInterface;", mapTypeName));
    220.  
    221.                 // Caching fields for all actions.
    222.                 foreach (var action in map.actions)
    223.                 {
    224.                     var actionName = CSharpCodeHelpers.MakeIdentifier(action.name);
    225.                     writer.WriteLine($"private readonly InputAction m_{mapName}_{actionName};");
    226.                 }
    227.  
    228.                 // Struct wrapping access to action set.
    229.                 writer.WriteLine($"public struct {mapTypeName}");
    230.                 writer.BeginBlock();
    231.  
    232.                 // Constructor.
    233.                 writer.WriteLine($"private @{options.className} m_Wrapper;");
    234.                 writer.WriteLine($"public {mapTypeName}(@{options.className} wrapper) {{ m_Wrapper = wrapper; }}");
    235.  
    236.                 // Getter for each action.
    237.                 foreach (var action in map.actions)
    238.                 {
    239.                     var actionName = CSharpCodeHelpers.MakeIdentifier(action.name);
    240.                     writer.WriteLine(
    241.                         $"public InputAction @{actionName} => m_Wrapper.m_{mapName}_{actionName};");
    242.                 }
    243.  
    244.                 // Action map getter.
    245.                 writer.WriteLine($"public InputActionMap Get() {{ return m_Wrapper.m_{mapName}; }}");
    246.  
    247.                 // Enable/disable methods.
    248.                 writer.WriteLine("public void Enable() { Get().Enable(); }");
    249.                 writer.WriteLine("public void Disable() { Get().Disable(); }");
    250.                 writer.WriteLine("public bool enabled => Get().enabled;");
    251.  
    252.                 // Implicit conversion operator.
    253.                 writer.WriteLine(
    254.                     $"public static implicit operator InputActionMap({mapTypeName} set) {{ return set.Get(); }}");
    255.  
    256.                 // SetCallbacks method.
    257.                 writer.WriteLine($"public void SetCallbacks(I{mapTypeName} instance)");
    258.                 writer.BeginBlock();
    259.  
    260.                 ////REVIEW: this would benefit from having a single callback on InputActions rather than three different endpoints
    261.  
    262.                 // Uninitialize existing interface.
    263.                 writer.WriteLine($"if (m_Wrapper.m_{mapTypeName}CallbackInterface != null)");
    264.                 writer.BeginBlock();
    265.                 foreach (var action in map.actions)
    266.                 {
    267.                     var actionName = CSharpCodeHelpers.MakeIdentifier(action.name);
    268.                     var actionTypeName = CSharpCodeHelpers.MakeTypeName(action.name);
    269.  
    270.                     writer.WriteLine($"@{actionName}.started -= m_Wrapper.m_{mapTypeName}CallbackInterface.On{actionTypeName};");
    271.                     writer.WriteLine($"@{actionName}.performed -= m_Wrapper.m_{mapTypeName}CallbackInterface.On{actionTypeName};");
    272.                     writer.WriteLine($"@{actionName}.canceled -= m_Wrapper.m_{mapTypeName}CallbackInterface.On{actionTypeName};");
    273.                 }
    274.                 writer.EndBlock();
    275.  
    276.                 // Initialize new interface.
    277.                 writer.WriteLine($"m_Wrapper.m_{mapTypeName}CallbackInterface = instance;");
    278.                 writer.WriteLine("if (instance != null)");
    279.                 writer.BeginBlock();
    280.                 foreach (var action in map.actions)
    281.                 {
    282.                     var actionName = CSharpCodeHelpers.MakeIdentifier(action.name);
    283.                     var actionTypeName = CSharpCodeHelpers.MakeTypeName(action.name);
    284.  
    285.                     writer.WriteLine($"@{actionName}.started += instance.On{actionTypeName};");
    286.                     writer.WriteLine($"@{actionName}.performed += instance.On{actionTypeName};");
    287.                     writer.WriteLine($"@{actionName}.canceled += instance.On{actionTypeName};");
    288.                 }
    289.                 writer.EndBlock();
    290.                 writer.EndBlock();
    291.                 writer.EndBlock();
    292.  
    293.                 // Getter for instance of struct.
    294.                 writer.WriteLine($"public {mapTypeName} @{mapName} => new {mapTypeName}(this);");
    295.             }
    296.  
    297.             // Control scheme accessors.
    298.             foreach (var scheme in schemes)
    299.             {
    300.                 var identifier = CSharpCodeHelpers.MakeIdentifier(scheme.name);
    301.  
    302.                 writer.WriteLine($"private int m_{identifier}SchemeIndex = -1;");
    303.                 writer.WriteLine($"public InputControlScheme {identifier}Scheme");
    304.                 writer.BeginBlock();
    305.                 writer.WriteLine("get");
    306.                 writer.BeginBlock();
    307.                 writer.WriteLine($"if (m_{identifier}SchemeIndex == -1) m_{identifier}SchemeIndex = asset.FindControlSchemeIndex(\"{scheme.name}\");");
    308.                 writer.WriteLine($"return asset.controlSchemes[m_{identifier}SchemeIndex];");
    309.                 writer.EndBlock();
    310.                 writer.EndBlock();
    311.             }
    312.  
    313.             // Generate interfaces.
    314.             foreach (var map in maps)
    315.             {
    316.                 var typeName = CSharpCodeHelpers.MakeTypeName(map.name);
    317.                 writer.WriteLine($"public interface I{typeName}Actions");
    318.                 writer.BeginBlock();
    319.  
    320.                 foreach (var action in map.actions)
    321.                 {
    322.                     var methodName = CSharpCodeHelpers.MakeTypeName(action.name);
    323.                     writer.WriteLine($"void On{methodName}(InputAction.CallbackContext context);");
    324.                 }
    325.  
    326.                 writer.EndBlock();
    327.             }
    328.  
    329.             // End class.
    330.             writer.EndBlock();
    331.  
    332.             // End namespace.
    333.             if (haveNamespace)
    334.                 writer.EndBlock();
    335.  
    336.             return writer.buffer.ToString();
    337.         }
    338.  
    339.         ////TODO: move this to a shared place
    340.         internal struct Writer
    341.         {
    342.             public StringBuilder buffer;
    343.             public int indentLevel;
    344.  
    345.             public void BeginBlock()
    346.             {
    347.                 WriteIndent();
    348.                 buffer.Append("{\n");
    349.                 ++indentLevel;
    350.             }
    351.  
    352.             public void EndBlock()
    353.             {
    354.                 --indentLevel;
    355.                 WriteIndent();
    356.                 buffer.Append("}\n");
    357.             }
    358.  
    359.             public void WriteLine()
    360.             {
    361.                 buffer.Append('\n');
    362.             }
    363.  
    364.             public void WriteLine(string text)
    365.             {
    366.                 if (!text.All(char.IsWhiteSpace))
    367.                 {
    368.                     WriteIndent();
    369.                     buffer.Append(text);
    370.                 }
    371.                 buffer.Append('\n');
    372.             }
    373.  
    374.             public void Write(string text)
    375.             {
    376.                 buffer.Append(text);
    377.             }
    378.  
    379.             public void WriteIndent()
    380.             {
    381.                 for (var i = 0; i < indentLevel; ++i)
    382.                 {
    383.                     for (var n = 0; n < kSpacesPerIndentLevel; ++n)
    384.                         buffer.Append(' ');
    385.                 }
    386.             }
    387.         }
    388.  
    389.         // Updates the given file with wrapper code generated for the given action sets.
    390.         // If the generated code is unchanged, does not touch the file.
    391.         // Returns true if the file was touched, false otherwise.
    392.         public static bool GenerateWrapperCode(string filePath, InputActionAsset asset, Options options)
    393.         {
    394.             if (!Path.HasExtension(filePath))
    395.                 filePath += ".cs";
    396.  
    397.             // Generate code.
    398.             var code = GenerateWrapperCode(asset, options);
    399.  
    400.             // Check if the code changed. Don't write if it hasn't.
    401.             if (File.Exists(filePath))
    402.             {
    403.                 var existingCode = File.ReadAllText(filePath);
    404.                 if (existingCode == code || existingCode.WithAllWhitespaceStripped() == code.WithAllWhitespaceStripped())
    405.                     return false;
    406.             }
    407.  
    408.             // Write.
    409.             EditorHelpers.CheckOut(filePath);
    410.             File.WriteAllText(filePath, code);
    411.             return true;
    412.         }
    413.     }
    414.  
    415.     internal static class EditorHelpers
    416.     {
    417.         public static void CheckOut(string path)
    418.         {
    419.             if (string.IsNullOrEmpty(path))
    420.                 throw new ArgumentNullException(nameof(path));
    421.  
    422.             // Make path relative to project folder.
    423.             var projectPath = Application.dataPath;
    424.             if (path.StartsWith(projectPath) && path.Length > projectPath.Length &&
    425.                 (path[projectPath.Length] == '/' || path[projectPath.Length] == '\\'))
    426.                 path = path.Substring(0, projectPath.Length + 1);
    427.  
    428.             AssetDatabase.MakeEditable(path);
    429.         }
    430.  
    431.         public static void CheckOut(UnityEngine.Object asset)
    432.         {
    433.             if (asset == null)
    434.                 throw new ArgumentNullException(nameof(asset));
    435.             var path = AssetDatabase.GetAssetPath(asset);
    436.             CheckOut(path);
    437.         }
    438.     }
    439.  
    440.     public static class CSharpCodeHelpers
    441.     {
    442.         public static bool IsProperIdentifier(string name)
    443.         {
    444.             if (string.IsNullOrEmpty(name))
    445.                 return false;
    446.  
    447.             if (char.IsDigit(name[0]))
    448.                 return false;
    449.  
    450.             for (var i = 0; i < name.Length; ++i)
    451.             {
    452.                 var ch = name[i];
    453.                 if (!char.IsLetterOrDigit(ch) && ch != '_')
    454.                     return false;
    455.             }
    456.  
    457.             return true;
    458.         }
    459.  
    460.         public static bool IsEmptyOrProperIdentifier(string name)
    461.         {
    462.             if (string.IsNullOrEmpty(name))
    463.                 return true;
    464.  
    465.             return IsProperIdentifier(name);
    466.         }
    467.  
    468.         public static bool IsEmptyOrProperNamespaceName(string name)
    469.         {
    470.             if (string.IsNullOrEmpty(name))
    471.                 return true;
    472.  
    473.             return name.Split('.').All(IsProperIdentifier);
    474.         }
    475.  
    476.         ////TODO: this one should add the @escape automatically so no other code has to worry
    477.         public static string MakeIdentifier(string name, string suffix = "")
    478.         {
    479.             if (string.IsNullOrEmpty(name))
    480.                 throw new ArgumentNullException(nameof(name));
    481.  
    482.             if (char.IsDigit(name[0]))
    483.                 name = "_" + name;
    484.  
    485.             // See if we have invalid characters in the name.
    486.             var nameHasInvalidCharacters = false;
    487.             for (var i = 0; i < name.Length; ++i)
    488.             {
    489.                 var ch = name[i];
    490.                 if (!char.IsLetterOrDigit(ch) && ch != '_')
    491.                 {
    492.                     nameHasInvalidCharacters = true;
    493.                     break;
    494.                 }
    495.             }
    496.  
    497.             // If so, create a new string where we remove them.
    498.             if (nameHasInvalidCharacters)
    499.             {
    500.                 var buffer = new StringBuilder();
    501.                 for (var i = 0; i < name.Length; ++i)
    502.                 {
    503.                     var ch = name[i];
    504.                     if (char.IsLetterOrDigit(ch) || ch == '_')
    505.                         buffer.Append(ch);
    506.                 }
    507.  
    508.                 name = buffer.ToString();
    509.             }
    510.  
    511.             return name + suffix;
    512.         }
    513.  
    514.         public static string MakeTypeName(string name, string suffix = "")
    515.         {
    516.             var symbolName = MakeIdentifier(name, suffix);
    517.             if (char.IsLower(symbolName[0]))
    518.                 symbolName = char.ToUpper(symbolName[0]) + symbolName.Substring(1);
    519.             return symbolName;
    520.         }
    521.  
    522. #if UNITY_EDITOR
    523.         public static string MakeAutoGeneratedCodeHeader(string toolName, string toolVersion, string sourceFileName = null)
    524.         {
    525.             return
    526.                 "//------------------------------------------------------------------------------\n"
    527.                 + "// <auto-generated>\n"
    528.                 + $"//     This code was auto-generated by {toolName}\n"
    529.                 + $"//     version {toolVersion}\n"
    530.                 + (string.IsNullOrEmpty(sourceFileName) ? "" : $"//     from {sourceFileName}\n")
    531.                 + "//\n"
    532.                 + "//     Changes to this file may cause incorrect behavior and will be lost if\n"
    533.                 + "//     the code is regenerated.\n"
    534.                 + "// </auto-generated>\n"
    535.                 + "//------------------------------------------------------------------------------\n";
    536.         }
    537.  
    538.         public static string ToLiteral(this object value)
    539.         {
    540.             if (value == null)
    541.                 return "null";
    542.  
    543.             var type = value.GetType();
    544.  
    545.             if (type == typeof(bool))
    546.             {
    547.                 if ((bool)value)
    548.                     return "true";
    549.                 return "false";
    550.             }
    551.  
    552.             if (type == typeof(char))
    553.                 return $"'\\u{(int)(char)value:X2}'";
    554.  
    555.             if (type == typeof(float))
    556.                 return value + "f";
    557.  
    558.             if (type == typeof(uint) || type == typeof(ulong))
    559.                 return value + "u";
    560.  
    561.             if (type == typeof(long))
    562.                 return value + "l";
    563.  
    564.             if (type.IsEnum)
    565.             {
    566.                 var enumValue = type.GetEnumName(value);
    567.                 if (!string.IsNullOrEmpty(enumValue))
    568.                     return $"{type.FullName.Replace("+", ".")}.{enumValue}";
    569.             }
    570.  
    571.             return value.ToString();
    572.         }
    573.  
    574.         public static string GetInitializersForPublicPrimitiveTypeFields(this object instance)
    575.         {
    576.             var type = instance.GetType();
    577.             var defaults = Activator.CreateInstance(type);
    578.             var fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public);
    579.             var fieldInits = string.Join(", ",
    580.                 fields.Where(f => (f.FieldType.IsPrimitive || f.FieldType.IsEnum) && !f.GetValue(instance).Equals(f.GetValue(defaults)))
    581.                     .Select(f => $"{f.Name} = {f.GetValue(instance).ToLiteral()}"));
    582.  
    583.             if (string.IsNullOrEmpty(fieldInits))
    584.                 return "()";
    585.  
    586.             return " { " + fieldInits + " }";
    587.         }
    588.  
    589. #endif
    590.     }
    591. }
    592.  
    593.  
     
    Lurking-Ninja likes this.
  6. Valentine13

    Valentine13

    Joined:
    Feb 22, 2020
    Posts:
    2

    Which classes did you copy? I only see a reference to the inputActionCodeGenerator class in your code, so was it only that one? And where did you copy it to? Lurking ninja suggested copying to the packages folder, but things in the packages folder don't show up in a file explorer—only within the unity editor, so that's all very confusing. lastly, in what script are you passing the inputActionAsset to the constructor? This seems like a very genius solution, but I'm not quite following what you did here.
     
  7. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 5, 2024
    Posts:
    418
    Capture2.PNG

    The package folder is in the
    <project folder>/Library/PackageCache/
    folder. You should copy the entire folder from the PackageCache to the
    <project folder>/Packages/
    folder.
    Capture.PNG
    Like I did with the
    Localization
    package for example.
     
  8. Valentine13

    Valentine13

    Joined:
    Feb 22, 2020
    Posts:
    2
    How did you see this post? ahaha. I don't know how this site works, but I didn't ping you as far as I know, and this is a 3 year old thread. Thank you for your response. The script in this thread works like magic, even though I barely understand how it works. I changed the constructor to accept my current action asset, plugged it in, and it just... worked.
     
    Lurking-Ninja likes this.