func (inv *Inventory) Clear() {
	inv.mu.Lock()
	for slot := range inv.slots {
		f := inv.setItem(slot, item.Stack{})
		defer f()
	}
	inv.mu.Unlock()
}
Clear clears the entire inventory. All items are removed, except for items in locked slots.
package inventory
import (
	"errors"
	"fmt"
	"github.com/df-mc/dragonfly/server/item"
	"math"
	"strings"
	"sync"
)
type Inventory struct {
	mu    sync.RWMutex
	h     Handler
	slots []item.Stack
	f      func(slot int, item item.Stack)
	canAdd func(s item.Stack, slot int) bool
}
var ErrSlotOutOfRange = errors.New("slot is out of range: must be in range 0 <= slot < inventory.Size()")
func New(size int, f func(slot int, item item.Stack)) *Inventory {
	if size <= 0 {
		panic("inventory size must be at least 1")
	}
	if f == nil {
		f = func(slot int, item item.Stack) {}
	}
	return &Inventory{h: NopHandler{}, slots: make([]item.Stack, size), f: f, canAdd: func(s item.Stack, slot int) bool { return true }}
}
func (inv *Inventory) Item(slot int) (item.Stack, error) {
	inv.check()
	if !inv.validSlot(slot) {
		return item.Stack{}, ErrSlotOutOfRange
	}
	inv.mu.RLock()
	i := inv.slots[slot]
	inv.mu.RUnlock()
	return i, nil
}
func (inv *Inventory) SetItem(slot int, item item.Stack) error {
	inv.check()
	if !inv.validSlot(slot) {
		return ErrSlotOutOfRange
	}
	inv.mu.Lock()
	f := inv.setItem(slot, item)
	inv.mu.Unlock()
	f()
	return nil
}
func (inv *Inventory) Slots() []item.Stack {
	r := make([]item.Stack, inv.Size())
	inv.mu.RLock()
	copy(r, inv.slots)
	inv.mu.RUnlock()
	return r
}
func (inv *Inventory) Items() []item.Stack {
	contents := make([]item.Stack, 0, inv.Size())
	inv.mu.RLock()
	for _, it := range inv.slots {
		if !it.Empty() {
			contents = append(contents, it)
		}
	}
	inv.mu.RUnlock()
	return contents
}
func (inv *Inventory) First(item item.Stack) (int, bool) {
	for slot, it := range inv.Slots() {
		if !it.Empty() && it.Comparable(item) {
			return slot, true
		}
	}
	return -1, false
}
func (inv *Inventory) FirstEmpty() (int, bool) {
	for slot, it := range inv.Slots() {
		if it.Empty() {
			return slot, true
		}
	}
	return -1, false
}
func (inv *Inventory) Swap(slotA, slotB int) error {
	inv.check()
	if !inv.validSlot(slotA) || !inv.validSlot(slotB) {
		return ErrSlotOutOfRange
	}
	itemA, _ := inv.Item(slotA)
	itemB, _ := inv.Item(slotB)
	_ = inv.SetItem(slotA, itemB)
	_ = inv.SetItem(slotB, itemA)
	return nil
}
func (inv *Inventory) AddItem(it item.Stack) (n int, err error) {
	if it.Empty() {
		return 0, nil
	}
	first := it.Count()
	inv.mu.Lock()
	for slot, invIt := range inv.slots {
		if invIt.Empty() {
			continue
		}
		a, b := invIt.AddStack(it)
		f := inv.setItem(slot, a)
		defer f()
		it = b
		if it.Empty() {
			inv.mu.Unlock()
			return first, nil
		}
	}
	for slot, invIt := range inv.slots {
		if !invIt.Empty() {
			continue
		}
		a, b := it.Grow(-math.MaxInt32).AddStack(it)
		f := inv.setItem(slot, a)
		defer f()
		it = b
		if it.Empty() {
			inv.mu.Unlock()
			return first, nil
		}
	}
	inv.mu.Unlock()
	return first - it.Count(), fmt.Errorf("could not add full item stack to inventory")
}
func (inv *Inventory) RemoveItem(it item.Stack) error {
	toRemove := it.Count()
	inv.mu.Lock()
	for slot, slotIt := range inv.slots {
		if slotIt.Empty() || !slotIt.Comparable(it) {
			continue
		}
		f := inv.setItem(slot, slotIt.Grow(-toRemove))
		defer f()
		toRemove -= slotIt.Count()
		if toRemove <= 0 {
			inv.mu.Unlock()
			return nil
		}
	}
	if toRemove <= 0 {
		inv.mu.Unlock()
		return nil
	}
	inv.mu.Unlock()
	return fmt.Errorf("could not remove all items from the inventory")
}
func (inv *Inventory) Empty() bool {
	inv.mu.RLock()
	defer inv.mu.RUnlock()
	for _, it := range inv.slots {
		if !it.Empty() {
			return false
		}
	}
	return true
}