From 66a8de883dd2897af3c79cb0cd0ff03f9b7b1b7c Mon Sep 17 00:00:00 2001 From: Matthew <3005344+LeFauxMatt@users.noreply.github.com> Date: Tue, 17 Dec 2024 18:38:43 -0800 Subject: [PATCH 1/5] draft api --- CJBItemSpawner/Framework/CJBItemSpawnerAPI.cs | 30 +++++++++++++++++++ CJBItemSpawner/ICJBItemSpawnerAPI.cs | 10 +++++++ CJBItemSpawner/ModEntry.cs | 5 ++++ 3 files changed, 45 insertions(+) create mode 100644 CJBItemSpawner/Framework/CJBItemSpawnerAPI.cs create mode 100644 CJBItemSpawner/ICJBItemSpawnerAPI.cs diff --git a/CJBItemSpawner/Framework/CJBItemSpawnerAPI.cs b/CJBItemSpawner/Framework/CJBItemSpawnerAPI.cs new file mode 100644 index 00000000..7c808eec --- /dev/null +++ b/CJBItemSpawner/Framework/CJBItemSpawnerAPI.cs @@ -0,0 +1,30 @@ +using System; +using StardewValley; + +namespace CJBItemSpawner.Framework; + +/// +public sealed class CJBItemSpawnerAPI : ICJBItemSpawnerAPI +{ + /********* + ** Fields + *********/ + /// Build an item spawner menu. + private readonly Func BuildMenu; + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// Method for building an item spawner menu. + internal CJBItemSpawnerAPI(Func buildMenu) + { + this.BuildMenu = buildMenu; + } + + /// + public void OpenItemSpawnerMenu() + { + Game1.activeClickableMenu = this.BuildMenu(); + } +} diff --git a/CJBItemSpawner/ICJBItemSpawnerAPI.cs b/CJBItemSpawner/ICJBItemSpawnerAPI.cs new file mode 100644 index 00000000..ea7a5252 --- /dev/null +++ b/CJBItemSpawner/ICJBItemSpawnerAPI.cs @@ -0,0 +1,10 @@ +namespace CJBItemSpawner; + +/// The API which lets other mods interact with CJB Item Spawner. +internal interface ICJBItemSpawnerAPI +{ + /// + /// Open the item spawner menu. + /// + void OpenItemSpawnerMenu(); +} diff --git a/CJBItemSpawner/ModEntry.cs b/CJBItemSpawner/ModEntry.cs index 4a6b8e6f..762e76f3 100644 --- a/CJBItemSpawner/ModEntry.cs +++ b/CJBItemSpawner/ModEntry.cs @@ -65,6 +65,11 @@ public override void Entry(IModHelper helper) helper.Events.GameLoop.UpdateTicked += this.OnUpdateTicked; } + /// + public override object GetApi() + { + return new CJBItemSpawnerAPI(this.BuildMenu); + } /********* ** Private methods From 7d1aa3e70f5fc9613d51ac847b410c831e3dd1c1 Mon Sep 17 00:00:00 2001 From: Matthew <3005344+LeFauxMatt@users.noreply.github.com> Date: Tue, 14 Jan 2025 10:24:09 -0800 Subject: [PATCH 2/5] Add api method for adding custom repository of searchable items --- .../Framework/ItemData/ItemRepository.cs | 28 ++++++------- .../Framework/ItemData/SearchableItem.cs | 30 ++++++------- .../Framework/Models/ModDataCategory.cs | 2 +- .../Framework/Models/ModDataCategoryRule.cs | 2 +- CJBItemSpawner/Framework/SpawnableItem.cs | 2 +- CJBItemSpawner/ICJBItemSpawnerAPI.cs | 4 ++ CJBItemSpawner/IItemRepository.cs | 17 ++++++++ CJBItemSpawner/ISearchableItem.cs | 42 +++++++++++++++++++ CJBItemSpawner/ModEntry.cs | 4 +- 9 files changed, 95 insertions(+), 36 deletions(-) create mode 100644 CJBItemSpawner/IItemRepository.cs create mode 100644 CJBItemSpawner/ISearchableItem.cs diff --git a/CJBItemSpawner/Framework/ItemData/ItemRepository.cs b/CJBItemSpawner/Framework/ItemData/ItemRepository.cs index 73ff7d1b..bc9c5d7e 100644 --- a/CJBItemSpawner/Framework/ItemData/ItemRepository.cs +++ b/CJBItemSpawner/Framework/ItemData/ItemRepository.cs @@ -13,16 +13,14 @@ namespace CJBItemSpawner.Framework.ItemData; /// Provides methods for searching and constructing items. /// This is copied from the SMAPI source code and should be kept in sync with it. -internal class ItemRepository +internal class ItemRepository : IItemRepository { /********* ** Public methods *********/ - /// Get all spawnable items. - /// Only include items for the given . - /// Whether to include flavored variants like "Sunflower Honey". + /// [SuppressMessage("ReSharper", "AccessToModifiedClosure", Justification = $"{nameof(ItemRepository.TryCreate)} invokes the lambda immediately.")] - public IEnumerable GetAll(string? onlyType = null, bool includeVariants = true) + public IEnumerable GetAll(string? onlyType = null, bool includeVariants = true) { // // @@ -34,7 +32,7 @@ public IEnumerable GetAll(string? onlyType = null, bool includeV // // - IEnumerable GetAllRaw() + IEnumerable GetAllRaw() { // get from item data definitions foreach (IItemDataDefinition itemType in ItemRegistry.ItemTypes) @@ -52,7 +50,7 @@ public IEnumerable GetAll(string? onlyType = null, bool includeV foreach (string id in itemType.GetAllIds()) { // base item - SearchableItem? result = this.TryCreate(itemType.Identifier, id, p => ItemRegistry.Create(itemType.Identifier + p.Id)); + ISearchableItem? result = this.TryCreate(itemType.Identifier, id, p => ItemRegistry.Create(itemType.Identifier + p.Id)); // ring if (result?.Item is Ring) @@ -61,14 +59,14 @@ public IEnumerable GetAll(string? onlyType = null, bool includeV // journal scraps else if (result?.QualifiedItemId == "(O)842") { - foreach (SearchableItem? journalScrap in this.GetSecretNotes(itemType, isJournalScrap: true)) + foreach (ISearchableItem? journalScrap in this.GetSecretNotes(itemType, isJournalScrap: true)) yield return journalScrap; } // secret notes else if (result?.QualifiedItemId == "(O)79") { - foreach (SearchableItem? secretNote in this.GetSecretNotes(itemType, isJournalScrap: false)) + foreach (ISearchableItem? secretNote in this.GetSecretNotes(itemType, isJournalScrap: false)) yield return secretNote; } @@ -97,7 +95,7 @@ public IEnumerable GetAll(string? onlyType = null, bool includeV if (includeVariants) { - foreach (SearchableItem? variant in this.GetFlavoredObjectVariants(objectDataDefinition, result?.Item as SObject, itemType)) + foreach (ISearchableItem? variant in this.GetFlavoredObjectVariants(objectDataDefinition, result?.Item as SObject, itemType)) yield return variant; } } @@ -129,7 +127,7 @@ select item /// The object data definition. /// Whether to get journal scraps. /// Derived from . - private IEnumerable GetSecretNotes(IItemDataDefinition itemType, bool isJournalScrap) + private IEnumerable GetSecretNotes(IItemDataDefinition itemType, bool isJournalScrap) { // get base item ID string baseId = isJournalScrap ? "842" : "79"; @@ -165,7 +163,7 @@ select item /// The item data definition for object items. /// A sample of the base item. /// The object data definition. - private IEnumerable GetFlavoredObjectVariants(ObjectDataDefinition objectDataDefinition, SObject? item, IItemDataDefinition itemType) + private IEnumerable GetFlavoredObjectVariants(ObjectDataDefinition objectDataDefinition, SObject? item, IItemDataDefinition itemType) { if (item is null) yield break; @@ -226,7 +224,7 @@ select item continue; // create roe - SearchableItem? roe = this.TryCreate(itemType.Identifier, $"812/{input.ItemId}", _ => objectDataDefinition.CreateFlavoredRoe(input)); + ISearchableItem? roe = this.TryCreate(itemType.Identifier, $"812/{input.ItemId}", _ => objectDataDefinition.CreateFlavoredRoe(input)); yield return roe; // create aged roe @@ -286,11 +284,11 @@ private TAsset TryLoad(Func load) /// The item type. /// The locally unique item key. /// Create an item instance. - private SearchableItem? TryCreate(string type, string key, Func createItem) + private ISearchableItem? TryCreate(string type, string key, Func createItem) { try { - SearchableItem item = new SearchableItem(type, key, createItem); + ISearchableItem item = new SearchableItem(type, key, createItem); item.Item.getDescription(); // force-load item data, so it crashes here if it's invalid if (item.Item.Name is null or "Error Item") diff --git a/CJBItemSpawner/Framework/ItemData/SearchableItem.cs b/CJBItemSpawner/Framework/ItemData/SearchableItem.cs index 33e050d3..1b9da2c4 100644 --- a/CJBItemSpawner/Framework/ItemData/SearchableItem.cs +++ b/CJBItemSpawner/Framework/ItemData/SearchableItem.cs @@ -1,35 +1,33 @@ using System; using StardewValley; -using StardewValley.ItemTypeDefinitions; namespace CJBItemSpawner.Framework.ItemData; -/// A game item with metadata. -/// This is copied from the SMAPI source code and should be kept in sync with it. -internal class SearchableItem +/// +internal class SearchableItem : ISearchableItem { /********* ** Accessors *********/ - /// The value for the item type. + /// public string Type { get; } - /// A sample item instance. + /// public Item Item { get; } - /// Create an item instance. + /// public Func CreateItem { get; } - /// The unqualified item ID. + /// public string Id { get; } - /// The qualified item ID. + /// public string QualifiedItemId { get; } - /// The item's default name. + /// public string Name => this.Item.Name; - /// The item's display name for the current language. + /// public string DisplayName => this.Item.DisplayName; @@ -40,7 +38,7 @@ internal class SearchableItem /// The item type. /// The unqualified item ID. /// Create an item instance. - public SearchableItem(string type, string id, Func createItem) + public SearchableItem(string type, string id, Func createItem) { this.Type = type; this.Id = id; @@ -51,7 +49,7 @@ public SearchableItem(string type, string id, Func createI /// Construct an instance. /// The item metadata to copy. - public SearchableItem(SearchableItem item) + public SearchableItem(ISearchableItem item) { this.Type = item.Type; this.Id = item.Id; @@ -60,8 +58,7 @@ public SearchableItem(SearchableItem item) this.Item = item.Item; } - /// Get whether the item name contains a case-insensitive substring. - /// The substring to find. + /// public bool NameContains(string substring) { return @@ -69,8 +66,7 @@ public bool NameContains(string substring) || this.DisplayName.IndexOf(substring, StringComparison.OrdinalIgnoreCase) != -1; } - /// Get whether the item name is exactly equal to a case-insensitive string. - /// The substring to find. + /// public bool NameEquivalentTo(string name) { return diff --git a/CJBItemSpawner/Framework/Models/ModDataCategory.cs b/CJBItemSpawner/Framework/Models/ModDataCategory.cs index 1d479ef3..4adc6b17 100644 --- a/CJBItemSpawner/Framework/Models/ModDataCategory.cs +++ b/CJBItemSpawner/Framework/Models/ModDataCategory.cs @@ -13,7 +13,7 @@ internal record ModDataCategory(string Label, ModDataCategoryRule? When, ModData *********/ /// Get whether a given item matches the rules for this category. /// The item to check. - public bool IsMatch(SearchableItem item) + public bool IsMatch(ISearchableItem item) { return this.When != null diff --git a/CJBItemSpawner/Framework/Models/ModDataCategoryRule.cs b/CJBItemSpawner/Framework/Models/ModDataCategoryRule.cs index 13e778d7..eb45ebe4 100644 --- a/CJBItemSpawner/Framework/Models/ModDataCategoryRule.cs +++ b/CJBItemSpawner/Framework/Models/ModDataCategoryRule.cs @@ -46,7 +46,7 @@ public ModDataCategoryRule(HashSet? @class, HashSet? objType, Ha /// Get whether a given item matches the rules for this category. /// The searchable item to check. - public bool IsMatch(SearchableItem entry) + public bool IsMatch(ISearchableItem entry) { Item item = entry.Item; SObject? obj = item as SObject; diff --git a/CJBItemSpawner/Framework/SpawnableItem.cs b/CJBItemSpawner/Framework/SpawnableItem.cs index c05628cc..7e1d2c74 100644 --- a/CJBItemSpawner/Framework/SpawnableItem.cs +++ b/CJBItemSpawner/Framework/SpawnableItem.cs @@ -18,7 +18,7 @@ internal class SpawnableItem : SearchableItem /// Construct an instance. /// The item metadata. /// The item's category filter label for the spawn menu. - public SpawnableItem(SearchableItem item, string category) + public SpawnableItem(ISearchableItem item, string category) : base(item) { this.Category = category; diff --git a/CJBItemSpawner/ICJBItemSpawnerAPI.cs b/CJBItemSpawner/ICJBItemSpawnerAPI.cs index ea7a5252..91d0decf 100644 --- a/CJBItemSpawner/ICJBItemSpawnerAPI.cs +++ b/CJBItemSpawner/ICJBItemSpawnerAPI.cs @@ -7,4 +7,8 @@ internal interface ICJBItemSpawnerAPI /// Open the item spawner menu. /// void OpenItemSpawnerMenu(); + + /// Add an item repository. + /// An item repository which returns all spawnable items. + void AddRepository(IItemRepository repository); } diff --git a/CJBItemSpawner/IItemRepository.cs b/CJBItemSpawner/IItemRepository.cs new file mode 100644 index 00000000..8c8649f9 --- /dev/null +++ b/CJBItemSpawner/IItemRepository.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using StardewValley.ItemTypeDefinitions; + +namespace CJBItemSpawner; + +/// Provides methods for searching and constructing items. +/// This is copied from the SMAPI source code and should be kept in sync with it. +public interface IItemRepository +{ + /********* + ** Public methods + *********/ + /// Get all spawnable items. + /// Only include items for the given . + /// Whether to include flavored variants like "Sunflower Honey". + public IEnumerable GetAll(string? onlyType = null, bool includeVariants = true); +} diff --git a/CJBItemSpawner/ISearchableItem.cs b/CJBItemSpawner/ISearchableItem.cs new file mode 100644 index 00000000..ee81ea6a --- /dev/null +++ b/CJBItemSpawner/ISearchableItem.cs @@ -0,0 +1,42 @@ +using System; +using StardewValley; +using StardewValley.ItemTypeDefinitions; + +namespace CJBItemSpawner; + +/// A game item with metadata. +/// This is copied from the SMAPI source code and should be kept in sync with it. +public interface ISearchableItem +{ + /********* + ** Accessors + *********/ + /// The value for the item type. + public string Type { get; } + + /// A sample item instance. + public Item Item { get; } + + /// Create an item instance. + public Func CreateItem { get; } + + /// The unqualified item ID. + public string Id { get; } + + /// The qualified item ID. + public string QualifiedItemId { get; } + + /// The item's default name. + public string Name { get; } + + /// The item's display name for the current language. + public string DisplayName { get; } + + /// Get whether the item name contains a case-insensitive substring. + /// The substring to find. + public bool NameContains(string substring); + + /// Get whether the item name is exactly equal to a case-insensitive string. + /// The substring to find. + public bool NameEquivalentTo(string name); +} diff --git a/CJBItemSpawner/ModEntry.cs b/CJBItemSpawner/ModEntry.cs index 762e76f3..65895e0a 100644 --- a/CJBItemSpawner/ModEntry.cs +++ b/CJBItemSpawner/ModEntry.cs @@ -127,7 +127,7 @@ private ItemMenu BuildMenu() /// Get the items which can be spawned. private IEnumerable GetSpawnableItems() { - foreach (SearchableItem entry in new ItemRepository().GetAll()) + foreach (ISearchableItem entry in new ItemRepository().GetAll()) { ModDataCategory? category = this.Categories.FirstOrDefault(rule => rule.IsMatch(entry)); @@ -140,6 +140,8 @@ private IEnumerable GetSpawnableItems() yield return new SpawnableItem(entry, categoryLabel); } + + // TODO: get items from api } /// Log a trace message which summarizes the user's current config. From cc93f8185c191bc4406219beeafa8a039377f89f Mon Sep 17 00:00:00 2001 From: Matthew <3005344+LeFauxMatt@users.noreply.github.com> Date: Tue, 14 Jan 2025 10:32:34 -0800 Subject: [PATCH 3/5] Implemented the interface --- CJBItemSpawner/Framework/CJBItemSpawnerAPI.cs | 13 ++++++- CJBItemSpawner/ModEntry.cs | 37 +++++++++++++------ 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/CJBItemSpawner/Framework/CJBItemSpawnerAPI.cs b/CJBItemSpawner/Framework/CJBItemSpawnerAPI.cs index 7c808eec..e764bb82 100644 --- a/CJBItemSpawner/Framework/CJBItemSpawnerAPI.cs +++ b/CJBItemSpawner/Framework/CJBItemSpawnerAPI.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using StardewValley; namespace CJBItemSpawner.Framework; @@ -12,14 +13,18 @@ public sealed class CJBItemSpawnerAPI : ICJBItemSpawnerAPI /// Build an item spawner menu. private readonly Func BuildMenu; + /// The item repositories which returns all spawnable items. + private readonly IList ItemRepositories; + /********* ** Public methods *********/ /// Construct an instance. /// Method for building an item spawner menu. - internal CJBItemSpawnerAPI(Func buildMenu) + internal CJBItemSpawnerAPI(Func buildMenu, IList itemRepositories) { this.BuildMenu = buildMenu; + this.ItemRepositories = itemRepositories; } /// @@ -27,4 +32,10 @@ public void OpenItemSpawnerMenu() { Game1.activeClickableMenu = this.BuildMenu(); } + + /// + public void AddRepository(IItemRepository repository) + { + this.ItemRepositories.Add(repository); + } } diff --git a/CJBItemSpawner/ModEntry.cs b/CJBItemSpawner/ModEntry.cs index 65895e0a..93d4ccdd 100644 --- a/CJBItemSpawner/ModEntry.cs +++ b/CJBItemSpawner/ModEntry.cs @@ -26,6 +26,9 @@ internal class ModEntry : Mod /// The item category filters available in the item spawner menu. private ModDataCategory[] Categories = null!; // set in Entry + /// The item repositories which returns all spawnable items. + private readonly IList ItemRepositories = new List(); + /// Manages the gamepad text entry UI. private readonly TextEntryManager TextEntryManager = new(); @@ -68,7 +71,7 @@ public override void Entry(IModHelper helper) /// public override object GetApi() { - return new CJBItemSpawnerAPI(this.BuildMenu); + return new CJBItemSpawnerAPI(this.BuildMenu, this.ItemRepositories); } /********* @@ -124,24 +127,36 @@ private ItemMenu BuildMenu() return new ItemMenu(items, this.TextEntryManager, this.ItemData, this.Helper.ModContent, this.Monitor, this.Config.ReclaimPriceInMenuTrashCan); } + /// Get the item repositories. + private IEnumerable GetRepositories() + { + yield return new ItemRepository(); + + foreach (IItemRepository repository in this.ItemRepositories) + { + yield return repository; + } + } + /// Get the items which can be spawned. private IEnumerable GetSpawnableItems() { - foreach (ISearchableItem entry in new ItemRepository().GetAll()) + foreach (IItemRepository repository in this.GetRepositories()) { - ModDataCategory? category = this.Categories.FirstOrDefault(rule => rule.IsMatch(entry)); + foreach (ISearchableItem entry in repository.GetAll()) + { + ModDataCategory? category = this.Categories.FirstOrDefault(rule => rule.IsMatch(entry)); - if (category?.Label != null && this.Config.HideCategories.Contains(category.Label)) - continue; + if (category?.Label != null && this.Config.HideCategories.Contains(category.Label)) + continue; - string categoryLabel = category != null - ? I18n.GetByKey(category.Label).Default(category.Label) - : I18n.Filter_Miscellaneous(); + string categoryLabel = category != null + ? I18n.GetByKey(category.Label).Default(category.Label) + : I18n.Filter_Miscellaneous(); - yield return new SpawnableItem(entry, categoryLabel); + yield return new SpawnableItem(entry, categoryLabel); + } } - - // TODO: get items from api } /// Log a trace message which summarizes the user's current config. From c70ad10a4d21fa37dde48041e294ee57ffd96372 Mon Sep 17 00:00:00 2001 From: Matthew <3005344+LeFauxMatt@users.noreply.github.com> Date: Tue, 14 Jan 2025 10:52:35 -0800 Subject: [PATCH 4/5] Alternative api proposal --- CJBItemSpawner/Framework/CJBItemSpawnerAPI.cs | 7 +-- .../Framework/ItemData/ItemRepository.cs | 6 ++- CJBItemSpawner/ICJBItemSpawnerAPI.cs | 19 +++++++- CJBItemSpawner/IItemRepository.cs | 17 ------- CJBItemSpawner/ModEntry.cs | 47 ++++++++++--------- 5 files changed, 50 insertions(+), 46 deletions(-) delete mode 100644 CJBItemSpawner/IItemRepository.cs diff --git a/CJBItemSpawner/Framework/CJBItemSpawnerAPI.cs b/CJBItemSpawner/Framework/CJBItemSpawnerAPI.cs index e764bb82..11608139 100644 --- a/CJBItemSpawner/Framework/CJBItemSpawnerAPI.cs +++ b/CJBItemSpawner/Framework/CJBItemSpawnerAPI.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using StardewValley; +using static CJBItemSpawner.ICJBItemSpawnerAPI; namespace CJBItemSpawner.Framework; @@ -14,14 +15,14 @@ public sealed class CJBItemSpawnerAPI : ICJBItemSpawnerAPI private readonly Func BuildMenu; /// The item repositories which returns all spawnable items. - private readonly IList ItemRepositories; + private readonly IList ItemRepositories; /********* ** Public methods *********/ /// Construct an instance. /// Method for building an item spawner menu. - internal CJBItemSpawnerAPI(Func buildMenu, IList itemRepositories) + internal CJBItemSpawnerAPI(Func buildMenu, IList itemRepositories) { this.BuildMenu = buildMenu; this.ItemRepositories = itemRepositories; @@ -34,7 +35,7 @@ public void OpenItemSpawnerMenu() } /// - public void AddRepository(IItemRepository repository) + public void AddRepository(Repository repository) { this.ItemRepositories.Add(repository); } diff --git a/CJBItemSpawner/Framework/ItemData/ItemRepository.cs b/CJBItemSpawner/Framework/ItemData/ItemRepository.cs index bc9c5d7e..5b1214f6 100644 --- a/CJBItemSpawner/Framework/ItemData/ItemRepository.cs +++ b/CJBItemSpawner/Framework/ItemData/ItemRepository.cs @@ -13,12 +13,14 @@ namespace CJBItemSpawner.Framework.ItemData; /// Provides methods for searching and constructing items. /// This is copied from the SMAPI source code and should be kept in sync with it. -internal class ItemRepository : IItemRepository +internal class ItemRepository { /********* ** Public methods *********/ - /// + /// Get all spawnable items. + /// Only include items for the given . + /// Whether to include flavored variants like "Sunflower Honey". [SuppressMessage("ReSharper", "AccessToModifiedClosure", Justification = $"{nameof(ItemRepository.TryCreate)} invokes the lambda immediately.")] public IEnumerable GetAll(string? onlyType = null, bool includeVariants = true) { diff --git a/CJBItemSpawner/ICJBItemSpawnerAPI.cs b/CJBItemSpawner/ICJBItemSpawnerAPI.cs index 91d0decf..cb7a4bc2 100644 --- a/CJBItemSpawner/ICJBItemSpawnerAPI.cs +++ b/CJBItemSpawner/ICJBItemSpawnerAPI.cs @@ -1,7 +1,12 @@ +using System; +using System.Collections.Generic; +using StardewValley; +using StardewValley.ItemTypeDefinitions; + namespace CJBItemSpawner; /// The API which lets other mods interact with CJB Item Spawner. -internal interface ICJBItemSpawnerAPI +public interface ICJBItemSpawnerAPI { /// /// Open the item spawner menu. @@ -10,5 +15,15 @@ internal interface ICJBItemSpawnerAPI /// Add an item repository. /// An item repository which returns all spawnable items. - void AddRepository(IItemRepository repository); + void AddRepository(Repository repository); + + /// Get all spawnable items. + /// Only include items for the given . + /// Whether to include flavored variants like "Sunflower Honey". + public delegate IEnumerable<(string Type, string Id, CreateItem CreateItem)> Repository(string? onlyType = null, bool includeVariants = true); + + /// Create an item instance. + /// The item type. + /// The unqualified item ID. + public delegate Item CreateItem(string type, string id); } diff --git a/CJBItemSpawner/IItemRepository.cs b/CJBItemSpawner/IItemRepository.cs deleted file mode 100644 index 8c8649f9..00000000 --- a/CJBItemSpawner/IItemRepository.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Collections.Generic; -using StardewValley.ItemTypeDefinitions; - -namespace CJBItemSpawner; - -/// Provides methods for searching and constructing items. -/// This is copied from the SMAPI source code and should be kept in sync with it. -public interface IItemRepository -{ - /********* - ** Public methods - *********/ - /// Get all spawnable items. - /// Only include items for the given . - /// Whether to include flavored variants like "Sunflower Honey". - public IEnumerable GetAll(string? onlyType = null, bool includeVariants = true); -} diff --git a/CJBItemSpawner/ModEntry.cs b/CJBItemSpawner/ModEntry.cs index 93d4ccdd..93835276 100644 --- a/CJBItemSpawner/ModEntry.cs +++ b/CJBItemSpawner/ModEntry.cs @@ -8,6 +8,7 @@ using StardewModdingAPI; using StardewModdingAPI.Events; using StardewValley; +using static CJBItemSpawner.ICJBItemSpawnerAPI; namespace CJBItemSpawner; @@ -27,7 +28,7 @@ internal class ModEntry : Mod private ModDataCategory[] Categories = null!; // set in Entry /// The item repositories which returns all spawnable items. - private readonly IList ItemRepositories = new List(); + private readonly IList ItemRepositories = new List(); /// Manages the gamepad text entry UI. private readonly TextEntryManager TextEntryManager = new(); @@ -127,35 +128,37 @@ private ItemMenu BuildMenu() return new ItemMenu(items, this.TextEntryManager, this.ItemData, this.Helper.ModContent, this.Monitor, this.Config.ReclaimPriceInMenuTrashCan); } - /// Get the item repositories. - private IEnumerable GetRepositories() - { - yield return new ItemRepository(); - - foreach (IItemRepository repository in this.ItemRepositories) - { - yield return repository; - } - } - /// Get the items which can be spawned. private IEnumerable GetSpawnableItems() { - foreach (IItemRepository repository in this.GetRepositories()) + IEnumerable GetSpawnableItemsRaw() { - foreach (ISearchableItem entry in repository.GetAll()) + foreach (ISearchableItem entry in new ItemRepository().GetAll()) + { + yield return entry; + } + + foreach (Repository getAll in this.ItemRepositories) { - ModDataCategory? category = this.Categories.FirstOrDefault(rule => rule.IsMatch(entry)); + foreach ((string type, string id, CreateItem createItem) in getAll()) + { + yield return new SearchableItem(type, id, p => createItem(p.Type, p.Id)); + } + } + } - if (category?.Label != null && this.Config.HideCategories.Contains(category.Label)) - continue; + foreach (ISearchableItem entry in GetSpawnableItemsRaw()) + { + ModDataCategory? category = this.Categories.FirstOrDefault(rule => rule.IsMatch(entry)); - string categoryLabel = category != null - ? I18n.GetByKey(category.Label).Default(category.Label) - : I18n.Filter_Miscellaneous(); + if (category?.Label != null && this.Config.HideCategories.Contains(category.Label)) + continue; - yield return new SpawnableItem(entry, categoryLabel); - } + string categoryLabel = category != null + ? I18n.GetByKey(category.Label).Default(category.Label) + : I18n.Filter_Miscellaneous(); + + yield return new SpawnableItem(entry, categoryLabel); } } From 6b806c85ef2980ec197745ef114d96d900651cb9 Mon Sep 17 00:00:00 2001 From: Matthew <3005344+LeFauxMatt@users.noreply.github.com> Date: Tue, 14 Jan 2025 10:56:48 -0800 Subject: [PATCH 5/5] Removed unused interface from proposal 1 --- .../Framework/ItemData/ItemRepository.cs | 22 +++++----- .../Framework/ItemData/SearchableItem.cs | 29 +++++++------ .../Framework/Models/ModDataCategory.cs | 2 +- .../Framework/Models/ModDataCategoryRule.cs | 2 +- CJBItemSpawner/Framework/SpawnableItem.cs | 2 +- CJBItemSpawner/ISearchableItem.cs | 42 ------------------- CJBItemSpawner/ModEntry.cs | 6 +-- 7 files changed, 33 insertions(+), 72 deletions(-) delete mode 100644 CJBItemSpawner/ISearchableItem.cs diff --git a/CJBItemSpawner/Framework/ItemData/ItemRepository.cs b/CJBItemSpawner/Framework/ItemData/ItemRepository.cs index 5b1214f6..73ff7d1b 100644 --- a/CJBItemSpawner/Framework/ItemData/ItemRepository.cs +++ b/CJBItemSpawner/Framework/ItemData/ItemRepository.cs @@ -22,7 +22,7 @@ internal class ItemRepository /// Only include items for the given . /// Whether to include flavored variants like "Sunflower Honey". [SuppressMessage("ReSharper", "AccessToModifiedClosure", Justification = $"{nameof(ItemRepository.TryCreate)} invokes the lambda immediately.")] - public IEnumerable GetAll(string? onlyType = null, bool includeVariants = true) + public IEnumerable GetAll(string? onlyType = null, bool includeVariants = true) { // // @@ -34,7 +34,7 @@ public IEnumerable GetAll(string? onlyType = null, bool include // // - IEnumerable GetAllRaw() + IEnumerable GetAllRaw() { // get from item data definitions foreach (IItemDataDefinition itemType in ItemRegistry.ItemTypes) @@ -52,7 +52,7 @@ public IEnumerable GetAll(string? onlyType = null, bool include foreach (string id in itemType.GetAllIds()) { // base item - ISearchableItem? result = this.TryCreate(itemType.Identifier, id, p => ItemRegistry.Create(itemType.Identifier + p.Id)); + SearchableItem? result = this.TryCreate(itemType.Identifier, id, p => ItemRegistry.Create(itemType.Identifier + p.Id)); // ring if (result?.Item is Ring) @@ -61,14 +61,14 @@ public IEnumerable GetAll(string? onlyType = null, bool include // journal scraps else if (result?.QualifiedItemId == "(O)842") { - foreach (ISearchableItem? journalScrap in this.GetSecretNotes(itemType, isJournalScrap: true)) + foreach (SearchableItem? journalScrap in this.GetSecretNotes(itemType, isJournalScrap: true)) yield return journalScrap; } // secret notes else if (result?.QualifiedItemId == "(O)79") { - foreach (ISearchableItem? secretNote in this.GetSecretNotes(itemType, isJournalScrap: false)) + foreach (SearchableItem? secretNote in this.GetSecretNotes(itemType, isJournalScrap: false)) yield return secretNote; } @@ -97,7 +97,7 @@ public IEnumerable GetAll(string? onlyType = null, bool include if (includeVariants) { - foreach (ISearchableItem? variant in this.GetFlavoredObjectVariants(objectDataDefinition, result?.Item as SObject, itemType)) + foreach (SearchableItem? variant in this.GetFlavoredObjectVariants(objectDataDefinition, result?.Item as SObject, itemType)) yield return variant; } } @@ -129,7 +129,7 @@ select item /// The object data definition. /// Whether to get journal scraps. /// Derived from . - private IEnumerable GetSecretNotes(IItemDataDefinition itemType, bool isJournalScrap) + private IEnumerable GetSecretNotes(IItemDataDefinition itemType, bool isJournalScrap) { // get base item ID string baseId = isJournalScrap ? "842" : "79"; @@ -165,7 +165,7 @@ select item /// The item data definition for object items. /// A sample of the base item. /// The object data definition. - private IEnumerable GetFlavoredObjectVariants(ObjectDataDefinition objectDataDefinition, SObject? item, IItemDataDefinition itemType) + private IEnumerable GetFlavoredObjectVariants(ObjectDataDefinition objectDataDefinition, SObject? item, IItemDataDefinition itemType) { if (item is null) yield break; @@ -226,7 +226,7 @@ select item continue; // create roe - ISearchableItem? roe = this.TryCreate(itemType.Identifier, $"812/{input.ItemId}", _ => objectDataDefinition.CreateFlavoredRoe(input)); + SearchableItem? roe = this.TryCreate(itemType.Identifier, $"812/{input.ItemId}", _ => objectDataDefinition.CreateFlavoredRoe(input)); yield return roe; // create aged roe @@ -286,11 +286,11 @@ private TAsset TryLoad(Func load) /// The item type. /// The locally unique item key. /// Create an item instance. - private ISearchableItem? TryCreate(string type, string key, Func createItem) + private SearchableItem? TryCreate(string type, string key, Func createItem) { try { - ISearchableItem item = new SearchableItem(type, key, createItem); + SearchableItem item = new SearchableItem(type, key, createItem); item.Item.getDescription(); // force-load item data, so it crashes here if it's invalid if (item.Item.Name is null or "Error Item") diff --git a/CJBItemSpawner/Framework/ItemData/SearchableItem.cs b/CJBItemSpawner/Framework/ItemData/SearchableItem.cs index 1b9da2c4..dc4aa5fd 100644 --- a/CJBItemSpawner/Framework/ItemData/SearchableItem.cs +++ b/CJBItemSpawner/Framework/ItemData/SearchableItem.cs @@ -3,31 +3,32 @@ namespace CJBItemSpawner.Framework.ItemData; -/// -internal class SearchableItem : ISearchableItem +/// A game item with metadata. +/// This is copied from the SMAPI source code and should be kept in sync with it. +internal class SearchableItem { /********* ** Accessors *********/ - /// + /// The value for the item type. public string Type { get; } - /// + /// A sample item instance. public Item Item { get; } - /// + /// Create an item instance. public Func CreateItem { get; } - /// + /// The unqualified item ID. public string Id { get; } - /// + /// The qualified item ID. public string QualifiedItemId { get; } - /// + /// The item's default name. public string Name => this.Item.Name; - /// + /// The item's display name for the current language. public string DisplayName => this.Item.DisplayName; @@ -38,7 +39,7 @@ internal class SearchableItem : ISearchableItem /// The item type. /// The unqualified item ID. /// Create an item instance. - public SearchableItem(string type, string id, Func createItem) + public SearchableItem(string type, string id, Func createItem) { this.Type = type; this.Id = id; @@ -49,7 +50,7 @@ public SearchableItem(string type, string id, Func create /// Construct an instance. /// The item metadata to copy. - public SearchableItem(ISearchableItem item) + public SearchableItem(SearchableItem item) { this.Type = item.Type; this.Id = item.Id; @@ -58,7 +59,8 @@ public SearchableItem(ISearchableItem item) this.Item = item.Item; } - /// + /// Get whether the item name contains a case-insensitive substring. + /// The substring to find. public bool NameContains(string substring) { return @@ -66,7 +68,8 @@ public bool NameContains(string substring) || this.DisplayName.IndexOf(substring, StringComparison.OrdinalIgnoreCase) != -1; } - /// + /// Get whether the item name is exactly equal to a case-insensitive string. + /// The substring to find. public bool NameEquivalentTo(string name) { return diff --git a/CJBItemSpawner/Framework/Models/ModDataCategory.cs b/CJBItemSpawner/Framework/Models/ModDataCategory.cs index 4adc6b17..1d479ef3 100644 --- a/CJBItemSpawner/Framework/Models/ModDataCategory.cs +++ b/CJBItemSpawner/Framework/Models/ModDataCategory.cs @@ -13,7 +13,7 @@ internal record ModDataCategory(string Label, ModDataCategoryRule? When, ModData *********/ /// Get whether a given item matches the rules for this category. /// The item to check. - public bool IsMatch(ISearchableItem item) + public bool IsMatch(SearchableItem item) { return this.When != null diff --git a/CJBItemSpawner/Framework/Models/ModDataCategoryRule.cs b/CJBItemSpawner/Framework/Models/ModDataCategoryRule.cs index eb45ebe4..13e778d7 100644 --- a/CJBItemSpawner/Framework/Models/ModDataCategoryRule.cs +++ b/CJBItemSpawner/Framework/Models/ModDataCategoryRule.cs @@ -46,7 +46,7 @@ public ModDataCategoryRule(HashSet? @class, HashSet? objType, Ha /// Get whether a given item matches the rules for this category. /// The searchable item to check. - public bool IsMatch(ISearchableItem entry) + public bool IsMatch(SearchableItem entry) { Item item = entry.Item; SObject? obj = item as SObject; diff --git a/CJBItemSpawner/Framework/SpawnableItem.cs b/CJBItemSpawner/Framework/SpawnableItem.cs index 7e1d2c74..c05628cc 100644 --- a/CJBItemSpawner/Framework/SpawnableItem.cs +++ b/CJBItemSpawner/Framework/SpawnableItem.cs @@ -18,7 +18,7 @@ internal class SpawnableItem : SearchableItem /// Construct an instance. /// The item metadata. /// The item's category filter label for the spawn menu. - public SpawnableItem(ISearchableItem item, string category) + public SpawnableItem(SearchableItem item, string category) : base(item) { this.Category = category; diff --git a/CJBItemSpawner/ISearchableItem.cs b/CJBItemSpawner/ISearchableItem.cs deleted file mode 100644 index ee81ea6a..00000000 --- a/CJBItemSpawner/ISearchableItem.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using StardewValley; -using StardewValley.ItemTypeDefinitions; - -namespace CJBItemSpawner; - -/// A game item with metadata. -/// This is copied from the SMAPI source code and should be kept in sync with it. -public interface ISearchableItem -{ - /********* - ** Accessors - *********/ - /// The value for the item type. - public string Type { get; } - - /// A sample item instance. - public Item Item { get; } - - /// Create an item instance. - public Func CreateItem { get; } - - /// The unqualified item ID. - public string Id { get; } - - /// The qualified item ID. - public string QualifiedItemId { get; } - - /// The item's default name. - public string Name { get; } - - /// The item's display name for the current language. - public string DisplayName { get; } - - /// Get whether the item name contains a case-insensitive substring. - /// The substring to find. - public bool NameContains(string substring); - - /// Get whether the item name is exactly equal to a case-insensitive string. - /// The substring to find. - public bool NameEquivalentTo(string name); -} diff --git a/CJBItemSpawner/ModEntry.cs b/CJBItemSpawner/ModEntry.cs index 93835276..4622b9ee 100644 --- a/CJBItemSpawner/ModEntry.cs +++ b/CJBItemSpawner/ModEntry.cs @@ -131,9 +131,9 @@ private ItemMenu BuildMenu() /// Get the items which can be spawned. private IEnumerable GetSpawnableItems() { - IEnumerable GetSpawnableItemsRaw() + IEnumerable GetSpawnableItemsRaw() { - foreach (ISearchableItem entry in new ItemRepository().GetAll()) + foreach (SearchableItem entry in new ItemRepository().GetAll()) { yield return entry; } @@ -147,7 +147,7 @@ IEnumerable GetSpawnableItemsRaw() } } - foreach (ISearchableItem entry in GetSpawnableItemsRaw()) + foreach (SearchableItem entry in GetSpawnableItemsRaw()) { ModDataCategory? category = this.Categories.FirstOrDefault(rule => rule.IsMatch(entry));