cvar overhaul

This commit is contained in:
2025-03-20 23:29:47 +02:00
parent b5c79a8088
commit d68c1c26ff
6 changed files with 117 additions and 75 deletions

3
.gitignore vendored
View File

@@ -30,4 +30,5 @@ Assets/desktop.ini
Assets/Maps/autosave/ Assets/Maps/autosave/
Demos/ Demos/
console.log console.log
console-1.log console-1.log
Content/devconfig.cfg

View File

@@ -13,7 +13,7 @@ public class CameraMovement : Script
public float MoveSpeed { get; set; } = 400; public float MoveSpeed { get; set; } = 400;
[ConsoleVariable("sensitivity")] [ConsoleVariable("sensitivity")]
public static float Sensitivity; private static float _sensitivity { get; set; } = 1.0f;
public override void OnStart() public override void OnStart()
{ {
@@ -29,8 +29,8 @@ public class CameraMovement : Script
Actor rootActor = Actor.GetChild(0); Actor rootActor = Actor.GetChild(0);
Camera camera = rootActor.GetChild<Camera>(); Camera camera = rootActor.GetChild<Camera>();
float xAxis = Input.GetAxisRaw("Mouse X") * Sensitivity; float xAxis = Input.GetAxisRaw("Mouse X") * _sensitivity;
float yAxis = Input.GetAxisRaw("Mouse Y") * Sensitivity; float yAxis = Input.GetAxisRaw("Mouse Y") * _sensitivity;
if (xAxis != 0.0f || yAxis != 0.0f) if (xAxis != 0.0f || yAxis != 0.0f)
{ {
viewPitch += yAxis; viewPitch += yAxis;

View File

@@ -148,7 +148,7 @@ public class ConsoleInstance : IDisposable
private readonly List<string> consoleBufferHistory = new(); private readonly List<string> consoleBufferHistory = new();
private readonly Dictionary<string, ConsoleCommand> consoleCommands = new(); private readonly Dictionary<string, ConsoleCommand> consoleCommands = new();
private readonly List<ConsoleLine> consoleLines = new(); private readonly List<ConsoleLine> consoleLines = new();
private readonly Dictionary<string, ConsoleVariable> consoleVariables = new(); private readonly Dictionary<string, (ConsoleVariable cvar, bool alias)> consoleVariables = new();
private readonly Stopwatch closeThrottleStopwatch = Stopwatch.StartNew(); private readonly Stopwatch closeThrottleStopwatch = Stopwatch.StartNew();
private StreamWriter logStream; private StreamWriter logStream;
@@ -294,7 +294,7 @@ public class ConsoleInstance : IDisposable
consoleCommands.Add(kv.Key, cmd); consoleCommands.Add(kv.Key, cmd);
} }
foreach (FieldInfo field in type.GetFields()) foreach (FieldInfo field in type.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))
{ {
if (!field.IsStatic) if (!field.IsStatic)
continue; continue;
@@ -306,36 +306,42 @@ public class ConsoleInstance : IDisposable
if (attr is ConsoleVariableAttribute cvarAttribute) if (attr is ConsoleVariableAttribute cvarAttribute)
{ {
//Console.Print("found cvar '" + cvarAttribute.name + "' bound to field '" + field.Name + "'"); //Console.Print("found cvar '" + cvarAttribute.name + "' bound to field '" + field.Name + "'");
consoleVariables.Add(cvarAttribute.name, if (!consoleVariables.TryGetValue(cvarAttribute.name, out var entry))
new ConsoleVariable(cvarAttribute.name, cvarAttribute.flags, field)); {
entry.cvar = new ConsoleVariable(cvarAttribute.name);
consoleVariables.Add(cvarAttribute.name, entry);
}
entry.cvar.AddField(field);
foreach (string alias in cvarAttribute.aliases) foreach (string alias in cvarAttribute.aliases)
consoleVariables.Add(alias, consoleVariables.Add(alias, (entry.cvar, true));
new ConsoleVariable(cvarAttribute.name,
cvarAttribute.flags | ConsoleFlags.NoSerialize, field));
} }
} }
} }
foreach (PropertyInfo prop in type.GetProperties()) foreach (PropertyInfo property in type.GetProperties(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))
{ {
MethodInfo getter = prop.GetGetMethod(); var attributes = Attribute.GetCustomAttributes(property);
MethodInfo setter = prop.GetSetMethod();
if (getter == null || setter == null || !getter.IsStatic || !setter.IsStatic)
continue;
var attributes = Attribute.GetCustomAttributes(prop);
foreach (Attribute attr in attributes) foreach (Attribute attr in attributes)
{ {
if (attr is ConsoleVariableAttribute cvarAttribute) if (attr is ConsoleVariableAttribute cvarAttribute)
{ {
MethodInfo getter = property.GetGetMethod() ?? property.GetMethod;
MethodInfo setter = property.GetSetMethod() ?? property.SetMethod;
if (getter == null || setter == null || !getter.IsStatic || !setter.IsStatic)
continue;
//Console.Print("found cvar '" + cvarAttribute.name + "' bound to field '" + field.Name + "'"); //Console.Print("found cvar '" + cvarAttribute.name + "' bound to field '" + field.Name + "'");
consoleVariables.Add(cvarAttribute.name, if (!consoleVariables.TryGetValue(cvarAttribute.name, out var entry))
new ConsoleVariable(cvarAttribute.name, cvarAttribute.flags, getter, setter)); {
entry.cvar = new ConsoleVariable(cvarAttribute.name);
consoleVariables.Add(cvarAttribute.name, entry);
}
entry.cvar.AddProperty(property);
foreach (string alias in cvarAttribute.aliases) foreach (string alias in cvarAttribute.aliases)
consoleVariables.Add(alias, consoleVariables.Add(alias, (entry.cvar, true));
new ConsoleVariable(cvarAttribute.name,
cvarAttribute.flags | ConsoleFlags.NoSerialize, getter, setter));
} }
} }
} }
@@ -479,13 +485,13 @@ public class ConsoleInstance : IDisposable
cmd.Invoke(); cmd.Invoke();
//Console.Print("Command bound to '" + execute + "' is '" + cmd.method.Name + "'"); //Console.Print("Command bound to '" + execute + "' is '" + cmd.method.Name + "'");
} }
else if (consoleVariables.TryGetValue(executeLower, out ConsoleVariable cvar)) else if (consoleVariables.TryGetValue(executeLower, out var entry))
{ {
if (value != null) if (value != null)
cvar.SetValue(value); entry.cvar.SetValue(value);
if (!noOutput) if (!noOutput)
Console.Print("'" + execute + "' is '" + cvar.GetValueString() + "'"); Console.Print("'" + execute + "' is '" + entry.cvar.GetValueString() + "'");
} }
else else
{ {
@@ -503,9 +509,9 @@ public class ConsoleInstance : IDisposable
public string GetVariable(string variableName) public string GetVariable(string variableName)
{ {
if (consoleVariables.TryGetValue(variableName, out ConsoleVariable cvar)) if (consoleVariables.TryGetValue(variableName, out var entry))
{ {
string value = cvar.GetValueString(); string value = entry.cvar.GetValueString();
return value; return value;
} }

View File

@@ -38,7 +38,7 @@ public class ConsoleVariableAttribute : ConsoleBaseAttribute
public class ConsoleCommandAttribute : ConsoleBaseAttribute public class ConsoleCommandAttribute : ConsoleBaseAttribute
{ {
/// <summary> /// <summary>
/// Registers a command to Console system. /// Registers a command to Console system.
/// </summary> /// </summary>
/// <param name="name">Name used for calling this command.</param> /// <param name="name">Name used for calling this command.</param>
public ConsoleCommandAttribute(string name) : base(name) public ConsoleCommandAttribute(string name) : base(name)
@@ -46,11 +46,11 @@ public class ConsoleCommandAttribute : ConsoleBaseAttribute
} }
/// <summary> /// <summary>
/// Registers a command to Console system. /// Registers a command to Console system.
/// </summary> /// </summary>
/// <param name="names"> /// <param name="names">
/// Names used for calling this command. First name is the main name for this command, rest of the /// Names used for calling this command. First name is the main name for this command,
/// names are aliases. /// rest of the names are aliases.
/// </param> /// </param>
public ConsoleCommandAttribute(params string[] names) : base(names) public ConsoleCommandAttribute(params string[] names) : base(names)
{ {
@@ -58,7 +58,7 @@ public class ConsoleCommandAttribute : ConsoleBaseAttribute
} }
/// <summary> /// <summary>
/// Constructor for the subsystem, must be called first before registering console commands. /// Constructor for the subsystem, must be called first before registering console commands.
/// </summary> /// </summary>
[AttributeUsage(AttributeTargets.All)] [AttributeUsage(AttributeTargets.All)]
public class ConsoleSubsystemInitializer : Attribute public class ConsoleSubsystemInitializer : Attribute

View File

@@ -1,88 +1,123 @@
using System; using System;
using System.Collections.Generic;
using System.Reflection; using System.Reflection;
using FlaxEngine;
using FlaxEngine.Assertions;
namespace Game; namespace Game;
[Flags] [Flags]
public enum ConsoleFlags public enum ConsoleFlags
{ {
NoSerialize = 1, // Value does not persist /// <summary>
/// Value does not persist.
Alias = NoSerialize /// </summary>
NoSerialize = 1,
} }
internal struct ConsoleVariable internal class ConsoleVariable
{ {
public string name { get; } public string Name { get; }
public ConsoleFlags flags { get; }
private readonly FieldInfo field; private readonly List<FieldInfo> _fields;
private readonly MethodInfo getter; private readonly List<MethodInfo> _getters;
private readonly MethodInfo setter; private readonly List<MethodInfo> _setters;
public ConsoleVariable(string name, ConsoleFlags flags, FieldInfo field) public ConsoleVariable(string name)
{ {
this.name = name; Name = name;
this.flags = flags; _fields = new List<FieldInfo>();
this.field = field; _getters = new List<MethodInfo>();
getter = null; _setters = new List<MethodInfo>();
setter = null;
} }
public ConsoleVariable(string name, ConsoleFlags flags, MethodInfo getter, MethodInfo setter) public void AddField(FieldInfo field)
{ {
this.name = name; Assert.IsTrue(_getters.Count == 0);
this.flags = flags;
field = null; _fields.Add(field);
this.getter = getter; }
this.setter = setter;
public void AddProperty(PropertyInfo property)
{
var getter = property.GetGetMethod() ?? property.GetMethod;
var setter = property.GetSetMethod() ?? property.SetMethod;
Assert.IsNotNull(getter);
Assert.IsNotNull(setter);
if (getter != null)
_getters.Add(getter);
if (setter != null)
_setters.Add(setter);
//Assert.IsTrue(_getters.Count > 0);
//Assert.IsTrue(_setters.Count <= 1);
/*if (setter == null)
{
FieldInfo backingField = property.DeclaringType.GetField($"<{property.Name}>k__BackingField", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
if (backingField != null)
_fields.Add(backingField);
}*/
} }
public string GetValueString() public string GetValueString()
{ {
FieldInfo field = _fields.Count > 0 ? _fields[0] : null;
MethodInfo getter = _getters.Count > 0 ? _getters[0] : null;
Type type = field != null ? field.FieldType : getter.ReturnType; Type type = field != null ? field.FieldType : getter.ReturnType;
if (type == typeof(string)) if (type == typeof(string))
{ {
if (field != null) if (field != null)
return (string)field.GetValue(null); return (string)field.GetValue(null);
if (getter != null) if (getter != null)
return (string)getter.Invoke(null, null); return ((float)getter.Invoke(null, null)).ToString();
} }
else if (type == typeof(float)) else if (type == typeof(float))
{ {
if (field != null) if (field != null)
return field.GetValue(null).ToString(); return field.GetValue(null).ToString();
if (getter != null) if (getter != null)
return (string)getter.Invoke(null, null); return ((float)getter.Invoke(null, null)).ToString();
} }
else else
throw new Exception($"Unsupported console variable type '{type.FullName}'"); throw new Exception($"ConsoleVariable: Unsupported variable type '{type.FullName}'");
throw new Exception("GetValueString no field or getter specified"); throw new Exception("ConsoleVariable: GetValueString no field or getter found");
} }
public void SetValue(string value) public void SetValue(string value)
{ {
Type type = field != null ? field.FieldType : getter.ReturnType; foreach (var field in _fields)
if (type == typeof(string))
{ {
if (field != null) Type type = field.FieldType;
if (type == typeof(string))
field.SetValue(null, value); field.SetValue(null, value);
else if (setter != null) else if (type == typeof(float))
setter.Invoke(null, new object[] { value }); {
} if (!float.TryParse(value, out var floatValue))
else if (type == typeof(float)) return;
{
if (!float.TryParse(value, out var floatValue))
return;
if (field != null)
field.SetValue(null, floatValue); field.SetValue(null, floatValue);
else if (setter != null) }
setter.Invoke(null, new object[] { floatValue }); else
throw new Exception($"ConsoleVariable: Unsupported type for SetValue: '{type.FullName}'");
} }
else
foreach (var setter in _setters)
{ {
throw new Exception("Unsupported type for SetValue: " + type.Name); Type type = setter.GetParameterTypes()[0];
if (type == typeof(string))
setter.Invoke(null, new object[] { value });
else if (type == typeof(float))
{
if (!float.TryParse(value, out var floatValue))
return;
setter.Invoke(null, new object[] { floatValue });
}
else
throw new Exception($"ConsoleVariable: Unsupported type for SetValue: '{type.FullName}'");
} }
} }
} }

View File

@@ -51,7 +51,7 @@ public class PlayerInput2 : IPlayerInput
private PlayerInputState2 _recordState; private PlayerInputState2 _recordState;
[ConsoleVariable("sensitivity")] [ConsoleVariable("sensitivity")]
public static float Sensitivity; private static float _sensitivity { get; set; } = 1.0f;
public void SetFrame(ulong frame) public void SetFrame(ulong frame)
{ {
@@ -67,7 +67,7 @@ public class PlayerInput2 : IPlayerInput
//sensitivity = 1.0f; //sensitivity = 1.0f;
float turnSpeed = 100.0f; float turnSpeed = 100.0f;
_recordState.ViewDelta += new Float2(Input.GetAxisRaw("Mouse X"), Input.GetAxisRaw("Mouse Y")) * Sensitivity; _recordState.ViewDelta += new Float2(Input.GetAxisRaw("Mouse X"), Input.GetAxisRaw("Mouse Y")) * _sensitivity;
_recordState.ViewDelta += new Float2(Input.GetAxisRaw("LookRight"), Input.GetAxisRaw("LookUp")) * Time.DeltaTime * turnSpeed; _recordState.ViewDelta += new Float2(Input.GetAxisRaw("LookRight"), Input.GetAxisRaw("LookUp")) * Time.DeltaTime * turnSpeed;
_recordState.MoveForward = MathF.MaxMagnitude(_recordState.MoveForward, Input.GetAxis("Vertical")); _recordState.MoveForward = MathF.MaxMagnitude(_recordState.MoveForward, Input.GetAxis("Vertical"));