This commit is contained in:
2025-05-14 10:52:53 +02:00
parent 1e190fe94b
commit f0536f4129
51 changed files with 934 additions and 381 deletions

View File

@@ -2,40 +2,35 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using RebootKit.Engine.Foundation;
using RebootKit.Engine.Main;
using UnityEngine;
using Logger = RebootKit.Engine.Foundation.Logger;
namespace RebootKit.Engine.Services.Console {
public interface IConsoleCommand {
string Name { get; }
string Description { get; }
void Execute(string[] args);
}
[AttributeUsage(AttributeTargets.Method)]
public class RCCMD : Attribute {
public string name;
public string description;
public class HelpCommand : IConsoleCommand {
public string Name { get; } = "help";
public string Description { get; } = "Prints available commands/cvars and their descriptions.";
public void Execute(string[] args) {
RR.Console.PrintHelp();
}
}
public class PrintCVarsCommand : IConsoleCommand {
public string Name { get; } = "print_cvars";
public string Description { get; } = "Prints all cvars and their values.";
public void Execute(string[] args) {
RR.Console.PrintCVars();
public RCCMD(string name, string description) {
this.name = name;
this.description = description;
}
}
public class ConsoleService : IService {
static readonly Logger s_logger = new(nameof(ConsoleService));
readonly List<IConsoleCommand> m_ConsoleCommands = new();
public struct ConsoleCommand {
public string name;
public string description;
public Action<string[]> action;
}
readonly List<ConsoleCommand> m_ConsoleCommands = new();
FileStream m_LogFileStream;
TextWriter m_LogFileWriter;
@@ -60,8 +55,7 @@ namespace RebootKit.Engine.Services.Console {
Load();
RegisterCommand(new PrintCVarsCommand());
RegisterCommand(new HelpCommand());
RegisterCommands();
}
public void Dispose() {
@@ -97,37 +91,34 @@ namespace RebootKit.Engine.Services.Console {
OnOutputMessage?.Invoke(message);
}
string[] ParseCommandInputArguments(string text) {
if (text.Length == 0) {
return Array.Empty<string>();
}
return new[] {text};
string[] ParseCommandInput(string text) {
return text.Split(' ');
}
// @NOTE: Input must be in format: "command arg1 arg2 arg3", one command = one call
public void Execute(string input) {
if (input.Length == 0) {
return;
}
string commandName = input;
if (input.IndexOf(' ') != -1) {
commandName = input.Substring(0, input.IndexOf(' '));
string[] arguments = ParseCommandInput(input);
if (arguments.Length == 0) {
return;
}
string[] arguments = ParseCommandInputArguments(input.Substring(commandName.Length));
string commandName = arguments[0];
foreach (IConsoleCommand command in m_ConsoleCommands) {
if (command.Name.Equals(commandName)) {
command.Execute(arguments);
foreach (ConsoleCommand command in m_ConsoleCommands) {
if (command.name.Equals(commandName)) {
command.action(arguments);
return;
}
}
foreach (ConfigVar cvar in ConfigVarsContainer.All()) {
if (cvar.name.Equals(commandName)) {
if (arguments.Length == 1) {
cvar.ParseFromString(arguments[0]);
if (arguments.Length == 2) {
cvar.ParseFromString(arguments[1]);
}
WriteToOutput($"<b>{cvar.name}</b> - {cvar}\n");
@@ -138,25 +129,84 @@ namespace RebootKit.Engine.Services.Console {
WriteToOutput($"ERROR: Command/CVar `{commandName}` not found.");
}
public void RegisterCommand(IConsoleCommand command) {
if (m_ConsoleCommands.Any(t => t.Name.Equals(command.Name))) {
s_logger.Error($"`{command.Name}` command is already registered");
public void RegisterCommand(string name, string description, Action<string[]> action) {
if (IsCommandRegistered(name)) {
s_logger.Error($"`{name}` command is already registered");
return;
}
m_ConsoleCommands.Add(command);
s_logger.Info($"Registered command: {command.Name}");
m_ConsoleCommands.Add(new ConsoleCommand {
name = name,
description = description,
action = action
});
s_logger.Info($"Registered command: {name}");
}
public void PrintHelp() {
public static ConsoleCommand[] GenerateCommandsToRegister() {
IEnumerable<MethodInfo> methods = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(assembly => assembly.GetTypes())
.SelectMany(type => type.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static))
.Where(method => method.GetCustomAttributes(typeof(RCCMD), false).Length > 0);
List<ConsoleCommand> commands = new();
foreach (MethodInfo method in methods) {
RCCMD attribute = (RCCMD)method.GetCustomAttributes(typeof(RCCMD), false)[0];
if (!method.IsStatic) {
s_logger.Error($"Command `{attribute.name}` is not static, skipping");
continue;
}
if (method.GetParameters().Length != 1) {
s_logger.Error($"Command `{attribute.name}` has invalid number of parameters, skipping");
continue;
}
if (method.GetParameters()[0].ParameterType != typeof(string[])) {
s_logger.Error($"Command `{attribute.name}` has invalid parameter type, skipping");
continue;
}
Action<string[]> action = (Action<string[]>)Delegate.CreateDelegate(typeof(Action<string[]>), method);
commands.Add(new ConsoleCommand {
name = attribute.name,
description = attribute.description,
action = action
});
}
return commands.ToArray();
}
public void RegisterCommands() {
ConsoleCommand[] commands = GenerateCommandsToRegister();
foreach (ConsoleCommand command in commands) {
RegisterCommand(command.name, command.description, command.action);
}
}
bool IsCommandRegistered(string name) {
foreach (ConsoleCommand command in m_ConsoleCommands) {
if (command.name.Equals(name)) {
return true;
}
}
return false;
}
[RCCMD("help", "Prints help message with all commands and cvars")]
public static void PrintHelpCommand(string[] args) {
StringBuilder message = new();
message.AppendLine("Available commands:");
foreach (IConsoleCommand command in m_ConsoleCommands) {
foreach (ConsoleCommand command in RR.Console.m_ConsoleCommands) {
message.Append(" ");
message.Append(command.Name);
message.Append(command.name);
message.Append(" - ");
message.Append(command.Description);
message.Append(command.description);
message.AppendLine();
}
@@ -169,17 +219,18 @@ namespace RebootKit.Engine.Services.Console {
message.AppendLine();
}
WriteToOutput(message.ToString());
RR.Console.WriteToOutput(message.ToString());
}
public void PrintCVars() {
[RCCMD("cvars", "Prints all cvars")]
public static void PrintCVars(string[] args) {
StringBuilder message = new();
foreach (ConfigVar cvar in ConfigVarsContainer.All()) {
message.AppendLine($"{cvar.name} - {cvar}");
}
WriteToOutput(message.ToString());
RR.Console.WriteToOutput(message.ToString());
}
void Save() {