CreatePrefabCommand.cs 3.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  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 void 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;
  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;
  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. }
  53. private static bool TryGetAnyModelFromUserChoice(string sourceObjectQuery, out string prefabPath)
  54. {
  55. 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.";
  56. var result = EditorUtility.DisplayDialog($"{sourceObjectQuery} is not found", message, "OK", "No");
  57. if (!result)
  58. {
  59. prefabPath = null;
  60. return false;
  61. }
  62. prefabPath = EditorUtility.OpenFilePanel("Choose the model to create prefab from", "", "obj,fbx,stl,gltf,glb,usdz,dae");
  63. if (string.IsNullOrEmpty(prefabPath))
  64. {
  65. prefabPath = null;
  66. return false;
  67. }
  68. Debug.Log($"[CreatePrefabCommand] User selected '{prefabPath}'.");
  69. var isInsideAssets = prefabPath.StartsWith(Application.dataPath);
  70. if (isInsideAssets) return true;
  71. prefabPath = null;
  72. return false;
  73. }
  74. }
  75. }