698 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			698 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| namespace Fusion.Addons.KCC.Editor
 | |
| {
 | |
| 	using System;
 | |
| 	using System.Collections;
 | |
| 	using System.Collections.Generic;
 | |
| 	using System.Collections.ObjectModel;
 | |
| 	using UnityEngine;
 | |
| 	using UnityEditor;
 | |
| 
 | |
| 	[InitializeOnLoad]
 | |
| 	[CustomEditor(typeof(KCC), true)]
 | |
| 	public class KCCEditor : Fusion.Editor.BehaviourEditor
 | |
| 	{
 | |
| 		// CONSTANTS
 | |
| 
 | |
| 		private const string SETTINGS_PROPERTY_NAME                  = "_settings";
 | |
| 		private const string INTERPOLATION_DATA_SOURCE_PROPERTY_NAME = "_interpolationDataSource";
 | |
| 
 | |
| 		// PRIVATE MEMBERS
 | |
| 
 | |
| 		private static string[]        _excludedProperties     = new string[] { SETTINGS_PROPERTY_NAME, INTERPOLATION_DATA_SOURCE_PROPERTY_NAME };
 | |
| 		private static bool            _localProcessorsFoldout = false;
 | |
| 		private static bool            _modifiersFoldout       = false;
 | |
| 		private static bool            _collisionsFoldout      = false;
 | |
| 		private static bool            _ignoresFoldout         = false;
 | |
| 		private static bool            _hitsFoldout            = false;
 | |
| 		private static bool            _resetTools             = false;
 | |
| 		private static GUIStyle        _stageButtonStyle;
 | |
| 		private static GUIStyle        _buttonFoldoutStyle;
 | |
| 		private static GUIStyle        _foldoutDotStyle;
 | |
| 
 | |
| 		// Initialization
 | |
| 
 | |
| 		[InitializeOnLoadMethod]
 | |
| 		private static void Initialize()
 | |
| 		{
 | |
| 			Selection.selectionChanged -= OnSelectionChanged;
 | |
| 			Selection.selectionChanged += OnSelectionChanged;
 | |
| 
 | |
| 			return;
 | |
| 
 | |
| 			static void OnSelectionChanged()
 | |
| 			{
 | |
| 				if (_resetTools == true)
 | |
| 				{
 | |
| 					_resetTools = false;
 | |
| 					Tools.hidden = false;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		// Editor INTERFACE
 | |
| 
 | |
| 		public override bool RequiresConstantRepaint()
 | |
| 		{
 | |
| 			return true;
 | |
| 		}
 | |
| 
 | |
| 		private void OnSceneGUI()
 | |
| 		{
 | |
| 			_resetTools = true;
 | |
| 
 | |
| 			if (Application.isPlaying == false)
 | |
| 				return;
 | |
| 
 | |
| 			KCC kcc = target as KCC;
 | |
| 			if (kcc.Object == null)
 | |
| 				return;
 | |
| 
 | |
| 			if (Tools.current == Tool.Move)
 | |
| 			{
 | |
| 				Tools.hidden = true;
 | |
| 
 | |
| 				Vector3 currentPosition = kcc.Transform.position;
 | |
| 				Vector3 newPosition     = Handles.PositionHandle(currentPosition, kcc.Transform.rotation);
 | |
| 
 | |
| 				if (newPosition.Equals(currentPosition) == false)
 | |
| 				{
 | |
| 					kcc.FixedData.TargetPosition  = newPosition;
 | |
| 					kcc.RenderData.TargetPosition = newPosition;
 | |
| 
 | |
| 					kcc.SynchronizeTransform(true, false, false);
 | |
| 				}
 | |
| 			}
 | |
| 			else if (Tools.current == Tool.Rotate)
 | |
| 			{
 | |
| 				Tools.hidden = true;
 | |
| 
 | |
| 				Quaternion currentRotation = kcc.Transform.rotation;
 | |
| 				Quaternion newRotation     = Handles.RotationHandle(currentRotation, kcc.Transform.position);
 | |
| 
 | |
| 				if (newRotation.Equals(currentRotation) == false)
 | |
| 				{
 | |
| 					Vector3 difference = (Quaternion.Inverse(currentRotation) * newRotation).eulerAngles;
 | |
| 
 | |
| 					if (difference.y != 0.0f)
 | |
| 					{
 | |
| 						kcc.Data.AddLookRotation(0.0f, difference.y);
 | |
| 
 | |
| 						float lookYaw = kcc.Data.LookYaw;
 | |
| 
 | |
| 						kcc.FixedData.LookYaw  = lookYaw;
 | |
| 						kcc.RenderData.LookYaw = lookYaw;
 | |
| 
 | |
| 						kcc.SynchronizeTransform(false, true, false);
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				Tools.hidden = false;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		public override void OnInspectorGUI()
 | |
| 		{
 | |
| 			PrepareOnInspectorGUI();
 | |
| 			DrawPropertiesExcluding(serializedObject, _excludedProperties);
 | |
| 			DrawEditorButtons();
 | |
| 
 | |
| 			SerializedProperty settingsProperty = serializedObject.FindProperty(SETTINGS_PROPERTY_NAME);
 | |
| 			IEnumerator innerSettingsProperties = settingsProperty.GetEnumerator();
 | |
| 			while (innerSettingsProperties.MoveNext())
 | |
| 			{
 | |
| 				if (innerSettingsProperties.Current is SerializedProperty innerSettingsProperty)
 | |
| 				{
 | |
| 					if (innerSettingsProperty.propertyPath.IndexOf('.') == innerSettingsProperty.propertyPath.LastIndexOf('.'))
 | |
| 					{
 | |
| 						EditorGUILayout.PropertyField(innerSettingsProperty);
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 			serializedObject.ApplyModifiedProperties();
 | |
| 
 | |
| 			if (Application.isPlaying == false)
 | |
| 			{
 | |
| 				DrawLine(Color.gray);
 | |
| 				EditorGUILayout.HelpBox("Additional information appears at runtime.", MessageType.Info);
 | |
| 				DrawLine(Color.gray);
 | |
| 				return;
 | |
| 			}
 | |
| 
 | |
| 			KCC kcc = target as KCC;
 | |
| 			if (kcc.Object == null)
 | |
| 				return;
 | |
| 
 | |
| 			KCCDebug kccDebug = kcc.Debug;
 | |
| 
 | |
| 			Color defaultColor             = GUI.color;
 | |
| 			Color defaultContentColor      = GUI.contentColor;
 | |
| 			Color defaultBackgroundColor   = GUI.backgroundColor;
 | |
| 			Color enabledBackgroundColor   = Color.green;
 | |
| 			Color disabledBackgroundColor  = defaultBackgroundColor;
 | |
| 			Color colliderBackgroundColor  = defaultBackgroundColor;
 | |
| 			Color processorBackgroundColor = Color.cyan;
 | |
| 			float foldoutStaticOffset      = 8.0f;
 | |
| 			float foldoutLevelOffset       = 20.0f;
 | |
| 
 | |
| 			DrawLine(Color.gray);
 | |
| 
 | |
| 			EditorGUILayout.BeginHorizontal();
 | |
| 			{
 | |
| 				EditorGUILayout.BeginVertical();
 | |
| 				{
 | |
| 					if (DrawButton("Input Authority",      kcc.HasInputAuthority       == true, enabledBackgroundColor,      disabledBackgroundColor) == true) {}
 | |
| 					if (DrawButton("Draw Path",            kccDebug.ShowPath           == true, enabledBackgroundColor,      disabledBackgroundColor) == true) { kccDebug.ShowPath           = !kccDebug.ShowPath;           }
 | |
| 					if (DrawButton("Draw Ground Normal",   kccDebug.ShowGroundNormal   == true, KCCDebug.GroundNormalColor,  disabledBackgroundColor) == true) { kccDebug.ShowGroundNormal   = !kccDebug.ShowGroundNormal;   }
 | |
| 					if (DrawButton("Draw Ground Tangent",  kccDebug.ShowGroundTangent  == true, KCCDebug.GroundTangentColor, disabledBackgroundColor) == true) { kccDebug.ShowGroundTangent  = !kccDebug.ShowGroundTangent;  }
 | |
| 					if (DrawButton("Draw Ground Snapping", kccDebug.ShowGroundSnapping == true, KCCDebug.GroundSnapingColor, disabledBackgroundColor) == true) { kccDebug.ShowGroundSnapping = !kccDebug.ShowGroundSnapping; }
 | |
| 				}
 | |
| 				EditorGUILayout.EndVertical();
 | |
| 				EditorGUILayout.BeginVertical();
 | |
| 				{
 | |
| 					if (DrawButton("State Authority",     kcc.HasStateAuthority      == true,  enabledBackgroundColor,      disabledBackgroundColor) == true) {}
 | |
| 					if (DrawButton("Draw Speed",          kccDebug.ShowSpeed         == true,  KCCDebug.SpeedColor,         disabledBackgroundColor) == true) { kccDebug.ShowSpeed         = !kccDebug.ShowSpeed;         }
 | |
| 					if (DrawButton("Draw Grounding",      kccDebug.ShowGrounding     == true,  KCCDebug.IsGroundedColor,    disabledBackgroundColor) == true) { kccDebug.ShowGrounding     = !kccDebug.ShowGrounding;     }
 | |
| 					if (DrawButton("Draw Stepping Up",    kccDebug.ShowSteppingUp    == true,  KCCDebug.IsSteppingUpColor,  disabledBackgroundColor) == true) { kccDebug.ShowSteppingUp    = !kccDebug.ShowSteppingUp;    }
 | |
| 					if (DrawButton("Draw Move Direction", kccDebug.ShowMoveDirection == true,  KCCDebug.MoveDirectionColor, disabledBackgroundColor) == true) { kccDebug.ShowMoveDirection = !kccDebug.ShowMoveDirection; }
 | |
| 				}
 | |
| 				EditorGUILayout.EndVertical();
 | |
| 			}
 | |
| 			EditorGUILayout.EndHorizontal();
 | |
| 
 | |
| 			if (DrawButton("Logs", kccDebug.LogsTime != default,  enabledBackgroundColor, disabledBackgroundColor) == true)
 | |
| 			{
 | |
| 				kccDebug.LogsTime = -1.0f;
 | |
| 			}
 | |
| 
 | |
| 			if (kccDebug.ShowPath == true || kccDebug.ShowSpeed == true || kccDebug.ShowGrounding == true || kccDebug.ShowGroundSnapping == true || kccDebug.ShowGroundNormal == true || kccDebug.ShowMoveDirection == true || kccDebug.ShowSteppingUp == true || kccDebug.ShowGroundTangent == true)
 | |
| 			{
 | |
| 				kccDebug.DisplayTime = EditorGUILayout.Slider("Display Time", kccDebug.DisplayTime, 1.0f, 60.0f);
 | |
| 			}
 | |
| 
 | |
| 			if (kccDebug.ShowPath == true)
 | |
| 			{
 | |
| 				kccDebug.PointSize = EditorGUILayout.Slider("Point Size", kccDebug.PointSize, 0.001f, 0.1f);
 | |
| 			}
 | |
| 
 | |
| 			if (kccDebug.ShowSpeed == true)
 | |
| 			{
 | |
| 				kccDebug.SpeedScale = EditorGUILayout.Slider("Speed Scale", kccDebug.SpeedScale, 0.01f, 1.0f);
 | |
| 			}
 | |
| 
 | |
| 			GUI.backgroundColor = defaultBackgroundColor;
 | |
| 
 | |
| 			DrawLine(Color.gray);
 | |
| 
 | |
| 			KCCData data = kcc.Object.IsInSimulation == true ? kcc.FixedData : kcc.RenderData;
 | |
| 
 | |
| 			EditorGUILayout.Toggle("Is In Simulation", kcc.Object.IsInSimulation);
 | |
| 			EditorGUILayout.LabelField("Word Count", kcc.DynamicWordCount.Value.ToString());
 | |
| 			EditorGUILayout.LabelField("Shape", kcc.Settings.Shape.ToString());
 | |
| 			EditorGUILayout.Toggle("Is Active", data.IsActive);
 | |
| 			EditorGUILayout.Toggle("Is Grounded", data.IsGrounded);
 | |
| 			EditorGUILayout.Toggle("Is On Edge", data.IsOnEdge);
 | |
| 			EditorGUILayout.Toggle("Is Stepping Up", data.IsSteppingUp);
 | |
| 			EditorGUILayout.Toggle("Is Snapping To Ground", data.IsSnappingToGround);
 | |
| 			EditorGUILayout.Toggle("Has Manual Update", kcc.HasManualUpdate);
 | |
| 			EditorGUILayout.LabelField("Look Pitch", data.LookPitch.ToString("0.00°"));
 | |
| 			EditorGUILayout.LabelField("Look Yaw", data.LookYaw.ToString("0.00°"));
 | |
| 			EditorGUILayout.LabelField("Real Speed", data.RealSpeed.ToString("0.00"));
 | |
| 			EditorGUILayout.LabelField("Ground Angle", data.GroundAngle.ToString("0.00°"));
 | |
| 			EditorGUILayout.LabelField("Ground Distance", data.IsGrounded == true ? data.GroundDistance.ToString("F6") : "N/A");
 | |
| 			EditorGUILayout.LabelField("Collision Hits", data.Hits.Count.ToString());
 | |
| 			EditorGUILayout.LabelField("Prediction Error", kcc.PredictionError.magnitude.ToString("F6"));
 | |
| 			EditorGUILayout.EnumFlagsField("Active Features", kcc.ActiveFeatures);
 | |
| 
 | |
| 			DrawLine(Color.gray);
 | |
| 
 | |
| 			if (_foldoutDotStyle == null)
 | |
| 			{
 | |
| 				_foldoutDotStyle = new GUIStyle(GUI.skin.label);
 | |
| 				_foldoutDotStyle.alignment = TextAnchor.MiddleCenter;
 | |
| 				_foldoutDotStyle.fixedWidth = foldoutLevelOffset * 0.5f;
 | |
| 				_foldoutDotStyle.stretchHeight = true;
 | |
| 			}
 | |
| 
 | |
| 			ReadOnlyCollection<IKCCProcessor> localProcessors = kcc.LocalProcessors;
 | |
| 
 | |
| 			if (DrawButtonFoldout($"Local Processors ({localProcessors.Count})", ref _localProcessorsFoldout, enabledBackgroundColor, disabledBackgroundColor) == true && localProcessors.Count > 0)
 | |
| 			{
 | |
| 				for (int i = 0; i < localProcessors.Count; ++i)
 | |
| 				{
 | |
| 					Component processor = localProcessors[i] as Component;
 | |
| 					if (processor != null)
 | |
| 					{
 | |
| 						DrawPingDotButton($"{processor.gameObject.name}\n({processor.GetType().Name})", processor.gameObject, foldoutStaticOffset, processorBackgroundColor);
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			List<KCCModifier> modifiers = data.Modifiers.All;
 | |
| 
 | |
| 			if (DrawButtonFoldout($"Networked Modifiers ({modifiers.Count})", ref _modifiersFoldout, enabledBackgroundColor, disabledBackgroundColor) == true && modifiers.Count > 0)
 | |
| 			{
 | |
| 				for (int i = 0; i < modifiers.Count; ++i)
 | |
| 				{
 | |
| 					Component processor = modifiers[i].Processor as Component;
 | |
| 					Component provider  = modifiers[i].Provider  as Component;
 | |
| 
 | |
| 					if (processor != null)
 | |
| 					{
 | |
| 						DrawPingDotButton($"{processor.gameObject.name}\n({processor.GetType().Name})", processor.gameObject, foldoutStaticOffset, processorBackgroundColor);
 | |
| 					}
 | |
| 					else if (provider != null)
 | |
| 					{
 | |
| 						DrawPingDotButton($"{provider.gameObject.name}\n({provider.GetType().Name})", provider.gameObject, foldoutStaticOffset, processorBackgroundColor);
 | |
| 					}
 | |
| 					else
 | |
| 					{
 | |
| 						DrawPingDotButton($"{modifiers[i].NetworkObject.gameObject.name}", modifiers[i].NetworkObject.gameObject, foldoutStaticOffset, processorBackgroundColor);
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			List<KCCCollision> collisions = data.Collisions.All;
 | |
| 
 | |
| 			if (DrawButtonFoldout($"Networked Collisions ({collisions.Count})", ref _collisionsFoldout, enabledBackgroundColor, disabledBackgroundColor) == true && collisions.Count > 0)
 | |
| 			{
 | |
| 				for (int i = 0; i < collisions.Count; ++i)
 | |
| 				{
 | |
| 					EditorGUILayout.BeginHorizontal();
 | |
| 					{
 | |
| 						GUILayout.Space(foldoutStaticOffset);
 | |
| 						GUILayout.Label("•", _foldoutDotStyle);
 | |
| 
 | |
| 						KCCCollision collision = collisions[i];
 | |
| 
 | |
| 						DrawPingButton($"{collision.Collider.name}\n{(collision.Collider.isTrigger ? "[Trigger] " : "")}({collision.Collider.GetType().Name})", collision.Collider.gameObject, colliderBackgroundColor);
 | |
| 
 | |
| 						Component processor = collision.Processor as Component;
 | |
| 						Component provider  = collision.Provider  as Component;
 | |
| 
 | |
| 						if (processor != null)
 | |
| 						{
 | |
| 							DrawPingButton($"{processor.gameObject.name}\n({processor.GetType().Name})", processor.gameObject, processorBackgroundColor);
 | |
| 						}
 | |
| 						else if (provider != null)
 | |
| 						{
 | |
| 							DrawPingButton($"{provider.gameObject.name}\n({provider.GetType().Name})", provider.gameObject, processorBackgroundColor);
 | |
| 						}
 | |
| 					}
 | |
| 					EditorGUILayout.EndHorizontal();
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			List<KCCIgnore> ignores = data.Ignores.All;
 | |
| 
 | |
| 			if (DrawButtonFoldout($"Ignored Colliders ({ignores.Count})", ref _ignoresFoldout, enabledBackgroundColor, disabledBackgroundColor) == true && ignores.Count > 0)
 | |
| 			{
 | |
| 				for (int i = 0; i < ignores.Count; ++i)
 | |
| 				{
 | |
| 					KCCIgnore ignore = ignores[i];
 | |
| 
 | |
| 					DrawPingDotButton($"{ignore.Collider.name}\n{(ignore.Collider.isTrigger ? "[Trigger] " : "")}({ignore.Collider.GetType().Name})", ignore.Collider.gameObject, foldoutStaticOffset, colliderBackgroundColor);
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			List<KCCHit> hits = data.Hits.All;
 | |
| 
 | |
| 			if (DrawButtonFoldout($"Collision Hits ({hits.Count})", ref _hitsFoldout, enabledBackgroundColor, disabledBackgroundColor) == true && hits.Count > 0)
 | |
| 			{
 | |
| 				for (int i = 0; i < hits.Count; ++i)
 | |
| 				{
 | |
| 					KCCHit hit = hits[i];
 | |
| 
 | |
| 					string colliderInfo = hit.CollisionType != default ? $"[{hit.CollisionType}] " : "[---] ";
 | |
| 
 | |
| 					DrawPingDotButton($"{hit.Collider.name}\n{colliderInfo}({hit.Collider.GetType().Name})", hit.Collider.gameObject, foldoutStaticOffset);
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			bool traceExecution = kccDebug.TraceExecution;
 | |
| 			if (traceExecution == false || kccDebug.TraceInfoCount <= 0)
 | |
| 			{
 | |
| 				DrawButtonFoldout($"Execution Stack", ref traceExecution, enabledBackgroundColor, disabledBackgroundColor);
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				GUILayout.BeginHorizontal();
 | |
| 
 | |
| 				int stageTraces     = 0;
 | |
| 				int processorTraces = 0;
 | |
| 
 | |
| 				for (int i = 0; i < kccDebug.TraceInfoCount; ++i)
 | |
| 				{
 | |
| 					KCCTraceInfo traceInfo = kccDebug.TraceInfos[i];
 | |
| 					if (traceInfo.Trace == EKCCTrace.Stage)
 | |
| 					{
 | |
| 						++stageTraces;
 | |
| 					}
 | |
| 					else if (traceInfo.Trace == EKCCTrace.Processor)
 | |
| 					{
 | |
| 						++processorTraces;
 | |
| 					}
 | |
| 				}
 | |
| 
 | |
| 				DrawButtonFoldout($"Execution Stack ({stageTraces} + {processorTraces})", ref traceExecution, enabledBackgroundColor, disabledBackgroundColor);
 | |
| 
 | |
| 				if (GUILayout.Button("▼", GUILayout.Width(24.0f)) == true)
 | |
| 				{
 | |
| 					traceExecution = true;
 | |
| 
 | |
| 					for (int i = 0; i < kccDebug.TraceInfoCount; ++i)
 | |
| 					{
 | |
| 						KCCTraceInfo traceInfo = kccDebug.TraceInfos[i];
 | |
| 						traceInfo.IsVisible = true;
 | |
| 					}
 | |
| 				}
 | |
| 				if (GUILayout.Button("▲", GUILayout.Width(24.0f)) == true)
 | |
| 				{
 | |
| 					for (int i = 0; i < kccDebug.TraceInfoCount; ++i)
 | |
| 					{
 | |
| 						KCCTraceInfo traceInfo = kccDebug.TraceInfos[i];
 | |
| 						traceInfo.IsVisible = false;
 | |
| 					}
 | |
| 				}
 | |
| 
 | |
| 				GUILayout.EndHorizontal();
 | |
| 			}
 | |
| 
 | |
| 			if (kccDebug.TraceExecution != traceExecution)
 | |
| 			{
 | |
| 				kccDebug.TraceExecution = traceExecution;
 | |
| 				kccDebug.TraceInfoCount = default;
 | |
| 			}
 | |
| 
 | |
| 			if (traceExecution == true && kccDebug.TraceInfoCount > 0)
 | |
| 			{
 | |
| 				if (_stageButtonStyle == null)
 | |
| 				{
 | |
| 					_stageButtonStyle = new GUIStyle(GUI.skin.button);
 | |
| 					_stageButtonStyle.alignment = TextAnchor.MiddleLeft;
 | |
| 				}
 | |
| 
 | |
| 				/*kccDebug.TraceExecution = false;
 | |
| 				for (int i = 0; i < kccDebug.TraceInfoCount; ++i)
 | |
| 				{
 | |
| 					Debug.LogError($"{kccDebug.TraceInfos[i].Trace} {kccDebug.TraceInfos[i].Name} {kccDebug.TraceInfos[i].Level} {kccDebug.TraceInfos[i].Processor}");
 | |
| 				}
 | |
| 				kccDebug.TraceInfoCount = 0;*/
 | |
| 
 | |
| 				for (int i = 0; i < kccDebug.TraceInfoCount; ++i)
 | |
| 				{
 | |
| 					KCCTraceInfo traceInfo = kccDebug.TraceInfos[i];
 | |
| 					if (traceInfo.IsStage == true && traceInfo.Level == default)
 | |
| 					{
 | |
| 						DrawStageTrace(kccDebug.TraceInfos, kccDebug.TraceInfoCount, i, default);
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			DrawLine(Color.gray);
 | |
| 
 | |
| 			GUI.color           = defaultColor;
 | |
| 			GUI.contentColor    = defaultContentColor;
 | |
| 			GUI.backgroundColor = defaultBackgroundColor;
 | |
| 
 | |
| 			void DrawStageTrace(KCCTraceInfo[] traceInfos, int traceInfoCount, int traceInfoIndex, int indentLevel)
 | |
| 			{
 | |
| 				KCCTraceInfo stageTraceInfo = traceInfos[traceInfoIndex];
 | |
| 				if (stageTraceInfo.IsStage == false)
 | |
| 				{
 | |
| 					Debug.LogError($"Unexpected trace {stageTraceInfo.Trace}!");
 | |
| 					return;
 | |
| 				}
 | |
| 
 | |
| 				int childCount           = 0;
 | |
| 				int childStages          = 0;
 | |
| 				int childProcessors      = 0;
 | |
| 				int childStageLevel      = stageTraceInfo.Level + 1;
 | |
| 				int childProcessorLevel  = stageTraceInfo.Level;
 | |
| 
 | |
| 				for (int i = traceInfoIndex + 1; i < traceInfoCount; ++i)
 | |
| 				{
 | |
| 					KCCTraceInfo nextTraceInfo  = traceInfos[i];
 | |
| 					int          nextTraceLevel = nextTraceInfo.Level;
 | |
| 
 | |
| 					if (nextTraceInfo.IsStage == true)
 | |
| 					{
 | |
| 						if (nextTraceLevel < childStageLevel)
 | |
| 							break;
 | |
| 						if (nextTraceLevel > childStageLevel)
 | |
| 							continue;
 | |
| 
 | |
| 						++childStages;
 | |
| 					}
 | |
| 					else if (nextTraceInfo.IsProcessor == true)
 | |
| 					{
 | |
| 						if (nextTraceLevel < childProcessorLevel)
 | |
| 							break;
 | |
| 						if (nextTraceLevel > childProcessorLevel)
 | |
| 							continue;
 | |
| 
 | |
| 						++childProcessors;
 | |
| 					}
 | |
| 					else
 | |
| 					{
 | |
| 						throw new NotImplementedException(nextTraceInfo.Trace.ToString());
 | |
| 					}
 | |
| 
 | |
| 					++childCount;
 | |
| 				}
 | |
| 
 | |
| 				float indent = foldoutStaticOffset + indentLevel * foldoutLevelOffset;
 | |
| 
 | |
| 				GUILayout.BeginHorizontal();
 | |
| 				GUILayout.Space(indent);
 | |
| 				GUILayout.Label("•", _foldoutDotStyle);
 | |
| 				DrawButtonFoldout($"{stageTraceInfo.Name} ({childProcessors})", ref stageTraceInfo.IsVisible, Color.yellow, disabledBackgroundColor, _stageButtonStyle);
 | |
| 				GUILayout.EndHorizontal();
 | |
| 
 | |
| 				if (stageTraceInfo.IsVisible == true && childCount > 0)
 | |
| 				{
 | |
| 					int nextIndentLevel = indentLevel + 1;
 | |
| 
 | |
| 					while (true)
 | |
| 					{
 | |
| 						++traceInfoIndex;
 | |
| 						if (traceInfoIndex >= traceInfoCount)
 | |
| 							break;
 | |
| 
 | |
| 						KCCTraceInfo nextTraceInfo  = traceInfos[traceInfoIndex];
 | |
| 						int          nextTraceLevel = nextTraceInfo.Level;
 | |
| 
 | |
| 						if (nextTraceInfo.IsStage == true)
 | |
| 						{
 | |
| 							if (nextTraceLevel < childStageLevel)
 | |
| 								break;
 | |
| 							if (nextTraceLevel > childStageLevel)
 | |
| 								continue;
 | |
| 
 | |
| 							DrawStageTrace(traceInfos, traceInfoCount, traceInfoIndex, nextIndentLevel);
 | |
| 						}
 | |
| 						else if (nextTraceInfo.IsProcessor == true)
 | |
| 						{
 | |
| 							if (nextTraceLevel < childProcessorLevel)
 | |
| 								break;
 | |
| 							if (nextTraceLevel > childProcessorLevel)
 | |
| 								continue;
 | |
| 
 | |
| 							IKCCProcessor processor  = nextTraceInfo.Processor;
 | |
| 							GameObject    gameObject = null;
 | |
| 							string        name       = "N/A";
 | |
| 
 | |
| 							if (processor is Component processorComponent)
 | |
| 							{
 | |
| 								gameObject = processorComponent.gameObject;
 | |
| 								name       = gameObject.name;
 | |
| 							}
 | |
| 
 | |
| 							DrawPingDotButton($"{name}\n({processor.GetType().Name})", gameObject, indent + foldoutLevelOffset, processorBackgroundColor);
 | |
| 
 | |
| 							nextIndentLevel = indentLevel + 2;
 | |
| 						}
 | |
| 						else
 | |
| 						{
 | |
| 							throw new NotImplementedException(nextTraceInfo.Trace.ToString());
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		// PRIVATE METHODS
 | |
| 
 | |
| 		public static void DrawLine(Color color, float thickness = 1.0f, float padding = 10.0f)
 | |
| 		{
 | |
| 			Rect controlRect = EditorGUILayout.GetControlRect(GUILayout.Height(padding + thickness));
 | |
| 
 | |
| 			controlRect.height = thickness;
 | |
| 			controlRect.y += padding * 0.5f;
 | |
| 
 | |
| 			EditorGUI.DrawRect(controlRect, color);
 | |
| 		}
 | |
| 
 | |
| 		private static bool DrawButton(string label, bool condition, Color enabledBackgroundColor, Color disabledBackgroundColor)
 | |
| 		{
 | |
| 			Color backupBackgroundColor = GUI.backgroundColor;
 | |
| 			GUI.backgroundColor = condition == true ? enabledBackgroundColor : disabledBackgroundColor;
 | |
| 			bool result = GUILayout.Button(label);
 | |
| 			GUI.backgroundColor = backupBackgroundColor;
 | |
| 			return result;
 | |
| 		}
 | |
| 
 | |
| 		private static bool DrawButton(string label, bool condition, Color enabledBackgroundColor, Color disabledBackgroundColor, GUIStyle style)
 | |
| 		{
 | |
| 			Color backupBackgroundColor = GUI.backgroundColor;
 | |
| 			GUI.backgroundColor = condition == true ? enabledBackgroundColor : disabledBackgroundColor;
 | |
| 			bool result = GUILayout.Button(label, style);
 | |
| 			GUI.backgroundColor = backupBackgroundColor;
 | |
| 			return result;
 | |
| 		}
 | |
| 
 | |
| 		private static bool DrawPingButton(string label, GameObject gameObject, Color backgroundColor)
 | |
| 		{
 | |
| 			Color backupBackgroundColor = GUI.backgroundColor;
 | |
| 			GUI.backgroundColor = backgroundColor;
 | |
| 			bool result = GUILayout.Button(label);
 | |
| 			GUI.backgroundColor = backupBackgroundColor;
 | |
| 			if (result == true)
 | |
| 			{
 | |
| 				EditorGUIUtility.PingObject(gameObject);
 | |
| 			}
 | |
| 			return result;
 | |
| 		}
 | |
| 
 | |
| 		private static bool DrawPingButton(string label, GameObject gameObject, Color backgroundColor, GUIStyle style)
 | |
| 		{
 | |
| 			Color backupBackgroundColor = GUI.backgroundColor;
 | |
| 			GUI.backgroundColor = backgroundColor;
 | |
| 			bool result = GUILayout.Button(label, style);
 | |
| 			GUI.backgroundColor = backupBackgroundColor;
 | |
| 			if (result == true)
 | |
| 			{
 | |
| 				EditorGUIUtility.PingObject(gameObject);
 | |
| 			}
 | |
| 			return result;
 | |
| 		}
 | |
| 
 | |
| 		private static bool DrawPingButton(string label, GameObject gameObject, bool condition, Color enabledBackgroundColor, Color disabledBackgroundColor)
 | |
| 		{
 | |
| 			Color backupBackgroundColor = GUI.backgroundColor;
 | |
| 			GUI.backgroundColor = condition == true ? enabledBackgroundColor : disabledBackgroundColor;
 | |
| 			bool result = GUILayout.Button(label);
 | |
| 			GUI.backgroundColor = backupBackgroundColor;
 | |
| 			if (result == true)
 | |
| 			{
 | |
| 				EditorGUIUtility.PingObject(gameObject);
 | |
| 			}
 | |
| 			return result;
 | |
| 		}
 | |
| 
 | |
| 		private static bool DrawPingButton(string label, GameObject gameObject, bool condition, Color enabledBackgroundColor, Color disabledBackgroundColor, GUIStyle style)
 | |
| 		{
 | |
| 			Color backupBackgroundColor = GUI.backgroundColor;
 | |
| 			GUI.backgroundColor = condition == true ? enabledBackgroundColor : disabledBackgroundColor;
 | |
| 			bool result = GUILayout.Button(label, style);
 | |
| 			GUI.backgroundColor = backupBackgroundColor;
 | |
| 			if (result == true)
 | |
| 			{
 | |
| 				EditorGUIUtility.PingObject(gameObject);
 | |
| 			}
 | |
| 			return result;
 | |
| 		}
 | |
| 
 | |
| 		private static bool DrawPingDotButton(string label, GameObject gameObject, float offset)
 | |
| 		{
 | |
| 			GUILayout.BeginHorizontal();
 | |
| 			GUILayout.Space(offset);
 | |
| 			GUILayout.Label("•", _foldoutDotStyle);
 | |
| 
 | |
| 			bool result = GUILayout.Button(label);
 | |
| 			if (result == true)
 | |
| 			{
 | |
| 				EditorGUIUtility.PingObject(gameObject);
 | |
| 			}
 | |
| 
 | |
| 			GUILayout.EndHorizontal();
 | |
| 
 | |
| 			return result;
 | |
| 		}
 | |
| 
 | |
| 		private static bool DrawPingDotButton(string label, GameObject gameObject, float offset, Color backgroundColor)
 | |
| 		{
 | |
| 			Color backupBackgroundColor = GUI.backgroundColor;
 | |
| 
 | |
| 			GUILayout.BeginHorizontal();
 | |
| 			GUILayout.Space(offset);
 | |
| 			GUILayout.Label("•", _foldoutDotStyle);
 | |
| 
 | |
| 			GUI.backgroundColor = backgroundColor;
 | |
| 			bool result = GUILayout.Button(label);
 | |
| 			GUI.backgroundColor = backupBackgroundColor;
 | |
| 			if (result == true)
 | |
| 			{
 | |
| 				EditorGUIUtility.PingObject(gameObject);
 | |
| 			}
 | |
| 
 | |
| 			GUILayout.EndHorizontal();
 | |
| 
 | |
| 			return result;
 | |
| 		}
 | |
| 
 | |
| 		private static bool DrawButtonFoldout(string label, ref bool condition, Color enabledBackgroundColor, Color disabledBackgroundColor)
 | |
| 		{
 | |
| 			return DrawButtonFoldout("▼", "▶", label, ref condition, enabledBackgroundColor, disabledBackgroundColor);
 | |
| 		}
 | |
| 
 | |
| 		private static bool DrawButtonFoldout(string label, ref bool condition, Color enabledBackgroundColor, Color disabledBackgroundColor, GUIStyle style)
 | |
| 		{
 | |
| 			return DrawButtonFoldout("▼", "▶", label, ref condition, enabledBackgroundColor, disabledBackgroundColor, style);
 | |
| 		}
 | |
| 
 | |
| 		private static bool DrawButtonFoldout(string enabledPrefix, string disabledPrefix, string label, ref bool condition, Color enabledBackgroundColor, Color disabledBackgroundColor)
 | |
| 		{
 | |
| 			if (_buttonFoldoutStyle == null)
 | |
| 			{
 | |
| 				_buttonFoldoutStyle = new GUIStyle(GUI.skin.button);
 | |
| 				_buttonFoldoutStyle.alignment = TextAnchor.MiddleLeft;
 | |
| 			}
 | |
| 
 | |
| 			return DrawButtonFoldout(enabledPrefix, disabledPrefix, label, ref condition, enabledBackgroundColor, disabledBackgroundColor, _buttonFoldoutStyle);
 | |
| 		}
 | |
| 
 | |
| 		private static bool DrawButtonFoldout(string enabledPrefix, string disabledPrefix, string label, ref bool condition, Color enabledBackgroundColor, Color disabledBackgroundColor, GUIStyle style)
 | |
| 		{
 | |
| 			Color backupBackgroundColor = GUI.backgroundColor;
 | |
| 
 | |
| 			if (condition == true)
 | |
| 			{
 | |
| 				GUI.backgroundColor = enabledBackgroundColor;
 | |
| 				if (string.IsNullOrEmpty(enabledPrefix) == false)
 | |
| 				{
 | |
| 					label = $"{enabledPrefix} {label}";
 | |
| 				}
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				GUI.backgroundColor = disabledBackgroundColor;
 | |
| 				if (string.IsNullOrEmpty(disabledPrefix) == false)
 | |
| 				{
 | |
| 					label = $"{disabledPrefix} {label}";
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			if (GUILayout.Button(label, style) == true)
 | |
| 			{
 | |
| 				condition = !condition;
 | |
| 			}
 | |
| 
 | |
| 			GUI.backgroundColor = backupBackgroundColor;
 | |
| 
 | |
| 			return condition;
 | |
| 		}
 | |
| 	}
 | |
| }
 |