public override void OnInspectorGUI() { t = (UdonSharpBehaviour)target; showUdonSettings = (bool)(UTUtils.GetUTSetting("showUdonSettings", UTUtils.UTSettingType.Bool) ?? false); // we force-disable collision transfer for toolkit driven behaviours as it is not applicable if (!nonUBChecked) { nonUBMode = t.gameObject.GetComponent <UdonBehaviour>() == null; nonUBChecked = true; } if (!nonUBMode) { if (UdonSharpEditorUtility.GetBackingUdonBehaviour(t).AllowCollisionOwnershipTransfer) { UdonSharpEditorUtility.GetBackingUdonBehaviour(t).AllowCollisionOwnershipTransfer = false; } } var headerExited = false; EditorGUI.BeginChangeCheck(); showUdonSettings = GUILayout.Toggle(showUdonSettings, "Udon Settings", UTStyles.smallButton); if (EditorGUI.EndChangeCheck()) { UTUtils.SetUTSetting("showUdonSettings", UTUtils.UTSettingType.Bool, showUdonSettings); } if (showUdonSettings) { headerExited = UdonSharpGUI.DrawDefaultUdonSharpBehaviourHeader(t, true); } if (headerExited) { return; } #region Caching if (!cacheBuilt) { tT = t.GetType(); programAsset = UdonSharpEditorUtility.GetUdonSharpProgramAsset(t); behInfo = new UTBehaviourInfo(t); var prop = serializedObject.GetIterator(); var next = prop.NextVisible(true); if (next) { do { if (prop.name == "m_Script") { continue; } if (!fieldCache.ContainsKey(prop.name)) { var newField = new UTField(prop); fieldCache.Add(prop.name, newField); if (newField.isInTabGroup) { if (!tabs.ContainsKey(newField.tabGroupName)) { tabs.Add(newField.tabGroupName, new Dictionary <string, UTFieldType>()); // we only support one tab group per behaviour right now if (!tabsExist) { fieldOrder.Add(newField.tabGroupName, UTFieldType.Tab); tabsExist = true; } } // since tabs can host foldouts - we need to explicitly retarget them // this logic could be generalized if i ever want to make all of this recursive if (newField.isInFoldout) { if (!foldouts.ContainsKey(newField.foldoutName)) { foldouts.Add(newField.foldoutName, new Dictionary <string, UTFieldType>()); tabs[newField.tabGroupName].Add(newField.foldoutName, UTFieldType.Foldout); } AddToFieldOrder(newField, prop, true); continue; } AddToFieldOrder(newField, prop, addToTabGroup: true); continue; } if (newField.isInFoldout) { if (!foldouts.ContainsKey(newField.foldoutName)) { foldouts.Add(newField.foldoutName, new Dictionary <string, UTFieldType>()); fieldOrder.Add(newField.foldoutName, UTFieldType.Foldout); } AddToFieldOrder(newField, prop, true); continue; } AddToFieldOrder(newField, prop); } } while (prop.NextVisible(false)); } cacheBuilt = true; return; } var e = Event.current; if (e.type == EventType.Repaint) { if (firstRepaint) { firstRepaint = false; return; } } #endregion if (behInfo.customName != null || behInfo.helpUrl != null) { EditorGUILayout.BeginHorizontal(); UTStyles.RenderHeader(behInfo.customName != null ? behInfo.customName : behInfo.name); if (behInfo.helpUrl != null) { if (GUILayout.Button("?", GUILayout.Height(26), GUILayout.Width(26))) { Application.OpenURL(behInfo.helpUrl); } } EditorGUILayout.EndHorizontal(); } if (behInfo.helpMsg != null) { UTStyles.RenderNote(behInfo.helpMsg); } if (behInfo.onBeforeEditor != null) { behInfo.onBeforeEditor.Invoke(t, new object[] { serializedObject }); } // handle jagged arrays Undo.RecordObject(t, "Change Properties"); EditorGUI.BeginChangeCheck(); droppedObjects = false; // this method is overrideable by custom code DrawGUI(); if (EditorGUI.EndChangeCheck() || droppedObjects || shouldReserialize) { if (behInfo.onValuesChanged != null) { behInfo.onValuesChanged.Invoke(t, new object[] { serializedObject }); } serializedObject.ApplyModifiedProperties(); } if (droppedObjects) { return; } if (behInfo.onAfterEditor != null) { behInfo.onAfterEditor.Invoke(t, new object[] { serializedObject }); } #region Buttons if (behInfo.buttons != null && !Application.isPlaying && behInfo.buttons.Length > 0) { buttonsExpanded = UTStyles.FoldoutHeader("Editor Methods", buttonsExpanded); if (buttonsExpanded) { EditorGUILayout.BeginVertical(new GUIStyle("helpBox")); foreach (var button in behInfo.buttons) { if (GUILayout.Button(button.Name)) { button.Invoke(t, new object[] {}); } } EditorGUILayout.EndVertical(); } } if (Application.isPlaying && behInfo.udonCustomEvents.Length > 0 && !nonUBMode) { methodsExpanded = UTStyles.FoldoutHeader("Udon Events", methodsExpanded); if (methodsExpanded) { EditorGUILayout.BeginVertical(new GUIStyle("helpBox")); var rowBreak = Mathf.Max(1, Mathf.Min(3, behInfo.udonCustomEvents.Length - 1)); var rowEndI = -100; foreach (var(button, i) in behInfo.udonCustomEvents.WithIndex()) { if (i == rowEndI && i != behInfo.udonCustomEvents.Length - 1) { EditorGUILayout.EndHorizontal(); } if (i % rowBreak == 0 && i != behInfo.udonCustomEvents.Length - 1) { EditorGUILayout.BeginHorizontal(); rowEndI = Math.Min(i + rowBreak, behInfo.udonCustomEvents.Length - 1); } if (GUILayout.Button(button)) { UdonSharpEditorUtility.GetBackingUdonBehaviour(t).SendCustomEvent(button); UdonSharpEditorUtility.CopyUdonToProxy(t); } if (i == behInfo.udonCustomEvents.Length - 1 && rowEndI != -100) { EditorGUILayout.EndHorizontal(); } } EditorGUILayout.EndVertical(); } } #endregion }