From b60e03089e6cb67b12c061f8b909865fe7c97971 Mon Sep 17 00:00:00 2001 From: Peter Andreasen Date: Wed, 30 Jul 2025 10:39:42 +0200 Subject: [PATCH] take 3 of ai added cvars --- Assets/Game/ConfigVar.cs | 134 ++++++++++++++++++++++++++++++++++ Assets/Game/ConfigVar.cs.meta | 2 + Assets/Game/Game.cs | 1 + Assets/Game/Stats.cs | 38 +++++++++- README.md | 42 +++++++++++ 5 files changed, 216 insertions(+), 1 deletion(-) create mode 100644 Assets/Game/ConfigVar.cs create mode 100644 Assets/Game/ConfigVar.cs.meta diff --git a/Assets/Game/ConfigVar.cs b/Assets/Game/ConfigVar.cs new file mode 100644 index 0000000..ce811db --- /dev/null +++ b/Assets/Game/ConfigVar.cs @@ -0,0 +1,134 @@ +using System; +using UnityEngine; + +public static class ConfigVar +{ + // Static arrays for O(1) access - no dictionary lookups in hot loops + private static string[] m_Names = new string[128]; + private static float[] m_FloatValues = new float[128]; + private static int[] m_IntValues = new int[128]; + private static bool[] m_BoolValues = new bool[128]; + private static ConfigVarType[] m_Types = new ConfigVarType[128]; + private static int m_Count = 0; + + public enum ConfigVarType { Float, Int, Bool } + + // Fast access methods for hot loops + public static float GetFloat(int id) => m_FloatValues[id]; + public static int GetInt(int id) => m_IntValues[id]; + public static bool GetBool(int id) => m_BoolValues[id]; + + // Registration methods + public static int RegisterFloat(string name, float defaultValue, string description = "") + { + int id = m_Count++; + m_Names[id] = name; + m_FloatValues[id] = defaultValue; + m_Types[id] = ConfigVarType.Float; + + // Add console command for setting + Game.console.AddCommand(name, (args) => CmdSetFloat(id, args), description); + return id; + } + + public static int RegisterInt(string name, int defaultValue, string description = "") + { + int id = m_Count++; + m_Names[id] = name; + m_IntValues[id] = defaultValue; + m_Types[id] = ConfigVarType.Int; + + Game.console.AddCommand(name, (args) => CmdSetInt(id, args), description); + return id; + } + + public static int RegisterBool(string name, bool defaultValue, string description = "") + { + int id = m_Count++; + m_Names[id] = name; + m_BoolValues[id] = defaultValue; + m_Types[id] = ConfigVarType.Bool; + + Game.console.AddCommand(name, (args) => CmdSetBool(id, args), description); + return id; + } + + // Console command handlers using existing StringFormatter + private static void CmdSetFloat(int id, string[] args) + { + if (args.Length < 1) + { + Game.console.Write("{0} = {1}\n", m_Names[id], m_FloatValues[id]); + return; + } + + if (float.TryParse(args[0], out float value)) + { + m_FloatValues[id] = value; + Game.console.Write("{0} = {1}\n", m_Names[id], value); + } + else + { + Game.console.Write("Invalid value for {0}\n", m_Names[id]); + } + } + + private static void CmdSetInt(int id, string[] args) + { + if (args.Length < 1) + { + Game.console.Write("{0} = {1}\n", m_Names[id], m_IntValues[id]); + return; + } + + if (int.TryParse(args[0], out int value)) + { + m_IntValues[id] = value; + Game.console.Write("{0} = {1}\n", m_Names[id], value); + } + else + { + Game.console.Write("Invalid value for {0}\n", m_Names[id]); + } + } + + private static void CmdSetBool(int id, string[] args) + { + if (args.Length < 1) + { + Game.console.Write("{0} = {1}\n", m_Names[id], m_BoolValues[id] ? "true" : "false"); + return; + } + + if (bool.TryParse(args[0], out bool value)) + { + m_BoolValues[id] = value; + Game.console.Write("{0} = {1}\n", m_Names[id], value ? "true" : "false"); + } + else + { + Game.console.Write("Invalid value for {0}\n", m_Names[id]); + } + } + + // List all config vars + public static void CmdList(string[] args) + { + Game.console.Write("Config Variables:\n"); + for (int i = 0; i < m_Count; i++) + { + switch (m_Types[i]) + { + case ConfigVarType.Float: + Game.console.Write(" {0} = {1}\n", m_Names[i], m_FloatValues[i]); + break; + case ConfigVarType.Int: + Game.console.Write(" {0} = {1}\n", m_Names[i], m_IntValues[i]); + break; + case ConfigVarType.Bool: + Game.console.Write(" {0} = {1}\n", m_Names[i], m_BoolValues[i] ? "true" : "false"); + break; + } + } + } +} \ No newline at end of file diff --git a/Assets/Game/ConfigVar.cs.meta b/Assets/Game/ConfigVar.cs.meta new file mode 100644 index 0000000..223b7ae --- /dev/null +++ b/Assets/Game/ConfigVar.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 34fc7cefac61bb446aac205087448b70 \ No newline at end of file diff --git a/Assets/Game/Game.cs b/Assets/Game/Game.cs index 1ba3bdc..2d483b5 100644 --- a/Assets/Game/Game.cs +++ b/Assets/Game/Game.cs @@ -41,6 +41,7 @@ public void Init() m_Console.Init(); m_Console.AddCommand("quit", CmdQuit, "Quit game"); + m_Console.AddCommand("cvarlist", ConfigVar.CmdList, "List all config variables"); m_Stats = new Stats(); m_Stats.Init(); diff --git a/Assets/Game/Stats.cs b/Assets/Game/Stats.cs index c43c503..4771c7e 100644 --- a/Assets/Game/Stats.cs +++ b/Assets/Game/Stats.cs @@ -14,6 +14,12 @@ public class Stats : IGameSystem int m_ShowStats = 1; + // Config variable IDs for fast access + private static int s_FovId; + private static int s_MouseSensitivityId; + private static int s_ShowDebugInfoId; + private static int s_GraphScaleId; + public void Init() { m_StopWatch = new System.Diagnostics.Stopwatch(); @@ -22,6 +28,13 @@ public void Init() m_LastFrameTicks = m_StopWatch.ElapsedTicks; Debug.Assert(System.Diagnostics.Stopwatch.IsHighResolution); Game.console.AddCommand("showstats", CmdShowstats, "Show or hide stats"); + Game.console.AddCommand("demo", CmdDemo, "Demo config variable usage"); + + // Register config variables + s_FovId = ConfigVar.RegisterFloat("fov", 70.0f, "Field of view"); + s_MouseSensitivityId = ConfigVar.RegisterFloat("mousesens", 1.0f, "Mouse sensitivity"); + s_ShowDebugInfoId = ConfigVar.RegisterBool("showdebug", true, "Show debug information"); + s_GraphScaleId = ConfigVar.RegisterFloat("graphscale", 1.5f, "Graph scale factor"); } private void CmdShowstats(string[] args) @@ -29,6 +42,17 @@ private void CmdShowstats(string[] args) m_ShowStats = (m_ShowStats + 1) % 3; } + private void CmdDemo(string[] args) + { + Game.console.Write("Config Variable Demo:\n"); + Game.console.Write("Try these commands:\n"); + Game.console.Write(" fov = 90\n"); + Game.console.Write(" mousesens = 2.5\n"); + Game.console.Write(" showdebug = false\n"); + Game.console.Write(" graphscale = 2.0\n"); + Game.console.Write(" cvarlist\n"); + } + void CalcStatistics(float[] data, out float mean, out float variance, out float minValue, out float maxValue) { float sum = 0, sum2 = 0; @@ -63,14 +87,26 @@ public void TickUpdate() float frameDurationMs = (ticks - m_LastFrameTicks) * 1000 / (float)m_StopWatchFreq; m_LastFrameTicks = ticks; + // Fast access to config variables - no allocations or lookups + float fov = ConfigVar.GetFloat(s_FovId); + float mouseSens = ConfigVar.GetFloat(s_MouseSensitivityId); + bool showDebug = ConfigVar.GetBool(s_ShowDebugInfoId); + float graphScale = ConfigVar.GetFloat(s_GraphScaleId); + DebugOverlay.SetColor(Color.yellow); DebugOverlay.SetOrigin(0, 0); DebugOverlay.Write(1, 0, "FPS:{0,6:###.##}", 1.0f / Time.deltaTime); fpsHistory[Time.frameCount % fpsHistory.Length] = 1.0f / Time.deltaTime; - DebugOverlay.DrawGraph(1, 1, 9, 1.5f, fpsHistory, Time.frameCount % fpsHistory.Length, Color.green); + DebugOverlay.DrawGraph(1, 1, 9, graphScale, fpsHistory, Time.frameCount % fpsHistory.Length, Color.green); DebugOverlay.Write(30, 0, "Open console (F12) and type: \"showstats\" to toggle graphs"); + + // Show config variables if debug is enabled + if (showDebug) + { + DebugOverlay.Write(1, 3, "FOV: {0}, MouseSens: {1}", fov, mouseSens); + } if (m_ShowStats < 2) return; diff --git a/README.md b/README.md index 53ac91c..08daa25 100644 --- a/README.md +++ b/README.md @@ -49,4 +49,46 @@ and it will work like this: ![Pretty picture](https://user-images.githubusercontent.com/4175246/28582984-d215e5f2-7167-11e7-99ff-e96b2981b9bb.gif) +## Config Variables + +The project includes a high-performance config variable system inspired by Quake and Source engines. Config variables can be set from the console and provide O(1) access for use in hot loops. + +### Usage + +```c# +// Register config variables (typically in Init()) +int fovId = ConfigVar.RegisterFloat("fov", 70.0f, "Field of view"); +int mouseSensId = ConfigVar.RegisterFloat("mousesens", 1.0f, "Mouse sensitivity"); +int showDebugId = ConfigVar.RegisterBool("showdebug", true, "Show debug information"); + +// Fast access in hot loops +float fov = ConfigVar.GetFloat(fovId); +float mouseSens = ConfigVar.GetFloat(mouseSensId); +bool showDebug = ConfigVar.GetBool(showDebugId); +``` + +### Console Commands + +``` +> fov = 90 +fov = 90 +> mousesens = 2.5 +mousesens = 2.5 +> showdebug = false +showdebug = False +> cvarlist +Config Variables: + fov = 90 + mousesens = 2.5 + showdebug = False +> demo +Config Variable Demo: +Try these commands: + fov = 90 + mousesens = 2.5 + showdebug = false + graphscale = 2.0 + cvarlist +``` +