-
Notifications
You must be signed in to change notification settings - Fork 74
Expand file tree
/
Copy pathGuidReferenceDrawer.cs
More file actions
134 lines (110 loc) · 5.36 KB
/
GuidReferenceDrawer.cs
File metadata and controls
134 lines (110 loc) · 5.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
using UnityEditor;
using UnityEngine;
// Using a property drawer to allow any class to have a field of type GuidRefernce and still get good UX
// If you are writing your own inspector for a class that uses a GuidReference, drawing it with
// EditorLayout.PropertyField(prop) or similar will get this to show up automatically
[CustomPropertyDrawer(typeof(GuidReference))]
public class GuidReferenceDrawer : PropertyDrawer
{
SerializedProperty guidProp;
SerializedProperty sceneProp;
SerializedProperty nameProp;
// cache off GUI content to avoid creating garbage every frame in editor
GUIContent sceneLabel = new GUIContent("Containing Scene", "The target object is expected in this scene asset.");
GUIContent clearButtonGUI = new GUIContent("Clear", "Remove Cross Scene Reference");
// add an extra line to display source scene for targets
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return base.GetPropertyHeight(property, label) + EditorGUIUtility.singleLineHeight;
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
guidProp = property.FindPropertyRelative("serializedGuid");
nameProp = property.FindPropertyRelative("cachedName");
sceneProp = property.FindPropertyRelative("cachedScene");
// Using BeginProperty / EndProperty on the parent property means that
// prefab override logic works on the entire property.
EditorGUI.BeginProperty(position, label, property);
position.height = EditorGUIUtility.singleLineHeight;
// Draw prefix label, returning the new rect we can draw in
var guidCompPosition = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);
System.Guid currentGuid;
GameObject currentGO = null;
// working with array properties is a bit unwieldy
// you have to get the property at each index manually
byte[] byteArray = new byte[16];
int arraySize = guidProp.arraySize;
for( int i = 0; i < arraySize; ++i )
{
var byteProp = guidProp.GetArrayElementAtIndex(i);
byteArray[i] = (byte)byteProp.intValue;
}
currentGuid = new System.Guid(byteArray);
currentGO = GuidManager.ResolveGuid(currentGuid);
GuidComponent currentGuidComponent = currentGO != null ? currentGO.GetComponent<GuidComponent>() : null;
GuidComponent component = null;
if (currentGuid != System.Guid.Empty && currentGuidComponent == null)
{
// if our reference is set, but the target isn't loaded, we display the target and the scene it is in, and provide a way to clear the reference
float buttonWidth = 55.0f;
guidCompPosition.xMax -= buttonWidth;
bool guiEnabled = GUI.enabled;
GUI.enabled = false;
EditorGUI.LabelField(guidCompPosition, new GUIContent(nameProp.stringValue, "Target GameObject is not currently loaded."), EditorStyles.objectField);
GUI.enabled = guiEnabled;
Rect clearButtonRect = new Rect(guidCompPosition);
clearButtonRect.xMin = guidCompPosition.xMax;
clearButtonRect.xMax += buttonWidth;
if (GUI.Button(clearButtonRect, clearButtonGUI, EditorStyles.miniButton))
{
ClearPreviousGuid();
}
}
else
{
// if our object is loaded, we can simply use an object field directly
component = EditorGUI.ObjectField(guidCompPosition, currentGuidComponent, typeof(GuidComponent), true) as GuidComponent;
}
if (currentGuidComponent != null && component == null)
{
ClearPreviousGuid();
}
// if we have a valid reference, draw the scene name of the scene it lives in so users can find it
if (component != null)
{
nameProp.stringValue = component.name;
string scenePath = component.gameObject.scene.path;
sceneProp.objectReferenceValue = AssetDatabase.LoadAssetAtPath<SceneAsset>(scenePath);
// only update the GUID Prop if something changed. This fixes multi-edit on GUID References
if (component != currentGuidComponent)
{
byteArray = component.GetGuid().ToByteArray();
arraySize = guidProp.arraySize;
for (int i = 0; i < arraySize; ++i)
{
var byteProp = guidProp.GetArrayElementAtIndex(i);
byteProp.intValue = byteArray[i];
}
}
}
EditorGUI.indentLevel++;
position.y += EditorGUIUtility.singleLineHeight;
bool cachedGUIState = GUI.enabled;
GUI.enabled = false;
EditorGUI.ObjectField(position, sceneLabel, sceneProp.objectReferenceValue, typeof(SceneAsset), false);
GUI.enabled = cachedGUIState;
EditorGUI.indentLevel--;
EditorGUI.EndProperty();
}
void ClearPreviousGuid()
{
nameProp.stringValue = string.Empty;
sceneProp.objectReferenceValue = null;
int arraySize = guidProp.arraySize;
for (int i = 0; i < arraySize; ++i)
{
var byteProp = guidProp.GetArrayElementAtIndex(i);
byteProp.intValue = 0;
}
}
}