public SharedVariablePresetListDrawer(SerializedObject serializedObject, SerializedProperty presetVariables, ISharedVariableHandler variableHandler, Func <int, Type> elementTypeGetter) { float lineHeight = EditorGUIUtility.singleLineHeight; float lineHeightSpace = lineHeight + EditorGUIUtility.standardVerticalSpacing; presetVariableList = new ReorderableList(serializedObject, presetVariables, true, true, true, true) { drawElementCallback = (rect, index, isFocused, isActive) => { serializedObject.UpdateIfRequiredOrScript(); EditorGUI.BeginChangeCheck(); SerializedProperty variable = presetVariables.GetArrayElementAtIndex(index); Type type = elementTypeGetter(index); SerializedProperty name = variable.FindPropertyRelative("_name"); List <SharedVariable> variables = variableHandler.GetVariables(type); EditorGUI.PropertyField(new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight), variable, new GUIContent(string.IsNullOrEmpty(name.stringValue) ? $"({type.Name})" : name.stringValue)); Rect valueRect = new Rect(rect.x, rect.y + lineHeightSpace, rect.width - 46, lineHeight); if (variable.isExpanded) { //这里的isShared用来标识变量名的填写方式,不作正常用途 SerializedProperty isShared = variable.FindPropertyRelative("isShared"); int typeIndex = isShared.boolValue ? 1 : 0; typeIndex = EditorGUI.Popup(new Rect(rect.x + rect.width - 44, rect.y + lineHeightSpace, 44, lineHeight), typeIndex, varType); switch (typeIndex) { case 0: isShared.boolValue = false; break; case 1: isShared.boolValue = true; break; } if (typeIndex == 1) { string[] varNames = variables.Select(x => x.name).ToArray(); bool noNames = varNames.Length < 1; int nameIndex = Array.IndexOf(varNames, name.stringValue); if (noNames) { varNames = varNames.Prepend("未选择").ToArray(); } if (nameIndex < 0) { nameIndex = 0; } nameIndex = EditorGUI.Popup(valueRect, "关联变量名称", nameIndex, varNames); string nameStr = name.stringValue; if (!noNames && nameIndex >= 0 && nameIndex < variables.Count) { nameStr = varNames[nameIndex]; } name.stringValue = nameStr; } else { EditorGUI.PropertyField(valueRect, name, new GUIContent("关联变量名称")); } SerializedProperty value = variable.FindPropertyRelative("value"); EditorGUI.PropertyField(new Rect(rect.x, rect.y + lineHeightSpace * 2, rect.width, EditorGUI.GetPropertyHeight(value, true) - lineHeight), value, new GUIContent("预设值"), true); } if (EditorGUI.EndChangeCheck()) { serializedObject.ApplyModifiedProperties(); } }, elementHeightCallback = (index) => { if (index >= presetVariables.arraySize) { return(0); } SerializedProperty variable = presetVariables.GetArrayElementAtIndex(index); if (variable.isExpanded) { return(EditorGUI.GetPropertyHeight(presetVariables.GetArrayElementAtIndex(index), true)); } else { return(lineHeightSpace); } }, onAddDropdownCallback = (rect, list) => { GenericMenu menu = new GenericMenu(); foreach (var type in TypeCache.GetTypesDerivedFrom <SharedVariable>()) { if (!type.IsGenericType) { menu.AddItem(new GUIContent($"自定义/{type.Name}"), false, () => { InsertNewVariable(type, false); }); } } if (ZetanUtility.Editor.TryGetValue(presetVariables, out var value)) { List <SharedVariable> variables = value as List <SharedVariable>; foreach (var variable in variableHandler.Variables) { Type type = variable.GetType(); if (!variables.Exists(x => x.name == variable.name && x.GetType() == type)) { menu.AddItem(new GUIContent(variable.name), false, () => { InsertNewVariable(type, true, variable.name); }); } } } menu.DropDown(rect); }, onRemoveCallback = (list) => { serializedObject.UpdateIfRequiredOrScript(); SerializedProperty _name = presetVariables.GetArrayElementAtIndex(list.index).FindPropertyRelative("_name"); if (EditorUtility.DisplayDialog("删除变量", $"确定要删除预设 {_name.stringValue} 吗?", "确定", "取消")) { list.serializedProperty.DeleteArrayElementAtIndex(list.index); GUIUtility.ExitGUI(); } serializedObject.ApplyModifiedProperties(); }, onCanRemoveCallback = (list) => { return(list.IsSelected(list.index)); }, drawHeaderCallback = (rect) => { EditorGUI.LabelField(rect, $"变量预设列表"); }, serializedProperty = presetVariables }; void InsertNewVariable(Type type, bool select, string name = "") { if (ZetanUtility.Editor.TryGetValue(presetVariables, out var value) && value is List <SharedVariable> list) { SharedVariable variable = (SharedVariable)Activator.CreateInstance(type); variable.GetType().GetField("_name", ZetanUtility.CommonBindingFlags).SetValue(variable, name); variable.isShared = select; list.Add(variable); presetVariableList.Select(presetVariables.arraySize); } else { Debug.LogError("添加失败,请检查变量列表归属"); } } }
void DrawRightPanel() { EditorGUIUtility.labelWidth = k_RightPanelLabelWidth; EditorGUILayout.BeginVertical(); m_RightScrollPosition = EditorGUILayout.BeginScrollView(m_RightScrollPosition, GUILayout.ExpandHeight(true), GUILayout.ExpandWidth(true)); using (new EditorGUILayout.HorizontalScope()) { var titleRect = EditorGUILayout.GetControlRect(true, k_TitleTextHeight); EditorGUI.LabelField(titleRect, "Probe Volume Settings", m_SubtitleStyle); var debugButtonRect = EditorGUILayout.GetControlRect(true, k_TitleTextHeight, GUILayout.Width(k_TitleTextHeight)); if (GUI.Button(debugButtonRect, Styles.debugButton)) { OpenProbeVolumeDebugPanel(); } } EditorGUILayout.Space(); SanitizeScenes(); m_ScenesInSet.DoLayoutList(); EditorGUILayout.Space(); m_Scenarios.Select(GetCurrentBakingSet().lightingScenarios.IndexOf(ProbeReferenceVolume.instance.lightingScenario)); m_Scenarios.DoLayoutList(); var set = GetCurrentBakingSet(); var sceneGUID = sceneData.GetFirstProbeVolumeSceneGUID(set); if (sceneGUID != null) { EditorGUILayout.Space(); // Show only the profile from the first scene of the set (they all should be the same) if (set.profile == null) { EditorUtility.DisplayDialog("Missing Probe Volume Profile Asset!", $"We couldn't find the asset profile associated with the Baking Set '{set.name}'.\nDo you want to create a new one?", "Yes"); set.profile = ScriptableObject.CreateInstance <ProbeReferenceVolumeProfile>(); // Delay asset creation, workaround to avoid creating assets while importing another one (SRP can be called from asset import). EditorApplication.update += DelayCreateAsset; void DelayCreateAsset() { EditorApplication.update -= DelayCreateAsset; ProjectWindowUtil.CreateAsset(set.profile, set.name + ".asset"); } } if (m_ProbeVolumeProfileEditor == null) { m_ProbeVolumeProfileEditor = Editor.CreateEditor(set.profile); } if (m_ProbeVolumeProfileEditor.target != set.profile) { Editor.CreateCachedEditor(set.profile, m_ProbeVolumeProfileEditor.GetType(), ref m_ProbeVolumeProfileEditor); } var serializedSets = m_ProbeSceneData.FindPropertyRelative("serializedBakingSets"); var serializedSet = serializedSets.GetArrayElementAtIndex(m_BakingSets.index); var probeVolumeBakingSettings = serializedSet.FindPropertyRelative("settings"); EditorGUILayout.LabelField("Probe Placement", EditorStyles.boldLabel); EditorGUI.indentLevel++; m_ProbeVolumeProfileEditor.OnInspectorGUI(); EditorGUILayout.Space(3, true); EditorGUILayout.PropertyField(probeVolumeBakingSettings); EditorGUI.indentLevel--; // Clamp to make sure minimum we set for dilation distance is min probe distance set.settings.dilationSettings.dilationDistance = Mathf.Max(set.profile.minDistanceBetweenProbes, set.settings.dilationSettings.dilationDistance); EditorGUILayout.Space(); EditorGUILayout.Space(); EditorGUILayout.LabelField(Styles.stats, EditorStyles.boldLabel); { EditorGUI.indentLevel++; if (AllSetScenesAreLoaded()) { long sharedCost = 0, scenarioCost = 0; foreach (var data in ProbeReferenceVolume.instance.perSceneDataList) { if (!set.sceneGUIDs.Contains(sceneData.GetSceneGUID(data.gameObject.scene))) { continue; } scenarioCost += data.GetDiskSizeOfScenarioData(ProbeReferenceVolume.instance.lightingScenario); sharedCost += data.GetDiskSizeOfSharedData(); foreach (var scenario in set.lightingScenarios) { sharedCost += data.GetDiskSizeOfScenarioData(scenario); } } EditorGUILayout.LabelField(Styles.scenarioCostStat, EditorGUIUtility.TrTextContent((scenarioCost / (float)(1000 * 1000)).ToString("F1") + " MB")); EditorGUILayout.LabelField(Styles.totalCostStat, EditorGUIUtility.TrTextContent((sharedCost / (float)(1000 * 1000)).ToString("F1") + " MB")); } else { EditorGUILayout.HelpBox("Somes scenes of the set are not currently loaded. Stats can't be displayed", MessageType.Info); } EditorGUI.indentLevel--; } } else { EditorGUILayout.HelpBox("You need to assign at least one scene with probe volumes to configure the baking settings", MessageType.Error, true); } EditorGUILayout.EndScrollView(); EditorGUILayout.Space(); DrawBakeButton(); EditorGUILayout.EndVertical(); }
public SharedVariableListDrawer(SerializedObject serializedObject, SerializedProperty serializedVariables, bool isShared) { variableList = new ReorderableList(serializedObject, serializedVariables, true, true, true, true) { drawElementCallback = (rect, index, isFocused, isActive) => { if (serializedObject.targetObject) { serializedObject.UpdateIfRequiredOrScript(); EditorGUI.BeginChangeCheck(); SerializedProperty variable = serializedVariables.GetArrayElementAtIndex(index); EditorGUI.PropertyField(new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight), variable, true); if (EditorGUI.EndChangeCheck()) { serializedObject.ApplyModifiedProperties(); } if (ZetanUtility.Editor.TryGetValue(variable, out var value) && value is SharedVariable sv && sv.GetType().GetField("linkedVariables", ZetanUtility.CommonBindingFlags).GetValue(sv) is HashSet <SharedVariable> lvs) { foreach (var lv in lvs) { lv.GetType().GetField("_name", ZetanUtility.CommonBindingFlags).SetValue(lv, sv.name); } } } }, elementHeightCallback = (index) => { if (index >= serializedVariables.arraySize) { return(0); } return(EditorGUI.GetPropertyHeight(serializedVariables.GetArrayElementAtIndex(index), true)); }, onAddDropdownCallback = (rect, list) => { GenericMenu menu = new GenericMenu(); menu.AddItem(new GUIContent("新建类型"), false, CreateVariableScript); menu.AddSeparator(""); foreach (var type in TypeCache.GetTypesDerivedFrom <SharedVariable>()) { if (!type.IsGenericType) { menu.AddItem(new GUIContent(type.Name), false, () => { InsertNewVariable(type); }); } } menu.DropDown(rect); }, onRemoveCallback = (list) => { serializedObject.UpdateIfRequiredOrScript(); SerializedProperty _name = serializedVariables.GetArrayElementAtIndex(list.index).FindPropertyRelative("_name"); if (EditorUtility.DisplayDialog("删除变量", $"确定要删除变量 {_name.stringValue} 吗?", "确定", "取消")) { if (ZetanUtility.Editor.TryGetValue(serializedVariables.GetArrayElementAtIndex(list.index), out var value) && value is SharedVariable sv && sv.GetType().GetField("linkedVariables", ZetanUtility.CommonBindingFlags).GetValue(sv) is HashSet <SharedVariable> lvs) { foreach (var lv in lvs) { lv.GetType().GetField("_name", ZetanUtility.CommonBindingFlags).SetValue(lv, string.Empty); lv.GetType().GetField("linkedVariable", ZetanUtility.CommonBindingFlags).SetValue(lv, null); } } list.serializedProperty.DeleteArrayElementAtIndex(list.index); } serializedObject.ApplyModifiedProperties(); }, onCanRemoveCallback = (list) => { return(list.IsSelected(list.index)); }, drawHeaderCallback = (rect) => { string typeMsg = EditorUtility.IsPersistent(serializedObject.targetObject) ? "(不可引用场景对象)" : "(可引用场景对象)"; EditorGUI.LabelField(rect, $"{(isShared ? "共享变量列表" : "全局变量列表")}{typeMsg}"); }, serializedProperty = serializedVariables }; void InsertNewVariable(Type type) { if (ZetanUtility.Editor.TryGetValue(serializedVariables, out var value) && value is List <SharedVariable> list) { SharedVariable variable = (SharedVariable)Activator.CreateInstance(type); string newName = $"{char.ToLower(type.Name[0])}{type.Name.Substring(1)}_{serializedVariables.arraySize}"; variable.GetType().GetField("_name", ZetanUtility.CommonBindingFlags).SetValue(variable, newName); variable.isShared = isShared; variable.isGlobal = !isShared; list.Add(variable); variableList.Select(serializedVariables.arraySize); } else { Debug.LogError("添加失败,请检查变量列表归属"); } } }
private void OnEnable() { if (ZetanUtility.TryGetMemberValue("attributeTypes", target, out var value, out _)) { dict = value as Dictionary <string, RoleAttributeValueType>; } names = serializedObject.FindProperty("names"); types = serializedObject.FindProperty("types"); list = new ReorderableList(serializedObject, names, false, true, true, true) { drawElementCallback = (rect, index, isActive, isFocused) => { SerializedProperty name = names.GetArrayElementAtIndex(index); SerializedProperty type = types.GetArrayElementAtIndex(index); EditorGUI.LabelField(new Rect(rect.x, rect.y, 30, EditorGUIUtility.singleLineHeight), $"[{index}]"); string nameBef = name.stringValue; EditorGUI.PropertyField(new Rect(rect.x + 30, rect.y, (rect.width - 30) / 2 - 2, EditorGUIUtility.singleLineHeight), name, new GUIContent(string.Empty)); if (nameBef != name.stringValue && dict.ContainsKey(name.stringValue)) { if (EditorUtility.DisplayDialog("错误", $"已存在属性名 [{name.stringValue}]", "确定")) { name.stringValue = nameBef; } } EditorGUI.PropertyField(new Rect(rect.x + +30 + (rect.width - 30) / 2, rect.y, (rect.width - 30) / 2 - 2, EditorGUIUtility.singleLineHeight), type, new GUIContent(string.Empty)); }, onAddCallback = (list) => { string name = "属性0"; int i = 1; while (dict.ContainsKey(name)) { name = $"属性{i}"; i++; } names.arraySize++; names.GetArrayElementAtIndex(names.arraySize - 1).stringValue = name; types.arraySize++; types.GetArrayElementAtIndex(types.arraySize - 1).enumValueIndex = (int)RoleAttributeValueType.Integer; list.Select(names.arraySize - 1); }, onRemoveCallback = (list) => { if (list.index >= 0 && list.index < names.arraySize) { if (EditorUtility.DisplayDialog("警告", $"确定删除属性 [{names.GetArrayElementAtIndex(list.index).stringValue}] 吗?", "删除", "取消")) { names.DeleteArrayElementAtIndex(list.index); types.DeleteArrayElementAtIndex(list.index); } } }, onCanRemoveCallback = (list) => { return(list.selectedIndices.Contains(list.index)); }, elementHeightCallback = (index) => { return(EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing); }, drawHeaderCallback = (rect) => { EditorGUI.LabelField(rect, "基础属性类型列表"); } }; }