Skip to content

Commit cf0c61b

Browse files
Merge pull request #629 from TheTrackerCouncil/setup-window
Add initial setup window
2 parents 355705a + 9f91397 commit cf0c61b

18 files changed

+902
-26
lines changed

src/TrackerCouncil.Smz3.Data/Options/GeneralOptions.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ public class GeneralOptions : INotifyPropertyChanged
2222
private string? _twitchChannel;
2323
private string? _twitchId;
2424

25+
public bool HasOpenedSetupWindow { get; set; }
26+
2527
public string? Z3RomPath { get; set; }
2628

2729
public string? SMRomPath { get; set; }

src/TrackerCouncil.Smz3.Data/Options/RandomizerOptions.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ public static RandomizerOptions Load(string loadPath, string savePath, bool isYa
9898
var options = serializer.Deserialize<RandomizerOptions>(fileText);
9999
options.FilePath = savePath;
100100

101+
var settingsUpdated = false;
102+
101103
// Update from AutoTracker connector settings to SnesConnector settings
102104
if (options.GeneralOptions.AutoTrackerDefaultConnectionType != EmulatorConnectorType.None)
103105
{
@@ -108,6 +110,7 @@ public static RandomizerOptions Load(string loadPath, string savePath, bool isYa
108110
options.GeneralOptions.SnesConnectorSettings.Usb2SnesAddress =
109111
options.GeneralOptions.AutoTrackerQUsb2SnesIp ?? "";
110112
options.GeneralOptions.AutoTrackerDefaultConnectionType = EmulatorConnectorType.None;
113+
settingsUpdated = true;
111114
}
112115

113116
if (options.GeneralOptions.MsuTrackDisplayStyle != null)
@@ -122,6 +125,7 @@ public static RandomizerOptions Load(string loadPath, string savePath, bool isYa
122125
_ => TrackDisplayFormat.Vertical
123126
};
124127
options.GeneralOptions.MsuTrackDisplayStyle = null;
128+
settingsUpdated = true;
125129
}
126130

127131
// Update AutoTrackerChangeMap to AutoMapUpdateBehavior
@@ -130,13 +134,27 @@ public static RandomizerOptions Load(string loadPath, string savePath, bool isYa
130134
options.GeneralOptions.AutoMapUpdateBehavior = options.GeneralOptions.AutoTrackerChangeMap
131135
? AutoMapUpdateBehavior.UpdateOnRegionChange
132136
: AutoMapUpdateBehavior.Disabled;
137+
settingsUpdated = true;
133138
}
134139

135140
// Remove deprecated config profiles
136141
if (options.GeneralOptions.SelectedProfiles.Any(p => p != null && ConfigProvider.DeprecatedConfigProfiles.Contains(p)))
137142
{
138143
options.GeneralOptions.SelectedProfiles = options.GeneralOptions.SelectedProfiles
139144
.Where(p => p != null && !ConfigProvider.DeprecatedConfigProfiles.Contains(p)).ToList();
145+
settingsUpdated = true;
146+
}
147+
148+
// Update HasOpenedSetupWindow if the Z3 rom path is populated
149+
if (!options.GeneralOptions.HasOpenedSetupWindow && !string.IsNullOrEmpty(options.GeneralOptions.Z3RomPath))
150+
{
151+
options.GeneralOptions.HasOpenedSetupWindow = true;
152+
settingsUpdated = true;
153+
}
154+
155+
if (settingsUpdated)
156+
{
157+
options.Save();
140158
}
141159

142160
return options;

src/TrackerCouncil.Smz3.Data/TrackerCouncil.Smz3.Data.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
<PackageReference Include="Avalonia" Version="11.0.11" />
2626
<PackageReference Include="MattEqualsCoder.DynamicForms.Core" Version="1.0.1" />
2727
<PackageReference Include="MattEqualsCoder.GitHubReleaseChecker" Version="1.1.2" />
28-
<PackageReference Include="MattEqualsCoder.MSURandomizer.Library" Version="3.0.0-rc.5" />
28+
<PackageReference Include="MattEqualsCoder.MSURandomizer.Library" Version="3.0.1" />
2929
<PackageReference Include="NAudio.Wasapi" Version="2.2.1" />
3030
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
3131
<PackageReference Include="YamlDotNet" Version="16.1.3" />

src/TrackerCouncil.Smz3.PatchBuilder/TrackerCouncil.Smz3.PatchBuilder.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
</ItemGroup>
1414

1515
<ItemGroup>
16-
<PackageReference Include="MattEqualsCoder.MSURandomizer.Library" Version="3.0.0-rc.5" />
16+
<PackageReference Include="MattEqualsCoder.MSURandomizer.Library" Version="3.0.1" />
1717
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.1" />
1818
</ItemGroup>
1919

src/TrackerCouncil.Smz3.Shared/TrackerCouncil.Smz3.Shared.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
</PropertyGroup>
88

99
<ItemGroup>
10-
<PackageReference Include="MattEqualsCoder.MSURandomizer.Library" Version="3.0.0-rc.5" />
10+
<PackageReference Include="MattEqualsCoder.MSURandomizer.Library" Version="3.0.1" />
1111
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.10" />
1212
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.10" />
1313
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.10">

src/TrackerCouncil.Smz3.Tracking/TrackerCouncil.Smz3.Tracking.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
<ItemGroup>
1010
<PackageReference Include="BunLabs.Common" Version="1.0.4" />
11-
<PackageReference Include="MattEqualsCoder.MSURandomizer.Library" Version="3.0.0-rc.5" />
11+
<PackageReference Include="MattEqualsCoder.MSURandomizer.Library" Version="3.0.1" />
1212
<PackageReference Include="NAudio.Wasapi" Version="2.2.1" />
1313
<PackageReference Include="SharpHook" Version="5.3.8" />
1414
<PackageReference Include="System.Speech" Version="8.0.0" />
48.1 KB
Loading

src/TrackerCouncil.Smz3.UI/Services/MainWindowService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public MainWindowViewModel InitializeModel(MainWindow window)
4040
{
4141
_window = window;
4242
_options = optionsFactory.Create();
43-
_model.HasInvalidOptions = !_options.GeneralOptions.Validate();
43+
_model.OpenSetupWindow = !_options.GeneralOptions.HasOpenedSetupWindow;
4444
ITaskService.Run(CheckForUpdates);
4545
return _model;
4646
}
Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Security.Cryptography;
5+
using System.Threading;
6+
using System.Threading.Tasks;
7+
using Avalonia.Media;
8+
using AvaloniaControls;
9+
using AvaloniaControls.ControlServices;
10+
using Material.Icons;
11+
using SnesConnectorLibrary;
12+
using SnesConnectorLibrary.Requests;
13+
using SNI;
14+
using TrackerCouncil.Smz3.Data.Options;
15+
using TrackerCouncil.Smz3.Shared.Enums;
16+
using TrackerCouncil.Smz3.UI.ViewModels;
17+
18+
namespace TrackerCouncil.Smz3.UI.Services;
19+
20+
public class SetupWindowService(OptionsFactory optionsFactory, ISnesConnectorService snesConnectorService) : ControlService
21+
{
22+
private const string Z3Hash = "03a63945398191337e896e5771f77173";
23+
private const string SMHash = "21f3e98df4780ee1c667b84e57d88675";
24+
25+
private SetupWindowViewModel _model = new();
26+
private RandomizerOptions _randomizerOptions = null!;
27+
private CancellationTokenSource _cancellationTokenSource = new();
28+
29+
public SetupWindowViewModel GetViewModel()
30+
{
31+
snesConnectorService.GameDetected += SnesConnectorServiceOnConnected;
32+
_randomizerOptions = optionsFactory.Create();
33+
SetZeldaRomPath(_randomizerOptions.GeneralOptions.Z3RomPath);
34+
SetMetroidRomPath(_randomizerOptions.GeneralOptions.SMRomPath);
35+
_randomizerOptions.GeneralOptions.HasOpenedSetupWindow = true;
36+
_randomizerOptions.Save();
37+
snesConnectorService.CreateLuaScriptsFolder(_randomizerOptions.AutoTrackerScriptsOutputPath);
38+
return _model;
39+
}
40+
41+
public bool SetRomPaths(IEnumerable<string> romPaths)
42+
{
43+
var anyInvalidRom = false;
44+
45+
foreach (var path in romPaths)
46+
{
47+
if (CheckFileHash(path, Z3Hash))
48+
{
49+
_model.ZeldaRomPath = path;
50+
_model.IsValidZeldaRom = true;
51+
}
52+
else if (CheckFileHash(path, SMHash))
53+
{
54+
_model.MetroidRomPath = path;
55+
_model.IsValidMetroidRom = true;
56+
}
57+
else
58+
{
59+
anyInvalidRom = true;
60+
}
61+
}
62+
63+
return !anyInvalidRom;
64+
}
65+
66+
public async Task TestAutoTracking()
67+
{
68+
if (_model.IsConnecting)
69+
{
70+
return;
71+
}
72+
73+
_model.IsConnecting = true;
74+
_cancellationTokenSource = new CancellationTokenSource();
75+
_model.AutoTrackerOpacity = 0.2f;
76+
_model.AutoTrackerIconKind = MaterialIconKind.CircleOutline;
77+
_model.AutoTrackerBrush = Brushes.White;
78+
_model.AutoTrackerMessage = "Connecting...";
79+
80+
snesConnectorService.Connect(GetSnesConnectorSettings());
81+
82+
try
83+
{
84+
await Task.Delay(TimeSpan.FromSeconds(20), _cancellationTokenSource.Token);
85+
86+
// If the task wasn't cancelled, then it didn't connect at all fully
87+
_model.AutoTrackerOpacity = 1;
88+
_model.AutoTrackerIconKind = MaterialIconKind.CloseCircleOutline;
89+
_model.AutoTrackerBrush = Brushes.IndianRed;
90+
_model.AutoTrackerMessage = "Unable to connect";
91+
await _cancellationTokenSource.CancelAsync();
92+
}
93+
catch
94+
{
95+
// Do nothing
96+
}
97+
98+
_model.IsConnecting = false;
99+
snesConnectorService.Disconnect();
100+
}
101+
102+
public void SaveSettings()
103+
{
104+
if (_model.IsValidZeldaRom)
105+
{
106+
_randomizerOptions.GeneralOptions.Z3RomPath = _model.ZeldaRomPath;
107+
}
108+
109+
if (_model.IsValidMetroidRom)
110+
{
111+
_randomizerOptions.GeneralOptions.SMRomPath = _model.MetroidRomPath;
112+
}
113+
114+
_randomizerOptions.GeneralOptions.SnesConnectorSettings = GetSnesConnectorSettings();
115+
116+
if (!_model.TrackerVoiceEnabled)
117+
{
118+
_randomizerOptions.GeneralOptions.SpeechRecognitionMode = SpeechRecognitionMode.Disabled;
119+
_randomizerOptions.GeneralOptions.TrackerVoiceFrequency = TrackerVoiceFrequency.Disabled;
120+
}
121+
122+
_randomizerOptions.GeneralOptions.SelectedProfiles = GetSelectedProfiles();
123+
_randomizerOptions.Save();
124+
}
125+
126+
public void OnClose()
127+
{
128+
snesConnectorService.GameDetected -= SnesConnectorServiceOnConnected;
129+
snesConnectorService.Disconnect();
130+
}
131+
132+
public void OpenLuaFolder()
133+
{
134+
CrossPlatformTools.OpenDirectory(_randomizerOptions.AutoTrackerScriptsOutputPath);
135+
}
136+
137+
private SnesConnectorSettings GetSnesConnectorSettings()
138+
{
139+
var snesConnectorSettings = new SnesConnectorSettings();
140+
141+
if (_model.AutoTrackingDisable)
142+
{
143+
snesConnectorSettings.ConnectorType = SnesConnectorType.None;
144+
}
145+
else if (_model.AutoTrackingLua)
146+
{
147+
snesConnectorSettings.ConnectorType = SnesConnectorType.Lua;
148+
}
149+
else if (_model.AutoTrackingEmoTracker)
150+
{
151+
snesConnectorSettings.ConnectorType = SnesConnectorType.LuaEmoTracker;
152+
}
153+
else if (_model.AutoTrackingUsb2Snes)
154+
{
155+
snesConnectorSettings.ConnectorType = SnesConnectorType.Usb2Snes;
156+
snesConnectorSettings.Usb2SnesAddress = _model.ConnectorIpAddress;
157+
}
158+
else if (_model.AutoTrackingSni)
159+
{
160+
snesConnectorSettings.ConnectorType = SnesConnectorType.Sni;
161+
snesConnectorSettings.SniAddress = _model.ConnectorIpAddress;
162+
}
163+
164+
return snesConnectorSettings;
165+
}
166+
167+
private List<string?> GetSelectedProfiles()
168+
{
169+
var profiles = new List<string?>();
170+
171+
if (_model.TrackerSassEnabled)
172+
{
173+
profiles.Add("Sassy");
174+
}
175+
176+
if (_model.TrackerCursingEnabled)
177+
{
178+
profiles.Add("Rated T for Teen");
179+
}
180+
181+
if (_model.TrackerBcuEnabled)
182+
{
183+
profiles.Add("BCU");
184+
}
185+
186+
return profiles;
187+
}
188+
189+
private void SetZeldaRomPath(string? path)
190+
{
191+
if (File.Exists(path) && CheckFileHash(path, Z3Hash))
192+
{
193+
_model.ZeldaRomPath = path;
194+
_model.IsValidZeldaRom = true;
195+
}
196+
else
197+
{
198+
_model.ZeldaRomPath = "Not Selected";
199+
_model.IsValidZeldaRom = false;
200+
}
201+
}
202+
203+
private void SetMetroidRomPath(string? path)
204+
{
205+
if (File.Exists(path) && CheckFileHash(path, SMHash))
206+
{
207+
_model.MetroidRomPath = path;
208+
_model.IsValidMetroidRom = true;
209+
}
210+
else
211+
{
212+
_model.MetroidRomPath = "Not Selected";
213+
_model.IsValidMetroidRom = false;
214+
}
215+
}
216+
217+
private bool CheckFileHash(string path, string expectedHash)
218+
{
219+
var bytes = File.ReadAllBytes(path);
220+
var hash = MD5.HashData(bytes);
221+
var hashString = BitConverter.ToString(hash).Replace("-", "");
222+
return expectedHash.Equals(hashString, StringComparison.OrdinalIgnoreCase);
223+
}
224+
225+
private void SnesConnectorServiceOnConnected(object? sender, EventArgs e)
226+
{
227+
_ = TestGetMemoryAsync();
228+
}
229+
230+
private async Task TestGetMemoryAsync()
231+
{
232+
for (var i = 0; i < 5 && !_cancellationTokenSource.IsCancellationRequested; i++)
233+
{
234+
var response = await snesConnectorService.MakeMemoryRequestAsync(new SnesSingleMemoryRequest()
235+
{
236+
MemoryRequestType = SnesMemoryRequestType.RetrieveMemory,
237+
SnesMemoryDomain = SnesMemoryDomain.ConsoleRAM,
238+
AddressFormat = AddressFormat.Snes9x,
239+
SniMemoryMapping = MemoryMapping.Unknown,
240+
Address = 0x7e0000,
241+
Length = 0x1
242+
});
243+
244+
if (response is { Successful: true, HasData: true })
245+
{
246+
_model.AutoTrackerOpacity = 1;
247+
_model.AutoTrackerIconKind = MaterialIconKind.CheckCircleOutline;
248+
_model.AutoTrackerBrush = Brushes.Lime;
249+
_model.AutoTrackerMessage = "Connection successful!";
250+
break;
251+
}
252+
else
253+
{
254+
_model.AutoTrackerOpacity = 1;
255+
_model.AutoTrackerIconKind = MaterialIconKind.CloseCircleOutline;
256+
_model.AutoTrackerBrush = Brushes.IndianRed;
257+
_model.AutoTrackerMessage = "Invalid response";
258+
await Task.Delay(TimeSpan.FromSeconds(2f));
259+
}
260+
}
261+
262+
await _cancellationTokenSource.CancelAsync();
263+
}
264+
}

src/TrackerCouncil.Smz3.UI/TrackerCouncil.Smz3.UI.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
<PackageReference Include="Avalonia_Gif" Version="1.0.0" />
2222
<PackageReference Include="MattEqualsCoder.AvaloniaControls" Version="1.4.3" />
2323
<PackageReference Include="MattEqualsCoder.DynamicForms.Avalonia" Version="1.0.1" />
24-
<PackageReference Include="MattEqualsCoder.MSURandomizer.Avalonia" Version="3.0.0-rc.5" />
24+
<PackageReference Include="MattEqualsCoder.MSURandomizer.Avalonia" Version="3.0.1" />
2525
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.2" />
2626
<PackageReference Include="ReactiveUI.Fody" Version="19.5.41" />
2727
<PackageReference Include="Serilog.Extensions.Hosting" Version="8.0.0" />

0 commit comments

Comments
 (0)