func allWoodSlabs() (slabs []world.Block) {
	f := func(double bool, upsideDown bool) {
		for _, w := range WoodTypes() {
			slabs = append(slabs, WoodSlab{Double: double, Top: upsideDown, Wood: w})
		}
	}
	f(false, false)
	f(false, true)
	f(true, false)
	f(true, true)
	return
}
allWoodSlabs returns all states of wood slabs.
package block
import (
	"github.com/df-mc/dragonfly/server/block/cube"
	"github.com/df-mc/dragonfly/server/block/model"
	"github.com/df-mc/dragonfly/server/entity/physics"
	"github.com/df-mc/dragonfly/server/item"
	"github.com/df-mc/dragonfly/server/item/tool"
	"github.com/df-mc/dragonfly/server/world"
	"github.com/go-gl/mathgl/mgl64"
)
type WoodSlab struct {
	bass
	Wood WoodType
	Top bool
	Double bool
}
func (s WoodSlab) FlammabilityInfo() FlammabilityInfo {
	if !s.Wood.Flammable() {
		return newFlammabilityInfo(0, 0, false)
	}
	return newFlammabilityInfo(5, 20, true)
}
func (s WoodSlab) Model() world.BlockModel {
	return model.Slab{Double: s.Double, Top: s.Top}
}
func (s WoodSlab) UseOnBlock(pos cube.Pos, face cube.Face, clickPos mgl64.Vec3, w *world.World, user item.User, ctx *item.UseContext) (used bool) {
	clickedBlock := w.Block(pos)
	if clickedSlab, ok := clickedBlock.(WoodSlab); ok && !s.Double {
		if (face == cube.FaceUp && !clickedSlab.Double && clickedSlab.Wood == s.Wood && !clickedSlab.Top) ||
			(face == cube.FaceDown && !clickedSlab.Double && clickedSlab.Wood == s.Wood && clickedSlab.Top) {
			clickedSlab.Double = true
			place(w, pos, clickedSlab, user, ctx)
			return placed(ctx)
		}
	}
	if sideSlab, ok := w.Block(pos.Side(face)).(WoodSlab); ok && !replaceableWith(w, pos, s) && !s.Double {
		if !sideSlab.Double && sideSlab.Wood == s.Wood {
			sideSlab.Double = true
			place(w, pos.Side(face), sideSlab, user, ctx)
			return placed(ctx)
		}
	}
	pos, face, used = firstReplaceable(w, pos, face, s)
	if !used {
		return
	}
	if face == cube.FaceDown || (clickPos[1] > 0.5 && face != cube.FaceUp) {
		s.Top = true
	}
	place(w, pos, s, user, ctx)
	return placed(ctx)
}
func (s WoodSlab) BreakInfo() BreakInfo {
	return newBreakInfo(2, alwaysHarvestable, axeEffective, func(tool.Tool, []item.Enchantment) []item.Stack {
		if s.Double {
			s.Double = false
			return []item.Stack{item.NewStack(s, 2)}
		}
		return []item.Stack{item.NewStack(s, 1)}
	})
}
func (s WoodSlab) LightDiffusionLevel() uint8 {
	if s.Double {
		return 15
	}
	return 0
}
func (s WoodSlab) AABB(cube.Pos, *world.World) []physics.AABB {
	if s.Double {
		return []physics.AABB{physics.NewAABB(mgl64.Vec3{}, mgl64.Vec3{1, 1, 1})}
	}
	if s.Top {
		return []physics.AABB{physics.NewAABB(mgl64.Vec3{0, 0.5, 0}, mgl64.Vec3{1, 1, 1})}
	}
	return []physics.AABB{physics.NewAABB(mgl64.Vec3{}, mgl64.Vec3{1, 0.5, 1})}
}
func (s WoodSlab) EncodeItem() (name string, meta int16) {
	switch s.Wood {
	case OakWood(), SpruceWood(), BirchWood(), JungleWood(), AcaciaWood(), DarkOakWood():
		if s.Double {
			return "minecraft:double_wooden_slab", int16(s.Wood.Uint8())
		}
		return "minecraft:wooden_slab", int16(s.Wood.Uint8())
	case CrimsonWood():
		if s.Double {
			return "minecraft:crimson_double_slab", 0
		}
		return "minecraft:crimson_slab", 0
	case WarpedWood():
		if s.Double {
			return "minecraft:warped_double_slab", 0
		}
		return "minecraft:warped_slab", 0
	}
	panic("invalid wood type")
}
func (s WoodSlab) EncodeBlock() (name string, properties map[string]interface{}) {
	if s.Double {
		if s.Wood == CrimsonWood() || s.Wood == WarpedWood() {
			return "minecraft:" + s.Wood.String() + "_double_slab", map[string]interface{}{"top_slot_bit": s.Top}
		}
		return "minecraft:double_wooden_slab", map[string]interface{}{"top_slot_bit": s.Top, "wood_type": s.Wood.String()}
	}
	if s.Wood == CrimsonWood() || s.Wood == WarpedWood() {
		return "minecraft:" + s.Wood.String() + "_slab", map[string]interface{}{"top_slot_bit": s.Top}
	}
	return "minecraft:wooden_slab", map[string]interface{}{"top_slot_bit": s.Top, "wood_type": s.Wood.String()}
}
func (s WoodSlab) CanDisplace(b world.Liquid) bool {
	_, ok := b.(Water)
	return !s.Double && ok
}
func (s WoodSlab) SideClosed(pos, side cube.Pos, _ *world.World) bool {
	return !s.Top && side[1] == pos[1]-1
}