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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 27 additions & 2 deletions CJBItemSpawner/Framework/ItemData/ItemRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,20 @@ namespace CJBItemSpawner.Framework.ItemData;
/// <remarks>This is copied from the SMAPI source code and should be kept in sync with it.</remarks>
internal class ItemRepository
{
/*********
** Fields
*********/
/// <summary>Used to communicate with other mods</summary>
private readonly ItemSpawnerAPI API;

/*********
** Public methods
*********/
public ItemRepository(ItemSpawnerAPI API)
{
this.API = API;
}

/// <summary>Get all spawnable items.</summary>
/// <param name="onlyType">Only include items for the given <see cref="IItemDataDefinition.Identifier"/>.</param>
/// <param name="includeVariants">Whether to include flavored variants like "Sunflower Honey".</param>
Expand Down Expand Up @@ -90,7 +101,8 @@ public IEnumerable<SearchableItem> GetAll(string? onlyType = null, bool includeV
break;

default:
if (result != null)
// skip blacklisted items
if (result != null && !this.API.IsBlacklisted(result.QualifiedItemId))
yield return result;
break;
}
Expand All @@ -99,6 +111,9 @@ public IEnumerable<SearchableItem> GetAll(string? onlyType = null, bool includeV
{
foreach (SearchableItem? variant in this.GetFlavoredObjectVariants(objectDataDefinition, result?.Item as SObject, itemType))
yield return variant;

foreach (SearchableItem? variant in this.API.GetVariantsFor("(O)", id, this.TryCreate))
yield return variant;
}
}
}
Expand All @@ -108,7 +123,17 @@ public IEnumerable<SearchableItem> GetAll(string? onlyType = null, bool includeV
// no special handling needed
default:
foreach (string id in itemType.GetAllIds())
yield return this.TryCreate(itemType.Identifier, id, p => ItemRegistry.Create(itemType.Identifier + p.Id));
{
// skip blacklisted items
if (!this.API.IsBlacklisted(itemType.Identifier + id))
yield return this.TryCreate(itemType.Identifier, id, p => ItemRegistry.Create(itemType.Identifier + p.Id));

if (includeVariants)
{
foreach (SearchableItem? variant in this.API.GetVariantsFor(itemType.Identifier, id, this.TryCreate))
yield return variant;
}
}
break;
}
}
Expand Down
90 changes: 90 additions & 0 deletions CJBItemSpawner/Framework/ItemSpawnerAPI.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
using System;
using System.Collections.Generic;
using CJBItemSpawner.Framework.ItemData;
using StardewValley;
using StardewValley.Menus;

namespace CJBItemSpawner.Framework
{
public class ItemSpawnerAPI : IItemSpawnerAPI
{
/*********
** Fields
*********/
internal delegate SearchableItem? SearchableItemFactory(string type, string key, Func<SearchableItem, Item> createItem);

private readonly HashSet<string> Blacklist = [];
private readonly Func<IClickableMenu> BuildMenu;

public class VariantsRequestedEventArgs : IItemSpawnerAPI.IVariantsRequestedEventArgs
{
private readonly SearchableItemFactory TryCreate;
private readonly string type;
internal readonly List<SearchableItem> Items = [];

/// <inheritdoc/>
public string BaseId { get; init; }

/// <inheritdoc/>
public void TryAddVariant(string variantId, Func<object, Item> createItem)
{
if (this.TryCreate(this.type,variantId, createItem) is SearchableItem result)
this.Items.Add(result);
}

internal VariantsRequestedEventArgs(string type, string baseId, SearchableItemFactory tryCreate)
{
this.BaseId = baseId;
this.TryCreate = tryCreate;
this.type = type;
}
}

/*********
** Public methods
*********/
/// <inheritdoc/>
public void OpenItemSpawnerMenu()
{
Game1.activeClickableMenu = this.BuildMenu();
}

/// <inheritdoc/>
public event EventHandler<IItemSpawnerAPI.IVariantsRequestedEventArgs>? VariantsRequested;

/// <inheritdoc/>
public void BlacklistItem(string qualifiedId)
{
this.Blacklist.Add(qualifiedId);
}

/*********
** Private methods
*********/
internal ItemSpawnerAPI(Func<IClickableMenu> BuildMenu)
{
this.BuildMenu = BuildMenu;
}

/// <summary>Gets API-Added variants for a given item.</summary>
/// <param name="type">The item type</param>
/// <param name="baseId">The item's unqualified id</param>
internal IEnumerable<SearchableItem> GetVariantsFor(string type, string baseId, SearchableItemFactory TryCreate)
{
// skip setup and teardown if nobody is using the api.
if (VariantsRequested is null)
return [];

VariantsRequestedEventArgs args = new(type, baseId, TryCreate);
VariantsRequested(this, args);
return args.Items;
}

/// <summary>Gets whether or not an item has been blacklisted.</summary>
/// <param name="id">The qualified id for the item</param>
internal bool IsBlacklisted(string id)
{
return this.Blacklist.Contains(id);
}
}
}
37 changes: 37 additions & 0 deletions CJBItemSpawner/IItemSpawnerAPI.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System;
using StardewValley;

namespace CJBItemSpawner
{
public interface IItemSpawnerAPI
{
public interface IVariantsRequestedEventArgs
{
/// <summary>The item to provide variants for</summary>
public string BaseId { get; }

/// <summary>Add an item variant if valid</summary>
/// <param name="variantId">A unique variant identifier. Should include the base item id.</param>
/// <param name="createItem">Creates an instance of the item</param>
public void TryAddVariant(string variantId, Func<object, Item> createItem);
}

/// <summary>
/// Open the item spawner menu.
/// </summary>
void OpenItemSpawnerMenu();

/// <summary>
/// Prevent an item from being displayed in the item spawner.
/// Should only be used for placeholder items. <br/>
/// Does not disable variants for this item.
/// </summary>
/// <param name="qualifiedId">The qualified item id</param>
public void BlacklistItem(string qualifiedId);

/// <summary>
/// Can be used to add custom variants to an existing item.
/// </summary>
public event EventHandler<IVariantsRequestedEventArgs>? VariantsRequested;
}
}
15 changes: 14 additions & 1 deletion CJBItemSpawner/ModEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,18 @@ internal class ModEntry : Mod
/// <summary>Manages the gamepad text entry UI.</summary>
private readonly TextEntryManager TextEntryManager = new();

/// <summary>The API</summary>
private readonly ItemSpawnerAPI API;


/*********
** Public methods
*********/
public ModEntry()
{
this.API = new(this.BuildMenu);
}

/// <inheritdoc />
public override void Entry(IModHelper helper)
{
Expand Down Expand Up @@ -65,6 +73,11 @@ public override void Entry(IModHelper helper)
helper.Events.GameLoop.UpdateTicked += this.OnUpdateTicked;
}

/// <inheritdoc/>
public override object? GetApi()
{
return this.API;
}

/*********
** Private methods
Expand Down Expand Up @@ -122,7 +135,7 @@ private ItemMenu BuildMenu()
/// <summary>Get the items which can be spawned.</summary>
private IEnumerable<SpawnableItem> GetSpawnableItems()
{
foreach (SearchableItem entry in new ItemRepository().GetAll())
foreach (SearchableItem entry in new ItemRepository(this.API).GetAll())
{
ModDataCategory? category = this.Categories.FirstOrDefault(rule => rule.IsMatch(entry));

Expand Down