Advertisement
Guest User

Older implementation

a guest
Dec 12th, 2019
115
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 23.62 KB | None | 0 0
  1. using Assets.Scripts.Items;
  2. using System;
  3. using UnityEngine;
  4.  
  5. namespace Assets.Scripts.Utils.Inventory
  6. {
  7. /// <summary>
  8. /// Represents a stack of an item in an inventory.
  9. /// </summary>
  10. public struct ItemStack : IComparable
  11. {
  12. #region Variables
  13.  
  14. /// <summary>
  15. /// The internal item held by the item stack.
  16. /// </summary>
  17. private IItem item;
  18.  
  19. /// <summary>
  20. /// Whether or not the item is stackable, and whether
  21. /// the item stack can exceed 1 item.
  22. /// </summary>
  23. private bool stackable;
  24.  
  25. #endregion Variables
  26.  
  27. #region Properties
  28.  
  29. /// <summary>
  30. /// The item represented by the item stack.
  31. /// </summary>
  32. public IItem Item
  33. {
  34. get { return item; }
  35. }
  36.  
  37. /// <summary>
  38. /// The name of the item represented by the item stack.
  39. /// </summary>
  40. public string Name
  41. {
  42. get { return item.Name; }
  43. }
  44.  
  45. /// <summary>
  46. /// The description of the item represented by the item stack.
  47. /// </summary>
  48. public string Description
  49. {
  50. get { return item.Description; }
  51. }
  52.  
  53. /// <summary>
  54. /// The parent game object of the item in the item stack.
  55. /// </summary>
  56. public GameObject ItemGameObject
  57. {
  58. get { return item.ParentGameObject; }
  59. }
  60.  
  61. /// <summary>
  62. /// The sprite renderer associated with the items parent game object.
  63. /// </summary>
  64. public SpriteRenderer ItemSpriteRenderer
  65. {
  66. get { return item.ParentGameObject.GetComponentInChildren<SpriteRenderer>(); }
  67. }
  68.  
  69. /// <summary>
  70. /// The sprite of the items sprite renderer.
  71. /// </summary>
  72. public Sprite ItemSprite
  73. {
  74. get { return item.ParentGameObject.GetComponentInChildren<SpriteRenderer>().sprite; }
  75. }
  76.  
  77. /// <summary>
  78. /// Whether the item stack can exceed 1 item or not.
  79. /// </summary>
  80. public bool Stackable
  81. {
  82. get { return stackable; }
  83. }
  84.  
  85. /// <summary>
  86. /// The number of items in the item stack.
  87. /// </summary>
  88. public int Count
  89. {
  90. get { return item.StackCount; }
  91. }
  92.  
  93. #endregion Properties
  94.  
  95. #region Constructors
  96.  
  97. public ItemStack(GameObject gameObject, bool stackable = true, ushort startItemCount = 1)
  98. {
  99. item = gameObject.GetComponent<IItem>();
  100.  
  101. this.stackable = stackable;
  102.  
  103. item.StackCount = startItemCount;
  104. }
  105.  
  106. #endregion Constructors
  107.  
  108. #region Methods
  109.  
  110. /// <summary>
  111. /// Adds 1 to the item counter.
  112. /// </summary>
  113. public void AddToStack(ushort count = 1)
  114. {
  115. if (stackable)
  116. {
  117. if (item.StackCount + count <= ushort.MaxValue) // as long as item count wouldn't exceed max value
  118. {
  119. item.StackCount += count;
  120. }
  121. else
  122. {
  123. throw new ArgumentOutOfRangeException(
  124. nameof(item.StackCount),
  125. item.StackCount,
  126. "Item count would have exceeded the max value and overflowed."
  127. );
  128. }
  129. }
  130. }
  131.  
  132. /// <summary>
  133. /// Takes 1 from the item counter.
  134. /// </summary>
  135. public void RemoveFromStack(ushort count = 1)
  136. {
  137. if (item.StackCount - count >= ushort.MinValue) // as long as item count wouldn't exceed min value
  138. {
  139. item.StackCount -= count;
  140. }
  141. else
  142. {
  143. throw new ArgumentOutOfRangeException(
  144. nameof(item.StackCount),
  145. item.StackCount,
  146. "Item count would have exceeded the min value and underflowed."
  147. );
  148. }
  149. }
  150.  
  151. /// <summary>
  152. /// Compares the item stack to the given item stack.
  153. /// </summary>
  154. /// <param name="obj">The item stack to compare to.</param>
  155. /// <returns>
  156. /// Whether the item stack is smaller than, equal to or greater than
  157. /// the given item stack.
  158. /// </returns>
  159. public int CompareTo(object obj)
  160. {
  161. ItemStack otherItemStack = (ItemStack)obj;
  162. return ToString().CompareTo(otherItemStack.ToString());
  163. }
  164.  
  165. #endregion Methods
  166. }
  167. }
  168.  
  169. // new file
  170.  
  171. using Assets.Scripts.Utils.Sorting;
  172. using System;
  173. using System.Collections;
  174. using System.Collections.Generic;
  175. using UnityEngine;
  176.  
  177. namespace Assets.Scripts.Utils.Inventory
  178. {
  179. /// <summary>
  180. /// A class encapsulating an inventory, with ItemStacks for each held item. Should be encapsulated by
  181. /// an inventory controller, and should not be directly placed onto a game object.
  182. /// </summary>
  183. public class Inventory : IEnumerable<ItemStack>
  184. {
  185. #region Variables
  186.  
  187. /// <summary>
  188. /// The parent game object of the inventory.
  189. /// </summary>
  190. private GameObject parentGameObject;
  191.  
  192. /// <summary>
  193. /// Whether the inventory has no size limit.
  194. /// </summary>
  195. private bool isInfinite = false;
  196.  
  197. /// <summary>
  198. /// The internal array of items, used if the inventory is not infinite.
  199. /// </summary>
  200. private ItemStack[] finiteItems;
  201.  
  202. /// <summary>
  203. /// The internal list of items, used if the inventory is infinite.
  204. /// </summary>
  205. private List<ItemStack> infiniteItems;
  206.  
  207. /// <summary>
  208. /// The internal count of the items in the inventory.
  209. /// </summary>
  210. private ushort itemCount;
  211.  
  212. /// <summary>
  213. /// The maximum size of the inventory.
  214. /// </summary>
  215. private ushort inventorySize;
  216.  
  217. /// <summary>
  218. /// The current item stack.
  219. /// </summary>
  220. private ItemStack heldItemStack;
  221.  
  222. /// <summary>
  223. /// The index currently selected.
  224. /// </summary>
  225. private int heldItemIndex;
  226.  
  227. /// <summary>
  228. /// The internal sorting algorithm to use when adding new items to
  229. /// the inventory, or when performing an inventory sort. Defaults
  230. /// to insertion sort, due to optimum performance when data is already
  231. /// mostly sorted.
  232. /// </summary>
  233. private ISorter<ItemStack> sorter = new InsertionSort<ItemStack>();
  234.  
  235. #endregion Variables
  236.  
  237. #region Properties
  238.  
  239. /// <summary>
  240. /// The publicly accessible inventory, exposes an array of item stacks;
  241. /// either the internal array or the internal list of items
  242. /// (converted to an array), depending on whether the inventory is infinite
  243. /// or not.
  244. /// </summary>
  245. public ItemStack[] Items
  246. {
  247. get
  248. {
  249. if (isInfinite)
  250. {
  251. return infiniteItems.ToArray();
  252. }
  253.  
  254. return finiteItems;
  255. }
  256. }
  257.  
  258. /// <summary>
  259. ///
  260. /// </summary>
  261. public ItemStack HeldItem
  262. {
  263. get { return Items[HeldItemIndex]; }
  264. }
  265.  
  266. /// <summary>
  267. ///
  268. /// </summary>
  269. public int HeldItemIndex
  270. {
  271. get { return heldItemIndex; }
  272. }
  273.  
  274. /// <summary>
  275. /// The maximum size of the inventory.
  276. /// </summary>
  277. public int Size
  278. {
  279. get
  280. {
  281. if (isInfinite)
  282. {
  283. return Items.Length;
  284. }
  285.  
  286. return inventorySize;
  287. }
  288. }
  289.  
  290. /// <summary>
  291. /// The amount of items in the inventory in question.
  292. /// </summary>
  293. public int ItemCount
  294. {
  295. get { return itemCount; }
  296. }
  297.  
  298. #endregion Properties
  299.  
  300. #region Constructors
  301.  
  302. /// <summary>
  303. /// Constructs a new inventory instance using the supplied parameters.
  304. /// </summary>
  305. /// <param name="parent">
  306. /// The parent game object of the inventory.
  307. /// </param>
  308. /// <param name="size">
  309. /// The maximum size of the inventory.
  310. /// </param>
  311. /// <param name="infinite">
  312. /// Whether or not the inventory is infinite. Overrides the size parameter.
  313. /// </param>
  314. public Inventory(GameObject parent, ushort size, bool infinite = false)
  315. {
  316. parentGameObject = parent;
  317. isInfinite = infinite;
  318.  
  319. finiteItems = new ItemStack[size];
  320. infiniteItems = new List<ItemStack>();
  321.  
  322. heldItemIndex = 0;
  323.  
  324. inventorySize = size;
  325. }
  326.  
  327. #endregion Constructors
  328.  
  329. #region Methods
  330.  
  331. #region Add Methods
  332.  
  333. /// <summary>
  334. /// A wrapper for TryAddItem that takes a game object instead of an IItem.
  335. /// </summary>
  336. /// <param name="itemGameObject">The game object of the item.</param>
  337. /// <param name="parentTransform">The parent transform to place the new item at.</param>
  338. /// <param name="sortOnAdd">Whether to sort the inventory upon adding the item.</param>
  339. /// <returns>If the original game object should be destroyed.</returns>
  340. public bool TryAddItem(GameObject itemGameObject, Transform parentTransform, bool sortOnAdd = false)
  341. {
  342. IItem item = itemGameObject?.GetComponent<IItem>();
  343.  
  344. /*
  345. Debug.Log($"TryAdd Item debug - " +
  346. $"Parent game object: {item.ParentGameObject}, name: {item.Name}, " +
  347. $"description: {item.Description}, metadata: {item.Metadata}, " +
  348. $"is stackable: {item.IsStackable}, stack count: {item.StackCount}" +
  349. $"");
  350. */
  351.  
  352. return TryAddItem(item, parentTransform, sortOnAdd);
  353. }
  354.  
  355. /// <summary>
  356. /// Adds the given item to the inventory.
  357. /// </summary>
  358. /// <param name="item">The item to add.</param>
  359. /// <param name="parentTransform">The transform to place the new item under.</param>
  360. /// <param name="sortOnAdd">Whether to sort the inventory upon addition.</param>
  361. /// <returns>If the original object should be destroyed.</returns>
  362. private bool TryAddItem(IItem item, Transform parentTransform, bool sortOnAdd = false)
  363. {
  364. if (Contains(item, out ItemStack foundItemStack, out int itemStackIndex) && foundItemStack.Stackable == true)
  365. {
  366. Items[itemStackIndex].AddToStack(item.StackCount);
  367. return true;
  368. }
  369.  
  370. if (!CollectionHelper.IsCollectionFull(Items, out int _, out int firstFreeIndex))
  371. {
  372. // creates a clone to use as the item parent game object
  373. GameObject cloneGameObject =
  374. UnityEngine.Object.Instantiate(item.ParentGameObject, parentTransform.position, parentTransform.rotation, parentTransform);
  375. cloneGameObject.GetComponent<Collider2D>().enabled = false; // turn off collider to stop unintended behaviour
  376. cloneGameObject.name = GameObjectHelper.GetGameObjectNameWithoutString(cloneGameObject); // changes name to just the name of the item
  377.  
  378. item = cloneGameObject.GetComponent<IItem>();
  379.  
  380. ItemStack newItemStack = new ItemStack(item.ParentGameObject, item.IsStackable, item.StackCount);
  381.  
  382. if (isInfinite)
  383. {
  384. infiniteItems.Add(newItemStack);
  385. }
  386. else
  387. {
  388. finiteItems[firstFreeIndex] = newItemStack;
  389. }
  390.  
  391. OnItemStackAdded(newItemStack);
  392.  
  393. if (sortOnAdd)
  394. {
  395. SortInventory();
  396. }
  397.  
  398. return true;
  399. }
  400.  
  401. return false;
  402. }
  403.  
  404. #endregion Add Methods
  405.  
  406. #region Remove Methods
  407.  
  408. /// <summary>
  409. /// A wrapper for RemoveItem that takes a game object rather than an IItem.
  410. /// </summary>
  411. /// <param name="itemGameObject">The item whose parent item stack should be removed.</param>
  412. /// <returns>Whether the item has been removed.</returns>
  413. public bool TryRemoveItem(GameObject itemGameObject)
  414. {
  415. IItem item = itemGameObject?.GetComponent<IItem>();
  416.  
  417. /*
  418. Debug.Log($"TryRemove Item debug - " +
  419. $"Parent game object: {item.ParentGameObject}, name: {item.Name}, " +
  420. $"description: {item.Description}, metadata: {item.Metadata}, " +
  421. $"is stackable: {item.IsStackable}, stack count: {item.StackCount}" +
  422. $"");
  423. */
  424.  
  425. return TryRemoveItem(item);
  426. }
  427.  
  428. /// <summary>
  429. /// Removes the item stack containing the given item from the inventory.
  430. /// </summary>
  431. /// <param name="item">The item whose parent item stack should be removed.</param>
  432. /// <returns>Whether the item has been removed.</returns>
  433. private bool TryRemoveItem(IItem item)
  434. {
  435. //Debug.Log($"Tried to remove {item} from inventory");
  436. if (!Contains(
  437. stack => ItemStackIsItemPredicate(stack, item),
  438. out ItemStack itemStack,
  439. out int index)
  440. )
  441. {
  442. return false;
  443. }
  444.  
  445. if (itemStack.Count - item.StackCount == 0) // need to remove item stack, as stack would be finished
  446. {
  447. ItemStack[] editedInventory = CollectionHelper.RemoveFromCollection(Items, itemStack);
  448. OnItemStackRemoved(itemStack);
  449.  
  450. if (isInfinite)
  451. {
  452. infiniteItems = new List<ItemStack>(editedInventory);
  453. }
  454. else
  455. {
  456. finiteItems = editedInventory;
  457. }
  458. }
  459. else // still has items in stack after decrementing. keep
  460. {
  461. Items[index].RemoveFromStack(item.StackCount);
  462. }
  463.  
  464. UpdateHeldItem(CollectionHelper.GetWrappingIndex(Items, index, 0));
  465. itemCount--;
  466. return true;
  467. }
  468.  
  469. #endregion Remove Methods
  470.  
  471. #region Sort Methods
  472.  
  473. /// <summary>
  474. /// Sorts the inventory using the current sorter.
  475. /// </summary>
  476. public void SortInventory()
  477. {
  478. ItemStack[] sortedItems = sorter?.Sort(Items);
  479.  
  480. if (isInfinite)
  481. {
  482. infiniteItems = new List<ItemStack>(sortedItems ?? new ItemStack[Size]);
  483. }
  484. else
  485. {
  486. finiteItems = sortedItems;
  487. }
  488. }
  489.  
  490. #endregion Sort Methods
  491.  
  492. #region Update Methods
  493.  
  494. /// <summary>
  495. /// Updates the held item index, as well as the held item.
  496. /// </summary>
  497. /// <param name="index">The index to set the new held item to.</param>
  498. public void UpdateHeldItem(int index)
  499. {
  500. heldItemIndex = index;
  501. heldItemStack = Items[index];
  502. }
  503.  
  504. #endregion Update Methods
  505.  
  506. #region Helper Methods
  507.  
  508. /// <summary>
  509. /// An enumerator for the items in the inventory.
  510. /// </summary>
  511. /// <returns>Every item stack in the inventory.</returns>
  512. /// <inheritdoc cref="IEnumerator"/>
  513. IEnumerator IEnumerable.GetEnumerator()
  514. {
  515. for (int i = 0; i < itemCount; i++)
  516. {
  517. yield return Items[i];
  518. }
  519. }
  520.  
  521. /// <summary>
  522. /// An enumerator for the items in the inventory.
  523. /// </summary>
  524. /// <returns>Every item stack in the inventory.</returns>
  525. /// <inheritdoc cref="IEnumerator{ItemStack}"/>
  526. IEnumerator<ItemStack> IEnumerable<ItemStack>.GetEnumerator()
  527. {
  528. for (int i = 0; i < itemCount; i++)
  529. {
  530. yield return Items[i];
  531. }
  532. }
  533.  
  534. /// <summary>
  535. /// A wrapper for the CollectionHelper CollectionContains method.
  536. /// </summary>
  537. /// <param name="itemStack">The item stack to check for.</param>
  538. /// <param name="index">The index the item stack was found at. -1 if not found.</param>
  539. /// <returns>Whether the item stack was found.</returns>
  540. /// <inheritdoc cref="CollectionHelper.CollectionContains{T}(T[],T,out int)"/>
  541. public bool Contains(ItemStack itemStack, out int index)
  542. {
  543. return CollectionHelper.CollectionContains(Items, itemStack, out index);
  544. }
  545.  
  546. /// <summary>
  547. /// A wrapper for the CollectionHelper CollectionContains method.
  548. /// </summary>
  549. /// <param name="item">The item to check for.</param>
  550. /// <param name="itemStack">The item stack found which contains the item.</param>
  551. /// <param name="index">The index the item stack was found at.</param>
  552. /// <returns>Whether an item stack with the item was found.</returns>
  553. /// <inheritdoc cref="CollectionHelper.CollectionContains{T}(T[],T,out int)"/>
  554. public bool Contains(IItem item, out ItemStack itemStack, out int index)
  555. {
  556. return CollectionHelper.CollectionContains(
  557. Items,
  558. stack => ItemStackIsItemPredicate(stack, item),
  559. out itemStack,
  560. out index
  561. );
  562. }
  563.  
  564. /// <summary>
  565. /// A wrapper for the CollectionHelper CollectionContains method.
  566. /// </summary>
  567. /// <param name="itemStackPredicate">The predicate to use for checking whether an item stack is suitable.</param>
  568. /// <param name="itemStack">The item stack specified.</param>
  569. /// <param name="index">The index of the item stack.</param>
  570. /// <returns>Whether the specified item stack was found.</returns>
  571. public bool Contains(
  572. Predicate<ItemStack> itemStackPredicate,
  573. out ItemStack itemStack,
  574. out int index
  575. )
  576. {
  577. return CollectionHelper.CollectionContains(
  578. Items,
  579. itemStackPredicate,
  580. out itemStack,
  581. out index
  582. );
  583. }
  584.  
  585. /// <summary>
  586. /// Attempts to get the item at the specified index in the inventory.
  587. /// </summary>
  588. /// <param name="index">The index to search for.</param>
  589. /// <returns>The item at the specified index.</returns>
  590. public ItemStack GetItemAtIndex(int index)
  591. {
  592. if (index < 0)
  593. {
  594. throw new ArgumentOutOfRangeException(
  595. nameof(index),
  596. index,
  597. "The index cannot be less than 0."
  598. );
  599. }
  600.  
  601. if (index > inventorySize)
  602. {
  603. throw new ArgumentOutOfRangeException(
  604. nameof(index),
  605. index,
  606. "The index cannot be greater than the size of the inventory."
  607. );
  608. }
  609.  
  610. return Items[index];
  611. }
  612.  
  613. #endregion Helper Methods
  614.  
  615. #region Operator Overloads
  616.  
  617. /// <summary>
  618. /// Returns the item stack at the specified position in the inventory.
  619. /// </summary>
  620. /// <param name="index">The index from which to return an item stack.</param>
  621. /// <returns>The item stack at the inventory index specified.</returns>
  622. public ItemStack this[ushort index]
  623. {
  624. get
  625. {
  626. return GetItemAtIndex(index);
  627. }
  628. }
  629.  
  630. /// <summary>
  631. /// Returns the item stack at the specified position in the inventory.
  632. /// </summary>
  633. /// <param name="index">The index from which to return an item stack.</param>
  634. /// <returns>The item stack at the inventory index specified.</returns>
  635. public ItemStack this[short index]
  636. {
  637. get
  638. {
  639. return GetItemAtIndex(index);
  640. }
  641. }
  642.  
  643. /// <summary>
  644. /// Returns the item stack at the specified position in the inventory.
  645. /// </summary>
  646. /// <param name="index">The index from which to return an item stack.</param>
  647. /// <returns>The item stack at the inventory index specified.</returns>
  648. public ItemStack this[int index]
  649. {
  650. get
  651. {
  652. return GetItemAtIndex(index);
  653. }
  654. }
  655.  
  656. #endregion Operator Overloads
  657.  
  658. #region Predicates
  659.  
  660. /// <summary>
  661. /// Predicate to use when comparing an item stack to an item with the IItem interface.
  662. /// </summary>
  663. /// <param name="itemStack">The item stack to compare.</param>
  664. /// <param name="desiredItem">The item to compare to.</param>
  665. /// <returns>Whether the item and item stack represent the same item.</returns>
  666. public static bool ItemStackIsItemPredicate(ItemStack itemStack, IItem desiredItem)
  667. {
  668. if (itemStack.Equals(default(ItemStack)) || desiredItem.Equals(null))
  669. {
  670. return false;
  671. }
  672.  
  673. if (desiredItem.IsStackable) // if item stacks, then its lifetime hash must be ignored
  674. {
  675. return itemStack.Item.Name == desiredItem.Name &&
  676. itemStack.Item.Metadata == desiredItem.Metadata;
  677. }
  678. else // item does not stack, so lifetime hash can be used
  679. {
  680. return itemStack.Item.Name == desiredItem.Name &&
  681. itemStack.Item.Metadata == desiredItem.Metadata &&
  682. itemStack.Item.LifetimeHash == desiredItem.LifetimeHash;
  683. }
  684. }
  685.  
  686. #endregion Predicates
  687.  
  688. #endregion Methods
  689.  
  690. #region Events
  691.  
  692. /// <summary>
  693. /// Event invoked whenever an item stack is added to the inventory.
  694. /// </summary>
  695. public event Action<ItemStack> ItemStackAdded;
  696.  
  697. /// <summary>
  698. /// Invokes the ItemStackAdded event with the given item stack.
  699. /// </summary>
  700. /// <param name="itemStack">The item stack that was added.</param>
  701. private void OnItemStackAdded(ItemStack itemStack)
  702. {
  703. ItemStackAdded?.Invoke(itemStack);
  704. }
  705.  
  706. /// <summary>
  707. /// Event invoked whenever an item stack is removed from the inventory.
  708. /// </summary>
  709. public event Action<ItemStack> ItemStackRemoved;
  710.  
  711. /// <summary>
  712. /// Invokes the ItemStackRemoved event with the given item stack.
  713. /// </summary>
  714. /// <param name="itemStack">The item stack that was removed.</param>
  715. private void OnItemStackRemoved(ItemStack itemStack)
  716. {
  717. ItemStackRemoved?.Invoke(itemStack);
  718. }
  719.  
  720. #endregion Events
  721. }
  722. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement