Files
MRCC/launcher/PCL-CE/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceInstall.xaml.cs
T

2554 lines
102 KiB
C#
Raw Normal View History

using System.Collections;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
using PCL.Core.App;
using PCL.Core.App.Localization;
using PCL.Core.UI;
using PCL.Core.Utils;
namespace PCL;
public partial class PageInstanceInstall
{
private enum InstallAction
{
Modify,
Reset
}
private bool isLoad;
private string lastVersionName;
private InstallAction _installAction;
public PageInstanceInstall()
{
Initialized += (a, b) => LoaderInit();
Loaded += (a, b) => Init();
InitializeComponent();
LoadMinecraft.Text = Lang.Text("Download.Version.LoadingList");
}
private void LoaderInit()
{
disabledPageAnimControls.Add(BtnSelectStart);
// PageLoaderInit(LoadMinecraft, PanLoad, PanBack, Nothing, DlClientListLoader, AddressOf LoadMinecraft_OnFinish)
PageLoaderInit(LoadMinecraft, PanLoad, PanAllBack, null, ModDownload.dlClientListLoader, _ => GetCurrentInfo());
LoadOptiFine.StateChanged += (_, _, _) => { OptiFine_Loaded(); ReloadSelected(); };
LoadLiteLoader.StateChanged += (_, _, _) => { LiteLoader_Loaded(); ReloadSelected(); };
LoadForge.StateChanged += (_, _, _) => { Forge_Loaded(); ReloadSelected(); };
LoadNeoForge.StateChanged += (_, _, _) => { NeoForge_Loaded(); ReloadSelected(); };
LoadCleanroom.StateChanged += (_, _, _) => { Cleanroom_Loaded(); ReloadSelected(); };
LoadFabric.StateChanged += (_, _, _) => { Fabric_Loaded(); ReloadSelected(); };
LoadFabricApi.StateChanged += (_, _, _) => { FabricApi_Loaded(); ReloadSelected(); };
LoadLegacyFabric.StateChanged += (_, _, _) => { LegacyFabric_Loaded(); ReloadSelected(); };
LoadLegacyFabricApi.StateChanged += (_, _, _) => { LegacyFabricApi_Loaded(); ReloadSelected(); };
LoadOptiFabric.StateChanged += (_, _, _) => { OptiFabric_Loaded(); ReloadSelected(); };
LoadLabyMod.StateChanged += (_, _, _) => { LabyMod_Loaded(); ReloadSelected(); };
PageExit += () => isInSelectPage = false;
}
private void Init()
{
PanBack.ScrollToHome();
GetCurrentInfo();
var needRefresh = lastVersionName is null || (lastVersionName ?? "") != (_vanillaName ?? "");
lastVersionName = _vanillaName;
ModDownload.dlOptiFineListLoader.Start(isForceRestart: needRefresh);
ModDownload.dlLiteLoaderListLoader.Start(isForceRestart: needRefresh);
ModDownload.dlFabricListLoader.Start(isForceRestart: needRefresh);
ModDownload.dlNeoForgeListLoader.Start(isForceRestart: needRefresh);
ModDownload.dlCleanroomListLoader.Start(isForceRestart: needRefresh);
ModDownload.dlLabyModListLoader.Start(isForceRestart: needRefresh);
ModDownload.dlLegacyFabricListLoader.Start(isForceRestart: needRefresh);
ModDownload.dlFabricApiLoader.Start(isForceRestart: needRefresh);
ModDownload.dlLegacyFabricApiLoader.Start(isForceRestart: needRefresh);
ModDownload.dlOptiFabricLoader.Start(isForceRestart: needRefresh);
// 非重复加载部分
if (isLoad)
{
ReloadSelected();
return;
}
isLoad = true;
ModDownloadLib.McDownloadForgeRecommendedRefresh();
LoadOptiFine.State = ModDownload.dlOptiFineListLoader;
LoadLiteLoader.State = ModDownload.dlLiteLoaderListLoader;
LoadFabric.State = ModDownload.dlFabricListLoader;
LoadFabricApi.State = ModDownload.dlFabricApiLoader;
LoadNeoForge.State = ModDownload.dlNeoForgeListLoader;
LoadCleanroom.State = ModDownload.dlCleanroomListLoader;
LoadOptiFabric.State = ModDownload.dlOptiFabricLoader;
LoadLabyMod.State = ModDownload.dlLabyModListLoader;
LoadLegacyFabric.State = ModDownload.dlLegacyFabricListLoader;
LoadLegacyFabricApi.State = ModDownload.dlLegacyFabricApiLoader;
}
#region 安装
private void BtnSelectStart_Click(object sender, MouseButtonEventArgs mouseButtonEventArgs)
{
// Quilt 实例无法通过安装管线重装/修改(已移除 Quilt 安装支持)
if (PageInstanceLeft.McInstance.Info.HasQuilt)
{
HintService.Hint(Lang.Text("Instance.Overall.Reset.QuiltUnsupported"));
return;
}
// 确认版本隔离
if (selectedLoaderName is not null &&
(Config.Launch.IndieSolutionV2 == 0 ||
Config.Launch.IndieSolutionV2 == 2))
if (ModMain.MyMsgBox(
Lang.Text("Download.Install.InstanceIsolation.Warning.Message"), Lang.Text("Download.Install.InstanceIsolation.Warning.Title"), Lang.Text("Download.Install.InstanceIsolation.Warning.Cancel"), Lang.Text("Download.Install.InstanceIsolation.Warning.Continue")) == 1)
return;
if (_installAction == InstallAction.Reset)
if (ModMain.MyMsgBox(
Lang.Text("Instance.Install.Reset.Message"),
Lang.Text("Instance.Install.Reset.Title"),
Lang.Text("Common.Action.Continue"),
Lang.Text("Common.Action.Cancel")
) == 2)
return;
// 删除 LabyMod Neo 文件
if ((PageInstanceLeft.McInstance.PathIndie ?? "") != (PageInstanceLeft.McInstance.PathInstance ?? "") &&
PageInstanceLeft.McInstance.Info.HasLabyMod)
Directory.Delete(System.IO.Path.Combine(PageInstanceLeft.McInstance.PathIndie, "labymod-neo"), true);
// 备份实例核心文件
ModBase.CopyFile(PageInstanceLeft.McInstance.PathInstance + PageInstanceLeft.McInstance.Name + ".json",
PageInstanceLeft.McInstance.PathInstance + @"PCLInstallBackups\" + PageInstanceLeft.McInstance.Name + ".json");
if (File.Exists(PageInstanceLeft.McInstance.PathInstance + PageInstanceLeft.McInstance.Name + ".jar"))
ModBase.CopyFile(PageInstanceLeft.McInstance.PathInstance + PageInstanceLeft.McInstance.Name + ".jar",
PageInstanceLeft.McInstance.PathInstance + @"PCLInstallBackups\" + PageInstanceLeft.McInstance.Name +
".jar");
// 确认独立 API (如 Fabric API 等) 是否需要被修改
if (selectedFabricApi?.Equals(_currentFabricApi) == true)
selectedFabricApi = null;
if (selectedLegacyFabricApi?.Equals(_currentLegacyFabricApi) == true)
selectedLegacyFabricApi = null;
if (selectedOptiFabric?.Equals(_currentOptiFabric) == true)
selectedOptiFabric = null;
// 提交安装申请
var request = new ModDownloadLib.McInstallRequest
{
targetInstanceName = PageInstanceLeft.McInstance.Name,
targetInstanceFolder = $@"{ModFolder.mcFolderSelected}versions\{PageInstanceLeft.McInstance.Name}\",
minecraftJson = _vanillaData?["url"].ToString(),
minecraftName = _vanillaName,
optiFineEntry = selectedOptiFine,
forgeEntry = selectedForge,
neoForgeEntry = selectedNeoForge,
neoForgeVersion = selectedNeoForgeVersion,
cleanroomEntry = selectedCleanroom,
cleanroomVersion = selectedCleanroomVersion,
fabricVersion = selectedFabric,
fabricApi = selectedFabricApi,
optiFabric = selectedOptiFabric,
liteLoaderEntry = selectedLiteLoader,
labyModChannel = selectedLabyModChannel,
labyModCommitRef = selectedLabyModCommitRef,
legacyFabricVersion = selectedLegacyFabric,
legacyFabricApi = selectedLegacyFabricApi
};
BtnSelectStart.IsEnabled = false;
if (!ModDownloadLib.McInstall(request, _installAction == InstallAction.Modify ? Lang.Text("Instance.Install.Action.ModifyLabel") : Lang.Text("Common.Action.Reset")))
return;
// 删除旧的独立 API 文件
if (selectedFabricApi is not null && _currentFabricApiPath is not null)
File.Delete(_currentFabricApiPath);
if (selectedLegacyFabricApi is not null && _currentLegacyFabricApiPath is not null)
File.Delete(_currentLegacyFabricApiPath);
if (selectedOptiFabric is not null && _currentOptiFabricPath is not null)
File.Delete(_currentOptiFabricPath);
// 返回主页
ModMain.frmMain.PageChange(new FormMain.PageStackData { page = FormMain.PageType.Launch });
}
#endregion
private string GetLoaderError(MyLoading loader)
{
if (loader is null || !loader.State.IsLoader)
return Lang.Text("Download.Install.State.Getting");
switch (loader.State.LoadingState)
{
case MyLoading.MyLoadingState.Run:
{
return Lang.Text("Download.Install.State.Getting");
}
case MyLoading.MyLoadingState.Error:
{
var message = ((ModLoader.LoaderBase)loader.State).Error.Message;
return message == Lang.Text("Download.Install.State.NoVersion") ? Lang.Text("Download.Install.State.NoVersion") : Lang.Text("Download.Install.State.GetFailed", message);
}
case MyLoading.MyLoadingState.Unloaded:
{
return Lang.Text("Download.Install.State.UnknownUnloaded");
}
default:
{
return null;
}
}
}
#region 页面切换
// 页面切换动画
public bool isInSelectPage;
private bool isFirstLoaded;
private void EnterSelectPage()
{
if (isInSelectPage)
return;
isInSelectPage = true;
disabledPageAnimControls.Remove(BtnSelectStart);
BtnSelectStart.Show = true;
autoSelectedFabricApi = false;
autoSelectedOptiFabric = false;
PanSelect.Visibility = Visibility.Visible;
PanSelect.IsHitTestVisible = true;
PanMinecraft.IsHitTestVisible = false;
PanBack.IsHitTestVisible = false;
PanBack.ScrollToHome();
CardMinecraft.IsSwapped = true;
CardOptiFine.IsSwapped = true;
CardLiteLoader.IsSwapped = true;
CardForge.IsSwapped = true;
CardNeoForge.IsSwapped = true;
CardCleanroom.IsSwapped = true;
CardFabric.IsSwapped = true;
CardFabricApi.IsSwapped = true;
CardOptiFabric.IsSwapped = true;
CardLabyMod.IsSwapped = true;
CardLegacyFabric.IsSwapped = true;
CardLegacyFabricApi.IsSwapped = true;
if (!(bool)States.Hint.InstallPageBack)
{
States.Hint.InstallPageBack = true;
HintService.Hint(Lang.Text("Download.Install.Hint.MinecraftBack"));
}
// 如果在选择页面按了刷新键,选择页的东西可能会由于动画被隐藏,但不会由于加载结束而再次显示,因此这里需要手动恢复
foreach (var Card in GetAllAnimControls(PanSelect))
{
Card.Opacity = 1d;
Card.RenderTransform = new TranslateTransform();
}
// 启动 Forge 加载
if (McInstanceInfo.IsFormatFit(_vanillaName))
{
var forgeLoader =
new ModLoader.LoaderTask<string, List<ModDownload.DlForgeVersionEntry>>(
"DlForgeVersion " + _vanillaName, ModDownload.DlForgeVersionMain);
LoadForge.State = forgeLoader;
forgeLoader.Start(_vanillaName);
}
// 启动 Fabric API、Legacy Fabric API、OptiFabric 加载
ModDownload.dlFabricApiLoader.Start();
ModDownload.dlLegacyFabricApiLoader.Start();
ModDownload.dlOptiFabricLoader.Start();
ModAnimation.AniStart(new[]
{
ModAnimation.AaOpacity(PanMinecraft, -PanMinecraft.Opacity, 100, 10),
ModAnimation.AaCode(() =>
{
PanBack.ScrollToHome();
OptiFine_Loaded();
LiteLoader_Loaded();
Forge_Loaded();
NeoForge_Loaded();
Cleanroom_Loaded();
Fabric_Loaded();
LegacyFabric_Loaded();
FabricApi_Loaded();
LegacyFabricApi_Loaded();
LabyMod_Loaded();
OptiFabric_Loaded();
ReloadSelected();
}, after: true),
ModAnimation.AaOpacity(PanSelect, 1d - PanSelect.Opacity, 250, 150),
ModAnimation.AaCode(() =>
{
PanMinecraft.Visibility = Visibility.Collapsed;
PanBack.IsHitTestVisible = true;
// 初始化 Binding
if (isFirstLoaded)
return;
isFirstLoaded = true;
BtnOptiFineClearInner.SetBinding(Shape.FillProperty,
new Binding("Foreground") { Source = CardOptiFine.MainTextBlock, Mode = BindingMode.OneWay });
BtnLiteLoaderClearInner.SetBinding(Shape.FillProperty,
new Binding("Foreground") { Source = CardLiteLoader.MainTextBlock, Mode = BindingMode.OneWay });
BtnForgeClearInner.SetBinding(Shape.FillProperty,
new Binding("Foreground") { Source = CardForge.MainTextBlock, Mode = BindingMode.OneWay });
BtnLegacyFabricClearInner.SetBinding(Shape.FillProperty,
new Binding("Foreground") { Source = CardLegacyFabric.MainTextBlock, Mode = BindingMode.OneWay });
BtnNeoForgeClearInner.SetBinding(Shape.FillProperty,
new Binding("Foreground") { Source = CardNeoForge.MainTextBlock, Mode = BindingMode.OneWay });
BtnCleanroomClearInner.SetBinding(Shape.FillProperty,
new Binding("Foreground") { Source = CardCleanroom.MainTextBlock, Mode = BindingMode.OneWay });
BtnFabricClearInner.SetBinding(Shape.FillProperty,
new Binding("Foreground") { Source = CardFabric.MainTextBlock, Mode = BindingMode.OneWay });
BtnLegacyFabricApiClearInner.SetBinding(Shape.FillProperty,
new Binding("Foreground")
{ Source = CardLegacyFabricApi.MainTextBlock, Mode = BindingMode.OneWay });
BtnFabricApiClearInner.SetBinding(Shape.FillProperty,
new Binding("Foreground") { Source = CardFabricApi.MainTextBlock, Mode = BindingMode.OneWay });
BtnLabyModClearInner.SetBinding(Shape.FillProperty,
new Binding("Foreground") { Source = CardLabyMod.MainTextBlock, Mode = BindingMode.OneWay });
BtnOptiFabricClearInner.SetBinding(Shape.FillProperty,
new Binding("Foreground") { Source = CardOptiFabric.MainTextBlock, Mode = BindingMode.OneWay });
}, after: true)
}, "FrmInstanceInstall SelectPageSwitch", true);
}
public void ExitSelectPage()
{
if (!isInSelectPage)
return;
isInSelectPage = false;
LoadMinecraft_OnFinish();
disabledPageAnimControls.Add(BtnSelectStart);
BtnSelectStart.Show = false;
ClearSelected(); // 清除已选择项
PanMinecraft.Visibility = Visibility.Visible;
PanSelect.IsHitTestVisible = false;
PanMinecraft.IsHitTestVisible = true;
PanBack.IsHitTestVisible = false;
PanBack.ScrollToHome();
ModAnimation.AniStart(new[]
{
ModAnimation.AaOpacity(PanSelect, -PanSelect.Opacity, 90, 10),
ModAnimation.AaCode(() => PanBack.ScrollToHome(), after: true),
ModAnimation.AaOpacity(PanMinecraft, 1d - PanMinecraft.Opacity, 150, 100),
ModAnimation.AaCode(() =>
{
PanSelect.Visibility = Visibility.Collapsed;
PanBack.IsHitTestVisible = true;
}, after: true)
}, "FrmInstanceInstall SelectPageSwitch");
}
// 页面切换触发
public void MinecraftSelected(MyListItem sender, MouseButtonEventArgs e)
{
_vanillaName = sender.Title;
_vanillaData = (JsonObject)sender.Tag;
_vanillaIcon = sender.Logo;
EnterSelectPage();
}
private void CardMinecraft_PreviewSwap(object sender, ModBase.RouteEventArgs e)
{
ExitSelectPage();
e.handled = true;
}
#endregion
#region 选择
// Minecraft
private string? _vanillaName;
private JsonObject? _vanillaData;
private string? _vanillaIcon;
private int VanillaDrop => McInstanceInfo.VersionToDrop(_vanillaName, true);
// OptiFine
private ModDownload.DlOptiFineListEntry? selectedOptiFine;
/// <summary>
/// 选定的 Mod Loader 名称,内容应为 Forge / NeoForge / Fabric / Cleanroom / LabyMod / LegacyFabric
/// </summary>
private string? selectedLoaderName;
/// <summary>
/// 选定的 Mod Loader API 名称,内容应为 Fabric API
/// </summary>
private string? selectedAPIName;
// LiteLoader
private ModDownload.DlLiteLoaderListEntry? selectedLiteLoader;
// Forge
private ModDownload.DlForgeVersionEntry? selectedForge;
// Cleanroom
private ModDownload.DlCleanroomListEntry? selectedCleanroom;
private string? selectedCleanroomVersion;
// NeoForge
private ModDownload.DlNeoForgeListEntry? selectedNeoForge;
private string? selectedNeoForgeVersion;
// Fabric
private string? selectedFabric;
// FabricApi
private ModComp.CompFile? selectedFabricApi;
// LegacyFabric
private string? selectedLegacyFabric;
// Legacy FabricApi
private ModComp.CompFile? selectedLegacyFabricApi;
// LabyMod
private string? selectedLabyModChannel;
private string? selectedLabyModCommitRef;
private string? selectedLabyModVersion;
// OptiFabric
private ModComp.CompFile? selectedOptiFabric;
private bool _ReloadSelected_Ongoing; // #3742 中,LoadOptiFineGetError 会初始化 LoadOptiFine,触发事件 LoadOptiFine.StateChanged,导致再次调用 SelectReload
/// <summary>
/// 重载已选择的项目的显示。
/// </summary>
private void ReloadSelected()
{
if (_vanillaName is null || _ReloadSelected_Ongoing)
return;
_ReloadSelected_Ongoing = true;
try
{
var selectedInfo = GetSelectInfo();
// 主预览
ItemSelect.Title = PageInstanceLeft.McInstance.Name;
ItemSelect.Logo = GetSelectLogo();
BtnSelectStart.IsEnabled = true;
if ((selectedInfo ?? "") == (currentInfo ?? ""))
{
ItemSelect.Info = selectedInfo;
BtnSelectStart.Text = Lang.Text("Instance.Install.Action.StartReset");
_installAction = InstallAction.Reset;
BtnSelectStart.SvgIcon = "lucide/rotate-ccw";
}
else
{
ItemSelect.Info = currentInfo + " → " + selectedInfo;
BtnSelectStart.Text = Lang.Text("Instance.Install.Action.StartModify");
_installAction = InstallAction.Modify;
BtnSelectStart.SvgIcon = "lucide/pencil";
}
// Minecraft
ImgMinecraft.Source = new MyBitmap(_vanillaIcon);
LabMinecraft.Text = _vanillaName;
LabMinecraft.Foreground = ThemeManager.colorGray1;
// OptiFine
if (!McVersionComparer.CompareVersionGe(_vanillaName, "1.7.2"))
{
CardOptiFine.Visibility = Visibility.Collapsed;
}
else
{
CardOptiFine.Visibility = Visibility.Visible;
var optiFineError = LoadOptiFineGetError();
CardOptiFine.MainSwap.Visibility = optiFineError is null ? Visibility.Visible : Visibility.Collapsed;
if (optiFineError is not null)
CardOptiFine.IsSwapped = true;
SetPanelVisibility(PanOptiFineInfo, CardOptiFine.IsSwapped);
if (selectedOptiFine is null)
{
BtnOptiFineClear.Visibility = Visibility.Collapsed;
ImgOptiFine.Visibility = Visibility.Collapsed;
LabOptiFine.Text = optiFineError ?? Lang.Text("Download.Install.State.CanAdd");
LabOptiFine.Foreground = ThemeManager.colorGray4;
}
else
{
BtnOptiFineClear.Visibility = Visibility.Visible;
ImgOptiFine.Visibility = Visibility.Visible;
LabOptiFine.Text = selectedOptiFine.DisplayName.Replace(_vanillaName + " ", "");
LabOptiFine.Foreground = ThemeManager.colorGray1;
}
}
// LiteLoader
if (!McInstanceInfo.IsFormatFit(_vanillaName)
|| !McVersionComparer.CompareVersionGe(_vanillaName, "1.5.2")
|| !McVersionComparer.CompareVersionGe("1.12.2", _vanillaName))
{
CardLiteLoader.Visibility = Visibility.Collapsed;
}
else
{
CardLiteLoader.Visibility = Visibility.Visible;
var liteLoaderError = LoadLiteLoaderGetError();
CardLiteLoader.MainSwap.Visibility = liteLoaderError is null ? Visibility.Visible : Visibility.Collapsed;
if (liteLoaderError is not null)
CardLiteLoader.IsSwapped = true; // 例如在同时展开卡片时选择了不兼容项则强制折叠
SetPanelVisibility(PanLiteLoaderInfo, CardLiteLoader.IsSwapped);
if (selectedLiteLoader is null)
{
BtnLiteLoaderClear.Visibility = Visibility.Collapsed;
ImgLiteLoader.Visibility = Visibility.Collapsed;
LabLiteLoader.Text = liteLoaderError ?? Lang.Text("Download.Install.State.CanAdd");
LabLiteLoader.Foreground = ThemeManager.colorGray4;
}
else
{
BtnLiteLoaderClear.Visibility = Visibility.Visible;
ImgLiteLoader.Visibility = Visibility.Visible;
LabLiteLoader.Text = selectedLiteLoader.Inherit;
LabLiteLoader.Foreground = ThemeManager.colorGray1;
}
}
// Forge
if (!McInstanceInfo.IsFormatFit(_vanillaName)
|| !McVersionComparer.CompareVersionGe(_vanillaName, "1.1"))
{
CardForge.Visibility = Visibility.Collapsed;
}
else
{
CardForge.Visibility = Visibility.Visible;
var forgeError = LoadForgeGetError();
CardForge.MainSwap.Visibility = forgeError is null ? Visibility.Visible : Visibility.Collapsed;
if (forgeError is not null)
CardForge.IsSwapped = true;
SetPanelVisibility(PanForgeInfo, CardForge.IsSwapped);
if (selectedForge is null)
{
BtnForgeClear.Visibility = Visibility.Collapsed;
ImgForge.Visibility = Visibility.Collapsed;
LabForge.Text = forgeError ?? Lang.Text("Download.Install.State.CanAdd");
LabForge.Foreground = ThemeManager.colorGray4;
}
else
{
BtnForgeClear.Visibility = Visibility.Visible;
ImgForge.Visibility = Visibility.Visible;
LabForge.Text = selectedForge.VersionName;
LabForge.Foreground = ThemeManager.colorGray1;
}
}
// Cleanroom
if (_vanillaName == "1.12.2")
{
CardCleanroom.Visibility = Visibility.Visible;
var cleanroomError = LoadCleanroomGetError();
CardCleanroom.MainSwap.Visibility = cleanroomError is null ? Visibility.Visible : Visibility.Collapsed;
if (cleanroomError is not null)
CardCleanroom.IsSwapped = true;
SetPanelVisibility(PanCleanroomInfo, CardCleanroom.IsSwapped);
if (selectedCleanroom is null)
{
BtnCleanroomClear.Visibility = Visibility.Collapsed;
ImgCleanroom.Visibility = Visibility.Collapsed;
LabCleanroom.Text = cleanroomError ?? Lang.Text("Download.Install.State.CanAdd");
LabCleanroom.Foreground = ThemeManager.colorGray4;
}
else
{
BtnCleanroomClear.Visibility = Visibility.Visible;
ImgCleanroom.Visibility = Visibility.Visible;
LabCleanroom.Text = selectedCleanroom.VersionName;
LabCleanroom.Foreground = ThemeManager.colorGray1;
}
}
else
{
CardCleanroom.Visibility = Visibility.Collapsed;
}
// NeoForge
if (!McVersionComparer.CompareVersionGe(_vanillaName, "1.20.1"))
{
CardNeoForge.Visibility = Visibility.Collapsed;
}
else
{
CardNeoForge.Visibility = Visibility.Visible;
var neoForgeError = LoadNeoForgeGetError();
CardNeoForge.MainSwap.Visibility = neoForgeError is null ? Visibility.Visible : Visibility.Collapsed;
if (neoForgeError is not null)
CardNeoForge.IsSwapped = true;
SetPanelVisibility(PanNeoForgeInfo, CardNeoForge.IsSwapped);
if (selectedNeoForge is null)
{
BtnNeoForgeClear.Visibility = Visibility.Collapsed;
ImgNeoForge.Visibility = Visibility.Collapsed;
LabNeoForge.Text = neoForgeError ?? Lang.Text("Download.Install.State.CanAdd");
LabNeoForge.Foreground = ThemeManager.colorGray4;
}
else
{
BtnNeoForgeClear.Visibility = Visibility.Visible;
ImgNeoForge.Visibility = Visibility.Visible;
LabNeoForge.Text = selectedNeoForge.VersionName;
LabNeoForge.Foreground = ThemeManager.colorGray1;
}
}
// Fabric
if (VanillaDrop < 130
|| (VanillaDrop == 130 && !McVersionComparer.CompareVersionGe(_vanillaName, "18w43b")))
{
CardFabric.Visibility = Visibility.Collapsed;
}
else
{
CardFabric.Visibility = Visibility.Visible;
var fabricError = LoadFabricGetError();
CardFabric.MainSwap.Visibility = fabricError is null ? Visibility.Visible : Visibility.Collapsed;
if (fabricError is not null)
CardFabric.IsSwapped = true;
SetPanelVisibility(PanFabricInfo, CardFabric.IsSwapped);
if (selectedFabric is null)
{
BtnFabricClear.Visibility = Visibility.Collapsed;
ImgFabric.Visibility = Visibility.Collapsed;
LabFabric.Text = fabricError ?? Lang.Text("Download.Install.State.CanAdd");
LabFabric.Foreground = ThemeManager.colorGray4;
}
else
{
BtnFabricClear.Visibility = Visibility.Visible;
ImgFabric.Visibility = Visibility.Visible;
LabFabric.Text = selectedFabric.Replace("+build", "");
LabFabric.Foreground = ThemeManager.colorGray1;
}
}
// FabricApi
if (selectedFabric is null)
{
CardFabricApi.Visibility = Visibility.Collapsed;
}
else
{
CardFabricApi.Visibility = Visibility.Visible;
var fabricApiError = LoadFabricApiGetError();
CardFabricApi.MainSwap.Visibility = fabricApiError is null ? Visibility.Visible : Visibility.Collapsed;
if (fabricApiError is not null || selectedFabric is null)
CardFabricApi.IsSwapped = true;
SetPanelVisibility(PanFabricApiInfo, CardFabricApi.IsSwapped);
if (selectedFabricApi is null)
{
BtnFabricApiClear.Visibility = Visibility.Collapsed;
ImgFabricApi.Visibility = Visibility.Collapsed;
LabFabricApi.Text = fabricApiError ?? Lang.Text("Download.Install.State.CanAdd");
LabFabricApi.Foreground = ThemeManager.colorGray4;
}
else
{
BtnFabricApiClear.Visibility = Visibility.Visible;
ImgFabricApi.Visibility = Visibility.Visible;
LabFabricApi.Text = selectedFabricApi.DisplayName.Split("]")[1].Replace("Fabric API ", "")
.Replace(" build ", ".").Split("+").First().Trim();
LabFabricApi.Foreground = ThemeManager.colorGray1;
}
}
// LegacyFabric
if (VanillaDrop < 30 || VanillaDrop > 130)
{
CardLegacyFabric.Visibility = Visibility.Collapsed;
}
else
{
CardLegacyFabric.Visibility = Visibility.Visible;
var legacyFabricError = LoadLegacyFabricGetError();
CardLegacyFabric.MainSwap.Visibility =
legacyFabricError is null ? Visibility.Visible : Visibility.Collapsed;
if (legacyFabricError is not null)
CardLegacyFabric.IsSwapped = true;
SetPanelVisibility(PanLegacyFabricInfo, CardLegacyFabric.IsSwapped);
if (selectedLegacyFabric is null)
{
BtnLegacyFabricClear.Visibility = Visibility.Collapsed;
ImgLegacyFabric.Visibility = Visibility.Collapsed;
LabLegacyFabric.Text = legacyFabricError ?? Lang.Text("Download.Install.State.CanAdd");
LabLegacyFabric.Foreground = ThemeManager.colorGray4;
}
else
{
BtnLegacyFabricClear.Visibility = Visibility.Visible;
ImgLegacyFabric.Visibility = Visibility.Visible;
LabLegacyFabric.Text = selectedLegacyFabric.Replace("+build", "");
LabLegacyFabric.Foreground = ThemeManager.colorGray1;
}
}
// LegacyFabricApi
if (selectedLegacyFabric is null)
{
CardLegacyFabricApi.Visibility = Visibility.Collapsed;
}
else
{
CardLegacyFabricApi.Visibility = Visibility.Visible;
var legacyFabricApiError = LoadLegacyFabricApiGetError();
CardLegacyFabricApi.MainSwap.Visibility =
legacyFabricApiError is null ? Visibility.Visible : Visibility.Collapsed;
if (legacyFabricApiError is not null || selectedLegacyFabric is null)
CardLegacyFabricApi.IsSwapped = true;
SetPanelVisibility(PanLegacyFabricApiInfo, CardLegacyFabricApi.IsSwapped);
if (selectedLegacyFabricApi is null)
{
BtnLegacyFabricApiClear.Visibility = Visibility.Collapsed;
ImgLegacyFabricApi.Visibility = Visibility.Collapsed;
LabLegacyFabricApi.Text = legacyFabricApiError ?? Lang.Text("Download.Install.State.CanAdd");
LabLegacyFabricApi.Foreground = ThemeManager.colorGray4;
}
else
{
BtnLegacyFabricApiClear.Visibility = Visibility.Visible;
ImgLegacyFabricApi.Visibility = Visibility.Visible;
LabLegacyFabricApi.Text = selectedLegacyFabricApi.DisplayName.Replace("Legacy Fabric API ", "");
LabLegacyFabricApi.Foreground = ThemeManager.colorGray1;
}
}
// LabyMod
if (!McInstanceInfo.IsFormatFit(_vanillaName)
|| !McVersionComparer.CompareVersionGe(_vanillaName, "1.8.9"))
{
CardLabyMod.Visibility = Visibility.Collapsed;
}
else
{
CardLabyMod.Visibility = Visibility.Visible;
var labyModError = LoadLabyModGetError();
CardLabyMod.MainSwap.Visibility = labyModError is null ? Visibility.Visible : Visibility.Collapsed;
if (labyModError is not null)
CardLabyMod.IsSwapped = true;
SetPanelVisibility(PanLabyModInfo, CardLabyMod.IsSwapped);
if (selectedLabyModVersion is null)
{
BtnLabyModClear.Visibility = Visibility.Collapsed;
ImgLabyMod.Visibility = Visibility.Collapsed;
LabLabyMod.Text = labyModError ?? Lang.Text("Download.Install.State.CanAdd");
LabLabyMod.Foreground = ThemeManager.colorGray4;
}
else
{
BtnLabyModClear.Visibility = Visibility.Visible;
ImgLabyMod.Visibility = Visibility.Visible;
LabLabyMod.Text = selectedLabyModVersion;
LabLabyMod.Foreground = ThemeManager.colorGray1;
}
}
// OptiFabric
if (selectedFabric is null || selectedOptiFine is null)
{
CardOptiFabric.Visibility = Visibility.Collapsed;
}
else
{
CardOptiFabric.Visibility = Visibility.Visible;
var optiFabricError = LoadOptiFabricGetError();
CardOptiFabric.MainSwap.Visibility = optiFabricError is null ? Visibility.Visible : Visibility.Collapsed;
if (optiFabricError is not null || selectedFabric is null)
CardOptiFabric.IsSwapped = true;
SetPanelVisibility(PanOptiFabricInfo, CardOptiFabric.IsSwapped);
if (selectedOptiFabric is null)
{
BtnOptiFabricClear.Visibility = Visibility.Collapsed;
ImgOptiFabric.Visibility = Visibility.Collapsed;
LabOptiFabric.Text = optiFabricError ?? Lang.Text("Download.Install.State.CanAdd");
LabOptiFabric.Foreground = ThemeManager.colorGray4;
}
else
{
BtnOptiFabricClear.Visibility = Visibility.Visible;
ImgOptiFabric.Visibility = Visibility.Visible;
LabOptiFabric.Text = selectedOptiFabric.DisplayName.ToLower().Replace("optifabric-", "")
.Replace(".jar", "").Trim().TrimStart('v');
LabOptiFabric.Foreground = ThemeManager.colorGray1;
}
}
// 主警告
if (selectedFabric is not null && selectedFabricApi is null)
HintFabricAPI.Visibility = Visibility.Visible;
else
HintFabricAPI.Visibility = Visibility.Collapsed;
if (selectedLegacyFabric is not null && selectedLegacyFabricApi is null)
HintLegacyFabricAPI.Visibility = Visibility.Visible;
else
HintLegacyFabricAPI.Visibility = Visibility.Collapsed;
if ((selectedFabric is not null || selectedLegacyFabric is not null) && selectedOptiFine is not null &&
selectedOptiFabric is null)
{
if (VanillaDrop >= 140 && VanillaDrop <= 150)
{
HintOptiFabric.Visibility = Visibility.Collapsed;
HintLegacyOptiFabric.Visibility = Visibility.Collapsed;
HintOptiFabricOld.Visibility = Visibility.Visible;
}
else if (selectedLegacyFabric is not null)
{
HintOptiFabric.Visibility = Visibility.Collapsed;
HintLegacyOptiFabric.Visibility = Visibility.Visible;
HintOptiFabricOld.Visibility = Visibility.Collapsed;
}
else
{
HintOptiFabric.Visibility = Visibility.Visible;
HintOptiFabricOld.Visibility = Visibility.Collapsed;
HintLegacyOptiFabric.Visibility = Visibility.Collapsed;
}
}
else
{
HintOptiFabric.Visibility = Visibility.Collapsed;
HintOptiFabricOld.Visibility = Visibility.Collapsed;
HintLegacyOptiFabric.Visibility = Visibility.Collapsed;
}
if (VanillaDrop >= 160 && selectedOptiFine is not null &&
(selectedForge is not null || selectedFabric is not null))
HintModOptiFine.Visibility = Visibility.Visible;
else
HintModOptiFine.Visibility = Visibility.Collapsed;
// 结束
}
finally
{
_ReloadSelected_Ongoing = false;
}
}
/// <summary>
/// 清空已选择的项目。
/// </summary>
private void ClearSelected()
{
_vanillaName = null;
_vanillaData = null;
_vanillaIcon = null;
selectedOptiFine = null;
selectedLiteLoader = null;
selectedLoaderName = null;
selectedAPIName = null;
selectedForge = null;
selectedNeoForge = null;
selectedNeoForgeVersion = null;
selectedCleanroom = null;
selectedCleanroomVersion = null;
selectedFabric = null;
selectedFabricApi = null;
selectedOptiFabric = null;
selectedLabyModCommitRef = null;
selectedLabyModVersion = null;
selectedLabyModChannel = null;
selectedLegacyFabric = null;
selectedLegacyFabricApi = null;
}
// 信息栏动画
private void SetPanelVisibility(Grid panel, bool visible)
{
if (Equals(panel.Tag, visible.ToString()))
return;
panel.Tag = visible.ToString();
if (visible)
ModAnimation.AniStart(
new[]
{
ModAnimation.AaTranslateY(panel, -((TranslateTransform)panel.RenderTransform).Y, 150,
ease: new ModAnimation.AniEaseOutFluent()),
ModAnimation.AaOpacity(panel, 1d - panel.Opacity, 60)
}, "PageDownloadInstall Visibility " + panel.Name);
else
ModAnimation.AniStart(
new[]
{
ModAnimation.AaTranslateY(panel, 6d - ((TranslateTransform)panel.RenderTransform).Y, 60),
ModAnimation.AaOpacity(panel, -panel.Opacity, 60)
}, "PageDownloadInstall Visibility " + panel.Name);
}
/// <summary>
/// 获取实例图标。
/// </summary>
private string GetSelectLogo()
{
if (selectedFabric is not null) return "pack://application:,,,/images/Blocks/Fabric.png";
if (selectedLegacyFabric is not null) return "pack://application:,,,/images/Blocks/Fabric.png";
if (selectedForge is not null) return "pack://application:,,,/images/Blocks/Anvil.png";
if (selectedNeoForge is not null) return "pack://application:,,,/images/Blocks/NeoForge.png";
if (selectedLiteLoader is not null) return "pack://application:,,,/images/Blocks/Egg.png";
if (selectedOptiFine is not null) return "pack://application:,,,/images/Blocks/GrassPath.png";
if (selectedCleanroom is not null) return "pack://application:,,,/images/Blocks/Cleanroom.png";
if (selectedLabyModVersion is not null) return "pack://application:,,,/images/Blocks/LabyMod.png";
return _vanillaIcon;
}
/// <summary>
/// 获取实例描述信息。
/// </summary>
private string GetSelectInfo()
{
var parts = new List<string>
{
_vanillaName
};
var loaderInfos = new (string NameKey, string? Version)[]
{
("Common.Installation.Fabric", selectedFabric?.Replace("+build", "")),
("Common.Installation.LegacyFabric", selectedLegacyFabric),
("Common.Installation.Forge", selectedForge?.VersionName),
("Common.Installation.NeoForge",
selectedNeoForge?.VersionName ?? VersionOrNull(selectedNeoForgeVersion)),
("Common.Installation.Cleanroom",
selectedCleanroom?.VersionName ?? VersionOrNull(selectedCleanroomVersion)),
("Common.Installation.LabyMod", selectedLabyModVersion),
("Common.Installation.OptiFine",
selectedOptiFine?.DisplayName.Replace(_vanillaName + " ", ""))
};
parts.AddRange(
loaderInfos
.Where(info => !string.IsNullOrWhiteSpace(info.Version))
.Select(info => $"{Lang.Text(info.NameKey)} {info.Version}")
);
if (selectedLiteLoader is not null) parts.Add(Lang.Text("Common.Installation.LiteLoader"));
if (parts.Count == 1) parts.Add(Lang.Text("Instance.Install.NoExtraInstall"));
return string.Join(" | ", parts);
}
private static string? VersionOrNull<T>(T version)
{
return EqualityComparer<T>.Default.Equals(version, default!)
? null
: version?.ToString();
}
#endregion
#region 当前信息获取
private ModComp.CompFile _currentFabricApi; // 加载完成后直接调用以提高性能
private string _currentFabricApiPath;
private object GetCurrentFabricApi() // 进入页面和联网加载时调用
{
var loaderOutput = ModDownload.dlFabricApiLoader.output;
if (loaderOutput is null)
return null; // 确保联网信息已加载
var localComp = ModLocalComp.GetModLocalCompByKeywords(PageInstanceLeft.McInstance,
new[] { "fabric-api", "fabric" }, "fabric", "api");
if (localComp is null)
return null;
var result = loaderOutput.FirstOrDefault(comp => (comp.Hash ?? "") == (localComp.ModrinthHash ?? ""));
if (result is not null)
{
_currentFabricApi = result;
_currentFabricApiPath = localComp.path;
}
return result;
}
private ModComp.CompFile _currentLegacyFabricApi; // 加载完成后直接调用以提高性能
private string _currentLegacyFabricApiPath;
private object GetCurrentLegacyFabricApi() // 进入页面和联网加载时调用
{
var loaderOutput = ModDownload.dlLegacyFabricApiLoader.output;
if (loaderOutput is null)
return null; // 确保联网信息已加载
var localComp = ModLocalComp.GetModLocalCompByKeywords(PageInstanceLeft.McInstance,
new[] { "legacy-fabric-api", "legacy-fabric" }, "legacy-fabric", "api");
if (localComp is null)
return null;
var result = loaderOutput.FirstOrDefault(comp => (comp.Hash ?? "") == (localComp.ModrinthHash ?? ""));
if (result is not null)
{
_currentLegacyFabricApi = result;
_currentLegacyFabricApiPath = localComp.path;
}
return result;
}
private ModComp.CompFile _currentOptiFabric;
private string _currentOptiFabricPath;
private object GetCurrentOptiFabric()
{
var loaderOutput = ModDownload.dlOptiFabricLoader.output;
if (loaderOutput is null)
return null;
var localComp =
ModLocalComp.GetModLocalCompByKeywords(PageInstanceLeft.McInstance, "optifabric", "optifabric", "opti");
if (localComp is null)
return null;
var result = loaderOutput.FirstOrDefault(comp => (comp.Hash ?? "") == (localComp.ModrinthHash ?? ""));
if (result is not null)
{
_currentOptiFabric = result;
_currentOptiFabricPath = localComp.path;
}
return result;
}
// 当前信息获取
public void GetCurrentInfo()
{
ClearSelected();
BtnSelectStart.IsEnabled = true;
var currentInstance = PageInstanceLeft.McInstance.Info;
_vanillaName = currentInstance.VanillaName;
if (currentInstance.HasLiteLoader)
selectedLiteLoader = new ModDownload.DlLiteLoaderListEntry { Inherit = currentInstance.VanillaName };
if (currentInstance.HasOptiFine)
selectedOptiFine = new ModDownload.DlOptiFineListEntry
{
DisplayName = currentInstance.VanillaName + " " + currentInstance.OptiFine.Replace("_", " "),
IsPreview = currentInstance.OptiFine.ContainsF("pre"), Inherit = currentInstance.VanillaName,
NameVersion = currentInstance.VanillaName + "-OptiFine_HD_U_" + currentInstance.OptiFine
};
if (currentInstance.HasCleanroom)
{
selectedLoaderName = "Cleanroom";
selectedAPIName = "Cleanroom";
selectedCleanroomVersion = currentInstance.Cleanroom;
selectedCleanroom = new ModDownload.DlCleanroomListEntry(selectedCleanroomVersion);
}
else if (currentInstance.HasForge)
{
selectedLoaderName = "Forge";
selectedForge =
new ModDownload.DlForgeVersionEntry(currentInstance.Forge, null, currentInstance.VanillaName)
{
Category = "installer", forgeType = ModDownload.DlForgelikeEntry.ForgelikeType.Forge,
Inherit = currentInstance.VanillaName
};
}
else if (currentInstance.HasLegacyFabric)
{
selectedLoaderName = "LegacyFabric";
selectedLegacyFabric = currentInstance.LegacyFabric;
selectedLegacyFabricApi = (ModComp.CompFile)GetCurrentLegacyFabricApi();
}
else if (currentInstance.HasFabric)
{
selectedLoaderName = "Fabric";
selectedFabric = currentInstance.Fabric;
selectedFabricApi = (ModComp.CompFile)GetCurrentFabricApi();
}
else if (currentInstance.HasLabyMod)
{
selectedLoaderName = "LabyMod";
selectedLabyModVersion = currentInstance.LabyMod;
}
else if (currentInstance.HasNeoForge)
{
selectedLoaderName = "NeoForge";
selectedNeoForgeVersion = currentInstance.NeoForge;
selectedNeoForge = new ModDownload.DlNeoForgeListEntry(currentInstance.NeoForge)
{
VersionName = currentInstance.NeoForge, Inherit = currentInstance.VanillaName,
forgeType = ModDownload.DlForgelikeEntry.ForgelikeType.NeoForge
};
}
if (currentInstance.HasFabric && currentInstance.HasOptiFine)
selectedOptiFabric = (ModComp.CompFile)GetCurrentOptiFabric();
_vanillaIcon = "pack://application:,,,/images/Blocks/Grass.png"; // TODO: 需要判断 Icon
currentInfo = GetSelectInfo();
EnterSelectPage();
}
private string currentInfo;
#endregion
#region 加载器
// 结果数据化
private static string GetVersionTypeTitle(string key) => key switch
{
"正式版" => Lang.Text("Download.Version.Type.Release"),
"预览版" => Lang.Text("Download.Version.Type.Development"),
"远古版" => Lang.Text("Download.Version.Type.BeforeRelease"),
"愚人节版" => Lang.Text("Download.Version.Type.AprilFools"),
_ => key
};
private void LoadMinecraft_OnFinish()
{
ExitSelectPage(); // 返回
do
{
try
{
var dict = new Dictionary<string, List<JsonObject>>
{
{ "正式版", new List<JsonObject>() }, { "预览版", new List<JsonObject>() }, { "远古版", new List<JsonObject>() },
{ "愚人节版", new List<JsonObject>() }
};
var versions = (JsonArray)ModDownload.dlClientListLoader.output.Value["versions"];
foreach (JsonObject Version in versions)
{
// 确定分类
var type = Version["type"].ToString();
var versionId = Version["id"].ToString().ToLower();
switch (type ?? "")
{
case "release":
{
type = "正式版";
break;
}
case "snapshot":
case "pending":
{
type = "预览版";
// Mojang 误分类
if (versionId.StartsWith("1.") && !versionId.Contains("combat") &&
!versionId.Contains("rc") && !versionId.Contains("experimental") &&
!versionId.Equals("1.2") && !versionId.Contains("pre"))
{
type = "正式版";
Version["type"] = "release";
}
// 愚人节版本
switch (Version["id"].ToString().ToLower() ?? "")
{
case "2point0_blue":
case "2point0_red":
case "2point0_purple":
case "2.0_blue":
case "2.0_red":
case "2.0_purple":
case "2.0":
{
type = "愚人节版";
Version["id"] = Version["id"].ToString().Replace("point", ".");
Version["type"] = "special";
Version.Add("lore", McVersionClassifier.GetMcFoolName((string)Version["id"]));
break;
}
case "20w14infinite":
case "20w14∞":
{
type = "愚人节版";
Version["id"] = "20w14∞";
Version["type"] = "special";
Version.Add("lore", McVersionClassifier.GetMcFoolName((string)Version["id"]));
break;
}
case "3d shareware v1.34":
case "1.rv-pre1":
case "15w14a":
case var @case when @case == "2.0":
case "22w13oneblockatatime":
case "23w13a_or_b":
case "24w14potato":
case "25w14craftmine":
case "26w14a":
{
type = "愚人节版";
Version["type"] = "special";
Version.Add("lore",
McVersionClassifier.GetMcFoolName((string)Version["id"])); // 4/1 自动视作愚人节版
break;
}
default:
{
var releaseDate = McVersionClassifier.GetReleaseTime(Version).ToUniversalTime().AddHours(2d);
if (releaseDate.Month == 4 && releaseDate.Day == 1)
{
type = "愚人节版";
Version["type"] = "special";
}
break;
}
}
break;
}
case "special":
{
// 已被处理的愚人节版
type = "愚人节版";
break;
}
default:
{
type = "远古版";
break;
}
}
// 加入辞典
dict[type].Add(Version);
}
// 排序
foreach (var Pair in dict.ToList())
dict[Pair.Key] = Pair.Value.OrderByDescending(McVersionClassifier.GetReleaseTime).ToList();
// 清空当前
PanMinecraft.Children.Clear();
// 添加最新版本
var cardInfo = new MyCard { Title = Lang.Text("Download.Version.Latest.Title"), Margin = new Thickness(0d, 15d, 0d, 15d) };
var topestVersions = new List<JsonObject>();
var release = (JsonObject)dict["正式版"][0].DeepClone();
release["lore"] = Lang.Text("Download.Version.Latest.Release", Lang.Date(release["releaseTime"].ToObject<DateTime>(), "g"));
topestVersions.Add(release);
if (dict["正式版"][0]["releaseTime"].ToObject<DateTime>() < dict["预览版"][0]["releaseTime"].ToObject<DateTime>())
{
var snapshot = (JsonObject)dict["预览版"][0].DeepClone();
snapshot["lore"] = Lang.Text("Download.Version.Latest.Development", Lang.Date(snapshot["releaseTime"].ToObject<DateTime>(), "g"));
topestVersions.Add(snapshot);
}
var panInfo = new StackPanel
{
Margin = new Thickness(20d, MyCard.SwapedHeight, 18d, 0d),
VerticalAlignment = VerticalAlignment.Top, RenderTransform = new TranslateTransform(0d, 0d),
Tag = topestVersions
};
void StackInstall(StackPanel stack)
{
foreach (var item in (IEnumerable)stack.Tag)
stack.Children.Add(ModDownloadLib.McDownloadListItem((JsonObject)item,
(sender, e) => MinecraftSelected((MyListItem)sender, e), false));
}
;
MyCard.StackInstall(ref panInfo, StackInstall);
cardInfo.Children.Add(panInfo);
PanMinecraft.Children.Insert(0, cardInfo);
// 添加其他版本
foreach (var Pair in dict)
{
if (!Pair.Value.Any())
continue;
// 增加卡片
var newCard = new MyCard
{ Title = GetVersionTypeTitle(Pair.Key) + " (" + Pair.Value.Count + ")", Margin = new Thickness(0d, 0d, 0d, 15d) };
var newStack = new StackPanel
{
Margin = new Thickness(20d, MyCard.SwapedHeight, 18d, 0d),
VerticalAlignment = VerticalAlignment.Top, RenderTransform = new TranslateTransform(0d, 0d),
Tag = Pair.Value
};
newCard.Children.Add(newStack);
newCard.SwapControl = newStack;
// 不能使用 AddressOf,这导致了 #535,原因完全不明,疑似是编译器 Bug
newCard.InstallMethod = StackInstall;
newCard.IsSwapped = true;
PanMinecraft.Children.Add(newCard);
}
// 自动选择版本
if (mcVersionWaitingForSelect is null)
break;
ModBase.Log("[Download] 自动选择 MC 版本:" + mcVersionWaitingForSelect);
foreach (JsonObject Version in versions)
{
if ((Version["id"].ToString() ?? "") != (mcVersionWaitingForSelect ?? ""))
continue;
var item = ModDownloadLib.McDownloadListItem(Version, (_, _) => { }, false);
MinecraftSelected(item, null);
}
}
catch (Exception ex)
{
ModBase.Log(
ex,
"可视化安装版本列表出错",
ModBase.LogLevel.Feedback,
userSummary: Lang.Text("Instance.Install.Error.OperationFailed"));
}
} while (false);
}
/// <summary>
/// 当 MC 版本列表加载完时,立即自动选择的版本。用于外部调用。
/// </summary>
public static string mcVersionWaitingForSelect = null;
#endregion
#region OptiFine 列表
/// <summary>
/// 获取 OptiFine 的加载异常信息。若正常则返回 Nothing。
/// </summary>
private string LoadOptiFineGetError()
{
if (selectedLoaderName == "NeoForge" || selectedLoaderName == "LabyMod" || selectedLoaderName == "Cleanroom")
return Lang.Text("Download.Install.Compat.IncompatibleWithLoader", selectedLoaderName);
if (LoadOptiFine is null || LoadOptiFine.State.LoadingState == MyLoading.MyLoadingState.Run)
return Lang.Text("Download.Install.State.Loading");
if (LoadOptiFine.State.LoadingState == MyLoading.MyLoadingState.Error)
return $"{Lang.Text("Download.Install.State.GetVersionListFailed")}{((ModLoader.LoaderBase)LoadOptiFine.State).Error.Message}";
// 检查 Forge 1.13 - 1.14.3:全部不兼容
if (selectedLoaderName == "Forge" && McVersionComparer.CompareVersion(_vanillaName, "1.13") >= 0 &&
McVersionComparer.CompareVersion("1.14.3", _vanillaName) >= 0) return Lang.Text("Download.Install.Compat.IncompatibleWithLoader", selectedLoaderName);
// 检查 Fabric 1.20.5+: 全部不兼容
if (selectedFabric is not null && McVersionComparer.CompareVersion(_vanillaName, "1.20.4") > 0)
return Lang.Text("Download.Install.Compat.IncompatibleWithLoader", selectedLoaderName);
// 检查 Loader
if (GetLoaderError(LoadOptiFine) is not null)
return GetLoaderError(LoadOptiFine);
// 检查 Forge 版本
var hasAny = false;
var hasRequiredVersion = false;
foreach (var OptiFineVersion in ModDownload.dlOptiFineListLoader.output.Value)
{
if (!OptiFineVersion.DisplayName.StartsWith(_vanillaName + " "))
continue; // 不是同一个大版本
hasAny = true;
if (selectedForge is null)
return null; // 未选择 Forge
if ((bool)IsOptiFineSuitForForge(OptiFineVersion, selectedForge))
return null; // 该版本可用
if (OptiFineVersion.RequiredForgeVersion is not null)
hasRequiredVersion = true;
}
if (!hasAny) return Lang.Text("Download.Install.State.NoVersion");
if (hasRequiredVersion) return Lang.Text("Download.Install.Compat.CompatForgeSpecificOnly");
return Lang.Text("Download.Install.Compat.IncompatibleWithLoader", selectedLoaderName);
}
// 检查某个 OptiFine 是否与某个 Forge 兼容
private object IsOptiFineSuitForForge(ModDownload.DlOptiFineListEntry optiFine,
ModDownload.DlForgeVersionEntry forge)
{
if ((forge.Inherit ?? "") != (optiFine.Inherit ?? ""))
return false; // 不是同一个大版本
if (optiFine.RequiredForgeVersion is null)
return false; // 不兼容 Forge
if (string.IsNullOrWhiteSpace(optiFine.RequiredForgeVersion))
return true; // #4183
if (optiFine.RequiredForgeVersion.Contains(".")) // XX.X.XXX
return McVersionComparer.CompareVersion(forge.version.ToString(), optiFine.RequiredForgeVersion) == 0;
// XXXX
return forge.version.Revision == Convert.ToDouble(optiFine.RequiredForgeVersion);
}
// 限制展开
private void CardOptiFine_PreviewSwap(object sender, ModBase.RouteEventArgs e)
{
if (LoadOptiFineGetError() is not null)
e.handled = true;
}
/// <summary>
/// 尝试重新可视化 OptiFine 版本列表。
/// </summary>
private void OptiFine_Loaded()
{
try
{
if (ModDownload.dlOptiFineListLoader.State != ModBase.LoadState.Finished)
return;
// 获取版本列表
var versions = new List<ModDownload.DlOptiFineListEntry>();
foreach (var Version in ModDownload.dlOptiFineListLoader.output.Value)
{
if (selectedForge is not null &&
!(bool)IsOptiFineSuitForForge(Version, selectedForge))
continue;
if (Version.DisplayName.StartsWith(_vanillaName + " "))
versions.Add(Version);
}
if (!versions.Any())
return;
// 排序
versions.Sort((left, right) =>
{
if (!left.IsPreview && right.IsPreview)
return true;
if (left.IsPreview && !right.IsPreview)
return false;
return McVersionComparer.CompareVersion(left.DisplayName, right.DisplayName) != 0;
});
// 可视化
PanOptiFine.Children.Clear();
foreach (var Version in versions)
PanOptiFine.Children.Add(
ModDownloadLib.OptiFineDownloadListItem(Version, (a, b) =>
this.OptiFine_Selected((dynamic)a, b), false));
}
catch (Exception ex)
{
ModBase.Log(
ex,
"可视化 OptiFine 安装版本列表出错",
ModBase.LogLevel.Feedback,
userSummary: Lang.Text("Instance.Install.Error.OperationFailed"));
}
}
// 选择与清除
private void OptiFine_Selected(MyListItem sender, EventArgs e)
{
selectedOptiFine = (ModDownload.DlOptiFineListEntry)sender.Tag;
if (selectedForge is not null &&
!(bool)IsOptiFineSuitForForge(selectedOptiFine, selectedForge))
selectedForge = null;
OptiFabric_Loaded();
Forge_Loaded();
NeoForge_Loaded();
CardOptiFine.IsSwapped = true;
ReloadSelected();
}
private void OptiFine_Clear(object sender, MouseButtonEventArgs e)
{
selectedOptiFine = null;
selectedOptiFabric = null;
autoSelectedOptiFabric = false;
CardOptiFine.IsSwapped = true;
e.Handled = true;
Forge_Loaded();
NeoForge_Loaded();
ReloadSelected();
}
#endregion
#region LiteLoader 列表
/// <summary>
/// 获取 LiteLoader 的加载异常信息。若正常则返回 Nothing。
/// </summary>
private string LoadLiteLoaderGetError()
{
// 检查 Loader
if (GetLoaderError(LoadLiteLoader) is not null)
return GetLoaderError(LoadLiteLoader);
if (selectedLoaderName == "NeoForge" || selectedLoaderName == "LegacyFabric" || selectedLoaderName == "LabyMod" || selectedLoaderName == "Cleanroom")
return Lang.Text("Download.Install.Compat.IncompatibleWithLoader", selectedLoaderName);
// 检查版本
return ModDownload.dlLiteLoaderListLoader.output.Value.Any(v => (v.Inherit ?? "") == (_vanillaName ?? ""))
? null
: Lang.Text("Download.Install.State.NoVersion");
}
// 限制展开
private void CardLiteLoader_PreviewSwap(object sender, ModBase.RouteEventArgs e)
{
if (LoadLiteLoaderGetError() is not null)
e.handled = true;
}
/// <summary>
/// 尝试重新可视化 LiteLoader 版本列表。
/// </summary>
private void LiteLoader_Loaded()
{
try
{
if (ModDownload.dlLiteLoaderListLoader.State != ModBase.LoadState.Finished)
return;
// 获取版本列表
var versions = new List<ModDownload.DlLiteLoaderListEntry>();
foreach (var Version in ModDownload.dlLiteLoaderListLoader.output.Value)
if ((Version.Inherit ?? "") == (_vanillaName ?? ""))
versions.Add(Version);
if (!versions.Any())
return;
// 可视化
PanLiteLoader.Children.Clear();
foreach (var Version in versions)
PanLiteLoader.Children.Add(ModDownloadLib.LiteLoaderDownloadListItem(Version,
(a, b) => this.LiteLoader_Selected((dynamic)a, b), false));
}
catch (Exception ex)
{
ModBase.Log(
ex,
"可视化 LiteLoader 安装版本列表出错",
ModBase.LogLevel.Feedback,
userSummary: Lang.Text("Instance.Install.Error.OperationFailed"));
}
}
// 选择与清除
private void LiteLoader_Selected(MyListItem sender, EventArgs e)
{
selectedLiteLoader = (ModDownload.DlLiteLoaderListEntry)sender.Tag;
CardLiteLoader.IsSwapped = true;
ReloadSelected();
}
private void LiteLoader_Clear(object sender, MouseButtonEventArgs e)
{
selectedLiteLoader = null;
CardLiteLoader.IsSwapped = true;
e.Handled = true;
ReloadSelected();
}
#endregion
#region Forge 列表
/// <summary>
/// 获取 Forge 的加载异常信息。若正常则返回 Nothing。
/// </summary>
private string LoadForgeGetError()
{
if (McVersionComparer.CompareVersionGe("1.5.1", _vanillaName) && McVersionComparer.CompareVersionGe(_vanillaName, "1.1"))
return Lang.Text("Download.Install.State.NoVersion");
if (selectedLoaderName is not null && !ReferenceEquals(selectedLoaderName, "Forge"))
return Lang.Text("Download.Install.Compat.IncompatibleWithLoader", selectedLoaderName);
// 检查 Loader
if (GetLoaderError(LoadForge) is not null)
return GetLoaderError(LoadForge);
var loader = (ModLoader.LoaderTask<string, List<ModDownload.DlForgeVersionEntry>>)LoadForge.State;
if ((_vanillaName ?? "") != (loader.input ?? ""))
return Lang.Text("Download.Install.State.Getting");
// 检查版本
foreach (var Version in loader.output)
{
if (Version.Category == "universal" || Version.Category == "client")
continue; // 跳过无法自动安装的版本
if (selectedLoaderName is not null && selectedLoaderName != "Forge")
return Lang.Text("Download.Install.Compat.IncompatibleWithLoader", selectedLoaderName);
if (selectedOptiFine is not null && McVersionComparer.CompareVersionGe(_vanillaName, "1.13") &&
McVersionComparer.CompareVersionGe("1.14.3", _vanillaName))
return Lang.Text("Download.Install.Compat.IncompatibleWithOptiFine"); // 1.13 ~ 1.14.3 OptiFine 检查
if (selectedOptiFine is not null && !(bool)IsOptiFineSuitForForge(selectedOptiFine, Version))
continue;
return null;
}
return Lang.Text("Download.Install.Compat.IncompatibleWithOptiFine");
}
// 限制展开
private void CardForge_PreviewSwap(object sender, ModBase.RouteEventArgs e)
{
if (LoadForgeGetError() is not null)
e.handled = true;
}
/// <summary>
/// 尝试重新可视化 Forge 版本列表。
/// </summary>
private void Forge_Loaded()
{
try
{
if (!LoadForge.State.IsLoader)
return;
var loader = (ModLoader.LoaderTask<string, List<ModDownload.DlForgeVersionEntry>>)LoadForge.State;
if ((_vanillaName ?? "") != (loader.input ?? ""))
return;
if (loader.State != ModBase.LoadState.Finished)
return;
// 获取要显示的版本
var versions = loader.output.ToList(); // 复制数组,以免 Output 在实例化后变空
if (!loader.output.Any())
return;
PanForge.Children.Clear();
versions = versions.Where(v =>
{
if (v.Category == "universal" || v.Category == "client")
return false; // 跳过无法自动安装的版本
if (selectedOptiFine is not null &&
!(bool)IsOptiFineSuitForForge(selectedOptiFine, v))
return false;
return true;
}).OrderByDescending(v => v).ToList();
ModDownloadLib.ForgeDownloadListItemPreload(PanForge, versions,
(a, b) => this.Forge_Selected((dynamic)a, b), false);
foreach (var Version in versions)
PanForge.Children.Add(
ModDownloadLib.ForgeDownloadListItem(Version, (a, b) => this.Forge_Selected((dynamic)a, b), false));
}
catch (Exception ex)
{
ModBase.Log(
ex,
"可视化 Forge 安装版本列表出错",
ModBase.LogLevel.Feedback,
userSummary: Lang.Text("Instance.Install.Error.OperationFailed"));
}
}
// 选择与清除
private void Forge_Selected(MyListItem sender, EventArgs e)
{
selectedForge = (ModDownload.DlForgeVersionEntry)sender.Tag;
selectedLoaderName = "Forge";
CardForge.IsSwapped = true;
if (selectedOptiFine is not null &&
!(bool)IsOptiFineSuitForForge(selectedOptiFine, selectedForge))
selectedOptiFine = null;
OptiFine_Loaded();
ReloadSelected();
}
private void Forge_Clear(object sender, MouseButtonEventArgs e)
{
selectedForge = null;
selectedLoaderName = null;
CardForge.IsSwapped = true;
e.Handled = true;
OptiFine_Loaded();
ReloadSelected();
}
#endregion
#region NeoForge 列表
/// <summary>
/// 获取 NeoForge 的加载异常信息。若正常则返回 Nothing。
/// </summary>
private string LoadNeoForgeGetError()
{
if (selectedOptiFine is not null)
return Lang.Text("Download.Install.Compat.IncompatibleWithOptiFine");
if (selectedLoaderName is not null && !ReferenceEquals(selectedLoaderName, "NeoForge"))
return Lang.Text("Download.Install.Compat.IncompatibleWithLoader", selectedLoaderName);
// 检查 Loader
if (GetLoaderError(LoadNeoForge) is not null)
return GetLoaderError(LoadNeoForge);
// 检查版本
return ModDownload.dlNeoForgeListLoader.output.Value.Any(v => (v.Inherit ?? "") == (_vanillaName ?? ""))
? null
: Lang.Text("Download.Install.State.NoVersion");
}
// 限制展开
private void CardNeoForge_PreviewSwap(object sender, ModBase.RouteEventArgs e)
{
if (LoadNeoForgeGetError() is not null)
e.handled = true;
}
/// <summary>
/// 尝试重新可视化 NeoForge 版本列表。
/// </summary>
private void NeoForge_Loaded()
{
try
{
// 获取版本列表
if (ModDownload.dlNeoForgeListLoader.State != ModBase.LoadState.Finished)
return;
var versions = ModDownload.dlNeoForgeListLoader.output.Value
.Where(v => (v.Inherit ?? "") == (_vanillaName ?? "")).ToList();
if (!versions.Any())
return;
// 可视化
PanNeoForge.Children.Clear();
ModDownloadLib.NeoForgeDownloadListItemPreload(PanNeoForge, versions,
(a, b) => this.NeoForge_Selected((dynamic)a, b),
false);
foreach (var Version in versions)
PanNeoForge.Children.Add(
ModDownloadLib.NeoForgeDownloadListItem(Version, (a, b) => this.NeoForge_Selected((dynamic)a, b),
false));
}
catch (Exception ex)
{
ModBase.Log(
ex,
"可视化 NeoForge 安装版本列表出错",
ModBase.LogLevel.Feedback,
userSummary: Lang.Text("Instance.Install.Error.OperationFailed"));
}
}
// 选择与清除
private void NeoForge_Selected(MyListItem sender, EventArgs e)
{
selectedNeoForge = (ModDownload.DlNeoForgeListEntry)sender.Tag;
selectedLoaderName = "NeoForge";
CardNeoForge.IsSwapped = true;
OptiFine_Loaded();
ReloadSelected();
}
private void NeoForge_Clear(object sender, MouseButtonEventArgs e)
{
selectedNeoForge = null;
selectedLoaderName = null;
CardNeoForge.IsSwapped = true;
e.Handled = true;
OptiFine_Loaded();
ReloadSelected();
}
#endregion
#region Cleanroom 列表
/// <summary>
/// 获取 Cleanroom 的加载异常信息。若正常则返回 Nothing。
/// </summary>
private string LoadCleanroomGetError()
{
if (!_vanillaName.StartsWith("1."))
return Lang.Text("Download.Install.State.NoAvailableVersion");
if (selectedOptiFine is not null)
return Lang.Text("Download.Install.Compat.IncompatibleWithOptiFine");
if (selectedLoaderName is not null && selectedLoaderName != "Cleanroom")
return Lang.Text("Download.Install.Compat.IncompatibleWithLoader", selectedLoaderName);
if (selectedLiteLoader is not null)
return Lang.Text("Download.Install.Compat.IncompatibleWithLiteLoader");
// 检查 Loader
if (GetLoaderError(LoadCleanroom) is not null)
return GetLoaderError(LoadCleanroom);
// 检查版本
return ModDownload.dlCleanroomListLoader.output.Value.Any(v => (v.Inherit ?? "") == (_vanillaName ?? ""))
? null
: Lang.Text("Download.Install.State.NoVersion");
}
// 限制展开
private void CardCleanroom_PreviewSwap(object sender, ModBase.RouteEventArgs e)
{
if (LoadCleanroomGetError() is not null)
e.handled = true;
}
/// <summary>
/// 尝试重新可视化 Cleanroom 版本列表。
/// </summary>
private void Cleanroom_Loaded()
{
try
{
// 获取版本列表
if (ModDownload.dlCleanroomListLoader.State != ModBase.LoadState.Finished)
return;
var versions = ModDownload.dlCleanroomListLoader.output.Value
.Where(v => (v.Inherit ?? "") == (_vanillaName ?? "")).ToList();
if (!versions.Any())
return;
// 可视化
PanCleanroom.Children.Clear();
ModDownloadLib.CleanroomDownloadListItemPreload(PanCleanroom, versions,
(a, b) => this.Cleanroom_Selected((dynamic)a, b), false);
foreach (var Version in versions)
PanCleanroom.Children.Add(
ModDownloadLib.CleanroomDownloadListItem(Version, (a, b) => this.Cleanroom_Selected((dynamic)a, b),
false));
}
catch (Exception ex)
{
ModBase.Log(
ex,
"可视化 Cleanroom 安装版本列表出错",
ModBase.LogLevel.Feedback,
userSummary: Lang.Text("Instance.Install.Error.OperationFailed"));
}
}
// 选择与清除
private void Cleanroom_Selected(MyListItem sender, EventArgs e)
{
selectedCleanroom = (ModDownload.DlCleanroomListEntry)sender.Tag;
selectedLoaderName = "Cleanroom";
CardCleanroom.IsSwapped = true;
OptiFine_Loaded();
ReloadSelected();
}
private void Cleanroom_Clear(object sender, MouseButtonEventArgs e)
{
selectedCleanroom = null;
selectedCleanroomVersion = null;
selectedLoaderName = null;
selectedAPIName = null;
CardCleanroom.IsSwapped = true;
e.Handled = true;
OptiFine_Loaded();
ReloadSelected();
}
#endregion
#region Fabric 列表
/// <summary>
/// 获取 Fabric 的加载异常信息。若正常则返回 Nothing。
/// </summary>
private string LoadFabricGetError()
{
// 检查 OptiFine 1.20.5+:没有 OptiFabric 故全部不兼容
if (selectedOptiFine is not null && McVersionComparer.CompareVersionGe(_vanillaName, "1.20.5"))
return Lang.Text("Download.Install.Compat.IncompatibleWithOptiFine");
// 检查 Loader
if (GetLoaderError(LoadFabric) is not null)
return GetLoaderError(LoadFabric);
// 检查版本
foreach (JsonObject version in ModDownload.dlFabricListLoader.output.Value["game"].AsArray())
if ((version["version"].ToString() ?? "") ==
(_vanillaName.Replace("∞", "infinite").Replace("Combat Test 7c", "1.16_combat-3") ?? ""))
{
if (selectedLoaderName is not null && !ReferenceEquals(selectedLoaderName, "Fabric"))
return Lang.Text("Download.Install.Compat.IncompatibleWithLoader", selectedLoaderName);
return null;
}
return Lang.Text("Download.Install.State.NoVersion");
}
// 限制展开
private void CardFabric_PreviewSwap(object sender, ModBase.RouteEventArgs e)
{
if (LoadFabricGetError() is not null)
e.handled = true;
}
/// <summary>
/// 尝试重新可视化 Fabric 版本列表。
/// </summary>
private void Fabric_Loaded()
{
try
{
if (ModDownload.dlFabricListLoader.State != ModBase.LoadState.Finished)
return;
// 获取版本列表
var versions = (JsonArray)ModDownload.dlFabricListLoader.output.Value["loader"];
if (!versions.Any())
return;
// 可视化
PanFabric.Children.Clear();
PanFabric.Tag = versions;
CardFabric.SwapControl = PanFabric;
CardFabric.InstallMethod = stack =>
{
foreach (var item in (IEnumerable)stack.Tag)
stack.Children.Add(
ModDownloadLib.FabricDownloadListItem((JsonObject)item,
(a, b) => this.Fabric_Selected((dynamic)a, b)));
};
}
catch (Exception ex)
{
ModBase.Log(
ex,
"可视化 Fabric 安装版本列表出错",
ModBase.LogLevel.Feedback,
userSummary: Lang.Text("Instance.Install.Error.OperationFailed"));
}
}
// 选择与清除
public void Fabric_Selected(MyListItem sender, EventArgs e)
{
selectedFabric = ((dynamic)sender.Tag)["version"].ToString();
selectedLoaderName = "Fabric";
FabricApi_Loaded();
OptiFabric_Loaded();
CardFabric.IsSwapped = true;
ReloadSelected();
}
private void Fabric_Clear(object sender, MouseButtonEventArgs e)
{
selectedFabric = null;
selectedFabricApi = null;
autoSelectedFabricApi = false;
selectedOptiFabric = null;
autoSelectedOptiFabric = false;
selectedLoaderName = null;
selectedAPIName = null;
CardFabric.IsSwapped = true;
e.Handled = true;
ReloadSelected();
}
#endregion
#region Fabric API 列表
/// <summary>
/// 判断某 Fabric API 是否适配当前选择的原版版本。
/// </summary>
public bool IsFabricApiCompatible(ModComp.CompFile fabricApi)
{
var fabricApiName = fabricApi.DisplayName;
try
{
if (fabricApiName is null || _vanillaName is null)
return false;
fabricApiName = fabricApiName.ToLower();
_vanillaName = _vanillaName.Replace("∞", "infinite").Replace("Combat Test 7c", "1.16_combat-3").ToLower();
if (fabricApiName.StartsWith("[" + _vanillaName + "]"))
return true;
if (!fabricApiName.Contains("/") || !fabricApiName.Contains("]"))
return false;
// 直接的判断(例如 1.18.1/22w03a
foreach (var part in fabricApiName.BeforeFirst("]").TrimStart('[').Split("/"))
if ((part ?? "") == (_vanillaName ?? ""))
return true;
// 将版本名分割语素(例如 1.16.4/5)
var lefts = fabricApiName.BeforeFirst("]").RegexSearch("[a-z/]+|[0-9/]+");
var rights = _vanillaName.BeforeFirst("]").RegexSearch("[a-z/]+|[0-9/]+");
// 对每段进行判断
var i = 0;
while (true)
{
// 两边均缺失,感觉是一个东西
if (lefts.Count - 1 < i && rights.Count - 1 < i)
return true;
// 确定两边是否一致
var leftValue = lefts.Count - 1 < i ? "-1" : lefts[i];
var rightValue = rights.Count - 1 < i ? "-1" : rights[i];
if (!leftValue.Contains("/"))
{
if ((leftValue ?? "") != (rightValue ?? ""))
return false;
}
// 左边存在斜杠
else if (!leftValue.Contains(rightValue))
{
return false;
}
i += 1;
}
return true;
}
catch (Exception ex)
{
ModBase.Log(ex, "判断 Fabric API 版本适配性出错(" + fabricApiName + ", " + _vanillaName + "");
return false;
}
}
/// <summary>
/// 获取 FabricApi 的加载异常信息。若正常则返回 Nothing。
/// </summary>
private string LoadFabricApiGetError()
{
// 检查 Loader
if (GetLoaderError(LoadFabricApi) is not null)
return GetLoaderError(LoadFabricApi);
if (ModDownload.dlFabricApiLoader.output is null)
return selectedFabric is null ? Lang.Text("Download.Install.Compat.RequiresFabric") : Lang.Text("Download.Install.State.Getting");
// 检查版本
if (ModDownload.dlFabricApiLoader.output.Any(f => IsFabricApiCompatible(f)))
return selectedFabric is null ? Lang.Text("Download.Install.Compat.RequiresFabric") : null;
return Lang.Text("Download.Install.State.NoVersion");
}
// 限制展开
private void CardFabricApi_PreviewSwap(object sender, ModBase.RouteEventArgs e)
{
if (LoadFabricApiGetError() is not null)
e.handled = true;
}
private bool autoSelectedFabricApi;
/// <summary>
/// 尝试重新可视化 FabricApi 版本列表。
/// </summary>
private void FabricApi_Loaded()
{
try
{
if (ModDownload.dlFabricApiLoader.State != ModBase.LoadState.Finished)
return;
if (_vanillaName is null || selectedFabric is null)
return;
// 获取版本列表
var versions = new List<ModComp.CompFile>();
foreach (var version in ModDownload.dlFabricApiLoader.output)
if (IsFabricApiCompatible(version))
{
if (!version.DisplayName.StartsWith("["))
{
ModBase.Log("[Download] 已特判修改 Fabric API 显示名:" + version.DisplayName, ModBase.LogLevel.Debug);
version.DisplayName = "[" + _vanillaName + "] " + version.DisplayName;
}
versions.Add(version);
}
if (!versions.Any())
return;
versions = versions.OrderByDescending(v => v.ReleaseDate).ToList();
// 可视化
PanFabricApi.Children.Clear();
foreach (var version in versions)
{
if (!IsFabricApiCompatible(version))
continue;
PanFabricApi.Children.Add(
ModDownloadLib.FabricApiDownloadListItem(version,
(a, b) => this.FabricApi_Selected((dynamic)a, b)));
}
// 自动选择 Fabric API
if (!autoSelectedFabricApi)
{
autoSelectedFabricApi = true;
ModBase.Log($"[Download] 已自动选择 Fabric API{((MyListItem)PanFabricApi.Children[0]).Title}");
FabricApi_Selected((MyListItem)PanFabricApi.Children[0], null);
}
}
catch (Exception ex)
{
ModBase.Log(
ex,
"可视化 Fabric API 安装版本列表出错",
ModBase.LogLevel.Feedback,
userSummary: Lang.Text("Instance.Install.Error.OperationFailed"));
}
}
// 选择与清除
private void FabricApi_Selected(MyListItem sender, EventArgs e)
{
selectedFabricApi = (ModComp.CompFile)sender.Tag;
selectedAPIName = "Fabric API";
CardFabricApi.IsSwapped = true;
ReloadSelected();
}
private void FabricApi_Clear(object sender, MouseButtonEventArgs e)
{
selectedFabricApi = null;
selectedAPIName = null;
CardFabricApi.IsSwapped = true;
e.Handled = true;
ReloadSelected();
}
#endregion
#region LegacyFabric 列表
/// <summary>
/// 获取 LegacyFabric 的加载异常信息。若正常则返回 Nothing。
/// </summary>
private string LoadLegacyFabricGetError()
{
if (LoadLegacyFabric is null || LoadLegacyFabric.State.LoadingState == MyLoading.MyLoadingState.Run)
return Lang.Text("Download.Install.State.Loading");
if (LoadLegacyFabric.State.LoadingState == MyLoading.MyLoadingState.Error)
return Lang.Text("Download.Install.State.GetVersionListFailed", ((ModLoader.LoaderBase)LoadLegacyFabric.State).Error.Message);
foreach (JsonObject Version in ModDownload.dlLegacyFabricListLoader.output.Value["game"].AsArray())
if ((Version["version"].ToString() ?? "") == (_vanillaName ?? ""))
{
if (selectedLiteLoader is not null)
return Lang.Text("Download.Install.Compat.IncompatibleWithLiteLoader");
if (selectedLoaderName is not null && !ReferenceEquals(selectedLoaderName, "LegacyFabric"))
return Lang.Text("Download.Install.Compat.IncompatibleWithLoader", selectedLoaderName);
return null;
}
return Lang.Text("Download.Install.State.NoVersion");
}
// 限制展开
private void CardLegacyFabric_PreviewSwap(object sender, ModBase.RouteEventArgs e)
{
if (LoadLegacyFabricGetError() is not null)
e.handled = true;
}
/// <summary>
/// 尝试重新可视化 LegacyFabric 版本列表。
/// </summary>
private void LegacyFabric_Loaded()
{
try
{
if (ModDownload.dlLegacyFabricListLoader.State != ModBase.LoadState.Finished)
return;
// 获取版本列表
var versions = (JsonArray)ModDownload.dlLegacyFabricListLoader.output.Value["loader"];
if (!versions.Any())
return;
// 可视化
PanLegacyFabric.Children.Clear();
PanLegacyFabric.Tag = versions;
CardLegacyFabric.SwapControl = PanLegacyFabric;
CardLegacyFabric.InstallMethod = stack =>
{
foreach (var item in (IEnumerable)stack.Tag)
stack.Children.Add(ModDownloadLib.LegacyFabricDownloadListItem((JsonObject)item,
(a, b) => this.LegacyFabric_Selected((dynamic)a, b)));
};
}
catch (Exception ex)
{
ModBase.Log(
ex,
"可视化 LegacyFabric 安装版本列表出错",
ModBase.LogLevel.Feedback,
userSummary: Lang.Text("Instance.Install.Error.OperationFailed"));
}
}
// 选择与清除
public void LegacyFabric_Selected(MyListItem sender, EventArgs e)
{
selectedLegacyFabric = ((dynamic)sender.Tag)["version"].ToString();
selectedLoaderName = "LegacyFabric";
LegacyFabricApi_Loaded();
CardLegacyFabric.IsSwapped = true;
ReloadSelected();
}
private void LegacyFabric_Clear(object sender, MouseButtonEventArgs e)
{
selectedLegacyFabric = null;
selectedLegacyFabricApi = null;
autoSelectedLegacyFabricApi = false;
selectedLoaderName = null;
selectedAPIName = null;
CardLegacyFabric.IsSwapped = true;
e.Handled = true;
ReloadSelected();
}
#endregion
#region Legacy Fabric API 列表
/// <summary>
/// 从显示名判断该 API 是否与某版本适配。
/// </summary>
public static bool IsSuitableLegacyFabricApi(List<string> supportVersions, string minecraftVersion)
{
try
{
if (supportVersions.Contains(minecraftVersion)) return true;
return false;
}
catch (Exception ex)
{
ModBase.Log(ex, "判断 Legacy Fabric API 版本适配性出错(" + supportVersions + ", " + minecraftVersion + "");
return false;
}
}
/// <summary>
/// 获取 LegacyFabricApi 的加载异常信息。若正常则返回 Nothing。
/// </summary>
private string LoadLegacyFabricApiGetError()
{
if (LoadLegacyFabricApi is null || LoadLegacyFabricApi.State.LoadingState == MyLoading.MyLoadingState.Run)
return Lang.Text("Download.Install.State.Loading");
if (LoadLegacyFabricApi.State.LoadingState == MyLoading.MyLoadingState.Error)
return Lang.Text("Download.Install.State.GetVersionListFailed", ((ModLoader.LoaderBase)LoadLegacyFabricApi.State).Error.Message);
if (selectedAPIName is not null && !ReferenceEquals(selectedAPIName, "Legacy Fabric API"))
return Lang.Text("Download.Install.Compat.IncompatibleWithLoader", selectedAPIName);
if (ModDownload.dlLegacyFabricApiLoader.output is null)
{
if (selectedLegacyFabric is null)
return Lang.Text("Download.Install.Compat.RequiresLegacyFabric");
return Lang.Text("Download.Install.State.Loading");
}
foreach (var Version in ModDownload.dlLegacyFabricApiLoader.output)
{
if (!IsSuitableLegacyFabricApi(Version.GameVersions, _vanillaName))
continue;
if (selectedLegacyFabric is null)
return Lang.Text("Download.Install.Compat.RequiresLegacyFabric");
return null;
}
return Lang.Text("Download.Install.State.NoVersion");
}
// 限制展开
private void CardLegacyFabricApi_PreviewSwap(object sender, ModBase.RouteEventArgs e)
{
if (LoadLegacyFabricApiGetError() is not null)
e.handled = true;
}
private bool autoSelectedLegacyFabricApi;
/// <summary>
/// 尝试重新可视化 LegacyFabricApi 版本列表。
/// </summary>
private void LegacyFabricApi_Loaded()
{
try
{
if (ModDownload.dlLegacyFabricApiLoader.State != ModBase.LoadState.Finished)
return;
if (_vanillaName is null || selectedLegacyFabric is null)
return;
// 获取版本列表
var versions = new List<ModComp.CompFile>();
foreach (var Version in ModDownload.dlLegacyFabricApiLoader.output)
if (IsSuitableLegacyFabricApi(Version.GameVersions, _vanillaName))
versions.Add(Version);
if (!versions.Any())
return;
versions = versions.OrderByDescending(v => v.ReleaseDate).ToList();
// 可视化
PanLegacyFabricApi.Children.Clear();
foreach (var Version in versions)
{
if (!IsSuitableLegacyFabricApi(Version.GameVersions, _vanillaName))
continue;
PanLegacyFabricApi.Children.Add(
ModDownloadLib.LegacyFabricApiDownloadListItem(Version,
(a, b) => this.LegacyFabricApi_Selected((dynamic)a, b)));
}
// 自动选择 Legacy Fabric API
if (!autoSelectedLegacyFabricApi)
{
autoSelectedLegacyFabricApi = true;
ModBase.Log($"[Download] 已自动选择 Legacy Fabric API{((MyListItem)PanLegacyFabricApi.Children[0]).Title}");
LegacyFabricApi_Selected((MyListItem)PanLegacyFabricApi.Children[0], null);
}
}
catch (Exception ex)
{
ModBase.Log(
ex,
"可视化 Legacy Fabric API 安装版本列表出错",
ModBase.LogLevel.Feedback,
userSummary: Lang.Text("Instance.Install.Error.OperationFailed"));
}
}
// 选择与清除
private void LegacyFabricApi_Selected(MyListItem sender, EventArgs e)
{
selectedLegacyFabricApi = (ModComp.CompFile)sender.Tag;
selectedAPIName = "Legacy Fabric API";
CardLegacyFabricApi.IsSwapped = true;
ReloadSelected();
}
private void LegacyFabricApi_Clear(object sender, MouseButtonEventArgs e)
{
selectedLegacyFabricApi = null;
selectedAPIName = null;
CardLegacyFabricApi.IsSwapped = true;
e.Handled = true;
ReloadSelected();
}
#endregion
#region OptiFabric 列表
/// <summary>
/// 判断某 OptiFabric 是否适配当前选择的原版版本。
/// </summary>
private bool IsOptiFabricCompatible(ModComp.CompFile modFile)
{
try
{
if (_vanillaName is null)
return false;
return modFile.GameVersions.Contains(_vanillaName);
}
catch (Exception ex)
{
ModBase.Log(ex, "判断 OptiFabric 版本适配性出错(" + _vanillaName + "");
return false;
}
}
private bool autoSelectedOptiFabric;
/// <summary>
/// 获取 OptiFabric 的加载异常信息。若正常则返回 Nothing。
/// </summary>
private string LoadOptiFabricGetError()
{
if (VanillaDrop >= 140 && VanillaDrop <= 150)
return Lang.Text("Download.Install.Compat.OptiFabricOriginsRequired");
// 检查 Loader
if (GetLoaderError(LoadOptiFabric) is not null)
return GetLoaderError(LoadOptiFabric);
// 检查版本
if (ModDownload.dlOptiFabricLoader.output is null)
{
if (selectedFabric is null && selectedOptiFine is null)
return Lang.Text("Download.Install.Compat.RequiresOptiFineAndFabric");
if (selectedFabric is null)
return Lang.Text("Download.Install.Compat.RequiresFabric");
if (selectedOptiFine is null)
return Lang.Text("Download.Install.Compat.RequiresOptiFine");
return Lang.Text("Download.Install.State.Getting");
}
foreach (var version in ModDownload.dlOptiFabricLoader.output)
{
if (!IsOptiFabricCompatible(version))
continue; // 2135#
if (selectedFabric is null && selectedOptiFine is null)
return Lang.Text("Download.Install.Compat.RequiresOptiFineAndFabric");
if (selectedFabric is null)
return Lang.Text("Download.Install.Compat.RequiresFabric");
if (selectedOptiFine is null)
return Lang.Text("Download.Install.Compat.RequiresOptiFine");
return null; // 通过检查
}
return Lang.Text("Download.Install.State.NoVersion");
}
// 限制展开
private void CardOptiFabric_PreviewSwap(object sender, ModBase.RouteEventArgs e)
{
if (LoadOptiFabricGetError() is not null)
e.handled = true;
}
/// <summary>
/// 尝试重新可视化 OptiFabric 版本列表。
/// </summary>
private void OptiFabric_Loaded()
{
try
{
if (ModDownload.dlOptiFabricLoader.State != ModBase.LoadState.Finished)
return;
if (_vanillaName is null || selectedFabric is null || selectedOptiFine is null)
return;
// 获取版本列表
var versions = new List<ModComp.CompFile>();
foreach (var Version in ModDownload.dlOptiFabricLoader.output)
if (IsOptiFabricCompatible(Version))
versions.Add(Version);
if (!versions.Any())
return;
// 排序
versions = versions.OrderByDescending(v => v.ReleaseDate).ToList();
// 可视化
PanOptiFabric.Children.Clear();
foreach (var Version in versions)
{
if (!IsOptiFabricCompatible(Version))
continue;
PanOptiFabric.Children.Add(
ModDownloadLib.OptiFabricDownloadListItem(Version,
(a, b) => this.OptiFabric_Selected((dynamic)a, b)));
}
// 自动选择 OptiFabric
if (autoSelectedOptiFabric || (VanillaDrop >= 140 && VanillaDrop <= 150))
return; // 1.14~15 不自动选择
autoSelectedOptiFabric = true;
ModBase.Log($"[Download] 已自动选择 OptiFabric{((MyListItem)PanOptiFabric.Children[0]).Title}");
OptiFabric_Selected((MyListItem)PanOptiFabric.Children[0], null);
}
catch (Exception ex)
{
ModBase.Log(
ex,
"可视化 OptiFabric 安装版本列表出错",
ModBase.LogLevel.Feedback,
userSummary: Lang.Text("Instance.Install.Error.OperationFailed"));
}
}
// 选择与清除
private void OptiFabric_Selected(MyListItem sender, EventArgs e)
{
selectedOptiFabric = (ModComp.CompFile)sender.Tag;
CardOptiFabric.IsSwapped = true;
ReloadSelected();
}
private void OptiFabric_Clear(object sender, MouseButtonEventArgs e)
{
selectedOptiFabric = null;
CardOptiFabric.IsSwapped = true;
e.Handled = true;
ReloadSelected();
}
#endregion
#region LabyMod 列表
/// <summary>
/// 获取 LabyMod 的加载异常信息。若正常则返回 Nothing。
/// </summary>
private string LoadLabyModGetError()
{
if (LoadLabyMod is null || LoadLabyMod.State.LoadingState == MyLoading.MyLoadingState.Run)
return Lang.Text("Download.Install.State.Loading");
if (LoadLabyMod.State.LoadingState == MyLoading.MyLoadingState.Error)
return Lang.Text("Download.Install.State.GetVersionListFailed", ((ModLoader.LoaderBase)LoadLabyMod.State).Error.Message);
// 检查 Loader
if (GetLoaderError(LoadLabyMod) is not null)
return GetLoaderError(LoadLabyMod);
if (selectedOptiFine is not null)
return Lang.Text("Download.Install.Compat.IncompatibleWithOptiFine");
if (selectedLoaderName is not null && selectedLoaderName != "LabyMod")
return Lang.Text("Download.Install.Compat.IncompatibleWithLoader", selectedLoaderName);
if (selectedLiteLoader is not null)
return Lang.Text("Download.Install.Compat.IncompatibleWithLiteLoader");
foreach (JsonObject Version in ModDownload.dlLabyModListLoader.output.Value["production"]["minecraftVersions"].AsArray())
if ((Version["version"].ToString() ?? "") == (_vanillaName ?? ""))
return null;
foreach (JsonObject Version in ModDownload.dlLabyModListLoader.output.Value["snapshot"]["minecraftVersions"].AsArray())
if ((Version["version"].ToString() ?? "") == (_vanillaName ?? ""))
return null;
return Lang.Text("Download.Install.State.NoVersion");
}
// 限制展开
private void CardLabyMod_PreviewSwap(object sender, ModBase.RouteEventArgs e)
{
if (LoadLabyModGetError() is not null)
e.handled = true;
}
/// <summary>
/// 尝试重新可视化 LabyMod 版本列表。
/// </summary>
private void LabyMod_Loaded()
{
try
{
if (LoadLabyMod.State.LoadingState == MyLoading.MyLoadingState.Run)
return;
// 获取版本列表
var versions = ModDownload.dlLabyModListLoader.output.Value;
if (versions is null || versions["production"] is null || versions["snapshot"] is null)
return;
// 可视化
var processedVersions = new JsonArray();
foreach (JsonObject Production in versions["production"]["minecraftVersions"].AsArray())
if ((Production["version"].ToString() ?? "") == (_vanillaName ?? ""))
{
var productionVersion = new JsonObject();
productionVersion.Add("version", versions["production"]["labyModVersion"].ToString());
productionVersion.Add("channel", "production");
productionVersion.Add("commitReference", versions["production"]["commitReference"].ToString());
processedVersions.Add(productionVersion);
}
foreach (JsonObject Snapshot in versions["snapshot"]["minecraftVersions"].AsArray())
if ((Snapshot["version"].ToString() ?? "") == (_vanillaName ?? ""))
{
var snapshotVersion = new JsonObject();
snapshotVersion.Add("version", versions["snapshot"]["labyModVersion"].ToString());
snapshotVersion.Add("channel", "snapshot");
snapshotVersion.Add("commitReference", versions["snapshot"]["commitReference"].ToString());
processedVersions.Add(snapshotVersion);
}
// MyMsgBox(If(ProcessedVersions.ToString, "Nothing"))
PanLabyMod.Children.Clear();
PanLabyMod.Tag = processedVersions;
CardLabyMod.SwapControl = PanLabyMod;
CardLabyMod.InstallMethod = stack =>
{
foreach (JsonObject item in (IEnumerable)stack.Tag)
stack.Children.Add(
ModDownloadLib.LabyModDownloadListItem(item, (a, b) => this.LabyMod_Selected((dynamic)a, b)));
};
}
catch (Exception ex)
{
ModBase.Log(
ex,
"可视化 LabyMod 安装版本列表出错",
ModBase.LogLevel.Feedback,
userSummary: Lang.Text("Instance.Install.Error.OperationFailed"));
}
}
// 选择与清除
public void LabyMod_Selected(MyListItem sender, EventArgs e)
{
selectedLabyModChannel = ((dynamic)sender.Tag)("channel").ToString();
selectedLabyModCommitRef = ((dynamic)sender.Tag)("commitReference").ToString();
selectedLabyModVersion =
((dynamic)sender.Tag)("version").ToString() + (selectedLabyModChannel == "snapshot" ? " " + Lang.Text("Download.Version.Type.Snapshot") : " " + Lang.Text("Download.Version.Type.Stable"));
selectedLoaderName = "LabyMod";
CardLabyMod.IsSwapped = true;
ReloadSelected();
}
private void LabyMod_Clear(object sender, MouseButtonEventArgs e)
{
selectedLabyModCommitRef = null;
selectedLabyModVersion = null;
selectedLabyModChannel = null;
if (selectedLoaderName == "LabyMod")
{
selectedLoaderName = null;
}
selectedAPIName = null;
CardLabyMod.IsSwapped = true;
e.Handled = true;
ReloadSelected();
}
#endregion
}