using System; using System.Collections.Generic; using System.Reflection; using ColdMint.scripts.map.events; namespace ColdMint.scripts.inventory; /// /// UniversalItemContainer /// 通用的物品容器 /// public class UniversalItemContainer(int totalCapacity) : IItemContainer { private readonly Dictionary _itemDictionary = []; /// /// UnknownIndex /// 未知位置 /// private const int UnknownIndex = -1; //_selectIndex defaults to 0. //_selectIndex默认为0. private int _selectIndex; /// /// The next available index /// 下个可用的索引 /// /// ///For example, the variable [1,2,3,5,6] represents 4, or the variable [1,2,3,4,5,6,7] represents 8. ///例如[1,2,3,5,6]这个变量表示4,再或者[1,2,3,4,5,6,7]这个变量表示8。 /// private int _nextAvailableIndex; /// /// The type of item that can be added to the item container /// 物品容器允许添加的物品类型 /// private readonly HashSet _allowedItemTypes = new(); public Action? SelectedItemChangeEvent { get; set; } public Action? ItemDataChangeEvent { get; set; } /// /// Allow Item Types Except Placeholder /// 允许添加除占位符以外的所有物品类型 /// public void AllowItemTypesExceptPlaceholder() { var itemTypeType = typeof(Config.ItemType); //Get all fields //获取所有字段 var fields = itemTypeType.GetFields(BindingFlags.Public | BindingFlags.Static); //Traversal field //遍历字段 foreach (var field in fields) { //Gets the value of the field //获取字段的值 var value = field.GetValue(null); if (value == null) { continue; } var intValue = (int)value; if (intValue == Config.ItemType.Placeholder) { continue; } _allowedItemTypes.Add(intValue); } } public void AllowAddingItemByType(int itemType) { _allowedItemTypes.Add(itemType); } public void DisallowAddingItemByType(int itemType) { _allowedItemTypes.Remove(itemType); } public bool CanAddItem(IItem item) { if (!_allowedItemTypes.Contains(item.ItemType)) { return false; } //If the capacity is not full, directly return to add items //如果未占满容量,直接返回可添加物品 if (GetUsedCapacity() < totalCapacity) { return true; } if (item.MaxQuantity == 1) { //New items do not support overlay, capacity is full, return cannot add. //新物品不支持叠加,容量已满,返回不能添加。 return false; } //If the capacity is full, we calculate whether we can spread the new items evenly among the existing items. //如果容量占满了,我们计算是否能将新物品均摊在已有的物品内。 var unallocatedQuantity = item.Quantity; foreach (var unitItem in _itemDictionary.Values) { var number = unitItem.MergeableItemCount(item, unallocatedQuantity); if (number == 0) { continue; } unallocatedQuantity -= number; if (unallocatedQuantity < 1) { return true; } } return unallocatedQuantity < 1; } private void UpdateSelectStatus(int index, IItem item) { item.IsSelect = index == _selectIndex; } /// /// Update the next available index location /// 更新下个可用的索引位置 /// private void UpdateNextAvailableIndex() { _nextAvailableIndex = UnknownIndex; if (totalCapacity <= 0) { return; } for (var i = 0; i < totalCapacity; i++) { var contains = _itemDictionary.ContainsKey(i); if (!contains) { _nextAvailableIndex = i; return; } } } public int AddItem(IItem item) { if (item.MaxQuantity == 1) { if (_nextAvailableIndex == UnknownIndex) { return 0; } var nextAvailableIndex = _nextAvailableIndex; _itemDictionary[nextAvailableIndex] = item; item.Index = nextAvailableIndex; item.ItemContainer = this; if (nextAvailableIndex != _selectIndex) { item.HideSelf(); } UpdateNextAvailableIndex(); UpdateSelectStatus(nextAvailableIndex, item); ItemDataChangeEvent?.Invoke(new ItemDataChangeEvent { NewItem = item, NewIndex = nextAvailableIndex, Type = Config.ItemDataChangeEventType.QuantityAdded }); return item.Quantity; } //There can be more than one item, try to share equally. //物品可有多个,尝试均摊。 var originalQuantity = item.Quantity; var temporarilyQuantity = item.Quantity; var index = 0; foreach (var unitItem in _itemDictionary.Values) { var number = unitItem.MergeableItemCount(item, temporarilyQuantity); if (number == 0) { continue; } temporarilyQuantity -= number; unitItem.Quantity += number; ItemDataChangeEvent?.Invoke(new ItemDataChangeEvent { NewItem = unitItem, NewIndex = index, Type = Config.ItemDataChangeEventType.QuantityAdded }); if (item.Quantity < 1) { //New items are fully shared. //新物品完全被均摊。 item.HideSelf(); return originalQuantity; } index++; } //New items have some left over. //新物品有一些剩余。 if (GetUsedCapacity() >= totalCapacity) { //The capacity is full. The remaining capacity cannot be stored. //容量已满,无法存放剩余。 return originalQuantity - temporarilyQuantity; } //Add the rest to the container. //添加剩余到容器内。 if (_nextAvailableIndex == UnknownIndex) { return 0; } var finalNextAvailableIndex = _nextAvailableIndex; _itemDictionary[finalNextAvailableIndex] = item; item.Index = finalNextAvailableIndex; item.ItemContainer = this; if (finalNextAvailableIndex != _selectIndex) { item.HideSelf(); } UpdateNextAvailableIndex(); UpdateSelectStatus(finalNextAvailableIndex, item); ItemDataChangeEvent?.Invoke(new ItemDataChangeEvent { NewItem = item, NewIndex = finalNextAvailableIndex, Type = Config.ItemDataChangeEventType.Add }); return originalQuantity; } public bool SupportSelect { get; set; } public IItem GetPlaceHolderItem(int index) { var placeholderItem = new PlaceholderItem { Index = index, ItemContainer = this }; return placeholderItem; } public int GetSelectIndex() { return _selectIndex; } public IItem? GetSelectItem() { return _itemDictionary.TryGetValue(_selectIndex, out var item) ? item : null; } public IItem? GetItem(int index) { return _itemDictionary.TryGetValue(index, out var item) ? item : null; } public bool ReplaceItem(int index, IItem item) { var oldItem = GetItem(index); _itemDictionary[index] = item; item.Index = index; item.ItemContainer = this; ItemDataChangeEvent?.Invoke(new ItemDataChangeEvent { NewItem = item, NewIndex = index, OldIndex = index, OldItem = oldItem, Type = Config.ItemDataChangeEventType.Replace }); return true; } public bool CanReplaceItem(int index, IItem item) { if (!_allowedItemTypes.Contains(item.ItemType)) { return false; } return true; } public bool ClearItem(int index) { if (!_itemDictionary.TryGetValue(index, out var item)) { return false; } var result = _itemDictionary.Remove(index); if (result) { ItemDataChangeEvent?.Invoke(new ItemDataChangeEvent { NewItem = null, NewIndex = index, OldIndex = index, OldItem = null, Type = Config.ItemDataChangeEventType.Clear }); if (SupportSelect && index == _selectIndex) { item.HideSelf(); SelectedItemChangeEvent?.Invoke(new SelectedItemChangeEvent() { NewIndex = index, OldIndex = index, NewItem = null, OldItem = null }); } } return result; } public int RemoveSelectItem(int number) { return RemoveItem(_selectIndex, number); } public int RemoveItem(int itemIndex, int number) { if (number == 0) { return 0; } if (!_itemDictionary.TryGetValue(itemIndex, out var item)) { return 0; } var originalQuantity = item.Quantity; if (number < 0) { //If the number entered is less than 0, all items are removed. //输入的数量小于0,则移除全部物品。 item.Quantity = 0; _itemDictionary.Remove(itemIndex); UpdateNextAvailableIndex(); ItemDataChangeEvent?.Invoke(new ItemDataChangeEvent { NewItem = item, NewIndex = itemIndex, Type = Config.ItemDataChangeEventType.Remove }); return originalQuantity; } var removed = Math.Min(number, item.Quantity); item.Quantity -= removed; if (item.Quantity < 1) { _itemDictionary.Remove(itemIndex); UpdateNextAvailableIndex(); ItemDataChangeEvent?.Invoke(new ItemDataChangeEvent { NewItem = item, NewIndex = itemIndex, Type = Config.ItemDataChangeEventType.Remove }); } return removed; } public int GetUsedCapacity() { return _itemDictionary.Count; } public int GetTotalCapacity() { return totalCapacity; } public void SelectNextItem() { var count = totalCapacity; if (count == 0) { return; } var oldSelectIndex = _selectIndex; var newSelectIndex = _selectIndex + 1; if (newSelectIndex >= count) { newSelectIndex = 0; } PrivateSelectItem(oldSelectIndex, newSelectIndex); } public void SelectPreviousItem() { var count = totalCapacity; if (count == 0) { return; } var oldSelectIndex = _selectIndex; var newSelectIndex = _selectIndex - 1; if (newSelectIndex < 0) { newSelectIndex = count - 1; } PrivateSelectItem(oldSelectIndex, newSelectIndex); } /// /// Private methods for selecting items /// 选择物品的私有方法 /// /// /// private void PrivateSelectItem(int oldIndex, int newIndex) { if (!SupportSelect || oldIndex == newIndex) { return; } //There is no need to broadcast placeholders when an event is invoked. //在调用事件时,无需广播占位符。 var oldItem = GetItem(oldIndex); if (oldItem != null) { oldItem.HideSelf(); oldItem.IsSelect = false; } //There is no need to broadcast placeholders when an event is invoked. //在调用事件时,无需广播占位符。 var newItem = GetItem(newIndex); if (newItem != null) { newItem.ShowSelf(); newItem.IsSelect = true; } _selectIndex = newIndex; SelectedItemChangeEvent?.Invoke(new SelectedItemChangeEvent { NewIndex = newIndex, OldIndex = oldIndex, NewItem = newItem, OldItem = oldItem }); } public void SelectItem(int index) { if (totalCapacity == 0 || index < 0) { return; } PrivateSelectItem(_selectIndex, index % totalCapacity); } }