From ba56f1ec9cde49c17f60912be0a2e46671ccdba1 Mon Sep 17 00:00:00 2001 From: Michal Pikulski Date: Wed, 10 Sep 2025 13:47:59 +0200 Subject: [PATCH] Add a prefab creator window --- Assets/Editor/PrefabCreatorWindow.cs | 210 ++++++++++++++++++++++ Assets/Editor/PrefabCreatorWindow.cs.meta | 3 + 2 files changed, 213 insertions(+) create mode 100644 Assets/Editor/PrefabCreatorWindow.cs create mode 100644 Assets/Editor/PrefabCreatorWindow.cs.meta diff --git a/Assets/Editor/PrefabCreatorWindow.cs b/Assets/Editor/PrefabCreatorWindow.cs new file mode 100644 index 00000000..73a76664 --- /dev/null +++ b/Assets/Editor/PrefabCreatorWindow.cs @@ -0,0 +1,210 @@ +using UnityEditor; +using UnityEngine; +using System.IO; + +namespace Editor +{ + public class PrefabCreatorWindow : EditorWindow + { + private string _prefabName = "NewPrefab"; + private string _saveFolderPath = "Assets/Prefabs/Items"; + private string _pickupSoFolderPath = "Assets/Data/Items"; + private string _puzzleSoFolderPath = "Assets/Data/Puzzles"; + private bool _addPickup; + private bool _addCombineWith; + private bool _addSlot; + private bool _addObjective; + + private PickupItemData _pickupData; + private PuzzleStepSO _objectiveData; + private UnityEditor.Editor _soEditor; + + [MenuItem("Tools/Prefab Creator")] + public static void ShowWindow() + { + var window = GetWindow("Prefab Creator"); + window.minSize = new Vector2(400, 400); + // Set default paths if not already set + if (string.IsNullOrEmpty(window._saveFolderPath)) + window._saveFolderPath = "Assets/Prefabs/Items"; + if (string.IsNullOrEmpty(window._pickupSoFolderPath)) + window._pickupSoFolderPath = "Assets/Data/Items"; + if (string.IsNullOrEmpty(window._puzzleSoFolderPath)) + window._puzzleSoFolderPath = "Assets/Data/Puzzles"; + } + + private void OnGUI() + { + EditorGUILayout.LabelField("Prefab Creator", EditorStyles.boldLabel); + _prefabName = EditorGUILayout.TextField("Prefab Name", _prefabName); + // Prefab save folder + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.PrefixLabel("Save Folder"); + EditorGUILayout.SelectableLabel(_saveFolderPath, EditorStyles.textField, GUILayout.Height(EditorGUIUtility.singleLineHeight)); + if (GUILayout.Button("Select...", GUILayout.Width(80))) + { + string selected = EditorUtility.OpenFolderPanel("Select Save Folder", Path.Combine(Application.dataPath, "Prefabs/Items"), ""); + if (!string.IsNullOrEmpty(selected)) + { + if (selected.Replace("\\", "/").Contains(Application.dataPath.Replace("\\", "/"))) + { + _saveFolderPath = "Assets" + selected.Replace("\\", "/").Substring(Application.dataPath.Replace("\\", "/").Length); + } + else + { + EditorUtility.DisplayDialog("Invalid Folder", "Please select a folder inside the Assets directory.", "OK"); + } + } + } + EditorGUILayout.EndHorizontal(); + EditorGUILayout.Space(); + EditorGUILayout.LabelField("Add Components:", EditorStyles.boldLabel); + _addPickup = EditorGUILayout.Toggle("Pickup", _addPickup); + _addCombineWith = EditorGUILayout.Toggle("CombineWithBehavior", _addCombineWith); + _addSlot = EditorGUILayout.Toggle("SlotItemBehavior", _addSlot); + _addObjective = EditorGUILayout.Toggle("ObjectiveStepBehaviour", _addObjective); + EditorGUILayout.Space(); + + if (_addPickup) + { + EditorGUILayout.LabelField("Pickup Data:", EditorStyles.boldLabel); + _pickupData = (PickupItemData)EditorGUILayout.ObjectField("PickupItemData", _pickupData, typeof(PickupItemData), false); + // Pickup SO save folder + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.PrefixLabel("Save To"); + EditorGUILayout.SelectableLabel(_pickupSoFolderPath, EditorStyles.textField, GUILayout.Height(EditorGUIUtility.singleLineHeight)); + if (GUILayout.Button("Select...", GUILayout.Width(80))) + { + string selected = EditorUtility.OpenFolderPanel("Select Pickup Data Folder", Path.Combine(Application.dataPath, "Data/Items"), ""); + if (!string.IsNullOrEmpty(selected)) + { + if (selected.Replace("\\", "/").Contains(Application.dataPath.Replace("\\", "/"))) + { + _pickupSoFolderPath = "Assets" + selected.Replace("\\", "/").Substring(Application.dataPath.Replace("\\", "/").Length); + } + else + { + EditorUtility.DisplayDialog("Invalid Folder", "Please select a folder inside the Assets directory.", "OK"); + } + } + } + EditorGUILayout.EndHorizontal(); + if (_pickupData == null && GUILayout.Button("Create New PickupItemData")) + { + _pickupData = CreateScriptableAsset(_prefabName + "_pickupSO", _pickupSoFolderPath); + } + if (_pickupData != null) + { + DrawScriptableObjectEditor(_pickupData); + } + } + if (_addObjective) + { + EditorGUILayout.LabelField("Objective Data:", EditorStyles.boldLabel); + _objectiveData = (PuzzleStepSO)EditorGUILayout.ObjectField("PuzzleStepSO", _objectiveData, typeof(PuzzleStepSO), false); + // Puzzle SO save folder + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.PrefixLabel("Save To"); + EditorGUILayout.SelectableLabel(_puzzleSoFolderPath, EditorStyles.textField, GUILayout.Height(EditorGUIUtility.singleLineHeight)); + if (GUILayout.Button("Select...", GUILayout.Width(80))) + { + string selected = EditorUtility.OpenFolderPanel("Select Puzzle Data Folder", Path.Combine(Application.dataPath, "Data/Puzzles"), ""); + if (!string.IsNullOrEmpty(selected)) + { + if (selected.Replace("\\", "/").Contains(Application.dataPath.Replace("\\", "/"))) + { + _puzzleSoFolderPath = "Assets" + selected.Replace("\\", "/").Substring(Application.dataPath.Replace("\\", "/").Length); + } + else + { + EditorUtility.DisplayDialog("Invalid Folder", "Please select a folder inside the Assets directory.", "OK"); + } + } + } + EditorGUILayout.EndHorizontal(); + if (_objectiveData == null && GUILayout.Button("Create New PuzzleStepSO")) + { + _objectiveData = CreateScriptableAsset(_prefabName + "_puzzleSO", _puzzleSoFolderPath); + } + if (_objectiveData != null) + { + DrawScriptableObjectEditor(_objectiveData); + } + } + GUILayout.FlexibleSpace(); + GUI.enabled = !string.IsNullOrEmpty(_prefabName) && !string.IsNullOrEmpty(_saveFolderPath); + if (GUILayout.Button("Create Prefab")) + { + CreatePrefab(); + } + GUI.enabled = true; + } + + private void CreatePrefab() + { + var go = new GameObject(_prefabName); + go.AddComponent(); + go.AddComponent(); + int interactableLayer = LayerMask.NameToLayer("Interactable"); + if (interactableLayer != -1) + go.layer = interactableLayer; + go.AddComponent(); + if (_addPickup) + { + var pickup = go.AddComponent(); + pickup.itemData = _pickupData; + } + if (_addCombineWith) + { + go.AddComponent(); + } + if (_addSlot) + { + go.AddComponent(); + } + if (_addObjective) + { + var obj = go.AddComponent(); + obj.stepData = _objectiveData; + } + string prefabPath = Path.Combine(_saveFolderPath, _prefabName + ".prefab").Replace("\\", "/"); + PrefabUtility.SaveAsPrefabAsset(go, prefabPath); + DestroyImmediate(go); + AssetDatabase.Refresh(); + EditorUtility.DisplayDialog("Prefab Created", $"Prefab saved to {prefabPath}", "OK"); + } + private T CreateScriptableAsset(string assetName, string folderPath) where T : ScriptableObject + { + // Ensure folder exists + if (!AssetDatabase.IsValidFolder(folderPath)) + { + Directory.CreateDirectory(Path.Combine(Directory.GetCurrentDirectory(), folderPath)); + AssetDatabase.Refresh(); + } + string folder = !string.IsNullOrEmpty(folderPath) ? folderPath : "Assets"; + string path = AssetDatabase.GenerateUniqueAssetPath(Path.Combine(folder, assetName + ".asset")); + var asset = ScriptableObject.CreateInstance(); + AssetDatabase.CreateAsset(asset, path); + AssetDatabase.SaveAssets(); + AssetDatabase.Refresh(); + Selection.activeObject = asset; + return asset; + } + + private string SanitizeFileName(string fileName) + { + foreach (char c in Path.GetInvalidFileNameChars()) + fileName = fileName.Replace(c, '_'); + return fileName; + } + + private void DrawScriptableObjectEditor(ScriptableObject so) + { + if (so == null) return; + if (_soEditor == null || _soEditor.target != so) + _soEditor = UnityEditor.Editor.CreateEditor(so); + if (_soEditor != null) + _soEditor.OnInspectorGUI(); + } + } +} diff --git a/Assets/Editor/PrefabCreatorWindow.cs.meta b/Assets/Editor/PrefabCreatorWindow.cs.meta new file mode 100644 index 00000000..1adc1155 --- /dev/null +++ b/Assets/Editor/PrefabCreatorWindow.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f67e06e997f642509ba61ea12b0f793e +timeCreated: 1757503955 \ No newline at end of file