Files

1054 lines
44 KiB
C#
Raw Permalink Normal View History

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;
}
/// <summary>
/// 刷新 UI 上的 RAM 显示。
/// </summary>
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;
/// <summary>
/// 刷新 UI 上的文本位置。
/// </summary>
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;
}
/// <summary>
/// 获取当前设置的 RAM 值。单位为 GB。
/// </summary>
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
}