Skip to content

Commit 6e3f5de

Browse files
committed
Working version of the ScriptableObjectCreationWizard; minor refactor changes
1 parent 31dec26 commit 6e3f5de

10 files changed

Lines changed: 201 additions & 172 deletions

Assets/Editor Toolbox/Editor/Windows/ScriptableObjectCreationWindow.cs

Lines changed: 0 additions & 127 deletions
This file was deleted.
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
using System;
2+
using System.IO;
3+
using System.Reflection;
4+
5+
using UnityEditor;
6+
using UnityEngine;
7+
using Object = UnityEngine.Object;
8+
9+
namespace Toolbox.Editor.Wizards
10+
{
11+
using Toolbox.Editor.Internal;
12+
13+
/// <summary>
14+
/// Utility window responsible for creation of <see cref="ScriptableObject"/>s.
15+
/// Allows to create multiple <see cref="ScriptableObject"/>s of the same <see cref="Type"/>.
16+
/// </summary>
17+
public class ScriptableObjectCreationWizard : ToolboxWizard
18+
{
19+
private class TypeConstraintScriptableObject : TypeConstraintStandard
20+
{
21+
public TypeConstraintScriptableObject() : base(typeof(ScriptableObject), TypeSettings.Class, false, false)
22+
{ }
23+
24+
public override bool IsSatisfied(Type type)
25+
{
26+
return Attribute.IsDefined(type, typeof(CreateAssetMenuAttribute)) && base.IsSatisfied(type);
27+
}
28+
}
29+
30+
[Serializable]
31+
private class CreationData
32+
{
33+
private bool IsDefaultObjectValid()
34+
{
35+
return DefaultObject != null && DefaultObject.GetType() == InstanceType;
36+
}
37+
38+
public void Validate()
39+
{
40+
if (string.IsNullOrEmpty(InstanceName))
41+
{
42+
InstanceName = InstanceType?.Name;
43+
}
44+
45+
InstancesCount = Mathf.Max(InstancesCount, 1);
46+
if (!IsDefaultObjectValid())
47+
{
48+
DefaultObject = null;
49+
}
50+
}
51+
52+
[field: SerializeField]
53+
public Type InstanceType { get; set; }
54+
[field: SerializeField]
55+
public string InstanceName { get; set; }
56+
[field: SerializeField]
57+
public int InstancesCount { get; set; } = 1;
58+
[field: SerializeField, InLineEditor]
59+
[field: Tooltip("Will be used as a blueprint for all created ScriptableObjects.")]
60+
public Object DefaultObject { get; set; }
61+
}
62+
63+
private static readonly TypeConstraintContext sharedConstraint = new TypeConstraintScriptableObject();
64+
private static readonly TypeAppearanceContext sharedAppearance = new TypeAppearanceContext(sharedConstraint, TypeGrouping.None, true);
65+
private static readonly TypeField typeField = new TypeField(sharedConstraint, sharedAppearance);
66+
67+
private readonly CreationData data = new CreationData();
68+
69+
[MenuItem("Assets/Create/Toolbox/ScriptableObject Creation Wizard", priority = 9)]
70+
internal static void Initialize()
71+
{
72+
var window = GetWindow<ScriptableObjectCreationWizard>();
73+
window.titleContent = new GUIContent("ScriptableObject Creation Window");
74+
window.Show();
75+
}
76+
77+
private void DrawSettingsPanel()
78+
{
79+
EditorGUILayout.LabelField("Settings", EditorStyles.boldLabel);
80+
var rect = EditorGUILayout.GetControlRect(true);
81+
typeField.OnGui(rect, true, OnTypeSelected, data.InstanceType);
82+
if (data.InstanceType == null)
83+
{
84+
return;
85+
}
86+
87+
EditorGUI.BeginChangeCheck();
88+
data.InstanceName = EditorGUILayout.TextField("Instance Name", data.InstanceName);
89+
data.InstancesCount = EditorGUILayout.IntField("Instances To Create", data.InstancesCount);
90+
var content = new GUIContent("Default Object", "Will be used as a blueprint for all created ScriptableObjects.");
91+
data.DefaultObject = EditorGUILayout.ObjectField(content, data.DefaultObject, data.InstanceType, false);
92+
if (EditorGUI.EndChangeCheck())
93+
{
94+
OnWizardUpdate();
95+
}
96+
}
97+
98+
private void CreateObjects()
99+
{
100+
CreateObjects(data);
101+
}
102+
103+
private void CreateObjects(CreationData data)
104+
{
105+
data.Validate();
106+
if (data.InstanceType == null)
107+
{
108+
ToolboxEditorLog.LogWarning("Cannot create ScriptableObjects, picked type is null.");
109+
return;
110+
}
111+
112+
var assetPath = GetActiveFolderPath();
113+
if (string.IsNullOrEmpty(assetPath))
114+
{
115+
ToolboxEditorLog.LogWarning("Cannot create ScriptableObjects, path cached from the Project Window is invalid.");
116+
return;
117+
}
118+
119+
var instancesCount = data.InstancesCount;
120+
for (var i = 0; i < instancesCount; i++)
121+
{
122+
var instance = CreateObject(data.InstanceType, data.DefaultObject);
123+
CreateAsset(instance, data.InstanceName, assetPath, i);
124+
}
125+
126+
AssetDatabase.SaveAssets();
127+
ToolboxEditorLog.LogInfo($"New ScriptableObjects created ({instancesCount}), at path: {assetPath}.");
128+
}
129+
130+
private Object CreateObject(Type targetType, Object defaultObject)
131+
{
132+
return defaultObject != null ? Instantiate(defaultObject) : CreateInstance(targetType);
133+
}
134+
135+
private void CreateAsset(Object asset, string assetName, string assetPath, int index)
136+
{
137+
var instanceName = assetName + (index > 0 ? $" [{index}]" : string.Empty);
138+
var instancePath = AssetDatabase.GenerateUniqueAssetPath(Path.Combine(assetPath, $"{instanceName}.asset"));
139+
AssetDatabase.CreateAsset(asset, instancePath);
140+
}
141+
142+
private void OnTypeSelected(Type type)
143+
{
144+
data.InstanceType = type;
145+
var attribute = type?.GetCustomAttribute<CreateAssetMenuAttribute>();
146+
if (attribute != null)
147+
{
148+
data.InstanceName = attribute.fileName;
149+
}
150+
else
151+
{
152+
data.InstanceName = string.Empty;
153+
}
154+
}
155+
156+
private static string GetActiveFolderPath()
157+
{
158+
var projectWindowUtilType = typeof(ProjectWindowUtil);
159+
var getActiveFolderPath = projectWindowUtilType.GetMethod("GetActiveFolderPath", BindingFlags.Static | BindingFlags.NonPublic);
160+
var obj = getActiveFolderPath.Invoke(null, new object[0]);
161+
var pathToCurrentFolder = obj.ToString();
162+
return pathToCurrentFolder;
163+
}
164+
165+
protected override void OnWizardCreate()
166+
{
167+
base.OnWizardCreate();
168+
CreateObjects();
169+
}
170+
171+
protected override void OnWizardUpdate()
172+
{
173+
base.OnWizardUpdate();
174+
data.Validate();
175+
}
176+
177+
protected override void OnWizardGui()
178+
{
179+
base.OnWizardGui();
180+
using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox))
181+
{
182+
DrawSettingsPanel();
183+
}
184+
}
185+
186+
protected override bool CloseOnCreate => false;
187+
}
188+
}

Assets/Editor Toolbox/Editor/Windows/ScriptableObjectCreationWindow.cs.meta renamed to Assets/Editor Toolbox/Editor/Wizards/ScriptableObjectCreationWizard.cs.meta

File renamed without changes.

Assets/Editor Toolbox/Editor/Windows/ToolboxWizard.cs renamed to Assets/Editor Toolbox/Editor/Wizards/ToolboxWizard.cs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,11 @@ private void OnGUI()
4040
if (HandleCreateButton())
4141
{
4242
OnWizardCreate();
43-
Close();
44-
GUIUtility.ExitGUI();
43+
if (CloseOnCreate)
44+
{
45+
Close();
46+
GUIUtility.ExitGUI();
47+
}
4548
}
4649

4750
GUI.enabled = true;
@@ -60,6 +63,11 @@ private void PrepareEditor()
6063

6164
targetEditor = Editor.CreateEditor(this);
6265
targetEditor.hideFlags = HideFlags.HideAndDontSave;
66+
if (targetEditor is ToolboxEditor toolboxEditor)
67+
{
68+
toolboxEditor.IgnoreProperty(PropertyUtility.Defaults.scriptPropertyName);
69+
}
70+
6371
OnWizardUpdate();
6472
}
6573

@@ -88,6 +96,8 @@ public static T DisplayWizard<T>(string title) where T : ToolboxWizard
8896
return GetWindow<T>(true, title);
8997
}
9098

91-
protected bool IsValid { get; set; } = true;
99+
protected virtual bool IsValid { get; set; } = true;
100+
101+
protected virtual bool CloseOnCreate => true;
92102
}
93103
}

Assets/Editor Toolbox/Editor/Windows/ToolboxWizard.cs.meta renamed to Assets/Editor Toolbox/Editor/Wizards/ToolboxWizard.cs.meta

File renamed without changes.

Assets/New Sample Sample SO.asset

Lines changed: 0 additions & 16 deletions
This file was deleted.

Assets/New Sample Sample SO.asset.meta

Lines changed: 0 additions & 8 deletions
This file was deleted.

Assets/SampleSampleSO.cs

Lines changed: 0 additions & 7 deletions
This file was deleted.

0 commit comments

Comments
 (0)