33 using System ;
44 using System . IO ;
55 using System . Reflection ;
6+ using MonoBehaviours ;
67 using ScriptableObjects ;
78 using SolidUtilities ;
89 using SolidUtilities . Editor ;
910 using SolidUtilities . UnityEditorInternals ;
11+ using TypeReferences ;
1012 using UnityEditor ;
1113 using UnityEngine ;
14+ using Util ;
15+ using Object = UnityEngine . Object ;
1216
1317#if ODIN_INSPECTOR
1418 using Sirenix . OdinInspector . Editor ;
@@ -24,6 +28,9 @@ public class CreatableObjectDrawer : PropertyDrawer
2428 private static readonly string _assetsPath ;
2529 private static readonly string _packagesPath ;
2630
31+ private static CreatableObjectDrawer _instance ;
32+ public static CreatableObjectDrawer Instance => _instance ??= new CreatableObjectDrawer ( ) ;
33+
2734 static CreatableObjectDrawer ( )
2835 {
2936 _projectPath = Directory . GetCurrentDirectory ( ) ;
@@ -35,9 +42,15 @@ public override void OnGUI(Rect rect, SerializedProperty property, GUIContent la
3542 {
3643 ( _ , Type type ) = property . GetFieldInfoAndType ( ) ;
3744
38- if ( ! type . InheritsFrom ( typeof ( ScriptableObject ) ) )
45+ if ( ! type . InheritsFrom ( typeof ( ScriptableObject ) ) && ! type . InheritsFrom ( typeof ( MonoBehaviour ) ) )
46+ {
47+ EditorGUILayoutHelper . DrawErrorMessage ( "Creatable attribute can only be used on ScriptableObjects and MonoBehaviours." ) ;
48+ return ;
49+ }
50+
51+ if ( type . IsAbstract )
3952 {
40- EditorGUILayoutHelper . DrawErrorMessage ( "Creatable attribute can only be used on ScriptableObjects ." ) ;
53+ EditorGUILayoutHelper . DrawErrorMessage ( "Creatable attribute can only be used on fields of non-abstract type ." ) ;
4154 return ;
4255 }
4356
@@ -57,6 +70,21 @@ public override void OnGUI(Rect rect, SerializedProperty property, GUIContent la
5770 if ( ! GUI . Button ( buttonRect , "+" ) )
5871 return ;
5972
73+ // this is for scriptable objects
74+ if ( type . InheritsFrom ( typeof ( ScriptableObject ) ) )
75+ {
76+ CreateScriptableObject ( property , type ) ;
77+ }
78+ else
79+ {
80+ CreateMonoBehaviour ( property , type ) ;
81+ }
82+ }
83+
84+ #region Create Scriptable Object
85+
86+ private void CreateScriptableObject ( SerializedProperty property , Type type )
87+ {
6088 var asset = CreateAsset ( property , type ) ;
6189 property . objectReferenceValue = asset ;
6290 EditorGUIUtility . PingObject ( asset ) ;
@@ -66,7 +94,7 @@ private ScriptableObject CreateAsset(SerializedProperty property, Type type)
6694 {
6795 var folderPath = ProjectWindowUtilProxy . GetActiveFolderPath ( ) ;
6896
69- bool isGeneric = type . InheritsFrom ( typeof ( ScriptableObject ) ) && type . IsGenericType && ! type . IsAbstract ;
97+ bool isGeneric = type . IsGenericType ;
7098
7199 string fileName = isGeneric
72100 ? type . GetCustomAttribute < CreateGenericAssetMenuAttribute > ( ) ? . FileName
@@ -115,5 +143,75 @@ private bool HasCorrectExtension(string path)
115143 Debug . LogError ( "The file must have the '.asset' extension." ) ;
116144 return false ;
117145 }
146+
147+ #endregion
148+
149+ #region Create MonoBehaviour
150+
151+ private const string TargetComponentKey = "CreatableObjectDrawer_TargetComponent" ;
152+ private const string PropertyPathKey = "CreatableObjectDrawer_PropertyPath" ;
153+ private const string AddedComponentTypeKey = "CreatableObjectDrawer_AddedComponent" ;
154+
155+ private void CreateMonoBehaviour ( SerializedProperty property , Type type )
156+ {
157+ var parentComponent = property . serializedObject . targetObject as MonoBehaviour ;
158+
159+ if ( parentComponent == null )
160+ return ;
161+
162+ var gameObject = parentComponent . gameObject ;
163+
164+ var component = AddComponentHelper . AddComponent ( gameObject , type , out bool reloadRequired ) ;
165+
166+ if ( reloadRequired )
167+ {
168+ PersistentStorage . SaveData ( TargetComponentKey , property . serializedObject . targetObject ) ;
169+ PersistentStorage . SaveData ( PropertyPathKey , property . propertyPath ) ;
170+ PersistentStorage . SaveData ( AddedComponentTypeKey , new TypeReference ( type ) ) ;
171+ PersistentStorage . ExecuteOnScriptsReload ( OnAfterComponentAdded ) ;
172+ AssetDatabase . Refresh ( ) ;
173+ }
174+ else
175+ {
176+ property . objectReferenceValue = component ;
177+ }
178+ }
179+
180+ private static void OnAfterComponentAdded ( )
181+ {
182+ try
183+ {
184+ var targetComponent = PersistentStorage . GetData < Object > ( TargetComponentKey ) ;
185+ var propertyPath = PersistentStorage . GetData < string > ( PropertyPathKey ) ;
186+ var componentType = PersistentStorage . GetData < TypeReference > ( AddedComponentTypeKey ) . Type ;
187+
188+ var addedComponent = ( ( MonoBehaviour ) targetComponent ) . gameObject . GetComponent ( componentType ) ;
189+ var property = Editor . CreateEditor ( targetComponent ) . serializedObject . FindProperty ( propertyPath ) ;
190+ property . objectReferenceValue = addedComponent ;
191+ property . serializedObject . ApplyModifiedProperties ( ) ;
192+ }
193+ finally
194+ {
195+ PersistentStorage . DeleteData ( TargetComponentKey ) ;
196+ PersistentStorage . DeleteData ( PropertyPathKey ) ;
197+ PersistentStorage . DeleteData ( AddedComponentTypeKey ) ;
198+ }
199+ }
200+
201+ #endregion
202+ }
203+
204+ public static class AddComponentHelper
205+ {
206+ public static Component AddComponent ( GameObject gameObject , Type componentType , out bool reloadRequired )
207+ {
208+ if ( ! componentType . IsGenericType )
209+ {
210+ reloadRequired = false ;
211+ return Undo . AddComponent ( gameObject , componentType ) ;
212+ }
213+
214+ return GenericBehaviourCreator . AddComponent ( null , gameObject , componentType . GetGenericTypeDefinition ( ) , componentType . GetGenericArguments ( ) , out reloadRequired ) ;
215+ }
118216 }
119217}
0 commit comments