using System.IO; using System.Text.Json; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Threading; using PCL.Core.App; using PCL.Core.App.Configuration; using PCL.Core.IO; using PCL.Core.Minecraft; using PCL.Core.Minecraft.Java.UserPreference; using PCL.Core.UI; using PCL.Core.Utils.OS; using PCL.Core.App.Localization; using PCL.Core.Utils; namespace PCL; public partial class PageInstanceSetup { private new bool isLoaded; public PageInstanceSetup() { Loaded += PageSetupSystem_Loaded; InitializeComponent(); ComboArgumentIndieV2.SelectionChanged += ComboArgumentIndieV2_SelectionChanged; TextArgumentTitle.TextChanged += TextArgumentTitle_TextChanged; TextArgumentInfo.TextChanged += TextBoxChange; ComboArgumentJava.SelectionChanged += JavaSelectionUpdate; RadioRamType2.Check += RadioBoxChange; RadioRamType0.Check += RadioBoxChange; RadioRamType1.Check += RadioBoxChange; SliderRamCustom.Change += SliderChange; ComboServerLoginRequire.SelectionChanged += ComboServerLogin_Changed; TextServerAuthServer.TextChanged += TextBoxChange; TextServerAuthServer.LostFocus += TextServerAuthServer_MouseLeave; TextServerAuthRegister.TextChanged += TextBoxChange; TextServerAuthName.TextChanged += TextBoxChange; TextServerEnter.TextChanged += TextBoxChange; BtnServerAuthLittle.Click += BtnServerAuthLittle_Click; BtnServerAuthLock.Click += BtnServerAuthLock_Click; BtnServerNewProfile.Click += BtnServerNewProfile_Click; ComboAdvanceRenderer.SelectionChanged += ComboAdvanceRenderer_SelectionChanged; TextAdvanceJvm.TextChanged += TextBoxChange; TextAdvanceGame.TextChanged += TextBoxChange; TextAdvanceClasspathHead.TextChanged += TextBoxChange; TextAdvanceRun.TextChanged += TextAdvanceRun_TextChanged; CheckAdvanceRunWait.Change += CheckBoxChange; CheckAdvanceJava.Change += CheckBoxChange; CheckAdvanceAssetsV2.Change += CheckBoxChange; CheckAdvanceUseProxyV2.Change += CheckBoxChange; CheckAdvanceDisableJLW.Change += CheckBoxChange; CheckAdvanceDisableLF.Change += CheckBoxChange; CheckUseDebugLog4j2Config.Change += CheckUseDebugLog4j2Config_CheckChanged; CheckAdvanceDisableLwjglUnsafeAgent.Change += CheckBoxChange; BtnSwitch.Click += BtnSwitch_Click; TextServerEnter.TextChanged += TextServerEnter_Change; ComboArgumentJava.DropDownOpened += ComboArgumentJava_DropDownOpened; CheckArgumentTitleEmpty.Change += CheckArgumentTitleEmpty_Change; } private void PageSetupSystem_Loaded(object sender, RoutedEventArgs e) { // 重复加载部分 PanBack.ScrollToHome(); RefreshRam(false); // 由于各个实例不同,每次都需要重新加载 ModAnimation.AniControlEnabled += 1; Reload(); ModAnimation.AniControlEnabled -= 1; // 非重复加载部分 if (isLoaded) return; isLoaded = true; // 内存自动刷新 var timer = new DispatcherTimer { Interval = new TimeSpan(0, 0, 0, 1) }; timer.Tick += (_, _) => RefreshRam(); timer.Start(); RectRamGame.SizeChanged += (s, e) => RefreshRamText(); } public void Reload() { try { // 启动参数 TextArgumentTitle.Text = Config.Instance.Title[PageInstanceLeft.McInstance.PathInstance]; CheckArgumentTitleEmpty.Checked = Config.Instance.UseGlobalTitle[PageInstanceLeft.McInstance.PathInstance]; TextArgumentInfo.Text = Config.Instance.TypeInfo[PageInstanceLeft.McInstance.PathInstance]; var _unused = PageInstanceLeft.McInstance.PathIndie; // 触发自动判定 ComboArgumentIndieV2.SelectedIndex = Config.Instance.IndieV2[PageInstanceLeft.McInstance.PathInstance] ? 0 : 1; CheckArgumentTitleEmpty.Visibility = TextArgumentTitle.Text.Length > 0 ? Visibility.Collapsed : Visibility.Visible; TextArgumentTitle.HintText = CheckArgumentTitleEmpty.Checked == true ? Lang.Text("Common.Option.Default") : Lang.Text("Instance.Setup.FollowGlobal"); RefreshJavaComboBox(); // 游戏内存 var ramType = Config.Instance.MemorySolution[PageInstanceLeft.McInstance.PathInstance]; ((MyRadioBox)FindName("RadioRamType" + ramType)).Checked = true; SliderRamCustom.Value = Config.Instance.CustomMemorySize[PageInstanceLeft.McInstance.PathInstance]; RamType(ramType); // 服务器 TextServerEnter.Text = Config.Instance.ServerToEnter[PageInstanceLeft.McInstance.PathInstance]; ComboServerLoginRequire.SelectedIndex = Config.InstanceAuth.LoginRequirementSolution[PageInstanceLeft.McInstance.PathInstance]; comboServerLoginLast = ComboServerLoginRequire.SelectedIndex; ServerLogin(ComboServerLoginRequire.SelectedIndex); TextServerAuthServer.Text = Config.InstanceAuth.AuthServerAddress[PageInstanceLeft.McInstance.PathInstance]; TextServerAuthName.Text = Config.InstanceAuth.AuthServerDisplayName[PageInstanceLeft.McInstance.PathInstance]; TextServerAuthRegister.Text = Config.InstanceAuth.AuthRegisterAddress[PageInstanceLeft.McInstance.PathInstance]; // 高级设置 ComboAdvanceRenderer.SelectedIndex = Config.Instance.Renderer[PageInstanceLeft.McInstance.PathInstance]; TextAdvanceClasspathHead.Text = Config.Instance.ClasspathHead[PageInstanceLeft.McInstance.PathInstance]; TextAdvanceJvm.Text = Config.Instance.JvmArgs[PageInstanceLeft.McInstance.PathInstance]; TextAdvanceGame.Text = Config.Instance.GameArgs[PageInstanceLeft.McInstance.PathInstance]; TextAdvanceRun.Text = Config.Instance.PreLaunchCommand[PageInstanceLeft.McInstance.PathInstance]; CheckAdvanceRunWait.Checked = Config.Instance.PreLaunchCommandWait[PageInstanceLeft.McInstance.PathInstance]; CheckAdvanceDisableLwjglUnsafeAgent.Checked = Config.Instance.DisableLwjglUnsafeAgent[PageInstanceLeft.McInstance.PathInstance]; if (Config.Instance.AssetVerifySolutionV1[PageInstanceLeft.McInstance.PathInstance] == 2) { ModBase.Log("[Setup] 已迁移老版本的关闭文件校验设置"); Config.Instance.AssetVerifySolutionV1Config.Reset(PageInstanceLeft.McInstance.PathInstance); Config.Instance.DisableAssetVerifyV2[PageInstanceLeft.McInstance.PathInstance] = true; } CheckAdvanceAssetsV2.Checked = Config.Instance.DisableAssetVerifyV2[PageInstanceLeft.McInstance.PathInstance]; CheckAdvanceUseProxyV2.Checked = Config.Instance.UseProxy[PageInstanceLeft.McInstance.PathInstance]; CheckAdvanceJava.Checked = Config.Instance.IgnoreJavaCompatibility[PageInstanceLeft.McInstance.PathInstance]; if (SystemInfo.IsArm64System) { CheckAdvanceDisableJLW.Checked = true; CheckAdvanceDisableJLW.IsEnabled = false; CheckAdvanceDisableJLW.ToolTip = Lang.Text("Setup.Launch.Advanced.DisableJlw.Arm64ToolTip"); } else { CheckAdvanceDisableJLW.Checked = Config.Instance.DisableJlw[PageInstanceLeft.McInstance.PathInstance]; } CheckUseDebugLog4j2Config.Checked = Config.Instance.UseDebugLof4j2Config[PageInstanceLeft.McInstance.PathInstance]; CheckAdvanceDisableLF.Checked = Config.Instance.DisableLF[PageInstanceLeft.McInstance.PathInstance]; } catch (Exception ex) { ModBase.Log( ex, "重载实例独立设置时出错", ModBase.LogLevel.Feedback, userSummary: Lang.Text("Instance.Setup.Error.OperationFailed")); } } // 初始化 public void Reset() { try { if (!Config.InstanceAuth.AuthLocked[PageInstanceLeft.McInstance.PathInstance]) Config.InstanceAuth.Reset(PageInstanceLeft.McInstance.PathInstance); Config.Instance.Reset(PageInstanceLeft.McInstance.PathInstance); ModBase.Log("[Setup] 已初始化实例独立设置"); HintService.Hint(Lang.Text("Instance.Setup.Initialize.Success"), HintType.Success, false); } catch (Exception ex) { ModBase.Log( ex, "初始化实例独立设置失败", ModBase.LogLevel.Msgbox, userSummary: Lang.Text("Instance.Setup.Error.OperationFailed")); } Reload(); } // 将控件改变路由到设置改变 private static void SetByTag(string tag, object value) => ConfigService.TrySetValue(tag, value, PageInstanceLeft.McInstance.PathInstance); private void RadioBoxChange(object o, ModBase.RouteEventArgs routeEventArgs) { if (ModAnimation.AniControlEnabled != 0) return; if (o is not MyRadioBox { Tag: string tag }) return; var slash = tag.IndexOf('/'); if (slash < 0) return; SetByTag(tag[..slash], int.Parse(tag[(slash + 1)..])); } private void TextBoxChange(object o, TextChangedEventArgs textChangedEventArgs) { if (ModAnimation.AniControlEnabled != 0) return; if (o is not MyTextBox textBox) return; SetByTag(textBox.Tag?.ToString(), textBox.Text); } private void SliderChange(object o, bool user) { if (ModAnimation.AniControlEnabled != 0) return; if (o is not MySlider slider) return; SetByTag(slider.Tag?.ToString(), slider.Value); } private void ComboChange(MyComboBox sender, object e) { if (ModAnimation.AniControlEnabled != 0) return; SetByTag(sender.Tag?.ToString(), sender.SelectedIndex); } private void CheckBoxChange(object sender, bool user) { if (ModAnimation.AniControlEnabled != 0) return; if (sender is not MyCheckBox checkBox) return; SetByTag(checkBox.Tag?.ToString(), checkBox.Checked.GetValueOrDefault()); } // 切换到全局设置 private void BtnSwitch_Click(object sender, MouseButtonEventArgs e) { ModMain.frmMain.PageChange(FormMain.PageType.Setup); } #region 游戏内存 public void RamType(int type) { if (SliderRamCustom is null) return; SliderRamCustom.IsEnabled = type == 1; } /// /// 刷新 UI 上的 RAM 显示。 /// public void RefreshRam(bool showAnim) { if (LabRamGame is null || LabRamUsed is null || ModMain.frmMain.pageCurrent != FormMain.PageType.InstanceSetup || ModMain.frmInstanceLeft.pageID != FormMain.PageSubType.VersionSetup) return; // 获取内存情况 var ramGame = Math.Round(GetRam(PageInstanceLeft.McInstance), 5); var phyRam = KernelInterop.GetPhysicalMemoryBytes(); var ramTotal = Math.Round((double)(phyRam.Total / 1024 / 1024 / 1024), 1); var ramAvailable = Math.Round((double)(phyRam.Available / 1024 / 1024 / 1024), 1); var ramGameActual = Math.Round(Math.Min(ramGame, ramAvailable), 5); var ramUsed = Math.Round(ramTotal - ramAvailable, 5); var ramEmpty = Math.Round(ModBase.MathClamp(ramTotal - ramUsed - ramGame, 0d, 1000d), 1); // 设置最大可用内存 if (ramTotal <= 1.5d) SliderRamCustom.MaxValue = (int)Math.Round(Math.Max(Math.Floor((ramTotal - 0.3d) / 0.1d), 1d)); else if (ramTotal <= 8d) SliderRamCustom.MaxValue = (int)Math.Round(Math.Floor((ramTotal - 1.5d) / 0.5d) + 12d); else if (ramTotal <= 16d) SliderRamCustom.MaxValue = (int)Math.Round(Math.Floor((ramTotal - 8d) / 1d) + 25d); else SliderRamCustom.MaxValue = (int)Math.Round(Math.Floor((ramTotal - 16d) / 2d) + 33d); // 设置文本 LabRamGame.Text = $"{Lang.Number(ramGame, "N1")} GiB{(ramGame != ramGameActual ? $" ({Lang.Text("Setup.Launch.Memory.AvailableSuffix", Lang.Number(ramGameActual, "N1"))})" : "")}"; LabRamUsed.Text = $"{Lang.Number(ramUsed, "N1")} GiB"; LabRamTotal.Text = $" / {Lang.Number(ramTotal, "N1")} GiB"; LabRamWarn.Visibility = ramGame == 1d && !ModJava.IsGameSet64BitJava(PageInstanceLeft.McInstance) && !SystemInfo.Is32BitSystem && ModJava.Javas.ExistAnyJava() ? Visibility.Visible : Visibility.Collapsed; HintRamTooHigh.Visibility = ramGame / ramTotal > 0.75d ? Visibility.Visible : Visibility.Collapsed; if (showAnim) { // 宽度动画 ModAnimation.AniStart( new[] { ModAnimation.AaGridLengthWidth(ColumnRamUsed, ramUsed - ColumnRamUsed.Width.Value, 800, ease: new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Strong)), ModAnimation.AaGridLengthWidth(ColumnRamGame, ramGameActual - ColumnRamGame.Width.Value, 800, ease: new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Strong)), ModAnimation.AaGridLengthWidth(ColumnRamEmpty, ramEmpty - ColumnRamEmpty.Width.Value, 800, ease: new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Strong)) }, "VersionSetup Ram Grid"); } else { // 宽度设置 ColumnRamUsed.Width = new GridLength(ramUsed, GridUnitType.Star); ColumnRamGame.Width = new GridLength(ramGameActual, GridUnitType.Star); ColumnRamEmpty.Width = new GridLength(ramEmpty, GridUnitType.Star); } } private void RefreshRam() { RefreshRam(true); } private int ramTextLeft = 2; private int ramTextRight = 1; /// /// 刷新 UI 上的文本位置。 /// private void RefreshRamText() { // 获取宽度信息 var rectUsedWidth = RectRamUsed.ActualWidth; var totalWidth = PanRamDisplay.ActualWidth; var labGameWidth = LabRamGame.ActualWidth; var labUsedWidth = LabRamUsed.ActualWidth; var labTotalWidth = LabRamTotal.ActualWidth; var labGameTitleWidth = LabRamGameTitle.ActualWidth; var labUsedTitleWidth = LabRamUsedTitle.ActualWidth; // 左侧 int left; if (rectUsedWidth - 30d < labUsedWidth || rectUsedWidth - 30d < labUsedTitleWidth) // 全写不下了 left = 0; else if (rectUsedWidth - 25d < labUsedWidth + labTotalWidth) // 显示不下完整数据 left = 1; else // 正常 left = 2; if (ramTextLeft != left) { ramTextLeft = left; switch (left) { case 0: { ModAnimation.AniStart( new[] { ModAnimation.AaOpacity(LabRamUsed, -LabRamUsed.Opacity, 100), ModAnimation.AaOpacity(LabRamTotal, -LabRamTotal.Opacity, 100), ModAnimation.AaOpacity(LabRamUsedTitle, -LabRamUsedTitle.Opacity, 100) }, "VersionSetup Ram TextLeft"); break; } case 1: { ModAnimation.AniStart( new[] { ModAnimation.AaOpacity(LabRamUsed, 1d - LabRamUsed.Opacity, 100), ModAnimation.AaOpacity(LabRamTotal, -LabRamTotal.Opacity, 100), ModAnimation.AaOpacity(LabRamUsedTitle, 0.7d - LabRamUsedTitle.Opacity, 100) }, "VersionSetup Ram TextLeft"); break; } case 2: { ModAnimation.AniStart( new[] { ModAnimation.AaOpacity(LabRamUsed, 1d - LabRamUsed.Opacity, 100), ModAnimation.AaOpacity(LabRamTotal, 1d - LabRamTotal.Opacity, 100), ModAnimation.AaOpacity(LabRamUsedTitle, 0.7d - LabRamUsedTitle.Opacity, 100) }, "VersionSetup Ram TextLeft"); break; } } } // 右侧 int right; if (totalWidth < labGameWidth + 2d + rectUsedWidth || totalWidth < labGameTitleWidth + 2d + rectUsedWidth) // 挤到最右边 right = 0; else // 正常情况 right = 1; if (right == 0) { if (ModAnimation.AniControlEnabled == 0 && (ramTextRight != right || ModAnimation.AniIsRun("VersionSetup Ram TextRight"))) { // 需要动画 ModAnimation.AniStart( new[] { ModAnimation.AaX(LabRamGame, totalWidth - labGameWidth - LabRamGame.Margin.Left, 100, ease: new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Weak)), ModAnimation.AaX(LabRamGameTitle, totalWidth - labGameTitleWidth - LabRamGameTitle.Margin.Left, 100, ease: new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Weak)) }, "VersionSetup Ram TextRight"); } else { // 不需要动画 LabRamGame.Margin = new Thickness(totalWidth - labGameWidth, 3d, 0d, 0d); LabRamGameTitle.Margin = new Thickness(totalWidth - labGameTitleWidth, 0d, 0d, 5d); } } else if (ModAnimation.AniControlEnabled == 0 && (ramTextRight != right || ModAnimation.AniIsRun("VersionSetup Ram TextRight"))) { // 需要动画 ModAnimation.AniStart( new[] { ModAnimation.AaX(LabRamGame, 2d + rectUsedWidth - LabRamGame.Margin.Left, 100, ease: new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Weak)), ModAnimation.AaX(LabRamGameTitle, 2d + rectUsedWidth - LabRamGameTitle.Margin.Left, 100, ease: new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Weak)) }, "VersionSetup Ram TextRight"); } else { // 不需要动画 LabRamGame.Margin = new Thickness(2d + rectUsedWidth, 3d, 0d, 0d); LabRamGameTitle.Margin = new Thickness(2d + rectUsedWidth, 0d, 0d, 5d); } ramTextRight = right; } /// /// 获取当前设置的 RAM 值。单位为 GB。 /// public static double GetRam(McInstance version, bool? is32BitJava = default) { var instancePath = version?.PathInstance; // 跟随全局设置 if (Config.Instance.MemorySolution[instancePath] == 2) return PageSetupLaunch.GetRam(version, true, is32BitJava); // ------------------------------------------ // 修改下方代码时需要一并修改 PageSetupLaunch // ------------------------------------------ // 使用当前实例的设置 var ramGive = default(double); if (Config.Instance.MemorySolution[instancePath] == 0) { // 自动配置 var ramAvailable = Math.Round((double)(KernelInterop.GetAvailablePhysicalMemoryBytes() / 1024 / 1024 / 1024 * 10)) / 10; // 确定需求的内存值 double ramMininum; // 无论如何也需要保证的最低限度内存 double ramTarget1; // 估计能勉强带动了的内存 double ramTarget2; // 估计没啥问题了的内存 double ramTarget3; // 安装过多附加组件需要的内存 if (version is not null && !version.IsLoaded) version.Load(); if (version is not null && version.Modable) { // 可安装 Mod 的实例 var modDir = new DirectoryInfo(version.PathIndie + @"mods\"); var modCount = modDir.Exists ? modDir.GetFiles().Length : 0; ramMininum = 0.5d + modCount / 150d; ramTarget1 = 1.5d + modCount / 90d; ramTarget2 = 2.7d + modCount / 50d; ramTarget3 = 4.5d + modCount / 25d; } else if (version is not null && version.Info.HasOptiFine) { // OptiFine 实例 ramMininum = 0.5d; ramTarget1 = 1.5d; ramTarget2 = 3d; ramTarget3 = 5d; } else { // 普通实例 ramMininum = 0.5d; ramTarget1 = 1.5d; ramTarget2 = 2.5d; ramTarget3 = 4d; } double ramDelta; // 预分配内存,阶段一,0 ~ T1,100% ramDelta = ramTarget1; ramGive += Math.Min(ramAvailable, ramDelta); ramAvailable -= ramDelta; if (ramAvailable >= 0.1d) { // 预分配内存,阶段二,T1 ~ T2,70% ramDelta = ramTarget2 - ramTarget1; ramGive += Math.Min(ramAvailable * 0.7d, ramDelta); ramAvailable -= ramDelta / 0.7d; if (ramAvailable >= 0.1d) { // 预分配内存,阶段三,T2 ~ T3,40% ramDelta = ramTarget3 - ramTarget2; ramGive += Math.Min(ramAvailable * 0.4d, ramDelta); ramAvailable -= ramDelta / 0.4d; if (ramAvailable >= 0.1d) { // 预分配内存,阶段四,T3 ~ T3 * 2,15% ramDelta = ramTarget3; ramGive += Math.Min(ramAvailable * 0.15d, ramDelta); ramAvailable -= ramDelta / 0.15d; } } } // 不低于最低值 ramGive = Math.Round(Math.Max(ramGive, ramMininum), 1); } else { // 手动配置 var value = Config.Instance.CustomMemorySize[instancePath]; if (value <= 12) ramGive = value * 0.1d + 0.3d; else if (value <= 25) ramGive = (value - 12) * 0.5d + 1.5d; else if (value <= 33) ramGive = (value - 25) * 1 + 8; else ramGive = (value - 33) * 2 + 16; } // 若使用 32 位 Java,则限制为 1G if (is32BitJava ?? !ModJava.IsGameSet64BitJava(PageInstanceLeft.McInstance)) ramGive = Math.Min(1d, ramGive); return ramGive; } #endregion #region 服务器 // 全局 private int comboServerLoginLast; private void ComboServerLogin_Changed(object sender, SelectionChangedEventArgs e) { if (ModAnimation.AniControlEnabled != 0) return; ServerLogin(ComboServerLoginRequire.SelectedIndex); if (TextServerAuthServer.IsValidated) BtnServerAuthLock.IsEnabled = true; else BtnServerAuthLock.IsEnabled = false; if ((ComboServerLoginRequire.SelectedIndex == 2 || ComboServerLoginRequire.SelectedIndex == 3) && !TextServerAuthServer.IsValidated) return; if (comboServerLoginLast == ComboServerLoginRequire.SelectedIndex) return; comboServerLoginLast = ComboServerLoginRequire.SelectedIndex; Config.InstanceAuth.LoginRequirementSolution[PageInstanceLeft.McInstance.PathInstance] = ComboServerLoginRequire.SelectedIndex; } private void TextServerAuthServer_MouseLeave(object sender, RoutedEventArgs e) { if (string.IsNullOrWhiteSpace(TextServerAuthServer.Text)) return; if (!(TextServerAuthServer.Text.EndsWithF("/api/yggdrasil/") || TextServerAuthServer.Text.EndsWithF("/api/yggdrasil"))) { if (TextServerAuthServer.Text.EndsWithF("/")) { TextServerAuthServer.Text = $"{TextServerAuthServer.Text}api/yggdrasil"; HintService.Hint(Lang.Text("Instance.Setup.Server.AuthServer.AutoFormatted")); } else { TextServerAuthServer.Text = $"{TextServerAuthServer.Text}/api/yggdrasil"; HintService.Hint(Lang.Text("Instance.Setup.Server.AuthServer.AutoFormatted")); } } if (TextServerAuthServer.Text.EndsWithF("/api/yggdrasil/")) { TextServerAuthServer.Text = TextServerAuthServer.Text.BeforeLast("/"); HintService.Hint(Lang.Text("Instance.Setup.Server.AuthServer.AutoFormatted")); } comboServerLoginLast = ComboServerLoginRequire.SelectedIndex; ComboChange(ComboServerLoginRequire, null); } public void ServerLogin(int type) { LabServerAuthName.Visibility = type == 2 || type == 3 ? Visibility.Visible : Visibility.Collapsed; TextServerAuthName.Visibility = type == 2 || type == 3 ? Visibility.Visible : Visibility.Collapsed; LabServerAuthRegister.Visibility = type == 2 || type == 3 ? Visibility.Visible : Visibility.Collapsed; TextServerAuthRegister.Visibility = type == 2 || type == 3 ? Visibility.Visible : Visibility.Collapsed; LabServerAuthServer.Visibility = type == 2 || type == 3 ? Visibility.Visible : Visibility.Collapsed; TextServerAuthServer.Visibility = type == 2 || type == 3 ? Visibility.Visible : Visibility.Collapsed; BtnServerAuthLittle.Visibility = type == 2 || type == 3 ? Visibility.Visible : Visibility.Collapsed; BtnServerNewProfile.Visibility = type == 2 || type == 3 ? Visibility.Visible : Visibility.Collapsed; if (type == 0 || type == 1) BtnServerAuthLock.Visibility = Visibility.Collapsed; else BtnServerAuthLock.Visibility = Visibility.Visible; if (Config.InstanceAuth.AuthLocked[PageInstanceLeft.McInstance.PathInstance]) { HintServerLoginLock.Visibility = Visibility.Visible; ComboServerLoginRequire.IsEnabled = false; TextServerAuthServer.IsEnabled = false; TextServerAuthName.IsEnabled = false; TextServerAuthRegister.IsEnabled = false; BtnServerAuthLittle.IsEnabled = false; } else { HintServerLoginLock.Visibility = Visibility.Collapsed; ComboServerLoginRequire.IsEnabled = true; TextServerAuthServer.IsEnabled = true; TextServerAuthName.IsEnabled = true; TextServerAuthRegister.IsEnabled = true; BtnServerAuthLittle.IsEnabled = true; } CardServer.TriggerForceResize(); // 避免正版验证和离线验证出现此提示 if (type != 2 && type != 3) { LabServerAuthServerSecurity.Visibility = Visibility.Collapsed; LabServerAuthServerSecurityCL.Visibility = Visibility.Collapsed; LabServerAuthServerSecurityVerify.Visibility = Visibility.Collapsed; } // 如果开头为 http:// 给予警告 else if (TextServerAuthServer.Text.StartsWithF("https://")) { LabServerAuthServerSecurity.Visibility = Visibility.Collapsed; LabServerAuthServerSecurityVerify.Visibility = Visibility.Visible; LabServerAuthServerSecurityCL.Visibility = Visibility.Visible; } else if (TextServerAuthServer.Text.StartsWithF("http://")) { LabServerAuthServerSecurity.Visibility = Visibility.Visible; LabServerAuthServerSecurityCL.Visibility = Visibility.Visible; LabServerAuthServerSecurityVerify.Visibility = Visibility.Collapsed; } else { LabServerAuthServerSecurity.Visibility = Visibility.Collapsed; LabServerAuthServerSecurityVerify.Visibility = Visibility.Collapsed; LabServerAuthServerSecurityCL.Visibility = Visibility.Collapsed; } } // LittleSkin private void BtnServerAuthLittle_Click(object sender, MouseButtonEventArgs e) { if (!string.IsNullOrEmpty(TextServerAuthServer.Text) && TextServerAuthServer.Text != "https://littleskin.cn/api/yggdrasil" && ModMain.MyMsgBox( Lang.Text("Instance.Setup.Server.LittleSkin.Override.Message"), Lang.Text("Instance.Setup.Server.LittleSkin.Override.Title"), Lang.Text("Instance.Setup.Server.LittleSkin.Override.Continue"), Lang.Text("Common.Action.Cancel")) == 2) return; TextServerAuthServer.Text = "https://littleskin.cn/api/yggdrasil"; TextServerAuthRegister.Text = "https://littleskin.cn/auth/register"; TextServerAuthName.Text = Lang.Text("Instance.Setup.Server.LittleSkin.Name"); } // 锁定设置 private void BtnServerAuthLock_Click(object sender, MouseButtonEventArgs e) { if (ModMain.MyMsgBox( Lang.Text("Instance.Setup.Server.LockLoginMethod.Message"), Lang.Text("Instance.Setup.Server.LockLoginMethod.Title"), Lang.Text("Common.Action.Confirm"), Lang.Text("Common.Action.Cancel"), isWarn: true) == 1) { Config.InstanceAuth.AuthLocked[PageInstanceLeft.McInstance.PathInstance] = true; Reload(); } } // 跳转新建档案 private void BtnServerNewProfile_Click(object sender, MouseButtonEventArgs e) { ModMain.frmMain.PageChange(new FormMain.PageStackData { page = FormMain.PageType.Launch }); PageLoginAuth.draggedAuthServer = TextServerAuthServer.Text; ModBase.RunInNewThread(() => { Thread.Sleep(150); ModBase.RunInUi(() => ModMain.frmLaunchLeft.RefreshPage(true, ModLaunch.McLoginType.Auth)); }); } private static void TextServerEnter_Change(object sender, TextChangedEventArgs e) { if (sender is MyTextBox textBox) textBox.Text = textBox.Text.Replace(":", ":"); } #endregion #region Java 选择 // 刷新 Java 下拉框显示 public void RefreshJavaComboBox() { if (ComboArgumentJava is null) return; // 获取实例的 Java 偏好(已兼容新旧格式) var preference = ModJava.GetInstanceJavaPreference(PageInstanceLeft.McInstance); // === 1. 初始化固定选项(使用类型安全的 Tag) === ComboArgumentJava.Items.Clear(); // 选项 0: 跟随全局设置 ComboArgumentJava.Items.Add(new MyComboBoxItem { Content = Lang.Text("Instance.Setup.FollowGlobal"), Tag = new UseGlobalPreference() }); // 选项 1: 自动选择 ComboArgumentJava.Items.Add(new MyComboBoxItem { Content = Lang.Text("Instance.Setup.Options.Java.AutoSelect"), Tag = new AutoSelect() // Nothing 表示自动选择 }); // 选项 2: 相对路径选项 MyComboBoxItem relativePathItem; if (preference is UseRelativePath) { var relPref = (UseRelativePath)preference; var absPath = Path.GetFullPath(Path.Combine(Basics.ExecutableDirectory, relPref.RelativePath)); var javaEntry = ModJava.Javas.Get(absPath); if (Files.IsPathWithinDirectory(absPath, Basics.ExecutableDirectory) && javaEntry is not null && javaEntry.IsEnabled) // 有效路径:显示具体 Java 信息 relativePathItem = new MyComboBoxItem { Content = Lang.Text("Instance.Setup.Options.Java.SelectRelative.WithJava", javaEntry.ToString()), Tag = new UseRelativePath(relPref.RelativePath), ToolTip = Lang.Text("Instance.Setup.Options.Java.RelativePathToolTip", relPref.RelativePath, absPath) }; else // 无效路径:提示用户重新选择 relativePathItem = new MyComboBoxItem { Content = Lang.Text("Instance.Setup.Options.Java.SelectRelative.Invalid"), Tag = new UseRelativePath(relPref.RelativePath), ToolTip = Lang.Text("Instance.Setup.Options.Java.InvalidPathToolTip", absPath) }; } else { // 未配置相对路径:使用默认模板 relativePathItem = new MyComboBoxItem { Content = Lang.Text("Instance.Setup.Options.Java.SelectRelative"), Tag = new UseRelativePath(@"jre\bin\java.exe"), ToolTip = Lang.Text("Instance.Setup.Options.Java.SelectRelativeToolTip") }; } ComboArgumentJava.Items.Add(relativePathItem); // === 2. 添加所有可用 Java 运行时 === MyComboBoxItem selectedItem = null; try { foreach (var curJava in ModJava.Javas.GetSortedJavaList()) { var item = new MyComboBoxItem { Content = curJava.ToString(), ToolTip = Lang.Text("Instance.Setup.Options.Java.Details.ToolTip", curJava.Installation.JavaExePath, curJava.Installation.Version, curJava.Source), Tag = curJava }; ToolTipService.SetInitialShowDelay(item, 300); ToolTipService.SetBetweenShowDelay(item, 100); ComboArgumentJava.Items.Add(item); } } catch (Exception ex) { Config.Instance.SelectedJava[PageInstanceLeft.McInstance.PathInstance] = "使用全局设置"; ModBase.Log( ex, "更新实例设置 Java 下拉框失败", ModBase.LogLevel.Feedback, userSummary: Lang.Text("Instance.Setup.Error.OperationFailed")); ComboArgumentJava.Items.Clear(); ComboArgumentJava.Items.Add(new MyComboBoxItem { Content = Lang.Text("Instance.Setup.Options.Java.LoadFailed"), IsEnabled = false }); ComboArgumentJava.SelectedIndex = 0; RefreshRam(true); return; } // === 3. 根据当前偏好设置选中项(优先使用新格式 preference) === if (preference is null) { // 自动选择 selectedItem = ComboArgumentJava.Items[1] as MyComboBoxItem; } else if (preference is UseGlobalPreference) { selectedItem = ComboArgumentJava.Items[0] as MyComboBoxItem; } else if (preference is UseRelativePath) { selectedItem = ComboArgumentJava.Items[2] as MyComboBoxItem; } else if (preference is ExistingJava) { var existPref = (ExistingJava)preference; // 在 Java 列表中查找匹配项(从索引 3 开始) for (int i = 3, loopTo = ComboArgumentJava.Items.Count - 1; i <= loopTo; i++) { var item = ComboArgumentJava.Items[i] as MyComboBoxItem; if (item is not null && item.Tag is JavaEntry) { var javaEntry = (JavaEntry)item.Tag; if (string.Equals(javaEntry.Installation.JavaExePath, existPref.JavaExePath, StringComparison.OrdinalIgnoreCase)) { selectedItem = item; break; } } } } // 降级处理:无匹配项时回退到自动选择 if (selectedItem is null && ComboArgumentJava.Items.Count > 1) selectedItem = ComboArgumentJava.Items[1] as MyComboBoxItem; // 设置选中项 if (selectedItem is not null) ComboArgumentJava.SelectedItem = selectedItem; // === 4. 无可用 Java 时的降级处理 === if (!ModJava.Javas.ExistAnyJava() && ComboArgumentJava.Items.Count <= 3) { ComboArgumentJava.Items.Clear(); var noJavaItem = new MyComboBoxItem { Content = Lang.Text("Instance.Setup.Options.Java.NoRuntime"), ToolTip = Lang.Text("Instance.Setup.Options.Java.NoRuntime.ToolTip"), IsEnabled = false }; ComboArgumentJava.Items.Add(noJavaItem); ComboArgumentJava.SelectedItem = noJavaItem; } // === 5. 刷新关联控件 === RefreshRam(true); } // 阻止在无效状态下展开下拉框 private void ComboArgumentJava_DropDownOpened(object? sender, EventArgs e) { if (ComboArgumentJava.SelectedItem is null) { ComboArgumentJava.IsDropDownOpen = false; return; } var firstItem = ComboArgumentJava.Items[0] as MyComboBoxItem; if (firstItem is not null && ((string)firstItem.Content == Lang.Text("Instance.Setup.Options.Java.NoRuntime") || (string)firstItem.Content == Lang.Text("Instance.Setup.Options.Java.LoadFailed"))) ComboArgumentJava.IsDropDownOpen = false; } // 下拉框选择更改处理(保存新格式配置) private void JavaSelectionUpdate(object sender, SelectionChangedEventArgs e) { if (ModAnimation.AniControlEnabled != 0) return; if (ComboArgumentJava.SelectedItem is null) return; var selectedItem = ComboArgumentJava.SelectedItem as MyComboBoxItem; if (selectedItem is null || (selectedItem.Tag is null && (string)selectedItem.Content != Lang.Text("Instance.Setup.Options.Java.AutoSelect"))) return; JavaPreference preference = default; var logMessage = ""; // 根据 Tag 类型生成偏好对象 if (selectedItem.Tag is null or AutoSelect) { // 自动选择:存储空字符串 preference = new AutoSelect(); logMessage = "[Java] 修改实例 Java 选择设置:自动选择"; } else if (selectedItem.Tag is UseGlobalPreference) { preference = new UseGlobalPreference(); logMessage = "[Java] 修改实例 Java 选择设置:跟随全局设置"; } else if (selectedItem.Tag is UseRelativePath) { // 相对路径:需要用户选择实际文件 var ret = SystemDialogs.SelectFile(Lang.Text("Setup.Java.SelectFile.Filter"), Lang.Text("Setup.Java.SelectFile.Title"), Basics.ExecutableDirectory); if (string.IsNullOrWhiteSpace(ret)) // 用户取消,不保存配置,保持原选择 return; ret = Path.GetFullPath(ret); var relativePath = Path.GetRelativePath(Basics.ExecutableDirectory, ret); // 验证路径是否在启动器目录内 if (!Files.IsPathWithinDirectory(relativePath, Basics.ExecutableDirectory)) { HintService.Hint(Lang.Text("Instance.Setup.Options.Java.PathOutOfRange"), HintType.Error); return; } preference = new UseRelativePath(relativePath); logMessage = $"[Java] 修改实例 Java 选择设置:相对路径 | {relativePath}"; } else if (selectedItem.Tag is JavaEntry) { var javaEntry = (JavaEntry)selectedItem.Tag; preference = new ExistingJava(javaEntry.Installation.JavaExePath); logMessage = $"[Java] 修改实例 Java 选择设置:{javaEntry}"; } // 保存配置 var json = JsonSerializer.Serialize(preference, JsonCompat.SerializerOptions); Config.Instance.SelectedJava[PageInstanceLeft.McInstance.PathInstance] = json; ModBase.Log(logMessage); RefreshRam(true); } #endregion #region 其他设置 // 版本隔离警告 private bool isReverting; private void ComboArgumentIndieV2_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (ModAnimation.AniControlEnabled != 0) return; if (isReverting) return; if (ModMain.MyMsgBox( Lang.Text("Instance.Setup.Options.InstanceIsolation.Message"), Lang.Text("Common.Dialog.Warning"), Lang.Text("Setup.Launch.Advanced.Renderer.Warning.Confirm"), Lang.Text("Common.Action.Cancel"), isWarn: true) == 2) { isReverting = true; ComboArgumentIndieV2.SelectedItem = e.RemovedItems[0]; isReverting = false; } else { bool newValue = ComboArgumentIndieV2.SelectedIndex == 0; Config.Instance.IndieV2[PageInstanceLeft.McInstance.PathInstance] = newValue; } } // 游戏窗口 private void CheckArgumentTitleEmpty_Change(object sender, bool e) { TextArgumentTitle.HintText = CheckArgumentTitleEmpty.Checked == true ? Lang.Text("Common.Option.Default") : Lang.Text("Instance.Setup.FollowGlobal"); CheckBoxChange(sender,e); } private void TextArgumentTitle_TextChanged(object sender, TextChangedEventArgs e) { CheckArgumentTitleEmpty.Visibility = TextArgumentTitle.Text.Length > 0 ? Visibility.Collapsed : Visibility.Visible; TextBoxChange(sender,e); } #endregion #region 高级设置 private void TextAdvanceRun_TextChanged(object sender, TextChangedEventArgs e) { CheckAdvanceRunWait.Visibility = string.IsNullOrEmpty(TextAdvanceRun.Text) ? Visibility.Collapsed : Visibility.Visible; TextBoxChange(sender,e); } private void ComboAdvanceRenderer_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (ModAnimation.AniControlEnabled != 0) return; var args = e; // 转换事件参数 if (!States.Hint.Renderer && ComboAdvanceRenderer.SelectedIndex != 0) { if (ModMain.MyMsgBox(Lang.Text("Setup.Launch.Advanced.Renderer.Warning.Message"), Lang.Text("Common.Dialog.Warning"), Lang.Text("Setup.Launch.Advanced.Renderer.Warning.Confirm"), Lang.Text("Common.Action.Cancel"), isWarn: true) == 2) { ComboAdvanceRenderer.SelectedItem = args.RemovedItems[0]; } else { ComboChange(ComboAdvanceRenderer, e); States.Hint.Renderer = true; } } else { ComboChange(ComboAdvanceRenderer, e); } } private void CheckUseDebugLog4j2Config_CheckChanged(object sender, bool e) { if (ModAnimation.AniControlEnabled != 0) return; var checkBox = sender as MyCheckBox; if (checkBox is null) return; if (checkBox.Checked.GetValueOrDefault() && !States.Hint.DebugLog4j2Config) { if (ModMain.MyMsgBox( Lang.Text("Instance.Setup.Advanced.UseDebugLog4j.Message"), Lang.Text("Common.Dialog.Warning"), Lang.Text("Setup.Launch.Advanced.Renderer.Warning.Confirm"), Lang.Text("Common.Action.Cancel"), isWarn: true) == 2) { checkBox.Checked = false; } else { CheckBoxChange(sender, e); States.Hint.DebugLog4j2Config = true; } } else { CheckBoxChange(sender, e); } } #endregion }