From 71fd96126b6d85704a21c434a7906b539e832ceb Mon Sep 17 00:00:00 2001
From: JungleDruid <3953982+JungleDruid@users.noreply.github.com>
Date: Tue, 27 Feb 2024 11:59:58 +0800
Subject: [PATCH] Add detailed error logging
---
BG3LocalizationMerger.csproj | 2 +-
Dialog.cs | 4 +-
HandleExtractor.cs | 205 +++++++++++++++++--------
MainWindow.xaml | 2 +-
MainWindow.xaml.cs | 49 +++++-
PackageManager.cs | 178 +++++++++++++--------
Resources/Strings/Strings.Designer.cs | 9 ++
Resources/Strings/Strings.resx | 3 +
Resources/Strings/Strings.zh-Hant.resx | 3 +
9 files changed, 318 insertions(+), 137 deletions(-)
diff --git a/BG3LocalizationMerger.csproj b/BG3LocalizationMerger.csproj
index 6de1476..e1f7f28 100644
--- a/BG3LocalizationMerger.csproj
+++ b/BG3LocalizationMerger.csproj
@@ -8,7 +8,7 @@
true
x64
en
- $(VersionPrefix)1.0.4
+ $(VersionPrefix)1.1.0
False
diff --git a/Dialog.cs b/Dialog.cs
index e7a231a..4494d10 100644
--- a/Dialog.cs
+++ b/Dialog.cs
@@ -113,8 +113,8 @@ ref childrenCount
}
}
- Children = childrenCount == 0 ? Array.Empty() : children[..childrenCount];
- Texts = textsCount == 0 ? Array.Empty() : texts[..textsCount];
+ Children = childrenCount == 0 ? [] : children[..childrenCount];
+ Texts = textsCount == 0 ? [] : texts[..textsCount];
Debug.Assert(!string.IsNullOrWhiteSpace(Id));
shared.Return(children);
shared.Return(texts);
diff --git a/HandleExtractor.cs b/HandleExtractor.cs
index 63a83a2..e381f5f 100644
--- a/HandleExtractor.cs
+++ b/HandleExtractor.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
@@ -48,95 +49,175 @@ internal static partial class HandleExtractor
)]
private static partial Regex TooltipFilter();
- public static IEnumerable ExtractCharacterHandles(string path)
+ public static IEnumerable? ExtractCharacterHandles(string path)
{
- var text = ReadText(path);
- if (!TemplateCharacterFilter().IsMatch(text))
- return Enumerable.Empty();
- return ExtractHandles(text, CharacterHandles());
+ try
+ {
+ var text = ReadText(path);
+ if (!TemplateCharacterFilter().IsMatch(text))
+ return Enumerable.Empty();
+ return ExtractHandles(text, CharacterHandles());
+ }
+ catch (Exception e)
+ {
+ MainWindow.LogFileError(path, e);
+ return null;
+ }
}
- public static IEnumerable ExtractWaypointHandles(string path)
+ public static IEnumerable? ExtractWaypointHandles(string path)
{
- return ExtractGenericHandles(path);
+ try
+ {
+ return ExtractGenericHandles(path);
+ }
+ catch (Exception e)
+ {
+ MainWindow.LogFileError(path, e);
+ return null;
+ }
}
- public static IEnumerable ExtractQuestMarkerHandles(string path)
+ public static IEnumerable? ExtractQuestMarkerHandles(string path)
{
- return ExtractGenericHandles(path);
+ try
+ {
+ return ExtractGenericHandles(path);
+ }
+ catch (Exception e)
+ {
+ MainWindow.LogFileError(path, e);
+ return null;
+ }
}
- public static IEnumerable ExtractBookHandles(string path)
+ public static IEnumerable? ExtractBookHandles(string path)
{
- return ExtractGenericHandles(path);
+ try
+ {
+ return ExtractGenericHandles(path);
+ }
+ catch (Exception e)
+ {
+ MainWindow.LogFileError(path, e);
+ return null;
+ }
}
- public static (IEnumerable, IEnumerable) ExtractQuestHandles(string path)
+ public static (IEnumerable, IEnumerable)? ExtractQuestHandles(string path)
{
- string text = ReadText(path);
- MatchCollection matches = QuestHandle().Matches(text);
- var group = matches.GroupBy(x => x.Groups["Type"].Value);
- return (
- group
- .FirstOrDefault(x => x.Key == "QuestTitle")
- ?.SelectMany(x => x.Groups.Values.Skip(1))
- .Select(x => x.Value) ?? Enumerable.Empty(),
- group
- .Where(x => x.Key.EndsWith("Description"))
- .SelectMany(x => x)
- ?.SelectMany(x => x.Groups.Values.Skip(1))
- .Select(x => x.Value) ?? Enumerable.Empty()
- );
+ try
+ {
+ string text = ReadText(path);
+ MatchCollection matches = QuestHandle().Matches(text);
+ var group = matches.GroupBy(x => x.Groups["Type"].Value);
+ return (
+ group
+ .FirstOrDefault(x => x.Key == "QuestTitle")
+ ?.SelectMany(x => x.Groups.Values.Skip(1))
+ .Select(x => x.Value) ?? Enumerable.Empty(),
+ group
+ .Where(x => x.Key.EndsWith("Description"))
+ .SelectMany(x => x)
+ ?.SelectMany(x => x.Groups.Values.Skip(1))
+ .Select(x => x.Value) ?? Enumerable.Empty()
+ );
+ }
+ catch (Exception e)
+ {
+ MainWindow.LogFileError(path, e);
+ return null;
+ }
}
- public static (IEnumerable, IEnumerable) ExtractStatusHandles(string path)
+ public static (IEnumerable, IEnumerable)? ExtractStatusHandles(string path)
{
- string text = ReadText(path);
- MatchCollection matches = StatusHandle().Matches(text);
- var group = matches.GroupBy(x => x.Groups["Type"].Value);
- return (
- group
- .FirstOrDefault(x => x.Key == "DisplayName")
- ?.SelectMany(x => x.Groups.Values.Skip(1))
- .Select(x => x.Value) ?? Enumerable.Empty(),
- group
- .Where(x => x.Key.EndsWith("Description"))
- .SelectMany(x => x)
- ?.SelectMany(x => x.Groups.Values.Skip(1))
- .Select(x => x.Value) ?? Enumerable.Empty()
- );
+ try
+ {
+ string text = ReadText(path);
+ MatchCollection matches = StatusHandle().Matches(text);
+ var group = matches.GroupBy(x => x.Groups["Type"].Value);
+ return (
+ group
+ .FirstOrDefault(x => x.Key == "DisplayName")
+ ?.SelectMany(x => x.Groups.Values.Skip(1))
+ .Select(x => x.Value) ?? Enumerable.Empty(),
+ group
+ .Where(x => x.Key.EndsWith("Description"))
+ .SelectMany(x => x)
+ ?.SelectMany(x => x.Groups.Values.Skip(1))
+ .Select(x => x.Value) ?? Enumerable.Empty()
+ );
+ }
+ catch (Exception e)
+ {
+ MainWindow.LogFileError(path, e);
+ return null;
+ }
}
- public static IEnumerable ExtractItemGroup(string path)
+ public static IEnumerable? ExtractItemGroup(string path)
{
- string text = ReadText(path);
- if (!TemplateItemFilter().IsMatch(text))
- return Enumerable.Empty();
- MatchCollection matches = TemplateHandles().Matches(text);
- return matches
- .SelectMany(x => x.Groups.Values.Skip(1))
- .Where(x => !string.IsNullOrEmpty(x.Value));
+ try
+ {
+ string text = ReadText(path);
+ if (!TemplateItemFilter().IsMatch(text))
+ return Enumerable.Empty();
+ MatchCollection matches = TemplateHandles().Matches(text);
+ return matches
+ .SelectMany(x => x.Groups.Values.Skip(1))
+ .Where(x => !string.IsNullOrEmpty(x.Value));
+ }
+ catch (Exception e)
+ {
+ MainWindow.LogFileError(path, e);
+ return null;
+ }
}
- public static IEnumerable ExtractTooltipHandles(string path)
+ public static IEnumerable? ExtractTooltipHandles(string path)
{
- string text = ReadText(path);
- MatchCollection matches = GenericHandle().Matches(text);
- return matches
- .Where(x => TooltipFilter().IsMatch(x.Groups[0].Value))
- .SelectMany(x => x.Groups.Values.Skip(1))
- .Select(x => x.Value)
- .Where(x => !string.IsNullOrEmpty(x));
+ try
+ {
+ string text = ReadText(path);
+ MatchCollection matches = GenericHandle().Matches(text);
+ return matches
+ .Where(x => TooltipFilter().IsMatch(x.Groups[0].Value))
+ .SelectMany(x => x.Groups.Values.Skip(1))
+ .Select(x => x.Value)
+ .Where(x => !string.IsNullOrEmpty(x));
+ }
+ catch (Exception e)
+ {
+ MainWindow.LogFileError(path, e);
+ return null;
+ }
}
- public static IEnumerable ExtractHintHandles(string path)
+ public static IEnumerable? ExtractHintHandles(string path)
{
- return ExtractGenericHandles(path);
+ try
+ {
+ return ExtractGenericHandles(path);
+ }
+ catch (Exception e)
+ {
+ MainWindow.LogFileError(path, e);
+ return null;
+ }
}
- public static IEnumerable ExtractGenericHandles(string path)
+ public static IEnumerable? ExtractGenericHandles(string path)
{
- return ExtractHandles(ReadText(path), GenericHandle());
+ try
+ {
+ return ExtractHandles(ReadText(path), GenericHandle());
+ }
+ catch (Exception e)
+ {
+ MainWindow.LogFileError(path, e);
+ return null;
+ }
}
private static string ReadText(string path)
diff --git a/MainWindow.xaml b/MainWindow.xaml
index 67209a0..ed929de 100644
--- a/MainWindow.xaml
+++ b/MainWindow.xaml
@@ -43,7 +43,7 @@
-
+
diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs
index 1c86041..6da50fd 100644
--- a/MainWindow.xaml.cs
+++ b/MainWindow.xaml.cs
@@ -4,6 +4,7 @@
using Ookii.Dialogs.Wpf;
using System;
using System.Collections.Generic;
+using System.Collections.Immutable;
using System.Diagnostics;
using System.Globalization;
using System.IO;
@@ -13,6 +14,7 @@
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
+using System.Windows.Documents;
using System.Windows.Media;
namespace BG3LocalizationMerger
@@ -26,6 +28,9 @@ public partial class MainWindow
public static MainWindow Instance => s_instance!;
+ public static int ErrorCount { get; private set; }
+ public static bool CacheValid { get; private set; }
+
public MainWindow()
{
s_instance = this;
@@ -100,26 +105,60 @@ private void InitCulture()
LanguageComboBox.SelectedIndex = 0;
}
- public static void Log(string text)
+ public static void Log(string text, Brush? foreground = null)
{
s_instance!.Dispatcher.Invoke(() =>
{
var textbox = s_instance.LogTextBox;
- text = $"[{DateTime.Now.ToLongTimeString()}] {text}";
- if (!string.IsNullOrEmpty(textbox.Text))
- text = '\n' + text;
- textbox.Text += text;
+ Paragraph paragraph = new();
+ Run run = new($"[{DateTime.Now.ToLongTimeString()}] {text}");
+ paragraph.Inlines.Add(run);
+ paragraph.Margin = new(0);
+ if (foreground != null)
+ {
+ paragraph.Foreground = foreground;
+ }
+ textbox.Document.Blocks.Add(paragraph);
textbox.ScrollToEnd();
});
}
+ public static void LogError(string text)
+ {
+ ErrorCount += 1;
+ Log(text, Brushes.Red);
+ }
+
+ public static void LogFileError(string path, Exception e)
+ {
+ LogError($"ERROR: {e.Message} ({path[Settings.Default.UnpackedDataPath.Length..]})");
+ }
+
private async void Merge_Click(object sender, RoutedEventArgs e)
{
if (!await VerifyTextBoxes(true))
return;
SaveSettings();
+ ErrorCount = 0;
+ LogTextBox.Document.Blocks.Clear();
+
await RunMerge(PackageManager.Instance.Merge);
+
+ if (ErrorCount > 0)
+ {
+ CacheValid = false;
+ MessageBox.Show(
+ $"{ErrorCount} error{(ErrorCount > 1 ? "s" : "")} occurred. Check the logs for details.",
+ "Error",
+ MessageBoxButton.OK,
+ MessageBoxImage.Error
+ );
+ }
+ else
+ {
+ CacheValid = true;
+ }
}
private Task VerifyTextBoxes(bool showWarning, bool checkUnpackedData = true)
diff --git a/PackageManager.cs b/PackageManager.cs
index 625efbc..c214e81 100644
--- a/PackageManager.cs
+++ b/PackageManager.cs
@@ -17,19 +17,19 @@ namespace BG3LocalizationMerger
{
internal sealed partial class PackageManager : SingletonBase
{
- internal static readonly ImmutableList s_modNames = new List()
- {
+ internal static readonly ImmutableList s_modNames =
+ [
"Shared",
"SharedDev",
"Gustav",
"GustavDev"
- }.ToImmutableList();
+ ];
- private static readonly string[] s_questPrototypeFiles = new string[]
- {
+ private static readonly string[] s_questPrototypeFiles =
+ [
"quest_prototypes.lsx",
"objective_prototypes.lsx"
- };
+ ];
public IReadOnlyDictionary? Dialogs { get; private set; }
public ISet? ItemNameHandles { get; private set; }
@@ -51,6 +51,11 @@ internal sealed partial class PackageManager : SingletonBase
public void Load(CancellationToken cancellationToken)
{
+ if (MainWindow.CacheValid)
+ {
+ MainWindow.Log(Strings.UsingCache);
+ }
+
LoadItems(cancellationToken);
LoadCharacters(cancellationToken);
LoadDialogues(cancellationToken);
@@ -71,15 +76,21 @@ private static void LogLoading(string text)
private static void LogLoaded(int amount, string text, TimeSpan elapsed)
{
- MainWindow.Log(
- string.Format(Strings.LoadedMessage, amount, text, elapsed.TotalSeconds)
- );
+ string message = string.Format(Strings.LoadedMessage, amount, text, elapsed.TotalSeconds);
+ if (amount > 0)
+ {
+ MainWindow.Log(message);
+ }
+ else
+ {
+ MainWindow.LogError(message);
+ }
}
private void LoadCharacters(CancellationToken cancellationToken)
{
var props = Properties.Settings.Default;
- if (!props.MergeCharacters || CharacterHandles != null)
+ if (MainWindow.CacheValid && !props.MergeCharacters || CharacterHandles != null)
return;
LogLoading(Strings.Characters);
@@ -130,7 +141,9 @@ private void LoadCharacters(CancellationToken cancellationToken)
.Concat(levelMergedFiles)
.AsParallel()
.WithCancellation(cancellationToken)
- .SelectMany(HandleExtractor.ExtractCharacterHandles)
+ .Select(HandleExtractor.ExtractCharacterHandles)
+ .Where(x => x != null)
+ .SelectMany(x => x!)
.ToHashSet();
sw.Stop();
@@ -140,7 +153,7 @@ private void LoadCharacters(CancellationToken cancellationToken)
private void LoadMiscs(CancellationToken cancellationToken)
{
var props = Properties.Settings.Default;
- if (!props.MergeMiscs || MiscHandles != null)
+ if (MainWindow.CacheValid && !props.MergeMiscs || MiscHandles != null)
return;
LogLoading(Strings.Miscs);
@@ -161,7 +174,9 @@ private void LoadMiscs(CancellationToken cancellationToken)
MiscHandles = files
.AsParallel()
.WithCancellation(cancellationToken)
- .SelectMany(HandleExtractor.ExtractGenericHandles)
+ .Select(HandleExtractor.ExtractGenericHandles)
+ .Where(x => x != null)
+ .SelectMany(x => x!)
.ToHashSet();
sw.Stop();
@@ -171,7 +186,7 @@ private void LoadMiscs(CancellationToken cancellationToken)
private void LoadWaypoints(CancellationToken cancellationToken)
{
var props = Properties.Settings.Default;
- if (!props.MergeWaypoints || WaypointHandles != null)
+ if (MainWindow.CacheValid && !props.MergeWaypoints || WaypointHandles != null)
return;
LogLoading(Strings.Waypoints);
@@ -195,7 +210,9 @@ private void LoadWaypoints(CancellationToken cancellationToken)
WaypointHandles = files
.AsParallel()
.WithCancellation(cancellationToken)
- .SelectMany(HandleExtractor.ExtractWaypointHandles)
+ .Select(HandleExtractor.ExtractWaypointHandles)
+ .Where(x => x != null)
+ .SelectMany(x => x!)
.ToHashSet();
sw.Stop();
@@ -205,7 +222,7 @@ private void LoadWaypoints(CancellationToken cancellationToken)
private void LoadQuestMarkers(CancellationToken cancellationToken)
{
var props = Properties.Settings.Default;
- if (!props.MergeQuestMarkers || QuestMarkerHandles != null)
+ if (MainWindow.CacheValid && !props.MergeQuestMarkers || QuestMarkerHandles != null)
return;
LogLoading(Strings.QuestMarkers);
@@ -227,7 +244,9 @@ private void LoadQuestMarkers(CancellationToken cancellationToken)
QuestMarkerHandles = files
.AsParallel()
.WithCancellation(cancellationToken)
- .SelectMany(HandleExtractor.ExtractQuestMarkerHandles)
+ .Select(HandleExtractor.ExtractQuestMarkerHandles)
+ .Where(x => x != null)
+ .SelectMany(x => x!)
.ToHashSet();
sw.Stop();
@@ -237,8 +256,8 @@ private void LoadQuestMarkers(CancellationToken cancellationToken)
private void LoadQuests(CancellationToken cancellationToken)
{
var props = Properties.Settings.Default;
- if (
- (!props.MergeQuestNames || QuestNameHandles != null)
+ if (MainWindow.CacheValid
+ && (!props.MergeQuestNames || QuestNameHandles != null)
&& (!props.MergeQuestDescriptions || QuestDescriptionHandles != null)
)
return;
@@ -264,7 +283,9 @@ private void LoadQuests(CancellationToken cancellationToken)
var handles = files
.AsParallel()
.WithCancellation(cancellationToken)
- .Select(HandleExtractor.ExtractQuestHandles);
+ .Select(HandleExtractor.ExtractQuestHandles)
+ .Where(x => x != null)
+ .Select(x => ((IEnumerable, IEnumerable))x!);
QuestNameHandles = handles.SelectMany(x => x.Item1).ToHashSet();
QuestDescriptionHandles = handles.SelectMany(x => x.Item2).ToHashSet();
@@ -280,8 +301,8 @@ private void LoadQuests(CancellationToken cancellationToken)
private void LoadStatus(CancellationToken cancellationToken)
{
var props = Properties.Settings.Default;
- if (
- (!props.MergeStatusNames || StatusNameHandles != null)
+ if (MainWindow.CacheValid
+ && (!props.MergeStatusNames || StatusNameHandles != null)
&& (!props.MergeStatusDescriptions || StatusDescriptionHandles != null)
)
return;
@@ -305,7 +326,9 @@ private void LoadStatus(CancellationToken cancellationToken)
var handles = files
.AsParallel()
.WithCancellation(cancellationToken)
- .Select(HandleExtractor.ExtractStatusHandles);
+ .Select(HandleExtractor.ExtractStatusHandles)
+ .Where(x => x != null)
+ .Select(x => ((IEnumerable, IEnumerable))x!);
StatusNameHandles = handles.SelectMany(x => x.Item1).ToHashSet();
StatusDescriptionHandles = handles.SelectMany(x => x.Item2).ToHashSet();
@@ -321,7 +344,7 @@ private void LoadStatus(CancellationToken cancellationToken)
private void LoadHints(CancellationToken cancellationToken)
{
var props = Properties.Settings.Default;
- if (!props.MergeHints || HintsHandles != null)
+ if (MainWindow.CacheValid && !props.MergeHints || HintsHandles != null)
return;
LogLoading(Strings.Hints);
@@ -336,7 +359,9 @@ private void LoadHints(CancellationToken cancellationToken)
HintsHandles = files
.AsParallel()
.WithCancellation(cancellationToken)
- .SelectMany(HandleExtractor.ExtractHintHandles)
+ .Select(HandleExtractor.ExtractHintHandles)
+ .Where(x => x != null)
+ .SelectMany(x => x!)
.ToHashSet();
sw.Stop();
@@ -346,7 +371,7 @@ private void LoadHints(CancellationToken cancellationToken)
private void LoadTooltips(CancellationToken cancellationToken)
{
var props = Properties.Settings.Default;
- if (!props.MergeTooltips || TooltipHandles != null)
+ if (MainWindow.CacheValid && !props.MergeTooltips || TooltipHandles != null)
return;
LogLoading(Strings.Tooltips);
@@ -361,7 +386,9 @@ private void LoadTooltips(CancellationToken cancellationToken)
TooltipHandles = files
.AsParallel()
.WithCancellation(cancellationToken)
- .SelectMany(HandleExtractor.ExtractTooltipHandles)
+ .Select(HandleExtractor.ExtractTooltipHandles)
+ .Where(x => x != null)
+ .SelectMany(x => x!)
.ToHashSet();
sw.Stop();
@@ -371,7 +398,7 @@ private void LoadTooltips(CancellationToken cancellationToken)
private void LoadBooks(CancellationToken cancellationToken)
{
var props = Properties.Settings.Default;
- if (!props.MergeBooks || BookHandles != null)
+ if (MainWindow.CacheValid && !props.MergeBooks || BookHandles != null)
return;
LogLoading(Strings.Books);
@@ -392,7 +419,9 @@ private void LoadBooks(CancellationToken cancellationToken)
BookHandles = files
.AsParallel()
.WithCancellation(cancellationToken)
- .SelectMany(HandleExtractor.ExtractBookHandles)
+ .Select(HandleExtractor.ExtractBookHandles)
+ .Where(x => x != null)
+ .SelectMany(x => x!)
.ToHashSet();
sw.Stop();
@@ -402,8 +431,8 @@ private void LoadBooks(CancellationToken cancellationToken)
private void LoadItems(CancellationToken cancellationToken)
{
var props = Properties.Settings.Default;
- if (
- (!props.MergeItemNames || ItemNameHandles != null)
+ if (MainWindow.CacheValid
+ && (!props.MergeItemNames || ItemNameHandles != null)
&& (!props.MergeItemDescriptions || ItemDescriptionHandles != null)
)
return;
@@ -456,7 +485,9 @@ private void LoadItems(CancellationToken cancellationToken)
.Concat(levelMergedFiles)
.AsParallel()
.WithCancellation(cancellationToken)
- .Select(HandleExtractor.ExtractItemGroup);
+ .Select(HandleExtractor.ExtractItemGroup)
+ .Where(x => x != null)
+ .Select(x => x!);
ItemNameHandles = groups
.SelectMany(x => x.Where(x => x.Name == "Name").Select(x => x.Value))
@@ -466,6 +497,7 @@ private void LoadItems(CancellationToken cancellationToken)
.ToHashSet();
sw.Stop();
+
LogLoaded(
ItemNameHandles?.Count ?? ItemDescriptionHandles!.Count,
Strings.Items,
@@ -476,7 +508,7 @@ private void LoadItems(CancellationToken cancellationToken)
private void LoadDialogues(CancellationToken cancellationToken)
{
var props = Properties.Settings.Default;
- if (!props.MergeDialogues || Dialogs != null)
+ if (MainWindow.CacheValid && !props.MergeDialogues || Dialogs != null)
return;
LogLoading(Strings.Dialogues);
@@ -500,41 +532,55 @@ private void LoadDialogues(CancellationToken cancellationToken)
.WithCancellation(cancellationToken)
.Select(lsx =>
{
- XmlReader reader = XmlReader.Create(
- lsx,
- new XmlReaderSettings { IgnoreWhitespace = true }
- );
- if (!reader.ReadToFollowing("save") || !reader.ReadToDescendant("region"))
- throw new InvalidOperationException();
- while (reader.GetAttribute("id") != "dialog")
- reader.Skip();
- if (!reader.ReadToDescendant("children"))
- throw new InvalidOperationException();
- reader = reader.ReadSubtree();
- if (!reader.ReadToDescendant("node"))
- throw new InvalidOperationException();
- do
+ XmlReader? reader = null;
+ try
{
- if (reader.NodeType != XmlNodeType.Element || reader.IsEmptyElement)
+ reader = XmlReader.Create(
+ lsx,
+ new XmlReaderSettings { IgnoreWhitespace = true }
+ );
+ if (!reader.ReadToFollowing("save") || !reader.ReadToDescendant("region"))
+ throw new InvalidOperationException();
+ while (reader.GetAttribute("id") != "dialog")
+ reader.Skip();
+ if (!reader.ReadToDescendant("children"))
+ throw new InvalidOperationException();
+ reader = reader.ReadSubtree();
+ if (!reader.ReadToDescendant("node"))
+ throw new InvalidOperationException();
+ do
{
- reader.Read();
- continue;
- }
- Debug.Assert(reader.Name == "node");
- string? id = reader.GetAttribute("id");
- switch (id)
- {
- case "nodes":
- var dialogs = ParseDialogs(reader.ReadSubtree());
- return dialogs;
- default:
- reader.Skip();
- break;
- }
- } while (reader.NodeType == XmlNodeType.Element || reader.Read());
- throw new InvalidOperationException();
+ if (reader.NodeType != XmlNodeType.Element || reader.IsEmptyElement)
+ {
+ reader.Read();
+ continue;
+ }
+ Debug.Assert(reader.Name == "node");
+ string? id = reader.GetAttribute("id");
+ switch (id)
+ {
+ case "nodes":
+ var dialogs = ParseDialogs(reader.ReadSubtree()).ToArray();
+ return dialogs;
+ default:
+ reader.Skip();
+ break;
+ }
+ } while (reader.NodeType == XmlNodeType.Element || reader.Read());
+ throw new InvalidOperationException();
+ }
+ catch (Exception e)
+ {
+ MainWindow.LogFileError(lsx, e);
+ return null;
+ }
+ finally
+ {
+ reader?.Close();
+ }
})
- .SelectMany(x => x)
+ .Where(x => x != null)
+ .SelectMany(x => x!)
.GroupBy(x => x.Id)
.Select(x => x.Last())
.ToDictionary(x => x.Id);
@@ -656,7 +702,7 @@ public async Task Save(CancellationToken cancellationToken)
try
{
cancellationToken.ThrowIfCancellationRequested();
- packager.CreatePackage(exportPath, _dir, options);
+ await packager.CreatePackage(exportPath, _dir, options);
break;
}
catch (IOException)
diff --git a/Resources/Strings/Strings.Designer.cs b/Resources/Strings/Strings.Designer.cs
index 88bbc81..8949434 100644
--- a/Resources/Strings/Strings.Designer.cs
+++ b/Resources/Strings/Strings.Designer.cs
@@ -507,6 +507,15 @@ public static string UnpackedData {
}
}
+ ///
+ /// Looks up a localized string similar to Using cached data from the previous merge. (To discard the cache, please relaunch the program.).
+ ///
+ public static string UsingCache {
+ get {
+ return ResourceManager.GetString("UsingCache", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Waypoints.
///
diff --git a/Resources/Strings/Strings.resx b/Resources/Strings/Strings.resx
index b454a56..0e498bc 100644
--- a/Resources/Strings/Strings.resx
+++ b/Resources/Strings/Strings.resx
@@ -256,4 +256,7 @@ Retry?
Total elapsed: {0:0.##}s
+
+ Using cached data from the previous merge. (To discard the cache, please relaunch the program.)
+
\ No newline at end of file
diff --git a/Resources/Strings/Strings.zh-Hant.resx b/Resources/Strings/Strings.zh-Hant.resx
index 69ce265..f8d9de2 100644
--- a/Resources/Strings/Strings.zh-Hant.resx
+++ b/Resources/Strings/Strings.zh-Hant.resx
@@ -256,4 +256,7 @@
總共耗時:{0:0.##}秒
+
+ 正在使用上次合併的暫存資料。(若要捨棄暫存資料,請重啟本程式)
+
\ No newline at end of file