@@ -11,17 +11,71 @@ public static class ManagedReferenceContextualPropertyMenu
1111
1212 private const string CopiedPropertyPathKey = "SerializeReferenceExtensions.CopiedPropertyPath" ;
1313 private const string ClipboardKey = "SerializeReferenceExtensions.CopyAndPasteProperty" ;
14+ private const string CopiedPropertyType = "SerializeReferenceExtensions.CopiedPropertyType" ;
1415
1516 private static readonly GUIContent PasteContent = new GUIContent ( "Paste Property" ) ;
1617 private static readonly GUIContent NewInstanceContent = new GUIContent ( "New Instance" ) ;
1718 private static readonly GUIContent ResetAndNewInstanceContent = new GUIContent ( "Reset and New Instance" ) ;
19+
20+ private enum ValuePasteState
21+ {
22+ Unavailable , // No copied value in clipboard
23+ Allowed , // No issues detected
24+ WillChangeType , // Pasting will overwrite type currently assigned to property
25+ IncompatibleType , // The copied type isn't compatible with the target property
26+ TypeNotFound // The copied data referenced a type that cannot be found or is invalid
27+ }
1828
1929 [ InitializeOnLoadMethod ]
2030 private static void Initialize ( )
2131 {
2232 EditorApplication . contextualPropertyMenu += OnContextualPropertyMenu ;
2333 }
2434
35+ private static ValuePasteState GetValuePasteState ( SerializedProperty property )
36+ {
37+ string copiedPropertyPath = SessionState . GetString ( CopiedPropertyPathKey , string . Empty ) ;
38+
39+ if ( string . IsNullOrEmpty ( copiedPropertyPath ) )
40+ {
41+ return ValuePasteState . Unavailable ;
42+ }
43+
44+ string copiedValueTypeName = SessionState . GetString ( CopiedPropertyType , string . Empty ) ;
45+ Type copiedValueType = Type . GetType ( copiedValueTypeName ) ;
46+
47+ if ( copiedValueType == null )
48+ {
49+ return ValuePasteState . TypeNotFound ;
50+ }
51+
52+ object currentPropertyValue = property . managedReferenceValue ;
53+
54+ if ( currentPropertyValue == null )
55+ {
56+ return IsValidTypeFor ( property , copiedValueType )
57+ ? ValuePasteState . Allowed
58+ : ValuePasteState . IncompatibleType ;
59+ }
60+
61+ if ( copiedValueType == currentPropertyValue . GetType ( ) )
62+ {
63+ return ValuePasteState . Allowed ;
64+ }
65+
66+ return IsValidTypeFor ( property , copiedValueType )
67+ ? ValuePasteState . WillChangeType
68+ : ValuePasteState . IncompatibleType ;
69+ }
70+
71+ private static bool IsValidTypeFor ( SerializedProperty property , Type candidateType )
72+ {
73+ Type baseType = ManagedReferenceUtility . GetType ( property . managedReferenceFieldTypename ) ;
74+ if ( baseType == null || candidateType == null ) return false ;
75+
76+ return TypeSearchService . TypeCandiateService . IsCandidateQualified ( baseType , candidateType ) ;
77+ }
78+
2579 private static void OnContextualPropertyMenu ( GenericMenu menu , SerializedProperty property )
2680 {
2781 if ( property . propertyType == SerializedPropertyType . ManagedReference )
@@ -32,14 +86,36 @@ private static void OnContextualPropertyMenu (GenericMenu menu, SerializedProper
3286
3387 menu . AddItem ( new GUIContent ( $ "Copy \" { property . propertyPath } \" property") , false , Copy , clonedProperty ) ;
3488
89+ string typeName = SessionState . GetString ( CopiedPropertyType , string . Empty ) ;
90+
3591 string copiedPropertyPath = SessionState . GetString ( CopiedPropertyPathKey , string . Empty ) ;
36- if ( ! string . IsNullOrEmpty ( copiedPropertyPath ) )
37- {
38- menu . AddItem ( new GUIContent ( $ "Paste \" { copiedPropertyPath } \" property") , false , Paste , clonedProperty ) ;
39- }
40- else
92+
93+ Type targetType = Type . GetType ( typeName ) ;
94+
95+ switch ( GetValuePasteState ( clonedProperty ) )
4196 {
42- menu . AddDisabledItem ( PasteContent ) ;
97+ case ValuePasteState . Allowed :
98+ menu . AddItem ( new GUIContent ( $ "Paste \" { copiedPropertyPath } \" property") , false , Paste , clonedProperty ) ;
99+ break ;
100+ case ValuePasteState . WillChangeType :
101+ menu . AddItem (
102+ new GUIContent (
103+ $ "Paste \" { copiedPropertyPath } \" property (⚠️ Will overwrite type with { targetType ? . Name } )"
104+ ) ,
105+ false ,
106+ Paste ,
107+ clonedProperty
108+ ) ;
109+ break ;
110+ case ValuePasteState . IncompatibleType :
111+ menu . AddDisabledItem ( new GUIContent ( $ "Paste \" { copiedPropertyPath } \" property (❌ Incompatible type { targetType ? . FullName } )") ) ;
112+ break ;
113+ case ValuePasteState . TypeNotFound :
114+ menu . AddDisabledItem ( new GUIContent ( $ "Paste \" { copiedPropertyPath } \" property (❌ Invalid type)") ) ;
115+ break ;
116+ default :
117+ menu . AddDisabledItem ( PasteContent ) ;
118+ break ;
43119 }
44120
45121 menu . AddSeparator ( "" ) ;
@@ -64,19 +140,49 @@ private static void Copy (object customData)
64140 string json = JsonUtility . ToJson ( property . managedReferenceValue ) ;
65141 SessionState . SetString ( CopiedPropertyPathKey , property . propertyPath ) ;
66142 SessionState . SetString ( ClipboardKey , json ) ;
143+ if ( property . managedReferenceValue == null )
144+ {
145+ SessionState . SetString ( CopiedPropertyType , string . Empty ) ;
146+ }
147+ else
148+ {
149+ string typeName = property . managedReferenceValue . GetType ( ) . AssemblyQualifiedName ;
150+ SessionState . SetString ( CopiedPropertyType , typeName ) ;
151+ }
67152 }
68153
69154 private static void Paste ( object customData )
70155 {
71156 SerializedProperty property = ( SerializedProperty ) customData ;
72157 string json = SessionState . GetString ( ClipboardKey , string . Empty ) ;
73- if ( string . IsNullOrEmpty ( json ) )
158+ string typeName = SessionState . GetString ( CopiedPropertyType , string . Empty ) ;
159+
160+ if ( string . IsNullOrEmpty ( json ) || string . IsNullOrEmpty ( typeName ) )
74161 {
75162 return ;
76163 }
77-
78164 Undo . RecordObject ( property . serializedObject . targetObject , "Paste Property" ) ;
79- JsonUtility . FromJsonOverwrite ( json , property . managedReferenceValue ) ;
165+
166+ Type targetType = Type . GetType ( typeName ) ;
167+
168+ if ( targetType == null )
169+ {
170+ Debug . LogError ( $ "Paste Failed: Could not find type { typeName } ") ;
171+ return ;
172+ }
173+
174+ object currentTargetValue = property . managedReferenceValue ;
175+
176+ if ( currentTargetValue == null || targetType != currentTargetValue . GetType ( ) )
177+ {
178+ object newInstance = Activator . CreateInstance ( targetType ) ;
179+ JsonUtility . FromJsonOverwrite ( json , newInstance ) ;
180+ property . managedReferenceValue = newInstance ;
181+ }
182+ else
183+ {
184+ JsonUtility . FromJsonOverwrite ( json , property . managedReferenceValue ) ;
185+ }
80186 property . serializedObject . ApplyModifiedProperties ( ) ;
81187 }
82188
0 commit comments