-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #46 from MuffinTastic/MuffinTastic/cvar-system-imp…
…rovements Console System Improvements
- Loading branch information
Showing
15 changed files
with
1,529 additions
and
168 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace Mocha.Common; | ||
|
||
public enum CVarFlags | ||
{ | ||
// Mirrors native | ||
|
||
None = 0, | ||
|
||
// If this isn't present, it's inherently assumed to be a variable | ||
Command = 1 << 0, | ||
|
||
// If this is present, it lives in managed space | ||
Managed = 1 << 1, | ||
|
||
// This cvar was created by the game, it should be wiped on hotload | ||
Game = 1 << 2, | ||
|
||
// Save this convar to cvars.json | ||
Archive = 1 << 3, | ||
|
||
Cheat = 1 << 4, | ||
|
||
Temp = 1 << 5, | ||
|
||
Replicated = 1 << 6, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
namespace Mocha.Common; | ||
|
||
public static class ConCmd | ||
{ | ||
public abstract class BaseAttribute : Attribute | ||
{ | ||
internal string? Name { get; init; } | ||
internal CVarFlags Flags { get; init; } | ||
internal string? Description { get; init; } | ||
|
||
public BaseAttribute( string? name, CVarFlags flags, string? description ) | ||
{ | ||
Name = name; | ||
Flags = flags; | ||
Description = description; | ||
} | ||
} | ||
|
||
// public class ServerAttribute | ||
// public class ClientAttribute | ||
|
||
public sealed class TestAttribute : BaseAttribute | ||
{ | ||
public TestAttribute() | ||
: base( null, CVarFlags.None, null ) | ||
{ | ||
|
||
} | ||
public TestAttribute( string name ) | ||
: base( name, CVarFlags.None, null ) | ||
{ | ||
|
||
} | ||
|
||
public TestAttribute( string name, string description ) | ||
: base( name, CVarFlags.None, description ) | ||
{ | ||
|
||
} | ||
} | ||
|
||
public sealed class CheatAttribute : BaseAttribute | ||
{ | ||
public CheatAttribute() | ||
: base( null, CVarFlags.Cheat, null ) | ||
{ | ||
|
||
} | ||
public CheatAttribute( string name ) | ||
: base( name, CVarFlags.Cheat, null ) | ||
{ | ||
|
||
} | ||
|
||
public CheatAttribute( string name, string description ) | ||
: base( name, CVarFlags.Cheat, description ) | ||
{ | ||
|
||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
namespace Mocha.Common; | ||
|
||
public static class ConVar | ||
{ | ||
public abstract class BaseAttribute : Attribute | ||
{ | ||
public required string Name { get; init; } | ||
public required CVarFlags Flags { get; init; } | ||
public required string Description { get; init; } | ||
} | ||
|
||
public class TestAttribute : Attribute | ||
{ | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Runtime.InteropServices; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace Mocha.Common.Console; | ||
|
||
|
||
[StructLayout( LayoutKind.Sequential )] | ||
public struct ConCmdDispatchInfo | ||
{ | ||
public IntPtr name; | ||
public IntPtr data; | ||
public int size; | ||
} | ||
|
||
[StructLayout( LayoutKind.Sequential )] | ||
public struct StringCVarDispatchInfo | ||
{ | ||
public IntPtr name; | ||
public IntPtr oldValue; | ||
public IntPtr newValue; | ||
} | ||
|
||
[StructLayout( LayoutKind.Sequential )] | ||
public struct FloatCVarDispatchInfo | ||
{ | ||
public IntPtr name; | ||
public float oldValue; | ||
public float newValue; | ||
} | ||
|
||
[StructLayout( LayoutKind.Sequential )] | ||
public struct BoolCVarDispatchInfo | ||
{ | ||
public IntPtr name; | ||
public bool oldValue; | ||
public bool newValue; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Reflection; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace Mocha.Common; | ||
|
||
public static partial class ConsoleSystem | ||
{ | ||
public static class Internal | ||
{ | ||
internal struct ConCmdCallbackInfo | ||
{ | ||
public required MethodInfo method; | ||
public required ParameterInfo[] parameters; | ||
} | ||
|
||
internal static class ConVarCallbackStore<T> | ||
{ | ||
public static Dictionary<string, Action<T, T>> Callbacks = new(); | ||
} | ||
|
||
internal static List<string> s_items = new(); | ||
|
||
internal static Dictionary<string, ConCmdCallbackInfo> s_commandCallbacks = new(); | ||
|
||
internal static void RegisterCommand( string name, CVarFlags flags, string description, ConCmdCallbackInfo callbackInfo ) | ||
{ | ||
Glue.ConsoleSystem.RegisterCommand( name, flags, description ); | ||
s_commandCallbacks[name] = callbackInfo; | ||
s_items.Add( name ); | ||
} | ||
|
||
internal static void RegisterStringConVar( string name, string value, CVarFlags flags, string description, Action<string, string> callback ) | ||
{ | ||
Glue.ConsoleSystem.RegisterString( name, value, flags, description ); | ||
ConVarCallbackStore<string>.Callbacks[name] = callback; | ||
s_items.Add( name ); | ||
} | ||
|
||
internal static void RegisterFloatConVar( string name, float value, CVarFlags flags, string description, Action<float, float> callback ) | ||
{ | ||
Glue.ConsoleSystem.RegisterFloat( name, value, flags, description ); | ||
ConVarCallbackStore<float>.Callbacks[name] = callback; | ||
s_items.Add( name ); | ||
} | ||
|
||
internal static void RegisterBoolConVar( string name, bool value, CVarFlags flags, string description, Action<bool, bool> callback ) | ||
{ | ||
Glue.ConsoleSystem.RegisterBool( name, value, flags, description ); | ||
ConVarCallbackStore<bool>.Callbacks[name] = callback; | ||
s_items.Add( name ); | ||
} | ||
|
||
/// <summary> | ||
/// Register all of the CVars in an assembly | ||
/// </summary> | ||
/// <param name="assembly">The assembly to grab from</param> | ||
/// <param name="extraFlags">Extra flags to force each CVar to have. Used mainly for hotloaded assemblies</param> | ||
public static void RegisterAssembly( Assembly assembly, CVarFlags extraFlags = CVarFlags.None ) | ||
{ | ||
if ( assembly is null ) | ||
return; | ||
|
||
foreach ( Type type in assembly.GetTypes() ) | ||
{ | ||
foreach ( MethodInfo method in type.GetMethods( BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic ) ) | ||
{ | ||
ConCmd.BaseAttribute? customAttribute = method.GetCustomAttribute<ConCmd.BaseAttribute>(); | ||
if ( customAttribute is not null ) | ||
{ | ||
var parameters = method.GetParameters(); | ||
|
||
var callbackInfo = new ConCmdCallbackInfo | ||
{ | ||
method = method, | ||
parameters = parameters | ||
}; | ||
|
||
RegisterCommand( customAttribute.Name ?? method.Name, customAttribute.Flags | extraFlags, customAttribute.Description ?? "", callbackInfo ); | ||
} | ||
} | ||
} | ||
} | ||
|
||
public static void ClearGameCVars() | ||
{ | ||
foreach ( var name in s_items.ToList() ) | ||
{ | ||
bool exists = Glue.ConsoleSystem.Exists( name ); | ||
CVarFlags flags = Glue.ConsoleSystem.GetFlags( name ); | ||
|
||
if ( exists && (flags & CVarFlags.Game) != 0 ) | ||
{ | ||
s_items.Remove( name ); | ||
s_commandCallbacks.Remove( name ); | ||
ConVarCallbackStore<string>.Callbacks.Remove( name ); | ||
ConVarCallbackStore<float>.Callbacks.Remove( name ); | ||
ConVarCallbackStore<bool>.Callbacks.Remove( name ); | ||
|
||
Glue.ConsoleSystem.Remove( name ); | ||
} | ||
} | ||
} | ||
|
||
public static void DispatchCommand( string name, List<string> dispatchArguments ) | ||
{ | ||
if ( !s_commandCallbacks.TryGetValue( name, out ConCmdCallbackInfo callbackInfo ) ) | ||
return; | ||
|
||
ParameterInfo[] callbackParameters = callbackInfo.parameters; | ||
|
||
if ( callbackParameters.Length == 1 && | ||
callbackParameters[0].ParameterType == dispatchArguments.GetType() ) | ||
{ | ||
// All it takes is a List<string> so we can probably assume they want direct access to the arguments | ||
callbackInfo.method.Invoke( null, new object[] { dispatchArguments } ); | ||
return; | ||
} | ||
|
||
object?[]? arguments = null; | ||
|
||
if ( callbackParameters.Length > 0 ) | ||
{ | ||
// | ||
// Softly convert arguments from strings to whatever the callback expects | ||
// | ||
|
||
arguments = new object[callbackParameters.Length]; | ||
|
||
for ( int i = 0; i < callbackParameters.Length; i++ ) | ||
{ | ||
object? value; | ||
|
||
ParameterInfo parameter = callbackParameters[i]; | ||
Type parameterType = parameter.ParameterType; | ||
|
||
if ( i < dispatchArguments.Count ) | ||
{ | ||
// Try to convert | ||
if ( !dispatchArguments[i].TryConvert( parameterType, out value ) ) | ||
{ | ||
Log.Error( $"Error dispatching ConCmd '{name}': Couldn't convert '{dispatchArguments[i]}' to type {parameterType}" ); | ||
return; | ||
} | ||
} | ||
else if ( parameter.HasDefaultValue ) | ||
{ | ||
// There weren't enough arguments passed in, | ||
// but we have a default value, so use that instead | ||
value = parameter.DefaultValue; | ||
} | ||
else | ||
{ | ||
Log.Error( $"Error dispatching ConCmd '{name}': Not enough arguments - expected {callbackParameters.Length}, got {dispatchArguments.Count}" ); | ||
return; | ||
} | ||
|
||
arguments[i] = value; | ||
} | ||
} | ||
|
||
callbackInfo.method.Invoke( null, arguments ); | ||
} | ||
|
||
public static void DispatchConVarCallback<T>( string name, T oldValue, T newValue ) | ||
{ | ||
if ( !ConVarCallbackStore<T>.Callbacks.TryGetValue( name, out var callback ) ) | ||
return; | ||
|
||
callback( oldValue, newValue ); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
using System; | ||
using System.Reflection; | ||
using Mocha.Common.Console; | ||
|
||
namespace Mocha.Common; | ||
|
||
public static partial class ConsoleSystem | ||
{ | ||
public static void Run( string command ) | ||
{ | ||
Glue.ConsoleSystem.Run( command ); | ||
} | ||
|
||
public static float GetFloat( string name ) | ||
{ | ||
return Glue.ConsoleSystem.GetFloat( name ); | ||
} | ||
|
||
public static bool GetBool( string name ) | ||
{ | ||
return Glue.ConsoleSystem.GetBool( name ); | ||
} | ||
|
||
public static void Set( string name, string value ) | ||
{ | ||
Glue.ConsoleSystem.SetString( name, value ); | ||
} | ||
|
||
public static void Set( string name, float value ) | ||
{ | ||
Glue.ConsoleSystem.SetFloat( name, value ); | ||
} | ||
|
||
public static void Set( string name, bool value ) | ||
{ | ||
Glue.ConsoleSystem.SetBool( name, value ); | ||
} | ||
|
||
public static void SetFromString( string name, string value ) | ||
{ | ||
Glue.ConsoleSystem.FromString( name, value ); | ||
} | ||
} |
Oops, something went wrong.