Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using Assets.Scripts.Items;
- using System;
- using UnityEngine;
- namespace Assets.Scripts.Utils.Inventory
- {
- /// <summary>
- /// Represents a stack of an item in an inventory.
- /// </summary>
- public struct ItemStack : IComparable
- {
- #region Variables
- /// <summary>
- /// The internal item held by the item stack.
- /// </summary>
- private IItem item;
- /// <summary>
- /// Whether or not the item is stackable, and whether
- /// the item stack can exceed 1 item.
- /// </summary>
- private bool stackable;
- #endregion Variables
- #region Properties
- /// <summary>
- /// The item represented by the item stack.
- /// </summary>
- public IItem Item
- {
- get { return item; }
- }
- /// <summary>
- /// The name of the item represented by the item stack.
- /// </summary>
- public string Name
- {
- get { return item.Name; }
- }
- /// <summary>
- /// The description of the item represented by the item stack.
- /// </summary>
- public string Description
- {
- get { return item.Description; }
- }
- /// <summary>
- /// The parent game object of the item in the item stack.
- /// </summary>
- public GameObject ItemGameObject
- {
- get { return item.ParentGameObject; }
- }
- /// <summary>
- /// The sprite renderer associated with the items parent game object.
- /// </summary>
- public SpriteRenderer ItemSpriteRenderer
- {
- get { return item.ParentGameObject.GetComponentInChildren<SpriteRenderer>(); }
- }
- /// <summary>
- /// The sprite of the items sprite renderer.
- /// </summary>
- public Sprite ItemSprite
- {
- get { return item.ParentGameObject.GetComponentInChildren<SpriteRenderer>().sprite; }
- }
- /// <summary>
- /// Whether the item stack can exceed 1 item or not.
- /// </summary>
- public bool Stackable
- {
- get { return stackable; }
- }
- /// <summary>
- /// The number of items in the item stack.
- /// </summary>
- public int Count
- {
- get { return item.StackCount; }
- }
- #endregion Properties
- #region Constructors
- public ItemStack(GameObject gameObject, bool stackable = true, ushort startItemCount = 1)
- {
- item = gameObject.GetComponent<IItem>();
- this.stackable = stackable;
- item.StackCount = startItemCount;
- }
- #endregion Constructors
- #region Methods
- /// <summary>
- /// Adds 1 to the item counter.
- /// </summary>
- public void AddToStack(ushort count = 1)
- {
- if (stackable)
- {
- if (item.StackCount + count <= ushort.MaxValue) // as long as item count wouldn't exceed max value
- {
- item.StackCount += count;
- }
- else
- {
- throw new ArgumentOutOfRangeException(
- nameof(item.StackCount),
- item.StackCount,
- "Item count would have exceeded the max value and overflowed."
- );
- }
- }
- }
- /// <summary>
- /// Takes 1 from the item counter.
- /// </summary>
- public void RemoveFromStack(ushort count = 1)
- {
- if (item.StackCount - count >= ushort.MinValue) // as long as item count wouldn't exceed min value
- {
- item.StackCount -= count;
- }
- else
- {
- throw new ArgumentOutOfRangeException(
- nameof(item.StackCount),
- item.StackCount,
- "Item count would have exceeded the min value and underflowed."
- );
- }
- }
- /// <summary>
- /// Compares the item stack to the given item stack.
- /// </summary>
- /// <param name="obj">The item stack to compare to.</param>
- /// <returns>
- /// Whether the item stack is smaller than, equal to or greater than
- /// the given item stack.
- /// </returns>
- public int CompareTo(object obj)
- {
- ItemStack otherItemStack = (ItemStack)obj;
- return ToString().CompareTo(otherItemStack.ToString());
- }
- #endregion Methods
- }
- }
- // new file
- using Assets.Scripts.Utils.Sorting;
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- namespace Assets.Scripts.Utils.Inventory
- {
- /// <summary>
- /// A class encapsulating an inventory, with ItemStacks for each held item. Should be encapsulated by
- /// an inventory controller, and should not be directly placed onto a game object.
- /// </summary>
- public class Inventory : IEnumerable<ItemStack>
- {
- #region Variables
- /// <summary>
- /// The parent game object of the inventory.
- /// </summary>
- private GameObject parentGameObject;
- /// <summary>
- /// Whether the inventory has no size limit.
- /// </summary>
- private bool isInfinite = false;
- /// <summary>
- /// The internal array of items, used if the inventory is not infinite.
- /// </summary>
- private ItemStack[] finiteItems;
- /// <summary>
- /// The internal list of items, used if the inventory is infinite.
- /// </summary>
- private List<ItemStack> infiniteItems;
- /// <summary>
- /// The internal count of the items in the inventory.
- /// </summary>
- private ushort itemCount;
- /// <summary>
- /// The maximum size of the inventory.
- /// </summary>
- private ushort inventorySize;
- /// <summary>
- /// The current item stack.
- /// </summary>
- private ItemStack heldItemStack;
- /// <summary>
- /// The index currently selected.
- /// </summary>
- private int heldItemIndex;
- /// <summary>
- /// The internal sorting algorithm to use when adding new items to
- /// the inventory, or when performing an inventory sort. Defaults
- /// to insertion sort, due to optimum performance when data is already
- /// mostly sorted.
- /// </summary>
- private ISorter<ItemStack> sorter = new InsertionSort<ItemStack>();
- #endregion Variables
- #region Properties
- /// <summary>
- /// The publicly accessible inventory, exposes an array of item stacks;
- /// either the internal array or the internal list of items
- /// (converted to an array), depending on whether the inventory is infinite
- /// or not.
- /// </summary>
- public ItemStack[] Items
- {
- get
- {
- if (isInfinite)
- {
- return infiniteItems.ToArray();
- }
- return finiteItems;
- }
- }
- /// <summary>
- ///
- /// </summary>
- public ItemStack HeldItem
- {
- get { return Items[HeldItemIndex]; }
- }
- /// <summary>
- ///
- /// </summary>
- public int HeldItemIndex
- {
- get { return heldItemIndex; }
- }
- /// <summary>
- /// The maximum size of the inventory.
- /// </summary>
- public int Size
- {
- get
- {
- if (isInfinite)
- {
- return Items.Length;
- }
- return inventorySize;
- }
- }
- /// <summary>
- /// The amount of items in the inventory in question.
- /// </summary>
- public int ItemCount
- {
- get { return itemCount; }
- }
- #endregion Properties
- #region Constructors
- /// <summary>
- /// Constructs a new inventory instance using the supplied parameters.
- /// </summary>
- /// <param name="parent">
- /// The parent game object of the inventory.
- /// </param>
- /// <param name="size">
- /// The maximum size of the inventory.
- /// </param>
- /// <param name="infinite">
- /// Whether or not the inventory is infinite. Overrides the size parameter.
- /// </param>
- public Inventory(GameObject parent, ushort size, bool infinite = false)
- {
- parentGameObject = parent;
- isInfinite = infinite;
- finiteItems = new ItemStack[size];
- infiniteItems = new List<ItemStack>();
- heldItemIndex = 0;
- inventorySize = size;
- }
- #endregion Constructors
- #region Methods
- #region Add Methods
- /// <summary>
- /// A wrapper for TryAddItem that takes a game object instead of an IItem.
- /// </summary>
- /// <param name="itemGameObject">The game object of the item.</param>
- /// <param name="parentTransform">The parent transform to place the new item at.</param>
- /// <param name="sortOnAdd">Whether to sort the inventory upon adding the item.</param>
- /// <returns>If the original game object should be destroyed.</returns>
- public bool TryAddItem(GameObject itemGameObject, Transform parentTransform, bool sortOnAdd = false)
- {
- IItem item = itemGameObject?.GetComponent<IItem>();
- /*
- Debug.Log($"TryAdd Item debug - " +
- $"Parent game object: {item.ParentGameObject}, name: {item.Name}, " +
- $"description: {item.Description}, metadata: {item.Metadata}, " +
- $"is stackable: {item.IsStackable}, stack count: {item.StackCount}" +
- $"");
- */
- return TryAddItem(item, parentTransform, sortOnAdd);
- }
- /// <summary>
- /// Adds the given item to the inventory.
- /// </summary>
- /// <param name="item">The item to add.</param>
- /// <param name="parentTransform">The transform to place the new item under.</param>
- /// <param name="sortOnAdd">Whether to sort the inventory upon addition.</param>
- /// <returns>If the original object should be destroyed.</returns>
- private bool TryAddItem(IItem item, Transform parentTransform, bool sortOnAdd = false)
- {
- if (Contains(item, out ItemStack foundItemStack, out int itemStackIndex) && foundItemStack.Stackable == true)
- {
- Items[itemStackIndex].AddToStack(item.StackCount);
- return true;
- }
- if (!CollectionHelper.IsCollectionFull(Items, out int _, out int firstFreeIndex))
- {
- // creates a clone to use as the item parent game object
- GameObject cloneGameObject =
- UnityEngine.Object.Instantiate(item.ParentGameObject, parentTransform.position, parentTransform.rotation, parentTransform);
- cloneGameObject.GetComponent<Collider2D>().enabled = false; // turn off collider to stop unintended behaviour
- cloneGameObject.name = GameObjectHelper.GetGameObjectNameWithoutString(cloneGameObject); // changes name to just the name of the item
- item = cloneGameObject.GetComponent<IItem>();
- ItemStack newItemStack = new ItemStack(item.ParentGameObject, item.IsStackable, item.StackCount);
- if (isInfinite)
- {
- infiniteItems.Add(newItemStack);
- }
- else
- {
- finiteItems[firstFreeIndex] = newItemStack;
- }
- OnItemStackAdded(newItemStack);
- if (sortOnAdd)
- {
- SortInventory();
- }
- return true;
- }
- return false;
- }
- #endregion Add Methods
- #region Remove Methods
- /// <summary>
- /// A wrapper for RemoveItem that takes a game object rather than an IItem.
- /// </summary>
- /// <param name="itemGameObject">The item whose parent item stack should be removed.</param>
- /// <returns>Whether the item has been removed.</returns>
- public bool TryRemoveItem(GameObject itemGameObject)
- {
- IItem item = itemGameObject?.GetComponent<IItem>();
- /*
- Debug.Log($"TryRemove Item debug - " +
- $"Parent game object: {item.ParentGameObject}, name: {item.Name}, " +
- $"description: {item.Description}, metadata: {item.Metadata}, " +
- $"is stackable: {item.IsStackable}, stack count: {item.StackCount}" +
- $"");
- */
- return TryRemoveItem(item);
- }
- /// <summary>
- /// Removes the item stack containing the given item from the inventory.
- /// </summary>
- /// <param name="item">The item whose parent item stack should be removed.</param>
- /// <returns>Whether the item has been removed.</returns>
- private bool TryRemoveItem(IItem item)
- {
- //Debug.Log($"Tried to remove {item} from inventory");
- if (!Contains(
- stack => ItemStackIsItemPredicate(stack, item),
- out ItemStack itemStack,
- out int index)
- )
- {
- return false;
- }
- if (itemStack.Count - item.StackCount == 0) // need to remove item stack, as stack would be finished
- {
- ItemStack[] editedInventory = CollectionHelper.RemoveFromCollection(Items, itemStack);
- OnItemStackRemoved(itemStack);
- if (isInfinite)
- {
- infiniteItems = new List<ItemStack>(editedInventory);
- }
- else
- {
- finiteItems = editedInventory;
- }
- }
- else // still has items in stack after decrementing. keep
- {
- Items[index].RemoveFromStack(item.StackCount);
- }
- UpdateHeldItem(CollectionHelper.GetWrappingIndex(Items, index, 0));
- itemCount--;
- return true;
- }
- #endregion Remove Methods
- #region Sort Methods
- /// <summary>
- /// Sorts the inventory using the current sorter.
- /// </summary>
- public void SortInventory()
- {
- ItemStack[] sortedItems = sorter?.Sort(Items);
- if (isInfinite)
- {
- infiniteItems = new List<ItemStack>(sortedItems ?? new ItemStack[Size]);
- }
- else
- {
- finiteItems = sortedItems;
- }
- }
- #endregion Sort Methods
- #region Update Methods
- /// <summary>
- /// Updates the held item index, as well as the held item.
- /// </summary>
- /// <param name="index">The index to set the new held item to.</param>
- public void UpdateHeldItem(int index)
- {
- heldItemIndex = index;
- heldItemStack = Items[index];
- }
- #endregion Update Methods
- #region Helper Methods
- /// <summary>
- /// An enumerator for the items in the inventory.
- /// </summary>
- /// <returns>Every item stack in the inventory.</returns>
- /// <inheritdoc cref="IEnumerator"/>
- IEnumerator IEnumerable.GetEnumerator()
- {
- for (int i = 0; i < itemCount; i++)
- {
- yield return Items[i];
- }
- }
- /// <summary>
- /// An enumerator for the items in the inventory.
- /// </summary>
- /// <returns>Every item stack in the inventory.</returns>
- /// <inheritdoc cref="IEnumerator{ItemStack}"/>
- IEnumerator<ItemStack> IEnumerable<ItemStack>.GetEnumerator()
- {
- for (int i = 0; i < itemCount; i++)
- {
- yield return Items[i];
- }
- }
- /// <summary>
- /// A wrapper for the CollectionHelper CollectionContains method.
- /// </summary>
- /// <param name="itemStack">The item stack to check for.</param>
- /// <param name="index">The index the item stack was found at. -1 if not found.</param>
- /// <returns>Whether the item stack was found.</returns>
- /// <inheritdoc cref="CollectionHelper.CollectionContains{T}(T[],T,out int)"/>
- public bool Contains(ItemStack itemStack, out int index)
- {
- return CollectionHelper.CollectionContains(Items, itemStack, out index);
- }
- /// <summary>
- /// A wrapper for the CollectionHelper CollectionContains method.
- /// </summary>
- /// <param name="item">The item to check for.</param>
- /// <param name="itemStack">The item stack found which contains the item.</param>
- /// <param name="index">The index the item stack was found at.</param>
- /// <returns>Whether an item stack with the item was found.</returns>
- /// <inheritdoc cref="CollectionHelper.CollectionContains{T}(T[],T,out int)"/>
- public bool Contains(IItem item, out ItemStack itemStack, out int index)
- {
- return CollectionHelper.CollectionContains(
- Items,
- stack => ItemStackIsItemPredicate(stack, item),
- out itemStack,
- out index
- );
- }
- /// <summary>
- /// A wrapper for the CollectionHelper CollectionContains method.
- /// </summary>
- /// <param name="itemStackPredicate">The predicate to use for checking whether an item stack is suitable.</param>
- /// <param name="itemStack">The item stack specified.</param>
- /// <param name="index">The index of the item stack.</param>
- /// <returns>Whether the specified item stack was found.</returns>
- public bool Contains(
- Predicate<ItemStack> itemStackPredicate,
- out ItemStack itemStack,
- out int index
- )
- {
- return CollectionHelper.CollectionContains(
- Items,
- itemStackPredicate,
- out itemStack,
- out index
- );
- }
- /// <summary>
- /// Attempts to get the item at the specified index in the inventory.
- /// </summary>
- /// <param name="index">The index to search for.</param>
- /// <returns>The item at the specified index.</returns>
- public ItemStack GetItemAtIndex(int index)
- {
- if (index < 0)
- {
- throw new ArgumentOutOfRangeException(
- nameof(index),
- index,
- "The index cannot be less than 0."
- );
- }
- if (index > inventorySize)
- {
- throw new ArgumentOutOfRangeException(
- nameof(index),
- index,
- "The index cannot be greater than the size of the inventory."
- );
- }
- return Items[index];
- }
- #endregion Helper Methods
- #region Operator Overloads
- /// <summary>
- /// Returns the item stack at the specified position in the inventory.
- /// </summary>
- /// <param name="index">The index from which to return an item stack.</param>
- /// <returns>The item stack at the inventory index specified.</returns>
- public ItemStack this[ushort index]
- {
- get
- {
- return GetItemAtIndex(index);
- }
- }
- /// <summary>
- /// Returns the item stack at the specified position in the inventory.
- /// </summary>
- /// <param name="index">The index from which to return an item stack.</param>
- /// <returns>The item stack at the inventory index specified.</returns>
- public ItemStack this[short index]
- {
- get
- {
- return GetItemAtIndex(index);
- }
- }
- /// <summary>
- /// Returns the item stack at the specified position in the inventory.
- /// </summary>
- /// <param name="index">The index from which to return an item stack.</param>
- /// <returns>The item stack at the inventory index specified.</returns>
- public ItemStack this[int index]
- {
- get
- {
- return GetItemAtIndex(index);
- }
- }
- #endregion Operator Overloads
- #region Predicates
- /// <summary>
- /// Predicate to use when comparing an item stack to an item with the IItem interface.
- /// </summary>
- /// <param name="itemStack">The item stack to compare.</param>
- /// <param name="desiredItem">The item to compare to.</param>
- /// <returns>Whether the item and item stack represent the same item.</returns>
- public static bool ItemStackIsItemPredicate(ItemStack itemStack, IItem desiredItem)
- {
- if (itemStack.Equals(default(ItemStack)) || desiredItem.Equals(null))
- {
- return false;
- }
- if (desiredItem.IsStackable) // if item stacks, then its lifetime hash must be ignored
- {
- return itemStack.Item.Name == desiredItem.Name &&
- itemStack.Item.Metadata == desiredItem.Metadata;
- }
- else // item does not stack, so lifetime hash can be used
- {
- return itemStack.Item.Name == desiredItem.Name &&
- itemStack.Item.Metadata == desiredItem.Metadata &&
- itemStack.Item.LifetimeHash == desiredItem.LifetimeHash;
- }
- }
- #endregion Predicates
- #endregion Methods
- #region Events
- /// <summary>
- /// Event invoked whenever an item stack is added to the inventory.
- /// </summary>
- public event Action<ItemStack> ItemStackAdded;
- /// <summary>
- /// Invokes the ItemStackAdded event with the given item stack.
- /// </summary>
- /// <param name="itemStack">The item stack that was added.</param>
- private void OnItemStackAdded(ItemStack itemStack)
- {
- ItemStackAdded?.Invoke(itemStack);
- }
- /// <summary>
- /// Event invoked whenever an item stack is removed from the inventory.
- /// </summary>
- public event Action<ItemStack> ItemStackRemoved;
- /// <summary>
- /// Invokes the ItemStackRemoved event with the given item stack.
- /// </summary>
- /// <param name="itemStack">The item stack that was removed.</param>
- private void OnItemStackRemoved(ItemStack itemStack)
- {
- ItemStackRemoved?.Invoke(itemStack);
- }
- #endregion Events
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement