CreatePrefabCommand.cs 3.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. using UnityEngine;
  2. using UnityEditor;
  3. using LLM.Editor.Helper;
  4. using JetBrains.Annotations;
  5. namespace LLM.Editor.Commands
  6. {
  7. [System.Serializable]
  8. public class CreatePrefabParams
  9. {
  10. public string sourceObjectQuery;
  11. public string defaultName;
  12. }
  13. [UsedImplicitly]
  14. public class CreatePrefabCommand : ICommand
  15. {
  16. private readonly CreatePrefabParams _params;
  17. public CreatePrefabCommand(string jsonParams)
  18. {
  19. _params = jsonParams?.FromJson<CreatePrefabParams>();
  20. }
  21. public CommandOutcome Execute(Data.CommandContext context)
  22. {
  23. // Step 1: Find the source asset.
  24. var guids = AssetDatabase.FindAssets(_params.sourceObjectQuery);
  25. if (guids.Length == 0)
  26. {
  27. Debug.LogError($"[CreatePrefabCommand] No asset found for query: '{_params.sourceObjectQuery}'");
  28. var choice = TryGetAnyModelFromUserChoice(_params.sourceObjectQuery, out var objPath);
  29. if (!choice) return CommandOutcome.Error;
  30. var relativeObjPath = "Assets" + objPath[Application.dataPath.Length..];
  31. guids = new [] { AssetDatabase.AssetPathToGUID(relativeObjPath) };
  32. }
  33. var assetPath = AssetDatabase.GUIDToAssetPath(guids[0]);
  34. var sourceAsset = AssetDatabase.LoadAssetAtPath<GameObject>(assetPath);
  35. // Step 2: Ask the user for a save path.
  36. var path = EditorUtility.SaveFilePanel("Save New Prefab", "Assets/", _params.defaultName, "prefab");
  37. if (string.IsNullOrEmpty(path))
  38. {
  39. Debug.LogWarning("[CreatePrefabCommand] User cancelled save dialog. Aborting.");
  40. // We could clear the command queue here if we want cancellation to stop everything.
  41. return CommandOutcome.Error;
  42. }
  43. // We need a relative path for AssetDatabase
  44. var prefabPath = "Assets" + path[Application.dataPath.Length..];
  45. // Step 3: Create the prefab.
  46. var instance = (GameObject)PrefabUtility.InstantiatePrefab(sourceAsset);
  47. PrefabUtility.SaveAsPrefabAsset(instance, prefabPath);
  48. Object.DestroyImmediate(instance);
  49. // Step 4: Store the chosen path in the context for the next commands.
  50. context.CurrentSubject = prefabPath;
  51. Debug.Log($"[CreatePrefabCommand] Created prefab at '{prefabPath}' from source '{assetPath}'.");
  52. return CommandOutcome.Success;
  53. }
  54. private static bool TryGetAnyModelFromUserChoice(string sourceObjectQuery, out string prefabPath)
  55. {
  56. const string message = "Do you want to select a model to create a prefab from? Choosing 'no' will fail to execute forthcoming commands as well.";
  57. var result = EditorUtility.DisplayDialog($"{sourceObjectQuery} is not found", message, "OK", "No");
  58. if (!result)
  59. {
  60. prefabPath = null;
  61. return false;
  62. }
  63. prefabPath = EditorUtility.OpenFilePanel("Choose the model to create prefab from", "", "obj,fbx,stl,gltf,glb,usdz,dae");
  64. if (string.IsNullOrEmpty(prefabPath))
  65. {
  66. prefabPath = null;
  67. return false;
  68. }
  69. Debug.Log($"[CreatePrefabCommand] User selected '{prefabPath}'.");
  70. var isInsideAssets = prefabPath.StartsWith(Application.dataPath);
  71. if (isInsideAssets) return true;
  72. prefabPath = null;
  73. return false;
  74. }
  75. }
  76. }