CommandExecutor.cs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. using System;
  2. using System.Linq;
  3. using UnityEditor;
  4. using UnityEngine;
  5. using LLM.Editor.Data;
  6. using System.Reflection;
  7. using LLM.Editor.Commands;
  8. using System.Collections.Generic;
  9. namespace LLM.Editor.Core
  10. {
  11. /// <summary>
  12. /// Responsible for finding and executing commands from the session queue.
  13. /// </summary>
  14. [InitializeOnLoad]
  15. public static class CommandExecutor
  16. {
  17. private static List<CommandData> _commandQueue;
  18. private static CommandContext _currentContext;
  19. public static Action OnQueueUpdated;
  20. static CommandExecutor()
  21. {
  22. // This will run when the editor loads, including after a recompile.
  23. EditorApplication.delayCall += Initialize;
  24. }
  25. private static void Initialize()
  26. {
  27. Debug.Log("[CommandExecutor] Initializing...");
  28. if (SessionManager.HasActiveSession())
  29. {
  30. _commandQueue = SessionManager.LoadCommandQueue();
  31. if (!_commandQueue.Any()) return;
  32. Debug.Log($"[CommandExecutor] Resuming session with {_commandQueue.Count} commands in queue.");
  33. _currentContext = new CommandContext();
  34. OnQueueUpdated?.Invoke();
  35. }
  36. else
  37. {
  38. _commandQueue = new List<CommandData>();
  39. }
  40. }
  41. public static void SetQueue(List<CommandData> commands)
  42. {
  43. _commandQueue = commands;
  44. _currentContext = new CommandContext();
  45. SessionManager.SaveCommandQueue(_commandQueue);
  46. OnQueueUpdated?.Invoke();
  47. }
  48. public static bool HasPendingCommands() => _commandQueue != null && _commandQueue.Any();
  49. public static CommandData GetNextCommand() => HasPendingCommands() ? _commandQueue.First() : null;
  50. public static void ExecuteNextCommand()
  51. {
  52. if (!HasPendingCommands())
  53. {
  54. Debug.LogWarning("[CommandExecutor] No commands to execute.");
  55. return;
  56. }
  57. var commandData = _commandQueue.First();
  58. _commandQueue.RemoveAt(0);
  59. try
  60. {
  61. var commandInstance = CreateCommandInstance(commandData);
  62. if (commandInstance != null)
  63. {
  64. Debug.Log($"[CommandExecutor] Executing: {commandData.commandName}");
  65. commandInstance.Execute(_currentContext);
  66. }
  67. else
  68. {
  69. Debug.LogError($"[CommandExecutor] Could not create instance for command: {commandData.commandName}");
  70. }
  71. }
  72. catch(Exception e)
  73. {
  74. Debug.LogError($"[CommandExecutor] Failed to execute command '{commandData.commandName}'. Error: {e.Message}");
  75. }
  76. // Save the modified queue
  77. SessionManager.SaveCommandQueue(_commandQueue);
  78. OnQueueUpdated?.Invoke();
  79. }
  80. private static ICommand CreateCommandInstance(CommandData data)
  81. {
  82. // Use reflection to find the command class in the Commands namespace
  83. // This makes the system extensible without needing a giant switch statement.
  84. var commandClassName = $"{data.commandName}Command";
  85. var type = Assembly.GetExecutingAssembly().GetTypes()
  86. .FirstOrDefault(t => t.Namespace == "LLM.Editor.Commands" && t.Name == commandClassName);
  87. if (type != null)
  88. {
  89. // Assumes commands have a constructor that takes a single string (the JSON parameters)
  90. return (ICommand)Activator.CreateInstance(type, data.jsonData);
  91. }
  92. Debug.LogError($"[CommandExecutor] Command type '{commandClassName}' not found.");
  93. return null;
  94. }
  95. }
  96. }