Files

2328 lines
91 KiB
C#
Raw Permalink Normal View History

using System.Collections;
using System.Collections.ObjectModel;
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.Utils.Validate;
using PCL.Core.App.Localization;
namespace PCL;
public partial class PageDownloadInstall
{
private bool isLoad;
public PageDownloadInstall()
{
Initialized += (_, _) => LoaderInit();
Loaded += (_, _) => Init();
InitializeComponent();
PanScroll = PanBack;
LoadMinecraft.Text = Lang.Text("Download.Version.LoadingList");
WeakLanguageChanged.Add(this, OnLanguageChanged);
BtnBack.Click += (_, _) => ExitSelectPage();
CardOptiFine.Swap += (_, _) => ReloadSelected();
LoadOptiFine.StateChanged += (_, _, _) => ReloadSelected();
CardForge.Swap += (_, _) => ReloadSelected();
LoadForge.StateChanged += (_, _, _) => ReloadSelected();
CardNeoForge.Swap += (_, _) => ReloadSelected();
LoadNeoForge.StateChanged += (_, _, _) => ReloadSelected();
CardFabric.Swap += (_, _) => ReloadSelected();
LoadFabric.StateChanged += (_, _, _) => ReloadSelected();
CardFabricApi.Swap += (_, _) => ReloadSelected();
LoadFabricApi.StateChanged += (_, _, _) => ReloadSelected();
CardOptiFabric.Swap += (_, _) => ReloadSelected();
LoadOptiFabric.StateChanged += (_, _, _) => ReloadSelected();
CardLiteLoader.Swap += (_, _) => ReloadSelected();
LoadLiteLoader.StateChanged += (_, _, _) => ReloadSelected();
LoadCleanroom.StateChanged += (_, _, _) => ReloadSelected();
CardCleanroom.Swap += (_, _) => ReloadSelected();
LoadLabyMod.StateChanged += (_, _, _) => ReloadSelected();
CardLabyMod.Swap += (_, _) => ReloadSelected();
TextSelectName.TextChanged += TextSelectName_TextChanged;
TextSelectName.ValidateChanged += TextSelectName_ValidateChanged;
CardOptiFine.PreviewSwap += CardOptiFine_PreviewSwap;
LoadOptiFine.StateChanged += (_, _, _) => OptiFine_Loaded();
BtnOptiFineClear.MouseLeftButtonUp += OptiFine_Clear;
CardLiteLoader.PreviewSwap += CardLiteLoader_PreviewSwap;
LoadLiteLoader.StateChanged += (_, _, _) => LiteLoader_Loaded();
BtnLiteLoaderClear.MouseLeftButtonUp += LiteLoader_Clear;
CardForge.PreviewSwap += CardForge_PreviewSwap;
LoadForge.StateChanged += (_, _, _) => Forge_Loaded();
BtnForgeClear.MouseLeftButtonUp += Forge_Clear;
CardNeoForge.PreviewSwap += CardNeoForge_PreviewSwap;
LoadNeoForge.StateChanged += (_, _, _) => NeoForge_Loaded();
BtnNeoForgeClear.MouseLeftButtonUp += NeoForge_Clear;
CardCleanroom.PreviewSwap += CardCleanroom_PreviewSwap;
LoadCleanroom.StateChanged += (_, _, _) => Cleanroom_Loaded();
BtnCleanroomClear.MouseLeftButtonUp += Cleanroom_Clear;
CardFabric.PreviewSwap += CardFabric_PreviewSwap;
LoadFabric.StateChanged += (_, _, _) => Fabric_Loaded();
BtnFabricClear.MouseLeftButtonUp += Fabric_Clear;
CardFabricApi.PreviewSwap += CardFabricApi_PreviewSwap;
LoadFabricApi.StateChanged += (_, _, _) => FabricApi_Loaded();
BtnFabricApiClear.MouseLeftButtonUp += FabricApi_Clear;
CardLegacyFabric.PreviewSwap += CardLegacyFabric_PreviewSwap;
LoadLegacyFabric.StateChanged += (_, _, _) => LegacyFabric_Loaded();
BtnLegacyFabricClear.MouseLeftButtonUp += LegacyFabric_Clear;
CardLegacyFabricApi.PreviewSwap += CardLegacyFabricApi_PreviewSwap;
LoadLegacyFabricApi.StateChanged += (_, _, _) => LegacyFabricApi_Loaded();
BtnLegacyFabricApiClear.MouseLeftButtonUp += LegacyFabricApi_Clear;
CardOptiFabric.PreviewSwap += CardOptiFabric_PreviewSwap;
LoadOptiFabric.StateChanged += (_, _, _) => OptiFabric_Loaded();
BtnOptiFabricClear.MouseLeftButtonUp += OptiFabric_Clear;
CardLabyMod.PreviewSwap += CardLabyMod_PreviewSwap;
LoadLabyMod.StateChanged += (_, _, _) => LabyMod_Loaded();
BtnLabyModClear.MouseLeftButtonUp += LabyMod_Clear;
TextSelectName.KeyDown += TextSelectName_KeyDown;
BtnStart.Click += (_, _) => BtnStart_Click();
}
private static void OnLanguageChanged(PageDownloadInstall page) => page._OnLanguageChanged();
private void LoaderInit()
{
disabledPageAnimControls.Add(BtnStart);
PageLoaderInit(LoadMinecraft, PanLoad, PanAllBack, null, ModDownload.dlClientListLoader,
_ => LoadMinecraft_OnFinish());
}
private void Init()
{
PanBack.ScrollToHome();
ModDownload.dlOptiFineListLoader.Start();
ModDownload.dlLiteLoaderListLoader.Start();
ModDownload.dlFabricListLoader.Start();
ModDownload.dlNeoForgeListLoader.Start();
ModDownload.dlCleanroomListLoader.Start();
ModDownload.dlLabyModListLoader.Start();
ModDownload.dlLegacyFabricListLoader.Start();
// 重载预览
TextSelectName.ValidateRules = [new FolderNameValidator(ModFolder.mcFolderSelected + "versions")];
TextSelectName.Validate();
ReloadSelected();
// 非重复加载部分
if (isLoad)
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;
}
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;
}
}
}
private void BtnBack_Click(object sender, EventArgs e)
{
ExitSelectPage();
}
#region 页面切换
// 页面切换动画
public bool isInSelectPage;
private bool isFirstLoaded;
private void EnterSelectPage()
{
if (isInSelectPage)
return;
isInSelectPage = true;
PanInner.Margin = new Thickness(25d, 10d, 25d, 40d);
autoSelectedFabricApi = false;
autoSelectedOptiFabric = false;
isSelectNameEdited = false;
PanSelect.Visibility = Visibility.Visible;
PanSelect.IsHitTestVisible = true;
PanMinecraft.IsHitTestVisible = false;
PanBack.IsHitTestVisible = false;
PanBack.ScrollToHome();
disabledPageAnimControls.Remove(BtnStart);
BtnStart.Show = 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;
if (!States.Hint.InstallPageBack)
{
States.Hint.InstallPageBack = true;
HintService.Hint(Lang.Text("Download.Install.Hint.MinecraftBack"));
}
// 如果在选择页面按了刷新键,选择页的东西可能会由于动画被隐藏,但不会由于加载结束而再次显示,因此这里需要手动恢复
foreach (var control in GetAllAnimControls(PanSelect))
{
control.Opacity = 1d;
if (control.RenderTransform is null || control.RenderTransform is TranslateTransform)
control.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、LabyMod 加载
ModDownload.dlFabricApiLoader.Start();
ModDownload.dlLegacyFabricApiLoader.Start();
ModDownload.dlOptiFabricLoader.Start();
ModDownload.dlLabyModListLoader.Start();
ModAnimation.AniStart(new[]
{
ModAnimation.AaOpacity(PanMinecraft, -PanMinecraft.Opacity, 70, 10),
ModAnimation.AaTranslateX(PanMinecraft, -50 - ((TranslateTransform)PanMinecraft.RenderTransform).X, 90, 10),
ModAnimation.AaCode(() =>
{
PanBack.ScrollToHome();
TextSelectName.Validate();
OptiFine_Loaded();
LiteLoader_Loaded();
Forge_Loaded();
NeoForge_Loaded();
Cleanroom_Loaded();
Fabric_Loaded();
LegacyFabric_Loaded();
FabricApi_Loaded();
LegacyFabricApi_Loaded();
OptiFabric_Loaded();
LabyMod_Loaded();
ReloadSelected();
PanMinecraft.Visibility = Visibility.Collapsed;
}, after: true),
ModAnimation.AaOpacity(PanSelect, 1d - PanSelect.Opacity, 70, 100),
ModAnimation.AaTranslateX(PanSelect, -((TranslateTransform)PanSelect.RenderTransform).X, 160, 100,
new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.ExtraStrong)),
ModAnimation.AaCode(() =>
{
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 });
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 });
BtnLegacyFabricClearInner.SetBinding(Shape.FillProperty,
new Binding("Foreground") { Source = CardLegacyFabric.MainTextBlock, Mode = BindingMode.OneWay });
BtnFabricApiClearInner.SetBinding(Shape.FillProperty,
new Binding("Foreground") { Source = CardFabricApi.MainTextBlock, Mode = BindingMode.OneWay });
BtnLegacyFabricApiClearInner.SetBinding(Shape.FillProperty,
new Binding("Foreground")
{ Source = CardLegacyFabricApi.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)
}, "FrmDownloadInstall SelectPageSwitch", true);
}
public void ExitSelectPage()
{
if (!isInSelectPage)
return;
isInSelectPage = false;
PanInner.Margin = new Thickness(25d, 10d, 25d, 25d);
disabledPageAnimControls.Add(BtnStart);
BtnStart.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, 70, 10),
ModAnimation.AaTranslateX(PanSelect, 50d - ((TranslateTransform)PanSelect.RenderTransform).X, 90, 10),
ModAnimation.AaCode(() => PanBack.ScrollToHome(), after: true),
ModAnimation.AaOpacity(PanMinecraft, 1d - PanMinecraft.Opacity, 70, 100),
ModAnimation.AaTranslateX(PanMinecraft, -((TranslateTransform)PanMinecraft.RenderTransform).X, 160, 100,
new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.ExtraStrong)),
ModAnimation.AaCode(() =>
{
PanSelect.Visibility = Visibility.Collapsed;
PanBack.IsHitTestVisible = true;
}, after: true)
}, "FrmDownloadInstall SelectPageSwitch");
}
public void MinecraftSelected(MyListItem sender, MouseButtonEventArgs e)
{
_vanillaName = sender.Title;
_vanillaData = (JsonObject)(dynamic)sender.Tag;
_vanillaIcon = sender.Logo;
EnterSelectPage();
}
#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;
// NeoForge
private ModDownload.DlNeoForgeListEntry? selectedNeoForge;
// 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;
private string? selectedLabyModBaseVersion;
// 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
{
SelectNameUpdate();
ImgLogo.Source = GetSelectLogo();
// 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 ", ".").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;
selectedCleanroom = null;
selectedFabric = null;
selectedFabricApi = null;
selectedOptiFabric = null;
selectedLabyModCommitRef = null;
selectedLabyModVersion = null;
selectedLabyModBaseVersion = 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 GetSelectName()
{
var name = _vanillaName;
if (selectedFabric is not null) name += "-Fabric_" + selectedFabric.Replace("+build", "");
if (selectedLegacyFabric is not null) name += "-LegacyFabric_" + selectedLegacyFabric;
if (selectedLabyModVersion is not null)
name += "-LabyMod_" + selectedLabyModBaseVersion + (selectedLabyModChannel == "snapshot" ? "_Snapshot" : "_Production");
if (selectedForge is not null) name += "-Forge_" + selectedForge.VersionName;
if (selectedNeoForge is not null) name += "-NeoForge_" + selectedNeoForge.VersionName;
if (selectedCleanroom is not null) name += "-Cleanroom_" + selectedCleanroom.VersionName;
if (selectedLiteLoader is not null) name += "-LiteLoader";
if (selectedOptiFine is not null)
name += "-OptiFine_" + selectedOptiFine.DisplayName.Replace(_vanillaName + " ", "").Replace(" ", "_");
return name;
}
private bool isSelectNameEdited;
private bool isSelectNameChanging;
private void SelectNameUpdate()
{
if (isSelectNameEdited || isSelectNameChanging)
return;
isSelectNameChanging = true;
TextSelectName.Text = GetSelectName();
isSelectNameChanging = false;
}
private void TextSelectName_TextChanged(object sender, TextChangedEventArgs e)
{
if (isSelectNameChanging)
return;
isSelectNameEdited = true;
ReloadSelected();
}
private void TextSelectName_ValidateChanged(object sender, EventArgs e)
{
BtnStart.IsEnabled = TextSelectName.IsValidated;
}
#endregion
#region 加载器
// 结果数据化
private void LoadMinecraft_OnFinish()
{
ExitSelectPage(); // 返回
try
{
if (ModDownload.dlClientListLoader.output.Value["versions"] is not JsonArray versions)
return;
_RebuildVersionCards(versions);
if (mcVersionWaitingForSelect is null) return;
ModBase.Log("[Download] 自动选择 MC 版本:" + mcVersionWaitingForSelect);
foreach (JsonObject version1 in versions)
{
if (((string)version1["id"] ?? "") != mcVersionWaitingForSelect)
continue;
var item = ModDownloadLib.McDownloadListItem(version1, (_, _) => { }, false);
MinecraftSelected(item, null);
break;
}
}
catch (Exception ex)
{
ModBase.Log(
ex,
"可视化安装版本列表出错",
ModBase.LogLevel.Feedback,
userSummary: Lang.Text("Download.Install.Error.OperationFailed"));
}
}
private void _RebuildVersionCards(JsonArray versions)
{
var categoryOrder = new[]
{
McVersionCategory.Release,
McVersionCategory.Snapshot,
McVersionCategory.BeforeRelease,
McVersionCategory.AprilFools
};
var dict = categoryOrder.ToDictionary(
category => category,
_ => new List<JsonObject>()
);
foreach (JsonObject version in versions)
{
var category = McVersionClassifier.ClassifyVersion(version);
dict[category].Add(version);
}
foreach (var category in categoryOrder)
dict[category] = dict[category]
.OrderByDescending(McVersionClassifier.GetReleaseTime)
.ToList();
PanMinecraft.Children.Clear();
_AddLatestVersionCard(dict);
_AddCategoryCards(dict, categoryOrder);
}
private void _OnLanguageChanged() => ModBase.RunInUi(() =>
{
LoadMinecraft.Text = Lang.Text("Download.Version.LoadingList");
if (ModDownload.dlClientListLoader.output.Value?["versions"] is JsonArray versions)
_RebuildVersionCards(versions);
});
private void _AddLatestVersionCard(Dictionary<McVersionCategory, List<JsonObject>> dict)
{
var latestRelease = dict[McVersionCategory.Release].FirstOrDefault();
var latestSnapshot = dict[McVersionCategory.Snapshot].FirstOrDefault();
var latestVersions = new List<JsonObject>();
if (latestRelease is not null)
{
var release = (JsonObject)latestRelease.DeepClone();
release["lore"] = Lang.Text(
"Download.Version.Latest.Release",
Lang.Date(McVersionClassifier.GetReleaseTime(release), "g")
);
latestVersions.Add(release);
}
if (latestSnapshot is not null &&
(latestRelease is null || McVersionClassifier.GetReleaseTime(latestRelease) <
McVersionClassifier.GetReleaseTime(latestSnapshot)))
{
var snapshot = (JsonObject)latestSnapshot.DeepClone();
snapshot["lore"] = Lang.Text(
"Download.Version.Latest.Development",
Lang.Date(McVersionClassifier.GetReleaseTime(snapshot), "g")
);
latestVersions.Add(snapshot);
}
if (latestVersions.Count == 0)
return;
var cardInfo = new MyCard
{
Title = Lang.Text("Download.Version.Latest.Title"),
Margin = new Thickness(0d, 15d, 0d, 15d)
};
var panInfo = _CreateVersionStack(latestVersions);
MyCard.StackInstall(ref panInfo, _StackInstall);
cardInfo.Children.Add(panInfo);
PanMinecraft.Children.Insert(0, cardInfo);
}
private void _AddCategoryCards(
Dictionary<McVersionCategory, List<JsonObject>> dict,
IEnumerable<McVersionCategory> categoryOrder)
{
foreach (var category in categoryOrder)
{
var versions = dict[category];
if (versions.Count == 0)
continue;
var card = new MyCard
{
Title = $"{McVersionClassifier.GetCategoryDisplayName(category)} ({versions.Count})",
Margin = new Thickness(0d, 0d, 0d, 15d)
};
var stack = _CreateVersionStack(versions);
card.Children.Add(stack);
card.SwapControl = stack;
// 不能使用 AddressOf,这导致了 #535,原因完全不明,疑似是编译器 Bug
card.InstallMethod = _StackInstall;
card.IsSwapped = true;
PanMinecraft.Children.Add(card);
}
}
private static StackPanel _CreateVersionStack(IEnumerable<JsonObject> versions)
{
return new StackPanel
{
Margin = new Thickness(20d, MyCard.SwapedHeight, 18d, 0d),
VerticalAlignment = VerticalAlignment.Top,
RenderTransform = new TranslateTransform(0d, 0d),
Tag = versions
};
}
private static void _StackInstall(StackPanel stack)
{
foreach (var item in (IEnumerable)stack.Tag)
stack.Children.Add(
ModDownloadLib.McDownloadListItem(
(JsonObject)item,
(sender, e) => ModMain.frmDownloadInstall.MinecraftSelected((MyListItem)sender, e),
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.CompareVersionGe(left.DisplayName, right.DisplayName);
});
// 可视化
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("Download.Install.Error.OperationFailed"));
}
}
// 选择与清除
private void OptiFine_Selected(MyListItem sender, EventArgs e)
{
selectedOptiFine = (ModDownload.DlOptiFineListEntry)(dynamic)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("Download.Install.Error.OperationFailed"));
}
}
// 选择与清除
private void LiteLoader_Selected(MyListItem sender, EventArgs e)
{
selectedLiteLoader = (ModDownload.DlLiteLoaderListEntry)(dynamic)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 (selectedNeoForge is not null || selectedFabric is not null)
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("Download.Install.Error.OperationFailed"));
}
}
// 选择与清除
private void Forge_Selected(MyListItem sender, EventArgs e)
{
selectedForge = (ModDownload.DlForgeVersionEntry)(dynamic)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("Download.Install.Error.OperationFailed"));
}
}
// 选择与清除
private void NeoForge_Selected(MyListItem sender, EventArgs e)
{
selectedNeoForge = (ModDownload.DlNeoForgeListEntry)(dynamic)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("Download.Install.Error.OperationFailed"));
}
}
// 选择与清除
private void Cleanroom_Selected(MyListItem sender, EventArgs e)
{
selectedCleanroom = (ModDownload.DlCleanroomListEntry)(dynamic)sender.Tag;
selectedLoaderName = "Cleanroom";
CardCleanroom.IsSwapped = true;
OptiFine_Loaded();
ReloadSelected();
}
private void Cleanroom_Clear(object sender, MouseButtonEventArgs e)
{
selectedCleanroom = null;
selectedLoaderName = 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("Download.Install.Error.OperationFailed"));
}
}
// 选择与清除
public void Fabric_Selected(MyListItem sender, EventArgs e)
{
ModBase.Log(((dynamic)sender.Tag).ToString());
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;
var targetName = _vanillaName.Replace("∞", "infinite").Replace("Combat Test 7c", "1.16_combat-3").ToLower();
return fabricApi.RawGameVersions.Any(f => f == targetName);
}
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("Download.Install.Error.OperationFailed"));
}
}
// 选择与清除
private void FabricApi_Selected(MyListItem sender, EventArgs e)
{
selectedFabricApi = (ModComp.CompFile)(dynamic)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("Download.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("Download.Install.Error.OperationFailed"));
}
}
// 选择与清除
private void LegacyFabricApi_Selected(MyListItem sender, EventArgs e)
{
selectedLegacyFabricApi = (ModComp.CompFile)(dynamic)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("Download.Install.Error.OperationFailed"));
}
}
// 选择与清除
private void OptiFabric_Selected(MyListItem sender, EventArgs e)
{
selectedOptiFabric = (ModComp.CompFile)(dynamic)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("Download.Install.Error.OperationFailed"));
}
}
// 选择与清除
public void LabyMod_Selected(MyListItem sender, EventArgs e)
{
selectedLabyModChannel = ((dynamic)sender.Tag)["channel"].ToString();
selectedLabyModCommitRef = ((dynamic)sender.Tag)["commitReference"].ToString();
selectedLabyModBaseVersion = ((dynamic)sender.Tag)["version"].ToString();
selectedLabyModVersion =
selectedLabyModBaseVersion + " " + (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;
selectedLabyModBaseVersion = null;
selectedLabyModChannel = null;
if (selectedLoaderName == "LabyMod")
{
selectedLoaderName = null;
}
selectedAPIName = null;
CardLabyMod.IsSwapped = true;
e.Handled = true;
ReloadSelected();
}
#endregion
#region 安装
private void TextSelectName_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter && BtnStart.IsEnabled)
BtnStart_Click();
}
private void BtnStart_Click()
{
// 确认版本隔离
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;
// 提交安装申请
var instanceName = TextSelectName.Text;
var request = new ModDownloadLib.McInstallRequest
{
targetInstanceName = instanceName,
targetInstanceFolder = $@"{ModFolder.mcFolderSelected}versions\{instanceName}\",
minecraftJson = _vanillaData?["url"].ToString(),
minecraftName = _vanillaName,
optiFineEntry = selectedOptiFine,
forgeEntry = selectedForge,
neoForgeEntry = selectedNeoForge,
cleanroomEntry = selectedCleanroom,
fabricVersion = selectedFabric,
fabricApi = selectedFabricApi,
optiFabric = selectedOptiFabric,
liteLoaderEntry = selectedLiteLoader,
labyModChannel = selectedLabyModChannel,
labyModCommitRef = selectedLabyModCommitRef,
legacyFabricVersion = selectedLegacyFabric,
legacyFabricApi = selectedLegacyFabricApi
};
if (!ModDownloadLib.McInstall(request))
return;
// 返回,这样在再次进入安装页面时这个实例就会显示文件夹已重复
ExitSelectPage();
}
#endregion
}