Skip to content

Commit 8ba1aa0

Browse files
committed
Added String Parser and Executer
1 parent 157230b commit 8ba1aa0

File tree

8 files changed

+163
-10
lines changed

8 files changed

+163
-10
lines changed

Runtime/Core/CommandData.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public CommandData(string commandName, MethodInfo methodData,
3434
/// Retrieves the parameters assigned to this command
3535
/// </summary>
3636
/// <returns></returns>
37-
public object[] GetParameters()
37+
public ParameterInfo[] GetParameters()
3838
{
3939
return MethodData.GetParameters();
4040
}

Runtime/Core/CommandExecutor.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
using System;
2+
using Commander.Core;
3+
using UnityEngine;
4+
5+
namespace Commander
6+
{
7+
public static class CommandExecutor
8+
{
9+
public static void ExecuteCommand(string userInput)
10+
{
11+
// Split the users input into its command name and it's arguments
12+
CommandParser.StringToCommand(userInput, out string command, out string[] args);
13+
var parameters = CommandRegistry.GetParameters(command);
14+
15+
// Ensure enough parameters from input is present
16+
if (parameters.Length != args.Length)
17+
{
18+
Debug.Log($"Command {command}: Not enough parameters passed");
19+
return;
20+
}
21+
22+
// Convert the raw input into the methods required parameters
23+
var converted = new object[parameters.Length];
24+
for (int i = 0; i < parameters.Length; i++)
25+
{
26+
var t = parameters[i].ParameterType;
27+
try
28+
{
29+
// Try converting the string into the parameter type
30+
converted[i] = CommandParser.ConvertStringToType(args[i], t);
31+
}
32+
catch (Exception e)
33+
{
34+
// Failed (probably because DataType is not defined)
35+
Debug.LogWarning($"Command '{command}': Failed to convert \"{args[i]}\" to {t.Name}: {e.Message}");
36+
return;
37+
}
38+
}
39+
40+
// Try executing the command
41+
CommandRegistry.TryExecuteCommand(command, converted);
42+
}
43+
}
44+
}

Runtime/Core/CommandExecutor.cs.meta

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Runtime/Core/CommandRegistry.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,11 +128,25 @@ public static bool TryExecuteCommand(string commandName, object[] args)
128128
Debug.Log($"[CommandRegistry] No command with name '{commandName}'");
129129
return false;
130130
}
131-
131+
132132
// Try executing command from CommandData
133133
return data.Execute(args);
134134
}
135135

136+
/// <summary>
137+
/// Gets the parameters of a given command and it's linked method
138+
/// </summary>
139+
/// <param name="commandName">The command name</param>
140+
/// <returns>ParameterInfo array</returns>
141+
public static ParameterInfo[] GetParameters(string commandName)
142+
{
143+
if (_registeredCommands.TryGetValue(commandName, out var data))
144+
{
145+
return data.GetParameters();
146+
}
147+
return null;
148+
}
149+
136150
#endregion
137151
}
138152
}

Runtime/Parser.meta

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Runtime/Parser/CommandParser.cs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Globalization;
4+
using System.Linq;
5+
using System.Text.RegularExpressions;
6+
7+
namespace Commander.Core
8+
{
9+
public static class CommandParser
10+
{
11+
private static readonly Regex _tokeniser = new Regex(
12+
@"[\""].+?[\""]|['].+?[']|[^ ]+",
13+
RegexOptions.Compiled);
14+
15+
/// <summary>
16+
/// Takes the raw input of the user and returns the command name and it's converted parameters
17+
/// </summary>
18+
/// <param name="rawInput">Input sent by user</param>
19+
/// <param name="command">The commands name</param>
20+
/// <param name="args">The command parameters</param>
21+
public static void StringToCommand(string rawInput, out string command, out string[] args)
22+
{
23+
// Skip empty input
24+
if (string.IsNullOrWhiteSpace(rawInput))
25+
{
26+
command = "";
27+
args = Array.Empty<string>();
28+
return;
29+
}
30+
31+
// Keep strings which are surrounded by " or '
32+
var matches = _tokeniser.Matches(rawInput.Trim());
33+
var tokens = new List<string>(matches.Count);
34+
foreach (Match m in matches)
35+
{
36+
var t = m.Value;
37+
38+
// Strip the quotes
39+
if ((t.StartsWith("\"") && t.EndsWith("\"")) || (t.StartsWith("'") && t.EndsWith("'")))
40+
{
41+
t = t.Substring(1, t.Length - 2);
42+
}
43+
tokens.Add(t);
44+
}
45+
46+
// Skip if we found no tokens from past stripping
47+
if (tokens.Count == 0)
48+
{
49+
command = "";
50+
args = Array.Empty<string>();
51+
return;
52+
}
53+
54+
command = tokens[0];
55+
args = tokens.Skip(1).ToArray();
56+
}
57+
58+
/// <summary>
59+
/// Convert string into it's given type. E.g "1" = int, "STATE_IDLE" = enum, etc...
60+
/// </summary>
61+
/// <param name="raw">The raw string</param>
62+
/// <param name="targetType">Type of data we will convert to</param>
63+
/// <returns></returns>
64+
/// <exception cref="InvalidOperationException"></exception>
65+
public static object ConvertStringToType(string raw, Type targetType)
66+
{
67+
// String Conversion
68+
if (targetType == typeof(string))
69+
{
70+
return raw;
71+
}
72+
73+
// Enum Conversion
74+
if (targetType.IsEnum)
75+
{
76+
return Enum.Parse(targetType, raw, ignoreCase: true);
77+
}
78+
79+
// IConvertible Primitive Converison
80+
if (typeof(IConvertible).IsAssignableFrom(targetType))
81+
{
82+
return Convert.ChangeType(raw, targetType, CultureInfo.InvariantCulture);
83+
}
84+
85+
// Data needs
86+
throw new InvalidOperationException($"No converter for type {targetType.Name}! Create conversion in .../Commander/Runtime/Core/CommandParse.cs");
87+
}
88+
}
89+
}

Runtime/Parser/CommandParser.cs.meta

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Samples/Simple Commands/TestCommand.cs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,12 @@ public class TestCommand : MonoBehaviour
77
void Awake()
88
{
99
CommandRegistry.RegisterInstanceCommands(this);
10-
CommandRegistry.TryExecuteCommand("publictestcommand", new object[2] { "Test", "test" });
10+
CommandExecutor.ExecuteCommand("test enum 'hello world'");
1111
}
1212

13-
[Command("PublicTestCommand", CommandRole.Any)]
13+
[Command("test", CommandRole.Any)]
1414
public void PublicMyCommand(int a, string b)
1515
{
1616
Debug.Log($"Command executed with parameters: a = {a}, b = {b}");
1717
}
18-
19-
[Command("PrivateTestCommand", CommandRole.Any)]
20-
private void PrivateMyCommand(int a, string b)
21-
{
22-
Debug.Log($"Command executed with parameters: a = {a}, b = {b}");
23-
}
2418
}

0 commit comments

Comments
 (0)