// Start is called before the first frame update
    void Start()
    {
        System.Type[] types = Assembly.GetExecutingAssembly().GetTypes();
        for (int i = 0; i < types.Length; i++)
        {
            MethodInfo[] methods = types[i].GetMethods();
            for (int m = 0; m < methods.Length; m++)
            {
                object[] attributes = methods[m].GetCustomAttributes(typeof(SteamPunkConsoleCommand), false);

                for (int a = 0; a < attributes.Length; a++)
                {
                    SteamPunkConsoleCommand macro = (SteamPunkConsoleCommand)attributes[a];
                    if (macro.command != "")
                    {
                        SteamPunkCommandEntry entry = new SteamPunkCommandEntry()
                        {
                            macro = macro, method = methods[m]
                        };
                        commands.Add(macro.command.ToLower(), entry);
                        commandList.Add(entry);
                    }
                }
            }
        }
    }
    SteamPunkCommandEntry GetCommandEntry(string rawCommand)
    {
        if (!rawCommand.Contains(" "))
        {
            SteamPunkCommandEntry entry = null;
            commands.TryGetValue(rawCommand.ToLower(), out entry);
            return(entry);
        }
        else
        {
            string firstSegment = rawCommand.Substring(0, rawCommand.IndexOf(' '));

            SteamPunkCommandEntry entry = null;
            commands.TryGetValue(firstSegment.ToLower(), out entry);

            return(entry);
        }
    }
    void RunCommand(string rawCommand)
    {
        bool willScroll = scrollRect.verticalNormalizedPosition == 0;

        commandHistory.Insert(0, rawCommand);
        consoleInput.text = "";

        SteamPunkCommandEntry entry = GetCommandEntry(rawCommand);

        if (entry == null)
        {
            WriteLine("Error: Invalid Command.");
        }
        else
        {
            object[] parameters = ParseParameters(entry, rawCommand);
            if (parameters != null)
            {
                ExecuteCommand(entry, parameters);
            }
        }
    }
    void ExecuteCommand(SteamPunkCommandEntry cmd, object[] parameters)
    {
        if (cmd.method.IsStatic)
        {
            cmd.method.Invoke(null, parameters);
        }
        else
        {
            Component component = null;
            if (targetGameObject != null)
            {
                component = targetGameObject.GetComponent(cmd.method.DeclaringType);
            }

            if (targetGameObject != null && component != null)
            {
                cmd.method.Invoke(component, parameters);
            }
            else
            {
                WriteLine("Error: [" + cmd.macro.command + "] requires a target with the component [" + cmd.method.DeclaringType + "]");
            }
        }
    }
    object[] ParseParameters(SteamPunkCommandEntry cmd, string rawCommand)
    {
        string currentCommand = rawCommand;

        parts.Clear();

        while (currentCommand.Length != 0)
        {
            int spaceIndex   = currentCommand.IndexOf(" ");
            int literalIndex = currentCommand.IndexOf('\'');
            if (literalIndex == -1)
            {
                literalIndex = int.MaxValue;
            }


            if (spaceIndex != -1)
            {
                int nextSpaceIndex = currentCommand.Substring(spaceIndex).IndexOf(" ");
                if (nextSpaceIndex == spaceIndex + 1)
                {
                    currentCommand = currentCommand.Substring(nextSpaceIndex + 1);
                    continue;
                }
            }

            if (spaceIndex < literalIndex || (spaceIndex == -1 && literalIndex == -1))
            {
                int nextIndex = currentCommand.IndexOf(" ");
                if (nextIndex != -1)
                {
                    string subString = currentCommand.Substring(0, nextIndex);
                    parts.Add(subString);

                    currentCommand = currentCommand.Substring(nextIndex + 1);
                }
                else
                {
                    parts.Add(currentCommand);
                    currentCommand = "";
                }
            }
            else if (literalIndex != -1) // found literal parse.
            {
                string subString = currentCommand.Substring(literalIndex + 1);
                int    endIndex  = subString.IndexOf("'");

                if (endIndex == -1) // invalid endIndex.
                {
                    WriteLine("Error. incorrect string literal.");
                    return(null);
                }

                string literalString = subString.Substring(0, endIndex);
                parts.Add(literalString);

                if (subString.Length < endIndex + 1 + 1)
                {
                    currentCommand = subString.Substring(endIndex + 1);
                }
                else
                {
                    currentCommand = subString.Substring(endIndex + 1 + 1);
                }
            }
        }

        object[]        parameters = new object[parts.Count - 1];
        ParameterInfo[] paramInfo  = cmd.method.GetParameters();
        if (paramInfo.Length != parameters.Length)
        {
            WriteLine("Error. Incorrect parameters count.");
            return(null);
        }

        for (int i = 0; i < parameters.Length; i++)
        {
            if (paramInfo[i].ParameterType == typeof(object))
            {
                parameters[i] = ParseObjectType(parts[i + 1]);
            }
            else if (paramInfo[i].ParameterType == typeof(string))
            {
                parameters[i] = parts[i + 1];
            }
            else if (paramInfo[i].ParameterType == typeof(bool))
            {
                string text = parts[i + 1];
                if (text.ToLower() == "false")
                {
                    parameters[i] = false;
                }
                else if (text.ToLower() == "true")
                {
                    parameters[i] = true;
                }
            }
            else if (paramInfo[i].ParameterType == typeof(int))
            {
                int intParam = 0;
                if (int.TryParse(parts[i + 1], out intParam))
                {
                    parameters[i] = intParam;
                }
                else
                {
                    WriteLine("Error. Invalid parameter. expected int received " + parts[i + 1]);
                    return(null);
                }
            }
            else if (paramInfo[i].ParameterType == typeof(float))
            {
                float floatParam = 0;
                if (float.TryParse(parts[i + 1], out floatParam))
                {
                    parameters[i] = floatParam;
                }
                else
                {
                    WriteLine("Error. Invalid parameter. expected float received " + parts[i + 1]);
                    return(null);
                }
            }
        }
        return(parameters);
    }