using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using Cysharp.Threading.Tasks; using RebootKit.Engine.Foundation; using RebootKit.Engine.Services.Input; using UnityEngine.InputSystem; using Logger = RebootKit.Engine.Foundation.Logger; namespace RebootKit.Engine.Services.Console { public interface IConsoleCommand { string Name { get; } string Description { get; } void Execute(string[] args); } 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 ConsoleService : IService { private static readonly Logger _logger = new(nameof(ConsoleService)); [Serializable] public class Config { public ConsoleUI ConsoleUIPrefab; public ScriptableInputAction ToggleAction; } private ConsoleUI _ui; private Config _config; private List _commands = new(); private List _cvars = new(); public bool IsVisible => _ui.IsVisible; public ConsoleService(Config config) { _config = config; } public async UniTask OnInit(CancellationToken cancellationToken) { _logger.Info("Waking up"); _ui = UnityEngine.Object.Instantiate(_config.ConsoleUIPrefab); UnityEngine.Object.DontDestroyOnLoad(_ui.gameObject); await UniTask.Yield(cancellationToken); _config.ToggleAction.Action.Enable(); _config.ToggleAction.Action.performed += OnToggleAction; RegisterCommand(new HelpCommand()); _ui.SetVisibility(false); _ui.Clear(); _ui.Write("Hello shelf\n"); } public void Dispose() { if (_ui != null) { UnityEngine.Object.Destroy(_ui); _ui = null; } _config.ToggleAction.Action.performed -= OnToggleAction; } public bool CVarExists(string name) { foreach (CVar cvar in _cvars) { if (cvar.Name.Equals(name)) { return true; } } return false; } public CVar GetCVar(string name) { foreach (CVar cvar in _cvars) { if (cvar.Name.Equals(name)) { return cvar; } } return null; } public CVar ReplaceOrDefault(CVar cvar) { CVar foundCVar = GetCVar(cvar.Name); if (foundCVar != null) { return foundCVar; } _cvars.Add(cvar); return cvar; } public void Replace(CVar cvar) { CVar foundCVar = GetCVar(cvar.Name); if (foundCVar != null) { _cvars.Remove(foundCVar); } _cvars.Add(cvar); } private string[] ParseCommandInputArguments(string text) { if (text.Length == 0) { return Array.Empty(); } return new string[] {text}; } 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 = ParseCommandInputArguments(input.Substring(commandName.Length)); foreach (IConsoleCommand command in _commands) { if (command.Name.Equals(commandName)) { command.Execute(arguments); return; } } foreach (CVar cvar in _cvars) { if (cvar.Name.Equals(commandName)) { if (arguments.Length == 1) { cvar.ParseFromString(arguments[0]); } _ui.Write($"{cvar.Name} - {cvar.ToString()}\n"); return; } } _ui.Write($"ERROR: Command/CVar `{commandName}` not found."); } public void ToggleVisibility() { _ui.SetVisibility(!_ui.IsVisible); if (_ui.IsVisible) { // RR.Input().DisableControls(); } else { RR.Input().EnableControls(); } } public void RegisterCommand(IConsoleCommand command) { if (_commands.Any(t => t.Name.Equals(command.Name))) { _logger.Error($"`{command.Name}` command is already registered"); return; } _commands.Add(command); _logger.Info($"Registered command: {command.Name}"); } public void PrintHelp() { StringBuilder message = new(); message.AppendLine("Available commands:"); foreach (IConsoleCommand command in _commands) { message.Append(" "); message.Append(command.Name); message.Append(" - "); message.Append(command.Description); message.AppendLine(); } message.AppendLine("Available cvars:"); foreach (CVar cvar in _cvars) { message.Append(" "); message.Append(cvar.Name); message.Append(" - "); message.Append(cvar.Description); message.AppendLine(); } _ui.Write(message.ToString()); } private void OnToggleAction(InputAction.CallbackContext obj) { ToggleVisibility(); } } }