2025-08-19 20:22:10 +08:00
using System.Collections.Generic ;
2025-08-27 19:56:49 +08:00
using System.Linq ;
using UnityEngine ;
2025-08-19 20:22:10 +08:00
namespace Entity
{
public class Inventory
{
2025-08-27 19:56:49 +08:00
public Entity From { get ; private set ; }
private readonly List < InventorySlot > _slots ;
public int Capacity { get ; private set ; }
public event System . Action < Item . ItemResource , int > OnItemAdded ;
public event System . Action < Item . ItemResource , int > OnItemRemoved ;
public event System . Action OnInventoryChanged ;
public Inventory ( Entity owner , int capacity = 20 )
2025-08-19 20:22:10 +08:00
{
2025-08-27 19:56:49 +08:00
From = owner ;
Capacity = Mathf . Max ( 1 , capacity ) ;
_slots = new List < InventorySlot > ( Capacity ) ;
}
2025-08-19 20:22:10 +08:00
2025-08-27 19:56:49 +08:00
public int AddItem ( Item . ItemResource itemResource , int quantity )
{
if ( itemResource = = null | | quantity < = 0 )
2025-08-19 20:22:10 +08:00
{
2025-08-27 19:56:49 +08:00
Debug . LogWarning (
$"Inventory for {From?.ToString() ?? " Unknown "}: Attempted to add null item or zero/negative quantity." ) ;
return quantity ;
}
var remainingQuantity = quantity ;
var addedTotal = 0 ;
// 1. 尝试堆叠到现有槽位 (使用 DefName 进行比较)
if ( itemResource . MaxStack > 1 )
{
foreach ( var slot in _slots . Where ( s = >
s . Item ! = null & & s . Item . DefName = = itemResource . DefName & & ! s . IsFull ) )
2025-08-19 20:22:10 +08:00
{
2025-08-27 19:56:49 +08:00
var addedToSlot = slot . AddQuantity ( remainingQuantity ) ;
remainingQuantity - = addedToSlot ;
addedTotal + = addedToSlot ;
if ( remainingQuantity < = 0 ) break ;
2025-08-19 20:22:10 +08:00
}
}
2025-08-27 19:56:49 +08:00
// 2. 如果还有剩余,尝试添加到新槽位
while ( remainingQuantity > 0 & & _slots . Count < Capacity )
{
var quantityToAdd = Mathf . Min ( remainingQuantity , itemResource . MaxStack ) ;
var newSlot = new InventorySlot ( itemResource , quantityToAdd ) ;
_slots . Add ( newSlot ) ;
remainingQuantity - = quantityToAdd ;
addedTotal + = quantityToAdd ;
}
if ( addedTotal > 0 )
{
OnItemAdded ? . Invoke ( itemResource , addedTotal ) ;
OnInventoryChanged ? . Invoke ( ) ;
}
if ( remainingQuantity > 0 )
{
Debug . LogWarning (
$"Inventory for {From?.ToString() ?? " Unknown "} is full or cannot stack. {remainingQuantity} of {itemResource.Name} (DefName: {itemResource.DefName}) could not be added." ) ;
}
return remainingQuantity ;
2025-08-19 20:22:10 +08:00
}
2025-08-27 19:56:49 +08:00
public int RemoveItem ( Item . ItemResource itemResource , int quantity )
2025-08-19 20:22:10 +08:00
{
2025-08-27 19:56:49 +08:00
if ( itemResource = = null | | quantity < = 0 )
{
Debug . LogWarning (
$"Inventory for {From?.ToString() ?? " Unknown "}: Attempted to remove null item or zero/negative quantity." ) ;
return quantity ;
}
var remainingQuantity = quantity ;
var removedTotal = 0 ;
var slotsToClean = new List < InventorySlot > ( ) ;
2025-08-19 20:22:10 +08:00
2025-08-27 19:56:49 +08:00
// 从后往前遍历,以便安全地移除空槽位 (使用 DefName 进行比较)
for ( var i = _slots . Count - 1 ; i > = 0 ; i - - )
2025-08-19 20:22:10 +08:00
{
2025-08-27 19:56:49 +08:00
var slot = _slots [ i ] ;
if ( slot . Item ! = null & & slot . Item . DefName = = itemResource . DefName )
2025-08-19 20:22:10 +08:00
{
2025-08-27 19:56:49 +08:00
var removedFromSlot = slot . RemoveQuantity ( remainingQuantity ) ;
remainingQuantity - = removedFromSlot ;
removedTotal + = removedFromSlot ;
2025-08-19 20:22:10 +08:00
2025-08-27 19:56:49 +08:00
if ( slot . IsEmpty )
2025-08-19 20:22:10 +08:00
{
2025-08-27 19:56:49 +08:00
slotsToClean . Add ( slot ) ;
2025-08-19 20:22:10 +08:00
}
2025-08-27 19:56:49 +08:00
if ( remainingQuantity < = 0 ) break ;
}
}
foreach ( var slot in slotsToClean )
{
_slots . Remove ( slot ) ;
}
if ( removedTotal > 0 )
{
OnItemRemoved ? . Invoke ( itemResource , removedTotal ) ;
OnInventoryChanged ? . Invoke ( ) ;
}
if ( remainingQuantity > 0 )
{
Debug . LogWarning (
$"Inventory for {From?.ToString() ?? " Unknown "}: Not enough {itemResource.Name} (DefName: {itemResource.DefName}). {remainingQuantity} could not be removed." ) ;
}
return remainingQuantity ;
}
public bool HasItem ( Item . ItemResource itemResource , int quantity = 1 )
{
if ( itemResource = = null | | quantity < = 0 ) return false ;
return GetItemCount ( itemResource ) > = quantity ;
}
public int GetItemCount ( Item . ItemResource itemResource )
{
if ( itemResource = = null ) return 0 ;
// 使用 DefName 进行计数
return _slots . Where ( s = > s . Item ! = null & & s . Item . DefName = = itemResource . DefName )
. Sum ( s = > s . Quantity ) ;
}
public IReadOnlyList < InventorySlot > GetSlots ( )
{
return _slots . AsReadOnly ( ) ;
}
public InventorySlot GetSlot ( Item . ItemResource itemResource )
{
if ( itemResource = = null ) return null ;
foreach ( var slot in _slots )
{
if ( slot . Item ! = null & & slot . Item . DefName = = itemResource . DefName )
{
return slot ;
2025-08-19 20:22:10 +08:00
}
}
2025-08-27 19:56:49 +08:00
return null ;
}
public InventorySlot GetSlot ( int i )
{
if ( i < 0 | | i > = OccupiedSlotsCount )
return null ;
return _slots [ i ] ;
2025-08-19 20:22:10 +08:00
}
2025-08-27 19:56:49 +08:00
public int OccupiedSlotsCount = > _slots . Count ;
public int AvailableSlotsCount = > Capacity - _slots . Count ;
2025-08-19 20:22:10 +08:00
}
}