up3
Build and deploy / Build (push) Has been cancelled
Build and deploy / Update Contributors (push) Has been cancelled
Build and deploy / Deploy (push) Has been cancelled
Build and deploy / Build (push) Has been cancelled
Build and deploy / Update Contributors (push) Has been cancelled
Build and deploy / Deploy (push) Has been cancelled
This commit is contained in:
Binary file not shown.
@@ -0,0 +1,120 @@
|
||||
package recipe
|
||||
|
||||
import (
|
||||
"github.com/df-mc/dragonfly/server/item"
|
||||
"github.com/df-mc/dragonfly/server/world"
|
||||
)
|
||||
|
||||
// DecoratedPotRecipe is a dynamic recipe for crafting decorated pots. The output depends on which
|
||||
// pottery sherds or bricks are used in the crafting grid.
|
||||
type DecoratedPotRecipe struct {
|
||||
block string
|
||||
}
|
||||
|
||||
// NewDecoratedPotRecipe creates a new decorated pot recipe.
|
||||
func NewDecoratedPotRecipe() DecoratedPotRecipe {
|
||||
return DecoratedPotRecipe{block: "crafting_table"}
|
||||
}
|
||||
|
||||
// potDecoration is a local interface to check if an item can be used as a pot decoration
|
||||
// without importing the block package (which would create an import cycle).
|
||||
type potDecoration interface {
|
||||
world.Item
|
||||
PotDecoration() bool
|
||||
}
|
||||
|
||||
// Match checks if the given input items match the decorated pot recipe pattern.
|
||||
// The pattern requires exactly 4 PotDecoration items (bricks or pottery sherds) in a diamond/plus shape:
|
||||
// - Slot 1 (top centre)
|
||||
// - Slot 3 (middle left)
|
||||
// - Slot 5 (middle right)
|
||||
// - Slot 7 (bottom centre)
|
||||
// All other slots must be empty.
|
||||
func (r DecoratedPotRecipe) Match(input []Item) (output []item.Stack, ok bool) {
|
||||
// For a 3x3 crafting grid, we need exactly 9 slots
|
||||
if len(input) != 9 {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// Define the slots for the diamond pattern (0-indexed)
|
||||
// Layout: 0 1 2
|
||||
// 3 4 5
|
||||
// 6 7 8
|
||||
// We need items at: 1 (top), 3 (left), 5 (right), 7 (bottom)
|
||||
// Odd indices should have items, even indices should be empty
|
||||
|
||||
decorations := [4]world.Item{}
|
||||
decorationIndex := 0
|
||||
for i := range input {
|
||||
it := input[i]
|
||||
if i%2 == 0 {
|
||||
// Even slots (0, 2, 4, 6, 8) should be empty
|
||||
if !it.Empty() {
|
||||
return nil, false
|
||||
}
|
||||
} else {
|
||||
// Odd slots (1, 3, 5, 7) should have items
|
||||
if it.Empty() {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// Extract the actual item from the Item interface
|
||||
var actualItem item.Stack
|
||||
if v, ok := it.(item.Stack); ok {
|
||||
actualItem = v
|
||||
} else {
|
||||
// ItemTag or other types are not valid for decorated pots
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// Check if the item implements PotDecoration
|
||||
decoration, ok := actualItem.Item().(potDecoration)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
decorations[decorationIndex] = decoration
|
||||
decorationIndex++
|
||||
}
|
||||
}
|
||||
|
||||
// Create the decorated pot by encoding the decorations into NBT
|
||||
// We'll use world.BlockByName to get the DecoratedPot block and set its decorations
|
||||
// The decorations are ordered: [top, left, right, bottom] in the crafting grid
|
||||
// For the pot NBT: [back, left, front, right] based on facing direction
|
||||
|
||||
// Get a decorated pot block instance
|
||||
pot, ok := world.BlockByName("minecraft:decorated_pot", map[string]any{"direction": int32(2)})
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// The pot will be decoded with the decorations through NBT when placed
|
||||
// For now, we'll create a pot with the decorations in the correct order
|
||||
// DecoratedPot.DecodeNBT expects sherds in order: [back, left, front, right]
|
||||
sherds := []any{}
|
||||
// Order: top -> back, left -> left, bottom -> front, right -> right
|
||||
for _, idx := range []int{0, 1, 3, 2} { // top, left, bottom, right
|
||||
name, _ := decorations[idx].EncodeItem()
|
||||
sherds = append(sherds, name)
|
||||
}
|
||||
|
||||
// Decode the pot with the sherds NBT data using type assertion
|
||||
if nbtDecoder, ok := pot.(interface {
|
||||
DecodeNBT(map[string]any) any
|
||||
}); ok {
|
||||
decodedPot := nbtDecoder.DecodeNBT(map[string]any{
|
||||
"id": "DecoratedPot",
|
||||
"sherds": sherds,
|
||||
})
|
||||
if potItem, ok := decodedPot.(world.Item); ok {
|
||||
return []item.Stack{item.NewStack(potItem, 1)}, true
|
||||
}
|
||||
}
|
||||
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// Block returns the block used to craft this recipe.
|
||||
func (r DecoratedPotRecipe) Block() string {
|
||||
return r.block
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
package recipe
|
||||
|
||||
import (
|
||||
"github.com/df-mc/dragonfly/server/item"
|
||||
"github.com/df-mc/dragonfly/server/world"
|
||||
"math"
|
||||
)
|
||||
|
||||
// Item represents an item that can be used as either the input or output of an item. These do not
|
||||
// necessarily resolve to an actual item, but can be just as simple as a tag etc.
|
||||
type Item interface {
|
||||
// Count returns the amount of items that is present on the stack. The count is guaranteed never to be
|
||||
// negative.
|
||||
Count() int
|
||||
// Empty checks if the stack is empty (has a count of 0).
|
||||
Empty() bool
|
||||
}
|
||||
|
||||
// inputItem is a type representing an input item, with a helper function to convert it to an Item.
|
||||
type inputItem struct {
|
||||
// Name is the name of the item being inputted.
|
||||
Name string `nbt:"name"`
|
||||
// Meta is the meta of the item. This can change the item almost completely, or act as durability.
|
||||
Meta int32 `nbt:"meta"`
|
||||
// Count is the amount of the item.
|
||||
Count int32 `nbt:"count"`
|
||||
// State is included if the output is a block. If it's not included, the meta can be discarded and the output item can be incorrect.
|
||||
State struct {
|
||||
Name string `nbt:"name"`
|
||||
Properties map[string]interface{} `nbt:"states"`
|
||||
Version int32 `nbt:"version"`
|
||||
} `nbt:"block"`
|
||||
// Tag is included if the input item is defined by a tag instead of a specific item.
|
||||
Tag string `nbt:"tag"`
|
||||
}
|
||||
|
||||
// Item converts an input item to a recipe item.
|
||||
func (i inputItem) Item() (Item, bool) {
|
||||
if i.Tag != "" {
|
||||
return NewItemTag(i.Tag, int(i.Count)), true
|
||||
}
|
||||
|
||||
it, ok := world.ItemByName(i.Name, int16(i.Meta))
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
st := item.NewStack(it, int(i.Count))
|
||||
if i.Meta == math.MaxInt16 {
|
||||
st = st.WithValue("variants", true)
|
||||
}
|
||||
|
||||
return st, true
|
||||
}
|
||||
|
||||
// inputItems is a type representing a list of input items, with a helper function to convert it to an Item.
|
||||
type inputItems []inputItem
|
||||
|
||||
// Items converts input items to recipe items.
|
||||
func (d inputItems) Items() ([]Item, bool) {
|
||||
s := make([]Item, 0, len(d))
|
||||
for _, i := range d {
|
||||
itemInput, ok := i.Item()
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
s = append(s, itemInput)
|
||||
}
|
||||
return s, true
|
||||
}
|
||||
|
||||
// outputItem is an output item.
|
||||
type outputItem struct {
|
||||
// Name is the name of the item being output.
|
||||
Name string `nbt:"name"`
|
||||
// Meta is the meta of the item. This can change the item almost completely, or act as durability.
|
||||
Meta int32 `nbt:"meta"`
|
||||
// Count is the amount of the item.
|
||||
Count int16 `nbt:"count"`
|
||||
// State is included if the output is a block. If it's not included, the meta can be discarded and the output item can be incorrect.
|
||||
State struct {
|
||||
Name string `nbt:"name"`
|
||||
Properties map[string]interface{} `nbt:"states"`
|
||||
Version int32 `nbt:"version"`
|
||||
} `nbt:"block"`
|
||||
// NBTData contains extra NBTData which may modify the item in other, more discreet ways.
|
||||
NBTData map[string]interface{} `nbt:"data"`
|
||||
}
|
||||
|
||||
// Stack converts an output item to an item stack.
|
||||
func (o outputItem) Stack() (item.Stack, bool) {
|
||||
it, ok := world.ItemByName(o.Name, int16(o.Meta))
|
||||
if !ok {
|
||||
return item.Stack{}, false
|
||||
}
|
||||
if n, ok := it.(world.NBTer); ok {
|
||||
it = n.DecodeNBT(o.NBTData).(world.Item)
|
||||
}
|
||||
|
||||
return item.NewStack(it, int(o.Count)), true
|
||||
}
|
||||
|
||||
// outputItems is an array of output items.
|
||||
type outputItems []outputItem
|
||||
|
||||
// Stacks converts output items to item stacks.
|
||||
func (d outputItems) Stacks() ([]item.Stack, bool) {
|
||||
s := make([]item.Stack, 0, len(d))
|
||||
for _, o := range d {
|
||||
itemOutput, ok := o.Stack()
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
s = append(s, itemOutput)
|
||||
}
|
||||
return s, true
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package recipe
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed item_tags.json
|
||||
itemTagData []byte
|
||||
itemTags = make(map[string][]string)
|
||||
)
|
||||
|
||||
func init() {
|
||||
if err := json.Unmarshal(itemTagData, &itemTags); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// ItemTag represents a recipe item that is identified by a tag, such as "minecraft:planks" or
|
||||
// "minecraft:digger" and so on.
|
||||
type ItemTag struct {
|
||||
tag string
|
||||
count int
|
||||
|
||||
items []string
|
||||
}
|
||||
|
||||
// NewItemTag creates a new item tag with the tag and count passed.
|
||||
func NewItemTag(tag string, count int) ItemTag {
|
||||
if count < 0 {
|
||||
count = 0
|
||||
}
|
||||
return ItemTag{tag: tag, count: count, items: itemTags[tag]}
|
||||
}
|
||||
|
||||
// Count ...
|
||||
func (i ItemTag) Count() int {
|
||||
return i.count
|
||||
}
|
||||
|
||||
// Empty ...
|
||||
func (i ItemTag) Empty() bool {
|
||||
return i.count == 0 || i.tag == ""
|
||||
}
|
||||
|
||||
// Tag returns the tag of the item.
|
||||
func (i ItemTag) Tag() string {
|
||||
return i.tag
|
||||
}
|
||||
|
||||
// Contains returns true if the item tag contains the item with the name passed.
|
||||
func (i ItemTag) Contains(name string) bool {
|
||||
for _, item := range i.items {
|
||||
if item == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -0,0 +1,829 @@
|
||||
{
|
||||
"minecraft:arrow": [
|
||||
"minecraft:arrow"
|
||||
],
|
||||
"minecraft:banner": [
|
||||
"minecraft:banner"
|
||||
],
|
||||
"minecraft:boat": [
|
||||
"minecraft:acacia_boat",
|
||||
"minecraft:acacia_chest_boat",
|
||||
"minecraft:bamboo_chest_raft",
|
||||
"minecraft:bamboo_raft",
|
||||
"minecraft:birch_boat",
|
||||
"minecraft:birch_chest_boat",
|
||||
"minecraft:cherry_boat",
|
||||
"minecraft:cherry_chest_boat",
|
||||
"minecraft:dark_oak_boat",
|
||||
"minecraft:dark_oak_chest_boat",
|
||||
"minecraft:jungle_boat",
|
||||
"minecraft:jungle_chest_boat",
|
||||
"minecraft:mangrove_boat",
|
||||
"minecraft:mangrove_chest_boat",
|
||||
"minecraft:oak_boat",
|
||||
"minecraft:oak_chest_boat",
|
||||
"minecraft:pale_oak_boat",
|
||||
"minecraft:pale_oak_chest_boat",
|
||||
"minecraft:spruce_boat",
|
||||
"minecraft:spruce_chest_boat"
|
||||
],
|
||||
"minecraft:boats": [
|
||||
"minecraft:acacia_boat",
|
||||
"minecraft:acacia_chest_boat",
|
||||
"minecraft:bamboo_chest_raft",
|
||||
"minecraft:bamboo_raft",
|
||||
"minecraft:birch_boat",
|
||||
"minecraft:birch_chest_boat",
|
||||
"minecraft:cherry_boat",
|
||||
"minecraft:cherry_chest_boat",
|
||||
"minecraft:dark_oak_boat",
|
||||
"minecraft:dark_oak_chest_boat",
|
||||
"minecraft:jungle_boat",
|
||||
"minecraft:jungle_chest_boat",
|
||||
"minecraft:mangrove_boat",
|
||||
"minecraft:mangrove_chest_boat",
|
||||
"minecraft:oak_boat",
|
||||
"minecraft:oak_chest_boat",
|
||||
"minecraft:pale_oak_boat",
|
||||
"minecraft:pale_oak_chest_boat",
|
||||
"minecraft:spruce_boat",
|
||||
"minecraft:spruce_chest_boat"
|
||||
],
|
||||
"minecraft:bookshelf_books": [
|
||||
"minecraft:book",
|
||||
"minecraft:enchanted_book",
|
||||
"minecraft:writable_book",
|
||||
"minecraft:written_book"
|
||||
],
|
||||
"minecraft:chainmail_tier": [
|
||||
"minecraft:chainmail_boots",
|
||||
"minecraft:chainmail_chestplate",
|
||||
"minecraft:chainmail_helmet",
|
||||
"minecraft:chainmail_leggings"
|
||||
],
|
||||
"minecraft:coals": [
|
||||
"minecraft:charcoal",
|
||||
"minecraft:coal"
|
||||
],
|
||||
"minecraft:crimson_stems": [
|
||||
"minecraft:crimson_hyphae",
|
||||
"minecraft:crimson_stem",
|
||||
"minecraft:stripped_crimson_hyphae",
|
||||
"minecraft:stripped_crimson_stem"
|
||||
],
|
||||
"minecraft:decorated_pot_sherds": [
|
||||
"minecraft:angler_pottery_sherd",
|
||||
"minecraft:archer_pottery_sherd",
|
||||
"minecraft:arms_up_pottery_sherd",
|
||||
"minecraft:blade_pottery_sherd",
|
||||
"minecraft:brewer_pottery_sherd",
|
||||
"minecraft:brick",
|
||||
"minecraft:burn_pottery_sherd",
|
||||
"minecraft:danger_pottery_sherd",
|
||||
"minecraft:explorer_pottery_sherd",
|
||||
"minecraft:flow_pottery_sherd",
|
||||
"minecraft:friend_pottery_sherd",
|
||||
"minecraft:guster_pottery_sherd",
|
||||
"minecraft:heart_pottery_sherd",
|
||||
"minecraft:heartbreak_pottery_sherd",
|
||||
"minecraft:howl_pottery_sherd",
|
||||
"minecraft:miner_pottery_sherd",
|
||||
"minecraft:mourner_pottery_sherd",
|
||||
"minecraft:plenty_pottery_sherd",
|
||||
"minecraft:prize_pottery_sherd",
|
||||
"minecraft:scrape_pottery_sherd",
|
||||
"minecraft:sheaf_pottery_sherd",
|
||||
"minecraft:shelter_pottery_sherd",
|
||||
"minecraft:skull_pottery_sherd",
|
||||
"minecraft:snort_pottery_sherd"
|
||||
],
|
||||
"minecraft:diamond_tier": [
|
||||
"minecraft:diamond_axe",
|
||||
"minecraft:diamond_boots",
|
||||
"minecraft:diamond_chestplate",
|
||||
"minecraft:diamond_helmet",
|
||||
"minecraft:diamond_hoe",
|
||||
"minecraft:diamond_leggings",
|
||||
"minecraft:diamond_pickaxe",
|
||||
"minecraft:diamond_shovel",
|
||||
"minecraft:diamond_sword",
|
||||
"minecraft:mace"
|
||||
],
|
||||
"minecraft:digger": [
|
||||
"minecraft:diamond_axe",
|
||||
"minecraft:diamond_hoe",
|
||||
"minecraft:diamond_pickaxe",
|
||||
"minecraft:diamond_shovel",
|
||||
"minecraft:golden_axe",
|
||||
"minecraft:golden_hoe",
|
||||
"minecraft:golden_pickaxe",
|
||||
"minecraft:golden_shovel",
|
||||
"minecraft:iron_axe",
|
||||
"minecraft:iron_hoe",
|
||||
"minecraft:iron_pickaxe",
|
||||
"minecraft:iron_shovel",
|
||||
"minecraft:netherite_axe",
|
||||
"minecraft:netherite_hoe",
|
||||
"minecraft:netherite_pickaxe",
|
||||
"minecraft:netherite_shovel",
|
||||
"minecraft:stone_axe",
|
||||
"minecraft:stone_hoe",
|
||||
"minecraft:stone_pickaxe",
|
||||
"minecraft:stone_shovel",
|
||||
"minecraft:wooden_axe",
|
||||
"minecraft:wooden_hoe",
|
||||
"minecraft:wooden_pickaxe",
|
||||
"minecraft:wooden_shovel"
|
||||
],
|
||||
"minecraft:door": [
|
||||
"minecraft:acacia_door",
|
||||
"minecraft:bamboo_door",
|
||||
"minecraft:birch_door",
|
||||
"minecraft:cherry_door",
|
||||
"minecraft:copper_door",
|
||||
"minecraft:crimson_door",
|
||||
"minecraft:dark_oak_door",
|
||||
"minecraft:exposed_copper_door",
|
||||
"minecraft:iron_door",
|
||||
"minecraft:jungle_door",
|
||||
"minecraft:mangrove_door",
|
||||
"minecraft:oxidized_copper_door",
|
||||
"minecraft:pale_oak_door",
|
||||
"minecraft:spruce_door",
|
||||
"minecraft:warped_door",
|
||||
"minecraft:waxed_copper_door",
|
||||
"minecraft:waxed_exposed_copper_door",
|
||||
"minecraft:waxed_oxidized_copper_door",
|
||||
"minecraft:waxed_weathered_copper_door",
|
||||
"minecraft:weathered_copper_door",
|
||||
"minecraft:wooden_door"
|
||||
],
|
||||
"minecraft:golden_tier": [
|
||||
"minecraft:golden_axe",
|
||||
"minecraft:golden_boots",
|
||||
"minecraft:golden_chestplate",
|
||||
"minecraft:golden_helmet",
|
||||
"minecraft:golden_hoe",
|
||||
"minecraft:golden_leggings",
|
||||
"minecraft:golden_pickaxe",
|
||||
"minecraft:golden_shovel",
|
||||
"minecraft:golden_sword"
|
||||
],
|
||||
"minecraft:hanging_actor": [
|
||||
"minecraft:painting"
|
||||
],
|
||||
"minecraft:hanging_sign": [
|
||||
"minecraft:acacia_hanging_sign",
|
||||
"minecraft:bamboo_hanging_sign",
|
||||
"minecraft:birch_hanging_sign",
|
||||
"minecraft:cherry_hanging_sign",
|
||||
"minecraft:crimson_hanging_sign",
|
||||
"minecraft:dark_oak_hanging_sign",
|
||||
"minecraft:jungle_hanging_sign",
|
||||
"minecraft:mangrove_hanging_sign",
|
||||
"minecraft:oak_hanging_sign",
|
||||
"minecraft:pale_oak_hanging_sign",
|
||||
"minecraft:spruce_hanging_sign",
|
||||
"minecraft:warped_hanging_sign"
|
||||
],
|
||||
"minecraft:horse_armor": [
|
||||
"minecraft:diamond_horse_armor",
|
||||
"minecraft:golden_horse_armor",
|
||||
"minecraft:iron_horse_armor",
|
||||
"minecraft:leather_horse_armor"
|
||||
],
|
||||
"minecraft:iron_tier": [
|
||||
"minecraft:iron_axe",
|
||||
"minecraft:iron_boots",
|
||||
"minecraft:iron_chestplate",
|
||||
"minecraft:iron_helmet",
|
||||
"minecraft:iron_hoe",
|
||||
"minecraft:iron_leggings",
|
||||
"minecraft:iron_pickaxe",
|
||||
"minecraft:iron_shovel",
|
||||
"minecraft:iron_sword"
|
||||
],
|
||||
"minecraft:is_armor": [
|
||||
"minecraft:chainmail_boots",
|
||||
"minecraft:chainmail_chestplate",
|
||||
"minecraft:chainmail_helmet",
|
||||
"minecraft:chainmail_leggings",
|
||||
"minecraft:diamond_boots",
|
||||
"minecraft:diamond_chestplate",
|
||||
"minecraft:diamond_helmet",
|
||||
"minecraft:diamond_leggings",
|
||||
"minecraft:elytra",
|
||||
"minecraft:golden_boots",
|
||||
"minecraft:golden_chestplate",
|
||||
"minecraft:golden_helmet",
|
||||
"minecraft:golden_leggings",
|
||||
"minecraft:iron_boots",
|
||||
"minecraft:iron_chestplate",
|
||||
"minecraft:iron_helmet",
|
||||
"minecraft:iron_leggings",
|
||||
"minecraft:leather_boots",
|
||||
"minecraft:leather_chestplate",
|
||||
"minecraft:leather_helmet",
|
||||
"minecraft:leather_leggings",
|
||||
"minecraft:netherite_boots",
|
||||
"minecraft:netherite_chestplate",
|
||||
"minecraft:netherite_helmet",
|
||||
"minecraft:netherite_leggings",
|
||||
"minecraft:turtle_helmet"
|
||||
],
|
||||
"minecraft:is_axe": [
|
||||
"minecraft:diamond_axe",
|
||||
"minecraft:golden_axe",
|
||||
"minecraft:iron_axe",
|
||||
"minecraft:netherite_axe",
|
||||
"minecraft:stone_axe",
|
||||
"minecraft:wooden_axe"
|
||||
],
|
||||
"minecraft:is_cooked": [
|
||||
"minecraft:cooked_beef",
|
||||
"minecraft:cooked_chicken",
|
||||
"minecraft:cooked_cod",
|
||||
"minecraft:cooked_mutton",
|
||||
"minecraft:cooked_porkchop",
|
||||
"minecraft:cooked_rabbit",
|
||||
"minecraft:cooked_salmon",
|
||||
"minecraft:rabbit_stew"
|
||||
],
|
||||
"minecraft:is_fish": [
|
||||
"minecraft:cod",
|
||||
"minecraft:cooked_cod",
|
||||
"minecraft:cooked_salmon",
|
||||
"minecraft:pufferfish",
|
||||
"minecraft:salmon",
|
||||
"minecraft:tropical_fish"
|
||||
],
|
||||
"minecraft:is_food": [
|
||||
"minecraft:apple",
|
||||
"minecraft:baked_potato",
|
||||
"minecraft:beef",
|
||||
"minecraft:beetroot",
|
||||
"minecraft:beetroot_soup",
|
||||
"minecraft:bread",
|
||||
"minecraft:carrot",
|
||||
"minecraft:chicken",
|
||||
"minecraft:cooked_beef",
|
||||
"minecraft:cooked_chicken",
|
||||
"minecraft:cooked_mutton",
|
||||
"minecraft:cooked_porkchop",
|
||||
"minecraft:cooked_rabbit",
|
||||
"minecraft:cookie",
|
||||
"minecraft:dried_kelp",
|
||||
"minecraft:enchanted_golden_apple",
|
||||
"minecraft:golden_apple",
|
||||
"minecraft:golden_carrot",
|
||||
"minecraft:melon_slice",
|
||||
"minecraft:mushroom_stew",
|
||||
"minecraft:mutton",
|
||||
"minecraft:porkchop",
|
||||
"minecraft:potato",
|
||||
"minecraft:pumpkin_pie",
|
||||
"minecraft:rabbit",
|
||||
"minecraft:rabbit_stew",
|
||||
"minecraft:rotten_flesh",
|
||||
"minecraft:sweet_berries"
|
||||
],
|
||||
"minecraft:is_hoe": [
|
||||
"minecraft:diamond_hoe",
|
||||
"minecraft:golden_hoe",
|
||||
"minecraft:iron_hoe",
|
||||
"minecraft:netherite_hoe",
|
||||
"minecraft:stone_hoe",
|
||||
"minecraft:wooden_hoe"
|
||||
],
|
||||
"minecraft:is_meat": [
|
||||
"minecraft:beef",
|
||||
"minecraft:chicken",
|
||||
"minecraft:cooked_beef",
|
||||
"minecraft:cooked_chicken",
|
||||
"minecraft:cooked_mutton",
|
||||
"minecraft:cooked_porkchop",
|
||||
"minecraft:cooked_rabbit",
|
||||
"minecraft:mutton",
|
||||
"minecraft:porkchop",
|
||||
"minecraft:rabbit",
|
||||
"minecraft:rabbit_stew",
|
||||
"minecraft:rotten_flesh"
|
||||
],
|
||||
"minecraft:is_minecart": [
|
||||
"minecraft:chest_minecart",
|
||||
"minecraft:command_block_minecart",
|
||||
"minecraft:hopper_minecart",
|
||||
"minecraft:minecart",
|
||||
"minecraft:tnt_minecart"
|
||||
],
|
||||
"minecraft:is_pickaxe": [
|
||||
"minecraft:diamond_pickaxe",
|
||||
"minecraft:golden_pickaxe",
|
||||
"minecraft:iron_pickaxe",
|
||||
"minecraft:netherite_pickaxe",
|
||||
"minecraft:stone_pickaxe",
|
||||
"minecraft:wooden_pickaxe"
|
||||
],
|
||||
"minecraft:is_shears": [
|
||||
"minecraft:shears"
|
||||
],
|
||||
"minecraft:is_shovel": [
|
||||
"minecraft:diamond_shovel",
|
||||
"minecraft:golden_shovel",
|
||||
"minecraft:iron_shovel",
|
||||
"minecraft:netherite_shovel",
|
||||
"minecraft:stone_shovel",
|
||||
"minecraft:wooden_shovel"
|
||||
],
|
||||
"minecraft:is_sword": [
|
||||
"minecraft:diamond_sword",
|
||||
"minecraft:golden_sword",
|
||||
"minecraft:iron_sword",
|
||||
"minecraft:mace",
|
||||
"minecraft:netherite_sword",
|
||||
"minecraft:stone_sword",
|
||||
"minecraft:wooden_sword"
|
||||
],
|
||||
"minecraft:is_tool": [
|
||||
"minecraft:diamond_axe",
|
||||
"minecraft:diamond_hoe",
|
||||
"minecraft:diamond_pickaxe",
|
||||
"minecraft:diamond_shovel",
|
||||
"minecraft:diamond_sword",
|
||||
"minecraft:golden_axe",
|
||||
"minecraft:golden_hoe",
|
||||
"minecraft:golden_pickaxe",
|
||||
"minecraft:golden_shovel",
|
||||
"minecraft:golden_sword",
|
||||
"minecraft:iron_axe",
|
||||
"minecraft:iron_hoe",
|
||||
"minecraft:iron_pickaxe",
|
||||
"minecraft:iron_shovel",
|
||||
"minecraft:iron_sword",
|
||||
"minecraft:mace",
|
||||
"minecraft:netherite_axe",
|
||||
"minecraft:netherite_hoe",
|
||||
"minecraft:netherite_pickaxe",
|
||||
"minecraft:netherite_shovel",
|
||||
"minecraft:netherite_sword",
|
||||
"minecraft:stone_axe",
|
||||
"minecraft:stone_hoe",
|
||||
"minecraft:stone_pickaxe",
|
||||
"minecraft:stone_shovel",
|
||||
"minecraft:stone_sword",
|
||||
"minecraft:wooden_axe",
|
||||
"minecraft:wooden_hoe",
|
||||
"minecraft:wooden_pickaxe",
|
||||
"minecraft:wooden_shovel",
|
||||
"minecraft:wooden_sword"
|
||||
],
|
||||
"minecraft:is_trident": [
|
||||
"minecraft:trident"
|
||||
],
|
||||
"minecraft:leather_tier": [
|
||||
"minecraft:leather_boots",
|
||||
"minecraft:leather_chestplate",
|
||||
"minecraft:leather_helmet",
|
||||
"minecraft:leather_leggings"
|
||||
],
|
||||
"minecraft:lectern_books": [
|
||||
"minecraft:writable_book",
|
||||
"minecraft:written_book"
|
||||
],
|
||||
"minecraft:logs": [
|
||||
"minecraft:acacia_log",
|
||||
"minecraft:acacia_wood",
|
||||
"minecraft:birch_log",
|
||||
"minecraft:birch_wood",
|
||||
"minecraft:cherry_log",
|
||||
"minecraft:cherry_wood",
|
||||
"minecraft:crimson_hyphae",
|
||||
"minecraft:crimson_stem",
|
||||
"minecraft:dark_oak_log",
|
||||
"minecraft:dark_oak_wood",
|
||||
"minecraft:jungle_log",
|
||||
"minecraft:jungle_wood",
|
||||
"minecraft:mangrove_log",
|
||||
"minecraft:mangrove_wood",
|
||||
"minecraft:oak_log",
|
||||
"minecraft:oak_wood",
|
||||
"minecraft:pale_oak_log",
|
||||
"minecraft:pale_oak_wood",
|
||||
"minecraft:spruce_log",
|
||||
"minecraft:spruce_wood",
|
||||
"minecraft:stripped_acacia_log",
|
||||
"minecraft:stripped_acacia_wood",
|
||||
"minecraft:stripped_birch_log",
|
||||
"minecraft:stripped_birch_wood",
|
||||
"minecraft:stripped_cherry_log",
|
||||
"minecraft:stripped_cherry_wood",
|
||||
"minecraft:stripped_crimson_hyphae",
|
||||
"minecraft:stripped_crimson_stem",
|
||||
"minecraft:stripped_dark_oak_log",
|
||||
"minecraft:stripped_dark_oak_wood",
|
||||
"minecraft:stripped_jungle_log",
|
||||
"minecraft:stripped_jungle_wood",
|
||||
"minecraft:stripped_mangrove_log",
|
||||
"minecraft:stripped_mangrove_wood",
|
||||
"minecraft:stripped_oak_log",
|
||||
"minecraft:stripped_oak_wood",
|
||||
"minecraft:stripped_pale_oak_log",
|
||||
"minecraft:stripped_pale_oak_wood",
|
||||
"minecraft:stripped_spruce_log",
|
||||
"minecraft:stripped_spruce_wood",
|
||||
"minecraft:stripped_warped_hyphae",
|
||||
"minecraft:stripped_warped_stem",
|
||||
"minecraft:warped_hyphae",
|
||||
"minecraft:warped_stem"
|
||||
],
|
||||
"minecraft:logs_that_burn": [
|
||||
"minecraft:acacia_log",
|
||||
"minecraft:acacia_wood",
|
||||
"minecraft:birch_log",
|
||||
"minecraft:birch_wood",
|
||||
"minecraft:cherry_log",
|
||||
"minecraft:cherry_wood",
|
||||
"minecraft:dark_oak_log",
|
||||
"minecraft:dark_oak_wood",
|
||||
"minecraft:jungle_log",
|
||||
"minecraft:jungle_wood",
|
||||
"minecraft:mangrove_log",
|
||||
"minecraft:mangrove_wood",
|
||||
"minecraft:oak_log",
|
||||
"minecraft:oak_wood",
|
||||
"minecraft:pale_oak_log",
|
||||
"minecraft:pale_oak_wood",
|
||||
"minecraft:spruce_log",
|
||||
"minecraft:spruce_wood",
|
||||
"minecraft:stripped_acacia_log",
|
||||
"minecraft:stripped_acacia_wood",
|
||||
"minecraft:stripped_birch_log",
|
||||
"minecraft:stripped_birch_wood",
|
||||
"minecraft:stripped_cherry_log",
|
||||
"minecraft:stripped_cherry_wood",
|
||||
"minecraft:stripped_dark_oak_log",
|
||||
"minecraft:stripped_dark_oak_wood",
|
||||
"minecraft:stripped_jungle_log",
|
||||
"minecraft:stripped_jungle_wood",
|
||||
"minecraft:stripped_mangrove_log",
|
||||
"minecraft:stripped_mangrove_wood",
|
||||
"minecraft:stripped_oak_log",
|
||||
"minecraft:stripped_oak_wood",
|
||||
"minecraft:stripped_pale_oak_log",
|
||||
"minecraft:stripped_pale_oak_wood",
|
||||
"minecraft:stripped_spruce_log",
|
||||
"minecraft:stripped_spruce_wood"
|
||||
],
|
||||
"minecraft:mangrove_logs": [
|
||||
"minecraft:mangrove_log",
|
||||
"minecraft:mangrove_wood",
|
||||
"minecraft:stripped_mangrove_log",
|
||||
"minecraft:stripped_mangrove_wood"
|
||||
],
|
||||
"minecraft:music_disc": [
|
||||
"minecraft:music_disc_11",
|
||||
"minecraft:music_disc_13",
|
||||
"minecraft:music_disc_5",
|
||||
"minecraft:music_disc_blocks",
|
||||
"minecraft:music_disc_cat",
|
||||
"minecraft:music_disc_chirp",
|
||||
"minecraft:music_disc_creator",
|
||||
"minecraft:music_disc_creator_music_box",
|
||||
"minecraft:music_disc_far",
|
||||
"minecraft:music_disc_mall",
|
||||
"minecraft:music_disc_mellohi",
|
||||
"minecraft:music_disc_otherside",
|
||||
"minecraft:music_disc_pigstep",
|
||||
"minecraft:music_disc_precipice",
|
||||
"minecraft:music_disc_relic",
|
||||
"minecraft:music_disc_stal",
|
||||
"minecraft:music_disc_strad",
|
||||
"minecraft:music_disc_wait",
|
||||
"minecraft:music_disc_ward"
|
||||
],
|
||||
"minecraft:netherite_tier": [
|
||||
"minecraft:netherite_axe",
|
||||
"minecraft:netherite_boots",
|
||||
"minecraft:netherite_chestplate",
|
||||
"minecraft:netherite_helmet",
|
||||
"minecraft:netherite_hoe",
|
||||
"minecraft:netherite_leggings",
|
||||
"minecraft:netherite_pickaxe",
|
||||
"minecraft:netherite_shovel",
|
||||
"minecraft:netherite_sword"
|
||||
],
|
||||
"minecraft:planks": [
|
||||
"minecraft:acacia_planks",
|
||||
"minecraft:bamboo_planks",
|
||||
"minecraft:birch_planks",
|
||||
"minecraft:cherry_planks",
|
||||
"minecraft:crimson_planks",
|
||||
"minecraft:dark_oak_planks",
|
||||
"minecraft:jungle_planks",
|
||||
"minecraft:mangrove_planks",
|
||||
"minecraft:oak_planks",
|
||||
"minecraft:pale_oak_planks",
|
||||
"minecraft:spruce_planks",
|
||||
"minecraft:warped_planks"
|
||||
],
|
||||
"minecraft:sand": [
|
||||
"minecraft:red_sand",
|
||||
"minecraft:sand"
|
||||
],
|
||||
"minecraft:sign": [
|
||||
"minecraft:acacia_hanging_sign",
|
||||
"minecraft:acacia_sign",
|
||||
"minecraft:bamboo_hanging_sign",
|
||||
"minecraft:bamboo_sign",
|
||||
"minecraft:birch_hanging_sign",
|
||||
"minecraft:birch_sign",
|
||||
"minecraft:cherry_hanging_sign",
|
||||
"minecraft:cherry_sign",
|
||||
"minecraft:crimson_hanging_sign",
|
||||
"minecraft:crimson_sign",
|
||||
"minecraft:dark_oak_hanging_sign",
|
||||
"minecraft:dark_oak_sign",
|
||||
"minecraft:jungle_hanging_sign",
|
||||
"minecraft:jungle_sign",
|
||||
"minecraft:mangrove_hanging_sign",
|
||||
"minecraft:mangrove_sign",
|
||||
"minecraft:oak_hanging_sign",
|
||||
"minecraft:oak_sign",
|
||||
"minecraft:pale_oak_hanging_sign",
|
||||
"minecraft:pale_oak_sign",
|
||||
"minecraft:spruce_hanging_sign",
|
||||
"minecraft:spruce_sign",
|
||||
"minecraft:warped_hanging_sign",
|
||||
"minecraft:warped_sign"
|
||||
],
|
||||
"minecraft:soul_fire_base_blocks": [
|
||||
"minecraft:soul_sand",
|
||||
"minecraft:soul_soil"
|
||||
],
|
||||
"minecraft:spawn_egg": [
|
||||
"minecraft:agent_spawn_egg",
|
||||
"minecraft:allay_spawn_egg",
|
||||
"minecraft:armadillo_spawn_egg",
|
||||
"minecraft:axolotl_spawn_egg",
|
||||
"minecraft:bat_spawn_egg",
|
||||
"minecraft:bee_spawn_egg",
|
||||
"minecraft:blaze_spawn_egg",
|
||||
"minecraft:bogged_spawn_egg",
|
||||
"minecraft:breeze_spawn_egg",
|
||||
"minecraft:camel_spawn_egg",
|
||||
"minecraft:cat_spawn_egg",
|
||||
"minecraft:cave_spider_spawn_egg",
|
||||
"minecraft:chicken_spawn_egg",
|
||||
"minecraft:cod_spawn_egg",
|
||||
"minecraft:cow_spawn_egg",
|
||||
"minecraft:creaking_spawn_egg",
|
||||
"minecraft:creeper_spawn_egg",
|
||||
"minecraft:dolphin_spawn_egg",
|
||||
"minecraft:donkey_spawn_egg",
|
||||
"minecraft:drowned_spawn_egg",
|
||||
"minecraft:elder_guardian_spawn_egg",
|
||||
"minecraft:ender_dragon_spawn_egg",
|
||||
"minecraft:enderman_spawn_egg",
|
||||
"minecraft:endermite_spawn_egg",
|
||||
"minecraft:evoker_spawn_egg",
|
||||
"minecraft:fox_spawn_egg",
|
||||
"minecraft:frog_spawn_egg",
|
||||
"minecraft:ghast_spawn_egg",
|
||||
"minecraft:glow_squid_spawn_egg",
|
||||
"minecraft:goat_spawn_egg",
|
||||
"minecraft:guardian_spawn_egg",
|
||||
"minecraft:hoglin_spawn_egg",
|
||||
"minecraft:horse_spawn_egg",
|
||||
"minecraft:husk_spawn_egg",
|
||||
"minecraft:iron_golem_spawn_egg",
|
||||
"minecraft:llama_spawn_egg",
|
||||
"minecraft:magma_cube_spawn_egg",
|
||||
"minecraft:mooshroom_spawn_egg",
|
||||
"minecraft:mule_spawn_egg",
|
||||
"minecraft:npc_spawn_egg",
|
||||
"minecraft:ocelot_spawn_egg",
|
||||
"minecraft:panda_spawn_egg",
|
||||
"minecraft:parrot_spawn_egg",
|
||||
"minecraft:phantom_spawn_egg",
|
||||
"minecraft:pig_spawn_egg",
|
||||
"minecraft:piglin_brute_spawn_egg",
|
||||
"minecraft:piglin_spawn_egg",
|
||||
"minecraft:pillager_spawn_egg",
|
||||
"minecraft:polar_bear_spawn_egg",
|
||||
"minecraft:pufferfish_spawn_egg",
|
||||
"minecraft:rabbit_spawn_egg",
|
||||
"minecraft:ravager_spawn_egg",
|
||||
"minecraft:salmon_spawn_egg",
|
||||
"minecraft:sheep_spawn_egg",
|
||||
"minecraft:shulker_spawn_egg",
|
||||
"minecraft:silverfish_spawn_egg",
|
||||
"minecraft:skeleton_horse_spawn_egg",
|
||||
"minecraft:skeleton_spawn_egg",
|
||||
"minecraft:slime_spawn_egg",
|
||||
"minecraft:sniffer_spawn_egg",
|
||||
"minecraft:snow_golem_spawn_egg",
|
||||
"minecraft:spawn_egg",
|
||||
"minecraft:spider_spawn_egg",
|
||||
"minecraft:squid_spawn_egg",
|
||||
"minecraft:stray_spawn_egg",
|
||||
"minecraft:strider_spawn_egg",
|
||||
"minecraft:tadpole_spawn_egg",
|
||||
"minecraft:trader_llama_spawn_egg",
|
||||
"minecraft:tropical_fish_spawn_egg",
|
||||
"minecraft:turtle_spawn_egg",
|
||||
"minecraft:vex_spawn_egg",
|
||||
"minecraft:villager_spawn_egg",
|
||||
"minecraft:vindicator_spawn_egg",
|
||||
"minecraft:wandering_trader_spawn_egg",
|
||||
"minecraft:warden_spawn_egg",
|
||||
"minecraft:witch_spawn_egg",
|
||||
"minecraft:wither_skeleton_spawn_egg",
|
||||
"minecraft:wither_spawn_egg",
|
||||
"minecraft:wolf_spawn_egg",
|
||||
"minecraft:zoglin_spawn_egg",
|
||||
"minecraft:zombie_horse_spawn_egg",
|
||||
"minecraft:zombie_pigman_spawn_egg",
|
||||
"minecraft:zombie_spawn_egg",
|
||||
"minecraft:zombie_villager_spawn_egg"
|
||||
],
|
||||
"minecraft:stone_bricks": [
|
||||
"minecraft:chiseled_stone_bricks",
|
||||
"minecraft:cracked_stone_bricks",
|
||||
"minecraft:mossy_stone_bricks",
|
||||
"minecraft:stone_bricks"
|
||||
],
|
||||
"minecraft:stone_crafting_materials": [
|
||||
"minecraft:blackstone",
|
||||
"minecraft:cobbled_deepslate",
|
||||
"minecraft:cobblestone"
|
||||
],
|
||||
"minecraft:stone_tier": [
|
||||
"minecraft:stone_axe",
|
||||
"minecraft:stone_hoe",
|
||||
"minecraft:stone_pickaxe",
|
||||
"minecraft:stone_shovel",
|
||||
"minecraft:stone_sword"
|
||||
],
|
||||
"minecraft:stone_tool_materials": [
|
||||
"minecraft:blackstone",
|
||||
"minecraft:cobbled_deepslate",
|
||||
"minecraft:cobblestone"
|
||||
],
|
||||
"minecraft:transform_materials": [
|
||||
"minecraft:netherite_ingot"
|
||||
],
|
||||
"minecraft:transform_templates": [
|
||||
"minecraft:netherite_upgrade_smithing_template"
|
||||
],
|
||||
"minecraft:transformable_items": [
|
||||
"minecraft:diamond_axe",
|
||||
"minecraft:diamond_boots",
|
||||
"minecraft:diamond_chestplate",
|
||||
"minecraft:diamond_helmet",
|
||||
"minecraft:diamond_hoe",
|
||||
"minecraft:diamond_leggings",
|
||||
"minecraft:diamond_pickaxe",
|
||||
"minecraft:diamond_shovel",
|
||||
"minecraft:diamond_sword",
|
||||
"minecraft:golden_boots"
|
||||
],
|
||||
"minecraft:trim_materials": [
|
||||
"minecraft:amethyst_shard",
|
||||
"minecraft:copper_ingot",
|
||||
"minecraft:diamond",
|
||||
"minecraft:emerald",
|
||||
"minecraft:gold_ingot",
|
||||
"minecraft:iron_ingot",
|
||||
"minecraft:lapis_lazuli",
|
||||
"minecraft:netherite_ingot",
|
||||
"minecraft:quartz",
|
||||
"minecraft:redstone",
|
||||
"minecraft:resin_brick"
|
||||
],
|
||||
"minecraft:trim_templates": [
|
||||
"minecraft:bolt_armor_trim_smithing_template",
|
||||
"minecraft:coast_armor_trim_smithing_template",
|
||||
"minecraft:dune_armor_trim_smithing_template",
|
||||
"minecraft:eye_armor_trim_smithing_template",
|
||||
"minecraft:flow_armor_trim_smithing_template",
|
||||
"minecraft:host_armor_trim_smithing_template",
|
||||
"minecraft:raiser_armor_trim_smithing_template",
|
||||
"minecraft:rib_armor_trim_smithing_template",
|
||||
"minecraft:sentry_armor_trim_smithing_template",
|
||||
"minecraft:shaper_armor_trim_smithing_template",
|
||||
"minecraft:silence_armor_trim_smithing_template",
|
||||
"minecraft:snout_armor_trim_smithing_template",
|
||||
"minecraft:spire_armor_trim_smithing_template",
|
||||
"minecraft:tide_armor_trim_smithing_template",
|
||||
"minecraft:vex_armor_trim_smithing_template",
|
||||
"minecraft:ward_armor_trim_smithing_template",
|
||||
"minecraft:wayfinder_armor_trim_smithing_template",
|
||||
"minecraft:wild_armor_trim_smithing_template"
|
||||
],
|
||||
"minecraft:trimmable_armors": [
|
||||
"minecraft:chainmail_boots",
|
||||
"minecraft:chainmail_chestplate",
|
||||
"minecraft:chainmail_helmet",
|
||||
"minecraft:chainmail_leggings",
|
||||
"minecraft:diamond_boots",
|
||||
"minecraft:diamond_chestplate",
|
||||
"minecraft:diamond_helmet",
|
||||
"minecraft:diamond_leggings",
|
||||
"minecraft:golden_boots",
|
||||
"minecraft:golden_chestplate",
|
||||
"minecraft:golden_helmet",
|
||||
"minecraft:golden_leggings",
|
||||
"minecraft:iron_boots",
|
||||
"minecraft:iron_chestplate",
|
||||
"minecraft:iron_helmet",
|
||||
"minecraft:iron_leggings",
|
||||
"minecraft:leather_boots",
|
||||
"minecraft:leather_chestplate",
|
||||
"minecraft:leather_helmet",
|
||||
"minecraft:leather_leggings",
|
||||
"minecraft:netherite_boots",
|
||||
"minecraft:netherite_chestplate",
|
||||
"minecraft:netherite_helmet",
|
||||
"minecraft:netherite_leggings",
|
||||
"minecraft:turtle_helmet"
|
||||
],
|
||||
"minecraft:vibration_damper": [
|
||||
"minecraft:black_carpet",
|
||||
"minecraft:black_wool",
|
||||
"minecraft:blue_carpet",
|
||||
"minecraft:blue_wool",
|
||||
"minecraft:brown_carpet",
|
||||
"minecraft:brown_wool",
|
||||
"minecraft:cyan_carpet",
|
||||
"minecraft:cyan_wool",
|
||||
"minecraft:gray_carpet",
|
||||
"minecraft:gray_wool",
|
||||
"minecraft:green_carpet",
|
||||
"minecraft:green_wool",
|
||||
"minecraft:light_blue_carpet",
|
||||
"minecraft:light_blue_wool",
|
||||
"minecraft:light_gray_carpet",
|
||||
"minecraft:light_gray_wool",
|
||||
"minecraft:lime_carpet",
|
||||
"minecraft:lime_wool",
|
||||
"minecraft:magenta_carpet",
|
||||
"minecraft:magenta_wool",
|
||||
"minecraft:orange_carpet",
|
||||
"minecraft:orange_wool",
|
||||
"minecraft:pink_carpet",
|
||||
"minecraft:pink_wool",
|
||||
"minecraft:purple_carpet",
|
||||
"minecraft:purple_wool",
|
||||
"minecraft:red_carpet",
|
||||
"minecraft:red_wool",
|
||||
"minecraft:white_carpet",
|
||||
"minecraft:white_wool",
|
||||
"minecraft:yellow_carpet",
|
||||
"minecraft:yellow_wool"
|
||||
],
|
||||
"minecraft:warped_stems": [
|
||||
"minecraft:stripped_warped_hyphae",
|
||||
"minecraft:stripped_warped_stem",
|
||||
"minecraft:warped_hyphae",
|
||||
"minecraft:warped_stem"
|
||||
],
|
||||
"minecraft:wooden_slabs": [
|
||||
"minecraft:acacia_slab",
|
||||
"minecraft:bamboo_slab",
|
||||
"minecraft:birch_slab",
|
||||
"minecraft:cherry_slab",
|
||||
"minecraft:crimson_slab",
|
||||
"minecraft:dark_oak_slab",
|
||||
"minecraft:jungle_slab",
|
||||
"minecraft:mangrove_slab",
|
||||
"minecraft:oak_slab",
|
||||
"minecraft:pale_oak_slab",
|
||||
"minecraft:spruce_slab",
|
||||
"minecraft:warped_slab"
|
||||
],
|
||||
"minecraft:wooden_tier": [
|
||||
"minecraft:wooden_axe",
|
||||
"minecraft:wooden_hoe",
|
||||
"minecraft:wooden_pickaxe",
|
||||
"minecraft:wooden_shovel",
|
||||
"minecraft:wooden_sword"
|
||||
],
|
||||
"minecraft:wool": [
|
||||
"minecraft:black_wool",
|
||||
"minecraft:blue_wool",
|
||||
"minecraft:brown_wool",
|
||||
"minecraft:cyan_wool",
|
||||
"minecraft:gray_wool",
|
||||
"minecraft:green_wool",
|
||||
"minecraft:light_blue_wool",
|
||||
"minecraft:light_gray_wool",
|
||||
"minecraft:lime_wool",
|
||||
"minecraft:magenta_wool",
|
||||
"minecraft:orange_wool",
|
||||
"minecraft:pink_wool",
|
||||
"minecraft:purple_wool",
|
||||
"minecraft:red_wool",
|
||||
"minecraft:white_wool",
|
||||
"minecraft:yellow_wool"
|
||||
]
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,163 @@
|
||||
package recipe
|
||||
|
||||
import (
|
||||
"github.com/df-mc/dragonfly/server/item"
|
||||
"github.com/df-mc/dragonfly/server/world"
|
||||
)
|
||||
|
||||
// Recipe is implemented by all recipe types.
|
||||
type Recipe interface {
|
||||
// Input returns the items required to craft the recipe.
|
||||
Input() []Item
|
||||
// Output returns the items that are produced when the recipe is crafted.
|
||||
Output() []item.Stack
|
||||
// Block returns the block that is used to craft the recipe.
|
||||
Block() string
|
||||
// Priority returns the priority of the recipe. Recipes with lower priority are preferred compared to recipes with
|
||||
// higher priority.
|
||||
Priority() uint32
|
||||
}
|
||||
|
||||
// DynamicRecipe represents a recipe whose output depends on the specific items used in crafting.
|
||||
// These recipes are not sent to the client and are validated server-side.
|
||||
type DynamicRecipe interface {
|
||||
// Match checks if the given input items match this dynamic recipe pattern.
|
||||
// It returns true if the pattern matches, along with the computed output items.
|
||||
Match(input []Item) (output []item.Stack, ok bool)
|
||||
// Block returns the block that is used to craft the recipe.
|
||||
Block() string
|
||||
}
|
||||
|
||||
// Shapeless is a recipe that has no particular shape.
|
||||
type Shapeless struct {
|
||||
recipe
|
||||
}
|
||||
|
||||
// NewShapeless creates a new shapeless recipe and returns it. The recipe can only be crafted on the block passed in the
|
||||
// parameters. If the block given a crafting table, the recipe can also be crafted in the 2x2 crafting grid in the
|
||||
// player's inventory.
|
||||
func NewShapeless(input []Item, output item.Stack, block string) Shapeless {
|
||||
return Shapeless{recipe: recipe{
|
||||
input: input,
|
||||
output: []item.Stack{output},
|
||||
block: block,
|
||||
}}
|
||||
}
|
||||
|
||||
// SmithingTransform represents a recipe only craftable on a smithing table.
|
||||
type SmithingTransform struct {
|
||||
recipe
|
||||
}
|
||||
|
||||
// NewSmithingTransform creates a new smithing recipe and returns it.
|
||||
func NewSmithingTransform(base, addition, template Item, output item.Stack, block string) SmithingTransform {
|
||||
return SmithingTransform{recipe: recipe{
|
||||
input: []Item{base, addition, template},
|
||||
output: []item.Stack{output},
|
||||
block: block,
|
||||
}}
|
||||
}
|
||||
|
||||
// SmithingTrim represents a recipe only craftable on a smithing table using an armour trim.
|
||||
type SmithingTrim struct {
|
||||
recipe
|
||||
}
|
||||
|
||||
// NewSmithingTrim creates a new smithing trim recipe and returns it. This is
|
||||
// almost identical to SmithingTransform except there is no output item.
|
||||
func NewSmithingTrim(base, addition, template Item, block string) SmithingTrim {
|
||||
return SmithingTrim{recipe: recipe{
|
||||
input: []Item{base, addition, template},
|
||||
block: block,
|
||||
}}
|
||||
}
|
||||
|
||||
// PotionContainerChange is a recipe to convert a potion from one type to another, such as from a drinkable potion to a
|
||||
// splash potion, or from a splash potion to a lingering potion.
|
||||
type PotionContainerChange struct {
|
||||
recipe
|
||||
}
|
||||
|
||||
// NewPotionContainerChange creates a new potion container change recipe and returns it.
|
||||
func NewPotionContainerChange(input, output world.Item, reagent item.Stack) PotionContainerChange {
|
||||
return PotionContainerChange{recipe: recipe{
|
||||
input: []Item{item.NewStack(input, 1), reagent},
|
||||
output: []item.Stack{item.NewStack(output, 1)},
|
||||
block: "brewing_stand",
|
||||
}}
|
||||
}
|
||||
|
||||
// Potion is a potion mixing recipe which may be used in the brewing stand.
|
||||
type Potion struct {
|
||||
recipe
|
||||
}
|
||||
|
||||
// NewPotion creates a new potion recipe and returns it.
|
||||
func NewPotion(input, reagent Item, output item.Stack) Potion {
|
||||
return Potion{recipe: recipe{
|
||||
input: []Item{input, reagent},
|
||||
output: []item.Stack{output},
|
||||
block: "brewing_stand",
|
||||
}}
|
||||
}
|
||||
|
||||
// Shaped is a recipe that has a specific shape that must be used to craft the output of the recipe.
|
||||
type Shaped struct {
|
||||
recipe
|
||||
// shape contains the width and height of the shaped recipe.
|
||||
shape Shape
|
||||
}
|
||||
|
||||
// NewShaped creates a new shaped recipe and returns it. The recipe can only be crafted on the block passed in the
|
||||
// parameters. If the block given a crafting table, the recipe can also be crafted in the 2x2 crafting grid in the
|
||||
// player's inventory. If nil is passed, the block will be autofilled as a crafting table. The inputs must always match
|
||||
// the width*height of the shape.
|
||||
func NewShaped(input []Item, output item.Stack, shape Shape, block string) Shaped {
|
||||
return Shaped{
|
||||
shape: shape,
|
||||
recipe: recipe{
|
||||
input: input,
|
||||
output: []item.Stack{output},
|
||||
block: block,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Shape returns the shape of the recipe.
|
||||
func (r Shaped) Shape() Shape {
|
||||
return r.shape
|
||||
}
|
||||
|
||||
// recipe implements the Recipe interface. Structs in this package may embed it to gets its functionality
|
||||
// out of the box.
|
||||
type recipe struct {
|
||||
// input is a list of items that serve as the input of the shaped recipe. These items are the items
|
||||
// required to craft the output. The amount of input items must be exactly equal to Width * Height.
|
||||
input []Item
|
||||
// output contains items that are created as a result of crafting the recipe.
|
||||
output []item.Stack
|
||||
// block is the block that is used to craft the recipe.
|
||||
block string
|
||||
// priority is the priority of the recipe versus others.
|
||||
priority uint32
|
||||
}
|
||||
|
||||
// Input ...
|
||||
func (r recipe) Input() []Item {
|
||||
return r.input
|
||||
}
|
||||
|
||||
// Output ...
|
||||
func (r recipe) Output() []item.Stack {
|
||||
return r.output
|
||||
}
|
||||
|
||||
// Block ...
|
||||
func (r recipe) Block() string {
|
||||
return r.block
|
||||
}
|
||||
|
||||
// Priority ...
|
||||
func (r recipe) Priority() uint32 {
|
||||
return r.priority
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
package recipe
|
||||
|
||||
import (
|
||||
"github.com/df-mc/dragonfly/server/internal/sliceutil"
|
||||
"github.com/df-mc/dragonfly/server/item"
|
||||
"github.com/df-mc/dragonfly/server/world"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// recipes is a list of each recipe.
|
||||
var (
|
||||
recipes []Recipe
|
||||
// dynamicRecipes is a list of each dynamic recipe.
|
||||
dynamicRecipes []DynamicRecipe
|
||||
// index maps an input hash to output stacks for each PotionContainerChange and Potion recipe.
|
||||
index = make(map[string]map[string]Recipe)
|
||||
// reagent maps the item name and an item.Stack.
|
||||
reagent = make(map[string]item.Stack)
|
||||
)
|
||||
|
||||
// Recipes returns each recipe in a slice.
|
||||
func Recipes() []Recipe {
|
||||
return slices.Clone(recipes)
|
||||
}
|
||||
|
||||
// DynamicRecipes returns each dynamic recipe in a slice.
|
||||
func DynamicRecipes() []DynamicRecipe {
|
||||
return slices.Clone(dynamicRecipes)
|
||||
}
|
||||
|
||||
// Register registers a new recipe.
|
||||
func Register(recipe Recipe) {
|
||||
recipes = append(recipes, recipe)
|
||||
|
||||
_, ok := recipe.(PotionContainerChange)
|
||||
p, okTwo := recipe.(Potion)
|
||||
|
||||
if okTwo {
|
||||
stack := p.Input()[1].(item.Stack)
|
||||
name, _ := stack.Item().EncodeItem()
|
||||
reagent[name] = stack
|
||||
}
|
||||
|
||||
if ok || okTwo {
|
||||
input := make([]world.Item, len(recipe.Input()))
|
||||
for i, stack := range recipe.Input() {
|
||||
if s, ok := stack.(item.Stack); ok {
|
||||
input[i] = s.Item()
|
||||
}
|
||||
}
|
||||
hash := hashItems(input, !ok)
|
||||
|
||||
block := recipe.Block()
|
||||
if index[block] == nil {
|
||||
index[block] = make(map[string]Recipe)
|
||||
}
|
||||
index[block][hash] = recipe
|
||||
}
|
||||
}
|
||||
|
||||
// Perform performs the recipe with the given block and inputs and returns the outputs. If the inputs do not map to
|
||||
// any outputs, false is returned for the second return value.
|
||||
func Perform(block string, input ...world.Item) (output []item.Stack, ok bool) {
|
||||
blockInd, ok := index[block]
|
||||
if !ok {
|
||||
// Block specific index didn't exist.
|
||||
return nil, false
|
||||
}
|
||||
r, ok := blockInd[hashItems(input, true)]
|
||||
if !ok {
|
||||
r, ok = blockInd[hashItems(input, false)]
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
_, containerChange := r.(PotionContainerChange)
|
||||
for ind, it := range r.Output() {
|
||||
if containerChange {
|
||||
name, _ := it.Item().EncodeItem()
|
||||
_, meta := input[ind].EncodeItem()
|
||||
if i, ok := world.ItemByName(name, meta); ok {
|
||||
it = item.NewStack(i, it.Count())
|
||||
}
|
||||
}
|
||||
output = append(output, it)
|
||||
}
|
||||
return output, ok
|
||||
}
|
||||
|
||||
// hashItems hashes the given list of item types and returns it.
|
||||
func hashItems(items []world.Item, useMeta bool) string {
|
||||
items = sliceutil.Filter(items, func(it world.Item) bool {
|
||||
return it != nil
|
||||
})
|
||||
sort.Slice(items, func(i, j int) bool {
|
||||
nameOne, metaOne := items[i].EncodeItem()
|
||||
nameTwo, metaTwo := items[j].EncodeItem()
|
||||
if nameOne == nameTwo {
|
||||
return metaOne < metaTwo
|
||||
}
|
||||
return nameOne < nameTwo
|
||||
})
|
||||
|
||||
var b strings.Builder
|
||||
for _, it := range items {
|
||||
name, meta := it.EncodeItem()
|
||||
b.WriteString(name)
|
||||
if useMeta {
|
||||
a := *(*[2]byte)(unsafe.Pointer(&meta))
|
||||
b.Write(a[:])
|
||||
}
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// ValidBrewingReagent checks if the world.Item is a brewing reagent.
|
||||
func ValidBrewingReagent(i world.Item) bool {
|
||||
name, _ := i.EncodeItem()
|
||||
_, exists := reagent[name]
|
||||
return exists
|
||||
}
|
||||
|
||||
// RegisterDynamic registers a new dynamic recipe. Dynamic recipes are not sent to the client
|
||||
// and are validated server-side.
|
||||
func RegisterDynamic(recipe DynamicRecipe) {
|
||||
dynamicRecipes = append(dynamicRecipes, recipe)
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package recipe
|
||||
|
||||
// Shape make up the shape of a shaped recipe. It consists of a width and a height.
|
||||
type Shape [2]int
|
||||
|
||||
// Width returns the width of the shape.
|
||||
func (s Shape) Width() int {
|
||||
return s[0]
|
||||
}
|
||||
|
||||
// Height returns the height of the shape.
|
||||
func (s Shape) Height() int {
|
||||
return s[1]
|
||||
}
|
||||
|
||||
// NewShape creates a new shape using the provided width and height.
|
||||
func NewShape(width, height int) Shape {
|
||||
return Shape{width, height}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,181 @@
|
||||
package recipe
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
|
||||
"github.com/df-mc/dragonfly/server/item"
|
||||
"github.com/df-mc/dragonfly/server/world"
|
||||
"github.com/sandertv/gophertunnel/minecraft/nbt"
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed crafting_data.nbt
|
||||
vanillaCraftingData []byte
|
||||
//go:embed smithing_data.nbt
|
||||
vanillaSmithingData []byte
|
||||
//go:embed smithing_trim_data.nbt
|
||||
vanillaSmithingTrimData []byte
|
||||
//go:embed potion_data.nbt
|
||||
vanillaPotionData []byte
|
||||
)
|
||||
|
||||
// shapedRecipe is a recipe that must be crafted in a specific shape.
|
||||
type shapedRecipe struct {
|
||||
Input inputItems `nbt:"input"`
|
||||
Output outputItems `nbt:"output"`
|
||||
Block string `nbt:"block"`
|
||||
Width int32 `nbt:"width"`
|
||||
Height int32 `nbt:"height"`
|
||||
Priority int32 `nbt:"priority"`
|
||||
}
|
||||
|
||||
// shapelessRecipe is a recipe that may be crafted without a strict shape.
|
||||
type shapelessRecipe struct {
|
||||
Input inputItems `nbt:"input"`
|
||||
Output outputItems `nbt:"output"`
|
||||
Block string `nbt:"block"`
|
||||
Priority int32 `nbt:"priority"`
|
||||
}
|
||||
|
||||
// potionRecipe is a recipe that may be crafted in a brewing stand.
|
||||
type potionRecipe struct {
|
||||
Input inputItem `nbt:"input"`
|
||||
Reagent inputItem `nbt:"reagent"`
|
||||
Output outputItem `nbt:"output"`
|
||||
}
|
||||
|
||||
// potionContainerChangeRecipe is a recipe that may be crafted in a brewing stand.
|
||||
type potionContainerChangeRecipe struct {
|
||||
Input string `nbt:"input"`
|
||||
Reagent inputItem `nbt:"reagent"`
|
||||
Output string `nbt:"output"`
|
||||
}
|
||||
|
||||
// registerVanilla can be called to register all vanilla recipes from the generated data files.
|
||||
// noinspection GoUnusedFunction
|
||||
//
|
||||
//lint:ignore U1000 Function is used through compiler directives.
|
||||
func registerVanilla() {
|
||||
var craftingRecipes struct {
|
||||
Shaped []shapedRecipe `nbt:"shaped"`
|
||||
Shapeless []shapelessRecipe `nbt:"shapeless"`
|
||||
}
|
||||
if err := nbt.Unmarshal(vanillaCraftingData, &craftingRecipes); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for _, s := range craftingRecipes.Shapeless {
|
||||
input, ok := s.Input.Items()
|
||||
output, okTwo := s.Output.Stacks()
|
||||
if !ok || !okTwo {
|
||||
// This can be expected to happen, as some recipes contain blocks or items that aren't currently implemented.
|
||||
continue
|
||||
}
|
||||
Register(Shapeless{recipe{
|
||||
input: input,
|
||||
output: output,
|
||||
block: s.Block,
|
||||
priority: uint32(s.Priority),
|
||||
}})
|
||||
}
|
||||
|
||||
for _, s := range craftingRecipes.Shaped {
|
||||
input, ok := s.Input.Items()
|
||||
output, okTwo := s.Output.Stacks()
|
||||
if !ok || !okTwo {
|
||||
// This can be expected to happen - refer to the comment above.
|
||||
continue
|
||||
}
|
||||
Register(Shaped{
|
||||
shape: Shape{int(s.Width), int(s.Height)},
|
||||
recipe: recipe{
|
||||
input: input,
|
||||
output: output,
|
||||
block: s.Block,
|
||||
priority: uint32(s.Priority),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
var smithingRecipes []shapelessRecipe
|
||||
if err := nbt.Unmarshal(vanillaSmithingData, &smithingRecipes); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for _, s := range smithingRecipes {
|
||||
input, ok := s.Input.Items()
|
||||
output, okTwo := s.Output.Stacks()
|
||||
if !ok || !okTwo {
|
||||
// This can be expected to happen - refer to the comment above.
|
||||
continue
|
||||
}
|
||||
Register(SmithingTransform{recipe{
|
||||
input: input,
|
||||
output: output,
|
||||
block: s.Block,
|
||||
priority: uint32(s.Priority),
|
||||
}})
|
||||
}
|
||||
|
||||
var smithingTrimRecipes []shapelessRecipe
|
||||
if err := nbt.Unmarshal(vanillaSmithingTrimData, &smithingTrimRecipes); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for _, s := range smithingTrimRecipes {
|
||||
input, ok := s.Input.Items()
|
||||
if !ok {
|
||||
// This can be expected to happen - refer to the comment above.
|
||||
continue
|
||||
}
|
||||
Register(SmithingTrim{recipe{
|
||||
input: input,
|
||||
block: s.Block,
|
||||
priority: uint32(s.Priority),
|
||||
}})
|
||||
}
|
||||
|
||||
var potionRecipes struct {
|
||||
Potions []potionRecipe `nbt:"potions"`
|
||||
ContainerChanges []potionContainerChangeRecipe `nbt:"container_changes"`
|
||||
}
|
||||
|
||||
if err := nbt.Unmarshal(vanillaPotionData, &potionRecipes); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for _, r := range potionRecipes.Potions {
|
||||
input, ok := r.Input.Item()
|
||||
reagent, okTwo := r.Reagent.Item()
|
||||
output, okThree := r.Output.Stack()
|
||||
if !ok || !okTwo || !okThree {
|
||||
// This can be expected to happen - refer to the comment above.
|
||||
continue
|
||||
}
|
||||
|
||||
Register(Potion{recipe{
|
||||
input: []Item{input, reagent},
|
||||
output: []item.Stack{output},
|
||||
block: "brewing_stand",
|
||||
}})
|
||||
}
|
||||
|
||||
for _, c := range potionRecipes.ContainerChanges {
|
||||
input, ok := world.ItemByName(c.Input, 0)
|
||||
reagent, okTwo := c.Reagent.Item()
|
||||
output, okThree := world.ItemByName(c.Output, 0)
|
||||
if !ok || !okTwo || !okThree {
|
||||
// This can be expected to happen - refer to the comment above.
|
||||
continue
|
||||
}
|
||||
|
||||
Register(PotionContainerChange{recipe{
|
||||
input: []Item{item.NewStack(input, 1), reagent},
|
||||
output: []item.Stack{item.NewStack(output, 1)},
|
||||
block: "brewing_stand",
|
||||
}})
|
||||
}
|
||||
|
||||
// Register dynamic recipes
|
||||
RegisterDynamic(NewDecoratedPotRecipe())
|
||||
}
|
||||
Reference in New Issue
Block a user