Menci 37044dae01
[RF] AquaMai configuration refactor (#82)
更新了配置文件格式,原有的配置文件将被自动无缝迁移,详情请见新的配置文件中的注释(例外:`SlideJudgeTweak` 不再默认启用)
旧配置文件将被重命名备份,如果更新到此版本遇到 Bug 请联系我们

Updated configuration file schema. The old config file will be migrated automatically and seamlessly. See the comments in the new configuration file for details. (Except for `SlideJudgeTweak` is no longer enabled by default)
Your old configuration file will be renamed as a backup. If you encounter any bug with this version, please contact us.
2024-11-25 01:25:19 +08:00

184 lines
5.2 KiB
C#

using System;
using System.Reflection;
using Tomlet.Models;
namespace AquaMai.Config;
public static class Utility
{
public static Action<string> LogFunction = Console.WriteLine;
public static bool IsTruty(TomlValue value, string path = null)
{
return value switch
{
TomlBoolean boolean => boolean.Value,
TomlLong @long => @long.Value != 0,
_ => throw new ArgumentException(
path == null
? $"Non-boolish TOML type {value.GetType().Name} value: {value}"
: $"When parsing {path}, got non-boolish TOML type {value.GetType().Name} value: {value}")
};
}
public static bool IsIntegerType(Type type)
{
return type == typeof(sbyte) || type == typeof(short) || type == typeof(int) || type == typeof(long)
|| type == typeof(byte) || type == typeof(ushort) || type == typeof(uint) || type == typeof(ulong);
}
public static bool IsFloatType(Type type)
{
return type == typeof(float) || type == typeof(double);
}
public static bool IsNumberType(Type type)
{
return IsIntegerType(type) || IsFloatType(type);
}
public static T ParseTomlValue<T>(TomlValue value)
{
return (T)ParseTomlValue(typeof(T), value);
}
public static object ParseTomlValue(Type type, TomlValue value)
{
if (type == typeof(bool))
{
return IsTruty(value);
}
else if (IsNumberType(type))
{
if (TryGetTomlNumberObject(value, out var numberObject))
{
return Convert.ChangeType(numberObject, type);
}
else
{
throw new InvalidCastException($"Non-number TOML type: {value.GetType().Name}");
}
}
else if (type == typeof(string))
{
if (value is TomlString @string)
{
return @string.Value;
}
else
{
throw new InvalidCastException($"Non-string TOML type: {value.GetType().Name}");
}
}
else if (type.IsEnum)
{
if (value is TomlString @string)
{
try
{
return Enum.Parse(type, @string.Value);
}
catch
{
throw new InvalidCastException($"Invalid enum {type.FullName} value: {@string.SerializedValue}");
}
}
else if (value is TomlLong @long)
{
if (Enum.IsDefined(type, @long.Value))
{
try
{
return Enum.ToObject(type, @long.Value);
}
catch
{}
}
throw new InvalidCastException($"Invalid enum {type.FullName} value: {@long.Value}");
}
else
{
throw new InvalidCastException($"Non-enum TOML type: {value.GetType().Name}");
}
}
else
{
var currentMethod = MethodBase.GetCurrentMethod();
throw new NotImplementedException($"Unsupported config entry type: {type.FullName}. Please implement in {currentMethod.DeclaringType.FullName}.{currentMethod.Name}");
}
}
private static bool TryGetTomlNumberObject(TomlValue value, out object numberObject)
{
if (value is TomlLong @long)
{
numberObject = @long.Value;
return true;
}
else if (value is TomlDouble @double)
{
numberObject = @double.Value;
return true;
}
else
{
numberObject = null;
return false;
}
}
public static bool TomlTryGetValueCaseInsensitive(TomlTable table, string key, out TomlValue value)
{
// Prefer exact match
if (table.TryGetValue(key, out value))
{
return true;
}
// Fallback to case-insensitive match
foreach (var kvp in table)
{
if (string.Equals(kvp.Key, key, StringComparison.OrdinalIgnoreCase))
{
value = kvp.Value;
return true;
}
}
value = null;
return false;
}
public static bool TomlContainsKeyCaseInsensitive(TomlTable table, string key)
{
// Prefer exact match
if (table.ContainsKey(key))
{
return true;
}
// Fallback to case-insensitive match
foreach (var kvp in table)
{
if (string.Equals(kvp.Key, key, StringComparison.OrdinalIgnoreCase))
{
return true;
}
}
return false;
}
public static string ToPascalCase(string str)
{
return str.Length switch
{
0 => str,
1 => char.ToUpperInvariant(str[0]).ToString(),
_ => char.ToUpperInvariant(str[0]) + str.Substring(1)
};
}
// We can test the configuration related code without loading the mod into the game.
public static void Log(string message)
{
LogFunction(message);
}
}