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>( "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; /// /// 选定的 Mod Loader 名称,内容应为 Forge / NeoForge / Fabric / Cleanroom / LabyMod / LegacyFabric /// private string? selectedLoaderName; /// /// 选定的 Mod Loader API 名称,内容应为 Fabric API /// 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 /// /// 重载已选择的项目的显示。 /// 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; } } /// /// 清空已选择的项目。 /// 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); } /// /// 获取实例图标。 /// 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; } // 实例名处理 /// /// 获取默认实例名。 /// 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() ); 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> dict) { var latestRelease = dict[McVersionCategory.Release].FirstOrDefault(); var latestSnapshot = dict[McVersionCategory.Snapshot].FirstOrDefault(); var latestVersions = new List(); 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> dict, IEnumerable 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 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 ) ); } /// /// 当 MC 版本列表加载完时,立即自动选择的版本。用于外部调用。 /// public static string mcVersionWaitingForSelect = null; #endregion #region OptiFine 列表 /// /// 获取 OptiFine 的加载异常信息。若正常则返回 Nothing。 /// 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; } /// /// 尝试重新可视化 OptiFine 版本列表。 /// private void OptiFine_Loaded() { try { if (ModDownload.dlOptiFineListLoader.State != ModBase.LoadState.Finished) return; // 获取版本列表 var versions = new List(); 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 列表 /// /// 获取 LiteLoader 的加载异常信息。若正常则返回 Nothing。 /// 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; } /// /// 尝试重新可视化 LiteLoader 版本列表。 /// private void LiteLoader_Loaded() { try { if (ModDownload.dlLiteLoaderListLoader.State != ModBase.LoadState.Finished) return; // 获取版本列表 var versions = new List(); 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 列表 /// /// 获取 Forge 的加载异常信息。若正常则返回 Nothing。 /// 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>)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; } /// /// 尝试重新可视化 Forge 版本列表。 /// private void Forge_Loaded() { try { if (!LoadForge.State.IsLoader) return; var loader = (ModLoader.LoaderTask>)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 列表 /// /// 获取 NeoForge 的加载异常信息。若正常则返回 Nothing。 /// 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; } /// /// 尝试重新可视化 NeoForge 版本列表。 /// 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 列表 /// /// 获取 Cleanroom 的加载异常信息。若正常则返回 Nothing。 /// 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; } /// /// 尝试重新可视化 Cleanroom 版本列表。 /// 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 列表 /// /// 获取 Fabric 的加载异常信息。若正常则返回 Nothing。 /// 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; } /// /// 尝试重新可视化 Fabric 版本列表。 /// 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 列表 /// /// 判断某 Fabric API 是否适配当前选择的原版版本。 /// 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; } } /// /// 获取 FabricApi 的加载异常信息。若正常则返回 Nothing。 /// 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; /// /// 尝试重新可视化 FabricApi 版本列表。 /// 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(); 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 列表 /// /// 获取 LegacyFabric 的加载异常信息。若正常则返回 Nothing。 /// 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; } /// /// 尝试重新可视化 LegacyFabric 版本列表。 /// 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 列表 /// /// 从显示名判断该 API 是否与某版本适配。 /// public static bool IsSuitableLegacyFabricApi(List 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; } } /// /// 获取 LegacyFabricApi 的加载异常信息。若正常则返回 Nothing。 /// 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; /// /// 尝试重新可视化 LegacyFabricApi 版本列表。 /// 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(); 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 列表 /// /// 判断某 OptiFabric 是否适配当前选择的原版版本。 /// 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; /// /// 获取 OptiFabric 的加载异常信息。若正常则返回 Nothing。 /// 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; } /// /// 尝试重新可视化 OptiFabric 版本列表。 /// 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(); 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 列表 /// /// 获取 LabyMod 的加载异常信息。若正常则返回 Nothing。 /// 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; } /// /// 尝试重新可视化 LabyMod 版本列表。 /// 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 }