AI/Guests/Inventory/Inventory.cs
using Sandbox.Diagnostics;

namespace HC3.Inventory;

public interface IItemEvents : ISceneEvent<IItemEvents>
{
	/// <summary>
	/// Called when an item is added to an inventory
	/// </summary>
	/// <param name="item"></param>
	public void OnAdded( Item item ) { }

	/// <summary>
	/// Called when an item is removed
	/// </summary>
	/// <param name="item"></param>
	public void OnRemoved( Item item ) { }

	/// <summary>
	/// Called when an item is consumed
	/// </summary>
	/// <param name="item"></param>
	public void OnUsed( Item item ) { }
}

/// <summary>
/// An inventory, it just stores items
/// </summary>
public partial class Inventory : Component
{
	private List<Item> _cachedItems;

	/// <summary>
	/// A list of items (cached, invalidated on add/remove)
	/// </summary>
	public IReadOnlyList<Item> Items
	{
		get
		{
			_cachedItems ??= GetComponentsInChildren<Item>().ToList();
			return _cachedItems;
		}
	}

	/// <summary>
	/// Invalidate the cached item list (call after add/remove)
	/// </summary>
	private void InvalidateItemCache() => _cachedItems = null;

	/// <summary>
	/// The guest who owns this
	/// </summary>
	public Guest Guest => GetComponentInParent<Guest>();

	protected virtual void OnRemove()
	{
		// Inventory removed!
	}

	protected override void OnDestroy()
	{
		OnRemove();
	}

	/// <summary>
	/// Add an item to the inventory via a prefab
	/// </summary>
	/// <param name="prefab"></param>
	public void Add( GameObject prefab )
	{
		Assert.True( prefab.IsValid(), "Tried to add invalid item prefab to inventory" );

		prefab?.Clone( new CloneConfig()
		{
			Parent = GameObject,
			StartEnabled = true
		} );

		InvalidateItemCache();
		Network.Refresh();
	}

	/// <summary>
	/// Remove all items that have this component
	/// </summary>
	public void RemoveAll<T>() where T : Component
	{
		var didDestroyItems = false;

		for ( int i = Items.Count - 1; i >= 0; i-- )
		{
			var item = Items[i];
			if ( item.GetComponent<T>() is null )
				continue;

			item.DestroyGameObject();
			didDestroyItems = true;
		}

		InvalidateItemCache();

		if ( didDestroyItems )
		{
			Network.Refresh();
		}
	}

	/// <summary>
	/// Remove an item from the inventory
	/// </summary>
	public void Remove( Item item )
	{
		// Don't remove it if this doesn't belong to our inventory
		if ( !GameObject.IsDescendant( item.GameObject ) )
			return;

		item.DestroyGameObject();
		InvalidateItemCache();
		Network.Refresh();
	}
}