#if UNITY_EDITOR using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using UnityEditor; using UnityEditor.Experimental.GraphView; using UnityEditor.Experimental.SceneManagement; using UnityEngine; using AlicizaX.UI; using TMPro; using UnityEditor.SceneManagement; using UnityEngine.UI; namespace AlicizaX.UI { [CustomEditor(typeof(UXControllerStateRecorder))] public class UXControllerStateRecorderEditor : UnityEditor.Editor { private SerializedProperty _stateEntriesProp; private SerializedProperty _controller; private SerializedProperty _id; private UXController _cacheController; private Dictionary _stateFoldouts = new Dictionary(); private bool _showControllerInfo = true; private bool _compactMode = false; private GUIStyle _headerStyle; private GUIStyle _toolbarStyle; private GUIStyle _stateHeaderStyle; private void OnEnable() { _controller = serializedObject.FindProperty("_controller"); _id = serializedObject.FindProperty("_id"); _stateEntriesProp = serializedObject.FindProperty("_stateEntries"); } private void OnDestroy() { if (target == null) { UnRegisterSelf(); } } private void InitStyles() { if (_headerStyle == null) { _headerStyle = new GUIStyle(EditorStyles.boldLabel) { fontSize = 13, fontStyle = FontStyle.Bold }; } if (_toolbarStyle == null) { _toolbarStyle = new GUIStyle(EditorStyles.toolbar) { fixedHeight = 25 }; } if (_stateHeaderStyle == null) { _stateHeaderStyle = new GUIStyle(EditorStyles.foldout) { fontStyle = FontStyle.Bold }; } } public override void OnInspectorGUI() { InitStyles(); serializedObject.Update(); var recorder = target as UXControllerStateRecorder; UXController prefabCtrl = GetPrefabStageController(); recorder.GenerateID(); // Header DrawHeader(recorder); EditorGUILayout.Space(5); // Controller Reference DrawControllerSection(recorder, prefabCtrl); EditorGUILayout.Space(5); // Toolbar DrawToolbar(); EditorGUILayout.Space(5); // States List DrawStatesList(recorder); serializedObject.ApplyModifiedProperties(); } private void DrawHeader(UXControllerStateRecorder recorder) { EditorGUILayout.BeginVertical(EditorStyles.helpBox); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("UX 状态记录器", _headerStyle, GUILayout.Width(150)); EditorGUILayout.LabelField($"ID: {_id.intValue}", EditorStyles.miniLabel); GUILayout.FlexibleSpace(); if (GUILayout.Button("刷新", EditorStyles.miniButtonLeft, GUILayout.Width(60))) { recorder.Initialize(); EditorUtility.SetDirty(recorder); } Color oldColor = GUI.backgroundColor; if (_compactMode) GUI.backgroundColor = Color.green; if (GUILayout.Button("紧凑", EditorStyles.miniButtonRight, GUILayout.Width(60))) { _compactMode = !_compactMode; _stateFoldouts.Clear(); } GUI.backgroundColor = oldColor; EditorGUILayout.EndHorizontal(); EditorGUILayout.EndVertical(); } private void DrawControllerSection(UXControllerStateRecorder recorder, UXController prefabCtrl) { if (prefabCtrl != null && prefabCtrl != _controller.objectReferenceValue) { _controller.objectReferenceValue = prefabCtrl; recorder.SetController(prefabCtrl); } if (prefabCtrl != null && !prefabCtrl.HasRecorder(recorder)) { RegisterSelfToController(prefabCtrl); } if (_controller.objectReferenceValue != null) { _cacheController = _controller.objectReferenceValue as UXController; } EditorGUILayout.BeginVertical(EditorStyles.helpBox); EditorGUILayout.BeginHorizontal(); _showControllerInfo = EditorGUILayout.Foldout(_showControllerInfo, "控制器引用", true); EditorGUILayout.EndHorizontal(); // Controller dropdown var availableControllers = GetAvailableControllers(recorder); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("控制器", GUILayout.Width(70)); if (availableControllers.Count > 0) { int currentIndex = -1; var currentController = _controller.objectReferenceValue as UXController; if (currentController != null) { currentIndex = availableControllers.IndexOf(currentController); } string[] options = new string[availableControllers.Count]; for (int i = 0; i < availableControllers.Count; i++) { var ctrl = availableControllers[i]; string path = GetGameObjectPath(ctrl.gameObject, recorder.gameObject); options[i] = $"{ctrl.gameObject.name} ({path})"; } EditorGUI.BeginChangeCheck(); int newIndex = EditorGUILayout.Popup(currentIndex, options); if (EditorGUI.EndChangeCheck() && newIndex >= 0 && newIndex < availableControllers.Count) { _controller.objectReferenceValue = availableControllers[newIndex]; recorder.SetController(availableControllers[newIndex]); if (!availableControllers[newIndex].HasRecorder(recorder)) { RegisterSelfToController(availableControllers[newIndex]); } } if (currentController != null && GUILayout.Button("选择", GUILayout.Width(60))) { Selection.activeGameObject = currentController.gameObject; } } else { EditorGUILayout.LabelField("(在父对象中未找到控制器)", EditorStyles.miniLabel); } EditorGUILayout.EndHorizontal(); // Controller info if (_showControllerInfo && _controller.objectReferenceValue != null) { UXController ctl = _controller.objectReferenceValue as UXController; EditorGUI.indentLevel++; EditorGUILayout.LabelField($"控制器数量: {ctl.ControllerCount}", EditorStyles.miniLabel); for (int i = 0; i < ctl.ControllerCount; i++) { var handle = ctl.GetControllerAt(i); if (handle != null) { string desc = string.IsNullOrEmpty(handle.Description) ? "" : $" - {handle.Description}"; EditorGUILayout.LabelField($" [{i}] {handle.Name} (长度: {handle.Length}){desc}", EditorStyles.miniLabel); } } EditorGUI.indentLevel--; } if (_controller.objectReferenceValue == null) { EditorGUILayout.HelpBox("未分配控制器。请在父对象上添加 UXController。", MessageType.Warning); } EditorGUILayout.EndVertical(); } private void DrawToolbar() { EditorGUILayout.BeginHorizontal(_toolbarStyle); if (GUILayout.Button("+ 添加状态", EditorStyles.toolbarButton, GUILayout.Width(100))) { ShowAddStateMenu(); } EditorGUI.BeginDisabledGroup(_stateEntriesProp.arraySize == 0); if (GUILayout.Button("清空全部", EditorStyles.toolbarButton, GUILayout.Width(70))) { if (EditorUtility.DisplayDialog("清空所有状态", "移除所有状态?", "清空", "取消")) { ClearAllStates(); } } EditorGUI.EndDisabledGroup(); if (GUILayout.Button("全部展开", EditorStyles.toolbarButton, GUILayout.Width(70))) { for (int i = 0; i < _stateEntriesProp.arraySize; i++) { _stateFoldouts[i] = true; } } if (GUILayout.Button("全部折叠", EditorStyles.toolbarButton, GUILayout.Width(75))) { _stateFoldouts.Clear(); } GUILayout.FlexibleSpace(); EditorGUILayout.LabelField($"状态数: {_stateEntriesProp.arraySize}", EditorStyles.miniLabel, GUILayout.Width(70)); EditorGUILayout.EndHorizontal(); } private void DrawStatesList(UXControllerStateRecorder recorder) { if (_stateEntriesProp.arraySize == 0) { EditorGUILayout.HelpBox("未定义状态。点击 '+ 添加状态' 开始。", MessageType.Info); return; } for (int i = 0; i < _stateEntriesProp.arraySize; i++) { DrawStateEntry(recorder, i); EditorGUILayout.Space(3); } } private void DrawStateEntry(UXControllerStateRecorder recorder, int index) { if (index < 0 || index >= _stateEntriesProp.arraySize) { return; } var entryProp = _stateEntriesProp.GetArrayElementAtIndex(index); if (entryProp == null) return; var stateProp = entryProp.FindPropertyRelative("State"); var controllerNameProp = entryProp.FindPropertyRelative("ControllerName"); var controllerIndexProp = entryProp.FindPropertyRelative("ControllerIndex"); // Validate all properties if (controllerNameProp == null || controllerIndexProp == null) { return; } if (stateProp == null || stateProp.managedReferenceValue == null) { DrawInvalidStateEntry(index); return; } var stateInstance = stateProp.managedReferenceValue as ControllerStateBase; var stateType = stateProp.managedReferenceValue.GetType(); var attr = stateType.GetCustomAttribute(); var stateName = attr != null ? attr.StateName : stateType.Name; bool isValid = ValidateState(recorder, stateInstance); bool isFolded = _stateFoldouts.ContainsKey(index) && _stateFoldouts[index]; // State box with validation color Color boxColor = GUI.backgroundColor; if (!isValid) GUI.backgroundColor = new Color(1f, 0.5f, 0.5f); EditorGUILayout.BeginVertical(EditorStyles.helpBox); GUI.backgroundColor = boxColor; // Header DrawStateHeader(index, stateName, ref isFolded); _stateFoldouts[index] = isFolded; // Compact mode: show binding info if (_compactMode && !isFolded) { EditorGUI.indentLevel++; try { string bindingText = string.IsNullOrEmpty(controllerNameProp.stringValue) ? "未绑定" : $"绑定到: {controllerNameProp.stringValue}[{controllerIndexProp.intValue}]"; EditorGUILayout.LabelField(bindingText, EditorStyles.miniLabel); // 在紧凑模式下也允许快速修改索引 if (!string.IsNullOrEmpty(controllerNameProp.stringValue)) { EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("索引", GUILayout.Width(50)); int ctrlLen = GetSelectedControllerLength(recorder, controllerNameProp.stringValue); if (ctrlLen <= 0) ctrlLen = 1; string[] idxOptions = new string[ctrlLen]; for (int j = 0; j < ctrlLen; j++) idxOptions[j] = j.ToString(); EditorGUI.BeginChangeCheck(); int newIdx = EditorGUILayout.Popup(controllerIndexProp.intValue, idxOptions, GUILayout.Width(60)); if (EditorGUI.EndChangeCheck()) { controllerIndexProp.intValue = newIdx; } EditorGUILayout.EndHorizontal(); } } catch (ObjectDisposedException) { EditorGUILayout.LabelField("绑定: (刷新中...)", EditorStyles.miniLabel); } EditorGUI.indentLevel--; } // Expanded content if (isFolded && !_compactMode) { EditorGUI.indentLevel++; // Binding DrawStateBinding(recorder, controllerNameProp, controllerIndexProp); EditorGUILayout.Space(3); // Properties if (stateInstance != null) { EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("属性", EditorStyles.boldLabel); // Set to Current Value button if (GUILayout.Button("设为当前值", GUILayout.Width(110))) { SetStateToCurrentValue(recorder, stateInstance, stateProp); } EditorGUILayout.EndHorizontal(); SerializedClassDrawer.DrawSerializableProperty(stateProp); // Description EditorGUILayout.Space(2); var description = stateInstance.GetDescription(); if (!string.IsNullOrEmpty(description)) { EditorGUILayout.LabelField($"ℹ {description}", EditorStyles.miniLabel); } } // Validation warning if (!isValid) { EditorGUILayout.HelpBox("状态验证失败。请检查所需组件。", MessageType.Error); } EditorGUI.indentLevel--; } EditorGUILayout.EndVertical(); } private void DrawStateHeader(int index, string stateName, ref bool isFolded) { EditorGUILayout.BeginHorizontal(); // Foldout with name isFolded = EditorGUILayout.Foldout(isFolded, $"[{index}] {stateName}", true, _stateHeaderStyle); GUILayout.FlexibleSpace(); // Buttons if (GUILayout.Button("▲", EditorStyles.miniButtonLeft, GUILayout.Width(25)) && index > 0) { MoveStateUp(index); } if (GUILayout.Button("▼", EditorStyles.miniButtonMid, GUILayout.Width(25)) && index < _stateEntriesProp.arraySize - 1) { MoveStateDown(index); } if (GUILayout.Button("⎘", EditorStyles.miniButtonMid, GUILayout.Width(25))) { DuplicateState(index); } if (GUILayout.Button("×", EditorStyles.miniButtonRight, GUILayout.Width(25))) { DeleteStateAtIndex(index); } EditorGUILayout.EndHorizontal(); } private void DrawStateBinding(UXControllerStateRecorder recorder, SerializedProperty controllerNameProp, SerializedProperty controllerIndexProp) { // Safety check: ensure properties are valid if (controllerNameProp == null || controllerIndexProp == null) { EditorGUILayout.HelpBox("绑定属性无效。请尝试刷新。", MessageType.Warning); return; } EditorGUILayout.BeginVertical(EditorStyles.helpBox); EditorGUILayout.LabelField("绑定", EditorStyles.boldLabel); var controllerNames = GetControllerNamesForRecorder(recorder); // Controller dropdown EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("控制器", GUILayout.Width(70)); if (controllerNames.Count > 0) { string currentName = ""; try { currentName = controllerNameProp.stringValue; } catch (ObjectDisposedException) { // Property has been disposed, exit gracefully EditorGUILayout.EndHorizontal(); EditorGUILayout.EndVertical(); return; } int selIdx = controllerNames.IndexOf(currentName); if (selIdx < 0) selIdx = 0; EditorGUI.BeginChangeCheck(); int newSel = EditorGUILayout.Popup(selIdx, controllerNames.ToArray()); if (EditorGUI.EndChangeCheck() && newSel >= 0 && newSel < controllerNames.Count) { controllerNameProp.stringValue = controllerNames[newSel]; } } else { EditorGUILayout.LabelField("(无可用控制器)", EditorStyles.miniLabel); } EditorGUILayout.EndHorizontal(); // Index dropdown if (controllerNames.Count > 0 && !string.IsNullOrEmpty(controllerNameProp.stringValue)) { EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("索引", GUILayout.Width(70)); int ctrlLen = GetSelectedControllerLength(recorder, controllerNameProp.stringValue); if (ctrlLen <= 0) ctrlLen = 1; controllerIndexProp.intValue = Mathf.Clamp(controllerIndexProp.intValue, 0, ctrlLen - 1); string[] idxOptions = new string[ctrlLen]; for (int j = 0; j < ctrlLen; j++) idxOptions[j] = j.ToString(); int curIdx = controllerIndexProp.intValue; EditorGUI.BeginChangeCheck(); int newIdx = EditorGUILayout.Popup(curIdx, idxOptions, GUILayout.Width(100)); if (EditorGUI.EndChangeCheck()) { controllerIndexProp.intValue = newIdx; } // Preview button if (_controller.objectReferenceValue != null && !Application.isPlaying) { if (GUILayout.Button("预览", GUILayout.Width(60))) { PreviewState(controllerNameProp.stringValue, controllerIndexProp.intValue); } } EditorGUILayout.EndHorizontal(); } EditorGUILayout.EndVertical(); } private void DrawInvalidStateEntry(int index) { Color oldColor = GUI.backgroundColor; GUI.backgroundColor = new Color(1f, 0.5f, 0.5f); EditorGUILayout.BeginVertical(EditorStyles.helpBox); GUI.backgroundColor = oldColor; EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField($"[{index}] 无效状态", EditorStyles.boldLabel); if (GUILayout.Button("移除", GUILayout.Width(60))) { DeleteStateAtIndex(index); } EditorGUILayout.EndHorizontal(); EditorGUILayout.HelpBox("状态数据已损坏。请移除并重新添加。", MessageType.Error); EditorGUILayout.EndVertical(); } private void DeleteStateAtIndex(int index) { if (index < 0 || index >= _stateEntriesProp.arraySize) { Debug.LogWarning($"Invalid state index: {index}"); return; } Undo.RecordObject(serializedObject.targetObject, "删除状态"); // Get the entry before deleting var entryProp = _stateEntriesProp.GetArrayElementAtIndex(index); var stateProp = entryProp?.FindPropertyRelative("State"); // If the state reference is not null, we need to delete twice // First deletion clears the reference, second removes the array element if (stateProp != null && stateProp.managedReferenceValue != null) { stateProp.managedReferenceValue = null; } // Now delete the array element _stateEntriesProp.DeleteArrayElementAtIndex(index); // Clean up foldout dictionary _stateFoldouts.Remove(index); // Rebuild foldout dictionary with corrected indices var newFoldouts = new Dictionary(); foreach (var kvp in _stateFoldouts) { if (kvp.Key < index) { newFoldouts[kvp.Key] = kvp.Value; } else if (kvp.Key > index) { newFoldouts[kvp.Key - 1] = kvp.Value; } } _stateFoldouts = newFoldouts; serializedObject.ApplyModifiedProperties(); EditorUtility.SetDirty(serializedObject.targetObject); // Exit GUI to prevent using disposed SerializedProperty GUIUtility.ExitGUI(); } private void ClearAllStates() { Undo.RecordObject(serializedObject.targetObject, "清空所有状态"); // Clear all managed references first for (int i = _stateEntriesProp.arraySize - 1; i >= 0; i--) { var entryProp = _stateEntriesProp.GetArrayElementAtIndex(i); var stateProp = entryProp?.FindPropertyRelative("State"); if (stateProp != null && stateProp.managedReferenceValue != null) { stateProp.managedReferenceValue = null; } } // Clear the array _stateEntriesProp.ClearArray(); _stateFoldouts.Clear(); serializedObject.ApplyModifiedProperties(); EditorUtility.SetDirty(serializedObject.targetObject); // Exit GUI to prevent using disposed SerializedProperty GUIUtility.ExitGUI(); } private void PreviewState(string controllerName, int index) { if (_controller.objectReferenceValue != null) { var ctl = _controller.objectReferenceValue as UXController; ctl.SetControllerIndex(controllerName, index); EditorUtility.SetDirty(ctl); SceneView.RepaintAll(); } } private void DuplicateState(int index) { if (index < 0 || index >= _stateEntriesProp.arraySize) { Debug.LogWarning($"Invalid state index: {index}"); return; } Undo.RecordObject(serializedObject.targetObject, "复制状态"); _stateEntriesProp.InsertArrayElementAtIndex(index); // Update foldout dictionary var newFoldouts = new Dictionary(); foreach (var kvp in _stateFoldouts) { if (kvp.Key <= index) { newFoldouts[kvp.Key] = kvp.Value; } else { newFoldouts[kvp.Key + 1] = kvp.Value; } } _stateFoldouts = newFoldouts; _stateFoldouts[index + 1] = true; serializedObject.ApplyModifiedProperties(); EditorUtility.SetDirty(serializedObject.targetObject); // Exit GUI to prevent using disposed SerializedProperty GUIUtility.ExitGUI(); } private void MoveStateUp(int index) { if (index <= 0 || index >= _stateEntriesProp.arraySize) { return; } Undo.RecordObject(serializedObject.targetObject, "上移状态"); _stateEntriesProp.MoveArrayElement(index, index - 1); // Update foldout dictionary if (_stateFoldouts.ContainsKey(index)) { bool wasFolded = _stateFoldouts[index]; _stateFoldouts.Remove(index); _stateFoldouts[index - 1] = wasFolded; } serializedObject.ApplyModifiedProperties(); EditorUtility.SetDirty(serializedObject.targetObject); // Exit GUI to prevent using disposed SerializedProperty GUIUtility.ExitGUI(); } private void MoveStateDown(int index) { if (index < 0 || index >= _stateEntriesProp.arraySize - 1) { return; } Undo.RecordObject(serializedObject.targetObject, "下移状态"); _stateEntriesProp.MoveArrayElement(index, index + 1); // Update foldout dictionary if (_stateFoldouts.ContainsKey(index)) { bool wasFolded = _stateFoldouts[index]; _stateFoldouts.Remove(index); _stateFoldouts[index + 1] = wasFolded; } serializedObject.ApplyModifiedProperties(); EditorUtility.SetDirty(serializedObject.targetObject); // Exit GUI to prevent using disposed SerializedProperty GUIUtility.ExitGUI(); } private bool ValidateState(UXControllerStateRecorder recorder, ControllerStateBase stateInstance) { if (stateInstance == null) return false; try { return stateInstance.Valid(recorder); } catch { return false; } } private void ShowAddStateMenu() { var provider = ScriptableObject.CreateInstance(); provider.Init(OnTypeSelected); SearchWindow.Open(new SearchWindowContext(GUIUtility.GUIToScreenPoint(Event.current.mousePosition)), provider); } private void OnTypeSelected(Type type) { if (type == null) return; Undo.RecordObject(serializedObject.targetObject, "添加控制器状态"); serializedObject.Update(); int idx = _stateEntriesProp.arraySize; _stateEntriesProp.InsertArrayElementAtIndex(idx); var entryProp = _stateEntriesProp.GetArrayElementAtIndex(idx); var stateProp = entryProp.FindPropertyRelative("State"); var controllerNameProp = entryProp.FindPropertyRelative("ControllerName"); var controllerIndexProp = entryProp.FindPropertyRelative("ControllerIndex"); ControllerStateBase instance = null; try { instance = (ControllerStateBase)Activator.CreateInstance(type); } catch (Exception ex) { Debug.LogException(ex); return; } var recorder = serializedObject.targetObject as UXControllerStateRecorder; if (instance != null) { instance.Init(recorder); } if (stateProp != null) { stateProp.managedReferenceValue = instance; stateProp.isExpanded = true; } var controllerNames = GetControllerNamesForRecorder(recorder); if (controllerNames.Count > 0) { controllerNameProp.stringValue = controllerNames[0]; controllerIndexProp.intValue = 0; } else { controllerNameProp.stringValue = ""; controllerIndexProp.intValue = 0; } serializedObject.ApplyModifiedProperties(); EditorUtility.SetDirty(serializedObject.targetObject); _stateFoldouts[idx] = true; } private void UnRegisterSelf() { UXController controller = (_cacheController != null) ? _cacheController : GetPrefabStageController(); if (controller == null) return; var so = new SerializedObject(controller); var recorders = so.FindProperty("_recorders"); for (int i = recorders.arraySize - 1; i >= 0; i--) { var el = recorders.GetArrayElementAtIndex(i); if (el.objectReferenceValue == null) { recorders.DeleteArrayElementAtIndex(i); } } so.ApplyModifiedProperties(); EditorUtility.SetDirty(controller); } private void RegisterSelfToController(UXController controller) { var so = new SerializedObject(controller); var recorders = so.FindProperty("_recorders"); int newIndex = recorders.arraySize; recorders.InsertArrayElementAtIndex(newIndex); var el = recorders.GetArrayElementAtIndex(newIndex); el.objectReferenceValue = target; so.ApplyModifiedProperties(); EditorUtility.SetDirty(controller); } private UXController GetPrefabStageController() { var stage = PrefabStageUtility.GetCurrentPrefabStage(); if (stage == null) return null; var root = stage.prefabContentsRoot; if (root == null) return null; return root.GetComponentInChildren(); } private List GetControllerNamesForRecorder(UXControllerStateRecorder recorder) { var names = new List(); var prefabCtrl = GetPrefabStageController(); if (prefabCtrl != null) { foreach (var cd in prefabCtrl.Controllers) names.Add(cd.Name); return names; } var assigned = recorder.Controller; if (assigned != null) { foreach (var cd in assigned.Controllers) names.Add(cd.Name); return names; } var inScene = recorder.gameObject.GetComponentInParent(); if (inScene != null) { foreach (var cd in inScene.Controllers) names.Add(cd.Name); return names; } return names; } private int GetSelectedControllerLength(UXControllerStateRecorder recorder, string controllerName) { var prefabCtrl = GetPrefabStageController(); if (prefabCtrl != null) { var ch = prefabCtrl.Controllers.ToList().Find(x => x.Name == controllerName); if (ch != null) return ch.Length; } var assigned = recorder.Controller; if (assigned != null) { var ch = assigned.Controllers.ToList().Find(x => x.Name == controllerName); if (ch != null) return ch.Length; } var inScene = recorder.gameObject.GetComponentInParent(); if (inScene != null) { var ch = inScene.Controllers.ToList().Find(x => x.Name == controllerName); if (ch != null) return ch.Length; } return 1; } private List GetAvailableControllers(UXControllerStateRecorder recorder) { var controllers = new List(); // Search upwards through all parent transforms Transform current = recorder.transform.parent; while (current != null) { var ctrl = current.GetComponent(); if (ctrl != null && !controllers.Contains(ctrl)) { controllers.Add(ctrl); } current = current.parent; } return controllers; } private string GetGameObjectPath(GameObject target, GameObject from) { if (target == null || from == null) return ""; List path = new List(); Transform current = from.transform.parent; while (current != null) { if (current.gameObject == target) { return path.Count == 0 ? "Parent" : string.Join("/", path); } path.Insert(0, ".."); current = current.parent; } return "Unknown"; } private void SetStateToCurrentValue(UXControllerStateRecorder recorder, ControllerStateBase state, SerializedProperty stateProp) { if (recorder == null || state == null) return; Undo.RecordObject(recorder, "设置状态为当前值"); // Use reflection to set current values based on state type var stateType = state.GetType(); if (state is TransformPositionState) { if (recorder.TryGetComponent(out var rect)) { var posField = stateType.GetField("_position", BindingFlags.NonPublic | BindingFlags.Instance); if (posField != null) { posField.SetValue(state, rect.anchoredPosition); serializedObject.ApplyModifiedProperties(); serializedObject.Update(); EditorUtility.SetDirty(recorder); } } } else if (state is TransformScaleState) { if (recorder.transform != null) { var scaleField = stateType.GetField("_scale", BindingFlags.NonPublic | BindingFlags.Instance); if (scaleField != null) { scaleField.SetValue(state, recorder.transform.localScale); serializedObject.ApplyModifiedProperties(); serializedObject.Update(); EditorUtility.SetDirty(recorder); } } } else if (state is TransformRotationState) { if (recorder.transform != null) { var rotField = stateType.GetField("_rotation", BindingFlags.NonPublic | BindingFlags.Instance); if (rotField != null) { rotField.SetValue(state, recorder.transform.localEulerAngles); serializedObject.ApplyModifiedProperties(); serializedObject.Update(); EditorUtility.SetDirty(recorder); } } } else if (state is GraphicColorState) { if (recorder.TryGetComponent(out var graphic)) { var colorField = stateType.GetField("_color", BindingFlags.NonPublic | BindingFlags.Instance); if (colorField != null) { colorField.SetValue(state, graphic.color); serializedObject.ApplyModifiedProperties(); serializedObject.Update(); EditorUtility.SetDirty(recorder); } } } else if (state is GraphicMaterialState) { if (recorder.TryGetComponent(out var graphic)) { var matField = stateType.GetField("_material", BindingFlags.NonPublic | BindingFlags.Instance); if (matField != null) { matField.SetValue(state, graphic.material); serializedObject.ApplyModifiedProperties(); serializedObject.Update(); EditorUtility.SetDirty(recorder); } } } else if (state is ImageSpriteState) { if (recorder.TryGetComponent(out var image)) { var spriteField = stateType.GetField("_sprite", BindingFlags.NonPublic | BindingFlags.Instance); if (spriteField != null) { spriteField.SetValue(state, image.sprite); serializedObject.ApplyModifiedProperties(); serializedObject.Update(); EditorUtility.SetDirty(recorder); } } } else if (state is TextContentState) { string currentText = ""; if (recorder.TryGetComponent(out var text)) { currentText = text.text; } else if (recorder.TryGetComponent(out var tmp)) { currentText = tmp.text; } var textField = stateType.GetField("_text", BindingFlags.NonPublic | BindingFlags.Instance); if (textField != null) { textField.SetValue(state, currentText); serializedObject.ApplyModifiedProperties(); serializedObject.Update(); EditorUtility.SetDirty(recorder); } } else if (state is TextColorState) { Color currentColor = Color.white; if (recorder.TryGetComponent(out var text)) { currentColor = text.color; } else if (recorder.TryGetComponent(out var tmp)) { currentColor = tmp.color; } var colorField = stateType.GetField("_color", BindingFlags.NonPublic | BindingFlags.Instance); if (colorField != null) { colorField.SetValue(state, currentColor); serializedObject.ApplyModifiedProperties(); serializedObject.Update(); EditorUtility.SetDirty(recorder); } } else if (state is CanvasGroupAlphaState) { if (recorder.TryGetComponent(out var canvasGroup)) { var alphaField = stateType.GetField("_alpha", BindingFlags.NonPublic | BindingFlags.Instance); if (alphaField != null) { alphaField.SetValue(state, canvasGroup.alpha); serializedObject.ApplyModifiedProperties(); serializedObject.Update(); EditorUtility.SetDirty(recorder); } } } else if (state is CanvasGroupInteractableState) { if (recorder.TryGetComponent(out var canvasGroup)) { var interField = stateType.GetField("_interactable", BindingFlags.NonPublic | BindingFlags.Instance); var blockField = stateType.GetField("_blocksRaycasts", BindingFlags.NonPublic | BindingFlags.Instance); if (interField != null && blockField != null) { interField.SetValue(state, canvasGroup.interactable); blockField.SetValue(state, canvasGroup.blocksRaycasts); serializedObject.ApplyModifiedProperties(); serializedObject.Update(); EditorUtility.SetDirty(recorder); } } } else if (state is GameObjectActiveState) { var activeField = stateType.GetField("_active", BindingFlags.NonPublic | BindingFlags.Instance); if (activeField != null) { activeField.SetValue(state, recorder.gameObject.activeSelf); serializedObject.ApplyModifiedProperties(); serializedObject.Update(); EditorUtility.SetDirty(recorder); } } Debug.Log($"Set {stateType.Name} to current value"); } } } #endif