Skip to content

Commit 3bf7ab0

Browse files
mburbeaamirburbea
andauthored
Prep for 4x. (#107)
* Updated help message. Looks a bit odd. * Add method to read dotnet runtime version from registry, or return null if not found. * simpler * Add comment explaining odd step. * Move check for dotnet * boom * Switch to a mdxaml so that net5 won't get compatibility warnings. * Switch to Kpressier.Ui.TaskDialog * Checkback in the footer. * Switch to new way to handle process starts. * Ensure add/remove works even when filted * Use pattern matching * Pattern matching changes * cleanup Co-authored-by: Amir Burbea <amir.burbea@gmail.com>
1 parent 784264c commit 3bf7ab0

13 files changed

+216
-156
lines changed

KoAR.Core/GameSave.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public GameSave(string fileName)
3333
IsRemaster = BitConverter.ToInt32(Bytes, 8) == 0;
3434
SaveType = IsRemaster switch
3535
{
36-
true when Path.GetExtension(fileName) is "" && Bytes.Length != 4_462_592 => SaveType.Switch,
36+
true when Path.GetExtension(fileName) is "" => SaveType.Switch,
3737
true => SaveType.Remaster,
3838
false => SaveType.Original,
3939
};
@@ -151,11 +151,10 @@ static int GetBagOffset(ReadOnlySpan<byte> data)
151151
private void FindEquippedItems(int playerActor)
152152
{
153153
var data = Body.AsSpan();
154-
ReadOnlySpan<byte> signature = new byte[9] { 0x0B, 0x00, 0x00, 0x00, 0x41, 0xF5, 0x7E, 0x00, (byte)(SaveType == SaveType.Switch ? 0x05 : 0x04) };
155-
Span<byte> temp = stackalloc byte[13];
154+
Span<byte> temp = stackalloc byte[12];
156155
MemoryUtilities.Write(temp, 0, playerActor);
157-
signature.CopyTo(temp[4..]);
158-
int offset = data.IndexOf(MemoryMarshal.AsBytes(temp));
156+
MemoryUtilities.Write(temp, 4, 0x00_7E_F5_41_00_00_00_0Bul);
157+
int offset = data.IndexOf(temp);
159158
int dataLength = MemoryUtilities.Read<int>(data, offset + 13);
160159
// 17 is the loot table
161160
// 21 is the count of items in the inventory.

KoAR.SaveEditor/App.xaml.cs

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
using System.Windows.Threading;
77
using KoAR.SaveEditor.Properties;
88
using Microsoft.Windows.Themes;
9-
using TaskDialogInterop;
9+
using KPreisser.UI;
1010

1111
namespace KoAR.SaveEditor
1212
{
@@ -19,19 +19,26 @@ partial class App
1919
public static void ShowExceptionDialog(string mainInstruction, Exception exception)
2020
{
2121
string content = $"{exception.GetType().FullName}: {exception.Message}";
22-
TaskDialogResult dialogResult = TaskDialog.Show(new()
22+
TaskDialog dialog = new(new()
2323
{
2424
Title = "KoAR Save Editor",
25-
MainInstruction = mainInstruction,
26-
Content = content,
27-
ExpandedInfo = exception.StackTrace,
28-
VerificationText = "Open GitHub bug report? (requires free account)",
29-
MainIcon = VistaTaskDialogIcon.Error,
25+
Instruction = mainInstruction,
26+
Text = content,
27+
Expander = {
28+
Text = exception.StackTrace,
29+
ExpandFooterArea = true,
30+
},
31+
CheckBox = new("Open GitHub bug report? (requires free account)"),
32+
Icon = TaskDialogStandardIcon.Error,
3033
});
31-
if (dialogResult.VerificationChecked == true)
34+
dialog.Show();
35+
if (dialog.Page.CheckBox.Checked)
3236
{
33-
string title = $"{content} (in v{App.Version})";
34-
Process.Start($"https://github.com/mburbea/koar-item-editor/issues/new?labels=bug&template=bug_report.md&title={WebUtility.UrlEncode(title)}");
37+
string title = $"{content} (in v{App.Version})";
38+
Process.Start(new ProcessStartInfo($"https://github.com/mburbea/koar-item-editor/issues/new?labels=bug&template=bug_report.md&title={WebUtility.UrlEncode(title)}")
39+
{
40+
UseShellExecute = true
41+
})?.Dispose();
3542
}
3643
}
3744

KoAR.SaveEditor/Constructs/DataContainer.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using System;
22
using System.Collections;
3-
using System.Diagnostics.CodeAnalysis;
43
using System.Globalization;
54
using System.Linq;
65
using System.Windows.Data;
@@ -38,11 +37,13 @@ int IComparable.CompareTo(object obj)
3837

3938
private sealed class DataContainerCollectionConverter : IValueConverter
4039
{
41-
[SuppressMessage("Style", "IDE0039:Use local function", Justification = "Prevent a delegate creation on each usage.")]
40+
private static readonly Func<object, DataContainer> _getContainer = value => value is DataContainer container ? container : new(value);
41+
4242
object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
4343
{
44-
Func<object, DataContainer> getContainer = value => value is DataContainer container ? container : new(value);
45-
return value is IEnumerable collection ? collection.Cast<object>().Select(getContainer).ToArray() : new[] { getContainer(value) };
44+
return value is IEnumerable collection
45+
? collection.Cast<object>().Select(DataContainerCollectionConverter._getContainer).ToArray()
46+
: new[] { DataContainerCollectionConverter._getContainer(value) };
4647
}
4748

4849
object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotImplementedException();

KoAR.SaveEditor/Constructs/ScrollingTabControl.cs

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,7 @@ private void LeftButton_Click(object sender, RoutedEventArgs e)
9292
return;
9393
}
9494
double offset = Math.Max(this._scrollViewer.HorizontalOffset - 2d, 0d);
95-
TabItem? tabItem = this.GetItemByOffset(offset);
96-
if (tabItem != null)
95+
if (this.GetItemByOffset(offset) is TabItem tabItem)
9796
{
9897
this.ScrollToItem(tabItem);
9998
}
@@ -106,8 +105,7 @@ private void RightButton_Click(object sender, RoutedEventArgs e)
106105
return;
107106
}
108107
double offset = Math.Min(this._scrollViewer.HorizontalOffset + this._scrollViewer.ViewportWidth + 2d, this._scrollViewer.ExtentWidth);
109-
TabItem? tabItem = this.GetItemByOffset(offset);
110-
if (tabItem != null)
108+
if (this.GetItemByOffset(offset) is TabItem tabItem)
111109
{
112110
this.ScrollToItem(tabItem);
113111
}
@@ -132,16 +130,17 @@ private void ScrollToItem(TabItem item)
132130

133131
private void ScrollToSelectedItem()
134132
{
135-
if (this._scrollViewer != null && this.ItemContainerGenerator.ContainerFromItem(this.SelectedItem) is TabItem tabItem)
133+
if (this._scrollViewer == null || this.ItemContainerGenerator.ContainerFromItem(this.SelectedItem) is not TabItem tabItem)
136134
{
137-
if (tabItem.IsLoaded)
138-
{
139-
this.ScrollToItem(tabItem);
140-
}
141-
else
142-
{
143-
tabItem.Loaded += this.TabItem_Loaded;
144-
}
135+
return;
136+
}
137+
if (tabItem.IsLoaded)
138+
{
139+
this.ScrollToItem(tabItem);
140+
}
141+
else
142+
{
143+
tabItem.Loaded += this.TabItem_Loaded;
145144
}
146145
}
147146

KoAR.SaveEditor/Constructs/TaskbarItemInfoOverlay.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,7 @@ private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChan
5353
{
5454
return;
5555
}
56-
object? content = TaskbarItemInfoOverlay.GetContent(info);
57-
if (content == null)
56+
if (TaskbarItemInfoOverlay.GetContent(info) is not object content)
5857
{
5958
info.Overlay = null;
6059
return;

KoAR.SaveEditor/Constructs/ValidatingPropertyBehavior.cs

Lines changed: 3 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -13,75 +13,44 @@ namespace KoAR.SaveEditor.Constructs
1313
/// </summary>
1414
public static class ValidatingPropertyBehavior
1515
{
16-
/// <summary>
17-
/// Defines the ValidatingProperty dependency property.
18-
/// </summary>
1916
public static readonly DependencyProperty ValidatingPropertyProperty = DependencyProperty.RegisterAttached("ValidatingProperty", typeof(DependencyProperty), typeof(ValidatingPropertyBehavior),
2017
new(ValidatingPropertyBehavior.ValidatingPropertyProperty_PropertyChanged));
2118

22-
/// <summary>
23-
/// Gets the validating dependency property for a dependency object.
24-
/// </summary>
25-
/// <param name="dependencyObject">The dependency object.</param>
26-
/// <returns>Dependency property.</returns>
2719
public static DependencyProperty? GetValidatingProperty(DependencyObject dependencyObject)
2820
{
2921
return (DependencyProperty?)dependencyObject?.GetValue(ValidatingPropertyBehavior.ValidatingPropertyProperty);
3022
}
3123

32-
/// <summary>
33-
/// Sets the validating dependency property for a dependency object.
34-
/// </summary>
35-
/// <param name="dependencyObject">The dependency object.</param>
36-
/// <param name="property">The dependency property.</param>
3724
public static void SetValidatingProperty(DependencyObject dependencyObject, DependencyProperty? property)
3825
{
3926
dependencyObject?.SetValue(ValidatingPropertyBehavior.ValidatingPropertyProperty, property);
4027
}
4128

42-
/// <summary>
43-
/// Called when the value of a validating property changes.
44-
/// </summary>
45-
/// <param name="sender">The source of the event.</param>
46-
/// <param name="e">Event arguments.</param>
4729
private static void DependencyProperty_ValueChanged(object sender, EventArgs e)
4830
{
4931
DependencyObject dependencyObject = (DependencyObject)sender;
50-
DependencyProperty? property = ValidatingPropertyBehavior.GetValidatingProperty(dependencyObject);
51-
if (property != null)
32+
if (ValidatingPropertyBehavior.GetValidatingProperty(dependencyObject) is DependencyProperty property)
5233
{
5334
dependencyObject.Validate(property);
5435
}
5536
}
5637

57-
/// <summary>
58-
/// Validate a value against a collection of validation rules.
59-
/// </summary>
60-
/// <param name="value">The value to validate.</param>
61-
/// <param name="validationRules">The validation rules collection.</param>
62-
/// <param name="bindingExpression">The binding expression.</param>
6338
private static void Validate(object value, IEnumerable<ValidationRule>? validationRules, BindingExpressionBase bindingExpression)
6439
{
6540
if (validationRules != null)
6641
{
6742
foreach (ValidationRule rule in validationRules)
6843
{
69-
ValidationResult result = rule.Validate(value, CultureInfo.InvariantCulture);
70-
if (!result.IsValid)
44+
if (rule.Validate(value, null) is { IsValid: false, ErrorContent: object errorContent })
7145
{
72-
Validation.MarkInvalid(bindingExpression, new(rule, bindingExpression.ParentBindingBase, result.ErrorContent, null));
46+
Validation.MarkInvalid(bindingExpression, new(rule, bindingExpression.ParentBindingBase, errorContent, null));
7347
return;
7448
}
7549
}
7650
}
7751
Validation.ClearInvalid(bindingExpression);
7852
}
7953

80-
/// <summary>
81-
/// Validate that a value of a dependency object/property combination does not violate any binding validation rules.
82-
/// </summary>
83-
/// <param name="dependencyObject">The dependency object.</param>
84-
/// <param name="dependencyProperty">The dependency property.</param>
8554
private static void Validate(this DependencyObject dependencyObject, DependencyProperty dependencyProperty)
8655
{
8756
BindingExpressionBase bindingExpression = BindingOperations.GetBindingExpressionBase(dependencyObject, dependencyProperty);
@@ -101,11 +70,6 @@ private static void Validate(this DependencyObject dependencyObject, DependencyP
10170
}
10271
}
10372

104-
/// <summary>
105-
/// Called when the value of the ValidatingProperty dependency property changes.
106-
/// </summary>
107-
/// <param name="d">The source of the event.</param>
108-
/// <param name="e">Event arguments.</param>
10973
private static void ValidatingPropertyProperty_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
11074
{
11175
if (e.OldValue != null)

KoAR.SaveEditor/KoAR.SaveEditor.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -208,8 +208,8 @@
208208
</None>
209209
</ItemGroup>
210210
<ItemGroup>
211-
<PackageReference Include="Markdown.Xaml" Version="1.0.0" />
212-
<PackageReference Include="WPFTaskDialog" Version="1.7.1" />
211+
<PackageReference Include="KPreisser.UI.TaskDialog" Version="1.0.0" />
212+
<PackageReference Include="MdXaml_migfree" Version="1.9.0" />
213213
</ItemGroup>
214214
<ItemGroup>
215215
<ProjectReference Include="..\KoAR.Core\KoAR.Core.csproj" />

KoAR.SaveEditor/Updates/UpdateMethods.cs

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Diagnostics;
4+
using System.Globalization;
45
using System.IO;
56
using System.Linq;
67
using System.Net;
@@ -11,6 +12,7 @@
1112
using System.Threading.Tasks;
1213
using System.Windows;
1314
using KoAR.Core;
15+
using Microsoft.Win32;
1416

1517
namespace KoAR.SaveEditor.Updates
1618
{
@@ -19,6 +21,18 @@ public static class UpdateMethods
1921
private static readonly Lazy<string?> _credentials = new(UpdateMethods.LoadCredentials);
2022
private static readonly JsonSerializerOptions _jsonOptions = new() { PropertyNamingPolicy = JsonSnakeCaseNamingPolicy.Instance };
2123

24+
public static bool CheckForNet5()
25+
{
26+
string arch = Environment.Is64BitProcess ? "x64" : "x86";
27+
using RegistryKey baseKey = Registry.LocalMachine.OpenSubKey($@"SOFTWARE\dotnet\Setup\InstalledVersions\{arch}\sharedhost");
28+
// Check for version string with extra info not applicable to
29+
// a version number and strip it out (6.0.0-preview.2.21154.6)
30+
return baseKey?.GetValue("Version") is string { Length: > 0 } value &&
31+
value.IndexOf('.') is int index and > -1 &&
32+
int.TryParse(value[..index], NumberStyles.Integer, CultureInfo.InvariantCulture, out int major) &&
33+
major >= 5;
34+
}
35+
2236
/// <summary>
2337
/// Given the path to a zip file containing an update, executes the update process.
2438
/// </summary>
@@ -36,22 +50,22 @@ public static async void ExecuteUpdate(string zipFilePath)
3650
}
3751

3852
/// <summary>
39-
/// Fetches the latest 2.x release.
53+
/// Fetches the latest release with the specified <paramref name="majorVersion"/>.
4054
/// </summary>
55+
/// <param name="majorVersion">The major version of the release.</param>
4156
/// <param name="cancellationToken">Optionally used to propagate cancellation requests.</param>
4257
/// <returns>Information related to a release. Returns <see langword="null"/> if not found or an error occurs.</returns>
43-
public static async Task<IReleaseInfo?> FetchLatest2xReleaseAsync(CancellationToken cancellationToken = default)
58+
public static async Task<IReleaseInfo?> FetchLatestVersionedRelease(int majorVersion, CancellationToken cancellationToken = default)
4459
{
4560
try
4661
{
4762
foreach (Tag tag in await UpdateMethods.FetchTagsAsync(cancellationToken).ConfigureAwait(false))
4863
{
49-
if (tag.Version.Major != 2)
64+
if (tag.Version.Major != majorVersion)
5065
{
5166
continue;
5267
}
53-
Release? release = await UpdateMethods.FetchReleaseAsync(tag.Name, cancellationToken).ConfigureAwait(false);
54-
if (release != null && release.HasUpdateAsset)
68+
if (await UpdateMethods.FetchReleaseAsync(tag.Name, cancellationToken).ConfigureAwait(false) is { HasUpdateAsset: true } release)
5569
{
5670
return release;
5771
}
@@ -63,6 +77,14 @@ public static async void ExecuteUpdate(string zipFilePath)
6377
return default;
6478
}
6579

80+
/// <summary>
81+
/// Fetches the latest 2.x release.
82+
/// </summary>
83+
/// <param name="cancellationToken">Optionally used to propagate cancellation requests.</param>
84+
/// <returns>Information related to a release. Returns <see langword="null"/> if not found or an error occurs.</returns>
85+
public static Task<IReleaseInfo?> FetchLatest2xReleaseAsync(CancellationToken cancellationToken = default) =>
86+
UpdateMethods.FetchLatestVersionedRelease(2, cancellationToken);
87+
6688
/// <summary>
6789
/// Fetches an array of the interim update releases for the current major version of the application to the latest.
6890
/// Only checks up to <paramref name="maxReleases"/> number of tags/releases.

KoAR.SaveEditor/Views/ItemDefinitionControl.cs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -65,17 +65,15 @@ private static void Definition_ValueChanged(DependencyObject d, DependencyProper
6565
private static void ItemProperty_ValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
6666
{
6767
ItemDefinitionControl control = (ItemDefinitionControl)d;
68-
if (e.OldValue != null)
68+
if (e.OldValue is ItemModelBase oldItem)
6969
{
70-
ItemModelBase oldItem = (ItemModelBase)e.OldValue;
7170
PropertyChangedEventManager.RemoveHandler(oldItem, control.Item_DefinitionChanged, nameof(oldItem.Definition));
7271
}
73-
ItemModelBase? item = (ItemModelBase)e.NewValue;
74-
if (item != null)
72+
if (e.NewValue is ItemModelBase newItem)
7573
{
76-
control.Definition = item.Definition;
77-
PropertyChangedEventManager.AddHandler(item, control.Item_DefinitionChanged, nameof(item.Definition));
78-
control.Sockets = item.Item.GetSockets();
74+
control.Definition = newItem.Definition;
75+
PropertyChangedEventManager.AddHandler(newItem, control.Item_DefinitionChanged, nameof(newItem.Definition));
76+
control.Sockets = newItem.Item.GetSockets();
7977
}
8078
else
8179
{

KoAR.SaveEditor/Views/Main/MainWindow.xaml.cs

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using System;
22
using System.Windows.Input;
33
using KoAR.SaveEditor.Properties;
4-
using TaskDialogInterop;
54

65
namespace KoAR.SaveEditor.Views.Main
76
{
@@ -27,20 +26,7 @@ protected override void OnPreviewKeyDown(KeyEventArgs e)
2726
base.OnPreviewKeyDown(e);
2827
}
2928

30-
private void Help_Executed(object sender, ExecutedRoutedEventArgs e) => TaskDialog.Show(new()
31-
{
32-
Owner = this,
33-
Title = $"KoAR Save Editor",
34-
MainInstruction = "Help",
35-
MainIcon = VistaTaskDialogIcon.Information,
36-
CommonButtons = TaskDialogCommonButtons.Close,
37-
Content = @"1. Your saves are usually not in the same folder as the game. The editor attemps to make
38-
educated guesses as to the save file directory.
39-
40-
2. When modifying item names, do NOT use special characters.
41-
42-
3. Editing equipped items may cause your file to not load."
43-
});
29+
private void Help_Executed(object sender, ExecutedRoutedEventArgs e) => this.ViewModel.ShowHelp();
4430

4531
private void Open_Executed(object sender, ExecutedRoutedEventArgs e) => this.ViewModel.OpenFile();
4632

0 commit comments

Comments
 (0)