diff --git a/.gitignore b/.gitignore index 5f011da..d87be09 100644 --- a/.gitignore +++ b/.gitignore @@ -30,4 +30,5 @@ Assets/desktop.ini Assets/Maps/autosave/ Demos/ console.log -console-1.log \ No newline at end of file +console-1.log +Content/devconfig.cfg diff --git a/Source/Game/Camera/CameraMovement.cs b/Source/Game/Camera/CameraMovement.cs index a5d6c37..1a6a28b 100644 --- a/Source/Game/Camera/CameraMovement.cs +++ b/Source/Game/Camera/CameraMovement.cs @@ -13,7 +13,7 @@ public class CameraMovement : Script public float MoveSpeed { get; set; } = 400; [ConsoleVariable("sensitivity")] - public static float Sensitivity; + private static float _sensitivity { get; set; } = 1.0f; public override void OnStart() { @@ -29,8 +29,8 @@ public class CameraMovement : Script Actor rootActor = Actor.GetChild(0); Camera camera = rootActor.GetChild(); - float xAxis = Input.GetAxisRaw("Mouse X") * Sensitivity; - float yAxis = Input.GetAxisRaw("Mouse Y") * Sensitivity; + float xAxis = Input.GetAxisRaw("Mouse X") * _sensitivity; + float yAxis = Input.GetAxisRaw("Mouse Y") * _sensitivity; if (xAxis != 0.0f || yAxis != 0.0f) { viewPitch += yAxis; diff --git a/Source/Game/Console/Console.cs b/Source/Game/Console/Console.cs index cc7a346..ecc09d2 100644 --- a/Source/Game/Console/Console.cs +++ b/Source/Game/Console/Console.cs @@ -148,7 +148,7 @@ public class ConsoleInstance : IDisposable private readonly List consoleBufferHistory = new(); private readonly Dictionary consoleCommands = new(); private readonly List consoleLines = new(); - private readonly Dictionary consoleVariables = new(); + private readonly Dictionary consoleVariables = new(); private readonly Stopwatch closeThrottleStopwatch = Stopwatch.StartNew(); private StreamWriter logStream; @@ -294,7 +294,7 @@ public class ConsoleInstance : IDisposable 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) continue; @@ -306,36 +306,42 @@ public class ConsoleInstance : IDisposable if (attr is ConsoleVariableAttribute cvarAttribute) { //Console.Print("found cvar '" + cvarAttribute.name + "' bound to field '" + field.Name + "'"); - consoleVariables.Add(cvarAttribute.name, - new ConsoleVariable(cvarAttribute.name, cvarAttribute.flags, field)); + if (!consoleVariables.TryGetValue(cvarAttribute.name, out var entry)) + { + entry.cvar = new ConsoleVariable(cvarAttribute.name); + consoleVariables.Add(cvarAttribute.name, entry); + } + entry.cvar.AddField(field); + foreach (string alias in cvarAttribute.aliases) - consoleVariables.Add(alias, - new ConsoleVariable(cvarAttribute.name, - cvarAttribute.flags | ConsoleFlags.NoSerialize, field)); + consoleVariables.Add(alias, (entry.cvar, true)); } } } - foreach (PropertyInfo prop in type.GetProperties()) + foreach (PropertyInfo property in type.GetProperties(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)) { - MethodInfo getter = prop.GetGetMethod(); - MethodInfo setter = prop.GetSetMethod(); - if (getter == null || setter == null || !getter.IsStatic || !setter.IsStatic) - continue; - - var attributes = Attribute.GetCustomAttributes(prop); + var attributes = Attribute.GetCustomAttributes(property); foreach (Attribute attr in attributes) { 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 + "'"); - consoleVariables.Add(cvarAttribute.name, - new ConsoleVariable(cvarAttribute.name, cvarAttribute.flags, getter, setter)); + if (!consoleVariables.TryGetValue(cvarAttribute.name, out var entry)) + { + entry.cvar = new ConsoleVariable(cvarAttribute.name); + consoleVariables.Add(cvarAttribute.name, entry); + } + entry.cvar.AddProperty(property); + foreach (string alias in cvarAttribute.aliases) - consoleVariables.Add(alias, - new ConsoleVariable(cvarAttribute.name, - cvarAttribute.flags | ConsoleFlags.NoSerialize, getter, setter)); + consoleVariables.Add(alias, (entry.cvar, true)); } } } @@ -479,13 +485,13 @@ public class ConsoleInstance : IDisposable cmd.Invoke(); //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) - cvar.SetValue(value); + entry.cvar.SetValue(value); if (!noOutput) - Console.Print("'" + execute + "' is '" + cvar.GetValueString() + "'"); + Console.Print("'" + execute + "' is '" + entry.cvar.GetValueString() + "'"); } else { @@ -503,9 +509,9 @@ public class ConsoleInstance : IDisposable 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; } diff --git a/Source/Game/Console/ConsoleAttributes.cs b/Source/Game/Console/ConsoleAttributes.cs index 9c4dac4..5f6c464 100644 --- a/Source/Game/Console/ConsoleAttributes.cs +++ b/Source/Game/Console/ConsoleAttributes.cs @@ -38,7 +38,7 @@ public class ConsoleVariableAttribute : ConsoleBaseAttribute public class ConsoleCommandAttribute : ConsoleBaseAttribute { /// - /// Registers a command to Console system. + /// Registers a command to Console system. /// /// Name used for calling this command. public ConsoleCommandAttribute(string name) : base(name) @@ -46,11 +46,11 @@ public class ConsoleCommandAttribute : ConsoleBaseAttribute } /// - /// Registers a command to Console system. + /// Registers a command to Console system. /// /// - /// Names used for calling this command. First name is the main name for this command, rest of the - /// names are aliases. + /// Names used for calling this command. First name is the main name for this command, + /// rest of the names are aliases. /// public ConsoleCommandAttribute(params string[] names) : base(names) { @@ -58,7 +58,7 @@ public class ConsoleCommandAttribute : ConsoleBaseAttribute } /// -/// Constructor for the subsystem, must be called first before registering console commands. +/// Constructor for the subsystem, must be called first before registering console commands. /// [AttributeUsage(AttributeTargets.All)] public class ConsoleSubsystemInitializer : Attribute diff --git a/Source/Game/Console/ConsoleVariable.cs b/Source/Game/Console/ConsoleVariable.cs index 9b0d6e9..8c77fb8 100644 --- a/Source/Game/Console/ConsoleVariable.cs +++ b/Source/Game/Console/ConsoleVariable.cs @@ -1,88 +1,123 @@ using System; +using System.Collections.Generic; using System.Reflection; +using FlaxEngine; +using FlaxEngine.Assertions; namespace Game; [Flags] public enum ConsoleFlags { - NoSerialize = 1, // Value does not persist - - Alias = NoSerialize + /// + /// Value does not persist. + /// + NoSerialize = 1, } -internal struct ConsoleVariable +internal class ConsoleVariable { - public string name { get; } - public ConsoleFlags flags { get; } + public string Name { get; } - private readonly FieldInfo field; - private readonly MethodInfo getter; - private readonly MethodInfo setter; + private readonly List _fields; + private readonly List _getters; + private readonly List _setters; - public ConsoleVariable(string name, ConsoleFlags flags, FieldInfo field) + public ConsoleVariable(string name) { - this.name = name; - this.flags = flags; - this.field = field; - getter = null; - setter = null; + Name = name; + _fields = new List(); + _getters = new List(); + _setters = new List(); } - public ConsoleVariable(string name, ConsoleFlags flags, MethodInfo getter, MethodInfo setter) + public void AddField(FieldInfo field) { - this.name = name; - this.flags = flags; - field = null; - this.getter = getter; - this.setter = setter; + Assert.IsTrue(_getters.Count == 0); + + _fields.Add(field); + } + + 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() { + FieldInfo field = _fields.Count > 0 ? _fields[0] : null; + MethodInfo getter = _getters.Count > 0 ? _getters[0] : null; + Type type = field != null ? field.FieldType : getter.ReturnType; if (type == typeof(string)) { if (field != null) return (string)field.GetValue(null); if (getter != null) - return (string)getter.Invoke(null, null); + return ((float)getter.Invoke(null, null)).ToString(); } else if (type == typeof(float)) { if (field != null) return field.GetValue(null).ToString(); if (getter != null) - return (string)getter.Invoke(null, null); + return ((float)getter.Invoke(null, null)).ToString(); } 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) { - Type type = field != null ? field.FieldType : getter.ReturnType; - if (type == typeof(string)) + foreach (var field in _fields) { - if (field != null) + Type type = field.FieldType; + if (type == typeof(string)) field.SetValue(null, value); - else if (setter != null) - setter.Invoke(null, new object[] { value }); - } - else if (type == typeof(float)) - { - if (!float.TryParse(value, out var floatValue)) - return; - if (field != null) + else if (type == typeof(float)) + { + if (!float.TryParse(value, out var floatValue)) + return; 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}'"); } } } \ No newline at end of file diff --git a/Source/Game/Player/PlayerInput2.cs b/Source/Game/Player/PlayerInput2.cs index 84505cc..650be6d 100644 --- a/Source/Game/Player/PlayerInput2.cs +++ b/Source/Game/Player/PlayerInput2.cs @@ -51,7 +51,7 @@ public class PlayerInput2 : IPlayerInput private PlayerInputState2 _recordState; [ConsoleVariable("sensitivity")] - public static float Sensitivity; + private static float _sensitivity { get; set; } = 1.0f; public void SetFrame(ulong frame) { @@ -67,7 +67,7 @@ public class PlayerInput2 : IPlayerInput //sensitivity = 1.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.MoveForward = MathF.MaxMagnitude(_recordState.MoveForward, Input.GetAxis("Vertical"));