func silkTouchOneOf(normal, silkTouch world.Item) func(tool.Tool, []item.Enchantment) []item.Stack {
	return func(t tool.Tool, enchantments []item.Enchantment) []item.Stack {
		if hasSilkTouch(enchantments) {
			return []item.Stack{item.NewStack(silkTouch, 1)}
		}
		return []item.Stack{item.NewStack(normal, 1)}
	}
}
silkTouchOneOf returns a drop function that returns 1x of the silk touch drop when silk touch exists, or 1x of the
normal drop when it does not.
package block
import (
	"github.com/df-mc/dragonfly/server/item"
	"github.com/df-mc/dragonfly/server/item/enchantment"
	"github.com/df-mc/dragonfly/server/item/tool"
	"github.com/df-mc/dragonfly/server/world"
	"math"
	"time"
)
type Breakable interface {
	BreakInfo() BreakInfo
}
func BreakDuration(b world.Block, i item.Stack) time.Duration {
	breakable, ok := b.(Breakable)
	if !ok {
		return math.MaxInt64
	}
	t, ok := i.Item().(tool.Tool)
	if !ok {
		t = tool.None{}
	}
	info := breakable.BreakInfo()
	breakTime := info.Hardness * 5
	if info.Harvestable(t) {
		breakTime = info.Hardness * 1.5
	}
	if info.Effective(t) {
		eff := t.BaseMiningEfficiency(b)
		if e, ok := i.Enchantment(enchantment.Efficiency{}); ok {
			breakTime += (enchantment.Efficiency{}).Addend(e.Level())
		}
		breakTime /= eff
	}
	timeInTicksAccurate := math.Round(breakTime/0.05) * 0.05
	return (time.Duration(math.Round(timeInTicksAccurate*20)) * time.Second) / 20
}
func BreaksInstantly(b world.Block, i item.Stack) bool {
	breakable, ok := b.(Breakable)
	if !ok {
		return false
	}
	hardness := breakable.BreakInfo().Hardness
	if hardness == 0 {
		return true
	}
	t, ok := i.Item().(tool.Tool)
	if !ok || !breakable.BreakInfo().Effective(t) {
		return false
	}
	efficiencyVal := 0.0
	if e, ok := i.Enchantment(enchantment.Efficiency{}); ok {
		efficiencyVal += (enchantment.Efficiency{}).Addend(e.Level())
	}
	hasteVal := 0.0
	return (t.BaseMiningEfficiency(b)+efficiencyVal)*hasteVal >= hardness*30
}
type BreakInfo struct {
	Hardness float64
	Harvestable func(t tool.Tool) bool
	Effective func(t tool.Tool) bool
	Drops func(t tool.Tool, enchantments []item.Enchantment) []item.Stack
	XPDrops XPDropRange
}
func newBreakInfo(hardness float64, harvestable func(tool.Tool) bool, effective func(tool.Tool) bool, drops func(tool.Tool, []item.Enchantment) []item.Stack) BreakInfo {
	return BreakInfo{
		Hardness:    hardness,
		Harvestable: harvestable,
		Effective:   effective,
		Drops:       drops,
	}
}
type XPDropRange [2]int
var pickaxeEffective = func(t tool.Tool) bool {
	return t.ToolType() == tool.TypePickaxe
}
var axeEffective = func(t tool.Tool) bool {
	return t.ToolType() == tool.TypeAxe
}
var shearsEffective = func(t tool.Tool) bool {
	return t.ToolType() == tool.TypeShears
}
var shovelEffective = func(t tool.Tool) bool {
	return t.ToolType() == tool.TypeShovel
}
var hoeEffective = func(t tool.Tool) bool {
	return t.ToolType() == tool.TypeHoe
}
var nothingEffective = func(tool.Tool) bool {
	return false
}
var alwaysHarvestable = func(t tool.Tool) bool {
	return true
}
var neverHarvestable = func(t tool.Tool) bool {
	return false
}
var pickaxeHarvestable = pickaxeEffective
func simpleDrops(s ...item.Stack) func(tool.Tool, []item.Enchantment) []item.Stack {
	return func(tool.Tool, []item.Enchantment) []item.Stack {
		return s
	}
}
func oneOf(i ...world.Item) func(tool.Tool, []item.Enchantment) []item.Stack {
	return func(tool.Tool, []item.Enchantment) []item.Stack {
		var s []item.Stack
		for _, it := range i {
			s = append(s, item.NewStack(it, 1))
		}
		return s
	}
}
func hasSilkTouch(enchantments []item.Enchantment) bool {
	for _, enchant := range enchantments {
		if _, ok := enchant.(enchantment.SilkTouch); ok {
			return true
		}
	}
	return false
}