Skip to content

Commit

Permalink
Adding rotation statistics. Adding option to flatten statistics to si…
Browse files Browse the repository at this point in the history
…ngle line.
  • Loading branch information
rorygames committed Jul 20, 2023
1 parent f560dc7 commit 1726704
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 43 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.1.3]

### Added
- Rotation statistic recording
- Option to flatten multipart statistics (e.g. XYZ) into a single line during CSV export

## [1.1.2] - 11/07/23

### Added
Expand Down
94 changes: 71 additions & 23 deletions Core/Editor/Scripts/Statistics/StatisticCSVPopup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using UnityEngine;
using UnityEditor;
using PlayRecorder.Tools;
using System.Reflection;

namespace PlayRecorder.Statistics
{
Expand All @@ -17,37 +18,43 @@ public class StatisticCSVPopup : PopupWindowContent

private string _exampleText = "";

private bool _keepFileNumbers = true, _keepFileNames = true;
private bool _keepFileNumbers = true, _keepFileNames = true, _flattenMultiStats = false;

private int _totalRows = 0;

private const string _keepNumbersKey = "PlayRecorder_CSV_Numbers", _keepNamesKey = "PlayRecorder_CSV_Names";
private const string _keepNumbersKey = "PlayRecorder_CSV_Numbers", _keepNamesKey = "PlayRecorder_CSV_Names", _flattenNamesKey = "PlayRecorder_CSV_Flatten";

private Vector2 _scrollPos = Vector2.zero;

public StatisticCSVPopup(List<StatisticWindow.StatCache> statsCache, float width)
{
_statsCache = statsCache;
_width = width;
for (int i = 0; i < _statsCache.Count; i++)
{
_totalRows += _statsCache[i].values.Length * _statsCache[i].statFields.Length;
}

if(EditorPrefs.HasKey(_keepNumbersKey))
if (EditorPrefs.HasKey(_keepNumbersKey))
{
_keepFileNumbers = EditorPrefs.GetBool(_keepNumbersKey);
}
if(EditorPrefs.HasKey(_keepNamesKey))
if (EditorPrefs.HasKey(_keepNamesKey))
{
_keepFileNames = EditorPrefs.GetBool(_keepNamesKey);
}
_exampleText = GetCSVLines(_statsCache[0]).TrimEnd();
if (EditorPrefs.HasKey(_flattenNamesKey))
{
_flattenMultiStats = EditorPrefs.GetBool(_flattenNamesKey);
}

for (int i = 0; i < _statsCache.Count; i++)
{
_totalRows += _statsCache[i].values.Length * (_flattenMultiStats ? 1 : _statsCache[i].statFields.Length);
}

_exampleText = GetCSVLines(_statsCache[0], 12).TrimEnd();
}

public override Vector2 GetWindowSize()
{
return new Vector2(_width-(Sizes.padding*3), ((Sizes.heightLine+Sizes.padding) * 9));
return new Vector2(_width - (Sizes.padding * 3), ((Sizes.heightLine + Sizes.padding) * 10));
}

public override void OnGUI(Rect rect)
Expand All @@ -58,7 +65,7 @@ public override void OnGUI(Rect rect)

GUIContent closeButton = new GUIContent(EditorGUIUtility.IconContent("winbtn_win_close"));

if(GUILayout.Button(closeButton,GUILayout.Width(Sizes.Timeline.widthFileButton)))
if (GUILayout.Button(closeButton, GUILayout.Width(Sizes.Timeline.widthFileButton)))
{
editorWindow.Close();
}
Expand All @@ -70,28 +77,44 @@ public override void OnGUI(Rect rect)
bool oldNumbers = _keepFileNumbers;
_keepFileNumbers = EditorGUILayout.Toggle(new GUIContent("Keep File Number", "Adds a column with the current file number as shown in the statistics window for this statistic."), _keepFileNumbers);

if(oldNumbers != _keepFileNumbers)
if (oldNumbers != _keepFileNumbers)
{
EditorPrefs.SetBool(_keepNumbersKey, _keepFileNumbers);
_exampleText = GetCSVLines(_statsCache[0]).TrimEnd();
_exampleText = GetCSVLines(_statsCache[0], 12).TrimEnd();
}

bool oldNames = _keepFileNames;
_keepFileNames = EditorGUILayout.Toggle(new GUIContent("Keep Recording Name", "Adds a column with the current recording name for this statistic."), _keepFileNames);

if(oldNames != _keepFileNames)
if (oldNames != _keepFileNames)
{
EditorPrefs.SetBool(_keepNamesKey, _keepFileNames);
_exampleText = GetCSVLines(_statsCache[0]).TrimEnd();
_exampleText = GetCSVLines(_statsCache[0], 12).TrimEnd();
}

bool oldFlatten = _flattenMultiStats;
_flattenMultiStats = EditorGUILayout.Toggle(new GUIContent("Flatten Stat Components", "By default, statistics with multiple parts will be stored as single row per element. (e.g. Vector3 XYZ -> Vector3_X Vector3_Y Vector3_Z)" +
"This changes it to store it as a single row (e.g. Vector3 XYZ -> (X,Y,Z)"), _flattenMultiStats);

if (oldFlatten != _flattenMultiStats)
{
EditorPrefs.SetBool(_flattenNamesKey, _flattenMultiStats);
_exampleText = GetCSVLines(_statsCache[0], 12).TrimEnd();

_totalRows = 0;
for (int i = 0; i < _statsCache.Count; i++)
{
_totalRows += _statsCache[i].values.Length * (_flattenMultiStats ? 1 : _statsCache[i].statFields.Length);
}
}

EditorGUILayout.EndHorizontal();

EditorGUILayout.LabelField("Example Headers and Rows", Styles.textBold);

_scrollPos = EditorGUILayout.BeginScrollView(_scrollPos, GUILayout.Height((Sizes.heightLine * 4) - Sizes.padding));
_scrollPos = EditorGUILayout.BeginScrollView(_scrollPos, GUILayout.Height((Sizes.heightLine * 5) - Sizes.padding));

EditorGUILayout.TextArea((_keepFileNumbers ? "FileNumber," : "") + (_keepFileNames ? "RecordingName," : "") + _columnsString +
EditorGUILayout.TextArea((_keepFileNumbers ? "FileNumber," : "") + (_keepFileNames ? "RecordingName," : "") + _columnsString +
_exampleText, GUILayout.ExpandHeight(true));

EditorGUILayout.EndScrollView();
Expand All @@ -100,23 +123,31 @@ public override void OnGUI(Rect rect)
EditorGUILayout.LabelField($"Columns: {_columnsPreCount + (_keepFileNumbers ? 1 : 0) + (_keepFileNames ? 1 : 0)}");
EditorGUILayout.LabelField($"Rows: {_totalRows}");
EditorGUILayout.EndHorizontal();
if(GUILayout.Button("Export CSV"))
if (GUILayout.Button("Export CSV"))
{
string name = System.DateTime.Now.ToString("yyyyMMddHHmmss") + " " + Application.productName.Replace(".", string.Empty) + " " + UnityEngine.SceneManagement.SceneManager.GetActiveScene().name + " Stats";
string s = EditorUtility.SaveFilePanel("Export CSV", null, name, "csv");
if(s.Length != 0)
if (s.Length != 0)
{
File.WriteAllText(s, GenerateCSV());
}
}
}

private string GetCSVLines(StatisticWindow.StatCache cache)
private string GetCSVLines(StatisticWindow.StatCache cache, int trimLines = 0)
{
string line = "";
for (int i = 0; i < cache.values.Length; i++)

int length = cache.values.Length;

if (trimLines > 0 && cache.values.Length > trimLines)
{
length = trimLines;
}

for (int i = 0; i < length; i++)
{
if (cache.statFields.Length > 1)
if (cache.statFields.Length > 1 && !_flattenMultiStats)
{
for (int y = 0; y < cache.statFields.Length; y++)
{
Expand All @@ -133,7 +164,14 @@ private string GetCSVLines(StatisticWindow.StatCache cache)
line += cache.statName.ToCSVCell() + ",";
line += i.ToString() + ",";
line += cache.statTimes[i].ToString() + ",";
line += cache.values[i].ToString().ToCSVCell() + "\n";
if (cache.statFields.Length > 1 && _flattenMultiStats)
{
line += MultiStatSingleLine(cache.statFields, cache.values[i]).ToCSVCell() + "\n";
}
else
{
line += cache.values[i].ToString().ToCSVCell() + "\n";
}
}
}
return line;
Expand All @@ -154,6 +192,16 @@ private string AddFileInfo(StatisticWindow.StatCache cache)
return s;
}

private string MultiStatSingleLine(FieldInfo[] fields, object parentObject)
{
string output = "(";
for (int i = 0; i < fields.Length; i++)
{
output += fields[i].GetValue(parentObject).ToString() + (i < fields.Length - 1 ? "," : "");
}
return output + ")";
}

private string GenerateCSV()
{
string output = "";
Expand Down
2 changes: 1 addition & 1 deletion Core/Editor/Scripts/Statistics/StatisticWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,7 @@ private void SingleMessage(StatCache cache, int index)
{
_statCount++;
GUILayout.BeginVertical(GUI.skin.box);

// Convert the time to readable formats
string timeLabel = TimeUtil.ConvertToTime(InverseLerpDouble(0, cache.maxFrame, cache.frameIndex) * cache.maxTime);
string endTimeLabel = TimeUtil.ConvertToTime(cache.maxTime);
Expand Down
50 changes: 31 additions & 19 deletions Core/Runtime/Scripts/Components/RecordComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ protected void OnEnable()

protected void OnDisable()
{
if(_recording)
if (_recording)
{
_recordItem.AddStatus(false, _currentTick);
OnRecordingDisable();
Expand All @@ -92,7 +92,7 @@ protected void OnDisable()

protected virtual void Reset()
{
_descriptor = name +"_"+ GetType().FormatType();
_descriptor = name + "_" + GetType().FormatType();
}

#endif
Expand Down Expand Up @@ -165,7 +165,7 @@ public void RecordTick(int tick)
{
RecordTickLogic();
}
catch(Exception error)
catch (Exception error)
{
Debug.LogError("Error with " + _gameObjectName + " on RecordTickLogic.\n" + error.ToString(), this);
}
Expand Down Expand Up @@ -220,7 +220,7 @@ public void AddStatistic(string message, int value)
return;

int ind = _recordItem.messages.FindIndex(x => x.message == message);
if(ind == -1)
if (ind == -1)
{
RecordStatInt rsi = new RecordStatInt { message = message };
rsi.frames.Add(_currentTick);
Expand Down Expand Up @@ -363,6 +363,18 @@ public void AddStatistic(string message, Vector4 value)
}
}

public void AddStatistic(string message, Quaternion value, bool eulerAngles = true)
{
if (eulerAngles)
{
AddStatistic(message, value.eulerAngles);
}
else
{
AddStatistic(message, new Vector4(value.x, value.y, value.z, value.w));
}
}

private void StatisticWarning(RecordMessage type)
{
Debug.LogWarning("Stat already assigned under different type: " + type.GetType().ToString());
Expand Down Expand Up @@ -399,9 +411,9 @@ protected virtual void OnSetPlaybackData()

public void SetPlaybackIgnores(PlaybackIgnoreItem playbackIgnore)
{
if(_customPlaybackIgnoreItem == null)
if (_customPlaybackIgnoreItem == null)
{
if(playbackIgnore != null)
if (playbackIgnore != null)
{
_playbackIgnoreItem = playbackIgnore;
}
Expand All @@ -415,7 +427,7 @@ public void SetPlaybackIgnores(PlaybackIgnoreItem playbackIgnore)
_playbackIgnoreItem = _customPlaybackIgnoreItem.item;
}
// This allows for empty ignores to not affect other components
if(_playbackIgnoreItem != null)
if (_playbackIgnoreItem != null)
{
SetPlaybackIgnoreTransforms();
PlaybackIgnore();
Expand Down Expand Up @@ -451,7 +463,7 @@ protected void PlaybackIgnore()
continue;
}

if(typeof(Collider).IsSameOrSubclass(components[j].GetType()) && _playbackIgnoreItem.disableCollisions)
if (typeof(Collider).IsSameOrSubclass(components[j].GetType()) && _playbackIgnoreItem.disableCollisions)
{
((Collider)components[j]).enabled = false;
continue;
Expand Down Expand Up @@ -480,11 +492,11 @@ protected void PlaybackIgnore()
// Enforce the settings for the specific defined items
if (behaviours[j].GetType() == typeof(Camera))
{
if(_playbackIgnoreItem.disableCamera)
if (_playbackIgnoreItem.disableCamera)
{
behaviours[j].enabled = false;
}
if(_playbackIgnoreItem.disableVRCamera)
if (_playbackIgnoreItem.disableVRCamera)
{
((Camera)behaviours[j]).stereoTargetEye = StereoTargetEyeMask.None;
}
Expand All @@ -494,13 +506,13 @@ protected void PlaybackIgnore()
found = false;
for (int k = 0; k < _playbackIgnoreItem.enabledBehaviours.Count; k++)
{
if(behaviours[j].GetType().ToString().Contains(_playbackIgnoreItem.enabledBehaviours[k],StringComparison.InvariantCultureIgnoreCase))
if (behaviours[j].GetType().ToString().Contains(_playbackIgnoreItem.enabledBehaviours[k], StringComparison.InvariantCultureIgnoreCase))
{
found = true;
}
}

if(!found)
if (!found)
{
behaviours[j].enabled = false;
}
Expand All @@ -511,7 +523,7 @@ protected void PlaybackIgnore()
public virtual void StartPlaying()
{
_playing = true;

OnStartPlayback?.Invoke();
}

Expand All @@ -525,9 +537,9 @@ public void PlayUpdate()
{
PlayUpdateLogic();
}
catch(Exception error)
catch (Exception error)
{
Debug.LogError("Error with " + _gameObjectName + " on PlayUpdateLogic.\n"+error.ToString(), this);
Debug.LogError("Error with " + _gameObjectName + " on PlayUpdateLogic.\n" + error.ToString(), this);
}
}
_playUpdatedParts.Clear();
Expand Down Expand Up @@ -581,13 +593,13 @@ public void PlayTick(int tick)
{
PlayTickLogic(i);
}
catch(Exception error)
catch (Exception error)
{
Debug.LogError("Error with " + _gameObjectName + " on PlayTickLogic.\n" + error.ToString(), this);
}
}
}
if(_playUpdatedParts.Count > 0)
if (_playUpdatedParts.Count > 0)
{
PlayAfterTickLogic();
}
Expand All @@ -600,7 +612,7 @@ public void PlayTick(int tick)
/// </summary>
protected virtual void PlayTickLogic(int index)
{

}

/// <summary>
Expand Down Expand Up @@ -630,7 +642,7 @@ public List<string> PlayMessages(int tick)
public void SetDescriptor(string descriptor)
{
_descriptor = descriptor;
if(_manager != null)
if (_manager != null)
{
_uniqueDescriptor = _manager.CheckUniqueDescriptor(this);
}
Expand Down

0 comments on commit 1726704

Please sign in to comment.