Editor/TypedInputGenerator.cs
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json;
using Editor;

public class TypedInputGenerator
{
	[Menu( "Editor", "Input/Generate Typed Inputs" )]
    public static void GenerateInputs()
    {
        if ( !Editor.FileSystem.ProjectSettings.FileExists( "Input.config" ) )
        {
            Log.Error( "[Input Generator] Could not find Input.config in ProjectSettings." );
            return;
        }

        string jsonContent = Editor.FileSystem.ProjectSettings.ReadAllText( "Input.config" );
        var actionNames = new HashSet<string>();

        try
        {
            using var document = JsonDocument.Parse( jsonContent );

            if ( document.RootElement.TryGetProperty( "Actions", out var actionsArray ) && 
                 actionsArray.ValueKind == JsonValueKind.Array )
            {
                foreach ( var action in actionsArray.EnumerateArray() )
                {
                    if ( action.TryGetProperty( "Name", out var nameProp ) )
                    {
                        string rawName = nameProp.GetString();
                        
                        if ( !string.IsNullOrWhiteSpace( rawName ) )
                        {
                            string cleanName = rawName.Replace( " ", "" );
                            actionNames.Add( cleanName );
                        }
                    }
                }
            }
        }
        catch ( JsonException e )
        {
            Log.Error( $"[Input Generator] Error parsing Input.config: {e.Message}" );
            return;
        }

        if ( actionNames.Count == 0 )
        {
            Log.Warning( "[Input Generator] Did not find any action on Input.config." );
            return;
        }

        string sourceCode = BuildCSharpCode( actionNames.ToList() );

        string configPhysicalPath = Editor.FileSystem.ProjectSettings.GetFullPath( "Input.config" );
        
        string projectRoot = System.IO.Path.GetDirectoryName( System.IO.Path.GetDirectoryName( configPhysicalPath ) );
        
        string finalPath = System.IO.Path.Combine( projectRoot, "Code", "InputManager", "GeneratedInputs.cs" );
        
        System.IO.Directory.CreateDirectory( System.IO.Path.GetDirectoryName( finalPath ) );
        System.IO.File.WriteAllText( finalPath, sourceCode );

        Log.Info( $"[Input Generator] Success! {actionNames.Count} inputs injected to  {finalPath}." );
    }

    private static string BuildCSharpCode( List<string> actions )
    {
        var sb = new StringBuilder();
        sb.AppendLine( "// AUTOGENERATED FILE. DO NOT MODIFY." );
        sb.AppendLine( "using System;" );
        sb.AppendLine( "using Sandbox;" );
        sb.AppendLine();
        sb.AppendLine( "namespace Sandbox.InputManager" );
        sb.AppendLine( "{" );
        
        sb.AppendLine( "    public static class InputActions" );
        sb.AppendLine( "    {" );
        
        sb.AppendLine( "        public static class Pressed" );
        sb.AppendLine( "        {" );
        foreach ( var a in actions ) 
        {
            sb.AppendLine( $"            public static event Action {a};" );
            sb.AppendLine( $"            internal static void Trigger{a}() => {a}?.Invoke();" );
        }
        sb.AppendLine( "        }" );
        
        sb.AppendLine( "        public static class Down" );
        sb.AppendLine( "        {" );
        foreach ( var a in actions ) 
        {
            sb.AppendLine( $"            public static event Action {a};" );
            sb.AppendLine( $"            internal static void Trigger{a}() => {a}?.Invoke();" );
        }
        sb.AppendLine( "        }" );

        sb.AppendLine( "        public static class Released" );
        sb.AppendLine( "        {" );
        foreach ( var a in actions ) 
        {
            sb.AppendLine( $"            public static event Action {a};" );
            sb.AppendLine( $"            internal static void Trigger{a}() => {a}?.Invoke();" );
        }
        sb.AppendLine( "        }" );
        
        sb.AppendLine( "    }" );
        sb.AppendLine();

        sb.AppendLine( "    public sealed class InputBroadcasterService : Component" );
        sb.AppendLine( "    {" );
        sb.AppendLine( "        protected override void OnUpdate()" );
        sb.AppendLine( "        {" );
        foreach ( var a in actions )
        {
            sb.AppendLine( $"            if ( Input.Pressed( \"{a}\" ) ) InputActions.Pressed.Trigger{a}();" );
            sb.AppendLine( $"            if ( Input.Down( \"{a}\" ) ) InputActions.Down.Trigger{a}();" );
            sb.AppendLine( $"            if ( Input.Released( \"{a}\" ) ) InputActions.Released.Trigger{a}();" );
        }
        sb.AppendLine( "        }" );
        sb.AppendLine( "    }" );
        
        sb.AppendLine( "}" );

        return sb.ToString();
    }
}