diff --git a/src/Randomizer.App/Windows/OptionsWindow.xaml b/src/Randomizer.App/Windows/OptionsWindow.xaml
index 7eccc908e..703dbf029 100644
--- a/src/Randomizer.App/Windows/OptionsWindow.xaml
+++ b/src/Randomizer.App/Windows/OptionsWindow.xaml
@@ -7,6 +7,7 @@
xmlns:vm="clr-namespace:Randomizer.App.ViewModels"
xmlns:options="clr-namespace:Randomizer.Data.Options;assembly=Randomizer.Data"
xmlns:app="clr-namespace:Randomizer.App"
+ xmlns:enums="clr-namespace:Randomizer.Shared.Enums;assembly=Randomizer.Shared"
x:Name="Self"
ResizeMode="NoResize"
mc:Ignorable="d"
@@ -177,10 +178,9 @@
-
+
@@ -192,10 +192,9 @@
-
+
@@ -218,10 +217,9 @@
-
+
diff --git a/src/Randomizer.App/Windows/TrackerWindow.xaml.cs b/src/Randomizer.App/Windows/TrackerWindow.xaml.cs
index a6c682a3f..066f52a2d 100644
--- a/src/Randomizer.App/Windows/TrackerWindow.xaml.cs
+++ b/src/Randomizer.App/Windows/TrackerWindow.xaml.cs
@@ -1048,9 +1048,9 @@ private async void LoadSavedStateMenuItem_Click(object sender, RoutedEventArgs e
private async Task SaveStateAsync()
{
// If there is a rom, save it to the database
- if (GeneratedRom.IsValid(Rom))
+ if (GeneratedRom.IsValid(Tracker.Rom))
{
- await Tracker.SaveAsync(Rom);
+ await Tracker.SaveAsync();
}
SavedState?.Invoke(this, EventArgs.Empty);
diff --git a/src/Randomizer.CrossPlatform/ConsoleTrackerDisplayService.cs b/src/Randomizer.CrossPlatform/ConsoleTrackerDisplayService.cs
new file mode 100644
index 000000000..ee0541345
--- /dev/null
+++ b/src/Randomizer.CrossPlatform/ConsoleTrackerDisplayService.cs
@@ -0,0 +1,284 @@
+using System.Text;
+using Microsoft.Extensions.DependencyInjection;
+using Randomizer.Data.Options;
+using Randomizer.Data.WorldData;
+using Randomizer.Data.WorldData.Regions;
+using Randomizer.Shared;
+using Randomizer.Shared.Enums;
+using Randomizer.Shared.Models;
+using Randomizer.SMZ3.Generation;
+using Randomizer.SMZ3.Tracking;
+using Randomizer.SMZ3.Tracking.AutoTracking;
+using Randomizer.SMZ3.Tracking.Services;
+
+namespace Randomizer.CrossPlatform;
+
+public class ConsoleTrackerDisplayService
+{
+ private readonly System.Timers.Timer _timer;
+ private readonly Smz3GeneratedRomLoader _romLoaderService;
+ private readonly TrackerOptionsAccessor _trackerOptionsAccessor;
+ private readonly RandomizerOptions _options;
+ private readonly IServiceProvider _serviceProvider;
+ private Tracker _tracker = null!;
+ private World _world = null!;
+ private IWorldService _worldService = null!;
+ private Region _lastRegion = null!;
+
+ public ConsoleTrackerDisplayService(IServiceProvider serviceProvider, Smz3GeneratedRomLoader romLoaderService, TrackerOptionsAccessor trackerOptionsAccessor, OptionsFactory optionsFactory)
+ {
+ _romLoaderService = romLoaderService;
+ _trackerOptionsAccessor = trackerOptionsAccessor;
+ _options = optionsFactory.Create();
+ _serviceProvider = serviceProvider;
+ _timer = new System.Timers.Timer(TimeSpan.FromMilliseconds(250));
+ _timer.Elapsed += delegate { UpdateScreen(); };
+ }
+
+ public async Task StartTracking(GeneratedRom rom, string romPath)
+ {
+ _trackerOptionsAccessor.Options = _options.GeneralOptions.GetTrackerOptions();
+ _world = _romLoaderService.LoadGeneratedRom(rom).First(x => x.IsLocalWorld);
+ _worldService = _serviceProvider.GetRequiredService();
+ _tracker = _serviceProvider.GetRequiredService();
+ _tracker.Load(rom, romPath);
+ _tracker.TryStartTracking();
+ _tracker.AutoTracker?.SetConnector(_options.AutoTrackerDefaultConnector, _options.AutoTrackerQUsb2SnesIp);
+
+ if (_tracker.AutoTracker != null)
+ {
+ _tracker.AutoTracker.AutoTrackerConnected += delegate
+ {
+ UpdateScreen();
+ if (!_timer.Enabled)
+ {
+ _timer.Start();
+ }
+ };
+
+ _tracker.LocationCleared += delegate(object? _, LocationClearedEventArgs args)
+ {
+ _lastRegion = args.Location.Region;
+ };
+ }
+
+ while (true)
+ {
+ Console.ReadKey();
+ _timer.Stop();
+ Console.Clear();
+ Console.Write("Do you want to quit? (y/n) ");
+ var response = Console.ReadLine();
+
+ if ("y".Equals(response, StringComparison.OrdinalIgnoreCase))
+ {
+ await _tracker.SaveAsync();
+ break;
+ }
+
+ _timer.Start();
+ UpdateScreen();
+ }
+ }
+
+ private void UpdateScreen()
+ {
+ var columnWidth = (Console.WindowWidth-6)/2;
+
+ var topLines = GetHeaderLines(columnWidth);
+
+ var leftColumnLines = new List();
+ leftColumnLines.AddRange(GetInventoryLines(columnWidth));
+ leftColumnLines.Add("");
+ leftColumnLines.AddRange(GetDungeonLines(columnWidth));
+
+ var rightColumnLines = new List();
+ rightColumnLines.AddRange(GetLocationLines(columnWidth));
+
+ while (leftColumnLines.Count < Console.WindowHeight - 1)
+ {
+ leftColumnLines.Add("");
+ }
+
+ while (rightColumnLines.Count < Console.WindowHeight - 1)
+ {
+ rightColumnLines.Add("");
+ }
+
+ var sb = new StringBuilder();
+
+ foreach (var line in topLines)
+ {
+ sb.AppendLine(line);
+ }
+
+ for (var i = 0; i < leftColumnLines.Count && i < Console.WindowHeight - topLines.Count - 1; i++)
+ {
+ // Retrieve and pad left column, trimming if needed
+ var leftColumn = leftColumnLines[i];
+ if (leftColumn.Length > columnWidth)
+ {
+ leftColumn = leftColumn[..(columnWidth - 3)] + "... ";
+ }
+ else
+ {
+ leftColumn = leftColumn.PadRight(columnWidth);
+ }
+
+ // Retrieve right column, trimming if needed
+ var rightColumn = rightColumnLines[i];
+ if (rightColumn.Length > columnWidth)
+ {
+ rightColumn = rightColumn[..(columnWidth - 3)] + "...";
+ }
+
+ sb.AppendLine($"{leftColumn} {rightColumn}");
+ }
+
+ Console.Clear();
+ Console.Write(sb.ToString());
+ }
+
+ private List GetHeaderLines(int columnWidth)
+ {
+ var lines = new List();
+
+ var connected = $"Connected: {_tracker.AutoTracker?.IsConnected == true}";
+
+ switch (_tracker.AutoTracker?.CurrentGame)
+ {
+ case Game.Zelda:
+ lines.Add($"{connected} | {_tracker.AutoTracker.ZeldaState}");
+ break;
+ case Game.SM:
+ lines.Add($"{connected} | {_tracker.AutoTracker.MetroidState}");
+ break;
+ default:
+ lines.Add(connected);
+ break;
+ }
+
+ lines.Add(new string('-', columnWidth * 2 + 5));
+
+ return lines;
+ }
+
+ private IEnumerable GetDungeonLines(int columnWidth)
+ {
+ var lines = new List { "Dungeons", new('-', columnWidth) };
+
+ var dungeons = _world.Dungeons
+ .Select(x => GetDungeonDetails(x).PadRight(18))
+ .ToList();
+
+ var dungeonLine = "";
+ foreach (var dungeon in dungeons)
+ {
+ if (dungeonLine == "")
+ {
+ dungeonLine = dungeon;
+ }
+ else if ($"{dungeonLine}{dungeon}".Length > columnWidth)
+ {
+ lines.Add(dungeonLine);
+ dungeonLine = dungeon;
+ }
+ else
+ {
+ dungeonLine += dungeon;
+ }
+ }
+ lines.Add(dungeonLine);
+
+ return lines;
+ }
+
+ private IEnumerable GetLocationLines(int columnWidth)
+ {
+ var lines = new List { "Locations", new('-', columnWidth) };
+
+ var locations = _worldService.Locations(unclearedOnly: true, outOfLogic: false, assumeKeys: true,
+ sortByTopRegion: true, regionFilter: RegionFilter.None).ToList();
+
+ var regionCounts = locations
+ .GroupBy(x => x.Region)
+ .OrderByDescending(x => x.Count())
+ .ToDictionary(x => x.Key, x => x.Count());
+
+ var locationNames = locations
+ .OrderByDescending(x => x.Region == _lastRegion)
+ .ThenByDescending(x => regionCounts[x.Region])
+ .ThenBy(x => x.ToString())
+ .Select(x => x.ToString());
+ lines.AddRange(locationNames);
+
+ return lines;
+ }
+
+ private IEnumerable GetInventoryLines(int columnWidth)
+ {
+ var lines = new List { "Inventory", new('-', columnWidth) };
+
+ var itemNames = _world.AllItems.Where(x => x.State.TrackingState > 0)
+ .DistinctBy(x => x.Type)
+ .Where(x => !x.Type.IsInAnyCategory(ItemCategory.Junk, ItemCategory.Map, ItemCategory.Compass, ItemCategory.Keycard, ItemCategory.BigKey, ItemCategory.SmallKey) || x.Type is ItemType.Missile or ItemType.Super or ItemType.PowerBomb or ItemType.ETank)
+ .OrderBy(x => x.Type.IsInCategory(ItemCategory.Metroid))
+ .ThenBy(x => x.Name)
+ .Select(x => x.Metadata.HasStages || x.Metadata.Multiple
+ ? $"{x.Name} ({x.State.TrackingState})"
+ : x.Name)
+ .ToList();
+
+ for (var i = 0; i < itemNames.Count; i += 2)
+ {
+ if (i < itemNames.Count - 1)
+ {
+ lines.Add(itemNames[i].PadRight(columnWidth/2) + itemNames[i+1]);
+ }
+ else
+ {
+ lines.Add(itemNames[i]);
+ }
+ }
+
+ return lines;
+ }
+
+ private string GetDungeonDetails(IDungeon dungeon)
+ {
+ var state = dungeon.DungeonState.Cleared ? "\u2713" : "\u274c";
+ var abbreviation = dungeon.DungeonMetadata.Abbreviation;
+
+ var reward = dungeon is IHasReward
+ ? dungeon.MarkedReward switch
+ {
+ RewardType.None => "??",
+ RewardType.CrystalBlue => "BC",
+ RewardType.CrystalRed => "RC",
+ RewardType.PendantBlue => "BP",
+ RewardType.PendantGreen => "GP",
+ RewardType.PendantRed => "RP",
+ _ => null
+ }
+ : null;
+
+ var requirement = dungeon is INeedsMedallion
+ ? dungeon.MarkedMedallion switch
+ {
+ ItemType.Quake => "Q",
+ ItemType.Bombos => "B",
+ ItemType.Ether => "E",
+ _ => "?"
+ }
+ : null;
+
+ var rewardRequirement = "";
+ if (reward != null)
+ {
+ rewardRequirement = requirement == null ? $" ({reward})" : $" ({reward}/{requirement})";
+ }
+
+ return $"{state} {abbreviation}{rewardRequirement}: {dungeon.DungeonState.RemainingTreasure}";
+ }
+
+}
diff --git a/src/Randomizer.CrossPlatform/Program.cs b/src/Randomizer.CrossPlatform/Program.cs
index c9fe6be5b..31b5ca080 100644
--- a/src/Randomizer.CrossPlatform/Program.cs
+++ b/src/Randomizer.CrossPlatform/Program.cs
@@ -7,7 +7,6 @@
using Randomizer.Data.Services;
using Randomizer.SMZ3.Generation;
using Serilog;
-using Serilog.Events;
namespace Randomizer.CrossPlatform;
@@ -17,13 +16,8 @@ public static class Program
public static void Main(string[] args)
{
- var logLevel = LogEventLevel.Warning;
- if (args.Any(x => x == "-v"))
- logLevel = LogEventLevel.Information;
-
Log.Logger = new LoggerConfiguration()
.Enrich.FromLogContext()
- .WriteTo.Console(logLevel)
.WriteTo.File(LogPath, rollingInterval: RollingInterval.Day, retainedFileCountLimit: 30)
.CreateLogger();
@@ -46,6 +40,8 @@ public static void Main(string[] args)
return;
}
+ Console.WriteLine($"Using Randomizer Options file at {optionsFile.FullName}");
+
var result = DisplayMenu("What do you want to do?", new List()
{
"Generate & Play a Rom",
@@ -82,6 +78,7 @@ public static void Main(string[] args)
var romPath = Path.Combine(randomizerOptions.RomOutputPath, results.Rom!.RomPath);
Console.WriteLine($"Rom generated successfully: {romPath}");
Launch(romPath, randomizerOptions);
+ _ = s_services.GetRequiredService().StartTracking(results.Rom, romPath);
}
else
{
@@ -103,7 +100,9 @@ public static void Main(string[] args)
var selectedRom = roms[result.Value.Item1];
var romPath = Path.Combine(randomizerOptions.RomOutputPath, selectedRom.RomPath);
Launch(romPath, randomizerOptions);
+ _ = s_services.GetRequiredService().StartTracking(selectedRom, romPath);
}
+
}
// Deletes rom(s)
else if (result.Value.Item1 == 2)
diff --git a/src/Randomizer.CrossPlatform/Randomizer.CrossPlatform.csproj b/src/Randomizer.CrossPlatform/Randomizer.CrossPlatform.csproj
index fe1311fd2..bdba4ab03 100644
--- a/src/Randomizer.CrossPlatform/Randomizer.CrossPlatform.csproj
+++ b/src/Randomizer.CrossPlatform/Randomizer.CrossPlatform.csproj
@@ -20,6 +20,7 @@
+
diff --git a/src/Randomizer.CrossPlatform/ServiceCollectionExtensions.cs b/src/Randomizer.CrossPlatform/ServiceCollectionExtensions.cs
index c507f17c9..e21742e6c 100644
--- a/src/Randomizer.CrossPlatform/ServiceCollectionExtensions.cs
+++ b/src/Randomizer.CrossPlatform/ServiceCollectionExtensions.cs
@@ -3,7 +3,11 @@
using Randomizer.Data.Configuration;
using Randomizer.Data.Options;
using Randomizer.Data.Services;
+using Randomizer.Multiplayer.Client;
using Randomizer.SMZ3.ChatIntegration;
+using Randomizer.SMZ3.Tracking;
+using Randomizer.SMZ3.Tracking.AutoTracking;
+using Randomizer.SMZ3.Tracking.VoiceCommands;
using Randomizer.SMZ3.Twitch;
using Randomizer.Sprites;
@@ -16,8 +20,16 @@ public static IServiceCollection ConfigureServices(this IServiceCollection servi
// Randomizer + Tracker
services.AddConfigs();
services.AddRandomizerServices();
-
+ services.AddTracker()
+ .AddOptionalModule()
+ .AddOptionalModule()
+ .AddOptionalModule()
+ .AddOptionalModule()
+ .AddOptionalModule();
+ services.AddScoped();
services.AddSingleton();
+ services.AddMultiplayerServices();
+
services.AddSingleton();
// Chat
@@ -32,6 +44,7 @@ public static IServiceCollection ConfigureServices(this IServiceCollection servi
services.AddSingleton();
services.AddSingleton();
services.AddTransient();
+ services.AddTransient();
return services;
}
diff --git a/src/Randomizer.Data/Options/GeneralOptions.cs b/src/Randomizer.Data/Options/GeneralOptions.cs
index ce9004254..fa99bfb34 100644
--- a/src/Randomizer.Data/Options/GeneralOptions.cs
+++ b/src/Randomizer.Data/Options/GeneralOptions.cs
@@ -3,11 +3,9 @@
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.IO;
-using System.Linq;
using System.Runtime.CompilerServices;
-using System.Text.Json.Serialization;
-using Microsoft.EntityFrameworkCore.Metadata.Conventions;
using Randomizer.Shared.Enums;
+using YamlDotNet.Serialization;
namespace Randomizer.Data.Options
{
@@ -22,48 +20,6 @@ public class GeneralOptions : INotifyPropertyChanged
private string? _twitchChannel;
private string? _twitchId;
- ///
- /// Converts the enum descriptions into a string array for displaying in a dropdown
- ///
- public static IEnumerable QuickLaunchOptions
- {
- get
- {
- var attributes = typeof(LaunchButtonOptions).GetMembers()
- .SelectMany(member => member.GetCustomAttributes(typeof(DescriptionAttribute), true).Cast())
- .ToList();
- return attributes.Select(x => x.Description);
- }
- }
-
- ///
- /// Converts the enum descriptions into a string array for displaying in a dropdown
- ///
- public static IEnumerable AutoTrackerConnectorOptions
- {
- get
- {
- var attributes = typeof(EmulatorConnectorType).GetMembers()
- .SelectMany(member => member.GetCustomAttributes(typeof(DescriptionAttribute), true).Cast())
- .ToList();
- return attributes.Select(x => x.Description);
- }
- }
-
- ///
- /// Converts the enum descriptions into a string array for displaying in a dropdown
- ///
- public static IEnumerable TrackerVoiceFrequencyOptions
- {
- get
- {
- var attributes = typeof(TrackerVoiceFrequency).GetMembers()
- .SelectMany(member => member.GetCustomAttributes(typeof(DescriptionAttribute), true).Cast())
- .ToList();
- return attributes.Select(x => x.Description);
- }
- }
-
public string? Z3RomPath { get; set; }
public string? SMRomPath { get; set; }
@@ -93,16 +49,25 @@ public static IEnumerable TrackerVoiceFrequencyOptions
public bool TrackerShadows { get; set; } = true;
+ [YamlIgnore]
public int LaunchButton { get; set; } = (int)LaunchButtonOptions.PlayAndTrack;
+ public LaunchButtonOptions LaunchButtonOption { get; set; }
+
+ [YamlIgnore]
public int VoiceFrequency { get; set; } = (int)TrackerVoiceFrequency.All;
+ public TrackerVoiceFrequency TrackerVoiceFrequency { get; set; }
+
public bool TrackerHintsEnabled { get; set; }
public bool TrackerSpoilersEnabled { get; set; }
+ [YamlIgnore]
public int AutoTrackerDefaultConnector { get; set; } = (int)EmulatorConnectorType.None;
+ public EmulatorConnectorType AutoTrackerDefaultConnectionType { get; set; }
+
public string? AutoTrackerQUsb2SnesIp { get; set; }
public bool AutoTrackerChangeMap { get; set; }
@@ -178,7 +143,7 @@ public string? TwitchId
public bool EnablePollCreation { get; set; } = true;
- public int ChatGreetingTimeLimit { get; set; } = 0;
+ public int ChatGreetingTimeLimit { get; set; }
public ICollection SelectedProfiles { get; set; } = new List { "Sassy" };
@@ -209,6 +174,11 @@ public string? TwitchId
///
public string? IgnoredUpdateUrl { get; set; }
+ ///
+ /// Automatically tracks the map and other "hey tracker, look at this" events when viewing
+ ///
+ public bool AutoSaveLookAtEvents { get; set; }
+
public event PropertyChangedEventHandler? PropertyChanged;
public bool Validate()
@@ -230,11 +200,12 @@ public bool Validate()
ChatGreetingTimeLimit = ChatGreetingTimeLimit,
PollCreationEnabled = EnablePollCreation,
AutoTrackerChangeMap = AutoTrackerChangeMap,
- VoiceFrequency = (TrackerVoiceFrequency)VoiceFrequency,
+ VoiceFrequency = TrackerVoiceFrequency,
TrackerProfiles = SelectedProfiles,
UndoExpirationTime = UndoExpirationTime,
MsuTrackDisplayStyle = MsuTrackDisplayStyle,
- MsuTrackOutputPath = MsuTrackOutputPath
+ MsuTrackOutputPath = MsuTrackOutputPath,
+ AutoSaveLookAtEvents = AutoSaveLookAtEvents
};
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
@@ -254,7 +225,10 @@ protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName
return twitchUri.AbsolutePath.TrimStart('/');
}
}
- catch { }
+ catch
+ {
+ // ignored
+ }
return value;
}
diff --git a/src/Randomizer.Data/Options/RandomizerOptions.cs b/src/Randomizer.Data/Options/RandomizerOptions.cs
index 4ac73121c..6b9adba5d 100644
--- a/src/Randomizer.Data/Options/RandomizerOptions.cs
+++ b/src/Randomizer.Data/Options/RandomizerOptions.cs
@@ -6,6 +6,7 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using Randomizer.Data.Logic;
+using Randomizer.Shared.Enums;
using YamlDotNet.Serialization;
namespace Randomizer.Data.Options
@@ -91,7 +92,7 @@ public string AutoTrackerScriptsOutputPath
[YamlIgnore]
public EmulatorConnectorType AutoTrackerDefaultConnector
{
- get => (EmulatorConnectorType)GeneralOptions.AutoTrackerDefaultConnector;
+ get => GeneralOptions.AutoTrackerDefaultConnectionType;
}
[YamlIgnore]
@@ -115,6 +116,12 @@ public static RandomizerOptions Load(string loadPath, string savePath, bool isYa
{
var options = JsonSerializer.Deserialize(fileText, s_jsonOptions) ?? new();
options.FilePath = savePath;
+ options.GeneralOptions.AutoTrackerDefaultConnectionType =
+ (EmulatorConnectorType)options.GeneralOptions.AutoTrackerDefaultConnector;
+ options.GeneralOptions.TrackerVoiceFrequency =
+ (TrackerVoiceFrequency)options.GeneralOptions.VoiceFrequency;
+ options.GeneralOptions.LaunchButtonOption =
+ (LaunchButtonOptions)options.GeneralOptions.LaunchButton;
return options;
}
}
diff --git a/src/Randomizer.Data/Options/TrackerOptions.cs b/src/Randomizer.Data/Options/TrackerOptions.cs
index 3b666e04d..86fb30478 100644
--- a/src/Randomizer.Data/Options/TrackerOptions.cs
+++ b/src/Randomizer.Data/Options/TrackerOptions.cs
@@ -110,5 +110,10 @@ public record TrackerOptions
/// The file to write the current song to
///
public string? MsuTrackOutputPath { get; set; }
+
+ ///
+ /// Automatically tracks the map and other "hey tracker, look at this" events when viewing
+ ///
+ public bool AutoSaveLookAtEvents { get; set; }
}
}
diff --git a/src/Randomizer.SMZ3.Tracking/AutoTracking/GameService.cs b/src/Randomizer.SMZ3.Tracking/AutoTracking/GameService.cs
index 91dd2073d..43db26e99 100644
--- a/src/Randomizer.SMZ3.Tracking/AutoTracking/GameService.cs
+++ b/src/Randomizer.SMZ3.Tracking/AutoTracking/GameService.cs
@@ -583,5 +583,10 @@ private bool IsInGame(Game game = Game.Both)
}
return false;
}
+
+ public override void AddCommands()
+ {
+
+ }
}
}
diff --git a/src/Randomizer.SMZ3.Tracking/AutoTracking/ZeldaStateChecks/ViewedMap.cs b/src/Randomizer.SMZ3.Tracking/AutoTracking/ZeldaStateChecks/ViewedMap.cs
index 4e516e9a0..2fa5d26d1 100644
--- a/src/Randomizer.SMZ3.Tracking/AutoTracking/ZeldaStateChecks/ViewedMap.cs
+++ b/src/Randomizer.SMZ3.Tracking/AutoTracking/ZeldaStateChecks/ViewedMap.cs
@@ -52,10 +52,18 @@ public bool ExecuteCheck(Tracker tracker, AutoTrackerZeldaState currentState, Au
if (currentRegion is LightWorldNorthWest or LightWorldNorthEast or LightWorldSouth or LightWorldDeathMountainEast or LightWorldDeathMountainWest)
{
tracker.AutoTracker.LatestViewAction = new AutoTrackerViewedAction(UpdateLightWorldRewards);
+ if (tracker.Options.AutoSaveLookAtEvents)
+ {
+ tracker.AutoTracker.LatestViewAction.Invoke();
+ }
}
else if (currentRegion is DarkWorldNorthWest or DarkWorldNorthEast or DarkWorldSouth or DarkWorldMire or DarkWorldDeathMountainEast or DarkWorldDeathMountainWest)
{
tracker.AutoTracker.LatestViewAction = new AutoTrackerViewedAction(UpdateDarkWorldRewards);
+ if (tracker.Options.AutoSaveLookAtEvents)
+ {
+ tracker.AutoTracker.LatestViewAction.Invoke();
+ }
}
return true;
diff --git a/src/Randomizer.SMZ3.Tracking/AutoTracking/ZeldaStateChecks/ViewedMedallion.cs b/src/Randomizer.SMZ3.Tracking/AutoTracking/ZeldaStateChecks/ViewedMedallion.cs
index 0590605b1..132d9e5ca 100644
--- a/src/Randomizer.SMZ3.Tracking/AutoTracking/ZeldaStateChecks/ViewedMedallion.cs
+++ b/src/Randomizer.SMZ3.Tracking/AutoTracking/ZeldaStateChecks/ViewedMedallion.cs
@@ -31,7 +31,7 @@ public ViewedMedallion(IWorldAccessor worldAccessor, IItemService itemService)
/// True if the check was identified, false otherwise
public bool ExecuteCheck(Tracker tracker, AutoTrackerZeldaState currentState, AutoTrackerZeldaState prevState)
{
- if (tracker.AutoTracker == null) return false;
+ if (tracker.AutoTracker == null || tracker.AutoTracker.LatestViewAction?.IsValid == true) return false;
_tracker = tracker;
@@ -41,11 +41,19 @@ public bool ExecuteCheck(Tracker tracker, AutoTrackerZeldaState currentState, Au
if (currentState.OverworldScreen == 112 && x is >= 172 and <= 438 && y is >= 3200 and <= 3432)
{
tracker.AutoTracker.LatestViewAction = new AutoTrackerViewedAction(MarkMiseryMireMedallion);
+ if (tracker.Options.AutoSaveLookAtEvents)
+ {
+ tracker.AutoTracker.LatestViewAction.Invoke();
+ }
return true;
}
else if (currentState.OverworldScreen == 71 && x is >= 3708 and <= 4016 && y is >= 128 and <= 368)
{
tracker.AutoTracker.LatestViewAction = new AutoTrackerViewedAction(MarkTurtleRockMedallion);
+ if (tracker.Options.AutoSaveLookAtEvents)
+ {
+ tracker.AutoTracker.LatestViewAction.Invoke();
+ }
return true;
}
diff --git a/src/Randomizer.SMZ3.Tracking/Services/ISpeechRecognitionService.cs b/src/Randomizer.SMZ3.Tracking/Services/ISpeechRecognitionService.cs
new file mode 100644
index 000000000..f4691be68
--- /dev/null
+++ b/src/Randomizer.SMZ3.Tracking/Services/ISpeechRecognitionService.cs
@@ -0,0 +1,46 @@
+using System.Speech.Recognition;
+
+namespace Randomizer.SMZ3.Tracking.Services;
+
+///
+/// Service for recognizing speech from a microphone
+///
+public interface ISpeechRecognitionService
+{
+ ///
+ /// Event fired when speech was successfully understood
+ ///
+ public event System.EventHandler? SpeechRecognized;
+
+ ///
+ /// Updates the microphone to be the default Windows mic
+ ///
+ public void SetInputToDefaultAudioDevice();
+
+ ///
+ /// The internal speech recognition engine used by the service, if applicable
+ ///
+ public SpeechRecognitionEngine? RecognitionEngine { get; }
+
+ ///
+ /// Stop recognizing speech
+ ///
+ public void RecognizeAsyncStop();
+
+ ///
+ /// Start recognizing speech
+ ///
+ /// The recognition mode (single/multiple)
+ public void RecognizeAsync(RecognizeMode Mode);
+
+ ///
+ /// Initializes the microphone to the default Windows mic
+ ///
+ /// True if successful, false otherwise
+ public bool InitializeMicrophone();
+
+ ///
+ /// Disposes of the service and speech recognition engine
+ ///
+ public void Dispose();
+}
diff --git a/src/Randomizer.SMZ3.Tracking/Services/SpeechRecognitionServiceDisabled.cs b/src/Randomizer.SMZ3.Tracking/Services/SpeechRecognitionServiceDisabled.cs
new file mode 100644
index 000000000..3022fe870
--- /dev/null
+++ b/src/Randomizer.SMZ3.Tracking/Services/SpeechRecognitionServiceDisabled.cs
@@ -0,0 +1,35 @@
+using System;
+using System.Speech.Recognition;
+
+namespace Randomizer.SMZ3.Tracking.Services;
+
+public class SpeechRecognitionServiceDisabled : ISpeechRecognitionService
+{
+ public event EventHandler? SpeechRecognized;
+
+ public void SetInputToDefaultAudioDevice()
+ {
+
+ }
+
+ public SpeechRecognitionEngine? RecognitionEngine => null;
+
+ public void RecognizeAsyncStop()
+ {
+ }
+
+ public void RecognizeAsync(RecognizeMode Mode)
+ {
+
+ }
+
+ public bool InitializeMicrophone()
+ {
+ return false;
+ }
+
+ public void Dispose()
+ {
+
+ }
+}
diff --git a/src/Randomizer.SMZ3.Tracking/Services/SpeechRecognitionServiceEnabled.cs b/src/Randomizer.SMZ3.Tracking/Services/SpeechRecognitionServiceEnabled.cs
new file mode 100644
index 000000000..62c748ad1
--- /dev/null
+++ b/src/Randomizer.SMZ3.Tracking/Services/SpeechRecognitionServiceEnabled.cs
@@ -0,0 +1,63 @@
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+using System.Speech.Recognition;
+using Microsoft.Extensions.Logging;
+
+namespace Randomizer.SMZ3.Tracking.Services;
+
+[SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")]
+public class SpeechRecognitionServiceEnabled : ISpeechRecognitionService
+{
+ private readonly ILogger _logger;
+ private readonly SpeechRecognitionEngine _recognizer = new();
+
+ ///
+ /// Dll to get the number of microphones
+ ///
+ ///
+ [DllImport("winmm.dll")]
+ private static extern int waveInGetNumDevs();
+
+ public SpeechRecognitionServiceEnabled(ILogger logger)
+ {
+ _logger = logger;
+ _recognizer.SpeechRecognized += RecognizerOnSpeechRecognized;
+ }
+
+ private void RecognizerOnSpeechRecognized(object? sender, SpeechRecognizedEventArgs e)
+ {
+ SpeechRecognized?.Invoke(sender, e);
+ }
+
+ public event EventHandler? SpeechRecognized;
+
+ public void SetInputToDefaultAudioDevice() => _recognizer.SetInputToDefaultAudioDevice();
+
+ public SpeechRecognitionEngine? RecognitionEngine => _recognizer;
+
+ public void RecognizeAsyncStop() =>_recognizer.RecognizeAsyncStop();
+
+ public void RecognizeAsync(RecognizeMode mode) => _recognizer.RecognizeAsync(mode);
+
+ public bool InitializeMicrophone()
+ {
+ try
+ {
+ if (waveInGetNumDevs() == 0)
+ {
+ _logger.LogWarning("No microphone device found.");
+ return false;
+ }
+ _recognizer.SetInputToDefaultAudioDevice();
+ return true;
+ }
+ catch (Exception e)
+ {
+ _logger.LogError(e, "Error initializing microphone");
+ return false;
+ }
+ }
+
+ public void Dispose() => _recognizer.Dispose();
+}
diff --git a/src/Randomizer.SMZ3.Tracking/Services/TextToSpeechCommunicator.cs b/src/Randomizer.SMZ3.Tracking/Services/TextToSpeechCommunicator.cs
index fd18f119d..6be8348cf 100644
--- a/src/Randomizer.SMZ3.Tracking/Services/TextToSpeechCommunicator.cs
+++ b/src/Randomizer.SMZ3.Tracking/Services/TextToSpeechCommunicator.cs
@@ -1,6 +1,5 @@
using System;
using System.Speech.Synthesis;
-using Randomizer.Data;
using Randomizer.Data.Options;
namespace Randomizer.SMZ3.Tracking.Services
@@ -11,7 +10,7 @@ namespace Randomizer.SMZ3.Tracking.Services
///
public class TextToSpeechCommunicator : ICommunicator, IDisposable
{
- private readonly SpeechSynthesizer _tts;
+ private readonly SpeechSynthesizer _tts = null!;
private bool _canSpeak;
///
@@ -20,6 +19,11 @@ public class TextToSpeechCommunicator : ICommunicator, IDisposable
///
public TextToSpeechCommunicator(TrackerOptionsAccessor trackerOptionsAccessor)
{
+ if (!OperatingSystem.IsWindows())
+ {
+ return;
+ }
+
_tts = new SpeechSynthesizer();
_tts.SelectVoiceByHints(VoiceGender.Female);
_canSpeak = trackerOptionsAccessor.Options?.VoiceFrequency != Shared.Enums.TrackerVoiceFrequency.Disabled;
@@ -29,13 +33,26 @@ public TextToSpeechCommunicator(TrackerOptionsAccessor trackerOptionsAccessor)
/// Selects a different text-to-speech voice.
///
public void UseAlternateVoice()
- => _tts.SelectVoiceByHints(VoiceGender.Male);
+ {
+ if (!OperatingSystem.IsWindows())
+ {
+ return;
+ }
+
+ _tts.SelectVoiceByHints(VoiceGender.Male);
+ }
///
/// Aborts all current and queued up text-to-speech actions.
///
public void Abort()
- => _tts.SpeakAsyncCancelAll();
+ {
+ if (!OperatingSystem.IsWindows())
+ {
+ return;
+ }
+ _tts.SpeakAsyncCancelAll();
+ }
///
/// Speaks the specified text or SSML.
@@ -45,9 +62,17 @@ public void Abort()
///
public void Say(string text)
{
+ if (!OperatingSystem.IsWindows())
+ {
+ return;
+ }
+
if (!_canSpeak) return;
var prompt = GetPromptFromText(text);
- _tts.SpeakAsync(prompt);
+ if (prompt != null)
+ {
+ _tts.SpeakAsync(prompt);
+ }
}
///
@@ -59,9 +84,17 @@ public void Say(string text)
///
public void SayWait(string text)
{
+ if (!OperatingSystem.IsWindows())
+ {
+ return;
+ }
+
if (!_canSpeak) return;
var prompt = GetPromptFromText(text);
- _tts.Speak(prompt);
+ if (prompt != null)
+ {
+ _tts.Speak(prompt);
+ }
}
///
@@ -69,6 +102,11 @@ public void SayWait(string text)
///
public void SpeedUp()
{
+ if (!OperatingSystem.IsWindows())
+ {
+ return;
+ }
+
_tts.Rate += 2;
}
@@ -77,6 +115,11 @@ public void SpeedUp()
///
public void SlowDown()
{
+ if (!OperatingSystem.IsWindows())
+ {
+ return;
+ }
+
_tts.Rate -= 2;
}
@@ -92,8 +135,13 @@ public void Dispose()
///
/// The plain text or SSML markup to parse.
/// A new .
- protected static Prompt GetPromptFromText(string text)
+ protected static Prompt? GetPromptFromText(string text)
{
+ if (!OperatingSystem.IsWindows())
+ {
+ return null;
+ }
+
// If text does not contain any XML elements, just interpret it as
// text
if (!text.Contains("<") && !text.Contains("/>"))
@@ -110,7 +158,7 @@ protected static Prompt GetPromptFromText(string text)
///
protected virtual void Dispose(bool disposing)
{
- if (disposing)
+ if (disposing && OperatingSystem.IsWindows())
{
_tts.Dispose();
}
diff --git a/src/Randomizer.SMZ3.Tracking/Tracker.cs b/src/Randomizer.SMZ3.Tracking/Tracker.cs
index 16379d0ee..63daffd4a 100644
--- a/src/Randomizer.SMZ3.Tracking/Tracker.cs
+++ b/src/Randomizer.SMZ3.Tracking/Tracker.cs
@@ -42,7 +42,7 @@ public class Tracker : IDisposable
private const int RepeatRateModifier = 2;
private static readonly Random s_random = new();
- private readonly SpeechRecognitionEngine _recognizer;
+
private readonly IWorldAccessor _worldAccessor;
private readonly TrackerModuleFactory _moduleFactory;
private readonly IChatClient _chatClient;
@@ -55,6 +55,7 @@ public class Tracker : IDisposable
private readonly ITrackerStateService _stateService;
private readonly IWorldService _worldService;
private readonly ITrackerTimerService _timerService;
+ private readonly ISpeechRecognitionService _recognizer;
private bool _disposed;
private string? _mood;
private string? _lastSpokenText;
@@ -64,13 +65,6 @@ public class Tracker : IDisposable
private bool _beatenGame;
private IEnumerable? _previousMissingItems;
- ///
- /// Dll to get the number of microphones
- ///
- ///
- [DllImport("winmm.dll")]
- private static extern int waveInGetNumDevs();
-
///
/// Initializes a new instance of the class.
///
@@ -107,7 +101,8 @@ public Tracker(ConfigProvider configProvider,
IMetadataService metadataService,
ITrackerStateService stateService,
IWorldService worldService,
- ITrackerTimerService timerService)
+ ITrackerTimerService timerService,
+ ISpeechRecognitionService speechRecognitionService)
{
if (trackerOptions.Options == null)
throw new InvalidOperationException("Tracker options have not yet been activated.");
@@ -145,7 +140,7 @@ public Tracker(ConfigProvider configProvider,
}
// Initialize the speech recognition engine
- _recognizer = new SpeechRecognitionEngine();
+ _recognizer = speechRecognitionService;
_recognizer.SpeechRecognized += Recognizer_SpeechRecognized;
InitializeMicrophone();
}
@@ -413,23 +408,8 @@ public string CorrectUserNamePronunciation(string userName)
public bool InitializeMicrophone()
{
if (MicrophoneInitialized) return true;
-
- try
- {
- if (waveInGetNumDevs() == 0)
- {
- _logger.LogWarning("No microphone device found.");
- return false;
- }
- _recognizer.SetInputToDefaultAudioDevice();
- MicrophoneInitialized = true;
- return true;
- }
- catch (Exception e)
- {
- _logger.LogError(e, "Error initializing microphone");
- return false;
- }
+ MicrophoneInitialized = _recognizer.InitializeMicrophone();
+ return MicrophoneInitialized;
}
///
@@ -457,12 +437,15 @@ public bool Load(GeneratedRom rom, string romPath)
///
/// Saves the state of the tracker to the database
///
- /// The rom to save
///
- public async Task SaveAsync(GeneratedRom rom)
+ public async Task SaveAsync()
{
+ if (Rom == null)
+ {
+ throw new NullReferenceException("No rom loaded into tracker");
+ }
IsDirty = false;
- await _stateService.SaveStateAsync(_worldAccessor.Worlds, rom, _timerService.SecondsElapsed);
+ await _stateService.SaveStateAsync(_worldAccessor.Worlds, Rom, _timerService.SecondsElapsed);
}
///
@@ -711,7 +694,17 @@ public virtual bool TryStartTracking()
{
// Load the modules for voice recognition
StartTimer(true);
- Syntax = _moduleFactory.LoadAll(this, _recognizer, out var loadError);
+
+ var loadError = false;
+ try
+ {
+ Syntax = _moduleFactory.LoadAll(this, _recognizer.RecognitionEngine, out loadError);
+ }
+ catch (Exception e)
+ {
+ _logger.LogError(e, "Unable to load modules");
+ loadError = true;
+ }
try
{
diff --git a/src/Randomizer.SMZ3.Tracking/TrackerServiceCollectionExtensions.cs b/src/Randomizer.SMZ3.Tracking/TrackerServiceCollectionExtensions.cs
index 4182b09be..56d05e26d 100644
--- a/src/Randomizer.SMZ3.Tracking/TrackerServiceCollectionExtensions.cs
+++ b/src/Randomizer.SMZ3.Tracking/TrackerServiceCollectionExtensions.cs
@@ -42,6 +42,15 @@ public static IServiceCollection AddTracker(this IServiceCollection services)
services.AddScoped();
services.AddScoped();
+ if (OperatingSystem.IsWindows())
+ {
+ services.AddScoped();
+ }
+ else
+ {
+ services.AddScoped();
+ }
+
var assemblies = new[] { Assembly.GetExecutingAssembly() };
var zeldaStateChecks = assemblies
@@ -63,7 +72,7 @@ public static IServiceCollection AddTracker(this IServiceCollection services)
return services;
}
-
+
///
/// Enables the specified tracker module.
diff --git a/src/Randomizer.SMZ3.Tracking/VoiceCommands/AutoTrackerModule.cs b/src/Randomizer.SMZ3.Tracking/VoiceCommands/AutoTrackerModule.cs
index b2ad59efe..fb1ee2c0c 100644
--- a/src/Randomizer.SMZ3.Tracking/VoiceCommands/AutoTrackerModule.cs
+++ b/src/Randomizer.SMZ3.Tracking/VoiceCommands/AutoTrackerModule.cs
@@ -27,11 +27,6 @@ public AutoTrackerModule(Tracker tracker, IItemService itemService, IWorldServic
{
Tracker.AutoTracker = autoTracker;
_autoTracker = autoTracker;
-
- AddCommand("Look at this", GetLookAtGameRule(), (result) =>
- {
- LookAtGame();
- });
}
private GrammarBuilder GetLookAtGameRule()
@@ -58,6 +53,14 @@ public void Dispose()
{
_autoTracker.SetConnector(EmulatorConnectorType.None, "");
}
+
+ public override void AddCommands()
+ {
+ AddCommand("Look at this", GetLookAtGameRule(), (result) =>
+ {
+ LookAtGame();
+ });
+ }
}
}
diff --git a/src/Randomizer.SMZ3.Tracking/VoiceCommands/BossTrackingModule.cs b/src/Randomizer.SMZ3.Tracking/VoiceCommands/BossTrackingModule.cs
index c6c58e50e..e1a197698 100644
--- a/src/Randomizer.SMZ3.Tracking/VoiceCommands/BossTrackingModule.cs
+++ b/src/Randomizer.SMZ3.Tracking/VoiceCommands/BossTrackingModule.cs
@@ -1,4 +1,5 @@
using System;
+using System.Diagnostics.CodeAnalysis;
using Microsoft.Extensions.Logging;
using Randomizer.Shared;
@@ -21,24 +22,89 @@ public class BossTrackingModule : TrackerModule
/// Used to write logging information.
public BossTrackingModule(Tracker tracker, IItemService itemService, IWorldService worldService, ILogger logger)
: base(tracker, itemService, worldService, logger)
+ {
+
+ }
+
+ private GrammarBuilder GetMarkBossAsDefeatedRule()
+ {
+ var bossNames = GetBossNames();
+ var beatBoss = new GrammarBuilder()
+ .Append("Hey tracker,")
+ .OneOf("track", "I beat", "I defeated", "I beat off", "I killed")
+ .Append(BossKey, bossNames);
+
+ var markBoss = new GrammarBuilder()
+ .Append("Hey tracker,")
+ .Append("mark")
+ .Append(BossKey, bossNames)
+ .Append("as")
+ .OneOf("beaten", "beaten off", "dead", "fucking dead", "defeated");
+
+ var bossIsDead = new GrammarBuilder()
+ .Append("Hey tracker,")
+ .Append(BossKey, bossNames)
+ .OneOf("is dead", "is fucking dead");
+
+ return GrammarBuilder.Combine(beatBoss, markBoss, bossIsDead);
+ }
+
+ private GrammarBuilder GetMarkBossAsNotDefeatedRule()
+ {
+ var bossNames = GetBossNames();
+
+ var markBoss = new GrammarBuilder()
+ .Append("Hey tracker,")
+ .Append("mark")
+ .Append(BossKey, bossNames)
+ .Append("as")
+ .OneOf("alive", "not defeated", "undefeated");
+
+ var bossIsAlive = new GrammarBuilder()
+ .Append("Hey tracker,")
+ .Append(BossKey, bossNames)
+ .OneOf("is alive", "is still alive");
+
+ return GrammarBuilder.Combine(markBoss, bossIsAlive);
+ }
+
+ private GrammarBuilder GetBossDefeatedWithContentRule()
+ {
+ var bossNames = GetBossNames();
+ var beatBoss = new GrammarBuilder()
+ .Append("Hey tracker,")
+ .OneOf("I beat", "I defeated", "I beat off", "I killed")
+ .Append(BossKey, bossNames)
+ .OneOf("Without getting hit", "Without taking damage", "And didn't get hit", "And didn't take damage", "In one cycle");
+
+ var oneCycled = new GrammarBuilder()
+ .Append("Hey tracker,")
+ .OneOf("I one cycled", "I quick killed")
+ .Append(BossKey, bossNames);
+
+ return GrammarBuilder.Combine(beatBoss, oneCycled);
+ }
+
+ [SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")]
+ public override void AddCommands()
{
AddCommand("Mark boss as defeated", GetMarkBossAsDefeatedRule(), (result) =>
{
- var dungeon = GetBossDungeonFromResult(tracker, result);
+ var dungeon = GetBossDungeonFromResult(Tracker, result);
if (dungeon != null)
{
// Track boss with associated dungeon
- tracker.MarkDungeonAsCleared(dungeon, result.Confidence);
+ Tracker.MarkDungeonAsCleared(dungeon, result.Confidence);
return;
}
- var boss = GetBossFromResult(tracker, result);
+ var boss = GetBossFromResult(Tracker, result);
if (boss != null)
{
// Track standalone boss
var admittedGuilt = result.Text.ContainsAny("killed", "beat", "defeated", "dead")
&& !result.Text.ContainsAny("beat off", "beaten off");
- tracker.MarkBossAsDefeated(boss, admittedGuilt, result.Confidence);
+ Tracker.MarkBossAsDefeated(boss, admittedGuilt, result.Confidence);
return;
}
@@ -47,19 +113,19 @@ public BossTrackingModule(Tracker tracker, IItemService itemService, IWorldServi
AddCommand("Mark boss as alive", GetMarkBossAsNotDefeatedRule(), (result) =>
{
- var dungeon = GetBossDungeonFromResult(tracker, result);
+ var dungeon = GetBossDungeonFromResult(Tracker, result);
if (dungeon != null)
{
// Untrack boss with associated dungeon
- tracker.MarkDungeonAsIncomplete(dungeon, result.Confidence);
+ Tracker.MarkDungeonAsIncomplete(dungeon, result.Confidence);
return;
}
- var boss = GetBossFromResult(tracker, result);
+ var boss = GetBossFromResult(Tracker, result);
if (boss != null)
{
// Untrack standalone boss
- tracker.MarkBossAsNotDefeated(boss, result.Confidence);
+ Tracker.MarkBossAsNotDefeated(boss, result.Confidence);
return;
}
@@ -68,9 +134,9 @@ public BossTrackingModule(Tracker tracker, IItemService itemService, IWorldServi
AddCommand("Mark boss as defeated with content", GetBossDefeatedWithContentRule(), (result) =>
{
- var contentItemData = itemService.FirstOrDefault("Content");
+ var contentItemData = ItemService.FirstOrDefault("Content");
- var dungeon = GetBossDungeonFromResult(tracker, result);
+ var dungeon = GetBossDungeonFromResult(Tracker, result);
if (dungeon != null)
{
if (contentItemData != null)
@@ -80,11 +146,11 @@ public BossTrackingModule(Tracker tracker, IItemService itemService, IWorldServi
}
// Track boss with associated dungeon
- tracker.MarkDungeonAsCleared(dungeon, result.Confidence);
+ Tracker.MarkDungeonAsCleared(dungeon, result.Confidence);
return;
}
- var boss = GetBossFromResult(tracker, result);
+ var boss = GetBossFromResult(Tracker, result);
if (boss != null)
{
if (contentItemData != null)
@@ -96,71 +162,12 @@ public BossTrackingModule(Tracker tracker, IItemService itemService, IWorldServi
// Track standalone boss
var admittedGuilt = result.Text.ContainsAny("killed", "beat", "defeated", "dead")
&& !result.Text.ContainsAny("beat off", "beaten off");
- tracker.MarkBossAsDefeated(boss, admittedGuilt, result.Confidence);
+ Tracker.MarkBossAsDefeated(boss, admittedGuilt, result.Confidence);
return;
}
throw new Exception($"Could not find boss or dungeon in command: '{result.Text}'");
});
}
-
- private GrammarBuilder GetMarkBossAsDefeatedRule()
- {
- var bossNames = GetBossNames();
- var beatBoss = new GrammarBuilder()
- .Append("Hey tracker,")
- .OneOf("track", "I beat", "I defeated", "I beat off", "I killed")
- .Append(BossKey, bossNames);
-
- var markBoss = new GrammarBuilder()
- .Append("Hey tracker,")
- .Append("mark")
- .Append(BossKey, bossNames)
- .Append("as")
- .OneOf("beaten", "beaten off", "dead", "fucking dead", "defeated");
-
- var bossIsDead = new GrammarBuilder()
- .Append("Hey tracker,")
- .Append(BossKey, bossNames)
- .OneOf("is dead", "is fucking dead");
-
- return GrammarBuilder.Combine(beatBoss, markBoss, bossIsDead);
- }
-
- private GrammarBuilder GetMarkBossAsNotDefeatedRule()
- {
- var bossNames = GetBossNames();
-
- var markBoss = new GrammarBuilder()
- .Append("Hey tracker,")
- .Append("mark")
- .Append(BossKey, bossNames)
- .Append("as")
- .OneOf("alive", "not defeated", "undefeated");
-
- var bossIsAlive = new GrammarBuilder()
- .Append("Hey tracker,")
- .Append(BossKey, bossNames)
- .OneOf("is alive", "is still alive");
-
- return GrammarBuilder.Combine(markBoss, bossIsAlive);
- }
-
- private GrammarBuilder GetBossDefeatedWithContentRule()
- {
- var bossNames = GetBossNames();
- var beatBoss = new GrammarBuilder()
- .Append("Hey tracker,")
- .OneOf("I beat", "I defeated", "I beat off", "I killed")
- .Append(BossKey, bossNames)
- .OneOf("Without getting hit", "Without taking damage", "And didn't get hit", "And didn't take damage", "In one cycle");
-
- var oneCycled = new GrammarBuilder()
- .Append("Hey tracker,")
- .OneOf("I one cycled", "I quick killed")
- .Append(BossKey, bossNames);
-
- return GrammarBuilder.Combine(beatBoss, oneCycled);
- }
}
}
diff --git a/src/Randomizer.SMZ3.Tracking/VoiceCommands/ChatIntegrationModule.cs b/src/Randomizer.SMZ3.Tracking/VoiceCommands/ChatIntegrationModule.cs
index b6416b717..1ea0acef3 100644
--- a/src/Randomizer.SMZ3.Tracking/VoiceCommands/ChatIntegrationModule.cs
+++ b/src/Randomizer.SMZ3.Tracking/VoiceCommands/ChatIntegrationModule.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Speech.Recognition;
using System.Text.RegularExpressions;
@@ -54,27 +55,6 @@ public ChatIntegrationModule(Tracker tracker, IChatClient chatClient, IItemServi
ChatClient.MessageReceived += ChatClient_MessageReceived;
ChatClient.Disconnected += ChatClient_Disconnected;
ChatClient.SendMessageFailure += ChatClient_SendMessageFailure;
-
- AddCommand("Start Ganon's Tower Big Key Guessing Game", GetStartGuessingGameRule(), async (result) =>
- {
- await StartGanonsTowerGuessingGame();
- });
-
- AddCommand("Close Ganon's Tower Big Key Guessing Game", GetStopGuessingGameGuessesRule(), async (result) =>
- {
- await CloseGanonsTowerGuessingGameGuesses();
- });
-
- AddCommand("Declare Ganon's Tower Big Key Guessing Game Winner", GetRevealGuessingGameWinnerRule(), async (result) =>
- {
- var winningNumber = (int)result.Semantics[WinningGuessKey].Value;
- await DeclareGanonsTowerGuessingGameWinner(winningNumber);
- });
-
- AddCommand("Track Content", GetTrackContent(), async (result) =>
- {
- await AskChatAboutContent();
- });
}
///
@@ -546,5 +526,30 @@ private GrammarBuilder GetTrackContent()
.OneOf("track", "add")
.OneOf("content", "con-tent");
}
+
+ [SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")]
+ public override void AddCommands()
+ {
+ AddCommand("Start Ganon's Tower Big Key Guessing Game", GetStartGuessingGameRule(), async (result) =>
+ {
+ await StartGanonsTowerGuessingGame();
+ });
+
+ AddCommand("Close Ganon's Tower Big Key Guessing Game", GetStopGuessingGameGuessesRule(), async (result) =>
+ {
+ await CloseGanonsTowerGuessingGameGuesses();
+ });
+
+ AddCommand("Declare Ganon's Tower Big Key Guessing Game Winner", GetRevealGuessingGameWinnerRule(), async (result) =>
+ {
+ var winningNumber = (int)result.Semantics[WinningGuessKey].Value;
+ await DeclareGanonsTowerGuessingGameWinner(winningNumber);
+ });
+
+ AddCommand("Track Content", GetTrackContent(), async (result) =>
+ {
+ await AskChatAboutContent();
+ });
+ }
}
}
diff --git a/src/Randomizer.SMZ3.Tracking/VoiceCommands/CheatsModule.cs b/src/Randomizer.SMZ3.Tracking/VoiceCommands/CheatsModule.cs
index bf732bd9b..5d5c041c9 100644
--- a/src/Randomizer.SMZ3.Tracking/VoiceCommands/CheatsModule.cs
+++ b/src/Randomizer.SMZ3.Tracking/VoiceCommands/CheatsModule.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Speech.Recognition;
using Microsoft.Extensions.Logging;
@@ -36,59 +37,7 @@ public class CheatsModule : TrackerModule
public CheatsModule(Tracker tracker, IItemService itemService, IWorldService worldService, ILogger logger)
: base(tracker, itemService, worldService, logger)
{
- if (tracker.World.Config.Race || tracker.World.Config.DisableCheats) return;
- AddCommand("Enable cheats", GetEnableCheatsRule(), (result) =>
- {
- _cheatsEnabled = true;
- Tracker.Say(x => x.Cheats.EnabledCheats);
- });
-
- AddCommand("Disable cheats", GetDisableHintsRule(), (result) =>
- {
- _cheatsEnabled = false;
- Tracker.Say(x => x.Cheats.DisabledCheats);
- });
-
- AddCommand("Fill rule", FillRule(), (result) =>
- {
- var fillType = result.Semantics.ContainsKey(s_fillCheatKey) ? (string)result.Semantics[s_fillCheatKey].Value : s_fillHealthChoices.First();
- Fill(fillType);
- });
-
- AddCommand("Give item", GiveItemRule(), (result) =>
- {
- var item = GetItemFromResult(tracker, result, out var itemName);
- GiveItem(item);
- });
-
- AddCommand("Kill player", KillPlayerRule(), (result) =>
- {
- if (!PlayerCanCheat()) return;
-
- if (Tracker.GameService?.TryKillPlayer() == true)
- {
- Tracker.Say(x => x.Cheats.CheatPerformed);
- }
- else
- {
- Tracker.Say(x => x.Cheats.CheatFailed);
- }
- });
-
- AddCommand("Setup Crystal Flash", SetupCrystalFlashRule(), (result) =>
- {
- if (!PlayerCanCheat()) return;
-
- if (Tracker.GameService?.TrySetupCrystalFlash() == true)
- {
- Tracker.Say(x => x.Cheats.CheatPerformed);
- }
- else
- {
- Tracker.Say(x => x.Cheats.CheatFailed);
- }
- });
}
private bool PlayerCanCheat()
@@ -192,6 +141,7 @@ private static GrammarBuilder GetDisableHintsRule()
.OneOf("cheats", "cheat codes", "sv_cheats");
}
+ [SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")]
private static GrammarBuilder FillRule()
{
var fillChoices = new Choices();
@@ -244,6 +194,64 @@ private GrammarBuilder SetupCrystalFlashRule()
.Optional("please", "would you kindly")
.OneOf("setup crystal flash requirements", "ready a crystal flash");
}
+
+ [SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")]
+ public override void AddCommands()
+ {
+ if (Tracker.World.Config.Race || Tracker.World.Config.DisableCheats) return;
+
+ AddCommand("Enable cheats", GetEnableCheatsRule(), (result) =>
+ {
+ _cheatsEnabled = true;
+ Tracker.Say(x => x.Cheats.EnabledCheats);
+ });
+
+ AddCommand("Disable cheats", GetDisableHintsRule(), (result) =>
+ {
+ _cheatsEnabled = false;
+ Tracker.Say(x => x.Cheats.DisabledCheats);
+ });
+
+ AddCommand("Fill rule", FillRule(), (result) =>
+ {
+ var fillType = result.Semantics.ContainsKey(s_fillCheatKey) ? (string)result.Semantics[s_fillCheatKey].Value : s_fillHealthChoices.First();
+ Fill(fillType);
+ });
+
+ AddCommand("Give item", GiveItemRule(), (result) =>
+ {
+ var item = GetItemFromResult(Tracker, result, out var itemName);
+ GiveItem(item);
+ });
+
+ AddCommand("Kill player", KillPlayerRule(), (result) =>
+ {
+ if (!PlayerCanCheat()) return;
+
+ if (Tracker.GameService?.TryKillPlayer() == true)
+ {
+ Tracker.Say(x => x.Cheats.CheatPerformed);
+ }
+ else
+ {
+ Tracker.Say(x => x.Cheats.CheatFailed);
+ }
+ });
+
+ AddCommand("Setup Crystal Flash", SetupCrystalFlashRule(), (result) =>
+ {
+ if (!PlayerCanCheat()) return;
+
+ if (Tracker.GameService?.TrySetupCrystalFlash() == true)
+ {
+ Tracker.Say(x => x.Cheats.CheatPerformed);
+ }
+ else
+ {
+ Tracker.Say(x => x.Cheats.CheatFailed);
+ }
+ });
+ }
}
}
diff --git a/src/Randomizer.SMZ3.Tracking/VoiceCommands/GoModeModule.cs b/src/Randomizer.SMZ3.Tracking/VoiceCommands/GoModeModule.cs
index aa823913c..02bfbb8da 100644
--- a/src/Randomizer.SMZ3.Tracking/VoiceCommands/GoModeModule.cs
+++ b/src/Randomizer.SMZ3.Tracking/VoiceCommands/GoModeModule.cs
@@ -1,5 +1,5 @@
-using System;
-using System.Collections.Generic;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using Microsoft.Extensions.Logging;
using Randomizer.Data.Configuration.ConfigFiles;
using Randomizer.SMZ3.Tracking.Services;
@@ -11,6 +11,7 @@ namespace Randomizer.SMZ3.Tracking.VoiceCommands
///
public class GoModeModule : TrackerModule
{
+ private ResponseConfig _responseConfig;
///
/// Initializes a new instance of the class.
@@ -23,10 +24,7 @@ public class GoModeModule : TrackerModule
public GoModeModule(Tracker tracker, IItemService itemService, IWorldService worldService, ILogger logger, ResponseConfig responseConfig)
: base(tracker, itemService, worldService, logger)
{
- AddCommand("Toggle Go Mode", GetGoModeRule(responseConfig.GoModePrompts), (result) =>
- {
- tracker.ToggleGoMode(result.Confidence);
- });
+ _responseConfig = responseConfig;
}
private GrammarBuilder GetGoModeRule(List prompts)
@@ -35,5 +33,14 @@ private GrammarBuilder GetGoModeRule(List prompts)
.Append("Hey tracker,")
.OneOf(prompts.ToArray());
}
+
+ [SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")]
+ public override void AddCommands()
+ {
+ AddCommand("Toggle Go Mode", GetGoModeRule(_responseConfig.GoModePrompts), (result) =>
+ {
+ Tracker.ToggleGoMode(result.Confidence);
+ });
+ }
}
}
diff --git a/src/Randomizer.SMZ3.Tracking/VoiceCommands/GrammarBuilder.cs b/src/Randomizer.SMZ3.Tracking/VoiceCommands/GrammarBuilder.cs
index 833403aae..436c8b1fa 100644
--- a/src/Randomizer.SMZ3.Tracking/VoiceCommands/GrammarBuilder.cs
+++ b/src/Randomizer.SMZ3.Tracking/VoiceCommands/GrammarBuilder.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.Linq;
using System.Speech.Recognition;
@@ -9,7 +10,7 @@ namespace Randomizer.SMZ3.Tracking.VoiceCommands
///
public class GrammarBuilder
{
- private readonly System.Speech.Recognition.GrammarBuilder _grammar;
+ private readonly System.Speech.Recognition.GrammarBuilder _grammar = null!;
private readonly List _elements;
///
@@ -18,7 +19,10 @@ public class GrammarBuilder
///
public GrammarBuilder()
{
- _grammar = new();
+ if (OperatingSystem.IsWindows())
+ {
+ _grammar = new();
+ }
_elements = new();
}
@@ -30,6 +34,10 @@ public GrammarBuilder()
public GrammarBuilder(IEnumerable choices)
: this()
{
+ if (!OperatingSystem.IsWindows())
+ {
+ return;
+ }
_grammar.Append(new Choices(choices.Select(x => (System.Speech.Recognition.GrammarBuilder)x).ToArray()));
foreach (var choice in choices)
_elements.Add(choice + "\n");
@@ -63,6 +71,10 @@ public static GrammarBuilder Combine(params GrammarBuilder[] choices)
/// This instance.
public GrammarBuilder Append(string text)
{
+ if (!OperatingSystem.IsWindows())
+ {
+ return this;
+ }
_grammar.Append(text);
_elements.Add(text);
return this;
@@ -81,6 +93,10 @@ public GrammarBuilder Append(string text)
/// This instance.
public GrammarBuilder Append(string key, Choices choices)
{
+ if (!OperatingSystem.IsWindows())
+ {
+ return this;
+ }
_grammar.Append(new SemanticResultKey(key, choices));
_elements.Add($"<{key}>");
return this;
@@ -95,6 +111,10 @@ public GrammarBuilder Append(string key, Choices choices)
/// This instance.
public GrammarBuilder OneOf(params string[] choices)
{
+ if (!OperatingSystem.IsWindows())
+ {
+ return this;
+ }
_grammar.Append(new Choices(choices));
_elements.Add($"[{string.Join('/', choices)}]");
return this;
@@ -109,6 +129,10 @@ public GrammarBuilder OneOf(params string[] choices)
/// This instance.
public GrammarBuilder Optional(string text)
{
+ if (!OperatingSystem.IsWindows())
+ {
+ return this;
+ }
_grammar.Append(text, 0, 1);
_elements.Add($"({text})");
return this;
@@ -121,6 +145,10 @@ public GrammarBuilder Optional(string text)
/// This instance.
public GrammarBuilder Optional(params string[] choices)
{
+ if (!OperatingSystem.IsWindows())
+ {
+ return this;
+ }
_grammar.Append(new Choices(choices), 0, 1);
_elements.Add($"({string.Join('/', choices)})");
return this;
diff --git a/src/Randomizer.SMZ3.Tracking/VoiceCommands/ItemTrackingModule.cs b/src/Randomizer.SMZ3.Tracking/VoiceCommands/ItemTrackingModule.cs
index 11b36a87e..bb7c4cf38 100644
--- a/src/Randomizer.SMZ3.Tracking/VoiceCommands/ItemTrackingModule.cs
+++ b/src/Randomizer.SMZ3.Tracking/VoiceCommands/ItemTrackingModule.cs
@@ -1,4 +1,5 @@
-using System.Speech.Recognition;
+using System.Diagnostics.CodeAnalysis;
+using System.Speech.Recognition;
using Microsoft.Extensions.Logging;
@@ -24,112 +25,7 @@ public class ItemTrackingModule : TrackerModule
public ItemTrackingModule(Tracker tracker, IItemService itemService, IWorldService worldService, ILogger logger)
: base(tracker, itemService, worldService, logger)
{
- var isMultiworld = worldService.World.Config.MultiWorld;
- AddCommand("Track item", GetTrackItemRule(isMultiworld), (result) =>
- {
- var item = GetItemFromResult(tracker, result, out var itemName);
-
- if (result.Semantics.ContainsKey(DungeonKey))
- {
- var dungeon = GetDungeonFromResult(tracker, result);
- tracker.TrackItem(item, dungeon,
- trackedAs: itemName,
- confidence: result.Confidence);
- }
- else if (result.Semantics.ContainsKey(RoomKey))
- {
- var room = GetRoomFromResult(tracker, result);
- tracker.TrackItem(item, room,
- trackedAs: itemName,
- confidence: result.Confidence);
- }
- else if (result.Semantics.ContainsKey(LocationKey))
- {
- var location = GetLocationFromResult(tracker, result);
- tracker.TrackItem(item: item,
- trackedAs: itemName,
- confidence: result.Confidence,
- tryClear: true,
- autoTracked: false,
- location: location);
- }
- else
- {
- tracker.TrackItem(item,
- trackedAs: itemName,
- confidence: result.Confidence);
- }
- });
-
- AddCommand("Track death", GetTrackDeathRule(), (result) =>
- {
- var death = itemService.FirstOrDefault("Death");
- if (death == null)
- {
- Logger.LogError("Tried to track death, but could not find an item named 'Death'.");
- tracker.Say(x => x.Error);
- return;
- }
-
- tracker.TrackItem(death, confidence: result.Confidence, tryClear: false);
- });
-
- if (!isMultiworld)
- {
- AddCommand("Track available items in an area", GetTrackEverythingRule(), (result) =>
- {
- if (result.Semantics.ContainsKey(RoomKey))
- {
- var room = GetRoomFromResult(tracker, result);
- tracker.ClearArea(room,
- trackItems: true,
- includeUnavailable: false,
- confidence: result.Confidence);
- }
- else if (result.Semantics.ContainsKey(RegionKey))
- {
- var region = GetRegionFromResult(tracker, result);
- tracker.ClearArea(region,
- trackItems: true,
- includeUnavailable: false,
- confidence: result.Confidence);
- }
- });
-
- AddCommand("Track all items in an area (including out-of-logic)", GetTrackEverythingIncludingOutOfLogicRule(), (result) =>
- {
- if (result.Semantics.ContainsKey(RoomKey))
- {
- var room = GetRoomFromResult(tracker, result);
- tracker.ClearArea(room,
- trackItems: true,
- includeUnavailable: true,
- confidence: result.Confidence);
- }
- else if (result.Semantics.ContainsKey(RegionKey))
- {
- var region = GetRegionFromResult(tracker, result);
- tracker.ClearArea(region,
- trackItems: true,
- includeUnavailable: true,
- confidence: result.Confidence);
- }
- });
- }
-
- AddCommand("Untrack an item", GetUntrackItemRule(), (result) =>
- {
- var item = GetItemFromResult(tracker, result, out _);
- tracker.UntrackItem(item, result.Confidence);
- });
-
- AddCommand("Set item count", GetSetItemCountRule(), (result) =>
- {
- var item = GetItemFromResult(tracker, result, out _);
- var count = (int)result.Semantics[ItemCountKey].Value;
- tracker.TrackItemAmount(item, count, result.Confidence);
- });
}
private GrammarBuilder GetTrackDeathRule()
@@ -269,6 +165,7 @@ private GrammarBuilder GetUntrackItemRule()
return GrammarBuilder.Combine(untrackItem, toggleItemOff);
}
+ [SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")]
private GrammarBuilder GetSetItemCountRule()
{
var itemNames = GetPluralItemNames();
@@ -282,5 +179,116 @@ private GrammarBuilder GetSetItemCountRule()
.Append(ItemCountKey, numbers)
.Append(ItemNameKey, itemNames);
}
+
+ [SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")]
+ public override void AddCommands()
+ {
+ var isMultiworld = WorldService.World.Config.MultiWorld;
+
+ AddCommand("Track item", GetTrackItemRule(isMultiworld), (result) =>
+ {
+ var item = GetItemFromResult(Tracker, result, out var itemName);
+
+ if (result.Semantics.ContainsKey(DungeonKey))
+ {
+ var dungeon = GetDungeonFromResult(Tracker, result);
+ Tracker.TrackItem(item, dungeon,
+ trackedAs: itemName,
+ confidence: result.Confidence);
+ }
+ else if (result.Semantics.ContainsKey(RoomKey))
+ {
+ var room = GetRoomFromResult(Tracker, result);
+ Tracker.TrackItem(item, room,
+ trackedAs: itemName,
+ confidence: result.Confidence);
+ }
+ else if (result.Semantics.ContainsKey(LocationKey))
+ {
+ var location = GetLocationFromResult(Tracker, result);
+ Tracker.TrackItem(item: item,
+ trackedAs: itemName,
+ confidence: result.Confidence,
+ tryClear: true,
+ autoTracked: false,
+ location: location);
+ }
+ else
+ {
+ Tracker.TrackItem(item,
+ trackedAs: itemName,
+ confidence: result.Confidence);
+ }
+ });
+
+ AddCommand("Track death", GetTrackDeathRule(), (result) =>
+ {
+ var death = ItemService.FirstOrDefault("Death");
+ if (death == null)
+ {
+ Logger.LogError("Tried to track death, but could not find an item named 'Death'.");
+ Tracker.Say(x => x.Error);
+ return;
+ }
+
+ Tracker.TrackItem(death, confidence: result.Confidence, tryClear: false);
+ });
+
+ if (!isMultiworld)
+ {
+ AddCommand("Track available items in an area", GetTrackEverythingRule(), (result) =>
+ {
+ if (result.Semantics.ContainsKey(RoomKey))
+ {
+ var room = GetRoomFromResult(Tracker, result);
+ Tracker.ClearArea(room,
+ trackItems: true,
+ includeUnavailable: false,
+ confidence: result.Confidence);
+ }
+ else if (result.Semantics.ContainsKey(RegionKey))
+ {
+ var region = GetRegionFromResult(Tracker, result);
+ Tracker.ClearArea(region,
+ trackItems: true,
+ includeUnavailable: false,
+ confidence: result.Confidence);
+ }
+ });
+
+ AddCommand("Track all items in an area (including out-of-logic)", GetTrackEverythingIncludingOutOfLogicRule(), (result) =>
+ {
+ if (result.Semantics.ContainsKey(RoomKey))
+ {
+ var room = GetRoomFromResult(Tracker, result);
+ Tracker.ClearArea(room,
+ trackItems: true,
+ includeUnavailable: true,
+ confidence: result.Confidence);
+ }
+ else if (result.Semantics.ContainsKey(RegionKey))
+ {
+ var region = GetRegionFromResult(Tracker, result);
+ Tracker.ClearArea(region,
+ trackItems: true,
+ includeUnavailable: true,
+ confidence: result.Confidence);
+ }
+ });
+ }
+
+ AddCommand("Untrack an item", GetUntrackItemRule(), (result) =>
+ {
+ var item = GetItemFromResult(Tracker, result, out _);
+ Tracker.UntrackItem(item, result.Confidence);
+ });
+
+ AddCommand("Set item count", GetSetItemCountRule(), (result) =>
+ {
+ var item = GetItemFromResult(Tracker, result, out _);
+ var count = (int)result.Semantics[ItemCountKey].Value;
+ Tracker.TrackItemAmount(item, count, result.Confidence);
+ });
+ }
}
}
diff --git a/src/Randomizer.SMZ3.Tracking/VoiceCommands/LocationTrackingModule.cs b/src/Randomizer.SMZ3.Tracking/VoiceCommands/LocationTrackingModule.cs
index 1edb29b27..fa845ceab 100644
--- a/src/Randomizer.SMZ3.Tracking/VoiceCommands/LocationTrackingModule.cs
+++ b/src/Randomizer.SMZ3.Tracking/VoiceCommands/LocationTrackingModule.cs
@@ -1,4 +1,5 @@
-using Microsoft.Extensions.Logging;
+using System.Diagnostics.CodeAnalysis;
+using Microsoft.Extensions.Logging;
using Randomizer.SMZ3.Tracking.Services;
@@ -20,68 +21,7 @@ public class LocationTrackingModule : TrackerModule
public LocationTrackingModule(Tracker tracker, IItemService itemService, IWorldService worldService, ILogger logger)
: base(tracker, itemService, worldService, logger)
{
- AddCommand("Mark item at specific location", GetMarkItemAtLocationRule(), (result) =>
- {
- var item = GetItemFromResult(tracker, result, out _);
- var location = GetLocationFromResult(tracker, result);
- tracker.MarkLocation(location, item, result.Confidence);
- });
-
- AddCommand("Clear specific item location", GetClearLocationRule(), (result) =>
- {
- var location = GetLocationFromResult(tracker, result);
- tracker.Clear(location, result.Confidence);
- });
-
- AddCommand("Clear available items in an area", GetClearAreaRule(), (result) =>
- {
- if (result.Semantics.ContainsKey(RoomKey))
- {
- var room = GetRoomFromResult(tracker, result);
- tracker.ClearArea(room,
- trackItems: false,
- includeUnavailable: false,
- confidence: result.Confidence);
- }
- else if (result.Semantics.ContainsKey(DungeonKey))
- {
- var dungeon = GetDungeonFromResult(tracker, result);
- tracker.ClearDungeon(dungeon, result.Confidence);
- }
- else if (result.Semantics.ContainsKey(RegionKey))
- {
- var region = GetRegionFromResult(tracker, result);
- tracker.ClearArea(region,
- trackItems:false,
- includeUnavailable: false,
- confidence: result.Confidence);
- }
- });
- AddCommand("Clear all items in an area (including out-of-logic)", GetClearAreaIncludingOutOfLogicRule(), (result) =>
- {
- if (result.Semantics.ContainsKey(RoomKey))
- {
- var room = GetRoomFromResult(tracker, result);
- tracker.ClearArea(room,
- trackItems: false,
- includeUnavailable: true,
- confidence: result.Confidence);
- }
- else if (result.Semantics.ContainsKey(DungeonKey))
- {
- var dungeon = GetDungeonFromResult(tracker, result);
- tracker.ClearDungeon(dungeon, result.Confidence);
- }
- else if (result.Semantics.ContainsKey(RegionKey))
- {
- var region = GetRegionFromResult(tracker, result);
- tracker.ClearArea(region,
- trackItems:false,
- includeUnavailable: true,
- confidence: result.Confidence);
- }
- });
}
private GrammarBuilder GetMarkItemAtLocationRule()
@@ -187,5 +127,72 @@ private GrammarBuilder GetClearAreaIncludingOutOfLogicRule()
return GrammarBuilder.Combine(clearDungeon, clearRoom, clearRegion);
}
+
+ [SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")]
+ public override void AddCommands()
+ {
+ AddCommand("Mark item at specific location", GetMarkItemAtLocationRule(), (result) =>
+ {
+ var item = GetItemFromResult(Tracker, result, out _);
+ var location = GetLocationFromResult(Tracker, result);
+ Tracker.MarkLocation(location, item, result.Confidence);
+ });
+
+ AddCommand("Clear specific item location", GetClearLocationRule(), (result) =>
+ {
+ var location = GetLocationFromResult(Tracker, result);
+ Tracker.Clear(location, result.Confidence);
+ });
+
+ AddCommand("Clear available items in an area", GetClearAreaRule(), (result) =>
+ {
+ if (result.Semantics.ContainsKey(RoomKey))
+ {
+ var room = GetRoomFromResult(Tracker, result);
+ Tracker.ClearArea(room,
+ trackItems: false,
+ includeUnavailable: false,
+ confidence: result.Confidence);
+ }
+ else if (result.Semantics.ContainsKey(DungeonKey))
+ {
+ var dungeon = GetDungeonFromResult(Tracker, result);
+ Tracker.ClearDungeon(dungeon, result.Confidence);
+ }
+ else if (result.Semantics.ContainsKey(RegionKey))
+ {
+ var region = GetRegionFromResult(Tracker, result);
+ Tracker.ClearArea(region,
+ trackItems:false,
+ includeUnavailable: false,
+ confidence: result.Confidence);
+ }
+ });
+
+ AddCommand("Clear all items in an area (including out-of-logic)", GetClearAreaIncludingOutOfLogicRule(), (result) =>
+ {
+ if (result.Semantics.ContainsKey(RoomKey))
+ {
+ var room = GetRoomFromResult(Tracker, result);
+ Tracker.ClearArea(room,
+ trackItems: false,
+ includeUnavailable: true,
+ confidence: result.Confidence);
+ }
+ else if (result.Semantics.ContainsKey(DungeonKey))
+ {
+ var dungeon = GetDungeonFromResult(Tracker, result);
+ Tracker.ClearDungeon(dungeon, result.Confidence);
+ }
+ else if (result.Semantics.ContainsKey(RegionKey))
+ {
+ var region = GetRegionFromResult(Tracker, result);
+ Tracker.ClearArea(region,
+ trackItems:false,
+ includeUnavailable: true,
+ confidence: result.Confidence);
+ }
+ });
+ }
}
}
diff --git a/src/Randomizer.SMZ3.Tracking/VoiceCommands/MapModule.cs b/src/Randomizer.SMZ3.Tracking/VoiceCommands/MapModule.cs
index 8663ba9c3..8da986550 100644
--- a/src/Randomizer.SMZ3.Tracking/VoiceCommands/MapModule.cs
+++ b/src/Randomizer.SMZ3.Tracking/VoiceCommands/MapModule.cs
@@ -28,8 +28,58 @@ public MapModule(Tracker tracker, IItemService itemService, ILogger l
{
_logger = logger;
_config = config;
+ }
+
+ private GrammarBuilder GetChangeMapRule()
+ {
+ var dungeonNames = GetDungeonNames(includeDungeonsWithoutReward: true);
+ var itemNames = GetItemNames(x => x.Name != "Content");
+ var locationNames = GetLocationNames();
+ var roomNames = GetRoomNames();
+
+ var maps = new Choices();
+ foreach (var map in _config.Maps)
+ {
+ foreach (var name in map.Name)
+ {
+ maps.Add(new SemanticResultValue(name, map.ToString()));
+ }
+ }
+
+ var version1 = new GrammarBuilder()
+ .Append("Hey tracker,")
+ .Optional("please", "would you kindly")
+ .OneOf("update my map to", "change my map to")
+ .Append(MapKey, maps);
+
+ var version2 = new GrammarBuilder()
+ .Append("Hey tracker,")
+ .Optional("please", "would you kindly")
+ .OneOf("show me")
+ .Optional("the")
+ .Append(MapKey, maps)
+ .Optional("map");
+
+ return GrammarBuilder.Combine(version1, version2);
+ }
+
+ private GrammarBuilder DarkRoomRule()
+ {
+ return new GrammarBuilder()
+ .Append("Hey tracker,")
+ .OneOf("it's dark in here", "I can't see", "show me this dark room map");
+ }
+
+ private GrammarBuilder CanSeeRule()
+ {
+ return new GrammarBuilder()
+ .Append("Hey tracker,")
+ .OneOf("I can see now", "I can see clearly now", "it's no longer dark", "I'm out of the dark room", "stop showing me the dark room map");
+ }
- var darkRoomMaps = config.Maps.Where(x => x.IsDarkRoomMap == true && x.MemoryRoomNumbers?.Count > 0).ToList();
+ public override void AddCommands()
+ {
+ var darkRoomMaps = _config.Maps.Where(x => x.IsDarkRoomMap == true && x.MemoryRoomNumbers?.Count > 0).ToList();
AddCommand("Update map", GetChangeMapRule(), (result) =>
{
@@ -53,7 +103,7 @@ public MapModule(Tracker tracker, IItemService itemService, ILogger l
if (map != null)
{
- if (itemService.IsTracked(Shared.ItemType.Lamp))
+ if (ItemService.IsTracked(Shared.ItemType.Lamp))
{
Tracker.Say(x => x.Map.HasLamp);
return;
@@ -87,52 +137,5 @@ public MapModule(Tracker tracker, IItemService itemService, ILogger l
}
});
}
-
- private GrammarBuilder GetChangeMapRule()
- {
- var dungeonNames = GetDungeonNames(includeDungeonsWithoutReward: true);
- var itemNames = GetItemNames(x => x.Name != "Content");
- var locationNames = GetLocationNames();
- var roomNames = GetRoomNames();
-
- var maps = new Choices();
- foreach (var map in _config.Maps)
- {
- foreach (var name in map.Name)
- {
- maps.Add(new SemanticResultValue(name, map.ToString()));
- }
- }
-
- var version1 = new GrammarBuilder()
- .Append("Hey tracker,")
- .Optional("please", "would you kindly")
- .OneOf("update my map to", "change my map to")
- .Append(MapKey, maps);
-
- var version2 = new GrammarBuilder()
- .Append("Hey tracker,")
- .Optional("please", "would you kindly")
- .OneOf("show me")
- .Optional("the")
- .Append(MapKey, maps)
- .Optional("map");
-
- return GrammarBuilder.Combine(version1, version2);
- }
-
- private GrammarBuilder DarkRoomRule()
- {
- return new GrammarBuilder()
- .Append("Hey tracker,")
- .OneOf("it's dark in here", "I can't see", "show me this dark room map");
- }
-
- private GrammarBuilder CanSeeRule()
- {
- return new GrammarBuilder()
- .Append("Hey tracker,")
- .OneOf("I can see now", "I can see clearly now", "it's no longer dark", "I'm out of the dark room", "stop showing me the dark room map");
- }
}
}
diff --git a/src/Randomizer.SMZ3.Tracking/VoiceCommands/MetaModule.cs b/src/Randomizer.SMZ3.Tracking/VoiceCommands/MetaModule.cs
index ae91e9bc9..f78967682 100644
--- a/src/Randomizer.SMZ3.Tracking/VoiceCommands/MetaModule.cs
+++ b/src/Randomizer.SMZ3.Tracking/VoiceCommands/MetaModule.cs
@@ -1,4 +1,5 @@
using System;
+using System.Diagnostics.CodeAnalysis;
using System.Speech.Recognition;
using Microsoft.Extensions.Logging;
@@ -12,6 +13,7 @@ namespace Randomizer.SMZ3.Tracking.VoiceCommands
///
public class MetaModule : TrackerModule
{
+ private readonly ICommunicator _communicator;
private const string ModifierKey = "Increase/Decrease";
private const string ThresholdSettingKey = "ThresholdSetting";
private const string ValueKey = "Value";
@@ -30,100 +32,10 @@ public class MetaModule : TrackerModule
public MetaModule(Tracker tracker, IItemService itemService, IWorldService worldService, ILogger logger, ICommunicator communicator)
: base(tracker, itemService, worldService, logger)
{
- AddCommand("Repeat that", GetRepeatThatRule(), (result) =>
- {
- tracker.Repeat();
- });
-
- AddCommand("Shut up", GetShutUpRule(), (result) =>
- {
- tracker.ShutUp();
- });
-
- AddCommand("Temporarily change threshold setting", GetIncreaseThresholdGrammar(), (result) =>
- {
- var modifier = (int)result.Semantics[ModifierKey].Value;
- var thresholdSetting = (int)result.Semantics[ThresholdSettingKey].Value;
- var value = (float)(double)result.Semantics[ValueKey].Value;
-
- var adjustment = modifier * value;
- switch (thresholdSetting)
- {
- case ThresholdSetting_Recognition:
- Tracker.Options.MinimumRecognitionConfidence += adjustment;
- Tracker.Say(Tracker.Responses.TrackerSettingChanged.Format(
- "recognition threshold", $"{Tracker.Options.MinimumRecognitionConfidence:P0}"));
- logger.LogInformation("Temporarily changed recognition threshold to {newValue}", Tracker.Options.MinimumRecognitionConfidence);
- break;
-
- case ThresholdSetting_Execution:
- Tracker.Options.MinimumExecutionConfidence += adjustment;
- Tracker.Say(Tracker.Responses.TrackerSettingChanged.Format(
- "execution threshold", $"{Tracker.Options.MinimumExecutionConfidence:P0}"));
- logger.LogInformation("Temporarily changed execution threshold to {newValue}", Tracker.Options.MinimumExecutionConfidence);
- break;
-
- case ThresholdSetting_Sass:
- Tracker.Options.MinimumSassConfidence += adjustment;
- Tracker.Say(Tracker.Responses.TrackerSettingChanged.Format(
- "sass threshold", $"{Tracker.Options.MinimumSassConfidence:P0}"));
- logger.LogInformation("Temporarily changed sass threshold to {newValue}", Tracker.Options.MinimumSassConfidence);
- break;
-
- default:
- throw new ArgumentException($"The threshold setting '{thresholdSetting}' was not recognized.");
- }
- });
-
- AddCommand("Pause timer", GetPauseTimerRule(), (result) =>
- {
- tracker.PauseTimer();
- });
-
- AddCommand("Start timer", GetResumeTimerRule(), (result) =>
- {
- tracker.StartTimer();
- });
-
- AddCommand("Reset timer", GetResetTimerRule(), (result) =>
- {
- tracker.ResetTimer();
- });
-
- AddCommand("Mute", GetMuteRule(), (result) =>
- {
- if (communicator.IsEnabled)
- {
- tracker.Say(x => x.Muted);
- communicator.Disable();
- tracker.AddUndo(() =>
- {
- communicator.Enable();
- Tracker.Say(x => x.ActionUndone);
- });
- }
-
- });
-
- AddCommand("Unmute", GetUnmuteRule(), (result) =>
- {
- if (!communicator.IsEnabled)
- {
- communicator.Enable();
- tracker.Say(x => x.Unmuted);
- tracker.AddUndo(() =>
- {
- communicator.Disable();
- });
- }
- });
-
- AddCommand("Beat game", GetBeatGameRule(), (result) =>
- {
- tracker.GameBeaten(false);
- });
+ _communicator = communicator;
}
+ [SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")]
private static Choices GetIncreaseDecrease()
{
var modifiers = new Choices();
@@ -132,6 +44,7 @@ private static Choices GetIncreaseDecrease()
return modifiers;
}
+ [SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")]
private static Choices GetOneThroughTenPercent()
{
var values = new Choices();
@@ -148,6 +61,7 @@ private static Choices GetOneThroughTenPercent()
return values;
}
+ [SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")]
private static Choices GetThresholdSettings()
{
var settings = new Choices();
@@ -238,5 +152,102 @@ private GrammarBuilder GetBeatGameRule()
.OneOf("I beat", "I finished")
.OneOf("the game", "the seed");
}
+
+ [SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")]
+ public override void AddCommands()
+ {
+ AddCommand("Repeat that", GetRepeatThatRule(), (_) =>
+ {
+ Tracker.Repeat();
+ });
+
+ AddCommand("Shut up", GetShutUpRule(), (_) =>
+ {
+ Tracker.ShutUp();
+ });
+
+ AddCommand("Temporarily change threshold setting", GetIncreaseThresholdGrammar(), (result) =>
+ {
+ var modifier = (int)result.Semantics[ModifierKey].Value;
+ var thresholdSetting = (int)result.Semantics[ThresholdSettingKey].Value;
+ var value = (float)(double)result.Semantics[ValueKey].Value;
+
+ var adjustment = modifier * value;
+ switch (thresholdSetting)
+ {
+ case ThresholdSetting_Recognition:
+ Tracker.Options.MinimumRecognitionConfidence += adjustment;
+ Tracker.Say(Tracker.Responses.TrackerSettingChanged.Format(
+ "recognition threshold", $"{Tracker.Options.MinimumRecognitionConfidence:P0}"));
+ Logger.LogInformation("Temporarily changed recognition threshold to {newValue}", Tracker.Options.MinimumRecognitionConfidence);
+ break;
+
+ case ThresholdSetting_Execution:
+ Tracker.Options.MinimumExecutionConfidence += adjustment;
+ Tracker.Say(Tracker.Responses.TrackerSettingChanged.Format(
+ "execution threshold", $"{Tracker.Options.MinimumExecutionConfidence:P0}"));
+ Logger.LogInformation("Temporarily changed execution threshold to {newValue}", Tracker.Options.MinimumExecutionConfidence);
+ break;
+
+ case ThresholdSetting_Sass:
+ Tracker.Options.MinimumSassConfidence += adjustment;
+ Tracker.Say(Tracker.Responses.TrackerSettingChanged.Format(
+ "sass threshold", $"{Tracker.Options.MinimumSassConfidence:P0}"));
+ Logger.LogInformation("Temporarily changed sass threshold to {newValue}", Tracker.Options.MinimumSassConfidence);
+ break;
+
+ default:
+ throw new ArgumentException($"The threshold setting '{thresholdSetting}' was not recognized.");
+ }
+ });
+
+ AddCommand("Pause timer", GetPauseTimerRule(), (_) =>
+ {
+ Tracker.PauseTimer();
+ });
+
+ AddCommand("Start timer", GetResumeTimerRule(), (_) =>
+ {
+ Tracker.StartTimer();
+ });
+
+ AddCommand("Reset timer", GetResetTimerRule(), (_) =>
+ {
+ Tracker.ResetTimer();
+ });
+
+ AddCommand("Mute", GetMuteRule(), (_) =>
+ {
+ if (_communicator.IsEnabled)
+ {
+ Tracker.Say(x => x.Muted);
+ _communicator.Disable();
+ Tracker.AddUndo(() =>
+ {
+ _communicator.Enable();
+ Tracker.Say(x => x.ActionUndone);
+ });
+ }
+
+ });
+
+ AddCommand("Unmute", GetUnmuteRule(), (_) =>
+ {
+ if (!_communicator.IsEnabled)
+ {
+ _communicator.Enable();
+ Tracker.Say(x => x.Unmuted);
+ Tracker.AddUndo(() =>
+ {
+ _communicator.Disable();
+ });
+ }
+ });
+
+ AddCommand("Beat game", GetBeatGameRule(), (_) =>
+ {
+ Tracker.GameBeaten(false);
+ });
+ }
}
}
diff --git a/src/Randomizer.SMZ3.Tracking/VoiceCommands/MsuModule.cs b/src/Randomizer.SMZ3.Tracking/VoiceCommands/MsuModule.cs
index 46e6049f9..6d142670d 100644
--- a/src/Randomizer.SMZ3.Tracking/VoiceCommands/MsuModule.cs
+++ b/src/Randomizer.SMZ3.Tracking/VoiceCommands/MsuModule.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Speech.Recognition;
using System.Timers;
@@ -9,7 +10,6 @@
using MSURandomizerLibrary.Models;
using MSURandomizerLibrary.Services;
using Randomizer.Data.Configuration.ConfigFiles;
-using Randomizer.Data.Configuration.ConfigTypes;
using Randomizer.Data.Options;
using Randomizer.SMZ3.Tracking.Services;
@@ -27,8 +27,8 @@ public class MsuModule : TrackerModule, IDisposable
private readonly Timer? _timer;
private readonly MsuType? _msuType;
private readonly MsuConfig _msuConfig;
- private readonly string MsuKey = "MsuKey";
- private int _currentTrackNumber = 0;
+ private readonly string _msuKey = "MsuKey";
+ private int _currentTrackNumber;
private readonly HashSet _validTrackNumbers;
private Track? _currentTrack;
@@ -91,65 +91,6 @@ public MsuModule(Tracker tracker, IItemService itemService, IWorldService worldS
tracker.TrackNumberUpdated += TrackerOnTrackNumberUpdated;
- AddCommand("location song", GetLocationSongRules(), (result) =>
- {
- if (_currentMsu == null)
- {
- Tracker.Say(_msuConfig.UnknownSong);
- return;
- }
-
- var trackNumber = (int)result.Semantics[MsuKey].Value;
- var track = _currentMsu.GetTrackFor(trackNumber);
- if (track != null)
- {
- Tracker.Say(_msuConfig.CurrentSong, GetTrackText(track));
- }
- else
- {
- Tracker.Say(_msuConfig.UnknownSong);
- }
- });
-
- AddCommand("location msu", GetLocationMsuRules(), (result) =>
- {
- if (_currentMsu == null)
- {
- Tracker.Say(_msuConfig.UnknownSong);
- return;
- }
-
- var trackNumber = (int)result.Semantics[MsuKey].Value;
- var track = _currentMsu.GetTrackFor(trackNumber);
- if (track?.GetMsuName() != null)
- {
- Tracker.Say(_msuConfig.CurrentMsu, track.GetMsuName());
- }
- else
- {
- Tracker.Say(_msuConfig.UnknownSong);
- }
- });
-
- AddCommand("current song", GetCurrentSongRules(), (result) =>
- {
- if (_currentTrack == null)
- {
- Tracker.Say(_msuConfig.UnknownSong);
- return;
- }
- Tracker.Say(_msuConfig.CurrentSong, GetTrackText(_currentTrack));
- });
-
- AddCommand("current msu", GetCurrentMsuRules(), (result) =>
- {
- if (_currentTrack == null)
- {
- Tracker.Say(_msuConfig.UnknownSong);
- return;
- }
- Tracker.Say(_msuConfig.CurrentMsu, _currentTrack.GetMsuName());
- });
}
private void TrackerOnTrackNumberUpdated(object? sender, TrackNumberEventArgs e)
@@ -177,7 +118,7 @@ private void TrackerOnTrackNumberUpdated(object? sender, TrackNumberEventArgs e)
}
}
- Logger.LogInformation("Current Track: {Track}", _currentTrack?.GetDisplayText(true) ?? "Unknown");
+ Logger.LogInformation("Current Track: {Track}", _currentTrack?.GetDisplayText() ?? "Unknown");
}
private string GetOutputText()
@@ -232,6 +173,7 @@ private string GetOutputText()
}
}
+ [SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")]
private GrammarBuilder GetLocationSongRules()
{
var msuLocations = new Choices();
@@ -248,18 +190,19 @@ private GrammarBuilder GetLocationSongRules()
.Append("Hey tracker,")
.OneOf("what's the current song for", "what's the song for", "what's the current theme for", "what's the theme for")
.Optional("the")
- .Append(MsuKey, msuLocations);
+ .Append(_msuKey, msuLocations);
var option2 = new GrammarBuilder()
.Append("Hey tracker,")
.OneOf("what's the current", "what's the")
- .Append(MsuKey, msuLocations)
+ .Append(_msuKey, msuLocations)
.OneOf("song", "theme");
return GrammarBuilder.Combine(option1, option2);
}
+ [SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")]
private GrammarBuilder GetLocationMsuRules()
{
var msuLocations = new Choices();
@@ -277,14 +220,14 @@ private GrammarBuilder GetLocationMsuRules()
.Append("what MSU pack is")
.OneOf("the current song for", "the song for", "the current theme for", "the theme for")
.Optional("the")
- .Append(MsuKey, msuLocations)
+ .Append(_msuKey, msuLocations)
.Append("from");
var option2 = new GrammarBuilder()
.Append("Hey tracker,")
.Append("what MSU pack is")
.OneOf("the current", "the")
- .Append(MsuKey, msuLocations)
+ .Append(_msuKey, msuLocations)
.OneOf("song", "theme")
.Append("from");
@@ -312,6 +255,7 @@ private string GetTrackText(Track track)
return string.Join("; ", parts);
}
+ [SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")]
private GrammarBuilder GetCurrentSongRules()
{
var msuLocations = new Choices();
@@ -364,4 +308,68 @@ public void Dispose()
_timer.Dispose();
}
}
+
+ [SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")]
+ public override void AddCommands()
+ {
+ AddCommand("location song", GetLocationSongRules(), (result) =>
+ {
+ if (_currentMsu == null)
+ {
+ Tracker.Say(_msuConfig.UnknownSong);
+ return;
+ }
+
+ var trackNumber = (int)result.Semantics[_msuKey].Value;
+ var track = _currentMsu.GetTrackFor(trackNumber);
+ if (track != null)
+ {
+ Tracker.Say(_msuConfig.CurrentSong, GetTrackText(track));
+ }
+ else
+ {
+ Tracker.Say(_msuConfig.UnknownSong);
+ }
+ });
+
+ AddCommand("location msu", GetLocationMsuRules(), (result) =>
+ {
+ if (_currentMsu == null)
+ {
+ Tracker.Say(_msuConfig.UnknownSong);
+ return;
+ }
+
+ var trackNumber = (int)result.Semantics[_msuKey].Value;
+ var track = _currentMsu.GetTrackFor(trackNumber);
+ if (track?.GetMsuName() != null)
+ {
+ Tracker.Say(_msuConfig.CurrentMsu, track.GetMsuName());
+ }
+ else
+ {
+ Tracker.Say(_msuConfig.UnknownSong);
+ }
+ });
+
+ AddCommand("current song", GetCurrentSongRules(), (_) =>
+ {
+ if (_currentTrack == null)
+ {
+ Tracker.Say(_msuConfig.UnknownSong);
+ return;
+ }
+ Tracker.Say(_msuConfig.CurrentSong, GetTrackText(_currentTrack));
+ });
+
+ AddCommand("current msu", GetCurrentMsuRules(), (_) =>
+ {
+ if (_currentTrack == null)
+ {
+ Tracker.Say(_msuConfig.UnknownSong);
+ return;
+ }
+ Tracker.Say(_msuConfig.CurrentMsu, _currentTrack.GetMsuName());
+ });
+ }
}
diff --git a/src/Randomizer.SMZ3.Tracking/VoiceCommands/MultiplayerModule.cs b/src/Randomizer.SMZ3.Tracking/VoiceCommands/MultiplayerModule.cs
index 94087cca3..1a60dda90 100644
--- a/src/Randomizer.SMZ3.Tracking/VoiceCommands/MultiplayerModule.cs
+++ b/src/Randomizer.SMZ3.Tracking/VoiceCommands/MultiplayerModule.cs
@@ -257,4 +257,8 @@ private async void TrackerOnPlayerDied(object? sender, TrackerEventArgs e)
await _multiplayerGameService.TrackDeath();
}
+ public override void AddCommands()
+ {
+
+ }
}
diff --git a/src/Randomizer.SMZ3.Tracking/VoiceCommands/PegWorldModeModule.cs b/src/Randomizer.SMZ3.Tracking/VoiceCommands/PegWorldModeModule.cs
index 4dc81faa7..1d0a6f421 100644
--- a/src/Randomizer.SMZ3.Tracking/VoiceCommands/PegWorldModeModule.cs
+++ b/src/Randomizer.SMZ3.Tracking/VoiceCommands/PegWorldModeModule.cs
@@ -1,4 +1,5 @@
-using Microsoft.Extensions.Logging;
+using System.Diagnostics.CodeAnalysis;
+using Microsoft.Extensions.Logging;
using Randomizer.SMZ3.Tracking.Services;
@@ -21,6 +22,12 @@ public class PegWorldModeModule : TrackerModule, IOptionalModule
/// Used to log information.
public PegWorldModeModule(Tracker tracker, IItemService itemService, IWorldService worldService, ILogger logger)
: base(tracker, itemService, worldService, logger)
+ {
+
+ }
+
+ [SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")]
+ public override void AddCommands()
{
AddCommand("Toggle Peg World mode on", new[] {
"Hey tracker, toggle Peg World Mode on",
@@ -28,7 +35,7 @@ public PegWorldModeModule(Tracker tracker, IItemService itemService, IWorldServi
"Hey tracker, let's go to Peg World!"
}, (result) =>
{
- tracker.StartPegWorldMode(result.Confidence);
+ Tracker.StartPegWorldMode(result.Confidence);
});
AddCommand("Toggle Peg World mode off", new[] {
@@ -39,7 +46,7 @@ public PegWorldModeModule(Tracker tracker, IItemService itemService, IWorldServi
"Hey tracker, release me from Peg World"
}, (result) =>
{
- tracker.StopPegWorldMode(result.Confidence);
+ Tracker.StopPegWorldMode(result.Confidence);
});
AddCommand("Track Peg World peg", new[] {
@@ -47,9 +54,9 @@ public PegWorldModeModule(Tracker tracker, IItemService itemService, IWorldServi
"Hey tracker, peg."
}, (result) =>
{
- if (tracker.PegsPegged < TotalPegs)
+ if (Tracker.PegsPegged < TotalPegs)
{
- tracker.Peg(result.Confidence);
+ Tracker.Peg(result.Confidence);
}
});
}
diff --git a/src/Randomizer.SMZ3.Tracking/VoiceCommands/PersonalityModule.cs b/src/Randomizer.SMZ3.Tracking/VoiceCommands/PersonalityModule.cs
index d030afdc5..45129233f 100644
--- a/src/Randomizer.SMZ3.Tracking/VoiceCommands/PersonalityModule.cs
+++ b/src/Randomizer.SMZ3.Tracking/VoiceCommands/PersonalityModule.cs
@@ -23,25 +23,30 @@ public class PersonalityModule : TrackerModule
public PersonalityModule(Tracker tracker, IItemService itemService, IWorldService worldService, ILogger logger)
: base(tracker, itemService, worldService, logger)
{
- AddCommand("Ask about tracker's mood", GetMoodRule(), (result) =>
+
+ }
+
+ public override void AddCommands()
+ {
+ AddCommand("Ask about tracker's mood", GetMoodRule(), (_) =>
{
- tracker.Say(tracker.Responses.Moods[tracker.Mood]);
+ Tracker.Say(Tracker.Responses.Moods[Tracker.Mood]);
});
- AddCommand("Hey, ya missed pal", GetYaMissedRule(), (result) =>
+ AddCommand("Hey, ya missed pal", GetYaMissedRule(), (_) =>
{
- tracker.Say("Here Mike. This will explain everything.", wait: true);
+ Tracker.Say("Here Mike. This will explain everything.", wait: true);
OpenInBrowser(new Uri("https://www.youtube.com/watch?v=5P6UirFDdxM"));
});
- foreach (var request in tracker.Requests)
+ foreach (var request in Tracker.Requests)
{
if (request.Phrases.Count == 0)
continue;
- AddCommand(request.Phrases.First(), GetRequestRule(request.Phrases), (result) =>
+ AddCommand(request.Phrases.First(), GetRequestRule(request.Phrases), (_) =>
{
- tracker.Say(request.Response);
+ Tracker.Say(request.Response);
});
}
}
diff --git a/src/Randomizer.SMZ3.Tracking/VoiceCommands/SpoilerModule.cs b/src/Randomizer.SMZ3.Tracking/VoiceCommands/SpoilerModule.cs
index 652045f6c..1a7646a55 100644
--- a/src/Randomizer.SMZ3.Tracking/VoiceCommands/SpoilerModule.cs
+++ b/src/Randomizer.SMZ3.Tracking/VoiceCommands/SpoilerModule.cs
@@ -2,13 +2,11 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
-
using Microsoft.Extensions.Logging;
using Randomizer.Data.Logic;
using Randomizer.Data.WorldData.Regions;
using Randomizer.Data.WorldData;
using Randomizer.Shared;
-using Randomizer.SMZ3.Text;
using Randomizer.Data.Configuration;
using Randomizer.Data.Configuration.ConfigTypes;
using Randomizer.SMZ3.Tracking.Services;
@@ -32,10 +30,9 @@ public class SpoilerModule : TrackerModule, IOptionalModule
private readonly Dictionary _itemHintsGiven = new();
private readonly Dictionary _locationHintsGiven = new();
- private readonly Playthrough? _playthrough;
+ private Playthrough? _playthrough;
private readonly IRandomizerConfigService _randomizerConfigService;
private readonly bool _isMultiworld;
- private readonly int _localWorldId;
///
/// Initializes a new instance of the class.
@@ -48,64 +45,10 @@ public class SpoilerModule : TrackerModule, IOptionalModule
public SpoilerModule(Tracker tracker, IItemService itemService, ILogger logger, IWorldService worldService, IRandomizerConfigService randomizerConfigService)
: base(tracker, itemService, worldService, logger)
{
- Tracker.HintsEnabled = !tracker.World.Config.Race && !tracker.World.Config.DisableTrackerHints && tracker.Options.HintsEnabled;
- Tracker.SpoilersEnabled = !tracker.World.Config.Race && !tracker.World.Config.DisableTrackerSpoilers && tracker.Options.SpoilersEnabled;
+ Tracker.HintsEnabled = tracker.World.Config is { Race: false, DisableTrackerHints: false } && tracker.Options.HintsEnabled;
+ Tracker.SpoilersEnabled = tracker.World.Config is { Race: false, DisableTrackerSpoilers: false } && tracker.Options.SpoilersEnabled;
_randomizerConfigService = randomizerConfigService;
_isMultiworld = tracker.World.Config.MultiWorld;
- _localWorldId = worldService.World.Id;
- if (tracker.World.Config.Race) return;
-
- Playthrough.TryGenerate(new[] { tracker.World }, tracker.World.Config, out _playthrough);
-
- if (!tracker.World.Config.DisableTrackerHints)
- {
- AddCommand("Enable hints", GetEnableHintsRule(), (result) =>
- {
- Tracker.HintsEnabled = true;
- tracker.Say(x => x.Hints.EnabledHints);
- });
- AddCommand("Disable hints", GetDisableHintsRule(), (result) =>
- {
- Tracker.HintsEnabled = false;
- tracker.Say(x => x.Hints.DisabledHints);
- });
- AddCommand("Give progression hint", GetProgressionHintRule(), (result) =>
- {
- GiveProgressionHint();
- });
-
- AddCommand("Give area hint", GetLocationUsefulnessHintRule(), (result) =>
- {
- var area = GetAreaFromResult(tracker, result);
- GiveAreaHint(area);
- });
- }
-
- if (!tracker.World.Config.DisableTrackerSpoilers)
- {
- AddCommand("Enable spoilers", GetEnableSpoilersRule(), (result) =>
- {
- Tracker.SpoilersEnabled = true;
- tracker.Say(x => x.Spoilers.EnabledSpoilers);
- });
- AddCommand("Disable spoilers", GetDisableSpoilersRule(), (result) =>
- {
- Tracker.SpoilersEnabled = false;
- tracker.Say(x => x.Spoilers.DisabledSpoilers);
- });
-
- AddCommand("Reveal item location", GetItemSpoilerRule(), (result) =>
- {
- var item = GetItemFromResult(tracker, result, out var itemName);
- RevealItemLocation(item);
- });
-
- AddCommand("Reveal location item", GetLocationSpoilerRule(), (result) =>
- {
- var location = GetLocationFromResult(tracker, result);
- RevealLocationItem(location);
- });
- }
}
private Config Config => _randomizerConfigService.Config;
@@ -113,9 +56,9 @@ public SpoilerModule(Tracker tracker, IItemService itemService, ILogger
/// Gives a hint about where to go next.
///
- public void GiveProgressionHint()
+ private void GiveProgressionHint()
{
- if (!Tracker.HintsEnabled && !Tracker.SpoilersEnabled)
+ if (Tracker is { HintsEnabled: false, SpoilersEnabled: false })
{
Tracker.Say(x => x.Hints.PromptEnableItemHints);
return;
@@ -138,9 +81,9 @@ public void GiveProgressionHint()
/// Gives a hint or spoiler about useful items in an area.
///
/// The area to give hints about.
- public void GiveAreaHint(IHasLocations area)
+ private void GiveAreaHint(IHasLocations area)
{
- if (!Tracker.HintsEnabled && !Tracker.SpoilersEnabled)
+ if (Tracker is { HintsEnabled: false, SpoilersEnabled: false })
{
Tracker.Say(x => x.Hints.PromptEnableItemHints);
return;
@@ -196,7 +139,7 @@ public void GiveAreaHint(IHasLocations area)
/// Gives a hint or spoiler about the location of an item.
///
/// The item to find.
- public void RevealItemLocation(Item item)
+ private void RevealItemLocation(Item item)
{
if (item.Metadata.HasStages && item.State.TrackingState >= item.Metadata.MaxStage)
{
@@ -221,7 +164,7 @@ public void RevealItemLocation(Item item)
}
// Now that we're ready to give hints, make sure they're turned on
- if (!Tracker.HintsEnabled && !Tracker.SpoilersEnabled)
+ if (Tracker is { HintsEnabled: false, SpoilersEnabled: false })
{
Tracker.Say(x => x.Hints.PromptEnableItemHints);
return;
@@ -270,7 +213,7 @@ public void RevealItemLocation(Item item)
/// Gives a hint or spoiler about the given location.
///
/// The location to ask about.
- public void RevealLocationItem(Location location)
+ private void RevealLocationItem(Location location)
{
var locationName = location.Metadata.Name;
if (location.State.Cleared)
@@ -570,7 +513,7 @@ private bool GiveItemLocationSpoiler(Item item)
private bool GiveItemLocationHint(Item item)
{
- var itemLocations = WorldService.Locations(outOfLogic: true, itemFilter: item.Type, checkAllWorlds: true);
+ var itemLocations = WorldService.Locations(outOfLogic: true, itemFilter: item.Type, checkAllWorlds: true).ToList();
if (!itemLocations.Any())
{
@@ -692,14 +635,14 @@ private bool GiveItemLocationHint(Item item)
// - Is it in another player's ALttP or SM?
case 2:
{
- var randomLocation = GetRandomItemLocationWithFilter(item, x => true);
+ var randomLocation = GetRandomItemLocationWithFilter(item, _ => true);
if (randomLocation?.World.IsLocalWorld == false)
{
- if (randomLocation?.Region is Z3Region)
+ if (randomLocation.Region is Z3Region)
return GiveItemHint(x => x.ItemInPlayerWorldALttP, item,
randomLocation.World.Config.PhoneticName);
- else if (randomLocation?.Region is SMRegion)
+ else if (randomLocation.Region is SMRegion)
return GiveItemHint(x => x.ItemInPlayerWorldSuperMetroid, item,
randomLocation.World.Config.PhoneticName);
}
@@ -744,7 +687,7 @@ private bool GiveItemLocationHint(Item item)
var randomLocation = GetRandomItemLocationWithFilter(item,
location =>
{
- if (location.Room != null && location.Room.Metadata.Hints?.Count > 0)
+ if (location.Room is { Metadata.Hints.Count: > 0 })
return true;
return location.Metadata.Hints?.Count > 0;
});
@@ -933,5 +876,62 @@ private GrammarBuilder GetLocationUsefulnessHintRule()
return GrammarBuilder.Combine(regionGrammar, roomGrammar);
}
+
+ public override void AddCommands()
+ {
+ if (Tracker.World.Config.Race) return;
+
+ Playthrough.TryGenerate(new[] { Tracker.World }, Tracker.World.Config, out _playthrough);
+
+ if (!Tracker.World.Config.DisableTrackerHints)
+ {
+ AddCommand("Enable hints", GetEnableHintsRule(), (_) =>
+ {
+ Tracker.HintsEnabled = true;
+ Tracker.Say(x => x.Hints.EnabledHints);
+ });
+ AddCommand("Disable hints", GetDisableHintsRule(), (_) =>
+ {
+ Tracker.HintsEnabled = false;
+ Tracker.Say(x => x.Hints.DisabledHints);
+ });
+ AddCommand("Give progression hint", GetProgressionHintRule(), (_) =>
+ {
+ GiveProgressionHint();
+ });
+
+ AddCommand("Give area hint", GetLocationUsefulnessHintRule(), (result) =>
+ {
+ var area = GetAreaFromResult(Tracker, result);
+ GiveAreaHint(area);
+ });
+ }
+
+ if (!Tracker.World.Config.DisableTrackerSpoilers)
+ {
+ AddCommand("Enable spoilers", GetEnableSpoilersRule(), (_) =>
+ {
+ Tracker.SpoilersEnabled = true;
+ Tracker.Say(x => x.Spoilers.EnabledSpoilers);
+ });
+ AddCommand("Disable spoilers", GetDisableSpoilersRule(), (_) =>
+ {
+ Tracker.SpoilersEnabled = false;
+ Tracker.Say(x => x.Spoilers.DisabledSpoilers);
+ });
+
+ AddCommand("Reveal item location", GetItemSpoilerRule(), (result) =>
+ {
+ var item = GetItemFromResult(Tracker, result, out _);
+ RevealItemLocation(item);
+ });
+
+ AddCommand("Reveal location item", GetLocationSpoilerRule(), (result) =>
+ {
+ var location = GetLocationFromResult(Tracker, result);
+ RevealLocationItem(location);
+ });
+ }
+ }
}
}
diff --git a/src/Randomizer.SMZ3.Tracking/VoiceCommands/TrackerModule.cs b/src/Randomizer.SMZ3.Tracking/VoiceCommands/TrackerModule.cs
index b8ada5b0e..14fb845b5 100644
--- a/src/Randomizer.SMZ3.Tracking/VoiceCommands/TrackerModule.cs
+++ b/src/Randomizer.SMZ3.Tracking/VoiceCommands/TrackerModule.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Speech.Recognition;
@@ -73,6 +74,8 @@ protected TrackerModule(Tracker tracker, IItemService itemService, IWorldService
Logger = logger;
}
+ public abstract void AddCommands();
+
///
/// Gets a dictionary that contains the rule names and their associated
/// speech recognition patterns.
@@ -104,6 +107,7 @@ public IReadOnlyDictionary> Syntax
///
/// Gets a list of speech recognition grammars provided by the module.
///
+ [SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")]
protected IList Grammars { get; }
= new List();
@@ -304,6 +308,11 @@ protected void AddCommand(string ruleName, string[] phrases,
protected void AddCommand(string ruleName, GrammarBuilder grammarBuilder,
Action executeCommand)
{
+ if (!OperatingSystem.IsWindows())
+ {
+ return;
+ }
+
_syntax.TryAdd(ruleName, grammarBuilder.ToString().Split('\n', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries));
try
diff --git a/src/Randomizer.SMZ3.Tracking/VoiceCommands/TrackerModuleFactory.cs b/src/Randomizer.SMZ3.Tracking/VoiceCommands/TrackerModuleFactory.cs
index a3775b6da..f833d0c49 100644
--- a/src/Randomizer.SMZ3.Tracking/VoiceCommands/TrackerModuleFactory.cs
+++ b/src/Randomizer.SMZ3.Tracking/VoiceCommands/TrackerModuleFactory.cs
@@ -44,20 +44,25 @@ public TrackerModuleFactory(IServiceProvider serviceProvider, ILogger
/// A dictionary that contains the loaded speech recognition syntax.
///
- public IReadOnlyDictionary> LoadAll(Tracker tracker, SpeechRecognitionEngine engine, out bool moduleLoadError)
+ public IReadOnlyDictionary> LoadAll(Tracker tracker, SpeechRecognitionEngine? engine, out bool moduleLoadError)
{
moduleLoadError = false;
_trackerModules = _serviceProvider.GetServices();
- foreach (var module in _trackerModules)
+
+ if (engine != null && OperatingSystem.IsWindows())
{
- try
- {
- module.LoadInto(engine);
- }
- catch (InvalidOperationException e)
+ foreach (var module in _trackerModules)
{
- _logger.LogError(e, $"Error with loading module {module.GetType().Name}");
- moduleLoadError = true;
+ try
+ {
+ module.AddCommands();
+ module.LoadInto(engine);
+ }
+ catch (InvalidOperationException e)
+ {
+ _logger.LogError(e, $"Error with loading module {module.GetType().Name}");
+ moduleLoadError = true;
+ }
}
}
diff --git a/src/Randomizer.SMZ3.Tracking/VoiceCommands/UndoModule.cs b/src/Randomizer.SMZ3.Tracking/VoiceCommands/UndoModule.cs
index 254aa3bd9..d5e0135b0 100644
--- a/src/Randomizer.SMZ3.Tracking/VoiceCommands/UndoModule.cs
+++ b/src/Randomizer.SMZ3.Tracking/VoiceCommands/UndoModule.cs
@@ -1,4 +1,5 @@
-using Microsoft.Extensions.Logging;
+using System.Diagnostics.CodeAnalysis;
+using Microsoft.Extensions.Logging;
using Randomizer.SMZ3.Tracking.Services;
@@ -19,10 +20,7 @@ public class UndoModule : TrackerModule
public UndoModule(Tracker tracker, IItemService itemService, IWorldService worldService, ILogger logger)
: base(tracker, itemService, worldService, logger)
{
- AddCommand("Undo last operation", GetUndoRule(), (result) =>
- {
- tracker.Undo(result.Confidence);
- });
+
}
private GrammarBuilder GetUndoRule()
@@ -31,5 +29,14 @@ private GrammarBuilder GetUndoRule()
.Append("Hey tracker,")
.OneOf("undo that", "control Z", "that's not what I said", "take backsies");
}
+
+ [SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")]
+ public override void AddCommands()
+ {
+ AddCommand("Undo last operation", GetUndoRule(), (result) =>
+ {
+ Tracker.Undo(result.Confidence);
+ });
+ }
}
}
diff --git a/src/Randomizer.SMZ3.Tracking/VoiceCommands/ZeldaDungeonTrackingModule.cs b/src/Randomizer.SMZ3.Tracking/VoiceCommands/ZeldaDungeonTrackingModule.cs
index d6d6dcf1c..48ce41890 100644
--- a/src/Randomizer.SMZ3.Tracking/VoiceCommands/ZeldaDungeonTrackingModule.cs
+++ b/src/Randomizer.SMZ3.Tracking/VoiceCommands/ZeldaDungeonTrackingModule.cs
@@ -1,4 +1,5 @@
using System;
+using System.Diagnostics.CodeAnalysis;
using System.Speech.Recognition;
using Microsoft.Extensions.Logging;
@@ -29,43 +30,10 @@ public class ZeldaDungeonTrackingModule : TrackerModule
public ZeldaDungeonTrackingModule(Tracker tracker, IItemService itemService, IWorldService worldService, ILogger logger)
: base(tracker, itemService, worldService, logger)
{
- AddCommand("Mark dungeon pendant/crystal", GetMarkDungeonRewardRule(), (result) =>
- {
- var dungeon = GetDungeonFromResult(tracker, result);
- var reward = (RewardType)result.Semantics[RewardKey].Value;
- tracker.SetDungeonReward(dungeon, reward, result.Confidence);
- });
-
- AddCommand("Mark remaining dungeons", GetMarkRemainingDungeonRewardsRule(), (result) =>
- {
- tracker.SetUnmarkedDungeonReward(RewardType.CrystalBlue, result.Confidence);
- });
-
- AddCommand("Mark dungeon as cleared", GetClearDungeonRule(), (result) =>
- {
- var dungeon = GetDungeonFromResult(tracker, result);
- tracker.MarkDungeonAsCleared(dungeon, result.Confidence);
- });
-
- AddCommand("Mark dungeon medallion", GetMarkDungeonRequirementRule(), (result) =>
- {
- var dungeon = GetDungeonFromResult(tracker, result);
- var medallion = GetItemFromResult(tracker, result, out var itemName);
- tracker.SetDungeonRequirement(dungeon, medallion.Type, result.Confidence);
- });
- AddCommand("Clear dungeon treasure", GetTreasureTrackingRule(), (result) =>
- {
- var count = result.Semantics.ContainsKey(TreasureCountKey)
- ? (int)result.Semantics[TreasureCountKey].Value
- : 1;
- var dungeon = GetDungeonFromResult(tracker, result);
- tracker.TrackDungeonTreasure(dungeon, result.Confidence, amount: count);
-
- dungeon.DungeonState.HasManuallyClearedTreasure = true;
- });
}
+ [SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")]
private GrammarBuilder GetMarkDungeonRewardRule()
{
var dungeonNames = GetDungeonNames(includeDungeonsWithoutReward: false);
@@ -144,6 +112,7 @@ private GrammarBuilder GetMarkDungeonRequirementRule()
markDungeon, markItem);
}
+ [SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")]
private GrammarBuilder GetTreasureTrackingRule()
{
var dungeonNames = GetDungeonNames(includeDungeonsWithoutReward: true);
@@ -169,5 +138,45 @@ private GrammarBuilder GetTreasureTrackingRule()
return GrammarBuilder.Combine(clearOne, clearMultiple);
}
+
+ [SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")]
+ public override void AddCommands()
+ {
+ AddCommand("Mark dungeon pendant/crystal", GetMarkDungeonRewardRule(), (result) =>
+ {
+ var dungeon = GetDungeonFromResult(Tracker, result);
+ var reward = (RewardType)result.Semantics[RewardKey].Value;
+ Tracker.SetDungeonReward(dungeon, reward, result.Confidence);
+ });
+
+ AddCommand("Mark remaining dungeons", GetMarkRemainingDungeonRewardsRule(), (result) =>
+ {
+ Tracker.SetUnmarkedDungeonReward(RewardType.CrystalBlue, result.Confidence);
+ });
+
+ AddCommand("Mark dungeon as cleared", GetClearDungeonRule(), (result) =>
+ {
+ var dungeon = GetDungeonFromResult(Tracker, result);
+ Tracker.MarkDungeonAsCleared(dungeon, result.Confidence);
+ });
+
+ AddCommand("Mark dungeon medallion", GetMarkDungeonRequirementRule(), (result) =>
+ {
+ var dungeon = GetDungeonFromResult(Tracker, result);
+ var medallion = GetItemFromResult(Tracker, result, out _);
+ Tracker.SetDungeonRequirement(dungeon, medallion.Type, result.Confidence);
+ });
+
+ AddCommand("Clear dungeon treasure", GetTreasureTrackingRule(), (result) =>
+ {
+ var count = result.Semantics.ContainsKey(TreasureCountKey)
+ ? (int)result.Semantics[TreasureCountKey].Value
+ : 1;
+ var dungeon = GetDungeonFromResult(Tracker, result);
+ Tracker.TrackDungeonTreasure(dungeon, result.Confidence, amount: count);
+
+ dungeon.DungeonState.HasManuallyClearedTreasure = true;
+ });
+ }
}
}
diff --git a/src/Randomizer.SMZ3/Generation/Smz3GeneratedRomLoader.cs b/src/Randomizer.SMZ3/Generation/Smz3GeneratedRomLoader.cs
index e28249c3e..101ecc59a 100644
--- a/src/Randomizer.SMZ3/Generation/Smz3GeneratedRomLoader.cs
+++ b/src/Randomizer.SMZ3/Generation/Smz3GeneratedRomLoader.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Linq;
using Randomizer.Data.Configuration.ConfigTypes;
using Randomizer.Data.Options;
@@ -33,7 +34,7 @@ public Smz3GeneratedRomLoader(IWorldAccessor worldAccessor, IMetadataService met
/// the given GeneratedRom
///
///
- public void LoadGeneratedRom(GeneratedRom rom)
+ public List LoadGeneratedRom(GeneratedRom rom)
{
var trackerState = rom.TrackerState;
@@ -121,9 +122,9 @@ public void LoadGeneratedRom(GeneratedRom rom)
}
}
-
_worldAccessor.Worlds = worlds;
_worldAccessor.World = worlds.First(x => x.IsLocalWorld);
+ return worlds;
}
}
}
diff --git a/tests/Randomizer.SMZ3.Tests/LogicTests/RandomizerTests.cs b/tests/Randomizer.SMZ3.Tests/LogicTests/RandomizerTests.cs
index b9a070d73..2a7732daf 100644
--- a/tests/Randomizer.SMZ3.Tests/LogicTests/RandomizerTests.cs
+++ b/tests/Randomizer.SMZ3.Tests/LogicTests/RandomizerTests.cs
@@ -1,4 +1,5 @@
-using System.Linq;
+using System;
+using System.Linq;
using System.Text;
using FluentAssertions;
@@ -27,6 +28,12 @@ public class RandomizerTests
[InlineData("test", 558598333)] // Smz3Randomizer v4.0
public void StandardFillerWithSameSeedGeneratesSameWorld(string seed, int expectedHash)
{
+ // Apparently RNG in Linux is different than on Windows...
+ if (OperatingSystem.IsLinux())
+ {
+ expectedHash = 951851411;
+ }
+
var filler = new StandardFiller(GetLogger());
var randomizer = GetRandomizer();
var config = new Config();