Compare commits
7 Commits
virtual-co
...
master
Author | SHA1 | Date | |
---|---|---|---|
cfa47142ac | |||
15b916a52a | |||
8ffedd6ba9 | |||
2a1c40a51c | |||
f1a4ea0a65 | |||
99ba6e1710 | |||
60979355d4 |
@ -5,6 +5,14 @@
|
|||||||
<TargetFramework>net9.0</TargetFramework>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
|
<GenerateTargetFrameworkAttribute>false</GenerateTargetFrameworkAttribute>
|
||||||
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
</Project>
|
<ItemGroup>
|
||||||
|
<Content Include="src\CogwheelLib.csproj" />
|
||||||
|
<Compile Remove="obj\**\*.AssemblyAttributes.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
@ -1,60 +0,0 @@
|
|||||||
namespace Cogwheel;
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
public class DeafultCogwheelConsole : ICogwheelConsole
|
|
||||||
{
|
|
||||||
public string OpeningMessage { get; set; } = "** COGWHEEL CONSOLE **";
|
|
||||||
public bool IsRunning { get; set; }
|
|
||||||
public CommandsManager CommandsManager { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
public void Initialize(CommandsManager commandsManager)
|
|
||||||
{
|
|
||||||
CommandsManager = commandsManager;
|
|
||||||
CommandsManager.RegisterObject(this);
|
|
||||||
|
|
||||||
Write(OpeningMessage);
|
|
||||||
|
|
||||||
IsRunning = true;
|
|
||||||
while (IsRunning)
|
|
||||||
{
|
|
||||||
Console.Write("> ");
|
|
||||||
string input = Console.ReadLine();
|
|
||||||
CommandsManager.RunCommand(input);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Log(string message)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"[COGWHEEL] {message}");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void LogError(string message)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"[COGWHEEL ERROR] {message}");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void LogWarning(string message)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"[COGWHEEL WARNING] {message}");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Write(string message)
|
|
||||||
{
|
|
||||||
Console.WriteLine(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ClearConsole()
|
|
||||||
{
|
|
||||||
Console.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Exit()
|
|
||||||
{
|
|
||||||
IsRunning = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
13
Program.cs
13
Program.cs
@ -1,9 +1,20 @@
|
|||||||
// Program.cs
|
/*
|
||||||
|
This is an example of how to initialize the Cogwheel system in a console application
|
||||||
|
using the default console implementation and adding the assembly containing the built-in commands.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System.Reflection;
|
||||||
using Cogwheel;
|
using Cogwheel;
|
||||||
|
|
||||||
|
// Create a new instance of an ICogwheelConsole implementation
|
||||||
ICogwheelConsole cogwheelConsole = new DeafultCogwheelConsole();
|
ICogwheelConsole cogwheelConsole = new DeafultCogwheelConsole();
|
||||||
|
|
||||||
|
// Create a new instance of a CommandsManager
|
||||||
CommandsManager commandsManager = new CommandsManager();
|
CommandsManager commandsManager = new CommandsManager();
|
||||||
|
|
||||||
|
// Register the assembly containing the built-in commands
|
||||||
|
commandsManager.AddAssembly(Assembly.GetCallingAssembly());
|
||||||
|
|
||||||
|
// Initialize the Cogwheel system
|
||||||
COGWHEEL.Initialize(commandsManager, cogwheelConsole);
|
COGWHEEL.Initialize(commandsManager, cogwheelConsole);
|
||||||
|
|
||||||
|
182
src/COGWHEEL.cs
182
src/COGWHEEL.cs
@ -1,26 +1,50 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
namespace Cogwheel;
|
namespace Cogwheel;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Static class for interacting with the Cogwheel system
|
||||||
|
/// </summary>
|
||||||
public static class COGWHEEL
|
public static class COGWHEEL
|
||||||
{
|
{
|
||||||
private static CommandsManager _commandsManager;
|
private static CommandsManager _commandsManager;
|
||||||
private static ICogwheelConsole _console;
|
private static ICogwheelConsole _console;
|
||||||
|
|
||||||
|
public static bool UseBuiltInCommands { get; set; } = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes the Cogwheel system
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="commandsManager"></param>
|
||||||
|
/// <param name="console"></param>
|
||||||
public static void Initialize(CommandsManager commandsManager, ICogwheelConsole console)
|
public static void Initialize(CommandsManager commandsManager, ICogwheelConsole console)
|
||||||
{
|
{
|
||||||
_console = console;
|
_console = console;
|
||||||
_commandsManager = commandsManager;
|
_commandsManager = commandsManager;
|
||||||
|
|
||||||
|
InitializeCustomParsers();
|
||||||
|
|
||||||
_commandsManager.Initialize(_console);
|
_commandsManager.Initialize(_console);
|
||||||
_console.Initialize(_commandsManager);
|
_console.Initialize(_commandsManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// == Public static methods for the CommandsManager == //
|
// == Public static methods for the CommandsManager == //
|
||||||
|
/// <summary>
|
||||||
|
/// Runs a command
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input"></param>
|
||||||
public static void RunCommand(string input)
|
public static void RunCommand(string input)
|
||||||
{
|
{
|
||||||
_commandsManager.RunCommand(input);
|
_commandsManager.RunCommand(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Registers an object with the CommandsManager for non-static commands
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj"></param>
|
||||||
public static void RegisterObject(object obj)
|
public static void RegisterObject(object obj)
|
||||||
{
|
{
|
||||||
_commandsManager.RegisterObject(obj);
|
_commandsManager.RegisterObject(obj);
|
||||||
@ -28,43 +52,96 @@ public static class COGWHEEL
|
|||||||
|
|
||||||
|
|
||||||
// == Public static methods for the Console == //
|
// == Public static methods for the Console == //
|
||||||
|
/// <summary>
|
||||||
|
/// Logs a message to the console
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
public static void Log(string message)
|
public static void Log(string message)
|
||||||
{
|
{
|
||||||
_console.Log(message);
|
_console.Log(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Logs an error message to the console
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
public static void LogError(string message)
|
public static void LogError(string message)
|
||||||
{
|
{
|
||||||
_console.LogError(message);
|
_console.LogError(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Logs a warning message to the console
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
public static void LogWarning(string message)
|
public static void LogWarning(string message)
|
||||||
{
|
{
|
||||||
_console.LogWarning(message);
|
_console.LogWarning(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a message to the console
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
public static void Write(string message)
|
public static void Write(string message)
|
||||||
{
|
{
|
||||||
_console.Write(message);
|
_console.Write(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the context for the CommandsManager
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj"></param>
|
||||||
|
public static void SetContext(object obj)
|
||||||
|
{
|
||||||
|
_commandsManager.SetContext(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the context for the CommandsManager by GUID
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="guid"></param>
|
||||||
|
public static void SetContext(Guid guid)
|
||||||
|
{
|
||||||
|
_commandsManager.SetContext(guid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the context for the CommandsManager by GUID string
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="guidString"></param>
|
||||||
|
public static void SetContext(string guidString)
|
||||||
|
{
|
||||||
|
_commandsManager.SetContext(guidString);
|
||||||
|
}
|
||||||
|
|
||||||
// == Built-in commands == //
|
// == Built-in commands == //
|
||||||
|
/// <summary>
|
||||||
|
/// Quit the Cogwheel console
|
||||||
|
/// </summary>
|
||||||
[Command(Name = "quit", Description = "Quits the Cogwheel console.")]
|
[Command(Name = "quit", Description = "Quits the Cogwheel console.")]
|
||||||
public static void QuitCogwheelConsole()
|
public static void QuitCogwheelConsole()
|
||||||
{
|
{
|
||||||
_console.Exit();
|
_console.Exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clears the console
|
||||||
|
/// </summary>
|
||||||
[Command(Name = "clear", Description = "Clears the console.")]
|
[Command(Name = "clear", Description = "Clears the console.")]
|
||||||
public static void ClearConsole()
|
public static void ClearConsole()
|
||||||
{
|
{
|
||||||
_console.ClearConsole();
|
_console.ClearConsole();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Shows the description and usage of a given command
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="commandName"></param>
|
||||||
[Command(Name = "help", Description = "Gets usage for given command.")]
|
[Command(Name = "help", Description = "Gets usage for given command.")]
|
||||||
public static void ShowHelp(string commandName)
|
public static void ShowHelp(string commandName)
|
||||||
{
|
{
|
||||||
ICommand command = _commandsManager.GetCommandByName(commandName);
|
ICommand? command = _commandsManager.GetCommandByName(commandName);
|
||||||
if (command is null)
|
if (command is null)
|
||||||
{
|
{
|
||||||
_console.LogError($"Command error: '{commandName}' is not a command.");
|
_console.LogError($"Command error: '{commandName}' is not a command.");
|
||||||
@ -76,6 +153,9 @@ public static class COGWHEEL
|
|||||||
$"Usage: {_commandsManager.GetCommandUsage(command)}");
|
$"Usage: {_commandsManager.GetCommandUsage(command)}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Lists all available commands
|
||||||
|
/// </summary>
|
||||||
[Command(Name = "list", Description = "Lists all available commands.")]
|
[Command(Name = "list", Description = "Lists all available commands.")]
|
||||||
public static void ListCommands()
|
public static void ListCommands()
|
||||||
{
|
{
|
||||||
@ -85,21 +165,55 @@ public static class COGWHEEL
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Logs the current context type and GUID
|
||||||
|
/// </summary>
|
||||||
[Command(Name = "what", Description = "Prints the current context.")]
|
[Command(Name = "what", Description = "Prints the current context.")]
|
||||||
public static void ShowCurrentContext()
|
public static void ShowCurrentContext()
|
||||||
{
|
{
|
||||||
|
if (_commandsManager.CurrentContext is null)
|
||||||
|
{
|
||||||
|
Log("No context set.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_console.Log($"Current context: {_commandsManager.CurrentContext.GetType()} : {_commandsManager.CurrentContextGuid}");
|
_console.Log($"Current context: {_commandsManager.CurrentContext.GetType()} : {_commandsManager.CurrentContextGuid}");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(Name = "test", Description = "Creates a new TestClass object.")]
|
/// <summary>
|
||||||
public static void CreateTestObject(string name)
|
/// Adds an assembly to the CommandsManager for command discovery
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="assembly"></param>
|
||||||
|
public static void AddAssembly(Assembly assembly)
|
||||||
{
|
{
|
||||||
_console.Log($"Creating new TestClass object with name: {name}");
|
_commandsManager.AddAssembly(assembly);
|
||||||
var test = new TestClass(name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes an assembly from the CommandsManager
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="assembly"></param>
|
||||||
|
public static void RemoveAssembly(Assembly assembly)
|
||||||
|
{
|
||||||
|
_commandsManager.RemoveAssembly(assembly);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a custom parser for a given type
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type"></param>
|
||||||
|
/// <param name="parser"></param>
|
||||||
|
public static void AddCustomParser(Type type, Func<string, object> parser)
|
||||||
|
{
|
||||||
|
_commandsManager.AddCustomParser(type, parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Logs all registered objects and their GUIDs, optionally filtered by type
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="typeName"></param>
|
||||||
[Command(Name = "find", Description = "Lists available registered objects to select from.")]
|
[Command(Name = "find", Description = "Lists available registered objects to select from.")]
|
||||||
private static void SelectContextFromRegisteredObjects(string typeName = "")
|
private static void FindAllContextsFromRegisteredObjects(string typeName = "")
|
||||||
{
|
{
|
||||||
var registeredObjects = _commandsManager.RegisteredObjectInstances;
|
var registeredObjects = _commandsManager.RegisteredObjectInstances;
|
||||||
var filteredObjects = string.IsNullOrEmpty(typeName)
|
var filteredObjects = string.IsNullOrEmpty(typeName)
|
||||||
@ -119,10 +233,62 @@ public static class COGWHEEL
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the context to the specified registered object by GUID
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="guidString"></param>
|
||||||
[Command(Name = "set", Description = "Sets the context to the specified registered object.")]
|
[Command(Name = "set", Description = "Sets the context to the specified registered object.")]
|
||||||
private static void SetContextFromGuid(string guidString)
|
private static void SetContextFromGuid(string guidString)
|
||||||
{
|
{
|
||||||
_commandsManager.SetContext(guidString);
|
SetContext(guidString);
|
||||||
Log($"Set context to {_commandsManager.CurrentContext?.GetType().FullName} : {_commandsManager.CurrentContextGuid}");
|
Log($"Set context to {_commandsManager.CurrentContext?.GetType().FullName} : {_commandsManager.CurrentContextGuid}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes custom parsers for the Cogwheel system
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="FormatException"></exception>
|
||||||
|
private static void InitializeCustomParsers()
|
||||||
|
{
|
||||||
|
// Add custom parser for Vector2
|
||||||
|
_commandsManager.AddCustomParser(typeof(Vector2), s =>
|
||||||
|
{
|
||||||
|
s = s.Trim('(', ')');
|
||||||
|
|
||||||
|
var parts = s.Split(',');
|
||||||
|
if (parts.Length != 2)
|
||||||
|
{
|
||||||
|
throw new FormatException("Input string must have exactly three components separated by commas.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!float.TryParse(parts[0].Trim(), out float x) ||
|
||||||
|
!float.TryParse(parts[1].Trim(), out float y))
|
||||||
|
{
|
||||||
|
throw new FormatException("Input string contains invalid float values.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Vector2(x, y);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add custom parser for Vector3
|
||||||
|
_commandsManager.AddCustomParser(typeof(Vector3), s =>
|
||||||
|
{
|
||||||
|
s = s.Trim('(', ')');
|
||||||
|
|
||||||
|
var parts = s.Split(',');
|
||||||
|
if (parts.Length != 3)
|
||||||
|
{
|
||||||
|
throw new FormatException("Input string must have exactly three components separated by commas.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!float.TryParse(parts[0].Trim(), out float x) ||
|
||||||
|
!float.TryParse(parts[1].Trim(), out float y) ||
|
||||||
|
!float.TryParse(parts[2].Trim(), out float z))
|
||||||
|
{
|
||||||
|
throw new FormatException("Input string contains invalid float values.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Vector3(x, y, z);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
29
src/CogwheelLib.csproj
Normal file
29
src/CogwheelLib.csproj
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
|
<GenerateTargetFrameworkAttribute>false</GenerateTargetFrameworkAttribute>
|
||||||
|
|
||||||
|
<Version>1.3.0</Version>
|
||||||
|
<Authors>Chris Bell</Authors>
|
||||||
|
<Company>Bellsworne Tech</Company>
|
||||||
|
<Description>A suite of development tools for games</Description>
|
||||||
|
<PackageTags>development tools, games</PackageTags>
|
||||||
|
<PackageProjectUrl>https://git.bellsworne.tech/Bellsworne/Cogwheel/packages</PackageProjectUrl>
|
||||||
|
<RepositoryUrl>https://git.bellsworne.tech/Bellsworne/Cogwheel.git</RepositoryUrl>
|
||||||
|
<RepositoryType>git</RepositoryType>
|
||||||
|
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||||
|
<!-- <PackageIcon>icon.png</PackageIcon>-->
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Remove="obj\**\*.AssemblyAttributes.cs" />
|
||||||
|
<None Include="changelog.md" Pack="true" PackagePath="" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
@ -2,12 +2,32 @@ using System.Reflection;
|
|||||||
|
|
||||||
namespace Cogwheel;
|
namespace Cogwheel;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a command in the Cogwheel system.
|
||||||
|
/// </summary>
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name of the command.
|
||||||
|
/// </summary>
|
||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the description of the command.
|
||||||
|
/// </summary>
|
||||||
public string Description { get; }
|
public string Description { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the method associated with the command.
|
||||||
|
/// </summary>
|
||||||
public MethodBase Method { get; }
|
public MethodBase Method { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="Command"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the command.</param>
|
||||||
|
/// <param name="description">The description of the command.</param>
|
||||||
|
/// <param name="method">The method associated with the command.</param>
|
||||||
public Command(string name, string description, MethodBase method)
|
public Command(string name, string description, MethodBase method)
|
||||||
{
|
{
|
||||||
Name = name;
|
Name = name;
|
||||||
|
@ -1,8 +1,20 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
namespace Cogwheel;
|
namespace Cogwheel;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attribute for marking methods as commands
|
||||||
|
/// </summary>
|
||||||
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
|
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
|
||||||
public class CommandAttribute : Attribute
|
public class CommandAttribute : Attribute
|
||||||
{
|
{
|
||||||
public string Name = "";
|
/// <summary>
|
||||||
|
/// Optional name of the command, if not provided the method name will be used
|
||||||
|
/// </summary>
|
||||||
|
public string? Name = "";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Optional description of the command
|
||||||
|
/// </summary>
|
||||||
public string Description = "";
|
public string Description = "";
|
||||||
}
|
}
|
@ -2,33 +2,75 @@ using System.Reflection;
|
|||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Exception = System.Exception;
|
|
||||||
|
|
||||||
namespace Cogwheel;
|
namespace Cogwheel;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Manages commands for the Cogwheel system.
|
||||||
|
/// </summary>
|
||||||
public class CommandsManager
|
public class CommandsManager
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the console used by the CommandsManager.
|
||||||
|
/// </summary>
|
||||||
protected virtual ICogwheelConsole CogwheelConsole { get; set; }
|
protected virtual ICogwheelConsole CogwheelConsole { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the pattern used to parse commands.
|
||||||
|
/// </summary>
|
||||||
protected virtual string CommandPattern { get; set; } = "(?<val>(\\([^\\)]+\\)))|\"(?<val>[^\"]+)\"|'(?<val>[^']+)'|(?<val>[^\\s]+)";
|
protected virtual string CommandPattern { get; set; } = "(?<val>(\\([^\\)]+\\)))|\"(?<val>[^\"]+)\"|'(?<val>[^']+)'|(?<val>[^\\s]+)";
|
||||||
|
|
||||||
protected virtual List<Assembly> Assemblies { get; set; } = [];
|
/// <summary>
|
||||||
|
/// Gets or sets the list of assemblies to search for commands.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual List<Assembly> Assemblies { get; set; } = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the dictionary of commands.
|
||||||
|
/// </summary>
|
||||||
public virtual Dictionary<string, ICommand> Commands { get; set; } = new();
|
public virtual Dictionary<string, ICommand> Commands { get; set; } = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the dictionary of custom parsers for command parameters.
|
||||||
|
/// </summary>
|
||||||
public virtual Dictionary<Type, Func<string, object>> CustomParsers { get; set; } = new();
|
public virtual Dictionary<Type, Func<string, object>> CustomParsers { get; set; } = new();
|
||||||
|
|
||||||
// Context related stuff
|
/// <summary>
|
||||||
|
/// Gets or sets the current context object.
|
||||||
|
/// </summary>
|
||||||
public virtual object? CurrentContext { get; set; }
|
public virtual object? CurrentContext { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the GUID of the current context.
|
||||||
|
/// </summary>
|
||||||
public virtual Guid? CurrentContextGuid { get; set; }
|
public virtual Guid? CurrentContextGuid { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the dictionary of registered object instances.
|
||||||
|
/// </summary>
|
||||||
public virtual Dictionary<Guid, object> RegisteredObjectInstances { get; set; } = new();
|
public virtual Dictionary<Guid, object> RegisteredObjectInstances { get; set; } = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the dictionary of registered object GUIDs.
|
||||||
|
/// </summary>
|
||||||
public virtual Dictionary<object, Guid> RegisteredObjectGuids { get; set; } = new();
|
public virtual Dictionary<object, Guid> RegisteredObjectGuids { get; set; } = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes the CommandsManager with the specified console.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="console">The console to use.</param>
|
||||||
public virtual void Initialize(ICogwheelConsole console)
|
public virtual void Initialize(ICogwheelConsole console)
|
||||||
{
|
{
|
||||||
CogwheelConsole = console;
|
CogwheelConsole = console;
|
||||||
RefreshCommandsList();
|
RefreshCommandsList();
|
||||||
CogwheelConsole.Log($"CommandsManager initialized, Commands found: {Commands.Count}");
|
CogwheelConsole.Log($"CommandsManager initialized, Commands found: {Commands.Count}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the command and arguments from the input string.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input">The input string.</param>
|
||||||
|
/// <returns>A tuple containing the command and arguments, or null if the command is not found.</returns>
|
||||||
public virtual (ICommand, List<object>)? GetCommandAndArgsFromString(string input)
|
public virtual (ICommand, List<object>)? GetCommandAndArgsFromString(string input)
|
||||||
{
|
{
|
||||||
var splitString = Regex.Matches(input, CommandPattern).Select(m => m.Groups["val"].Value).ToArray();
|
var splitString = Regex.Matches(input, CommandPattern).Select(m => m.Groups["val"].Value).ToArray();
|
||||||
@ -38,7 +80,7 @@ public class CommandsManager
|
|||||||
{
|
{
|
||||||
args.Add(splitString[splitIndex]);
|
args.Add(splitString[splitIndex]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Commands.TryGetValue(commandName, out var command))
|
if (Commands.TryGetValue(commandName, out var command))
|
||||||
{
|
{
|
||||||
return (command, args);
|
return (command, args);
|
||||||
@ -47,6 +89,12 @@ public class CommandsManager
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Runs the command specified by the input string.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input">The input string.</param>
|
||||||
|
/// <param name="context">The context object, if any.</param>
|
||||||
|
/// <returns>True if the command was executed successfully, otherwise false.</returns>
|
||||||
public virtual bool RunCommand(string input, object? context = null)
|
public virtual bool RunCommand(string input, object? context = null)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(input)) return false;
|
if (string.IsNullOrWhiteSpace(input)) return false;
|
||||||
@ -72,11 +120,18 @@ public class CommandsManager
|
|||||||
return ExecuteCommand(CurrentContext, command.Value);
|
return ExecuteCommand(CurrentContext, command.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
//CogwheelConsole.LogWarning($"Command '{command.Value.Item1.Name}' is not static and no valid context was provided, searching for first registered context of type '{command.Value.Item1.Method.DeclaringType}'");
|
if (command.Value.Item1.Method.DeclaringType != null)
|
||||||
context = GetFirstValidRegisteredContext(command.Value.Item1.Method.DeclaringType);
|
|
||||||
if (context is null)
|
|
||||||
{
|
{
|
||||||
CogwheelConsole.LogError($"No context of type '{command.Value.Item1.Method.DeclaringType}' found");
|
context = GetFirstValidRegisteredContext(command.Value.Item1.Method.DeclaringType);
|
||||||
|
if (context is null)
|
||||||
|
{
|
||||||
|
CogwheelConsole.LogError($"No context of type '{command.Value.Item1.Method.DeclaringType}' found");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CogwheelConsole.LogError($"Command '{command.Value.Item1.Name}' has no declaring type");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,6 +143,11 @@ public class CommandsManager
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the usage information for the specified command.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="command">The command.</param>
|
||||||
|
/// <returns>The usage information for the command.</returns>
|
||||||
public virtual string GetCommandUsage(ICommand command)
|
public virtual string GetCommandUsage(ICommand command)
|
||||||
{
|
{
|
||||||
string output = "";
|
string output = "";
|
||||||
@ -99,18 +159,18 @@ public class CommandsManager
|
|||||||
{
|
{
|
||||||
output += "|Global| ";
|
output += "|Global| ";
|
||||||
}
|
}
|
||||||
|
|
||||||
output += $"{command.Name}: ";
|
output += $"{command.Name}: ";
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(command.Description))
|
if (!string.IsNullOrWhiteSpace(command.Description))
|
||||||
{
|
{
|
||||||
output += $"{command.Description} ";
|
output += $"{command.Description} ";
|
||||||
}
|
}
|
||||||
|
|
||||||
string paramUsage = string.Join(" ",
|
string paramUsage = string.Join(" ",
|
||||||
command.Method.GetParameters().Select(param =>
|
command.Method.GetParameters().Select(param =>
|
||||||
$"<{(param.IsDefined(typeof(ParamArrayAttribute)) ? "params " : "")}{param}>"));
|
$"<{(param.IsDefined(typeof(ParamArrayAttribute)) ? "params " : "")}{param}>"));
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(paramUsage))
|
if (!string.IsNullOrWhiteSpace(paramUsage))
|
||||||
{
|
{
|
||||||
output += $"- {paramUsage}";
|
output += $"- {paramUsage}";
|
||||||
@ -119,49 +179,26 @@ public class CommandsManager
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual bool ExecuteCommand(object obj, (ICommand command, List<object> args) command)
|
/// <summary>
|
||||||
|
/// Executes the specified command with the given arguments.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The object on which to execute the command.</param>
|
||||||
|
/// <param name="command">The command and arguments.</param>
|
||||||
|
/// <returns>True if the command was executed successfully, otherwise false.</returns>
|
||||||
|
public virtual bool ExecuteCommand(object? obj, (ICommand command, List<object> args) command)
|
||||||
{
|
{
|
||||||
var parameters = command.command.Method.GetParameters();
|
var parameters = command.command.Method.GetParameters();
|
||||||
for (var parameterIndex = 0; parameterIndex < parameters.Length; parameterIndex++)
|
for (var parameterIndex = 0; parameterIndex < parameters.Length; parameterIndex++)
|
||||||
|
{
|
||||||
|
if (parameters[parameterIndex].IsDefined(typeof(ParamArrayAttribute), false))
|
||||||
{
|
{
|
||||||
if (parameters[parameterIndex].IsDefined(typeof(ParamArrayAttribute), false))
|
var paramList = Activator.CreateInstance(typeof(List<>).MakeGenericType(parameters[parameterIndex].ParameterType.GetElementType()!));
|
||||||
|
for (var argIndex = parameterIndex; argIndex < parameters.Length; argIndex++)
|
||||||
{
|
{
|
||||||
var paramList = Activator.CreateInstance(typeof(List<>).MakeGenericType(parameters[parameterIndex].ParameterType.GetElementType()!));
|
if (TryParseParameter(parameters[parameterIndex].ParameterType.GetElementType(),
|
||||||
for (var argIndex = parameterIndex; argIndex < parameters.Length; argIndex++)
|
(string)command.args[argIndex], out var val))
|
||||||
{
|
{
|
||||||
if (TryParseParameter(parameters[parameterIndex].ParameterType.GetElementType(),
|
paramList.GetType().GetMethod("Add")?.Invoke(paramList, [val]);
|
||||||
(string)command.args[argIndex], out var val))
|
|
||||||
{
|
|
||||||
paramList.GetType().GetMethod("Add")?.Invoke(paramList, new[] { val });
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CogwheelConsole.LogError($"Format exception: could not parse '{command.args[parameterIndex]}' as '{parameters[parameterIndex].ParameterType}'");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
command.args = command.args.Take(parameterIndex).ToList();
|
|
||||||
command.args.Add(paramList.GetType().GetMethod("ToArray")?.Invoke(paramList, null));
|
|
||||||
}
|
|
||||||
else if (parameterIndex >= command.args.Count)
|
|
||||||
{
|
|
||||||
if (parameters[parameterIndex].IsOptional)
|
|
||||||
{
|
|
||||||
command.args.Add(Type.Missing);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CogwheelConsole.LogError("Not enough args passed");
|
|
||||||
CogwheelConsole.Log(GetCommandUsage(command.command));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (TryParseParameter(parameters[parameterIndex].ParameterType, (string)command.args[parameterIndex], out var val))
|
|
||||||
{
|
|
||||||
command.args[parameterIndex] = val;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -169,21 +206,56 @@ public class CommandsManager
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
try
|
command.args = command.args.Take(parameterIndex).ToList();
|
||||||
{
|
command.args.Add(paramList.GetType().GetMethod("ToArray")?.Invoke(paramList, null));
|
||||||
command.command.Method.Invoke(obj, command.args.ToArray());
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
else if (parameterIndex >= command.args.Count)
|
||||||
{
|
{
|
||||||
CogwheelConsole.LogError(e.Message);
|
if (parameters[parameterIndex].IsOptional)
|
||||||
throw;
|
{
|
||||||
|
command.args.Add(Type.Missing);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CogwheelConsole.LogError($"Not enough args passed. Usage: {GetCommandUsage(command.command)}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (TryParseParameter(parameters[parameterIndex].ParameterType, (string)command.args[parameterIndex], out var val))
|
||||||
|
{
|
||||||
|
command.args[parameterIndex] = val;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CogwheelConsole.LogError($"Format exception: could not parse '{command.args[parameterIndex]}' as '{parameters[parameterIndex].ParameterType}'");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
command.command.Method.Invoke(obj, command.args.ToArray());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
CogwheelConsole.LogError(e.Message);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual bool TryParseParameter(Type parameterType, string parameterString, out object parsedValue)
|
/// <summary>
|
||||||
|
/// Tries to parse the parameter string into the specified parameter type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="parameterType">The type of the parameter.</param>
|
||||||
|
/// <param name="parameterString">The parameter string.</param>
|
||||||
|
/// <param name="parsedValue">The parsed value.</param>
|
||||||
|
/// <returns>True if the parameter was parsed successfully, otherwise false.</returns>
|
||||||
|
public virtual bool TryParseParameter(Type parameterType, string parameterString, out object? parsedValue)
|
||||||
{
|
{
|
||||||
if (parameterType == typeof(string))
|
if (parameterType == typeof(string))
|
||||||
{
|
{
|
||||||
@ -224,21 +296,27 @@ public class CommandsManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
parsedValue = null;
|
parsedValue = null;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the command by its name.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="commandName">The name of the command.</param>
|
||||||
|
/// <returns>The command, or null if not found.</returns>
|
||||||
public virtual ICommand? GetCommandByName(string commandName)
|
public virtual ICommand? GetCommandByName(string commandName)
|
||||||
{
|
{
|
||||||
return Commands.GetValueOrDefault(commandName);
|
return Commands.GetValueOrDefault(commandName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Context related stuff
|
/// <summary>
|
||||||
|
/// Registers the specified object with the CommandsManager.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The object to register.</param>
|
||||||
public virtual void RegisterObject(object obj)
|
public virtual void RegisterObject(object obj)
|
||||||
{
|
{
|
||||||
// Use a combination of the object's type and a hash of its properties to generate a deterministic GUID
|
|
||||||
string seed = obj.GetType().FullName + GetObjectPropertiesHash(obj);
|
string seed = obj.GetType().FullName + GetObjectPropertiesHash(obj);
|
||||||
using (MD5 md5 = MD5.Create())
|
using (MD5 md5 = MD5.Create())
|
||||||
{
|
{
|
||||||
@ -257,7 +335,13 @@ public class CommandsManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the command context is valid.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="command">The command.</param>
|
||||||
|
/// <param name="context">The context object, if any.</param>
|
||||||
|
/// <returns>True if the context is valid, otherwise false.</returns>
|
||||||
public virtual bool IsCommandContextValid(ICommand command, object? context = null)
|
public virtual bool IsCommandContextValid(ICommand command, object? context = null)
|
||||||
{
|
{
|
||||||
if (context is not null)
|
if (context is not null)
|
||||||
@ -267,6 +351,11 @@ public class CommandsManager
|
|||||||
return command.Method.DeclaringType == CurrentContext?.GetType();
|
return command.Method.DeclaringType == CurrentContext?.GetType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the current context to the specified object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">The context object.</param>
|
||||||
|
/// <returns>True if the context was set successfully, otherwise false.</returns>
|
||||||
public virtual bool SetContext(object context)
|
public virtual bool SetContext(object context)
|
||||||
{
|
{
|
||||||
CurrentContext = context;
|
CurrentContext = context;
|
||||||
@ -279,6 +368,11 @@ public class CommandsManager
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the current context to the object with the specified GUID.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="guid">The GUID of the context object.</param>
|
||||||
|
/// <returns>True if the context was set successfully, otherwise false.</returns>
|
||||||
public virtual bool SetContext(Guid guid)
|
public virtual bool SetContext(Guid guid)
|
||||||
{
|
{
|
||||||
if (RegisteredObjectInstances.ContainsKey(guid))
|
if (RegisteredObjectInstances.ContainsKey(guid))
|
||||||
@ -295,6 +389,11 @@ public class CommandsManager
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the current context to the object with the specified GUID string.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="guidString">The GUID string of the context object.</param>
|
||||||
|
/// <returns>True if the context was set successfully, otherwise false.</returns>
|
||||||
public virtual bool SetContext(string guidString)
|
public virtual bool SetContext(string guidString)
|
||||||
{
|
{
|
||||||
if (Guid.TryParse(guidString, out var guid))
|
if (Guid.TryParse(guidString, out var guid))
|
||||||
@ -306,21 +405,96 @@ public class CommandsManager
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the first valid registered context of the specified type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">The type of the context.</param>
|
||||||
|
/// <returns>The first valid registered context, or null if not found.</returns>
|
||||||
public virtual object? GetFirstValidRegisteredContext(Type type)
|
public virtual object? GetFirstValidRegisteredContext(Type type)
|
||||||
{
|
{
|
||||||
return RegisteredObjectInstances.Values.FirstOrDefault(obj => obj.GetType() == type);
|
return RegisteredObjectInstances.Values.FirstOrDefault(obj => obj.GetType() == type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the GUID of the specified context object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">The context object, if any.</param>
|
||||||
|
/// <returns>The GUID of the context object.</returns>
|
||||||
public virtual Guid GetGuidFromContext(object? context = null)
|
public virtual Guid GetGuidFromContext(object? context = null)
|
||||||
{
|
{
|
||||||
if (context is not null)
|
if (context is not null)
|
||||||
{
|
{
|
||||||
return RegisteredObjectGuids[context];
|
return RegisteredObjectGuids[context];
|
||||||
}
|
}
|
||||||
|
|
||||||
return CurrentContextGuid ?? Guid.Empty;
|
return CurrentContextGuid ?? Guid.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds the specified assembly to the list of assemblies used to search for commands.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="assembly"></param>
|
||||||
|
public void AddAssembly(Assembly assembly)
|
||||||
|
{
|
||||||
|
if (!Assemblies.Contains(assembly))
|
||||||
|
{
|
||||||
|
Assemblies.Add(assembly);
|
||||||
|
RefreshCommandsList();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CogwheelConsole.LogWarning($"Tried to add {assembly.FullName} but it is already registered.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes the specified assembly from the list of assemblies used to search for commands.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="assembly"></param>
|
||||||
|
public void RemoveAssembly(Assembly assembly)
|
||||||
|
{
|
||||||
|
if (Assemblies.Contains(assembly))
|
||||||
|
{
|
||||||
|
Assemblies.Remove(assembly);
|
||||||
|
RefreshCommandsList();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CogwheelConsole.LogWarning($"Tried to remove {assembly.FullName} but it is not registered.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clears the list of assemblies used to search for commands.
|
||||||
|
/// </summary>
|
||||||
|
public void ClearAssemblies()
|
||||||
|
{
|
||||||
|
Assemblies.Clear();
|
||||||
|
RefreshCommandsList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a custom parser for the specified type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type"></param>
|
||||||
|
/// <param name="parser"></param>
|
||||||
|
public void AddCustomParser(Type type, Func<string, object> parser)
|
||||||
|
{
|
||||||
|
if (!CustomParsers.ContainsKey(type))
|
||||||
|
{
|
||||||
|
CustomParsers[type] = parser;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CogwheelConsole.LogWarning($"Tried to add a custom parser for {type.FullName} but it is already registered.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the hash of the properties of the specified object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The object.</param>
|
||||||
|
/// <returns>The hash of the object's properties.</returns>
|
||||||
protected virtual string GetObjectPropertiesHash(object obj)
|
protected virtual string GetObjectPropertiesHash(object obj)
|
||||||
{
|
{
|
||||||
var properties = obj.GetType().GetProperties();
|
var properties = obj.GetType().GetProperties();
|
||||||
@ -335,21 +509,27 @@ public class CommandsManager
|
|||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Refreshes the list of commands by scanning the assemblies.
|
||||||
|
/// </summary>
|
||||||
protected virtual void RefreshCommandsList()
|
protected virtual void RefreshCommandsList()
|
||||||
{
|
{
|
||||||
foreach (var type in Assembly.GetCallingAssembly().GetTypes())
|
foreach (var assembly in Assemblies)
|
||||||
{
|
{
|
||||||
var methods = type.GetMethods(BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Public | BindingFlags.Instance);
|
foreach (var type in assembly.GetTypes())
|
||||||
|
|
||||||
foreach (var method in methods)
|
|
||||||
{
|
{
|
||||||
var attributes = method.GetCustomAttributes<CommandAttribute>();
|
var methods = type.GetMethods(BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Public | BindingFlags.Instance);
|
||||||
|
|
||||||
foreach (var attribute in attributes)
|
foreach (var method in methods)
|
||||||
{
|
{
|
||||||
var commandName = attribute.Name ?? method.Name;
|
var attributes = method.GetCustomAttributes<CommandAttribute>();
|
||||||
var newCommand = new Command(commandName, attribute.Description, method);
|
|
||||||
Commands.TryAdd(newCommand.Name, newCommand);
|
foreach (var attribute in attributes)
|
||||||
|
{
|
||||||
|
var commandName = attribute.Name ?? method.Name;
|
||||||
|
var newCommand = new Command(commandName, attribute.Description, method);
|
||||||
|
Commands.TryAdd(newCommand.Name, newCommand);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
105
src/DeafultCogwheelConsole.cs
Normal file
105
src/DeafultCogwheelConsole.cs
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
namespace Cogwheel;
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Default implementation of the Cogwheel console.
|
||||||
|
/// </summary>
|
||||||
|
public class DeafultCogwheelConsole : ICogwheelConsole
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the opening message of the console.
|
||||||
|
/// </summary>
|
||||||
|
public string OpeningMessage { get; set; } = "** COGWHEEL CONSOLE **";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether the console is running.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsRunning { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the commands manager associated with the console.
|
||||||
|
/// </summary>
|
||||||
|
public CommandsManager CommandsManager { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes the console with the specified commands manager.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="commandsManager">The commands manager to use.</param>
|
||||||
|
public void Initialize(CommandsManager commandsManager)
|
||||||
|
{
|
||||||
|
CommandsManager = commandsManager;
|
||||||
|
CommandsManager.RegisterObject(this);
|
||||||
|
|
||||||
|
Write(OpeningMessage);
|
||||||
|
|
||||||
|
IsRunning = true;
|
||||||
|
while (IsRunning)
|
||||||
|
{
|
||||||
|
if (CommandsManager.CurrentContext != null)
|
||||||
|
{
|
||||||
|
Console.Write($"({CommandsManager.CurrentContext.GetType().FullName})> ");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.Write("(Global)> ");
|
||||||
|
}
|
||||||
|
string input = Console.ReadLine();
|
||||||
|
Console.WriteLine();
|
||||||
|
CommandsManager.RunCommand(input);
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Logs a message to the console.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to log.</param>
|
||||||
|
public void Log(string message)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"[COGWHEEL] {message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Logs an error message to the console.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message to log.</param>
|
||||||
|
public void LogError(string message)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"[COGWHEEL ERROR] {message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Logs a warning message to the console.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The warning message to log.</param>
|
||||||
|
public void LogWarning(string message)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"[COGWHEEL WARNING] {message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a message to the console.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to write.</param>
|
||||||
|
public void Write(string message)
|
||||||
|
{
|
||||||
|
Console.WriteLine(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clears the console.
|
||||||
|
/// </summary>
|
||||||
|
public void ClearConsole()
|
||||||
|
{
|
||||||
|
Console.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Exits the console.
|
||||||
|
/// </summary>
|
||||||
|
public void Exit()
|
||||||
|
{
|
||||||
|
IsRunning = false;
|
||||||
|
}
|
||||||
|
}
|
@ -1,20 +0,0 @@
|
|||||||
namespace Cogwheel;
|
|
||||||
|
|
||||||
public class TestClass
|
|
||||||
{
|
|
||||||
|
|
||||||
public string Name { get; set; } = "Test";
|
|
||||||
|
|
||||||
public TestClass(string name)
|
|
||||||
{
|
|
||||||
Name = name;
|
|
||||||
|
|
||||||
COGWHEEL.RegisterObject(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Command(Name = "getname", Description = "Prints the name of the TestClass instance.")]
|
|
||||||
private void GetName()
|
|
||||||
{
|
|
||||||
COGWHEEL.Log($"My name is {Name}");
|
|
||||||
}
|
|
||||||
}
|
|
52
src/changelog.md
Normal file
52
src/changelog.md
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [1.3.0] - 2025-01-03
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Added more public CommandsManager access methods to the COGWHEEL static class
|
||||||
|
- Ability to add custom parsers to the CommandManager with AddCustomerParser(Type, Func<string, object>)
|
||||||
|
- Added two custom parsers from the COGWHEEL class: `System.Numerics.Vector2` and `System.Numerics.Vector3`
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
## [1.2.0] - 2025-01-02
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Ability to add assemblies to the CommandManager
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
|
||||||
|
## [1.1.0] - 2025-01-02
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
|
||||||
|
## [1.0.0] - 2025-01-02
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
### Removed
|
@ -1,17 +1,62 @@
|
|||||||
namespace Cogwheel;
|
namespace Cogwheel;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Interface for the Cogwheel console.
|
||||||
|
/// </summary>
|
||||||
public interface ICogwheelConsole
|
public interface ICogwheelConsole
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the opening message of the console.
|
||||||
|
/// </summary>
|
||||||
public string OpeningMessage { get; set; }
|
public string OpeningMessage { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether the console is running.
|
||||||
|
/// </summary>
|
||||||
public bool IsRunning { get; set; }
|
public bool IsRunning { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the commands manager associated with the console.
|
||||||
|
/// </summary>
|
||||||
public CommandsManager CommandsManager { get; set; }
|
public CommandsManager CommandsManager { get; set; }
|
||||||
|
|
||||||
public void Initialize(CommandsManager commandsManager); // Make sure to pass the CommandsManager instance to the Console
|
/// <summary>
|
||||||
|
/// Initializes the console with the specified commands manager.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="commandsManager">The commands manager to use.</param>
|
||||||
|
public void Initialize(CommandsManager commandsManager);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Logs a message to the console.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to log.</param>
|
||||||
public void Log(string message);
|
public void Log(string message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Logs an error message to the console.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message to log.</param>
|
||||||
public void LogError(string message);
|
public void LogError(string message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Logs a warning message to the console.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The warning message to log.</param>
|
||||||
public void LogWarning(string message);
|
public void LogWarning(string message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a message to the console.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to write.</param>
|
||||||
public void Write(string message);
|
public void Write(string message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clears the console.
|
||||||
|
/// </summary>
|
||||||
public void ClearConsole();
|
public void ClearConsole();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Exits the console.
|
||||||
|
/// </summary>
|
||||||
public void Exit();
|
public void Exit();
|
||||||
|
|
||||||
}
|
}
|
@ -2,9 +2,23 @@ using System.Reflection;
|
|||||||
|
|
||||||
namespace Cogwheel;
|
namespace Cogwheel;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a command in the Cogwheel system.
|
||||||
|
/// </summary>
|
||||||
public interface ICommand
|
public interface ICommand
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name of the command.
|
||||||
|
/// </summary>
|
||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the description of the command.
|
||||||
|
/// </summary>
|
||||||
public string Description { get; }
|
public string Description { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the method associated with the command.
|
||||||
|
/// </summary>
|
||||||
public MethodBase Method { get; }
|
public MethodBase Method { get; }
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user