using System; using JetBrains.Annotations; using Sirenix.OdinInspector; using UnityEngine; using VOID.Generic.Dict; using VOID.Generic.Objects.Abstract.Events; using VOID.Generic.Objects.Container.Events; using VOID.Generic.Objects.Item; using VOID.Generic.Objects.Unit; using VOID.Generic.Util; using Object = UnityEngine.Object; namespace VOID.Generic.Objects.Container { [Serializable] public class ContainerObjectContent : ObjectComponent { #region Initialize protected override void SelfInitialize() { // Empty GameObject where all items from backpack are "attached" _content = new GameObject("_content"); _content.transform.parent = parent.gameObject.transform; _content.transform.localPosition = Vector3.zero; } protected override void Initialize() { // Instantiate all prefabs for (var i = 0; i < _items.Length; i++) { if (!_items[i]) continue; var item = _items[i]; _items[i] = null; // Selected item is ASSET (prefab), we need to instantiate it first if (!item.gameObject.scene.IsValid()) item = Object.Instantiate(item.gameObject).GetComponent(); // Instantiate prefab and get references to its GameObject and ItemObject MoveIn(i, item); } Resize(); } #endregion private GameObject _content; // Items in content (list of ItemObjects and their GameObjects) [SerializeField, DisableInPlayMode] private ItemObject[] _items = Array.Empty(); public ItemObject[] items => _items; public void MoveIn(int itemIndex, ItemObject item, UnitObject byWho = null) { if (items.Length <= itemIndex) Resize(itemIndex); if (items[itemIndex]) { MoveIn(item, byWho); return; } items[itemIndex] = item; var moveInEvent = new ContainerMoveInEvent { byWho = byWho, item = item, slotIndex = itemIndex, container = parent, }; parent.containerEvents.onMoveIn.Invoke(moveInEvent); item.itemEvents.onMovedIntoContainer.Invoke(moveInEvent); var itemGameObject = item.gameObject; itemGameObject.transform.parent = _content.transform; itemGameObject.transform.localPosition = Vector3.zero; itemGameObject.transform.localRotation = new Quaternion(); item.basicEvents.onRemove.AddListener(OnItemRemove); Resize(); } public void MoveIn(ItemObject item, UnitObject byWho = null) { // Find first free slot in backpack var firstFreeIndex = Array.IndexOf(items, null); // No free slots, we need to resize array if (firstFreeIndex == -1) { firstFreeIndex = items.Length; Resize(); } MoveIn(firstFreeIndex, item, byWho); } public void MoveOut(int itemIndex, UnitObject byWho = null) { var tempMoveOutItem = items[itemIndex]; items[itemIndex].basicEvents.onRemove.RemoveListener(OnItemRemove); items[itemIndex] = null; var moveOutEvent = new ContainerMoveOutEvent { byWho = byWho, item = tempMoveOutItem, slotIndex = itemIndex, container = parent, }; parent.containerEvents.onMoveOut.Invoke(moveOutEvent); tempMoveOutItem.itemEvents.onMovedOutOfContainer.Invoke(moveOutEvent); var tempItemGameObject = tempMoveOutItem.gameObject; tempItemGameObject.gameObject.transform.parent = null; tempItemGameObject.gameObject.transform.position = parent.transform.position; Resize(); } public void MoveOut(ItemObject item, UnitObject byWho = null) { MoveOut(Array.IndexOf(items, item), byWho); } public void Swap(int firstItemIndex, int secondItemIndex, UnitObject byWho = null) { Resize(Math.Max(firstItemIndex, secondItemIndex)); (items[firstItemIndex], items[secondItemIndex]) = (items[secondItemIndex], items[firstItemIndex]); var swapEvent = new ContainerSwapEvent { byWho = byWho, firstSlotIndex = firstItemIndex, firstItem = items[firstItemIndex], secondSlotIndex = secondItemIndex, secondItem = items[secondItemIndex], }; parent.containerEvents.onSwap.Invoke(swapEvent); Resize(); } public void Sort(Func valueGetter, SortDirectionType sortDirection, [CanBeNull] UnitObject byWho = null) { ItemObjectSortUtil.Sort(ref _items, valueGetter, sortDirection); var containerSortEvent = new ContainerSortEvent { container = parent, byUnit = byWho }; parent.containerEvents.onSort.Invoke(containerSortEvent); Resize(); } private void OnItemRemove(RemoveEvent removeEvent) { var removedItem = removeEvent.obj as ItemObject; MoveOut(removedItem); } public void Resize(int minSize = 0, int rowSize = 10) { var beforeSlotCount = items.Length; var lastItemIndex = 0; // Find last slotIndex with existing item (not null) for (var i = beforeSlotCount - 1; i >= 0; i--) { lastItemIndex = i; if (items[i] is not null) break; } // Count how many slots backpack will have after resize var afterSlotCount = Mathf.CeilToInt((Mathf.Max(lastItemIndex, minSize) + rowSize) / (float)rowSize) * rowSize; // Size not changed, do nothing if (beforeSlotCount == afterSlotCount) return; // Resize backpack's arrays var tempItems = items; Array.Resize(ref tempItems, afterSlotCount); _items = tempItems; var containerResizeEvent = new ContainerResizeEvent { container = parent, beforeSlotCount = beforeSlotCount, afterSlotCount = afterSlotCount, lastItemIndex = lastItemIndex, }; parent.containerEvents.onResize.Invoke(containerResizeEvent); } } }