2.14.0.0
This commit is contained in:
+1
-1
Submodule MeloongCore updated: 811438aa3c...c774ae4c85
+10
-2
@@ -1,13 +1,21 @@
|
||||
namespace PCLCS;
|
||||
public static class Configs {
|
||||
|
||||
/// <summary>当前 Java 相关配置的版本。0 代表尚未从老的 Settings 系统中迁移。</summary>
|
||||
public static readonly DynamicConfigEntry<McInstallManifest> McInstallManifest = new("MinecraftInstallManifest", null);
|
||||
|
||||
// Java
|
||||
|
||||
/// <summary> 当前 Java 相关配置的版本。0 代表尚未从老的 Settings 系统中迁移。</summary>
|
||||
public static readonly ConfigEntry<int> JavaConfigVersion = new("JavaConfigVersion", 0);
|
||||
public static readonly ConfigEntry<ConcurrentList<Java>> JavaList = new("JavaList", []);
|
||||
public static readonly ConfigEntry<List<string>> JavaRemovedList = new("JavaRemovedList", []);
|
||||
public static readonly DynamicConfigEntry<bool> JavaMigrated = new("InstanceMigratedJava", false);
|
||||
public static readonly DynamicConfigEntry<Java> JavaForced = new("InstanceForcedJava", null);
|
||||
|
||||
// 提示
|
||||
|
||||
public static readonly ConfigEntry<bool> HintModifyInstanceWarning = new("HintModifyInstanceWarning", false);
|
||||
|
||||
static Configs() {
|
||||
/// 当 JavaForced 获取到一个不在 JavaList 中的值时,将其重置为 null。
|
||||
JavaForced.PreviewGet += (args, provider) => {
|
||||
@@ -17,4 +25,4 @@ public static class Configs {
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-2
@@ -68,13 +68,17 @@ public static class Versions {
|
||||
/// <summary>
|
||||
/// 版本管理中 Mod 信息缓存的版本号。
|
||||
/// </summary>
|
||||
public const int LocalModCacheVersion = 19;
|
||||
public const int LocalModCacheVersion = 21;
|
||||
/// <summary>
|
||||
/// Minecraft 本地实例信息缓存的版本号。
|
||||
/// </summary>
|
||||
public const int McInstanceCacheVersion = 38;
|
||||
public const int McInstanceCacheVersion = 39;
|
||||
/// <summary>
|
||||
/// Java 相关配置的版本号。
|
||||
/// </summary>
|
||||
public const int JavaConfigVersion = 1;
|
||||
/// <summary>
|
||||
/// Minecraft 安装清单的版本号。
|
||||
/// </summary>
|
||||
public const int McInstallManifestVersion = 1;
|
||||
}
|
||||
|
||||
+3
-3
@@ -87,9 +87,9 @@ namespace PCLCS;
|
||||
|
||||
// 相同检查
|
||||
public bool Equals(Java? other)
|
||||
=> other is not null && string.Equals(Folder, other.Folder, StringComparison.OrdinalIgnoreCase);
|
||||
=> other is not null && PathUtils.IsSame(Folder, other.Folder);
|
||||
public override bool Equals(object? obj) => obj is Java other && Equals(other);
|
||||
public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Folder);
|
||||
public override int GetHashCode() => StringComparer.CurrentCultureIgnoreCase.GetHashCode(PathUtils.ForCompare(Folder));
|
||||
|
||||
/// <summary>用户友好的描述文本。</summary>
|
||||
public override string ToString()
|
||||
@@ -211,7 +211,7 @@ public static class JavaUtils {
|
||||
}
|
||||
// 结果
|
||||
var hasReparsePoint = HasReparsePoint(FileUtils.GetInfo(Path.Combine(targetFolder, "java.exe")));
|
||||
var isSpecialPath = targetFolder.Contains("java8path_target_") || targetFolder.Contains("javapath_target_") || targetFolder.Contains("javatmp") || targetFolder.Contains("system32");
|
||||
var isSpecialPath = targetFolder.ContainsIgnoreCase("java8path_target_") || targetFolder.ContainsIgnoreCase("javapath_target_") || targetFolder.ContainsIgnoreCase("javatmp") || targetFolder.ContainsIgnoreCase("system32");
|
||||
results.Add((targetFolder, hasReparsePoint, isSpecialPath));
|
||||
}
|
||||
} catch (UnauthorizedAccessException) {
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
using System.Globalization;
|
||||
|
||||
namespace PCLCS;
|
||||
|
||||
public static class McUtils {
|
||||
|
||||
/// <summary>
|
||||
/// 比较两个版本名;左侧较新返回正数,相同返回 0,右侧较新返回负数。
|
||||
/// 无法比较两个预发布版的大小。
|
||||
/// 支持的格式:未知版本, 26.1-snapshot-1,1.13.2, 1.7.10-pre4, 1.8_pre, 1.14 Pre-Release 2, 1.14.4 C6
|
||||
/// </summary>
|
||||
public static int CompareVersion(string left, string right) {
|
||||
if (left == right) return 0;
|
||||
if (left == "未知版本" || right == "未知版本") return left == "未知版本" ? 1 : -1;
|
||||
left = left.Lower();
|
||||
right = right.Lower();
|
||||
var leftParts = left.Replace("快照", "snapshot").Replace("预览版", "pre").RegexSearch("[a-z]+|[0-9]+").ToList();
|
||||
var rightParts = right.Replace("快照", "snapshot").Replace("预览版", "pre").RegexSearch("[a-z]+|[0-9]+").ToList();
|
||||
for (int i = 0; ; i++) {
|
||||
if (i >= leftParts.Count && i >= rightParts.Count) return string.Compare(left, right, StringComparison.Ordinal); // 两边均缺失,感觉是一个东西
|
||||
string leftValue = i < leftParts.Count ? leftParts[i] : "0";
|
||||
string rightValue = i < rightParts.Count ? rightParts[i] : "0";
|
||||
if (leftValue == rightValue) continue;
|
||||
int leftNumber = leftValue switch {
|
||||
"rc" => -1,
|
||||
"pre" => -2,
|
||||
"snapshot" => -3,
|
||||
"experimental" => -4,
|
||||
_ => int.TryParse(leftValue, NumberStyles.Integer, CultureInfo.InvariantCulture, out int leftResult) ? leftResult : 0
|
||||
};
|
||||
int rightNumber = rightValue switch {
|
||||
"rc" => -1,
|
||||
"pre" => -2,
|
||||
"snapshot" => -3,
|
||||
"experimental" => -4,
|
||||
_ => int.TryParse(rightValue, NumberStyles.Integer, CultureInfo.InvariantCulture, out int rightResult) ? rightResult : 0
|
||||
};
|
||||
if (leftNumber == 0 && rightNumber == 0) return string.Compare(leftValue, rightValue, StringComparison.Ordinal);
|
||||
if (leftNumber != rightNumber) return leftNumber.CompareTo(rightNumber);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 比较两个版本名;左侧不旧于右侧返回 True。
|
||||
/// </summary>
|
||||
public static bool CompareVersionGE(string left, string right) => CompareVersion(left, right) >= 0;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
namespace PCLCS;
|
||||
|
||||
/// <summary>
|
||||
/// MC 版本安装清单及 PCL 管理文件清单。
|
||||
/// </summary>
|
||||
/// <param name="SchemaVersion"> 清单格式版本;无版本的旧清单为 0。</param>
|
||||
/// <param name="Components"> 安装目标及受管理组件版本。</param>
|
||||
/// <param name="LastModifiedUtc"> 最后修改时间(UTC)。</param>
|
||||
/// <param name="ManagedFiles"> 受管理文件;没有文件时为空列表。</param>
|
||||
public record McInstallManifest(int SchemaVersion, McComponents Components, DateTime LastModifiedUtc, IReadOnlyList<McInstallManifest.ManagedFile> ManagedFiles) {
|
||||
/// <summary>
|
||||
/// 清理以 Mod 形式安装的、已删除或修改的组件的记录,并更新清单。
|
||||
/// </summary>
|
||||
public McInstallManifest RefreshModComponents(string gameFolder) {
|
||||
List<ManagedFile> invalidFiles = [];
|
||||
foreach (ManagedFile entry in ManagedFiles) {
|
||||
if (entry.Component is null) continue; // 不检查非组件文件
|
||||
FileInfo file = new(Path.Combine(gameFolder, entry.RelativePath));
|
||||
if (!file.Exists || file.LastWriteTimeUtc != entry.LastWriteTimeUtc.ToUniversalTime()) invalidFiles.Add(entry);
|
||||
}
|
||||
if (!invalidFiles.Any()) return this;
|
||||
return this with {
|
||||
Components = Components with {
|
||||
OptiFineEntry = invalidFiles.Any(file => file.Component == "OptiFine") ? null : Components.OptiFineEntry,
|
||||
FabricApiVersion = invalidFiles.Any(file => file.Component == "FabricApi") ? null : Components.FabricApiVersion,
|
||||
OptiFabricVersion = invalidFiles.Any(file => file.Component == "OptiFabric") ? null : Components.OptiFabricVersion
|
||||
},
|
||||
ManagedFiles = ManagedFiles.Where(file => !invalidFiles.Contains(file)).ToList(),
|
||||
LastModifiedUtc = DateTime.UtcNow
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 由 PCL 管理并记录的版本内文件。
|
||||
/// </summary>
|
||||
/// <param name="RelativePath"> 相对于游戏目录的文件路径。确保路径为全小写且可比较。</param>
|
||||
/// <param name="Sha1"> 小写的 SHA1。</param>
|
||||
/// <param name="LastWriteTimeUtc"> 目标文件的最后修改时间(UTC)。</param>
|
||||
/// <param name="Component"> 安装器组件名;为空时表示文件由整合包管理。</param>
|
||||
public record ManagedFile(string RelativePath, string Sha1, DateTime LastWriteTimeUtc,
|
||||
[property: JsonProperty(NullValueHandling = NullValueHandling.Ignore)] string? Component = null);
|
||||
}
|
||||
|
||||
/// <param name="MinecraftVersion"> 目标 Minecraft 版本。</param>
|
||||
/// <param name="ModLoaderVersions"> 目标中各个 Mod Loader 的版本;原版为空字典。</param>
|
||||
/// <param name="OptiFineEntry"> OptiFine 条目信息,不安装时为 <see langword="null"/>。</param>
|
||||
/// <param name="FabricApiVersion"> 由 PCL 管理的 Fabric API 版本;不安装时为 <see langword="null"/>。</param>
|
||||
/// <param name="OptiFabricVersion"> 由 PCL 管理的 OptiFabric 版本;不安装时为 <see langword="null"/>。</param>
|
||||
[method: JsonConstructor]
|
||||
public record McComponents(string MinecraftVersion, Dictionary<ModLoaders, string> ModLoaderVersions,
|
||||
[property: JsonProperty(NullValueHandling = NullValueHandling.Ignore)] JObject? OptiFineEntry = null,
|
||||
[property: JsonProperty(NullValueHandling = NullValueHandling.Ignore)] string? FabricApiVersion = null,
|
||||
[property: JsonProperty(NullValueHandling = NullValueHandling.Ignore)] string? OptiFabricVersion = null) {
|
||||
[JsonIgnore]
|
||||
public string? OptiFineVersion => OptiFineEntry?["InstanceName"]?.Value<string>()?.AfterLast("-OptiFine_");
|
||||
public McComponents(string minecraftVersion, JObject? optiFineEntry, string? forgeVersion,
|
||||
string? neoForgeVersion, string? fabricVersion, string? fabricApiVersion, string? optiFabricVersion, string? liteLoaderVersion)
|
||||
: this(minecraftVersion, [], optiFineEntry, fabricApiVersion, optiFabricVersion) {
|
||||
if (forgeVersion is not null) ModLoaderVersions[ModLoaders.Forge] = forgeVersion;
|
||||
if (neoForgeVersion is not null) ModLoaderVersions[ModLoaders.NeoForge] = neoForgeVersion;
|
||||
if (fabricVersion is not null) ModLoaderVersions[ModLoaders.Fabric] = fabricVersion;
|
||||
if (liteLoaderVersion is not null) ModLoaderVersions[ModLoaders.LiteLoader] = liteLoaderVersion;
|
||||
}
|
||||
public bool IsEquivalentTo(McComponents other) =>
|
||||
MinecraftVersion == other.MinecraftVersion &&
|
||||
OptiFineVersion == other.OptiFineVersion &&
|
||||
FabricApiVersion == other.FabricApiVersion &&
|
||||
OptiFabricVersion == other.OptiFabricVersion &&
|
||||
ModLoaderVersions.Count == other.ModLoaderVersions.Count &&
|
||||
ModLoaderVersions.All(entry => other.ModLoaderVersions.TryGetValue(entry.Key, out string? version) && version == entry.Value);
|
||||
}
|
||||
@@ -0,0 +1,295 @@
|
||||
using System.Globalization;
|
||||
|
||||
namespace PCLCS;
|
||||
|
||||
/// <summary>
|
||||
/// Minecraft 版本号和组件信息
|
||||
/// </summary>
|
||||
public sealed class McVersion {
|
||||
/// <summary>
|
||||
/// 原版版本名,如 26.1、26.1-snapshot-1、1.12.2、16w01a。
|
||||
/// </summary>
|
||||
public string VanillaName {
|
||||
get => _vanillaName;
|
||||
set {
|
||||
_vanillaName = value ?? "Unknown";
|
||||
Vanilla = NameToVersion(_vanillaName);
|
||||
}
|
||||
}
|
||||
private string _vanillaName = "Unknown";
|
||||
/// <summary>
|
||||
/// 可比较的三段式原版版本号。
|
||||
/// 旧格式会将次版本号移到主版本号,例如 1.20.1 会转换为 20.0.1,若没有版本号,例如旧快照,则为 9999.0.0。
|
||||
/// </summary>
|
||||
public Version Vanilla = new(9999, 0, 0);
|
||||
/// <summary> 原版版本号是否可靠(不是通过猜测获取)。</summary>
|
||||
public bool Reliable;
|
||||
/// <summary> 原版版本号是否有效。</summary>
|
||||
public bool Valid => Vanilla.Major < 1000;
|
||||
/// <summary> 可供比较的原版 Drop 序数,例如 26.3.2 为 263,1.21.5 为 210;若没有版本号,例如旧快照,则直接指定为 209。</summary>
|
||||
public int Drop => Valid ? Vanilla.Major * 10 + Vanilla.Minor : 209;
|
||||
/// <summary> 已安装的 Mod Loader,可能有多个。未安装时为 <see cref="ModLoaders.None"/>。</summary>
|
||||
public ModLoaders ModLoaders => ModLoaderVersions.Keys.Aggregate(ModLoaders.None, (result, loader) => result | loader);
|
||||
/// <summary> 已安装的各个 Mod Loader 及其版本;无法确定精确版本时为“未知版本”。</summary>
|
||||
public Dictionary<ModLoaders, string> ModLoaderVersions { get; } = [];
|
||||
/// <summary> OptiFine 版本名,如 C8、C9_pre10;未识别到时为 null。</summary>
|
||||
public string? OptiFine;
|
||||
/// <summary> OptiFine 是否以 Mod 形式安装。</summary>
|
||||
public bool OptiFineAsMod;
|
||||
/// <summary> 版本的发布时间。</summary>
|
||||
public DateTime ReleaseTime = new(1970, 1, 1, 15, 0, 0);
|
||||
/// <summary> 是否为愚人节版本。</summary>
|
||||
public bool IsFool;
|
||||
/// <summary> 是否为快照、预发布版、发布候选或实验性版本。</summary>
|
||||
public bool IsSnapshot;
|
||||
/// <summary> 是否识别到已安装的 OptiFine。</summary>
|
||||
public bool HasOptiFine => OptiFine is not null;
|
||||
/// <summary>
|
||||
/// 可供比较的 OptiFine 版本序数。
|
||||
/// </summary>
|
||||
public int OptiFineCode {
|
||||
get {
|
||||
if (OptiFine is null or "未知版本" || OptiFine.Length == 0) return 0;
|
||||
// 字母编号,如 G2 中的 G(7)
|
||||
int result = char.ToUpperInvariant(OptiFine[0]) - 'A' + 1;
|
||||
// 末尾数字,如 C5 beta4 中的 5
|
||||
result = result * 100 + (int.TryParse(OptiFine.Substring(1).RegexSeek(@"\d+"), out int mainVersion) ? mainVersion : 0);
|
||||
// 测试标记(正式版为 99,Pre[x] 为 50+x,Beta[x] 为 x)
|
||||
result *= 100;
|
||||
string? preview = OptiFine.RegexSeek(@"(?i)(pre|beta)\d*");
|
||||
if (preview is null) return result + 99;
|
||||
int sequence = int.TryParse(preview.RegexSeek(@"\d+"), out int value) ? value : 1; // 为 pre 或 beta 结尾,视作 1
|
||||
return result + (preview.StartsWithF("pre", true) ? 50 : 0) + sequence;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 可供比较的类 Forge 版本序数。
|
||||
/// </summary>
|
||||
public int ForgelikeCode {
|
||||
get {
|
||||
if (!ModLoaderVersions.TryGetValue(ModLoaders.Forge, out string? version)) {
|
||||
ModLoaderVersions.TryGetValue(ModLoaders.NeoForge, out version);
|
||||
}
|
||||
if (version is null or "未知版本") return 0;
|
||||
// 提取所有数字段,以兼容 beta、alpha 和 snapshot 等非数字后缀。
|
||||
int[] segments = version.RegexSearch(@"\d+")
|
||||
.Select(segment => int.TryParse(segment, out int value) ? value : 0).ToArray();
|
||||
return segments.Length switch {
|
||||
>= 4 => segments[0] * 1000000 + segments[1] * 10000 + segments[3],
|
||||
3 => segments[0] * 1000000 + segments[1] * 10000 + segments[2],
|
||||
2 => segments[0] * 1000000 + segments[1] * 10000,
|
||||
1 => segments[0] * 1000000,
|
||||
_ => 0
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建默认 Minecraft 版本。
|
||||
/// </summary>
|
||||
/// <param name="vanillaName">原版版本名。</param>
|
||||
/// <param name="reliable">版本名是否来自可靠依据。</param>
|
||||
public McVersion(string vanillaName, bool reliable = true) {
|
||||
Reliable = reliable;
|
||||
VanillaName = vanillaName;
|
||||
IsFool = IsFoolName(VanillaName);
|
||||
IsSnapshot = IsSnapshotName(VanillaName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过 Components 创建 Minecraft 版本信息。
|
||||
/// </summary>
|
||||
public McVersion(McComponents components) : this(components.MinecraftVersion) {
|
||||
OptiFine = components.OptiFineVersion?.AfterLast("HD_").AfterFirst("_");
|
||||
foreach (var loader in components.ModLoaderVersions) ModLoaderVersions[loader.Key] = loader.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过 JSON 识别 Minecraft 版本和已安装组件。
|
||||
/// </summary>
|
||||
/// <param name="instanceName">实例文件夹名。</param>
|
||||
/// <param name="json">展开的版本 JSON。</param>
|
||||
/// <param name="jarVersionJson">版本 JAR 中的 version.json。</param>
|
||||
public McVersion(string instanceName, JObject json, JObject? jarVersionJson = null) {
|
||||
string jsonText = json.ToString(Formatting.None);
|
||||
DateTime releaseTime = new(1970, 1, 1, 15, 0, 0); // 未知版本也可能显示为 1970 年
|
||||
try {
|
||||
if (json["releaseTime"] is JToken releaseTimeToken) releaseTime = releaseTimeToken.ToObject<DateTime>();
|
||||
} catch {
|
||||
}
|
||||
bool reliable = true;
|
||||
// 获取游戏版本
|
||||
string vanillaName = (GetVanillaName(instanceName, json, jarVersionJson, releaseTime, ref reliable) ?? "Unknown").Replace("_unobfuscated", "").Replace(" Unobfuscated", "");
|
||||
Reliable = reliable;
|
||||
VanillaName = vanillaName;
|
||||
ReleaseTime = releaseTime;
|
||||
// 确定版本分类
|
||||
string jsonType = json.Value<string>("type") ?? "";
|
||||
// OptiFine
|
||||
OptiFine = jsonText.ContainsIgnoreCase("optifine") ? jsonText.RegexSeek(@"(?<=HD_U_)[^\"":/]+") ?? "未知版本": null;
|
||||
// 愚人节与快照版本
|
||||
DateTime fixedReleaseTime = releaseTime.ToUniversalTime().AddHours(2);
|
||||
IsFool = jsonType == "fool" || IsFoolName(vanillaName) || (fixedReleaseTime.Month == 4 && fixedReleaseTime.Day == 1 && jsonType == "snapshot");
|
||||
IsSnapshot = IsSnapshotName(vanillaName) || instanceName.ContainsIgnoreCase("combat") || jsonType is "snapshot" or "pending" or "fool";
|
||||
if (!Reliable) Logger.Info($"无法完全确认 MC 版本号的版本:{VanillaName}");
|
||||
// LiteLoader
|
||||
if (jsonText.ContainsIgnoreCase("liteloader")) {
|
||||
ModLoaderVersions[ModLoaders.LiteLoader] = jsonText.RegexSeek(@"(?<=com\.mumfrey:liteloader:)[^\"":/]+") ?? "未知版本";
|
||||
}
|
||||
// Fabric、Forge、NeoForge
|
||||
if (jsonText.ContainsIgnoreCase("net.fabricmc:fabric-loader") || jsonText.ContainsIgnoreCase("org.quiltmc:quilt-loader")) {
|
||||
ModLoaderVersions[ModLoaders.Fabric] = jsonText.RegexSeek(@"(?<=(net\.fabricmc:fabric-loader:|org\.quiltmc:quilt-loader:))[0-9\.]+(\+build.[0-9]+)?")?
|
||||
.Replace("+build", "") ?? "未知版本";
|
||||
} else if (jsonText.ContainsIgnoreCase("net.neoforge")) {
|
||||
// 1.20.1 JSON 范例:"--fml.forgeVersion", "47.1.99"
|
||||
// 1.20.2+ JSON 范例:"--fml.neoForgeVersion", "20.6.119-beta"
|
||||
ModLoaderVersions[ModLoaders.NeoForge] = FindArgumentValue(json, "--fml.neoForgeVersion") ?? FindArgumentValue(json, "--fml.forgeVersion") ?? "未知版本";
|
||||
} else if (jsonText.ContainsIgnoreCase("minecraftforge")) {
|
||||
ModLoaderVersions[ModLoaders.Forge] = jsonText.RegexSeek(@"(?<=forge:[0-9\.]+(?:_pre[0-9]*)?-)[0-9\.]+")
|
||||
?? jsonText.RegexSeek(@"(?<=net\.minecraftforge:minecraftforge:)[0-9\.]+")
|
||||
?? jsonText.RegexSeek(@"(?<=net\.minecraftforge:fmlloader:[0-9\.]+-)[0-9\.]+") ?? "未知版本";
|
||||
}
|
||||
}
|
||||
|
||||
private static string? GetVanillaName(string instanceName, JObject json, JObject? jarVersionJson, DateTime releaseTime, ref bool reliable) {
|
||||
// 获取发布时间并判断是否为老版本
|
||||
if (releaseTime.Year is > 2000 and < 2013) return "Old";
|
||||
// 实验性快照
|
||||
if (json.Value<string>("type") == "pending") return "pending";
|
||||
// 从 PCL 下载的版本信息中获取版本号
|
||||
if (json["clientVersion"] is JToken clientVersion) return clientVersion.ToString();
|
||||
// 从 HMCL 下载的版本信息中获取版本号
|
||||
if (json["patches"] is JArray patches) {
|
||||
JToken? gameVersion = patches.OfType<JObject>().FirstOrDefault(patch => patch.Value<string>("id") == "game")?["version"];
|
||||
if (gameVersion is not null) return gameVersion.ToString();
|
||||
}
|
||||
// 从 Forge / NeoForge Arguments 中获取版本号
|
||||
if (FindArgumentValue(json, "--fml.mcVersion") is { Length: > 0 } fmlVersion) return fmlVersion;
|
||||
// 从继承版本中获取版本号
|
||||
string inherit = json["inheritsFrom"]?.ToString() ?? "";
|
||||
if (inherit.Length > 0) {
|
||||
string jar = json["jar"]?.ToString() ?? ""; // LiteLoader 优先使用 Jar
|
||||
return jar.Length > 0 ? jar : inherit;
|
||||
}
|
||||
// 从下载地址中获取版本号
|
||||
string? download = json["downloads"]?.ToString(Formatting.None).RegexSeek(@"(?<=launcher.mojang.com/mc/game/)[^/]*");
|
||||
if (download is not null) return download;
|
||||
// 从 Forge/OptiFine/Fabric 版本中获取版本号
|
||||
string librariesText = json["libraries"]!.ToString();
|
||||
string[] libraryPatterns = [
|
||||
@"(?<=net.minecraftforge:forge:)[0-9]{1,2}.[0-9+.]+",
|
||||
@"(?<=net.minecraftforge:fmlloader:)[0-9]{1,2}.[0-9+.]+",
|
||||
@"(?<=optifine:OptiFine:)[0-9]{1,2}.[0-9+.]+",
|
||||
@"(?<=((fabricmc)|(quiltmc)):intermediary:)[^\""]*"
|
||||
];
|
||||
foreach (string pattern in libraryPatterns) {
|
||||
if (librariesText.RegexSeek(pattern) is string match) return match;
|
||||
}
|
||||
// 从 jar 项中获取版本号
|
||||
if (json["jar"] is JToken jarToken) return jarToken.ToString();
|
||||
// 从 jar 文件的 version.json 中获取版本号
|
||||
if (jarVersionJson?["name"] is JToken jarNameToken && jarNameToken.ToString() is { Length: < 32 } jarName) { // 因为 wiki 说这玩意儿可能是个 hash,虽然我没发现
|
||||
Logger.Info($"从版本 jar 中的 version.json 获取到版本号:{jarName}");
|
||||
return jarName;
|
||||
}
|
||||
string VersionPattern = @"(([1-9][0-9]w[0-9]{2}[a-g])|((1|[2-9][0-9])\.[0-9]+(\.[0-9]+)?(-(pre|rc|snapshot-?)[1-9]*| Pre-Release( [1-9])?)?))(_unobfuscated)?";
|
||||
// 从 JSON 的 ID 中获取
|
||||
if (json["id"]!.ToString().RegexSeek(VersionPattern, RegexOptions.IgnoreCase) is string idMatch) return idMatch;
|
||||
// 非准确的版本判断警告
|
||||
Logger.Info($"无法完全确认 MC 版本号的版本:{instanceName}");
|
||||
reliable = false;
|
||||
// 从文件夹名中获取
|
||||
if (instanceName.RegexSeek(VersionPattern, RegexOptions.IgnoreCase) is string folderMatch) return folderMatch;
|
||||
// 从 JSON 出现的版本号中获取
|
||||
JObject withoutLibraries = (JObject) json.DeepClone();
|
||||
withoutLibraries.Remove("libraries");
|
||||
return withoutLibraries.ToString(Formatting.None).RegexSeek(VersionPattern, RegexOptions.IgnoreCase);
|
||||
}
|
||||
|
||||
private static bool IsFoolName(string name) {
|
||||
name = name.Lower();
|
||||
return name.StartsWithF("2.0") || name is "15w14a" or "1.rv-pre1" or
|
||||
"3d shareware v1.34" or "20w14∞" or "22w13oneblockatatime" or "23w13a_or_b" or
|
||||
"24w14potato" or "25w14craftmine" or "26w14a" || name.StartsWithF("20w14inf");
|
||||
}
|
||||
|
||||
private static bool IsSnapshotName(string name) =>
|
||||
new[] { "w", "snapshot", "rc", "pre", "experimental", "-" }.Any(name.ContainsIgnoreCase);
|
||||
|
||||
/// <summary>
|
||||
/// 读取 arguments 中指定参数的字符串值。
|
||||
/// </summary>
|
||||
private static string? FindArgumentValue(JObject json, string name) {
|
||||
JArray? arguments = json["arguments"]?["game"] as JArray;
|
||||
if (arguments is null) return null;
|
||||
for (int i = 0; i + 1 < arguments.Count; i++) {
|
||||
if (arguments[i]?.ToString() == name) return arguments[i + 1]?.ToString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断版本字符串是否符合 Minecraft 原版格式,例如 1.x、26.x。
|
||||
/// </summary>
|
||||
public static bool IsStandardFormat(string? version) {
|
||||
if (version is null) return false;
|
||||
if (Regex.IsMatch(version, @"^1\.\d")) return true;
|
||||
return double.TryParse(version.RegexSeek(@"^[2-9]\d\.\d+"), NumberStyles.Float,
|
||||
CultureInfo.InvariantCulture, out double value) && value >= 26;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将版本名转换为 Drop 序数;无法转换时返回 209。
|
||||
/// </summary>
|
||||
public static int VersionToDrop(string? vanillaName) {
|
||||
if (vanillaName is null) return 209;
|
||||
Version version = NameToVersion(vanillaName);
|
||||
return version.Major >= 1000 ? 209 : version.Major * 10 + version.Minor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将 Drop 序数转换为版本字符串。
|
||||
/// </summary>
|
||||
public static string DropToVersion(int drop) {
|
||||
if (drop >= 250) return $"{drop / 10}.{drop % 10}";
|
||||
if (drop != 209) return $"1.{drop / 10}";
|
||||
Logger.Warn(new Exception("尝试将旧快照版 Drop 序数转换为版本字符串,这不应该发生!"));
|
||||
return "1.20";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将版本名转换为可比较的三段式原版版本号。
|
||||
/// 对老版本格式,例如 1.20.3,会被转换为 20.0.3。
|
||||
/// 对愚人节版本,返回其基于的正式版版本号。
|
||||
/// 若没有版本号,例如旧快照,则为 9999.0.0。
|
||||
/// </summary>
|
||||
public static Version NameToVersion(string? name) {
|
||||
if (name is null) return new Version(9999, 0, 0);
|
||||
name = name.Lower().Replace("_unobfuscated", "").Replace(" unobfuscated", "");
|
||||
// 愚人节版本
|
||||
if (name.StartsWithF("2.0")) return NameToVersion("1.5.1");
|
||||
if (name == "15w14a") return NameToVersion("1.8.3");
|
||||
if (name.ContainsIgnoreCase(".rv-pre")) return NameToVersion("1.9.2");
|
||||
if (name.ContainsIgnoreCase("shareware")) return NameToVersion("1.13.2");
|
||||
if (name.StartsWithF("20w14") && name != "20w14a") return NameToVersion("1.15.2");
|
||||
if (name.ContainsIgnoreCase("oneblockatatime")) return NameToVersion("1.18.2");
|
||||
if (name.ContainsIgnoreCase("23w13a") && name != "20w13a") return NameToVersion("1.19.4");
|
||||
if (name == "24w14potato") return NameToVersion("1.20.4");
|
||||
if (name == "25w14craftmine") return NameToVersion("1.21.4");
|
||||
if (name == "26w14a") return NameToVersion("26.1.1");
|
||||
// 其余版本
|
||||
static int ParseSegment(string[] segments, int index) {
|
||||
if (index >= segments.Length) return 0;
|
||||
// 只读取该段开头连续的数字,忽略其后的预览版标记。
|
||||
return int.TryParse(segments[index].RegexSeek(@"^\d+"), out int value) ? value : 0;
|
||||
}
|
||||
string[] segments = name.Split([' ', '_', '-', '.'], StringSplitOptions.None);
|
||||
if (name.StartsWithF("1.")) {
|
||||
return new Version(ParseSegment(segments, 1), 0, ParseSegment(segments, 2));
|
||||
} else if (name.RegexCheck(@"^[2-9][0-9]\.")) {
|
||||
return new Version(ParseSegment(segments, 0), ParseSegment(segments, 1), ParseSegment(segments, 2));
|
||||
} else {
|
||||
return new Version(9999, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,423 @@
|
||||
{
|
||||
"f3a3c9d792bdb48595405d52c02cc7baf1db4ecb": "OptiFine_1.7.2_HD_U_E3.jar",
|
||||
"657169c421ce280f80c73b05ab71ad582d2b37fd": "OptiFine_1.7.2_HD_U_E4.jar",
|
||||
"99f20d449912cd860b409e4679c54dd8da43d55e": "OptiFine_1.7.2_HD_U_E7.jar",
|
||||
"8253f6ed418a2a61a612cc9e69fd1fea1d11fa7d": "OptiFine_1.7.2_HD_U_E8.jar",
|
||||
"379e52fc02cd75562d201b0c505269b6109b2136": "OptiFine_1.7.2_HD_U_F3.jar",
|
||||
"fb04b91e47b5eaa172d2b76c843e488dba8f909b": "OptiFine_1.7.2_HD_U_F7.jar",
|
||||
"b4b6c2c99f5734e4267030a47f2eaad2796eb2a7": "OptiFine_1.7.10_HD_U_D3.jar",
|
||||
"a0b533bc97b24fe771f5b08536c6339d04f92bae": "OptiFine_1.7.10_HD_U_D4.jar",
|
||||
"5e9327dd05a1e762c23c3c0227445d90f193922f": "OptiFine_1.7.10_HD_U_D6.jar",
|
||||
"7a7d2adf21038d241dd375faa7316fb2c74d34d3": "OptiFine_1.7.10_HD_U_D7.jar",
|
||||
"2345677be44dd56a0ae5b90e747a590c3cc00ff8": "OptiFine_1.7.10_HD_U_D8.jar",
|
||||
"23f133173428aee712eb11f200b461e3114bde31": "OptiFine_1.7.10_HD_U_E3.jar",
|
||||
"2130d7266224da6a7325051e37444f7e7c19277c": "OptiFine_1.7.10_HD_U_E7.jar",
|
||||
"55c9c475ecd0f62cc1776ce52be04c5937112936": "OptiFine_1.8.0_HD_U_H5.jar",
|
||||
"bb2c2997cdc66cfb3c311a3dc065752a4845c1a8": "OptiFine_1.8.0_HD_U_H6.jar",
|
||||
"692b0b7e878c3416f21b4347fab4516f3cc86dfc": "OptiFine_1.8.0_HD_U_H7.jar",
|
||||
"5464962b66b9b0dacb3d787e6a71d2365ae50bca": "OptiFine_1.8.0_HD_U_H8.jar",
|
||||
"b7718b03111bec04036fd3352ce374eea273171c": "OptiFine_1.8.0_HD_U_I3.jar",
|
||||
"0d1dcf64b4d104a71e8f65a1362a163ed81a9030": "OptiFine_1.8.0_HD_U_I7.jar",
|
||||
"e5e5eb03748af0fa160b502a28359c0144e254d2": "OptiFine_1.8.8_HD_U_H5.jar",
|
||||
"9294bc4562a143c35ece03a6b3d3a000109def5f": "OptiFine_1.8.8_HD_U_H6.jar",
|
||||
"1c06c011904ab22952a96f73d4b575a5c265d207": "OptiFine_1.8.8_HD_U_H7.jar",
|
||||
"3984e4dd222bb62cb7e28e4d3092029cc7534fd1": "OptiFine_1.8.8_HD_U_H8.jar",
|
||||
"0dc33a9761ceac19ca0bbb1ea6813c0160d43aa1": "OptiFine_1.8.8_HD_U_I3.jar",
|
||||
"30cbf4d61052cbfb736a78117da333df23c129a3": "OptiFine_1.8.8_HD_U_I7.jar",
|
||||
"d8240cfa7387b994fdf2a64bdc8a8860857adc18": "OptiFine_1.8.9_HD_U_H5.jar",
|
||||
"2636689b31810896cf80493f6fc4d8c1783048ea": "OptiFine_1.8.9_HD_U_H6.jar",
|
||||
"e4544c9210bc056abffa1986a33c4e72623d4f31": "OptiFine_1.8.9_HD_U_H7.jar",
|
||||
"4b73738913453bcbca969d3e77f05ae0cf5b8a7e": "OptiFine_1.8.9_HD_U_H8.jar",
|
||||
"d5cd8b902077075bbf1d865cfd5b3362a6863ace": "OptiFine_1.8.9_HD_U_I3.jar",
|
||||
"58bec8f8766918dcad2b8412f1fbb6f30cc9319f": "OptiFine_1.8.9_HD_U_I7.jar",
|
||||
"dcab4849a24ccad5a6a3496c67bc5a88411d2a35": "OptiFine_1.8.9_HD_U_L5.jar",
|
||||
"d362d58a28f5373b141b9e426e8e160638bfafcd": "OptiFine_1.8.9_HD_U_M5.jar",
|
||||
"1f9dcc9735e94ebb5195c4014300ea462eb12878": "preview_OptiFine_1.8.9_HD_U_L6_pre1.jar",
|
||||
"6e0b3b86e51c2647c98e277475ee7e68f32a0d0e": "preview_OptiFine_1.8.9_HD_U_M5_pre2.jar",
|
||||
"7287fcd1a415ab87eca5e89457cc3507aa3fa579": "preview_OptiFine_1.8.9_HD_U_M6_pre1.jar",
|
||||
"0bb792be16ec78d8b62586cc4856950befb3391b": "preview_OptiFine_1.8.9_HD_U_M6_pre2.jar",
|
||||
"fd87c53197312614c34669feb7608f74a30da712": "OptiFine_1.9.0_HD_U_B1.jar",
|
||||
"f99941037f3633926ffebb3eda67f296a701c019": "OptiFine_1.9.0_HD_U_B2.jar",
|
||||
"34c47106cda1371ecf13e61aed4c1b53a3a53163": "OptiFine_1.9.0_HD_U_B3.jar",
|
||||
"ebc7258e13344097588c73a0b48457083069e1df": "OptiFine_1.9.0_HD_U_B5.jar",
|
||||
"999df92e8904f9268e549135edbec322d332ef62": "OptiFine_1.9.0_HD_U_D7.jar",
|
||||
"0fe031e95f9c01481c9376d9a1df68f9e9857db8": "OptiFine_1.9.0_HD_U_D8.jar",
|
||||
"f4bc2eb5e039e842eb07181ea564eba487513228": "OptiFine_1.9.0_HD_U_E3.jar",
|
||||
"78870a94ec3c4db8aebc4c29d4d39bdda2bf05da": "OptiFine_1.9.0_HD_U_E7.jar",
|
||||
"d3d55bb37e76d1932cb3ad9dde4b9127993f856d": "OptiFine_1.9.0_HD_U_H5.jar",
|
||||
"b5faec3b84f42dd396512a3ce7c1b57c0b972b70": "OptiFine_1.9.0_HD_U_I5.jar",
|
||||
"92742ecac143b1d28c215ca145bd9775a01c5085": "preview_OptiFine_1.9.0_HD_U_I5_pre1.jar",
|
||||
"c87029938376017deba9108322bcb8424d64e92c": "OptiFine_1.9.2_HD_U_B1.jar",
|
||||
"d3e5e1fa480e66603ca037d74966a95d25968d51": "OptiFine_1.9.2_HD_U_B2.jar",
|
||||
"fbd545f921d098235a28f87cda55a0504e831954": "OptiFine_1.9.2_HD_U_B3.jar",
|
||||
"1ae8e6daeeccb6ee48618e8ccdc0b6276d47944f": "OptiFine_1.9.2_HD_U_D7.jar",
|
||||
"3350c829b29d170e9ac19809a3ae45cb099277b5": "OptiFine_1.9.2_HD_U_D8.jar",
|
||||
"c032b2ae0b6087077efef8ae89b612e0d4ea81b7": "OptiFine_1.9.2_HD_U_E3.jar",
|
||||
"3d8cbc19bcad9e9ecc98f607e10f65673a09b482": "OptiFine_1.9.4_HD_U_B4.jar",
|
||||
"b6b9e66b34ddcda5294b016602fb17d741ff6f54": "OptiFine_1.9.4_HD_U_B5.jar",
|
||||
"060ddd5a0b7b7ac5586de04ae53cf923ae5c7290": "OptiFine_1.9.4_HD_U_B6.jar",
|
||||
"2c39611a89dc583cdb403f402c2efd2bd8c6da63": "OptiFine_1.9.4_HD_U_D7.jar",
|
||||
"4b26926208de270225eb9d3af24a4ff3841238f5": "OptiFine_1.9.4_HD_U_D8.jar",
|
||||
"012f82fce41aee5e6e56e551d450a07b2b361646": "OptiFine_1.9.4_HD_U_E3.jar",
|
||||
"cf9c075fa71dab34cdf1c376a76bd08295c69ce6": "OptiFine_1.9.4_HD_U_E7.jar",
|
||||
"b3a76b92e0e9594f6fa135f1156b9cc13712db20": "OptiFine_1.9.4_HD_U_H5.jar",
|
||||
"68a206db0d425dd85f6eba33e52122b01e844c46": "OptiFine_1.9.4_HD_U_I5.jar",
|
||||
"2e48d20605340cfad844a6587d3848e328fd4399": "preview_OptiFine_1.9.4_HD_U_I5_pre1.jar",
|
||||
"d7a1e5f40e28fa3283b82bf3af7d3f433b91df08": "OptiFine_1.10_HD_U_B6.jar",
|
||||
"717a02b21136e022cdb4d7d6ec6a4125f4ed2312": "OptiFine_1.10_HD_U_B7.jar",
|
||||
"0b5d1719592a57cf414643c5b56f4bb3c23a5b94": "OptiFine_1.10_HD_U_C1.jar",
|
||||
"236747126edcf0c97fc6a20fa7f6491accbf0108": "OptiFine_1.10_HD_U_D7.jar",
|
||||
"c5fd78710e821f06f871994032e951065c15c40d": "OptiFine_1.10_HD_U_D8.jar",
|
||||
"1bea8b0bae04ca4b25c6824a6f23a5442d5aa926": "OptiFine_1.10_HD_U_E3.jar",
|
||||
"7a7195348ea583458b657573b5fcc72e4adc8308": "OptiFine_1.10_HD_U_E7.jar",
|
||||
"3bcc46f718711cd6fe3db49de4cc810b75420de8": "OptiFine_1.10_HD_U_H5.jar",
|
||||
"a0070afe9c1c0ced4bcfcda85359e07917d569bd": "OptiFine_1.10_HD_U_I5.jar",
|
||||
"f9a36eb0246ad6ba303e670082be2c2515c50dcd": "preview_OptiFine_1.10_HD_U_I5_pre1.jar",
|
||||
"3ea5dae651b6d64900562d1cde5070ebd9db2936": "OptiFine_1.10.2_HD_U_C1.jar",
|
||||
"41968442e8d1e30e9a32e7a5594caca22312d9d6": "OptiFine_1.10.2_HD_U_C2.jar",
|
||||
"9c8bc96d3125199e96f5dbfda685ea5dd92c253e": "OptiFine_1.10.2_HD_U_C3.jar",
|
||||
"7ec4ccc213b482936baaffb9f1937f7147796893": "OptiFine_1.10.2_HD_U_D1.jar",
|
||||
"3ee5aecc8e11567fb46de0b94e23cf1428f4c9fc": "OptiFine_1.10.2_HD_U_D2.jar",
|
||||
"98059ed7e93d0fc058203569ccfe965b022fb18f": "OptiFine_1.10.2_HD_U_D3.jar",
|
||||
"c3165d0a0207d72e18f4533e7aa5ca30e96819a9": "OptiFine_1.10.2_HD_U_D4.jar",
|
||||
"347359aef422d64711b470f4cf0803cb072da0fa": "OptiFine_1.10.2_HD_U_D6.jar",
|
||||
"4ddf7c45e00839031f5793451541bca002f9257f": "OptiFine_1.10.2_HD_U_D7.jar",
|
||||
"5c3685e279c664a818c41ca213b2bc9bfc4340b0": "OptiFine_1.10.2_HD_U_D8.jar",
|
||||
"129581af3d7d73b506b42d822cb2d3fce68c8e2e": "OptiFine_1.10.2_HD_U_E3.jar",
|
||||
"f052d269109154d851cc7a8e766c78802a76e9b2": "OptiFine_1.10.2_HD_U_E7.jar",
|
||||
"f285cfe6753c5d987e4cb0940da05e9513334d98": "OptiFine_1.10.2_HD_U_H5.jar",
|
||||
"12fd8dd33150f9e4436f23bac08265305f949e20": "OptiFine_1.10.2_HD_U_I5.jar",
|
||||
"adac69b25bb95242422a635965c7f17503c694be": "preview_OptiFine_1.10.2_HD_U_I5_pre1.jar",
|
||||
"06031e4c828b66facefdfa32cd29c585909d9e45": "OptiFine_1.11_HD_U_B1.jar",
|
||||
"449aef14cee17cf1c79d4bad73b69107202d3c1c": "OptiFine_1.11_HD_U_B2.jar",
|
||||
"7663e1ee572c742e96a71a355f0775baf7cbc6ef": "OptiFine_1.11_HD_U_B3.jar",
|
||||
"bde9d34f84a030734c7b9d09eda700c7c828eb96": "OptiFine_1.11_HD_U_B5.jar",
|
||||
"579cfb75b86f3404c5f6e8f694c51b09b7c9b261": "OptiFine_1.11_HD_U_B6.jar",
|
||||
"350af22b31dbc27d1b928e7144582fd361deb193": "OptiFine_1.11_HD_U_B7.jar",
|
||||
"236161183cc5cd5faf84dd27824cc3eaa107ed5f": "OptiFine_1.11_HD_U_B8.jar",
|
||||
"9ca32d42c7e5ad9de9665ffee9ddd41dddd33b66": "OptiFine_1.11_HD_U_C3.jar",
|
||||
"2e45de9e9fb385f24c6eecb1a64537de78778105": "OptiFine_1.11_HD_U_C7.jar",
|
||||
"32df58fec7148e75b599b18691f80e69b7f9cd1b": "OptiFine_1.11_HD_U_F5.jar",
|
||||
"71057cb7a3d0971c3b56e1fbbc333304a72e1352": "OptiFine_1.11_HD_U_G5.jar",
|
||||
"c2ee1e1019ab26bee56447f4df8a2639d2029925": "preview_OptiFine_1.11_HD_U_G5_pre1.jar",
|
||||
"083a002215e2174c0d40af20d2f3844ea349a354": "OptiFine_1.11.2_HD_U_B5.jar",
|
||||
"eb92ce00048faa95b184d121fa667074532fb9db": "OptiFine_1.11.2_HD_U_B6.jar",
|
||||
"7449a2db44e86303d588b526dc73127c16b0e94f": "OptiFine_1.11.2_HD_U_B7.jar",
|
||||
"3e1006c935fe27d83459e77d336460ac5b5c81b4": "OptiFine_1.11.2_HD_U_B8.jar",
|
||||
"049e7e134e8c7364ab61810d84289394e17921de": "OptiFine_1.11.2_HD_U_B9.jar",
|
||||
"4871f2edf7ded30c374aa770e9ea4adcc0b786d0": "OptiFine_1.11.2_HD_U_C1.jar",
|
||||
"e7a54d9e203a1b951f8373ab6dcdedb348e536b1": "OptiFine_1.11.2_HD_U_C2.jar",
|
||||
"8d7fd0facc2299f3dad9dc7c19cc13f72a780343": "OptiFine_1.11.2_HD_U_C3.jar",
|
||||
"20db26eaafb1c4ebd99e1dc2fffe4a62456bf60e": "OptiFine_1.11.2_HD_U_C7.jar",
|
||||
"e4efcf05086389fe18d6fe62eb8ab7512a07323c": "OptiFine_1.11.2_HD_U_F5.jar",
|
||||
"65c425ab628d1748b489dee8619271402428509e": "OptiFine_1.11.2_HD_U_G5.jar",
|
||||
"f253807a4689e44da030acd5c2187d2184885e87": "preview_OptiFine_1.11.2_HD_U_G5_pre1.jar",
|
||||
"1fdacab6f3b0df1f46142acf9c427db2a653d680": "OptiFine_1.12_HD_U_C2.jar",
|
||||
"a62a02c8437a0dccaf2ea89ab8392fd40dc92eb1": "OptiFine_1.12_HD_U_C3.jar",
|
||||
"36d6f6f64048f68dd248a4d3c43a6f5e51fbb9c5": "OptiFine_1.12_HD_U_C4.jar",
|
||||
"fd8e0e3ba43568e5ca0ce31c87373806d269b7e5": "OptiFine_1.12_HD_U_C5.jar",
|
||||
"25ba634e5105e6d1e615dad0046905b68313cc9f": "OptiFine_1.12_HD_U_C7.jar",
|
||||
"b9cd2775fc49bf009f82d3ce36235b1e702d46bb": "OptiFine_1.12_HD_U_F5.jar",
|
||||
"3b8369d33c3257cb247c22b13a41b7db0924e948": "OptiFine_1.12_HD_U_G5.jar",
|
||||
"aeee885ccf821c34d86537184389873d8c312ae1": "preview_OptiFine_1.12_HD_U_G5_pre1.jar",
|
||||
"c754771bf6a7371a7084459505c244cbec61a7cf": "OptiFine_1.12.1_HD_U_C5.jar",
|
||||
"4362a9d38542b5f4ba07782fc4d07949f4fede08": "OptiFine_1.12.1_HD_U_C6.jar",
|
||||
"38785968beeb796cde55f91995c6cf8bfbc3b062": "OptiFine_1.12.1_HD_U_C7.jar",
|
||||
"e6f9e6b573119c052062192695fed4ef388db9c1": "OptiFine_1.12.1_HD_U_F5.jar",
|
||||
"3c9cd74810cad75de5091633a1e0c7d3d76ea09c": "OptiFine_1.12.1_HD_U_G5.jar",
|
||||
"aaaaff3ae13a0cdffa2475632cf6303b9f86e0b0": "preview_OptiFine_1.12.1_HD_U_G5_pre1.jar",
|
||||
"a9d21f084a485bc12fce8c9bea1660c6d4b08855": "OptiFine_1.12.2_HD_U_C5.jar",
|
||||
"2159a0a754828d63446fca7b6f8fa57b710c6048": "OptiFine_1.12.2_HD_U_C6.jar",
|
||||
"8ed8009fc82b43909190882927f335d5250a0e19": "OptiFine_1.12.2_HD_U_C7.jar",
|
||||
"a55768a83db4ad0599f68d9bf3fa8041e2ae3852": "OptiFine_1.12.2_HD_U_C8.jar",
|
||||
"e0236d21a2a164f2af1cfff8f9f325f53c9125f2": "OptiFine_1.12.2_HD_U_C9.jar",
|
||||
"b91a0d82c24eef95be0af92993b14e94b842f166": "OptiFine_1.12.2_HD_U_D1.jar",
|
||||
"04c28238506dc3561addb6efb87c9878d5b82ffe": "OptiFine_1.12.2_HD_U_D2.jar",
|
||||
"b784000951d41f54d67685a0a275d9f61f810514": "OptiFine_1.12.2_HD_U_D3.jar",
|
||||
"343f814410401ebdbb3314deb17c27cbab67bfac": "OptiFine_1.12.2_HD_U_E1.jar",
|
||||
"5c87706b6d14061fed248506d8e3f95b7824ad18": "OptiFine_1.12.2_HD_U_E2.jar",
|
||||
"e805d4be5c2a3343488c573145606e90bb13816d": "OptiFine_1.12.2_HD_U_E3.jar",
|
||||
"0e8d45666e80829c9ab74527628dace9187fbfb5": "OptiFine_1.12.2_HD_U_F4.jar",
|
||||
"84ada0f48bcfb16c37c49283627597bb74d935f6": "OptiFine_1.12.2_HD_U_F5.jar",
|
||||
"ca3aea3a09ce215906c346fe190907fe0347b0c4": "OptiFine_1.12.2_HD_U_G5.jar",
|
||||
"23a8be042f354ec97c99672906c3e61fdf54ca2c": "preview_OptiFine_1.12.2_HD_U_F6_pre1.jar",
|
||||
"b71f993a364c7945081cc6cde9a20d29b4e43f1f": "preview_OptiFine_1.12.2_HD_U_G5_pre1.jar",
|
||||
"ab2118b1ed23444d6decf081e0295e4c679af6c2": "preview_OptiFine_1.12.2_HD_U_G6_pre1.jar",
|
||||
"25498de48dd9b7ed2ba5b83464950ad132e61c1f": "preview_OptiFine_1.14_HD_U_F1_pre6.jar",
|
||||
"396ce7f0e22aae3543134baabd61ad547334c0aa": "OptiFine_1.14.2_HD_U_F1.jar",
|
||||
"c8c6da3e2ae32d020d9001d4489aad702680f50f": "preview_OptiFine_1.14.2_HD_U_F1_pre15.jar",
|
||||
"52420ef34128a8b15d7c8f5ed8f7ebc94b708efd": "OptiFine_1.14.3_HD_U_F1.jar",
|
||||
"887d648f26f7ba17ea34c0c2dcff4096f7a226b1": "OptiFine_1.14.3_HD_U_F2.jar",
|
||||
"ad8a8f60931f48e2873238d1460268bb4111f6c9": "OptiFine_1.14.4_HD_U_F2.jar",
|
||||
"c9710081fb7012ddb56838ac54653ac2258a2404": "OptiFine_1.14.4_HD_U_F3.jar",
|
||||
"c09f4d1ad66df8e3039334023422f1bc8cc211b8": "OptiFine_1.14.4_HD_U_F4.jar",
|
||||
"3408258990309de773cc5a8ab71cb4137718a82b": "OptiFine_1.14.4_HD_U_F5.jar",
|
||||
"117c01a5431244a8b6a3ac393374dac9624f9be6": "OptiFine_1.14.4_HD_U_G5.jar",
|
||||
"ac602fe6a39d2fb4cadfe08e87af0b0daa2d8ac9": "preview_OptiFine_1.14.4_HD_U_G5_pre1.jar",
|
||||
"630a32be9b711b5a479507159d5d2598189fed33": "OptiFine_1.15.2_HD_U_G6.jar",
|
||||
"8339858b33056ec8975f6c0c9e1694a11f0d209a": "preview_OptiFine_1.15.2_HD_U_G1_pre1.jar",
|
||||
"6cdf96d972b5f70c4575ff875a031c4931985686": "preview_OptiFine_1.15.2_HD_U_G1_pre10.jar",
|
||||
"489d2284f2d50bd7c7cf4c216a766503d37e1f3c": "preview_OptiFine_1.15.2_HD_U_G1_pre12.jar",
|
||||
"c66d412c4cb46c6f2c76c224dc45a62d30ee8b43": "preview_OptiFine_1.15.2_HD_U_G1_pre13.jar",
|
||||
"582eb1d6470cc133db563bd1c2c8bc2068215806": "preview_OptiFine_1.15.2_HD_U_G1_pre18.jar",
|
||||
"64d738862683c54a22e1856b2c13379599ca79ce": "preview_OptiFine_1.15.2_HD_U_G1_pre19.jar",
|
||||
"3da9d466c847c50a73dc634dabc6a57f3b24e2f7": "preview_OptiFine_1.15.2_HD_U_G1_pre2.jar",
|
||||
"e6583246a85dba26a478dd4925c298bb5b3f277a": "preview_OptiFine_1.15.2_HD_U_G1_pre20.jar",
|
||||
"84c5d50e26aaa02733fa15a8c13ab845fbdea97f": "preview_OptiFine_1.15.2_HD_U_G1_pre21.jar",
|
||||
"c55e449386eeca34df5b428d85927242fc841438": "preview_OptiFine_1.15.2_HD_U_G1_pre22.jar",
|
||||
"459e17c77059671ef5daa9ab794400e8ae25095d": "preview_OptiFine_1.15.2_HD_U_G1_pre23.jar",
|
||||
"2c6e4f61b1ceea92b76e0be40bc672e5b6d58efe": "preview_OptiFine_1.15.2_HD_U_G1_pre24.jar",
|
||||
"4ea53e3d202239c5ffa2affa809e36998194f1bc": "preview_OptiFine_1.15.2_HD_U_G1_pre26.jar",
|
||||
"29861ba50021b08200ef33f77c776f9f5b7135f7": "preview_OptiFine_1.15.2_HD_U_G1_pre27.jar",
|
||||
"454dc0e03dab9d30a2ccce5823b7a0b309f5c859": "preview_OptiFine_1.15.2_HD_U_G1_pre28.jar",
|
||||
"3c3623d75dc47722149edfb93fdca121c32e8987": "preview_OptiFine_1.15.2_HD_U_G1_pre29.jar",
|
||||
"942e23fa0169c693fb1b645fae4db9217c6b5916": "preview_OptiFine_1.15.2_HD_U_G1_pre3.jar",
|
||||
"bdbd92e5252c0afc0f22d6d5840f96762e5d01ea": "preview_OptiFine_1.15.2_HD_U_G1_pre30.jar",
|
||||
"5daa9461c5762bdd647665f49d2e0ef0eb348910": "preview_OptiFine_1.15.2_HD_U_G1_pre4.jar",
|
||||
"0029ab50050d19f4009f0a7d708982dde736f022": "preview_OptiFine_1.15.2_HD_U_G1_pre5.jar",
|
||||
"646b279927cab6036e8f295efd5bda268acd85cf": "preview_OptiFine_1.15.2_HD_U_G1_pre7.jar",
|
||||
"f11e79a7bc91a5fd985cb756445fc88e8c2dd31b": "preview_OptiFine_1.15.2_HD_U_G1_pre9.jar",
|
||||
"1e9869b63a89a8ab81a58e1473dd2c2291fbd943": "preview_OptiFine_1.15.2_HD_U_G6_pre5.jar",
|
||||
"87533b8ac0dfeb11241041f197f8f95c0ffa8c08": "OptiFine_1.16.1_HD_U_G2.jar",
|
||||
"3e610c9bd89ae2a54cc06de6dfb1b00cd45e9895": "preview_OptiFine_1.16.1_HD_U_G2_pre1.jar",
|
||||
"df817e1ab0e577be1dfb6c20a9b628d3d725c780": "preview_OptiFine_1.16.1_HD_U_G2_pre10.jar",
|
||||
"dbca331e7abbe64d6aa360e6a93beec2935d24e3": "preview_OptiFine_1.16.1_HD_U_G2_pre11.jar",
|
||||
"6fef880338cabe32443557762ca43fb36fe01f7c": "preview_OptiFine_1.16.1_HD_U_G2_pre12.jar",
|
||||
"ea7bea6511f3b20aa672544d28dbc6d1a2ee8b41": "preview_OptiFine_1.16.1_HD_U_G2_pre13.jar",
|
||||
"efdc788f59e1c1bcde3b64430322d8990ce7c7d6": "preview_OptiFine_1.16.1_HD_U_G2_pre14.jar",
|
||||
"388100110b4dc8ef28eaa2f3a4ae2f33a8beb5ae": "preview_OptiFine_1.16.1_HD_U_G2_pre15.jar",
|
||||
"63f5f097ce2e678d69767981b09b133ab8eac4f5": "preview_OptiFine_1.16.1_HD_U_G2_pre16.jar",
|
||||
"c56031c3f6e5dcad536115e9f6a1fb5710b72391": "preview_OptiFine_1.16.1_HD_U_G2_pre2.jar",
|
||||
"da269cdb109b6441ebed179a8d9f974590006cbb": "preview_OptiFine_1.16.1_HD_U_G2_pre3.jar",
|
||||
"ad9b5d4e0bdd5697d4f6a6b9c30a64977bb8834e": "preview_OptiFine_1.16.1_HD_U_G2_pre4.jar",
|
||||
"f6d5ea6cedff1f80bed298f9b456de2448b1f268": "preview_OptiFine_1.16.1_HD_U_G2_pre5.jar",
|
||||
"f57a4269d404d4025de4d864b88510504e785e19": "preview_OptiFine_1.16.1_HD_U_G2_pre6.jar",
|
||||
"28b46592e2f510a246a8bf62a2b12e808094167c": "preview_OptiFine_1.16.1_HD_U_G2_pre7.jar",
|
||||
"26207daec6acc66250116e4f73295c9a031b491a": "preview_OptiFine_1.16.1_HD_U_G2_pre8.jar",
|
||||
"6902e902866b765ff8e31716980c2067d491e004": "preview_OptiFine_1.16.1_HD_U_G2_pre9.jar",
|
||||
"dde4274c696063496323731ad7b58e0f6d7265af": "OptiFine_1.16.2_HD_U_G3.jar",
|
||||
"5b5627a814e8c95aa7ac27fa4cf2cc0b8bd4519b": "OptiFine_1.16.2_HD_U_G5.jar",
|
||||
"5dafc10061020c519ba4abe4982a7dc80eae30f6": "preview_OptiFine_1.16.2_HD_U_G3_pre1.jar",
|
||||
"0c0d9828984da34f9d5967027c244bb2c83a4396": "preview_OptiFine_1.16.2_HD_U_G3_pre2.jar",
|
||||
"7c791e4348808132b8c7b59e6350ae2ee25a1918": "preview_OptiFine_1.16.2_HD_U_G3_pre3.jar",
|
||||
"9a30a2cbc81095d38b4dc17e7d30a4b84e10e235": "preview_OptiFine_1.16.2_HD_U_G3_pre4.jar",
|
||||
"ec1a4ce97e29c9ee2ac259d98e35bc386035a66d": "preview_OptiFine_1.16.2_HD_U_G3_pre5.jar",
|
||||
"e03b0cdfbbcf01b1371b3e1090dee64e60a759d8": "preview_OptiFine_1.16.2_HD_U_G3_pre6.jar",
|
||||
"40ae5fbb4e3724d6e5525d2688445c09ecfe5d39": "preview_OptiFine_1.16.2_HD_U_G3_pre7.jar",
|
||||
"dc83d55f74722e1e6f503817e00e5ba2e6cb4abb": "OptiFine_1.16.3_HD_U_G3.jar",
|
||||
"89d9472ee507946caa227e226524e5260ed944db": "OptiFine_1.16.3_HD_U_G4.jar",
|
||||
"6a8f57ca84628da47b011e608ff449cde7ec13ed": "OptiFine_1.16.3_HD_U_G5.jar",
|
||||
"f53bad69adaac9e523577dcb1c65b158802f3dee": "preview_OptiFine_1.16.3_HD_U_G3_pre2.jar",
|
||||
"5b970eeae2ba07316b3e3a53da1d71de87c9f9f2": "preview_OptiFine_1.16.3_HD_U_G4_pre1.jar",
|
||||
"599d9de6b656077b03fbebc9478924c548a6e9e0": "OptiFine_1.16.4_HD_U_G5.jar",
|
||||
"7cce72db1f77c6178b549fa430e241eadb318f69": "OptiFine_1.16.4_HD_U_G6.jar",
|
||||
"f49c042fa099907eafcbe22d7035d84f8b5715f1": "OptiFine_1.16.4_HD_U_G7.jar",
|
||||
"f0b1eb59acdae57e10bb928046ee26012ef220ad": "preview_OptiFine_1.16.4_HD_U_G6_pre12.jar",
|
||||
"ded7894eebda787b7bd5013aa8c66577f2ba03fc": "preview_OptiFine_1.16.4_HD_U_G7_pre1.jar",
|
||||
"57cfcec3dd99b9f0950d0d6305bc95ecd8563212": "OptiFine_1.16.5_HD_U_G6.jar",
|
||||
"706fb33784045d69e7ac5730426d813a39511dcd": "OptiFine_1.16.5_HD_U_G7.jar",
|
||||
"137363842c5bfdebb72356a4079faeef3157eb3c": "OptiFine_1.16.5_HD_U_G8.jar",
|
||||
"ad0f1577ce02a703185e46ee9e24fdeb65479fd5": "preview_OptiFine_1.16.5_HD_U_G7_pre10.jar",
|
||||
"11770876367980da546c68bc95c4f794582907f2": "preview_OptiFine_1.16.5_HD_U_G7_pre11.jar",
|
||||
"c5b32d2bad3bd54c31ddb29869a55fe44409cfe2": "preview_OptiFine_1.16.5_HD_U_G7_pre2.jar",
|
||||
"9fc9cc09e72a3060d577f62f3535820056b0c2d4": "preview_OptiFine_1.16.5_HD_U_G7_pre4.jar",
|
||||
"577fae32b60ac8d1b91e3fa645dc004d4a9e513e": "preview_OptiFine_1.16.5_HD_U_G7_pre5.jar",
|
||||
"4bccf7f371ac83523796b4706569cc5077c46aea": "preview_OptiFine_1.16.5_HD_U_G7_pre6.jar",
|
||||
"97b8d413a909354e2e0f42943cf292941dfe4c38": "preview_OptiFine_1.16.5_HD_U_G7_pre7.jar",
|
||||
"9c48a804ee990e526000c7061bde9aa6f75d62a6": "preview_OptiFine_1.16.5_HD_U_G7_pre8.jar",
|
||||
"9a9b69a52a4514f5d25c9f47127a822e93458fa3": "preview_OptiFine_1.16.5_HD_U_G7_pre9.jar",
|
||||
"d16a450ec4205d02319480799008d8177ba05d69": "preview_OptiFine_1.16.5_HD_U_G8_pre1.jar",
|
||||
"539c215aa0e8b8f696b325e89f3f9a3658ab32c8": "preview_OptiFine_1.16.5_HD_U_G8_pre10.jar",
|
||||
"311ed81a27d24047b6ade33f46ac21c962897016": "preview_OptiFine_1.16.5_HD_U_G8_pre11.jar",
|
||||
"4bc50f85809a299d30c3e3e73cfd87cad61cf7e6": "preview_OptiFine_1.16.5_HD_U_G8_pre12.jar",
|
||||
"7de1b8e9f7cd6d7ca941d90121e50206aba80c68": "preview_OptiFine_1.16.5_HD_U_G8_pre13.jar",
|
||||
"a4e021a75aab7ed1eb83ff7b45182d497aa930f2": "preview_OptiFine_1.16.5_HD_U_G8_pre14.jar",
|
||||
"0ddcc4f47e10b2d671ebbf9147eb16cf8f1bb92a": "preview_OptiFine_1.16.5_HD_U_G8_pre2.jar",
|
||||
"b8600be4fde6f8cc3c28173cc9bde6923956ff42": "preview_OptiFine_1.16.5_HD_U_G8_pre3.jar",
|
||||
"d46b10098309929d9a6583323f059e65ba40a5e5": "preview_OptiFine_1.16.5_HD_U_G8_pre4.jar",
|
||||
"e835424b36fdae3d5f46c6bf096852848127f1e7": "preview_OptiFine_1.16.5_HD_U_G8_pre5.jar",
|
||||
"5a84983221331597f58e9636d41f1fb0c9e3de61": "preview_OptiFine_1.16.5_HD_U_G8_pre6.jar",
|
||||
"d03ce2209d787539e5e51f80a7cbffc69a49ce9f": "preview_OptiFine_1.16.5_HD_U_G8_pre7.jar",
|
||||
"1c646dc058aa32898917589858d900407883ba3f": "preview_OptiFine_1.16.5_HD_U_G8_pre8.jar",
|
||||
"9bf369aa609e5612247473326dc298e6e6c9fecf": "preview_OptiFine_1.16.5_HD_U_G8_pre9.jar",
|
||||
"b88b05278fbbf400cb5ec0cc26e0c5b7306e0c1e": "preview_OptiFine_1.17_HD_U_G9_pre16.jar",
|
||||
"a6beac3091d17a4ba420116c75c89faeaee48539": "preview_OptiFine_1.17_HD_U_G9_pre17.jar",
|
||||
"2839c5e74f64500561ee3e8605c51d9f06727c22": "preview_OptiFine_1.17_HD_U_G9_pre18.jar",
|
||||
"455243ff55177189fff140ba7f4c4777cc977ef6": "preview_OptiFine_1.17_HD_U_G9_pre19.jar",
|
||||
"bcc390e34bd529a86e6ae0e25d50417f46ba482f": "preview_OptiFine_1.17_HD_U_G9_pre20.jar",
|
||||
"d30c23d745df54fd6ea2374e9c0b4392f0a78199": "preview_OptiFine_1.17_HD_U_G9_pre21.jar",
|
||||
"075e7f8473b6785c3c6bbeeb41a3728f6ff3c3ba": "preview_OptiFine_1.17_HD_U_G9_pre22.jar",
|
||||
"2ffaee36c717ae918cc93661df739740636900c9": "preview_OptiFine_1.17_HD_U_G9_pre23.jar",
|
||||
"4385493e7ce4c6f4a3945f1d96246bce0b151c7e": "preview_OptiFine_1.17_HD_U_G9_pre24.jar",
|
||||
"bcc33e67f134861eb30b1f0b9a829183c8afdebf": "preview_OptiFine_1.17_HD_U_G9_pre25.jar",
|
||||
"6a8e34605cc828091027d9f011b804d916808af4": "preview_OptiFine_1.17_HD_U_G9_pre26.jar",
|
||||
"4714bdceaefc15e0af9d5c72de8c05cf3051d760": "OptiFine_1.17.1_HD_U_G9.jar",
|
||||
"cc64084e73d6423baf7ccbdd9f3760dd56f2fce5": "OptiFine_1.17.1_HD_U_H1.jar",
|
||||
"1ee73bd882385a7abb9896b9469586741a6850a8": "preview_OptiFine_1.17.1_HD_U_G9_pre26.jar",
|
||||
"537c1fbee9ebe25b49a8e6fb93db162d217f1c83": "preview_OptiFine_1.17.1_HD_U_G9_pre27.jar",
|
||||
"68e1124f4b0376773d8d581da78f9bb6fc76486e": "preview_OptiFine_1.17.1_HD_U_G9_pre28.jar",
|
||||
"3f80a562b39439831491c650c65ecb762e70d5f7": "preview_OptiFine_1.17.1_HD_U_G9_pre29.jar",
|
||||
"9751c69568a61ce5b2a602b4dcf77c1cea57c709": "preview_OptiFine_1.17.1_HD_U_G9_pre30.jar",
|
||||
"162fa1b4a0d5b89dad6030b5fd5903a3f24d39c7": "preview_OptiFine_1.17.1_HD_U_G9_pre31.jar",
|
||||
"c4f3a33d892948927cecfaa60b284217325557c5": "preview_OptiFine_1.17.1_HD_U_G9_pre32.jar",
|
||||
"12dbbc8ccd8dc02806768fb3fbe4a2d8c7c11301": "preview_OptiFine_1.17.1_HD_U_G9_pre33.jar",
|
||||
"f74d1dfcb24c43e633076c63dd4492b29fca14b3": "preview_OptiFine_1.17.1_HD_U_G9_pre34.jar",
|
||||
"42e55681fb106475ef13d5c5ef7113fb631392d4": "preview_OptiFine_1.17.1_HD_U_G9_pre35.jar",
|
||||
"245ddb68349f5f81d067f4d9402d62db3d439d50": "preview_OptiFine_1.17.1_HD_U_H1_pre1.jar",
|
||||
"0ac033f5ba4089311af55172281e73df143b9ac4": "preview_OptiFine_1.17.1_HD_U_H1_pre2.jar",
|
||||
"68a3727bcdb0eac0986ff4e883d93fef406eb1c3": "preview_OptiFine_1.17.1_HD_U_H1_pre3.jar",
|
||||
"a6534877558f0438bda604dc43093d61c6de88ae": "preview_OptiFine_1.17.1_HD_U_H1_pre4.jar",
|
||||
"3e18db17b8695feb0a188ecdcb81b561d9d7030c": "preview_OptiFine_1.17.1_HD_U_H1_pre5.jar",
|
||||
"c2e0c4391a671cd06931f7b6e965085c04c58762": "preview_OptiFine_1.17.1_HD_U_H1_pre6.jar",
|
||||
"1ffb7325df5bf01b1d99bbbed8006a477b861394": "preview_OptiFine_1.17.1_HD_U_H1_pre7.jar",
|
||||
"f2fa727e67b4795ddea3cc37cc5ced42e9c3b0c5": "preview_OptiFine_1.17.1_HD_U_H1_pre8.jar",
|
||||
"aee167aff9937a068d514c85e3f8c766db99ed43": "preview_OptiFine_1.17.1_HD_U_H1_pre9.jar",
|
||||
"59709e09632c80ab80ffcc4b5bf380d073bf467f": "preview_OptiFine_1.17.1_HD_U_H2_pre1.jar",
|
||||
"52629bc5319ec203edd42de1776cb8d67a0e6b1b": "OptiFine_1.18_HD_U_H3.jar",
|
||||
"e5077b4be03956118613162b5dbcf90406b27747": "preview_OptiFine_1.18_HD_U_H3_pre7.jar",
|
||||
"326c160481cc849bccb821939992c101a8fe163b": "OptiFine_1.18.1_HD_U_H4.jar",
|
||||
"1679654fdf49fd1216b090d51d3d8ec906094619": "OptiFine_1.18.1_HD_U_H5.jar",
|
||||
"c86534ee821a78efc741c9cb407eec76625e1bab": "OptiFine_1.18.1_HD_U_H6.jar",
|
||||
"34c98382131efa1394cff06528238dc44d255794": "preview_OptiFine_1.18.1_HD_U_H4_pre1.jar",
|
||||
"d6cd0a2d0243ecad107220bff639eb46277762ea": "preview_OptiFine_1.18.1_HD_U_H5_pre1.jar",
|
||||
"e24d766864f9238b94be5b3ad65608d7eb521fad": "preview_OptiFine_1.18.1_HD_U_H5_pre2.jar",
|
||||
"bc1b87a6379acf5a5dca2a56196080ace49e4864": "preview_OptiFine_1.18.1_HD_U_H5_pre3.jar",
|
||||
"555a6b8e420bd63a04d9f338d61f3333b4ccf5d9": "preview_OptiFine_1.18.1_HD_U_H5_pre4.jar",
|
||||
"1d02694393f10992cbbd11a802568b0890b4dc81": "preview_OptiFine_1.18.1_HD_U_H5_pre5.jar",
|
||||
"e3a22adc6931dcd7513f26afa1adecd62a35641b": "preview_OptiFine_1.18.1_HD_U_H5_pre6.jar",
|
||||
"445a8cb8a1d565d8a1fabc0ba984c5936edbf561": "OptiFine_1.18.2_HD_U_H6.jar",
|
||||
"8d83d4d5e325887e000a462029d2bf7a6e77eebc": "OptiFine_1.18.2_HD_U_H7.jar",
|
||||
"2a461188167c1da6b1cfd520d85a656f45c74d70": "OptiFine_1.18.2_HD_U_H9.jar",
|
||||
"e591777f272df533b62260a6dbe0e6cde62066f6": "preview_OptiFine_1.18.2_HD_U_H6_pre1.jar",
|
||||
"f7c727c99e7f58ef9b86cc96fb894f628391016c": "preview_OptiFine_1.18.2_HD_U_H7_pre1.jar",
|
||||
"cb51529f94e0eff5b9da92c8f70b1d498662a115": "preview_OptiFine_1.18.2_HD_U_H7_pre2.jar",
|
||||
"ceea3c6612d2ec36c6ef1ca4a9355a141df9089f": "preview_OptiFine_1.18.2_HD_U_H7_pre3.jar",
|
||||
"596c3a399889c3e2ef1d8fee994e8cf5a91e457e": "preview_OptiFine_1.18.2_HD_U_H8_pre1.jar",
|
||||
"85f545aeb9d232ae970b0efa24e833f9c5d0fe33": "preview_OptiFine_1.18.2_HD_U_H9_pre1.jar",
|
||||
"b9bbabb8f31f2b04ca1a1a8645df1be701f705bd": "preview_OptiFine_1.18.2_HD_U_H9_pre2.jar",
|
||||
"c2bf213b4f60b6a29e402e3eaf219a4c85a5d1e6": "preview_OptiFine_1.18.2_HD_U_H9_pre3.jar",
|
||||
"64c8c35313d25a64a8a8677cb851a2c83556ddc8": "OptiFine_1.19_HD_U_H8.jar",
|
||||
"c668eaf9b6ce4e64f26a29fb27e830229ab4bef3": "OptiFine_1.19_HD_U_H9.jar",
|
||||
"cda9130e0d36f0d6e06950ab393a8929b502a440": "preview_OptiFine_1.19_HD_U_H8_pre1.jar",
|
||||
"cd1ae81f544672df776dc4426269771d2e82d0b2": "preview_OptiFine_1.19_HD_U_H8_pre10.jar",
|
||||
"cb3ad2a9b4c23675ca569058f55dd174eed67a38": "preview_OptiFine_1.19_HD_U_H8_pre2.jar",
|
||||
"2f7139ea0888ed18006e3a39b7475e88a3fd545d": "preview_OptiFine_1.19_HD_U_H8_pre3.jar",
|
||||
"85cd70bb714e65935abf351811889a47a648bb96": "preview_OptiFine_1.19_HD_U_H8_pre4.jar",
|
||||
"c65cbae4c1cfb5b9a5a573e4b83424df2d81b172": "preview_OptiFine_1.19_HD_U_H8_pre5.jar",
|
||||
"10cd57890ebf449f5c258cff1c60d8dcefcc6cf6": "preview_OptiFine_1.19_HD_U_H8_pre6.jar",
|
||||
"eb03e60c2fa9904a47eec1ef4a2c8804ee6cc0b8": "preview_OptiFine_1.19_HD_U_H8_pre7.jar",
|
||||
"40d0b514168161fdefc91594f0d3f774f831d7de": "preview_OptiFine_1.19_HD_U_H8_pre8.jar",
|
||||
"8e5bedd1c1a3641caad0743c4629db51c11f8feb": "preview_OptiFine_1.19_HD_U_H9_pre1.jar",
|
||||
"7745216a810f0d617ed17a520fda44e12456492f": "preview_OptiFine_1.19_HD_U_H9_pre2.jar",
|
||||
"6d6ed920eb99836e76549a7803af85881fcdee34": "preview_OptiFine_1.19_HD_U_H9_pre3.jar",
|
||||
"7604e63ca74876b4e8ea9c3a36dbe80111c776b1": "preview_OptiFine_1.19_HD_U_H9_pre4.jar",
|
||||
"b42dcce86c88ad4bcfa52a9d297afa800477aa78": "OptiFine_1.19.1_HD_U_H9.jar",
|
||||
"648427a02940b3c53b3678cd5df1ff6997bd1e6c": "preview_OptiFine_1.19.1_HD_U_H9_pre1.jar",
|
||||
"7cc221a6df6831b62c3b676b5f958e82a4487fd8": "OptiFine_1.19.2_HD_U_H9.jar",
|
||||
"f304c56c7ab9119ce4269f2b019cd4668f48376d": "OptiFine_1.19.2_HD_U_I1.jar",
|
||||
"708c1ecc148a0bd7d341e8f5e005e670903650f7": "OptiFine_1.19.2_HD_U_I2.jar",
|
||||
"e0e924990bd12cc499fc89439f0b2c50b6e147fa": "preview_OptiFine_1.19.2_HD_U_I1_pre1.jar",
|
||||
"465b229481c0a285195a168bf6581549a5cd7373": "preview_OptiFine_1.19.2_HD_U_I1_pre2.jar",
|
||||
"af4398d0ce0628bcc0204e61c157e3c8951b9ad5": "preview_OptiFine_1.19.2_HD_U_I1_pre3.jar",
|
||||
"35ef18f953bbea9a4cba6e14d0731d56f888114f": "preview_OptiFine_1.19.2_HD_U_I1_pre4.jar",
|
||||
"b24d8725a8d06e1c190d1d2b3bc51c899f74b36d": "OptiFine_1.19.3_HD_U_I3.jar",
|
||||
"f5ce615d9886e377079fd13cc4700a51d5a9c7b6": "preview_OptiFine_1.19.3_HD_U_I2_pre1.jar",
|
||||
"10e6d97ea2c97cf0575a7c587fb11e1ddb73aa71": "preview_OptiFine_1.19.3_HD_U_I2_pre2.jar",
|
||||
"89718cd608225d7c23f7e180d011daa4a47ce6bd": "preview_OptiFine_1.19.3_HD_U_I2_pre3.jar",
|
||||
"204baf0fd59432054aebd2f83c83fe15fdd3e611": "preview_OptiFine_1.19.3_HD_U_I2_pre4.jar",
|
||||
"90a52b3adc94a1b9a70f03f4c4ea14dfdf3424d8": "preview_OptiFine_1.19.3_HD_U_I2_pre5.jar",
|
||||
"050d787936cc239ea8db0aa250d2ed72a44fa71d": "OptiFine_1.19.4_HD_U_I3.jar",
|
||||
"253e9d29c6826c134fbdeea074d1d91c3410225c": "OptiFine_1.19.4_HD_U_I4.jar",
|
||||
"068b998d6c5db5b3bb7ad6a0a7d0c6aefc4dc191": "preview_OptiFine_1.19.4_HD_U_I3_pre3.jar",
|
||||
"a8b9156811c4745dbd612ebbb1df6f93d2fa734a": "preview_OptiFine_1.19.4_HD_U_I3_pre4.jar",
|
||||
"6f2793e6236a27c06a74e8a1876ea6b29be038a7": "preview_OptiFine_1.19.4_HD_U_I3_pre5.jar",
|
||||
"9ad82ef9f32fb5a0e7e7e0c7e8906c9f319a9705": "preview_OptiFine_1.19.4_HD_U_I3_pre6.jar",
|
||||
"cf02ee8b5cf6922fbc28d6ffc8183949fff55d49": "preview_OptiFine_1.19.4_HD_U_I3_pre7.jar",
|
||||
"702e0e9987209f66a5b4f825e7ac658fd49dd4b1": "preview_OptiFine_1.19.4_HD_U_I3_pre8.jar",
|
||||
"04c8eaeadf24c42929500812a8f3f5fe634f0d1f": "preview_OptiFine_1.19.4_HD_U_I3_pre9.jar",
|
||||
"968784e051c2c44f10a4ab448c979572977969c0": "preview_OptiFine_1.19.4_HD_U_I4_pre1.jar",
|
||||
"abe4b1dbda7d95eb47953ef8aa11ed8ed1d8e238": "preview_OptiFine_1.20_HD_U_I5_pre3.jar",
|
||||
"6612ce97d846018126f91cdbae23f0eff6bd2bab": "preview_OptiFine_1.20_HD_U_I5_pre4.jar",
|
||||
"f37d62b6a071f6cd3d6bdfa378b56f7f5b9ec7c6": "preview_OptiFine_1.20_HD_U_I5_pre5.jar",
|
||||
"c44bd276edd10fa910d929a4e7f6b8c7ffe6c23f": "OptiFine_1.20.1_HD_U_I5.jar",
|
||||
"227914ab1037762eae44a2e66a568b87d7a02365": "OptiFine_1.20.1_HD_U_I6.jar",
|
||||
"7484cf60bd8e019c40fa448daa294bd31f52962b": "preview_OptiFine_1.20.1_HD_U_I5_pre4.jar",
|
||||
"953b1b4f15f56329bc4ade851846ef004ebbd5d0": "preview_OptiFine_1.20.1_HD_U_I5_pre5.jar",
|
||||
"ebbdb3076f8291d7f8e10cbec3b1d3c49a0a701d": "preview_OptiFine_1.20.1_HD_U_I5_pre6.jar",
|
||||
"b831d59eeb63122893f87a62ec3e5b3f1cc5586a": "preview_OptiFine_1.20.1_HD_U_I5_pre7.jar",
|
||||
"dc93d991b07b2c5c6d2cd50a553599900c256264": "preview_OptiFine_1.20.1_HD_U_I5_pre8.jar",
|
||||
"040a73427541170bccf162c04f4129b3909b8da1": "preview_OptiFine_1.20.1_HD_U_I5_pre9.jar",
|
||||
"9f5fd75ede7770ad35383443b0a203f026cef5db": "preview_OptiFine_1.20.1_HD_U_I6_pre1.jar",
|
||||
"85d5566b440036b926c5dd306108e48e7fb9b6e8": "preview_OptiFine_1.20.1_HD_U_I6_pre2.jar",
|
||||
"d09c110358117336472414720bf961a581690dc5": "preview_OptiFine_1.20.1_HD_U_I6_pre3.jar",
|
||||
"3365577f5161f9a1bbfefb15675bb5ece27600e4": "preview_OptiFine_1.20.1_HD_U_I6_pre4.jar",
|
||||
"f317c701ae8c533fc34809dbce914bcced4e9a03": "preview_OptiFine_1.20.1_HD_U_I6_pre5.jar",
|
||||
"445b32b14a2c2802d5a0832a708712d2fabafbc2": "preview_OptiFine_1.20.1_HD_U_I6_pre6.jar",
|
||||
"9ea6b1389e88b81797f54b9d8d1e870d3fe8532c": "preview_OptiFine_1.20.2_HD_U_I7_pre1.jar",
|
||||
"f2475e8d5746477d1d2972cd5aae62a5d9c04264": "OptiFine_1.20.4_HD_U_I7.jar",
|
||||
"fec28a2fa152744bc2b47b3c5db3217974aa57ee": "preview_OptiFine_1.20.4_HD_U_I7_pre2.jar",
|
||||
"4068365a57f4b154f4ebbc670894dc9038cf3819": "preview_OptiFine_1.20.4_HD_U_I7_pre3.jar",
|
||||
"2481e0bed7610bfdfe26dea5a6bd8f01537c4ea8": "preview_OptiFine_1.20.4_HD_U_I7_pre4.jar",
|
||||
"150990ba068cfb55bbf9e525c5ab84db0b8903e1": "preview_OptiFine_1.20.4_HD_U_I7_pre5.jar",
|
||||
"fcf0f0f278d1901e4341d5ec8022bede03572430": "preview_OptiFine_1.20.4_HD_U_I7_pre6.jar",
|
||||
"1c3395efa928758505b808291162a2514523b399": "preview_OptiFine_1.20.4_HD_U_I7_pre7.jar",
|
||||
"4bcfec24e5d917ee96e0de6ef095bfc08782217b": "preview_OptiFine_1.20.4_HD_U_I8_pre1.jar",
|
||||
"c931df21309800f1d1ece59b318e6b3e39c98176": "preview_OptiFine_1.20.4_HD_U_I8_pre2.jar",
|
||||
"83f5ad147536405d86bf4ee47a7f7970e1fa8329": "preview_OptiFine_1.20.4_HD_U_I8_pre3.jar",
|
||||
"7c6669319db18c9622d896da2a061479be88acf5": "preview_OptiFine_1.20.4_HD_U_I8_pre4.jar",
|
||||
"bda7bbdd5e2d8c73148372e8c3b34d7c2485a4e8": "preview_OptiFine_1.20.6_HD_U_J1_pre18.jar",
|
||||
"24a20f949a719480523669669a4e5e7339df6186": "OptiFine_1.21.1_HD_U_J1.jar",
|
||||
"6bc74af8f733864539404a3f087aeb6f0cadc6b1": "preview_OptiFine_1.21.1_HD_U_J1_pre10.jar",
|
||||
"4813a6cde6b0f5b20223d486ba7adf0816236a77": "preview_OptiFine_1.21.1_HD_U_J1_pre11.jar",
|
||||
"c99ea98d8537f99b7470f1bcfa81c7ce405fd97e": "preview_OptiFine_1.21.1_HD_U_J1_pre12.jar",
|
||||
"f2f55e6d61a4b90bdaa31eb520f5af78f8a1833b": "preview_OptiFine_1.21.1_HD_U_J1_pre13.jar",
|
||||
"53a15b75ea9d20b644b0d3e9c7280ba172ade053": "preview_OptiFine_1.21.1_HD_U_J1_pre14.jar",
|
||||
"da5575e1138fc2a4c28779cfc5e7d260253ccbdb": "preview_OptiFine_1.21.1_HD_U_J1_pre15.jar",
|
||||
"0930876341beadf7014f57e9ebdd44be445dacbe": "OptiFine_1.21.3_HD_U_J2.jar",
|
||||
"350f63ec3e59d21227f803d4078883884e482660": "preview_OptiFine_1.21.3_HD_U_J2_pre10.jar",
|
||||
"2c48a4210acd25082c220f9601f17d1cc7769098": "preview_OptiFine_1.21.3_HD_U_J2_pre11.jar",
|
||||
"8f0a097b1f7c9d065396bac9230eab62412a8b54": "preview_OptiFine_1.21.3_HD_U_J2_pre12.jar",
|
||||
"f97df5638fcda7f4380d9284b329569d4e1554aa": "preview_OptiFine_1.21.3_HD_U_J2_pre8.jar",
|
||||
"77df50552deea51687592b60c6d24561ee11aa74": "preview_OptiFine_1.21.3_HD_U_J2_pre9.jar",
|
||||
"bcc6a7a140320566a985b1499a59fcb085255d14": "OptiFine_1.21.4_HD_U_J3.jar",
|
||||
"e7bff4575b7311e11d7111506e855b4ad910481f": "preview_OptiFine_1.21.4_HD_U_J3_pre10.jar",
|
||||
"52b2b6defdb8d1c189afb42125079f1b76ff72e2": "preview_OptiFine_1.21.4_HD_U_J3_pre11.jar",
|
||||
"708f70aa5f70919a40d02ba75fc30d2d60c8e7cd": "preview_OptiFine_1.21.4_HD_U_J3_pre12.jar",
|
||||
"86b796325d03d4571809a155c54cf6cba7c7482b": "preview_OptiFine_1.21.4_HD_U_J3_pre13.jar",
|
||||
"618719a6a69eb674ea50c82cffe3d4e3c2f67abf": "preview_OptiFine_1.21.4_HD_U_J3_pre14.jar",
|
||||
"98dd84b0581fcf7a27aa96238acb615b5b719825": "preview_OptiFine_1.21.4_HD_U_J3_pre15.jar",
|
||||
"5c8573ae921082a069a9e7269500178f0c580c97": "preview_OptiFine_1.21.4_HD_U_J3_pre4.jar",
|
||||
"17d51e1bfc94dde95368ab91aa0bb56e89c706bf": "preview_OptiFine_1.21.4_HD_U_J3_pre5.jar",
|
||||
"1a4311606ac94d682800714793ea887c3276b18d": "preview_OptiFine_1.21.4_HD_U_J3_pre6.jar",
|
||||
"12bf1a1b5607b5c62405a8c6ab4e1bd02bef2c8d": "preview_OptiFine_1.21.4_HD_U_J3_pre7.jar",
|
||||
"f1f56403dc575fd975a000bfb133060285cacd6f": "preview_OptiFine_1.21.4_HD_U_J3_pre8.jar",
|
||||
"9584de0e8204f5c855b60741d58af967dfc599a8": "preview_OptiFine_1.21.4_HD_U_J3_pre9.jar",
|
||||
"0b97631e166ace9346744de33b7772df7bf5fbeb": "preview_OptiFine_1.21.4_HD_U_J4_pre1.jar",
|
||||
"a776ec6c072529d4b731e0e6929a8aee56d04e76": "preview_OptiFine_1.21.4_HD_U_J4_pre2.jar",
|
||||
"2a3fdfcbfc9c572b22c7d15c6129b8ea58ea1712": "preview_OptiFine_1.21.8_HD_U_J6_pre13.jar",
|
||||
"ba7ca56c9b33d2fc7f7d22e20ce2765e4d257299": "preview_OptiFine_1.21.8_HD_U_J6_pre14.jar",
|
||||
"097d3acd315b0682a4565ab9cbb4cdc1cc17d81f": "preview_OptiFine_1.21.8_HD_U_J6_pre15.jar",
|
||||
"d7effca0de34c9442f06776848679a684f1f166a": "preview_OptiFine_1.21.8_HD_U_J6_pre16.jar",
|
||||
"696ed52cdfd0ac2eafab8e98575d146b400de530": "preview_OptiFine_1.21.10_HD_U_J7_pre10.jar",
|
||||
"be7bc81f0c9ce15316f76a059b0a690f62c03a5d": "preview_OptiFine_1.21.10_HD_U_J7_pre11.jar",
|
||||
"731e698abe94bbd90cda628f80b4ce6ac5af8188": "preview_OptiFine_1.21.10_HD_U_J7_pre6.jar",
|
||||
"63f189a4b7ff5b53e5bc56391f5274eab8555def": "preview_OptiFine_1.21.10_HD_U_J7_pre7.jar",
|
||||
"7ccfc0085ccdef3f4ec21918a059ddd05171711a": "preview_OptiFine_1.21.10_HD_U_J7_pre8.jar",
|
||||
"aad53ad3346944a12ed088ffbba98cf9eccc474c": "preview_OptiFine_1.21.10_HD_U_J7_pre9.jar",
|
||||
"2800efeb56565f23494d372e7edac29333113e11": "OptiFine_1.21.11_HD_U_J8.jar",
|
||||
"cee35b83c75da33dc07ffbb344386cae5cdc5c5b": "OptiFine_1.21.11_HD_U_J9.jar",
|
||||
"687046282c370e690ec4b4aa6d90a6b42ada3ee1": "preview_OptiFine_1.21.11_HD_U_J8_pre10.jar",
|
||||
"c09b05637610072bc33023d1c901e2726b7d16ce": "preview_OptiFine_1.21.11_HD_U_J8_pre11.jar",
|
||||
"88682b40f08f462c4daae8e6b25ea99b1ed5cd14": "preview_OptiFine_1.21.11_HD_U_J8_pre12.jar",
|
||||
"1c69de725c249d487df676470c71a7c05ece943c": "preview_OptiFine_1.21.11_HD_U_J8_pre3.jar",
|
||||
"921b68e014539d75b77a47ca2117fc9e09ace4ed": "preview_OptiFine_1.21.11_HD_U_J8_pre4.jar",
|
||||
"2fee496a35eeebf39fbb43017b12d752f5c37dee": "preview_OptiFine_1.21.11_HD_U_J8_pre5.jar",
|
||||
"e5b5da810d43c02dccedfd99f83ae8ad63e49966": "preview_OptiFine_1.21.11_HD_U_J8_pre6.jar",
|
||||
"8309638bab4d99258354b4d13c3cd82ff7c9645b": "preview_OptiFine_1.21.11_HD_U_J8_pre7.jar",
|
||||
"b3d208ec7b5015842fcc77b3399b04b24e0b54cb": "preview_OptiFine_1.21.11_HD_U_J8_pre8.jar",
|
||||
"c4ac7401bb5f668e4e92121501d1537cdbe7343c": "preview_OptiFine_1.21.11_HD_U_J8_pre9.jar",
|
||||
"fd96031b5fc4c41ad71581eea53eb122022fff5b": "preview_OptiFine_1.21.11_HD_U_J9_pre1.jar",
|
||||
"a159a217aba02cd7897394a51bd346c3b658b9f9": "preview_OptiFine_1.21.11_HD_U_J9_pre2.jar",
|
||||
"2a784437076b539ea1a3c1a37ec98ff21bc3952c": "preview_OptiFine_1.21.11_HD_U_J9_pre3.jar",
|
||||
"ee32ce4b406e290a0e99685afd09dc44cad03ddd": "preview_OptiFine_1.21.11_HD_U_J9_pre4.jar"
|
||||
}
|
||||
@@ -27,6 +27,7 @@
|
||||
<Using Include="System.Collections.Generic" />
|
||||
<Using Include="System.Collections.Concurrent" />
|
||||
<Using Include="System.Text" />
|
||||
<Using Include="System.Text.RegularExpressions" />
|
||||
<Using Include="System.Net" />
|
||||
<Using Include="System.Runtime.CompilerServices" />
|
||||
<Using Include="System.Runtime.InteropServices" />
|
||||
@@ -58,6 +59,7 @@
|
||||
<EmbeddedResource Include="Launch\JavaWrapper.jar" LogicalName="Launch\JavaWrapper.jar" />
|
||||
<EmbeddedResource Include="Launch\LwjglUnsafeAgent.jar" LogicalName="Launch\LwjglUnsafeAgent.jar" />
|
||||
<EmbeddedResource Include="Resource\WikiEntries.txt" LogicalName="Resource\WikiEntries.txt" />
|
||||
<EmbeddedResource Include="Minecraft\OptiFineHashes.json" LogicalName="Minecraft\OptiFineHashes.json" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.VisualBasic" />
|
||||
|
||||
+3106
-476
File diff suppressed because one or more lines are too long
@@ -9,7 +9,10 @@ Public Class Application
|
||||
'核心初始化
|
||||
MeloongCore.Main.Init("PCL")
|
||||
MeloongCore.Wpf.Main.Init()
|
||||
Logger.Instance = New PclLogger With {.logFolder = Paths.BaseThenName, .MinLevel = If(ModeDebug, LogLevel.Trace, LogLevel.Info)}
|
||||
If Not (e.Args.Contains("--update") OrElse e.Args.Contains("--gpu") OrElse e.Args.Contains("--memory")) Then '若是通过命令行调用,则不检查单例、不轮换日志(#9137)
|
||||
WaitingMutex(e)
|
||||
Logger.Instance = New PclLogger With {.logFolder = Paths.BaseThenName, .MinLevel = If(ModeDebug, LogLevel.Trace, LogLevel.Info)}
|
||||
End If
|
||||
'提升主线程优先级
|
||||
Thread.CurrentThread.Priority = ThreadPriority.Highest
|
||||
'执行开发版测试
|
||||
@@ -47,7 +50,7 @@ Public Class Application
|
||||
Catch ex As Exception
|
||||
Environment.Exit(ProcessReturnValues.Fail)
|
||||
End Try
|
||||
ElseIf e.Args(0).StartsWithF("--memory") Then
|
||||
ElseIf e.Args(0) = "--memory" Then
|
||||
'内存优化
|
||||
Dim Ram = My.Computer.Info.AvailablePhysicalMemory
|
||||
Try
|
||||
@@ -70,7 +73,7 @@ Public Class Application
|
||||
CheckPermissionWithException(Paths.Base & "PCL\")
|
||||
Catch ex As Exception
|
||||
MsgBox($"PCL 没有对当前文件夹的权限({Paths.Base}PCL\),请尝试:" & vbCrLf &
|
||||
"1. 将 PCL 移动到其他文件夹" & If(Paths.Base.StartsWithF("C:", True), ",例如 C 盘和桌面以外的其他位置。", "。") & vbCrLf &
|
||||
"1. 将 PCL 移动到其他文件夹" & If(PathUtils.GetDiskName(Paths.Base) = "C"c, ",例如 C 盘和桌面以外的其他位置。", "。") & vbCrLf &
|
||||
"2. 删除当前目录中的 PCL 文件夹,然后再试。" & vbCrLf &
|
||||
"3. 右键 PCL 选择属性,打开 兼容性 中的 以管理员身份运行此程序。",
|
||||
MsgBoxStyle.Critical, "运行环境错误")
|
||||
@@ -81,7 +84,7 @@ RetryCacheCheck:
|
||||
DirectoryUtils.Create(PathTemp)
|
||||
CheckPermissionWithException(PathTemp)
|
||||
Catch ex As Exception
|
||||
If PathTemp = Path.GetTempPath() & "PCL\" Then
|
||||
If PathUtils.IsSame(PathTemp, Path.GetTempPath() & "PCL\") Then
|
||||
MyMsgBox("PCL 无法访问缓存文件夹,可能导致程序出错或无法正常使用!" & vbCrLf & vbCrLf & "错误原因:" & ex.GetDisplay(True), "缓存文件夹不可用")
|
||||
Else
|
||||
MyMsgBox("手动设置的缓存文件夹不可用,PCL 将使用默认缓存文件夹。" & vbCrLf & vbCrLf & "错误原因:" & ex.GetDisplay(True), "缓存文件夹不可用")
|
||||
@@ -92,8 +95,6 @@ RetryCacheCheck:
|
||||
End Try
|
||||
DirectoryUtils.Create(PathTemp & "Cache\")
|
||||
DirectoryUtils.Create(Paths.AppDataThenName)
|
||||
'要求单例
|
||||
WaitingMutex(e)
|
||||
'设置 ToolTipService 默认值
|
||||
ToolTipService.InitialShowDelayProperty.OverrideMetadata(GetType(DependencyObject), New FrameworkPropertyMetadata(100))
|
||||
'设置网络配置默认值
|
||||
@@ -231,7 +232,7 @@ RetryCacheCheck:
|
||||
End Function
|
||||
End Sub
|
||||
Private Shared Sub ExtractLibwebp() '这个方法会调用 ModBase,进而调用 MeloongCore,所以不能放在 New 里
|
||||
SetDllDirectory(PathPure.Value.TrimEnd("\"c))
|
||||
SetDllDirectory(PathUtils.RemoveSlashSuffix(PathPure.Value))
|
||||
Try
|
||||
ExtractResources(PathPure.Value & "libwebp.dll", "libwebp64")
|
||||
Catch ex As Exception
|
||||
|
||||
@@ -44,8 +44,8 @@ Namespace Controls.Behaviors
|
||||
|
||||
Private Shared Sub AddCommandBindingsToTextBox(tb As TextBox)
|
||||
tb.CommandBindings.Add(New CommandBinding(ApplicationCommands.Copy, AddressOf OnCopyTextBox))
|
||||
tb.CommandBindings.Add(New CommandBinding(ApplicationCommands.Cut, AddressOf OnCutTextBox))
|
||||
tb.CommandBindings.Add(New CommandBinding(ApplicationCommands.Paste, AddressOf OnPasteTextBox))
|
||||
tb.CommandBindings.Add(New CommandBinding(ApplicationCommands.Cut, AddressOf OnCutTextBox, AddressOf CanEditTextBox))
|
||||
tb.CommandBindings.Add(New CommandBinding(ApplicationCommands.Paste, AddressOf OnPasteTextBox, AddressOf CanEditTextBox))
|
||||
End Sub
|
||||
|
||||
Private Shared Sub AddCommandBindingsToRichTextBox(rtb As RichTextBox)
|
||||
@@ -58,42 +58,61 @@ Namespace Controls.Behaviors
|
||||
dg.CommandBindings.Add(New CommandBinding(ApplicationCommands.Copy, AddressOf OnCopyDataGrid))
|
||||
End Sub
|
||||
|
||||
Private Shared Sub SetClipboardText(text As String)
|
||||
Forms.Clipboard.SetDataObject(text, False, retryTimes:=10, retryDelay:=100) '实际的复制
|
||||
Try
|
||||
System.Windows.Clipboard.Flush() '将数据持久化到系统剪贴板,避免应用程序退出后数据丢失
|
||||
Catch ex As Exception '持久化失败不抛出异常
|
||||
Logger.Warn(ex, $"剪贴板持久化失败(错误码:0x{ex.HResult:X8})")
|
||||
End Try
|
||||
End Sub
|
||||
|
||||
Private Shared Sub OnCopyTextBox(sender As Object, e As ExecutedRoutedEventArgs)
|
||||
Dim tb = TryCast(sender, TextBox)
|
||||
If tb Is Nothing OrElse tb.SelectionLength <= 0 Then Return
|
||||
|
||||
Try
|
||||
Forms.Clipboard.Clear()
|
||||
Forms.Clipboard.SetDataObject(tb.SelectedText, True)
|
||||
SetClipboardText(tb.SelectedText)
|
||||
Catch ex As Exception
|
||||
Logger.Warn(ex, "复制失败,请稍后再试", LogBehavior.Toast)
|
||||
Logger.Warn(ex, $"复制失败,请稍后再试(错误码:0x{ex.HResult:X8})", LogBehavior.Toast)
|
||||
End Try
|
||||
|
||||
e.Handled = True
|
||||
End Sub
|
||||
|
||||
Private Shared Sub CanEditTextBox(sender As Object, e As CanExecuteRoutedEventArgs)
|
||||
Dim tb = TryCast(sender, TextBox)
|
||||
e.CanExecute = tb IsNot Nothing AndAlso Not tb.IsReadOnly AndAlso
|
||||
(e.Command IsNot ApplicationCommands.Cut OrElse tb.SelectionLength > 0)
|
||||
e.Handled = True
|
||||
End Sub
|
||||
|
||||
Private Shared Sub OnCutTextBox(sender As Object, e As ExecutedRoutedEventArgs)
|
||||
Dim tb = TryCast(sender, TextBox)
|
||||
If tb Is Nothing OrElse tb.SelectionLength <= 0 Then Return
|
||||
e.Handled = True
|
||||
If tb Is Nothing OrElse tb.IsReadOnly OrElse tb.SelectionLength <= 0 Then Return
|
||||
|
||||
Try
|
||||
Forms.Clipboard.Clear()
|
||||
Forms.Clipboard.SetDataObject(tb.SelectedText, True)
|
||||
SetClipboardText(tb.SelectedText)
|
||||
Catch ex As Exception
|
||||
Logger.Warn(ex, "剪切失败,请稍后再试", LogBehavior.Toast)
|
||||
Logger.Warn(ex, $"剪切失败,请稍后再试(错误码:0x{ex.HResult:X8})", LogBehavior.Toast)
|
||||
Return
|
||||
End Try
|
||||
|
||||
tb.SelectedText = String.Empty
|
||||
e.Handled = True
|
||||
End Sub
|
||||
|
||||
Private Shared Sub OnPasteTextBox(sender As Object, e As ExecutedRoutedEventArgs)
|
||||
Dim tb = TryCast(sender, TextBox)
|
||||
If tb Is Nothing Then Return
|
||||
e.Handled = True
|
||||
If tb Is Nothing OrElse tb.IsReadOnly Then Return
|
||||
|
||||
Try
|
||||
If Forms.Clipboard.ContainsText() Then
|
||||
Dim pasteText = Forms.Clipboard.GetText()
|
||||
Dim pasteText = Retrier.Attempt(func:=
|
||||
Function(Attempt) As String
|
||||
Return If(Forms.Clipboard.ContainsText(), Forms.Clipboard.GetText(), Nothing)
|
||||
End Function, maxAttempts:=10, delay:=Function() TimeSpan.FromMilliseconds(100))
|
||||
If pasteText IsNot Nothing Then
|
||||
|
||||
'将换行符替换为空格(#7825)
|
||||
If Not tb.AcceptsReturn Then pasteText = pasteText.ReplaceLineEndings(" ", mergeMultiple:=True)
|
||||
@@ -105,10 +124,8 @@ Namespace Controls.Behaviors
|
||||
tb.SelectionLength = 0
|
||||
End If
|
||||
Catch ex As Exception
|
||||
Logger.Warn(ex, "粘贴失败,请稍后再试", LogBehavior.Toast)
|
||||
Logger.Warn(ex, $"粘贴失败,请稍后再试(错误码:0x{ex.HResult:X8})", LogBehavior.Toast)
|
||||
End Try
|
||||
|
||||
e.Handled = True
|
||||
End Sub
|
||||
|
||||
Private Shared Sub OnCopyRichTextBox(sender As Object, e As ExecutedRoutedEventArgs)
|
||||
@@ -119,10 +136,9 @@ Namespace Controls.Behaviors
|
||||
If String.IsNullOrEmpty(textRange.Text) Then Return
|
||||
|
||||
Try
|
||||
Forms.Clipboard.Clear()
|
||||
Forms.Clipboard.SetDataObject(textRange.Text, True)
|
||||
SetClipboardText(textRange.Text)
|
||||
Catch ex As Exception
|
||||
Logger.Warn(ex, "复制失败,请稍后再试", LogBehavior.Toast)
|
||||
Logger.Warn(ex, $"复制失败,请稍后再试(错误码:0x{ex.HResult:X8})", LogBehavior.Toast)
|
||||
End Try
|
||||
|
||||
e.Handled = True
|
||||
@@ -134,16 +150,16 @@ Namespace Controls.Behaviors
|
||||
|
||||
Dim selection = New TextRange(rtb.Selection.Start, rtb.Selection.End)
|
||||
If String.IsNullOrEmpty(selection.Text) Then Return
|
||||
e.Handled = True
|
||||
|
||||
Try
|
||||
Forms.Clipboard.Clear()
|
||||
Forms.Clipboard.SetDataObject(selection.Text, True)
|
||||
SetClipboardText(selection.Text)
|
||||
Catch ex As Exception
|
||||
Logger.Warn(ex, "剪切失败,请稍后再试", LogBehavior.Toast)
|
||||
Logger.Warn(ex, $"剪切失败,请稍后再试(错误码:0x{ex.HResult:X8})", LogBehavior.Toast)
|
||||
Return
|
||||
End Try
|
||||
|
||||
selection.Text = String.Empty
|
||||
e.Handled = True
|
||||
End Sub
|
||||
|
||||
Private Shared Sub OnPasteRichTextBox(sender As Object, e As ExecutedRoutedEventArgs)
|
||||
@@ -151,9 +167,11 @@ Namespace Controls.Behaviors
|
||||
If rtb Is Nothing Then Return
|
||||
|
||||
Try
|
||||
If Not Forms.Clipboard.ContainsText() Then Return
|
||||
|
||||
Dim pasteText = Forms.Clipboard.GetText()
|
||||
Dim pasteText = Retrier.Attempt(func:=
|
||||
Function(Attempt) As String
|
||||
Return If(Forms.Clipboard.ContainsText(), Forms.Clipboard.GetText(), Nothing)
|
||||
End Function, maxAttempts:=2, delay:=Function() TimeSpan.FromMilliseconds(200))
|
||||
If pasteText Is Nothing Then Return
|
||||
Dim selection = rtb.Selection
|
||||
|
||||
selection.Text = pasteText
|
||||
@@ -162,7 +180,7 @@ Namespace Controls.Behaviors
|
||||
rtb.CaretPosition = caretPos
|
||||
rtb.Selection.Select(caretPos, caretPos)
|
||||
Catch ex As Exception
|
||||
Logger.Warn(ex, "粘贴失败,请稍后再试", LogBehavior.Toast)
|
||||
Logger.Warn(ex, $"粘贴失败,请稍后再试(错误码:0x{ex.HResult:X8})", LogBehavior.Toast)
|
||||
End Try
|
||||
|
||||
e.Handled = True
|
||||
@@ -187,10 +205,9 @@ Namespace Controls.Behaviors
|
||||
Dim sbStr = sb.ToString().TrimEnd(ControlChars.Cr, ControlChars.Lf)
|
||||
|
||||
Try
|
||||
Forms.Clipboard.Clear()
|
||||
Forms.Clipboard.SetDataObject(sbStr, True)
|
||||
SetClipboardText(sbStr)
|
||||
Catch ex As Exception
|
||||
Logger.Warn(ex, "复制失败,请稍后再试", LogBehavior.Toast)
|
||||
Logger.Warn(ex, $"复制失败,请稍后再试(错误码:0x{ex.HResult:X8})", LogBehavior.Toast)
|
||||
End Try
|
||||
|
||||
e.Handled = True
|
||||
|
||||
@@ -102,73 +102,36 @@ Public Class MyCard
|
||||
RunInUi(Sub() UseAnimation = RawUseAnimation, True)
|
||||
End If
|
||||
End Sub
|
||||
Public Sub StackInstall()
|
||||
StackInstall(SwapControl, SwapType, Title)
|
||||
TriggerForceResize()
|
||||
|
||||
'填充
|
||||
Private ContentBuilder As Action(Of Panel)
|
||||
Public Sub SetContentBuilder(Builder As Action(Of Panel))
|
||||
ContentBuilder = Builder
|
||||
End Sub
|
||||
Public Shared Sub StackInstall(ByRef Stack As StackPanel, Type As Integer, Optional CardTitle As String = "")
|
||||
'这一部分的代码是好几年前留下的究极屎坑,当时还不知道该咋正确调用这种方法,就写了这么一坨屎
|
||||
'但是现在……反正勉强能用……懒得改了就这样吧.jpg
|
||||
'别骂了别骂了.jpg
|
||||
If Stack.Tag Is Nothing Then Return
|
||||
'排序
|
||||
Dim HasDuplicates As Boolean = False
|
||||
Select Case Type
|
||||
Case 3
|
||||
Stack.Tag = CType(Stack.Tag, List(Of DlOptiFineListEntry)).SortByComparison(Function(a, b) CompareVersionGE(a.DisplayName, b.DisplayName))
|
||||
Case 4, 10
|
||||
Stack.Tag = CType(Stack.Tag, List(Of DlLiteLoaderListEntry)).SortByComparison(Function(a, b) CompareVersionGE(a.Inherit, b.Inherit))
|
||||
Case 6
|
||||
Stack.Tag = CType(Stack.Tag, List(Of DlForgeVersionEntry)).OrderByDescending(Function(a) a).ToList
|
||||
Case 8, 9
|
||||
Stack.Tag = CType(Stack.Tag, List(Of ResourceVersion)).SortByComparison(Function(a, b) a.ReleaseDate > b.ReleaseDate)
|
||||
HasDuplicates =
|
||||
CType(Stack.Tag, List(Of ResourceVersion)).DistinctBy(Function(a) a.Display).Count <>
|
||||
CType(Stack.Tag, List(Of ResourceVersion)).Count
|
||||
End Select
|
||||
'控件转换
|
||||
Select Case Type
|
||||
Case 6
|
||||
ForgeDownloadListItemPreload(Stack, Stack.Tag, AddressOf ForgeSave_Click, True)
|
||||
Case 8
|
||||
PageDownloadResourceDetail.ResourceFilesCardPreload(Stack, Stack.Tag)
|
||||
End Select
|
||||
'实现控件虚拟化
|
||||
For Each Data As Object In Stack.Tag
|
||||
Select Case Type
|
||||
Case 0
|
||||
Stack.Children.Add(CType(Data, McInstance).ToListItem(AddressOf PageSelectRight.McInstanceListContent))
|
||||
Case 2
|
||||
Stack.Children.Add(McDownloadListItem(Data, AddressOf McDownloadMenuSave, True))
|
||||
Case 3
|
||||
Stack.Children.Add(OptiFineDownloadListItem(Data, AddressOf OptiFineSave_Click, True))
|
||||
Case 6
|
||||
Stack.Children.Add(ForgeDownloadListItem(Data, AddressOf ForgeSave_Click, True))
|
||||
Case 7
|
||||
'不能使用 AddressOf,这导致了 #535,原因完全不明,疑似是编译器 Bug
|
||||
Stack.Children.Add(McDownloadListItem(Data, Sub(sender, e) FrmDownloadInstall.MinecraftSelected(sender, e), False))
|
||||
Case 8
|
||||
'若存在重复的版本名,则显示文件名而非版本名(#1344)
|
||||
Stack.Children.Add(CType(Data, ResourceVersion).ToListItem(
|
||||
AddressOf FrmDownloadResourceDetail.Save_Click, IsBadDisplay:=HasDuplicates))
|
||||
Case 9
|
||||
'若存在重复的版本名,则显示文件名而非版本名(#1344)
|
||||
Stack.Children.Add(CType(Data, ResourceVersion).ToListItem(
|
||||
AddressOf FrmDownloadResourceDetail.Install_Click, AddressOf FrmDownloadResourceDetail.Save_Click, IsBadDisplay:=HasDuplicates))
|
||||
Case 10
|
||||
Stack.Children.Add(LiteLoaderDownloadListItem(Data, AddressOf LiteLoaderSave_Click, True))
|
||||
Case 11
|
||||
Stack.Children.Add(CType(Data, HelpEntry).ToListItem)
|
||||
Case 12
|
||||
Stack.Children.Add(FabricDownloadListItem(CType(Data, JObject), AddressOf FrmDownloadInstall.Fabric_Selected))
|
||||
Case 13
|
||||
Stack.Children.Add(NeoForgeDownloadListItem(Data, AddressOf NeoForgeSave_Click, True))
|
||||
Case Else
|
||||
Logger.Error($"未知的虚拟化种类:{Type}")
|
||||
End Select
|
||||
Next
|
||||
Stack.Children.Add(New FrameworkElement With {.Height = 18}) '下边距,同时适应折叠
|
||||
Stack.Tag = Nothing
|
||||
Public Sub SetContentBuilder(Of T)(Items As IEnumerable(Of T), ItemBuilder As Func(Of T, UIElement))
|
||||
SetContentBuilder(
|
||||
Sub(Stack)
|
||||
For Each Item In Items
|
||||
Stack.Children.Add(ItemBuilder(Item))
|
||||
Next
|
||||
Stack.Children.Add(New FrameworkElement With {.Height = 18})
|
||||
End Sub)
|
||||
End Sub
|
||||
''' <summary>
|
||||
''' 使用 ContentBuilder 生成卡片内容。
|
||||
''' </summary>
|
||||
Public Sub BuildContent()
|
||||
If ContentBuilder Is Nothing Then Return
|
||||
Dim Stack = TryCast(SwapControl, Panel)
|
||||
If Stack Is Nothing Then Return
|
||||
Try
|
||||
ContentBuilder(Stack)
|
||||
ContentBuilder = Nothing
|
||||
Catch
|
||||
Stack.Children.Clear()
|
||||
Throw
|
||||
End Try
|
||||
TriggerForceResize()
|
||||
End Sub
|
||||
|
||||
'动画
|
||||
@@ -278,10 +241,6 @@ Public Class MyCard
|
||||
Public SwapControl As FrameworkElement
|
||||
Public Property CanSwap As Boolean = False
|
||||
''' <summary>
|
||||
''' 被折叠的种类,用于控件虚拟化。
|
||||
''' </summary>
|
||||
Public Property SwapType As Integer
|
||||
''' <summary>
|
||||
''' 是否已被折叠。
|
||||
''' </summary>
|
||||
Public Property IsSwapped As Boolean
|
||||
@@ -293,7 +252,7 @@ Public Class MyCard
|
||||
_IsSwapped = value
|
||||
If SwapControl Is Nothing Then Return
|
||||
'展开
|
||||
If Not IsSwapped AndAlso TypeOf SwapControl Is StackPanel Then StackInstall(SwapControl, SwapType, Title)
|
||||
If Not IsSwapped Then BuildContent()
|
||||
'若尚未加载,会在 Loaded 事件中触发无动画的折叠,不需要在这里进行
|
||||
If Not IsLoaded Then Return
|
||||
'更新样式
|
||||
@@ -397,4 +356,4 @@ Partial Public Module ModAnimation
|
||||
If CallBack IsNot Nothing Then CallBack(Control)
|
||||
End If
|
||||
End Sub
|
||||
End Module
|
||||
End Module
|
||||
|
||||
@@ -90,7 +90,7 @@ Public Class MyImage
|
||||
Catch ex As Exception
|
||||
Logger.Warn(ex, $"加载图片失败({value})")
|
||||
Try
|
||||
If value.StartsWithF(PathTemp) Then FileUtils.Delete(value)
|
||||
If value.StartsWithF(PathTemp, True) Then FileUtils.Delete(value)
|
||||
Catch
|
||||
End Try
|
||||
End Try
|
||||
|
||||
@@ -11,6 +11,13 @@ Public Class FormMain
|
||||
Dim FeatureList As New List(Of KeyValuePair(Of Integer, String))
|
||||
'统计更新日志条目
|
||||
If BuildType = BuildTypes.Release Then
|
||||
If LastVersion < 411 Then 'Release 2.14.0.0
|
||||
FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "新增:允许修改、添加、移除、更新已安装版本的 MC 版本以及各个组件,可从版本设置中进入"))
|
||||
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化:启动游戏时允许按 Esc 取消"))
|
||||
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化:允许复制主页的启动日志中的内容"))
|
||||
FeatureCount += 19
|
||||
BugCount += 26
|
||||
End If
|
||||
If LastVersion < 408 Then 'Release 2.13.1.1
|
||||
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化:版本设置中,添加打开截图文件夹的快捷方式"))
|
||||
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化:导出整合包时,可以勾选导出光影设置文件"))
|
||||
@@ -93,6 +100,13 @@ Public Class FormMain
|
||||
'3:BUG+ IMP* FEAT-
|
||||
'2:BUG* IMP-
|
||||
'1:BUG-
|
||||
If LastVersion < 412 Then 'Snapshot 2.14.0.0
|
||||
FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "新增:允许修改、添加、移除、更新已安装版本的 MC 版本以及各个组件,可从版本设置中进入"))
|
||||
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化:启动游戏时允许按 Esc 取消"))
|
||||
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化:允许复制主页的启动日志中的内容"))
|
||||
FeatureCount += 19
|
||||
BugCount += 26
|
||||
End If
|
||||
If LastVersion < 410 Then 'Snapshot 2.13.1.1
|
||||
If LastVersion = 409 Then FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:更新 Mod 时可能更新成另一个 Mod 加载器的版本"))
|
||||
FeatureCount += 2
|
||||
@@ -786,7 +800,7 @@ Public Class FormMain
|
||||
If PanMsg.Children.Any Then
|
||||
If e.Key = Key.Enter Then
|
||||
CType(PanMsg.Children(0), Object).Btn1_Click()
|
||||
ElseIf e.Key = Key.Escape OrElse (e.Key = Key.W AndAlso Keyboard.Modifiers.HasFlag(ModifierKeys.Control)) Then
|
||||
ElseIf e.Key = Key.Escape Then
|
||||
Dim Msg As Object = PanMsg.Children(0)
|
||||
If TypeOf Msg IsNot MyMsgInput AndAlso TypeOf Msg IsNot MyMsgSelect AndAlso Msg.Btn3.Visibility = Visibility.Visible Then
|
||||
Msg.Btn3_Click()
|
||||
@@ -803,13 +817,13 @@ Public Class FormMain
|
||||
' 在没有弹窗时:继续检查……
|
||||
'==========================
|
||||
|
||||
'按 ESC:启动中则取消启动,否则返回上一级
|
||||
'按 ESC 取消启动,或返回上一级
|
||||
If e.Key = Key.Escape Then
|
||||
If McLaunchLoader.State = LoadState.Loading Then
|
||||
McLaunchCancel()
|
||||
Else
|
||||
TriggerPageBack()
|
||||
If PageCurrent = FormMain.PageType.Launch AndAlso McLaunchLoader.State = LoadState.Loading Then
|
||||
FrmLaunchLeft.BtnCancel_Click()
|
||||
Return
|
||||
End If
|
||||
TriggerPageBack()
|
||||
End If
|
||||
'更改隐藏版本可见性
|
||||
If e.Key = Key.F11 AndAlso PageCurrent = FormMain.PageType.InstanceSelect Then
|
||||
@@ -834,11 +848,6 @@ Public Class FormMain
|
||||
If TypeOf PageRight Is IRefreshable Then CType(PageRight, IRefreshable).Refresh()
|
||||
Return
|
||||
End If
|
||||
'Ctrl + w 关闭程序
|
||||
If e.Key = Key.W AndAlso Keyboard.Modifiers.HasFlag(ModifierKeys.Control) Then
|
||||
EndProgram(True)
|
||||
Return
|
||||
End If
|
||||
'调用启动游戏
|
||||
If e.Key = Key.Enter AndAlso PageCurrent = FormMain.PageType.Launch Then
|
||||
If IsAprilEnabled AndAlso Not IsAprilGiveup Then
|
||||
@@ -1026,14 +1035,14 @@ Public Class FormMain
|
||||
If FilePathList.Count > 1 Then
|
||||
'必须要求全部为 jar 文件
|
||||
For Each File In PathList
|
||||
If Not {"jar", "litemod", "disabled", "old"}.Contains(File.AfterLast(".").Lower) Then
|
||||
If Not {"jar", "litemod", "disabled", "old"}.Contains(PathUtils.GetExtension(File)) Then
|
||||
Hint("一次请只拖入一个文件!", HintType.Red)
|
||||
Return
|
||||
End If
|
||||
Next
|
||||
End If
|
||||
'主页
|
||||
Dim Extension As String = FilePath.AfterLast(".").Lower
|
||||
Dim Extension As String = PathUtils.GetExtension(FilePath)
|
||||
If Extension = "xaml" Then
|
||||
Logger.Info("文件后缀为 XAML,作为主页加载")
|
||||
If FileUtils.Exists(Paths.Base & "PCL\Custom.xaml") Then
|
||||
@@ -1054,9 +1063,9 @@ Public Class FormMain
|
||||
If PageInstanceMod.InstallMods(PathList) Then Return
|
||||
'安装整合包
|
||||
If {"zip", "rar", "mrpack"}.Any(Function(t) t = Extension) Then '部分压缩包是 zip 格式但后缀为 rar,总之试一试
|
||||
Logger.Info("文件为压缩包,尝试作为整合包安装")
|
||||
Hint("检测到压缩包拖入,正在准备安装……")
|
||||
Hint("正在读取压缩包……")
|
||||
Try
|
||||
Logger.Info("文件为压缩包,尝试作为整合包安装")
|
||||
ModpackInstall(FilePath)
|
||||
RunInUi(Sub() FrmMain.PageChange(FormMain.PageType.TaskManager))
|
||||
Return
|
||||
@@ -1067,7 +1076,7 @@ Public Class FormMain
|
||||
End If
|
||||
'RAR 处理
|
||||
If Extension = "rar" Then
|
||||
Hint("PCL 无法处理 rar 格式的压缩包,请在解压后重新压缩为 zip 格式再试!")
|
||||
Hint("PCL 无法处理 rar 格式的压缩包,请在解压后重新压缩为 zip 格式再试!", HintType.Red)
|
||||
Return
|
||||
End If
|
||||
'错误报告分析
|
||||
@@ -1083,7 +1092,7 @@ Public Class FormMain
|
||||
Logger.Error(ex, "自主错误报告分析失败")
|
||||
End Try
|
||||
'未知操作
|
||||
Hint("PCL 无法确定应当执行的文件拖拽操作……")
|
||||
Hint("PCL 无法确定适合的操作……", HintType.Red)
|
||||
End Sub, "文件拖拽")
|
||||
End Sub
|
||||
|
||||
@@ -1225,9 +1234,10 @@ Public Class FormMain
|
||||
OtherTest = 2
|
||||
InstanceOverall = 0
|
||||
InstanceSetup = 1
|
||||
InstanceMod = 2
|
||||
InstanceModDisabled = 3
|
||||
InstanceExport = 4
|
||||
InstanceModify = 2
|
||||
InstanceMod = 3
|
||||
InstanceModDisabled = 4
|
||||
InstanceExport = 5
|
||||
End Enum
|
||||
''' <summary>
|
||||
''' 获取次级页面的名称。若并非次级页面则返回空字符串,故可以以此判断是否为次级页面。
|
||||
@@ -1392,6 +1402,10 @@ Public Class FormMain
|
||||
''' </summary>
|
||||
Private Sub PageChangeActual(Stack As PageStackData, Optional SubType As PageSubType = -1)
|
||||
If PageCurrent = Stack AndAlso (PageCurrentSub = SubType OrElse SubType = -1) Then Return
|
||||
If Stack.Page = PageType.InstanceSetup AndAlso PageInstanceLeft.Instance IsNot Nothing AndAlso McInstanceLock.IsLocked(PageInstanceLeft.Instance) Then
|
||||
Hint("该版本正在被修改,暂时无法进入版本设置!", HintType.Red)
|
||||
Return
|
||||
End If
|
||||
AniControlEnabled += 1
|
||||
Try
|
||||
|
||||
|
||||
@@ -6,12 +6,12 @@ Public Module ModBase
|
||||
#Region "声明"
|
||||
|
||||
'下列版本信息由更新器自动修改
|
||||
Public Const VersionBaseName As String = "2.13.1.1" '显示用版本名
|
||||
Public Const VersionBaseName As String = "2.14.0.0" '显示用版本名
|
||||
Public Const CommitHash As String = "" 'Commit Hash,由 GitHub Workflow 自动替换
|
||||
#If RELEASE Then
|
||||
Public Const VersionCode As Integer = 408 '正式版
|
||||
Public Const VersionCode As Integer = 411 '正式版
|
||||
#Else
|
||||
Public Const VersionCode As Integer = 410 '快照版
|
||||
Public Const VersionCode As Integer = 412 '快照版
|
||||
#End If
|
||||
|
||||
'版本信息
|
||||
@@ -47,7 +47,7 @@ Public Module ModBase
|
||||
''' <summary>
|
||||
''' 程序的缓存文件夹路径,以 \ 结尾。
|
||||
''' </summary>
|
||||
Public PathTemp As String = If(Settings.Get(Of String)("SystemSystemCache") = "", Path.GetTempPath() & "PCL\", Settings.Get(Of String)("SystemSystemCache")).ToString.Replace("/", "\").TrimEnd("\") & "\"
|
||||
Public PathTemp As String = PathUtils.AddSlashSuffix(If(Settings.Get(Of String)("SystemSystemCache") = "", Path.GetTempPath() & "PCL\", Settings.Get(Of String)("SystemSystemCache")).Replace("/", "\"))
|
||||
''' <summary>
|
||||
''' 当前程序的语言。
|
||||
''' </summary>
|
||||
@@ -75,7 +75,7 @@ Public Module ModBase
|
||||
''' <summary>
|
||||
''' 系统盘盘符,以 \ 结尾。例如 “C:\”。
|
||||
''' </summary>
|
||||
Public OsDrive As String = Environment.GetLogicalDrives().Where(Function(p) Directory.Exists(p)).First.Upper.First & ":\" '#3799
|
||||
Public OsDrive As String = Environment.GetLogicalDrives().First(Function(p) Directory.Exists(p)) '#3799
|
||||
|
||||
Public ReadOnly Property ModeDebug As Boolean
|
||||
Get
|
||||
@@ -576,7 +576,7 @@ Public Module ModBase
|
||||
Try
|
||||
If String.IsNullOrEmpty(Folder) Then Return False
|
||||
Folder = PathUtils.AddSlashSuffix(Folder)
|
||||
If Folder.EndsWithF(":\System Volume Information\") OrElse Folder.EndsWithF(":\$RECYCLE.BIN\") Then Return False
|
||||
If Folder.EndsWithF(":\System Volume Information\", True) OrElse Folder.EndsWithF(":\$RECYCLE.BIN\", True) Then Return False
|
||||
If Not DirectoryUtils.Exists(Folder) Then Return False
|
||||
Dim TestFilePath As String = $"{Folder}CheckPermission{GetUuid()}.txt"
|
||||
FileUtils.Write(TestFilePath, "临时文件,用于检测该文件夹的权限是否正常。")
|
||||
@@ -593,7 +593,7 @@ Public Module ModBase
|
||||
Public Sub CheckPermissionWithException(Folder As String)
|
||||
If String.IsNullOrWhiteSpace(Folder) Then Throw New ArgumentNullException("文件夹名不能为空!")
|
||||
Folder = PathUtils.AddSlashSuffix(Folder)
|
||||
If Folder.EndsWithF(":\System Volume Information\") OrElse Folder.EndsWithF(":\$RECYCLE.BIN\") Then Throw New UnauthorizedAccessException("没有对系统文件夹的权限!")
|
||||
If Folder.EndsWithF(":\System Volume Information\", True) OrElse Folder.EndsWithF(":\$RECYCLE.BIN\", True) Then Throw New UnauthorizedAccessException("没有对系统文件夹的权限!")
|
||||
If Not DirectoryUtils.Exists(Folder) Then Throw New DirectoryNotFoundException("文件夹不存在!")
|
||||
Dim TestFilePath As String = $"{Folder}CheckPermission{GetUuid()}.txt"
|
||||
FileUtils.Write(TestFilePath, "临时文件,用于检测该文件夹的权限是否正常。")
|
||||
@@ -788,7 +788,7 @@ Public Module ModBase
|
||||
''' <summary>
|
||||
''' 可用于临时存放文件的,不含任何特殊字符的文件夹路径,以“\”结尾。
|
||||
''' </summary>
|
||||
Public PathPure As Lazy(Of String) = New Lazy(Of String)(
|
||||
Public PathPure As New Lazy(Of String)(
|
||||
Function()
|
||||
If Paths.Base.IsAsciiOnly() Then
|
||||
Return Paths.Base & "PCL\"
|
||||
@@ -845,6 +845,12 @@ Public Module ModBase
|
||||
Return (Now.ToUniversalTime().Ticks - 621355968000000000) / 10000000
|
||||
End Function
|
||||
''' <summary>
|
||||
''' 获取十进制 Unix 时间戳。
|
||||
''' </summary>
|
||||
Public Function ToUnixTimestampUtc(Time As Date) As Long
|
||||
Return (Time.ToUniversalTime().Ticks - 621355968000000000) / 10000000
|
||||
End Function
|
||||
''' <summary>
|
||||
''' 时间戳转化为日期。
|
||||
''' </summary>
|
||||
Public Function GetDate(timeStamp As Integer) As Date
|
||||
@@ -1021,20 +1027,22 @@ Public Module ModBase
|
||||
''' <summary>
|
||||
''' 设置剪贴板。将在另一线程运行,且不会抛出异常。
|
||||
''' </summary>
|
||||
Public Sub ClipboardSet(Text As String, Optional ShowSuccessHint As Boolean = True, Optional SuccessHint As String = "")
|
||||
Public Sub ClipboardSet(Text As String, Optional ShowSuccessHint As Boolean = True)
|
||||
RunInThread(
|
||||
Sub()
|
||||
RunInUi(
|
||||
Sub()
|
||||
Try
|
||||
My.Computer.Clipboard.Clear()
|
||||
If Not String.IsNullOrEmpty(Text) Then My.Computer.Clipboard.SetText(Text)
|
||||
If ShowSuccessHint Then Hint(If(String.IsNullOrEmpty(SuccessHint), "已成功复制!", SuccessHint), HintType.Green)
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex, behavior:=LogBehavior.None)
|
||||
Hint("复制失败,可能由于剪贴板被其他程序占用!", HintType.Red)
|
||||
End Try
|
||||
End Sub)
|
||||
Try
|
||||
Retrier.Attempt(delay:=Function(Attempt) TimeSpan.FromMilliseconds(200), maxAttempts:=4, isRetryAllowed:=Function(ex) True, action:=
|
||||
Sub()
|
||||
RunInUiWait(
|
||||
Sub()
|
||||
My.Computer.Clipboard.Clear()
|
||||
If Not String.IsNullOrEmpty(Text) Then My.Computer.Clipboard.SetText(Text)
|
||||
End Sub)
|
||||
End Sub)
|
||||
If ShowSuccessHint Then Hint("已成功复制!", HintType.Green)
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex, "可能由于剪贴板被其他程序占用,文本复制失败", LogBehavior.Toast)
|
||||
End Try
|
||||
End Sub)
|
||||
End Sub
|
||||
''' <summary>
|
||||
|
||||
@@ -1396,7 +1396,7 @@ FinishExCatch:
|
||||
Public Overrides Sub Start(Optional Input As Object = Nothing, Optional IsForceRestart As Boolean = False)
|
||||
If Input IsNot Nothing Then Files = New ConcurrentQueue(Of NetFile)(CType(Input, IEnumerable(Of NetFile)))
|
||||
'去重
|
||||
Files = New ConcurrentQueue(Of NetFile)(Files.DistinctBy(Function(a) a.LocalPath))
|
||||
Files = New ConcurrentQueue(Of NetFile)(Files.DistinctBy(Function(a) PathUtils.ForCompare(a.LocalPath).Lower()))
|
||||
'设置剩余文件数
|
||||
SyncLock FileRemainLock
|
||||
FileRemain += Files.Where(Function(f) f.State <> NetState.Finished).Count
|
||||
@@ -1421,7 +1421,7 @@ FinishExCatch:
|
||||
Next
|
||||
If Not File.HasAvailableSource() Then Throw New ArgumentException("输入的下载链接不正确!")
|
||||
File.LocalPath = File.LocalPath.Replace("/", "\")
|
||||
If Not File.LocalPath.Lower.Contains(":\") Then Throw New ArgumentException("输入的本地文件地址不正确:" & File.LocalPath)
|
||||
If Not File.LocalPath.Contains(":\") Then Throw New ArgumentException("输入的本地文件地址不正确:" & File.LocalPath)
|
||||
If File.LocalPath.EndsWithF("\") Then Throw New ArgumentException("请输入含文件名的完整文件路径:" & File.LocalPath)
|
||||
DirectoryUtils.Create(PathUtils.RemoveLastPart(File.LocalPath)) '创建目标文件夹
|
||||
Next
|
||||
@@ -1519,7 +1519,7 @@ FinishExCatch:
|
||||
Select(Function(FolderName) (FolderName, File.LocalPath.IndexOfF(FolderName, True))).
|
||||
Where(Function(kv) kv.Item2 >= 0).ToList
|
||||
If Not TypeIndexes.Any Then
|
||||
If File.LocalName.EndsWithF(".jar") Then
|
||||
If PathUtils.GetExtension(File.LocalName) = "jar" Then
|
||||
TypeIndexes.Add(("\versions\", 1)) '总是对 jar 进行版本文件检查,以包括另存为 jar 的情况
|
||||
Else
|
||||
Return Nothing
|
||||
@@ -1547,7 +1547,7 @@ FinishExCatch:
|
||||
Case "versions\"
|
||||
'版本 jar 或 json:查找 MC 文件夹下的各个版本文件夹
|
||||
For Each VersionFolder In VersionFolders
|
||||
For Each Candidate In DirectoryUtils.EnumerateFiles(VersionFolder, searchPattern:="*." & PathUtils.GetLastPart(File.LocalPath).AfterLast(".").Lower)
|
||||
For Each Candidate In DirectoryUtils.EnumerateFiles(VersionFolder, searchPattern:="*." & PathUtils.GetExtension(File.LocalPath))
|
||||
If CheckCandidate(Candidate, File.Check) Then Return Candidate
|
||||
Next
|
||||
Next
|
||||
|
||||
@@ -382,7 +382,7 @@ Public Class ValidateFolderPath
|
||||
Public Overrides Function Validate(Str As String) As String
|
||||
'去除尾部斜线,统一为 \
|
||||
Str = Str.Replace("/", "\")
|
||||
If Not Str.TrimEnd("\").EndsWithF(":") Then Str = Str.TrimEnd("\")
|
||||
If Not PathUtils.RemoveSlashSuffix(Str).EndsWithF(":") Then Str = PathUtils.RemoveSlashSuffix(Str)
|
||||
'检查是否为空
|
||||
Dim LengthCheck As String = New ValidateNullOrWhiteSpace().Validate(Str)
|
||||
If LengthCheck <> "" Then Return LengthCheck
|
||||
|
||||
@@ -92,7 +92,7 @@ Public Class CrashAnalyzer
|
||||
'尝试视作压缩包解压
|
||||
Try
|
||||
Dim Info = FileUtils.GetInfo(FilePath)
|
||||
If Info.Exists AndAlso Info.Length > 0 AndAlso Not FilePath.EndsWithF(".jar", True) Then
|
||||
If Info.Exists AndAlso Info.Length > 0 AndAlso Not PathUtils.GetExtension(FilePath) = "jar" Then
|
||||
FileUtils.ExtractToDirectory(FilePath, TempFolder & "Temp\")
|
||||
Logger.Info($"已解压导入的日志文件:{FilePath}")
|
||||
GoTo Extracted
|
||||
@@ -163,9 +163,9 @@ Extracted:
|
||||
Else
|
||||
TargetType = AnalyzeFileType.ExtraLogFile
|
||||
End If
|
||||
ElseIf MatchName.EndsWithF(".log", True) Then
|
||||
ElseIf PathUtils.GetExtension(MatchName) = "log" Then
|
||||
TargetType = AnalyzeFileType.ExtraLogFile
|
||||
ElseIf MatchName.EndsWithF(".txt", True) Then
|
||||
ElseIf PathUtils.GetExtension(MatchName) = "txt" Then
|
||||
TargetType = AnalyzeFileType.ExtraReportFile
|
||||
Else
|
||||
Logger.Info($"{MatchName} 分类为 Ignore")
|
||||
|
||||
@@ -242,8 +242,6 @@ Public Module ModDownload
|
||||
DlPreferMojang = DeltaTime < 4000
|
||||
Logger.Info($"Mojang 官方源加载耗时:{DeltaTime}ms,{If(DlPreferMojang, "可优先使用官方源", "不优先使用官方源")}")
|
||||
End If
|
||||
'添加 PCL 特供项
|
||||
If FileUtils.Exists(PathTemp & "Cache\download.json") Then Versions.Merge(FileUtils.ReadAsJson(PathTemp & "Cache\download.json"))
|
||||
'返回
|
||||
Loader.Output = New DlClientListResult With {.IsOfficial = True, .SourceName = "Mojang 官方源", .Value = Json}
|
||||
'MC 更新提示
|
||||
@@ -438,7 +436,7 @@ Public Module ModDownload
|
||||
.FileName = If(Name(i).ContainsIgnoreCase("pre"), "preview_", "") & "OptiFine_" & Name(i).Replace(" ", "_") & ".jar",
|
||||
.RequiredForgeVersion = Forge(i).Replace("Forge ", "").Replace("#", "")}
|
||||
If Entry.RequiredForgeVersion.Contains("N/A") Then Entry.RequiredForgeVersion = Nothing
|
||||
Entry.InstanceName = Entry.Inherit & "-OptiFine_" & Name(i).ToString.Replace(" ", "_").Replace(Entry.Inherit & "_", "")
|
||||
Entry.InstanceName = Entry.Inherit & "-OptiFine_" & Name(i).AfterFirst(" ").Replace(" ", "_")
|
||||
Versions.Add(Entry)
|
||||
Next
|
||||
Loader.Output = New DlOptiFineListResult With {.IsOfficial = True, .SourceName = "OptiFine 官方源", .Value = Versions}
|
||||
@@ -581,7 +579,7 @@ Public Module ModDownload
|
||||
If Version <> other.Version Then
|
||||
Return Version.CompareTo(other.Version)
|
||||
Else
|
||||
Return CompareVersion(VersionName, other.VersionName)
|
||||
Return McUtils.CompareVersion(VersionName, other.VersionName)
|
||||
End If
|
||||
End Function
|
||||
End Class
|
||||
|
||||
@@ -18,7 +18,7 @@ Public Module ModJava
|
||||
'强制选择的 Java
|
||||
Dim SelectedJavaSetting = Settings.Get(Of String)("LaunchArgumentJavaSelect")
|
||||
Dim SelectedJava = If(SelectedJavaSetting.StartsWithF("{"), SelectedJavaSetting.DeserializeJson(Of JObject)()("Path").ToString, "")
|
||||
Dim Match = OldJavaList.FirstOrDefault(Function(j) j.Folder.Equals(SelectedJava, StringComparison.OrdinalIgnoreCase))
|
||||
Dim Match = OldJavaList.FirstOrDefault(Function(j) PathUtils.IsSame(j.Folder, SelectedJava))
|
||||
If Match IsNot Nothing Then
|
||||
OldJavaList.Remove(Match)
|
||||
OldJavaList.Insert(0, Match)
|
||||
@@ -78,7 +78,7 @@ Public Module ModJava
|
||||
Return
|
||||
End If
|
||||
'不再移除它
|
||||
Configs.JavaRemovedList.Edit(Sub(ByRef List) List.RemoveIf(Function(f) f.Equals(NewJava.Folder, StringComparison.OrdinalIgnoreCase)))
|
||||
Configs.JavaRemovedList.Edit(Sub(ByRef List) List.RemoveIf(Function(f) PathUtils.IsSame(f, NewJava.Folder)))
|
||||
'加入列表顶部
|
||||
Configs.JavaList.Edit(
|
||||
Sub(ByRef List)
|
||||
@@ -150,16 +150,16 @@ Public Module ModJava
|
||||
End Sub
|
||||
|
||||
'原版 26-:通过版本号判断
|
||||
If (Not Instance.Version.Vaild AndAlso Instance.ReleaseTime >= New Date(2024, 4, 2)) OrElse
|
||||
(Instance.Version.Vaild AndAlso Instance.Version.Vanilla >= New Version(20, 0, 5)) Then
|
||||
If (Not Instance.Version.Valid AndAlso Instance.ReleaseTime >= New Date(2024, 4, 2)) OrElse
|
||||
(Instance.Version.Valid AndAlso Instance.Version.Vanilla >= New Version(20, 0, 5)) Then
|
||||
'1.20.5+(24w14a+):至少 Java 21
|
||||
AddConstraint(ValueRange(Of Version).AtLeast(New Version(21, 0)))
|
||||
ElseIf (Not Instance.Version.Vaild AndAlso Instance.ReleaseTime >= New Date(2021, 11, 16)) OrElse
|
||||
(Instance.Version.Vaild AndAlso Instance.Version.Vanilla.Major >= 18) Then
|
||||
ElseIf (Not Instance.Version.Valid AndAlso Instance.ReleaseTime >= New Date(2021, 11, 16)) OrElse
|
||||
(Instance.Version.Valid AndAlso Instance.Version.Vanilla.Major >= 18) Then
|
||||
'1.18 pre2+:至少 Java 17
|
||||
AddConstraint(ValueRange(Of Version).AtLeast(New Version(17, 0)))
|
||||
ElseIf (Not Instance.Version.Vaild AndAlso Instance.ReleaseTime >= New Date(2021, 5, 11)) OrElse
|
||||
(Instance.Version.Vaild AndAlso Instance.Version.Vanilla.Major >= 17) Then
|
||||
ElseIf (Not Instance.Version.Valid AndAlso Instance.ReleaseTime >= New Date(2021, 5, 11)) OrElse
|
||||
(Instance.Version.Valid AndAlso Instance.Version.Vanilla.Major >= 17) Then
|
||||
'1.17+ (21w19a+):至少 Java 16
|
||||
AddConstraint(ValueRange(Of Version).AtLeast(New Version(16, 0)))
|
||||
ElseIf Instance.ReleaseTime.Year >= 2017 Then 'Minecraft 1.12 与 1.11 的分界线正好是 2017 年,太棒了
|
||||
@@ -185,7 +185,7 @@ Public Module ModJava
|
||||
End If
|
||||
|
||||
'OptiFine 检测
|
||||
If Instance.Version.HasOptiFine AndAlso Instance.Version.Vaild Then '不管非标准版本
|
||||
If Instance.Version.HasOptiFine AndAlso Instance.Version.Valid Then '不管非标准版本
|
||||
If Instance.Version.Vanilla.Major < 7 Then
|
||||
'<1.7:至多 Java 8
|
||||
AddConstraint(ValueRange(Of Version).LessThan(New Version(9, 0)))
|
||||
@@ -199,11 +199,11 @@ Public Module ModJava
|
||||
End If
|
||||
|
||||
'Forge 检测(部分测试结果见 #8432)
|
||||
If Instance.Version.HasForge Then
|
||||
If Instance.Version.ModLoaders.HasFlagF(ModLoaders.Forge) Then
|
||||
If Instance.Version.Vanilla >= New Version(6, 0, 1) AndAlso Instance.Version.Vanilla <= New Version(7, 0, 2) Then
|
||||
'1.6.1 - 1.7.2:必须 Java 7
|
||||
AddConstraint(ValueRange(Of Version).ClosedOpen(New Version(7, 0), New Version(8, 0)))
|
||||
ElseIf Instance.Version.Vanilla.Major <= 12 OrElse Not Instance.Version.Vaild Then '非标准版本
|
||||
ElseIf Instance.Version.Vanilla.Major <= 12 OrElse Not Instance.Version.Valid Then '非标准版本
|
||||
'<=1.12:Java 8
|
||||
AddConstraint(ValueRange(Of Version).LessThan(New Version(9, 0)))
|
||||
ElseIf Instance.Version.Vanilla.Major <= 14 Then
|
||||
@@ -212,38 +212,38 @@ Public Module ModJava
|
||||
ElseIf Instance.Version.Vanilla.Major = 15 Then
|
||||
'1.15:Java 8 - 15
|
||||
AddConstraint(ValueRange(Of Version).ClosedOpen(New Version(8, 0), New Version(16, 0)))
|
||||
ElseIf CompareVersionGE(Instance.Version.Forge, "34.0.0") AndAlso CompareVersionGE("36.2.25", Instance.Version.Forge) Then
|
||||
ElseIf McUtils.CompareVersionGE(Instance.Version.ModLoaderVersions(ModLoaders.Forge), "34.0.0") AndAlso McUtils.CompareVersionGE("36.2.25", Instance.Version.ModLoaderVersions(ModLoaders.Forge)) Then
|
||||
'1.16.3~5,Forge 34.0.0 ~ 36.2.25:最高 Java 8u320
|
||||
AddConstraint(ValueRange(Of Version).AtMost(New Version(8, 0, 320)))
|
||||
ElseIf CompareVersionGE(Instance.Version.Forge, "36.2.26") AndAlso CompareVersionGE("36.999999.999999", Instance.Version.Forge) Then
|
||||
ElseIf McUtils.CompareVersionGE(Instance.Version.ModLoaderVersions(ModLoaders.Forge), "36.2.26") AndAlso McUtils.CompareVersionGE("36.999999.999999", Instance.Version.ModLoaderVersions(ModLoaders.Forge)) Then
|
||||
'1.16.5,Forge 36.2.26+,<37.0.0:最高 Java 23
|
||||
AddConstraint(ValueRange(Of Version).LessThan(New Version(24, 0)))
|
||||
ElseIf CompareVersionGE(Instance.Version.Forge, "37.0.0") AndAlso CompareVersionGE("37.0.79", Instance.Version.Forge) Then
|
||||
ElseIf McUtils.CompareVersionGE(Instance.Version.ModLoaderVersions(ModLoaders.Forge), "37.0.0") AndAlso McUtils.CompareVersionGE("37.0.79", Instance.Version.ModLoaderVersions(ModLoaders.Forge)) Then
|
||||
'1.17.1,Forge 37.0.0 ~ 37.0.79:最高 Java 16
|
||||
AddConstraint(ValueRange(Of Version).LessThan(New Version(17, 0)))
|
||||
ElseIf Instance.Version.Vanilla.Major = 18 AndAlso Instance.Version.HasOptiFine Then '#305
|
||||
'1.18:若安装了 OptiFine,最高 Java 18
|
||||
AddConstraint(ValueRange(Of Version).LessThan(New Version(19, 0)))
|
||||
ElseIf CompareVersionGE(Instance.Version.Forge, "45.0.21") AndAlso CompareVersionGE("45.0.65", Instance.Version.Forge) Then
|
||||
ElseIf McUtils.CompareVersionGE(Instance.Version.ModLoaderVersions(ModLoaders.Forge), "45.0.21") AndAlso McUtils.CompareVersionGE("45.0.65", Instance.Version.ModLoaderVersions(ModLoaders.Forge)) Then
|
||||
'1.19.4,Forge 45.0.21 ~ 45.0.65:最高 Java 19
|
||||
AddConstraint(ValueRange(Of Version).LessThan(New Version(20, 0)))
|
||||
ElseIf CompareVersionGE(Instance.Version.Forge, "45.0.66") AndAlso CompareVersionGE("47.4.8", Instance.Version.Forge) Then
|
||||
ElseIf McUtils.CompareVersionGE(Instance.Version.ModLoaderVersions(ModLoaders.Forge), "45.0.66") AndAlso McUtils.CompareVersionGE("47.4.8", Instance.Version.ModLoaderVersions(ModLoaders.Forge)) Then
|
||||
'1.19.4~1.20.1,Forge 45.0.66 ~ 47.4.8:最高 Java 21
|
||||
AddConstraint(ValueRange(Of Version).LessThan(New Version(22, 0)))
|
||||
End If
|
||||
End If
|
||||
|
||||
'NeoForge 检测
|
||||
If Instance.Version.HasNeoForge Then
|
||||
If Instance.Version.ModLoaders.HasFlagF(ModLoaders.NeoForge) Then
|
||||
If Instance.Version.Vanilla = New Version(20, 0, 1) OrElse
|
||||
(CompareVersionGE("20.2.62-beta", Instance.Version.NeoForge) AndAlso Not Instance.Version.NeoForge.Contains("25w14craftmine")) Then
|
||||
(McUtils.CompareVersionGE("20.2.62-beta", Instance.Version.ModLoaderVersions(ModLoaders.NeoForge)) AndAlso Not Instance.Version.ModLoaderVersions(ModLoaders.NeoForge).Contains("25w14craftmine")) Then
|
||||
'1.20.1,以及 1.20.2 的 20.2.62-beta 之前:最高 Java 21
|
||||
AddConstraint(ValueRange(Of Version).LessThan(New Version(22, 0)))
|
||||
End If
|
||||
End If
|
||||
|
||||
'Fabric 检测
|
||||
If Instance.Version.HasFabric AndAlso Instance.Version.Vaild Then '不管非标准版本
|
||||
If Instance.Version.ModLoaders.HasFlagF(ModLoaders.Fabric) AndAlso Instance.Version.Valid Then '不管非标准版本
|
||||
If Instance.Version.Vanilla.Major >= 15 AndAlso Instance.Version.Vanilla.Major <= 16 Then
|
||||
'1.15 - 1.16:Java 8+
|
||||
AddConstraint(ValueRange(Of Version).AtLeast(New Version(8, 0)))
|
||||
@@ -251,15 +251,14 @@ Public Module ModJava
|
||||
'1.18+:Java 17+
|
||||
AddConstraint(ValueRange(Of Version).AtLeast(New Version(17, 0)))
|
||||
End If
|
||||
If Instance.Version.Fabric <> "未知版本" AndAlso
|
||||
CompareVersion(Instance.Version.Fabric, "0.17.0") < 0 Then
|
||||
If Instance.Version.ModLoaderVersions(ModLoaders.Fabric) <> "未知版本" AndAlso McUtils.CompareVersion(Instance.Version.ModLoaderVersions(ModLoaders.Fabric), "0.17.0") < 0 Then
|
||||
'Fabric Loader 0.16.x 及更早版本的 Mixin/ASM 不兼容 Java 25
|
||||
AddConstraint(ValueRange(Of Version).LessThan(New Version(25, 0)))
|
||||
End If
|
||||
End If
|
||||
|
||||
'LiteLoader 检测
|
||||
If Instance.Version.HasLiteLoader AndAlso Instance.Version.Vaild Then '不管非标准版本
|
||||
If Instance.Version.ModLoaders.HasFlagF(ModLoaders.LiteLoader) AndAlso Instance.Version.Valid Then '不管非标准版本
|
||||
'最高 Java 8
|
||||
AddConstraint(ValueRange(Of Version).LessThan(New Version(9, 0)))
|
||||
End If
|
||||
@@ -411,9 +410,9 @@ Public Module ModJava
|
||||
Dim Components = DownloadListWorker.LastResult
|
||||
|
||||
'确定要下载的目标 Java
|
||||
Dim JavaToDownload As JavaDownloadInfo = If(
|
||||
Components.FirstOrDefault(Function(Comp) Comp.Java("version")("name").ToString = RecommendedComponent), '优先选择指定的 Component
|
||||
Components.FirstOrDefault(Function(Comp) Range.Contains(Comp.JavaVersion)))
|
||||
Dim JavaToDownload As JavaDownloadInfo = Components.FirstOrDefault(
|
||||
Function(Comp) Comp.Java("version")("name").ToString = RecommendedComponent, '优先选择指定的 Component
|
||||
Function(Comp) Range.Contains(Comp.JavaVersion))
|
||||
If JavaToDownload Is Nothing Then
|
||||
Logger.Warn($"Mojang 提供的 Java 列表中没有合适的 Java,无法自动下载")
|
||||
'提示需要手动下载 Java
|
||||
|
||||
@@ -48,7 +48,7 @@ Public Module ModLaunch
|
||||
End Try
|
||||
'检查版本
|
||||
CurrentLaunchOptions.Instance.Load()
|
||||
If CurrentLaunchOptions.Instance.State = McInstanceState.Error Then
|
||||
If CurrentLaunchOptions.Instance.State = McInstance.McInstanceState.Error Then
|
||||
Hint($"无法启动 {CurrentLaunchOptions.Instance.Name}:{CurrentLaunchOptions.Instance.Info}", HintType.Red)
|
||||
Return False
|
||||
End If
|
||||
@@ -57,6 +57,10 @@ Public Module ModLaunch
|
||||
FrmLaunchLeft.RefreshButtonsUI()
|
||||
FrmLaunchLeft.RefreshPage(False, False)
|
||||
End If
|
||||
If McInstanceSelected IsNot Nothing AndAlso McInstanceLock.IsLocked(McInstanceSelected) Then
|
||||
Hint($"版本 {McInstanceSelected.Name} 正在被修改,请稍后再启动!", HintType.Red)
|
||||
Return False
|
||||
End If
|
||||
FrmMain.AprilGiveup()
|
||||
'禁止进入版本选择页面(否则就可以在启动中切换 McInstanceSelected 了)
|
||||
FrmMain.PageStack = FrmMain.PageStack.Where(Function(p) p.Page <> FormMain.PageType.InstanceSelect).ToList
|
||||
@@ -70,7 +74,12 @@ Public Module ModLaunch
|
||||
''' </summary>
|
||||
Public Sub McLaunchLog(Text As String, Optional Level As LogLevel = LogLevel.Info)
|
||||
Text = FilterUserName(FilterAccessToken(Text, "*"), "*")
|
||||
If ModeDebug Then RunInUi(Sub() FrmLaunchRight.LabLog.Text += $"{vbCrLf}[{Date.Now:HH':'mm':'ss'.'fff}] {Text}")
|
||||
If ModeDebug Then
|
||||
RunInUi(
|
||||
Sub()
|
||||
FrmLaunchRight.LabLog.AppendText($"[{Date.Now:HH':'mm':'ss'.'fff}] {Text}{vbCrLf}")
|
||||
End Sub)
|
||||
End If
|
||||
Logger.Log(Text, Level)
|
||||
End Sub
|
||||
|
||||
@@ -196,25 +205,6 @@ NextInner:
|
||||
End Try
|
||||
End Sub
|
||||
|
||||
''' <summary>
|
||||
''' 取消正在进行的游戏启动。
|
||||
''' </summary>
|
||||
Public Sub McLaunchCancel()
|
||||
If McLaunchLoaderReal IsNot Nothing Then
|
||||
McLaunchLoaderReal.Cancel()
|
||||
McLaunchLog("已取消启动")
|
||||
Try
|
||||
If McLaunchWatcher IsNot Nothing Then
|
||||
McLaunchWatcher.Kill()
|
||||
ElseIf McLaunchProcess IsNot Nothing Then
|
||||
If Not McLaunchProcess.HasExited Then McLaunchProcess.Kill()
|
||||
End If
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex, "取消启动结束进程失败", LogBehavior.Toast)
|
||||
End Try
|
||||
End If
|
||||
End Sub
|
||||
|
||||
#End Region
|
||||
|
||||
#Region "内存优化"
|
||||
@@ -249,7 +239,7 @@ NextInner:
|
||||
'检查版本
|
||||
If McInstanceSelected Is Nothing Then Throw New Exception("未选择 Minecraft 版本!")
|
||||
McInstanceSelected.Load()
|
||||
If McInstanceSelected.State = McInstanceState.Error Then Throw New Exception("Minecraft 存在问题:" & McInstanceSelected.Info)
|
||||
If McInstanceSelected.State = McInstance.McInstanceState.Error Then Throw New Exception("Minecraft 存在问题:" & McInstanceSelected.Info)
|
||||
'检查输入信息
|
||||
Dim CheckResult As String = ""
|
||||
RunInUiWait(Sub() CheckResult = McLoginAble(McLoginInput()))
|
||||
@@ -557,7 +547,7 @@ NextInner:
|
||||
'检查是否已经登录完成
|
||||
Dim ExpiresAt = Settings.Get(Of Long)("CacheMsV2Expires")
|
||||
If Not Data.IsForceRestarting AndAlso '不要求强行重启
|
||||
ExpiresAt > 0 AndAlso ExpiresAt > GetUnixTimestampUtc() AndAlso 'AccessToken 尚未过期
|
||||
ExpiresAt > 0 AndAlso ExpiresAt > ToUnixTimestampUtc(Date.UtcNow) AndAlso 'AccessToken 尚未过期
|
||||
Input.UserName = Settings.Get(Of String)("CacheMsV2Name") Then
|
||||
Data.Output = New McLoginResult With {
|
||||
.Name = Input.UserName, .Type = "Microsoft",
|
||||
@@ -1052,7 +1042,7 @@ Retry:
|
||||
Dim ResultJson As JObject = Result.DeserializeJson()
|
||||
Return (
|
||||
ResultJson("access_token").ToString,
|
||||
ResultJson("expires_in").ToObject(Of Integer) + GetUnixTimestampUtc() - 1200) '提前 20 分钟视作过期
|
||||
ResultJson("expires_in").ToObject(Of Integer) + GetUnixTimestampUtc() - 3600) '提前 1 小时视作过期
|
||||
End Function
|
||||
'微软登录步骤 5:验证微软账号是否持有 MC,这也会刷新 XGP
|
||||
Private Sub MsLoginStep5(AccessToken As String)
|
||||
@@ -1382,16 +1372,11 @@ NextInstance:
|
||||
'Log4j 漏洞防御参数
|
||||
Args.Add("-Dlog4j2.formatMsgNoLookups=true")
|
||||
|
||||
'编码(#4700、#5892、#5909、#6934、#8950)
|
||||
Dim EncodingName As String
|
||||
Select Case McLaunchJavaSelected.Version.Major
|
||||
Case Is >= 21 'Java 21+ 会固定使用 UTF-8
|
||||
EncodingName = "UTF-8"
|
||||
Case Is >= 18 'Java 18~20 时,启动 MC 时会添加 COMPAT 参数,因此 Java 会回退到 native.encoding
|
||||
EncodingName = McLaunchJavaSelected.NativeEncodingName
|
||||
Case Else 'Java 17- 时,直接使用 file.encoding
|
||||
EncodingName = McLaunchJavaSelected.FileEncodingName
|
||||
End Select
|
||||
'编码(#4700、#5892、#5909、#6934、#8950、#9241)
|
||||
Dim UseCompatEncoding = McLaunchJavaSelected.Version.Major >= 18
|
||||
Dim EncodingName = If(UseCompatEncoding,
|
||||
McLaunchJavaSelected.NativeEncodingName, 'Java 18+ 会添加 COMPAT,因此 Java 会回退到 native.encoding
|
||||
McLaunchJavaSelected.FileEncodingName) 'Java 17- 直接使用 file.encoding
|
||||
Try
|
||||
McLaunchEncoding = Encoding.GetEncoding(If(EncodingName.Equals("GBK", StringComparison.OrdinalIgnoreCase), "GB18030", EncodingName))
|
||||
Catch ex As Exception
|
||||
@@ -1405,7 +1390,7 @@ NextInstance:
|
||||
Dim StderrArgName = If(McLaunchJavaSelected.Version.Major < 19, "sun.stderr.encoding", "stderr.encoding")
|
||||
If Not Args.Any(Function(a) a.StartsWithF($"-D{StdoutArgName}=")) Then Args.Add($"-D{StdoutArgName}={LaunchEncodingName}")
|
||||
If Not Args.Any(Function(a) a.StartsWithF($"-D{StderrArgName}=")) Then Args.Add($"-D{StderrArgName}={LaunchEncodingName}")
|
||||
If McLaunchJavaSelected.Version.Major >= 18 AndAlso McLaunchJavaSelected.Version.Major < 21 Then Args.Add("-Dfile.encoding=COMPAT") '使用 COMPAT 防止部分 Mod 配置文件不兼容 UTF-8
|
||||
If UseCompatEncoding AndAlso Not Args.Any(Function(a) a.StartsWithF("-Dfile.encoding=")) Then Args.Add("-Dfile.encoding=COMPAT") '防止老版本 MC 与部分 Mod 不兼容 UTF-8
|
||||
|
||||
'为 JLW 添加 -jar,它必须放在最后
|
||||
If UseJLW Then
|
||||
@@ -1465,7 +1450,8 @@ NextInstance:
|
||||
Arg &= " " & CustomArg
|
||||
|
||||
'把 OptiFineForgeTweaker 放在参数的末尾
|
||||
If (McInstanceSelected.Version.HasForge OrElse McInstanceSelected.Version.HasLiteLoader) AndAlso McInstanceSelected.Version.HasOptiFine Then
|
||||
If (McInstanceSelected.Version.ModLoaders.HasFlagF(ModLoaders.Forge) OrElse McInstanceSelected.Version.ModLoaders.HasFlagF(ModLoaders.LiteLoader)) AndAlso
|
||||
McInstanceSelected.Version.HasOptiFine AndAlso Not McInstanceSelected.Version.OptiFineAsMod Then
|
||||
If Arg.Contains("--tweakClass optifine.OptiFineForgeTweaker") Then
|
||||
McLaunchLog("发现正确的 OptiFineForge TweakClass,目前的游戏参数:" & Arg)
|
||||
Arg = Arg.Replace(" --tweakClass optifine.OptiFineForgeTweaker", "") & " --tweakClass optifine.OptiFineForgeTweaker"
|
||||
@@ -1520,10 +1506,10 @@ NextInstance:
|
||||
Private Iterator Function McLaunchArgumentsReplace(Arguments As List(Of String)) As IEnumerable(Of (Key As String, Value As String))
|
||||
'基础参数
|
||||
Yield ("${classpath_separator}", ";")
|
||||
Yield ("${natives_directory}", GetNativesFolder().TrimEnd("\"c))
|
||||
Yield ("${natives_directory}", PathUtils.RemoveSlashSuffix(GetNativesFolder()))
|
||||
Yield ("${library_directory}", PathUtils.ToShortPath(McFolderSelected & "libraries"))
|
||||
Yield ("${libraries_directory}", PathUtils.ToShortPath(McFolderSelected & "libraries"))
|
||||
Yield ("${pure_directory}", PathPure.Value.TrimEnd("\"c)) '由 PCL 添加,这会允许在分割参数并去重后再替换路径,防止路径中的特殊字符影响参数分割和去重
|
||||
Yield ("${pure_directory}", PathUtils.RemoveSlashSuffix(PathPure.Value)) '由 PCL 添加,这会允许在分割参数并去重后再替换路径,防止路径中的特殊字符影响参数分割和去重
|
||||
Yield ("${launcher_name}", "PCL")
|
||||
Yield ("${launcher_version}", VersionCode)
|
||||
Yield ("${version_name}", McInstanceSelected.Name)
|
||||
@@ -1568,9 +1554,8 @@ NextInstance:
|
||||
Case Else
|
||||
TargetSize = New Size(854, 480)
|
||||
End Select
|
||||
If McInstanceSelected.Version.Vanilla.Major <= 12 AndAlso
|
||||
McLaunchJavaSelected.Version >= New Version(8, 0, 200) AndAlso McLaunchJavaSelected.Version <= New Version(8, 0, 321) AndAlso
|
||||
Not McInstanceSelected.Version.HasOptiFine AndAlso Not McInstanceSelected.Version.HasForge Then '修复 1.12.2- 下 JRE 8u200~321 下窗口大小为设置大小的 DPI% 倍(#3463)
|
||||
If McInstanceSelected.Version.Vanilla.Major <= 12 AndAlso McLaunchJavaSelected.Version >= New Version(8, 0, 200) AndAlso McLaunchJavaSelected.Version <= New Version(8, 0, 321) AndAlso
|
||||
Not McInstanceSelected.Version.HasOptiFine AndAlso Not McInstanceSelected.Version.ModLoaders.HasFlagF(ModLoaders.Forge) Then '修复 1.12.2- 下 JRE 8u200~321 下窗口大小为设置大小的 DPI% 倍(#3463)
|
||||
McLaunchLog($"已应用窗口大小过大修复(Java 版本:{McLaunchJavaSelected.Version})")
|
||||
TargetSize.Width /= DPI / 96
|
||||
TargetSize.Height /= DPI / 96
|
||||
@@ -1694,7 +1679,7 @@ NextInstance:
|
||||
End Try
|
||||
For Each Entry In Zip.Entries
|
||||
Dim FileName As String = Entry.FullName
|
||||
If FileName.EndsWithF(".dll", True) Then
|
||||
If PathUtils.GetExtension(FileName) = "dll" Then
|
||||
'实际解压文件的步骤
|
||||
Dim FilePath As String = Target & FileName
|
||||
ExistFiles.Add(FilePath)
|
||||
@@ -1738,8 +1723,9 @@ NextInstance:
|
||||
''' <summary>
|
||||
''' 获取 Natives 文件夹路径,以 \ 结尾。
|
||||
''' </summary>
|
||||
Private Function GetNativesFolder() As String
|
||||
Dim Result As String = PathUtils.AddSlashSuffix(PathUtils.ToShortPath(McInstanceSelected.PathVersion)) & McInstanceSelected.Name & "-natives\"
|
||||
Public Function GetNativesFolder(Optional Instance As McInstance = Nothing) As String
|
||||
If Instance Is Nothing Then Instance = McInstanceSelected
|
||||
Dim Result As String = PathUtils.AddSlashSuffix(PathUtils.ToShortPath(Instance.PathVersion)) & Instance.Name & "-natives\"
|
||||
If Not (IsGBKEncoding OrElse Result.IsAsciiOnly()) Then
|
||||
Result = Paths.AppData & ".minecraft\bin\natives\"
|
||||
If Not Result.IsAsciiOnly() Then
|
||||
@@ -1865,7 +1851,7 @@ NextInstance:
|
||||
Dim CurrentLang As String = ReadIni(SetupFileAddress, "lang", "none")
|
||||
Dim RequiredLang As String = If(CurrentLang = "none" OrElse Not DirectoryUtils.Exists(McInstanceSelected.PathIndie & "saves"), '#3844,整合包可能已经自带了 options.txt
|
||||
If(Settings.Get(Of Boolean)("ToolHelpChinese"), "zh_cn", "en_us"), CurrentLang.Lower)
|
||||
If Not McInstanceSelected.Version.Vaild OrElse McInstanceSelected.Version.Vanilla.Major <= 10 Then
|
||||
If Not McInstanceSelected.Version.Valid OrElse McInstanceSelected.Version.Vanilla.Major <= 10 Then
|
||||
'将最后两位改为大写,前面的部分保留
|
||||
RequiredLang = RequiredLang.Substring(0, RequiredLang.Length - 2) & RequiredLang.Substring(RequiredLang.Length - 2).Upper
|
||||
End If
|
||||
@@ -1908,53 +1894,40 @@ NextInstance:
|
||||
If McLoginLoader.Input.Type = McLoginType.Legacy AndAlso Settings.Get(Of Integer)("LaunchSkinType") = 4 AndAlso FileUtils.Exists(Paths.AppDataThenName & "CustomSkin.png") Then
|
||||
Dim MetaFileAddress As String = PathTemp & "pack.mcmeta"
|
||||
Dim PackPicAddress As String = PathTemp & "pack.png"
|
||||
Dim PackFormat As Integer
|
||||
Select Case McInstanceSelected.Version.Vanilla.Major
|
||||
Case 0, 1, 2, 3, 4, 5
|
||||
'更早的版本没有资源包
|
||||
McLaunchLog("Minecraft 版本过老,尚不支持自定义离线皮肤")
|
||||
GoTo IgnoreCustomSkin
|
||||
Case 6, 7, 8
|
||||
PackFormat = 1
|
||||
Case 9, 10
|
||||
PackFormat = 2
|
||||
Case 11, 12
|
||||
PackFormat = 3
|
||||
Case 13, 14
|
||||
PackFormat = 4
|
||||
Case 15
|
||||
PackFormat = 5
|
||||
Case 16
|
||||
PackFormat = 6
|
||||
Case 17
|
||||
PackFormat = 7
|
||||
Case 18
|
||||
If McInstanceSelected.Version.Vanilla.Minor <= 2 Then
|
||||
PackFormat = 8
|
||||
Else
|
||||
PackFormat = 9
|
||||
End If
|
||||
Case 19
|
||||
If McInstanceSelected.Version.Vanilla.Minor <= 3 Then
|
||||
PackFormat = 9
|
||||
Else
|
||||
PackFormat = 12
|
||||
End If
|
||||
Case 20
|
||||
If McInstanceSelected.Version.Vanilla.Minor <= 1 Then
|
||||
PackFormat = 15
|
||||
Else
|
||||
PackFormat = 17
|
||||
End If
|
||||
Case Else '快照版是 9999
|
||||
PackFormat = 17
|
||||
'https://zh.minecraft.wiki/w/数据包#数据包版本
|
||||
End Select
|
||||
McLaunchLog("正在构建自定义皮肤资源包,格式为:" & PackFormat)
|
||||
If McInstanceSelected.Version.Vanilla.Major < 6 Then
|
||||
McLaunchLog("Minecraft 版本过老,尚不支持自定义离线皮肤")
|
||||
GoTo IgnoreCustomSkin
|
||||
End If
|
||||
Dim PackVersionJToken As JToken = McInstanceSelected.JsonVersion?("pack_version")
|
||||
If TypeOf PackVersionJToken Is JObject Then PackVersionJToken = DirectCast(PackVersionJToken, JObject)("resource") '从 1.17 开始,可以从 pack_version.resource 获取资源包版本
|
||||
Dim PackVersion As Integer = Val(PackVersionJToken?.ToString)
|
||||
If PackVersion <= 0 Then '没有对应字段的老版本 MC,或兜底
|
||||
Select Case McInstanceSelected.Version.Vanilla.Major
|
||||
Case 6, 7, 8
|
||||
PackVersion = 1
|
||||
Case 9, 10
|
||||
PackVersion = 2
|
||||
Case 11, 12
|
||||
PackVersion = 3
|
||||
Case 13, 14
|
||||
PackVersion = 4
|
||||
Case 15
|
||||
PackVersion = 5
|
||||
Case 16
|
||||
PackVersion = If(McInstanceSelected.Version.Vanilla.Build <= 1, 5, 6)
|
||||
Case 17
|
||||
PackVersion = 7
|
||||
Case 18
|
||||
PackVersion = 8
|
||||
Case Else '旧版快照可能没有可用的资源包格式声明
|
||||
PackVersion = 17
|
||||
End Select
|
||||
End If
|
||||
McLaunchLog($"正在构建自定义皮肤资源包,版本号 {PackVersion},MC 版本 {McInstanceSelected.Version.Vanilla}")
|
||||
'准备文件
|
||||
Dim Bit As New MyBitmap(PathImage & "Heads/Logo.png")
|
||||
Bit.Save(PackPicAddress)
|
||||
FileUtils.Write(MetaFileAddress, "{""pack"":{""pack_format"":" & PackFormat & ",""description"":""PCL 自定义离线皮肤资源包""}}")
|
||||
FileUtils.Write(MetaFileAddress, "{""pack"":{""pack_format"":" & PackVersion & ",""description"":""PCL 自定义离线皮肤资源包""}}")
|
||||
Dim Skin As New MyBitmap(Paths.AppDataThenName & "CustomSkin.png")
|
||||
If (McInstanceSelected.Version.Vanilla.Major = 6 OrElse McInstanceSelected.Version.Vanilla.Major = 7) AndAlso Skin.Pic.Height = 64 Then
|
||||
McLaunchLog("该 Minecraft 版本不支持双层皮肤,已进行裁剪")
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -74,7 +74,7 @@ Public Module ModModpack
|
||||
Catch ex As Exception
|
||||
If ex.GetDisplay(True).Contains("Error.WinIOError") Then
|
||||
Throw New Exception("打开整合包文件失败", ex)
|
||||
ElseIf File.EndsWithF(".rar", True) Then
|
||||
ElseIf PathUtils.GetExtension(File) = "rar" Then
|
||||
Throw New Exception("PCL 无法处理 rar 格式的压缩包,请在解压后重新压缩为 zip 格式再试", ex)
|
||||
Else
|
||||
Throw New Exception("打开整合包文件失败,文件可能损坏或为不支持的压缩包格式", ex)
|
||||
@@ -119,8 +119,8 @@ Public Module ModModpack
|
||||
''' 对路径末尾是否为 \ 没有要求。
|
||||
''' </summary>
|
||||
Private Sub CopyOverrideDirectory(OverridesFolder As String, VersionFolder As String, Loader As LoaderBase)
|
||||
If Not OverridesFolder.EndsWithF("\") Then OverridesFolder += "\"
|
||||
If Not VersionFolder.EndsWithF("\") Then VersionFolder += "\"
|
||||
OverridesFolder = PathUtils.AddSlashSuffix(OverridesFolder)
|
||||
VersionFolder = PathUtils.AddSlashSuffix(VersionFolder)
|
||||
'复制文件
|
||||
If DirectoryUtils.Exists(OverridesFolder) Then
|
||||
Logger.Info($"处理整合包覆写文件夹:{OverridesFolder} → {VersionFolder}")
|
||||
@@ -174,25 +174,25 @@ Public Module ModModpack
|
||||
If InstanceName = "" Then InstanceName = MyMsgBoxInput("输入版本名称", "", "", New Collection(Of Validate) From {Validate})
|
||||
If String.IsNullOrEmpty(InstanceName) Then Throw New OperationCanceledException
|
||||
End If
|
||||
Dim VersionFolder As String = PathUtils.AddSlashSuffix(Path.Combine(McFolderSelected, "versions", InstanceName) & "\")
|
||||
|
||||
'获取 Mod API 版本信息
|
||||
Dim TargetVersion As New McVersion
|
||||
TargetVersion.VanillaName = Json("minecraft")("version").ToString
|
||||
Dim TargetVersion As New McVersion(Json("minecraft")("version").ToString)
|
||||
For Each Entry In If(Json("minecraft")("modLoaders"), {})
|
||||
Dim Id As String = If(Entry("id"), "").ToString.Lower
|
||||
If Id.StartsWithF("forge-") Then
|
||||
'Forge 指定
|
||||
If Id.Contains("recommended") Then Throw New Exception("该整合包版本过老,已不支持进行安装!")
|
||||
Logger.Info($"整合包 Forge 版本:{Id}")
|
||||
TargetVersion.Forge = Id.Replace("forge-", "")
|
||||
TargetVersion.ModLoaderVersions(ModLoaders.Forge) = Id.Replace("forge-", "")
|
||||
ElseIf Id.StartsWithF("neoforge-") Then
|
||||
'NeoForge 指定
|
||||
Logger.Info($"整合包 NeoForge 版本:{Id}")
|
||||
TargetVersion.NeoForge = Id.Replace("neoforge-", "")
|
||||
TargetVersion.ModLoaderVersions(ModLoaders.NeoForge) = Id.Replace("neoforge-", "")
|
||||
ElseIf Id.StartsWithF("fabric-") Then
|
||||
'Fabric 指定
|
||||
Logger.Info($"整合包 Fabric 版本:{Id}")
|
||||
TargetVersion.Fabric = Id.Replace("fabric-", "")
|
||||
TargetVersion.ModLoaderVersions(ModLoaders.Fabric) = Id.Replace("fabric-", "")
|
||||
Else
|
||||
NotifyIncompatibleLoader(Id)
|
||||
End If
|
||||
@@ -202,12 +202,12 @@ Public Module ModModpack
|
||||
Dim InstallLoaders As New List(Of LoaderBase)
|
||||
Dim OverrideHome As String = If(Json("overrides"), "")
|
||||
If OverrideHome <> "" Then
|
||||
Dim OverridesFolder As String = InstallTemp & ArchiveBaseFolder & If(OverrideHome = "." OrElse OverrideHome = "./", "", OverrideHome) '#5613
|
||||
If Not PathUtils.IsParentOf(InstallTemp, OverridesFolder) Then Throw New Exception("整合包的 overrides 路径超出了解压目录,请向整合包作者反馈此问题!")
|
||||
InstallLoaders.Add(New LoaderTask(Of String, Integer)("解压整合包文件",
|
||||
Sub(Task As LoaderTask(Of String, Integer))
|
||||
ExtractModpackFiles(InstallTemp, FileAddress, Task.CreateCancellationToken(), Task.CreateSyncProgressProvider(ToPercentage:=0.6))
|
||||
CopyOverrideDirectory(
|
||||
InstallTemp & ArchiveBaseFolder & If(OverrideHome = "." OrElse OverrideHome = "./", "", OverrideHome), '#5613
|
||||
$"{McFolderSelected}versions\{InstanceName}", Task)
|
||||
CopyOverrideDirectory(OverridesFolder, VersionFolder, Task)
|
||||
End Sub) With {
|
||||
.ProgressWeight = FileUtils.GetInfo(FileAddress).Length / 1024 / 1024 / 6, .Block = False}) '每 6M 需要 1s
|
||||
End If
|
||||
@@ -293,7 +293,7 @@ Public Module ModModpack
|
||||
Dim File = ResourceVersion.FromPlatformJson(ModJson, Type)
|
||||
If Not File.DownloadAvailable Then Continue For
|
||||
'实际的添加
|
||||
FileList.Add(Id, File.ToNetFile($"{McFolderSelected}versions\{InstanceName}\{TargetFolder}\",
|
||||
FileList.Add(Id, File.ToNetFile(PathUtils.AddSlashSuffix(Path.Combine(VersionFolder, TargetFolder)),
|
||||
ResourceVersion.DownloadReason.ModPack, TargetVersion.VanillaName, TargetVersion.ModLoaders))
|
||||
Task.Progress += 1 / (1 + ModList.Count)
|
||||
Next
|
||||
@@ -307,15 +307,9 @@ Public Module ModModpack
|
||||
End If
|
||||
|
||||
'构造加载器
|
||||
Dim Request As New McInstallRequest With {
|
||||
.NewInstanceName = InstanceName,
|
||||
.VersionFolder = $"{McFolderSelected}versions\{InstanceName}\",
|
||||
.MinecraftName = TargetVersion.VanillaName,
|
||||
.ForgeVersion = TargetVersion.Forge,
|
||||
.NeoForgeVersion = TargetVersion.NeoForge,
|
||||
.FabricVersion = TargetVersion.Fabric
|
||||
}
|
||||
Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request)
|
||||
Dim Target As New McComponents(TargetVersion.VanillaName, TargetVersion.ModLoaderVersions)
|
||||
Dim MergeLoaders = McInstallLoadersGet(New McInstallRequest With {
|
||||
.NewInstanceName = InstanceName, .InstanceFolder = VersionFolder, .Components = Target})
|
||||
'构造总加载器
|
||||
Dim Loaders As New List(Of LoaderBase)
|
||||
Loaders.Add(New LoaderCombo(Of String)("整合包安装", InstallLoaders) With {.Show = False, .Block = False, .ProgressWeight = InstallLoaders.Sum(Function(l) l.ProgressWeight)})
|
||||
@@ -323,7 +317,6 @@ Public Module ModModpack
|
||||
Loaders.Add(New LoaderTask(Of String, String)("最终整理文件",
|
||||
Sub(Task As LoaderTask(Of String, String))
|
||||
'设置图标
|
||||
Dim VersionFolder As String = $"{McFolderSelected}versions\{InstanceName}\"
|
||||
If Logo IsNot Nothing AndAlso FileUtils.Exists(Logo) Then
|
||||
FileUtils.Copy(Logo, VersionFolder & "PCL\Logo.png")
|
||||
WriteIni(VersionFolder & "PCL\Setup.ini", "Logo", "PCL\Logo.png")
|
||||
@@ -337,10 +330,10 @@ Public Module ModModpack
|
||||
FileUtils.Delete(MapFile)
|
||||
Next
|
||||
'删除原始整合包文件
|
||||
For Each Target As String In {VersionFolder & "原始整合包.zip", VersionFolder & "原始整合包.mrpack"}
|
||||
If FileUtils.Exists(Target) Then
|
||||
Logger.Info($"删除原始整合包文件:{Target}")
|
||||
FileUtils.Delete(Target)
|
||||
For Each FileToDelete As String In {VersionFolder & "原始整合包.zip", VersionFolder & "原始整合包.mrpack"}
|
||||
If FileUtils.Exists(FileToDelete) Then
|
||||
Logger.Info($"删除原始整合包文件:{FileToDelete}")
|
||||
FileUtils.Delete(FileToDelete)
|
||||
End If
|
||||
Next
|
||||
If FileUtils.Exists(FileAddress) AndAlso PathUtils.GetFileNameWithoutExtension(FileAddress) = "modpack" Then
|
||||
@@ -358,7 +351,7 @@ Public Module ModModpack
|
||||
|
||||
'启动
|
||||
Dim Loader As New LoaderCombo(Of String)(LoaderName, Loaders) With {.OnStateChanged = AddressOf McInstallState}
|
||||
Loader.Start(Request.VersionFolder)
|
||||
Loader.Start(VersionFolder)
|
||||
LoaderTaskbarAdd(Loader)
|
||||
FrmMain.BtnExtraDownload.ShowRefresh()
|
||||
Return Loader
|
||||
@@ -376,20 +369,21 @@ Public Module ModModpack
|
||||
End Try
|
||||
If Json("dependencies") Is Nothing OrElse Json("dependencies")("minecraft") Is Nothing Then Throw New Exception("Modrinth 整合包未提供 Minecraft 版本信息")
|
||||
'获取 Mod API 版本信息
|
||||
Dim TargetVersion As New McVersion
|
||||
'TODO: 改为使用类似 InstallPackMMC 中,一个版本名一个字典的方式来存储它,不要用 Unknown
|
||||
Dim TargetVersion As New McVersion("Unknown")
|
||||
For Each Entry As JProperty In If(Json("dependencies"), {})
|
||||
Select Case Entry.Name.Lower
|
||||
Case "minecraft"
|
||||
TargetVersion.VanillaName = Entry.Value.ToString
|
||||
Case "forge" 'eg. 14.23.5.2859 / 1.19-41.1.0
|
||||
TargetVersion.Forge = Entry.Value.ToString
|
||||
Logger.Info($"整合包 Forge 版本:{TargetVersion.Forge}")
|
||||
TargetVersion.ModLoaderVersions(ModLoaders.Forge) = Entry.Value.ToString
|
||||
Logger.Info($"整合包 Forge 版本:{TargetVersion.ModLoaderVersions(ModLoaders.Forge)}")
|
||||
Case "neoforge", "neo-forge" 'eg. 20.6.98-beta
|
||||
TargetVersion.NeoForge = Entry.Value.ToString
|
||||
Logger.Info($"整合包 NeoForge 版本:{TargetVersion.NeoForge}")
|
||||
TargetVersion.ModLoaderVersions(ModLoaders.NeoForge) = Entry.Value.ToString
|
||||
Logger.Info($"整合包 NeoForge 版本:{TargetVersion.ModLoaderVersions(ModLoaders.NeoForge)}")
|
||||
Case "fabric-loader" 'eg. 0.14.14
|
||||
TargetVersion.Fabric = Entry.Value.ToString
|
||||
Logger.Info($"整合包 Fabric 版本:{TargetVersion.Fabric}")
|
||||
TargetVersion.ModLoaderVersions(ModLoaders.Fabric) = Entry.Value.ToString
|
||||
Logger.Info($"整合包 Fabric 版本:{TargetVersion.ModLoaderVersions(ModLoaders.Fabric)}")
|
||||
Case Else
|
||||
NotifyIncompatibleLoader(Entry.Name)
|
||||
End Select
|
||||
@@ -402,18 +396,15 @@ Public Module ModModpack
|
||||
If InstanceName = "" Then InstanceName = MyMsgBoxInput("输入版本名称", "", "", New Collection(Of Validate) From {Validate})
|
||||
If String.IsNullOrEmpty(InstanceName) Then Throw New OperationCanceledException
|
||||
End If
|
||||
Dim VersionFolder As String = Path.Combine(McFolderSelected, "versions", InstanceName) & "\"
|
||||
'解压
|
||||
Dim InstallTemp As String = RequestTaskTempFolder()
|
||||
Dim InstallLoaders As New List(Of LoaderBase)
|
||||
InstallLoaders.Add(New LoaderTask(Of String, Integer)("解压整合包文件",
|
||||
Sub(Task As LoaderTask(Of String, Integer))
|
||||
ExtractModpackFiles(InstallTemp, FileAddress, Task.CreateCancellationToken(), Task.CreateSyncProgressProvider(ToPercentage:=0.5))
|
||||
CopyOverrideDirectory(
|
||||
InstallTemp & ArchiveBaseFolder & "overrides",
|
||||
McFolderSelected & "versions\" & InstanceName, Task)
|
||||
CopyOverrideDirectory(
|
||||
InstallTemp & ArchiveBaseFolder & "client-overrides",
|
||||
McFolderSelected & "versions\" & InstanceName, Task)
|
||||
CopyOverrideDirectory(InstallTemp & ArchiveBaseFolder & "overrides", VersionFolder, Task)
|
||||
CopyOverrideDirectory(InstallTemp & ArchiveBaseFolder & "client-overrides", VersionFolder, Task)
|
||||
End Sub) With {.ProgressWeight = FileUtils.GetInfo(FileAddress).Length / 1024 / 1024 / 6, .Block = False}) '每 6M 需要 1s
|
||||
'获取下载文件列表
|
||||
Dim FileList As New List(Of NetFile)
|
||||
@@ -436,8 +427,8 @@ Public Module ModModpack
|
||||
Urls = ResourceVersion.ParseModrinthTrackArguments(Urls,
|
||||
ResourceVersion.DownloadReason.ModPack, TargetVersion.VanillaName, TargetVersion.ModLoaders).ToList 'Modrinth 来源追踪信息
|
||||
Urls = Urls.Distinct.ToList()
|
||||
Dim TargetPath As String = Path.Combine(McFolderSelected, "versions", InstanceName, File("path").ToString().TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar))
|
||||
If Not PathUtils.IsParentOf($"{McFolderSelected}versions\{InstanceName}\", TargetPath) Then
|
||||
Dim TargetPath As String = Path.Combine(VersionFolder, File("path").ToString().TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar))
|
||||
If Not PathUtils.IsParentOf(VersionFolder, TargetPath) Then
|
||||
MyMsgBox($"整合包的文件路径超出了版本文件夹,请向整合包作者反馈此问题!{vbCrLf}目标:{Path.GetFullPath(TargetPath)}{vbCrLf}错误的文件:{TargetPath}", "文件路径校验失败", IsWarn:=True)
|
||||
Throw New OperationCanceledException
|
||||
End If
|
||||
@@ -449,15 +440,10 @@ Public Module ModModpack
|
||||
End If
|
||||
|
||||
'构造加载器
|
||||
Dim Request As New McInstallRequest With {
|
||||
.NewInstanceName = InstanceName,
|
||||
.VersionFolder = $"{McFolderSelected}versions\{InstanceName}\",
|
||||
.MinecraftName = TargetVersion.VanillaName,
|
||||
.ForgeVersion = TargetVersion.Forge,
|
||||
.NeoForgeVersion = TargetVersion.NeoForge,
|
||||
.FabricVersion = TargetVersion.Fabric
|
||||
}
|
||||
Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request)
|
||||
Dim Target As New McComponents(TargetVersion.VanillaName, TargetVersion.ModLoaderVersions)
|
||||
Dim MergeLoaders = McInstallLoadersGet(New McInstallRequest With {
|
||||
.NewInstanceName = InstanceName, .InstanceFolder = VersionFolder,
|
||||
.Components = Target})
|
||||
'构造总加载器
|
||||
Dim Loaders As New List(Of LoaderBase)
|
||||
Loaders.Add(New LoaderCombo(Of String)("整合包安装", InstallLoaders) With {.Show = False, .Block = False, .ProgressWeight = InstallLoaders.Sum(Function(l) l.ProgressWeight)})
|
||||
@@ -465,7 +451,6 @@ Public Module ModModpack
|
||||
Loaders.Add(New LoaderTask(Of String, String)("最终整理文件",
|
||||
Sub(Task As LoaderTask(Of String, String))
|
||||
'设置图标
|
||||
Dim VersionFolder As String = $"{McFolderSelected}versions\{InstanceName}\"
|
||||
If Logo IsNot Nothing AndAlso FileUtils.Exists(Logo) Then
|
||||
FileUtils.Copy(Logo, VersionFolder & "PCL\Logo.png")
|
||||
WriteIni(VersionFolder & "PCL\Setup.ini", "Logo", "PCL\Logo.png")
|
||||
@@ -473,10 +458,10 @@ Public Module ModModpack
|
||||
Logger.Info($"已设置整合包 Logo:{Logo}")
|
||||
End If
|
||||
'删除原始整合包文件
|
||||
For Each Target As String In {VersionFolder & "原始整合包.zip", VersionFolder & "原始整合包.mrpack"}
|
||||
If FileUtils.Exists(Target) Then
|
||||
Logger.Info($"删除原始整合包文件:{Target}")
|
||||
FileUtils.Delete(Target)
|
||||
For Each FileToDelete As String In {VersionFolder & "原始整合包.zip", VersionFolder & "原始整合包.mrpack"}
|
||||
If FileUtils.Exists(FileToDelete) Then
|
||||
Logger.Info($"删除原始整合包文件:{FileToDelete}")
|
||||
FileUtils.Delete(FileToDelete)
|
||||
End If
|
||||
Next
|
||||
If FileUtils.Exists(FileAddress) AndAlso PathUtils.GetFileNameWithoutExtension(FileAddress) = "modpack" Then
|
||||
@@ -494,7 +479,7 @@ Public Module ModModpack
|
||||
|
||||
'启动
|
||||
Dim Loader As New LoaderCombo(Of String)(LoaderName, Loaders) With {.OnStateChanged = AddressOf McInstallState}
|
||||
Loader.Start(Request.VersionFolder)
|
||||
Loader.Start(VersionFolder)
|
||||
LoaderTaskbarAdd(Loader)
|
||||
FrmMain.BtnExtraDownload.ShowRefresh()
|
||||
Return Loader
|
||||
@@ -515,24 +500,21 @@ Public Module ModModpack
|
||||
If Validate.Validate(InstanceName) <> "" Then InstanceName = ""
|
||||
If InstanceName = "" Then InstanceName = MyMsgBoxInput("输入版本名称", "", "", New Collection(Of Validate) From {Validate})
|
||||
If String.IsNullOrEmpty(InstanceName) Then Throw New OperationCanceledException
|
||||
Dim VersionFolder As String = Path.Combine(McFolderSelected, "versions", InstanceName) & "\"
|
||||
'解压
|
||||
Dim InstallTemp As String = RequestTaskTempFolder()
|
||||
Dim InstallLoaders As New List(Of LoaderBase)
|
||||
InstallLoaders.Add(New LoaderTask(Of String, Integer)("解压整合包文件",
|
||||
Sub(Task As LoaderTask(Of String, Integer))
|
||||
ExtractModpackFiles(InstallTemp, FileAddress, Task.CreateCancellationToken(), Task.CreateSyncProgressProvider(ToPercentage:=0.6))
|
||||
CopyOverrideDirectory(
|
||||
InstallTemp & ArchiveBaseFolder & "minecraft",
|
||||
McFolderSelected & "versions\" & InstanceName, Task)
|
||||
CopyOverrideDirectory(InstallTemp & ArchiveBaseFolder & "minecraft", VersionFolder, Task)
|
||||
End Sub) With {.ProgressWeight = FileUtils.GetInfo(FileAddress).Length / 1024 / 1024 / 6, .Block = False}) '每 6M 需要 1s
|
||||
'构造游戏本体安装加载器
|
||||
If Json("gameVersion") Is Nothing Then Throw New Exception("该 HMCL 整合包未提供游戏版本信息,无法安装!")
|
||||
Dim Request As New McInstallRequest With {
|
||||
.NewInstanceName = InstanceName,
|
||||
.VersionFolder = $"{McFolderSelected}versions\{InstanceName}\",
|
||||
.MinecraftName = Json("gameVersion").ToString
|
||||
}
|
||||
Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request)
|
||||
Dim Target As New McComponents(Json("gameVersion").ToString, New Dictionary(Of ModLoaders, String))
|
||||
Dim MergeLoaders = McInstallLoadersGet(New McInstallRequest With {
|
||||
.NewInstanceName = InstanceName, .InstanceFolder = VersionFolder,
|
||||
.Components = Target})
|
||||
'构造总加载器
|
||||
Dim Loaders As New List(Of LoaderBase) From {
|
||||
New LoaderCombo(Of String)("整合包安装", InstallLoaders) With {.Show = False, .Block = False, .ProgressWeight = InstallLoaders.Sum(Function(l) l.ProgressWeight)},
|
||||
@@ -546,7 +528,7 @@ Public Module ModModpack
|
||||
End If
|
||||
'启动
|
||||
Dim Loader As New LoaderCombo(Of String)(LoaderName, Loaders) With {.OnStateChanged = AddressOf McInstallState}
|
||||
Loader.Start(Request.VersionFolder)
|
||||
Loader.Start(VersionFolder)
|
||||
LoaderTaskbarAdd(Loader)
|
||||
FrmMain.BtnExtraDownload.ShowRefresh()
|
||||
Return Loader
|
||||
@@ -568,16 +550,22 @@ Public Module ModModpack
|
||||
If Validate.Validate(InstanceName) <> "" Then InstanceName = ""
|
||||
If InstanceName = "" Then InstanceName = MyMsgBoxInput("输入版本名称", "", "", New Collection(Of Validate) From {Validate})
|
||||
If String.IsNullOrEmpty(InstanceName) Then Throw New OperationCanceledException
|
||||
Dim VersionFolder As String = Path.Combine(McFolderSelected, "versions", InstanceName) & "\"
|
||||
'解压
|
||||
Dim InstallTemp As String = RequestTaskTempFolder()
|
||||
Dim SetupFile As String = $"{McFolderSelected}versions\{InstanceName}\PCL\Setup.ini"
|
||||
Dim SetupFile As String = VersionFolder & "PCL\Setup.ini"
|
||||
Dim InstallLoaders As New List(Of LoaderBase)
|
||||
InstallLoaders.Add(New LoaderTask(Of String, Integer)("解压整合包文件",
|
||||
Sub(Task As LoaderTask(Of String, Integer))
|
||||
ExtractModpackFiles(InstallTemp, FileAddress, Task.CreateCancellationToken(), Task.CreateSyncProgressProvider(ToPercentage:=0.55))
|
||||
CopyOverrideDirectory(
|
||||
InstallTemp & ArchiveBaseFolder & ".minecraft",
|
||||
McFolderSelected & "versions\" & InstanceName, Task)
|
||||
'Prism 优先使用 minecraft/ 而非 .minecraft/(#9272)
|
||||
Dim MmcGameRoot As String
|
||||
If DirectoryUtils.Exists(InstallTemp & ArchiveBaseFolder & ".minecraft") AndAlso Not DirectoryUtils.Exists(InstallTemp & ArchiveBaseFolder & "minecraft") Then
|
||||
MmcGameRoot = InstallTemp & ArchiveBaseFolder & ".minecraft"
|
||||
Else
|
||||
MmcGameRoot = InstallTemp & ArchiveBaseFolder & "minecraft"
|
||||
End If
|
||||
CopyOverrideDirectory(MmcGameRoot, VersionFolder, Task)
|
||||
'读取 MMC 设置文件(#2655)
|
||||
Try
|
||||
Dim MmcSetupFile As String = InstallTemp & ArchiveBaseFolder & "instance.cfg"
|
||||
@@ -611,7 +599,7 @@ Public Module ModModpack
|
||||
If Logo <> "" AndAlso FileUtils.Exists($"{InstallTemp}{ArchiveBaseFolder}{Logo}.png") Then
|
||||
WriteIni(SetupFile, "LogoCustom", True)
|
||||
WriteIni(SetupFile, "Logo", "PCL\Logo.png")
|
||||
FileUtils.Copy($"{InstallTemp}{ArchiveBaseFolder}{Logo}.png", $"{McFolderSelected}versions\{InstanceName}\PCL\Logo.png")
|
||||
FileUtils.Copy($"{InstallTemp}{ArchiveBaseFolder}{Logo}.png", VersionFolder & "PCL\Logo.png")
|
||||
Logger.Info($"迁移 MultiMC 版本独立设置:版本图标({Logo}.png)")
|
||||
End If
|
||||
'JVM 参数
|
||||
@@ -633,19 +621,20 @@ Public Module ModModpack
|
||||
End Sub) With {.ProgressWeight = FileUtils.GetInfo(FileAddress).Length / 1024 / 1024 / 6, .Block = False}) '每 6M 需要 1s
|
||||
'构造版本安装请求
|
||||
If PackJson("components") Is Nothing Then Throw New Exception("该 MMC 整合包未提供游戏版本信息,无法安装!")
|
||||
Dim Request As New McInstallRequest With {.NewInstanceName = InstanceName, .VersionFolder = $"{McFolderSelected}versions\{InstanceName}\"}
|
||||
Dim MinecraftVersion As String = Nothing
|
||||
Dim ModLoaderVersions As New Dictionary(Of ModLoaders, String)
|
||||
For Each Component As JObject In PackJson("components")
|
||||
If Not Component.ContainsKey("uid") Then Continue For
|
||||
Dim UID As String = Component("uid").ToString
|
||||
Select Case UID
|
||||
Case "net.minecraft"
|
||||
Request.MinecraftName = Component("version")
|
||||
MinecraftVersion = Component("version")
|
||||
Case "net.minecraftforge"
|
||||
Request.ForgeVersion = Component("version")
|
||||
ModLoaderVersions(ModLoaders.Forge) = Component("version")
|
||||
Case "net.neoforged"
|
||||
Request.NeoForgeVersion = Component("version")
|
||||
ModLoaderVersions(ModLoaders.NeoForge) = Component("version")
|
||||
Case "net.fabricmc.fabric-loader"
|
||||
Request.FabricVersion = Component("version")
|
||||
ModLoaderVersions(ModLoaders.Fabric) = Component("version")
|
||||
Case Else
|
||||
If UID.StartsWithF("org.lwjgl") Then '#8210
|
||||
Logger.Info($"已跳过 LWJGL 项:{UID}")
|
||||
@@ -655,7 +644,10 @@ Public Module ModModpack
|
||||
End Select
|
||||
Next
|
||||
'构造加载器
|
||||
Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request)
|
||||
Dim Target As New McComponents(MinecraftVersion, ModLoaderVersions)
|
||||
Dim MergeLoaders = McInstallLoadersGet(New McInstallRequest With {
|
||||
.NewInstanceName = InstanceName, .InstanceFolder = VersionFolder,
|
||||
.Components = Target})
|
||||
'构造总加载器
|
||||
Dim Loaders As New List(Of LoaderBase)
|
||||
Loaders.Add(New LoaderCombo(Of String)("整合包安装", InstallLoaders) With {.Show = False, .Block = False, .ProgressWeight = InstallLoaders.Sum(Function(l) l.ProgressWeight)})
|
||||
@@ -670,7 +662,7 @@ Public Module ModModpack
|
||||
|
||||
'启动
|
||||
Dim Loader As New LoaderCombo(Of String)(LoaderName, Loaders) With {.OnStateChanged = AddressOf McInstallState}
|
||||
Loader.Start(Request.VersionFolder)
|
||||
Loader.Start(VersionFolder)
|
||||
LoaderTaskbarAdd(Loader)
|
||||
FrmMain.BtnExtraDownload.ShowRefresh()
|
||||
Return Loader
|
||||
@@ -695,16 +687,15 @@ Public Module ModModpack
|
||||
If InstanceName = "" Then InstanceName = MyMsgBoxInput("输入版本名称", "", "", New Collection(Of Validate) From {Validate})
|
||||
If String.IsNullOrEmpty(InstanceName) Then Throw New OperationCanceledException
|
||||
End If
|
||||
Dim VersionFolder As String = Path.Combine(McFolderSelected, "versions", InstanceName) & "\"
|
||||
'解压
|
||||
Dim InstallTemp As String = RequestTaskTempFolder()
|
||||
Dim SetupFile As String = $"{McFolderSelected}versions\{InstanceName}\PCL\Setup.ini"
|
||||
Dim SetupFile As String = VersionFolder & "PCL\Setup.ini"
|
||||
Dim InstallLoaders As New List(Of LoaderBase)
|
||||
InstallLoaders.Add(New LoaderTask(Of String, Integer)("解压整合包文件",
|
||||
Sub(Task As LoaderTask(Of String, Integer))
|
||||
ExtractModpackFiles(InstallTemp, FileAddress, Task.CreateCancellationToken(), Task.CreateSyncProgressProvider(ToPercentage:=0.6))
|
||||
CopyOverrideDirectory(
|
||||
InstallTemp & ArchiveBaseFolder & "overrides",
|
||||
McFolderSelected & "versions\" & InstanceName, Task)
|
||||
CopyOverrideDirectory(InstallTemp & ArchiveBaseFolder & "overrides", VersionFolder, Task)
|
||||
'JVM 参数
|
||||
If Json("launchInfo") IsNot Nothing Then
|
||||
Dim LaunchInfo As JObject = Json("launchInfo")
|
||||
@@ -723,16 +714,26 @@ Public Module ModModpack
|
||||
Hint("PCL 不支持安装 Quilt 整合包!", HintType.Red)
|
||||
Throw New OperationCanceledException
|
||||
End If
|
||||
Dim Request As New McInstallRequest With {
|
||||
.NewInstanceName = InstanceName,
|
||||
.VersionFolder = $"{McFolderSelected}versions\{InstanceName}\",
|
||||
.MinecraftName = Addons("game"),
|
||||
.OptiFineVersion = If(Addons.ContainsKey("optifine"), Addons("optifine"), Nothing),
|
||||
.ForgeVersion = If(Addons.ContainsKey("forge"), Addons("forge"), Nothing),
|
||||
.NeoForgeVersion = If(Addons.ContainsKey("neoforge"), Addons("neoforge"), Nothing),
|
||||
.FabricVersion = If(Addons.ContainsKey("fabric"), Addons("fabric"), Nothing)
|
||||
}
|
||||
Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request)
|
||||
Dim ModLoaderVersions As New Dictionary(Of ModLoaders, String)
|
||||
If Addons.ContainsKey("forge") Then ModLoaderVersions(ModLoaders.Forge) = Addons("forge")
|
||||
If Addons.ContainsKey("neoforge") Then ModLoaderVersions(ModLoaders.NeoForge) = Addons("neoforge")
|
||||
If Addons.ContainsKey("fabric") Then ModLoaderVersions(ModLoaders.Fabric) = Addons("fabric")
|
||||
Dim OptiFineEntry As JObject = Nothing
|
||||
If Addons.ContainsKey("optifine") Then
|
||||
Dim MinecraftVersion = Addons("game")
|
||||
If MinecraftVersion.EndsWithF(".0") Then MinecraftVersion = MinecraftVersion.Substring(0, MinecraftVersion.Length - 2)
|
||||
Dim OptiFineFileSuffix = "_HD_" & Addons("optifine").AfterLast("HD_") & ".jar"
|
||||
'从镜像源拉取 OptiFine 列表
|
||||
If DlOptiFineListBmclapiLoader.State <> LoadState.Finished Then DlOptiFineListBmclapiLoader.WaitForExit()
|
||||
Dim Entry = DlOptiFineListBmclapiLoader.Output.Value.FirstOrDefault(
|
||||
Function(v) v.Inherit = MinecraftVersion AndAlso v.FileName.EndsWithF(OptiFineFileSuffix))
|
||||
If Entry Is Nothing Then Throw New Exception($"OptiFine 列表中没有整合包所需的 OptiFine {Addons("optifine")}(Minecraft {Addons("game")})")
|
||||
OptiFineEntry = JObject.FromObject(Entry)
|
||||
End If
|
||||
Dim Target As New McComponents(Addons("game"), ModLoaderVersions, OptiFineEntry)
|
||||
Dim MergeLoaders = McInstallLoadersGet(New McInstallRequest With {
|
||||
.NewInstanceName = InstanceName, .InstanceFolder = VersionFolder,
|
||||
.Components = Target})
|
||||
'构造总加载器
|
||||
Dim Loaders As New List(Of LoaderBase)
|
||||
Loaders.Add(New LoaderCombo(Of String)("整合包安装", InstallLoaders) With {.Show = False, .Block = False, .ProgressWeight = InstallLoaders.Sum(Function(l) l.ProgressWeight)})
|
||||
@@ -748,7 +749,7 @@ Public Module ModModpack
|
||||
'启动
|
||||
Dim Loader As New LoaderCombo(Of String)(LoaderName, Loaders) With {.OnStateChanged = AddressOf McInstallState}
|
||||
'If Archive IsNot Nothing Then Archive.Dispose() '解除占用,以免在加载器中触发 “正由另一进程使用,因此该进程无法访问此文件”
|
||||
Loader.Start(Request.VersionFolder)
|
||||
Loader.Start(VersionFolder)
|
||||
LoaderTaskbarAdd(Loader)
|
||||
FrmMain.BtnExtraDownload.ShowRefresh()
|
||||
Return Loader
|
||||
|
||||
@@ -319,6 +319,8 @@ Public Module ModWatcher
|
||||
GetClassName(hwnd, str, str.Capacity)
|
||||
Dim ClassName As String = str.ToString
|
||||
If Not (ClassName = "GLFW30" OrElse ClassName = "SDL_app" OrElse ClassName = "LWJGL" OrElse ClassName = "SunAwtFrame") Then Return
|
||||
'SDL 会先创建隐藏窗口,待初始化完成后才显示(#9073)
|
||||
If ClassName = "SDL_app" AndAlso Not IsWindowVisible(hwnd) Then Return
|
||||
'获取窗口标题名
|
||||
str = New StringBuilder(512)
|
||||
GetWindowText(hwnd, str, str.Capacity)
|
||||
@@ -347,6 +349,7 @@ Public Module ModWatcher
|
||||
Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (hWnd As Integer, str As StringBuilder, maxCount As Integer) As Integer
|
||||
Private Declare Function SetWindowText Lib "user32" Alias "SetWindowTextA" (hWnd As Integer, str As String) As Boolean
|
||||
Private Declare Function ShowWindow Lib "user32" (hWnd As IntPtr, cmdWindow As UInteger) As Boolean
|
||||
Private Declare Function IsWindowVisible Lib "user32" (hWnd As IntPtr) As Boolean
|
||||
Private Declare Function GetWindowThreadProcessId Lib "user32" (hWnd As IntPtr, ByRef lpdwProcessId As Integer) As Integer
|
||||
|
||||
'崩溃处理
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
|
||||
|
||||
#Region "附加属性"
|
||||
|
||||
Imports PCL.FormMain
|
||||
|
||||
''' <summary>
|
||||
''' 用于在 XAML 中初始化列表对象。
|
||||
''' 附加属性无法在 XAML 中为每个对象初始化独立的列表对象,因此需要一个包装类,然后在 XAML 中显式初始化。
|
||||
@@ -272,9 +275,23 @@ Public Class CustomEvent
|
||||
Hint(Arg0.Replace("\n", vbCrLf), If(Args.Length = 1, HintType.Blue, EnumUtils.FromString(Of HintType)(Arg1)))
|
||||
|
||||
Case EventType.切换页面
|
||||
RunInUi(Sub() FrmMain.PageChange(
|
||||
EnumUtils.FromString(Of FormMain.PageType)(Arg0),
|
||||
If(Args.Length = 1, FormMain.PageSubType.Default, EnumUtils.FromString(Of FormMain.PageSubType)(Arg1))))
|
||||
RunInUi(
|
||||
Sub()
|
||||
Dim TargetPage = EnumUtils.FromString(Of PageType)(Arg0)
|
||||
If TargetPage = PageType.InstanceSetup Then
|
||||
If McInstanceSelected Is Nothing Then
|
||||
Hint("请先选择一个 Minecraft 版本!", HintType.Red)
|
||||
Return
|
||||
End If
|
||||
If McInstanceLock.IsLocked(McInstanceSelected) Then
|
||||
Hint("该版本正在被修改,暂时无法进入版本设置!", HintType.Red)
|
||||
Return
|
||||
End If
|
||||
PageInstanceLeft.Instance = McInstanceSelected
|
||||
End If
|
||||
FrmMain.PageChange(TargetPage,
|
||||
If(Args.Length = 1, PageSubType.Default, EnumUtils.FromString(Of PageSubType)(Arg1)))
|
||||
End Sub)
|
||||
|
||||
Case EventType.导入整合包, EventType.安装整合包
|
||||
RunInUi(Sub() ModpackInstall())
|
||||
@@ -295,7 +312,7 @@ Public Class CustomEvent
|
||||
Case 2
|
||||
PageOtherTest.StartCustomDownload(Arg0, Arg1)
|
||||
Case Else
|
||||
PageOtherTest.StartCustomDownload(Arg0, Arg(1), Args(2))
|
||||
PageOtherTest.StartCustomDownload(Arg0, Args(1), Args(2))
|
||||
End Select
|
||||
Catch
|
||||
PageOtherTest.StartCustomDownload(Arg0, "未知")
|
||||
@@ -304,16 +321,16 @@ Public Class CustomEvent
|
||||
|
||||
Case EventType.修改设置, EventType.写入设置
|
||||
If Args.Length = 1 Then Throw New Exception($"EventType {Type} 需要至少 2 个以 | 分割的参数,例如 UiLauncherTransparent|400")
|
||||
Settings.SetSafe(Arg0, Arg1, Instance:=McInstanceSelected)
|
||||
If Args.Length = 2 Then Hint($"已写入设置:{Arg0} → {Arg1}", HintType.Green)
|
||||
Settings.SetSafe(Arg0, Args(1), Instance:=McInstanceSelected)
|
||||
If Args.Length = 2 Then Hint($"已写入设置:{Arg0} → {Args(1)}", HintType.Green)
|
||||
|
||||
Case EventType.修改变量, EventType.写入变量
|
||||
If Args.Length = 1 Then Throw New Exception($"EventType {Type} 需要至少 2 个以 | 分割的参数,例如 VariableName|SomeValue")
|
||||
Try
|
||||
RegistryUtils.Write($"HKEY_CURRENT_USER\Software\{RegFolder}", $"CustomEvent{Arg0}", Arg1)
|
||||
If Args.Length = 2 Then Hint($"已写入变量:{Arg0} → {Arg1}", HintType.Green)
|
||||
RegistryUtils.Write($"HKEY_CURRENT_USER\Software\{RegFolder}", $"CustomEvent{Arg0}", Args(1))
|
||||
If Args.Length = 2 Then Hint($"已写入变量:{Arg0} → {Args(1)}", HintType.Green)
|
||||
Catch ex As Exception
|
||||
Logger.Warn(ex, $"写入变量失败:{Arg0} → {Arg1}", LogBehavior.Toast)
|
||||
Logger.Warn(ex, $"写入变量失败:{Arg0} → {Args(1)}", LogBehavior.Toast)
|
||||
End Try
|
||||
|
||||
Case EventType.加入房间
|
||||
@@ -353,7 +370,7 @@ Public Class CustomEvent
|
||||
Dim RawFileName As String
|
||||
Try
|
||||
RawFileName = PathUtils.GetLastPart(RelativeUrl)
|
||||
If Not RawFileName.EndsWithF(".json", True) Then Throw New Exception("未指向 .json 后缀的文件")
|
||||
If Not PathUtils.GetExtension(RawFileName) = "json" Then Throw New Exception("未指向 .json 后缀的文件")
|
||||
Catch ex As Exception
|
||||
Throw New Exception("联网帮助页面须指向一个帮助 JSON 文件,并在同路径下包含相应 XAML 文件!" & vbCrLf &
|
||||
"例如:" & vbCrLf &
|
||||
|
||||
@@ -414,6 +414,7 @@ EndHint:
|
||||
Public FrmInstanceModDisabled As PageInstanceModDisabled
|
||||
Public FrmInstanceSetup As PageInstanceSetup
|
||||
Public FrmInstanceExport As PageInstanceExport
|
||||
Public FrmDownloadModify As PageDownloadModify
|
||||
|
||||
'资源信息分页声明
|
||||
Public FrmDownloadResourceDetail As PageDownloadResourceDetail
|
||||
@@ -510,7 +511,7 @@ EndHint:
|
||||
EventData = If(JsonData("EventData"), "")
|
||||
IsEvent = True
|
||||
Else
|
||||
Dim XamlAddress As String = FilePath.Lower.Replace(".json", ".xaml")
|
||||
Dim XamlAddress As String = Path.ChangeExtension(FilePath, ".xaml")
|
||||
If FileUtils.Exists(XamlAddress) Then
|
||||
XamlContent = FileUtils.ReadAsString(XamlAddress)
|
||||
IsEvent = False
|
||||
@@ -596,9 +597,9 @@ EndHint:
|
||||
'读取自带文件
|
||||
For Each File In DirectoryUtils.EnumerateFiles(PathTemp & "Help", True)
|
||||
'跳过非 json 文件与以 . 开头的文件夹
|
||||
If PathUtils.RemoveLastPart(File).Replace(PathTemp & "Help", "").Contains("\.") OrElse PathUtils.GetExtension(File) <> "json" Then Continue For
|
||||
If PathUtils.RemoveLastPart(File).Substring((PathTemp & "Help").Length).Contains("\.") OrElse PathUtils.GetExtension(File) <> "json" Then Continue For
|
||||
'检查忽略列表
|
||||
Dim RealPath As String = File.Replace(PathTemp & "Help\", "")
|
||||
Dim RealPath As String = File.Substring((PathTemp & "Help\").Length)
|
||||
For Each Ignore In IgnoreList
|
||||
If RealPath.RegexCheck(Ignore) Then
|
||||
Logger.Trace($"已忽略 {RealPath}:{Ignore}")
|
||||
@@ -857,10 +858,10 @@ NextFile:
|
||||
Else
|
||||
Text = Text.Replace("{version}", Replacer(McInstanceSelected.Version.VanillaName))
|
||||
End If
|
||||
Text = Text.Replace("{forge}", Replacer(If(McInstanceSelected.Version.HasForge, McInstanceSelected.Version.Forge, "")))
|
||||
Text = Text.Replace("{fabric}", Replacer(If(McInstanceSelected.Version.HasFabric, McInstanceSelected.Version.Fabric, "")))
|
||||
Text = Text.Replace("{neoforge}", Replacer(If(McInstanceSelected.Version.HasNeoForge, McInstanceSelected.Version.NeoForge, "")))
|
||||
Text = Text.Replace("{liteloader}", Replacer(If(McInstanceSelected.Version.HasLiteLoader, "true", "")))
|
||||
Text = Text.Replace("{forge}", Replacer(If(McInstanceSelected.Version.ModLoaders.HasFlagF(ModLoaders.Forge), McInstanceSelected.Version.ModLoaderVersions(ModLoaders.Forge), "")))
|
||||
Text = Text.Replace("{fabric}", Replacer(If(McInstanceSelected.Version.ModLoaders.HasFlagF(ModLoaders.Fabric), McInstanceSelected.Version.ModLoaderVersions(ModLoaders.Fabric), "")))
|
||||
Text = Text.Replace("{neoforge}", Replacer(If(McInstanceSelected.Version.ModLoaders.HasFlagF(ModLoaders.NeoForge), McInstanceSelected.Version.ModLoaderVersions(ModLoaders.NeoForge), "")))
|
||||
Text = Text.Replace("{liteloader}", Replacer(If(McInstanceSelected.Version.ModLoaders.HasFlagF(ModLoaders.LiteLoader), "true", "")))
|
||||
Else
|
||||
Text = Text.Replace("{version_path}", Replacer(Nothing)) : Text = Text.Replace("{verpath}", Replacer(Nothing))
|
||||
Text = Text.Replace("{version_indie}", Replacer(Nothing)) : Text = Text.Replace("{verindie}", Replacer(Nothing))
|
||||
|
||||
@@ -320,7 +320,7 @@ Public Module ModMusic
|
||||
Hint("由于音频设备变更,音乐播放功能在重启 PCL 后才能恢复!", HintType.Red)
|
||||
Thread.Sleep(1000000000)
|
||||
End If
|
||||
If Not (MusicCurrent.EndsWithF(".wav", True) OrElse MusicCurrent.EndsWithF(".mp3", True) OrElse MusicCurrent.EndsWithF(".flac", True)) OrElse
|
||||
If Not ({"wav", "mp3", "flac"}.Contains(PathUtils.GetExtension(MusicCurrent))) OrElse
|
||||
ex.Message.Contains("0xC00D36C4") Then '#5096:不支持给定的 URL 的字节流类型。 (异常来自 HRESULT:0xC00D36C4)
|
||||
Hint("播放音乐失败(" & PathUtils.GetLastPart(MusicCurrent) & "):PCL 可能不支持此音乐格式,请将格式转换为 .wav、.mp3 或 .flac 后再试", HintType.Red)
|
||||
Else
|
||||
|
||||
@@ -25,7 +25,7 @@ Public Class LocalResourceFile
|
||||
End Get
|
||||
End Property
|
||||
''' <summary>
|
||||
''' 假若该资源未被禁用时,文件的文件名。
|
||||
''' 假若该资源未被禁用时,文件的文件名。包含 .jar/.litemod 等后缀。
|
||||
''' </summary>
|
||||
Public ReadOnly Property EnabledName As String
|
||||
Get
|
||||
@@ -57,7 +57,7 @@ Public Class LocalResourceFile
|
||||
Public Property Display As String
|
||||
Get
|
||||
If _Display Is Nothing Then _Display = ProjectVersion?.Display
|
||||
If _Display Is Nothing Then _Display = PathUtils.GetFileNameWithoutExtension(File.FullName)
|
||||
If _Display Is Nothing Then _Display = PathUtils.GetFileNameWithoutExtension(EnabledName)
|
||||
Return _Display
|
||||
End Get
|
||||
Set(value As String)
|
||||
@@ -238,7 +238,7 @@ Public Class LocalResourceFile
|
||||
Private _CurseForgeHash As UInteger?
|
||||
|
||||
''' <summary>
|
||||
''' 获取用于 Modrinth 信息获取的 Hash 值(SHA1)。
|
||||
''' 获取用于 Modrinth 信息获取的 Hash 值(SHA1)。固定为小写。
|
||||
''' </summary>
|
||||
Public ReadOnly Property ModrinthHash As String
|
||||
Get
|
||||
@@ -269,7 +269,7 @@ Public Class LocalResourceFile
|
||||
End Function
|
||||
Public Overrides Function Equals(obj As Object) As Boolean
|
||||
Dim Target = TryCast(obj, LocalResourceFile)
|
||||
Return Target IsNot Nothing AndAlso File.FullName = Target.File.FullName
|
||||
Return Target IsNot Nothing AndAlso PathUtils.IsSame(File.FullName, Target.File.FullName)
|
||||
End Function
|
||||
|
||||
#End Region
|
||||
|
||||
@@ -24,11 +24,10 @@ Public Module LocalResourceLoaders
|
||||
'获取 Mod 文件夹下的可用文件列表
|
||||
Dim ModFileList As New List(Of String)
|
||||
If DirectoryUtils.Exists(Loader.Input) Then
|
||||
Dim RawName As String = Loader.Input.Lower
|
||||
For Each File In DirectoryUtils.EnumerateFiles(Loader.Input, True)
|
||||
If File.BeforeLast("\").Lower & "\" <> RawName Then
|
||||
If Not PathUtils.IsSame(PathUtils.RemoveLastPart(File), Loader.Input) Then
|
||||
'仅当 Forge 1.13- 且文件夹名与版本号相同时,才加载该子文件夹下的 Mod
|
||||
If Not (PageInstanceLeft.Instance IsNot Nothing AndAlso PageInstanceLeft.Instance.Version.HasForge AndAlso
|
||||
If Not (PageInstanceLeft.Instance IsNot Nothing AndAlso PageInstanceLeft.Instance.Version.ModLoaders.HasFlagF(ModLoaders.Forge) AndAlso
|
||||
PageInstanceLeft.Instance.Version.Vanilla.Major < 13 AndAlso
|
||||
PathUtils.GetLastPart(PathUtils.RemoveLastPart(File)) = $"1.{PageInstanceLeft.Instance.Version.Vanilla.Major}.{PageInstanceLeft.Instance.Version.Vanilla.Build}") Then
|
||||
Continue For
|
||||
@@ -36,12 +35,9 @@ Public Module LocalResourceLoaders
|
||||
End If
|
||||
Static IsModFile As Func(Of String, Boolean) =
|
||||
Function(FullName As String)
|
||||
If FullName Is Nothing OrElse Not FullName.Contains(".") Then Return False
|
||||
FullName = FullName.Lower
|
||||
If FullName.EndsWithF(".jar", True) OrElse FullName.EndsWithF(".zip", True) OrElse FullName.EndsWithF(".litemod", True) OrElse
|
||||
FullName.EndsWithF(".jar.disabled", True) OrElse FullName.EndsWithF(".zip.disabled", True) OrElse FullName.EndsWithF(".litemod.disabled", True) OrElse
|
||||
FullName.EndsWithF(".jar.old", True) OrElse FullName.EndsWithF(".zip.old", True) OrElse FullName.EndsWithF(".litemod.old", True) Then Return True
|
||||
Return False
|
||||
If FullName Is Nothing Then Return False
|
||||
If {"disabled", "old"}.Contains(PathUtils.GetExtension(FullName)) Then FullName = PathUtils.GetFileNameWithoutExtension(FullName)
|
||||
Return {"jar", "zip", "litemod"}.Contains(PathUtils.GetExtension(FullName))
|
||||
End Function
|
||||
If IsModFile(File) Then ModFileList.Add(File)
|
||||
Next
|
||||
@@ -271,7 +267,7 @@ Public Module LocalResourceLoaders
|
||||
Dim EntryVersion As String = Entry("gameVersion")
|
||||
Return EntryVersion IsNot Nothing AndAlso EntryVersion = VanillaVersion
|
||||
End Function).
|
||||
MaxByAll(Function(Entry) Entry("gameVersion").ToString, New VersionComparer) '只保留最新的 MC 版本
|
||||
MaxByAll(Function(Entry) Entry("gameVersion").ToString, Comparer(Of String).Create(Function(x, y) McUtils.CompareVersion(x, y))) '只保留最新的 MC 版本
|
||||
For Each Entry In LatestFiles
|
||||
Dim FileId = Entry("fileId").ToObject(Of Integer)
|
||||
If Not UpdateFileIds.ContainsKey(FileId) Then UpdateFileIds(FileId) = New List(Of LocalResourceFile)
|
||||
|
||||
@@ -184,11 +184,11 @@ Public Class ResourceProject
|
||||
If Not NewFile.DownloadAvailable Then Continue For
|
||||
ModLoaders = ModLoaders Or NewFile.ModLoaders
|
||||
Dim GameVersions = File("gameVersions").ToObject(Of List(Of String))
|
||||
If Not GameVersions.Any(Function(v) McVersion.IsFormatFit(v)) Then Continue For
|
||||
If Not GameVersions.Any(Function(v) McVersion.IsStandardFormat(v)) Then Continue For
|
||||
Files.Add(New KeyValuePair(Of Integer, List(Of String))(File("id"), GameVersions))
|
||||
Next
|
||||
For Each File In If(Data("latestFilesIndexes"), New JArray) '这俩玩意儿包含的文件不一样,见 #3599
|
||||
If Not McVersion.IsFormatFit(File("gameVersion")) Then Continue For
|
||||
If Not McVersion.IsStandardFormat(File("gameVersion")) Then Continue For
|
||||
Files.Add(New KeyValuePair(Of Integer, List(Of String))(File("fileId"), {File("gameVersion").ToString}.ToList))
|
||||
Next
|
||||
CurseForgeFileIds = Files.Select(Function(f) f.Key).Distinct.ToList
|
||||
|
||||
@@ -99,12 +99,12 @@ Public Class ResourceSearcher
|
||||
Dim Address As String = $"https://api.modrinth.com/v2/search?limit={RESULT_PAGE_SIZE}&index=relevance"
|
||||
If Not String.IsNullOrEmpty(SearchText) Then Address += "&query=" & StringUtils.UrlEscape(SearchText)
|
||||
If Storage.ModrinthOffset > 0 Then Address += "&offset=" & Storage.ModrinthOffset
|
||||
'facets=[["categories:'game-mechanics'"],["categories:'forge',categories:'fabric'"],["versions:1.19.3"],["project_type:mod"]]
|
||||
'facets=[["categories:'game-mechanics'"],["categories:forge","categories:fabric"],["versions:1.19.3"],["project_type:mod"]]
|
||||
Dim Facets As New List(Of String)
|
||||
Facets.Add($"[""project_type:{Type.ToString.Lower}""]")
|
||||
If Not String.IsNullOrEmpty(Tag) Then Facets.Add($"[""categories:'{Tag.AfterLast("/")}'""]")
|
||||
If ModLoaders <> ModLoaders.None AndAlso Not IgnoreModLoaderFilter Then
|
||||
Facets.Add($"[""categories:'{ModLoaders.Flags.Select(Function(f) f.ToString.Lower).Join("',categories:'")}'""]")
|
||||
Facets.Add($"[""categories:{ModLoaders.Flags.Select(Function(f) f.ToString.Lower).Join(""",""categories:")}""]")
|
||||
End If
|
||||
If Not String.IsNullOrEmpty(GameVersion) Then Facets.Add($"[""versions:'{GameVersion}'""]")
|
||||
Address += "&facets=[" & String.Join(",", Facets) & "]"
|
||||
@@ -378,21 +378,19 @@ NextPage:
|
||||
If Request.Type <> ResourceTypes.Any AndAlso Not Project.Types.HasFlagF(Request.Type) Then Continue For
|
||||
If Not String.IsNullOrEmpty(Request.Tag) AndAlso
|
||||
Not JsonEntry("categories").Any(Function(c) c.ToString = Request.Tag.AfterLast("/")) Then Continue For 'Project.Tags 已经转换成中文了,只能从 json 判
|
||||
If Request.ModLoaders <> ModLoaders.None AndAlso Not IgnoreModLoaderFilter AndAlso
|
||||
Not Project.ModLoaders.Flags.Intersect(Request.ModLoaders.Flags).Any() Then Continue For
|
||||
If Not String.IsNullOrEmpty(Request.GameVersion) AndAlso
|
||||
Not Project.UnsafeGameVersions.Any(Function(d) d = Request.GameVersion) Then Continue For
|
||||
ProjectList.Add(Project)
|
||||
Next
|
||||
Dim Facets As New List(Of String)
|
||||
If Request.ModLoaders <> ModLoaders.None AndAlso Not IgnoreModLoaderFilter Then
|
||||
Facets.Add($"[""categories:'{Request.ModLoaders.Flags.Select(Function(f) f.ToString.Lower).Join("'"",""categories:'")}'""]")
|
||||
End If
|
||||
If Not String.IsNullOrEmpty(Request.GameVersion) Then Facets.Add($"[""versions:'{Request.GameVersion}'""]")
|
||||
If ProjectList.Any AndAlso Facets.Any Then
|
||||
Facets.Add("[""project_id:" & ProjectList.Select(Function(p) p.Id).Join(""",""project_id:") & """]")
|
||||
Dim FilterUrl As String = $"https://api.modrinth.com/v2/search?limit={Math.Min(ProjectList.Count, 100)}&facets=[" & String.Join(",", Facets) & "]"
|
||||
Logger.Info($"开始 Modrinth 直接获取筛选:{FilterUrl}")
|
||||
Dim MatchedIds As New List(Of String)
|
||||
For Each JsonEntry As JObject In DlModRequest(FilterUrl)("hits")
|
||||
MatchedIds.Add(JsonEntry("project_id").ToString)
|
||||
Next
|
||||
If ProjectList.Any AndAlso Request.ModLoaders <> ModLoaders.None AndAlso Not IgnoreModLoaderFilter AndAlso
|
||||
Not String.IsNullOrEmpty(Request.GameVersion) Then
|
||||
Dim ProjectIds = ProjectList.Select(Function(p) p.Id).Join(""",""project_id:")
|
||||
Dim Loaders = Request.ModLoaders.Flags.Select(Function(f) f.ToString.Lower).Join(""",""categories:")
|
||||
Dim FilterUrl = $"https://api.modrinth.com/v2/search?limit={ProjectList.Count}&facets=" &
|
||||
$"[[""project_id:{ProjectIds}""],[""categories:{Loaders}""],[""versions:{Request.GameVersion}""]]"
|
||||
Dim MatchedIds = DlModRequest(FilterUrl)("hits").Select(Function(h) h("project_id").ToString).ToList
|
||||
ProjectList.KeepIf(Function(p) MatchedIds.Contains(p.Id))
|
||||
End If
|
||||
'更新结果
|
||||
|
||||
@@ -90,7 +90,7 @@ Public Class ResourceVersion
|
||||
''' </summary>
|
||||
Public DownloadUrls As List(Of String)
|
||||
''' <summary>
|
||||
''' 对应文件的 SHA1 或 MD5。
|
||||
''' 对应文件的 SHA1 或 MD5。固定为小写。
|
||||
''' </summary>
|
||||
Public Hash As String = Nothing
|
||||
''' <summary>
|
||||
@@ -127,8 +127,9 @@ Public Class ResourceVersion
|
||||
.DownloadCount = Data("downloadCount")
|
||||
.FileName = Data("fileName")
|
||||
.Size = Data("fileLength")
|
||||
.Hash = CType(Data("hashes"), JArray).ToList.FirstOrDefault(Function(s) s("algo").ToObject(Of Integer) = 1)?("value")
|
||||
If .Hash Is Nothing Then .Hash = CType(Data("hashes"), JArray).ToList.FirstOrDefault(Function(s) s("algo").ToObject(Of Integer) = 2)?("value")
|
||||
If .Size = 0 Then .Size = -1 'CurseForge 可能错误地返回 0 尺寸(#9104)
|
||||
.Hash = CType(Data("hashes"), JArray).ToList.FirstOrDefault(Function(s) s("algo").ToObject(Of Integer) = 1)?("value")?.ToString().Lower()
|
||||
If .Hash Is Nothing Then .Hash = CType(Data("hashes"), JArray).ToList.FirstOrDefault(Function(s) s("algo").ToObject(Of Integer) = 2)?("value")?.ToString().Lower()
|
||||
'DownloadAddress
|
||||
Dim Url = Data("downloadUrl").ToString
|
||||
If Url = "" Then Url = $"https://edge.forgecdn.net/files/{CInt(.Id.ToString.Substring(0, 4))}/{CInt(.Id.ToString.Substring(4))}/{ .FileName}"
|
||||
@@ -145,13 +146,13 @@ Public Class ResourceVersion
|
||||
'GameVersions
|
||||
Dim RawVersions As List(Of String) = Data("gameVersions").Select(Function(t) t.ToString.Trim.Lower).ToList
|
||||
.GameVersions = RawVersions.
|
||||
Where(Function(v) McVersion.IsFormatFit(v)).
|
||||
Where(Function(v) McVersion.IsStandardFormat(v)).
|
||||
Select(Function(v) v.Replace("-snapshot", " 预览版")).
|
||||
Distinct.ToList
|
||||
If .GameVersions.IsSingle Then
|
||||
.GameVersions = .GameVersions.ToList
|
||||
ElseIf .GameVersions.Count > 1 Then
|
||||
.GameVersions = .GameVersions.SortByComparison(AddressOf CompareVersionGE).ToList
|
||||
.GameVersions = .GameVersions.SortByComparison(AddressOf McUtils.CompareVersionGE).ToList
|
||||
If .ResourceType = ResourceTypes.ModPack Then .GameVersions = { .GameVersions(0)}.ToList '整合包理应只 “支持” 一个版本
|
||||
Else
|
||||
.GameVersions = New List(Of String) From {"未知版本"}
|
||||
@@ -176,7 +177,7 @@ Public Class ResourceVersion
|
||||
.FileName = File("filename")
|
||||
.DownloadUrls = New List(Of String) From {File("url"), DlSourceModGet(File("url"))}.Distinct.ToList '同时添加了镜像源
|
||||
.Size = File("size")
|
||||
.Hash = File("hashes")("sha1")
|
||||
.Hash = File("hashes")("sha1")?.ToString.Lower()
|
||||
End If
|
||||
'类别与 Loaders
|
||||
'结果可能混杂着 Mod、数据包和服务端插件
|
||||
@@ -208,7 +209,7 @@ Public Class ResourceVersion
|
||||
If .GameVersions.IsSingle Then
|
||||
'无需处理
|
||||
ElseIf .GameVersions.Count > 1 Then
|
||||
.GameVersions = .GameVersions.SortByComparison(AddressOf CompareVersionGE).ToList
|
||||
.GameVersions = .GameVersions.SortByComparison(AddressOf McUtils.CompareVersionGE).ToList
|
||||
If .ResourceType = ResourceTypes.ModPack Then .GameVersions = New List(Of String) From { .GameVersions(0)} '整合包理应只 “支持” 一个版本
|
||||
ElseIf RawVersions.Any(Function(v) v.RegexCheck("[0-9]{2}w[0-9]{2}[a-z]")) Then
|
||||
.GameVersions = RawVersions.Where(Function(v) v.RegexCheck("[0-9]{2}w[0-9]{2}[a-z]")).ToList
|
||||
@@ -355,7 +356,7 @@ Public Class ResourceVersion
|
||||
.Info =
|
||||
Iterator Function()
|
||||
If ModLoaders <> ModLoaders.None Then Yield ModLoaders.Flags.Join("、"c)
|
||||
If .Title <> FileName.BeforeLast(".") Then Yield FileName.BeforeLast(".")
|
||||
If .Title <> PathUtils.GetFileNameWithoutExtension(FileName) Then Yield PathUtils.GetFileNameWithoutExtension(FileName)
|
||||
If Dependencies.Any Then Yield $"{Dependencies.Count} 项前置"
|
||||
If GameVersions.All(Function(v) Not v.Contains(".") OrElse {"w", "snapshot", "rc", "pre", "experimental", "-"}.Any(Function(s) v.ContainsIgnoreCase(s))) Then Yield $"游戏版本 {GameVersions.Join("、"c)}"
|
||||
If DownloadCount > 0 Then Yield $"下载 {If(DownloadCount > 100000, Math.Round(DownloadCount / 10000) & " 万", DownloadCount.ToString() + " ")}次" 'CurseForge 的下载次数经常错误地返回 0
|
||||
|
||||
@@ -51,6 +51,6 @@ Imports System.Runtime.InteropServices
|
||||
' 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
|
||||
' 方法是按如下所示使用“*”
|
||||
|
||||
<Assembly: AssemblyVersion("2.13.1.1")>
|
||||
<Assembly: AssemblyFileVersion("2.13.1.1")>
|
||||
<Assembly: AssemblyVersion("2.14.0.0")>
|
||||
<Assembly: AssemblyFileVersion("2.14.0.0")>
|
||||
<Assembly: NeutralResourcesLanguage("")>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
<local:MyPageRight
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:PCL" xmlns:sys="clr-namespace:System;assembly=mscorlib" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d" x:Class="PageDownloadInstall"
|
||||
PanScroll="PanBack">
|
||||
<Grid>
|
||||
@@ -14,19 +14,96 @@
|
||||
</StackPanel.RenderTransform>
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Row="1" x:Name="PanSelect" Visibility="Collapsed" Opacity="0" IsHitTestVisible="False" Margin="0,0,0,45">
|
||||
<StackPanel.Resources>
|
||||
<Style x:Key="ModifyCompareIcon" TargetType="{x:Type local:MyImage}">
|
||||
<Setter Property="Width" Value="18" />
|
||||
<Setter Property="Height" Value="18" />
|
||||
<Setter Property="RenderOptions.BitmapScalingMode" Value="Linear" />
|
||||
</Style>
|
||||
<Style x:Key="ModifyCompareText" TargetType="{x:Type TextBlock}" BasedOn="{StaticResource BasedOnTextBlock}">
|
||||
<Setter Property="Margin" Value="7,0,0,0" />
|
||||
<Setter Property="VerticalAlignment" Value="Center" />
|
||||
</Style>
|
||||
<Style x:Key="ModifyCompareArrow" TargetType="{x:Type Path}">
|
||||
<Setter Property="Data" Value="M3,3 L7,7 3,11 M9,3 L13,7 9,11" />
|
||||
<Setter Property="Margin" Value="10,0,18,0" />
|
||||
<Setter Property="Height" Value="14" />
|
||||
<Setter Property="HorizontalAlignment" Value="Center" />
|
||||
<Setter Property="VerticalAlignment" Value="Center" />
|
||||
<Setter Property="Stroke" Value="{DynamicResource ColorBrushGray2}" />
|
||||
<Setter Property="StrokeThickness" Value="1.4" />
|
||||
<Setter Property="StrokeStartLineCap" Value="Round" />
|
||||
<Setter Property="StrokeEndLineCap" Value="Round" />
|
||||
<Setter Property="StrokeLineJoin" Value="Round" />
|
||||
</Style>
|
||||
<sys:String x:Key="ModifyRestoreLogo">M9.83,3.17 A1.18,1.18 0 0 1 9.83,4.83 L6.85,7.82 H14.5 A6.68,6.68 0 0 1 14.5,21.18 H11 A1.18,1.18 0 0 1 11,18.82 H14.5 A4.32,4.32 0 0 0 14.5,10.18 H6.85 L9.83,13.17 A1.18,1.18 0 0 1 8.17,14.83 L3.17,9.83 A1.18,1.18 0 0 1 3.17,8.17 L8.17,3.17 A1.18,1.18 0 0 1 9.83,3.17 Z</sys:String>
|
||||
<sys:String x:Key="ModifyClearLogo">F1 M2,0 L0,2 8,10 0,18 2,20 10,12 18,20 20,18 12,10 20,2 18,0 10,8 2,0Z</sys:String>
|
||||
<Style x:Key="ModifyRestoreButton" TargetType="{x:Type local:MyIconButton}">
|
||||
<Setter Property="Visibility" Value="Collapsed" />
|
||||
<Setter Property="Height" Value="30" />
|
||||
<Setter Property="Width" Value="30" />
|
||||
<Setter Property="HorizontalAlignment" Value="Right" />
|
||||
<Setter Property="VerticalAlignment" Value="Top" />
|
||||
<Setter Property="Margin" Value="0,5,32,0" />
|
||||
<Setter Property="ToolTip" Value="撤销更改" />
|
||||
<Setter Property="Cursor" Value="Hand" />
|
||||
</Style>
|
||||
<Style x:Key="ModifyClearButton" TargetType="{x:Type local:MyIconButton}">
|
||||
<Setter Property="Height" Value="30" />
|
||||
<Setter Property="Width" Value="30" />
|
||||
<Setter Property="HorizontalAlignment" Value="Right" />
|
||||
<Setter Property="VerticalAlignment" Value="Top" />
|
||||
<Setter Property="Margin" Value="0,5,32,0" />
|
||||
<Setter Property="ToolTip" Value="取消安装" />
|
||||
</Style>
|
||||
</StackPanel.Resources>
|
||||
<StackPanel.RenderTransform>
|
||||
<TranslateTransform X="40" />
|
||||
</StackPanel.RenderTransform>
|
||||
<local:MyCard Margin="0,15,0,15" UseAnimation="False" Height="62">
|
||||
<local:MyCard x:Name="CardSelectName" Margin="0,15,0,15" MinHeight="62">
|
||||
<local:MyIconButton HorizontalAlignment="Left" Theme="Black" Opacity="0.6" x:Name="BtnBack" Margin="13,0,0,0" Height="26" Width="26"
|
||||
LogoScale="0.87" Logo="M1097 584 250 584 562 896C591 925 591 972 562 1001 533 1030 487 1030 458 1001L21 565C6 550-0 531 0 511L0 511 0 511C-0 492 6 472 21 457L458 21C487-7 533-7 562 21 591 50 591 97 562 126L250 438 1097 438C1137 438 1170 471 1170 511 1170 551 1137 584 1097 584L1097 584Z" />
|
||||
<local:MyImage x:Name="ImgLogo" Margin="52,0,0,0" VerticalAlignment="Center" HorizontalAlignment="Left" Height="32" RenderOptions.BitmapScalingMode="HighQuality" />
|
||||
<local:MyTextBox Margin="93,0,16,0" Padding="-1,0" MinHeight="30" FontSize="15" VerticalAlignment="Center" x:Name="TextSelectName" MaxLength="70" HasBackground="False" />
|
||||
<local:MyImage x:Name="ImgLogo" Margin="52,15,0,0" VerticalAlignment="Top" HorizontalAlignment="Left" Height="32" RenderOptions.BitmapScalingMode="HighQuality" />
|
||||
<local:MyTextBox Margin="93,16,16,0" Padding="-1,0" MinHeight="30" FontSize="15" VerticalAlignment="Top" x:Name="TextSelectName" MaxLength="70" HasBackground="False" ShowValidateResult="False" />
|
||||
<TextBlock x:Name="LabSelectName" Visibility="Collapsed" Height="21" Margin="56,47,42,11" Padding="0,4,0,0" VerticalAlignment="Top" FontSize="12.5" Foreground="{DynamicResource ColorBrushGray3}" TextTrimming="CharacterEllipsis" />
|
||||
<local:MyIconButton x:Name="BtnOriginalNameRestore" Style="{StaticResource ModifyRestoreButton}" Margin="0,16,6,0"
|
||||
Theme="Black" LogoScale="0.55" Logo="{StaticResource ModifyRestoreLogo}" />
|
||||
</local:MyCard>
|
||||
<local:MyHint x:Name="HintSelectName" Theme="Red" Visibility="Collapsed" />
|
||||
<local:MyHint Text="如果不安装 Fabric API,大多数 Mod 都会无法使用!" Margin="0,10,0,0" x:Name="HintFabricAPI" Theme="Red" />
|
||||
<local:MyHint Text="必须安装 OptiFabric 才能正常使用 OptiFine!" Margin="0,10,0,0" x:Name="HintOptiFabric" Theme="Red" />
|
||||
<local:MyHint Text="安装结束后,请在 Mod 下载中搜索 OptiFabric Origins 并下载,否则 OptiFine 会无法使用!" Margin="0,10,0,0" x:Name="HintOptiFabricOld" Theme="Yellow" />
|
||||
<local:MyHint Text="OptiFine 与一部分 Mod 的兼容性不佳,请谨慎安装。" Margin="0,10,0,0" x:Name="HintModOptiFine" Theme="Yellow" />
|
||||
<local:MyCard Title="Minecraft" Height="40" Margin="0,12,0,0" x:Name="CardMinecraft" Visibility="Collapsed">
|
||||
<Grid x:Name="PanMinecraftInfo" Height="18" Margin="132,11,35,0" VerticalAlignment="Top">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" /><ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<local:MyImage x:Name="ImgMinecraft" Height="18" Width="18" Margin="0,0,7,0" RenderOptions.BitmapScalingMode="Linear" />
|
||||
<TextBlock x:Name="LabMinecraftVersion" Grid.Column="1" VerticalAlignment="Center" TextTrimming="CharacterEllipsis" />
|
||||
</Grid>
|
||||
<Grid x:Name="PanMinecraftCompare" Height="18" Margin="132,11,80,0" VerticalAlignment="Top" Visibility="Collapsed" IsHitTestVisible="False">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180" /><ColumnDefinition Width="Auto" /><ColumnDefinition Width="1*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<DockPanel>
|
||||
<local:MyImage x:Name="ImgMinecraftOld" Style="{StaticResource ModifyCompareIcon}" DockPanel.Dock="Left" />
|
||||
<TextBlock x:Name="LabMinecraftOld" Style="{StaticResource ModifyCompareText}" />
|
||||
</DockPanel>
|
||||
<Path Grid.Column="1" Style="{StaticResource ModifyCompareArrow}" />
|
||||
<DockPanel Grid.Column="2">
|
||||
<local:MyImage x:Name="ImgMinecraftNew" Style="{StaticResource ModifyCompareIcon}" DockPanel.Dock="Left" />
|
||||
<TextBlock x:Name="LabMinecraftNew" Style="{StaticResource ModifyCompareText}" />
|
||||
</DockPanel>
|
||||
</Grid>
|
||||
<Grid Height="40" VerticalAlignment="Top" Background="Transparent" Cursor="Hand">
|
||||
<Path HorizontalAlignment="Right" Margin="0,0,16,0" Stretch="Uniform" Height="6" Width="10" Fill="{StaticResource ColorBrush1}" RenderTransformOrigin="0.5,0.5">
|
||||
<Path.Data>M2,4 l-2,2 10,10 10,-10 -2,-2 -8,8 -8,-8 z</Path.Data>
|
||||
<Path.RenderTransform><RotateTransform Angle="270" /></Path.RenderTransform>
|
||||
</Path>
|
||||
</Grid>
|
||||
<local:MyIconButton x:Name="BtnMinecraftRestore" Style="{StaticResource ModifyRestoreButton}" Theme="Black" LogoScale="0.55" Logo="{StaticResource ModifyRestoreLogo}" />
|
||||
</local:MyCard>
|
||||
<local:MyCard Title="Forge" Height="40" Margin="0,12,0,0" x:Name="CardForge" IsSwapped="True" CanSwap="True" SwapLogoRight="True">
|
||||
<StackPanel Margin="20,40,18,15" VerticalAlignment="Top" Name="PanForge" />
|
||||
<Grid x:Name="PanForgeInfo" Height="18" Margin="132,11,15,0" VerticalAlignment="Top" Tag="True">
|
||||
@@ -37,13 +114,25 @@
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Image x:Name="ImgForge" Margin="0,0,7,0" SnapsToDevicePixels="True" Height="18" RenderOptions.BitmapScalingMode="Linear" Source="pack://application:,,,/images/Blocks/Anvil.png" />
|
||||
<local:MyImage x:Name="ImgForge" Margin="0,0,7,0" SnapsToDevicePixels="True" Height="18" RenderOptions.BitmapScalingMode="Linear" Source="pack://application:,,,/images/Blocks/Anvil.png" />
|
||||
<TextBlock x:Name="LabForge" VerticalAlignment="Center" TextTrimming="CharacterEllipsis" Grid.Column="1" />
|
||||
</Grid>
|
||||
<Grid x:Name="BtnForgeClear" Height="30" Width="30" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,5,32,0" Background="{StaticResource ColorBrushSemiTransparent}">
|
||||
<Path x:Name="BtnForgeClearInner" Height="10" Width="10" Stretch="Uniform" Fill="{StaticResource ColorBrushGray1}" HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
Data="F1 M2,0 L0,2 8,10 0,18 2,20 10,12 18,20 20,18 12,10 20,2 18,0 10,8 2,0Z" />
|
||||
<Grid x:Name="PanForgeCompare" Height="18" Margin="132,11,80,0" VerticalAlignment="Top" Visibility="Collapsed" IsHitTestVisible="False">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180" /><ColumnDefinition Width="Auto" /><ColumnDefinition Width="1*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<DockPanel>
|
||||
<local:MyImage Style="{StaticResource ModifyCompareIcon}" Source="pack://application:,,,/images/Blocks/Anvil.png" DockPanel.Dock="Left" />
|
||||
<TextBlock x:Name="LabForgeOld" Style="{StaticResource ModifyCompareText}" />
|
||||
</DockPanel>
|
||||
<Path Grid.Column="1" Style="{StaticResource ModifyCompareArrow}" />
|
||||
<DockPanel Grid.Column="2">
|
||||
<local:MyImage Style="{StaticResource ModifyCompareIcon}" Source="pack://application:,,,/images/Blocks/Anvil.png" DockPanel.Dock="Left" />
|
||||
<TextBlock Style="{StaticResource ModifyCompareText}" />
|
||||
</DockPanel>
|
||||
</Grid>
|
||||
<local:MyIconButton x:Name="BtnForgeClear" Style="{StaticResource ModifyClearButton}" Theme="Black" LogoScale="0.5" Logo="{StaticResource ModifyClearLogo}" />
|
||||
<local:MyIconButton x:Name="BtnForgeRestore" Style="{StaticResource ModifyRestoreButton}" Theme="Black" LogoScale="0.55" Logo="{StaticResource ModifyRestoreLogo}" />
|
||||
</local:MyCard>
|
||||
<local:MyCard Title="NeoForge" Height="40" Margin="0,12,0,0" x:Name="CardNeoForge" IsSwapped="True" CanSwap="True" SwapLogoRight="True">
|
||||
<StackPanel Margin="20,40,18,15" VerticalAlignment="Top" Name="PanNeoForge" />
|
||||
@@ -55,13 +144,25 @@
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Image x:Name="ImgNeoForge" Margin="0,0,7,0" SnapsToDevicePixels="True" Height="18" RenderOptions.BitmapScalingMode="Linear" Source="pack://application:,,,/images/Blocks/NeoForge.png" />
|
||||
<local:MyImage x:Name="ImgNeoForge" Margin="0,0,7,0" SnapsToDevicePixels="True" Height="18" RenderOptions.BitmapScalingMode="Linear" Source="pack://application:,,,/images/Blocks/NeoForge.png" />
|
||||
<TextBlock x:Name="LabNeoForge" VerticalAlignment="Center" TextTrimming="CharacterEllipsis" Grid.Column="1" />
|
||||
</Grid>
|
||||
<Grid x:Name="BtnNeoForgeClear" Height="30" Width="30" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,5,32,0" Background="{StaticResource ColorBrushSemiTransparent}">
|
||||
<Path x:Name="BtnNeoForgeClearInner" Height="10" Width="10" Stretch="Uniform" Fill="{StaticResource ColorBrushGray1}" HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
Data="F1 M2,0 L0,2 8,10 0,18 2,20 10,12 18,20 20,18 12,10 20,2 18,0 10,8 2,0Z" />
|
||||
<Grid x:Name="PanNeoForgeCompare" Height="18" Margin="132,11,80,0" VerticalAlignment="Top" Visibility="Collapsed" IsHitTestVisible="False">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180" /><ColumnDefinition Width="Auto" /><ColumnDefinition Width="1*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<DockPanel>
|
||||
<local:MyImage Style="{StaticResource ModifyCompareIcon}" Source="pack://application:,,,/images/Blocks/NeoForge.png" DockPanel.Dock="Left" />
|
||||
<TextBlock x:Name="LabNeoForgeOld" Style="{StaticResource ModifyCompareText}" />
|
||||
</DockPanel>
|
||||
<Path Grid.Column="1" Style="{StaticResource ModifyCompareArrow}" />
|
||||
<DockPanel Grid.Column="2">
|
||||
<local:MyImage Style="{StaticResource ModifyCompareIcon}" Source="pack://application:,,,/images/Blocks/NeoForge.png" DockPanel.Dock="Left" />
|
||||
<TextBlock Style="{StaticResource ModifyCompareText}" />
|
||||
</DockPanel>
|
||||
</Grid>
|
||||
<local:MyIconButton x:Name="BtnNeoForgeClear" Style="{StaticResource ModifyClearButton}" Theme="Black" LogoScale="0.5" Logo="{StaticResource ModifyClearLogo}" />
|
||||
<local:MyIconButton x:Name="BtnNeoForgeRestore" Style="{StaticResource ModifyRestoreButton}" Theme="Black" LogoScale="0.55" Logo="{StaticResource ModifyRestoreLogo}" />
|
||||
</local:MyCard>
|
||||
<local:MyCard Title="Fabric" Height="40" Margin="0,12,0,0" x:Name="CardFabric" IsSwapped="True" CanSwap="True" SwapLogoRight="True">
|
||||
<StackPanel Margin="20,40,18,15" VerticalAlignment="Top" Name="PanFabric" />
|
||||
@@ -73,13 +174,25 @@
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Image x:Name="ImgFabric" Margin="0,0,7,0" SnapsToDevicePixels="True" Height="18" RenderOptions.BitmapScalingMode="Linear" Source="pack://application:,,,/images/Blocks/Fabric.png" />
|
||||
<local:MyImage x:Name="ImgFabric" Margin="0,0,7,0" SnapsToDevicePixels="True" Height="18" RenderOptions.BitmapScalingMode="Linear" Source="pack://application:,,,/images/Blocks/Fabric.png" />
|
||||
<TextBlock x:Name="LabFabric" VerticalAlignment="Center" TextTrimming="CharacterEllipsis" Grid.Column="1" />
|
||||
</Grid>
|
||||
<Grid x:Name="BtnFabricClear" Height="30" Width="30" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,5,32,0" Background="{StaticResource ColorBrushSemiTransparent}">
|
||||
<Path x:Name="BtnFabricClearInner" Height="10" Width="10" Stretch="Uniform" Fill="{StaticResource ColorBrushGray1}" HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
Data="F1 M2,0 L0,2 8,10 0,18 2,20 10,12 18,20 20,18 12,10 20,2 18,0 10,8 2,0Z" />
|
||||
<Grid x:Name="PanFabricCompare" Height="18" Margin="132,11,80,0" VerticalAlignment="Top" Visibility="Collapsed" IsHitTestVisible="False">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180" /><ColumnDefinition Width="Auto" /><ColumnDefinition Width="1*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<DockPanel>
|
||||
<local:MyImage Style="{StaticResource ModifyCompareIcon}" Source="pack://application:,,,/images/Blocks/Fabric.png" DockPanel.Dock="Left" />
|
||||
<TextBlock x:Name="LabFabricOld" Style="{StaticResource ModifyCompareText}" />
|
||||
</DockPanel>
|
||||
<Path Grid.Column="1" Style="{StaticResource ModifyCompareArrow}" />
|
||||
<DockPanel Grid.Column="2">
|
||||
<local:MyImage Style="{StaticResource ModifyCompareIcon}" Source="pack://application:,,,/images/Blocks/Fabric.png" DockPanel.Dock="Left" />
|
||||
<TextBlock Style="{StaticResource ModifyCompareText}" />
|
||||
</DockPanel>
|
||||
</Grid>
|
||||
<local:MyIconButton x:Name="BtnFabricClear" Style="{StaticResource ModifyClearButton}" Theme="Black" LogoScale="0.5" Logo="{StaticResource ModifyClearLogo}" />
|
||||
<local:MyIconButton x:Name="BtnFabricRestore" Style="{StaticResource ModifyRestoreButton}" Theme="Black" LogoScale="0.55" Logo="{StaticResource ModifyRestoreLogo}" />
|
||||
</local:MyCard>
|
||||
<local:MyCard Title="Fabric API" Height="40" Margin="0,12,0,0" x:Name="CardFabricApi" IsSwapped="True" CanSwap="True" SwapLogoRight="True">
|
||||
<StackPanel Margin="20,40,18,15" VerticalAlignment="Top" Name="PanFabricApi" />
|
||||
@@ -91,13 +204,25 @@
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Image x:Name="ImgFabricApi" Margin="0,0,7,0" SnapsToDevicePixels="True" Height="18" RenderOptions.BitmapScalingMode="Linear" Source="pack://application:,,,/images/Blocks/Fabric.png" />
|
||||
<local:MyImage x:Name="ImgFabricApi" Margin="0,0,7,0" SnapsToDevicePixels="True" Height="18" RenderOptions.BitmapScalingMode="Linear" Source="pack://application:,,,/images/Blocks/Fabric.png" />
|
||||
<TextBlock x:Name="LabFabricApi" VerticalAlignment="Center" TextTrimming="CharacterEllipsis" Grid.Column="1" />
|
||||
</Grid>
|
||||
<Grid x:Name="BtnFabricApiClear" Height="30" Width="30" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,5,32,0" Background="{StaticResource ColorBrushSemiTransparent}">
|
||||
<Path x:Name="BtnFabricApiClearInner" Height="10" Width="10" Stretch="Uniform" Fill="{StaticResource ColorBrushGray1}" HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
Data="F1 M2,0 L0,2 8,10 0,18 2,20 10,12 18,20 20,18 12,10 20,2 18,0 10,8 2,0Z" />
|
||||
<Grid x:Name="PanFabricApiCompare" Height="18" Margin="132,11,80,0" VerticalAlignment="Top" Visibility="Collapsed" IsHitTestVisible="False">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180" /><ColumnDefinition Width="Auto" /><ColumnDefinition Width="1*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<DockPanel>
|
||||
<local:MyImage Style="{StaticResource ModifyCompareIcon}" Source="pack://application:,,,/images/Blocks/Fabric.png" DockPanel.Dock="Left" />
|
||||
<TextBlock x:Name="LabFabricApiOld" Style="{StaticResource ModifyCompareText}" />
|
||||
</DockPanel>
|
||||
<Path Grid.Column="1" Style="{StaticResource ModifyCompareArrow}" />
|
||||
<DockPanel Grid.Column="2">
|
||||
<local:MyImage Style="{StaticResource ModifyCompareIcon}" Source="pack://application:,,,/images/Blocks/Fabric.png" DockPanel.Dock="Left" />
|
||||
<TextBlock Style="{StaticResource ModifyCompareText}" />
|
||||
</DockPanel>
|
||||
</Grid>
|
||||
<local:MyIconButton x:Name="BtnFabricApiClear" Style="{StaticResource ModifyClearButton}" Theme="Black" LogoScale="0.5" Logo="{StaticResource ModifyClearLogo}" />
|
||||
<local:MyIconButton x:Name="BtnFabricApiRestore" Style="{StaticResource ModifyRestoreButton}" Theme="Black" LogoScale="0.55" Logo="{StaticResource ModifyRestoreLogo}" />
|
||||
</local:MyCard>
|
||||
<local:MyCard Title="OptiFine" Height="40" Margin="0,12,0,0" x:Name="CardOptiFine" IsSwapped="True" CanSwap="True" SwapLogoRight="True">
|
||||
<StackPanel Margin="20,40,18,15" VerticalAlignment="Top">
|
||||
@@ -111,13 +236,25 @@
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Image x:Name="ImgOptiFine" Margin="0,0,7,0" SnapsToDevicePixels="True" Height="18" RenderOptions.BitmapScalingMode="Linear" Source="pack://application:,,,/images/Blocks/GrassPath.png" />
|
||||
<local:MyImage x:Name="ImgOptiFine" Margin="0,0,7,0" SnapsToDevicePixels="True" Height="18" RenderOptions.BitmapScalingMode="Linear" Source="pack://application:,,,/images/Blocks/GrassPath.png" />
|
||||
<TextBlock x:Name="LabOptiFine" VerticalAlignment="Center" TextTrimming="CharacterEllipsis" Grid.Column="1" />
|
||||
</Grid>
|
||||
<Grid x:Name="BtnOptiFineClear" Height="30" Width="30" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,5,32,0" Background="{StaticResource ColorBrushSemiTransparent}">
|
||||
<Path x:Name="BtnOptiFineClearInner" Height="10" Width="10" Stretch="Uniform" Fill="{StaticResource ColorBrushGray1}" HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
Data="F1 M2,0 L0,2 8,10 0,18 2,20 10,12 18,20 20,18 12,10 20,2 18,0 10,8 2,0Z" />
|
||||
<Grid x:Name="PanOptiFineCompare" Height="18" Margin="132,11,80,0" VerticalAlignment="Top" Visibility="Collapsed" IsHitTestVisible="False">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180" /><ColumnDefinition Width="Auto" /><ColumnDefinition Width="1*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<DockPanel>
|
||||
<local:MyImage Style="{StaticResource ModifyCompareIcon}" Source="pack://application:,,,/images/Blocks/GrassPath.png" DockPanel.Dock="Left" />
|
||||
<TextBlock x:Name="LabOptiFineOld" Style="{StaticResource ModifyCompareText}" />
|
||||
</DockPanel>
|
||||
<Path Grid.Column="1" Style="{StaticResource ModifyCompareArrow}" />
|
||||
<DockPanel Grid.Column="2">
|
||||
<local:MyImage Style="{StaticResource ModifyCompareIcon}" Source="pack://application:,,,/images/Blocks/GrassPath.png" DockPanel.Dock="Left" />
|
||||
<TextBlock Style="{StaticResource ModifyCompareText}" />
|
||||
</DockPanel>
|
||||
</Grid>
|
||||
<local:MyIconButton x:Name="BtnOptiFineClear" Style="{StaticResource ModifyClearButton}" Theme="Black" LogoScale="0.5" Logo="{StaticResource ModifyClearLogo}" />
|
||||
<local:MyIconButton x:Name="BtnOptiFineRestore" Style="{StaticResource ModifyRestoreButton}" Theme="Black" LogoScale="0.55" Logo="{StaticResource ModifyRestoreLogo}" />
|
||||
</local:MyCard>
|
||||
<local:MyCard Title="OptiFabric" Height="40" Margin="0,12,0,0" x:Name="CardOptiFabric" IsSwapped="True" CanSwap="True" SwapLogoRight="True">
|
||||
<StackPanel Margin="20,40,18,15" VerticalAlignment="Top" Name="PanOptiFabric" />
|
||||
@@ -129,13 +266,25 @@
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Image x:Name="ImgOptiFabric" Margin="0,0,7,0" SnapsToDevicePixels="True" Height="18" RenderOptions.BitmapScalingMode="HighQuality" Source="pack://application:,,,/images/Blocks/OptiFabric.png" />
|
||||
<local:MyImage x:Name="ImgOptiFabric" Margin="0,0,7,0" SnapsToDevicePixels="True" Height="18" RenderOptions.BitmapScalingMode="HighQuality" Source="pack://application:,,,/images/Blocks/OptiFabric.png" />
|
||||
<TextBlock x:Name="LabOptiFabric" VerticalAlignment="Center" TextTrimming="CharacterEllipsis" Grid.Column="1" />
|
||||
</Grid>
|
||||
<Grid x:Name="BtnOptiFabricClear" Height="30" Width="30" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,5,32,0" Background="{StaticResource ColorBrushSemiTransparent}">
|
||||
<Path x:Name="BtnOptiFabricClearInner" Height="10" Width="10" Stretch="Uniform" Fill="{StaticResource ColorBrushGray1}" HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
Data="F1 M2,0 L0,2 8,10 0,18 2,20 10,12 18,20 20,18 12,10 20,2 18,0 10,8 2,0Z" />
|
||||
<Grid x:Name="PanOptiFabricCompare" Height="18" Margin="132,11,80,0" VerticalAlignment="Top" Visibility="Collapsed" IsHitTestVisible="False">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180" /><ColumnDefinition Width="Auto" /><ColumnDefinition Width="1*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<DockPanel>
|
||||
<local:MyImage Style="{StaticResource ModifyCompareIcon}" Source="pack://application:,,,/images/Blocks/OptiFabric.png" DockPanel.Dock="Left" />
|
||||
<TextBlock x:Name="LabOptiFabricOld" Style="{StaticResource ModifyCompareText}" />
|
||||
</DockPanel>
|
||||
<Path Grid.Column="1" Style="{StaticResource ModifyCompareArrow}" />
|
||||
<DockPanel Grid.Column="2">
|
||||
<local:MyImage Style="{StaticResource ModifyCompareIcon}" Source="pack://application:,,,/images/Blocks/OptiFabric.png" DockPanel.Dock="Left" />
|
||||
<TextBlock Style="{StaticResource ModifyCompareText}" />
|
||||
</DockPanel>
|
||||
</Grid>
|
||||
<local:MyIconButton x:Name="BtnOptiFabricClear" Style="{StaticResource ModifyClearButton}" Theme="Black" LogoScale="0.5" Logo="{StaticResource ModifyClearLogo}" />
|
||||
<local:MyIconButton x:Name="BtnOptiFabricRestore" Style="{StaticResource ModifyRestoreButton}" Theme="Black" LogoScale="0.55" Logo="{StaticResource ModifyRestoreLogo}" />
|
||||
</local:MyCard>
|
||||
<local:MyCard Title="LiteLoader" Height="40" Margin="0,12,0,0" x:Name="CardLiteLoader" IsSwapped="True" CanSwap="True" SwapLogoRight="True">
|
||||
<StackPanel Margin="20,40,18,15" VerticalAlignment="Top" Name="PanLiteLoader" />
|
||||
@@ -147,13 +296,25 @@
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Image x:Name="ImgLiteLoader" Margin="-1,0,6,0" SnapsToDevicePixels="True" Height="20" RenderOptions.BitmapScalingMode="Linear" Source="pack://application:,,,/images/Blocks/Egg.png" />
|
||||
<local:MyImage x:Name="ImgLiteLoader" Margin="-1,0,6,0" SnapsToDevicePixels="True" Height="20" RenderOptions.BitmapScalingMode="Linear" Source="pack://application:,,,/images/Blocks/Egg.png" />
|
||||
<TextBlock x:Name="LabLiteLoader" VerticalAlignment="Center" TextTrimming="CharacterEllipsis" Grid.Column="1" />
|
||||
</Grid>
|
||||
<Grid x:Name="BtnLiteLoaderClear" Height="30" Width="30" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,5,32,0" Background="{StaticResource ColorBrushSemiTransparent}">
|
||||
<Path x:Name="BtnLiteLoaderClearInner" Height="10" Width="10" Stretch="Uniform" Fill="{StaticResource ColorBrushGray1}" HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
Data="F1 M2,0 L0,2 8,10 0,18 2,20 10,12 18,20 20,18 12,10 20,2 18,0 10,8 2,0Z" />
|
||||
<Grid x:Name="PanLiteLoaderCompare" Height="18" Margin="132,11,80,0" VerticalAlignment="Top" Visibility="Collapsed" IsHitTestVisible="False">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180" /><ColumnDefinition Width="Auto" /><ColumnDefinition Width="1*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<DockPanel>
|
||||
<local:MyImage Style="{StaticResource ModifyCompareIcon}" Source="pack://application:,,,/images/Blocks/Egg.png" DockPanel.Dock="Left" />
|
||||
<TextBlock x:Name="LabLiteLoaderOld" Style="{StaticResource ModifyCompareText}" />
|
||||
</DockPanel>
|
||||
<Path Grid.Column="1" Style="{StaticResource ModifyCompareArrow}" />
|
||||
<DockPanel Grid.Column="2">
|
||||
<local:MyImage Style="{StaticResource ModifyCompareIcon}" Source="pack://application:,,,/images/Blocks/Egg.png" DockPanel.Dock="Left" />
|
||||
<TextBlock Style="{StaticResource ModifyCompareText}" />
|
||||
</DockPanel>
|
||||
</Grid>
|
||||
<local:MyIconButton x:Name="BtnLiteLoaderClear" Style="{StaticResource ModifyClearButton}" Theme="Black" LogoScale="0.5" Logo="{StaticResource ModifyClearLogo}" />
|
||||
<local:MyIconButton x:Name="BtnLiteLoaderRestore" Style="{StaticResource ModifyRestoreButton}" Theme="Black" LogoScale="0.55" Logo="{StaticResource ModifyRestoreLogo}" />
|
||||
</local:MyCard>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
@@ -163,7 +324,7 @@
|
||||
LogoScale="0.95" Logo="M955 610h-59c-15 0-29 13-29 29v196c0 15-13 29-29 29h-649c-15 0-29-13-29-29v-196c0-15-13-29-29-29h-59c-15 0-29 13-29 29V905c0 43 35 78 78 78h787c43 0 78-35 78-78V640c0-15-13-29-29-29zM492 740c11 11 29 11 41 0l265-265c11-11 11-29 0-41l-41-41c-11-11-29-11-41 0l-110 110c-11 11-33 3-33-13V68C571 53 555 39 541 39h-59c-15 0-29 13-29 29v417c0 17-21 25-33 13l-110-110c-11-11-29-11-41 0L226 433c-11 11-11 29 0 41L492 740z" />
|
||||
</Grid>
|
||||
<local:MyCard HorizontalAlignment="Center" VerticalAlignment="Center" Margin="40,0" SnapsToDevicePixels="True" x:Name="PanLoad" UseAnimation="False">
|
||||
<local:MyLoading Text="正在获取版本列表" Margin="20,20,20,17" x:Name="LoadMinecraft" HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||
<local:MyLoading Text="正在加载" Margin="20,20,20,17" x:Name="LoadMinecraft" HorizontalAlignment="Center" VerticalAlignment="Center" ShowProgress="True" />
|
||||
<local:MyLoading Visibility="Collapsed" x:Name="LoadOptiFine" HasAnimation="False" />
|
||||
<local:MyLoading Visibility="Collapsed" x:Name="LoadForge" HasAnimation="False" />
|
||||
<local:MyLoading Visibility="Collapsed" x:Name="LoadNeoForge" HasAnimation="False" />
|
||||
@@ -196,4 +357,4 @@
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
-->
|
||||
-->
|
||||
|
||||
@@ -1,12 +1,30 @@
|
||||
Public Class PageDownloadInstall
|
||||
|
||||
Private Sub LoaderInit() Handles Me.Initialized
|
||||
Public Sub ControlInit()
|
||||
DisabledPageAnimControls.Add(BtnStart)
|
||||
LoadOptiFine.State = DlOptiFineListLoader
|
||||
LoadLiteLoader.State = DlLiteLoaderListLoader
|
||||
LoadFabric.State = DlFabricListLoader
|
||||
LoadFabricApi.State = DlFabricApiLoader
|
||||
LoadNeoForge.State = DlNeoForgeListLoader
|
||||
LoadOptiFabric.State = DlOptiFabricLoader
|
||||
|
||||
McDownloadForgeRecommendedRefresh()
|
||||
End Sub
|
||||
|
||||
Public Overridable Sub LoaderInit() Handles Me.Initialized
|
||||
ControlInit()
|
||||
PageLoaderInit(LoadMinecraft, PanLoad, PanAllBack, Nothing, DlClientListLoader, AddressOf LoadMinecraft_OnFinish)
|
||||
End Sub
|
||||
|
||||
Private IsLoad As Boolean = False
|
||||
Private Sub Init() Handles Me.Loaded
|
||||
Public Overridable Sub Init() Handles Me.Loaded
|
||||
If IsLoad Then
|
||||
IsSelectNameEdited = False
|
||||
ExitSelectPage()
|
||||
If DlClientListLoader.State = LoadState.Finished Then TrySelectWaitingVersion()
|
||||
End If
|
||||
IsLoad = True
|
||||
PanBack.ScrollToHome()
|
||||
DlOptiFineListLoader.Start()
|
||||
DlLiteLoaderListLoader.Start()
|
||||
@@ -17,35 +35,19 @@ Public Class PageDownloadInstall
|
||||
TextSelectName.ValidateRules = New ObjectModel.Collection(Of Validate) From {New ValidateFolderName(McFolderSelected & "versions")}
|
||||
TextSelectName.Validate()
|
||||
ReloadSelected()
|
||||
|
||||
'非重复加载部分
|
||||
If IsLoad Then Return
|
||||
IsLoad = True
|
||||
|
||||
McDownloadForgeRecommendedRefresh()
|
||||
|
||||
LoadOptiFine.State = DlOptiFineListLoader
|
||||
LoadLiteLoader.State = DlLiteLoaderListLoader
|
||||
LoadFabric.State = DlFabricListLoader
|
||||
LoadFabricApi.State = DlFabricApiLoader
|
||||
LoadNeoForge.State = DlNeoForgeListLoader
|
||||
LoadOptiFabric.State = DlOptiFabricLoader
|
||||
End Sub
|
||||
|
||||
#Region "页面切换"
|
||||
|
||||
'页面切换动画
|
||||
Public IsInSelectPage As Boolean = False
|
||||
Private IsFirstLoaded As Boolean = False
|
||||
Private Sub EnterSelectPage()
|
||||
If IsInSelectPage Then Return
|
||||
|
||||
''' <summary>
|
||||
''' 选择页面 UI 初始化。
|
||||
''' </summary>
|
||||
Public Sub PrepareSelectPage()
|
||||
IsInSelectPage = True
|
||||
|
||||
PanInner.Margin = New Thickness(25, 10, 25, 40)
|
||||
|
||||
AutoSelectedFabricApi = False
|
||||
AutoSelectedOptiFabric = False
|
||||
IsSelectNameEdited = False
|
||||
PanSelect.Visibility = Visibility.Visible
|
||||
PanSelect.IsHitTestVisible = True
|
||||
PanMinecraft.IsHitTestVisible = False
|
||||
@@ -54,13 +56,9 @@ Public Class PageDownloadInstall
|
||||
|
||||
DisabledPageAnimControls.Remove(BtnStart)
|
||||
BtnStart.Show = True
|
||||
CardOptiFine.IsSwapped = True
|
||||
CardLiteLoader.IsSwapped = True
|
||||
CardForge.IsSwapped = True
|
||||
CardNeoForge.IsSwapped = True
|
||||
CardFabric.IsSwapped = True
|
||||
CardFabricApi.IsSwapped = True
|
||||
CardOptiFabric.IsSwapped = True
|
||||
For Each Card In {CardOptiFine, CardLiteLoader, CardForge, CardNeoForge, CardFabric, CardFabricApi, CardOptiFabric}
|
||||
Card.IsSwapped = True
|
||||
Next
|
||||
|
||||
'如果在选择页面按了刷新键,选择页的东西可能会由于动画被隐藏,但不会由于加载结束而再次显示,因此这里需要手动恢复
|
||||
For Each Control In GetAllAnimControls(PanSelect)
|
||||
@@ -69,9 +67,16 @@ Public Class PageDownloadInstall
|
||||
Control.RenderTransform = New TranslateTransform
|
||||
End If
|
||||
Next
|
||||
End Sub
|
||||
|
||||
Private Sub EnterSelectPage()
|
||||
If IsInSelectPage Then Return
|
||||
AutoSelectedFabricApi = False
|
||||
AutoSelectedOptiFabric = False
|
||||
PrepareSelectPage()
|
||||
|
||||
'启动 Forge 加载
|
||||
If McVersion.IsFormatFit(VanillaName) Then
|
||||
If McVersion.IsStandardFormat(VanillaName) Then
|
||||
Dim ForgeLoader = New LoaderTask(Of String, List(Of DlForgeVersionEntry))("DlForgeVersion " & VanillaName, AddressOf DlForgeVersionMain)
|
||||
LoadForge.State = ForgeLoader
|
||||
ForgeLoader.Start(VanillaName)
|
||||
@@ -87,35 +92,27 @@ Public Class PageDownloadInstall
|
||||
AaCode(
|
||||
Sub()
|
||||
PanBack.ScrollToHome()
|
||||
TextSelectName.Validate()
|
||||
OptiFine_Loaded()
|
||||
LiteLoader_Loaded()
|
||||
Forge_Loaded()
|
||||
NeoForge_Loaded()
|
||||
Fabric_Loaded()
|
||||
FabricApi_Loaded()
|
||||
OptiFabric_Loaded()
|
||||
ReloadSelected()
|
||||
ReloadComponentLists()
|
||||
PanMinecraft.Visibility = Visibility.Collapsed
|
||||
End Sub, After:=True),
|
||||
AaOpacity(PanSelect, 1 - PanSelect.Opacity, 70, 100),
|
||||
AaTranslateX(PanSelect, -CType(PanSelect.RenderTransform, TranslateTransform).X, 160, 100, Ease:=New AniEaseOutFluent(AniEasePower.ExtraStrong)),
|
||||
AaCode(
|
||||
Sub()
|
||||
PanBack.IsHitTestVisible = True
|
||||
'初始化 Binding
|
||||
If IsFirstLoaded Then Return
|
||||
IsFirstLoaded = True
|
||||
BtnOptiFineClearInner.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = CardOptiFine.MainTextBlock, .Mode = BindingMode.OneWay})
|
||||
BtnLiteLoaderClearInner.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = CardLiteLoader.MainTextBlock, .Mode = BindingMode.OneWay})
|
||||
BtnForgeClearInner.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = CardForge.MainTextBlock, .Mode = BindingMode.OneWay})
|
||||
BtnNeoForgeClearInner.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = CardNeoForge.MainTextBlock, .Mode = BindingMode.OneWay})
|
||||
BtnFabricClearInner.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = CardFabric.MainTextBlock, .Mode = BindingMode.OneWay})
|
||||
BtnFabricApiClearInner.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = CardFabricApi.MainTextBlock, .Mode = BindingMode.OneWay})
|
||||
BtnOptiFabricClearInner.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = CardOptiFabric.MainTextBlock, .Mode = BindingMode.OneWay})
|
||||
End Sub,, True)
|
||||
AaCode(Sub() PanBack.IsHitTestVisible = True,, True)
|
||||
}, "FrmDownloadInstall SelectPageSwitch", True)
|
||||
End Sub
|
||||
|
||||
Public Sub ReloadComponentLists()
|
||||
TextSelectName.Validate()
|
||||
OptiFine_Loaded()
|
||||
LiteLoader_Loaded()
|
||||
Forge_Loaded()
|
||||
NeoForge_Loaded()
|
||||
Fabric_Loaded()
|
||||
FabricApi_Loaded()
|
||||
OptiFabric_Loaded()
|
||||
ReloadSelected()
|
||||
End Sub
|
||||
|
||||
Public Sub ExitSelectPage() Handles BtnBack.Click
|
||||
If Not IsInSelectPage Then Return
|
||||
IsInSelectPage = False
|
||||
@@ -144,10 +141,11 @@ Public Class PageDownloadInstall
|
||||
End Sub,, True)
|
||||
}, "FrmDownloadInstall SelectPageSwitch")
|
||||
End Sub
|
||||
Public Sub MinecraftSelected(sender As MyListItem, e As MouseButtonEventArgs)
|
||||
Public Overridable Sub MinecraftSelected(sender As MyListItem, e As MouseButtonEventArgs)
|
||||
VanillaName = sender.Title
|
||||
VanillaData = sender.Tag
|
||||
VanillaIcon = sender.Logo
|
||||
LabMinecraftVersion.Text = VanillaName
|
||||
EnterSelectPage()
|
||||
End Sub
|
||||
|
||||
@@ -156,9 +154,9 @@ Public Class PageDownloadInstall
|
||||
#Region "选择"
|
||||
|
||||
'Minecraft
|
||||
Private VanillaName As String
|
||||
Private VanillaData As JObject
|
||||
Private VanillaIcon As String
|
||||
Public VanillaName As String
|
||||
Public VanillaData As JObject
|
||||
Public VanillaIcon As String
|
||||
Private ReadOnly Property VanillaDrop As Integer
|
||||
Get
|
||||
Return McVersion.VersionToDrop(VanillaName)
|
||||
@@ -166,24 +164,25 @@ Public Class PageDownloadInstall
|
||||
End Property
|
||||
|
||||
'附加组件
|
||||
Private SelectedOptiFine As DlOptiFineListEntry = Nothing
|
||||
Private SelectedLiteLoader As DlLiteLoaderListEntry = Nothing
|
||||
Private SelectedForge As DlForgeVersionEntry = Nothing
|
||||
Private SelectedNeoForge As DlNeoForgeListEntry = Nothing
|
||||
Private SelectedFabric As String = Nothing
|
||||
Private SelectedFabricApi As ResourceVersion = Nothing
|
||||
Private SelectedOptiFabric As ResourceVersion = Nothing
|
||||
Public SelectedOptiFine As DlOptiFineListEntry = Nothing
|
||||
Public SelectedLiteLoader As DlLiteLoaderListEntry = Nothing
|
||||
Public SelectedForge As DlForgeVersionEntry = Nothing
|
||||
Public SelectedNeoForge As DlNeoForgeListEntry = Nothing
|
||||
Public SelectedFabric As String = Nothing
|
||||
Public SelectedFabricApi As ResourceVersion = Nothing
|
||||
Public SelectedOptiFabric As ResourceVersion = Nothing
|
||||
|
||||
''' <summary>
|
||||
''' 重载已选择的项目的显示。
|
||||
''' </summary>
|
||||
Private Sub ReloadSelected() Handles CardOptiFine.Swap, LoadOptiFine.StateChanged, CardForge.Swap, LoadForge.StateChanged, CardNeoForge.Swap, LoadNeoForge.StateChanged, CardFabric.Swap, LoadFabric.StateChanged, CardFabricApi.Swap, LoadFabricApi.StateChanged, CardOptiFabric.Swap, LoadOptiFabric.StateChanged, CardLiteLoader.Swap, LoadLiteLoader.StateChanged
|
||||
Public Overridable Sub ReloadSelected() Handles CardOptiFine.Swap, LoadOptiFine.StateChanged, CardForge.Swap, LoadForge.StateChanged, CardNeoForge.Swap, LoadNeoForge.StateChanged, CardFabric.Swap, LoadFabric.StateChanged, CardFabricApi.Swap, LoadFabricApi.StateChanged, CardOptiFabric.Swap, LoadOptiFabric.StateChanged, CardLiteLoader.Swap, LoadLiteLoader.StateChanged
|
||||
Static Ongoing As Boolean = False '#3742 中,LoadOptiFineGetError 会初始化 LoadOptiFine,触发事件 LoadOptiFine.StateChanged,导致再次调用 SelectReload
|
||||
If VanillaName Is Nothing OrElse Ongoing Then Return
|
||||
Ongoing = True
|
||||
'主预览
|
||||
SelectNameUpdate()
|
||||
ImgLogo.Source = GetSelectLogo()
|
||||
ImgMinecraft.Source = VanillaIcon
|
||||
'OptiFine
|
||||
Dim OptiFineError As String = LoadOptiFineGetError()
|
||||
CardOptiFine.MainSwap.Visibility = If(OptiFineError Is Nothing, Visibility.Visible, Visibility.Collapsed)
|
||||
@@ -222,7 +221,7 @@ Public Class PageDownloadInstall
|
||||
End If
|
||||
End If
|
||||
'Forge
|
||||
If Not McVersion.IsFormatFit(VanillaName) Then
|
||||
If Not McVersion.IsStandardFormat(VanillaName) Then
|
||||
CardForge.Visibility = Visibility.Collapsed
|
||||
Else
|
||||
CardForge.Visibility = Visibility.Visible
|
||||
@@ -356,7 +355,7 @@ Public Class PageDownloadInstall
|
||||
''' <summary>
|
||||
''' 清空已选择的项目。
|
||||
''' </summary>
|
||||
Private Sub ClearSelected()
|
||||
Public Sub ClearSelected()
|
||||
VanillaName = Nothing
|
||||
VanillaData = Nothing
|
||||
VanillaIcon = Nothing
|
||||
@@ -367,7 +366,10 @@ Public Class PageDownloadInstall
|
||||
SelectedFabric = Nothing
|
||||
SelectedFabricApi = Nothing
|
||||
SelectedOptiFabric = Nothing
|
||||
IsSelectNameEdited = False
|
||||
For Each ClearButton In {BtnOptiFineClear, BtnLiteLoaderClear, BtnForgeClear, BtnNeoForgeClear,
|
||||
BtnFabricClear, BtnFabricApiClear, BtnOptiFabricClear}
|
||||
ClearButton.Visibility = Visibility.Collapsed
|
||||
Next
|
||||
End Sub
|
||||
'信息栏动画
|
||||
Private Sub SetPanelVisibility(Panel As Grid, IsVisible As Boolean)
|
||||
@@ -389,7 +391,7 @@ Public Class PageDownloadInstall
|
||||
''' <summary>
|
||||
''' 获取版本图标。
|
||||
''' </summary>
|
||||
Private Function GetSelectLogo() As String
|
||||
Public Overridable Function GetSelectLogo() As String
|
||||
If SelectedFabric IsNot Nothing Then
|
||||
Return "pack://application:,,,/images/Blocks/Fabric.png"
|
||||
ElseIf SelectedForge IsNot Nothing Then
|
||||
@@ -409,7 +411,7 @@ Public Class PageDownloadInstall
|
||||
''' <summary>
|
||||
''' 获取默认版本名。
|
||||
''' </summary>
|
||||
Private Function GetSelectName() As String
|
||||
Public Function GetSelectName() As String
|
||||
Dim Name As String = VanillaName
|
||||
If SelectedFabric IsNot Nothing Then Name += "-Fabric " & SelectedFabric.BeforeFirst("+")
|
||||
If SelectedForge IsNot Nothing Then Name += "-Forge_" & SelectedForge.VersionName
|
||||
@@ -418,36 +420,39 @@ Public Class PageDownloadInstall
|
||||
If SelectedOptiFine IsNot Nothing Then Name += "-OptiFine_" & SelectedOptiFine.DisplayName.Replace(VanillaName & " ", "").Replace(" ", "_")
|
||||
Return Name
|
||||
End Function
|
||||
Private IsSelectNameEdited As Boolean = False
|
||||
Private IsSelectNameChanging As Boolean = False
|
||||
Public IsSelectNameEdited As Boolean = False
|
||||
Private Sub SelectNameUpdate()
|
||||
If IsSelectNameEdited OrElse IsSelectNameChanging Then Return
|
||||
IsSelectNameChanging = True
|
||||
If IsSelectNameEdited Then Return
|
||||
TextSelectName.Text = GetSelectName()
|
||||
IsSelectNameChanging = False
|
||||
IsSelectNameEdited = False
|
||||
End Sub
|
||||
Private Sub TextSelectName_TextChanged(sender As Object, e As TextChangedEventArgs) Handles TextSelectName.TextChanged
|
||||
If IsSelectNameChanging Then Return
|
||||
IsSelectNameEdited = True
|
||||
ReloadSelected()
|
||||
End Sub
|
||||
Private Sub TextSelectName_ValidateChanged(sender As Object, e As EventArgs) Handles TextSelectName.ValidateChanged
|
||||
BtnStart.IsEnabled = TextSelectName.IsValidated
|
||||
HintSelectName.Text = TextSelectName.ValidateResult
|
||||
HintSelectName.Visibility = If(TextSelectName.IsValidated, Visibility.Collapsed, Visibility.Visible)
|
||||
End Sub
|
||||
|
||||
#End Region
|
||||
|
||||
#Region "加载器"
|
||||
Public MinecraftVersions As JArray
|
||||
Private Sub LoadMinecraft_OnFinish()
|
||||
MinecraftVersions = CType(DlClientListLoader.Output.Value("versions").DeepClone(), JArray)
|
||||
ShowMinecraftVersionList()
|
||||
TrySelectWaitingVersion() '自动选择版本
|
||||
End Sub
|
||||
|
||||
'结果数据化
|
||||
Private Sub LoadMinecraft_OnFinish()
|
||||
Public Overridable Sub ShowMinecraftVersionList()
|
||||
ExitSelectPage() '返回
|
||||
Try
|
||||
Dim Dict As New Dictionary(Of String, List(Of JObject)) From {
|
||||
{"正式版", New List(Of JObject)}, {"预览版", New List(Of JObject)}, {"远古版", New List(Of JObject)}, {"愚人节版", New List(Of JObject)}
|
||||
}
|
||||
Dim Versions As JArray = DlClientListLoader.Output.Value("versions")
|
||||
For Each Version As JObject In Versions
|
||||
For Each Version As JObject In MinecraftVersions
|
||||
'确定分类
|
||||
Dim Type As String = Version("type")
|
||||
Select Case Type
|
||||
@@ -498,7 +503,7 @@ Public Class PageDownloadInstall
|
||||
'清空当前
|
||||
PanMinecraft.Children.Clear()
|
||||
'添加最新版本
|
||||
Dim CardInfo As New MyCard With {.Title = "最新版本", .Margin = New Thickness(0, 15, 0, 15), .SwapType = 2}
|
||||
Dim CardInfo As New MyCard With {.Title = "最新版本", .Margin = New Thickness(0, 15, 0, 15)}
|
||||
Dim PinnedVersions As New List(Of JObject)
|
||||
Dim Release As JObject = Dict("正式版")(0).DeepClone()
|
||||
Release("lore") = "最新正式版,发布于 " & Release("releaseTime").Value(Of Date).ToString("yyyy'/'MM'/'dd HH':'mm")
|
||||
@@ -508,36 +513,41 @@ Public Class PageDownloadInstall
|
||||
Snapshot("lore") = "最新预览版,发布于 " & Snapshot("releaseTime").Value(Of Date).ToString("yyyy'/'MM'/'dd HH':'mm")
|
||||
PinnedVersions.Add(Snapshot)
|
||||
End If
|
||||
Dim PanInfo As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0), .Tag = PinnedVersions}
|
||||
MyCard.StackInstall(PanInfo, 7)
|
||||
Dim PanInfo As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0)}
|
||||
CardInfo.Children.Add(PanInfo)
|
||||
CardInfo.SwapControl = PanInfo
|
||||
CardInfo.SetContentBuilder(PinnedVersions, '使用 Lambda 转发点击事件,避免 #535
|
||||
Function(Version) McDownloadListItem(Version, Sub(sender, e) MinecraftSelected(sender, e), False))
|
||||
CardInfo.BuildContent()
|
||||
PanMinecraft.Children.Insert(0, CardInfo)
|
||||
'添加其他版本
|
||||
For Each Pair As KeyValuePair(Of String, List(Of JObject)) In Dict
|
||||
If Not Pair.Value.Any() Then Continue For
|
||||
'增加卡片
|
||||
Dim NewCard As New MyCard With {.Title = Pair.Key, .Margin = New Thickness(0, 0, 0, 15), .SwapType = 7}
|
||||
Dim NewStack As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0), .Tag = Pair.Value}
|
||||
Dim NewCard As New MyCard With {.Title = Pair.Key, .Margin = New Thickness(0, 0, 0, 15)}
|
||||
Dim NewStack As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0)}
|
||||
NewCard.Children.Add(NewStack)
|
||||
NewCard.SwapControl = NewStack
|
||||
NewCard.SetContentBuilder(Pair.Value,
|
||||
Function(Version) McDownloadListItem(Version, Sub(sender, e) MinecraftSelected(sender, e), False))
|
||||
NewCard.IsSwapped = True
|
||||
PanMinecraft.Children.Add(NewCard)
|
||||
Next
|
||||
'自动选择版本
|
||||
If VersionWaitingSelect Is Nothing Then Exit Try
|
||||
Logger.Info($"自动选择 MC 版本:{VersionWaitingSelect}")
|
||||
For Each Version As JObject In Versions
|
||||
If Version("id").ToString <> VersionWaitingSelect Then Continue For
|
||||
Dim Item = McDownloadListItem(Version, Sub()
|
||||
End Sub, False).Init()
|
||||
MinecraftSelected(Item, Nothing)
|
||||
VersionWaitingSelect = Nothing
|
||||
Return
|
||||
Next
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex, "可视化安装版本列表出错")
|
||||
End Try
|
||||
End Sub
|
||||
Private Sub TrySelectWaitingVersion()
|
||||
If VersionWaitingSelect Is Nothing Then Return
|
||||
For Each Version As JObject In MinecraftVersions
|
||||
If Version("id").ToString <> VersionWaitingSelect Then Continue For
|
||||
Logger.Info($"自动选择 MC 版本:{VersionWaitingSelect}")
|
||||
MinecraftSelected(McDownloadListItem(Version, Nothing, False).Init(), Nothing)
|
||||
VersionWaitingSelect = Nothing
|
||||
Return
|
||||
Next
|
||||
End Sub
|
||||
|
||||
''' <summary>
|
||||
''' 当 MC 版本列表加载完时,立即自动选择的版本。用于外部调用。
|
||||
''' </summary>
|
||||
@@ -550,16 +560,16 @@ Public Class PageDownloadInstall
|
||||
''' <summary>
|
||||
''' 获取 OptiFine 的加载异常信息。若正常则返回 Nothing。
|
||||
''' </summary>
|
||||
Private Function LoadOptiFineGetError() As String
|
||||
Public Function LoadOptiFineGetError() As String
|
||||
If SelectedNeoForge IsNot Nothing Then Return "与 NeoForge 不兼容"
|
||||
'检查 Forge 1.13 - 1.14.3:全部不兼容
|
||||
If SelectedForge IsNot Nothing AndAlso
|
||||
CompareVersion(VanillaName, "1.13") >= 0 AndAlso CompareVersion("1.14.3", VanillaName) >= 0 Then
|
||||
McUtils.CompareVersionGE(VanillaName, "1.13") AndAlso McUtils.CompareVersionGE("1.14.3", VanillaName) Then
|
||||
Return "与 Forge 不兼容"
|
||||
End If
|
||||
'检查 Fabric 1.20.5+:全部不兼容
|
||||
If SelectedFabric IsNot Nothing AndAlso
|
||||
CompareVersion(VanillaName, "1.20.4") > 0 Then
|
||||
McUtils.CompareVersion(VanillaName, "1.20.4") > 0 Then
|
||||
Return "与 Fabric 不兼容"
|
||||
End If
|
||||
'检查 Loader
|
||||
@@ -584,12 +594,12 @@ Public Class PageDownloadInstall
|
||||
End Function
|
||||
|
||||
'检查某个 OptiFine 是否与某个 Forge 兼容
|
||||
Private Function IsOptiFineSuitForForge(OptiFine As DlOptiFineListEntry, Forge As DlForgeVersionEntry)
|
||||
Public Shared Function IsOptiFineSuitForForge(OptiFine As DlOptiFineListEntry, Forge As DlForgeVersionEntry) As Boolean
|
||||
If Forge.Inherit <> OptiFine.Inherit Then Return False '不是同一个大版本
|
||||
If OptiFine.RequiredForgeVersion Is Nothing Then Return False '不兼容 Forge
|
||||
If String.IsNullOrWhiteSpace(OptiFine.RequiredForgeVersion) Then Return True '#4183
|
||||
If OptiFine.RequiredForgeVersion.Contains(".") Then 'XX.X.XXX
|
||||
Return CompareVersion(Forge.Version.ToString, OptiFine.RequiredForgeVersion) = 0
|
||||
Return McUtils.CompareVersion(Forge.Version.ToString, OptiFine.RequiredForgeVersion) = 0
|
||||
Else 'XXXX
|
||||
Return Forge.Version.Revision = OptiFine.RequiredForgeVersion
|
||||
End If
|
||||
@@ -619,7 +629,7 @@ Public Class PageDownloadInstall
|
||||
Function(Left As DlOptiFineListEntry, Right As DlOptiFineListEntry) As Boolean
|
||||
If Not Left.IsPreview AndAlso Right.IsPreview Then Return True
|
||||
If Left.IsPreview AndAlso Not Right.IsPreview Then Return False
|
||||
Return CompareVersionGE(Left.DisplayName, Right.DisplayName)
|
||||
Return McUtils.CompareVersionGE(Left.DisplayName, Right.DisplayName)
|
||||
End Function)
|
||||
'可视化
|
||||
PanOptiFine.Children.Clear()
|
||||
@@ -641,12 +651,12 @@ Public Class PageDownloadInstall
|
||||
CardOptiFine.IsSwapped = True
|
||||
ReloadSelected()
|
||||
End Sub
|
||||
Private Sub OptiFine_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnOptiFineClear.MouseLeftButtonUp
|
||||
Private Sub OptiFine_Clear(sender As Object, e As EventArgs) Handles BtnOptiFineClear.Click
|
||||
SelectedOptiFine = Nothing
|
||||
SelectedOptiFabric = Nothing
|
||||
BtnOptiFabricClear.Visibility = Visibility.Collapsed
|
||||
AutoSelectedOptiFabric = False
|
||||
CardOptiFine.IsSwapped = True
|
||||
e.Handled = True
|
||||
Forge_Loaded()
|
||||
NeoForge_Loaded()
|
||||
ReloadSelected()
|
||||
@@ -659,7 +669,7 @@ Public Class PageDownloadInstall
|
||||
''' <summary>
|
||||
''' 获取 LiteLoader 的加载异常信息。若正常则返回 Nothing。
|
||||
''' </summary>
|
||||
Private Function LoadLiteLoaderGetError() As String
|
||||
Public Function LoadLiteLoaderGetError() As String
|
||||
'检查 Loader
|
||||
If GetLoaderError(LoadLiteLoader) IsNot Nothing Then Return GetLoaderError(LoadLiteLoader)
|
||||
'检查版本
|
||||
@@ -699,10 +709,9 @@ Public Class PageDownloadInstall
|
||||
CardLiteLoader.IsSwapped = True
|
||||
ReloadSelected()
|
||||
End Sub
|
||||
Private Sub LiteLoader_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnLiteLoaderClear.MouseLeftButtonUp
|
||||
Private Sub LiteLoader_Clear(sender As Object, e As EventArgs) Handles BtnLiteLoaderClear.Click
|
||||
SelectedLiteLoader = Nothing
|
||||
CardLiteLoader.IsSwapped = True
|
||||
e.Handled = True
|
||||
ReloadSelected()
|
||||
End Sub
|
||||
|
||||
@@ -713,8 +722,8 @@ Public Class PageDownloadInstall
|
||||
''' <summary>
|
||||
''' 获取 Forge 的加载异常信息。若正常则返回 Nothing。
|
||||
''' </summary>
|
||||
Private Function LoadForgeGetError() As String
|
||||
If CompareVersionGE("1.5.1", VanillaName) AndAlso CompareVersionGE(VanillaName, "1.1") Then Return "无"
|
||||
Public Function LoadForgeGetError() As String
|
||||
If McUtils.CompareVersionGE("1.5.1", VanillaName) AndAlso McUtils.CompareVersionGE(VanillaName, "1.1") Then Return "无"
|
||||
'检查 Loader
|
||||
If GetLoaderError(LoadForge) IsNot Nothing Then Return GetLoaderError(LoadForge)
|
||||
Dim Loader As LoaderTask(Of String, List(Of DlForgeVersionEntry)) = LoadForge.State
|
||||
@@ -725,7 +734,7 @@ Public Class PageDownloadInstall
|
||||
If SelectedNeoForge IsNot Nothing Then Return "与 NeoForge 不兼容"
|
||||
If SelectedFabric IsNot Nothing Then Return "与 Fabric 不兼容"
|
||||
If SelectedOptiFine IsNot Nothing AndAlso
|
||||
CompareVersionGE(VanillaName, "1.13") AndAlso CompareVersionGE("1.14.3", VanillaName) Then
|
||||
McUtils.CompareVersionGE(VanillaName, "1.13") AndAlso McUtils.CompareVersionGE("1.14.3", VanillaName) Then
|
||||
Return "与 OptiFine 不兼容" '1.13 ~ 1.14.3 OptiFine 检查
|
||||
End If
|
||||
If SelectedOptiFine IsNot Nothing AndAlso Not IsOptiFineSuitForForge(SelectedOptiFine, Version) Then Continue For
|
||||
@@ -775,10 +784,9 @@ Public Class PageDownloadInstall
|
||||
OptiFine_Loaded()
|
||||
ReloadSelected()
|
||||
End Sub
|
||||
Private Sub Forge_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnForgeClear.MouseLeftButtonUp
|
||||
Private Sub Forge_Clear(sender As Object, e As EventArgs) Handles BtnForgeClear.Click
|
||||
SelectedForge = Nothing
|
||||
CardForge.IsSwapped = True
|
||||
e.Handled = True
|
||||
OptiFine_Loaded()
|
||||
ReloadSelected()
|
||||
End Sub
|
||||
@@ -790,7 +798,7 @@ Public Class PageDownloadInstall
|
||||
''' <summary>
|
||||
''' 获取 NeoForge 的加载异常信息。若正常则返回 Nothing。
|
||||
''' </summary>
|
||||
Private Function LoadNeoForgeGetError() As String
|
||||
Public Function LoadNeoForgeGetError() As String
|
||||
If SelectedOptiFine IsNot Nothing Then Return "与 OptiFine 不兼容"
|
||||
If SelectedForge IsNot Nothing Then Return "与 Forge 不兼容"
|
||||
If SelectedFabric IsNot Nothing Then Return "与 Fabric 不兼容"
|
||||
@@ -832,10 +840,9 @@ Public Class PageDownloadInstall
|
||||
OptiFine_Loaded()
|
||||
ReloadSelected()
|
||||
End Sub
|
||||
Private Sub NeoForge_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnNeoForgeClear.MouseLeftButtonUp
|
||||
Private Sub NeoForge_Clear(sender As Object, e As EventArgs) Handles BtnNeoForgeClear.Click
|
||||
SelectedNeoForge = Nothing
|
||||
CardNeoForge.IsSwapped = True
|
||||
e.Handled = True
|
||||
OptiFine_Loaded()
|
||||
ReloadSelected()
|
||||
End Sub
|
||||
@@ -847,9 +854,9 @@ Public Class PageDownloadInstall
|
||||
''' <summary>
|
||||
''' 获取 Fabric 的加载异常信息。若正常则返回 Nothing。
|
||||
''' </summary>
|
||||
Private Function LoadFabricGetError() As String
|
||||
Public Function LoadFabricGetError() As String
|
||||
'检查 OptiFine 1.20.5+:没有 OptiFabric 故全部不兼容
|
||||
If SelectedOptiFine IsNot Nothing AndAlso CompareVersionGE(VanillaName, "1.20.5") Then Return "与 OptiFine 不兼容"
|
||||
If SelectedOptiFine IsNot Nothing AndAlso McUtils.CompareVersionGE(VanillaName, "1.20.5") Then Return "与 OptiFine 不兼容"
|
||||
'检查 Loader
|
||||
If GetLoaderError(LoadFabric) IsNot Nothing Then Return GetLoaderError(LoadFabric)
|
||||
'检查版本
|
||||
@@ -879,9 +886,10 @@ Public Class PageDownloadInstall
|
||||
If Not Versions.Any() Then Return
|
||||
'可视化
|
||||
PanFabric.Children.Clear()
|
||||
PanFabric.Tag = Versions
|
||||
CardFabric.SwapControl = PanFabric
|
||||
CardFabric.SwapType = 12
|
||||
CardFabric.SetContentBuilder(Versions.OfType(Of JObject),
|
||||
Function(Version) FabricDownloadListItem(Version, AddressOf Fabric_Selected))
|
||||
If Not CardFabric.IsSwapped Then CardFabric.BuildContent()
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex, "可视化 Fabric 安装版本列表出错")
|
||||
End Try
|
||||
@@ -895,14 +903,15 @@ Public Class PageDownloadInstall
|
||||
CardFabric.IsSwapped = True
|
||||
ReloadSelected()
|
||||
End Sub
|
||||
Private Sub Fabric_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnFabricClear.MouseLeftButtonUp
|
||||
Private Sub Fabric_Clear(sender As Object, e As EventArgs) Handles BtnFabricClear.Click
|
||||
SelectedFabric = Nothing
|
||||
SelectedFabricApi = Nothing
|
||||
BtnFabricApiClear.Visibility = Visibility.Collapsed
|
||||
AutoSelectedFabricApi = False
|
||||
SelectedOptiFabric = Nothing
|
||||
BtnOptiFabricClear.Visibility = Visibility.Collapsed
|
||||
AutoSelectedOptiFabric = False
|
||||
CardFabric.IsSwapped = True
|
||||
e.Handled = True
|
||||
ReloadSelected()
|
||||
End Sub
|
||||
|
||||
@@ -911,14 +920,14 @@ Public Class PageDownloadInstall
|
||||
#Region "Fabric API 列表"
|
||||
|
||||
''' <summary>
|
||||
''' 判断某 Fabric API 是否适配当前选择的原版版本。
|
||||
''' 判断某 Fabric API 是否适配指定的原版版本。
|
||||
''' </summary>
|
||||
Public Function IsFabricApiCompatible(FabricApi As ResourceVersion) As Boolean
|
||||
Public Shared Function IsFabricApiCompatible(FabricApi As ResourceVersion, MinecraftVersion As String) As Boolean
|
||||
Dim FabricApiName = FabricApi.Display
|
||||
Try
|
||||
If FabricApiName Is Nothing OrElse VanillaName Is Nothing Then Return False
|
||||
If FabricApiName Is Nothing OrElse MinecraftVersion Is Nothing Then Return False
|
||||
FabricApiName = FabricApiName.Lower
|
||||
Dim TargetName = VanillaName.Replace("∞", "infinite").Replace("Combat Test 7c", "1.16_combat-3").Lower
|
||||
Dim TargetName = MinecraftVersion.Replace("∞", "infinite").Replace("Combat Test 7c", "1.16_combat-3").Lower
|
||||
If FabricApiName.StartsWithF("[" & TargetName & "]") Then Return True
|
||||
If Not FabricApiName.Contains("/") OrElse Not FabricApiName.Contains("]") Then Return False
|
||||
'直接的判断(例如 1.18.1/22w03a)
|
||||
@@ -946,7 +955,7 @@ Public Class PageDownloadInstall
|
||||
End While
|
||||
Return True
|
||||
Catch ex As Exception
|
||||
Logger.Warn(ex, $"判断 Fabric API 版本适配性出错({FabricApiName}, {VanillaName})")
|
||||
Logger.Warn(ex, $"判断 Fabric API 版本适配性出错({FabricApiName}, {MinecraftVersion})")
|
||||
Return False
|
||||
End Try
|
||||
End Function
|
||||
@@ -954,12 +963,12 @@ Public Class PageDownloadInstall
|
||||
''' <summary>
|
||||
''' 获取 FabricApi 的加载异常信息。若正常则返回 Nothing。
|
||||
''' </summary>
|
||||
Private Function LoadFabricApiGetError() As String
|
||||
Public Function LoadFabricApiGetError() As String
|
||||
'检查 Loader
|
||||
If GetLoaderError(LoadFabricApi) IsNot Nothing Then Return GetLoaderError(LoadFabricApi)
|
||||
If DlFabricApiLoader.Output Is Nothing Then Return If(SelectedFabric Is Nothing, "需要安装 Fabric", "获取中……")
|
||||
'检查版本
|
||||
If DlFabricApiLoader.Output.Any(Function(f) IsFabricApiCompatible(f)) Then
|
||||
If DlFabricApiLoader.Output.Any(Function(f) IsFabricApiCompatible(f, VanillaName)) Then
|
||||
Return If(SelectedFabric Is Nothing, "需要安装 Fabric", Nothing)
|
||||
Else
|
||||
Return "无"
|
||||
@@ -971,7 +980,7 @@ Public Class PageDownloadInstall
|
||||
If LoadFabricApiGetError() IsNot Nothing Then e.Handled = True
|
||||
End Sub
|
||||
|
||||
Private AutoSelectedFabricApi As Boolean = False
|
||||
Public AutoSelectedFabricApi As Boolean = False
|
||||
''' <summary>
|
||||
''' 尝试重新可视化 FabricApi 版本列表。
|
||||
''' </summary>
|
||||
@@ -982,7 +991,7 @@ Public Class PageDownloadInstall
|
||||
'获取版本列表
|
||||
Dim Versions As New List(Of ResourceVersion)
|
||||
For Each Version In DlFabricApiLoader.Output
|
||||
If IsFabricApiCompatible(Version) Then
|
||||
If IsFabricApiCompatible(Version, VanillaName) Then
|
||||
If Not Version.Display.StartsWithF("[") Then
|
||||
Logger.Warn($"已特判修改 Fabric API 显示名:{Version.Display}")
|
||||
Version.Display = "[" & VanillaName & "] " & Version.Display
|
||||
@@ -995,7 +1004,6 @@ Public Class PageDownloadInstall
|
||||
'可视化
|
||||
PanFabricApi.Children.Clear()
|
||||
For Each Version In Versions
|
||||
If Not IsFabricApiCompatible(Version) Then Continue For
|
||||
PanFabricApi.Children.Add(FabricApiDownloadListItem(Version, AddressOf FabricApi_Selected))
|
||||
Next
|
||||
'自动选择 Fabric API
|
||||
@@ -1016,10 +1024,9 @@ Public Class PageDownloadInstall
|
||||
CardFabricApi.IsSwapped = True
|
||||
ReloadSelected()
|
||||
End Sub
|
||||
Private Sub FabricApi_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnFabricApiClear.MouseLeftButtonUp
|
||||
Private Sub FabricApi_Clear(sender As Object, e As EventArgs) Handles BtnFabricApiClear.Click
|
||||
SelectedFabricApi = Nothing
|
||||
CardFabricApi.IsSwapped = True
|
||||
e.Handled = True
|
||||
ReloadSelected()
|
||||
End Sub
|
||||
|
||||
@@ -1028,23 +1035,23 @@ Public Class PageDownloadInstall
|
||||
#Region "OptiFabric 列表"
|
||||
|
||||
''' <summary>
|
||||
''' 判断某 OptiFabric 是否适配当前选择的原版版本。
|
||||
''' 判断某 OptiFabric 是否适配指定的原版版本。
|
||||
''' </summary>
|
||||
Private Function IsOptiFabricCompatible(ModFile As ResourceVersion) As Boolean
|
||||
Public Shared Function IsOptiFabricCompatible(ModFile As ResourceVersion, MinecraftVersion As String) As Boolean
|
||||
Try
|
||||
If VanillaName Is Nothing Then Return False
|
||||
Return ModFile.GameVersions.Contains(VanillaName)
|
||||
If MinecraftVersion Is Nothing Then Return False
|
||||
Return ModFile.GameVersions.Contains(MinecraftVersion)
|
||||
Catch ex As Exception
|
||||
Logger.Warn(ex, $"判断 OptiFabric 版本适配性出错({VanillaName})")
|
||||
Logger.Warn(ex, $"判断 OptiFabric 版本适配性出错({MinecraftVersion})")
|
||||
Return False
|
||||
End Try
|
||||
End Function
|
||||
|
||||
Private AutoSelectedOptiFabric As Boolean = False
|
||||
Public AutoSelectedOptiFabric As Boolean = False
|
||||
''' <summary>
|
||||
''' 获取 OptiFabric 的加载异常信息。若正常则返回 Nothing。
|
||||
''' </summary>
|
||||
Private Function LoadOptiFabricGetError() As String
|
||||
Public Function LoadOptiFabricGetError() As String
|
||||
If VanillaDrop >= 140 AndAlso VanillaDrop <= 150 Then Return "不兼容老版本 Fabric,请手动下载 OptiFabric Origins"
|
||||
'检查 Loader
|
||||
If GetLoaderError(LoadOptiFabric) IsNot Nothing Then Return GetLoaderError(LoadOptiFabric)
|
||||
@@ -1056,7 +1063,7 @@ Public Class PageDownloadInstall
|
||||
Return "获取中……"
|
||||
End If
|
||||
For Each Version In DlOptiFabricLoader.Output
|
||||
If Not IsOptiFabricCompatible(Version) Then Continue For '2135#
|
||||
If Not IsOptiFabricCompatible(Version, VanillaName) Then Continue For '2135#
|
||||
If SelectedFabric Is Nothing AndAlso SelectedOptiFine Is Nothing Then Return "需要安装 OptiFine 与 Fabric"
|
||||
If SelectedFabric Is Nothing Then Return "需要安装 Fabric"
|
||||
If SelectedOptiFine Is Nothing Then Return "需要安装 OptiFine"
|
||||
@@ -1080,7 +1087,7 @@ Public Class PageDownloadInstall
|
||||
'获取版本列表
|
||||
Dim Versions As New List(Of ResourceVersion)
|
||||
For Each Version In DlOptiFabricLoader.Output
|
||||
If IsOptiFabricCompatible(Version) Then Versions.Add(Version)
|
||||
If IsOptiFabricCompatible(Version, VanillaName) Then Versions.Add(Version)
|
||||
Next
|
||||
If Not Versions.Any() Then Return
|
||||
'排序
|
||||
@@ -1088,7 +1095,6 @@ Public Class PageDownloadInstall
|
||||
'可视化
|
||||
PanOptiFabric.Children.Clear()
|
||||
For Each Version In Versions
|
||||
If Not IsOptiFabricCompatible(Version) Then Continue For
|
||||
PanOptiFabric.Children.Add(OptiFabricDownloadListItem(Version, AddressOf OptiFabric_Selected))
|
||||
Next
|
||||
'自动选择 OptiFabric
|
||||
@@ -1108,10 +1114,9 @@ Public Class PageDownloadInstall
|
||||
CardOptiFabric.IsSwapped = True
|
||||
ReloadSelected()
|
||||
End Sub
|
||||
Private Sub OptiFabric_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnOptiFabricClear.MouseLeftButtonUp
|
||||
Private Sub OptiFabric_Clear(sender As Object, e As EventArgs) Handles BtnOptiFabricClear.Click
|
||||
SelectedOptiFabric = Nothing
|
||||
CardOptiFabric.IsSwapped = True
|
||||
e.Handled = True
|
||||
ReloadSelected()
|
||||
End Sub
|
||||
|
||||
@@ -1119,10 +1124,42 @@ Public Class PageDownloadInstall
|
||||
|
||||
#Region "安装"
|
||||
|
||||
''' <summary>
|
||||
''' 获取当前选择的组件信息。
|
||||
''' </summary>
|
||||
Public Function GetSelectedComponents() As McComponents
|
||||
Return New McComponents(
|
||||
minecraftVersion:=VanillaName,
|
||||
optiFineEntry:=If(SelectedOptiFine Is Nothing, Nothing, JObject.FromObject(SelectedOptiFine)),
|
||||
forgeVersion:=SelectedForge?.VersionName,
|
||||
neoForgeVersion:=SelectedNeoForge?.VersionName,
|
||||
fabricVersion:=SelectedFabric,
|
||||
fabricApiVersion:=If(SelectedFabricApi?.Version, If(SelectedFabricApi?.Id, SelectedFabricApi?.Display)),
|
||||
optiFabricVersion:=If(SelectedOptiFabric?.Version, If(SelectedOptiFabric?.Id, SelectedOptiFabric?.Display)),
|
||||
liteLoaderVersion:=SelectedLiteLoader?.JsonToken?("version").ToString())
|
||||
End Function
|
||||
|
||||
Private Sub TextSelectName_KeyDown(sender As Object, e As KeyEventArgs) Handles TextSelectName.KeyDown
|
||||
If e.Key = Key.Enter AndAlso IsInSelectPage AndAlso BtnStart.IsEnabled Then BtnStart_Click()
|
||||
End Sub
|
||||
Private Sub BtnStart_Click() Handles BtnStart.Click
|
||||
'提交安装申请
|
||||
Dim InstanceName As String = TextSelectName.Text
|
||||
Dim Request As New McInstallRequest With {
|
||||
.NewInstanceName = InstanceName,
|
||||
.InstanceFolder = $"{McFolderSelected}versions\{InstanceName}\",
|
||||
.Components = GetSelectedComponents(),
|
||||
.MinecraftJson = VanillaData("url").ToString,
|
||||
.ForgeEntry = SelectedForge,
|
||||
.NeoForgeEntry = SelectedNeoForge,
|
||||
.FabricApi = SelectedFabricApi,
|
||||
.OptiFabric = SelectedOptiFabric,
|
||||
.LiteLoaderEntry = SelectedLiteLoader
|
||||
}
|
||||
StartInstall(Request)
|
||||
End Sub
|
||||
|
||||
Public Overridable Sub StartInstall(Request As McInstallRequest)
|
||||
'确认版本隔离
|
||||
If (SelectedForge IsNot Nothing OrElse SelectedNeoForge IsNot Nothing OrElse SelectedFabric IsNot Nothing) AndAlso
|
||||
(Settings.Get(Of Integer)("LaunchArgumentIndieV2") = 0 OrElse Settings.Get(Of Integer)("LaunchArgumentIndieV2") = 2) Then
|
||||
@@ -1132,22 +1169,7 @@ Public Class PageDownloadInstall
|
||||
Return
|
||||
End If
|
||||
End If
|
||||
'提交安装申请
|
||||
Dim InstanceName As String = TextSelectName.Text
|
||||
Dim Request As New McInstallRequest With {
|
||||
.NewInstanceName = InstanceName,
|
||||
.VersionFolder = $"{McFolderSelected}versions\{InstanceName}\",
|
||||
.MinecraftJson = VanillaData("url").ToString,
|
||||
.MinecraftName = VanillaName,
|
||||
.OptiFineEntry = SelectedOptiFine,
|
||||
.ForgeEntry = SelectedForge,
|
||||
.NeoForgeEntry = SelectedNeoForge,
|
||||
.FabricVersion = SelectedFabric,
|
||||
.FabricApi = SelectedFabricApi,
|
||||
.OptiFabric = SelectedOptiFabric,
|
||||
.LiteLoaderEntry = SelectedLiteLoader
|
||||
}
|
||||
If Not McInstall(Request) Then Return
|
||||
If Not McInstallStart(Request) Then Return
|
||||
'返回,这样在再次进入安装页面时这个版本就会显示文件夹已重复
|
||||
ExitSelectPage()
|
||||
End Sub
|
||||
|
||||
@@ -0,0 +1,727 @@
|
||||
''' <summary>
|
||||
''' 版本修改页:完整还原已安装组件后,复用安装页的选择交互。
|
||||
''' </summary>
|
||||
Public Class PageDownloadModify
|
||||
Inherits PageDownloadInstall
|
||||
|
||||
Private InitLoader As LoaderTask(Of McInstance, Object)
|
||||
Private ForgeVersionLoader As LoaderTask(Of String, List(Of DlForgeVersionEntry))
|
||||
Private InitialTarget As McComponents '进入时的组件快照
|
||||
''' <summary>
|
||||
''' 原版的版本号是否可靠(不是通过 json 模糊分析)。
|
||||
''' </summary>
|
||||
Private IsVanillaVersionReliable As Boolean
|
||||
Private OriginalName As String
|
||||
Private CustomLogo As String
|
||||
''' <summary>
|
||||
''' 开始修改 MC 版本时,记录当前选择的组件,以在修改 MC 版本后尝试自动选中相同组件。
|
||||
''' </summary>
|
||||
Private ReadOnly PendingComponents As New Dictionary(Of MyLoading, String)
|
||||
Private IsRestoringComponents As Boolean
|
||||
|
||||
Public Overrides Sub LoaderInit() '父级 Handles Me.Initialized
|
||||
ControlInit()
|
||||
InitLoader = New LoaderTask(Of McInstance, Object)("初始化版本修改", AddressOf LoadInstance)
|
||||
PageLoaderInit(LoadMinecraft, PanLoad, PanAllBack, Nothing, InitLoader, AddressOf LoadInstanceFinished, Function() PageInstanceLeft.Instance)
|
||||
End Sub
|
||||
Public Overrides Sub Init() '父级 Handles Me.Loaded
|
||||
PanBack.ScrollToHome()
|
||||
Static IsLoad As Boolean = False
|
||||
If IsLoad Then PageLoaderRestart()
|
||||
IsLoad = True
|
||||
End Sub
|
||||
Private Sub PageUnloaded() Handles Me.Unloaded
|
||||
InitLoader.Cancel()
|
||||
End Sub
|
||||
|
||||
''' <summary>
|
||||
''' 读取或初始化版本的安装清单。
|
||||
''' </summary>
|
||||
Private Sub LoadInstance(Task As LoaderTask(Of McInstance, Object))
|
||||
|
||||
'旧状态清理
|
||||
RunInUiWait(
|
||||
Sub()
|
||||
AniStop("FrmDownloadInstall SelectPageSwitch")
|
||||
IsSelectNameEdited = False
|
||||
ClearSelected()
|
||||
PendingComponents.Clear()
|
||||
InitialTarget = Nothing
|
||||
IsInSelectPage = False
|
||||
PanAllBack.IsHitTestVisible = False
|
||||
End Sub)
|
||||
Task.Input.Config.DiscardCache()
|
||||
|
||||
'获取 Components
|
||||
Dim Manifest = Configs.McInstallManifest.Get(Task.Input.Config)
|
||||
If Manifest IsNot Nothing AndAlso Manifest.SchemaVersion > Versions.McInstallManifestVersion Then
|
||||
Logger.Warn($"安装清单由更新版本的 PCL 创建(清单版本:{Manifest.SchemaVersion},当前版本:{Versions.McInstallManifestVersion})")
|
||||
Throw New Exception($"更新 PCL 后才能修改它!点击【设置 → 其他 → 检查更新】以更新。")
|
||||
End If
|
||||
If Manifest IsNot Nothing Then
|
||||
Dim LatestManifest = Manifest.RefreshModComponents(Task.Input.PathIndie)
|
||||
If LatestManifest IsNot Manifest Then
|
||||
Manifest = LatestManifest
|
||||
Configs.McInstallManifest.Set(Manifest, Task.Input.Config)
|
||||
Task.Input.Config.Save()
|
||||
End If
|
||||
End If
|
||||
Dim Components As McComponents
|
||||
Dim OptiFineVersion As String = Nothing
|
||||
If Manifest IsNot Nothing Then
|
||||
'有清单:从清单读取
|
||||
Components = Manifest.Components
|
||||
If Components Is Nothing Then Throw New Exception("安装清单缺少组件信息,无法还原已安装组件。")
|
||||
IsVanillaVersionReliable = True
|
||||
Else
|
||||
'无清单:通过版本 JSON 获取
|
||||
Dim VersionInfo = New McInstance(Task.Input.PathVersion).Version
|
||||
If VersionInfo.VanillaName = "Unknown" Then Throw New Exception("无法确定 Minecraft 版本,无法修改")
|
||||
Dim UnknownLoaders = VersionInfo.ModLoaderVersions.
|
||||
Where(Function(Loader) String.IsNullOrWhiteSpace(Loader.Value) OrElse Loader.Value = "未知版本").
|
||||
Select(Function(Loader) Loader.Key.ToString()).ToList()
|
||||
If UnknownLoaders.Any() Then Throw New Exception($"无法确定 {UnknownLoaders.Join("、")} 的版本,无法修改")
|
||||
Components = New McComponents(VersionInfo.VanillaName, VersionInfo.ModLoaderVersions)
|
||||
OptiFineVersion = VersionInfo.OptiFine
|
||||
IsVanillaVersionReliable = VersionInfo.Reliable
|
||||
End If
|
||||
Dim MinecraftVersion = Components.MinecraftVersion
|
||||
If String.IsNullOrWhiteSpace(MinecraftVersion) Then Throw New Exception("无法确定当前 Minecraft 版本,请检查版本文件")
|
||||
'等待子列表加载器完成获取
|
||||
Dim LoaderList As New Dictionary(Of String, LoaderBase) From {
|
||||
{"Minecraft", DlClientListLoader}, {"OptiFine", DlOptiFineListLoader}, {"LiteLoader", DlLiteLoaderListLoader},
|
||||
{"NeoForge", DlNeoForgeListLoader}, {"Fabric", DlFabricListLoader}, {"Fabric API", DlFabricApiLoader}, {"OptiFabric", DlOptiFabricLoader}}
|
||||
Dim ForgeLoader As LoaderTask(Of String, List(Of DlForgeVersionEntry)) = Nothing
|
||||
If McVersion.IsStandardFormat(MinecraftVersion) Then
|
||||
ForgeLoader = New LoaderTask(Of String, List(Of DlForgeVersionEntry))("DlForgeVersion " & MinecraftVersion, AddressOf DlForgeVersionMain)
|
||||
LoaderList.Add("Forge", ForgeLoader)
|
||||
End If
|
||||
For Each Loader In LoaderList.Values
|
||||
Loader.Start(If(Loader Is ForgeLoader, MinecraftVersion, Nothing), Task.IsForceRestarting)
|
||||
Next
|
||||
Do
|
||||
If Task.IsCanceled Then Return
|
||||
For Each Pair In LoaderList
|
||||
Dim Loader = Pair.Value
|
||||
If Loader.State = LoadState.Failed Then
|
||||
If Loader Is ForgeLoader AndAlso Loader.Error.Message = "无" Then Continue For 'Forge 无版本时不报错
|
||||
Throw New Exception($"获取 {Pair.Key} 版本列表失败,请稍后再试,或使用 VPN 改善网络环境", Loader.Error)
|
||||
ElseIf Loader.State = LoadState.Canceled Then
|
||||
Throw New Exception($"获取 {Pair.Key} 版本列表被中断,请稍后再试,或使用 VPN 改善网络环境")
|
||||
End If
|
||||
Next
|
||||
If LoaderList.Values.All(Function(Loader) Loader.State = LoadState.Finished OrElse Loader.State = LoadState.Failed) Then Exit Do
|
||||
Task.Progress = 0.7 * LoaderList.Values.Average(Function(Loader) Loader.Progress)
|
||||
Thread.Sleep(10)
|
||||
Loop
|
||||
If Task.IsCanceled Then Return
|
||||
Task.Progress = 0.7
|
||||
'Minecraft
|
||||
MinecraftVersions = CType(DlClientListLoader.Output.Value("versions").DeepClone(), JArray)
|
||||
VanillaData = MinecraftVersions.OfType(Of JObject).FirstOrDefault(
|
||||
Function(v) v("id").ToString.Replace("∞", "infinite") = MinecraftVersion.Replace("∞", "infinite"))
|
||||
If VanillaData Is Nothing Then Throw New Exception($"Minecraft 列表中没有已安装的 {MinecraftVersion}")
|
||||
VanillaData("id") = MinecraftVersion
|
||||
'OptiFine
|
||||
If Manifest IsNot Nothing Then
|
||||
SelectedOptiFine = Components.OptiFineEntry?.ToObject(Of DlOptiFineListEntry)()
|
||||
If SelectedOptiFine IsNot Nothing AndAlso Not DlOptiFineListLoader.Output.Value.Any(Function(v) v.FileName = SelectedOptiFine.FileName) Then
|
||||
'如果 OptiFine 是 pre 版,可能只在 BMCLAPI 下有,官方源删了。如果是这种缺失数据的情况,换用 BMCLAPI 源作为输出
|
||||
If DlOptiFineListBmclapiLoader.State <> LoadState.Finished Then DlOptiFineListBmclapiLoader.WaitForExit()
|
||||
DlOptiFineListLoader.Output = DlOptiFineListBmclapiLoader.Output
|
||||
End If
|
||||
ElseIf OptiFineVersion IsNot Nothing AndAlso OptiFineVersion <> "未知版本" Then
|
||||
SelectedOptiFine = DlOptiFineListLoader.Output.Value.FirstOrDefault(
|
||||
Function(v) v.Inherit = MinecraftVersion AndAlso
|
||||
v.InstanceName.AfterLast("-OptiFine_").Replace("HD_U_", "") = OptiFineVersion.Replace("HD_U_", ""))
|
||||
If SelectedOptiFine Is Nothing Then Throw New Exception($"OptiFine 列表中没有已安装的 {OptiFineVersion}")
|
||||
End If
|
||||
'Forge
|
||||
If Components.ModLoaderVersions.ContainsKey(ModLoaders.Forge) Then
|
||||
SelectedForge = ForgeLoader?.Output?.FirstOrDefault(
|
||||
Function(v) v.Inherit = MinecraftVersion AndAlso v.VersionName = Components.ModLoaderVersions(ModLoaders.Forge) AndAlso
|
||||
v.Category <> "universal" AndAlso v.Category <> "client" AndAlso (SelectedOptiFine Is Nothing OrElse IsOptiFineSuitForForge(SelectedOptiFine, v)))
|
||||
If SelectedForge Is Nothing Then Throw New Exception($"Forge 列表中没有已安装的 {Components.ModLoaderVersions(ModLoaders.Forge)}")
|
||||
End If
|
||||
'NeoForge
|
||||
If Components.ModLoaderVersions.ContainsKey(ModLoaders.NeoForge) Then
|
||||
SelectedNeoForge = DlNeoForgeListLoader.Output.Value.FirstOrDefault(
|
||||
Function(v) v.Inherit = MinecraftVersion AndAlso v.VersionName = Components.ModLoaderVersions(ModLoaders.NeoForge))
|
||||
If SelectedNeoForge Is Nothing Then Throw New Exception($"NeoForge 列表中没有已安装的 {Components.ModLoaderVersions(ModLoaders.NeoForge)}")
|
||||
End If
|
||||
'Fabric
|
||||
If Components.ModLoaderVersions.ContainsKey(ModLoaders.Fabric) Then
|
||||
Dim FabricEntry = DlFabricListLoader.Output.Value("loader").OfType(Of JObject).FirstOrDefault(
|
||||
Function(v) v("version").ToString = Components.ModLoaderVersions(ModLoaders.Fabric),
|
||||
Function(v) v("version").ToString.Replace("+build", "") = Components.ModLoaderVersions(ModLoaders.Fabric))
|
||||
If FabricEntry Is Nothing OrElse Not DlFabricListLoader.Output.Value("game").OfType(Of JObject).
|
||||
Any(Function(v) v("version").ToString = MinecraftVersion.Replace("∞", "infinite").Replace("Combat Test 7c", "1.16_combat-3")) Then
|
||||
Throw New Exception($"Fabric 列表中没有已安装的 {Components.ModLoaderVersions(ModLoaders.Fabric)}")
|
||||
End If
|
||||
SelectedFabric = FabricEntry("version").ToString
|
||||
End If
|
||||
'LiteLoader
|
||||
If Components.ModLoaderVersions.ContainsKey(ModLoaders.LiteLoader) Then
|
||||
SelectedLiteLoader = DlLiteLoaderListLoader.Output.Value.FirstOrDefault(
|
||||
Function(v) v.Inherit = MinecraftVersion AndAlso v.JsonToken("version").ToString = Components.ModLoaderVersions(ModLoaders.LiteLoader))
|
||||
If SelectedLiteLoader Is Nothing Then Throw New Exception($"LiteLoader 列表中没有已安装的 {Components.ModLoaderVersions(ModLoaders.LiteLoader)}")
|
||||
End If
|
||||
'Fabric API
|
||||
If Components.FabricApiVersion IsNot Nothing Then
|
||||
SelectedFabricApi = DlFabricApiLoader.Output.FirstOrDefault(
|
||||
Function(v) (v.Version = Components.FabricApiVersion OrElse v.Id = Components.FabricApiVersion OrElse
|
||||
v.Display = Components.FabricApiVersion) AndAlso IsFabricApiCompatible(v, MinecraftVersion))
|
||||
If SelectedFabricApi Is Nothing Then Throw New Exception($"Fabric API 列表中没有已安装的 {Components.FabricApiVersion}")
|
||||
End If
|
||||
'OptiFabric
|
||||
If Components.OptiFabricVersion IsNot Nothing Then
|
||||
SelectedOptiFabric = DlOptiFabricLoader.Output.FirstOrDefault(
|
||||
Function(v) (v.Version = Components.OptiFabricVersion OrElse v.Id = Components.OptiFabricVersion OrElse
|
||||
v.Display = Components.OptiFabricVersion) AndAlso IsOptiFabricCompatible(v, MinecraftVersion))
|
||||
If SelectedOptiFabric Is Nothing Then Throw New Exception($"OptiFabric 列表中没有已安装的 {Components.OptiFabricVersion}")
|
||||
End If
|
||||
|
||||
'扫描尚未识别的 Mod 组件
|
||||
Dim ManagedFiles As New List(Of McInstallManifest.ManagedFile)
|
||||
If Manifest IsNot Nothing Then ManagedFiles.AddRange(Manifest.ManagedFiles)
|
||||
|
||||
#Region "从 mods 文件夹中获取以 Mod 形式安装的组件信息"
|
||||
|
||||
'获取 mods 文件夹下的 jar 文件与 SHA1
|
||||
Dim Mods As New Lazy(Of List(Of (File As FileInfo, Sha1 As String)))(
|
||||
Function()
|
||||
Dim ModsFolder = Task.Input.PathIndie & "mods\"
|
||||
Dim Files = DirectoryUtils.EnumerateFiles(ModsFolder, searchPattern:="*.jar").ToList()
|
||||
If SelectedLiteLoader IsNot Nothing Then 'LiteLoader 的 OptiFine 安装目录
|
||||
Files.AddRange(DirectoryUtils.EnumerateFiles(Path.Combine(ModsFolder, MinecraftVersion), searchPattern:="*.jar"))
|
||||
End If
|
||||
Dim Entries As New List(Of (File As FileInfo, Sha1 As String))
|
||||
For Each FilePath In Files
|
||||
If Task.IsCanceled Then Return Entries
|
||||
Dim File = FileUtils.GetInfo(FilePath)
|
||||
Entries.Add((File, New LocalResourceFile(File).ModrinthHash))
|
||||
Task.Progress = 0.7 + 0.28 * Entries.Count / Files.Count
|
||||
Next
|
||||
Return Entries
|
||||
End Function)
|
||||
'Fabric API
|
||||
If SelectedFabric IsNot Nothing AndAlso SelectedFabricApi Is Nothing Then
|
||||
Dim FabricApiList = DlFabricApiLoader.Output.Where(Function(v) IsFabricApiCompatible(v, MinecraftVersion)).ToList()
|
||||
Dim Matches As New List(Of (File As FileInfo, Sha1 As String, Version As ResourceVersion))
|
||||
For Each Entry In Mods.Value
|
||||
Dim Match = FabricApiList.FirstOrDefault(Function(v) v.Hash = Entry.Sha1)
|
||||
If Match Is Nothing Then Continue For
|
||||
Matches.Add((Entry.File, Entry.Sha1, Match))
|
||||
Next
|
||||
Dim SelectedFile = SelectMod("Fabric API", Matches)
|
||||
If SelectedFile IsNot Nothing Then
|
||||
SelectedFabricApi = SelectedFile.Value.Version
|
||||
ManagedFiles.Add(New McInstallManifest.ManagedFile("mods/" & SelectedFile.Value.File.Name.Lower(), SelectedFile.Value.Sha1, SelectedFile.Value.File.LastWriteTimeUtc, "FabricApi"))
|
||||
End If
|
||||
End If
|
||||
If Task.IsCanceled Then Return
|
||||
'OptiFabric
|
||||
If SelectedFabric IsNot Nothing AndAlso SelectedOptiFabric Is Nothing Then
|
||||
Dim OptiFabricList = DlOptiFabricLoader.Output.Where(Function(v) IsOptiFabricCompatible(v, MinecraftVersion)).ToList()
|
||||
Dim HasMd5 = OptiFabricList.Any(Function(v) If(v.Hash, "").Length = 32) 'CurseForge 的 OptiFabric 信息可能提供 SHA1 或 MD5
|
||||
Dim Matches As New List(Of (File As FileInfo, Sha1 As String, Version As ResourceVersion))
|
||||
For Each Entry In Mods.Value
|
||||
Dim Match = OptiFabricList.FirstOrDefault(Function(v) v.Hash = Entry.Sha1)
|
||||
If Match Is Nothing AndAlso HasMd5 Then
|
||||
Dim Md5 = CryptographyUtils.ComputeFileHash(Entry.File.FullName, CryptographyUtils.HashMethod.Md5)
|
||||
Match = OptiFabricList.FirstOrDefault(Function(v) v.Hash = Md5)
|
||||
End If
|
||||
If Match Is Nothing Then Continue For
|
||||
Matches.Add((Entry.File, Entry.Sha1, Match))
|
||||
Next
|
||||
Dim SelectedFile = SelectMod("OptiFabric", Matches)
|
||||
If SelectedFile IsNot Nothing Then
|
||||
SelectedOptiFabric = SelectedFile.Value.Version
|
||||
ManagedFiles.Add(New McInstallManifest.ManagedFile("mods/" & SelectedFile.Value.File.Name.Lower(), SelectedFile.Value.Sha1, SelectedFile.Value.File.LastWriteTimeUtc, "OptiFabric"))
|
||||
End If
|
||||
End If
|
||||
If Task.IsCanceled Then Return
|
||||
'OptiFine
|
||||
Dim OptiFineFiles As New List(Of (File As FileInfo, Sha1 As String, OriginalName As String))
|
||||
If SelectedOptiFine Is Nothing AndAlso (SelectedForge IsNot Nothing OrElse SelectedLiteLoader IsNot Nothing OrElse SelectedFabric IsNot Nothing) Then 'OptiFine 只在有 Mod 加载器时才看在不在 mods 文件夹中
|
||||
Static OptiFineHashes As JObject = FileUtils.ReadAsJson("Minecraft\OptiFineHashes.json", type:=GetType(Resource)) 'JSON 内容:{"SHA1": "原始文件名", ...}
|
||||
OptiFineFiles = Mods.Value.
|
||||
Select(Function(Entry) (Entry.File, Entry.Sha1, OriginalName:=OptiFineHashes(Entry.Sha1)?.ToString())). '用本地文件的 SHA1 匹配下载时的原始文件名,再根据原始文件名取得下载源信息
|
||||
Where(Function(Entry) Entry.OriginalName IsNot Nothing).ToList()
|
||||
Dim Matches As New List(Of (File As FileInfo, Sha1 As String, Version As DlOptiFineListEntry))
|
||||
For Each Entry In OptiFineFiles '遍历 hash 匹配到了的本地文件
|
||||
Dim Match = DlOptiFineListLoader.Output.Value.FirstOrDefault(
|
||||
Function(v) v.Inherit = MinecraftVersion AndAlso v.FileName = Entry.OriginalName AndAlso (SelectedForge Is Nothing OrElse IsOptiFineSuitForForge(v, SelectedForge)))
|
||||
If Match Is Nothing Then
|
||||
Hint($"无法从 OptiFine 列表还原 {Entry.File.Name} 对应的 {Entry.OriginalName},将跳过该文件。")
|
||||
Continue For
|
||||
End If
|
||||
Matches.Add((Entry.File, Entry.Sha1, Match))
|
||||
Next
|
||||
Dim SelectedFile = SelectMod("OptiFine", Matches)
|
||||
If SelectedFile IsNot Nothing Then
|
||||
SelectedOptiFine = SelectedFile.Value.Version
|
||||
Dim RelativePath = PathUtils.RemoveExtendedPrefix(SelectedFile.Value.File.FullName).Substring(Task.Input.PathIndie.Length).Replace("\", "/").Lower()
|
||||
ManagedFiles.Add(New McInstallManifest.ManagedFile(RelativePath, SelectedFile.Value.Sha1, SelectedFile.Value.File.LastWriteTimeUtc, "OptiFine"))
|
||||
End If
|
||||
End If
|
||||
If Task.IsCanceled Then Return
|
||||
|
||||
#End Region
|
||||
|
||||
'保存 Manifest
|
||||
If IsVanillaVersionReliable Then
|
||||
Components = New McComponents(MinecraftVersion, Components.ModLoaderVersions,
|
||||
If(SelectedOptiFine Is Nothing, Nothing, JObject.FromObject(SelectedOptiFine)),
|
||||
If(SelectedFabricApi?.Version, If(SelectedFabricApi?.Id, SelectedFabricApi?.Display)),
|
||||
If(SelectedOptiFabric?.Version, If(SelectedOptiFabric?.Id, SelectedOptiFabric?.Display)))
|
||||
If Manifest Is Nothing OrElse Not Components.IsEquivalentTo(Manifest.Components) OrElse Not ManagedFiles.SequenceEqual(Manifest.ManagedFiles) Then
|
||||
Configs.McInstallManifest.Set(New McInstallManifest(Versions.McInstallManifestVersion, Components, Date.UtcNow, ManagedFiles), Task.Input.Config)
|
||||
Task.Input.Config.Save()
|
||||
Logger.Info($"已为 {Task.Input.Name} 更新安装清单")
|
||||
End If
|
||||
End If
|
||||
If Task.IsCanceled Then Return
|
||||
ForgeVersionLoader = ForgeLoader
|
||||
End Sub
|
||||
Private Function SelectMod(Of T)(ComponentName As String, Matches As List(Of (File As FileInfo, Sha1 As String, Version As T))) As (File As FileInfo, Sha1 As String, Version As T)?
|
||||
If Matches.Count = 0 Then Return Nothing
|
||||
If Matches.Count = 1 Then Return Matches(0)
|
||||
Dim Choice As Integer? = Nothing
|
||||
RunInUiWait(Sub() Choice = MyMsgBoxSelect(Matches.Select(Function(Entry) CType(New MyRadioBox With {.Text = Entry.File.Name}, IMyRadio)), $"选择当前使用的 {ComponentName}"))
|
||||
If Not Choice.HasValue Then Throw New Exception($"发现了多个 {ComponentName}")
|
||||
Return Matches(Choice.Value)
|
||||
End Function
|
||||
|
||||
''' <summary>
|
||||
''' 初始化修改页
|
||||
''' </summary>
|
||||
Private Sub LoadInstanceFinished(Task As LoaderTask(Of McInstance, Object))
|
||||
'还原原版信息
|
||||
OriginalName = Task.Input.Name
|
||||
CustomLogo = Nothing
|
||||
If ReadIni(Task.Input.PathVersion & "PCL\Setup.ini", "LogoCustom", False) Then
|
||||
CustomLogo = If(Task.Input.Logo.EndsWithF("PCL\Logo.png"), Task.Input.PathVersion & "PCL\Logo.png", Task.Input.Logo)
|
||||
End If
|
||||
Dim Item = McDownloadListItem(VanillaData, Nothing, False).Init()
|
||||
VanillaName = Item.Title
|
||||
VanillaIcon = Item.Logo
|
||||
LabMinecraftVersion.Text = VanillaName
|
||||
TextSelectName.Text = OriginalName
|
||||
IsSelectNameEdited = Not String.Equals(OriginalName, GetSelectName(), StringComparison.Ordinal)
|
||||
TextSelectName.ValidateRules = New ObjectModel.Collection(Of Validate) From {
|
||||
New ValidateFolderName(McFolderSelected & "versions", IgnoreList:=New List(Of String) From {OriginalName})}
|
||||
'修改页 UI
|
||||
CardMinecraft.Visibility = Visibility.Visible
|
||||
BtnBack.Visibility = Visibility.Collapsed
|
||||
ImgLogo.Margin = New Thickness(15, 15, 0, 0)
|
||||
TextSelectName.Margin = New Thickness(56, 16, 16, 0)
|
||||
LabSelectName.Text = $"原名 : {OriginalName}"
|
||||
UpdateOriginalNameVisibility()
|
||||
BtnStart.Text = "开始修改"
|
||||
BtnStart.Logo = FrmInstanceLeft.ItemModify.Logo
|
||||
AutoSelectedFabricApi = SelectedFabric IsNot Nothing
|
||||
AutoSelectedOptiFabric = SelectedFabric IsNot Nothing AndAlso SelectedOptiFine IsNot Nothing
|
||||
If ForgeVersionLoader IsNot Nothing Then LoadForge.State = ForgeVersionLoader
|
||||
PrepareSelectPage()
|
||||
ReloadComponentLists()
|
||||
'进入动画
|
||||
PanMinecraft.Visibility = Visibility.Collapsed
|
||||
PanMinecraft.Opacity = 0
|
||||
PanMinecraft.RenderTransform = New TranslateTransform(-50, 0)
|
||||
PanSelect.Opacity = 1
|
||||
PanSelect.RenderTransform = New TranslateTransform
|
||||
PanBack.IsHitTestVisible = True
|
||||
PanAllBack.IsHitTestVisible = True
|
||||
InitialTarget = GetSelectedComponents()
|
||||
'设置原始数据
|
||||
BtnMinecraftRestore.Tag = VanillaData
|
||||
BtnOptiFineRestore.Tag = SelectedOptiFine
|
||||
BtnForgeRestore.Tag = SelectedForge
|
||||
BtnNeoForgeRestore.Tag = SelectedNeoForge
|
||||
BtnFabricRestore.Tag = SelectedFabric
|
||||
BtnFabricApiRestore.Tag = SelectedFabricApi
|
||||
BtnOptiFabricRestore.Tag = SelectedOptiFabric
|
||||
BtnLiteLoaderRestore.Tag = SelectedLiteLoader
|
||||
ImgMinecraftOld.Source = VanillaIcon
|
||||
LabMinecraftOld.Text = LabMinecraftVersion.Text
|
||||
LabOptiFineOld.Text = If(SelectedOptiFine Is Nothing, "无", LabOptiFine.Text)
|
||||
LabForgeOld.Text = If(SelectedForge Is Nothing, "无", LabForge.Text)
|
||||
LabNeoForgeOld.Text = If(SelectedNeoForge Is Nothing, "无", LabNeoForge.Text)
|
||||
LabFabricOld.Text = If(SelectedFabric Is Nothing, "无", LabFabric.Text)
|
||||
LabLiteLoaderOld.Text = If(SelectedLiteLoader Is Nothing, "无", LabLiteLoader.Text)
|
||||
LabFabricApiOld.Text = If(SelectedFabricApi Is Nothing, "无", LabFabricApi.Text)
|
||||
LabOptiFabricOld.Text = If(SelectedOptiFabric Is Nothing, "无", LabOptiFabric.Text)
|
||||
RefreshComparisons()
|
||||
End Sub
|
||||
|
||||
Public Overrides Function GetSelectLogo() As String
|
||||
Return If(CustomLogo, MyBase.GetSelectLogo())
|
||||
End Function
|
||||
|
||||
Public Overrides Sub ShowMinecraftVersionList()
|
||||
If IsInSelectPage Then
|
||||
'把当前已选择的组件记录到 PendingComponents
|
||||
Dim Components = GetSelectedComponents()
|
||||
For Each Component In {
|
||||
(Loader:=LoadOptiFine, Version:=Components.OptiFineVersion),
|
||||
(Loader:=LoadFabricApi, Version:=Components.FabricApiVersion),
|
||||
(Loader:=LoadOptiFabric, Version:=Components.OptiFabricVersion),
|
||||
(Loader:=LoadForge, Version:=SelectedForge?.VersionName),
|
||||
(Loader:=LoadNeoForge, Version:=SelectedNeoForge?.VersionName),
|
||||
(Loader:=LoadFabric, Version:=SelectedFabric),
|
||||
(Loader:=LoadLiteLoader, Version:=SelectedLiteLoader?.JsonToken?("version").ToString())}
|
||||
'保留尚未加载完成的组件选择
|
||||
If Component.Version IsNot Nothing Then PendingComponents(Component.Loader) = Component.Version
|
||||
Next
|
||||
End If
|
||||
MyBase.ShowMinecraftVersionList()
|
||||
End Sub
|
||||
|
||||
Public Overrides Sub ReloadSelected()
|
||||
If IsRestoringComponents Then Return
|
||||
If IsInSelectPage AndAlso VanillaName IsNot Nothing AndAlso PendingComponents.Any() Then
|
||||
IsRestoringComponents = True
|
||||
Try
|
||||
Dim HasProcessed As Boolean = False
|
||||
'优先恢复 Mod 加载器,再匹配兼容的附加组件
|
||||
For Each LoadingComponent In {LoadFabric, LoadForge, LoadNeoForge, LoadLiteLoader, LoadOptiFine, LoadFabricApi, LoadOptiFabric}
|
||||
Dim Version As String = Nothing
|
||||
If Not PendingComponents.TryGetValue(LoadingComponent, Version) Then Continue For
|
||||
If Not LoadingComponent.State.IsLoader Then Continue For
|
||||
Dim Loader = DirectCast(LoadingComponent.State, LoaderBase)
|
||||
'检查前置组件
|
||||
If LoadingComponent Is LoadOptiFine Then
|
||||
If {LoadFabric, LoadForge, LoadNeoForge, LoadLiteLoader}.Any(Function(Component) PendingComponents.ContainsKey(Component)) Then Continue For
|
||||
ElseIf LoadingComponent Is LoadFabricApi Then
|
||||
If PendingComponents.ContainsKey(LoadFabric) Then Continue For
|
||||
ElseIf LoadingComponent Is LoadForge Then
|
||||
If Not McVersion.IsStandardFormat(VanillaName) Then
|
||||
PendingComponents.Remove(LoadingComponent)
|
||||
Continue For
|
||||
End If
|
||||
If DirectCast(Loader, LoaderTask(Of String, List(Of DlForgeVersionEntry))).Input <> VanillaName Then Continue For
|
||||
If Loader.State = LoadState.Failed AndAlso Loader.Error.Message = "无" Then
|
||||
PendingComponents.Remove(LoadingComponent)
|
||||
Continue For
|
||||
End If
|
||||
ElseIf LoadingComponent Is LoadOptiFabric Then
|
||||
If PendingComponents.ContainsKey(LoadFabric) OrElse PendingComponents.ContainsKey(LoadOptiFine) Then Continue For
|
||||
End If
|
||||
If Loader.State <> LoadState.Finished Then Continue For
|
||||
'移除已处理的组件
|
||||
PendingComponents.Remove(LoadingComponent)
|
||||
HasProcessed = True
|
||||
'匹配目标 MC 版本下兼容的组件
|
||||
If LoadingComponent Is LoadFabric Then
|
||||
If SelectedFabric Is Nothing AndAlso LoadFabricGetError() Is Nothing Then
|
||||
Dim Versions = DlFabricListLoader.Output.Value("loader").OfType(Of JObject)
|
||||
SelectedFabric = If(Versions.FirstOrDefault(Function(v) v("version").ToString = Version), Versions.FirstOrDefault())?("version").ToString()
|
||||
End If
|
||||
ElseIf LoadingComponent Is LoadOptiFine Then
|
||||
If SelectedOptiFine Is Nothing AndAlso LoadOptiFineGetError() Is Nothing Then
|
||||
Dim Versions = DlOptiFineListLoader.Output.Value.Where(Function(v) v.Inherit = VanillaName AndAlso
|
||||
(SelectedForge Is Nothing OrElse IsOptiFineSuitForForge(v, SelectedForge)))
|
||||
SelectedOptiFine = If(Versions.FirstOrDefault(Function(v) v.InstanceName.AfterLast("-OptiFine_") = Version),
|
||||
Versions.OrderBy(Function(v) v.IsPreview).
|
||||
ThenByDescending(Function(v) v.DisplayName, Comparer(Of String).Create(AddressOf McUtils.CompareVersion)).FirstOrDefault())
|
||||
End If
|
||||
ElseIf LoadingComponent Is LoadForge Then
|
||||
If SelectedForge Is Nothing AndAlso LoadForgeGetError() Is Nothing Then
|
||||
Dim Versions = DirectCast(Loader, LoaderTask(Of String, List(Of DlForgeVersionEntry))).Output.Where(
|
||||
Function(v) v.Inherit = VanillaName AndAlso
|
||||
v.Category <> "universal" AndAlso v.Category <> "client" AndAlso
|
||||
(SelectedOptiFine Is Nothing OrElse IsOptiFineSuitForForge(SelectedOptiFine, v)))
|
||||
SelectedForge = If(Versions.FirstOrDefault(Function(v) v.VersionName = Version), Versions.OrderByDescending(Function(v) v).FirstOrDefault())
|
||||
End If
|
||||
ElseIf LoadingComponent Is LoadNeoForge Then
|
||||
If SelectedNeoForge Is Nothing AndAlso LoadNeoForgeGetError() Is Nothing Then
|
||||
Dim Versions = DlNeoForgeListLoader.Output.Value.Where(Function(v) v.Inherit = VanillaName)
|
||||
SelectedNeoForge = If(Versions.FirstOrDefault(Function(v) v.VersionName = Version), Versions.FirstOrDefault())
|
||||
End If
|
||||
ElseIf LoadingComponent Is LoadLiteLoader Then
|
||||
If SelectedLiteLoader Is Nothing AndAlso LoadLiteLoaderGetError() Is Nothing Then
|
||||
Dim Versions = DlLiteLoaderListLoader.Output.Value.Where(Function(v) v.Inherit = VanillaName)
|
||||
SelectedLiteLoader = If(Versions.FirstOrDefault(Function(v) v.JsonToken("version").ToString = Version), Versions.FirstOrDefault())
|
||||
End If
|
||||
ElseIf LoadingComponent Is LoadFabricApi Then
|
||||
If SelectedFabricApi Is Nothing AndAlso LoadFabricApiGetError() Is Nothing Then
|
||||
Dim Versions = DlFabricApiLoader.Output.Where(Function(v) IsFabricApiCompatible(v, VanillaName))
|
||||
SelectedFabricApi = If(Versions.FirstOrDefault(Function(v) v.Version = Version OrElse v.Id = Version OrElse v.Display = Version),
|
||||
Versions.OrderByDescending(Function(v) v.ReleaseDate).FirstOrDefault())
|
||||
End If
|
||||
If SelectedFabricApi IsNot Nothing Then AutoSelectedFabricApi = True
|
||||
ElseIf LoadingComponent Is LoadOptiFabric Then
|
||||
If SelectedOptiFabric Is Nothing AndAlso LoadOptiFabricGetError() Is Nothing Then
|
||||
Dim Versions = DlOptiFabricLoader.Output.Where(Function(v) IsOptiFabricCompatible(v, VanillaName))
|
||||
SelectedOptiFabric = If(Versions.FirstOrDefault(Function(v) v.Version = Version OrElse v.Id = Version OrElse v.Display = Version),
|
||||
Versions.OrderByDescending(Function(v) v.ReleaseDate).FirstOrDefault())
|
||||
End If
|
||||
If SelectedOptiFabric IsNot Nothing Then AutoSelectedOptiFabric = True
|
||||
End If
|
||||
Next
|
||||
'更新组件列表
|
||||
If HasProcessed Then ReloadComponentLists()
|
||||
Finally
|
||||
IsRestoringComponents = False
|
||||
End Try
|
||||
End If
|
||||
'刷新当前选择与原始版本的对比
|
||||
MyBase.ReloadSelected()
|
||||
If InitialTarget IsNot Nothing Then RefreshComparisons()
|
||||
End Sub
|
||||
|
||||
Private Sub RefreshComparisons()
|
||||
Dim Current = GetSelectedComponents()
|
||||
ImgMinecraftNew.Source = VanillaIcon
|
||||
'Minecraft
|
||||
Dim IsMinecraftUnchanged = InitialTarget.MinecraftVersion = Current.MinecraftVersion
|
||||
ShowComparison(PanMinecraftCompare, PanMinecraftInfo, InitialTarget.MinecraftVersion, Current.MinecraftVersion,
|
||||
LabMinecraftVersion.Text, BtnMinecraftRestore, True)
|
||||
'OptiFine
|
||||
Dim OriginalOptiFine = TryCast(BtnOptiFineRestore.Tag, DlOptiFineListEntry)
|
||||
ShowComparison(PanOptiFineCompare, PanOptiFineInfo, InitialTarget.OptiFineVersion, Current.OptiFineVersion,
|
||||
LabOptiFine.Text, BtnOptiFineRestore, InitialTarget.OptiFineEntry Is Nothing OrElse
|
||||
IsMinecraftUnchanged AndAlso CardOptiFine.MainSwap.Visibility = Visibility.Visible AndAlso OriginalOptiFine IsNot Nothing AndAlso
|
||||
(SelectedForge Is Nothing OrElse IsOptiFineSuitForForge(OriginalOptiFine, SelectedForge)), BtnOptiFineClear)
|
||||
'Fabric API
|
||||
ShowComparison(PanFabricApiCompare, PanFabricApiInfo, InitialTarget.FabricApiVersion, Current.FabricApiVersion,
|
||||
LabFabricApi.Text, BtnFabricApiRestore, InitialTarget.FabricApiVersion Is Nothing OrElse
|
||||
IsMinecraftUnchanged AndAlso SelectedFabric IsNot Nothing AndAlso CardFabricApi.MainSwap.Visibility = Visibility.Visible, BtnFabricApiClear)
|
||||
'OptiFabric
|
||||
ShowComparison(PanOptiFabricCompare, PanOptiFabricInfo, InitialTarget.OptiFabricVersion, Current.OptiFabricVersion,
|
||||
LabOptiFabric.Text, BtnOptiFabricRestore, InitialTarget.OptiFabricVersion Is Nothing OrElse
|
||||
IsMinecraftUnchanged AndAlso SelectedFabric IsNot Nothing AndAlso SelectedOptiFine IsNot Nothing AndAlso CardOptiFabric.MainSwap.Visibility = Visibility.Visible, BtnOptiFabricClear)
|
||||
'Mod Loader
|
||||
For Each Loader In {
|
||||
(Kind:=ModLoaders.Forge, Card:=CardForge, ComparePanel:=PanForgeCompare, CurrentPanel:=PanForgeInfo, Label:=LabForge, RestoreButton:=BtnForgeRestore, ClearButton:=BtnForgeClear),
|
||||
(Kind:=ModLoaders.NeoForge, Card:=CardNeoForge, ComparePanel:=PanNeoForgeCompare, CurrentPanel:=PanNeoForgeInfo, Label:=LabNeoForge, RestoreButton:=BtnNeoForgeRestore, ClearButton:=BtnNeoForgeClear),
|
||||
(Kind:=ModLoaders.Fabric, Card:=CardFabric, ComparePanel:=PanFabricCompare, CurrentPanel:=PanFabricInfo, Label:=LabFabric, RestoreButton:=BtnFabricRestore, ClearButton:=BtnFabricClear),
|
||||
(Kind:=ModLoaders.LiteLoader, Card:=CardLiteLoader, ComparePanel:=PanLiteLoaderCompare, CurrentPanel:=PanLiteLoaderInfo, Label:=LabLiteLoader, RestoreButton:=BtnLiteLoaderRestore, ClearButton:=BtnLiteLoaderClear)}
|
||||
Dim OldVersion As String = Nothing, NewVersion As String = Nothing
|
||||
InitialTarget.ModLoaderVersions.TryGetValue(Loader.Kind, OldVersion)
|
||||
Current.ModLoaderVersions.TryGetValue(Loader.Kind, NewVersion)
|
||||
Dim CanRestore = OldVersion Is Nothing OrElse IsMinecraftUnchanged AndAlso
|
||||
Loader.Card.MainSwap.Visibility = Visibility.Visible AndAlso Loader.RestoreButton.Tag IsNot Nothing
|
||||
If Loader.Kind = ModLoaders.Forge AndAlso OldVersion IsNot Nothing AndAlso CanRestore Then
|
||||
CanRestore = SelectedOptiFine Is Nothing OrElse IsOptiFineSuitForForge(SelectedOptiFine, DirectCast(Loader.RestoreButton.Tag, DlForgeVersionEntry))
|
||||
End If
|
||||
If Loader.Kind = ModLoaders.Fabric AndAlso OldVersion IsNot Nothing Then
|
||||
Dim TargetVersion = VanillaName.Replace("∞", "infinite").Replace("Combat Test 7c", "1.16_combat-3")
|
||||
CanRestore = CardFabric.Visibility = Visibility.Visible AndAlso CardFabric.MainSwap.Visibility = Visibility.Visible AndAlso
|
||||
DlFabricListLoader.Output.Value("loader").OfType(Of JObject).Any(Function(v) v("version").ToString = OldVersion) AndAlso
|
||||
DlFabricListLoader.Output.Value("game").OfType(Of JObject).Any(Function(v) v("version").ToString = TargetVersion)
|
||||
End If
|
||||
ShowComparison(Loader.ComparePanel, Loader.CurrentPanel, OldVersion, NewVersion, Loader.Label.Text,
|
||||
Loader.RestoreButton, CanRestore, Loader.ClearButton)
|
||||
Next
|
||||
UpdateStartButton()
|
||||
End Sub
|
||||
|
||||
Private Sub ShowComparison(ComparePanel As Grid, CurrentPanel As FrameworkElement, OldVersion As String, NewVersion As String, NewText As String,
|
||||
RestoreButton As MyIconButton, CanRestore As Boolean, Optional ClearButton As FrameworkElement = Nothing)
|
||||
'获取不可安装的原因
|
||||
Dim UnavailableReason As String = Nothing
|
||||
If NewVersion Is Nothing Then
|
||||
If RestoreButton Is BtnOptiFineRestore Then
|
||||
UnavailableReason = LoadOptiFineGetError()
|
||||
ElseIf RestoreButton Is BtnForgeRestore Then
|
||||
UnavailableReason = If(McVersion.IsStandardFormat(VanillaName), LoadForgeGetError(), "无")
|
||||
ElseIf RestoreButton Is BtnNeoForgeRestore Then
|
||||
UnavailableReason = If(CardNeoForge.Visibility = Visibility.Collapsed, "无", LoadNeoForgeGetError())
|
||||
ElseIf RestoreButton Is BtnFabricRestore Then
|
||||
UnavailableReason = If(CardFabric.Visibility = Visibility.Collapsed, "无", LoadFabricGetError())
|
||||
ElseIf RestoreButton Is BtnLiteLoaderRestore Then
|
||||
UnavailableReason = If(CardLiteLoader.Visibility = Visibility.Collapsed, "无", LoadLiteLoaderGetError())
|
||||
ElseIf RestoreButton Is BtnFabricApiRestore Then
|
||||
UnavailableReason = LoadFabricApiGetError()
|
||||
ElseIf RestoreButton Is BtnOptiFabricRestore Then
|
||||
UnavailableReason = LoadOptiFabricGetError()
|
||||
End If
|
||||
NewText = If(UnavailableReason, "可以添加")
|
||||
End If
|
||||
'修改对比
|
||||
Dim IsPending = NewVersion Is Nothing AndAlso (NewText = "获取中……" OrElse NewText.StartsWithF("获取失败:"))
|
||||
Dim IsChanged = OldVersion <> NewVersion AndAlso Not IsPending
|
||||
CanRestore = IsChanged AndAlso OldVersion IsNot Nothing AndAlso CanRestore
|
||||
ComparePanel.Visibility = If(IsChanged, Visibility.Visible, Visibility.Collapsed)
|
||||
CurrentPanel.Visibility = If(IsChanged, Visibility.Collapsed, Visibility.Visible)
|
||||
'还原与取消安装按钮
|
||||
RestoreButton.Visibility = If(CanRestore, Visibility.Visible, Visibility.Collapsed)
|
||||
If ClearButton IsNot Nothing Then ClearButton.ToolTip = If(OldVersion Is Nothing, "取消安装", "移除")
|
||||
Dim HasClearButton = ClearButton IsNot Nothing AndAlso ClearButton.Visibility = Visibility.Visible
|
||||
RestoreButton.Margin = New Thickness(0, 5, If(CanRestore AndAlso HasClearButton, 60, 32), 0)
|
||||
ComparePanel.Margin = New Thickness(ComparePanel.Margin.Left, ComparePanel.Margin.Top,
|
||||
If(CanRestore AndAlso HasClearButton, 110, 80), ComparePanel.Margin.Bottom)
|
||||
If Not IsChanged Then Return
|
||||
'显示修改前已安装组件的对比卡片
|
||||
If OldVersion IsNot Nothing Then
|
||||
Dim Card = CType(ComparePanel.Parent, MyCard)
|
||||
If Card.Visibility = Visibility.Collapsed Then
|
||||
Card.IsSwapped = True
|
||||
If Card.MainSwap IsNot Nothing Then Card.MainSwap.Visibility = Visibility.Collapsed
|
||||
Card.Visibility = Visibility.Visible
|
||||
End If
|
||||
End If
|
||||
Dim OldSide = CType(ComparePanel.Children(0), DockPanel)
|
||||
Dim NewSide = CType(ComparePanel.Children(2), DockPanel)
|
||||
OldSide.Children(0).Visibility = If(OldVersion Is Nothing, Visibility.Collapsed, Visibility.Visible)
|
||||
CType(OldSide.Children(1), TextBlock).Margin = If(OldVersion Is Nothing, New Thickness(0), New Thickness(7, 0, 0, 0))
|
||||
NewSide.Children(0).Visibility = If(NewVersion Is Nothing, Visibility.Collapsed, Visibility.Visible)
|
||||
Dim NewLabel = CType(NewSide.Children(1), TextBlock)
|
||||
NewLabel.Margin = If(NewVersion Is Nothing, New Thickness(0), New Thickness(7, 0, 0, 0))
|
||||
NewLabel.Text = If(NewVersion Is Nothing, "移除", NewText)
|
||||
If NewVersion Is Nothing AndAlso UnavailableReason IsNot Nothing Then
|
||||
NewLabel.Inlines.Add(New Run($"({If(UnavailableReason = "无", "无可用版本", UnavailableReason)})") With {.Foreground = ColorGray4})
|
||||
End If
|
||||
End Sub
|
||||
|
||||
Private Sub RestoreComponent(sender As Object, e As EventArgs) Handles BtnMinecraftRestore.Click, BtnOptiFineRestore.Click, BtnForgeRestore.Click,
|
||||
BtnNeoForgeRestore.Click, BtnFabricRestore.Click, BtnFabricApiRestore.Click, BtnOptiFabricRestore.Click, BtnLiteLoaderRestore.Click
|
||||
Dim Button = DirectCast(sender, MyIconButton)
|
||||
'恢复初始选择
|
||||
If Button Is BtnMinecraftRestore Then
|
||||
IsRestoringComponents = True
|
||||
Try
|
||||
PendingComponents.Clear()
|
||||
MinecraftSelected(McDownloadListItem(DirectCast(Button.Tag, JObject), Nothing, False).Init(), Nothing)
|
||||
If ForgeVersionLoader IsNot Nothing Then LoadForge.State = ForgeVersionLoader
|
||||
'恢复初始的组件
|
||||
SelectedOptiFine = TryCast(BtnOptiFineRestore.Tag, DlOptiFineListEntry)
|
||||
SelectedForge = TryCast(BtnForgeRestore.Tag, DlForgeVersionEntry)
|
||||
SelectedNeoForge = TryCast(BtnNeoForgeRestore.Tag, DlNeoForgeListEntry)
|
||||
SelectedFabric = TryCast(BtnFabricRestore.Tag, String)
|
||||
SelectedLiteLoader = TryCast(BtnLiteLoaderRestore.Tag, DlLiteLoaderListEntry)
|
||||
SelectedFabricApi = TryCast(BtnFabricApiRestore.Tag, ResourceVersion)
|
||||
SelectedOptiFabric = TryCast(BtnOptiFabricRestore.Tag, ResourceVersion)
|
||||
AutoSelectedFabricApi = SelectedFabric IsNot Nothing
|
||||
AutoSelectedOptiFabric = SelectedFabric IsNot Nothing AndAlso SelectedOptiFine IsNot Nothing
|
||||
Finally
|
||||
IsRestoringComponents = False
|
||||
End Try
|
||||
ReloadComponentLists()
|
||||
Return
|
||||
ElseIf Button Is BtnOptiFineRestore Then
|
||||
SelectedOptiFine = TryCast(Button.Tag, DlOptiFineListEntry)
|
||||
AutoSelectedOptiFabric = SelectedOptiFine IsNot Nothing AndAlso SelectedFabric IsNot Nothing
|
||||
If SelectedOptiFine Is Nothing Then SelectedOptiFabric = Nothing
|
||||
ElseIf Button Is BtnForgeRestore Then
|
||||
SelectedForge = TryCast(Button.Tag, DlForgeVersionEntry)
|
||||
ElseIf Button Is BtnNeoForgeRestore Then
|
||||
SelectedNeoForge = TryCast(Button.Tag, DlNeoForgeListEntry)
|
||||
ElseIf Button Is BtnFabricRestore Then
|
||||
SelectedFabric = TryCast(Button.Tag, String)
|
||||
AutoSelectedFabricApi = SelectedFabric IsNot Nothing
|
||||
AutoSelectedOptiFabric = SelectedFabric IsNot Nothing AndAlso SelectedOptiFine IsNot Nothing
|
||||
If SelectedFabric Is Nothing Then
|
||||
SelectedFabricApi = Nothing
|
||||
SelectedOptiFabric = Nothing
|
||||
End If
|
||||
ElseIf Button Is BtnFabricApiRestore Then
|
||||
SelectedFabricApi = TryCast(Button.Tag, ResourceVersion)
|
||||
AutoSelectedFabricApi = True
|
||||
ElseIf Button Is BtnOptiFabricRestore Then
|
||||
SelectedOptiFabric = TryCast(Button.Tag, ResourceVersion)
|
||||
AutoSelectedOptiFabric = True
|
||||
ElseIf Button Is BtnLiteLoaderRestore Then
|
||||
SelectedLiteLoader = TryCast(Button.Tag, DlLiteLoaderListEntry)
|
||||
End If
|
||||
DirectCast(Button.Parent, MyCard).IsSwapped = True
|
||||
'刷新组件
|
||||
ReloadComponentLists()
|
||||
End Sub
|
||||
|
||||
Private Sub CardMinecraft_MouseLeftButtonUp(sender As Object, e As MouseButtonEventArgs) Handles CardMinecraft.MouseLeftButtonUp
|
||||
ShowMinecraftVersionList()
|
||||
e.Handled = True
|
||||
End Sub
|
||||
|
||||
Private Sub UpdateStartButton() Handles TextSelectName.TextChanged, TextSelectName.ValidateChanged
|
||||
BtnStart.IsEnabled = TextSelectName.IsValidated AndAlso InitialTarget IsNot Nothing AndAlso
|
||||
Not PendingComponents.Any() AndAlso
|
||||
(Not IsVanillaVersionReliable OrElse Not InitialTarget.IsEquivalentTo(GetSelectedComponents()) OrElse
|
||||
Not String.Equals(TextSelectName.Text, OriginalName, StringComparison.Ordinal))
|
||||
End Sub
|
||||
|
||||
Private Sub UpdateOriginalNameVisibility() Handles TextSelectName.TextChanged
|
||||
Dim IsNameChanged = Not String.Equals(TextSelectName.Text, OriginalName, StringComparison.Ordinal)
|
||||
Dim NewVisibility = If(IsNameChanged, Visibility.Visible, Visibility.Collapsed)
|
||||
If LabSelectName.Visibility = NewVisibility Then Return
|
||||
LabSelectName.Visibility = NewVisibility
|
||||
BtnOriginalNameRestore.Visibility = NewVisibility
|
||||
Dim RightMargin = If(IsNameChanged, 40, 16)
|
||||
If IsInSelectPage AndAlso AniControlEnabled = 0 Then
|
||||
AniStart(AaDouble(Sub(Delta) TextSelectName.Margin = New Thickness(56, 16, TextSelectName.Margin.Right + Delta, 0),
|
||||
RightMargin - TextSelectName.Margin.Right, 150,, New AniEaseOutFluent), "DownloadModify Name Margin")
|
||||
Else
|
||||
AniStop("DownloadModify Name Margin")
|
||||
TextSelectName.Margin = New Thickness(56, 16, RightMargin, 0)
|
||||
End If
|
||||
End Sub
|
||||
|
||||
Private Sub BtnOriginalNameRestore_Click(sender As Object, e As EventArgs) Handles BtnOriginalNameRestore.Click
|
||||
TextSelectName.Text = OriginalName
|
||||
IsSelectNameEdited = Not String.Equals(OriginalName, GetSelectName(), StringComparison.Ordinal)
|
||||
End Sub
|
||||
|
||||
Public Overrides Sub StartInstall(Request As McInstallRequest)
|
||||
UpdateStartButton()
|
||||
If Not BtnStart.IsEnabled Then Return
|
||||
Dim TargetInstance = InitLoader.Input
|
||||
Dim Target = Request.Components
|
||||
Dim InstanceName = Request.NewInstanceName
|
||||
Dim IsNameChanged = Not String.Equals(InstanceName, TargetInstance.Name, StringComparison.Ordinal)
|
||||
Request.NewInstanceName = If(IsNameChanged, InstanceName, Nothing)
|
||||
Request.InstanceFolder = TargetInstance.PathVersion
|
||||
'警告
|
||||
Dim Warnings As New List(Of String)
|
||||
If (SelectedForge IsNot Nothing OrElse SelectedNeoForge IsNot Nothing OrElse SelectedFabric IsNot Nothing) AndAlso
|
||||
Not PathUtils.IsSame(TargetInstance.PathIndie, TargetInstance.PathVersion) Then
|
||||
Warnings.Add("该版本尚未开启版本隔离,可能与别的 MC 版本共用同一个 Mod 和存档文件夹。" & vbCrLf &
|
||||
"修改版本后,已有的 Mod、存档等需要手动迁移到新的游戏目录。")
|
||||
End If
|
||||
Dim IsMinecraftVersionChanged = InitialTarget.MinecraftVersion <> Target.MinecraftVersion
|
||||
If Not IsVanillaVersionReliable AndAlso Not IsMinecraftVersionChanged Then
|
||||
Warnings.Add($"PCL 未能精准识别该版本,请确认它是不是 Minecraft {InitialTarget.MinecraftVersion},如果不正确,请取消并选择正确的版本!")
|
||||
End If
|
||||
If Not Configs.HintModifyInstanceWarning.Get() Then
|
||||
Warnings.Add("如果该版本安装了 PCL 不兼容的加载器,或经过第三方修改,这些改动将会丢失!")
|
||||
End If
|
||||
Dim IsModLoaderChanged As Boolean = False
|
||||
For Each Loader In InitialTarget.ModLoaderVersions.Keys.Union(Target.ModLoaderVersions.Keys)
|
||||
Dim CurrentVersion As String = Nothing, TargetVersion As String = Nothing
|
||||
Dim HasCurrent = InitialTarget.ModLoaderVersions.TryGetValue(Loader, CurrentVersion)
|
||||
Dim HasTarget = Target.ModLoaderVersions.TryGetValue(Loader, TargetVersion)
|
||||
If HasCurrent <> HasTarget OrElse CurrentVersion <> TargetVersion Then
|
||||
IsModLoaderChanged = True
|
||||
Exit For
|
||||
End If
|
||||
Next
|
||||
If (IsModLoaderChanged OrElse IsMinecraftVersionChanged) AndAlso InitialTarget.ModLoaderVersions.Any Then
|
||||
Warnings.Add("现有的 Mod、资源包等在修改后可能会不兼容!")
|
||||
End If
|
||||
If Warnings.Any() Then
|
||||
If MyMsgBox("请注意:" & vbCrLf & "• " & Warnings.Join(vbCrLf & "• "), "修改确认", "开始修改", "取消", IsWarn:=True) <> 1 Then Return
|
||||
End If
|
||||
If Not Configs.HintModifyInstanceWarning.Get() Then Configs.HintModifyInstanceWarning.Set(True)
|
||||
'开始修改
|
||||
If IsVanillaVersionReliable AndAlso InitialTarget.IsEquivalentTo(Target) Then
|
||||
'仅重命名
|
||||
Try
|
||||
Dim OldPath = TargetInstance.PathVersion
|
||||
Dim RenamedInstance = TargetInstance.Rename(InstanceName)
|
||||
If PageInstanceLeft.Instance IsNot Nothing AndAlso PathUtils.IsSame(PageInstanceLeft.Instance.PathVersion, OldPath) Then PageInstanceLeft.Instance = RenamedInstance
|
||||
If McInstanceSelected IsNot Nothing AndAlso PathUtils.IsSame(McInstanceSelected.PathVersion, OldPath) Then McInstanceSelected = RenamedInstance
|
||||
PageInstanceLeft.ReloadCurrentJava()
|
||||
Hint("重命名成功!", HintType.Green)
|
||||
LoaderFolderRun(McInstanceListLoader, McFolderSelected, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\")
|
||||
FrmMain.PageBack()
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex, "重命名版本失败", LogBehavior.Alert)
|
||||
End Try
|
||||
Else
|
||||
'实际修改
|
||||
If McModificationStart(Request, TargetInstance) Then FrmMain.PageBack()
|
||||
End If
|
||||
End Sub
|
||||
End Class
|
||||
@@ -64,10 +64,10 @@ Public Class PageDownloadResourceDetail
|
||||
If IsXSpecial Then Return 1
|
||||
If IsYSpecial Then Return -1
|
||||
'比较版本号
|
||||
Dim VersionCodeSort = -CompareVersion(x.Replace(x.BeforeFirst(" ") & " ", ""), y.Replace(y.BeforeFirst(" ") & " ", ""))
|
||||
Dim VersionCodeSort = -McUtils.CompareVersion(x.Replace(x.BeforeFirst(" ") & " ", ""), y.Replace(y.BeforeFirst(" ") & " ", ""))
|
||||
If VersionCodeSort <> 0 Then Return VersionCodeSort
|
||||
'比较全部
|
||||
Return -CompareVersion(x, y)
|
||||
Return -McUtils.CompareVersion(x, y)
|
||||
End Function
|
||||
Public Sub New(Optional Topmost As String = "")
|
||||
Me.Topmost = If(Topmost, "")
|
||||
@@ -98,7 +98,7 @@ Public Class PageDownloadResourceDetail
|
||||
Dim UpdateFilters =
|
||||
Sub()
|
||||
Filters = Results.SelectMany(Function(v) v.GameVersions).Select(Function(v) GetGroupedVersionName(v, GroupedDrop, GroupedOld)).
|
||||
Distinct.OrderByDescending(Function(s) s, New VersionComparer).ToList
|
||||
Distinct.OrderByDescending(Function(s) s, Comparer(Of String).Create(Function(x, y) McUtils.CompareVersion(x, y))).ToList
|
||||
End Sub
|
||||
|
||||
'确定分组方式
|
||||
@@ -174,7 +174,7 @@ GroupDone:
|
||||
Dim Loaders As New List(Of String)
|
||||
If Project.ModLoaders.Flags.Count > 1 AndAlso '工程至少有两个加载器
|
||||
Version.ResourceType = ResourceTypes.Mod AndAlso '是 Mod
|
||||
McVersion.IsFormatFit(VerName) Then '不是 “快照版本” 之类的
|
||||
McVersion.IsStandardFormat(VerName) Then '不是 “快照版本” 之类的
|
||||
Loaders.AddRange(Version.ModLoaders.Flags.Select(Function(f) f.ToString & " "))
|
||||
End If
|
||||
If Not Loaders.Any() Then Loaders.Add("") '保底加一个空的,确保它在一张卡片里
|
||||
@@ -206,16 +206,17 @@ GroupDone:
|
||||
If Not Pair.Value.Any() Then Continue For
|
||||
If Pair.Key = TargetCardName.Replace("(所选版本)", "") Then Continue For
|
||||
'增加卡片
|
||||
Dim NewCard As New MyCard With {.Title = Pair.Key, .Margin = New Thickness(0, 0, 0, 15), .SwapType = If(TargetResourceType = ResourceTypes.ModPack, 9, 8)} '9 是安装,8 是另存为
|
||||
Dim NewCard As New MyCard With {.Title = Pair.Key, .Margin = New Thickness(0, 0, 0, 15)}
|
||||
Dim NewStack As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0), .Tag = Pair.Value}
|
||||
NewCard.Children.Add(NewStack)
|
||||
NewCard.SwapControl = NewStack
|
||||
NewCard.SetContentBuilder(AddressOf InitializeStackResourceVersions)
|
||||
PanResults.Children.Add(NewCard)
|
||||
'确定卡片是否默认展开
|
||||
If Pair.Key = TargetCardName OrElse
|
||||
(FrmMain.PageCurrent.Additional IsNot Nothing AndAlso '#2761
|
||||
CType(FrmMain.PageCurrent.Additional(1), List(Of String)).Contains(NewCard.Title)) Then
|
||||
MyCard.StackInstall(NewStack, If(TargetResourceType = ResourceTypes.ModPack, 9, 8), Pair.Key) '9 是安装,8 是另存为
|
||||
NewCard.BuildContent()
|
||||
Else
|
||||
NewCard.IsSwapped = True
|
||||
End If
|
||||
@@ -240,13 +241,53 @@ GroupDone:
|
||||
Logger.Error(ex, "可视化工程下载列表出错")
|
||||
End Try
|
||||
End Sub
|
||||
''' <summary>
|
||||
''' 根据卡片中的 StackPanel.Tag 将资源版本列表数据实例化为 UI。
|
||||
''' </summary>
|
||||
Private Sub InitializeStackResourceVersions(Stack As StackPanel)
|
||||
Dim Versions = CType(Stack.Tag, List(Of ResourceVersion)).SortByComparison(Function(a, b) a.ReleaseDate > b.ReleaseDate)
|
||||
Dim HasDuplicates = Versions.DistinctBy(Function(a) a.Display).Count <> Versions.Count
|
||||
Dim Dependences As List(Of String)
|
||||
'获取并添加前置信息
|
||||
If TargetResourceType = ResourceTypes.ModPack Then
|
||||
Dependences = New List(Of String) '整合包的前置信息会显示其中包含的一大堆 Mod,不是真正意义的前置
|
||||
Else
|
||||
Dependences = Versions.SelectMany(Function(f) f.Dependencies).Distinct.Ordered.ToList()
|
||||
End If
|
||||
If Dependences.Any() Then
|
||||
Dependences = Dependences.Where(
|
||||
Function(d)
|
||||
If Not ResourceProject.Cache.ContainsKey(d) Then Logger.Warn($"未找到 ID {d} 的前置信息")
|
||||
Return ResourceProject.Cache.ContainsKey(d)
|
||||
End Function).ToList
|
||||
'添加开头间隔
|
||||
Stack.Children.Add(New TextBlock With {.Text = "前置资源", .FontSize = 14, .HorizontalAlignment = HorizontalAlignment.Left, .Margin = New Thickness(6, 2, 0, 5)})
|
||||
'添加前置列表
|
||||
For Each Dep In Dependences
|
||||
Dim Item = ResourceProject.Cache(Dep).ToResourceItem(False, False)
|
||||
Stack.Children.Add(Item)
|
||||
Next
|
||||
'添加结尾间隔
|
||||
Stack.Children.Add(New TextBlock With {.Text = "版本列表", .FontSize = 14, .HorizontalAlignment = HorizontalAlignment.Left, .Margin = New Thickness(6, 12, 0, 5)})
|
||||
End If
|
||||
'实例化每个元素
|
||||
For Each Version In Versions
|
||||
If TargetResourceType = ResourceTypes.ModPack Then
|
||||
Stack.Children.Add(Version.ToListItem(AddressOf Install_Click, AddressOf Save_Click, IsBadDisplay:=HasDuplicates))
|
||||
Else
|
||||
Stack.Children.Add(Version.ToListItem(AddressOf Save_Click, IsBadDisplay:=HasDuplicates))
|
||||
End If
|
||||
Next
|
||||
Stack.Children.Add(New FrameworkElement With {.Height = 18})
|
||||
Stack.Tag = Nothing
|
||||
End Sub
|
||||
Private Function GetGroupedVersionName(Name As String, GroupedByDrop As Boolean, FoldOld As Boolean) As String
|
||||
Dim Drop = McVersion.VersionToDrop(Name)
|
||||
If Name Is Nothing Then
|
||||
Return "其他"
|
||||
ElseIf Name.Contains("w") OrElse Drop = 209 Then
|
||||
Return "快照版"
|
||||
ElseIf Not McVersion.IsFormatFit(Name) OrElse (FoldOld AndAlso Drop < 120) Then
|
||||
ElseIf Not McVersion.IsStandardFormat(Name) OrElse (FoldOld AndAlso Drop < 120) Then
|
||||
Return "远古版"
|
||||
ElseIf GroupedByDrop Then
|
||||
Return McVersion.DropToVersion(Drop)
|
||||
@@ -469,19 +510,23 @@ GroupDone:
|
||||
'弹窗要求选择保存位置
|
||||
Dim Target As String
|
||||
Dim Ext As String = If(File.ResourceType = ResourceTypes.Mod,
|
||||
If(File.FileName.EndsWithF(".litemod"), "litemod", "jar"),
|
||||
If(File.FileName.EndsWithF(".mrpack"), "mrpack", "zip"))
|
||||
If(PathUtils.GetExtension(File.FileName) = "litemod", "litemod", "jar"),
|
||||
If(PathUtils.GetExtension(File.FileName) = "mrpack", "mrpack", "zip"))
|
||||
Target = Dialogs.SaveFile("选择保存位置", FileName, DefaultFolder, {(Ext, Desc & "文件")})
|
||||
If Target Is Nothing Then Return
|
||||
'构造步骤加载器
|
||||
Dim LoaderName As String = Desc & "下载:" & PathUtils.GetFileNameWithoutExtension(Target) & " "
|
||||
If Target <> DefaultFolder Then CachedFolder(File.ResourceType) = PathUtils.RemoveLastPart(Target)
|
||||
If Not PathUtils.IsSame(PathUtils.RemoveLastPart(Target), DefaultFolder) Then CachedFolder(File.ResourceType) = PathUtils.RemoveLastPart(Target)
|
||||
Dim Loaders As New List(Of LoaderBase)
|
||||
Loaders.Add(New LoaderDownload("下载文件", {
|
||||
File.ToNetFile(Target, If(TargetResourceType = ResourceTypes.Any, ResourceVersion.DownloadReason.Dependency, ResourceVersion.DownloadReason.Standalone))
|
||||
}) With {.ProgressWeight = 6, .Block = True})
|
||||
'启动
|
||||
Dim Loader As New LoaderCombo(Of Integer)(LoaderName, Loaders) With {.OnStateChanged = AddressOf LoaderStateChangedHintOnly}
|
||||
Dim Loader As New LoaderCombo(Of Integer)(LoaderName, Loaders) With {.OnStateChanged =
|
||||
Sub(MyLoader)
|
||||
LoaderStateChangedHintOnly(MyLoader)
|
||||
If MyLoader.State = LoadState.Finished AndAlso File.ResourceType = ResourceTypes.ModPack Then OpenExplorer(Target)
|
||||
End Sub}
|
||||
Loader.Start(1)
|
||||
LoaderTaskbarAdd(Loader)
|
||||
FrmMain.BtnExtraDownload.ShowRefresh()
|
||||
@@ -510,29 +555,4 @@ GroupDone:
|
||||
PageLoaderRestart(IsForceRestart:=True)
|
||||
End Sub
|
||||
|
||||
''' <summary>
|
||||
''' 预载包含大量 ProjectVersion 的卡片,添加必要的元素和前置列表。
|
||||
''' </summary>
|
||||
Public Shared Sub ResourceFilesCardPreload(Stack As StackPanel, Files As List(Of ResourceVersion))
|
||||
'获取卡片对应的前置 ID
|
||||
'如果为整合包就不会有 Dependencies 信息,所以不用管
|
||||
Dim Deps As List(Of String) = Files.SelectMany(Function(f) f.Dependencies).Distinct.ToList()
|
||||
Deps.Sort()
|
||||
If Not Deps.Any() Then Return
|
||||
Deps = Deps.Where(
|
||||
Function(dep)
|
||||
If Not ResourceProject.Cache.ContainsKey(dep) Then Logger.Warn($"未找到 ID {dep} 的前置信息")
|
||||
Return ResourceProject.Cache.ContainsKey(dep)
|
||||
End Function).ToList
|
||||
'添加开头间隔
|
||||
Stack.Children.Add(New TextBlock With {.Text = "前置资源", .FontSize = 14, .HorizontalAlignment = HorizontalAlignment.Left, .Margin = New Thickness(6, 2, 0, 5)})
|
||||
'添加前置列表
|
||||
For Each Dep In Deps
|
||||
Dim Item = ResourceProject.Cache(Dep).ToResourceItem(False, False)
|
||||
Stack.Children.Add(Item)
|
||||
Next
|
||||
'添加结尾间隔
|
||||
Stack.Children.Add(New TextBlock With {.Text = "版本列表", .FontSize = 14, .HorizontalAlignment = HorizontalAlignment.Left, .Margin = New Thickness(6, 12, 0, 5)})
|
||||
End Sub
|
||||
|
||||
End Class
|
||||
|
||||
@@ -90,11 +90,11 @@ Public Class PageResource
|
||||
Next
|
||||
Return ComboSearchLoader.Items(0)
|
||||
End Function
|
||||
If TargetInstance.Version.HasForge Then
|
||||
If TargetInstance.Version.ModLoaders.HasFlagF(ModLoaders.Forge) Then
|
||||
ComboSearchLoader.SelectedItem = GetTargetItemByName("Forge")
|
||||
ElseIf TargetInstance.Version.HasFabric Then
|
||||
ElseIf TargetInstance.Version.ModLoaders.HasFlagF(ModLoaders.Fabric) Then
|
||||
ComboSearchLoader.SelectedItem = GetTargetItemByName("Fabric")
|
||||
ElseIf TargetInstance.Version.HasNeoForge Then
|
||||
ElseIf TargetInstance.Version.ModLoaders.HasFlagF(ModLoaders.NeoForge) Then
|
||||
ComboSearchLoader.SelectedItem = GetTargetItemByName("NeoForge")
|
||||
End If
|
||||
TargetInstance = Nothing
|
||||
|
||||
@@ -335,7 +335,7 @@ Public Class MyLocalModItem
|
||||
BtnUpdate.Visibility = Visibility.Collapsed
|
||||
End If
|
||||
'标题与描述
|
||||
Dim DescFileName As String = Entry.File.Name.BeforeLast(".")
|
||||
Dim DescFileName As String = PathUtils.GetFileNameWithoutExtension(Entry.EnabledName)
|
||||
Dim NewDescription As String
|
||||
If Settings.Get(Of Integer)("ToolModLocalNameStyle") = 1 Then
|
||||
'标题显示文件名,详情显示译名
|
||||
|
||||
@@ -65,10 +65,10 @@
|
||||
<local:MyCheckBox Margin="30,0,0,0">
|
||||
<local:MyCheckBox.Tag>
|
||||
<local:ExportOption
|
||||
Title="OptiFine 设置"
|
||||
Rules="optionsof.txt|optionsshaders.txt"
|
||||
DefaultChecked="True"
|
||||
RequireOptiFine="True" />
|
||||
Title="OptiFine 设置"
|
||||
Rules="optionsof.txt|optionsshaders.txt"
|
||||
DefaultChecked="True"
|
||||
RequireOptiFine="True" />
|
||||
</local:MyCheckBox.Tag>
|
||||
</local:MyCheckBox>
|
||||
<local:MyCheckBox x:Name="CheckOptionsMod">
|
||||
|
||||
@@ -22,14 +22,14 @@ Public Class PageInstanceExport
|
||||
End Sub
|
||||
Private Sub PageInstanceExport_Loaded() Handles Me.Loaded
|
||||
AniControlEnabled += 1
|
||||
If CurrentInstance <> PageInstanceLeft.Instance.PathVersion Then RefreshAll() '切换到了另一个版本,重置页面
|
||||
If Not PathUtils.IsSame(CurrentInstance, PageInstanceLeft.Instance.PathVersion) Then RefreshAll() '切换到了另一个版本,重置页面
|
||||
CustomEventService.SetEventData(BtnAdvancedHelp,
|
||||
If(BuildType = BuildTypes.Release, "指南/整合包制作 - Public.json", "指南/整合包制作 - Snapshot.json"))
|
||||
AniControlEnabled -= 1
|
||||
End Sub
|
||||
Public Sub RefreshAll() Implements IRefreshable.Refresh
|
||||
Logger.Info("刷新导出页面")
|
||||
HintOptiFine.Visibility = If(PageInstanceLeft.Instance.Version.HasOptiFine, Visibility.Visible, Visibility.Collapsed)
|
||||
HintOptiFine.Visibility = If(PageInstanceLeft.Instance.Version.HasOptiFine AndAlso Not PageInstanceLeft.Instance.Version.OptiFineAsMod, Visibility.Visible, Visibility.Collapsed)
|
||||
CurrentInstance = PageInstanceLeft.Instance.PathVersion
|
||||
TextExportName.Text = ""
|
||||
TextExportName.HintText = PageInstanceLeft.Instance.Name
|
||||
@@ -114,7 +114,7 @@ Public Class PageInstanceExport
|
||||
'确认选项是否应该被显示
|
||||
Dim IsVisible =
|
||||
Function(TargetOption As ExportOption) As Boolean
|
||||
'检查需要 OptiFine 或 Mod 加载器
|
||||
'检查需要 OptiFine(例如光影)或 Mod 加载器(例如 mods/)
|
||||
If TargetOption.RequireOptiFine AndAlso Not PageInstanceLeft.Instance.Version.HasOptiFine Then Return False
|
||||
If TargetOption.RequireModLoader AndAlso Not PageInstanceLeft.Instance.Modable Then Return False
|
||||
If TargetOption.RequireModLoaderOrOptiFine AndAlso Not PageInstanceLeft.Instance.Version.HasOptiFine AndAlso Not PageInstanceLeft.Instance.Modable Then Return False
|
||||
@@ -257,9 +257,9 @@ Public Class PageInstanceExport
|
||||
For Each ShaderPackCheckBox In PanOptionsShaderPacks.Children.OfType(Of MyCheckBox)()
|
||||
If Not ShaderPackCheckBox.Checked Then Continue For
|
||||
Dim ShaderPackOption = GetExportOption(ShaderPackCheckBox)
|
||||
Dim SettingFileName = ShaderPackOption.Rules.TrimEnd("/") & ".txt"
|
||||
If Not FileUtils.Exists(Path.Combine(PageInstanceLeft.Instance.PathIndie, SettingFileName)) Then Continue For
|
||||
Rules.Add(StringUtils.LikePatternEscape($"shaderpacks/{SettingFileName}"))
|
||||
Dim SettingsFile = $"shaderpacks/{ShaderPackOption.Title}.txt"
|
||||
If Not FileUtils.Exists(Path.Combine(PageInstanceLeft.Instance.PathIndie, SettingsFile)) Then Continue For
|
||||
Rules.Add(StringUtils.LikePatternEscape(SettingsFile))
|
||||
Next
|
||||
End If
|
||||
|
||||
@@ -457,11 +457,11 @@ Public Class PageInstanceExport
|
||||
'缓存所需参数
|
||||
Dim CacheFolder = RequestTaskTempFolder()
|
||||
Dim OverridesFolder = CacheFolder & "modpack\overrides\"
|
||||
Dim McVersion = PageInstanceLeft.Instance
|
||||
Dim TargetInstance = PageInstanceLeft.Instance
|
||||
Dim IncludeJava As Boolean =
|
||||
(RulesOverrides Is Nothing AndAlso CheckOptionsJava.Visibility = Visibility.Visible AndAlso CheckOptionsJava.Checked) OrElse
|
||||
(RulesOverrides IsNot Nothing AndAlso CheckOptionsJava.Checked AndAlso Settings.Get(Of Integer)("VersionArgumentJavaV2", McVersion) = 2)
|
||||
Dim PathIndie As String = McVersion.PathIndie
|
||||
(RulesOverrides IsNot Nothing AndAlso CheckOptionsJava.Checked AndAlso Settings.Get(Of Integer)("VersionArgumentJavaV2", TargetInstance) = 2)
|
||||
Dim PathIndie As String = TargetInstance.PathIndie
|
||||
Dim CheckHostedAssets As Boolean = Not CheckAdvancedInclude.Checked
|
||||
Dim ModrinthUploadMode As Boolean = CheckAdvancedModrinth.Checked
|
||||
Dim IncludePCL As Boolean = CheckOptionsPcl.Checked
|
||||
@@ -498,7 +498,7 @@ Public Class PageInstanceExport
|
||||
'文件夹:进一步搜索
|
||||
For Each SubFolder In Folder.EnumerateDirectories("*", SearchOption.TopDirectoryOnly)
|
||||
'跳过部分又没用文件又多的文件夹,加快搜索
|
||||
If {"assets", "versions", "libraries"}.Contains(SubFolder.Name) AndAlso PathIndie = PathUtils.RemoveExtendedPrefix(Folder.FullName) Then Continue For
|
||||
If {"assets", "versions", "libraries"}.Contains(SubFolder.Name) AndAlso PathUtils.IsSame(PathIndie, Folder.FullName) Then Continue For
|
||||
If {"structureCacheV1", ".fabric", ".git", "avatar-cache", "cosmetic-cache"}.Contains(SubFolder.Name) Then Continue For
|
||||
SearchFolder(SubFolder)
|
||||
Next
|
||||
@@ -536,10 +536,10 @@ Public Class PageInstanceExport
|
||||
Loader.Progress = 0.85
|
||||
'复制 Java
|
||||
If IncludeJava Then
|
||||
Dim JavaToExport = SelectOrDownloadJava(McVersion, False, Loader.CreateCancellationToken, Loader.CreateSyncProgressProvider(0.85, 0.93))
|
||||
Dim JavaToExport = SelectOrDownloadJava(TargetInstance, False, Loader.CreateCancellationToken, Loader.CreateSyncProgressProvider(0.85, 0.93))
|
||||
If JavaToExport Is Nothing Then Throw New FileNotFoundException("版本文件夹中没有找到可导出的 Java。")
|
||||
Dim JavaFolder = PathUtils.RemoveLastPart(JavaToExport.Folder)
|
||||
Dim DestFolder As String = Path.Combine(OverridesFolder, JavaFolder.AfterFirst(McVersion.PathVersion, True))
|
||||
Dim DestFolder As String = Path.Combine(OverridesFolder, JavaFolder.AfterFirst(TargetInstance.PathVersion, True))
|
||||
DirectoryUtils.Copy(JavaFolder, DestFolder)
|
||||
Logger.Info($"已复制版本文件夹中的 Java:{JavaFolder} → {DestFolder}")
|
||||
End If
|
||||
@@ -563,7 +563,7 @@ Public Class PageInstanceExport
|
||||
Next
|
||||
Loader.Progress = 0.97
|
||||
'复制 PCL 版本设置
|
||||
If DirectoryUtils.Exists(McVersion.PathVersion & "PCL\") Then DirectoryUtils.Copy(McVersion.PathVersion & "PCL\", OverridesFolder & "PCL\")
|
||||
If DirectoryUtils.Exists(TargetInstance.PathVersion & "PCL\") Then DirectoryUtils.Copy(TargetInstance.PathVersion & "PCL\", OverridesFolder & "PCL\")
|
||||
WriteIni(OverridesFolder & "PCL\Setup.ini", "IsStar", False)
|
||||
'复制 PCL 本体(正式版)
|
||||
If BuildType = BuildTypes.Release AndAlso IncludePCL Then FileUtils.Copy(PathExe, CacheFolder & "Plain Craft Launcher.exe")
|
||||
@@ -686,16 +686,16 @@ Public Class PageInstanceExport
|
||||
Next
|
||||
Loader.Progress = 0.2
|
||||
'导出最终 JSON 文件
|
||||
Dim Dependencies As New JObject From {{"minecraft", McVersion.Version.VanillaName}}
|
||||
If McVersion.Version.HasForge Then Dependencies.Add("forge", McVersion.Version.Forge)
|
||||
If McVersion.Version.HasFabric Then Dependencies.Add("fabric-loader", McVersion.Version.Fabric)
|
||||
If McVersion.Version.HasNeoForge Then Dependencies.Add("neoforge", McVersion.Version.NeoForge)
|
||||
Dim Dependencies As New JObject From {{"minecraft", TargetInstance.Version.VanillaName}}
|
||||
If TargetInstance.Version.ModLoaders.HasFlagF(ModLoaders.Forge) Then Dependencies.Add("forge", TargetInstance.Version.ModLoaderVersions(ModLoaders.Forge))
|
||||
If TargetInstance.Version.ModLoaders.HasFlagF(ModLoaders.Fabric) Then Dependencies.Add("fabric-loader", TargetInstance.Version.ModLoaderVersions(ModLoaders.Fabric))
|
||||
If TargetInstance.Version.ModLoaders.HasFlagF(ModLoaders.NeoForge) Then Dependencies.Add("neoforge", TargetInstance.Version.ModLoaderVersions(ModLoaders.NeoForge))
|
||||
Dim ResultJson As New JObject From {
|
||||
{"game", "minecraft"},
|
||||
{"formatVersion", 1},
|
||||
{"versionId", PackVersion},
|
||||
{"name", PackName},
|
||||
{"summary", McVersion.Info},
|
||||
{"summary", TargetInstance.Info},
|
||||
{"files", Files},
|
||||
{"dependencies", Dependencies}
|
||||
}
|
||||
|
||||
@@ -13,21 +13,29 @@
|
||||
</x:Array>
|
||||
</local:MyListItem.Buttons>
|
||||
</local:MyListItem>
|
||||
<local:MyListItem x:Name="ItemMod" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="2" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="Mod 管理"
|
||||
Logo="M789.504 912.896h-195.072a35.328 35.328 0 0 1-34.816-35.328v-77.312a39.936 39.936 0 0 0-40.448-39.936H481.28a40.448 40.448 0 0 0-40.448 39.936v77.312a34.816 34.816 0 0 1-34.816 35.328H204.8a41.984 41.984 0 0 1-40.448-42.496v-200.192a35.328 35.328 0 0 1 35.328-35.328h72.704a39.936 39.936 0 0 0 39.936-39.936v-37.888a39.936 39.936 0 0 0-39.936-40.448H199.68a35.328 35.328 0 0 1-35.328-35.328V287.744A41.984 41.984 0 0 1 204.8 245.76h176.64v-32.768a102.4 102.4 0 0 1 102.4-102.4h33.792a102.4 102.4 0 0 1 102.4 102.4v32.768h170.496a41.984 41.984 0 0 1 41.984 41.984V460.8h28.672a102.4 102.4 0 0 1 102.4 102.4v33.792a102.4 102.4 0 0 1-102.4 102.4h-28.672V870.4a41.984 41.984 0 0 1-43.008 42.496z m-159.744-70.144h131.584V665.6a34.304 34.304 0 0 1 34.816-34.816h64a31.744 31.744 0 0 0 31.744-31.744V563.2a31.744 31.744 0 0 0-31.744-31.744h-64a34.816 34.816 0 0 1-34.816-35.328V316.416h-177.152a35.328 35.328 0 0 1-35.328-35.328V212.992a31.744 31.744 0 0 0-31.744-31.744h-33.792a31.744 31.744 0 0 0-31.744 31.744v68.096a35.328 35.328 0 0 1-34.816 35.328H234.496v130.048h37.888a110.592 110.592 0 0 1 110.08 110.592v37.888a110.592 110.592 0 0 1-110.08 110.592h-37.888v137.216h136.192v-42.496a110.592 110.592 0 0 1 110.592-110.08h37.888a110.592 110.592 0 0 1 110.592 110.08z" >
|
||||
<local:MyListItem x:Name="ItemModify" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="2" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="修改" LogoScale="0.95"
|
||||
Logo="F1 M652.624 145.904c62.256-62.272 163.2-62.272 225.472 0 62.272 62.256 62.272 163.2 0 225.472L477.808 771.664a28.8 28.8 0 0 1-10.816 6.8L242.4 857.376c-47.04 16.544-92.32-28.736-75.776-75.776l78.896-224.592c1.44-4.08 3.76-7.776 6.816-10.816L652.624 145.904z M828.604 195.396a89.44 89.44 0 0 0-126.488 0L308.48 589.032 241.68 781.12 433.768 714.32 828.604 321.884a89.44 89.44 0 0 0 0-126.488z M606.256 194.816a35 35 0 0 1 49.504 0l173.728 173.728a35 35 0 0 1-49.504 49.504L606.256 244.32a35 35 0 0 1 0-49.504z M261.984 539.104a35 35 0 0 1 49.504 0l173.728 173.728a35 35 0 0 1-49.504 49.504L261.984 588.608a35 35 0 0 1 0-49.504z" >
|
||||
<local:MyListItem.Buttons>
|
||||
<x:Array Type="{x:Type local:MyIconButton}">
|
||||
<local:MyIconButton Tag="2" ToolTip="刷新" Click="Refresh_Click" LogoScale="0.85" Logo="M512.0 838.3c-80.2 0-153.4-29.3-210.2-77.4l75.5-75.5c11.5-11.5 25.8-22.0 25.8-37.0a27.2 27.2 0 0 0-27.1-27.1H104.0c-27.1 0-27.1 23.9-27.1 27.1v271.9a27.1 27.1 0 0 0 27.1 27.1c15.0 0 27.8-16.6 42.5-31.2l77.9-77.9c76.6 67.7 177.1 108.9 287.4 108.9 221.7 0 404.5-166.0 431.2-380.6h-109.8c-25.9 154.2-159.7 271.9-321.3 271.9zM919.9 76.6c-15.0 0-27.8 16.6-42.5 31.3L799.5 185.8c-76.5-67.7-177.1-108.9-287.4-108.9-221.8 0-404.5 166.1-431.3 380.6H190.6c25.9-154.2 159.7-271.9 321.4-271.9 80.2 0 153.4 29.3 210.1 77.4l-75.5 75.5c-11.6 11.5-25.8 22.0-25.8 37.1a27.2 27.2 0 0 0 27.1 27.1h271.9c27.1 0 27.1-23.9 27.1-27.1V103.8a27.1 27.1 0 0 0-27.1-27.1z" />
|
||||
</x:Array>
|
||||
</local:MyListItem.Buttons>
|
||||
</local:MyListItem>
|
||||
<local:MyListItem x:Name="ItemModDisabled" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="3" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="Mod 管理"
|
||||
<local:MyListItem x:Name="ItemMod" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="3" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="Mod 管理"
|
||||
Logo="M789.504 912.896h-195.072a35.328 35.328 0 0 1-34.816-35.328v-77.312a39.936 39.936 0 0 0-40.448-39.936H481.28a40.448 40.448 0 0 0-40.448 39.936v77.312a34.816 34.816 0 0 1-34.816 35.328H204.8a41.984 41.984 0 0 1-40.448-42.496v-200.192a35.328 35.328 0 0 1 35.328-35.328h72.704a39.936 39.936 0 0 0 39.936-39.936v-37.888a39.936 39.936 0 0 0-39.936-40.448H199.68a35.328 35.328 0 0 1-35.328-35.328V287.744A41.984 41.984 0 0 1 204.8 245.76h176.64v-32.768a102.4 102.4 0 0 1 102.4-102.4h33.792a102.4 102.4 0 0 1 102.4 102.4v32.768h170.496a41.984 41.984 0 0 1 41.984 41.984V460.8h28.672a102.4 102.4 0 0 1 102.4 102.4v33.792a102.4 102.4 0 0 1-102.4 102.4h-28.672V870.4a41.984 41.984 0 0 1-43.008 42.496z m-159.744-70.144h131.584V665.6a34.304 34.304 0 0 1 34.816-34.816h64a31.744 31.744 0 0 0 31.744-31.744V563.2a31.744 31.744 0 0 0-31.744-31.744h-64a34.816 34.816 0 0 1-34.816-35.328V316.416h-177.152a35.328 35.328 0 0 1-35.328-35.328V212.992a31.744 31.744 0 0 0-31.744-31.744h-33.792a31.744 31.744 0 0 0-31.744 31.744v68.096a35.328 35.328 0 0 1-34.816 35.328H234.496v130.048h37.888a110.592 110.592 0 0 1 110.08 110.592v37.888a110.592 110.592 0 0 1-110.08 110.592h-37.888v137.216h136.192v-42.496a110.592 110.592 0 0 1 110.592-110.08h37.888a110.592 110.592 0 0 1 110.592 110.08z" >
|
||||
<local:MyListItem.Buttons>
|
||||
<x:Array Type="{x:Type local:MyIconButton}">
|
||||
<local:MyIconButton Tag="3" ToolTip="刷新" Click="Refresh_Click" LogoScale="0.85" Logo="M512.0 838.3c-80.2 0-153.4-29.3-210.2-77.4l75.5-75.5c11.5-11.5 25.8-22.0 25.8-37.0a27.2 27.2 0 0 0-27.1-27.1H104.0c-27.1 0-27.1 23.9-27.1 27.1v271.9a27.1 27.1 0 0 0 27.1 27.1c15.0 0 27.8-16.6 42.5-31.2l77.9-77.9c76.6 67.7 177.1 108.9 287.4 108.9 221.7 0 404.5-166.0 431.2-380.6h-109.8c-25.9 154.2-159.7 271.9-321.3 271.9zM919.9 76.6c-15.0 0-27.8 16.6-42.5 31.3L799.5 185.8c-76.5-67.7-177.1-108.9-287.4-108.9-221.8 0-404.5 166.1-431.3 380.6H190.6c25.9-154.2 159.7-271.9 321.4-271.9 80.2 0 153.4 29.3 210.1 77.4l-75.5 75.5c-11.6 11.5-25.8 22.0-25.8 37.1a27.2 27.2 0 0 0 27.1 27.1h271.9c27.1 0 27.1-23.9 27.1-27.1V103.8a27.1 27.1 0 0 0-27.1-27.1z" />
|
||||
</x:Array>
|
||||
</local:MyListItem.Buttons>
|
||||
</local:MyListItem>
|
||||
<local:MyListItem x:Name="ItemModDisabled" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="4" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="Mod 管理"
|
||||
Logo="M789.504 912.896h-195.072a35.328 35.328 0 0 1-34.816-35.328v-77.312a39.936 39.936 0 0 0-40.448-39.936H481.28a40.448 40.448 0 0 0-40.448 39.936v77.312a34.816 34.816 0 0 1-34.816 35.328H204.8a41.984 41.984 0 0 1-40.448-42.496v-200.192a35.328 35.328 0 0 1 35.328-35.328h72.704a39.936 39.936 0 0 0 39.936-39.936v-37.888a39.936 39.936 0 0 0-39.936-40.448H199.68a35.328 35.328 0 0 1-35.328-35.328V287.744A41.984 41.984 0 0 1 204.8 245.76h176.64v-32.768a102.4 102.4 0 0 1 102.4-102.4h33.792a102.4 102.4 0 0 1 102.4 102.4v32.768h170.496a41.984 41.984 0 0 1 41.984 41.984V460.8h28.672a102.4 102.4 0 0 1 102.4 102.4v33.792a102.4 102.4 0 0 1-102.4 102.4h-28.672V870.4a41.984 41.984 0 0 1-43.008 42.496z m-159.744-70.144h131.584V665.6a34.304 34.304 0 0 1 34.816-34.816h64a31.744 31.744 0 0 0 31.744-31.744V563.2a31.744 31.744 0 0 0-31.744-31.744h-64a34.816 34.816 0 0 1-34.816-35.328V316.416h-177.152a35.328 35.328 0 0 1-35.328-35.328V212.992a31.744 31.744 0 0 0-31.744-31.744h-33.792a31.744 31.744 0 0 0-31.744 31.744v68.096a35.328 35.328 0 0 1-34.816 35.328H234.496v130.048h37.888a110.592 110.592 0 0 1 110.08 110.592v37.888a110.592 110.592 0 0 1-110.08 110.592h-37.888v137.216h136.192v-42.496a110.592 110.592 0 0 1 110.592-110.08h37.888a110.592 110.592 0 0 1 110.592 110.08z" />
|
||||
<local:MyListItem x:Name="ItemExport" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="4" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="导出"
|
||||
<local:MyListItem x:Name="ItemExport" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="5" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="导出"
|
||||
Logo="M511 995a128 128 0 0 1-57-13L70 791a126 126 0 0 1-70-113V311a126 126 0 0 1 15-60V248c1-2 3-5 5-8a127 127 0 0 1 49-42L454 13a128 128 0 0 1 112 0l383 190a126 126 0 0 1 72 113v360a126 126 0 0 1-70 115L568 984c-17 7-37 11-57 11z m42-470v370l360-178c14-7 23-21 23-38v-335L554 524zM85 330v347a42 42 0 0 0 23 38l360 178V523L85 330zM135 260l375 189 137-65L286 188 135 260z m245-118l363 197 150-71-365-180a42 42 0 0 0-37 0l-111 53z">
|
||||
<local:MyListItem.Buttons>
|
||||
<x:Array Type="{x:Type local:MyIconButton}">
|
||||
<local:MyIconButton Tag="4" ToolTip="刷新" Click="Refresh_Click" LogoScale="0.85" Logo="M512.0 838.3c-80.2 0-153.4-29.3-210.2-77.4l75.5-75.5c11.5-11.5 25.8-22.0 25.8-37.0a27.2 27.2 0 0 0-27.1-27.1H104.0c-27.1 0-27.1 23.9-27.1 27.1v271.9a27.1 27.1 0 0 0 27.1 27.1c15.0 0 27.8-16.6 42.5-31.2l77.9-77.9c76.6 67.7 177.1 108.9 287.4 108.9 221.7 0 404.5-166.0 431.2-380.6h-109.8c-25.9 154.2-159.7 271.9-321.3 271.9zM919.9 76.6c-15.0 0-27.8 16.6-42.5 31.3L799.5 185.8c-76.5-67.7-177.1-108.9-287.4-108.9-221.8 0-404.5 166.1-431.3 380.6H190.6c25.9-154.2 159.7-271.9 321.4-271.9 80.2 0 153.4 29.3 210.1 77.4l-75.5 75.5c-11.6 11.5-25.8 22.0-25.8 37.1a27.2 27.2 0 0 0 27.1 27.1h271.9c27.1 0 27.1-23.9 27.1-27.1V103.8a27.1 27.1 0 0 0-27.1-27.1z" />
|
||||
<local:MyIconButton Tag="5" ToolTip="刷新" Click="Refresh_Click" LogoScale="0.85" Logo="M512.0 838.3c-80.2 0-153.4-29.3-210.2-77.4l75.5-75.5c11.5-11.5 25.8-22.0 25.8-37.0a27.2 27.2 0 0 0-27.1-27.1H104.0c-27.1 0-27.1 23.9-27.1 27.1v271.9a27.1 27.1 0 0 0 27.1 27.1c15.0 0 27.8-16.6 42.5-31.2l77.9-77.9c76.6 67.7 177.1 108.9 287.4 108.9 221.7 0 404.5-166.0 431.2-380.6h-109.8c-25.9 154.2-159.7 271.9-321.3 271.9zM919.9 76.6c-15.0 0-27.8 16.6-42.5 31.3L799.5 185.8c-76.5-67.7-177.1-108.9-287.4-108.9-221.8 0-404.5 166.1-431.3 380.6H190.6c25.9-154.2 159.7-271.9 321.4-271.9 80.2 0 153.4 29.3 210.1 77.4l-75.5 75.5c-11.6 11.5-25.8 22.0-25.8 37.1a27.2 27.2 0 0 0 27.1 27.1h271.9c27.1 0 27.1-23.9 27.1-27.1V103.8a27.1 27.1 0 0 0-27.1-27.1z" />
|
||||
</x:Array>
|
||||
</local:MyListItem.Buttons>
|
||||
</local:MyListItem>
|
||||
|
||||
@@ -6,6 +6,10 @@ Public Class PageInstanceLeft
|
||||
''' </summary>
|
||||
Public Shared Instance As McInstance = Nothing
|
||||
|
||||
Private Sub PageInstanceLeft_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
|
||||
PageSetupUI.HiddenRefresh()
|
||||
End Sub
|
||||
|
||||
Public Sub RefreshModDisabled() Handles Me.Loaded
|
||||
If Instance IsNot Nothing AndAlso Instance.Modable Then
|
||||
ItemMod.Visibility = Visibility.Visible
|
||||
@@ -26,7 +30,7 @@ Public Class PageInstanceLeft
|
||||
''' <summary>
|
||||
''' 勾选事件改变页面。
|
||||
''' </summary>
|
||||
Private Sub PageCheck(sender As FrameworkElement, e As RouteEventArgs) Handles ItemOverall.Check, ItemMod.Check, ItemModDisabled.Check, ItemSetup.Check, ItemExport.Check
|
||||
Private Sub PageCheck(sender As FrameworkElement, e As RouteEventArgs) Handles ItemOverall.Check, ItemMod.Check, ItemModDisabled.Check, ItemSetup.Check, ItemModify.Check, ItemExport.Check
|
||||
'尚未初始化控件属性时,sender.Tag 为 Nothing,会导致切换到页面 0
|
||||
'若使用 IsLoaded,则会导致模拟点击不被执行(模拟点击切换页面时,控件的 IsLoaded 为 False)
|
||||
If sender.Tag IsNot Nothing Then PageChange(Val(sender.Tag))
|
||||
@@ -45,11 +49,14 @@ Public Class PageInstanceLeft
|
||||
If FrmInstanceModDisabled Is Nothing Then FrmInstanceModDisabled = New PageInstanceModDisabled
|
||||
Return FrmInstanceModDisabled
|
||||
Case FormMain.PageSubType.InstanceSetup
|
||||
If IsNothing(FrmInstanceSetup) Then FrmInstanceSetup = New PageInstanceSetup
|
||||
If FrmInstanceSetup Is Nothing Then FrmInstanceSetup = New PageInstanceSetup
|
||||
Return FrmInstanceSetup
|
||||
Case FormMain.PageSubType.InstanceExport
|
||||
If FrmInstanceExport Is Nothing Then FrmInstanceExport = New PageInstanceExport
|
||||
Return FrmInstanceExport
|
||||
Case FormMain.PageSubType.InstanceModify
|
||||
If FrmDownloadModify Is Nothing Then FrmDownloadModify = New PageDownloadModify
|
||||
Return FrmDownloadModify
|
||||
Case Else
|
||||
Throw New Exception("未知的版本设置子页面种类:" & ID)
|
||||
End Select
|
||||
@@ -60,6 +67,10 @@ Public Class PageInstanceLeft
|
||||
''' </summary>
|
||||
Public Sub PageChange(ID As FormMain.PageSubType)
|
||||
If PageID = ID Then Return
|
||||
If Instance IsNot Nothing AndAlso McInstanceLock.IsLocked(Instance) Then
|
||||
Hint("该版本正在被修改,请稍后再切换页面!", HintType.Red)
|
||||
Return
|
||||
End If
|
||||
AniControlEnabled += 1
|
||||
Try
|
||||
PageChangeRun(PageGet(ID))
|
||||
@@ -98,13 +109,20 @@ Public Class PageInstanceLeft
|
||||
Refresh(FrmMain.PageCurrentSub)
|
||||
End Sub
|
||||
Public Sub Refresh(SubType As FormMain.PageSubType)
|
||||
If Instance IsNot Nothing AndAlso McInstanceLock.IsLocked(Instance) Then
|
||||
Hint("该版本正在被修改,请稍后再刷新!", HintType.Red)
|
||||
Return
|
||||
End If
|
||||
Select Case SubType
|
||||
Case FormMain.PageSubType.InstanceMod
|
||||
PageInstanceMod.Refresh()
|
||||
ItemMod.Checked = True
|
||||
Case FormMain.PageSubType.InstanceExport
|
||||
If FrmInstanceExport IsNot Nothing Then FrmInstanceExport.RefreshAll()
|
||||
FrmInstanceExport?.RefreshAll()
|
||||
ItemExport.Checked = True
|
||||
Case FormMain.PageSubType.InstanceModify
|
||||
FrmDownloadModify?.PageLoaderRestart()
|
||||
ItemModify.Checked = True
|
||||
End Select
|
||||
End Sub
|
||||
|
||||
|
||||
@@ -284,7 +284,7 @@ Public Class PageInstanceMod
|
||||
''' 返回输入的文件是否为一个 Mod 文件,仅用于判断拖拽行为。
|
||||
''' </summary>
|
||||
Public Shared Function InstallMods(FilePathList As IEnumerable(Of String)) As Boolean
|
||||
Dim Extension As String = FilePathList.First.AfterLast(".").Lower
|
||||
Dim Extension As String = PathUtils.GetExtension(FilePathList.First)
|
||||
'检查文件扩展名
|
||||
If Not {"jar", "litemod", "disabled", "old"}.Any(Function(t) t = Extension) Then Return False
|
||||
Logger.Info("文件为 jar/litemod 格式,尝试作为 Mod 安装")
|
||||
@@ -307,15 +307,15 @@ Public Class PageInstanceMod
|
||||
Install:
|
||||
Try
|
||||
For Each ModFile In FilePathList
|
||||
Dim NewFileName = PathUtils.GetLastPart(ModFile).Replace(".disabled", "").Replace(".old", "")
|
||||
Dim NewFileName = (New LocalResourceFile(ModFile)).EnabledName
|
||||
If Not NewFileName.Contains(".") Then NewFileName += ".jar" '#4227
|
||||
NewFileName = Instance.PathIndie & "mods\" & NewFileName
|
||||
If ModFile = NewFileName Then Continue For '防止安装相同文件导致文件被删除
|
||||
If PathUtils.IsSame(ModFile, NewFileName) Then Continue For '防止安装相同文件导致文件被删除
|
||||
FileUtils.Delete(NewFileName, True)
|
||||
FileUtils.Copy(ModFile, NewFileName)
|
||||
Next
|
||||
If FilePathList.IsSingle Then
|
||||
Hint($"已安装 {PathUtils.GetLastPart(FilePathList.First).Replace(".disabled", "").Replace(".old", "")}!", HintType.Green)
|
||||
Hint($"已安装 {(New LocalResourceFile(FilePathList.First)).EnabledName}!", HintType.Green)
|
||||
Else
|
||||
Hint($"已安装 {FilePathList.Count} 个 Mod!", HintType.Green)
|
||||
End If
|
||||
@@ -553,8 +553,8 @@ Install:
|
||||
Dim File As ResourceVersion = Entry.UpdateFile
|
||||
If Not File.DownloadAvailable Then Continue For
|
||||
'确认更新后的文件名
|
||||
Dim CurrentReplaceName = Entry.ProjectVersion.FileName.Replace(".jar", "").Replace(".old", "").Replace(".disabled", "")
|
||||
Dim NewestReplaceName = Entry.UpdateFile.FileName.Replace(".jar", "").Replace(".old", "").Replace(".disabled", "")
|
||||
Dim CurrentReplaceName = PathUtils.GetFileNameWithoutExtension(Entry.ProjectVersion.FileName)
|
||||
Dim NewestReplaceName = PathUtils.GetFileNameWithoutExtension(Entry.UpdateFile.FileName)
|
||||
Dim CurrentSegs = CurrentReplaceName.Split("-"c).ToList()
|
||||
Dim NewestSegs = NewestReplaceName.Split("-"c).ToList()
|
||||
Dim Shortened As Boolean = False
|
||||
|
||||
@@ -104,51 +104,21 @@ Public Class PageInstanceOverall
|
||||
'重命名版本
|
||||
Private Sub BtnDisplayRename_Click(sender As Object, e As EventArgs) Handles BtnDisplayRename.Click
|
||||
Try
|
||||
If McInstanceLock.IsLocked(PageInstanceLeft.Instance) Then
|
||||
Hint("该版本正在被修改,请稍后再重命名!", HintType.Red)
|
||||
Return
|
||||
End If
|
||||
'确认输入的新名称
|
||||
Dim OldName As String = PageInstanceLeft.Instance.Name
|
||||
Dim OldPath As String = PageInstanceLeft.Instance.PathVersion
|
||||
'修改此部分的同时修改快速安装的版本名检测*
|
||||
Dim NewName As String = MyMsgBoxInput("重命名版本", "", OldName, New ObjectModel.Collection(Of Validate) From {
|
||||
New ValidateFolderName(McFolderSelected & "versions", IgnoreList:=New List(Of String) From {OldName})
|
||||
})
|
||||
If String.IsNullOrWhiteSpace(NewName) Then Return
|
||||
Dim NewPath As String = McFolderSelected & "versions\" & NewName & "\"
|
||||
'重新读取版本 JSON 信息,避免 JsonObject 中已被合并的项被重新存储
|
||||
Dim JsonObject As JObject
|
||||
Dim OldJsonPath As String = PageInstanceLeft.Instance.GetJsonPath()
|
||||
Try
|
||||
JsonObject = FileUtils.ReadAsJson(OldJsonPath)
|
||||
Catch ex As Exception
|
||||
Logger.Warn(ex, "在重命名读取 JSON 时失败")
|
||||
JsonObject = PageInstanceLeft.Instance.JsonObject
|
||||
End Try
|
||||
'重命名主文件夹
|
||||
DirectoryUtils.Move(OldPath, NewPath)
|
||||
'清理 ini 缓存
|
||||
PageInstanceLeft.Instance.ResetSettingsCache()
|
||||
'重命名 jar 文件与 natives 文件夹
|
||||
'不能进行遍历重命名,否则在版本名很短的时候容易误伤其他文件(#6443)
|
||||
If DirectoryUtils.Exists($"{NewPath}{OldName}-natives") Then DirectoryUtils.Move($"{NewPath}{OldName}-natives", $"{NewPath}{NewName}-natives")
|
||||
If FileUtils.Exists($"{NewPath}{OldName}.jar") Then FileUtils.Move($"{NewPath}{OldName}.jar", $"{NewPath}{NewName}.jar")
|
||||
'替换版本设置文件中的路径
|
||||
If FileUtils.Exists(NewPath & "PCL\Setup.ini") Then
|
||||
FileUtils.Write(NewPath & "PCL\Setup.ini", FileUtils.ReadAsString(NewPath & "PCL\Setup.ini").Replace(OldPath, NewPath))
|
||||
End If
|
||||
'更改已选中的版本
|
||||
If ReadIni(McFolderSelected & "PCL.ini", "Version") = OldName Then
|
||||
WriteIni(McFolderSelected & "PCL.ini", "Version", NewName)
|
||||
End If
|
||||
'更新版本 Json
|
||||
Try
|
||||
JsonObject("id") = NewName
|
||||
FileUtils.Delete(NewPath & PathUtils.GetLastPart(OldJsonPath))
|
||||
FileUtils.Write(NewPath & NewName & ".json", JsonObject.ToString)
|
||||
Catch ex As Exception
|
||||
Logger.Warn(ex, "重命名版本 json 失败")
|
||||
End Try
|
||||
Dim NewInstance = PageInstanceLeft.Instance.Rename(NewName)
|
||||
'刷新与提示
|
||||
Hint("重命名成功!", HintType.Green)
|
||||
PageInstanceLeft.Instance = New McInstance(NewName).Load()
|
||||
PageInstanceLeft.Instance = NewInstance
|
||||
If Not IsNothing(McInstanceSelected) AndAlso McInstanceSelected.Equals(PageInstanceLeft.Instance) Then WriteIni(McFolderSelected & "PCL.ini", "Version", NewName)
|
||||
Reload()
|
||||
LoaderFolderRun(McInstanceListLoader, McFolderSelected, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\")
|
||||
@@ -267,6 +237,10 @@ Public Class PageInstanceOverall
|
||||
'补全文件
|
||||
Private Sub BtnManageCheck_Click(sender As Object, e As EventArgs) Handles BtnManageCheck.Click
|
||||
Try
|
||||
If McInstanceLock.IsLocked(PageInstanceLeft.Instance) Then
|
||||
Hint("该版本正在被修改,请稍后再补全文件!", HintType.Red)
|
||||
Return
|
||||
End If
|
||||
'忽略文件检查提示
|
||||
If ShouldIgnoreFileCheck(PageInstanceLeft.Instance) Then
|
||||
Hint("请先关闭 [版本设置 → 设置 → 高级启动选项 → 关闭文件校验],然后再尝试补全文件!", HintType.Blue)
|
||||
@@ -304,8 +278,12 @@ Public Class PageInstanceOverall
|
||||
'修改此代码时,同时修改 PageSelectRight 中的代码
|
||||
Private Sub BtnManageDelete_Click(sender As Object, e As EventArgs) Handles BtnManageDelete.Click
|
||||
Try
|
||||
If McInstanceLock.IsLocked(PageInstanceLeft.Instance) Then
|
||||
Hint("该版本正在被修改,请稍后再删除!", HintType.Red)
|
||||
Return
|
||||
End If
|
||||
Dim IsShiftPressed As Boolean = My.Computer.Keyboard.ShiftKeyDown
|
||||
Dim IsHintIndie As Boolean = PageInstanceLeft.Instance.State <> McInstanceState.Error AndAlso PageInstanceLeft.Instance.PathIndie <> McFolderSelected
|
||||
Dim IsHintIndie As Boolean = PageInstanceLeft.Instance.State <> McInstance.McInstanceState.Error AndAlso PageInstanceLeft.Instance.PathIndie <> McFolderSelected
|
||||
Dim SavesFolder = DirectoryUtils.GetInfo(PageInstanceLeft.Instance.PathIndie & "saves\")
|
||||
Dim SaveEntries = If(IsHintIndie AndAlso SavesFolder.Exists, SavesFolder.EnumerateDirectories.OrderByDescending(Function(Save) Save.LastWriteTime).Select(Function(Save) $"{Save.Name}(上次修改:{StringUtils.FormatTimeSpan(Save.LastWriteTime - Date.Now, False)})").ToList, New List(Of String))
|
||||
Select Case MyMsgBox($"你确定要{If(IsShiftPressed, "永久", "")}删除版本 {PageInstanceLeft.Instance.Name} 吗?" &
|
||||
|
||||
@@ -499,7 +499,7 @@ PreFin:
|
||||
ComboArgumentJavaSelect.Items.Add(JavaItem)
|
||||
Dim Buttons As New List(Of MyIconButton)
|
||||
'从列表中移除按钮
|
||||
Dim IsOfficial As Boolean = JavaEntry.Folder.StartsWithF($"{Paths.AppData}.minecraft\runtime\")
|
||||
Dim IsOfficial As Boolean = PathUtils.IsParentOf($"{Paths.AppData}.minecraft\runtime\", JavaEntry.Folder)
|
||||
Dim DeleteButton As New MyIconButton With {.Logo = Logo.IconButtonStop, .Height = 24, .Width = 24}
|
||||
DeleteButton.IsEnabled = Not IsOfficial
|
||||
DeleteButton.ToolTip = If(DeleteButton.IsEnabled, "从列表中移除", "无法移除官方 Java")
|
||||
|
||||
@@ -65,7 +65,7 @@ Public Class PageLaunchLeft
|
||||
'确认 Minecraft 版本存在
|
||||
Dim Selection As String = ReadIni(McFolderSelected & "PCL.ini", "Version")
|
||||
Dim Instance As McInstance = If(Selection = "", Nothing, New McInstance(Selection))
|
||||
If Instance Is Nothing OrElse Not Instance.PathVersion.StartsWithF(McFolderSelected) OrElse Not Instance.Check() Then
|
||||
If Instance Is Nothing OrElse Not PathUtils.IsParentOf(McFolderSelected, Instance.PathVersion) OrElse Not Instance.Check() Then
|
||||
'无效的版本
|
||||
Logger.Info($"当前选择的 Minecraft 版本无效:{If(Instance Is Nothing, "null", Instance.PathVersion)}", If(IsNothing(Instance), LogBehavior.None, LogBehavior.ToastIfDebug))
|
||||
If Not McInstanceListLoader.State = LoadState.Finished Then LoaderFolderRun(McInstanceListLoader, McFolderSelected, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\", WaitForExit:=True)
|
||||
@@ -691,12 +691,28 @@ ExitRefresh:
|
||||
End If
|
||||
End Sub
|
||||
'取消按钮
|
||||
Private Sub BtnCancel_Click() Handles BtnCancel.Click
|
||||
McLaunchCancel()
|
||||
Public Sub BtnCancel_Click() Handles BtnCancel.Click
|
||||
If McLaunchLoaderReal IsNot Nothing Then
|
||||
McLaunchLoaderReal.Cancel()
|
||||
McLaunchLog("已取消启动")
|
||||
Try
|
||||
If McLaunchWatcher IsNot Nothing Then
|
||||
McLaunchWatcher.Kill()
|
||||
ElseIf McLaunchProcess IsNot Nothing Then
|
||||
If Not McLaunchProcess.HasExited Then McLaunchProcess.Kill()
|
||||
End If
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex, "取消启动结束进程失败", LogBehavior.Toast)
|
||||
End Try
|
||||
End If
|
||||
End Sub
|
||||
'版本设置按钮
|
||||
Private Sub BtnMore_Click() Handles BtnMore.Click
|
||||
If McLaunchLoader.State = LoadState.Loading Then Return
|
||||
If McInstanceLock.IsLocked(McInstanceSelected) Then
|
||||
Hint("该版本正在被修改,暂时无法进入版本设置!", HintType.Red)
|
||||
Return
|
||||
End If
|
||||
McInstanceSelected.Load()
|
||||
PageInstanceLeft.Instance = McInstanceSelected
|
||||
FrmMain.PageChange(FormMain.PageType.InstanceSetup, 0)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:behaviors="clr-namespace:PCL.Controls.Behaviors"
|
||||
xmlns:local="clr-namespace:PCL" PanScroll="PanBack">
|
||||
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
|
||||
<StackPanel Name="PanMain" Margin="25,25,25,10" Grid.IsSharedSizeScope="True">
|
||||
@@ -11,8 +12,10 @@
|
||||
<StackPanel x:Name="PanCustom">
|
||||
</StackPanel>
|
||||
<local:MyCard Margin="0,0,0,15" Title="启动日志" x:Name="PanLog">
|
||||
<TextBlock x:Name="LabLog" Margin="20,38,20,18" TextTrimming="None" TextWrapping="Wrap" />
|
||||
<local:MyTextBox x:Name="LabLog" Margin="15,34,15,13" Padding="0,4" IsReadOnly="True" IsUndoEnabled="False"
|
||||
AcceptsReturn="True" TextWrapping="Wrap" BorderThickness="0" HasBackground="False"
|
||||
VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Disabled" />
|
||||
</local:MyCard>
|
||||
</StackPanel>
|
||||
</local:MyScrollViewer>
|
||||
</local:MyPageRight>
|
||||
</local:MyPageRight>
|
||||
|
||||
@@ -101,19 +101,34 @@ Public Class PageLaunchRight
|
||||
Url = "https://pcl.wyc-w.top/index.xaml"
|
||||
Case 15
|
||||
Logger.Info("主页预设:Minecraft 芝士站")
|
||||
Url = "https://www.xxag.top/mkss"
|
||||
Url = "https://mkss-services.awaeric.xyz"
|
||||
Case 16
|
||||
Logger.Info("主页预设:整合包推荐引擎")
|
||||
Url = "https://qawsedrftgyhujiko.fun/pcl2/Custom.xaml"
|
||||
Case 17
|
||||
Logger.Info("Bangumi 番剧主页")
|
||||
Url = "https://bangumi.p.kaphia.qzz.io"
|
||||
Logger.Info("主页预设:Bangumi 番剧主页")
|
||||
Url = "https://bangumi.p.kaphia.top"
|
||||
Case 18
|
||||
Logger.Info("Bilibili 热门")
|
||||
Url = "https://bilibili.p.kaphia.qzz.io"
|
||||
Logger.Info("主页预设:Bilibili 热门")
|
||||
Url = "https://bilibili.p.kaphia.top"
|
||||
Case 19
|
||||
Logger.Info("Music 云音乐热门")
|
||||
Url = "https://cloudmusic.p.kaphia.qzz.io"
|
||||
Logger.Info("主页预设:Music 云音乐热门")
|
||||
Url = "https://cloudmusic.p.kaphia.top"
|
||||
Case 20
|
||||
Logger.Info("主页预设:模组推荐")
|
||||
Url = "https://g-fish.dpdns.org/download/ModPage.xaml"
|
||||
Case 21
|
||||
Logger.Info("主页预设:每日游戏推荐")
|
||||
Url = "https://pcl.xn--9iq209asnop94b.top/download/GamePage.xaml"
|
||||
Case 22
|
||||
Logger.Info("主页预设:Wallpaper 每日壁纸")
|
||||
Url = "https://wallpaper.p.kaphia.top"
|
||||
Case 23
|
||||
Logger.Info("主页预设:Weather 天气预报")
|
||||
Url = "https://weather-p.kaphia.top/{variable:PCLDailyWeatherPage:choose}.xaml"
|
||||
Case 24
|
||||
Logger.Info("主页预设:新一代狗屁王大杂烩主页")
|
||||
Url = "https://end.g-fish.dpdns.org/Custom.xaml"
|
||||
End Select
|
||||
End Select
|
||||
'联网下载
|
||||
|
||||
@@ -45,7 +45,7 @@ Public Class PageLoginLegacy
|
||||
If LoginData.UserName.Trim = "" Then Return "玩家名不能为空!"
|
||||
If LoginData.UserName.Contains("""") Then Return "玩家名不能包含英文引号!"
|
||||
If McInstanceSelected IsNot Nothing AndAlso
|
||||
McInstanceSelected.Version.Vaild AndAlso McInstanceSelected.Version.Vanilla >= New Version(20, 0, 3) AndAlso
|
||||
McInstanceSelected.Version.Valid AndAlso McInstanceSelected.Version.Vanilla >= New Version(20, 0, 3) AndAlso
|
||||
LoginData.UserName.Trim.Length > 16 Then
|
||||
Return "自 1.20.3 起,玩家名至多只能包含 16 个字符!"
|
||||
End If
|
||||
|
||||
@@ -358,8 +358,9 @@ Public Class PageLinkMain
|
||||
'复制邀请码
|
||||
Private Sub Copy() Handles BtnFinishCopy.Click
|
||||
Dim CodeText As String = $"在 PCL 启动器中输入邀请码【{GetInviteCode()}】,即可加入联机房间!"
|
||||
ClipboardSet(CodeText, SuccessHint:="已复制邀请码!")
|
||||
ClipboardSet(CodeText, False)
|
||||
Settings.Set("LinkLastAutoJoinInviteCode", CodeText)
|
||||
Hint("已复制邀请码!", HintType.Green)
|
||||
End Sub
|
||||
Private Function GetInviteCode() As String
|
||||
Return $"{NetworkName}-{NetworkSecret}-{INVITE_CODE_VERSION.ToString.PadLeft(2, "0"c)}{ _
|
||||
@@ -368,7 +369,8 @@ Public Class PageLinkMain
|
||||
|
||||
'复制 IP
|
||||
Private Sub BtnFinishIp_MouseLeftButtonUp(sender As Object, e As MouseButtonEventArgs) Handles BtnFinishIp.MouseLeftButtonUp
|
||||
ClipboardSet(ClientAddress, SuccessHint:="已复制服务器地址!")
|
||||
ClipboardSet(ClientAddress, False)
|
||||
Hint("已复制服务器地址!", HintType.Green)
|
||||
End Sub
|
||||
|
||||
#End Region
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -48,12 +48,13 @@ Public Class PageOtherHelp
|
||||
If Item.Types.Contains(Type) Then TypeItems.Add(Item)
|
||||
Next
|
||||
'增加卡片
|
||||
Dim NewCard As New MyCard With {.Title = Type, .Margin = New Thickness(0, 0, 0, 15), .SwapType = 11}
|
||||
Dim NewStack As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0), .Tag = TypeItems}
|
||||
Dim NewCard As New MyCard With {.Title = Type, .Margin = New Thickness(0, 0, 0, 15)}
|
||||
Dim NewStack As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0)}
|
||||
NewCard.Children.Add(NewStack)
|
||||
NewCard.SwapControl = NewStack
|
||||
NewCard.SetContentBuilder(TypeItems, Function(Entry) Entry.ToListItem)
|
||||
If Type = "指南" Then
|
||||
MyCard.StackInstall(NewStack, 11, "指南")
|
||||
NewCard.BuildContent()
|
||||
Else
|
||||
NewCard.IsSwapped = True
|
||||
End If
|
||||
|
||||
@@ -64,7 +64,7 @@ Public Class PageSelectLeft
|
||||
</ContextMenu>
|
||||
)
|
||||
End Select
|
||||
If (Folder.Type = McFolder.Types.Vanilla OrElse Folder.Type = McFolder.Types.RenamedVanilla) AndAlso Folder.Location = Paths.Base & ".minecraft\" AndAlso McFolderList.IsSingle Then CType(ContMenu.FindName("Delete"), MyMenuItem).Header = "清空"
|
||||
If (Folder.Type = McFolder.Types.Vanilla OrElse Folder.Type = McFolder.Types.RenamedVanilla) AndAlso PathUtils.IsSame(Folder.Location, Paths.Base & ".minecraft\") AndAlso McFolderList.IsSingle Then CType(ContMenu.FindName("Delete"), MyMenuItem).Header = "清空"
|
||||
'注册事件
|
||||
If Not Folder.Type = McFolder.Types.Vanilla Then CType(ContMenu.FindName("Remove"), MyMenuItem).AddHandler(MyMenuItem.ClickEvent, New RoutedEventHandler(AddressOf FrmSelectLeft.Remove_Click))
|
||||
CType(ContMenu.FindName("Open"), MyMenuItem).AddHandler(MyMenuItem.ClickEvent, New RoutedEventHandler(AddressOf FrmSelectLeft.Open_Click))
|
||||
@@ -116,7 +116,7 @@ Public Class PageSelectLeft
|
||||
|
||||
'确认勾选状态
|
||||
For i = 0 To McFolderList.Count - 1
|
||||
If McFolderList(i).Location = McFolderSelected Then
|
||||
If PathUtils.IsSame(McFolderList(i).Location, McFolderSelected) Then
|
||||
CType(FrmSelectLeft.PanList.Children(i + 1), MyListItem).Checked = True '去掉第一个标题
|
||||
Return
|
||||
End If
|
||||
@@ -139,9 +139,9 @@ Public Class PageSelectLeft
|
||||
'添加文件夹
|
||||
Public Sub Add_Click()
|
||||
Dim NewFolder As String = ""
|
||||
'检查是否有下载任务
|
||||
If HasDownloadingTask() Then
|
||||
Hint("在下载任务进行时,无法添加游戏文件夹!", HintType.Red)
|
||||
'下载或版本修改期间禁止更改游戏文件夹
|
||||
If McInstanceLock.IsAnyLocked OrElse HasDownloadingTask() Then
|
||||
Hint("请在其他任务完成后,再添加游戏文件夹!", HintType.Red)
|
||||
Return
|
||||
End If
|
||||
Try
|
||||
@@ -150,8 +150,11 @@ Public Class PageSelectLeft
|
||||
If NewFolder Is Nothing Then Return
|
||||
If NewFolder.Contains("!") OrElse NewFolder.Contains(";") Then Hint("Minecraft 文件夹路径中不能含有感叹号或分号!", HintType.Red) : Return
|
||||
'要求输入显示名称
|
||||
Dim SplitedNames As String() = NewFolder.TrimEnd("\").Split("\")
|
||||
Dim DefaultName As String = If(SplitedNames.Last = ".minecraft", If(SplitedNames.Count >= 3, SplitedNames(SplitedNames.Count - 2), ""), SplitedNames.Last)
|
||||
Dim DefaultName = PathUtils.GetLastPart(NewFolder)
|
||||
If DefaultName = ".minecraft" Then
|
||||
Dim ParentFolder = PathUtils.RemoveLastPart(NewFolder)
|
||||
DefaultName = If(ParentFolder.EndsWithF(":"), "", PathUtils.GetLastPart(ParentFolder))
|
||||
End If
|
||||
If DefaultName.Length > 40 Then DefaultName = DefaultName.Substring(0, 39)
|
||||
Dim NewName As String = MyMsgBoxInput("输入显示名称", "输入该文件夹在左边栏列表中显示的名称。", DefaultName,
|
||||
New ObjectModel.Collection(Of Validate) From {New ValidateNullOrWhiteSpace, New ValidateLength(1, 30), New ValidateExcept({">", "|"})})
|
||||
@@ -169,7 +172,7 @@ Public Class PageSelectLeft
|
||||
RunInThread(
|
||||
Sub()
|
||||
Try
|
||||
If Not FolderPath.EndsWithF("\") Then FolderPath &= "\"
|
||||
FolderPath = PathUtils.AddSlashSuffix(FolderPath)
|
||||
'检查文件夹权限
|
||||
If Not CheckPermission(FolderPath) Then
|
||||
If ShowHint Then
|
||||
@@ -195,7 +198,7 @@ Public Class PageSelectLeft
|
||||
For i = 0 To Folders.Count - 1
|
||||
Dim Folder As String = Folders(i)
|
||||
If Folder = "" Then Continue For
|
||||
If Folder.Split(">")(1) = FolderPath Then
|
||||
If PathUtils.IsSame(Folder.Split(">")(1), FolderPath) Then
|
||||
IsAdded = True
|
||||
If Folder.Split(">")(0) = DisplayName Then
|
||||
If ShowHint Then Hint("此文件夹已在列表中!", HintType.Blue)
|
||||
@@ -246,9 +249,9 @@ Public Class PageSelectLeft
|
||||
|
||||
'创建文件夹
|
||||
Public Sub Create_Click()
|
||||
'检查是否有下载任务
|
||||
If HasDownloadingTask() Then
|
||||
Hint("在下载任务进行时,无法创建游戏文件夹!", HintType.Red)
|
||||
'下载或版本修改期间禁止更改游戏文件夹
|
||||
If McInstanceLock.IsAnyLocked OrElse HasDownloadingTask() Then
|
||||
Hint("请在其他任务完成后,再创建游戏文件夹!", HintType.Red)
|
||||
Return
|
||||
End If
|
||||
CreateMcFolderInCurrentPath()
|
||||
@@ -270,6 +273,10 @@ Public Class PageSelectLeft
|
||||
Dim Target As McFolder = CType(CType(CType(sender.Parent, ContextMenu).Parent, Primitives.Popup).PlacementTarget, MyListItem).Tag
|
||||
'若为 “移除”,则提醒是否删除 PCL 的配置文件
|
||||
If Target.Type = McFolder.Types.Custom Then
|
||||
If McInstanceLock.IsAnyLocked OrElse HasDownloadingTask() Then
|
||||
Hint("请在其他任务完成后,再移除游戏文件夹!", HintType.Red)
|
||||
Return
|
||||
End If
|
||||
Select Case MyMsgBox("是否需要清理 PCL 在该文件夹中的配置文件?" & vbCrLf & "这包括各个版本的独立设置(如自定义图标、第三方登录配置)等,对游戏本身没有影响。", "配置文件清理", "删除", "保留", "取消")
|
||||
Case 1
|
||||
'删除配置文件
|
||||
@@ -292,6 +299,10 @@ Public Class PageSelectLeft
|
||||
End Try
|
||||
End Sub
|
||||
Public Sub Delete_Click(sender As Object, e As RoutedEventArgs)
|
||||
If McInstanceLock.IsAnyLocked OrElse HasDownloadingTask() Then
|
||||
Hint("请在其他任务完成后,再删除游戏文件夹!", HintType.Red)
|
||||
Return
|
||||
End If
|
||||
Dim Target As McFolder = CType(CType(CType(sender.Parent, ContextMenu).Parent, Primitives.Popup).PlacementTarget, MyListItem).Tag
|
||||
Dim DeleteText As String = If((Target.Type = McFolder.Types.Vanilla OrElse Target.Type = McFolder.Types.RenamedVanilla) AndAlso Target.Location = Paths.Base & ".minecraft\" AndAlso McFolderList.IsSingle, "清空", "删除")
|
||||
If MyMsgBox("你确定要" & DeleteText & "这个文件夹吗?" & vbCrLf &
|
||||
@@ -328,7 +339,7 @@ Public Class PageSelectLeft
|
||||
Dim DeletedName As String = Nothing
|
||||
Dim Folders = Settings.Get(Of String)("LaunchFolders").Split("|"c, True).ToList
|
||||
For Each Folder In Folders.ToList
|
||||
If Not Folder.EndsWithF(Target.Location) Then Continue For
|
||||
If Not Folder.Contains(">") OrElse Not PathUtils.IsSame(Folder.AfterFirst(">"), Target.Location) Then Continue For
|
||||
DeletedName = Folder.BeforeFirst(">")
|
||||
Folders.Remove(Folder)
|
||||
Exit For
|
||||
@@ -349,7 +360,7 @@ Public Class PageSelectLeft
|
||||
End Sub
|
||||
Public Shared Sub RefreshCurrent(Folder As String)
|
||||
WriteIni(Folder & "PCL.ini", "InstanceCache", "") '删除缓存以强制要求下一次加载时更新列表
|
||||
If Folder = McFolderSelected Then LoaderFolderRun(McInstanceListLoader, McFolderSelected, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\")
|
||||
If PathUtils.IsSame(Folder, McFolderSelected) Then LoaderFolderRun(McInstanceListLoader, McFolderSelected, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\")
|
||||
End Sub
|
||||
Public Sub Rename_Click(sender As Object, e As RoutedEventArgs)
|
||||
Dim Folder As McFolder = CType(CType(CType(sender.Parent, ContextMenu).Parent, Primitives.Popup).PlacementTarget, MyListItem).Tag
|
||||
@@ -365,7 +376,7 @@ Public Class PageSelectLeft
|
||||
For i = 0 To Folders.Count - 1
|
||||
Dim FolderCurrent As String = Folders(i)
|
||||
If FolderCurrent = "" Then Continue For
|
||||
If FolderCurrent.Split(">")(1) = Folder.Location Then
|
||||
If PathUtils.IsSame(FolderCurrent.Split(">")(1), Folder.Location) Then
|
||||
IsAdded = True
|
||||
If FolderCurrent.Split(">")(0) = NewName Then
|
||||
'名称未修改
|
||||
@@ -390,9 +401,9 @@ Public Class PageSelectLeft
|
||||
'点击选项
|
||||
Public Sub Folder_Change(sender As MyListItem, e As RouteEventArgs)
|
||||
If Not e.RaiseByMouse OrElse Not sender.Checked Then Return
|
||||
'检查是否有下载任务
|
||||
If HasDownloadingTask(True) Then
|
||||
Hint("在下载任务进行时,无法切换游戏文件夹!", HintType.Red)
|
||||
'下载或版本修改期间禁止更改游戏文件夹
|
||||
If McInstanceLock.IsAnyLocked OrElse HasDownloadingTask(True) Then
|
||||
Hint("请在其他任务完成后,再切换游戏文件夹!", HintType.Red)
|
||||
e.Handled = True
|
||||
Return
|
||||
End If
|
||||
|
||||
@@ -30,6 +30,8 @@ Public Class PageSelectRight
|
||||
For Each Card As KeyValuePair(Of McInstanceCardType, List(Of McInstance)) In McInstanceList.ToArray
|
||||
'确认是否为隐藏版本显示状态
|
||||
If Card.Key = McInstanceCardType.Hidden Xor ShowHidden Then Continue For
|
||||
Dim Instances = Card.Value.Where(Function(Instance) Not McInstanceLock.IsLocked(Instance)).ToList
|
||||
If Not Instances.Any Then Continue For
|
||||
#Region "确认卡片名称"
|
||||
Dim CardName As String = ""
|
||||
Select Case Card.Key
|
||||
@@ -40,11 +42,11 @@ Public Class PageSelectRight
|
||||
Dim IsNeoForgeExists As Boolean = False
|
||||
Dim IsFabricExists As Boolean = False
|
||||
Dim IsLiteExists As Boolean = False
|
||||
For Each Instance As McInstance In Card.Value
|
||||
If Instance.Version.HasFabric Then IsFabricExists = True
|
||||
If Instance.Version.HasLiteLoader Then IsLiteExists = True
|
||||
If Instance.Version.HasForge Then IsForgeExists = True
|
||||
If Instance.Version.HasNeoForge Then IsNeoForgeExists = True
|
||||
For Each Instance As McInstance In Instances
|
||||
If Instance.Version.ModLoaders.HasFlagF(ModLoaders.Fabric) Then IsFabricExists = True
|
||||
If Instance.Version.ModLoaders.HasFlagF(ModLoaders.LiteLoader) Then IsLiteExists = True
|
||||
If Instance.Version.ModLoaders.HasFlagF(ModLoaders.Forge) Then IsForgeExists = True
|
||||
If Instance.Version.ModLoaders.HasFlagF(ModLoaders.NeoForge) Then IsNeoForgeExists = True
|
||||
Next
|
||||
If If(IsLiteExists, 1, 0) + If(IsForgeExists, 1, 0) + If(IsFabricExists, 1, 0) + If(IsNeoForgeExists, 1, 0) > 1 Then
|
||||
CardName = "可安装 Mod"
|
||||
@@ -72,17 +74,18 @@ Public Class PageSelectRight
|
||||
End Select
|
||||
#End Region
|
||||
'建立控件
|
||||
Dim CardTitle As String = CardName & If(CardName = "收藏夹", "", " (" & Card.Value.Count & ")")
|
||||
Dim NewCard As New MyCard With {.Title = CardTitle, .Margin = New Thickness(0, 0, 0, 15), .SwapType = 0}
|
||||
Dim NewStack As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0), .Tag = Card.Value}
|
||||
Dim CardTitle As String = CardName & If(CardName = "收藏夹", "", " (" & Instances.Count & ")")
|
||||
Dim NewCard As New MyCard With {.Title = CardTitle, .Margin = New Thickness(0, 0, 0, 15)}
|
||||
Dim NewStack As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0)}
|
||||
NewCard.Children.Add(NewStack)
|
||||
NewCard.SwapControl = NewStack
|
||||
NewCard.SetContentBuilder(Instances, Function(Instance) Instance.ToListItem(AddressOf McInstanceListContent))
|
||||
PanMain.Children.Add(NewCard)
|
||||
'确定卡片是否展开
|
||||
If Card.Key = McInstanceCardType.Rubbish OrElse Card.Key = McInstanceCardType.Error OrElse Card.Key = McInstanceCardType.Fool Then
|
||||
NewCard.IsSwapped = True
|
||||
Else
|
||||
MyCard.StackInstall(NewStack, 0, CardTitle)
|
||||
NewCard.BuildContent()
|
||||
End If
|
||||
Next
|
||||
|
||||
@@ -128,15 +131,16 @@ Public Class PageSelectRight
|
||||
BtnStar.LogoScale = 1.1
|
||||
BtnStar.Logo = Logo.IconButtonLikeLine
|
||||
End If
|
||||
AddHandler BtnStar.Click, Sub()
|
||||
WriteIni(Instance.PathVersion & "PCL\Setup.ini", "IsStar", Not Instance.IsStar)
|
||||
McInstanceListForceRefresh = True
|
||||
LoaderFolderRun(McInstanceListLoader, McFolderSelected, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\")
|
||||
End Sub
|
||||
AddHandler BtnStar.Click,
|
||||
Sub()
|
||||
WriteIni(Instance.PathVersion & "PCL\Setup.ini", "IsStar", Not Instance.IsStar)
|
||||
McInstanceListForceRefresh = True
|
||||
LoaderFolderRun(McInstanceListLoader, McFolderSelected, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\")
|
||||
End Sub
|
||||
Dim BtnDel As New MyIconButton With {.LogoScale = 1.1, .Logo = Logo.IconButtonDelete}
|
||||
BtnDel.ToolTip = "删除"
|
||||
AddHandler BtnDel.Click, Sub() DeleteInstance(sender, Instance)
|
||||
If Instance.State <> McInstanceState.Error Then
|
||||
If Instance.State <> McInstance.McInstanceState.Error Then
|
||||
Dim BtnCont As New MyIconButton With {.LogoScale = 1.1, .Logo = Logo.IconButtonSetup}
|
||||
BtnCont.ToolTip = "设置"
|
||||
AddHandler BtnCont.Click,
|
||||
@@ -166,6 +170,10 @@ Public Class PageSelectRight
|
||||
'点击选项
|
||||
Public Shared Sub Item_Click(sender As MyListItem, e As EventArgs)
|
||||
Dim Instance As McInstance = sender.Tag
|
||||
If McInstanceLock.IsLocked(Instance) Then
|
||||
Hint("该版本正在被修改,请稍后再选择!", HintType.Red)
|
||||
Return
|
||||
End If
|
||||
If New McInstance(Instance.PathVersion).Check Then
|
||||
'正常版本
|
||||
McInstanceSelected = Instance
|
||||
@@ -183,8 +191,12 @@ Public Class PageSelectRight
|
||||
'修改此代码时,同时修改 PageInstanceOverall 中的代码
|
||||
Public Shared Sub DeleteInstance(Item As MyListItem, Instance As McInstance)
|
||||
Try
|
||||
If McInstanceLock.IsLocked(Instance) Then
|
||||
Hint("该版本正在被修改,请稍后再删除!", HintType.Red)
|
||||
Return
|
||||
End If
|
||||
Dim IsShiftPressed As Boolean = My.Computer.Keyboard.ShiftKeyDown
|
||||
Dim IsHintIndie As Boolean = Instance.State <> McInstanceState.Error AndAlso Instance.PathIndie <> McFolderSelected
|
||||
Dim IsHintIndie As Boolean = Instance.State <> McInstance.McInstanceState.Error AndAlso Instance.PathIndie <> McFolderSelected
|
||||
Dim SavesFolder = DirectoryUtils.GetInfo(Instance.PathIndie & "saves\")
|
||||
Dim SaveEntries = If(IsHintIndie AndAlso SavesFolder.Exists, SavesFolder.EnumerateDirectories.OrderByDescending(Function(Save) Save.LastWriteTime).Select(Function(Save) $"{Save.Name}(上次修改:{StringUtils.FormatTimeSpan(Save.LastWriteTime - Date.Now, False)})").ToList, New List(Of String))
|
||||
Select Case MyMsgBox($"你确定要{If(IsShiftPressed, "永久", "")}删除版本 {Instance.Name} 吗?" &
|
||||
@@ -207,7 +219,7 @@ Public Class PageSelectRight
|
||||
Dim Card As MyCard = Parent.Parent
|
||||
Card.Title = Card.Title.Replace(Parent.Children.Count - 1, Parent.Children.Count - 2) '有一个占位符
|
||||
Parent.Children.Remove(Item)
|
||||
If McInstanceSelected IsNot Nothing AndAlso Instance.PathVersion = McInstanceSelected.PathVersion Then
|
||||
If McInstanceSelected IsNot Nothing AndAlso PathUtils.IsSame(Instance.PathVersion, McInstanceSelected.PathVersion) Then
|
||||
'删除当前版本就更改选择
|
||||
McInstanceSelected = MyVirtualizingElement.TryInit(Parent.Children(0)).Tag
|
||||
End If
|
||||
|
||||
@@ -27,8 +27,6 @@
|
||||
<RowDefinition Height="28" />
|
||||
<RowDefinition Height="9" />
|
||||
<RowDefinition Height="28" />
|
||||
<RowDefinition Height="9" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Grid.Row="0" VerticalAlignment="Center" HorizontalAlignment="Left" Text="默认版本隔离" Margin="0,0,25,0" />
|
||||
<local:MyComboBox local:SettingService.Key="LaunchArgumentIndieV2" x:Name="ComboArgumentIndieV2"
|
||||
@@ -106,9 +104,6 @@
|
||||
</local:MyTextBox.ValidateRules>
|
||||
</local:MyTextBox>
|
||||
</Grid>
|
||||
<local:MyCheckBox Margin="0,8,0,4" Text="在正版登录时验证 SSL 证书" Grid.Row="12" Height="22" Grid.ColumnSpan="2"
|
||||
x:Name="CheckDownloadCert" local:SettingService.Key="ToolDownloadCert"
|
||||
ToolTip="开启验证可以提高安全性,但可能会导致正版登录失败(见 #3018)。
若登录因为 “未能为 SSL/TLS 安全通道建立信任关系” 失败,请考虑关闭此选项。" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</local:MyCard>
|
||||
@@ -291,6 +286,7 @@
|
||||
<local:MyCheckBox Height="28" Text="禁用 Java Launch Wrapper" local:SettingService.Key="LaunchAdvanceDisableJLW" ToolTip="是否使用 Java Launch Wrapper 修复 Java 18- 在中文路径下可能无法正常启动的问题。
详见:https://github.com/00ll00/java_launch_wrapper" />
|
||||
<local:MyCheckBox Height="28" Text="禁用 LWJGL Unsafe Agent" local:SettingService.Key="LaunchAdvanceDisableLUA" ToolTip="是否使用 LWJGL Unsafe Agent 修复 LWJGL 3.4.1 的一个性能问题。
详见:https://github.com/HMCL-dev/lwjgl-unsafe-agent" />
|
||||
<local:MyCheckBox Height="28" Text="使用高性能显卡" local:SettingService.Key="LaunchAdvanceGraphicCard" ToolTip="自动在 Windows 设置 → 系统 → 屏幕 → 显示卡 中将 PCL 和 Java 改为使用高性能显卡。
如果同时有集成显卡和独立显卡,这能确保 MC 使用独立显卡进行渲染,以大幅提高帧率。" />
|
||||
<local:MyCheckBox Height="28" Text="在正版登录时验证 SSL 证书" local:SettingService.Key="ToolDownloadCert" ToolTip="开启验证可以提高安全性,但可能会导致正版登录失败(见 #3018)。
若登录因为 “未能为 SSL/TLS 安全通道建立信任关系” 失败,请考虑关闭此选项。" />
|
||||
</StackPanel>
|
||||
<local:MyHint Text="版本独立设置中还有更多高级选项可供调整。" Margin="0,5,0,10" Theme="Blue" Grid.Row="11" Grid.ColumnSpan="2"
|
||||
CanClose="True" RelativeSetup="HintMoreAdvancedSetup" />
|
||||
|
||||
@@ -396,7 +396,7 @@ PreFin:
|
||||
AddHandler DownButton.Click, Sub() MoveJavaInList(JavaEntry, 1)
|
||||
Buttons.Add(DownButton)
|
||||
'从列表中移除按钮
|
||||
Dim IsOfficial As Boolean = JavaEntry.Folder.StartsWithF($"{Paths.AppData}.minecraft\runtime\")
|
||||
Dim IsOfficial As Boolean = PathUtils.IsParentOf($"{Paths.AppData}.minecraft\runtime\", JavaEntry.Folder)
|
||||
Dim DeleteButton As New MyIconButton With {.Logo = Logo.IconButtonStop, .Height = 24, .Width = 24}
|
||||
DeleteButton.IsEnabled = Not IsOfficial
|
||||
DeleteButton.ToolTip = If(DeleteButton.IsEnabled, "从列表中移除", "无法移除官方 Java")
|
||||
|
||||
@@ -235,18 +235,16 @@
|
||||
<local:MyHint Margin="0,15,0,-4" Text="内容见 ModSetup" Theme="Blue" x:Name="HintCustom" />
|
||||
<local:MyHint Margin="0,15,0,6" Text="请谨慎使用陌生人提供的主页,恶意代码可能会造成损害!" Theme="Yellow" x:Name="HintCustomWarn"
|
||||
CanClose="True" RelativeSetup="HintCustomWarn" />
|
||||
<Grid Height="35" x:Name="PanCustomLocal" Visibility="Collapsed" Margin="0,10,0,5">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
|
||||
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
|
||||
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
|
||||
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<local:MyButton x:Name="BtnCustomRefresh" Grid.Column="0" Height="32" MinWidth="140" Text="刷新主页" Padding="13,0" Margin="0,0,20,0" ColorType="Highlight" />
|
||||
<local:MyButton x:Name="BtnCustomFile" Grid.Column="1" Height="32" MinWidth="140" Text="生成教学文件" Padding="13,0" Margin="0,0,20,0" />
|
||||
<local:MyButton x:Name="BtnCustomTutorial" Grid.Column="2" Height="32" MinWidth="140" Text="查看教程" Padding="13,0" Margin="0,0,20,0" />
|
||||
<local:MyButton x:Name="BtnCustomOpen" Grid.Column="3" Height="32" MinWidth="140" Text="打开主页文件夹" Padding="13,0" Margin="0,0,20,0" />
|
||||
</Grid>
|
||||
<WrapPanel x:Name="PanCustomLocal" Visibility="Collapsed" Margin="0,0,0,5">
|
||||
<local:MyButton x:Name="BtnCustomRefresh" Text="刷新主页"
|
||||
MinWidth="140" Height="35" Padding="13,0" Margin="0,10,20,0" HorizontalAlignment="Left" ColorType="Highlight" />
|
||||
<local:MyButton x:Name="BtnCustomFile" Text="生成教学文件"
|
||||
MinWidth="140" Height="35" Padding="13,0" Margin="0,10,20,0" HorizontalAlignment="Left" />
|
||||
<local:MyButton x:Name="BtnCustomTutorial" Text="查看教程"
|
||||
MinWidth="140" Height="35" Padding="13,0" Margin="0,10,20,0" HorizontalAlignment="Left" />
|
||||
<local:MyButton x:Name="BtnCustomFolder" Text="打开主页文件夹"
|
||||
MinWidth="140" Height="35" Padding="13,0" Margin="0,10,20,0" HorizontalAlignment="Left" />
|
||||
</WrapPanel>
|
||||
<Grid x:Name="PanCustomNet" Visibility="Collapsed" Margin="0,10,0,5">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" SharedSizeGroup="Name" />
|
||||
@@ -288,6 +286,11 @@
|
||||
<local:MyComboBoxItem local:SettingService.Value="17" Content="Bangumi 番剧主页(作者:wzyaeu)" />
|
||||
<local:MyComboBoxItem local:SettingService.Value="18" Content="Bilibili 热门(作者:wzyaeu)" />
|
||||
<local:MyComboBoxItem local:SettingService.Value="19" Content="Music 云音乐热门(作者:wzyaeu)" />
|
||||
<local:MyComboBoxItem local:SettingService.Value="20" Content="模组推荐(作者:llsgllsg)" />
|
||||
<local:MyComboBoxItem local:SettingService.Value="21" Content="每日游戏推荐(作者:llsgllsg)" />
|
||||
<local:MyComboBoxItem local:SettingService.Value="22" Content="Wallpaper 每日壁纸(作者:wzyaeu)" />
|
||||
<local:MyComboBoxItem local:SettingService.Value="23" Content="Weather 天气预报(作者:wzyaeu)" />
|
||||
<local:MyComboBoxItem local:SettingService.Value="24" Content="新一代狗屁王大杂烩主页(作者:llsgllsg)" />
|
||||
</local:MyComboBox>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
@@ -334,6 +337,7 @@
|
||||
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="4" Grid.Column="3" Text="版本管理" x:Name="CheckHiddenFunctionSelect" local:SettingService.Key="UiHiddenFunctionSelect" ToolTip="隐藏启动按钮下方的版本选择与版本设置入口。" />
|
||||
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="4" Grid.Column="4" Text="Mod 更新" x:Name="CheckHiddenFunctionModUpdate" local:SettingService.Key="UiHiddenFunctionModUpdate" ToolTip="禁止在 Mod 管理页面更新 Mod。" />
|
||||
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="4" Grid.Column="5" Text="功能隐藏" x:Name="CheckHiddenFunctionHidden" local:SettingService.Key="UiHiddenFunctionHidden" ToolTip="仅隐藏本选项卡,设置的禁用内容依然有效。
可以在保留个性化设置页面的情况下避免隐藏设置被修改。" />
|
||||
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="4" Grid.Column="6" Text="版本修改" x:Name="CheckHiddenFunctionModify" local:SettingService.Key="UiHiddenFunctionInstanceModify" ToolTip="隐藏版本设置中的版本修改功能。" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</local:MyCard>
|
||||
|
||||
@@ -306,19 +306,6 @@ Refresh:
|
||||
"你可以在生成教学文件后直接刷新主页,对照着进行修改,更有助于理解。" & vbCrLf &
|
||||
"直接将主页文件拖进 PCL 窗口也可以快捷加载。", "主页自定义教程")
|
||||
End Sub
|
||||
Private Sub BtnCustomOpen_Click(sender As Object, e As EventArgs) Handles BtnCustomOpen.Click
|
||||
Try
|
||||
Dim CustomPath As String = Paths.Base & "PCL\Custom.xaml"
|
||||
If FileUtils.Exists(CustomPath) Then
|
||||
OpenExplorer(CustomPath)
|
||||
Else
|
||||
OpenExplorer(Paths.Base & "PCL\")
|
||||
Hint("未找到 Custom.xaml,已打开 PCL 文件夹。", HintType.Blue)
|
||||
End If
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex, "打开主页文件失败")
|
||||
End Try
|
||||
End Sub
|
||||
Public Shared Sub OnMainPageTypeChanged()
|
||||
If FrmSetupUI Is Nothing Then Return
|
||||
Select Case CInt(Settings.Get(Of Integer)("UiCustomType"))
|
||||
@@ -354,6 +341,14 @@ Refresh:
|
||||
End Select
|
||||
FrmSetupUI.CardCustom.TriggerForceResize()
|
||||
End Sub
|
||||
Private Sub BtnCustomFolder_Click(sender As Object, e As MouseButtonEventArgs) Handles BtnCustomFolder.Click
|
||||
Dim CustomPath As String = Paths.Base & "PCL\Custom.xaml"
|
||||
If FileUtils.Exists(CustomPath) Then
|
||||
OpenExplorer(CustomPath)
|
||||
Else
|
||||
OpenExplorer(Paths.Base & "PCL\")
|
||||
End If
|
||||
End Sub
|
||||
|
||||
'主题
|
||||
Private Sub LabLauncherTheme5Unlock_MouseLeftButtonUp(sender As Object, e As MouseButtonEventArgs) Handles LabLauncherTheme5Unlock.MouseLeftButtonUp
|
||||
@@ -458,6 +453,10 @@ Refresh:
|
||||
If FrmSetupUI IsNot Nothing Then
|
||||
FrmSetupUI.CardSwitch.Visibility = If(Not HiddenForceShow AndAlso Settings.Get(Of Boolean)("UiHiddenFunctionHidden"), Visibility.Collapsed, Visibility.Visible)
|
||||
End If
|
||||
'版本设置子页面
|
||||
If FrmInstanceLeft IsNot Nothing Then
|
||||
FrmInstanceLeft.ItemModify.Visibility = If(Not HiddenForceShow AndAlso Settings.Get(Of Boolean)("UiHiddenFunctionInstanceModify"), Visibility.Collapsed, Visibility.Visible)
|
||||
End If
|
||||
'设置子页面
|
||||
If FrmSetupLeft IsNot Nothing Then
|
||||
FrmSetupLeft.ItemLaunch.Visibility = If(Not HiddenForceShow AndAlso Settings.Get(Of Boolean)("UiHiddenSetupLaunch"), Visibility.Collapsed, Visibility.Visible)
|
||||
|
||||
@@ -158,6 +158,7 @@ Public Class Settings
|
||||
New Setting("UiHiddenPageOther", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
|
||||
New Setting("UiHiddenFunctionSelect", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
|
||||
New Setting("UiHiddenFunctionModUpdate", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
|
||||
New Setting("UiHiddenFunctionInstanceModify", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
|
||||
New Setting("UiHiddenFunctionHidden", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
|
||||
New Setting("UiHiddenSetupLaunch", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
|
||||
New Setting("UiHiddenSetupUi", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
|
||||
|
||||
@@ -93,7 +93,8 @@ Public Class PageSpeedLeft
|
||||
Tb.Text = Loader.Error.GetDisplay(True)
|
||||
AddHandler Tb.MouseLeftButtonDown,
|
||||
Sub(sender As TextBlock, e As EventArgs)
|
||||
ClipboardSet(sender.Text, SuccessHint:="已复制错误详情!")
|
||||
ClipboardSet(sender.Text, False)
|
||||
Hint("已复制错误详情!", HintType.Green)
|
||||
End Sub
|
||||
Card.Children.Add(Tb)
|
||||
#End Region
|
||||
|
||||
@@ -282,6 +282,7 @@
|
||||
<Compile Include="Pages\PageDownload\PageDownloadInstall.xaml.vb">
|
||||
<DependentUpon>PageDownloadInstall.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Pages\PageDownload\PageDownloadModify.vb" />
|
||||
<Compile Include="Pages\PageDownload\Resource\PageDownloadCompDetail.xaml.vb">
|
||||
<DependentUpon>PageDownloadCompDetail.xaml</DependentUpon>
|
||||
</Compile>
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user