初始化 monorepo: Go后端(7微服务) + Unity客户端(9模块) + 启动器 HTML5原型: Three.js 3D体素世界, Perlin噪声地形, 原版材质, 22种方块 Minecraft创造模式背包: 双栏布局, 拖拽移动物品, 方向性元件引脚 AI助搭策划文档 + 客户端/服务端骨架 + Docker Compose + CI
This commit is contained in:
+189
@@ -0,0 +1,189 @@
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using PCL.Core.App;
|
||||
using PCL.Core.App.Localization;
|
||||
using PCL.Core.Logging;
|
||||
using PCL.Core.UI;
|
||||
|
||||
namespace PCL;
|
||||
|
||||
internal sealed class CrashDialogPresenter(CrashAnalysisContext context)
|
||||
{
|
||||
private readonly CrashReportExporter _exporter = new();
|
||||
private readonly CrashResultFormatter _formatter = new();
|
||||
|
||||
public void Output(
|
||||
bool isHandAnalyze,
|
||||
List<string>? extraFiles)
|
||||
{
|
||||
ModMain.frmMain.ShowWindowToTop();
|
||||
|
||||
var crashContent = _formatter.Format(context, isHandAnalyze);
|
||||
var resultText = crashContent.Text;
|
||||
var directFile = context.DirectOpenFile;
|
||||
var openInstanceSettings =
|
||||
context.Instance is not null &&
|
||||
crashContent.SuggestedAction == CrashSuggestedAction.OpenInstanceSettings;
|
||||
|
||||
var title = isHandAnalyze
|
||||
? Lang.Text("Crash.Dialog.Title.Manual")
|
||||
: Lang.Text("Crash.Dialog.Title.Auto");
|
||||
|
||||
var secondButtonText = _GetSecondButtonText(
|
||||
isHandAnalyze,
|
||||
directFile,
|
||||
openInstanceSettings);
|
||||
|
||||
var thirdButtonText = isHandAnalyze
|
||||
? ""
|
||||
: Lang.Text("Crash.Dialog.Button.ExportReport");
|
||||
|
||||
var secondButtonAction = _GetSecondButtonAction(
|
||||
isHandAnalyze,
|
||||
directFile,
|
||||
openInstanceSettings);
|
||||
|
||||
var selectedButton = MsgBoxWrapper.ShowWithCustomButtons(
|
||||
resultText,
|
||||
title,
|
||||
MsgBoxTheme.Info,
|
||||
true,
|
||||
new MsgBoxButtonInfo(Lang.Text("Common.Action.Confirm"), 1),
|
||||
new MsgBoxButtonInfo(secondButtonText, 2, secondButtonAction),
|
||||
new MsgBoxButtonInfo(thirdButtonText, 3));
|
||||
|
||||
switch (selectedButton)
|
||||
{
|
||||
case 2:
|
||||
if (openInstanceSettings)
|
||||
_OpenModLoaderInstallPage();
|
||||
else if (directFile is not null)
|
||||
_OpenDirectFile(directFile);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
_ExportReport(extraFiles);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static string _GetSecondButtonText(
|
||||
bool isHandAnalyze,
|
||||
CrashLogEntry? directFile,
|
||||
bool openInstanceSettings)
|
||||
{
|
||||
if (isHandAnalyze || directFile is null)
|
||||
return "";
|
||||
|
||||
return openInstanceSettings
|
||||
? Lang.Text("Crash.Dialog.Button.GoToModify")
|
||||
: Lang.Text("Crash.Dialog.Button.OpenLog");
|
||||
}
|
||||
|
||||
private static Action? _GetSecondButtonAction(
|
||||
bool isHandAnalyze,
|
||||
CrashLogEntry? directFile,
|
||||
bool openInstanceSettings)
|
||||
{
|
||||
if (isHandAnalyze ||
|
||||
directFile is null ||
|
||||
openInstanceSettings)
|
||||
return null;
|
||||
|
||||
return () => _OpenDirectFile(directFile);
|
||||
}
|
||||
|
||||
private void _OpenModLoaderInstallPage()
|
||||
{
|
||||
PageInstanceLeft.McInstance = context.Instance;
|
||||
|
||||
ModBase.RunInUi(() => ModMain.frmMain.PageChange(
|
||||
FormMain.PageType.InstanceSetup,
|
||||
FormMain.PageSubType.VersionInstall));
|
||||
}
|
||||
|
||||
private static void _OpenDirectFile(CrashLogEntry directFile)
|
||||
{
|
||||
if (File.Exists(directFile.FullPath))
|
||||
{
|
||||
Basics.OpenPath(directFile.FullPath);
|
||||
return;
|
||||
}
|
||||
|
||||
var filePath = Path.Combine(Paths.Temp, "Crash.txt");
|
||||
|
||||
CrashFileIo.WriteText(filePath, string.Join("\r\n", directFile.Lines));
|
||||
Basics.OpenPath(filePath);
|
||||
}
|
||||
|
||||
private void _ExportReport(List<string>? extraFiles)
|
||||
{
|
||||
string? fileAddress = null;
|
||||
|
||||
try
|
||||
{
|
||||
fileAddress = _SelectReportSavePath();
|
||||
|
||||
if (string.IsNullOrEmpty(fileAddress))
|
||||
return;
|
||||
|
||||
_exporter.Export(context, fileAddress, extraFiles);
|
||||
|
||||
HintWrapper.Show(
|
||||
Lang.Text("Crash.Report.Export.Success"),
|
||||
HintTheme.Success);
|
||||
|
||||
Basics.OpenPath(Path.GetDirectoryName(fileAddress) ?? fileAddress);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogWrapper.Error(ex, "Crash", "导出错误报告失败");
|
||||
|
||||
var message = _CreateExportFailureMessage(fileAddress, ex);
|
||||
MsgBoxWrapper.ShowWithCustomButtons(
|
||||
message,
|
||||
Lang.Text("Crash.Export.Failed.Title"),
|
||||
MsgBoxTheme.Error,
|
||||
false,
|
||||
new MsgBoxButtonInfo(Lang.Text("Common.Action.Confirm"), 1),
|
||||
new MsgBoxButtonInfo(
|
||||
Lang.Text("Crash.Export.Failed.CopyDetails"),
|
||||
2,
|
||||
() => ModBase.ClipboardSet(message, false)));
|
||||
}
|
||||
}
|
||||
|
||||
private static string _CreateExportFailureMessage(
|
||||
string? targetZipPath,
|
||||
Exception exception)
|
||||
{
|
||||
var summary = string.IsNullOrWhiteSpace(targetZipPath)
|
||||
? Lang.Text("Crash.Export.Failed.MessageWithoutPath")
|
||||
: Lang.Text("Crash.Export.Failed.Message", targetZipPath);
|
||||
|
||||
return ExceptionDetails.Compose(summary, exception);
|
||||
}
|
||||
|
||||
private static string? _SelectReportSavePath()
|
||||
{
|
||||
string? fileAddress = null;
|
||||
|
||||
ModBase.RunInUiWait(() => fileAddress = SystemDialogs.SelectSaveFile(
|
||||
Lang.Text("Crash.Report.SaveDialog.Title"),
|
||||
_GetDefaultReportFileName(),
|
||||
Lang.Text("Crash.Report.SaveDialog.Filter")));
|
||||
|
||||
return fileAddress;
|
||||
}
|
||||
|
||||
private static string _GetDefaultReportFileName()
|
||||
{
|
||||
var time = DateTime.Now
|
||||
.ToString("G", CultureInfo.InvariantCulture)
|
||||
.Replace("/", "-")
|
||||
.Replace(":", ".")
|
||||
.Replace(" ", "_");
|
||||
|
||||
return Lang.Text("Crash.Report.SaveDialog.DefaultFileName", time);
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
namespace PCL;
|
||||
|
||||
internal enum CrashSuggestedAction
|
||||
{
|
||||
None,
|
||||
OpenInstanceSettings
|
||||
}
|
||||
|
||||
internal sealed class CrashMessageSpec(
|
||||
string reasonKey,
|
||||
object?[] reasonArgs,
|
||||
string? suggestionKey,
|
||||
object?[] suggestionArgs,
|
||||
bool appendReportHint,
|
||||
bool appendHelpHint,
|
||||
CrashSuggestedAction suggestedAction = CrashSuggestedAction.None)
|
||||
{
|
||||
public string ReasonKey { get; } = reasonKey;
|
||||
|
||||
public object?[] ReasonArgs { get; } = reasonArgs;
|
||||
|
||||
public string? SuggestionKey { get; } = suggestionKey;
|
||||
|
||||
public object?[] SuggestionArgs { get; } = suggestionArgs;
|
||||
|
||||
public bool AppendReportHint { get; } = appendReportHint;
|
||||
|
||||
public bool AppendHelpHint { get; } = appendHelpHint;
|
||||
|
||||
public CrashSuggestedAction SuggestedAction { get; } = suggestedAction;
|
||||
}
|
||||
|
||||
internal sealed class CrashDialogContent(string text, CrashSuggestedAction suggestedAction)
|
||||
{
|
||||
public string Text { get; } = text;
|
||||
|
||||
public CrashSuggestedAction SuggestedAction { get; } = suggestedAction;
|
||||
}
|
||||
+525
@@ -0,0 +1,525 @@
|
||||
using PCL.Core.App.Localization;
|
||||
using PCL.Core.Logging;
|
||||
using PCL.Core.Utils;
|
||||
using PCL.Core.Utils.Exts;
|
||||
|
||||
namespace PCL;
|
||||
|
||||
internal sealed class CrashResultFormatter
|
||||
{
|
||||
public CrashDialogContent Format(
|
||||
CrashAnalysisContext context,
|
||||
bool isHandAnalyze)
|
||||
{
|
||||
var result = context.Result ?? new CrashAnalysisResult();
|
||||
|
||||
if (!result.Any)
|
||||
return _CreateUnknownContent(isHandAnalyze);
|
||||
|
||||
var specs = result.Findings
|
||||
.Select(finding => _CreateMessageSpec(finding, context.LogAll))
|
||||
.ToList();
|
||||
|
||||
var text = _JoinParagraphs(specs.Select(_Render));
|
||||
if (!isHandAnalyze)
|
||||
text = _AppendFollowUps(text, specs);
|
||||
|
||||
return new CrashDialogContent(
|
||||
_NormalizeLineEndings(text).Trim('\r', '\n'),
|
||||
specs[0].SuggestedAction);
|
||||
}
|
||||
|
||||
private static CrashDialogContent _CreateUnknownContent(bool isHandAnalyze)
|
||||
{
|
||||
var spec = isHandAnalyze
|
||||
? _Spec("Crash.Reason.Unknown.Manual")
|
||||
: _Spec("Crash.Reason.Unknown.Auto", "Crash.Suggestion.ExportReport");
|
||||
|
||||
return new CrashDialogContent(
|
||||
_NormalizeLineEndings(_Render(spec)).Trim('\r', '\n'),
|
||||
CrashSuggestedAction.None);
|
||||
}
|
||||
|
||||
private static string _AppendFollowUps(
|
||||
string text,
|
||||
IReadOnlyCollection<CrashMessageSpec> specs)
|
||||
{
|
||||
var followUps = new List<string>();
|
||||
|
||||
if (specs.Any(spec => spec.AppendReportHint))
|
||||
followUps.Add(Lang.Text("Crash.Suggestion.ViewReport"));
|
||||
|
||||
if (specs.Any(spec => spec.AppendHelpHint))
|
||||
followUps.Add(Lang.Text("Crash.Suggestion.ExportReport"));
|
||||
|
||||
var launcherOutdatedSuggestion = _GetLauncherOutdatedSuggestion();
|
||||
if (!string.IsNullOrWhiteSpace(launcherOutdatedSuggestion))
|
||||
followUps.Add(launcherOutdatedSuggestion);
|
||||
|
||||
return followUps.Count == 0
|
||||
? text
|
||||
: Lang.Text(
|
||||
"Crash.Presentation.WithFollowUps",
|
||||
text,
|
||||
_JoinParagraphs(followUps));
|
||||
}
|
||||
|
||||
private static string _Render(CrashMessageSpec spec)
|
||||
{
|
||||
var reason = Lang.Text(spec.ReasonKey, spec.ReasonArgs);
|
||||
if (spec.SuggestionKey is null)
|
||||
return Lang.Text("Crash.Presentation.ReasonOnly", reason);
|
||||
|
||||
return Lang.Text(
|
||||
"Crash.Presentation.WithSuggestion",
|
||||
reason,
|
||||
Lang.Text(spec.SuggestionKey, spec.SuggestionArgs));
|
||||
}
|
||||
|
||||
private static CrashMessageSpec _CreateMessageSpec(
|
||||
CrashFinding finding,
|
||||
string combinedLogText)
|
||||
{
|
||||
var additional = finding.Details.ToList();
|
||||
|
||||
switch (finding.Cause)
|
||||
{
|
||||
case CrashCause.ExtractedModFile:
|
||||
return _Spec(
|
||||
"Crash.Reason.ExtractedModFile",
|
||||
"Crash.Suggestion.ExtractedModFile");
|
||||
|
||||
case CrashCause.OutOfMemory:
|
||||
return _Spec(
|
||||
"Crash.Reason.OutOfMemory",
|
||||
"Crash.Suggestion.OutOfMemory",
|
||||
help: true);
|
||||
|
||||
case CrashCause.UsingOpenJ9:
|
||||
return _Spec(
|
||||
"Crash.Reason.UsingOpenJ9",
|
||||
"Crash.Suggestion.UsingOpenJ9");
|
||||
|
||||
case CrashCause.UsingJdk:
|
||||
return _Spec(
|
||||
"Crash.Reason.UsingJdk",
|
||||
"Crash.Suggestion.UsingJdk");
|
||||
|
||||
case CrashCause.JavaTooNew:
|
||||
return _Spec(
|
||||
"Crash.Reason.JavaTooNew",
|
||||
"Crash.Suggestion.JavaTooNew");
|
||||
|
||||
case CrashCause.JavaIncompatible:
|
||||
return _Spec(
|
||||
"Crash.Reason.JavaIncompatible",
|
||||
"Crash.Suggestion.JavaIncompatible");
|
||||
|
||||
case CrashCause.InvalidModFileName:
|
||||
return _Spec(
|
||||
"Crash.Reason.InvalidModFileName",
|
||||
"Crash.Suggestion.InvalidModFileName");
|
||||
|
||||
case CrashCause.MissingMixinBootstrap:
|
||||
return _Spec(
|
||||
"Crash.Reason.MissingMixinBootstrap",
|
||||
"Crash.Suggestion.MissingMixinBootstrap");
|
||||
|
||||
case CrashCause.X86JavaMemoryLimit:
|
||||
return Environment.Is64BitOperatingSystem
|
||||
? _Spec(
|
||||
"Crash.Reason.X86JavaMemoryLimit.OnX64Os",
|
||||
"Crash.Suggestion.X86JavaMemoryLimit.OnX64Os")
|
||||
: _Spec(
|
||||
"Crash.Reason.X86JavaMemoryLimit.OnX86Os",
|
||||
"Crash.Suggestion.X86JavaMemoryLimit.OnX86Os",
|
||||
help: true);
|
||||
|
||||
case CrashCause.MissingDependencyOrWrongMcVersion:
|
||||
return _FormatMissingDependency(additional);
|
||||
|
||||
case CrashCause.StackKeywordFound:
|
||||
return additional.Count == 1
|
||||
? _Spec(
|
||||
"Crash.Reason.StackKeyword.Single",
|
||||
"Crash.Suggestion.StackKeyword", _Args(additional[0]),
|
||||
help: true)
|
||||
: _Spec(
|
||||
"Crash.Reason.StackKeyword.Multiple",
|
||||
"Crash.Suggestion.StackKeyword",
|
||||
_Args(_BulletList(additional)),
|
||||
help: true);
|
||||
|
||||
case CrashCause.StackModNameFound or CrashCause.SuspectedModCrash:
|
||||
return additional.Count == 1
|
||||
? _Spec(
|
||||
"Crash.Reason.SuspectedMod.Single",
|
||||
"Crash.Suggestion.DisableThisMod",
|
||||
_Args(additional[0]),
|
||||
report: true,
|
||||
help: true)
|
||||
: _Spec(
|
||||
"Crash.Reason.SuspectedMod.Multiple",
|
||||
"Crash.Suggestion.DisableTheseMods",
|
||||
_Args(_BulletList(additional)),
|
||||
report: true,
|
||||
help: true);
|
||||
|
||||
case CrashCause.ConfirmedModCrash:
|
||||
return additional.Count == 1
|
||||
? _Spec(
|
||||
"Crash.Reason.ConfirmedMod.Single",
|
||||
"Crash.Suggestion.DisableThisMod",
|
||||
_Args(additional[0]),
|
||||
report: true,
|
||||
help: true)
|
||||
: _Spec(
|
||||
"Crash.Reason.ConfirmedMod.Multiple",
|
||||
"Crash.Suggestion.DisableTheseMods",
|
||||
_Args(_BulletList(additional)),
|
||||
report: true,
|
||||
help: true);
|
||||
|
||||
case CrashCause.ModMixinFailed:
|
||||
if (additional.Count == 0)
|
||||
return _Spec(
|
||||
"Crash.Reason.ModMixinFailed.None",
|
||||
"Crash.Suggestion.ModMixinFailed",
|
||||
report: true,
|
||||
help: true);
|
||||
|
||||
return additional.Count == 1
|
||||
? _Spec(
|
||||
"Crash.Reason.ModMixinFailed.Single",
|
||||
"Crash.Suggestion.DisableThisMod",
|
||||
_Args(additional[0]),
|
||||
report: true,
|
||||
help: true)
|
||||
: _Spec(
|
||||
"Crash.Reason.ModMixinFailed.Multiple",
|
||||
"Crash.Suggestion.DisableTheseMods",
|
||||
_Args(_BulletList(additional)),
|
||||
report: true,
|
||||
help: true);
|
||||
|
||||
case CrashCause.ModConfigCrash:
|
||||
return additional.Count > 1 && additional[1] is not null
|
||||
? _Spec(
|
||||
"Crash.Reason.ModConfigCrash.WithConfig",
|
||||
"Crash.Suggestion.ModConfigCrash",
|
||||
_Args(additional[0], additional[1]))
|
||||
: _Spec(
|
||||
"Crash.Reason.ModConfigCrash.Simple",
|
||||
"Crash.Suggestion.DisableThisMod",
|
||||
_Args(additional.FirstOrDefault() ?? string.Empty),
|
||||
report: true,
|
||||
help: true);
|
||||
|
||||
case CrashCause.ModInitializationFailed:
|
||||
return additional.Count == 1
|
||||
? _Spec(
|
||||
"Crash.Reason.ModInitializationFailed.Single",
|
||||
"Crash.Suggestion.DisableThisMod",
|
||||
_Args(additional[0]),
|
||||
report: true,
|
||||
help: true)
|
||||
: _Spec(
|
||||
"Crash.Reason.ModInitializationFailed.Multiple",
|
||||
"Crash.Suggestion.DisableTheseMods",
|
||||
_Args(_BulletList(additional)),
|
||||
report: true,
|
||||
help: true);
|
||||
|
||||
case CrashCause.SpecificBlockCrash:
|
||||
return additional.Count == 1
|
||||
? _Spec(
|
||||
"Crash.Reason.SpecificBlock.Single",
|
||||
"Crash.Suggestion.SpecificBlock.Single",
|
||||
_Args(additional[0]),
|
||||
help: true)
|
||||
: _Spec(
|
||||
"Crash.Reason.SpecificBlock.Multiple",
|
||||
"Crash.Suggestion.SpecificBlock.Multiple",
|
||||
help: true);
|
||||
|
||||
case CrashCause.DuplicateMods:
|
||||
return additional.Count >= 2
|
||||
? _Spec(
|
||||
"Crash.Reason.DuplicateMods.Known",
|
||||
"Crash.Suggestion.DuplicateMods",
|
||||
_Args(_BulletList(additional)))
|
||||
: _Spec(
|
||||
"Crash.Reason.DuplicateMods.Unknown",
|
||||
"Crash.Suggestion.DuplicateMods",
|
||||
report: true,
|
||||
help: true);
|
||||
|
||||
case CrashCause.SpecificEntityCrash:
|
||||
return additional.Count == 1
|
||||
? _Spec(
|
||||
"Crash.Reason.SpecificEntity.Single",
|
||||
"Crash.Suggestion.SpecificEntity.Single",
|
||||
_Args(additional[0]),
|
||||
help: true)
|
||||
: _Spec(
|
||||
"Crash.Reason.SpecificEntity.Multiple",
|
||||
"Crash.Suggestion.SpecificEntity.Multiple",
|
||||
help: true);
|
||||
|
||||
case CrashCause.OptiFineForgeIncompatible:
|
||||
return _Spec(
|
||||
"Crash.Reason.OptiFineForgeIncompatible",
|
||||
"Crash.Suggestion.OptiFineForgeIncompatible");
|
||||
|
||||
case CrashCause.ShadersModWithOptiFine:
|
||||
return _Spec(
|
||||
"Crash.Reason.ShadersModWithOptiFine",
|
||||
"Crash.Suggestion.ShadersModWithOptiFine");
|
||||
|
||||
case CrashCause.OldForgeNewJavaIncompatible:
|
||||
return _Spec(
|
||||
"Crash.Reason.OldForgeNewJavaIncompatible",
|
||||
"Crash.Suggestion.OldForgeNewJavaIncompatible");
|
||||
|
||||
case CrashCause.MultipleForgeInInstanceJson:
|
||||
return _Spec(
|
||||
"Crash.Reason.MultipleForgeInInstanceJson",
|
||||
"Crash.Suggestion.MultipleForgeInInstanceJson");
|
||||
|
||||
case CrashCause.ManualDebugCrash:
|
||||
return _Spec("Crash.Reason.ManualDebugCrash");
|
||||
|
||||
case CrashCause.ModRequiresJava11:
|
||||
return _Spec(
|
||||
"Crash.Reason.ModRequiresJava11",
|
||||
"Crash.Suggestion.ModRequiresJava11");
|
||||
|
||||
case CrashCause.VeryShortOutput:
|
||||
return _Spec(
|
||||
"Crash.Reason.VeryShortOutput",
|
||||
"Crash.Suggestion.ExportReport",
|
||||
_Args(additional.FirstOrDefault() ?? string.Empty));
|
||||
|
||||
case CrashCause.OptiFineWorldLoadCrash:
|
||||
return _Spec(
|
||||
"Crash.Reason.OptiFineWorldLoadCrash",
|
||||
"Crash.Suggestion.OptiFineWorldLoadCrash",
|
||||
help: true);
|
||||
|
||||
case CrashCause.PixelFormatNotSupported
|
||||
or CrashCause.IntelDriverAccessViolation
|
||||
or CrashCause.AmdDriverAccessViolation
|
||||
or CrashCause.NvidiaDriverAccessViolation
|
||||
or CrashCause.UnsupportedOpenGl:
|
||||
return combinedLogText.Contains("hd graphics ")
|
||||
? _Spec(
|
||||
"Crash.Reason.GraphicsDriver.IntelOrIntegrated",
|
||||
"Crash.Suggestion.GraphicsDriver.IntelOrIntegrated",
|
||||
help: true)
|
||||
: _Spec(
|
||||
"Crash.Reason.GraphicsDriver.Generic",
|
||||
"Crash.Suggestion.GraphicsDriver.Generic",
|
||||
help: true);
|
||||
|
||||
case CrashCause.ResourcePackTooLarge:
|
||||
return _Spec(
|
||||
"Crash.Reason.ResourcePackTooLarge",
|
||||
"Crash.Suggestion.ResourcePackTooLarge",
|
||||
help: true);
|
||||
|
||||
case CrashCause.NightConfigBug:
|
||||
return _Spec(
|
||||
"Crash.Reason.NightConfigBug",
|
||||
"Crash.Suggestion.NightConfigBug",
|
||||
help: true);
|
||||
|
||||
case CrashCause.OpenGl1282:
|
||||
return _Spec(
|
||||
"Crash.Reason.OpenGl1282",
|
||||
"Crash.Suggestion.OpenGl1282",
|
||||
help: true);
|
||||
|
||||
case CrashCause.TooManyModsIdLimit:
|
||||
return _Spec(
|
||||
"Crash.Reason.TooManyModsIdLimit",
|
||||
"Crash.Suggestion.TooManyModsIdLimit");
|
||||
|
||||
case CrashCause.FileOrContentValidationFailed:
|
||||
return _Spec(
|
||||
"Crash.Reason.FileOrContentValidationFailed",
|
||||
"Crash.Suggestion.FileOrContentValidationFailed",
|
||||
help: true);
|
||||
|
||||
case CrashCause.IncompleteForgeInstallation:
|
||||
return _Spec(
|
||||
"Crash.Reason.IncompleteForgeInstallation",
|
||||
"Crash.Suggestion.IncompleteForgeInstallation",
|
||||
help: true);
|
||||
|
||||
case CrashCause.FabricError:
|
||||
return additional.Count == 1
|
||||
? _Spec(
|
||||
"Crash.Reason.FabricError.WithDetail",
|
||||
"Crash.Suggestion.FollowLoaderInstructions",
|
||||
_Args(additional[0]))
|
||||
: _Spec(
|
||||
"Crash.Reason.FabricError.Generic",
|
||||
"Crash.Suggestion.FollowLoaderInstructions",
|
||||
help: true);
|
||||
|
||||
case CrashCause.IncompatibleMods:
|
||||
return _FormatIncompatibleMods(additional);
|
||||
|
||||
case CrashCause.ModLoaderError:
|
||||
return additional.Count == 1
|
||||
? _Spec(
|
||||
"Crash.Reason.ModLoaderError.WithDetail",
|
||||
"Crash.Suggestion.FollowLoaderInstructions",
|
||||
_Args(additional[0]))
|
||||
: _Spec(
|
||||
"Crash.Reason.ModLoaderError.Generic",
|
||||
"Crash.Suggestion.FollowLoaderInstructions",
|
||||
help: true);
|
||||
|
||||
case CrashCause.FabricSolutionProvided:
|
||||
return additional.Count == 1
|
||||
? _Spec(
|
||||
"Crash.Reason.FabricSolution.WithDetail",
|
||||
"Crash.Suggestion.FollowLoaderInstructions",
|
||||
_Args(additional[0]))
|
||||
: _Spec(
|
||||
"Crash.Reason.FabricSolution.Generic",
|
||||
"Crash.Suggestion.FollowLoaderInstructions",
|
||||
help: true);
|
||||
|
||||
case CrashCause.ForgeError:
|
||||
return additional.Count == 1
|
||||
? _Spec(
|
||||
"Crash.Reason.ForgeError.WithDetail",
|
||||
"Crash.Suggestion.FollowLoaderInstructions",
|
||||
_Args(additional[0]))
|
||||
: _Spec(
|
||||
"Crash.Reason.ForgeError.Generic",
|
||||
"Crash.Suggestion.FollowLoaderInstructions",
|
||||
help: true);
|
||||
|
||||
case CrashCause.NoAnalyzableFile:
|
||||
return _Spec(
|
||||
"Crash.Reason.NoAnalyzableFile",
|
||||
"Crash.Suggestion.ExportReport",
|
||||
help: true);
|
||||
|
||||
default:
|
||||
return _Spec(
|
||||
"Crash.Reason.UnknownFinding",
|
||||
"Crash.Suggestion.ExportReport",
|
||||
_Args(finding.Cause.ToString()),
|
||||
help: true);
|
||||
}
|
||||
}
|
||||
|
||||
private static CrashMessageSpec _FormatMissingDependency(List<string> additional)
|
||||
{
|
||||
if (additional.Count == 0)
|
||||
return _Spec(
|
||||
"Crash.Reason.MissingDependency.Generic",
|
||||
"Crash.Suggestion.FollowLoaderInstructions",
|
||||
help: true);
|
||||
|
||||
var info = _BulletList(additional);
|
||||
|
||||
return info.IsMatch(RegexPatterns.IncompatibleModLoaderErrorHint)
|
||||
? _Spec(
|
||||
"Crash.Reason.ModLoaderIncompatible",
|
||||
"Crash.Suggestion.ModLoaderIncompatible",
|
||||
_Args(info),
|
||||
action: CrashSuggestedAction.OpenInstanceSettings)
|
||||
: _Spec(
|
||||
"Crash.Reason.MissingDependency.WithDetail",
|
||||
"Crash.Suggestion.FollowLoaderInstructions",
|
||||
_Args(info));
|
||||
}
|
||||
|
||||
private static CrashMessageSpec _FormatIncompatibleMods(List<string> additional)
|
||||
{
|
||||
if (additional.Count != 1)
|
||||
return _Spec(
|
||||
"Crash.Reason.IncompatibleMods.Generic",
|
||||
"Crash.Suggestion.FollowLoaderInstructions",
|
||||
help: true);
|
||||
|
||||
var info = additional[0];
|
||||
|
||||
return info.IsMatch(RegexPatterns.IncompatibleModLoaderErrorHint)
|
||||
? _Spec(
|
||||
"Crash.Reason.ModLoaderIncompatible",
|
||||
"Crash.Suggestion.ModLoaderIncompatible",
|
||||
_Args(info),
|
||||
action: CrashSuggestedAction.OpenInstanceSettings)
|
||||
: _Spec(
|
||||
"Crash.Reason.IncompatibleMods.WithDetail",
|
||||
"Crash.Suggestion.FollowLoaderInstructions",
|
||||
_Args(info));
|
||||
}
|
||||
|
||||
private static CrashMessageSpec _Spec(
|
||||
string reasonKey,
|
||||
string? suggestionKey = null,
|
||||
object?[]? reasonArgs = null,
|
||||
object?[]? suggestionArgs = null,
|
||||
bool report = false,
|
||||
bool help = false,
|
||||
CrashSuggestedAction action = CrashSuggestedAction.None)
|
||||
{
|
||||
return new CrashMessageSpec(
|
||||
reasonKey,
|
||||
reasonArgs ?? [],
|
||||
suggestionKey,
|
||||
suggestionArgs ?? [],
|
||||
report,
|
||||
help,
|
||||
action);
|
||||
}
|
||||
|
||||
private static object?[] _Args(params object?[] args)
|
||||
{
|
||||
return args;
|
||||
}
|
||||
|
||||
private static string _BulletList(IEnumerable<string> items)
|
||||
{
|
||||
return string.Join(
|
||||
Environment.NewLine,
|
||||
items.Select(item => Lang.Text("Crash.Presentation.ListItem", item)));
|
||||
}
|
||||
|
||||
private static string _JoinParagraphs(IEnumerable<string> items)
|
||||
{
|
||||
return string.Join(
|
||||
Environment.NewLine + Environment.NewLine,
|
||||
items.Where(item => !string.IsNullOrWhiteSpace(item)));
|
||||
}
|
||||
|
||||
private static string _NormalizeLineEndings(string text)
|
||||
{
|
||||
return text
|
||||
.Replace("\r\n", "\r")
|
||||
.Replace("\n", "\r")
|
||||
.Replace("\r", "\r\n");
|
||||
}
|
||||
|
||||
private static string? _GetLauncherOutdatedSuggestion()
|
||||
{
|
||||
try
|
||||
{
|
||||
return UpdateManager.GetVersionStatus() == UpdateEnums.VersionStatus.Latest
|
||||
? null
|
||||
: Lang.Text("Crash.Suggestion.LauncherOutdated");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogWrapper.Error(ex, "Crash", "确认启动器更新失败");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user