Ready for alpha 0.4.0 (the final alpha version (hopefully)) #72
33
SrcMod/Shell/Extensions/ConversionExtension.cs
Normal file
33
SrcMod/Shell/Extensions/ConversionExtension.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
namespace SrcMod.Shell.Extensions;
|
||||||
|
|
||||||
|
public static class ConversionExtension
|
||||||
|
{
|
||||||
|
public static T Cast<T>(this object obj) => (T)Cast(obj, typeof(T));
|
||||||
|
public static object Cast(this object obj, Type newType) => Convert.ChangeType(obj, newType);
|
||||||
|
|
||||||
|
public static object CastArray(this object[] obj, Type newElementType)
|
||||||
|
{
|
||||||
|
Array result = Array.CreateInstance(newElementType, obj.Length);
|
||||||
|
for (int i = 0; i < obj.Length; i++) result.SetValue(obj[i].Cast(newElementType), i);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
public static T[] CastArray<T>(this object[] obj)
|
||||||
|
{
|
||||||
|
Array result = Array.CreateInstance(typeof(T), obj.Length);
|
||||||
|
for (int i = 0; i < obj.Length; i++) result.SetValue(obj[i].Cast<T>(), i);
|
||||||
|
return (T[])result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static object CastArray(this Array obj, Type newElementType)
|
||||||
|
{
|
||||||
|
Array result = Array.CreateInstance(newElementType, obj.Length);
|
||||||
|
for (int i = 0; i < obj.Length; i++) result.SetValue(obj.GetValue(i)!.Cast(newElementType), i);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
public static T[] CastArray<T>(this Array obj)
|
||||||
|
{
|
||||||
|
Array result = Array.CreateInstance(typeof(T), obj.Length);
|
||||||
|
for (int i = 0; i < obj.Length; i++) result.SetValue(obj.GetValue(i)!.Cast<T>(), i);
|
||||||
|
return (T[])result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,10 +3,12 @@ global using Newtonsoft.Json;
|
|||||||
global using SharpCompress.Archives.Rar;
|
global using SharpCompress.Archives.Rar;
|
||||||
global using SharpCompress.Archives.SevenZip;
|
global using SharpCompress.Archives.SevenZip;
|
||||||
global using SharpCompress.Readers;
|
global using SharpCompress.Readers;
|
||||||
|
global using SrcMod.Shell.Extensions;
|
||||||
global using SrcMod.Shell.Interop;
|
global using SrcMod.Shell.Interop;
|
||||||
global using SrcMod.Shell.Modules.ObjectModels;
|
global using SrcMod.Shell.Modules.ObjectModels;
|
||||||
global using SrcMod.Shell.ObjectModels;
|
global using SrcMod.Shell.ObjectModels;
|
||||||
global using System;
|
global using System;
|
||||||
|
global using System.Collections;
|
||||||
global using System.Collections.Generic;
|
global using System.Collections.Generic;
|
||||||
global using System.ComponentModel;
|
global using System.ComponentModel;
|
||||||
global using System.Diagnostics;
|
global using System.Diagnostics;
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
namespace SrcMod.Shell;
|
namespace SrcMod.Shell;
|
||||||
|
|
||||||
internal static class LoadingBar
|
public static class LoadingBar
|
||||||
{
|
{
|
||||||
public static int position = -1;
|
public static int position = -1;
|
||||||
public static int bufferSize = 0;
|
public static int bufferSize = 0;
|
||||||
|
|||||||
@ -1,28 +1,26 @@
|
|||||||
namespace SrcMod.Shell.Modules;
|
using SharpCompress;
|
||||||
|
|
||||||
|
namespace SrcMod.Shell.Modules;
|
||||||
|
|
||||||
[Module("config")]
|
[Module("config")]
|
||||||
public static class ConfigModule
|
public static class ConfigModule
|
||||||
{
|
{
|
||||||
[Command("display")]
|
[Command("display")]
|
||||||
[Command("list")]
|
[Command("list")]
|
||||||
public static void DisplayConfig(ConfigDisplayMode mode = ConfigDisplayMode.All)
|
public static void DisplayConfig(string display = "all")
|
||||||
{
|
{
|
||||||
switch (mode)
|
switch (display.Trim().ToLower())
|
||||||
{
|
{
|
||||||
case ConfigDisplayMode.Raw:
|
case "all":
|
||||||
DisplayConfigRaw();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ConfigDisplayMode.All:
|
|
||||||
DisplayConfigAll();
|
DisplayConfigAll();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ConfigDisplayMode.GameDirectories:
|
case "raw":
|
||||||
DisplayConfigGameDirectories();
|
DisplayConfigRaw();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ConfigDisplayMode.RunUnsafeCommands:
|
default:
|
||||||
DisplayConfigUnsafeCommands();
|
DisplayConfigName(display);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -31,164 +29,197 @@ public static class ConfigModule
|
|||||||
[Command("append")]
|
[Command("append")]
|
||||||
public static void AppendConfigVariable(string name, string value)
|
public static void AppendConfigVariable(string name, string value)
|
||||||
{
|
{
|
||||||
Config config = Config.LoadedConfig;
|
FieldInfo[] validFields = (from field in typeof(Config).GetFields()
|
||||||
|
let isPublic = field.IsPublic
|
||||||
|
let isStatic = field.IsStatic
|
||||||
|
where isPublic && !isStatic
|
||||||
|
select field).ToArray();
|
||||||
|
|
||||||
switch (name.Trim().ToLower())
|
FieldInfo? chosenField = validFields.FirstOrDefault(x => x.Name.Trim().ToLower() == name.Trim().ToLower());
|
||||||
{
|
if (chosenField is null) throw new($"No valid config variable named \"{name}\".");
|
||||||
case "gamedirectories":
|
else if (!chosenField.FieldType.IsArray) throw new($"The variable \"{chosenField.Name}\" is not an array" +
|
||||||
config.GameDirectories = config.GameDirectories.Append(value).ToArray();
|
" and cannot have data added or removed from it." +
|
||||||
break;
|
" Instead, set or reset the variable.");
|
||||||
|
|
||||||
case "rununsafecommands":
|
object parsed = TypeParsers.ParseAll(value);
|
||||||
throw new($"The config variable \"{name}\" is a single variable and cannot be appended to.");
|
if (parsed is string parsedStr
|
||||||
|
&& chosenField.FieldType.IsEnum
|
||||||
|
&& Enum.TryParse(chosenField.FieldType, parsedStr, true, out object? obj)) parsed = obj;
|
||||||
|
|
||||||
default: throw new($"Unknown config variable \"{name}\"");
|
Type arrayType = chosenField.FieldType.GetElementType()!;
|
||||||
}
|
|
||||||
|
|
||||||
Config.LoadedConfig = config;
|
Array arrayValue = (Array)chosenField.GetValue(Config.LoadedConfig)!;
|
||||||
|
ArrayList collection = new(arrayValue) { parsed };
|
||||||
|
|
||||||
|
chosenField.SetValue(Config.LoadedConfig, collection.ToArray()!.CastArray(arrayType));
|
||||||
|
Config.UpdateChanges();
|
||||||
|
DisplayConfigItem(chosenField.GetValue(Config.LoadedConfig), name: chosenField.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command("delete")]
|
[Command("delete")]
|
||||||
[Command("remove")]
|
[Command("remove")]
|
||||||
public static void RemoveConfigVariable(string name, string value)
|
public static void RemoveConfigVariable(string name, string value)
|
||||||
{
|
{
|
||||||
Config config = Config.LoadedConfig;
|
FieldInfo[] validFields = (from field in typeof(Config).GetFields()
|
||||||
|
let isPublic = field.IsPublic
|
||||||
|
let isStatic = field.IsStatic
|
||||||
|
where isPublic && !isStatic
|
||||||
|
select field).ToArray();
|
||||||
|
|
||||||
switch (name.Trim().ToLower())
|
FieldInfo? chosenField = validFields.FirstOrDefault(x => x.Name.Trim().ToLower() == name.Trim().ToLower());
|
||||||
{
|
if (chosenField is null) throw new($"No valid config variable named \"{name}\".");
|
||||||
case "gamedirectories":
|
else if (!chosenField.FieldType.IsArray) throw new($"The variable \"{chosenField.Name}\" is not an array" +
|
||||||
config.GameDirectories = config.GameDirectories
|
" and cannot have data added or removed from it." +
|
||||||
.Where(x => x.Trim().ToLower() != value.Trim().ToLower())
|
" Instead, set or reset the variable.");
|
||||||
.ToArray();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "rununsafecommands":
|
object parsed = TypeParsers.ParseAll(value);
|
||||||
throw new($"The config variable \"{name}\" is a single variable and cannot be appended to.");
|
if (parsed is string parsedStr
|
||||||
|
&& chosenField.FieldType.IsEnum
|
||||||
|
&& Enum.TryParse(chosenField.FieldType, parsedStr, true, out object? obj)) parsed = obj;
|
||||||
|
|
||||||
default: throw new($"Unknown config variable \"{name}\"");
|
Type arrayType = chosenField.FieldType.GetElementType()!;
|
||||||
}
|
|
||||||
|
|
||||||
Config.LoadedConfig = config;
|
Array arrayValue = (Array)chosenField.GetValue(Config.LoadedConfig)!;
|
||||||
|
ArrayList collection = new(arrayValue);
|
||||||
|
if (!collection.Contains(parsed)) throw new($"The value \"{value}\" is not contained in this variable.");
|
||||||
|
collection.Remove(parsed);
|
||||||
|
|
||||||
|
chosenField.SetValue(Config.LoadedConfig, collection.ToArray()!.CastArray(arrayType));
|
||||||
|
Config.UpdateChanges();
|
||||||
|
DisplayConfigItem(chosenField.GetValue(Config.LoadedConfig), name: chosenField.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command("reset")]
|
[Command("reset")]
|
||||||
public static void ResetConfig(string name = "all")
|
public static void ResetConfig(string name = "all")
|
||||||
{
|
{
|
||||||
Config config = Config.LoadedConfig;
|
|
||||||
|
|
||||||
switch (name.Trim().ToLower())
|
switch (name.Trim().ToLower())
|
||||||
{
|
{
|
||||||
case "gamedirectories":
|
|
||||||
config.GameDirectories = Config.Defaults.GameDirectories;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "rununsafecommands":
|
|
||||||
config.RunUnsafeCommands = Config.Defaults.RunUnsafeCommands;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "all":
|
case "all":
|
||||||
config = Config.Defaults;
|
Config.LoadedConfig = Config.Defaults;
|
||||||
|
DisplayConfig("all");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: throw new($"Unknown config variable \"{name}\"");
|
default:
|
||||||
|
ResetConfigVar(name);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Config.LoadedConfig = config;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command("set")]
|
[Command("set")]
|
||||||
public static void SetConfigVariable(string name, string value)
|
public static void SetConfigVariable(string name, string value)
|
||||||
{
|
{
|
||||||
Config config = Config.LoadedConfig;
|
FieldInfo[] validFields = (from field in typeof(Config).GetFields()
|
||||||
|
let isPublic = field.IsPublic
|
||||||
|
let isStatic = field.IsStatic
|
||||||
|
where isPublic && !isStatic
|
||||||
|
select field).ToArray();
|
||||||
|
|
||||||
switch (name.Trim().ToLower())
|
FieldInfo? chosenField = validFields.FirstOrDefault(x => x.Name.Trim().ToLower() == name.Trim().ToLower());
|
||||||
{
|
if (chosenField is null) throw new($"No valid config variable named \"{name}\".");
|
||||||
case "gamedirectories":
|
else if (chosenField.FieldType.IsArray) throw new($"The variable \"{chosenField.Name}\" is an array and" +
|
||||||
throw new($"The config variable \"{name}\" is a list and must be added or removed to.");
|
" cannot be directly set. Instead, add or remove items" +
|
||||||
|
" from it.");
|
||||||
|
|
||||||
case "rununsafecommands":
|
object parsed = TypeParsers.ParseAll(value);
|
||||||
if (int.TryParse(value, out int intRes))
|
if (parsed is string parsedStr
|
||||||
{
|
&& chosenField.FieldType.IsEnum
|
||||||
AskMode mode = (AskMode)intRes;
|
&& Enum.TryParse(chosenField.FieldType, parsedStr, true, out object? obj)) parsed = obj;
|
||||||
if (!Enum.IsDefined(mode)) throw new($"(AskMode){value} is not a valid AskMode.");
|
|
||||||
config.RunUnsafeCommands = mode;
|
|
||||||
}
|
|
||||||
else if (Enum.TryParse(value, true, out AskMode modeRes))
|
|
||||||
{
|
|
||||||
if (!Enum.IsDefined(modeRes)) throw new($"\"{value}\" is not a valid AskMode.");
|
|
||||||
config.RunUnsafeCommands = modeRes;
|
|
||||||
}
|
|
||||||
else throw new($"\"{value}\" is not a valid AskMode.");
|
|
||||||
break;
|
|
||||||
|
|
||||||
default: throw new($"Unknown config variable \"{name}\"");
|
chosenField.SetValue(Config.LoadedConfig, parsed);
|
||||||
}
|
Config.UpdateChanges();
|
||||||
|
DisplayConfigItem(chosenField.GetValue(Config.LoadedConfig), name: chosenField.Name);
|
||||||
Config.LoadedConfig = config;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DisplayConfigAll()
|
private static void DisplayConfigAll()
|
||||||
{
|
{
|
||||||
DisplayConfigGameDirectories();
|
FieldInfo[] validFields = (from field in typeof(Config).GetFields()
|
||||||
DisplayConfigUnsafeCommands();
|
let isPublic = field.IsPublic
|
||||||
|
let isStatic = field.IsStatic
|
||||||
|
where isPublic && !isStatic
|
||||||
|
select field).ToArray();
|
||||||
|
|
||||||
|
foreach (FieldInfo field in validFields)
|
||||||
|
DisplayConfigItem(field.GetValue(Config.LoadedConfig), name: field.Name);
|
||||||
}
|
}
|
||||||
private static void DisplayConfigRaw()
|
private static void DisplayConfigItem<T>(T item, int indents = 0, string name = "", bool newLine = true)
|
||||||
{
|
{
|
||||||
// This is definitely a bit inefficient, but shouldn't be too much of an issue.
|
Write(new string(' ', indents * 4), newLine: false);
|
||||||
|
if (!string.IsNullOrWhiteSpace(name)) Write($"{name}: ", newLine: false);
|
||||||
|
|
||||||
MemoryStream ms = new();
|
if (item is null) Write("null", ConsoleColor.DarkRed, newLine);
|
||||||
StreamWriter writer = new(ms, leaveOpen: true);
|
else if (item is Array itemArray)
|
||||||
JsonTextWriter jsonWriter = new(writer);
|
|
||||||
|
|
||||||
Serializer.Serialize(jsonWriter, Config.LoadedConfig);
|
|
||||||
|
|
||||||
jsonWriter.Close();
|
|
||||||
writer.Close();
|
|
||||||
ms.Position = 0;
|
|
||||||
|
|
||||||
StreamReader reader = new(ms);
|
|
||||||
string msg = reader.ReadToEnd();
|
|
||||||
|
|
||||||
Write(msg);
|
|
||||||
|
|
||||||
reader.Close();
|
|
||||||
ms.Close();
|
|
||||||
}
|
|
||||||
private static void DisplayConfigGameDirectories()
|
|
||||||
{
|
|
||||||
Write("Steam Game Directories: ", null, false);
|
|
||||||
if (Config.LoadedConfig.GameDirectories is null || Config.LoadedConfig.GameDirectories.Length <= 0)
|
|
||||||
Write("None", ConsoleColor.DarkGray);
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
Write("[", ConsoleColor.DarkGray);
|
if (itemArray.Length < 1)
|
||||||
for (int i = 0; i < Config.LoadedConfig.GameDirectories.Length; i++)
|
|
||||||
{
|
{
|
||||||
Write(" \"", ConsoleColor.DarkGray, false);
|
Write("[]", ConsoleColor.DarkGray, newLine);
|
||||||
Write(Config.LoadedConfig.GameDirectories[i], ConsoleColor.White, false);
|
return;
|
||||||
if (i < Config.LoadedConfig.GameDirectories.Length - 1) Write("\",", ConsoleColor.DarkGray);
|
|
||||||
else Write("\"", ConsoleColor.DarkGray);
|
|
||||||
}
|
}
|
||||||
Write("]", ConsoleColor.DarkGray);
|
|
||||||
|
Write("[", ConsoleColor.DarkGray);
|
||||||
|
for (int i = 0; i < itemArray.Length; i++)
|
||||||
|
{
|
||||||
|
DisplayConfigItem(itemArray.GetValue(i), indents + 1, newLine: false);
|
||||||
|
if (i < itemArray.Length - 1) Write(',', newLine: false);
|
||||||
|
Write('\n', newLine: false);
|
||||||
|
}
|
||||||
|
Write(new string(' ', indents * 4) + "]", ConsoleColor.DarkGray, newLine);
|
||||||
}
|
}
|
||||||
}
|
else if (item is byte itemByte) Write($"0x{itemByte:X2}", ConsoleColor.Yellow, newLine);
|
||||||
private static void DisplayConfigUnsafeCommands()
|
else if (item is sbyte or short or ushort or int or uint or long or ulong or float or double or decimal)
|
||||||
{
|
Write(item, ConsoleColor.Yellow, newLine);
|
||||||
Write("Run Unsafe Commands: ", null, false);
|
else if (item is bool itemBool) Write(item, itemBool ? ConsoleColor.Green : ConsoleColor.Red, newLine);
|
||||||
ConsoleColor color = Config.LoadedConfig.RunUnsafeCommands switch
|
else if (item is char)
|
||||||
|
{
|
||||||
|
Write("\'", ConsoleColor.DarkGray, false);
|
||||||
|
Write(item, ConsoleColor.Blue, false);
|
||||||
|
Write("\'", ConsoleColor.DarkGray, newLine);
|
||||||
|
}
|
||||||
|
else if (item is string)
|
||||||
|
{
|
||||||
|
Write("\"", ConsoleColor.DarkGray, false);
|
||||||
|
Write(item, ConsoleColor.DarkCyan, false);
|
||||||
|
Write("\"", ConsoleColor.DarkGray, newLine);
|
||||||
|
}
|
||||||
|
else if (item is AskMode) Write(item, item switch
|
||||||
{
|
{
|
||||||
AskMode.Never => ConsoleColor.Red,
|
AskMode.Never => ConsoleColor.Red,
|
||||||
AskMode.Always => ConsoleColor.Green,
|
AskMode.Always => ConsoleColor.Green,
|
||||||
AskMode.Ask or _ => ConsoleColor.DarkGray
|
AskMode.Ask or _ => ConsoleColor.DarkGray
|
||||||
};
|
}, newLine);
|
||||||
Write(Config.LoadedConfig.RunUnsafeCommands, color);
|
else Write(item, newLine: newLine);
|
||||||
|
}
|
||||||
|
private static void DisplayConfigName(string name)
|
||||||
|
{
|
||||||
|
FieldInfo[] validFields = (from field in typeof(Config).GetFields()
|
||||||
|
let isPublic = field.IsPublic
|
||||||
|
let isStatic = field.IsStatic
|
||||||
|
where isPublic && !isStatic
|
||||||
|
select field).ToArray();
|
||||||
|
|
||||||
|
FieldInfo? chosenField = validFields.FirstOrDefault(x => x.Name.Trim().ToLower() == name.Trim().ToLower());
|
||||||
|
if (chosenField is null) throw new($"No config variable named \"{name}\".");
|
||||||
|
|
||||||
|
DisplayConfigItem(chosenField.GetValue(Config.LoadedConfig), name: chosenField.Name);
|
||||||
|
}
|
||||||
|
private static void DisplayConfigRaw()
|
||||||
|
{
|
||||||
|
string json = JsonConvert.SerializeObject(Config.LoadedConfig, Formatting.Indented);
|
||||||
|
Write(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ConfigDisplayMode
|
private static void ResetConfigVar(string name)
|
||||||
{
|
{
|
||||||
Raw,
|
FieldInfo[] validFields = (from field in typeof(Config).GetFields()
|
||||||
All,
|
let isPublic = field.IsPublic
|
||||||
GameDirectories,
|
let isStatic = field.IsStatic
|
||||||
RunUnsafeCommands
|
where isPublic && !isStatic
|
||||||
|
select field).ToArray();
|
||||||
|
|
||||||
|
FieldInfo? chosenField = validFields.FirstOrDefault(x => x.Name.Trim().ToLower() == name.Trim().ToLower());
|
||||||
|
if (chosenField is null) throw new($"No valid config variable named \"{name}\".");
|
||||||
|
|
||||||
|
chosenField.SetValue(Config.LoadedConfig, chosenField.GetValue(Config.Defaults));
|
||||||
|
Config.UpdateChanges();
|
||||||
|
DisplayConfigItem(chosenField.GetValue(Config.LoadedConfig), name: chosenField.Name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,13 @@
|
|||||||
namespace SrcMod.Shell.ObjectModels;
|
namespace SrcMod.Shell.ObjectModels;
|
||||||
|
|
||||||
public struct Config
|
public class Config
|
||||||
{
|
{
|
||||||
public const string FilePath = "config.json";
|
public const string FilePath = "config.json";
|
||||||
|
|
||||||
public static readonly Config Defaults;
|
public static Config Defaults => new();
|
||||||
|
|
||||||
|
private static readonly FieldInfo[] p_configSharedFields;
|
||||||
|
private static readonly FieldInfo[] p_changeSharedFields;
|
||||||
|
|
||||||
public static Config LoadedConfig
|
public static Config LoadedConfig
|
||||||
{
|
{
|
||||||
@ -12,39 +15,107 @@ public struct Config
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
p_applied = value;
|
p_applied = value;
|
||||||
p_changes = p_applied.GetChanges(Defaults);
|
UpdateChanges();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Config p_applied;
|
private static Config p_applied;
|
||||||
private static ConfigChanges? p_changes;
|
private static Changes? p_changes;
|
||||||
|
|
||||||
static Config()
|
static Config()
|
||||||
{
|
{
|
||||||
Defaults = new()
|
p_applied = Defaults;
|
||||||
|
|
||||||
|
FieldInfo[] configFields = (from field in typeof(Config).GetFields()
|
||||||
|
let isPublic = field.IsPublic
|
||||||
|
let isStatic = field.IsStatic
|
||||||
|
where isPublic && !isStatic
|
||||||
|
select field).ToArray(),
|
||||||
|
changeFields = (from field in typeof(Changes).GetFields()
|
||||||
|
let isPublic = field.IsPublic
|
||||||
|
let isStatic = field.IsStatic
|
||||||
|
where isPublic && !isStatic
|
||||||
|
select field).ToArray();
|
||||||
|
|
||||||
|
List<FieldInfo> sharedConfigFields = new(),
|
||||||
|
sharedChangeFields = new();
|
||||||
|
foreach (FieldInfo field in configFields)
|
||||||
{
|
{
|
||||||
GameDirectories = Array.Empty<string>(),
|
FieldInfo? changeEquivalent = changeFields.FirstOrDefault(
|
||||||
RunUnsafeCommands = AskMode.Ask
|
x => x.Name == field.Name &&
|
||||||
};
|
(x.FieldType == field.FieldType || Nullable.GetUnderlyingType(x.FieldType) == field.FieldType));
|
||||||
|
|
||||||
|
if (changeEquivalent is null) continue;
|
||||||
|
|
||||||
|
sharedConfigFields.Add(field);
|
||||||
|
sharedChangeFields.Add(changeEquivalent);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sortByName(FieldInfo a, FieldInfo b) => a.Name.CompareTo(b.Name);
|
||||||
|
|
||||||
|
sharedConfigFields.Sort(sortByName);
|
||||||
|
sharedChangeFields.Sort(sortByName);
|
||||||
|
|
||||||
|
p_configSharedFields = sharedConfigFields.ToArray();
|
||||||
|
p_changeSharedFields = sharedChangeFields.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public string[] GameDirectories;
|
public string[] GameDirectories;
|
||||||
public AskMode RunUnsafeCommands;
|
public AskMode RunUnsafeCommands;
|
||||||
|
|
||||||
public Config ApplyChanges(ConfigChanges changes) => this with
|
internal Config()
|
||||||
{
|
{
|
||||||
GameDirectories = GameDirectories.Union(changes.GameDirectories ?? Array.Empty<string>()).ToArray(),
|
GameDirectories = Array.Empty<string>();
|
||||||
RunUnsafeCommands = changes.RunUnsafeCommands ?? RunUnsafeCommands
|
RunUnsafeCommands = AskMode.Ask;
|
||||||
};
|
}
|
||||||
public ConfigChanges GetChanges(Config? baseConfig = null)
|
|
||||||
|
public Config ApplyChanges(Changes changes)
|
||||||
{
|
{
|
||||||
Config reference = baseConfig ?? Defaults;
|
for (int i = 0; i < p_configSharedFields.Length; i++)
|
||||||
ConfigChanges changes = new()
|
|
||||||
{
|
{
|
||||||
GameDirectories = reference.GameDirectories == GameDirectories ? null :
|
FieldInfo configField = p_configSharedFields[i],
|
||||||
GameDirectories.Where(x => !reference.GameDirectories.Contains(x)).ToArray(),
|
changeField = p_changeSharedFields[i];
|
||||||
RunUnsafeCommands = reference.RunUnsafeCommands == RunUnsafeCommands ? null : RunUnsafeCommands
|
|
||||||
};
|
object? toChange = changeField.GetValue(changes);
|
||||||
|
|
||||||
|
if (toChange is null) continue;
|
||||||
|
|
||||||
|
if (configField.FieldType.IsArray)
|
||||||
|
{
|
||||||
|
object[] currentArray = ((Array)configField.GetValue(this)!).CastArray<object>(),
|
||||||
|
changeArray = ((Array)toChange).CastArray<object>();
|
||||||
|
|
||||||
|
currentArray = currentArray.Union(changeArray).ToArray();
|
||||||
|
configField.SetValue(this, currentArray.CastArray(configField.FieldType.GetElementType()!));
|
||||||
|
}
|
||||||
|
else configField.SetValue(this, toChange);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public Changes GetChanges(Config? reference = null)
|
||||||
|
{
|
||||||
|
reference ??= Defaults;
|
||||||
|
Changes changes = new();
|
||||||
|
|
||||||
|
for (int i = 0; i < p_configSharedFields.Length; i++)
|
||||||
|
{
|
||||||
|
FieldInfo configField = p_configSharedFields[i],
|
||||||
|
changeField = p_changeSharedFields[i];
|
||||||
|
|
||||||
|
object? toSet = configField.GetValue(this);
|
||||||
|
|
||||||
|
if (toSet is null) continue;
|
||||||
|
|
||||||
|
if (configField.FieldType.IsArray)
|
||||||
|
{
|
||||||
|
object[] configArray = ((Array)toSet).CastArray<object>(),
|
||||||
|
referenceArray = ((Array)configField.GetValue(Defaults)!).CastArray<object>(),
|
||||||
|
changesArray = configArray.Where(x => !referenceArray.Contains(x)).ToArray();
|
||||||
|
changeField.SetValue(changes, changesArray.CastArray(configField.FieldType.GetElementType()!));
|
||||||
|
}
|
||||||
|
else changeField.SetValue(changes, toSet);
|
||||||
|
}
|
||||||
|
|
||||||
return changes;
|
return changes;
|
||||||
}
|
}
|
||||||
@ -61,26 +132,42 @@ public struct Config
|
|||||||
}
|
}
|
||||||
StreamReader reader = new(fullPath);
|
StreamReader reader = new(fullPath);
|
||||||
JsonTextReader jsonReader = new(reader);
|
JsonTextReader jsonReader = new(reader);
|
||||||
p_changes = Serializer.Deserialize<ConfigChanges?>(jsonReader);
|
p_changes = Serializer.Deserialize<Changes?>(jsonReader);
|
||||||
jsonReader.Close();
|
jsonReader.Close();
|
||||||
reader.Close();
|
reader.Close();
|
||||||
|
|
||||||
p_applied = p_changes is null ? Defaults : Defaults.ApplyChanges(p_changes.Value);
|
p_applied = p_changes is null ? Defaults : Defaults.ApplyChanges(p_changes);
|
||||||
}
|
}
|
||||||
public static void SaveConfig(string basePath)
|
public static void SaveConfig(string basePath)
|
||||||
{
|
{
|
||||||
string fullPath = Path.Combine(basePath, FilePath);
|
string fullPath = Path.Combine(basePath, FilePath);
|
||||||
|
|
||||||
if (p_changes is null || !p_changes.Value.HasChange)
|
if (p_changes is null || !p_changes.Any())
|
||||||
{
|
{
|
||||||
if (File.Exists(fullPath)) File.Delete(fullPath);
|
if (File.Exists(fullPath)) File.Delete(fullPath);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
StreamWriter writer = new(fullPath);
|
StreamWriter writer = new(fullPath);
|
||||||
JsonTextWriter jsonWriter = new(writer);
|
JsonTextWriter jsonWriter = new(writer)
|
||||||
|
{
|
||||||
|
Indentation = 4
|
||||||
|
};
|
||||||
Serializer.Serialize(jsonWriter, p_changes);
|
Serializer.Serialize(jsonWriter, p_changes);
|
||||||
jsonWriter.Close();
|
jsonWriter.Close();
|
||||||
writer.Close();
|
writer.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void UpdateChanges()
|
||||||
|
{
|
||||||
|
p_changes = p_applied.GetChanges(Defaults);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Changes
|
||||||
|
{
|
||||||
|
public string[]? GameDirectories;
|
||||||
|
public AskMode? RunUnsafeCommands;
|
||||||
|
|
||||||
|
public bool Any() => typeof(Changes).GetFields().Any(x => x.GetValue(this) is not null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +0,0 @@
|
|||||||
namespace SrcMod.Shell.ObjectModels;
|
|
||||||
|
|
||||||
public record struct ConfigChanges
|
|
||||||
{
|
|
||||||
[JsonIgnore]
|
|
||||||
public bool HasChange => GameDirectories is not null || RunUnsafeCommands is not null;
|
|
||||||
|
|
||||||
public string[]? GameDirectories;
|
|
||||||
public AskMode? RunUnsafeCommands;
|
|
||||||
}
|
|
||||||
@ -4,7 +4,7 @@ public class Shell
|
|||||||
{
|
{
|
||||||
public const string Author = "That_One_Nerd";
|
public const string Author = "That_One_Nerd";
|
||||||
public const string Name = "SrcMod";
|
public const string Name = "SrcMod";
|
||||||
public const string Version = "Alpha 0.3.3";
|
public const string Version = "Alpha 0.4.0";
|
||||||
|
|
||||||
public readonly string? ShellDirectory;
|
public readonly string? ShellDirectory;
|
||||||
|
|
||||||
@ -239,24 +239,27 @@ public class Shell
|
|||||||
|
|
||||||
void runCommand(object? sender, DoWorkEventArgs e)
|
void runCommand(object? sender, DoWorkEventArgs e)
|
||||||
{
|
{
|
||||||
#if RELEASE
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
#endif
|
|
||||||
command.Invoke(args);
|
command.Invoke(args);
|
||||||
#if RELEASE
|
|
||||||
}
|
}
|
||||||
|
#if RELEASE
|
||||||
catch (TargetInvocationException ex)
|
catch (TargetInvocationException ex)
|
||||||
{
|
{
|
||||||
Write($"[ERROR] {ex.InnerException!.Message}", ConsoleColor.Red);
|
Write($"[ERROR] {ex.InnerException!.Message}", ConsoleColor.Red);
|
||||||
if (LoadingBar.Enabled) LoadingBar.End();
|
if (LoadingBar.Enabled) LoadingBar.End();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
#if RELEASE
|
||||||
Write($"[ERROR] {ex.Message}", ConsoleColor.Red);
|
Write($"[ERROR] {ex.Message}", ConsoleColor.Red);
|
||||||
if (LoadingBar.Enabled) LoadingBar.End();
|
if (LoadingBar.Enabled) LoadingBar.End();
|
||||||
}
|
#else
|
||||||
|
Write($"[ERROR] {ex}", ConsoleColor.Red);
|
||||||
|
if (LoadingBar.Enabled) LoadingBar.End();
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
activeCommand = new();
|
activeCommand = new();
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
namespace SrcMod.Shell;
|
namespace SrcMod.Shell;
|
||||||
|
|
||||||
internal static class Tools
|
public static class Tools
|
||||||
{
|
{
|
||||||
public static JsonSerializer Serializer { get; private set; }
|
public static JsonSerializer Serializer { get; private set; }
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user