Files
scaryposadzka/Assets/SzafaKit/Runtime/Console/ScriptableConsoleService.cs
2025-03-02 02:25:06 +01:00

200 lines
5.8 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Cysharp.Threading.Tasks;
using SzafaKit.Foundation;
using SzafaKit.Input;
using UnityEngine;
using UnityEngine.InputSystem;
using Object = UnityEngine.Object;
namespace SzafaKit.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) {
SzafaEngine.Shared.GetService<ConsoleService>().PrintHelp();
}
}
public class ConsoleService : IEngineService {
private struct Command {
public string Name;
public string Description;
public IConsoleCommand Executor;
}
[Serializable]
public class Config {
public ConsoleUI ConsoleUIPrefab;
public ScriptableInputAction ToggleAction;
}
private ConsoleUI _ui;
private Config _config;
private List<IConsoleCommand> _commands = new();
private List<CVar> _cvars = new();
public bool IsVisible => _ui.IsVisible;
public ConsoleService(Config config) {
_config = config;
}
public async UniTask OnStart(CancellationToken cancellationToken) {
_ui = Object.Instantiate(_config.ConsoleUIPrefab);
await UniTask.Yield();
_config.ToggleAction.Action.Enable();
_config.ToggleAction.Action.performed += OnToggleAction;
RegisterCommand(new HelpCommand());
_ui.SetVisibility(false);
_ui.Clear();
_ui.Write("Hello shelf\n");
}
public void OnStop() {
_config.ToggleAction.Action.performed -= OnToggleAction;
}
public CVar GetCVar(string name) {
foreach (CVar cvar in _cvars) {
if (cvar.Name.Equals(name)) {
return cvar;
}
}
return null;
}
public CVar CreateCVar(string name, string description = "") {
CVar cvar = GetCVar(name);
if (cvar != null) {
return cvar;
}
Debug.Log($"Creating new cvar: {name}");
cvar = new(name, description);
_cvars.Add(cvar);
return cvar;
}
private string[] ParseCommandInputArguments(string text) {
if (text.Length == 0) {
return Array.Empty<string>();
}
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($"<b>{cvar.Name}</b> - {cvar.ToString()}\n");
return;
}
}
_ui.Write($"ERROR: Command/CVar `{commandName}` not found.");
}
public void ToggleVisibility() {
_ui.SetVisibility(!_ui.IsVisible);
if (_ui.IsVisible) {
SzafaEngine.Shared.GetService<InputService>().DisableControls();
} else {
SzafaEngine.Shared.GetService<InputService>().EnableControls();
}
}
public void RegisterCommand(IConsoleCommand command) {
if (_commands.Any(t => t.Name.Equals(command.Name))) {
Debug.LogError($"`{command.Name}` command is already registered");
return;
}
_commands.Add(command);
}
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());
}
public void Dispose() {
if (_ui != null) {
Object.Destroy(_ui);
_ui = null;
}
}
private void OnToggleAction(InputAction.CallbackContext obj) {
ToggleVisibility();
}
}
[CreateAssetMenu(menuName = SzafaConsts.AssetMenu + "Services/Console Service")]
public class ScriptableConsoleService : ScriptableEngineService {
[SerializeField]
private ConsoleService.Config _config;
public override IEngineService Create() {
return new ConsoleService(_config);
}
}
}