- ShrinkModComponentDiscovery.Discover 公开:只发现、不执行生命周期 - ShrinkModLoader.LoadComposed / ShrinkModCordisRuntime.ApplyComposedAsync:宿主提供元数据组合加载,支持纯数据包与 IShrinkModWrapper 公开真实实例 - 公开 TryAttachEventBusInstance,随生命周期逆操作释放 - 依赖新增 VersionRange(Maven/Forge 区间语法)与 Ordering(Before/After) - AssemblyResolvePolicy 可限制跨模组程序集解析
79 lines
3.6 KiB
C#
79 lines
3.6 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text.RegularExpressions;
|
|
|
|
namespace ShrinkModFramework
|
|
{
|
|
/// <summary>Maven 风格区间/并集;裸版本表示最低版本。版本比较沿用框架规则,数字尾部零等价。</summary>
|
|
public sealed class ShrinkModVersionRange
|
|
{
|
|
private readonly List<Func<string, bool>> _ranges = new();
|
|
private ShrinkModVersionRange() { }
|
|
|
|
public static ShrinkModVersionRange Parse(string expression)
|
|
{
|
|
var result = new ShrinkModVersionRange();
|
|
if (string.IsNullOrWhiteSpace(expression)) return result;
|
|
var text = expression.Trim();
|
|
if (text[0] != '[' && text[0] != '(')
|
|
{
|
|
ValidateVersion(text);
|
|
result._ranges.Add(version => ShrinkVersionUtility.Compare(version, text) >= 0);
|
|
return result;
|
|
}
|
|
while (text.Length > 0)
|
|
{
|
|
var end = text.IndexOfAny(new[] { ']', ')' });
|
|
if (end < 0 || (text[0] != '[' && text[0] != '(')) throw Invalid(expression);
|
|
var lowerInclusive = text[0] == '[';
|
|
var upperInclusive = text[end] == ']';
|
|
var bounds = text.Substring(1, end - 1).Split(',');
|
|
string lower, upper;
|
|
if (bounds.Length == 1)
|
|
{
|
|
if (!lowerInclusive || !upperInclusive) throw Invalid(expression);
|
|
lower = upper = bounds[0].Trim();
|
|
ValidateVersion(lower);
|
|
}
|
|
else if (bounds.Length == 2)
|
|
{
|
|
lower = bounds[0].Trim(); upper = bounds[1].Trim();
|
|
if (lower.Length > 0) ValidateVersion(lower);
|
|
if (upper.Length > 0) ValidateVersion(upper);
|
|
if ((lower.Length == 0 && lowerInclusive) || (upper.Length == 0 && upperInclusive))
|
|
throw Invalid(expression);
|
|
if (lower.Length > 0 && upper.Length > 0)
|
|
{
|
|
var comparison = ShrinkVersionUtility.Compare(lower, upper);
|
|
if (comparison > 0 || (comparison == 0 && (!lowerInclusive || !upperInclusive))) throw Invalid(expression);
|
|
}
|
|
}
|
|
else throw Invalid(expression);
|
|
result._ranges.Add(version =>
|
|
(lower.Length == 0 || (lowerInclusive ? ShrinkVersionUtility.Compare(version, lower) >= 0 : ShrinkVersionUtility.Compare(version, lower) > 0)) &&
|
|
(upper.Length == 0 || (upperInclusive ? ShrinkVersionUtility.Compare(version, upper) <= 0 : ShrinkVersionUtility.Compare(version, upper) < 0)));
|
|
text = text.Substring(end + 1).Trim();
|
|
if (text.Length == 0) break;
|
|
if (text[0] != ',' || text.Length == 1) throw Invalid(expression);
|
|
text = text.Substring(1).Trim();
|
|
if (text.Length == 0) throw Invalid(expression);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public bool Contains(string version)
|
|
{
|
|
ValidateVersion(version);
|
|
return _ranges.Count == 0 || _ranges.Any(range => range(version));
|
|
}
|
|
|
|
private static void ValidateVersion(string version)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(version) || !Regex.IsMatch(version, @"^[0-9]+(?:[.][0-9]+)*(?:[-+][A-Za-z0-9.-]+)?$"))
|
|
throw Invalid(version);
|
|
}
|
|
private static FormatException Invalid(string value) => new FormatException($"Invalid mod version range: '{value}'.");
|
|
}
|
|
}
|