using JetBrains.Annotations; using LLM.Editor.Helper; using UnityEditor; using UnityEngine; namespace LLM.Editor.Commands { [System.Serializable] public class CreatePrefabParams { public string sourceObjectQuery; public string defaultName; } [UsedImplicitly] public class CreatePrefabCommand : ICommand { private readonly CreatePrefabParams _params; public CreatePrefabCommand(string jsonParams) { _params = jsonParams?.FromJson(); } public CommandOutcome Execute(Data.CommandContext context) { // Step 1: Find the source asset. var guids = AssetDatabase.FindAssets(_params.sourceObjectQuery); if (guids.Length == 0) { Debug.LogError($"[CreatePrefabCommand] No asset found for query: '{_params.sourceObjectQuery}'"); var choice = TryGetAnyModelFromUserChoice(_params.sourceObjectQuery, out var objPath); if (!choice) return CommandOutcome.Error; var relativeObjPath = "Assets" + objPath[Application.dataPath.Length..]; guids = new [] { AssetDatabase.AssetPathToGUID(relativeObjPath) }; } var assetPath = AssetDatabase.GUIDToAssetPath(guids[0]); var sourceAsset = AssetDatabase.LoadAssetAtPath(assetPath); // Step 2: Ask the user for a save path. var path = EditorUtility.SaveFilePanel("Save New Prefab", "Assets/", _params.defaultName, "prefab"); if (string.IsNullOrEmpty(path)) { Debug.LogWarning("[CreatePrefabCommand] User cancelled save dialog. Aborting."); // We could clear the command queue here if we want cancellation to stop everything. return CommandOutcome.Error; } // We need a relative path for AssetDatabase var prefabPath = "Assets" + path[Application.dataPath.Length..]; // Step 3: Create the prefab. var instance = (GameObject)PrefabUtility.InstantiatePrefab(sourceAsset); PrefabUtility.SaveAsPrefabAsset(instance, prefabPath); Object.DestroyImmediate(instance); // Step 4: Store the chosen path in the context for the next commands. context.CurrentSubject = prefabPath; Debug.Log($"[CreatePrefabCommand] Created prefab at '{prefabPath}' from source '{assetPath}'."); return CommandOutcome.Success; } private static bool TryGetAnyModelFromUserChoice(string sourceObjectQuery, out string prefabPath) { 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."; var result = EditorUtility.DisplayDialog($"{sourceObjectQuery} is not found", message, "OK", "No"); if (!result) { prefabPath = null; return false; } prefabPath = EditorUtility.OpenFilePanel("Choose the model to create prefab from", "", "obj,fbx,stl,gltf,glb,usdz,dae"); if (string.IsNullOrEmpty(prefabPath)) { prefabPath = null; return false; } Debug.Log($"[CreatePrefabCommand] User selected '{prefabPath}'."); var isInsideAssets = prefabPath.StartsWith(Application.dataPath); if (isInsideAssets) return true; prefabPath = null; return false; } } }