您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
353 行
11 KiB
353 行
11 KiB
using System;
|
|
using System.Reflection;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEditor;
|
|
|
|
|
|
public class StateHistoryWindow : EditorWindow
|
|
{
|
|
|
|
[MenuItem("FPS Sample/Windows/State History")]
|
|
public static void ShowWindow()
|
|
{
|
|
GetWindow<StateHistoryWindow>(false, "State History", true);
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
StateHistorySampler.Capture += OnCapture;
|
|
EditorApplication.playModeStateChanged += OnPlaymodeChanged;
|
|
EditorApplication.quitting += OnQuitting;
|
|
}
|
|
|
|
void OnDisable()
|
|
{
|
|
StateHistorySampler.Capture -= OnCapture;
|
|
EditorApplication.playModeStateChanged -= OnPlaymodeChanged;
|
|
EditorApplication.quitting -= OnQuitting;
|
|
|
|
}
|
|
|
|
void OnQuitting()
|
|
{
|
|
Reset();
|
|
}
|
|
|
|
void OnPlaymodeChanged(PlayModeStateChange state)
|
|
{
|
|
if (state == PlayModeStateChange.ExitingPlayMode)
|
|
Reset();
|
|
}
|
|
|
|
private void OnCapture(StateHistorySampler.CaptureResult result)
|
|
{
|
|
//if(m_pauseOnCapture)
|
|
//EditorApplication.isPaused = true;
|
|
|
|
int endTick = result.firstTick + result.count - 1;
|
|
|
|
if (m_captureResults.ContainsKey(endTick))
|
|
m_captureResults[endTick] = result;
|
|
else
|
|
m_captureResults.Add(endTick, result);
|
|
|
|
SetActiveResult(result);
|
|
|
|
Repaint();
|
|
}
|
|
|
|
void SetActiveResult(StateHistorySampler.CaptureResult result)
|
|
{
|
|
if (result == m_activeResult)
|
|
return;
|
|
|
|
Reset();
|
|
m_activeResult = result;
|
|
}
|
|
|
|
private void Reset()
|
|
{
|
|
m_selectedColumnIndex = -1;
|
|
m_selectedRowIndex = 0;
|
|
m_activeResult = null;
|
|
}
|
|
|
|
void OnGUI()
|
|
{
|
|
GUILayout.BeginVertical();
|
|
DrawHeader();
|
|
GUILayout.EndVertical();
|
|
|
|
if (!StateHistory.Enabled)
|
|
return;
|
|
|
|
GUILayout.BeginHorizontal();
|
|
|
|
DrawStates();
|
|
|
|
// EditorGUILayout.LabelField("", GUI.skin.verticalSlider);
|
|
|
|
DrawInspector();
|
|
|
|
GUILayout.EndHorizontal();
|
|
}
|
|
|
|
void DrawHeader()
|
|
{
|
|
GUILayout.BeginHorizontal();
|
|
|
|
bool enabled = GUILayout.Toggle(StateHistory.Enabled, "Enabled", EditorStyles.toolbarButton);
|
|
if(enabled != StateHistory.Enabled)
|
|
{
|
|
StateHistory.Enabled = enabled;
|
|
}
|
|
|
|
StateHistorySampler.captureOnMispredict = GUILayout.Toggle(StateHistorySampler.captureOnMispredict, "Capture on mispredict", EditorStyles.toolbarButton);
|
|
|
|
// m_pauseOnCapture = GUILayout.Toggle(m_pauseOnCapture, "Pause on capture", EditorStyles.toolbarButton);
|
|
|
|
if (GUILayout.Button("SAMPLE [Ctrl+H]", EditorStyles.toolbarButton, GUILayout.MinWidth(200)))
|
|
{
|
|
StateHistorySampler.RequestCapture();
|
|
}
|
|
|
|
GUILayout.FlexibleSpace();
|
|
|
|
// Capture selection
|
|
{
|
|
string[] options = new string[m_captureResults.Count];
|
|
int i = 0;
|
|
int selected = -1;
|
|
foreach(var pair in m_captureResults)
|
|
{
|
|
if (pair.Value == m_activeResult)
|
|
selected = i;
|
|
options[i] = pair.Key.ToString();
|
|
i++;
|
|
}
|
|
|
|
GUILayout.Label("Show:", EditorStyles.toolbarButton);
|
|
|
|
int newSelected = EditorGUILayout.Popup(selected, options, EditorStyles.toolbarDropDown, GUILayout.Width(80));
|
|
if(newSelected != selected)
|
|
{
|
|
int key = int.Parse(options[newSelected]);
|
|
SetActiveResult(m_captureResults[key]);
|
|
}
|
|
}
|
|
|
|
GUILayout.EndHorizontal();
|
|
}
|
|
|
|
void DrawStates()
|
|
{
|
|
if (m_activeResult == null)
|
|
return;
|
|
|
|
int tickWidth = 40;
|
|
int commandWidth = 20;
|
|
int stateWidth = 100;
|
|
|
|
// Handle arrow navigation
|
|
Event e = Event.current;
|
|
if (e.isKey && e.type == EventType.KeyDown)
|
|
{
|
|
bool repaint = false;
|
|
if (e.keyCode == KeyCode.UpArrow && m_selectedRowIndex > 0)
|
|
{
|
|
m_selectedRowIndex--;
|
|
repaint = true;
|
|
}
|
|
|
|
if (e.keyCode == KeyCode.DownArrow && m_selectedRowIndex < m_activeResult.count - 1)
|
|
{
|
|
m_selectedRowIndex++;
|
|
repaint = true;
|
|
}
|
|
|
|
if (e.keyCode == KeyCode.LeftArrow && m_selectedColumnIndex > -1)
|
|
{
|
|
m_selectedColumnIndex--;
|
|
repaint = true;
|
|
}
|
|
|
|
if (e.keyCode == KeyCode.RightArrow && m_selectedColumnIndex < m_activeResult.componentData.Count - 1)
|
|
{
|
|
m_selectedColumnIndex++;
|
|
repaint = true;
|
|
}
|
|
|
|
if(repaint)
|
|
{
|
|
Repaint();
|
|
EditorGUIUtility.ExitGUI();
|
|
}
|
|
}
|
|
|
|
|
|
GUILayout.BeginVertical();
|
|
|
|
// Headed
|
|
GUILayout.BeginScrollView(m_statesScrolllPosition, GUIStyle.none, GUIStyle.none);
|
|
GUILayout.BeginHorizontal();
|
|
GUILayout.Label("Tick", GUILayout.Width(tickWidth));
|
|
GUILayout.Label("Command", GUILayout.Width(commandWidth));
|
|
foreach (var componentData in m_activeResult.componentData)
|
|
{
|
|
GUILayout.BeginVertical(GUILayout.Width(stateWidth));
|
|
GUILayout.Label(componentData.component.gameObject.name, GUILayout.Width(stateWidth));
|
|
GUILayout.Label(componentData.component.GetType().Name, GUILayout.Width(stateWidth));
|
|
GUILayout.EndVertical();
|
|
}
|
|
GUILayout.EndHorizontal();
|
|
GUILayout.EndScrollView();
|
|
|
|
// State grid
|
|
m_statesScrolllPosition = GUILayout.BeginScrollView(m_statesScrolllPosition);
|
|
GUILayout.BeginHorizontal();
|
|
|
|
string[] stringRows = new string[m_activeResult.count];
|
|
|
|
|
|
// Ticks
|
|
{
|
|
for (int i = 0; i < m_activeResult.count; i++)
|
|
{
|
|
int tick = i + m_activeResult.firstTick;
|
|
stringRows[i] = tick.ToString();
|
|
}
|
|
GUILayout.SelectionGrid(-1, stringRows, 1, GUILayout.Width(tickWidth));
|
|
}
|
|
|
|
// Command
|
|
{
|
|
int selectedIndex = m_selectedColumnIndex == -1 ? m_selectedRowIndex : -1;
|
|
for (int i = 0; i < m_activeResult.count; i++)
|
|
{
|
|
stringRows[i] = "C";
|
|
}
|
|
int newIndex = GUILayout.SelectionGrid(selectedIndex, stringRows, 1, GUILayout.Width(commandWidth));
|
|
if (newIndex != selectedIndex)
|
|
{
|
|
m_selectedRowIndex = newIndex;
|
|
if (m_selectedColumnIndex != -1)
|
|
{
|
|
m_selectedColumnIndex = -1;
|
|
Repaint();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// States
|
|
for(int componentIndex=0;componentIndex< m_activeResult.componentData.Count;componentIndex++)
|
|
{
|
|
bool isSelectedColumn = m_selectedColumnIndex == componentIndex;
|
|
int selectedIndex = isSelectedColumn ? m_selectedRowIndex : -1;
|
|
|
|
StateHistorySampler.ComponentData componentData = m_activeResult.componentData[componentIndex];
|
|
|
|
for (int i = 0; i < m_activeResult.count; i++)
|
|
{
|
|
bool state = componentData.states[i] != null;
|
|
bool predicted = componentData.predictedStates[i] != null;
|
|
bool predictionValid = componentData.predictionValid[i];
|
|
stringRows[i] = !predictionValid ? "MISS" : predicted && state ? "P+S" : predicted ? "P" : state ? "S" : "";
|
|
}
|
|
|
|
int newIndex = GUILayout.SelectionGrid(selectedIndex, stringRows, 1, GUILayout.Width(stateWidth));
|
|
if (newIndex != selectedIndex)
|
|
{
|
|
m_selectedRowIndex = newIndex;
|
|
if (m_selectedColumnIndex != componentIndex)
|
|
{
|
|
m_selectedColumnIndex = componentIndex;
|
|
Repaint();
|
|
}
|
|
}
|
|
}
|
|
|
|
GUILayout.FlexibleSpace();
|
|
GUILayout.EndHorizontal();
|
|
|
|
GUILayout.EndScrollView();
|
|
|
|
GUILayout.EndVertical();
|
|
|
|
}
|
|
|
|
void DrawInspector()
|
|
{
|
|
int fieldNameWidth = 100;
|
|
int fieldValueWitdh = 140;
|
|
int totalWidth = fieldNameWidth + 2 * fieldValueWitdh+ 10;
|
|
|
|
GUILayout.BeginVertical();
|
|
|
|
m_inspectorScrolllPosition = GUILayout.BeginScrollView(m_inspectorScrolllPosition, GUILayout.Width(totalWidth));
|
|
|
|
GUILayout.BeginHorizontal();
|
|
GUILayout.Label("Field", EditorStyles.boldLabel, GUILayout.Width(fieldNameWidth));
|
|
GUILayout.Label("Predicted", EditorStyles.boldLabel, GUILayout.Width(fieldValueWitdh));
|
|
GUILayout.Label("State", EditorStyles.boldLabel, GUILayout.Width(fieldValueWitdh));
|
|
GUILayout.EndHorizontal();
|
|
|
|
if (m_activeResult != null)
|
|
{
|
|
//int tick = m_activeResult.firstTick + m_selectedRowIndex;
|
|
System.Object stateObject = null;
|
|
System.Object predictedObject = null;
|
|
|
|
if (m_selectedColumnIndex == -1)
|
|
{
|
|
stateObject = m_activeResult.commands[m_selectedRowIndex];
|
|
}
|
|
else
|
|
{
|
|
if (m_selectedColumnIndex < m_activeResult.componentData.Count)
|
|
{
|
|
StateHistorySampler.ComponentData data = m_activeResult.componentData[m_selectedColumnIndex];
|
|
stateObject = data.states[m_selectedRowIndex];
|
|
predictedObject = data.predictedStates[m_selectedRowIndex];
|
|
}
|
|
}
|
|
|
|
System.Object typeReferenceObject = stateObject != null ? stateObject : predictedObject != null ? predictedObject : null;
|
|
if (typeReferenceObject != null)
|
|
{
|
|
|
|
Type stateObjectType = typeReferenceObject.GetType();
|
|
foreach (var field in stateObjectType.GetFields())
|
|
{
|
|
GUILayout.BeginHorizontal();
|
|
|
|
GUILayout.Label(field.Name, GUILayout.Width(fieldNameWidth));
|
|
|
|
System.Object predictedVal = predictedObject != null ? field.GetValue(predictedObject) : "";
|
|
GUILayout.Label(predictedVal.ToString(), GUILayout.Width(fieldValueWitdh));
|
|
|
|
System.Object stateVal = stateObject != null ? field.GetValue(stateObject) : "";
|
|
GUILayout.Label(stateVal.ToString(), GUILayout.Width(fieldValueWitdh));
|
|
|
|
GUILayout.EndHorizontal();
|
|
}
|
|
}
|
|
}
|
|
|
|
GUILayout.EndScrollView();
|
|
|
|
GUILayout.EndVertical();
|
|
}
|
|
|
|
//bool m_pauseOnCapture;
|
|
|
|
Dictionary<int, StateHistorySampler.CaptureResult> m_captureResults = new Dictionary<int, StateHistorySampler.CaptureResult>();
|
|
StateHistorySampler.CaptureResult m_activeResult;
|
|
int m_selectedColumnIndex; // is -1 when commands selected
|
|
int m_selectedRowIndex;
|
|
|
|
|
|
Vector2 m_statesScrolllPosition;
|
|
Vector2 m_inspectorScrolllPosition;
|
|
}
|