Files
MRCC/launcher/PCL-CE/Plain Craft Launcher 2/Modules/Minecraft/McInstanceInfo.cs
T
xyou f70b061d1a
CI / Go Backend (push) Canceled after 0s
feat: 项目初始化 + 3D方块世界原型 + AI助搭系统
初始化 monorepo: Go后端(7微服务) + Unity客户端(9模块) + 启动器

HTML5原型: Three.js 3D体素世界, Perlin噪声地形, 原版材质, 22种方块

Minecraft创造模式背包: 双栏布局, 拖拽移动物品, 方向性元件引脚

AI助搭策划文档 + 客户端/服务端骨架 + Docker Compose + CI
2026-08-08 14:07:56 +08:00

340 lines
11 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using PCL.Core.App.Localization;
namespace PCL;
/// <summary>
/// 某个 Minecraft 实例的版本名、附加组件信息。
/// </summary>
public class McInstanceInfo
{
/// <summary>
/// Cleanroom 版本号,如 0.2.4-alpha。
/// </summary>
public string Cleanroom = "";
/// <summary>
/// Fabric 版本号,如 0.7.2.175。
/// </summary>
public string Fabric = "";
/// <summary>
/// Forge 版本号,如 31.1.2、14.23.5.2847。
/// </summary>
public string Forge = "";
// Cleanroom
/// <summary>
/// 该实例是否安装了 Cleanroom。
/// </summary>
public bool HasCleanroom;
// Fabric
/// <summary>
/// 该实例是否安装了 Fabric。
/// </summary>
public bool HasFabric;
// Forge
/// <summary>
/// 该实例是否安装了 Forge。
/// </summary>
public bool HasForge;
// LabyMod
/// <summary>
/// 该实例是否安装了 LabyMod。
/// </summary>
public bool HasLabyMod;
// LegacyFabric
/// <summary>
/// 该实例是否安装了 Fabric。
/// </summary>
public bool HasLegacyFabric;
// LiteLoader
/// <summary>
/// 该实例是否安装了 LiteLoader。
/// </summary>
public bool HasLiteLoader;
// NeoForge
/// <summary>
/// 该实例是否安装了 NeoForge。
/// </summary>
public bool HasNeoForge;
// OptiFine
/// <summary>
/// 该实例是否通过 JSON 安装了 OptiFine。
/// </summary>
public bool HasOptiFine;
// Quilt
/// <summary>
/// 该实例是否安装了 Quilt。
/// </summary>
public bool HasQuilt;
/// <summary>
/// LabyMod 版本号,如 4.2.59。
/// </summary>
public string LabyMod = "";
/// <summary>
/// Fabric 版本号,如 0.7.2.175。
/// </summary>
public string LegacyFabric = "";
/// <summary>
/// NeoForge 版本号,如 21.0.2-beta、47.1.79。
/// </summary>
public string NeoForge = "";
/// <summary>
/// OptiFine 版本号,如 C8、C9_pre10。
/// </summary>
public string OptiFine = "";
/// <summary>
/// Quilt 版本号,如 0.26.1-beta.1、0.26.0。
/// </summary>
public string Quilt = "";
/// <summary>
/// 指示原版版本号是否可靠(不是通过猜测获取)。
/// </summary>
public bool Reliable = true;
/// <summary>
/// 可比较的三段式原版版本号。
/// 对老版本格式,例如 1.20.3,会被转换为 20.0.3。
/// 若没有版本号,例如旧快照,则为 9999.0.0。
/// </summary>
public Version vanilla;
// 原版
/// <summary>
/// 原版版本名。
/// 如 26.126.1-snapshot-11.12.216w01a。
/// </summary>
public string VanillaName;
/// <summary>
/// 原版版本号是否有效。
/// </summary>
public bool Valid => vanilla.Major < 1000;
/// <summary>
/// 可供比较的原版 Drop 序数。
/// 例如 26.3.2 为 2631.21.5 为 210。
/// 若没有版本号,例如旧快照,则直接指定为 209。
/// </summary>
public int Drop => Valid ? vanilla.Major * 10 + vanilla.Minor : 209;
/// <summary>
/// 可供比较的 OptiFine 版本序数。
/// </summary>
public int OptiFineCode
{
get
{
if (string.IsNullOrEmpty(OptiFine) || OptiFine == Lang.Text("Minecraft.Version.Unknown"))
return 0;
// 字母编号,如 G2 中的 G(7)
var result = char.ToUpperInvariant(OptiFine.First()) - 'A' + 1;
// 末尾数字,如 C5 beta4 中的 5
result *= 100;
result = (int)Math.Round(result +
ModBase.Val(OptiFine[1..].RegexSeek("[0-9]+")));
// 测试标记(正式版为 99Pre[x] 为 50+xBeta[x] 为 x
result *= 100;
if (OptiFine.ContainsF("pre", true))
result += 50;
if (OptiFine.ContainsF("pre", true) || OptiFine.ContainsF("beta", true))
{
var lastChar = OptiFine[^1..];
if (ModBase.Val(lastChar) == 0d && lastChar != "0")
result += 1; // 为 pre 或 beta 结尾,视作 1
else
result =
(int)Math.Round(result +
ModBase.Val(OptiFine.ToLower().RegexSeek("(?<=((pre)|(beta)))[0-9]+")));
}
else
{
result += 99;
}
return result;
}
}
// Forgelike
/// <summary>
/// 该版本是否安装了 Forgelike 加载器。
/// </summary>
public bool HasForgelike => HasForge || HasNeoForge || HasCleanroom;
/// <summary>
/// 可供比较的类 Forge 版本序数。
/// </summary>
public int ForgelikeCode
{
get
{
if (!HasForgelike)
return 0;
if ((string.IsNullOrEmpty(Forge) || Forge == Lang.Text("Minecraft.Version.Unknown")) &&
(string.IsNullOrEmpty(NeoForge) || NeoForge == Lang.Text("Minecraft.Version.Unknown")))
return 0;
var segments = (HasForge ? Forge : NeoForge).RegexSearch(@"\d+");
switch (segments.Count)
{
case var @case when @case > 4:
{
return (int)Math.Round(ModBase.Val(segments[0]) * 1000000d + ModBase.Val(segments[1]) * 10000d +
ModBase.Val(segments[3]));
}
case 3:
{
return (int)Math.Round(ModBase.Val(segments[0]) * 1000000d + ModBase.Val(segments[1]) * 10000d +
ModBase.Val(segments[2]));
}
case 2:
{
return (int)Math.Round(ModBase.Val(segments[0]) * 1000000d + ModBase.Val(segments[1]) * 10000d);
}
default:
{
return (int)Math.Round(ModBase.Val(segments[0]) * 1000000d);
}
}
}
}
// Fabriclike
/// <summary>
/// 该版本是否安装了 Fabriclike 加载器。
/// </summary>
public bool HasFabriclike => HasFabric || HasQuilt || HasLegacyFabric;
// API
/// <summary>
/// 生成对此实例信息的用户友好的描述性字符串。
/// </summary>
public override string ToString()
{
string toStringRet = default;
toStringRet = "";
if (HasForge)
toStringRet += ", Forge" + (Forge == Lang.Text("Minecraft.Version.Unknown") ? "" : " " + Forge);
if (HasNeoForge)
toStringRet += ", NeoForge" +
(NeoForge == Lang.Text("Minecraft.Version.Unknown") ? "" : " " + NeoForge);
if (HasCleanroom)
toStringRet += ", Cleanroom" +
(Cleanroom == Lang.Text("Minecraft.Version.Unknown") ? "" : " " + Cleanroom);
if (HasFabric)
toStringRet += ", Fabric" + (Fabric == Lang.Text("Minecraft.Version.Unknown") ? "" : " " + Fabric);
if (HasLegacyFabric)
toStringRet += ", LegacyFabric" +
(LegacyFabric == Lang.Text("Minecraft.Version.Unknown") ? "" : " " + LegacyFabric);
if (HasQuilt)
toStringRet += ", Quilt" + (Quilt == Lang.Text("Minecraft.Version.Unknown") ? "" : " " + Quilt);
if (HasLabyMod)
toStringRet += ", LabyMod" + (LabyMod == Lang.Text("Minecraft.Version.Unknown") ? "" : " " + LabyMod);
if (HasOptiFine)
toStringRet += ", OptiFine" +
(OptiFine == Lang.Text("Minecraft.Version.Unknown") ? "" : " " + OptiFine);
if (HasLiteLoader)
toStringRet += ", LiteLoader";
if (string.IsNullOrEmpty(toStringRet)) return Lang.Text("Minecraft.Version.Vanilla") + " " + VanillaName;
return VanillaName + toStringRet;
}
// Helpers
/// <summary>
/// 版本字符串是否符合 Minecraft 原版格式,例如 1.x、26.x。
/// </summary>
public static bool IsFormatFit(string version)
{
if (version is null)
return false;
if (version.RegexCheck(@"^1\.\d"))
return true;
if (ModBase.Val(version.RegexSeek(@"^[2-9]\d\.\d+")) > 25d)
return true;
return false;
}
/// <summary>
/// 尝试将版本字符串转换为 Drop 序数。
/// 若无法转换则返回 -1。
/// </summary>
public static int VersionToDrop(string? version, bool allowSnapshot = false)
{
if (string.IsNullOrEmpty(version))
return -1;
var lower = version.ToLowerInvariant();
if (lower.StartsWith("1.rv")) return 90; // 1.rv-pre1,约1.9
if (lower.StartsWith("3d shareware")) return 140; // 3d shareware v1.34,约1.14
if (!allowSnapshot && lower.Contains('-'))
return -1;
var baseVer = lower.BeforeFirst("-");
var segments = baseVer.Split('.');
//XXwYY的快照
// 按年份估算
if (allowSnapshot && segments.Length == 1 && segments[0].Length >= 3
&& segments[0][2] == 'w'
&& char.IsDigit(segments[0][0]) && char.IsDigit(segments[0][1]))
{
var year = int.Parse(segments[0][..2]);
if (year <= 16) return Math.Max(year * 10 - 70, 20);
if (year == 17) return 120;
return Math.Min(130 + (year - 18) * 10, 210);
}
if (segments.Length < 2)
return -1;
var major = (int)Math.Round(ModBase.Val(segments[0]));
var minor = (int)Math.Round(ModBase.Val(segments[1]));
if (major == 1) return minor * 10;
if (major >= 25) return major * 10 + minor;
if (major == 2) return 50; //2.0愚人节
return -1;
}
/// <summary>
/// 将 Drop 序数转换为版本字符串。
/// </summary>
public static string DropToVersion(int drop)
{
if (drop >= 250) return $"{drop / 10}.{drop % 10}";
return $"1.{drop / 10}";
}
}