using UnityEngine; using UnityEditor; using System.IO; namespace BrewMonster { public class PrefabMoverTool : EditorWindow { private Object folderRoot; private string folderRootPath = ""; private string subfolderPath = ""; private Object prefabToMove; private Vector2 scrollPosition; private GUIStyle headerStyle; private GUIStyle boxStyle; [MenuItem("Tools/Prefab Mover")] public static void ShowWindow() { PrefabMoverTool window = GetWindow("Prefab Mover"); window.minSize = new Vector2(400, 300); window.Show(); } private void OnEnable() { // Initialize styles InitializeStyles(); } private void InitializeStyles() { if (headerStyle == null) { headerStyle = new GUIStyle(EditorStyles.boldLabel) { fontSize = 14, alignment = TextAnchor.MiddleLeft, margin = new RectOffset(5, 5, 10, 10) }; } if (boxStyle == null) { boxStyle = new GUIStyle(GUI.skin.box) { padding = new RectOffset(10, 10, 10, 10), margin = new RectOffset(5, 5, 5, 5) }; } } private void OnGUI() { InitializeStyles(); scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition); // Title GUILayout.Label("Prefab Mover Tool", headerStyle); EditorGUILayout.Space(5); // Folder Root Section EditorGUILayout.BeginVertical(boxStyle); { GUILayout.Label("1. Set Folder Root", EditorStyles.boldLabel); EditorGUILayout.HelpBox("Drag and drop a folder from the Project window to set the root folder.", MessageType.Info); EditorGUILayout.BeginHorizontal(); GUILayout.Label("Folder Root:", GUILayout.Width(100)); Object newFolderRoot = EditorGUILayout.ObjectField(folderRoot, typeof(Object), false); if (newFolderRoot != folderRoot) { folderRoot = newFolderRoot; UpdateFolderRootPath(); } EditorGUILayout.EndHorizontal(); if (!string.IsNullOrEmpty(folderRootPath)) { EditorGUILayout.BeginHorizontal(); GUILayout.Label("Path:", GUILayout.Width(100)); EditorGUILayout.SelectableLabel(folderRootPath, EditorStyles.textField, GUILayout.Height(18)); EditorGUILayout.EndHorizontal(); } } EditorGUILayout.EndVertical(); EditorGUILayout.Space(5); // Subfolder Path Section EditorGUILayout.BeginVertical(boxStyle); { GUILayout.Label("2. Set Subfolder Path", EditorStyles.boldLabel); EditorGUILayout.HelpBox("Enter the subfolder path (e.g., 'a/b' or 'a\\b'). This will be created inside the folder root.", MessageType.Info); EditorGUILayout.BeginHorizontal(); GUILayout.Label("Subfolder Path:", GUILayout.Width(100)); subfolderPath = EditorGUILayout.TextField(subfolderPath); EditorGUILayout.EndHorizontal(); if (!string.IsNullOrEmpty(folderRootPath) && !string.IsNullOrEmpty(subfolderPath)) { string fullPath = GetFullTargetPath(); EditorGUILayout.BeginHorizontal(); GUILayout.Label("Full Path:", GUILayout.Width(100)); EditorGUILayout.SelectableLabel(fullPath, EditorStyles.textField, GUILayout.Height(18)); EditorGUILayout.EndHorizontal(); } } EditorGUILayout.EndVertical(); EditorGUILayout.Space(5); // Prefab Section EditorGUILayout.BeginVertical(boxStyle); { GUILayout.Label("3. Select Prefab to Move", EditorStyles.boldLabel); EditorGUILayout.HelpBox("Drag and drop a prefab from the Project window.", MessageType.Info); EditorGUILayout.BeginHorizontal(); GUILayout.Label("Prefab:", GUILayout.Width(100)); prefabToMove = EditorGUILayout.ObjectField(prefabToMove, typeof(GameObject), false); EditorGUILayout.EndHorizontal(); } EditorGUILayout.EndVertical(); EditorGUILayout.Space(10); // Move Button EditorGUI.BeginDisabledGroup(!CanMovePrefab()); { if (GUILayout.Button("Move Prefab", GUILayout.Height(35))) { MovePrefab(); } } EditorGUI.EndDisabledGroup(); if (!CanMovePrefab()) { if (string.IsNullOrEmpty(folderRootPath)) EditorGUILayout.HelpBox("Please set a folder root.", MessageType.Warning); else if (string.IsNullOrEmpty(subfolderPath)) EditorGUILayout.HelpBox("Please enter a subfolder path.", MessageType.Warning); else if (prefabToMove == null) EditorGUILayout.HelpBox("Please select a prefab to move.", MessageType.Warning); } EditorGUILayout.EndScrollView(); } private void UpdateFolderRootPath() { if (folderRoot == null) { folderRootPath = ""; return; } string path = AssetDatabase.GetAssetPath(folderRoot); // Check if it's a folder if (Directory.Exists(path)) { folderRootPath = path; } else if (File.Exists(path)) { // If user dropped a file, use its parent folder folderRootPath = Path.GetDirectoryName(path); EditorUtility.DisplayDialog("Info", "You selected a file. Using its parent folder instead.", "OK"); } else { folderRootPath = ""; EditorUtility.DisplayDialog("Error", "Invalid folder selected.", "OK"); } } private string GetFullTargetPath() { if (string.IsNullOrEmpty(folderRootPath) || string.IsNullOrEmpty(subfolderPath)) return ""; // Normalize the subfolder path (replace backslashes with forward slashes) string normalizedSubPath = subfolderPath.Replace('\\', '/'); // Combine paths string fullPath = Path.Combine(folderRootPath, normalizedSubPath); // Normalize to forward slashes (Unity convention) return fullPath.Replace('\\', '/'); } private bool CanMovePrefab() { return !string.IsNullOrEmpty(folderRootPath) && !string.IsNullOrEmpty(subfolderPath) && prefabToMove != null; } private void MovePrefab() { string prefabPath = AssetDatabase.GetAssetPath(prefabToMove); if (string.IsNullOrEmpty(prefabPath)) { EditorUtility.DisplayDialog("Error", "Cannot get prefab path.", "OK"); return; } // Get the full target path string targetFolder = GetFullTargetPath(); // Create the folder structure if it doesn't exist CreateFolderStructure(targetFolder); // Get prefab filename string prefabFileName = Path.GetFileName(prefabPath); string targetPath = Path.Combine(targetFolder, prefabFileName).Replace('\\', '/'); // Check if file already exists at target if (File.Exists(targetPath)) { bool overwrite = EditorUtility.DisplayDialog( "File Exists", $"A file with the name '{prefabFileName}' already exists at:\n{targetPath}\n\nDo you want to overwrite it?", "Overwrite", "Cancel" ); if (!overwrite) { return; } } // Move the asset string error = AssetDatabase.MoveAsset(prefabPath, targetPath); if (string.IsNullOrEmpty(error)) { AssetDatabase.Refresh(); EditorUtility.DisplayDialog("Success", $"Prefab moved successfully to:\n{targetPath}", "OK"); // Clear the prefab field after successful move prefabToMove = null; // Ping the moved asset in the Project window Object movedAsset = AssetDatabase.LoadAssetAtPath(targetPath); EditorGUIUtility.PingObject(movedAsset); } else { EditorUtility.DisplayDialog("Error", $"Failed to move prefab:\n{error}", "OK"); } } private void CreateFolderStructure(string fullPath) { // Normalize path fullPath = fullPath.Replace('\\', '/'); // Split the path into parts string[] pathParts = fullPath.Split('/'); string currentPath = ""; foreach (string part in pathParts) { if (string.IsNullOrEmpty(part)) continue; string parentPath = currentPath; currentPath = string.IsNullOrEmpty(currentPath) ? part : currentPath + "/" + part; // Check if folder exists if (!Directory.Exists(currentPath)) { // Create the folder using AssetDatabase if (!string.IsNullOrEmpty(parentPath)) { AssetDatabase.CreateFolder(parentPath, part); Debug.Log($"Created folder: {currentPath}"); } } } AssetDatabase.Refresh(); } } }