Skip to content

Commit d492f8e

Browse files
committed
Added user-defined developer console stats that are displayed on-screen.
Added multiple stats_ commands.
1 parent 0af4961 commit d492f8e

File tree

2 files changed

+233
-1
lines changed

2 files changed

+233
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

77
## [Unreleased]
8+
- Added user-defined developer console stats which are displayed on-screen (stats_ commands).
89
- Fixed exception not being caught when an issue occurs serialising or deserialising the preferences file.
910

1011
## [1.0.0] - 2021-08-22

Runtime/DevConsoleMono.cs

Lines changed: 232 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ internal sealed class DevConsoleMono : MonoBehaviour
5555
private const int CommandHistoryLength = 10;
5656
private const int MaxCachedEnumTypes = 6;
5757
private const float FpsUpdateRate = 4f;
58+
private const float StatUpdateRate = 0.1f;
5859

5960
#region Input constants
6061

@@ -103,6 +104,9 @@ internal sealed class DevConsoleMono : MonoBehaviour
103104
private const string PrefShowFps = "DevConsole.displayFps";
104105
private const string PrefLogTextSize = "DevConsole.logTextSize";
105106
private const string PrefIncludedUsings = "DevConsole.includedUsings";
107+
private const string PrefShowStats = "DevConsole.displayStats";
108+
private const string PrefStats = "DevConsole.stats";
109+
private const string PrefHiddenStats = "DevConsole.hiddenStats";
106110

107111
#endregion
108112

@@ -397,6 +401,17 @@ internal sealed class DevConsoleMono : MonoBehaviour
397401

398402
#endregion
399403

404+
#region Stat display fields
405+
406+
private bool _isDisplayingStats;
407+
private GUIStyle _statStyle;
408+
private Dictionary<string, string> _stats = new Dictionary<string, string>();
409+
private HashSet<string> _hiddenStats = new HashSet<string>();
410+
private Dictionary<string, string> _cachedStats = new Dictionary<string, string>();
411+
private float _statUpdateTime;
412+
413+
#endregion
414+
400415
#endregion
401416

402417
#region Properties
@@ -1389,6 +1404,85 @@ private void OnGUI()
13891404
GUI.backgroundColor = oldBackgroundColour;
13901405
GUI.contentColor = oldContentColour;
13911406
}
1407+
1408+
if (_isDisplayingStats && _stats.Any())
1409+
{
1410+
if (_statStyle == null)
1411+
{
1412+
// Create the style
1413+
_statStyle = new GUIStyle(GUI.skin.box)
1414+
{
1415+
alignment = TextAnchor.MiddleCenter,
1416+
fontSize = 18,
1417+
normal = { textColor = Color.white, background = Texture2D.whiteTexture }
1418+
};
1419+
}
1420+
1421+
// Initialise
1422+
Color oldBackgroundColour = GUI.backgroundColor;
1423+
Color oldContentColour = GUI.contentColor;
1424+
GUI.backgroundColor = new Color(0f, 0f, 0f, 0.75f);
1425+
const float padding = 5f;
1426+
int num = 0;
1427+
InitMonoEvaluator();
1428+
1429+
bool updateCache = Time.time > _statUpdateTime;
1430+
if (updateCache)
1431+
{
1432+
_statUpdateTime = Time.time + StatUpdateRate;
1433+
}
1434+
1435+
// Create a label for each stat
1436+
foreach (KeyValuePair<string, string> stat in _stats)
1437+
{
1438+
// Ignore if hidden
1439+
if (_hiddenStats.Contains(stat.Key))
1440+
{
1441+
continue;
1442+
}
1443+
1444+
// Determine stat result
1445+
string result;
1446+
if (!updateCache && _cachedStats.ContainsKey(stat.Key))
1447+
{
1448+
// Note: updates very often
1449+
result = _cachedStats[stat.Key];
1450+
}
1451+
else
1452+
{
1453+
// Note: updates once every now and then (according to StatUpdateRate)
1454+
try
1455+
{
1456+
result = _monoEvaluator?.Evaluate(stat.Value).ToString() ?? null;
1457+
}
1458+
catch (Exception)
1459+
{
1460+
result = "ERROR";
1461+
}
1462+
1463+
_cachedStats[stat.Key] = result;
1464+
}
1465+
1466+
// Set content
1467+
string content = $"{stat.Key}: {result}";
1468+
GUI.contentColor = result.Equals("ERROR") ? Color.red : Color.white;
1469+
1470+
// Determine label size
1471+
Vector2 size = _statStyle.CalcSize(new GUIContent(content));
1472+
1473+
// Create the label
1474+
GUI.Box(
1475+
new Rect(10, 50 + ((num * (size.y + 10f + padding)) + padding), size.x + 10f, size.y + 10f),
1476+
content,
1477+
_statStyle);
1478+
1479+
++num;
1480+
}
1481+
1482+
// Reset colours
1483+
GUI.backgroundColor = oldBackgroundColour;
1484+
GUI.contentColor = oldContentColour;
1485+
}
13921486
}
13931487

13941488
private void OnDestroy()
@@ -2406,6 +2500,137 @@ void logChildren(GameObject obj, int tabAmount)
24062500

24072501
#endregion
24082502

2503+
#region Stat display commands
2504+
2505+
AddCommand(Command.Create(
2506+
"stats_list",
2507+
"",
2508+
"Display a list of the stored developer console stats that can be displayed on-screen",
2509+
() =>
2510+
{
2511+
if (!_stats.Any())
2512+
{
2513+
DevConsole.Log($"There are no stored developer console stats. Use {GetCommand("stats_set").GetFormattedName()} to set one up.");
2514+
return;
2515+
}
2516+
2517+
LogCollection(_stats, x => $"{x.Key}: {x.Value}{(_hiddenStats.Contains(x.Key) ? " [Disabled]" : "")}");
2518+
}
2519+
));
2520+
2521+
AddCommand(Command.Create<bool?>(
2522+
"stats_display",
2523+
"",
2524+
"Set or query whether the developer console stats are being displayed on-screen",
2525+
Parameter.Create("display", ""),
2526+
b =>
2527+
{
2528+
if (!b.HasValue)
2529+
{
2530+
b = !_isDisplayingStats;
2531+
}
2532+
2533+
_isDisplayingStats = b.Value;
2534+
DevConsole.LogSuccess($"{(_isDisplayingStats ? "Enabled" : "Disabled")} the on-screen developer console stats display.");
2535+
},
2536+
() => DevConsole.LogVariable("Display on-screen developer console stats", _isDisplayingStats)
2537+
));
2538+
2539+
AddCommand(Command.Create<string, string>(
2540+
"stats_set",
2541+
"",
2542+
"Set a stat on the developer console which can be displayed on-screen",
2543+
Parameter.Create("name", "Name of the stat"),
2544+
Parameter.Create("expression", "The C# expression to evaluate"),
2545+
(name, expression) =>
2546+
{
2547+
if (name == null || expression == null)
2548+
{
2549+
DevConsole.LogError("Parameters cannot be null.");
2550+
return;
2551+
}
2552+
2553+
if (!expression.EndsWith(";"))
2554+
{
2555+
expression += ";";
2556+
}
2557+
2558+
_stats[name] = expression;
2559+
DevConsole.LogSuccess($"Successfully set {name} as a developer console stat.");
2560+
}
2561+
));
2562+
2563+
AddCommand(Command.Create<string>(
2564+
"stats_evaluate",
2565+
"stats_eval",
2566+
"Evaluate one of the developer console stats",
2567+
Parameter.Create("name", "Name of the stat"),
2568+
name =>
2569+
{
2570+
if (!_stats.ContainsKey(name))
2571+
{
2572+
DevConsole.LogError($"Could not find {name}. Use {GetCommand("stats_display").GetFormattedName()} to display a list of all developer console stats.");
2573+
return;
2574+
}
2575+
2576+
RunCommand($"cs_evaluate {_stats[name]}");
2577+
}
2578+
));
2579+
2580+
AddCommand(Command.Create<string>(
2581+
"stats_remove",
2582+
"",
2583+
"Remove a stat from the developer console",
2584+
Parameter.Create("name", "Name of the stat"),
2585+
name =>
2586+
{
2587+
if (!_stats.Remove(name))
2588+
{
2589+
DevConsole.LogError($"Could not remove {name}. Use {GetCommand("stats_display").GetFormattedName()} to display a list of all developer console stats.");
2590+
return;
2591+
}
2592+
2593+
_hiddenStats.Remove(name);
2594+
_cachedStats.Remove(name);
2595+
DevConsole.LogSuccess($"Successfully removed {name} from the developer console stats.");
2596+
}
2597+
));
2598+
2599+
AddCommand(Command.Create<string, bool?>(
2600+
"stats_toggle",
2601+
"",
2602+
"Set whether a particular developer console stat should be displayed or not",
2603+
Parameter.Create("name", "Name of the stat"),
2604+
Parameter.Create("display", ""),
2605+
(name, b) =>
2606+
{
2607+
if (!_stats.ContainsKey(name))
2608+
{
2609+
DevConsole.LogError($"Could not find {name}. Use {GetCommand("stats_display").GetFormattedName()} to display a list of all developer console stats.");
2610+
return;
2611+
}
2612+
2613+
// Flip
2614+
if (!b.HasValue)
2615+
{
2616+
b = _hiddenStats.Contains(name);
2617+
}
2618+
2619+
if (b.Value)
2620+
{
2621+
_hiddenStats.Remove(name);
2622+
}
2623+
else
2624+
{
2625+
_hiddenStats.Add(name);
2626+
}
2627+
2628+
DevConsole.LogSuccess($"{(b.Value ? "Enabled" : "Disabled")} the on-screen developer console stats display for {name}.");
2629+
}
2630+
));
2631+
2632+
#endregion
2633+
24092634
#region Misc commands
24102635

24112636
AddCommand(Command.Create(
@@ -2620,7 +2845,7 @@ private void InitAttributeCommands()
26202845
catch (System.IO.FileNotFoundException) { }
26212846
catch (Exception e)
26222847
{
2623-
Debug.LogError("Error whilst searching for debug console command attributes in assembly(" + assemblyName + "): " + e.Message + ".");
2848+
Debug.LogError("Error whilst searching for developer console attributes in assembly(" + assemblyName + "): " + e.Message + ".");
26242849
}
26252850
}
26262851
}
@@ -3165,6 +3390,9 @@ private void SavePreferences()
31653390
DevConsoleData.SetObject(PrefShowFps, _isDisplayingFps);
31663391
DevConsoleData.SetObject(PrefLogTextSize, LogTextSize);
31673392
DevConsoleData.SetObject(PrefIncludedUsings, _includedUsings);
3393+
DevConsoleData.SetObject(PrefShowStats, _isDisplayingStats);
3394+
DevConsoleData.SetObject(PrefStats, _stats);
3395+
DevConsoleData.SetObject(PrefHiddenStats, _hiddenStats);
31683396

31693397
DevConsoleData.Save();
31703398
}
@@ -3188,6 +3416,9 @@ private void LoadPreferences()
31883416
{
31893417
"System", "System.Linq", "UnityEngine", "UnityEngine.SceneManagement", "UnityEngine.UI"
31903418
});
3419+
_isDisplayingStats = DevConsoleData.GetObject(PrefShowStats, true);
3420+
_stats = DevConsoleData.GetObject(PrefStats, new Dictionary<string, string>());
3421+
_hiddenStats = DevConsoleData.GetObject(PrefHiddenStats, new HashSet<string>());
31913422

31923423
DevConsoleData.Clear();
31933424
}

0 commit comments

Comments
 (0)