unify item diff logic for players & chests
This commit is contained in:
parent
6766fcd0fd
commit
e64a1220e3
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using StardewValley;
|
||||
using StardewValley.Objects;
|
||||
|
||||
|
@ -16,8 +17,14 @@ namespace StardewModdingAPI.Events
|
|||
/// <summary>The location containing the chest.</summary>
|
||||
public GameLocation Location { get; }
|
||||
|
||||
/// <summary>The inventory changes in the chest.</summary>
|
||||
public ItemStackChange[] Changes { get; }
|
||||
/// <summary>The added item stacks.</summary>
|
||||
public IEnumerable<Item> Added { get; }
|
||||
|
||||
/// <summary>The removed item stacks.</summary>
|
||||
public IEnumerable<Item> Removed { get; }
|
||||
|
||||
/// <summary>The item stacks whose size changed.</summary>
|
||||
public IEnumerable<ItemStackSizeChange> QuantityChanged { get; }
|
||||
|
||||
|
||||
/*********
|
||||
|
@ -26,12 +33,16 @@ namespace StardewModdingAPI.Events
|
|||
/// <summary>Construct an instance.</summary>
|
||||
/// <param name="chest">The chest whose inventory changed.</param>
|
||||
/// <param name="location">The location containing the chest.</param>
|
||||
/// <param name="changes">The inventory changes in the chest.</param>
|
||||
internal ChestInventoryChangedEventArgs(Chest chest, GameLocation location, ItemStackChange[] changes)
|
||||
/// <param name="added">The added item stacks.</param>
|
||||
/// <param name="removed">The removed item stacks.</param>
|
||||
/// <param name="quantityChanged">The item stacks whose size changed.</param>
|
||||
internal ChestInventoryChangedEventArgs(Chest chest, GameLocation location, Item[] added, Item[] removed, ItemStackSizeChange[] quantityChanged)
|
||||
{
|
||||
this.Location = location;
|
||||
this.Chest = chest;
|
||||
this.Changes = changes;
|
||||
this.Added = added;
|
||||
this.Removed = removed;
|
||||
this.QuantityChanged = quantityChanged;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using StardewValley;
|
||||
|
||||
namespace StardewModdingAPI.Events
|
||||
|
@ -14,13 +13,13 @@ namespace StardewModdingAPI.Events
|
|||
/// <summary>The player whose inventory changed.</summary>
|
||||
public Farmer Player { get; }
|
||||
|
||||
/// <summary>The added items.</summary>
|
||||
/// <summary>The added item stacks.</summary>
|
||||
public IEnumerable<Item> Added { get; }
|
||||
|
||||
/// <summary>The removed items.</summary>
|
||||
/// <summary>The removed item stacks.</summary>
|
||||
public IEnumerable<Item> Removed { get; }
|
||||
|
||||
/// <summary>The items whose stack sizes changed, with the relative change.</summary>
|
||||
/// <summary>The item stacks whose size changed.</summary>
|
||||
public IEnumerable<ItemStackSizeChange> QuantityChanged { get; }
|
||||
|
||||
/// <summary>Whether the affected player is the local one.</summary>
|
||||
|
@ -32,28 +31,15 @@ namespace StardewModdingAPI.Events
|
|||
*********/
|
||||
/// <summary>Construct an instance.</summary>
|
||||
/// <param name="player">The player whose inventory changed.</param>
|
||||
/// <param name="changedItems">The inventory changes.</param>
|
||||
internal InventoryChangedEventArgs(Farmer player, ItemStackChange[] changedItems)
|
||||
/// <param name="added">The added item stacks.</param>
|
||||
/// <param name="removed">The removed item stacks.</param>
|
||||
/// <param name="quantityChanged">The item stacks whose size changed.</param>
|
||||
internal InventoryChangedEventArgs(Farmer player, Item[] added, Item[] removed, ItemStackSizeChange[] quantityChanged)
|
||||
{
|
||||
this.Player = player;
|
||||
this.Added = changedItems
|
||||
.Where(n => n.ChangeType == ChangeType.Added)
|
||||
.Select(p => p.Item)
|
||||
.ToArray();
|
||||
|
||||
this.Removed = changedItems
|
||||
.Where(n => n.ChangeType == ChangeType.Removed)
|
||||
.Select(p => p.Item)
|
||||
.ToArray();
|
||||
|
||||
this.QuantityChanged = changedItems
|
||||
.Where(n => n.ChangeType == ChangeType.StackChange)
|
||||
.Select(change => new ItemStackSizeChange(
|
||||
item: change.Item,
|
||||
oldSize: change.Item.Stack - change.StackChange,
|
||||
newSize: change.Item.Stack
|
||||
))
|
||||
.ToArray();
|
||||
this.Added = added;
|
||||
this.Removed = removed;
|
||||
this.QuantityChanged = quantityChanged;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
using StardewValley;
|
||||
|
||||
namespace StardewModdingAPI.Events
|
||||
{
|
||||
/// <summary>Represents an inventory slot that changed.</summary>
|
||||
public class ItemStackChange
|
||||
{
|
||||
/*********
|
||||
** Accessors
|
||||
*********/
|
||||
/// <summary>The item in the slot.</summary>
|
||||
public Item Item { get; set; }
|
||||
|
||||
/// <summary>The amount by which the item's stack size changed.</summary>
|
||||
public int StackChange { get; set; }
|
||||
|
||||
/// <summary>How the inventory slot changed.</summary>
|
||||
public ChangeType ChangeType { get; set; }
|
||||
}
|
||||
}
|
|
@ -706,7 +706,10 @@ namespace StardewModdingAPI.Framework
|
|||
if (events.ChestInventoryChanged.HasListeners())
|
||||
{
|
||||
foreach (var pair in locState.ChestItems)
|
||||
events.ChestInventoryChanged.Raise(new ChestInventoryChangedEventArgs(pair.Key, location, pair.Value));
|
||||
{
|
||||
SnapshotItemListDiff diff = pair.Value;
|
||||
events.ChestInventoryChanged.Raise(new ChestInventoryChangedEventArgs(pair.Key, location, added: diff.Added, removed: diff.Removed, quantityChanged: diff.QuantityChanged));
|
||||
}
|
||||
}
|
||||
|
||||
// terrain features changed
|
||||
|
@ -747,12 +750,13 @@ namespace StardewModdingAPI.Framework
|
|||
}
|
||||
|
||||
// raise player inventory changed
|
||||
ItemStackChange[] changedItems = playerState.InventoryChanges.ToArray();
|
||||
if (changedItems.Any())
|
||||
if (playerState.Inventory.IsChanged)
|
||||
{
|
||||
var inventory = playerState.Inventory;
|
||||
|
||||
if (this.Monitor.IsVerbose)
|
||||
this.Monitor.Log("Events: player inventory changed.", LogLevel.Trace);
|
||||
events.InventoryChanged.Raise(new InventoryChangedEventArgs(player, changedItems));
|
||||
events.InventoryChanged.Raise(new InventoryChangedEventArgs(player, added: inventory.Added, removed: inventory.Removed, quantityChanged: inventory.QuantityChanged));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using StardewModdingAPI.Events;
|
||||
using StardewValley;
|
||||
|
||||
namespace StardewModdingAPI.Framework
|
||||
{
|
||||
/// <summary>A snapshot of a tracked item list.</summary>
|
||||
internal class SnapshotItemListDiff
|
||||
{
|
||||
/*********
|
||||
** Accessors
|
||||
*********/
|
||||
/// <summary>Whether the item list changed.</summary>
|
||||
public bool IsChanged { get; }
|
||||
|
||||
/// <summary>The removed values.</summary>
|
||||
public Item[] Removed { get; }
|
||||
|
||||
/// <summary>The added values.</summary>
|
||||
public Item[] Added { get; }
|
||||
|
||||
/// <summary>The items whose stack sizes changed.</summary>
|
||||
public ItemStackSizeChange[] QuantityChanged { get; }
|
||||
|
||||
|
||||
/*********
|
||||
** Public methods
|
||||
*********/
|
||||
/// <summary>Update the snapshot.</summary>
|
||||
/// <param name="added">The added values.</param>
|
||||
/// <param name="removed">The removed values.</param>
|
||||
/// <param name="sizesChanged">The items whose stack sizes changed.</param>
|
||||
public SnapshotItemListDiff(Item[] added, Item[] removed, ItemStackSizeChange[] sizesChanged)
|
||||
{
|
||||
this.Removed = removed;
|
||||
this.Added = added;
|
||||
this.QuantityChanged = sizesChanged;
|
||||
|
||||
this.IsChanged = removed.Length > 0 || added.Length > 0 || sizesChanged.Length > 0;
|
||||
}
|
||||
|
||||
/// <summary>Get a snapshot diff if anything changed in the given data.</summary>
|
||||
/// <param name="added">The added item stacks.</param>
|
||||
/// <param name="removed">The removed item stacks.</param>
|
||||
/// <param name="stackSizes">The items with their previous stack sizes.</param>
|
||||
/// <param name="changes">The inventory changes, or <c>null</c> if nothing changed.</param>
|
||||
/// <returns>Returns whether anything changed.</returns>
|
||||
public static bool TryGetChanges(ISet<Item> added, ISet<Item> removed, IDictionary<Item, int> stackSizes, out SnapshotItemListDiff changes)
|
||||
{
|
||||
KeyValuePair<Item, int>[] sizesChanged = stackSizes.Where(p => p.Key.Stack != p.Value).ToArray();
|
||||
if (sizesChanged.Any() || added.Any() || removed.Any())
|
||||
{
|
||||
changes = new SnapshotItemListDiff(
|
||||
added: added.ToArray(),
|
||||
removed: removed.ToArray(),
|
||||
sizesChanged: sizesChanged.Select(p => new ItemStackSizeChange(p.Key, p.Value, p.Key.Stack)).ToArray()
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
changes = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,12 +1,10 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using StardewModdingAPI.Events;
|
||||
using StardewModdingAPI.Framework.StateTracking.Comparers;
|
||||
using StardewModdingAPI.Framework.StateTracking.FieldWatchers;
|
||||
using StardewValley;
|
||||
using StardewValley.Objects;
|
||||
using ChangeType = StardewModdingAPI.Events.ChangeType;
|
||||
|
||||
namespace StardewModdingAPI.Framework.StateTracking
|
||||
{
|
||||
|
@ -83,26 +81,12 @@ namespace StardewModdingAPI.Framework.StateTracking
|
|||
this.Removed.Clear();
|
||||
}
|
||||
|
||||
/// <summary>Get the inventory changes since the last update.</summary>
|
||||
public IEnumerable<ItemStackChange> GetInventoryChanges()
|
||||
/// <summary>Get the inventory changes since the last update, if anything changed.</summary>
|
||||
/// <param name="changes">The inventory changes, or <c>null</c> if nothing changed.</param>
|
||||
/// <returns>Returns whether anything changed.</returns>
|
||||
public bool TryGetInventoryChanges(out SnapshotItemListDiff changes)
|
||||
{
|
||||
// removed
|
||||
foreach (Item item in this.Removed)
|
||||
yield return new ItemStackChange { Item = item, StackChange = -item.Stack, ChangeType = ChangeType.Removed };
|
||||
|
||||
// added
|
||||
foreach (Item item in this.Added)
|
||||
yield return new ItemStackChange { Item = item, StackChange = item.Stack, ChangeType = ChangeType.Added };
|
||||
|
||||
// stack size changed
|
||||
foreach (var entry in this.StackSizes)
|
||||
{
|
||||
Item item = entry.Key;
|
||||
int prevStack = entry.Value;
|
||||
|
||||
if (item.Stack != prevStack)
|
||||
yield return new ItemStackChange { Item = item, StackChange = item.Stack - prevStack, ChangeType = ChangeType.StackChange };
|
||||
}
|
||||
return SnapshotItemListDiff.TryGetChanges(added: this.Added, removed: this.Removed, stackSizes: this.StackSizes, out changes);
|
||||
}
|
||||
|
||||
/// <summary>Release watchers and resources.</summary>
|
||||
|
|
|
@ -2,10 +2,9 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using StardewModdingAPI.Enums;
|
||||
using StardewModdingAPI.Events;
|
||||
using StardewModdingAPI.Framework.StateTracking.Comparers;
|
||||
using StardewModdingAPI.Framework.StateTracking.FieldWatchers;
|
||||
using StardewValley;
|
||||
using ChangeType = StardewModdingAPI.Events.ChangeType;
|
||||
|
||||
namespace StardewModdingAPI.Framework.StateTracking
|
||||
{
|
||||
|
@ -99,20 +98,24 @@ namespace StardewModdingAPI.Framework.StateTracking
|
|||
return this.Player.currentLocation ?? this.LastValidLocation;
|
||||
}
|
||||
|
||||
/// <summary>Get the inventory changes since the last update.</summary>
|
||||
public IEnumerable<ItemStackChange> GetInventoryChanges()
|
||||
/// <summary>Get the inventory changes since the last update, if anything changed.</summary>
|
||||
/// <param name="changes">The inventory changes, or <c>null</c> if nothing changed.</param>
|
||||
/// <returns>Returns whether anything changed.</returns>
|
||||
public bool TryGetInventoryChanges(out SnapshotItemListDiff changes)
|
||||
{
|
||||
IDictionary<Item, int> previous = this.PreviousInventory;
|
||||
IDictionary<Item, int> current = this.GetInventory();
|
||||
foreach (Item item in previous.Keys.Union(current.Keys))
|
||||
|
||||
ISet<Item> added = new HashSet<Item>(new ObjectReferenceComparer<Item>());
|
||||
ISet<Item> removed = new HashSet<Item>(new ObjectReferenceComparer<Item>());
|
||||
foreach (Item item in this.PreviousInventory.Keys.Union(current.Keys))
|
||||
{
|
||||
if (!previous.TryGetValue(item, out int prevStack))
|
||||
yield return new ItemStackChange { Item = item, StackChange = item.Stack, ChangeType = ChangeType.Added };
|
||||
else if (!current.TryGetValue(item, out int newStack))
|
||||
yield return new ItemStackChange { Item = item, StackChange = -item.Stack, ChangeType = ChangeType.Removed };
|
||||
else if (prevStack != newStack)
|
||||
yield return new ItemStackChange { Item = item, StackChange = newStack - prevStack, ChangeType = ChangeType.StackChange };
|
||||
if (!this.PreviousInventory.ContainsKey(item))
|
||||
added.Add(item);
|
||||
else if (!current.ContainsKey(item))
|
||||
removed.Add(item);
|
||||
}
|
||||
|
||||
return SnapshotItemListDiff.TryGetChanges(added: added, removed: removed, stackSizes: this.PreviousInventory, out changes);
|
||||
}
|
||||
|
||||
/// <summary>Release watchers and resources.</summary>
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Xna.Framework;
|
||||
using StardewModdingAPI.Events;
|
||||
using StardewValley;
|
||||
using StardewValley.Buildings;
|
||||
using StardewValley.Objects;
|
||||
|
@ -37,7 +35,7 @@ namespace StardewModdingAPI.Framework.StateTracking.Snapshots
|
|||
public SnapshotListDiff<KeyValuePair<Vector2, TerrainFeature>> TerrainFeatures { get; } = new SnapshotListDiff<KeyValuePair<Vector2, TerrainFeature>>();
|
||||
|
||||
/// <summary>Tracks changed chest inventories.</summary>
|
||||
public IDictionary<Chest, ItemStackChange[]> ChestItems { get; } = new Dictionary<Chest, ItemStackChange[]>();
|
||||
public IDictionary<Chest, SnapshotItemListDiff> ChestItems { get; } = new Dictionary<Chest, SnapshotItemListDiff>();
|
||||
|
||||
|
||||
/*********
|
||||
|
@ -66,8 +64,7 @@ namespace StardewModdingAPI.Framework.StateTracking.Snapshots
|
|||
this.ChestItems.Clear();
|
||||
foreach (ChestTracker tracker in watcher.ChestWatchers.Values)
|
||||
{
|
||||
ItemStackChange[] changes = tracker.GetInventoryChanges().ToArray();
|
||||
if (changes.Length > 0)
|
||||
if (tracker.TryGetInventoryChanges(out SnapshotItemListDiff changes))
|
||||
this.ChestItems[tracker.Chest] = changes;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,13 @@ namespace StardewModdingAPI.Framework.StateTracking.Snapshots
|
|||
/// <summary>A frozen snapshot of a tracked player.</summary>
|
||||
internal class PlayerSnapshot
|
||||
{
|
||||
/*********
|
||||
** Fields
|
||||
*********/
|
||||
/// <summary>An empty item list diff.</summary>
|
||||
private readonly SnapshotItemListDiff EmptyItemListDiff = new SnapshotItemListDiff(new Item[0], new Item[0], new ItemStackSizeChange[0]);
|
||||
|
||||
|
||||
/*********
|
||||
** Accessors
|
||||
*********/
|
||||
|
@ -27,7 +34,7 @@ namespace StardewModdingAPI.Framework.StateTracking.Snapshots
|
|||
.ToDictionary(skill => skill, skill => new SnapshotDiff<int>());
|
||||
|
||||
/// <summary>Get a list of inventory changes.</summary>
|
||||
public IEnumerable<ItemStackChange> InventoryChanges { get; private set; }
|
||||
public SnapshotItemListDiff Inventory { get; private set; }
|
||||
|
||||
|
||||
/*********
|
||||
|
@ -47,7 +54,11 @@ namespace StardewModdingAPI.Framework.StateTracking.Snapshots
|
|||
this.Location.Update(watcher.LocationWatcher);
|
||||
foreach (var pair in this.Skills)
|
||||
pair.Value.Update(watcher.SkillWatchers[pair.Key]);
|
||||
this.InventoryChanges = watcher.GetInventoryChanges().ToArray();
|
||||
|
||||
this.Inventory = watcher.TryGetInventoryChanges(out SnapshotItemListDiff itemChanges)
|
||||
? itemChanges
|
||||
: this.EmptyItemListDiff;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue