Skip to content

Commit a4f4a3c

Browse files
committed
Fix pasting field on null current instance, and added checks for pasting compatibility.
1 parent 5fadcb6 commit a4f4a3c

2 files changed

Lines changed: 122 additions & 11 deletions

File tree

Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/ManagedReferenceContextualPropertyMenu.cs

Lines changed: 115 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch/TypeCandiateService.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,18 @@ public IReadOnlyList<Type> GetDisplayableTypes (Type baseType)
3333

3434
var candiateTypes = typeCandiateProvider.GetTypeCandidates(baseType);
3535
var result = candiateTypes
36-
.Where(intrinsicTypePolicy.IsAllowed)
37-
.Where(t => typeCompatibilityPolicy.IsCompatible(baseType, t))
36+
.Where(t => IsCandidateQualified(baseType, t))
3837
.Distinct()
3938
.ToArray();
4039

4140
typeCache.Add(baseType, result);
4241
return result;
4342
}
43+
44+
public bool IsCandidateQualified (Type baseType, Type candidateType)
45+
{
46+
return intrinsicTypePolicy.IsAllowed(candidateType)
47+
&& typeCompatibilityPolicy.IsCompatible(baseType, candidateType);
48+
}
4449
}
4550
}

0 commit comments

Comments
 (0)