From 28306e93ecf1dc042bc11853991c58c95c99bf33 Mon Sep 17 00:00:00 2001 From: MattEqualsCoder Date: Mon, 30 Dec 2024 22:58:14 -0500 Subject: [PATCH 01/13] Fix random sprites not working --- src/TrackerCouncil.Smz3.Data/Services/SpriteService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TrackerCouncil.Smz3.Data/Services/SpriteService.cs b/src/TrackerCouncil.Smz3.Data/Services/SpriteService.cs index 423cfc17..56ad04d2 100644 --- a/src/TrackerCouncil.Smz3.Data/Services/SpriteService.cs +++ b/src/TrackerCouncil.Smz3.Data/Services/SpriteService.cs @@ -210,7 +210,7 @@ public Sprite GetSprite(SpriteType type) if (sprite.IsRandomSprite) { - var spriteType = sprite.SpriteType; + var spriteType = type; var searchText = spriteType switch { From f1e05c14068e1e34e028caa9f25b15ff116f8f42 Mon Sep 17 00:00:00 2001 From: MattEqualsCoder Date: Mon, 30 Dec 2024 23:49:15 -0500 Subject: [PATCH 02/13] Fix not being able to track some items in AP mode --- src/TrackerCouncil.Smz3.Tracking/Services/WorldQueryService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TrackerCouncil.Smz3.Tracking/Services/WorldQueryService.cs b/src/TrackerCouncil.Smz3.Tracking/Services/WorldQueryService.cs index c20abcef..29535fc2 100644 --- a/src/TrackerCouncil.Smz3.Tracking/Services/WorldQueryService.cs +++ b/src/TrackerCouncil.Smz3.Tracking/Services/WorldQueryService.cs @@ -146,7 +146,7 @@ private bool IsValidLocation(Location location, bool unclearedOnly, bool outOfLo /// /// A collection of items. public IEnumerable LocalPlayersItems() - => AllItems().Where(x => x.World.Id == World.Id); + => AllItems().Where(x => x.World.Id == World.Id && x.IsLocalPlayerItem); /// /// Enumerates all rewards that can be tracked for all players. From 665e0805c27c1aaf382bba1924a25bd51f867274 Mon Sep 17 00:00:00 2001 From: MattEqualsCoder Date: Tue, 31 Dec 2024 15:48:56 -0500 Subject: [PATCH 03/13] Fix other player keys not appearing as progression --- .../Configuration/ConfigTypes/ItemData.cs | 5 +++-- src/TrackerCouncil.Smz3.Data/WorldData/Location.cs | 2 +- .../Generation/GameHintService.cs | 2 +- .../Generation/MultiplayerFiller.cs | 2 +- .../Generation/Smz3GeneratedRomLoader.cs | 2 +- .../Generation/StatGenerator.cs | 2 +- .../Enums/ItemTypeExtensions.cs | 11 ++++++----- src/TrackerCouncil.Smz3.Tracking/NaturalLanguage.cs | 4 ++-- .../TrackingServices/TrackerItemService.cs | 6 +++--- .../TrackingServices/TrackerLocationService.cs | 2 +- .../VoiceCommands/MultiplayerModule.cs | 2 +- .../VoiceCommands/SpoilerModule.cs | 4 ++-- 12 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/TrackerCouncil.Smz3.Data/Configuration/ConfigTypes/ItemData.cs b/src/TrackerCouncil.Smz3.Data/Configuration/ConfigTypes/ItemData.cs index df3d024b..153674ff 100644 --- a/src/TrackerCouncil.Smz3.Data/Configuration/ConfigTypes/ItemData.cs +++ b/src/TrackerCouncil.Smz3.Data/Configuration/ConfigTypes/ItemData.cs @@ -301,6 +301,7 @@ public bool IsJunk(Config? config) /// configuration, assuming one is provided. /// /// The randomizer configuration. + /// If the item is for the local player /// /// true if the item is considered progression; otherwise, false. /// @@ -308,10 +309,10 @@ public bool IsJunk(Config? config) /// This method only considers the item's value on its own. Call TrackerBase.IsWorth(ItemData) to include /// items that this item might logically lead to. /// - public bool IsProgression(Config? config) + public bool IsProgression(Config? config, bool isLocalPlayerItem) { // Todo: We can add special logic like checking if it's one of the first two swords - return InternalItemType.IsPossibleProgression(config?.ZeldaKeysanity == true, config?.MetroidKeysanity == true); + return InternalItemType.IsPossibleProgression(config?.ZeldaKeysanity == true, config?.MetroidKeysanity == true, isLocalPlayerItem); } /// diff --git a/src/TrackerCouncil.Smz3.Data/WorldData/Location.cs b/src/TrackerCouncil.Smz3.Data/WorldData/Location.cs index 21812fd7..7c7c6109 100644 --- a/src/TrackerCouncil.Smz3.Data/WorldData/Location.cs +++ b/src/TrackerCouncil.Smz3.Data/WorldData/Location.cs @@ -136,7 +136,7 @@ public ItemType? MarkedItem if (value != null) { State.MarkedUsefulness = - Item.Type.IsPossibleProgression(World.Config.ZeldaKeysanity, World.Config.MetroidKeysanity) + Item.Type.IsPossibleProgression(World.Config.ZeldaKeysanity, World.Config.MetroidKeysanity, Item.IsLocalPlayerItem) ? LocationUsefulness.NiceToHave : LocationUsefulness.Useless; } diff --git a/src/TrackerCouncil.Smz3.SeedGenerator/Generation/GameHintService.cs b/src/TrackerCouncil.Smz3.SeedGenerator/Generation/GameHintService.cs index 1dcebbf0..862dd450 100644 --- a/src/TrackerCouncil.Smz3.SeedGenerator/Generation/GameHintService.cs +++ b/src/TrackerCouncil.Smz3.SeedGenerator/Generation/GameHintService.cs @@ -419,7 +419,7 @@ private PlayerHintTile GetBasicLocationHint(Location location) Locations = [location.Id], Usefulness = location.ItemType.IsPossibleProgression(location.World.Config.ZeldaKeysanity, - location.World.Config.MetroidKeysanity) + location.World.Config.MetroidKeysanity, location.Item.IsLocalPlayerItem) ? LocationUsefulness.NiceToHave : LocationUsefulness.Useless }; diff --git a/src/TrackerCouncil.Smz3.SeedGenerator/Generation/MultiplayerFiller.cs b/src/TrackerCouncil.Smz3.SeedGenerator/Generation/MultiplayerFiller.cs index 91074ba4..44cf22aa 100644 --- a/src/TrackerCouncil.Smz3.SeedGenerator/Generation/MultiplayerFiller.cs +++ b/src/TrackerCouncil.Smz3.SeedGenerator/Generation/MultiplayerFiller.cs @@ -76,7 +76,7 @@ private void FillItems(World world, List worlds) var generatedData = generatedLocationData.Single(x => x.Id == location.Id); var itemType = generatedData.Item; var itemWorld = worlds.Single(x => x.Id == generatedData.ItemWorldId); - location.Item = new Item(itemType, itemWorld, isProgression: itemType.IsPossibleProgression(itemWorld.Config.ZeldaKeysanity, itemWorld.Config.MetroidKeysanity)); + location.Item = new Item(itemType, itemWorld, isProgression: itemType.IsPossibleProgression(itemWorld.Config.ZeldaKeysanity, itemWorld.Config.MetroidKeysanity, itemWorld == world)); _logger.LogDebug("Fast-filled {Item} at {Location}", generatedData.Item, location.Name); } EnsureLocationsHaveItems(world); diff --git a/src/TrackerCouncil.Smz3.SeedGenerator/Generation/Smz3GeneratedRomLoader.cs b/src/TrackerCouncil.Smz3.SeedGenerator/Generation/Smz3GeneratedRomLoader.cs index cbd8f717..f6199b48 100644 --- a/src/TrackerCouncil.Smz3.SeedGenerator/Generation/Smz3GeneratedRomLoader.cs +++ b/src/TrackerCouncil.Smz3.SeedGenerator/Generation/Smz3GeneratedRomLoader.cs @@ -71,7 +71,7 @@ public List LoadGeneratedRom(GeneratedRom rom) location.Item = new Item(locationState.Item, itemWorld, itemState.ItemName, itemMetadata, itemState, locationState.Item.IsPossibleProgression(itemWorld.Config.ZeldaKeysanity, - itemWorld.Config.MetroidKeysanity), + itemWorld.Config.MetroidKeysanity, itemWorld == location.World), locationState.ItemOwnerName, locationState.ItemName ); } diff --git a/src/TrackerCouncil.Smz3.SeedGenerator/Generation/StatGenerator.cs b/src/TrackerCouncil.Smz3.SeedGenerator/Generation/StatGenerator.cs index 1a3245ed..068a0410 100644 --- a/src/TrackerCouncil.Smz3.SeedGenerator/Generation/StatGenerator.cs +++ b/src/TrackerCouncil.Smz3.SeedGenerator/Generation/StatGenerator.cs @@ -209,7 +209,7 @@ int GetLocationProgressionCount(LocationId locationId) return itemCounts.Where(x => x.Key.locationId == locationId && !items[x.Key.itemId].IsInAnyCategory(ItemCategory.BigKey, ItemCategory.SmallKey, ItemCategory.Compass, ItemCategory.Map) && - items[x.Key.itemId].IsPossibleProgression(false, false)) + items[x.Key.itemId].IsPossibleProgression(false, false, true)) .Sum(x => x.Value); } } diff --git a/src/TrackerCouncil.Smz3.Shared/Enums/ItemTypeExtensions.cs b/src/TrackerCouncil.Smz3.Shared/Enums/ItemTypeExtensions.cs index 7ffaee13..53ef4dcb 100644 --- a/src/TrackerCouncil.Smz3.Shared/Enums/ItemTypeExtensions.cs +++ b/src/TrackerCouncil.Smz3.Shared/Enums/ItemTypeExtensions.cs @@ -62,22 +62,23 @@ public static ItemCategory[] GetCategories(this ItemType itemType) /// The type of item. /// If playing with Zelda Key Sanity enabled. /// If playing with Metroid Key Sanity enabled. + /// /// /// if matches any of /// could possibly be progression; otherwise, . /// - public static bool IsPossibleProgression(this ItemType itemType, bool isZeldaKeysanity, bool isMetroidKeysanity) + public static bool IsPossibleProgression(this ItemType itemType, bool isZeldaKeysanity, bool isMetroidKeysanity, bool isLocalPlayerItem) { - if (itemType.IsInAnyCategory(new[] { ItemCategory.SmallKey, ItemCategory.BigKey })) - return isZeldaKeysanity; + if (itemType.IsInAnyCategory(ItemCategory.SmallKey, ItemCategory.BigKey)) + return isZeldaKeysanity || !isLocalPlayerItem; if (itemType.IsInCategory(ItemCategory.Keycard)) - return isMetroidKeysanity; + return isMetroidKeysanity || !isLocalPlayerItem; if (itemType == ItemType.OtherGameProgressionItem) return true; - if (itemType == ItemType.Nothing || itemType.IsInAnyCategory(new[] { ItemCategory.Junk, ItemCategory.Scam, ItemCategory.NonRandomized, ItemCategory.Map, ItemCategory.Compass, ItemCategory.Nice })) + if (itemType == ItemType.Nothing || itemType.IsInAnyCategory(ItemCategory.Junk, ItemCategory.Scam, ItemCategory.NonRandomized, ItemCategory.Map, ItemCategory.Compass, ItemCategory.Nice)) return false; return true; diff --git a/src/TrackerCouncil.Smz3.Tracking/NaturalLanguage.cs b/src/TrackerCouncil.Smz3.Tracking/NaturalLanguage.cs index 20ee97be..4e10b29b 100644 --- a/src/TrackerCouncil.Smz3.Tracking/NaturalLanguage.cs +++ b/src/TrackerCouncil.Smz3.Tracking/NaturalLanguage.cs @@ -98,8 +98,8 @@ public static string Join(IEnumerable items, Config config) return (item, count); }).ToList(); - var interestingItems = groupedItems.Where(x => x.item.Metadata.IsProgression(config)).ToList(); - var junkItems = groupedItems.Where(x => !x.item.Metadata.IsProgression(config)).OrderBy(x => x.item.IsDungeonItem).ToList(); + var interestingItems = groupedItems.Where(x => x.item.Metadata.IsProgression(config, x.item.IsLocalPlayerItem)).ToList(); + var junkItems = groupedItems.Where(x => !x.item.Metadata.IsProgression(config, x.item.IsLocalPlayerItem)).OrderBy(x => x.item.IsDungeonItem).ToList(); if (junkItems.Count == 0) { diff --git a/src/TrackerCouncil.Smz3.Tracking/TrackingServices/TrackerItemService.cs b/src/TrackerCouncil.Smz3.Tracking/TrackingServices/TrackerItemService.cs index 4344756b..1f2a06e8 100644 --- a/src/TrackerCouncil.Smz3.Tracking/TrackingServices/TrackerItemService.cs +++ b/src/TrackerCouncil.Smz3.Tracking/TrackingServices/TrackerItemService.cs @@ -222,7 +222,7 @@ public bool TrackItem(Item item, string? trackedAs = null, float? confidence = n var addedEvent = History.AddEvent( HistoryEventType.TrackedItem, - item.Metadata.IsProgression(World.Config), + item.Metadata.IsProgression(World.Config, item.IsLocalPlayerItem), item.Metadata.NameWithArticle, location ); @@ -528,11 +528,11 @@ private void AnnounceTrackedItems(List items) } else { - var itemsToSay = items.Where(x => x.Type.IsPossibleProgression(World.Config.ZeldaKeysanity, World.Config.MetroidKeysanity)).Take(2).ToList(); + var itemsToSay = items.Where(x => x.Type.IsPossibleProgression(World.Config.ZeldaKeysanity, World.Config.MetroidKeysanity, x.IsLocalPlayerItem)).Take(2).ToList(); if (itemsToSay.Count() < 2) { var numToTake = 2 - itemsToSay.Count(); - itemsToSay.AddRange(items.Where(x => !x.Type.IsPossibleProgression(World.Config.ZeldaKeysanity, World.Config.MetroidKeysanity)).Take(numToTake)); + itemsToSay.AddRange(items.Where(x => !x.Type.IsPossibleProgression(World.Config.ZeldaKeysanity, World.Config.MetroidKeysanity, x.IsLocalPlayerItem)).Take(numToTake)); } Tracker.Say(x => x.TrackedManyItems, args: [itemsToSay[0].Metadata.NameWithArticle, itemsToSay[1].Metadata.NameWithArticle, items.Count - 2]); diff --git a/src/TrackerCouncil.Smz3.Tracking/TrackingServices/TrackerLocationService.cs b/src/TrackerCouncil.Smz3.Tracking/TrackingServices/TrackerLocationService.cs index 6d78a633..33f2a695 100644 --- a/src/TrackerCouncil.Smz3.Tracking/TrackingServices/TrackerLocationService.cs +++ b/src/TrackerCouncil.Smz3.Tracking/TrackingServices/TrackerLocationService.cs @@ -452,7 +452,7 @@ private void GiveLocationComment(ItemType item, Location location, bool isTracki } // Give some sass if the user tracks or marks the wrong item at a // location unless the user is clearing a useless item like missiles - else if (location.Item.Type != ItemType.Nothing && !item.IsEquivalentTo(location.Item.Type) && (item != ItemType.Nothing || location.Item.Metadata.IsProgression(World.Config))) + else if (location.Item.Type != ItemType.Nothing && !item.IsEquivalentTo(location.Item.Type) && (item != ItemType.Nothing || location.Item.Metadata.IsProgression(World.Config, location.Item.IsLocalPlayerItem))) { if (confidence == null || confidence < Options.MinimumSassConfidence) return; diff --git a/src/TrackerCouncil.Smz3.Tracking/VoiceCommands/MultiplayerModule.cs b/src/TrackerCouncil.Smz3.Tracking/VoiceCommands/MultiplayerModule.cs index 64bf4cb1..94768d5d 100644 --- a/src/TrackerCouncil.Smz3.Tracking/VoiceCommands/MultiplayerModule.cs +++ b/src/TrackerCouncil.Smz3.Tracking/VoiceCommands/MultiplayerModule.cs @@ -152,7 +152,7 @@ private void PlayerTrackedLocation(PlayerTrackedLocationEventHandlerArgs args) if (item == null) throw new InvalidOperationException($"Player retrieved invalid item {args.ItemToGive}"); _ = TrackerBase.GameService!.TryGiveItemAsync(item, args.PlayerId); - if (item.Type.IsPossibleProgression(item.World.Config.ZeldaKeysanity, item.World.Config.MetroidKeysanity)) + if (item.Type.IsPossibleProgression(item.World.Config.ZeldaKeysanity, item.World.Config.MetroidKeysanity, item.IsLocalPlayerItem)) { TrackerBase.Say(x => x.Multiplayer.ReceivedUsefulItemFromOtherPlayer, args: [args.PhoneticName, item.Metadata.Name, item.Metadata.NameWithArticle]); diff --git a/src/TrackerCouncil.Smz3.Tracking/VoiceCommands/SpoilerModule.cs b/src/TrackerCouncil.Smz3.Tracking/VoiceCommands/SpoilerModule.cs index 8b5d35db..c608bffc 100644 --- a/src/TrackerCouncil.Smz3.Tracking/VoiceCommands/SpoilerModule.cs +++ b/src/TrackerCouncil.Smz3.Tracking/VoiceCommands/SpoilerModule.cs @@ -126,7 +126,7 @@ private void GiveAreaHint(IHasLocations area) { var config = area.Region.Config; var anyPossibleProgression = area.Locations.Any(x => - x.ItemType.IsPossibleProgression(config.ZeldaKeysanity, config.MetroidKeysanity)); + x.ItemType.IsPossibleProgression(config.ZeldaKeysanity, config.MetroidKeysanity, x.Item.IsLocalPlayerItem)); if (anyPossibleProgression) { TrackerBase.Say(x => x.Hints.AreaHasNonCasPossibleProgression, args: [area.GetName()]); @@ -450,7 +450,7 @@ private bool GiveLocationHints(Location location) if (HintsGiven(location) == 0) { if (location.ItemType.IsPossibleProgression(location.World.Config.ZeldaKeysanity, - location.World.Config.MetroidKeysanity)) + location.World.Config.MetroidKeysanity, location.Item.IsLocalPlayerItem)) { return GiveLocationHint(x => x.LocationHasNonCasProgressionItem, location, location.Item.PlayerName); } From 1bae9268c3d622750c21ba366af5ba93d5301b70 Mon Sep 17 00:00:00 2001 From: MattEqualsCoder Date: Tue, 31 Dec 2024 16:28:28 -0500 Subject: [PATCH 04/13] Update marked location item opacity on availability change --- .../ViewModels/MarkedLocationViewModel.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/TrackerCouncil.Smz3.UI/ViewModels/MarkedLocationViewModel.cs b/src/TrackerCouncil.Smz3.UI/ViewModels/MarkedLocationViewModel.cs index 82dabe31..25c710f9 100644 --- a/src/TrackerCouncil.Smz3.UI/ViewModels/MarkedLocationViewModel.cs +++ b/src/TrackerCouncil.Smz3.UI/ViewModels/MarkedLocationViewModel.cs @@ -1,4 +1,5 @@ using System; +using AvaloniaControls.Models; using ReactiveUI.Fody.Helpers; using TrackerCouncil.Smz3.Data.WorldData; using TrackerCouncil.Smz3.Shared.Enums; @@ -9,7 +10,10 @@ public class MarkedLocationViewModel(Location location, Item? itemData, string? { public Location Location => location; public string? ItemSprite { get; init; } = itemSprite; - [Reactive] public bool IsAvailable { get; set; } = location.Accessibility is Accessibility.Available or Accessibility.AvailableWithKeys; + + [Reactive, ReactiveLinkedProperties(nameof(Opacity))] + public bool IsAvailable { get; set; } = location.Accessibility is Accessibility.Available or Accessibility.AvailableWithKeys; + public bool ShowOutOfLogic { get; set; } public double Opacity => ShowOutOfLogic || IsAvailable ? 1.0 : 0.33; public string Item { get; init; }= itemData?.Name ?? ""; From 8bd44cb8ad8dedb8ec3a81e7593183c9a01f90ab Mon Sep 17 00:00:00 2001 From: MattEqualsCoder Date: Tue, 31 Dec 2024 16:31:14 -0500 Subject: [PATCH 05/13] Fix tracking items in the UI not working --- src/TrackerCouncil.Smz3.UI/Services/TrackerWindowService.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/TrackerCouncil.Smz3.UI/Services/TrackerWindowService.cs b/src/TrackerCouncil.Smz3.UI/Services/TrackerWindowService.cs index ff3ee963..1d8211dd 100644 --- a/src/TrackerCouncil.Smz3.UI/Services/TrackerWindowService.cs +++ b/src/TrackerCouncil.Smz3.UI/Services/TrackerWindowService.cs @@ -525,11 +525,11 @@ private TrackerWindowPanelViewModel GetItemPanelViewModel(UIGridLocation gridLoc if (items.Count == 1) { - model.Clicked += (_, _) => tracker.ItemTracker.TrackItem(items.Keys.First()); + model.Clicked += (_, _) => tracker.ItemTracker.TrackItem(items.Keys.First(), force: true); } - model.ItemGiven += (_, args) => tracker.ItemTracker.TrackItem(args.Item); - model.ItemRemoved += (_, args) => tracker.ItemTracker.UntrackItem(args.Item); + model.ItemGiven += (_, args) => tracker.ItemTracker.TrackItem(args.Item, force: true); + model.ItemRemoved += (_, args) => tracker.ItemTracker.UntrackItem(args.Item, force: true); model.ItemSetAsDungeonRequirement += (_, args) => { var item = items.Keys.First(); From c39c2a1c6f2e84d82b962f2f8d117b7c873f847f Mon Sep 17 00:00:00 2001 From: MattEqualsCoder Date: Tue, 31 Dec 2024 17:50:49 -0500 Subject: [PATCH 06/13] Prevent deleting git repo sprites --- src/TrackerCouncil.Smz3.Data/RandomizerDirectories.cs | 4 ++++ .../Services/GitHubFileSynchronizerService.cs | 7 ++++++- .../Services/OptionsWindowService.cs | 2 ++ src/TrackerCouncil.Smz3.UI/Services/MainWindowService.cs | 2 ++ 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/TrackerCouncil.Smz3.Data/RandomizerDirectories.cs b/src/TrackerCouncil.Smz3.Data/RandomizerDirectories.cs index 9c5c3fb7..e4c1893b 100644 --- a/src/TrackerCouncil.Smz3.Data/RandomizerDirectories.cs +++ b/src/TrackerCouncil.Smz3.Data/RandomizerDirectories.cs @@ -67,6 +67,8 @@ public static string SpritePath } } + public static bool DeleteSprites => SpritePath == Path.Combine(AppContext.BaseDirectory, "Sprites"); + public static string UserSpritePath => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "SMZ3CasRandomizer", "Sprites"); @@ -105,4 +107,6 @@ public static string TrackerSpritePath #endif public static string TrackerSpriteInitialJsonFilePath => Path.Combine(TrackerSpritePath, "tracker-sprites.json"); + + public static bool DeleteTrackerSprites => SpritePath == Path.Combine(AppContext.BaseDirectory, "Sprites"); } diff --git a/src/TrackerCouncil.Smz3.Data/Services/GitHubFileSynchronizerService.cs b/src/TrackerCouncil.Smz3.Data/Services/GitHubFileSynchronizerService.cs index 239da47b..e49d4a2c 100644 --- a/src/TrackerCouncil.Smz3.Data/Services/GitHubFileSynchronizerService.cs +++ b/src/TrackerCouncil.Smz3.Data/Services/GitHubFileSynchronizerService.cs @@ -62,6 +62,11 @@ public class GitHubFileDownloaderRequest /// Timeout value for each individual request /// public TimeSpan Timeout { get; set; } = TimeSpan.FromSeconds(5); + + /// + /// If any files that exist on the local computer but not on GitHub should be deleted + /// + public bool DeleteExtraFiles { get; set; } } /// @@ -153,7 +158,7 @@ public async Task> GetGitHubFileDetailsAsync(GitHubFileD }); }); - if (Directory.Exists(request.DestinationFolder)) + if (Directory.Exists(request.DestinationFolder) && request.DeleteExtraFiles) { var foundLocalFiles = fileList.Select(x => x.LocalPath).ToHashSet(); diff --git a/src/TrackerCouncil.Smz3.Data/Services/OptionsWindowService.cs b/src/TrackerCouncil.Smz3.Data/Services/OptionsWindowService.cs index d3e299a4..019f5526 100644 --- a/src/TrackerCouncil.Smz3.Data/Services/OptionsWindowService.cs +++ b/src/TrackerCouncil.Smz3.Data/Services/OptionsWindowService.cs @@ -216,6 +216,7 @@ private async Task UpdateSpritesAsync() InitialJsonPath = RandomizerDirectories.SpriteInitialJsonFilePath, ValidPathCheck = p => p.StartsWith("Sprites/") && p.Contains('.'), ConvertGitHubPathToLocalPath = p => p.Replace("Sprites/", ""), + DeleteExtraFiles = RandomizerDirectories.DeleteSprites }; var sprites = await gitHubFileSynchronizerService.GetGitHubFileDetailsAsync(spriteDownloadRequest); @@ -228,6 +229,7 @@ private async Task UpdateSpritesAsync() HashPath = RandomizerDirectories.TrackerSpritePath, InitialJsonPath = RandomizerDirectories.TrackerSpritePath, ValidPathCheck = p => p.EndsWith(".png", StringComparison.OrdinalIgnoreCase) || p.EndsWith(".gif", StringComparison.OrdinalIgnoreCase), + DeleteExtraFiles = RandomizerDirectories.DeleteTrackerSprites }; sprites.AddRange(await gitHubFileSynchronizerService.GetGitHubFileDetailsAsync(spriteDownloadRequest)); diff --git a/src/TrackerCouncil.Smz3.UI/Services/MainWindowService.cs b/src/TrackerCouncil.Smz3.UI/Services/MainWindowService.cs index 00497e85..2e373bc3 100644 --- a/src/TrackerCouncil.Smz3.UI/Services/MainWindowService.cs +++ b/src/TrackerCouncil.Smz3.UI/Services/MainWindowService.cs @@ -141,6 +141,7 @@ public async Task DownloadSpritesAsync() InitialJsonPath = RandomizerDirectories.SpriteInitialJsonFilePath, ValidPathCheck = p => Sprite.ValidDownloadExtensions.Contains(Path.GetExtension(p).ToLowerInvariant()), ConvertGitHubPathToLocalPath = p => p.Replace("Sprites/", ""), + DeleteExtraFiles = RandomizerDirectories.DeleteSprites }; var toDownload = await gitHubFileSynchronizerService.GetGitHubFileDetailsAsync(spriteDownloadRequest); @@ -153,6 +154,7 @@ public async Task DownloadSpritesAsync() HashPath = RandomizerDirectories.TrackerSpriteHashYamlFilePath, InitialJsonPath = RandomizerDirectories.TrackerSpriteInitialJsonFilePath, ValidPathCheck = p => p.EndsWith(".png", StringComparison.OrdinalIgnoreCase) || p.EndsWith(".gif", StringComparison.OrdinalIgnoreCase), + DeleteExtraFiles = RandomizerDirectories.DeleteSprites }; toDownload.AddRange(await gitHubFileSynchronizerService.GetGitHubFileDetailsAsync(spriteDownloadRequest)); From 68878e15edf50d4b5c70ef409470c5a4b4cf903a Mon Sep 17 00:00:00 2001 From: MattEqualsCoder Date: Tue, 31 Dec 2024 17:51:07 -0500 Subject: [PATCH 07/13] Add Archipelago other game item sprites --- src/TrackerCouncil.Smz3.Shared/Enums/ItemType.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/TrackerCouncil.Smz3.Shared/Enums/ItemType.cs b/src/TrackerCouncil.Smz3.Shared/Enums/ItemType.cs index 10262d76..bee8edb1 100644 --- a/src/TrackerCouncil.Smz3.Shared/Enums/ItemType.cs +++ b/src/TrackerCouncil.Smz3.Shared/Enums/ItemType.cs @@ -615,9 +615,11 @@ public enum ItemType : byte [ItemCategory(ItemCategory.Metroid, ItemCategory.MetroidMap)] SmMapLowerNorfair = 0xCD, + [Description("Other Game Item")] [ItemCategory(ItemCategory.NonRandomized)] OtherGameItem = 0xFE, + [Description("Important Other Game Item")] [ItemCategory(ItemCategory.NonRandomized)] OtherGameProgressionItem = 0xFF } From 3389d2d5f460fc2836069c4d6dbef474d0340c69 Mon Sep 17 00:00:00 2001 From: MattEqualsCoder Date: Tue, 31 Dec 2024 17:51:22 -0500 Subject: [PATCH 08/13] Fix selected sprites not saving properly --- src/TrackerCouncil.Smz3.Data/Options/Sprite.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/TrackerCouncil.Smz3.Data/Options/Sprite.cs b/src/TrackerCouncil.Smz3.Data/Options/Sprite.cs index 212b9342..65039cac 100644 --- a/src/TrackerCouncil.Smz3.Data/Options/Sprite.cs +++ b/src/TrackerCouncil.Smz3.Data/Options/Sprite.cs @@ -61,9 +61,9 @@ private Sprite(string name, SpriteType spriteType, bool isDefault, bool isRandom [YamlIgnore] public string Author { get; set; } - public string FilePath { get; } = ""; + public string FilePath { get; set; } = ""; - public SpriteType SpriteType { get; } + public SpriteType SpriteType { get; set; } [YamlIgnore] public string PreviewPath { get; set; } From 13c48086fda47c5d1076890c4d94b172f377a319 Mon Sep 17 00:00:00 2001 From: MattEqualsCoder Date: Wed, 1 Jan 2025 13:30:35 -0500 Subject: [PATCH 09/13] Add error window if invalid rom was entered to parse --- .../Generation/Smz3RomParser.cs | 178 ++++++++++-------- .../Services/SoloRomListService.cs | 42 ----- .../Views/SoloRomListPanel.axaml.cs | 13 +- 3 files changed, 107 insertions(+), 126 deletions(-) diff --git a/src/TrackerCouncil.Smz3.SeedGenerator/Generation/Smz3RomParser.cs b/src/TrackerCouncil.Smz3.SeedGenerator/Generation/Smz3RomParser.cs index 649dec83..97feff44 100644 --- a/src/TrackerCouncil.Smz3.SeedGenerator/Generation/Smz3RomParser.cs +++ b/src/TrackerCouncil.Smz3.SeedGenerator/Generation/Smz3RomParser.cs @@ -36,102 +36,118 @@ public ParsedRomDetails ParseRomFile(string filePath) var exampleWorld = new World(new Config(), "", 1, ""); var rom = File.ReadAllBytes(filePath); - var isMultiworldEnabled = MetadataPatch.IsRomMultiworldEnabled(rom); - var isKeysanityEnabled = MetadataPatch.IsRomKeysanityEnabled(rom); - var romTitle = MetadataPatch.GetGameTitle(rom); - var playerNames = isMultiworldEnabled ? MetadataPatch.GetPlayerNames(rom): [ "Player" ]; - var playerIndex = MetadataPatch.GetPlayerIndex(rom); - var players = playerNames.Select((name, index) => new ParsedRomPlayer() + try { - PlayerName = name.Trim(), PlayerIndex = index, IsLocalPlayer = index == playerIndex, - }).ToList(); - logger.LogInformation("Parsed players {PlayerList}", string.Join(", ", players.Select(p => p.PlayerName))); - - var itemTypes = configs.Items.Where(x => x.InternalItemType != ItemType.Nothing) - .Select(x => (int)x.InternalItemType).ToList(); - var locations = LocationsPatch.GetLocationsFromRom(rom, playerNames, exampleWorld, isMultiworldEnabled, itemTypes); - var prerequisites = MedallionPatch.GetPrerequisitesFromRom(rom, exampleWorld.PrerequisiteRegions); - var bosses = exampleWorld.BossRegions.Select(x => new ParsedRomBossDetails() - { - RegionType = x.GetType(), RegionName = x.Name, BossType = x.BossType - }).ToList(); - - var keysanityMode = KeysanityMode.None; - if (isKeysanityEnabled) - { - var isMetroidKeysanity = MetroidKeysanityPatch.GetIsMetroidKeysanity(rom); - var isZeldaKeysanity = ZeldaKeysanityPatch.GetIsZeldaKeysanity(rom); + var isMultiworldEnabled = MetadataPatch.IsRomMultiworldEnabled(rom); + var isKeysanityEnabled = MetadataPatch.IsRomKeysanityEnabled(rom); + var romTitle = MetadataPatch.GetGameTitle(rom); + var playerNames = isMultiworldEnabled ? MetadataPatch.GetPlayerNames(rom) : ["Player"]; + var playerIndex = MetadataPatch.GetPlayerIndex(rom); + var players = playerNames.Select((name, index) => new ParsedRomPlayer() + { + PlayerName = name.Trim(), PlayerIndex = index, IsLocalPlayer = index == playerIndex, + }).ToList(); + logger.LogInformation("Parsed players {PlayerList}", string.Join(", ", players.Select(p => p.PlayerName))); + + var itemTypes = configs.Items.Where(x => x.InternalItemType != ItemType.Nothing) + .Select(x => (int)x.InternalItemType).ToList(); + var locations = + LocationsPatch.GetLocationsFromRom(rom, playerNames, exampleWorld, isMultiworldEnabled, itemTypes); + var prerequisites = MedallionPatch.GetPrerequisitesFromRom(rom, exampleWorld.PrerequisiteRegions); + var bosses = exampleWorld.BossRegions.Select(x => new ParsedRomBossDetails() + { + RegionType = x.GetType(), RegionName = x.Name, BossType = x.BossType + }).ToList(); - if (isMetroidKeysanity && isZeldaKeysanity) + var keysanityMode = KeysanityMode.None; + if (isKeysanityEnabled) { - keysanityMode = KeysanityMode.Both; + var isMetroidKeysanity = MetroidKeysanityPatch.GetIsMetroidKeysanity(rom); + var isZeldaKeysanity = ZeldaKeysanityPatch.GetIsZeldaKeysanity(rom); + + if (isMetroidKeysanity && isZeldaKeysanity) + { + keysanityMode = KeysanityMode.Both; + } + else if (isMetroidKeysanity) + { + keysanityMode = KeysanityMode.SuperMetroid; + } + else if (isZeldaKeysanity) + { + keysanityMode = KeysanityMode.Zelda; + } } - else if (isMetroidKeysanity) + + logger.LogInformation("Keysanity: {Mode}", keysanityMode); + + var hardLogic = false; + var seedNumber = 0; + RomGenerator? romGenerator = null; + + if (romTitle.StartsWith("ZSM")) { - keysanityMode = KeysanityMode.SuperMetroid; + romGenerator = playerNames.First() == "Archipelago" ? RomGenerator.Archipelago : RomGenerator.Mainline; + + var flags = romTitle[3..]; + var flagIndex = flags.IndexOf(flags.FirstOrDefault(char.IsLetter)); + flags = flags.Substring(flagIndex, 2); + hardLogic = flags[1] == 'H'; + + var seedString = romTitle[(3 + flagIndex + 2)..]; + var seed = romGenerator == RomGenerator.Archipelago + ? seedString[playerIndex.ToString().Length..] + : seedString; + var match = HexRegex().Match(seed); + seedNumber = match.Success ? Convert.ToInt32(seed, 16) : new Random().Next(); } - else if (isZeldaKeysanity) + else if (romTitle.StartsWith("SMZ3 Cas")) { - keysanityMode = KeysanityMode.Zelda; + romGenerator = RomGenerator.Cas; } - } - - logger.LogInformation("Keysanity: {Mode}", keysanityMode); - var hardLogic = false; - var seedNumber = 0; - var isCasRom = false; - var romGenerator = RomGenerator.Cas; + if (romGenerator == null) + { + throw new InvalidOperationException("Could not determine rom generator from the rom details"); + } - if (romTitle.StartsWith("ZSM")) - { - romGenerator = playerNames.First() == "Archipelago" ? RomGenerator.Archipelago : RomGenerator.Mainline; + var rewards = + ZeldaRewardsPatch.GetRewardsFromRom(rom, exampleWorld.RewardRegions, romGenerator == RomGenerator.Cas); + var startingItems = StartingEquipmentPatch.GetStartingItemList(rom, romGenerator == RomGenerator.Cas); + var gtCrystalCount = GoalsPatch.GetGanonsTowerCrystalCountFromRom(rom); + var ganonCrystalCount = GoalsPatch.GetGanonCrystalCountFromRom(rom); + var tourianBossCount = GoalsPatch.GetTourianBossCountFromRom(rom, romGenerator == RomGenerator.Cas); + var text = ZeldaTextsPatch.ParseRomText(rom); - var flags = romTitle[3..]; - var flagIndex = flags.IndexOf(flags.FirstOrDefault(char.IsLetter)); - flags = flags.Substring(flagIndex, 2); - hardLogic = flags[1] == 'H'; + logger.LogInformation("Imported {Title} (Seed {SeedNumber})", romTitle, seedNumber); - var seedString = romTitle[(3 + flagIndex + 2)..]; - var seed = romGenerator == RomGenerator.Archipelago ? seedString[playerIndex.ToString().Length..] : seedString; - var match = HexRegex().Match(seed); - seedNumber = match.Success ? Convert.ToInt32(seed, 16) : new Random().Next(); + return new ParsedRomDetails + { + OriginalPath = filePath, + OriginalFilename = Path.GetFileNameWithoutExtension(filePath), + RomTitle = romTitle, + Seed = seedNumber, + IsMultiworld = isMultiworldEnabled, + IsHardLogic = hardLogic, + KeysanityMode = keysanityMode, + GanonsTowerCrystalCount = gtCrystalCount, + GanonCrystalCount = ganonCrystalCount, + TourianBossCount = tourianBossCount, + RomGenerator = romGenerator.Value, + Players = players, + Locations = locations, + Rewards = rewards, + Bosses = bosses, + Prerequisites = prerequisites, + StartingItems = startingItems, + ParsedText = text + }; } - else if (romTitle.StartsWith("SMZ3 Cas")) + catch (Exception e) { - isCasRom = true; + logger.LogError(e, "Error while parsing rom"); + throw; } - - var rewards = ZeldaRewardsPatch.GetRewardsFromRom(rom, exampleWorld.RewardRegions, isCasRom); - var startingItems = StartingEquipmentPatch.GetStartingItemList(rom, isCasRom); - var gtCrystalCount = GoalsPatch.GetGanonsTowerCrystalCountFromRom(rom); - var ganonCrystalCount = GoalsPatch.GetGanonCrystalCountFromRom(rom); - var tourianBossCount = GoalsPatch.GetTourianBossCountFromRom(rom, isCasRom); - var text = ZeldaTextsPatch.ParseRomText(rom); - - logger.LogInformation("Imported {Title} (Seed {SeedNumber})", romTitle, seedNumber); - - return new ParsedRomDetails() - { - OriginalPath = filePath, - OriginalFilename = Path.GetFileNameWithoutExtension(filePath), - RomTitle = romTitle, - Seed = seedNumber, - IsMultiworld = isMultiworldEnabled, - IsHardLogic = hardLogic, - KeysanityMode = keysanityMode, - GanonsTowerCrystalCount = gtCrystalCount, - GanonCrystalCount = ganonCrystalCount, - TourianBossCount = tourianBossCount, - RomGenerator = romGenerator, - Players = players, - Locations = locations, - Rewards = rewards, - Bosses = bosses, - Prerequisites = prerequisites, - StartingItems = startingItems, - ParsedText = text - }; } public SeedData GenerateSeedData(RandomizerOptions options, ParsedRomDetails parsedRomDetails, CancellationToken cancellationToken = default) diff --git a/src/TrackerCouncil.Smz3.UI/Services/SoloRomListService.cs b/src/TrackerCouncil.Smz3.UI/Services/SoloRomListService.cs index 9bf292c0..925de1fa 100644 --- a/src/TrackerCouncil.Smz3.UI/Services/SoloRomListService.cs +++ b/src/TrackerCouncil.Smz3.UI/Services/SoloRomListService.cs @@ -1,7 +1,6 @@ using System.IO; using System.Linq; using System.Threading.Tasks; -using System.Web; using Avalonia.Controls; using Avalonia.Platform.Storage; using AvaloniaControls; @@ -182,47 +181,6 @@ public async Task OpenArchipelagoModeAsync() { UpdateList(); } - - // archipelagoScannerService.ScanArchipelagoRom(rom); - - /*var rom = await File.ReadAllBytesAsync(pathString); - romGenerationService.ApplyCasPatches(rom, new PatchOptions() - { - CasPatches = new CasPatches() - { - AimAnyButton = true, - DisableFlashing = true, - DisableScreenShake = true, - EasierWallJumps = true, - FastDoors = true, - FastElevators = true, - InfiniteSpaceJump = true, - MetroidAutoSave = true, - NerfedCharge = true, - SnapMorph = true, - Respin = true, - RefillAtSaveStation = true, - SandPitPlatforms = true, - }, - MetroidControls = new MetroidControlOptions() - { - RunButtonBehavior = RunButtonBehavior.AutoRun, - ItemCancelBehavior = ItemCancelBehavior.HoldSupersOnly, - AimButtonBehavior = AimButtonBehavior.UnifiedAim, - Shoot = MetroidButton.Y, - Jump = MetroidButton.B, - Dash = MetroidButton.X, - ItemSelect = MetroidButton.Select, - ItemCancel = MetroidButton.R, - AimUp = MetroidButton.L, - AimDown = MetroidButton.R - } - }); - - var folder = Path.GetDirectoryName(pathString)!; - var fileName = Path.GetFileNameWithoutExtension(pathString)+"_updated"; - var extension = Path.GetExtension(pathString); - await File.WriteAllBytesAsync(Path.Combine(folder, fileName + extension), rom);*/ } private void OpenMessageWindow(string message, MessageWindowIcon icon = MessageWindowIcon.Error, MessageWindowButtons buttons = MessageWindowButtons.OK) diff --git a/src/TrackerCouncil.Smz3.UI/Views/SoloRomListPanel.axaml.cs b/src/TrackerCouncil.Smz3.UI/Views/SoloRomListPanel.axaml.cs index 0a8c184b..6a312211 100644 --- a/src/TrackerCouncil.Smz3.UI/Views/SoloRomListPanel.axaml.cs +++ b/src/TrackerCouncil.Smz3.UI/Views/SoloRomListPanel.axaml.cs @@ -4,7 +4,7 @@ using Avalonia.Input; using Avalonia.Interactivity; using Avalonia.LogicalTree; -using AvaloniaControls; +using AvaloniaControls.Controls; using AvaloniaControls.Services; using TrackerCouncil.Smz3.UI.Services; using TrackerCouncil.Smz3.UI.ViewModels; @@ -217,8 +217,15 @@ private bool GetRomFromControl(object? control, out GeneratedRomViewModel? mo private async void ArchipelagoButton_OnClick(object? sender, RoutedEventArgs e) { - if (_service == null) return; - await _service.OpenArchipelagoModeAsync(); + try + { + if (_service == null) return; + await _service.OpenArchipelagoModeAsync(); + } + catch + { + await MessageWindow.ShowErrorDialog("Invalid ROM file. Please select a valid generated SMZ3 rom."); + } } } From bcaa262d7e8cf58aafb6eb1574199a7d27763c7f Mon Sep 17 00:00:00 2001 From: MattEqualsCoder Date: Wed, 1 Jan 2025 13:31:42 -0500 Subject: [PATCH 10/13] Fix issue with unnecessary sprite downloads --- .../Services/GitHubFileSynchronizerService.cs | 46 ++++++++++--------- .../Services/OptionsWindowService.cs | 2 +- .../Services/MainWindowService.cs | 14 +++--- 3 files changed, 33 insertions(+), 29 deletions(-) diff --git a/src/TrackerCouncil.Smz3.Data/Services/GitHubFileSynchronizerService.cs b/src/TrackerCouncil.Smz3.Data/Services/GitHubFileSynchronizerService.cs index e49d4a2c..26392c9a 100644 --- a/src/TrackerCouncil.Smz3.Data/Services/GitHubFileSynchronizerService.cs +++ b/src/TrackerCouncil.Smz3.Data/Services/GitHubFileSynchronizerService.cs @@ -69,6 +69,13 @@ public class GitHubFileDownloaderRequest public bool DeleteExtraFiles { get; set; } } +public enum GitHubFileAction +{ + Nothing, + Download, + Delete +} + /// /// Class that houses data of a file to synchronize /// @@ -92,17 +99,12 @@ public class GitHubFileDetails /// /// The hash of the file on GitHub to track if the file was previously downloaded /// - public required string RemoteHash { get; set; } + public required string Hash { get; set; } /// - /// If the file is found on the local computer + /// What needs to happen for the file /// - public required bool FileExistsLocally { get; set; } - - /// - /// If there is a difference in the file between the local computer and Github - /// - public required bool FileMatchesLocally { get; set; } + public required GitHubFileAction Action { get; set; } /// /// The path to the file to save the GitHub hash to @@ -137,6 +139,8 @@ public async Task> GetGitHubFileDetailsAsync(GitHubFileD var previousHashes = GetPreviousHashes(request); + _logger.LogInformation("{Count} previous file hashes found", previousHashes.Count); + var fileList = new ConcurrentBag(); Parallel.ForEach(files, parallelOptions: new ParallelOptions { MaxDegreeOfParallelism = 4 }, @@ -145,40 +149,40 @@ public async Task> GetGitHubFileDetailsAsync(GitHubFileD var localPath = ConvertToLocalPath(request, fileData.Key); var currentHash = fileData.Value; previousHashes.TryGetValue(localPath, out var prevHash); + var needToDownload = !File.Exists(localPath) || prevHash != currentHash; fileList.Add(new GitHubFileDetails() { Path = fileData.Key, LocalPath = localPath, DownloadUrl = $"https://raw.githubusercontent.com/{request.RepoOwner}/{request.RepoName}/main/{fileData.Key}", - RemoteHash = fileData.Value, - FileExistsLocally = File.Exists(localPath), - FileMatchesLocally = File.Exists(localPath) && prevHash == currentHash, + Hash = fileData.Value, + Action = needToDownload ? GitHubFileAction.Download : GitHubFileAction.Nothing, HashPath = request.HashPath }); }); - if (Directory.Exists(request.DestinationFolder) && request.DeleteExtraFiles) + if (Directory.Exists(request.DestinationFolder)) { var foundLocalFiles = fileList.Select(x => x.LocalPath).ToHashSet(); foreach (var file in Directory.EnumerateFiles(request.DestinationFolder, "*", SearchOption.AllDirectories).Where(x => !foundLocalFiles.Contains(x) && IsValidPath(request, x))) { + previousHashes.TryGetValue(file, out var previousHash); + fileList.Add(new GitHubFileDetails() { Path = file, LocalPath = file, DownloadUrl = "", - RemoteHash = "", - FileExistsLocally = true, - FileMatchesLocally = false, + Hash = previousHash ?? "", + Action = request.DeleteExtraFiles ? GitHubFileAction.Delete : GitHubFileAction.Nothing, HashPath = request.HashPath }); } } - - return fileList.Where(x => !x.FileMatchesLocally).ToList(); + return fileList.ToList(); } public async Task SyncGitHubFilesAsync(GitHubFileDownloaderRequest request) @@ -195,7 +199,7 @@ public async Task SyncGitHubFilesAsync(List fileDetails) return; } - var filesToProcess = fileDetails.Where(x => !x.FileMatchesLocally).ToList(); + var filesToProcess = fileDetails.Where(x => x.Action != GitHubFileAction.Nothing).ToList(); var total = filesToProcess.Count; var completed = 0; @@ -221,9 +225,9 @@ public async Task SyncGitHubFilesAsync(List fileDetails) foreach (var hashPath in fileDetails.Select(x => x.HashPath).Distinct()) { - SaveFileHashYaml(hashPath, - fileDetails.Where(x => x.HashPath == hashPath && !string.IsNullOrEmpty(x.DownloadUrl)) - .ToDictionary(x => x.LocalPath, x => x.RemoteHash)); + var hashDetails = fileDetails.Where(x => x.HashPath == hashPath && !string.IsNullOrEmpty(x.Hash)) + .ToDictionary(x => x.LocalPath, x => x.Hash); + SaveFileHashYaml(hashPath, hashDetails); } } diff --git a/src/TrackerCouncil.Smz3.Data/Services/OptionsWindowService.cs b/src/TrackerCouncil.Smz3.Data/Services/OptionsWindowService.cs index 019f5526..0e7eb1eb 100644 --- a/src/TrackerCouncil.Smz3.Data/Services/OptionsWindowService.cs +++ b/src/TrackerCouncil.Smz3.Data/Services/OptionsWindowService.cs @@ -234,7 +234,7 @@ private async Task UpdateSpritesAsync() sprites.AddRange(await gitHubFileSynchronizerService.GetGitHubFileDetailsAsync(spriteDownloadRequest)); - if (sprites.Count > 0) + if (sprites.Any(x => x.Action != GitHubFileAction.Nothing)) { SpriteDownloadStarted?.Invoke(this, EventArgs.Empty); await gitHubFileSynchronizerService.SyncGitHubFilesAsync(sprites); diff --git a/src/TrackerCouncil.Smz3.UI/Services/MainWindowService.cs b/src/TrackerCouncil.Smz3.UI/Services/MainWindowService.cs index 2e373bc3..7a7271e5 100644 --- a/src/TrackerCouncil.Smz3.UI/Services/MainWindowService.cs +++ b/src/TrackerCouncil.Smz3.UI/Services/MainWindowService.cs @@ -33,12 +33,10 @@ public class MainWindowService( Configs configs) : ControlService { private MainWindowViewModel _model = new(); - private MainWindow _window = null!; private RandomizerOptions _options = null!; public MainWindowViewModel InitializeModel(MainWindow window) { - _window = window; _options = optionsFactory.Create(); _model.OpenSetupWindow = !_options.GeneralOptions.HasOpenedSetupWindow; ITaskService.Run(CheckForUpdates); @@ -159,11 +157,9 @@ public async Task DownloadSpritesAsync() toDownload.AddRange(await gitHubFileSynchronizerService.GetGitHubFileDetailsAsync(spriteDownloadRequest)); - if (toDownload is not { Count: > 4 }) - { - await gitHubFileSynchronizerService.SyncGitHubFilesAsync(toDownload); - } - else + var numToDownload = toDownload.Count(x => x.Action != GitHubFileAction.Nothing); + + if (numToDownload > 4) { await Dispatcher.UIThread.InvokeAsync(async () => { @@ -172,6 +168,10 @@ await Dispatcher.UIThread.InvokeAsync(async () => SpriteDownloadEnd?.Invoke(this, EventArgs.Empty); }); } + else if (numToDownload > 0) + { + await gitHubFileSynchronizerService.SyncGitHubFilesAsync(toDownload); + } await spriteService.LoadSpritesAsync(); trackerSpriteService.LoadSprites(); From ebb2a106c9f8e459eefb1e0b48e4c3d8a1fe124b Mon Sep 17 00:00:00 2001 From: MattEqualsCoder Date: Wed, 1 Jan 2025 14:51:59 -0500 Subject: [PATCH 11/13] Update AP rom update to inform people not to reuse OG rom --- src/TrackerCouncil.Smz3.UI/Services/SoloRomListService.cs | 7 +++++-- src/TrackerCouncil.Smz3.UI/Views/SoloRomListPanel.axaml.cs | 6 +++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/TrackerCouncil.Smz3.UI/Services/SoloRomListService.cs b/src/TrackerCouncil.Smz3.UI/Services/SoloRomListService.cs index 925de1fa..d250264b 100644 --- a/src/TrackerCouncil.Smz3.UI/Services/SoloRomListService.cs +++ b/src/TrackerCouncil.Smz3.UI/Services/SoloRomListService.cs @@ -163,7 +163,7 @@ public async Task LaunchTracker(GeneratedRomViewModel rom) await sharedCrossplatformService.LaunchTrackerAsync(rom.Rom); } - public async Task OpenArchipelagoModeAsync() + public async Task OpenArchipelagoModeAsync() { var storageItem = await CrossPlatformTools.OpenFileDialogAsync(ParentWindow, FileInputControlType.OpenFile, "Rom file (*.sfc)|*.sfc|All files (*.*)|*.*", "/home/matt/Games/Randomizers/Archipelago"); @@ -172,7 +172,7 @@ public async Task OpenArchipelagoModeAsync() if (pathString == null) { - return; + return false; } var parsedRomDetails = smz3RomParser.ParseRomFile(pathString); @@ -180,7 +180,10 @@ public async Task OpenArchipelagoModeAsync() if (await sharedCrossplatformService.OpenGenerationWindow(importDetails: parsedRomDetails) != null) { UpdateList(); + return true; } + + return false; } private void OpenMessageWindow(string message, MessageWindowIcon icon = MessageWindowIcon.Error, MessageWindowButtons buttons = MessageWindowButtons.OK) diff --git a/src/TrackerCouncil.Smz3.UI/Views/SoloRomListPanel.axaml.cs b/src/TrackerCouncil.Smz3.UI/Views/SoloRomListPanel.axaml.cs index 6a312211..a54b8fb9 100644 --- a/src/TrackerCouncil.Smz3.UI/Views/SoloRomListPanel.axaml.cs +++ b/src/TrackerCouncil.Smz3.UI/Views/SoloRomListPanel.axaml.cs @@ -220,7 +220,11 @@ private async void ArchipelagoButton_OnClick(object? sender, RoutedEventArgs e) try { if (_service == null) return; - await _service.OpenArchipelagoModeAsync(); + if (await _service.OpenArchipelagoModeAsync()) + { + await MessageWindow.ShowInfoDialog( + "ROM successfully parsed and updated into a new file. The original ROM has been been left alone with no modifications. You will need to launch the ROM from SZM3 Cas' or right click on the entry in the list to open the folder and find the updated ROM file."); + } } catch { From 64d85f75e601051e14c8bec9b40b8f13db21e22f Mon Sep 17 00:00:00 2001 From: MattEqualsCoder Date: Wed, 1 Jan 2025 14:54:47 -0500 Subject: [PATCH 12/13] Add code to give items to AP roms for testing --- .../AutoTracking/GameService.cs | 34 +++++++++++++++---- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/src/TrackerCouncil.Smz3.Tracking/AutoTracking/GameService.cs b/src/TrackerCouncil.Smz3.Tracking/AutoTracking/GameService.cs index 4d7e68d2..92de3079 100644 --- a/src/TrackerCouncil.Smz3.Tracking/AutoTracking/GameService.cs +++ b/src/TrackerCouncil.Smz3.Tracking/AutoTracking/GameService.cs @@ -27,6 +27,9 @@ public class GameService : TrackerModule, IGameService private readonly ILogger _logger; private readonly int _trackerPlayerId; private readonly Dictionary _emulatorActions = new(); + private int _giveItemCountAddress = 0xA26602; + private int _giveItemDetailLength = 4; + private int _giveItemDetailStartingIndex = 2; /// /// Initializes a new instance of the @@ -117,11 +120,18 @@ public async Task TryGiveItemsAsync(List items, int fromPlayerId) /// False if it is currently unable to give the items to the player public async Task TryGiveItemTypesAsync(List<(ItemType type, int fromPlayerId)> items) { - if (!IsInGame()) + if (!IsInGame() || TrackerBase.World.Config.RomGenerator != RomGenerator.Cas) { return false; } + if (TrackerBase.World.Config.RomGenerator == RomGenerator.Archipelago) + { + _giveItemCountAddress = 0xA26D38; + _giveItemDetailLength = 2; + _giveItemDetailStartingIndex = 0; + } + // Get the first block of memory var firstBlockResponse = await _snesConnectorService.MakeMemoryRequestAsync(new SnesSingleMemoryRequest() { @@ -156,9 +166,11 @@ public async Task TryGiveItemTypesAsync(List<(ItemType type, int fromPlaye // Each item takes up two words and we're interested in the second word in each pair. var data = firstDataSet.Raw.Concat(secondDataSet.Raw).ToArray(); var itemCounter = 0; - for (var i = 2; i < 0x600; i += 4) + for (var i = _giveItemDetailStartingIndex; i < 0x600; i += _giveItemDetailLength) { - var item = (ItemType)BitConverter.ToUInt16(data.AsSpan(i, 2)); + var item = _giveItemDetailLength == 4 + ? (ItemType)BitConverter.ToUInt16(data.AsSpan(i, 2)) + : (ItemType)data[i + 1]; if (item != ItemType.Nothing) { itemCounter++; @@ -172,8 +184,16 @@ public async Task TryGiveItemTypesAsync(List<(ItemType type, int fromPlaye var bytes = new List(); foreach (var item in batch) { - bytes.AddRange(Int16ToBytes(item.fromPlayerId)); - bytes.AddRange(Int16ToBytes((int)item.type)); + if (_giveItemDetailLength == 4) + { + bytes.AddRange(Int16ToBytes(item.fromPlayerId)); + bytes.AddRange(Int16ToBytes((int)item.type)); + } + else + { + bytes.Add((byte)item.fromPlayerId); + bytes.Add((byte)item.type); + } } _snesConnectorService.MakeMemoryRequest(new SnesSingleMemoryRequest() @@ -182,7 +202,7 @@ public async Task TryGiveItemTypesAsync(List<(ItemType type, int fromPlaye SnesMemoryDomain = SnesMemoryDomain.CartridgeSave, AddressFormat = AddressFormat.Snes9x, SniMemoryMapping = MemoryMapping.ExHiRom, - Address = 0xA26000 + (itemCounter * 4), + Address = 0xA26000 + (itemCounter * _giveItemDetailLength), Data = bytes }); @@ -196,7 +216,7 @@ public async Task TryGiveItemTypesAsync(List<(ItemType type, int fromPlaye SnesMemoryDomain = SnesMemoryDomain.CartridgeSave, AddressFormat = AddressFormat.Snes9x, SniMemoryMapping = MemoryMapping.ExHiRom, - Address = 0xA26602, + Address = _giveItemCountAddress, Data = Int16ToBytes(itemCounter) }); From cc1124b847f1c8e80cef9875469006fcf68aae52 Mon Sep 17 00:00:00 2001 From: MattEqualsCoder Date: Wed, 1 Jan 2025 15:19:30 -0500 Subject: [PATCH 13/13] Update lower norfair east exit logic for keysanity --- .../WorldData/Regions/SuperMetroid/Norfair/LowerNorfairEast.cs | 3 ++- src/TrackerCouncil.Smz3.UI/TrackerCouncil.Smz3.UI.csproj | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/TrackerCouncil.Smz3.Data/WorldData/Regions/SuperMetroid/Norfair/LowerNorfairEast.cs b/src/TrackerCouncil.Smz3.Data/WorldData/Regions/SuperMetroid/Norfair/LowerNorfairEast.cs index 2a3e5f62..8a8c7ed0 100644 --- a/src/TrackerCouncil.Smz3.Data/WorldData/Regions/SuperMetroid/Norfair/LowerNorfairEast.cs +++ b/src/TrackerCouncil.Smz3.Data/WorldData/Regions/SuperMetroid/Norfair/LowerNorfairEast.cs @@ -81,7 +81,8 @@ public bool CanBeatBoss(Progression items) private bool CanExit(Progression items) { return items.CardNorfairL2 /*Bubble Mountain*/ || - (items.Gravity && items.Wave /* Volcano Room and Blue Gate */ && (items.Grapple || items.SpaceJump /*Spikey Acid Snakes and Croc Escape*/)); + items is { Gravity: true, SpaceJump: true } /* Path back to Mire*/ || + (items is { Gravity: true, Wave: true } /* Volcano Room and Blue Gate */ && (items.Grapple || items.SpaceJump /*Spikey Acid Snakes and Croc Escape*/)); } public class SpringBallMazeRoom : Room diff --git a/src/TrackerCouncil.Smz3.UI/TrackerCouncil.Smz3.UI.csproj b/src/TrackerCouncil.Smz3.UI/TrackerCouncil.Smz3.UI.csproj index 40ac3512..631dc709 100644 --- a/src/TrackerCouncil.Smz3.UI/TrackerCouncil.Smz3.UI.csproj +++ b/src/TrackerCouncil.Smz3.UI/TrackerCouncil.Smz3.UI.csproj @@ -6,7 +6,7 @@ true app.manifest true - 9.9.0 + 9.9.0-rc.3 SMZ3CasRandomizer Assets\smz3.ico $(MSBuildProjectName.Replace(" ", "_"))