Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/TrackerCouncil.Smz3.Data/Options/GeneralOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ public class GeneralOptions : INotifyPropertyChanged
private string? _twitchChannel;
private string? _twitchId;

public bool HasOpenedSetupWindow { get; set; }

public string? Z3RomPath { get; set; }

public string? SMRomPath { get; set; }
Expand Down
18 changes: 18 additions & 0 deletions src/TrackerCouncil.Smz3.Data/Options/RandomizerOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ public static RandomizerOptions Load(string loadPath, string savePath, bool isYa
var options = serializer.Deserialize<RandomizerOptions>(fileText);
options.FilePath = savePath;

var settingsUpdated = false;

// Update from AutoTracker connector settings to SnesConnector settings
if (options.GeneralOptions.AutoTrackerDefaultConnectionType != EmulatorConnectorType.None)
{
Expand All @@ -108,6 +110,7 @@ public static RandomizerOptions Load(string loadPath, string savePath, bool isYa
options.GeneralOptions.SnesConnectorSettings.Usb2SnesAddress =
options.GeneralOptions.AutoTrackerQUsb2SnesIp ?? "";
options.GeneralOptions.AutoTrackerDefaultConnectionType = EmulatorConnectorType.None;
settingsUpdated = true;
}

if (options.GeneralOptions.MsuTrackDisplayStyle != null)
Expand All @@ -122,6 +125,7 @@ public static RandomizerOptions Load(string loadPath, string savePath, bool isYa
_ => TrackDisplayFormat.Vertical
};
options.GeneralOptions.MsuTrackDisplayStyle = null;
settingsUpdated = true;
}

// Update AutoTrackerChangeMap to AutoMapUpdateBehavior
Expand All @@ -130,13 +134,27 @@ public static RandomizerOptions Load(string loadPath, string savePath, bool isYa
options.GeneralOptions.AutoMapUpdateBehavior = options.GeneralOptions.AutoTrackerChangeMap
? AutoMapUpdateBehavior.UpdateOnRegionChange
: AutoMapUpdateBehavior.Disabled;
settingsUpdated = true;
}

// Remove deprecated config profiles
if (options.GeneralOptions.SelectedProfiles.Any(p => p != null && ConfigProvider.DeprecatedConfigProfiles.Contains(p)))
{
options.GeneralOptions.SelectedProfiles = options.GeneralOptions.SelectedProfiles
.Where(p => p != null && !ConfigProvider.DeprecatedConfigProfiles.Contains(p)).ToList();
settingsUpdated = true;
}

// Update HasOpenedSetupWindow if the Z3 rom path is populated
if (!options.GeneralOptions.HasOpenedSetupWindow && !string.IsNullOrEmpty(options.GeneralOptions.Z3RomPath))
{
options.GeneralOptions.HasOpenedSetupWindow = true;
settingsUpdated = true;
}

if (settingsUpdated)
{
options.Save();
}

return options;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
<PackageReference Include="Avalonia" Version="11.0.11" />
<PackageReference Include="MattEqualsCoder.DynamicForms.Core" Version="1.0.1" />
<PackageReference Include="MattEqualsCoder.GitHubReleaseChecker" Version="1.1.2" />
<PackageReference Include="MattEqualsCoder.MSURandomizer.Library" Version="3.0.0-rc.5" />
<PackageReference Include="MattEqualsCoder.MSURandomizer.Library" Version="3.0.1" />
<PackageReference Include="NAudio.Wasapi" Version="2.2.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="YamlDotNet" Version="16.1.3" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="MattEqualsCoder.MSURandomizer.Library" Version="3.0.0-rc.5" />
<PackageReference Include="MattEqualsCoder.MSURandomizer.Library" Version="3.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.1" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="MattEqualsCoder.MSURandomizer.Library" Version="3.0.0-rc.5" />
<PackageReference Include="MattEqualsCoder.MSURandomizer.Library" Version="3.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.10">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

<ItemGroup>
<PackageReference Include="BunLabs.Common" Version="1.0.4" />
<PackageReference Include="MattEqualsCoder.MSURandomizer.Library" Version="3.0.0-rc.5" />
<PackageReference Include="MattEqualsCoder.MSURandomizer.Library" Version="3.0.1" />
<PackageReference Include="NAudio.Wasapi" Version="2.2.1" />
<PackageReference Include="SharpHook" Version="5.3.8" />
<PackageReference Include="System.Speech" Version="8.0.0" />
Expand Down
Binary file added src/TrackerCouncil.Smz3.UI/Assets/Tracker.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/TrackerCouncil.Smz3.UI/Services/MainWindowService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public MainWindowViewModel InitializeModel(MainWindow window)
{
_window = window;
_options = optionsFactory.Create();
_model.HasInvalidOptions = !_options.GeneralOptions.Validate();
_model.OpenSetupWindow = !_options.GeneralOptions.HasOpenedSetupWindow;
ITaskService.Run(CheckForUpdates);
return _model;
}
Expand Down
264 changes: 264 additions & 0 deletions src/TrackerCouncil.Smz3.UI/Services/SetupWindowService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;
using Avalonia.Media;
using AvaloniaControls;
using AvaloniaControls.ControlServices;
using Material.Icons;
using SnesConnectorLibrary;
using SnesConnectorLibrary.Requests;
using SNI;
using TrackerCouncil.Smz3.Data.Options;
using TrackerCouncil.Smz3.Shared.Enums;
using TrackerCouncil.Smz3.UI.ViewModels;

namespace TrackerCouncil.Smz3.UI.Services;

public class SetupWindowService(OptionsFactory optionsFactory, ISnesConnectorService snesConnectorService) : ControlService
{
private const string Z3Hash = "03a63945398191337e896e5771f77173";
private const string SMHash = "21f3e98df4780ee1c667b84e57d88675";

private SetupWindowViewModel _model = new();
private RandomizerOptions _randomizerOptions = null!;
private CancellationTokenSource _cancellationTokenSource = new();

public SetupWindowViewModel GetViewModel()
{
snesConnectorService.GameDetected += SnesConnectorServiceOnConnected;
_randomizerOptions = optionsFactory.Create();
SetZeldaRomPath(_randomizerOptions.GeneralOptions.Z3RomPath);
SetMetroidRomPath(_randomizerOptions.GeneralOptions.SMRomPath);
_randomizerOptions.GeneralOptions.HasOpenedSetupWindow = true;
_randomizerOptions.Save();
snesConnectorService.CreateLuaScriptsFolder(_randomizerOptions.AutoTrackerScriptsOutputPath);
return _model;
}

public bool SetRomPaths(IEnumerable<string> romPaths)
{
var anyInvalidRom = false;

foreach (var path in romPaths)
{
if (CheckFileHash(path, Z3Hash))
{
_model.ZeldaRomPath = path;
_model.IsValidZeldaRom = true;
}
else if (CheckFileHash(path, SMHash))
{
_model.MetroidRomPath = path;
_model.IsValidMetroidRom = true;
}
else
{
anyInvalidRom = true;
}
}

return !anyInvalidRom;
}

public async Task TestAutoTracking()
{
if (_model.IsConnecting)
{
return;
}

_model.IsConnecting = true;
_cancellationTokenSource = new CancellationTokenSource();
_model.AutoTrackerOpacity = 0.2f;
_model.AutoTrackerIconKind = MaterialIconKind.CircleOutline;
_model.AutoTrackerBrush = Brushes.White;
_model.AutoTrackerMessage = "Connecting...";

snesConnectorService.Connect(GetSnesConnectorSettings());

try
{
await Task.Delay(TimeSpan.FromSeconds(20), _cancellationTokenSource.Token);

// If the task wasn't cancelled, then it didn't connect at all fully
_model.AutoTrackerOpacity = 1;
_model.AutoTrackerIconKind = MaterialIconKind.CloseCircleOutline;
_model.AutoTrackerBrush = Brushes.IndianRed;
_model.AutoTrackerMessage = "Unable to connect";
await _cancellationTokenSource.CancelAsync();
}
catch
{
// Do nothing
}

_model.IsConnecting = false;
snesConnectorService.Disconnect();
}

public void SaveSettings()
{
if (_model.IsValidZeldaRom)
{
_randomizerOptions.GeneralOptions.Z3RomPath = _model.ZeldaRomPath;
}

if (_model.IsValidMetroidRom)
{
_randomizerOptions.GeneralOptions.SMRomPath = _model.MetroidRomPath;
}

_randomizerOptions.GeneralOptions.SnesConnectorSettings = GetSnesConnectorSettings();

if (!_model.TrackerVoiceEnabled)
{
_randomizerOptions.GeneralOptions.SpeechRecognitionMode = SpeechRecognitionMode.Disabled;
_randomizerOptions.GeneralOptions.TrackerVoiceFrequency = TrackerVoiceFrequency.Disabled;
}

_randomizerOptions.GeneralOptions.SelectedProfiles = GetSelectedProfiles();
_randomizerOptions.Save();
}

public void OnClose()
{
snesConnectorService.GameDetected -= SnesConnectorServiceOnConnected;
snesConnectorService.Disconnect();
}

public void OpenLuaFolder()
{
CrossPlatformTools.OpenDirectory(_randomizerOptions.AutoTrackerScriptsOutputPath);
}

private SnesConnectorSettings GetSnesConnectorSettings()
{
var snesConnectorSettings = new SnesConnectorSettings();

if (_model.AutoTrackingDisable)
{
snesConnectorSettings.ConnectorType = SnesConnectorType.None;
}
else if (_model.AutoTrackingLua)
{
snesConnectorSettings.ConnectorType = SnesConnectorType.Lua;
}
else if (_model.AutoTrackingEmoTracker)
{
snesConnectorSettings.ConnectorType = SnesConnectorType.LuaEmoTracker;
}
else if (_model.AutoTrackingUsb2Snes)
{
snesConnectorSettings.ConnectorType = SnesConnectorType.Usb2Snes;
snesConnectorSettings.Usb2SnesAddress = _model.ConnectorIpAddress;
}
else if (_model.AutoTrackingSni)
{
snesConnectorSettings.ConnectorType = SnesConnectorType.Sni;
snesConnectorSettings.SniAddress = _model.ConnectorIpAddress;
}

return snesConnectorSettings;
}

private List<string?> GetSelectedProfiles()
{
var profiles = new List<string?>();

if (_model.TrackerSassEnabled)
{
profiles.Add("Sassy");
}

if (_model.TrackerCursingEnabled)
{
profiles.Add("Rated T for Teen");
}

if (_model.TrackerBcuEnabled)
{
profiles.Add("BCU");
}

return profiles;
}

private void SetZeldaRomPath(string? path)
{
if (File.Exists(path) && CheckFileHash(path, Z3Hash))
{
_model.ZeldaRomPath = path;
_model.IsValidZeldaRom = true;
}
else
{
_model.ZeldaRomPath = "Not Selected";
_model.IsValidZeldaRom = false;
}
}

private void SetMetroidRomPath(string? path)
{
if (File.Exists(path) && CheckFileHash(path, SMHash))
{
_model.MetroidRomPath = path;
_model.IsValidMetroidRom = true;
}
else
{
_model.MetroidRomPath = "Not Selected";
_model.IsValidMetroidRom = false;
}
}

private bool CheckFileHash(string path, string expectedHash)
{
var bytes = File.ReadAllBytes(path);
var hash = MD5.HashData(bytes);
var hashString = BitConverter.ToString(hash).Replace("-", "");
return expectedHash.Equals(hashString, StringComparison.OrdinalIgnoreCase);
}

private void SnesConnectorServiceOnConnected(object? sender, EventArgs e)
{
_ = TestGetMemoryAsync();
}

private async Task TestGetMemoryAsync()
{
for (var i = 0; i < 5 && !_cancellationTokenSource.IsCancellationRequested; i++)
{
var response = await snesConnectorService.MakeMemoryRequestAsync(new SnesSingleMemoryRequest()
{
MemoryRequestType = SnesMemoryRequestType.RetrieveMemory,
SnesMemoryDomain = SnesMemoryDomain.ConsoleRAM,
AddressFormat = AddressFormat.Snes9x,
SniMemoryMapping = MemoryMapping.Unknown,
Address = 0x7e0000,
Length = 0x1
});

if (response is { Successful: true, HasData: true })
{
_model.AutoTrackerOpacity = 1;
_model.AutoTrackerIconKind = MaterialIconKind.CheckCircleOutline;
_model.AutoTrackerBrush = Brushes.Lime;
_model.AutoTrackerMessage = "Connection successful!";
break;
}
else
{
_model.AutoTrackerOpacity = 1;
_model.AutoTrackerIconKind = MaterialIconKind.CloseCircleOutline;
_model.AutoTrackerBrush = Brushes.IndianRed;
_model.AutoTrackerMessage = "Invalid response";
await Task.Delay(TimeSpan.FromSeconds(2f));
}
}

await _cancellationTokenSource.CancelAsync();
}
}
2 changes: 1 addition & 1 deletion src/TrackerCouncil.Smz3.UI/TrackerCouncil.Smz3.UI.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<PackageReference Include="Avalonia_Gif" Version="1.0.0" />
<PackageReference Include="MattEqualsCoder.AvaloniaControls" Version="1.4.3" />
<PackageReference Include="MattEqualsCoder.DynamicForms.Avalonia" Version="1.0.1" />
<PackageReference Include="MattEqualsCoder.MSURandomizer.Avalonia" Version="3.0.0-rc.5" />
<PackageReference Include="MattEqualsCoder.MSURandomizer.Avalonia" Version="3.0.1" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.2" />
<PackageReference Include="ReactiveUI.Fody" Version="19.5.41" />
<PackageReference Include="Serilog.Extensions.Hosting" Version="8.0.0" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ public MainWindowViewModel()

public string NewVersionGitHubUrl { get; set; } = "";

public bool HasInvalidOptions { get; set; }
public bool OpenSetupWindow { get; set; }
}
Loading
Loading