refactor
This commit is contained in:
@@ -1,159 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace RebootKit.Engine.Services.Console {
|
||||
public enum CVarValueKind {
|
||||
Number, String
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public struct CVarValue {
|
||||
public CVarValueKind kind;
|
||||
|
||||
public double numberValue;
|
||||
public string stringValue;
|
||||
|
||||
public CVarValue(int value) {
|
||||
kind = CVarValueKind.Number;
|
||||
numberValue = value;
|
||||
stringValue = null;
|
||||
}
|
||||
|
||||
public CVarValue(float value) {
|
||||
kind = CVarValueKind.Number;
|
||||
numberValue = value;
|
||||
stringValue = null;
|
||||
}
|
||||
|
||||
public CVarValue(double value) {
|
||||
kind = CVarValueKind.Number;
|
||||
numberValue = value;
|
||||
stringValue = null;
|
||||
}
|
||||
|
||||
public CVarValue(string value) {
|
||||
kind = CVarValueKind.String;
|
||||
numberValue = 0;
|
||||
stringValue = value;
|
||||
}
|
||||
|
||||
public void CopyFrom(CVarValue value) {
|
||||
kind = value.kind;
|
||||
numberValue = value.numberValue;
|
||||
stringValue = value.stringValue;
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return kind switch {
|
||||
CVarValueKind.Number => numberValue.ToString(),
|
||||
CVarValueKind.String => $"\"{stringValue}\"",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum CVarFlags {
|
||||
None, Persistent, ReadOnly
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class CVar {
|
||||
public CVarFlags flags;
|
||||
public string name;
|
||||
public string description;
|
||||
public CVarValue defaultValue;
|
||||
|
||||
public CVar(CVar other) {
|
||||
flags = other.flags;
|
||||
name = other.name;
|
||||
description = other.description;
|
||||
defaultValue = other.defaultValue;
|
||||
Value = other.Value;
|
||||
}
|
||||
|
||||
public CVar(string name, CVarValue value, string description = "") {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
defaultValue = value;
|
||||
Value = defaultValue;
|
||||
}
|
||||
|
||||
public CVar(string name, int value, string description = "") {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
defaultValue = new CVarValue(value);
|
||||
Value = defaultValue;
|
||||
}
|
||||
|
||||
public CVar(string name, float value, string description = "") {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
defaultValue = new CVarValue(value);
|
||||
Value = defaultValue;
|
||||
}
|
||||
|
||||
public CVar(string name, double value, string description = "") {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
defaultValue = new CVarValue(value);
|
||||
Value = defaultValue;
|
||||
}
|
||||
|
||||
public CVar(string name, string value, string description = "") {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
defaultValue = new CVarValue(value);
|
||||
Value = defaultValue;
|
||||
}
|
||||
|
||||
public CVarValue Value { get; private set; }
|
||||
|
||||
public int IndexValue => (int) Value.numberValue;
|
||||
public float FloatValue => (float) Value.numberValue;
|
||||
public double NumberValue => Value.numberValue;
|
||||
public string StringValue => Value.stringValue;
|
||||
|
||||
public event Action StateChanged = delegate { };
|
||||
|
||||
public void Set(int value) {
|
||||
if (flags.HasFlag(CVarFlags.ReadOnly)) return;
|
||||
|
||||
Value = new CVarValue(value);
|
||||
StateChanged?.Invoke();
|
||||
}
|
||||
|
||||
public void Set(float value) {
|
||||
if (flags.HasFlag(CVarFlags.ReadOnly)) return;
|
||||
|
||||
Value = new CVarValue(value);
|
||||
StateChanged?.Invoke();
|
||||
}
|
||||
|
||||
public void Set(string value) {
|
||||
if (flags.HasFlag(CVarFlags.ReadOnly)) return;
|
||||
|
||||
Value = new CVarValue(value);
|
||||
StateChanged?.Invoke();
|
||||
}
|
||||
|
||||
public void ParseFromString(string str) {
|
||||
if (flags.HasFlag(CVarFlags.ReadOnly)) return;
|
||||
|
||||
if (float.TryParse(str, out float f))
|
||||
Set(f);
|
||||
else
|
||||
Set(str);
|
||||
}
|
||||
|
||||
public void Reset() {
|
||||
if (flags.HasFlag(CVarFlags.ReadOnly)) return;
|
||||
|
||||
Value = defaultValue;
|
||||
StateChanged?.Invoke();
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return Value.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0f560b25a893456c90fac62ad278c02b
|
||||
timeCreated: 1740779755
|
||||
@@ -1,16 +0,0 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace RebootKit.Engine.Services.Console {
|
||||
[CreateAssetMenu(menuName = RConsts.k_AddComponentMenu + "cvar", fileName = "cvar")]
|
||||
public class CVarAsset : ScriptableObject {
|
||||
[SerializeField] CVar m_CVar;
|
||||
|
||||
public CVar Create(string cvarName = null) {
|
||||
CVar cvar = new(m_CVar);
|
||||
|
||||
if (cvarName != null) cvar.name = cvarName;
|
||||
|
||||
return cvar;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 443a66c3a441450d96d222872a567df0
|
||||
timeCreated: 1741639598
|
||||
@@ -1,57 +0,0 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using RebootKit.Engine.Foundation;
|
||||
|
||||
namespace RebootKit.Engine.Services.Console {
|
||||
[AttributeUsage(AttributeTargets.Field)]
|
||||
public class CVarAttribute : Attribute {
|
||||
public CVarAttribute(string name, float defaultValue) {
|
||||
Name = name;
|
||||
Value = new CVarValue(defaultValue);
|
||||
}
|
||||
|
||||
public CVarAttribute(string name, double defaultValue) {
|
||||
Name = name;
|
||||
Value = new CVarValue(defaultValue);
|
||||
}
|
||||
|
||||
public CVarAttribute(string name, string defaultValue) {
|
||||
Name = name;
|
||||
Value = new CVarValue(defaultValue);
|
||||
}
|
||||
|
||||
public CVarAttribute(string name, int defaultValue) {
|
||||
Name = name;
|
||||
Value = new CVarValue(defaultValue);
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
public CVarValue Value { get; }
|
||||
}
|
||||
|
||||
public class CVarFieldInjector : DIContext.IFieldInjector {
|
||||
static readonly Logger s_logger = new(nameof(CVarFieldInjector));
|
||||
|
||||
public bool Inject(FieldInfo field, object target, DIContext context) {
|
||||
if (!Attribute.IsDefined(field, typeof(CVarAttribute))) return false;
|
||||
|
||||
ConsoleService console = context.Resolve<ConsoleService>();
|
||||
if (console == null) {
|
||||
s_logger.Error($"Cannot inject field because cannot resolve `{nameof(ConsoleService)}`");
|
||||
return false;
|
||||
}
|
||||
|
||||
CVarAttribute cvarAttribute = field.GetCustomAttribute<CVarAttribute>();
|
||||
CVar cvar = console.GetCVar(cvarAttribute.Name);
|
||||
|
||||
if (cvar == null) {
|
||||
cvar = new CVar(cvarAttribute.Name, cvarAttribute.Value);
|
||||
console.Replace(cvar);
|
||||
}
|
||||
|
||||
field.SetValue(target, cvar);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1ce6213dda8c4f8d9eafe4afd1614a86
|
||||
timeCreated: 1742005021
|
||||
@@ -1,8 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using RebootKit.Engine.Foundation;
|
||||
using UnityEngine;
|
||||
using Logger = RebootKit.Engine.Foundation.Logger;
|
||||
|
||||
namespace RebootKit.Engine.Services.Console {
|
||||
@@ -21,104 +23,136 @@ namespace RebootKit.Engine.Services.Console {
|
||||
}
|
||||
}
|
||||
|
||||
public class ConsoleService : IService {
|
||||
static readonly Logger _logger = new(nameof(ConsoleService));
|
||||
public class PrintCVarsCommand : IConsoleCommand {
|
||||
public string Name { get; } = "print_cvars";
|
||||
public string Description { get; } = "Prints all cvars and their values.";
|
||||
|
||||
readonly List<IConsoleCommand> _commands = new();
|
||||
readonly List<CVar> _cvars = new();
|
||||
public void Execute(string[] args) {
|
||||
RR.Console.PrintCVars();
|
||||
}
|
||||
}
|
||||
|
||||
public class ConsoleService : IService {
|
||||
static readonly Logger s_logger = new(nameof(ConsoleService));
|
||||
|
||||
readonly List<IConsoleCommand> m_ConsoleCommands = new();
|
||||
|
||||
FileStream m_LogFileStream;
|
||||
TextWriter m_LogFileWriter;
|
||||
|
||||
bool m_IsLoading;
|
||||
|
||||
public ConsoleService() {
|
||||
_logger.Info("Waking up");
|
||||
ConfigVar.StateChanged += OnCVarStateChanged;
|
||||
|
||||
m_LogFileStream = new FileStream(Application.persistentDataPath + "/rr_logs.txt", FileMode.Append, FileAccess.Write);
|
||||
m_LogFileWriter = new StreamWriter(m_LogFileStream);
|
||||
|
||||
m_LogFileWriter.WriteLine("============================");
|
||||
m_LogFileWriter.WriteLine("Starting new log");
|
||||
m_LogFileWriter.WriteLine($" > Game: {Application.productName}");
|
||||
m_LogFileWriter.WriteLine($" > Version: {Application.version}");
|
||||
m_LogFileWriter.WriteLine($" > Date: {DateTime.Now}");
|
||||
m_LogFileWriter.WriteLine("============================");
|
||||
m_LogFileWriter.Flush();
|
||||
|
||||
s_logger.Info("Waking up");
|
||||
|
||||
Load();
|
||||
|
||||
RegisterCommand(new PrintCVarsCommand());
|
||||
RegisterCommand(new HelpCommand());
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
s_logger.Info("Shutting down");
|
||||
|
||||
ConfigVar.StateChanged -= OnCVarStateChanged;
|
||||
|
||||
m_LogFileWriter.Dispose();
|
||||
m_LogFileStream.Dispose();
|
||||
|
||||
m_LogFileStream = null;
|
||||
m_LogFileWriter = null;
|
||||
}
|
||||
|
||||
void OnCVarStateChanged(ConfigVar cvar) {
|
||||
if (m_IsLoading) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!cvar.flags.HasFlag(CVarFlags.ReadOnly)) {
|
||||
Save();
|
||||
}
|
||||
}
|
||||
|
||||
public event Action<string> OnOutputMessage = _ => { };
|
||||
|
||||
public void WriteToOutput(string message) {
|
||||
if (m_LogFileWriter != null) {
|
||||
m_LogFileWriter.WriteLine(message);
|
||||
m_LogFileWriter.Flush();
|
||||
}
|
||||
|
||||
OnOutputMessage?.Invoke(message);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
string[] ParseCommandInputArguments(string text) {
|
||||
if (text.Length == 0) return Array.Empty<string>();
|
||||
if (text.Length == 0) {
|
||||
return Array.Empty<string>();
|
||||
}
|
||||
|
||||
return new[] {text};
|
||||
}
|
||||
|
||||
public void Execute(string input) {
|
||||
if (input.Length == 0) return;
|
||||
if (input.Length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
string commandName = input;
|
||||
if (input.IndexOf(' ') != -1) commandName = input.Substring(0, input.IndexOf(' '));
|
||||
if (input.IndexOf(' ') != -1) {
|
||||
commandName = input.Substring(0, input.IndexOf(' '));
|
||||
}
|
||||
|
||||
string[] arguments = ParseCommandInputArguments(input.Substring(commandName.Length));
|
||||
|
||||
foreach (IConsoleCommand command in _commands)
|
||||
foreach (IConsoleCommand command in m_ConsoleCommands) {
|
||||
if (command.Name.Equals(commandName)) {
|
||||
command.Execute(arguments);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (CVar cvar in _cvars)
|
||||
foreach (ConfigVar cvar in ConfigVarsContainer.All()) {
|
||||
if (cvar.name.Equals(commandName)) {
|
||||
if (arguments.Length == 1) cvar.ParseFromString(arguments[0]);
|
||||
if (arguments.Length == 1) {
|
||||
cvar.ParseFromString(arguments[0]);
|
||||
}
|
||||
|
||||
WriteToOutput($"<b>{cvar.name}</b> - {cvar}\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
WriteToOutput($"ERROR: Command/CVar `{commandName}` not found.");
|
||||
}
|
||||
|
||||
public void RegisterCommand(IConsoleCommand command) {
|
||||
if (_commands.Any(t => t.Name.Equals(command.Name))) {
|
||||
_logger.Error($"`{command.Name}` command is already registered");
|
||||
if (m_ConsoleCommands.Any(t => t.Name.Equals(command.Name))) {
|
||||
s_logger.Error($"`{command.Name}` command is already registered");
|
||||
return;
|
||||
}
|
||||
|
||||
_commands.Add(command);
|
||||
_logger.Info($"Registered command: {command.Name}");
|
||||
m_ConsoleCommands.Add(command);
|
||||
s_logger.Info($"Registered command: {command.Name}");
|
||||
}
|
||||
|
||||
public void PrintHelp() {
|
||||
StringBuilder message = new();
|
||||
|
||||
message.AppendLine("Available commands:");
|
||||
foreach (IConsoleCommand command in _commands) {
|
||||
foreach (IConsoleCommand command in m_ConsoleCommands) {
|
||||
message.Append(" ");
|
||||
message.Append(command.Name);
|
||||
message.Append(" - ");
|
||||
@@ -127,7 +161,7 @@ namespace RebootKit.Engine.Services.Console {
|
||||
}
|
||||
|
||||
message.AppendLine("Available cvars:");
|
||||
foreach (CVar cvar in _cvars) {
|
||||
foreach (ConfigVar cvar in ConfigVarsContainer.All()) {
|
||||
message.Append(" ");
|
||||
message.Append(cvar.name);
|
||||
message.Append(" - ");
|
||||
@@ -137,5 +171,60 @@ namespace RebootKit.Engine.Services.Console {
|
||||
|
||||
WriteToOutput(message.ToString());
|
||||
}
|
||||
|
||||
public void PrintCVars() {
|
||||
StringBuilder message = new();
|
||||
|
||||
foreach (ConfigVar cvar in ConfigVarsContainer.All()) {
|
||||
message.AppendLine($"{cvar.name} - {cvar}");
|
||||
}
|
||||
|
||||
WriteToOutput(message.ToString());
|
||||
}
|
||||
|
||||
void Save() {
|
||||
string path = Application.persistentDataPath + "/" + RConsts.k_CVarsFilename;
|
||||
|
||||
s_logger.Info("Saving cvars to file: " + path);
|
||||
|
||||
StringBuilder sb = new();
|
||||
|
||||
foreach (ConfigVar cvar in ConfigVarsContainer.All()) {
|
||||
if (!cvar.flags.HasFlag(CVarFlags.ReadOnly)) {
|
||||
sb.AppendFormat("{0} {1}\n", cvar.name, cvar);
|
||||
}
|
||||
}
|
||||
|
||||
File.WriteAllText(path, sb.ToString());
|
||||
}
|
||||
|
||||
void Load() {
|
||||
string path = Application.persistentDataPath + "/" + RConsts.k_CVarsFilename;
|
||||
if (!File.Exists(path)) {
|
||||
s_logger.Info("CVar file not found, skipping load");
|
||||
return;
|
||||
}
|
||||
|
||||
m_IsLoading = true;
|
||||
ExecuteFile(path);
|
||||
m_IsLoading = false;
|
||||
}
|
||||
|
||||
bool ExecuteFile(string path) {
|
||||
if (!File.Exists(path)) {
|
||||
s_logger.Error($"Cannot load file '{path}', file not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
s_logger.Info($"Executing file '{path}'");
|
||||
|
||||
string[] lines = File.ReadAllLines(path);
|
||||
foreach (string line in lines) {
|
||||
WriteToOutput(path + " > " + line);
|
||||
Execute(line);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +1,15 @@
|
||||
using RebootKit.Engine.Foundation;
|
||||
using UnityEngine;
|
||||
using Logger = RebootKit.Engine.Foundation.Logger;
|
||||
|
||||
namespace RebootKit.Engine.Services.Console {
|
||||
[CreateAssetMenu(menuName = RConsts.k_ServiceAssetMenu + "Console")]
|
||||
public class ConsoleServiceAsset : ServiceAsset<ConsoleService> {
|
||||
[SerializeField] CVar[] _initialCVars;
|
||||
|
||||
[SerializeField] bool _loadCVarsFromResources = true;
|
||||
static readonly Logger s_logger = new(nameof(ConsoleServiceAsset));
|
||||
|
||||
public override ConsoleService Create(DIContext context) {
|
||||
ConsoleService service = new();
|
||||
context.Inject(service);
|
||||
|
||||
foreach (CVar cvar in _initialCVars) {
|
||||
service.Replace(cvar);
|
||||
cvar.Reset();
|
||||
}
|
||||
|
||||
if (_loadCVarsFromResources) {
|
||||
CVarAsset[] cvarsAssets = Resources.LoadAll<CVarAsset>("cvar");
|
||||
foreach (CVarAsset cvarAsset in cvarsAssets) {
|
||||
CVar cvar = cvarAsset.Create();
|
||||
service.Replace(cvar);
|
||||
}
|
||||
}
|
||||
|
||||
return service;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user