using Godot;
using System.IO;
using WeavUtils;
public partial class DebugGUI : Control
{
// Other scripts may use us right off the bat, so we make sure we initialize first
public DebugGUI()
{
ProcessPhysicsPriority = int.MinValue;
}
static DebugGUI Instance;
#region Settings
public static class Settings
{
const string DEBUGGUI_SETTINGS_DIR = "DebugGUI/Settings/";
public static void Init()
{
if (!Engine.IsEditorHint()) return;
// Inits defaults or load current if present
Load();
ProjectSettings.SetSetting($"{DEBUGGUI_SETTINGS_DIR}{nameof(enableGraphs)}", enableGraphs);
ProjectSettings.SetSetting($"{DEBUGGUI_SETTINGS_DIR}{nameof(enableLogs)}", enableLogs);
ProjectSettings.SetSetting($"{DEBUGGUI_SETTINGS_DIR}{nameof(backgroundColor)}", backgroundColor);
ProjectSettings.SetSetting($"{DEBUGGUI_SETTINGS_DIR}{nameof(scrubberColor)}", scrubberColor);
ProjectSettings.SetSetting($"{DEBUGGUI_SETTINGS_DIR}{nameof(graphWidth)}", graphWidth);
ProjectSettings.SetSetting($"{DEBUGGUI_SETTINGS_DIR}{nameof(graphHeight)}", graphHeight);
ProjectSettings.SetSetting($"{DEBUGGUI_SETTINGS_DIR}{nameof(temporaryLogLifetime)}", temporaryLogLifetime);
ProjectSettings.SetAsBasic($"{DEBUGGUI_SETTINGS_DIR}{nameof(enableGraphs)}", true);
ProjectSettings.SetAsBasic($"{DEBUGGUI_SETTINGS_DIR}{nameof(enableLogs)}", true);
ProjectSettings.SetAsBasic($"{DEBUGGUI_SETTINGS_DIR}{nameof(backgroundColor)}", true);
ProjectSettings.SetAsBasic($"{DEBUGGUI_SETTINGS_DIR}{nameof(scrubberColor)}", true);
ProjectSettings.SetAsBasic($"{DEBUGGUI_SETTINGS_DIR}{nameof(graphWidth)}", true);
ProjectSettings.SetAsBasic($"{DEBUGGUI_SETTINGS_DIR}{nameof(graphHeight)}", true);
ProjectSettings.SetAsBasic($"{DEBUGGUI_SETTINGS_DIR}{nameof(temporaryLogLifetime)}", true);
var err = ProjectSettings.Save();
if(err != Error.Ok)
{
GD.PrintErr(err);
}
}
public static void Load()
{
textFont = ThemeDB.FallbackFont;
enableGraphs = ProjectSettings.GetSetting(
$"{DEBUGGUI_SETTINGS_DIR}{nameof(enableGraphs)}",
true
).AsBool();
enableLogs = ProjectSettings.GetSetting(
$"{DEBUGGUI_SETTINGS_DIR}{nameof(enableLogs)}",
true
).AsBool();
backgroundColor = ProjectSettings.GetSetting(
$"{DEBUGGUI_SETTINGS_DIR}{nameof(backgroundColor)}",
new Color(0f, 0f, 0f, 0.7f)
).AsColor();
scrubberColor = ProjectSettings.GetSetting(
$"{DEBUGGUI_SETTINGS_DIR}{nameof(scrubberColor)}",
new Color(1f, 1f, 0f, 0.7f)
).AsColor();
graphWidth = ProjectSettings.GetSetting(
$"{DEBUGGUI_SETTINGS_DIR}{nameof(graphWidth)}",
300
).AsInt32();
graphHeight = ProjectSettings.GetSetting(
$"{DEBUGGUI_SETTINGS_DIR}{nameof(graphHeight)}",
100
).AsInt32();
temporaryLogLifetime = ProjectSettings.GetSetting(
$"{DEBUGGUI_SETTINGS_DIR}{nameof(temporaryLogLifetime)}",
5
).AsDouble();
}
public static bool enableGraphs;
public static bool enableLogs;
public static Color backgroundColor;
public static Color scrubberColor;
public static int graphWidth;
public static int graphHeight;
public static double temporaryLogLifetime;
public static Font textFont;
}
#endregion
#region Graph
///
/// Set the properties of a graph.
///
/// The graph's key
/// The graph's label
/// Value at the bottom of the graph box
/// Value at the top of the graph box
/// The graph's ordinal position on screen
/// The graph's color
public static void SetGraphProperties(object key, string label, float min, float max, int group, Color color, bool autoScale)
{
if (Settings.enableGraphs)
Instance?.graphWindow.SetGraphProperties(key, label, min, max, group, color, autoScale);
}
///
/// Set the properties of a graph.
///
/// The graph's key
/// The graph's label
/// Value at the bottom of the graph box
/// Value at the top of the graph box
/// The graph's ordinal position on screen
/// The graph's color
public static void SetGraphProperties(GodotObject key, string label, float min, float max, int group, Color color, bool autoScale)
{
SetGraphProperties((object)key, label, min, max, group, color, autoScale);
}
///
/// Add a data point to a graph.
///
/// The graph's key
/// Value to be added
public static void Graph(object key, float val)
{
if (Settings.enableGraphs)
Instance?.graphWindow.Graph(key, val);
}
///
/// Add a data point to a graph.
///
/// The graph's key
/// Value to be added
public static void Graph(GodotObject key, float val)
{
Graph((object)key, val);
}
///
/// Remove an existing graph.
///
/// The graph's key
public static void RemoveGraph(object key)
{
if (Settings.enableGraphs)
Instance?.graphWindow.RemoveGraph(key);
}
///
/// Remove an existing graph.
///
/// The graph's key
public static void RemoveGraph(GodotObject key)
{
RemoveGraph((object)key);
}
///
/// Resets a graph's data.
///
/// The graph's key
public static void ClearGraph(object key)
{
if (Settings.enableGraphs)
Instance?.graphWindow.ClearGraph(key);
}
///
/// Resets a graph's data.
///
/// The graph's key
public static void ClearGraph(GodotObject key)
{
ClearGraph((object)key);
}
///
/// Export graphs to a json file. See path in log.
///
public static void ExportGraphs()
{
if (Instance == null || !Settings.enableGraphs)
return;
string dateTimeStr = Time.GetDatetimeStringFromSystem().Replace(':', '-');
string filename = $"debuggui_graph_export_{dateTimeStr}.json";
using var file = Godot.FileAccess.Open(
"user://" + filename,
Godot.FileAccess.ModeFlags.Write
);
if (file == null)
{
GD.Print("DebugGUI graph export failed: " + Godot.FileAccess.GetOpenError());
}
else
{
file.StoreString(Instance.graphWindow.ToJson());
GD.Print($"Wrote graph data to {Path.Combine(OS.GetUserDataDir(), filename)}");
}
}
#endregion
#region Log
///
/// Create or update an existing message with the same key.
///
public static void LogPersistent(object key, string message)
{
if (Settings.enableLogs)
Instance?.logWindow.LogPersistent(key, message);
}
///
/// Create or update an existing message with the same key.
///
public static void LogPersistent(GodotObject key, string message)
{
LogPersistent((object)key, message);
}
///
/// Remove an existing persistent message.
///
public static void RemovePersistent(object key)
{
if (Settings.enableLogs)
Instance?.logWindow.RemovePersistent(key);
}
///
/// Remove an existing persistent message.
///
public static void RemovePersistent(GodotObject key)
{
RemovePersistent((object)key);
}
///
/// Clears all persistent logs.
///
public static void ClearPersistent()
{
if (Settings.enableLogs)
Instance?.logWindow.ClearPersistent();
}
///
/// Print a temporary message.
///
public static void Log(object message)
{
Log(message.ToString());
}
///
/// Print a temporary message.
///
public static void Log(string message)
{
if (Settings.enableLogs)
Instance?.logWindow.Log(message);
}
#endregion
///
/// Re-scans for DebugGUI attribute holders (i.e. [DebugGUIGraph] and [DebugGUIPrint])
///
public static void ForceReinitializeAttributes()
{
if (Instance == null) return;
Instance.graphWindow.ReinitializeAttributes();
Instance.logWindow.ReinitializeAttributes();
}
GraphWindow graphWindow;
LogWindow logWindow;
public override void _Ready()
{
Instance = this;
Settings.Load();
if (Settings.enableGraphs)
{
AddChild(graphWindow = new());
}
if (Settings.enableGraphs)
{
AddChild(logWindow = new());
}
}
}