Skip to content

Commit da91f25

Browse files
authored
Replace command dispatcher with CommandRegistry, allow to add custom command handlers. (#261)
* Replace hard coded command dispatcher to command registry * Bug fixed. * bug fixed. * bug fixed. * Bug fixed. * Fix tests.
1 parent b57a3b8 commit da91f25

File tree

3 files changed

+40
-46
lines changed

3 files changed

+40
-46
lines changed

TestProjects/UnityMCPTests/Assets/Tests/EditMode/Tools/CommandRegistryTests.cs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,29 @@ namespace MCPForUnityTests.Editor.Tools
88
public class CommandRegistryTests
99
{
1010
[Test]
11-
public void GetHandler_ReturnsNull_ForUnknownCommand()
11+
public void GetHandler_ThrowException_ForUnknownCommand()
1212
{
1313
var unknown = "HandleDoesNotExist";
14-
var handler = CommandRegistry.GetHandler(unknown);
15-
Assert.IsNull(handler, "Expected null handler for unknown command name.");
14+
try
15+
{
16+
var handler = CommandRegistry.GetHandler(unknown);
17+
Assert.Fail("Should throw InvalidOperation for unknown handler.");
18+
}
19+
catch (InvalidOperationException)
20+
{
21+
22+
}
23+
catch
24+
{
25+
Assert.Fail("Should throw InvalidOperation for unknown handler.");
26+
}
1627
}
1728

1829
[Test]
1930
public void GetHandler_ReturnsManageGameObjectHandler()
2031
{
21-
var handler = CommandRegistry.GetHandler("HandleManageGameObject");
22-
Assert.IsNotNull(handler, "Expected a handler for HandleManageGameObject.");
32+
var handler = CommandRegistry.GetHandler("manage_gameobject");
33+
Assert.IsNotNull(handler, "Expected a handler for manage_gameobject.");
2334

2435
var methodInfo = handler.Method;
2536
Assert.AreEqual("HandleCommand", methodInfo.Name, "Handler method name should be HandleCommand.");

UnityMcpBridge/Editor/MCPForUnityBridge.cs

Lines changed: 5 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ private static bool IsDebugEnabled()
6363
{
6464
try { return EditorPrefs.GetBool("MCPForUnity.DebugLogs", false); } catch { return false; }
6565
}
66-
66+
6767
private static void LogBreadcrumb(string stage)
6868
{
6969
if (IsDebugEnabled())
@@ -82,7 +82,7 @@ private static void LogBreadcrumb(string stage)
8282
public static void StartAutoConnect()
8383
{
8484
Stop(); // Stop current connection
85-
85+
8686
try
8787
{
8888
// Prefer stored project port and start using the robust Start() path (with retries/options)
@@ -314,7 +314,7 @@ public static void Start()
314314
const int maxImmediateRetries = 3;
315315
const int retrySleepMs = 75;
316316
int attempt = 0;
317-
for (;;)
317+
for (; ; )
318318
{
319319
try
320320
{
@@ -755,7 +755,7 @@ private static async System.Threading.Tasks.Task<string> ReadFrameAsUtf8Async(Ne
755755
{
756756
byte[] header = await ReadExactAsync(stream, 8, timeoutMs, cancel).ConfigureAwait(false);
757757
ulong payloadLen = ReadUInt64BigEndian(header);
758-
if (payloadLen > MaxFrameBytes)
758+
if (payloadLen > MaxFrameBytes)
759759
{
760760
throw new System.IO.IOException($"Invalid framed length: {payloadLen}");
761761
}
@@ -1040,25 +1040,7 @@ private static string ExecuteCommand(Command command)
10401040
// Use JObject for parameters as the new handlers likely expect this
10411041
JObject paramsObject = command.@params ?? new JObject();
10421042

1043-
// Route command based on the new tool structure from the refactor plan
1044-
object result = command.type switch
1045-
{
1046-
// Maps the command type (tool name) to the corresponding handler's static HandleCommand method
1047-
// Assumes each handler class has a static method named 'HandleCommand' that takes JObject parameters
1048-
"manage_script" => ManageScript.HandleCommand(paramsObject),
1049-
// Run scene operations on the main thread to avoid deadlocks/hangs (with diagnostics under debug flag)
1050-
"manage_scene" => HandleManageScene(paramsObject)
1051-
?? throw new TimeoutException($"manage_scene timed out after {FrameIOTimeoutMs} ms on main thread"),
1052-
"manage_editor" => ManageEditor.HandleCommand(paramsObject),
1053-
"manage_gameobject" => ManageGameObject.HandleCommand(paramsObject),
1054-
"manage_asset" => ManageAsset.HandleCommand(paramsObject),
1055-
"manage_shader" => ManageShader.HandleCommand(paramsObject),
1056-
"read_console" => ReadConsole.HandleCommand(paramsObject),
1057-
"manage_menu_item" => ManageMenuItem.HandleCommand(paramsObject),
1058-
_ => throw new ArgumentException(
1059-
$"Unknown or unsupported command type: {command.type}"
1060-
),
1061-
};
1043+
object result = CommandRegistry.GetHandler(command.type)(paramsObject);
10621044

10631045
// Standard success response format
10641046
var response = new { status = "success", result };

UnityMcpBridge/Editor/Tools/CommandRegistry.cs

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,14 @@ public static class CommandRegistry
1414
// to the corresponding static HandleCommand method in the appropriate tool class.
1515
private static readonly Dictionary<string, Func<JObject, object>> _handlers = new()
1616
{
17-
{ "HandleManageScript", ManageScript.HandleCommand },
18-
{ "HandleManageScene", ManageScene.HandleCommand },
19-
{ "HandleManageEditor", ManageEditor.HandleCommand },
20-
{ "HandleManageGameObject", ManageGameObject.HandleCommand },
21-
{ "HandleManageAsset", ManageAsset.HandleCommand },
22-
{ "HandleReadConsole", ReadConsole.HandleCommand },
23-
{ "HandleManageMenuItem", ManageMenuItem.HandleCommand },
24-
{ "HandleManageShader", ManageShader.HandleCommand},
17+
{ "manage_script", ManageScript.HandleCommand },
18+
{ "manage_scene", ManageScene.HandleCommand },
19+
{ "manage_editor", ManageEditor.HandleCommand },
20+
{ "manage_gameobject", ManageGameObject.HandleCommand },
21+
{ "manage_asset", ManageAsset.HandleCommand },
22+
{ "read_console", ReadConsole.HandleCommand },
23+
{ "manage_menu_item", ManageMenuItem.HandleCommand },
24+
{ "manage_shader", ManageShader.HandleCommand},
2525
};
2626

2727
/// <summary>
@@ -31,17 +31,18 @@ public static class CommandRegistry
3131
/// <returns>The command handler function if found, null otherwise.</returns>
3232
public static Func<JObject, object> GetHandler(string commandName)
3333
{
34-
// Use case-insensitive comparison for flexibility, although Python side should be consistent
35-
return _handlers.TryGetValue(commandName, out var handler) ? handler : null;
36-
// Consider adding logging here if a handler is not found
37-
/*
38-
if (_handlers.TryGetValue(commandName, out var handler)) {
39-
return handler;
40-
} else {
41-
UnityEngine.Debug.LogError($\"[CommandRegistry] No handler found for command: {commandName}\");
42-
return null;
34+
if (!_handlers.TryGetValue(commandName, out var handler))
35+
{
36+
throw new InvalidOperationException(
37+
$"Unknown or unsupported command type: {commandName}");
4338
}
44-
*/
39+
40+
return handler;
41+
}
42+
43+
public static void Add(string commandName, Func<JObject, object> handler)
44+
{
45+
_handlers.Add(commandName, handler);
4546
}
4647
}
4748
}

0 commit comments

Comments
 (0)