570 lines
19 KiB
C#
570 lines
19 KiB
C#
|
/* ---------------------------------------
|
|||
|
* Author: Martin Pane (martintayx@gmail.com) (@tayx94)
|
|||
|
* Contributors: https://github.com/Tayx94/graphy/graphs/contributors
|
|||
|
* Project: Graphy - Ultimate Stats Monitor
|
|||
|
* Date: 23-Dec-17
|
|||
|
* Studio: Tayx
|
|||
|
*
|
|||
|
* Git repo: https://github.com/Tayx94/graphy
|
|||
|
*
|
|||
|
* This project is released under the MIT license.
|
|||
|
* Attribution is not required, but it is always welcomed!
|
|||
|
* -------------------------------------*/
|
|||
|
|
|||
|
using UnityEngine;
|
|||
|
using UnityEngine.Events;
|
|||
|
using Debug = UnityEngine.Debug;
|
|||
|
|
|||
|
using System;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Linq;
|
|||
|
|
|||
|
using Tayx.Graphy.Audio;
|
|||
|
using Tayx.Graphy.Fps;
|
|||
|
using Tayx.Graphy.Ram;
|
|||
|
using Tayx.Graphy.Utils;
|
|||
|
|
|||
|
namespace Tayx.Graphy
|
|||
|
{
|
|||
|
/// <summary>
|
|||
|
/// Main class to access the Graphy Debugger API.
|
|||
|
/// </summary>
|
|||
|
public class GraphyDebugger : G_Singleton<GraphyDebugger>
|
|||
|
{
|
|||
|
/* ----- TODO: ----------------------------
|
|||
|
* Add summaries to the variables.
|
|||
|
* Add summaries to the functions.
|
|||
|
* Ask why we're not using System.Serializable instead for the helper class.
|
|||
|
* Simplify the initializers of the DebugPackets, but check wether we should as some wont work with certain lists.
|
|||
|
* --------------------------------------*/
|
|||
|
|
|||
|
protected GraphyDebugger () { }
|
|||
|
|
|||
|
#region Enums -> Public
|
|||
|
|
|||
|
public enum DebugVariable
|
|||
|
{
|
|||
|
Fps,
|
|||
|
Fps_Min,
|
|||
|
Fps_Max,
|
|||
|
Fps_Avg,
|
|||
|
Ram_Allocated,
|
|||
|
Ram_Reserved,
|
|||
|
Ram_Mono,
|
|||
|
Audio_DB
|
|||
|
}
|
|||
|
|
|||
|
public enum DebugComparer
|
|||
|
{
|
|||
|
Less_than,
|
|||
|
Equals_or_less_than,
|
|||
|
Equals,
|
|||
|
Equals_or_greater_than,
|
|||
|
Greater_than
|
|||
|
}
|
|||
|
|
|||
|
public enum ConditionEvaluation
|
|||
|
{
|
|||
|
All_conditions_must_be_met,
|
|||
|
Only_one_condition_has_to_be_met,
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
public enum MessageType
|
|||
|
{
|
|||
|
Log,
|
|||
|
Warning,
|
|||
|
Error
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region Structs -> Public
|
|||
|
|
|||
|
[System.Serializable]
|
|||
|
public struct DebugCondition
|
|||
|
{
|
|||
|
[Tooltip("Variable to compare against")]
|
|||
|
public DebugVariable Variable;
|
|||
|
[Tooltip("Comparer operator to use")]
|
|||
|
public DebugComparer Comparer;
|
|||
|
[Tooltip("Value to compare against the chosen variable")]
|
|||
|
public float Value;
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region Helper Classes
|
|||
|
|
|||
|
[System.Serializable]
|
|||
|
public class DebugPacket
|
|||
|
{
|
|||
|
|
|||
|
[Tooltip("If false, it won't be checked")]
|
|||
|
public bool Active = true;
|
|||
|
[Tooltip("Optional Id. It's used to get or remove DebugPackets in runtime")]
|
|||
|
public int Id;
|
|||
|
[Tooltip("If true, once the actions are executed, this DebugPacket will delete itself")]
|
|||
|
public bool ExecuteOnce = true;
|
|||
|
[Tooltip("Time to wait before checking if conditions are met (use this to avoid low fps drops triggering the conditions when loading the game)")]
|
|||
|
public float InitSleepTime = 2;
|
|||
|
[Tooltip("Time to wait before checking if conditions are met again (once they have already been met and if ExecuteOnce is false)")]
|
|||
|
public float ExecuteSleepTime = 2;
|
|||
|
|
|||
|
public ConditionEvaluation ConditionEvaluation = ConditionEvaluation.All_conditions_must_be_met;
|
|||
|
[Tooltip("List of conditions that will be checked each frame")]
|
|||
|
public List<DebugCondition> DebugConditions = new List<DebugCondition>();
|
|||
|
|
|||
|
// Actions on conditions met
|
|||
|
|
|||
|
public MessageType MessageType;
|
|||
|
[Multiline]
|
|||
|
public string Message = string.Empty;
|
|||
|
public bool TakeScreenshot = false;
|
|||
|
public string ScreenshotFileName = "Graphy_Screenshot";
|
|||
|
[Tooltip("If true, it pauses the editor")]
|
|||
|
public bool DebugBreak = false;
|
|||
|
public UnityEvent UnityEvents;
|
|||
|
public List<System.Action> Callbacks = new List<System.Action>();
|
|||
|
|
|||
|
|
|||
|
private bool canBeChecked = false;
|
|||
|
private bool executed = false;
|
|||
|
|
|||
|
private float timePassed = 0;
|
|||
|
|
|||
|
public bool Check { get { return canBeChecked; } }
|
|||
|
|
|||
|
public void Update()
|
|||
|
{
|
|||
|
if (!canBeChecked)
|
|||
|
{
|
|||
|
timePassed += Time.deltaTime;
|
|||
|
|
|||
|
if ( (executed && timePassed >= ExecuteSleepTime)
|
|||
|
|| (!executed && timePassed >= InitSleepTime))
|
|||
|
{
|
|||
|
canBeChecked = true;
|
|||
|
|
|||
|
timePassed = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void Executed()
|
|||
|
{
|
|||
|
canBeChecked = false;
|
|||
|
executed = true;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region Variables -> Serialized Private
|
|||
|
|
|||
|
[SerializeField] private List<DebugPacket> m_debugPackets = new List<DebugPacket>();
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region Variables -> Private
|
|||
|
|
|||
|
private G_FpsMonitor m_fpsMonitor = null;
|
|||
|
private G_RamMonitor m_ramMonitor = null;
|
|||
|
private G_AudioMonitor m_audioMonitor = null;
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region Methods -> Unity Callbacks
|
|||
|
|
|||
|
private void Start()
|
|||
|
{
|
|||
|
m_fpsMonitor = GetComponentInChildren<G_FpsMonitor>();
|
|||
|
m_ramMonitor = GetComponentInChildren<G_RamMonitor>();
|
|||
|
m_audioMonitor = GetComponentInChildren<G_AudioMonitor>();
|
|||
|
}
|
|||
|
|
|||
|
private void Update()
|
|||
|
{
|
|||
|
CheckDebugPackets();
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region Public Methods
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Add a new DebugPacket.
|
|||
|
/// </summary>
|
|||
|
public void AddNewDebugPacket(DebugPacket newDebugPacket)
|
|||
|
{
|
|||
|
m_debugPackets?.Add(newDebugPacket);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Add a new DebugPacket.
|
|||
|
/// </summary>
|
|||
|
public void AddNewDebugPacket
|
|||
|
(
|
|||
|
int newId,
|
|||
|
DebugCondition newDebugCondition,
|
|||
|
MessageType newMessageType,
|
|||
|
string newMessage,
|
|||
|
bool newDebugBreak,
|
|||
|
System.Action newCallback
|
|||
|
)
|
|||
|
{
|
|||
|
DebugPacket newDebugPacket = new DebugPacket();
|
|||
|
|
|||
|
newDebugPacket.Id = newId;
|
|||
|
newDebugPacket.DebugConditions.Add(newDebugCondition);
|
|||
|
newDebugPacket.MessageType = newMessageType;
|
|||
|
newDebugPacket.Message = newMessage;
|
|||
|
newDebugPacket.DebugBreak = newDebugBreak;
|
|||
|
newDebugPacket.Callbacks.Add(newCallback);
|
|||
|
|
|||
|
AddNewDebugPacket(newDebugPacket);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Add a new DebugPacket.
|
|||
|
/// </summary>
|
|||
|
public void AddNewDebugPacket
|
|||
|
(
|
|||
|
int newId,
|
|||
|
List<DebugCondition> newDebugConditions,
|
|||
|
MessageType newMessageType,
|
|||
|
string newMessage,
|
|||
|
bool newDebugBreak,
|
|||
|
System.Action newCallback
|
|||
|
)
|
|||
|
{
|
|||
|
DebugPacket newDebugPacket = new DebugPacket();
|
|||
|
|
|||
|
newDebugPacket.Id = newId;
|
|||
|
newDebugPacket.DebugConditions = newDebugConditions;
|
|||
|
newDebugPacket.MessageType = newMessageType;
|
|||
|
newDebugPacket.Message = newMessage;
|
|||
|
newDebugPacket.DebugBreak = newDebugBreak;
|
|||
|
newDebugPacket.Callbacks.Add(newCallback);
|
|||
|
|
|||
|
AddNewDebugPacket(newDebugPacket);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Add a new DebugPacket.
|
|||
|
/// </summary>
|
|||
|
public void AddNewDebugPacket
|
|||
|
(
|
|||
|
int newId,
|
|||
|
DebugCondition newDebugCondition,
|
|||
|
MessageType newMessageType,
|
|||
|
string newMessage,
|
|||
|
bool newDebugBreak,
|
|||
|
List<System.Action> newCallbacks
|
|||
|
)
|
|||
|
{
|
|||
|
DebugPacket newDebugPacket = new DebugPacket();
|
|||
|
|
|||
|
newDebugPacket.Id = newId;
|
|||
|
newDebugPacket.DebugConditions.Add(newDebugCondition);
|
|||
|
newDebugPacket.MessageType = newMessageType;
|
|||
|
newDebugPacket.Message = newMessage;
|
|||
|
newDebugPacket.DebugBreak = newDebugBreak;
|
|||
|
newDebugPacket.Callbacks = newCallbacks;
|
|||
|
|
|||
|
AddNewDebugPacket(newDebugPacket);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Add a new DebugPacket.
|
|||
|
/// </summary>
|
|||
|
public void AddNewDebugPacket
|
|||
|
(
|
|||
|
int newId,
|
|||
|
List<DebugCondition> newDebugConditions,
|
|||
|
MessageType newMessageType,
|
|||
|
string newMessage,
|
|||
|
bool newDebugBreak,
|
|||
|
List<System.Action> newCallbacks
|
|||
|
)
|
|||
|
{
|
|||
|
DebugPacket newDebugPacket = new DebugPacket();
|
|||
|
|
|||
|
newDebugPacket.Id = newId;
|
|||
|
newDebugPacket.DebugConditions = newDebugConditions;
|
|||
|
newDebugPacket.MessageType = newMessageType;
|
|||
|
newDebugPacket.Message = newMessage;
|
|||
|
newDebugPacket.DebugBreak = newDebugBreak;
|
|||
|
newDebugPacket.Callbacks = newCallbacks;
|
|||
|
|
|||
|
AddNewDebugPacket(newDebugPacket);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Returns the first Packet with the specified ID in the DebugPacket list.
|
|||
|
/// </summary>
|
|||
|
/// <param name="packetId"></param>
|
|||
|
/// <returns></returns>
|
|||
|
public DebugPacket GetFirstDebugPacketWithId(int packetId)
|
|||
|
{
|
|||
|
return m_debugPackets.First(x => x.Id == packetId);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Returns a list with all the Packets with the specified ID in the DebugPacket list.
|
|||
|
/// </summary>
|
|||
|
/// <param name="packetId"></param>
|
|||
|
/// <returns></returns>
|
|||
|
public List<DebugPacket> GetAllDebugPacketsWithId(int packetId)
|
|||
|
{
|
|||
|
return m_debugPackets.FindAll(x => x.Id == packetId);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Removes the first Packet with the specified ID in the DebugPacket list.
|
|||
|
/// </summary>
|
|||
|
/// <param name="packetId"></param>
|
|||
|
/// <returns></returns>
|
|||
|
public void RemoveFirstDebugPacketWithId(int packetId)
|
|||
|
{
|
|||
|
if (m_debugPackets != null && GetFirstDebugPacketWithId(packetId) != null)
|
|||
|
{
|
|||
|
m_debugPackets.Remove(GetFirstDebugPacketWithId(packetId));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Removes all the Packets with the specified ID in the DebugPacket list.
|
|||
|
/// </summary>
|
|||
|
/// <param name="packetId"></param>
|
|||
|
/// <returns></returns>
|
|||
|
public void RemoveAllDebugPacketsWithId(int packetId)
|
|||
|
{
|
|||
|
if (m_debugPackets != null)
|
|||
|
{
|
|||
|
m_debugPackets.RemoveAll(x => x.Id == packetId);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Add an Action callback to the first Packet with the specified ID in the DebugPacket list.
|
|||
|
/// </summary>
|
|||
|
/// <param name="callback"></param>
|
|||
|
/// <param name="id"></param>
|
|||
|
public void AddCallbackToFirstDebugPacketWithId(System.Action callback, int id)
|
|||
|
{
|
|||
|
if (GetFirstDebugPacketWithId(id) != null)
|
|||
|
{
|
|||
|
GetFirstDebugPacketWithId(id).Callbacks.Add(callback);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Add an Action callback to all the Packets with the specified ID in the DebugPacket list.
|
|||
|
/// </summary>
|
|||
|
/// <param name="callback"></param>
|
|||
|
/// <param name="id"></param>
|
|||
|
public void AddCallbackToAllDebugPacketWithId(System.Action callback, int id)
|
|||
|
{
|
|||
|
if (GetAllDebugPacketsWithId(id) != null)
|
|||
|
{
|
|||
|
foreach (var debugPacket in GetAllDebugPacketsWithId(id))
|
|||
|
{
|
|||
|
if (callback != null)
|
|||
|
{
|
|||
|
debugPacket.Callbacks.Add(callback);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region Methods -> Private
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Checks all the Debug Packets to see if they have to be executed.
|
|||
|
/// </summary>
|
|||
|
private void CheckDebugPackets()
|
|||
|
{
|
|||
|
if (m_debugPackets == null)
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
for (int i = 0; i < m_debugPackets.Count; i++)
|
|||
|
{
|
|||
|
DebugPacket packet = m_debugPackets[i];
|
|||
|
|
|||
|
if (packet != null && packet.Active)
|
|||
|
{
|
|||
|
packet.Update();
|
|||
|
|
|||
|
if (packet.Check)
|
|||
|
{
|
|||
|
switch (packet.ConditionEvaluation)
|
|||
|
{
|
|||
|
case ConditionEvaluation.All_conditions_must_be_met:
|
|||
|
int count = 0;
|
|||
|
|
|||
|
foreach (var packetDebugCondition in packet.DebugConditions)
|
|||
|
{
|
|||
|
if (CheckIfConditionIsMet(packetDebugCondition))
|
|||
|
{
|
|||
|
count++;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (count >= packet.DebugConditions.Count)
|
|||
|
{
|
|||
|
ExecuteOperationsInDebugPacket(packet);
|
|||
|
|
|||
|
if (packet.ExecuteOnce)
|
|||
|
{
|
|||
|
m_debugPackets[i] = null;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case ConditionEvaluation.Only_one_condition_has_to_be_met:
|
|||
|
foreach (var packetDebugCondition in packet.DebugConditions)
|
|||
|
{
|
|||
|
if (CheckIfConditionIsMet(packetDebugCondition))
|
|||
|
{
|
|||
|
ExecuteOperationsInDebugPacket(packet);
|
|||
|
|
|||
|
if (packet.ExecuteOnce)
|
|||
|
{
|
|||
|
m_debugPackets[i] = null;
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
m_debugPackets.RemoveAll((packet) => packet == null);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Returns true if a condition is met.
|
|||
|
/// </summary>
|
|||
|
/// <param name="debugCondition"></param>
|
|||
|
/// <returns></returns>
|
|||
|
private bool CheckIfConditionIsMet(DebugCondition debugCondition)
|
|||
|
{
|
|||
|
switch (debugCondition.Comparer)
|
|||
|
{
|
|||
|
case DebugComparer.Less_than:
|
|||
|
return GetRequestedValueFromDebugVariable(debugCondition.Variable) < debugCondition.Value;
|
|||
|
case DebugComparer.Equals_or_less_than:
|
|||
|
return GetRequestedValueFromDebugVariable(debugCondition.Variable) <= debugCondition.Value;
|
|||
|
case DebugComparer.Equals:
|
|||
|
return Mathf.Approximately(GetRequestedValueFromDebugVariable(debugCondition.Variable), debugCondition.Value);
|
|||
|
case DebugComparer.Equals_or_greater_than:
|
|||
|
return GetRequestedValueFromDebugVariable(debugCondition.Variable) >= debugCondition.Value;
|
|||
|
case DebugComparer.Greater_than:
|
|||
|
return GetRequestedValueFromDebugVariable(debugCondition.Variable) > debugCondition.Value;
|
|||
|
|
|||
|
default:
|
|||
|
return false;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Obtains the requested value from the specified variable.
|
|||
|
/// </summary>
|
|||
|
/// <param name="debugVariable"></param>
|
|||
|
/// <returns></returns>
|
|||
|
private float GetRequestedValueFromDebugVariable(DebugVariable debugVariable)
|
|||
|
{
|
|||
|
switch (debugVariable)
|
|||
|
{
|
|||
|
case DebugVariable.Fps:
|
|||
|
return m_fpsMonitor != null ? m_fpsMonitor.CurrentFPS : 0;
|
|||
|
case DebugVariable.Fps_Min:
|
|||
|
return m_fpsMonitor != null ? m_fpsMonitor.OnePercentFPS : 0;
|
|||
|
case DebugVariable.Fps_Max:
|
|||
|
return m_fpsMonitor != null ? m_fpsMonitor.Zero1PercentFps : 0;
|
|||
|
case DebugVariable.Fps_Avg:
|
|||
|
return m_fpsMonitor != null ? m_fpsMonitor.AverageFPS : 0;
|
|||
|
|
|||
|
case DebugVariable.Ram_Allocated:
|
|||
|
return m_ramMonitor != null ? m_ramMonitor.AllocatedRam : 0;
|
|||
|
case DebugVariable.Ram_Reserved:
|
|||
|
return m_ramMonitor != null ? m_ramMonitor.AllocatedRam : 0;
|
|||
|
case DebugVariable.Ram_Mono:
|
|||
|
return m_ramMonitor != null ? m_ramMonitor.AllocatedRam : 0;
|
|||
|
|
|||
|
case DebugVariable.Audio_DB:
|
|||
|
return m_audioMonitor != null ? m_audioMonitor.MaxDB : 0;
|
|||
|
|
|||
|
default:
|
|||
|
return 0;
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Executes the operations in the DebugPacket specified.
|
|||
|
/// </summary>
|
|||
|
/// <param name="debugPacket"></param>
|
|||
|
private void ExecuteOperationsInDebugPacket(DebugPacket debugPacket)
|
|||
|
{
|
|||
|
if (debugPacket != null)
|
|||
|
{
|
|||
|
if (debugPacket.DebugBreak)
|
|||
|
{
|
|||
|
Debug.Break();
|
|||
|
}
|
|||
|
|
|||
|
if (debugPacket.Message != "")
|
|||
|
{
|
|||
|
string message = "[Graphy] (" + System.DateTime.Now + "): " + debugPacket.Message;
|
|||
|
|
|||
|
switch (debugPacket.MessageType)
|
|||
|
{
|
|||
|
case MessageType.Log:
|
|||
|
Debug.Log(message);
|
|||
|
break;
|
|||
|
case MessageType.Warning:
|
|||
|
Debug.LogWarning(message);
|
|||
|
break;
|
|||
|
case MessageType.Error:
|
|||
|
Debug.LogError(message);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (debugPacket.TakeScreenshot)
|
|||
|
{
|
|||
|
string path = debugPacket.ScreenshotFileName + "_" + System.DateTime.Now + ".png";
|
|||
|
path = path.Replace("/", "-").Replace(" ", "_").Replace(":", "-");
|
|||
|
|
|||
|
#if UNITY_2017_1_OR_NEWER
|
|||
|
ScreenCapture.CaptureScreenshot(path);
|
|||
|
#else
|
|||
|
Application.CaptureScreenshot(path);
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
debugPacket.UnityEvents.Invoke();
|
|||
|
|
|||
|
foreach (var callback in debugPacket.Callbacks)
|
|||
|
{
|
|||
|
if (callback != null) callback();
|
|||
|
}
|
|||
|
|
|||
|
debugPacket.Executed();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
}
|
|||
|
}
|