summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CONTRIBUTORS1
-rw-r--r--Server/Plugins/APIDump/APIDesc.lua34
-rw-r--r--Server/Protocol/1.12.2/base.recipes.txt434
-rw-r--r--Server/crafting.txt774
-rw-r--r--src/ClientHandle.cpp44
-rw-r--r--src/ClientHandle.h10
-rw-r--r--src/CraftingRecipes.cpp95
-rw-r--r--src/CraftingRecipes.h52
-rw-r--r--src/Entities/Player.cpp102
-rw-r--r--src/Entities/Player.h14
-rw-r--r--src/Inventory.cpp26
-rw-r--r--src/Inventory.h7
-rw-r--r--src/Item.h25
-rw-r--r--src/ItemGrid.cpp29
-rw-r--r--src/ItemGrid.h6
-rw-r--r--src/Protocol/CMakeLists.txt2
-rw-r--r--src/Protocol/Packetizer.cpp5
-rw-r--r--src/Protocol/Protocol.h3
-rw-r--r--src/Protocol/ProtocolRecognizer.cpp21
-rw-r--r--src/Protocol/ProtocolRecognizer.h2
-rw-r--r--src/Protocol/Protocol_1_12.cpp76
-rw-r--r--src/Protocol/Protocol_1_12.h9
-rw-r--r--src/Protocol/Protocol_1_13.cpp1
-rw-r--r--src/Protocol/Protocol_1_8.cpp20
-rw-r--r--src/Protocol/Protocol_1_8.h2
-rw-r--r--src/Protocol/Protocol_1_9.cpp6
-rw-r--r--src/Protocol/RecipeMapper.cpp128
-rw-r--r--src/Protocol/RecipeMapper.h35
-rw-r--r--src/Root.cpp2
-rw-r--r--src/Root.h8
-rw-r--r--src/UI/CraftingWindow.cpp6
-rw-r--r--src/UI/CraftingWindow.h7
-rw-r--r--src/UI/InventoryWindow.cpp6
-rw-r--r--src/UI/InventoryWindow.h6
-rw-r--r--src/UI/SlotArea.cpp70
-rw-r--r--src/UI/SlotArea.h9
36 files changed, 1617 insertions, 460 deletions
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 281ca6f74..c1e8c171c 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -63,6 +63,7 @@ Sxw1212
Taugeshtu
tigerw (Tiger Wang)
tonibm19
+TooAngel
UltraCoderRU
Warmist
WebFreak001
diff --git a/Server/Plugins/APIDump/APIDesc.lua b/Server/Plugins/APIDump/APIDesc.lua
index ab31ad6b2..a55c2cade 100644
--- a/Server/Plugins/APIDump/APIDesc.lua
+++ b/Server/Plugins/APIDump/APIDesc.lua
@@ -6345,6 +6345,23 @@ These ItemGrids are available in the API and can be manipulated by the plugins,
},
Notes = "Adds the specified damage (1 by default) to the specified item. Removes the item and returns true if the item reached its max damage and was destroyed.",
},
+ FindItem =
+ {
+ Params =
+ {
+ {
+ Name = "RecipeItem",
+ Type = "cItem",
+ },
+ },
+ Returns =
+ {
+ {
+ Type = "cItem",
+ },
+ },
+ Notes = "Finds an item in the shield, hotbar and inventory slots matching `ItemType` and `ItemDamage`. The actual item is returned, if none is found `nullptr`. This can be used to validate that the player has a specific type of item.",
+ },
GetArmorGrid =
{
Returns =
@@ -7496,6 +7513,23 @@ This class represents a 2D array of items. It is used as the underlying storage
Notes = "Destroys the item in the specified slot",
},
},
+ FindItem =
+ {
+ Params =
+ {
+ {
+ Name = "RecipeItem",
+ Type = "cItem",
+ },
+ },
+ Returns =
+ {
+ {
+ Type = "cItem",
+ },
+ },
+ Notes = "Finds an item within the grid matching `ItemType` and `ItemDamage`. The actual item is returned, if none is found `nullptr`.",
+ },
GetFirstEmptySlot =
{
Returns =
diff --git a/Server/Protocol/1.12.2/base.recipes.txt b/Server/Protocol/1.12.2/base.recipes.txt
new file mode 100644
index 000000000..e5c52fa8b
--- /dev/null
+++ b/Server/Protocol/1.12.2/base.recipes.txt
@@ -0,0 +1,434 @@
+# recipeId minecraftName
+
+11 yellow_wool
+12 yellow_terracotta
+13 yellow_stained_glass_pane
+14 yellow_stained_glass
+15 yellow_dye_from_sunflower
+16 yellow_dye_from_dandelion
+17 yellow_concrete_powder
+18 yellow_carpet
+19 yellow_bed_from_white_bed
+20 yellow_bed
+21 yellow_banner
+22 writable_book
+23 wooden_sword
+24 wooden_shovel
+25 wooden_pressure_plate
+26 wooden_pickaxe
+27 wooden_hoe
+28 oak_door
+29 oak_button
+30 wooden_axe
+31 white_terracotta
+32 white_stained_glass_pane
+33 white_stained_glass
+34 white_concrete_powder
+35 white_carpet
+36 white_bed
+37 white_banner
+38 wheat
+39 tripwire_hook
+40 trapped_chest
+41 oak_trapdoor
+42 torch
+43 tnt_minecart
+44 tnt
+45 sugar
+46 white_wool_from_string
+47 stone_bricks
+48 stone_sword
+49 stone_stairs
+50 stone_slab
+51 stone_shovel
+52 stone_pressure_plate
+53 stone_pickaxe
+54 stone_hoe
+55 stone_button
+56 stone_brick_stairs
+57 stone_brick_slab
+58 stone_axe
+59 sticky_piston
+60 stick
+61 spruce_stairs
+62 spruce_slab
+63 spruce_planks
+64 spruce_fence_gate
+65 spruce_fence
+66 spruce_door
+67 spruce_boat
+68 spectral_arrow
+69 glistering_melon_slice
+70 snow
+71 snow_block
+72 smooth_sandstone
+73 smooth_red_sandstone
+74 slime_ball
+75 slime_block
+76 oak_sign
+77 shield
+78 shears
+79 sea_lantern
+80 sandstone_stairs
+81 sandstone_slab
+82 sandstone
+83 repeater
+84 redstone_torch
+85 redstone_lamp
+86 redstone_block
+87 redstone
+88 red_wool
+89 red_terracotta
+90 red_stained_glass_pane
+91 red_stained_glass
+92 red_sandstone_stairs
+93 red_sandstone_slab
+94 red_sandstone
+95 red_nether_bricks
+96 red_dye_from_tulip
+97 red_dye_from_rose_bush
+98 red_dye_from_poppy
+99 red_dye_from_beetroot
+100 red_concrete_powder
+101 red_carpet
+102 red_bed_from_white_bed
+103 red_bed
+104 red_banner
+105 rail
+106 rabbit_stew_from_red_mushroom
+107 rabbit_stew_from_brown_mushroom
+108 quartz_stairs
+109 quartz_slab
+110 quartz_block
+111 purpur_stairs
+112 purpur_slab
+113 purpur_pillar
+114 purpur_block
+115 purple_wool
+116 purple_terracotta
+117 purple_stained_glass_pane
+118 purple_stained_glass
+119 purpur_shulker_box
+120 purple_dye
+121 purple_concrete_powder
+122 purple_carpet
+123 purple_bed_from_white_bed
+124 purple_bed
+125 purple_banner
+126 pumpkin_seeds
+127 pumpkin_pie
+128 prismarine_bricks
+129 prismarine
+130 polished_granite
+131 polished_diorite
+132 polished_andesite
+133 piston
+134 pink_wool
+135 pink_terracotta
+136 pink_stained_glass_pane
+137 pink_stained_glass
+138 pink_dye_from_red_white_dye
+139 pink_tulip
+140 peony
+141 pink_concrete_powder
+142 pink_carpet
+143 pink_bed_from_white_bed
+144 pink_bed
+145 pink_banner
+146 quartz_pillar
+147 paper
+148 painting
+149 orange_wool
+150 orange_terracotta
+151 orange_stained_glass_pane
+152 orange_stained_glass
+153 orange_dye_from_red_yellow
+154 orange_dye_from_orange_tulip
+155 orange_concrete_powder
+156 orange_carpet
+157 orange_bed_from_white_bed
+158 orange_bed
+159 orange_banner
+160 observer
+161 oak_stairs
+162 oak_slab
+163 oak_planks
+164 note_block
+165 nether_wart_block
+166 nether_brick_stairs
+167 nether_brick_slab
+168 nether_brick_fence
+169 nether_bricks
+170 mushroom_stew
+171 mossy_stone_bricks
+172 mossy_cobblestone_wall
+173 mossy_cobblestone
+174 minecart
+175 melon_seeds
+176 melon
+177 map
+178 magma_cream
+179 magma_block
+180 magenta_wool
+181 magenta_terracotta
+182 magenta_stained_glass_pane
+183 magenta_stained_glass
+184 magenta_dye_from_purple_and_pink
+185 magenta_dye_from_lilac
+186 magenta_dye_from_blue_red_pink
+187 magenta_dye_from_blue_red_white_dye
+188 magenta_dye_from_allium
+189 magenta_concrete_powder
+190 magenta_carpet
+191 magenta_bed_from_white_bed
+192 magenta_bed
+193 magenta_banner
+194 jack_o_lantern
+195 lime_wool
+196 lime_terracotta
+197 lime_stained_glass_pane
+198 lime_stained_glass
+199 lime_dye
+200 lime_concrete_powder
+201 lime_carpet
+202 lime_bed_from_white_bed
+203 lime_bed
+204 lime_banner
+205 light_weighted_pressure_plate
+206 light_gray_wool
+207 light_gray_terracotta
+208 light_gray_stained_glass_pane
+209 light_gray_stained_glass
+210 light_gray_dye_from_white_tulip
+211 light_gray_dye_from_oxeye_daisy
+212 light_gray_dye_from_gray_white_dye
+213 light_gray_dye_from_black_white_dye
+214 light_gray_dye_from_azure_bluet
+215 light_gray_concrete_powder
+216 light_gray_carpet
+217 light_gray_bed_from_white_bed
+218 light_gray_bed
+219 light_gray_banner
+220 light_blue_wool
+221 light_blue_terracotta
+222 light_blue_stained_glass_pane
+223 light_blue_stained_glass
+224 light_blue_dye_from_blue_white_dye
+225 light_blue_dye_from_blue_orchid
+226 light_blue_concrete_powder
+227 light_blue_carpet
+228 light_blue_bed_from_white_bed
+229 light_blue_bed
+230 light_blue_banner
+231 lever
+232 leather_leggings
+233 leather_helmet
+234 leather_chestplate
+235 leather_boots
+236 leather
+237 lead
+238 lapis_lazuli
+239 lapis_block
+240 ladder
+241 jungle_slab
+242 jungle_stairs
+243 jungle_planks
+244 jungle_fence_gate
+245 jungle_fence
+246 jungle_door
+247 jungle_boat
+248 jukebox
+249 item_frame
+250 iron_trapdoor
+251 iron_sword
+252 iron_shovel
+253 iron_pickaxe
+254 iron_nugget
+255 iron_leggings
+256 iron_ingot_from_iron_block
+257 iron_ingot_from_nuggets
+258 iron_hoe
+259 iron_helmet
+260 iron_door
+261 iron_chestplate
+262 iron_boots
+263 iron_block
+264 iron_bars
+265 iron_axe
+266 hopper_minecart
+267 hopper
+268 heavy_weighted_pressure_plate
+269 hay_block
+270 green_wool
+271 green_terracotta
+272 green_stained_glass_pane
+273 green_stained_glass
+274 green_concrete_powder
+275 green_carpet
+276 green_bed_from_white_bed
+277 green_bed
+278 green_banner
+279 gray_wool
+280 gray_terracotta
+281 gray_stained_glass_pane
+282 gray_stained_glass
+283 gray_dye
+284 gray_concrete_powder
+285 gray_carpet
+286 gray_bed_from_white_bed
+287 gray_bed
+288 gray_banner
+289 granite
+290 golden_sword
+291 golden_shovel
+292 powered_rail
+293 golden_pickaxe
+294 golden_leggings
+295 golden_hoe
+296 golden_helmet
+297 golden_chestplate
+298 golden_carrot
+299 golden_boots
+300 golden_axe
+301 golden_apple
+302 gold_nugget
+303 gold_ingot_from_gold_block
+304 gold_ingot
+305 gold_block
+306 glowstone
+307 glass_pane
+308 glass_bottle
+309 furnace_minecart
+310 furnace
+311 flower_pot
+312 flint_and_steel
+313 fishing_rod
+314 fire_charge
+315 fermented_spider_eye
+316 oak_fence_gate
+317 oak_fence
+318 ender_eye
+319 ender_chest
+320 end_rod
+321 end_crystal
+322 end_stone_bricks
+323 enchanting_table
+324 emerald_block
+325 emerald
+326 dropper
+327 dispenser
+328 diorite
+329 diamond_sword
+330 diamond_shovel
+331 diamond_pickaxe
+332 diamond_leggings
+333 diamond_hoe
+334 diamond_helmet
+335 diamond_chestplate
+336 diamond_boots
+337 diamond_block
+338 diamond_axe
+339 diamond
+340 detector_rail
+341 daylight_detector
+342 dark_prismarine
+343 dark_oak_slab
+344 dark_oak_stairs
+345 dark_oak_planks
+346 dark_oak_fence_gate
+347 dark_oak_fence
+348 dark_oak_door
+349 dark_oak_boat
+350 cyan_wool
+351 cyan_terracotta
+352 cyan_stained_glass_pane
+353 cyan_stained_glass
+354 cyan_dye
+355 cyan_concrete_powder
+356 cyan_carpet
+357 cyan_bed_from_white_bed
+358 cyan_bed
+359 cyan_banner
+360 crafting_table
+361 cookie
+362 compass
+363 comparator
+364 cobblestone_wall
+365 cobblestone_slab
+366 coarse_dirt
+367 coal_block
+368 coal
+369 clock
+370 clay
+371 chiseled_stone_bricks
+372 chiseled_sandstone
+373 chiseled_red_sandstone
+374 chiseled_quartz_block
+375 chest_minecart
+376 chest
+377 cauldron
+378 carrot_on_a_stick
+379 cake
+380 bucket
+381 brown_wool
+382 brown_terracotta
+383 brown_stained_glass_pane
+384 brown_stained_glass
+385 brown_concrete_powder
+386 brown_carpet
+387 brown_bed_from_white_bed
+388 brown_bed
+389 brown_banner
+390 brick_stairs
+391 brick_slab
+392 bricks
+393 brewing_stand
+394 bread
+395 bowl
+396 bow
+397 bookshelf
+398 book
+399 bone_meal
+400 bone_meal_from_bone_block
+401 bone_block
+402 oak_boat
+403 blue_wool
+404 blue_terracotta
+405 blue_stained_glass_pane
+406 blue_stained_glass
+407 blue_concrete_powder
+408 blue_carpet
+409 blue_bed_from_white_bed
+410 blue_bed
+411 blue_banner
+412 blaze_powder
+413 black_wool
+414 black_terracotta
+415 black_stained_glass_pane
+416 black_stained_glass
+417 black_concrete_powder
+418 black_carpet
+419 black_bed_from_white_bed
+420 black_bed
+421 black_banner
+422 birch_slab
+423 birch_stairs
+424 birch_planks
+425 birch_fence_gate
+426 birch_fence
+427 birch_door
+428 birch_boat
+429 beetroot_soup
+430 beacon
+431 arrow
+432 armor_stand
+433 anvil
+434 andesite
+435 activator_rail
+436 acacia_slab
+437 acacia_stairs
+438 acacia_planks
+439 acacia_fence_gate
+440 acacia_fence
+441 acacia_door
+442 acacia_boat
diff --git a/Server/crafting.txt b/Server/crafting.txt
index c85943996..e1a07d96b 100644
--- a/Server/crafting.txt
+++ b/Server/crafting.txt
@@ -43,19 +43,19 @@
# Need to list each of the four log types, otherwise all logs would get converted into apple planks (^0)
-AcaciaPlanks, 4 = AcaciaLog, *
-BirchPlanks, 4 = BirchLog, *
-Chest = Planks^-1, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3
-DarkOakPlanks, 4 = DarkOakLog, *
-EnderChest = EyeOfEnder, 2:2 | Obsidian, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3
-Furnace = Cobblestone, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3
-JunglePlanks, 4 = JungleLog, *
-OakPlanks, 4 = OakLog, *
-SprucePlanks, 4 = SpruceLog, *
-Stick, 4 = Planks^-1, 2:2, 2:3
-Torch, 4 = Stick, 1:2 | Coal^-1, 1:1
-TrappedChest = TripWireHook, * | Chest, *
-Workbench = Planks^-1, 1:1, 1:2, 2:1, 2:2
+acacia_planks: AcaciaPlanks, 4 = AcaciaLog, *
+birch_planks: BirchPlanks, 4 = BirchLog, *
+chest: Chest = Planks^-1, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3
+dark_oak_planks: DarkOakPlanks, 4 = DarkOakLog, *
+ender_chest: EnderChest = EyeOfEnder, 2:2 | Obsidian, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3
+furnace: Furnace = Cobblestone, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3
+jungle_planks: JunglePlanks, 4 = JungleLog, *
+oak_planks: OakPlanks, 4 = OakLog, *
+spruce_planks: SprucePlanks, 4 = SpruceLog, *
+stick: Stick, 4 = Planks^-1, 2:2, 2:3
+torch: Torch, 4 = Stick, 1:2 | Coal^-1, 1:1
+trapped_chest: TrappedChest = TripWireHook, * | Chest, *
+crafting_table: Workbench = Planks^-1, 1:1, 1:2, 2:1, 2:2
@@ -64,110 +64,110 @@ Workbench = Planks^-1, 1:1, 1:2, 2:1, 2:2
#******************************************************#
# Blocks
#
-Andesite, 2 = Diorite, * | Cobblestone, *
-BoneBlock = BoneMeal, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
-BookShelf = Planks^-1, 1:1, 2:1, 3:1, 1:3, 2:3, 3:3 | Book, 1:2, 2:2, 3:2
-BrickBlock = Brick, 1:1, 1:2, 2:1, 2:2
-ChiseledQuartzBlock = QuartzSlab, 1:1, 1:2
-ChiseledRedSandstone = RedSandstoneSlab, 1:1, 1:2
-ChiseledStoneBrick = StoneBrickSlab, 1:1, 1:2
-ClayBlock = Clay, 1:1, 1:2, 2:1, 2:2
-CoalBlock = Coal, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
-CoarsedDirt, 4 = Dirt, 1:1, 2:2 | Gravel, 1:2, 2:1
+andesite: Andesite, 2 = Diorite, * | Cobblestone, *
+bone_block: BoneBlock = BoneMeal, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
+bookshelf: BookShelf = Planks^-1, 1:1, 2:1, 3:1, 1:3, 2:3, 3:3 | Book, 1:2, 2:2, 3:2
+bricks: BrickBlock = Brick, 1:1, 1:2, 2:1, 2:2
+chiseled_quartz_block: ChiseledQuartzBlock = QuartzSlab, 1:1, 1:2
+chiseled_red_sandstone: ChiseledRedSandstone = RedSandstoneSlab, 1:1, 1:2
+chiseled_stone_bricks: ChiseledStoneBrick = StoneBrickSlab, 1:1, 1:2
+clay: ClayBlock = Clay, 1:1, 1:2, 2:1, 2:2
+coal_block: CoalBlock = Coal, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
+coarse_dirt: CoarsedDirt, 4 = Dirt, 1:1, 2:2 | Gravel, 1:2, 2:1
CoarsedDirt, 4 = Gravel, 1:1, 2:2 | Dirt, 1:2, 2:1
-DarkPrismarine = PrismarineShard, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | Inksac, 2:2
-DiamondBlock = Diamond, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
-Diorite, 2 = Cobblestone, * | NetherQuartz, *
-EmeraldBlock = Emerald, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
-EndstoneBrick, 4 = Endstone, 1:1, 1:2, 2:1, 2:2
-Glowstone = GlowstoneDust, 1:1, 1:2, 2:1, 2:2
-GoldBlock = GoldIngot, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
-Granite, 2 = Diorite, * | NetherQuartz, *
-HayBale = Wheat, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
-IronBlock = IronIngot, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
-JackOLantern = Pumpkin, 1:1 | Torch, 1:2
-LapisBlock = LapisLazuli, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
-Leather = RabbitHide, 1:1, 1:2, 2:1, 2:2
-MossyCobblestone = Cobblestone, * | Vines, *
-MossyStoneBrick = Stonebrick, * | Vines, *
-NetherBrickBlock = NetherBrick, 1:1, 1:2, 2:1, 2:2
-NetherWartBlock = NetherWart, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
-OrnamentSandstone = SandstoneSlab, 1:1, 1:2
-PillarQuartzBlock, 2 = QuartzBlock, 1:1, 1:2
-PolishedAndesite, 4 = Andesite, 1:1, 1:2, 2:1, 2:2
-PolishedDiorite, 4 = Diorite, 1:1, 1:2, 2:1, 2:2
-PolishedGranite, 4 = Granite, 1:1, 1:2, 2:1, 2:2
-Prismarine = PrismarineShard, 1:1, 1:2, 2:1, 2:2
-PrismarineBricks = PrismarineShard, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
-PurpurBlock, 4 = PoppedChorusFruit, 1:1, 1:2, 2:1, 2:2
-PurpurPillar, 1 = PurpurSlab, 1:1, 1:2
-QuartzBlock = NetherQuartz, 1:1, 1:2, 2:1, 2:2
-RedNetherBrick = NetherBrick, 1:1, 2:2 | NetherWart, 1:2, 2:1
+dark_prismarine: DarkPrismarine = PrismarineShard, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | Inksac, 2:2
+diamond_block: DiamondBlock = Diamond, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
+diorite: Diorite, 2 = Cobblestone, * | NetherQuartz, *
+emerald_block: EmeraldBlock = Emerald, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
+end_stone_bricks: EndstoneBrick, 4 = Endstone, 1:1, 1:2, 2:1, 2:2
+glowstone: Glowstone = GlowstoneDust, 1:1, 1:2, 2:1, 2:2
+gold_block: GoldBlock = GoldIngot, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
+granite: Granite, 2 = Diorite, * | NetherQuartz, *
+hay_block: HayBale = Wheat, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
+iron_block: IronBlock = IronIngot, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
+jack_o_lantern: JackOLantern = Pumpkin, 1:1 | Torch, 1:2
+lapis_block: LapisBlock = LapisLazuli, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
+leather: Leather = RabbitHide, 1:1, 1:2, 2:1, 2:2
+mossy_cobblestone: MossyCobblestone = Cobblestone, * | Vines, *
+mossy_stone_bricks: MossyStoneBrick = Stonebrick, * | Vines, *
+nether_bricks: NetherBrickBlock = NetherBrick, 1:1, 1:2, 2:1, 2:2
+nether_wart_block: NetherWartBlock = NetherWart, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
+chiseled_sandstone: OrnamentSandstone = SandstoneSlab, 1:1, 1:2
+quartz_pillar: PillarQuartzBlock, 2 = QuartzBlock, 1:1, 1:2
+polished_andesite: PolishedAndesite, 4 = Andesite, 1:1, 1:2, 2:1, 2:2
+polished_diorite: PolishedDiorite, 4 = Diorite, 1:1, 1:2, 2:1, 2:2
+polished_granite: PolishedGranite, 4 = Granite, 1:1, 1:2, 2:1, 2:2
+prismarine: Prismarine = PrismarineShard, 1:1, 1:2, 2:1, 2:2
+prismarine_bricks: PrismarineBricks = PrismarineShard, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
+purpur_block: PurpurBlock, 4 = PoppedChorusFruit, 1:1, 1:2, 2:1, 2:2
+purpur_pillar: PurpurPillar, 1 = PurpurSlab, 1:1, 1:2
+quartz_block: QuartzBlock = NetherQuartz, 1:1, 1:2, 2:1, 2:2
+red_nether_bricks: RedNetherBrick = NetherBrick, 1:1, 2:2 | NetherWart, 1:2, 2:1
RedNetherBrick = NetherWart, 1:1, 2:2 | NetherBrick, 1:2, 2:1
-RedSandstone = RedSand, 1:1, 1:2, 2:1, 2:2
-RedstoneBlock = RedstoneDust, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
-Sandstone = Sand, 1:1, 1:2, 2:1, 2:2
-SeaLantern = PrismarineShard, 1:1, 1:3, 3:1, 3:3 | PrismarineCrystals, 1:2, 2:1, 2:2, 2:3, 3:2
-SlimeBlock = Slimeball, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
-SmoothRedSandstone, 4 = RedSandstone, 1:1, 1:2, 2:1, 2:2
-SmoothSandstone, 4 = Sandstone, 1:1, 1:2, 2:1, 2:2
-SnowBlock = SnowBall, 1:1, 1:2, 2:1, 2:2
-StoneBrick, 4 = Stone, 1:1, 1:2, 2:1, 2:2
-TNT = Gunpowder, 1:1, 3:1, 2:2, 1:3, 3:3 | Sand, 2:1, 1:2, 3:2, 2:3
+red_sandstone: RedSandstone = RedSand, 1:1, 1:2, 2:1, 2:2
+redstone_block: RedstoneBlock = RedstoneDust, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
+sandstone: Sandstone = Sand, 1:1, 1:2, 2:1, 2:2
+sea_lantern: SeaLantern = PrismarineShard, 1:1, 1:3, 3:1, 3:3 | PrismarineCrystals, 1:2, 2:1, 2:2, 2:3, 3:2
+slime_block: SlimeBlock = Slimeball, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
+smooth_red_sandstone: SmoothRedSandstone, 4 = RedSandstone, 1:1, 1:2, 2:1, 2:2
+smooth_sandstone: SmoothSandstone, 4 = Sandstone, 1:1, 1:2, 2:1, 2:2
+snow_block: SnowBlock = SnowBall, 1:1, 1:2, 2:1, 2:2
+stone_bricks: StoneBrick, 4 = Stone, 1:1, 1:2, 2:1, 2:2
+tnt: TNT = Gunpowder, 1:1, 3:1, 2:2, 1:3, 3:3 | Sand, 2:1, 1:2, 3:2, 2:3
Wool = String, 1:1, 1:2, 2:1, 2:2
# Slabs:
-AcaciaWoodSlab, 6 = AcaciaPlanks, 1:1, 2:1, 3:1
-BirchWoodSlab, 6 = BirchPlanks, 1:1, 2:1, 3:1
-BrickSlab, 6 = BrickBlock, 1:1, 2:1, 3:1
-CobblestoneSlab, 6 = Cobblestone, 1:1, 2:1, 3:1
-DarkOakWoodSlab, 6 = DarkOakPlanks, 1:1, 2:1, 3:1
-JungleWoodSlab, 6 = JunglePlanks, 1:1, 2:1, 3:1
-NetherBrickSlab, 6 = NetherBrickBlock, 1:1, 2:1, 3:1
-OakWoodSlab, 6 = OakPlanks, 1:1, 2:1, 3:1
-PurpurSlab, 6 = PurpurBlock, 1:1, 2:1, 3:1
-Quartzslab, 6 = QuartzBlock, 1:1, 2:1, 3:1
-RedSandstoneSlab, 6 = RedSandstone^-1, 1:1, 2:1, 3:1
-SandstoneSlab, 6 = OrnamentSandstone, 1:1, 2:1, 3:1
+acacia_slab: AcaciaWoodSlab, 6 = AcaciaPlanks, 1:1, 2:1, 3:1
+birch_slab: BirchWoodSlab, 6 = BirchPlanks, 1:1, 2:1, 3:1
+brick_slab: BrickSlab, 6 = BrickBlock, 1:1, 2:1, 3:1
+cobblestone_slab: CobblestoneSlab, 6 = Cobblestone, 1:1, 2:1, 3:1
+dark_oak_slab: DarkOakWoodSlab, 6 = DarkOakPlanks, 1:1, 2:1, 3:1
+jungle_slab: JungleWoodSlab, 6 = JunglePlanks, 1:1, 2:1, 3:1
+nether_brick_slab: NetherBrickSlab, 6 = NetherBrickBlock, 1:1, 2:1, 3:1
+oak_slab: OakWoodSlab, 6 = OakPlanks, 1:1, 2:1, 3:1
+purpur_slab: PurpurSlab, 6 = PurpurBlock, 1:1, 2:1, 3:1
+quartz_slab: Quartzslab, 6 = QuartzBlock, 1:1, 2:1, 3:1
+red_sandstone_slab: RedSandstoneSlab, 6 = RedSandstone^-1, 1:1, 2:1, 3:1
+sandstone_slab: SandstoneSlab, 6 = OrnamentSandstone, 1:1, 2:1, 3:1
SandstoneSlab, 6 = Sandstone, 1:1, 2:1, 3:1
SandstoneSlab, 6 = SmoothSandstone, 1:1, 2:1, 3:1
-SnowLayer, 6 = SnowBlock, 1:1, 2:1, 3:1
-SpruceWoodSlab, 6 = SprucePlanks, 1:1, 2:1, 3:1
-StonebrickSlab, 6 = StoneBrick, 1:1, 2:1, 3:1
-StoneSlab, 6 = Stone, 1:1, 2:1, 3:1
+snow: SnowLayer, 6 = SnowBlock, 1:1, 2:1, 3:1
+spruce_slab: SpruceWoodSlab, 6 = SprucePlanks, 1:1, 2:1, 3:1
+stone_brick_slab: StonebrickSlab, 6 = StoneBrick, 1:1, 2:1, 3:1
+stone_slab: StoneSlab, 6 = Stone, 1:1, 2:1, 3:1
# Stairs:
-AcaciaWoodStairs, 4 = AcaciaPlanks, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
+acacia_stairs: AcaciaWoodStairs, 4 = AcaciaPlanks, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
AcaciaWoodStairs, 4 = AcaciaPlanks, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
-BirchWoodStairs, 4 = BirchPlanks, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
+birch_stairs: BirchWoodStairs, 4 = BirchPlanks, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
BirchWoodStairs, 4 = BirchPlanks, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
-BrickStairs, 4 = BrickBlock, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
+brick_stairs: BrickStairs, 4 = BrickBlock, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
BrickStairs, 4 = BrickBlock, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
-cobblestoneStairs, 4 = Cobblestone, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
+stone_stairs: cobblestoneStairs, 4 = Cobblestone, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
cobblestoneStairs, 4 = Cobblestone, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
-DarkOakWoodStairs, 4 = DarkOakPlanks, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
+dark_oak_stairs: DarkOakWoodStairs, 4 = DarkOakPlanks, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
DarkOakWoodStairs, 4 = DarkOakPlanks, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
-JungleWoodStairs, 4 = JunglePlanks, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
+jungle_stairs: JungleWoodStairs, 4 = JunglePlanks, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
JungleWoodStairs, 4 = JunglePlanks, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
-NetherBrickStairs, 4 = NetherBrickBlock, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
+nether_brick_stairs: NetherBrickStairs, 4 = NetherBrickBlock, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
NetherBrickStairs, 4 = NetherBrickBlock, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
-PurpurStairs, 4 = PurpurBlock, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
+purpur_stairs: PurpurStairs, 4 = PurpurBlock, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
PurpurStairs, 4 = PurpurBlock, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
-QuartzStairs, 4 = QuartzBlock, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
+quartz_stairs: QuartzStairs, 4 = QuartzBlock, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
QuartzStairs, 4 = QuartzBlock, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
-RedSandstoneStairs, 4 = RedSandstone^-1, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
+red_sandstone_stairs: RedSandstoneStairs, 4 = RedSandstone^-1, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
RedSandstoneStairs, 4 = RedSandstone^-1, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
-SandstoneStairs, 4 = OrnamentSandstone, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
+sandstone_stairs: SandstoneStairs, 4 = OrnamentSandstone, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
SandstoneStairs, 4 = OrnamentSandstone, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
SandstoneStairs, 4 = Sandstone, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
SandstoneStairs, 4 = Sandstone, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
SandstoneStairs, 4 = SmoothSandstone, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
SandstoneStairs, 4 = SmoothSandstone, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
-SpruceWoodStairs, 4 = SprucePlanks, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
+spruce_stairs: SpruceWoodStairs, 4 = SprucePlanks, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
SpruceWoodStairs, 4 = SprucePlanks, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
-StoneBrickStairs, 4 = StoneBrick, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
+stone_brick_stairs: StoneBrickStairs, 4 = StoneBrick, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
StoneBrickStairs, 4 = StoneBrick, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
-WoodStairs, 4 = OakPlanks, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
+oak_stairs: WoodStairs, 4 = OakPlanks, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
WoodStairs, 4 = OakPlanks, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
@@ -177,49 +177,49 @@ WoodStairs, 4 = OakPlanks, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
#
# Axes:
-DiamondAxe = Stick, 2:2, 2:3 | Diamond, 2:1, 1:1, 1:2
+diamond_axe: DiamondAxe = Stick, 2:2, 2:3 | Diamond, 2:1, 1:1, 1:2
DiamondAxe = Stick, 2:2, 2:3 | Diamond, 2:1, 3:1, 3:2
-GoldenAxe = Stick, 2:2, 2:3 | GoldIngot, 2:1, 1:1, 1:2
+golden_axe: GoldenAxe = Stick, 2:2, 2:3 | GoldIngot, 2:1, 1:1, 1:2
GoldenAxe = Stick, 2:2, 2:3 | GoldIngot, 2:1, 3:1, 3:2
-IronAxe = Stick, 2:2, 2:3 | IronIngot, 2:1, 1:1, 1:2
+iron_axe: IronAxe = Stick, 2:2, 2:3 | IronIngot, 2:1, 1:1, 1:2
IronAxe = Stick, 2:2, 2:3 | IronIngot, 2:1, 3:1, 3:2
-StoneAxe = Stick, 2:2, 2:3 | Cobblestone, 2:1, 1:1, 1:2
+stone_axe: StoneAxe = Stick, 2:2, 2:3 | Cobblestone, 2:1, 1:1, 1:2
StoneAxe = Stick, 2:2, 2:3 | Cobblestone, 2:1, 3:1, 3:2
-WoodenAxe = Stick, 2:2, 2:3 | Planks^-1, 2:1, 1:1, 1:2
+wooden_axe: WoodenAxe = Stick, 2:2, 2:3 | Planks^-1, 2:1, 1:1, 1:2
WoodenAxe = Stick, 2:2, 2:3 | Planks^-1, 2:1, 3:1, 3:2
# Pickaxes:
-DiamondPickaxe = Stick, 2:2, 2:3 | Diamond, 1:1, 2:1, 3:1
-GoldenPickaxe = Stick, 2:2, 2:3 | GoldIngot, 1:1, 2:1, 3:1
-IronPickaxe = Stick, 2:2, 2:3 | IronIngot, 1:1, 2:1, 3:1
-StonePickaxe = Stick, 2:2, 2:3 | Cobblestone, 1:1, 2:1, 3:1
-WoodenPickaxe = Stick, 2:2, 2:3 | Planks^-1, 1:1, 2:1, 3:1
+diamond_pickaxe: DiamondPickaxe = Stick, 2:2, 2:3 | Diamond, 1:1, 2:1, 3:1
+golden_pickaxe: GoldenPickaxe = Stick, 2:2, 2:3 | GoldIngot, 1:1, 2:1, 3:1
+iron_pickaxe: IronPickaxe = Stick, 2:2, 2:3 | IronIngot, 1:1, 2:1, 3:1
+stone_pickaxe: StonePickaxe = Stick, 2:2, 2:3 | Cobblestone, 1:1, 2:1, 3:1
+wooden_pickaxe: WoodenPickaxe = Stick, 2:2, 2:3 | Planks^-1, 1:1, 2:1, 3:1
# Shovels:
-DiamondShovel = Stick, 2:2, 2:3 | Diamond, 2:1
-GoldenShovel = Stick, 2:2, 2:3 | GoldIngot, 2:1
-IronShovel = Stick, 2:2, 2:3 | IronIngot, 2:1
-StoneShovel = Stick, 2:2, 2:3 | Cobblestone, 2:1
-WoodenShovel = Stick, 2:2, 2:3 | Planks^-1, 2:1
+diamond_shovel: DiamondShovel = Stick, 2:2, 2:3 | Diamond, 2:1
+golden_shovel: GoldenShovel = Stick, 2:2, 2:3 | GoldIngot, 2:1
+iron_shovel: IronShovel = Stick, 2:2, 2:3 | IronIngot, 2:1
+stone_shovel: StoneShovel = Stick, 2:2, 2:3 | Cobblestone, 2:1
+wooden_shovel: WoodenShovel = Stick, 2:2, 2:3 | Planks^-1, 2:1
# Hoes:
-DiamondHoe = Stick, 2:2, 2:3 | Diamond, 2:1, *:1
-GoldenHoe = Stick, 2:2, 2:3 | GoldIngot, 2:1, *:1
-IronHoe = Stick, 2:2, 2:3 | IronIngot, 2:1, *:1
-StoneHoe = Stick, 2:2, 2:3 | Cobblestone, 2:1, *:1
-WoodenHoe = Stick, 2:2, 2:3 | Planks^-1, 2:1, *:1
-
-Bucket = IronIngot, 1:1, 2:2, 3:1
-Compass = IronIngot, 2:1, 1:2, 3:2, 2:3 | RedstoneDust, 2:2
-EmptyMap = Paper, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | Compass, 2:2
-FireCharge, 3 = BlazePowder, * | Coal, * | Gunpowder, *
-FishingRod = Stick, 1:3, 2:2, 3:1 | String, 3:2, 3:3
+diamond_hoe: DiamondHoe = Stick, 2:2, 2:3 | Diamond, 2:1, *:1
+golden_hoe: GoldenHoe = Stick, 2:2, 2:3 | GoldIngot, 2:1, *:1
+iron_hoe: IronHoe = Stick, 2:2, 2:3 | IronIngot, 2:1, *:1
+stone_hoe: StoneHoe = Stick, 2:2, 2:3 | Cobblestone, 2:1, *:1
+wooden_hoe: WoodenHoe = Stick, 2:2, 2:3 | Planks^-1, 2:1, *:1
+
+bucket: Bucket = IronIngot, 1:1, 2:2, 3:1
+compass: Compass = IronIngot, 2:1, 1:2, 3:2, 2:3 | RedstoneDust, 2:2
+map: EmptyMap = Paper, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | Compass, 2:2
+fire_charge: FireCharge, 3 = BlazePowder, * | Coal, * | Gunpowder, *
+fishing_rod: FishingRod = Stick, 1:3, 2:2, 3:1 | String, 3:2, 3:3
FishingRod = Stick, 3:3, 2:2, 1:1 | String, 1:2, 1:3
-Lead, 2 = String, 1:1, 1:2, 2:1, 3:3 | Slimeball, 2:2
-Lighter = IronIngot, * | Flint, *
-Shears = IronIngot, 1:1, 2:2
+lead: Lead, 2 = String, 1:1, 1:2, 2:1, 3:3 | Slimeball, 2:2
+flint_and_steel: Lighter = IronIngot, * | Flint, *
+shears: Shears = IronIngot, 1:1, 2:2
Shears = IronIngot, 2:1, 1:2
-Watch = GoldIngot, 2:1, 1:2, 3:2, 2:3 | RedstoneDust, 2:2
+clock: Watch = GoldIngot, 2:1, 1:2, 3:2, 2:3 | RedstoneDust, 2:2
@@ -228,15 +228,15 @@ Watch = GoldIngot, 2:1, 1:2, 3:2, 2:3 | RedstoneDust, 2:2
#******************************************************#
# Weapons
#
-Arrow, 4 = Flint, 1:1 | Stick, 1:2 | Feather, 1:3
-Bow = Stick, 2:1, 1:2, 2:3 | String, 3:1, 3:2, 3:3
+arrow: Arrow, 4 = Flint, 1:1 | Stick, 1:2 | Feather, 1:3
+bow: Bow = Stick, 2:1, 1:2, 2:3 | String, 3:1, 3:2, 3:3
Bow = Stick, 2:1, 3:2, 2:3 | String, 1:1, 1:2, 1:3
-DiamondSword = Stick, 2:3 | Diamond, 2:1, 2:2
-GoldenSword = Stick, 2:3 | GoldIngot, 2:1, 2:2
-IronSword = Stick, 2:3 | IronIngot, 2:1, 2:2
-SpectralArrow, 2 = Arrow, 2:2 | GlowstoneDust, 1:2, 2:1, 2:3, 3:2
-StoneSword = Stick, 2:3 | Cobblestone, 2:1, 2:2
-WoodenSword = Stick, 2:3 | Planks^-1, 2:1, 2:2
+diamond_sword: DiamondSword = Stick, 2:3 | Diamond, 2:1, 2:2
+golden_sword: GoldenSword = Stick, 2:3 | GoldIngot, 2:1, 2:2
+iron_sword: IronSword = Stick, 2:3 | IronIngot, 2:1, 2:2
+spectral_arrow: SpectralArrow, 2 = Arrow, 2:2 | GlowstoneDust, 1:2, 2:1, 2:3, 3:2
+stone_sword: StoneSword = Stick, 2:3 | Cobblestone, 2:1, 2:2
+wooden_sword: WoodenSword = Stick, 2:3 | Planks^-1, 2:1, 2:2
@@ -248,31 +248,31 @@ WoodenSword = Stick, 2:3 | Planks^-1, 2:1, 2:2
#
# Helmets:
-DiamondHelmet = Diamond, 1:1, 2:1, 3:1, 1:2, 3:2
-GoldenHelmet = GoldIngot, 1:1, 2:1, 3:1, 1:2, 3:2
-IronHelmet = IronIngot, 1:1, 2:1, 3:1, 1:2, 3:2
-LeatherHelmet = Leather, 1:1, 2:1, 3:1, 1:2, 3:2
+diamond_helmet: DiamondHelmet = Diamond, 1:1, 2:1, 3:1, 1:2, 3:2
+golden_helmet: GoldenHelmet = GoldIngot, 1:1, 2:1, 3:1, 1:2, 3:2
+iron_helmet: IronHelmet = IronIngot, 1:1, 2:1, 3:1, 1:2, 3:2
+leather_helmet: LeatherHelmet = Leather, 1:1, 2:1, 3:1, 1:2, 3:2
# Chestplates:
-DiamondChestplate = Diamond, 1:1, 3:1, 1:2, 2:2, 3:2, 1:3, 2:3, 3:3
-GoldenChestplate = GoldIngot, 1:1, 3:1, 1:2, 2:2, 3:2, 1:3, 2:3, 3:3
-IronChestplate = IronIngot, 1:1, 3:1, 1:2, 2:2, 3:2, 1:3, 2:3, 3:3
-LeatherChestplate = Leather, 1:1, 3:1, 1:2, 2:2, 3:2, 1:3, 2:3, 3:3
+diamond_chestplate: DiamondChestplate = Diamond, 1:1, 3:1, 1:2, 2:2, 3:2, 1:3, 2:3, 3:3
+golden_chestplate: GoldenChestplate = GoldIngot, 1:1, 3:1, 1:2, 2:2, 3:2, 1:3, 2:3, 3:3
+iron_chestplate: IronChestplate = IronIngot, 1:1, 3:1, 1:2, 2:2, 3:2, 1:3, 2:3, 3:3
+leather_chestplate: LeatherChestplate = Leather, 1:1, 3:1, 1:2, 2:2, 3:2, 1:3, 2:3, 3:3
# Leggings:
-DiamondLeggings = Diamond, 1:1, 2:1, 3:1, 1:2, 3:2, 1:3, 3:3
-GoldenLeggings = GoldIngot, 1:1, 2:1, 3:1, 1:2, 3:2, 1:3, 3:3
-IronLeggings = IronIngot, 1:1, 2:1, 3:1, 1:2, 3:2, 1:3, 3:3
-LeatherPants = Leather, 1:1, 2:1, 3:1, 1:2, 3:2, 1:3, 3:3
+diamond_leggings: DiamondLeggings = Diamond, 1:1, 2:1, 3:1, 1:2, 3:2, 1:3, 3:3
+golden_leggings: GoldenLeggings = GoldIngot, 1:1, 2:1, 3:1, 1:2, 3:2, 1:3, 3:3
+iron_leggings: IronLeggings = IronIngot, 1:1, 2:1, 3:1, 1:2, 3:2, 1:3, 3:3
+leather_leggings: LeatherPants = Leather, 1:1, 2:1, 3:1, 1:2, 3:2, 1:3, 3:3
# Boots:
-DiamondBoots = Diamond, 1:1, 3:1, 1:2, 3:2
-GoldenBoots = GoldIngot, 1:1, 3:1, 1:2, 3:2
-IronBoots = IronIngot, 1:1, 3:1, 1:2, 3:2
-LeatherBoots = Leather, 1:1, 3:1, 1:2, 3:2
+diamond_boots: DiamondBoots = Diamond, 1:1, 3:1, 1:2, 3:2
+golden_boots: GoldenBoots = GoldIngot, 1:1, 3:1, 1:2, 3:2
+iron_boots: IronBoots = IronIngot, 1:1, 3:1, 1:2, 3:2
+leather_boots: LeatherBoots = Leather, 1:1, 3:1, 1:2, 3:2
# Shield:
-Shield = IronIngot, 2:1 | Planks^-1, 1:1, 3:1, 1:2, 2:2, 3:2, 2:3
+shield: Shield = IronIngot, 2:1 | Planks^-1, 1:1, 3:1, 1:2, 2:2, 3:2, 2:3
@@ -280,22 +280,22 @@ Shield = IronIngot, 2:1 | Planks^-1, 1:1, 3:1, 1:2, 2:2, 3:2, 2:3
#******************************************************#
# Transportation
#
-AcaciaBoat = AcaciaPlanks, 1:1, 3:1, 1:2, 2:2, 3:2
-ActivatorRail, 6 = IronIngot, 1:1, 1:2, 1:3, 3:1, 3:2, 3:3 | Stick, 2:1, 2:3 | RedstoneTorchon, 2:2
-BirchBoat = BirchPlanks, 1:1, 3:1, 1:2, 2:2, 3:2
-CarrotOnAStick = FishingRod, 1:2 | Carrot, 2:3
-DarkOakBoat = DarkOakPlanks, 1:1, 3:1, 1:2, 2:2, 3:2
-DetectorRail, 6 = IronIngot, 1:1, 3:1, 1:2, 3:2, 1:3, 3:3 | StonePlate, 2:2 | RedstoneDust, 2:3
-hopperminecart = Minecart, * | Hopper, *
-JungleBoat = JunglePlanks, 1:1, 3:1, 1:2, 2:2, 3:2
-Minecart = IronIngot, 1:1, 3:1, 1:2, 2:2, 3:2
-OakBoat = OakPlanks, 1:1, 3:1, 1:2, 2:2, 3:2
-PoweredMinecart = Minecart, * | Furnace, *
-PoweredRail, 6 = GoldIngot, 1:1, 3:1, 1:2, 3:2, 1:3, 3:3 | Stick, 2:2 | RedstoneDust, 2:3
-Rails, 16 = IronIngot, 1:1, 3:1, 1:2, 3:2, 1:3, 3:3 | Stick, 2:2
-SpruceBoat = SprucePlanks, 1:1, 3:1, 1:2, 2:2, 3:2
-StorageMinecart = Minecart, * | Chest, *
-TNTMinecart = Minecart, * | TNT, *
+acacia_boat: AcaciaBoat = AcaciaPlanks, 1:1, 3:1, 1:2, 2:2, 3:2
+activator_rail: ActivatorRail, 6 = IronIngot, 1:1, 1:2, 1:3, 3:1, 3:2, 3:3 | Stick, 2:1, 2:3 | RedstoneTorchon, 2:2
+birch_boat: BirchBoat = BirchPlanks, 1:1, 3:1, 1:2, 2:2, 3:2
+carrot_on_a_stick: CarrotOnAStick = FishingRod, 1:2 | Carrot, 2:3
+dark_oak_boat: DarkOakBoat = DarkOakPlanks, 1:1, 3:1, 1:2, 2:2, 3:2
+detector_rail: DetectorRail, 6 = IronIngot, 1:1, 3:1, 1:2, 3:2, 1:3, 3:3 | StonePlate, 2:2 | RedstoneDust, 2:3
+hopper_minecart: hopperminecart = Minecart, * | Hopper, *
+jungle_boat: JungleBoat = JunglePlanks, 1:1, 3:1, 1:2, 2:2, 3:2
+minecart: Minecart = IronIngot, 1:1, 3:1, 1:2, 2:2, 3:2
+oak_boat: OakBoat = OakPlanks, 1:1, 3:1, 1:2, 2:2, 3:2
+furnace_minecart: PoweredMinecart = Minecart, * | Furnace, *
+powered_rail: PoweredRail, 6 = GoldIngot, 1:1, 3:1, 1:2, 3:2, 1:3, 3:3 | Stick, 2:2 | RedstoneDust, 2:3
+rail: Rails, 16 = IronIngot, 1:1, 3:1, 1:2, 3:2, 1:3, 3:3 | Stick, 2:2
+spruce_boat: SpruceBoat = SprucePlanks, 1:1, 3:1, 1:2, 2:2, 3:2
+chest_minecart: StorageMinecart = Minecart, * | Chest, *
+tnt_minecart: TNTMinecart = Minecart, * | TNT, *
@@ -303,35 +303,35 @@ TNTMinecart = Minecart, * | TNT, *
#******************************************************#
# Mechanisms
#
-AcaciaDoor, 3 = AcaciaPlanks, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3
-BirchDoor, 3 = BirchPlanks, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3
-Comparator = RedstoneTorchOn, 2:1, 1:2, 3:2 | NetherQuartz, 2:2 | Stone, 1:3, 2:3, 3:3
-DarkOakDoor, 3 = DarkOakPlanks, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3
-DaylightSensor = Glass, 1:1, 2:1, 3:1 | NetherQuartz, 1:2, 2:2, 3:2 | WoodenSlab^-1, 1:3, 2:3, 3:3
-Dispenser = Cobblestone, 1:1, 1:2, 1:3, 2:1, 3:1, 3:2, 3:3 | RedstoneDust, 2:3 | Bow, 2:2
-Dropper = Cobblestone, 1:1, 2:1, 3:1, 1:2, 1:3, 3:2, 3:3 | RedstoneDust, 2:3
-heavyweightedpressureplate = IronIngot, 1:1, 2:1
-Hopper = IronIngot, 1:1, 3:1, 1:2, 3:2, 2:3 | Chest, 2:2
-IronDoor, 3 = IronIngot, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3
-IronTrapDoor = IronIngot, 1:1, 1:2, 2:1, 2:2
-Jukebox = Planks^-1, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | Diamond, 2:2
-JungleDoor, 3 = JunglePlanks, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3
-Lever = Cobblestone, 1:2 | Stick, 1:1
-lightweightedpressureplate = GoldIngot, 1:1, 2:1
-NoteBlock = Planks^-1, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | RedstoneDust, 2:2
-Piston = Planks^-1, 1:1, 2:1, 3:1 | RedstoneDust, 2:3 | Cobblestone, 1:2, 3:2, 1:3, 3:3 | IronIngot, 2:2
-RedstoneLamp = RedstoneDust, 2:1, 1:2, 3:2, 2:3 | Glowstone, 2:2
-RedstoneTorchOn = Stick, 1:2 | RedstoneDust, 1:1
-Repeater = Stone, 1:2, 2:2, 3:2 | RedstoneTorchOn, 1:1, 3:1 | RedstoneDust, 2:1
-PurpleShulkerBox = ShulkerShell, 2:1, 2:3 | Chest, 2:2
-SpruceDoor, 3 = SprucePlanks, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3
-StickyPiston = Piston, * | SlimeBall, *
-StoneButton = Stone, 1:1
-StonePlate = Stone, 1:1, 2:1
-TrapDoor, 2 = Planks^-1, 1:1, 2:1, 3:1, 1:2, 2:2, 3:2
-TripwireHook, 2 = Planks^-1, 2:3 | stick, 2:2 | IronIngot, 2:1
+acacia_door: AcaciaDoor, 3 = AcaciaPlanks, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3
+birch_door: BirchDoor, 3 = BirchPlanks, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3
+comparator: Comparator = RedstoneTorchOn, 2:1, 1:2, 3:2 | NetherQuartz, 2:2 | Stone, 1:3, 2:3, 3:3
+dark_oak_door: DarkOakDoor, 3 = DarkOakPlanks, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3
+daylight_detector: DaylightSensor = Glass, 1:1, 2:1, 3:1 | NetherQuartz, 1:2, 2:2, 3:2 | WoodenSlab^-1, 1:3, 2:3, 3:3
+dispenser: Dispenser = Cobblestone, 1:1, 1:2, 1:3, 2:1, 3:1, 3:2, 3:3 | RedstoneDust, 2:3 | Bow, 2:2
+dropper: Dropper = Cobblestone, 1:1, 2:1, 3:1, 1:2, 1:3, 3:2, 3:3 | RedstoneDust, 2:3
+heavy_weighted_pressure_plate: heavyweightedpressureplate = IronIngot, 1:1, 2:1
+hopper: Hopper = IronIngot, 1:1, 3:1, 1:2, 3:2, 2:3 | Chest, 2:2
+iron_door: IronDoor, 3 = IronIngot, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3
+iron_trapdoor: IronTrapDoor = IronIngot, 1:1, 1:2, 2:1, 2:2
+jukebox: Jukebox = Planks^-1, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | Diamond, 2:2
+jungle_door: JungleDoor, 3 = JunglePlanks, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3
+lever: Lever = Cobblestone, 1:2 | Stick, 1:1
+light_weighted_pressure_plate: lightweightedpressureplate = GoldIngot, 1:1, 2:1
+note_block: NoteBlock = Planks^-1, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | RedstoneDust, 2:2
+piston: Piston = Planks^-1, 1:1, 2:1, 3:1 | RedstoneDust, 2:3 | Cobblestone, 1:2, 3:2, 1:3, 3:3 | IronIngot, 2:2
+redstone_lamp: RedstoneLamp = RedstoneDust, 2:1, 1:2, 3:2, 2:3 | Glowstone, 2:2
+redstone_torch: RedstoneTorchOn = Stick, 1:2 | RedstoneDust, 1:1
+repeater: Repeater = Stone, 1:2, 2:2, 3:2 | RedstoneTorchOn, 1:1, 3:1 | RedstoneDust, 2:1
+purpur_shulker_box: PurpleShulkerBox = ShulkerShell, 2:1, 2:3 | Chest, 2:2
+spruce_door: SpruceDoor, 3 = SprucePlanks, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3
+sticky_piston: StickyPiston = Piston, * | SlimeBall, *
+stone_button: StoneButton = Stone, 1:1
+stone_pressure_plate: StonePlate = Stone, 1:1, 2:1
+oak_trapdoor: TrapDoor, 2 = Planks^-1, 1:1, 2:1, 3:1, 1:2, 2:2, 3:2
+tripwire_hook: TripwireHook, 2 = Planks^-1, 2:3 | stick, 2:2 | IronIngot, 2:1
WoodenButton = Planks^-1, 1:1
-WoodenDoor, 3 = OakPlanks, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3
+oak_button: WoodenDoor, 3 = OakPlanks, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3
WoodPlate = Planks^-1, 1:1, 2:1
@@ -341,21 +341,21 @@ WoodPlate = Planks^-1, 1:1, 2:1
#******************************************************#
# Food
#
-Bowl, 4 = Planks^-1, 1:1, 2:2, 3:1
-Bread = Wheat, 1:1, 2:1, 3:1
-Cake = MilkBucket, 1:1, 2:1, 3:1 | Sugar, 1:2, 3:2 | Egg, 2:2 | Wheat, 1:3, 2:3, 3:3
-Cookie, 8 = Wheat, *, * | CocoaBeans, *
-GoldenApple = RedApple, 2:2 | GoldIngot, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3
-MelonBlock = MelonSlice, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
-MelonSeeds = MelonSlice, *
-MushroomStew = Bowl, * | BrownMushroom, * | RedMushroom, *
-BeetrootSoup = Bowl, 2:3 | Beetroot, 1:1, 1:2, 2:1, 2:2, 3:1, 3:2
-PumpkinPie = Pumpkin, * | Sugar, * | egg, *
-PumpkinSeeds, 4 = Pumpkin, *
-RabbitStew = Cooked Rabbit, 2:1 | Carrot, 1:2 | BakedPotato, 2:2 | BrownMushroom, 3:2 | Bowl, 2:3
-RabbitStew = Cooked Rabbit, 2:1 | Carrot, 1:2 | BakedPotato, 2:2 | RedMushroom, 3:2 | Bowl, 2:3
-Sugar = Sugarcane, *
-Wheat, 9 = Haybale, *
+bowl: Bowl, 4 = Planks^-1, 1:1, 2:2, 3:1
+bread: Bread = Wheat, 1:1, 2:1, 3:1
+cake: Cake = MilkBucket, 1:1, 2:1, 3:1 | Sugar, 1:2, 3:2 | Egg, 2:2 | Wheat, 1:3, 2:3, 3:3
+cookie: Cookie, 8 = Wheat, *, * | CocoaBeans, *
+golden_apple: GoldenApple = RedApple, 2:2 | GoldIngot, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3
+melon: MelonBlock = MelonSlice, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
+melon_seeds: MelonSeeds = MelonSlice, *
+mushroom_stew: MushroomStew = Bowl, * | BrownMushroom, * | RedMushroom, *
+beetroot_soup: BeetrootSoup = Bowl, 2:3 | Beetroot, 1:1, 1:2, 2:1, 2:2, 3:1, 3:2
+pumpkin_pie: PumpkinPie = Pumpkin, * | Sugar, * | egg, *
+pumpkin_seeds: PumpkinSeeds, 4 = Pumpkin, *
+rabbit_stew_from_brown_mushroom: RabbitStew = Cooked Rabbit, 2:1 | Carrot, 1:2 | BakedPotato, 2:2 | BrownMushroom, 3:2 | Bowl, 2:3
+rabbit_stew_from_red_mushroom: RabbitStew = Cooked Rabbit, 2:1 | Carrot, 1:2 | BakedPotato, 2:2 | RedMushroom, 3:2 | Bowl, 2:3
+sugar: Sugar = Sugarcane, *
+wheat: Wheat, 9 = Haybale, *
@@ -366,71 +366,71 @@ Wheat, 9 = Haybale, *
#
# Minerals:
-Clay, 4 = ClayBlock, *
-Coal, 9 = CoalBlock, *
-Diamond, 9 = DiamondBlock, *
-Emerald, 9 = EmeraldBlock, *
-GoldIngot, 9 = GoldBlock, *
-IronIngot = IronNugget, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
-IronIngot, 9 = IronBlock, *
-LapisLazuli, 9 = LapisBlock, *
-RedstoneDust, 9 = RedstoneBlock, *
-SlimeBall, 9 = SlimeBlock, *
-
-AcaciaFence, 3 = AcaciaPlanks, 1:1, 1:2, 3:1, 3:2 | Stick, 2:1, 2:2
-AcaciaFenceGate = Stick, 1:1, 1:2, 3:1, 3:2 | AcaciaPlanks, 2:1, 2:2
-Anvil = IronBlock, 1:1, 2:1, 3:1 | IronIngot, 2:2, 1:3, 2:3, 3:3
-ArmorStand = Stick, 1:1, 1:3, 2:1, 2:2, 3:1, 3:3 | StoneSlab, 2:3
-Beacon = Glass, 1:1, 1:2, 2:1, 3:1, 3:2 | Obsidian, 1:3, 2:3, 3:3 | NetherStar, 2:2
-BirchFence, 3 = BirchPlanks, 1:1, 1:2, 3:1, 3:2 | Stick, 2:1, 2:2
-BirchFenceGate = Stick, 1:1, 1:2, 3:1, 3:2 | BirchPlanks, 2:1, 2:2
-Bookandquill = Book, * | feather, * | inksac, *
-Book = Paper, *, *, * | leather, *
-Cobblestonewall, 6 = cobblestone, 1:2, 1:3, 2:2, 2:3, 3:2, 3:3
-DarkOakFence, 3 = DarkOakPlanks, 1:1, 1:2, 3:1, 3:2 | Stick, 2:1, 2:2
-DarkOakFenceGate = Stick, 1:1, 1:2, 3:1, 3:2 | DarkOakPlanks, 2:1, 2:2
-EndCrystal = Glass, 1:1, 1:2, 1:3, 2:1, 3:1, 3:2, 3:3 | EyeOfEnder, 2:2 | GhastTear, 2:3
-EndRod, 4 = BlazeRod, 1:1 | PoppedChorusFruit, 1:2
-EyeOfEnder = EnderPearl, * | BlazePowder, *
-Fence, 3 = OakPlanks, 1:1, 1:2, 3:1, 3:2 | Stick, 2:1, 2:2
-FenceGate = Stick, 1:1, 1:2, 3:1, 3:2 | OakPlanks, 2:1, 2:2
-FlowerPot = Brick, 1:2, 2:3, 3:2
-GlassPane, 16 = Glass, 1:1, 2:1, 3:1, 1:2, 2:2, 3:2
-GoldIngot = GoldNugget, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
-IronBars, 16 = IronIngot, 1:1, 2:1, 3:1, 1:2, 2:2, 3:2
-IronNugget, 9 = IronIngot, *
-ItemFrame = Stick, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | Leather, 2:2
-JungleFence, 3 = JunglePlanks, 1:1, 1:2, 3:1, 3:2 | Stick, 2:1, 2:2
-JungleFenceGate = Stick, 1:1, 1:2, 3:1, 3:2 | JunglePlanks, 2:1, 2:2
-Ladder, 3 = Stick, 1:1, 3:1, 1:2, 2:2, 3:2, 1:3, 3:3
-mossycobblestonewall, 6 = mossycobblestone, 1:2, 1:3, 2:2, 2:3, 3:2, 3:3
-NetherBrickFence, 6 = NetherBrickBlock, 1:1, 2:1, 3:1, 1:2, 2:2, 3:2
-Painting = Stick, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | Wool^-1, 2:2
-Paper, 3 = Sugarcane, 1:1, 2:1, 3:1
-Sign, 3 = Planks^-1, 1:1, 2:1, 3:1, 1:2, 2:2, 3:2 | Stick, 2:3
-SpruceFence, 3 = SprucePlanks, 1:1, 1:2, 3:1, 3:2 | Stick, 2:1, 2:2
-SpruceFenceGate = Stick, 1:1, 1:2, 3:1, 3:2 | SprucePlanks, 2:1, 2:2
+terracotta: Clay, 4 = ClayBlock, *
+coal: Coal, 9 = CoalBlock, *
+diamond: Diamond, 9 = DiamondBlock, *
+emerald: Emerald, 9 = EmeraldBlock, *
+gold_ingot_from_gold_block: GoldIngot, 9 = GoldBlock, *
+iron_ingot_from_nuggets: IronIngot = IronNugget, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
+iron_ingot_from_iron_block: IronIngot, 9 = IronBlock, *
+lapis_lazuli: LapisLazuli, 9 = LapisBlock, *
+redstone: RedstoneDust, 9 = RedstoneBlock, *
+slime_ball: SlimeBall, 9 = SlimeBlock, *
+
+acacia_fence: AcaciaFence, 3 = AcaciaPlanks, 1:1, 1:2, 3:1, 3:2 | Stick, 2:1, 2:2
+acacia_fence_gate: AcaciaFenceGate = Stick, 1:1, 1:2, 3:1, 3:2 | AcaciaPlanks, 2:1, 2:2
+anvil: Anvil = IronBlock, 1:1, 2:1, 3:1 | IronIngot, 2:2, 1:3, 2:3, 3:3
+armor_stand: ArmorStand = Stick, 1:1, 1:3, 2:1, 2:2, 3:1, 3:3 | StoneSlab, 2:3
+beacon: Beacon = Glass, 1:1, 1:2, 2:1, 3:1, 3:2 | Obsidian, 1:3, 2:3, 3:3 | NetherStar, 2:2
+birch_fence: BirchFence, 3 = BirchPlanks, 1:1, 1:2, 3:1, 3:2 | Stick, 2:1, 2:2
+birch_fence_gate: BirchFenceGate = Stick, 1:1, 1:2, 3:1, 3:2 | BirchPlanks, 2:1, 2:2
+writable_book: Bookandquill = Book, * | feather, * | inksac, *
+book: Book = Paper, *, *, * | leather, *
+cobblestone_wall: Cobblestonewall, 6 = cobblestone, 1:2, 1:3, 2:2, 2:3, 3:2, 3:3
+dark_oak_fence: DarkOakFence, 3 = DarkOakPlanks, 1:1, 1:2, 3:1, 3:2 | Stick, 2:1, 2:2
+dark_oak_fence_gate: DarkOakFenceGate = Stick, 1:1, 1:2, 3:1, 3:2 | DarkOakPlanks, 2:1, 2:2
+end_crystal: EndCrystal = Glass, 1:1, 1:2, 1:3, 2:1, 3:1, 3:2, 3:3 | EyeOfEnder, 2:2 | GhastTear, 2:3
+end_rod: EndRod, 4 = BlazeRod, 1:1 | PoppedChorusFruit, 1:2
+ender_eye: EyeOfEnder = EnderPearl, * | BlazePowder, *
+oak_fence: Fence, 3 = OakPlanks, 1:1, 1:2, 3:1, 3:2 | Stick, 2:1, 2:2
+oak_fence_gate: FenceGate = Stick, 1:1, 1:2, 3:1, 3:2 | OakPlanks, 2:1, 2:2
+flower_pot: FlowerPot = Brick, 1:2, 2:3, 3:2
+glass_pane: GlassPane, 16 = Glass, 1:1, 2:1, 3:1, 1:2, 2:2, 3:2
+gold_ingot: GoldIngot = GoldNugget, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
+iron_bars: IronBars, 16 = IronIngot, 1:1, 2:1, 3:1, 1:2, 2:2, 3:2
+iron_nugget: IronNugget, 9 = IronIngot, *
+item_frame: ItemFrame = Stick, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | Leather, 2:2
+jungle_fence: JungleFence, 3 = JunglePlanks, 1:1, 1:2, 3:1, 3:2 | Stick, 2:1, 2:2
+jungle_fence_gate: JungleFenceGate = Stick, 1:1, 1:2, 3:1, 3:2 | JunglePlanks, 2:1, 2:2
+ladder: Ladder, 3 = Stick, 1:1, 3:1, 1:2, 2:2, 3:2, 1:3, 3:3
+mossy_cobblestone_wall: mossycobblestonewall, 6 = mossycobblestone, 1:2, 1:3, 2:2, 2:3, 3:2, 3:3
+nether_brick_fence: NetherBrickFence, 6 = NetherBrickBlock, 1:1, 2:1, 3:1, 1:2, 2:2, 3:2
+painting: Painting = Stick, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | Wool^-1, 2:2
+paper: Paper, 3 = Sugarcane, 1:1, 2:1, 3:1
+oak_sign: Sign, 3 = Planks^-1, 1:1, 2:1, 3:1, 1:2, 2:2, 3:2 | Stick, 2:3
+spruce_fence: SpruceFence, 3 = SprucePlanks, 1:1, 1:2, 3:1, 3:2 | Stick, 2:1, 2:2
+spruce_fence_gate: SpruceFenceGate = Stick, 1:1, 1:2, 3:1, 3:2 | SprucePlanks, 2:1, 2:2
# These are just the basic ones, you can add various shapes and stuff to each of them
# ToDo: Add the various shapes (saved in NBT-Tags, not in meta)
# Banners:
-BlackBanner = Stick, 2:3 | BlackWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
-BlueBanner = Stick, 2:3 | BlueWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
-BrownBanner = Stick, 2:3 | BrownWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
-CyanBanner = Stick, 2:3 | CyanWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
-GrayBanner = Stick, 2:3 | GrayWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
-GreenBanner = Stick, 2:3 | GreenWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
-LightBlueBanner = Stick, 2:3 | LightBlueWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
-LightGrayBanner = Stick, 2:3 | LightGrayWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
-LimeBanner = Stick, 2:3 | LimeWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
-MagentaBanner = Stick, 2:3 | MagentaWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
-OrangeBanner = Stick, 2:3 | OrangeWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
-PinkBanner = Stick, 2:3 | PinkWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
-PurpleBanner = Stick, 2:3 | PurpleWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
-RedBanner = Stick, 2:3 | RedWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
-WhiteBanner = Stick, 2:3 | WhiteWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
-YellowBanner = Stick, 2:3 | YellowWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
+black_banner: BlackBanner = Stick, 2:3 | BlackWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
+blue_banner: BlueBanner = Stick, 2:3 | BlueWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
+brown_banner: BrownBanner = Stick, 2:3 | BrownWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
+cyan_banner: CyanBanner = Stick, 2:3 | CyanWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
+gray_banner: GrayBanner = Stick, 2:3 | GrayWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
+green_banner: GreenBanner = Stick, 2:3 | GreenWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
+light_blue_banner: LightBlueBanner = Stick, 2:3 | LightBlueWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
+light_gray_banner: LightGrayBanner = Stick, 2:3 | LightGrayWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
+lime_banner: LimeBanner = Stick, 2:3 | LimeWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
+magenta_banner: MagentaBanner = Stick, 2:3 | MagentaWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
+orange_banner: OrangeBanner = Stick, 2:3 | OrangeWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
+pink_banner: PinkBanner = Stick, 2:3 | PinkWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
+purple_banner: PurpleBanner = Stick, 2:3 | PurpleWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
+red_banner: RedBanner = Stick, 2:3 | RedWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
+white_banner: WhiteBanner = Stick, 2:3 | WhiteWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
+yellow_banner: YellowBanner = Stick, 2:3 | YellowWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
@@ -440,28 +440,28 @@ YellowBanner = Stick, 2:3 | YellowWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
# Dyes
#
-RedDye, 1 = Beetroot, *
-RedDye, 2 = Rose, *
+red_dye_from_beetroot: RedDye, 1 = Beetroot, *
+red_dye_from_rose_bush: RedDye, 2 = Rose, *
WhiteDye, 3 = Bone, *
-YellowDye, 2 = Dandelion, *
+yellow_dye_from_dandelion: YellowDye, 2 = Dandelion, *
# Color mixing, duals:
-CyanDye, 2 = GreenDye, * | BlueDye, *
-GrayDye, 2 = BlackDye, * | WhiteDye, *
-LimeDye, 2 = GreenDye, * | WhiteDye, *
-LtBlueDye, 2 = BlueDye, * | WhiteDye, *
-LtGrayDye, 2 = GrayDye, * | WhiteDye, *
-MagentaDye, 2 = PurpleDye, * | PinkDye, *
-OrangeDye, 2 = YellowDye, * | RedDye, *
-PinkDye, 2 = RedDye, * | WhiteDye, *
-PurpleDye, 2 = RedDye, * | BlueDye, *
+cyan_dye: CyanDye, 2 = GreenDye, * | BlueDye, *
+gray_dye: GrayDye, 2 = BlackDye, * | WhiteDye, *
+lime_dye: LimeDye, 2 = GreenDye, * | WhiteDye, *
+light_blue_dye_from_blue_white_dye: LtBlueDye, 2 = BlueDye, * | WhiteDye, *
+light_gray_dye_from_gray_white_dye: LtGrayDye, 2 = GrayDye, * | WhiteDye, *
+magenta_dye_from_purple_and_pink: MagentaDye, 2 = PurpleDye, * | PinkDye, *
+orange_dye_from_red_yellow: OrangeDye, 2 = YellowDye, * | RedDye, *
+pink_dye_from_red_white_dye: PinkDye, 2 = RedDye, * | WhiteDye, *
+purple_dye: PurpleDye, 2 = RedDye, * | BlueDye, *
# triplets:
-LtGrayDye, 3 = BlackDye, * | WhiteDye, *, *
-MagentaDye, 3 = BlueDye, * | PinkDye, * | RedDye, *
+light_gray_dye_from_black_white_dye: LtGrayDye, 3 = BlackDye, * | WhiteDye, *, *
+magenta_dye_from_blue_red_pink: MagentaDye, 3 = BlueDye, * | PinkDye, * | RedDye, *
# quads:
-MagentaDye, 4 = BlueDye, * | WhiteDye, * | RedDye, *, *
+magenta_dye_from_blue_red_white_dye: MagentaDye, 4 = BlueDye, * | WhiteDye, * | RedDye, *, *
@@ -469,21 +469,21 @@ MagentaDye, 4 = BlueDye, * | WhiteDye, * | RedDye, *, *
#******************************************************#
# Concrete Powder:
#
-White_Concrete_Powder = Sand, 1:1, 3:1, 1:3, 3:3 | Gravel, 2:1, 1:2, 3:2, 2:3 | BoneMeal, 2:2
-Orange_Concrete_Powder = Sand, 1:1, 3:1, 1:3, 3:3 | Gravel, 2:1, 1:2, 3:2, 2:3 | OrangeDye, 2:2
-Magenta_Concrete_Powder = Sand, 1:1, 3:1, 1:3, 3:3 | Gravel, 2:1, 1:2, 3:2, 2:3 | MagentaDye, 2:2
-Light_Blue_Concrete_Powder = Sand, 1:1, 3:1, 1:3, 3:3 | Gravel, 2:1, 1:2, 3:2, 2:3 | LightBlueDye, 2:2
-Yellow_Concrete_Powder = Sand, 1:1, 3:1, 1:3, 3:3 | Gravel, 2:1, 1:2, 3:2, 2:3 | YellowDye, 2:2
-Lime_Concrete_Powder = Sand, 1:1, 3:1, 1:3, 3:3 | Gravel, 2:1, 1:2, 3:2, 2:3 | LimeDye, 2:2
-Pink_Concrete_Powder = Sand, 1:1, 3:1, 1:3, 3:3 | Gravel, 2:1, 1:2, 3:2, 2:3 | PinkDye, 2:2
-Gray_Concrete_Powder = Sand, 1:1, 3:1, 1:3, 3:3 | Gravel, 2:1, 1:2, 3:2, 2:3 | GrayDye, 2:2
-Light_Gray_Concrete_Powder = Sand, 1:1, 3:1, 1:3, 3:3 | Gravel, 2:1, 1:2, 3:2, 2:3 | LightGrayDye, 2:2
-Cyan_Concrete_Powder = Sand, 1:1, 3:1, 1:3, 3:3 | Gravel, 2:1, 1:2, 3:2, 2:3 | CyanDye, 2:2
-Blue_Concrete_Powder = Sand, 1:1, 3:1, 1:3, 3:3 | Gravel, 2:1, 1:2, 3:2, 2:3 | BlueDye, 2:2
-Brown_Concrete_Powder = Sand, 1:1, 3:1, 1:3, 3:3 | Gravel, 2:1, 1:2, 3:2, 2:3 | BrownDye, 2:2
-Green_Concrete_Powder = Sand, 1:1, 3:1, 1:3, 3:3 | Gravel, 2:1, 1:2, 3:2, 2:3 | GreenDye, 2:2
-Red_Concrete_Powder = Sand, 1:1, 3:1, 1:3, 3:3 | Gravel, 2:1, 1:2, 3:2, 2:3 | RedDye, 2:2
-Black_Concrete_Powder = Sand, 1:1, 3:1, 1:3, 3:3 | Gravel, 2:1, 1:2, 3:2, 2:3 | BlackDye, 2:2
+white_concrete_powder: White_Concrete_Powder = Sand, 1:1, 3:1, 1:3, 3:3 | Gravel, 2:1, 1:2, 3:2, 2:3 | BoneMeal, 2:2
+orange_concrete_powder: Orange_Concrete_Powder = Sand, 1:1, 3:1, 1:3, 3:3 | Gravel, 2:1, 1:2, 3:2, 2:3 | OrangeDye, 2:2
+magenta_concrete_powder: Magenta_Concrete_Powder = Sand, 1:1, 3:1, 1:3, 3:3 | Gravel, 2:1, 1:2, 3:2, 2:3 | MagentaDye, 2:2
+light_blue_concrete_powder: Light_Blue_Concrete_Powder = Sand, 1:1, 3:1, 1:3, 3:3 | Gravel, 2:1, 1:2, 3:2, 2:3 | LightBlueDye, 2:2
+yellow_concrete_powder: Yellow_Concrete_Powder = Sand, 1:1, 3:1, 1:3, 3:3 | Gravel, 2:1, 1:2, 3:2, 2:3 | YellowDye, 2:2
+lime_concrete_powder: Lime_Concrete_Powder = Sand, 1:1, 3:1, 1:3, 3:3 | Gravel, 2:1, 1:2, 3:2, 2:3 | LimeDye, 2:2
+pink_concrete_powder: Pink_Concrete_Powder = Sand, 1:1, 3:1, 1:3, 3:3 | Gravel, 2:1, 1:2, 3:2, 2:3 | PinkDye, 2:2
+gray_concrete_powder: Gray_Concrete_Powder = Sand, 1:1, 3:1, 1:3, 3:3 | Gravel, 2:1, 1:2, 3:2, 2:3 | GrayDye, 2:2
+light_gray_concrete_powder: Light_Gray_Concrete_Powder = Sand, 1:1, 3:1, 1:3, 3:3 | Gravel, 2:1, 1:2, 3:2, 2:3 | LightGrayDye, 2:2
+cyan_concrete_powder: Cyan_Concrete_Powder = Sand, 1:1, 3:1, 1:3, 3:3 | Gravel, 2:1, 1:2, 3:2, 2:3 | CyanDye, 2:2
+blue_concrete_powder: Blue_Concrete_Powder = Sand, 1:1, 3:1, 1:3, 3:3 | Gravel, 2:1, 1:2, 3:2, 2:3 | BlueDye, 2:2
+brown_concrete_powder: Brown_Concrete_Powder = Sand, 1:1, 3:1, 1:3, 3:3 | Gravel, 2:1, 1:2, 3:2, 2:3 | BrownDye, 2:2
+green_concrete_powder: Green_Concrete_Powder = Sand, 1:1, 3:1, 1:3, 3:3 | Gravel, 2:1, 1:2, 3:2, 2:3 | GreenDye, 2:2
+red_concrete_powder: Red_Concrete_Powder = Sand, 1:1, 3:1, 1:3, 3:3 | Gravel, 2:1, 1:2, 3:2, 2:3 | RedDye, 2:2
+black_concrete_powder: Black_Concrete_Powder = Sand, 1:1, 3:1, 1:3, 3:3 | Gravel, 2:1, 1:2, 3:2, 2:3 | BlackDye, 2:2
#******************************************************#
# Colored shulker boxes:
@@ -748,118 +748,118 @@ YellowShulkerBox = YellowShulkerBox, * | YellowDye, *
#******************************************************#
# Colored wool:
#
-BlackWool = WhiteWool, * | BlackDye, *
-BlueWool = WhiteWool, * | BlueDye, *
-BrownWool = WhiteWool, * | BrownDye, *
-CyanWool = WhiteWool, * | CyanDye, *
-GrayWool = WhiteWool, * | GrayDye, *
-GreenWool = WhiteWool, * | GreenDye, *
-LightBlueWool = WhiteWool, * | LightBlueDye, *
-LightGrayWool = WhiteWool, * | LightGrayDye, *
-LimeWool = WhiteWool, * | LimeDye, *
-MagentaWool = WhiteWool, * | MagentaDye, *
-OrangeWool = WhiteWool, * | OrangeDye, *
-PinkWool = WhiteWool, * | PinkDye, *
-PurpleWool = WhiteWool, * | PurpleDye, *
-RedWool = WhiteWool, * | RedDye, *
+black_wool: BlackWool = WhiteWool, * | BlackDye, *
+blue_wool: BlueWool = WhiteWool, * | BlueDye, *
+brown_wool: BrownWool = WhiteWool, * | BrownDye, *
+cyan_wool: CyanWool = WhiteWool, * | CyanDye, *
+gray_wool: GrayWool = WhiteWool, * | GrayDye, *
+green_wool: GreenWool = WhiteWool, * | GreenDye, *
+light_blue_wool: LightBlueWool = WhiteWool, * | LightBlueDye, *
+light_gray_wool: LightGrayWool = WhiteWool, * | LightGrayDye, *
+lime_wool: LimeWool = WhiteWool, * | LimeDye, *
+magenta_wool: MagentaWool = WhiteWool, * | MagentaDye, *
+orange_wool: OrangeWool = WhiteWool, * | OrangeDye, *
+pink_wool: PinkWool = WhiteWool, * | PinkDye, *
+purple_wool: PurpleWool = WhiteWool, * | PurpleDye, *
+red_wool: RedWool = WhiteWool, * | RedDye, *
WhiteWool = Wool^-1, * | BoneMeal, *
-YellowWool = WhiteWool, * | YellowDye, *
-
-BlackCarpet, 3 = BlackWool, 1:1, 2:1
-BlueCarpet, 3 = BlueWool, 1:1, 2:1
-BrownCarpet, 3 = BrownWool, 1:1, 2:1
-CyanCarpet, 3 = CyanWool, 1:1, 2:1
-GrayCarpet, 3 = GrayWool, 1:1, 2:1
-GreenCarpet, 3 = GreenWool, 1:1, 2:1
-LightBlueCarpet, 3 = LightBlueWool, 1:1, 2:1
-LightGrayCarpet, 3 = LightGrayWool, 1:1, 2:1
-LimeCarpet, 3 = LimeWool, 1:1, 2:1
-MagentaCarpet, 3 = MagentaWool, 1:1, 2:1
-OrangeCarpet, 3 = OrangeWool, 1:1, 2:1
-PinkCarpet, 3 = PinkWool, 1:1, 2:1
-PurpleCarpet, 3 = PurpleWool, 1:1, 2:1
-RedCarpet, 3 = RedWool, 1:1, 2:1
-WhiteCarpet, 3 = WhiteWool, 1:1, 2:1
-YellowCarpet, 3 = YellowWool, 1:1, 2:1
+yellow_wool: YellowWool = WhiteWool, * | YellowDye, *
+
+black_carpet: BlackCarpet, 3 = BlackWool, 1:1, 2:1
+blue_carpet: BlueCarpet, 3 = BlueWool, 1:1, 2:1
+brown_carpet: BrownCarpet, 3 = BrownWool, 1:1, 2:1
+cyan_carpet: CyanCarpet, 3 = CyanWool, 1:1, 2:1
+gray_carpet: GrayCarpet, 3 = GrayWool, 1:1, 2:1
+green_carpet: GreenCarpet, 3 = GreenWool, 1:1, 2:1
+light_blue_carpet: LightBlueCarpet, 3 = LightBlueWool, 1:1, 2:1
+light_gray_carpet: LightGrayCarpet, 3 = LightGrayWool, 1:1, 2:1
+lime_carpet: LimeCarpet, 3 = LimeWool, 1:1, 2:1
+magenta_carpet: MagentaCarpet, 3 = MagentaWool, 1:1, 2:1
+orange_carpet: OrangeCarpet, 3 = OrangeWool, 1:1, 2:1
+pink_carpet: PinkCarpet, 3 = PinkWool, 1:1, 2:1
+purple_carpet: PurpleCarpet, 3 = PurpleWool, 1:1, 2:1
+red_carpet: RedCarpet, 3 = RedWool, 1:1, 2:1
+white_carpet: WhiteCarpet, 3 = WhiteWool, 1:1, 2:1
+yellow_carpet: YellowCarpet, 3 = YellowWool, 1:1, 2:1
#******************************************************#
# Stained Glass:
#
-BlackStainedGlass, 8 = Glass, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | BlackDye, 2:2
-BlueStainedGlass, 8 = Glass, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | BlueDye, 2:2
-BrownStainedGlass, 8 = Glass, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | BrownDye, 2:2
-CyanStainedGlass, 8 = Glass, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | CyanDye, 2:2
-GrayStainedGlass, 8 = Glass, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | GrayDye, 2:2
-GreenStainedGlass, 8 = Glass, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | GreenDye, 2:2
-LightBlueStainedGlass, 8 = Glass, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | LightBlueDye, 2:2
-LightGrayStainedGlass, 8 = Glass, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | LightGrayDye, 2:2
-LimeStainedGlass, 8 = Glass, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | LimeDye, 2:2
-MagentaStainedGlass, 8 = Glass, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | MagentaDye, 2:2
-OrangeStainedGlass, 8 = Glass, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | OrangeDye, 2:2
-PinkStainedGlass, 8 = Glass, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | PinkDye, 2:2
-RedStainedGlass, 8 = Glass, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | RedDye, 2:2
-VioletStainedGlass, 8 = Glass, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | VioletDye, 2:2
-WhiteStainedGlass, 8 = Glass, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | BoneMeal, 2:2
-YellowStainedGlass, 8 = Glass, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | YellowDye, 2:2
+black_stained_glass: BlackStainedGlass, 8 = Glass, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | BlackDye, 2:2
+blue_stained_glass: BlueStainedGlass, 8 = Glass, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | BlueDye, 2:2
+brown_stained_glass: BrownStainedGlass, 8 = Glass, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | BrownDye, 2:2
+cyan_stained_glass: CyanStainedGlass, 8 = Glass, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | CyanDye, 2:2
+gray_stained_glass: GrayStainedGlass, 8 = Glass, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | GrayDye, 2:2
+green_stained_glass: GreenStainedGlass, 8 = Glass, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | GreenDye, 2:2
+light_blue_stained_glass: LightBlueStainedGlass, 8 = Glass, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | LightBlueDye, 2:2
+light_gray_stained_glass: LightGrayStainedGlass, 8 = Glass, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | LightGrayDye, 2:2
+lime_stained_glass: LimeStainedGlass, 8 = Glass, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | LimeDye, 2:2
+magenta_stained_glass: MagentaStainedGlass, 8 = Glass, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | MagentaDye, 2:2
+orange_stained_glass: OrangeStainedGlass, 8 = Glass, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | OrangeDye, 2:2
+pink_stained_glass: PinkStainedGlass, 8 = Glass, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | PinkDye, 2:2
+red_stained_glass: RedStainedGlass, 8 = Glass, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | RedDye, 2:2
+purple_stained_glass: VioletStainedGlass, 8 = Glass, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | VioletDye, 2:2
+white_stained_glass: WhiteStainedGlass, 8 = Glass, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | BoneMeal, 2:2
+yellow_stained_glass: YellowStainedGlass, 8 = Glass, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | YellowDye, 2:2
#******************************************************#
# Stained Glass Pane:
#
-BlackStainedGlassPane , 16 = BlackStainedGlass, 1:2, 1:3, 2:2, 2:3, 3:2, 3:3
-BlueStainedGlassPane, 16 = BlueStainedGlass, 1:2, 1:3, 2:2, 2:3, 3:2, 3:3
-BrownStainedGlassPane, 16 = BrownStainedGlass, 1:2, 1:3, 2:2, 2:3, 3:2, 3:3
-CyanStainedGlassPane, 16 = CyanStainedGlass, 1:2, 1:3, 2:2, 2:3, 3:2, 3:3
-GrayStainedGlassPane, 16 = GrayStainedGlass, 1:2, 1:3, 2:2, 2:3, 3:2, 3:3
-GreenStainedGlassPane, 16 = GreenStainedGlass, 1:2, 1:3, 2:2, 2:3, 3:2, 3:3
-LightBlueStainedGlassPane, 16 = LightBlueStainedGlass, 1:2, 1:3, 2:2, 2:3, 3:2, 3:3
-LightGrayStainedGlassPane, 16 = LightGrayStainedGlass, 1:2, 1:3, 2:2, 2:3, 3:2, 3:3
-LimeStainedGlassPane, 16 = LimeStainedGlass, 1:2, 1:3, 2:2, 2:3, 3:2, 3:3
-MagentaStainedGlassPane, 16 = MagentaStainedGlass, 1:2, 1:3, 2:2, 2:3, 3:2, 3:3
-OrangeStainedGlassPane, 16 = OrangeStainedGlass, 1:2, 1:3, 2:2, 2:3, 3:2, 3:3
-PinkStainedGlassPane, 16 = PinkStainedGlass, 1:2, 1:3, 2:2, 2:3, 3:2, 3:3
-RedStainedGlassPane, 16 = RedStainedGlass, 1:2, 1:3, 2:2, 2:3, 3:2, 3:3
-VioletStainedGlassPane, 16 = VioletStainedGlass, 1:2, 1:3, 2:2, 2:3, 3:2, 3:3
-WhiteStainedGlassPane, 16 = WhiteStainedGlass, 1:2, 1:3, 2:2, 2:3, 3:2, 3:3
-YellowStainedGlassPane, 16 = YellowStainedGlass, 1:2, 1:3, 2:2, 2:3, 3:2, 3:3
+black_stained_glass_pane: BlackStainedGlassPane , 16 = BlackStainedGlass, 1:2, 1:3, 2:2, 2:3, 3:2, 3:3
+blue_stained_glass_pane: BlueStainedGlassPane, 16 = BlueStainedGlass, 1:2, 1:3, 2:2, 2:3, 3:2, 3:3
+brown_stained_glass_pane: BrownStainedGlassPane, 16 = BrownStainedGlass, 1:2, 1:3, 2:2, 2:3, 3:2, 3:3
+cyan_stained_glass_pane: CyanStainedGlassPane, 16 = CyanStainedGlass, 1:2, 1:3, 2:2, 2:3, 3:2, 3:3
+gray_stained_glass_pane: GrayStainedGlassPane, 16 = GrayStainedGlass, 1:2, 1:3, 2:2, 2:3, 3:2, 3:3
+green_stained_glass_pane: GreenStainedGlassPane, 16 = GreenStainedGlass, 1:2, 1:3, 2:2, 2:3, 3:2, 3:3
+light_blue_stained_glass_pane: LightBlueStainedGlassPane, 16 = LightBlueStainedGlass, 1:2, 1:3, 2:2, 2:3, 3:2, 3:3
+light_gray_stained_glass_pane: LightGrayStainedGlassPane, 16 = LightGrayStainedGlass, 1:2, 1:3, 2:2, 2:3, 3:2, 3:3
+lime_stained_glass_pane: LimeStainedGlassPane, 16 = LimeStainedGlass, 1:2, 1:3, 2:2, 2:3, 3:2, 3:3
+magenta_stained_glass_pane: MagentaStainedGlassPane, 16 = MagentaStainedGlass, 1:2, 1:3, 2:2, 2:3, 3:2, 3:3
+orange_stained_glass_pane: OrangeStainedGlassPane, 16 = OrangeStainedGlass, 1:2, 1:3, 2:2, 2:3, 3:2, 3:3
+pink_stained_glass_pane: PinkStainedGlassPane, 16 = PinkStainedGlass, 1:2, 1:3, 2:2, 2:3, 3:2, 3:3
+red_stained_glass_pane: RedStainedGlassPane, 16 = RedStainedGlass, 1:2, 1:3, 2:2, 2:3, 3:2, 3:3
+purple_stained_glass_pane: VioletStainedGlassPane, 16 = VioletStainedGlass, 1:2, 1:3, 2:2, 2:3, 3:2, 3:3
+white_stained_glass_pane: WhiteStainedGlassPane, 16 = WhiteStainedGlass, 1:2, 1:3, 2:2, 2:3, 3:2, 3:3
+yellow_stained_glass_pane: YellowStainedGlassPane, 16 = YellowStainedGlass, 1:2, 1:3, 2:2, 2:3, 3:2, 3:3
#******************************************************#
# Stained Clay:
#
-BlackStainedClay, 8 = HardenedClay, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | BlackDye, 2:2
-BlueStainedClay, 8 = HardenedClay, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | BlueDye, 2:2
-BrownStainedClay, 8 = HardenedClay, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | BrownDye, 2:2
-CyanStainedClay, 8 = HardenedClay, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | CyanDye, 2:2
-GrayStainedClay, 8 = HardenedClay, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | GrayDye, 2:2
-GreenStainedClay, 8 = HardenedClay, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | GreenDye, 2:2
-LightBlueStainedClay, 8 = HardenedClay, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | LightBlueDye, 2:2
-LightGrayStainedClay, 8 = HardenedClay, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | LightGrayDye, 2:2
-LimeStainedClay, 8 = HardenedClay, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | LimeDye, 2:2
-MagentaStainedClay, 8 = HardenedClay, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | MagentaDye, 2:2
-OrangeStainedClay, 8 = HardenedClay, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | OrangeDye, 2:2
-PinkStainedClay, 8 = HardenedClay, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | PinkDye, 2:2
+black_terracotta: BlackStainedClay, 8 = HardenedClay, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | BlackDye, 2:2
+blue_terracotta: BlueStainedClay, 8 = HardenedClay, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | BlueDye, 2:2
+brown_terracotta: BrownStainedClay, 8 = HardenedClay, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | BrownDye, 2:2
+cyan_terracotta: CyanStainedClay, 8 = HardenedClay, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | CyanDye, 2:2
+gray_terracotta: GrayStainedClay, 8 = HardenedClay, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | GrayDye, 2:2
+green_terracotta: GreenStainedClay, 8 = HardenedClay, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | GreenDye, 2:2
+light_blue_terracotta: LightBlueStainedClay, 8 = HardenedClay, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | LightBlueDye, 2:2
+light_gray_terracotta: LightGrayStainedClay, 8 = HardenedClay, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | LightGrayDye, 2:2
+lime_terracotta: LimeStainedClay, 8 = HardenedClay, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | LimeDye, 2:2
+magenta_terracotta: MagentaStainedClay, 8 = HardenedClay, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | MagentaDye, 2:2
+orange_terracotta: OrangeStainedClay, 8 = HardenedClay, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | OrangeDye, 2:2
+pink_terracotta: PinkStainedClay, 8 = HardenedClay, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | PinkDye, 2:2
RedStainedClay, 8 = HardenedClay, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | RedDye, 2:2
-VioletStainedClay, 8 = HardenedClay, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | VioletDye, 2:2
+purple_terracotta: VioletStainedClay, 8 = HardenedClay, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | VioletDye, 2:2
WhiteStainedClay, 8 = HardenedClay, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | BoneMeal, 2:2
-YellowStainedClay, 8 = HardenedClay, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | YellowDye, 2:2
+yellow_terracotta: YellowStainedClay, 8 = HardenedClay, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | YellowDye, 2:2
#******************************************************#
# Enchantment & Brewing
#
-BlazePowder, 2 = BlazeRod, *
-BrewingStand = Cobblestone, 1:2, 2:2, 3:2 | BlazeRod, 2:1
-Cauldron = IronIngot, 1:1, 3:1, 1:2, 3:2, 1:3, 2:3, 3:3
-EnchantmentTable = Obsidian, 1:3, 2:3, 3:3, 2:2 | Diamond, 1:2, 3:2 | Book, 2:1
-FermentedSpiderEye = SpiderEye, * | Sugar, * | BrownMushroom, *
-GlassBottle, 3 = Glass, 1:1, 2:2, 3:1
-GlisteringMelon = MelonSlice, 2:2 | GoldNugget, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3
-GoldenCarrot = Carrot, 2:2 | GoldNugget, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3
-GoldNugget, 9 = GoldIngot, *
-MagmaCream = SlimeBall, * | BlazePowder, *
+blaze_powder: BlazePowder, 2 = BlazeRod, *
+brewing_stand: BrewingStand = Cobblestone, 1:2, 2:2, 3:2 | BlazeRod, 2:1
+cauldron: Cauldron = IronIngot, 1:1, 3:1, 1:2, 3:2, 1:3, 2:3, 3:3
+enchanting_table: EnchantmentTable = Obsidian, 1:3, 2:3, 3:3, 2:2 | Diamond, 1:2, 3:2 | Book, 2:1
+fermented_spider_eye: FermentedSpiderEye = SpiderEye, * | Sugar, * | BrownMushroom, *
+glass_bottle: GlassBottle, 3 = Glass, 1:1, 2:2, 3:1
+glistering_melon_slice: GlisteringMelon = MelonSlice, 2:2 | GoldNugget, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3
+golden_carrot: GoldenCarrot = Carrot, 2:2 | GoldNugget, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3
+gold_nugget: GoldNugget, 9 = GoldIngot, *
+magma_cream: MagmaCream = SlimeBall, * | BlazePowder, *
#******************************************************#
# Dyed Armor
# Do not modify
-LeatherHelmet = LeatherHelmet^-1, * | Dye^-1, *
+leather_helmet: LeatherHelmet = LeatherHelmet^-1, * | Dye^-1, *
LeatherHelmet = LeatherHelmet^-1, * | Dye^-1, * | Dye^-1, *
LeatherHelmet = LeatherHelmet^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, *
LeatherHelmet = LeatherHelmet^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, *
@@ -868,7 +868,7 @@ LeatherHelmet = LeatherHelmet^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1
LeatherHelmet = LeatherHelmet^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, *
LeatherHelmet = LeatherHelmet^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, *
-LeatherChestplate = LeatherChestplate^-1, * | Dye^-1, *
+leather_chestplate: LeatherChestplate = LeatherChestplate^-1, * | Dye^-1, *
LeatherChestplate = LeatherChestplate^-1, * | Dye^-1, * | Dye^-1, *
LeatherChestplate = LeatherChestplate^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, *
LeatherChestplate = LeatherChestplate^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, *
@@ -877,7 +877,7 @@ LeatherChestplate = LeatherChestplate^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, *
LeatherChestplate = LeatherChestplate^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, *
LeatherChestplate = LeatherChestplate^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, *
-LeatherPants = LeatherPants^-1, * | Dye^-1, *
+leather_leggings: LeatherPants = LeatherPants^-1, * | Dye^-1, *
LeatherPants = LeatherPants^-1, * | Dye^-1, * | Dye^-1, *
LeatherPants = LeatherPants^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, *
LeatherPants = LeatherPants^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, *
@@ -886,7 +886,7 @@ LeatherPants = LeatherPants^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1,
LeatherPants = LeatherPants^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, *
LeatherPants = LeatherPants^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, *
-LeatherBoots = LeatherBoots^-1, * | Dye^-1, *
+leather_boots: LeatherBoots = LeatherBoots^-1, * | Dye^-1, *
LeatherBoots = LeatherBoots^-1, * | Dye^-1, * | Dye^-1, *
LeatherBoots = LeatherBoots^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, *
LeatherBoots = LeatherBoots^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, *
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index 3cad17849..9fbc9f89d 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -14,6 +14,8 @@
#include "BlockEntities/ChestEntity.h"
#include "BlockEntities/CommandBlockEntity.h"
#include "BlockEntities/SignEntity.h"
+#include "UI/InventoryWindow.h"
+#include "UI/CraftingWindow.h"
#include "UI/Window.h"
#include "UI/AnvilWindow.h"
#include "UI/BeaconWindow.h"
@@ -1692,7 +1694,7 @@ void cClientHandle::HandleWindowClick(UInt8 a_WindowID, Int16 a_SlotNum, eClickA
LOGWARNING("Player \"%s\" clicked in a non-existent window. Ignoring", m_Username.c_str());
return;
}
-
+ m_Player->AddKnownItem(a_HeldItem);
Window->Clicked(*m_Player, a_WindowID, a_SlotNum, a_ClickAction, a_HeldItem);
}
@@ -3129,6 +3131,46 @@ void cClientHandle::SendUseBed(const cEntity & a_Entity, int a_BlockX, int a_Blo
+void cClientHandle::SendUnlockRecipe(UInt32 a_RecipeId)
+{
+ m_Protocol->SendUnlockRecipe(a_RecipeId);
+}
+
+
+
+
+
+void cClientHandle::SendInitRecipes(UInt32 a_RecipeId)
+{
+ m_Protocol->SendInitRecipes(a_RecipeId);
+}
+
+
+
+
+
+void cClientHandle::HandleCraftRecipe(UInt32 a_RecipeId)
+{
+ auto * Window = m_Player->GetWindow();
+ if (Window == nullptr)
+ {
+ return;
+ }
+
+ if (Window->GetWindowType() == cWindow::wtInventory)
+ {
+ static_cast<cInventoryWindow *>(Window)->LoadRecipe(*m_Player, a_RecipeId);
+ }
+ else if (Window->GetWindowType() == cWindow::wtWorkbench)
+ {
+ static_cast<cCraftingWindow *>(Window)->LoadRecipe(*m_Player, a_RecipeId);
+ }
+}
+
+
+
+
+
void cClientHandle::SendWeather(eWeather a_Weather)
{
m_Protocol->SendWeather(a_Weather);
diff --git a/src/ClientHandle.h b/src/ClientHandle.h
index 8495fb239..1d988b137 100644
--- a/src/ClientHandle.h
+++ b/src/ClientHandle.h
@@ -221,6 +221,13 @@ public: // tolua_export
void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity);
void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4);
void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ);
+
+ /** Send a newly discovered recipe to show the notification and unlock in the recipe book */
+ void SendUnlockRecipe (UInt32 a_RecipeId);
+
+ /** Send already known recipes without notification but visible in the recipe book */
+ void SendInitRecipes (UInt32 a_RecipeId);
+
void SendWeather (eWeather a_Weather);
void SendWholeInventory (const cWindow & a_Window);
void SendWindowClose (const cWindow & a_Window);
@@ -371,6 +378,9 @@ public: // tolua_export
void HandleWindowClick (UInt8 a_WindowID, Int16 a_SlotNum, eClickAction a_ClickAction, const cItem & a_HeldItem);
void HandleWindowClose (UInt8 a_WindowID);
+ /** Called when a recipe from the recipe book is selected */
+ void HandleCraftRecipe (UInt32 a_RecipeId);
+
/** Called when the protocol has finished logging the user in.
Return true to allow the user in; false to kick them.
*/
diff --git a/src/CraftingRecipes.cpp b/src/CraftingRecipes.cpp
index bdc98e151..7cd41ec97 100644
--- a/src/CraftingRecipes.cpp
+++ b/src/CraftingRecipes.cpp
@@ -268,6 +268,7 @@ void cCraftingRecipe::Dump(void)
cCraftingRecipes::cCraftingRecipes(void)
{
LoadRecipes();
+ PopulateRecipeNameMap();
}
@@ -283,6 +284,72 @@ cCraftingRecipes::~cCraftingRecipes()
+bool cCraftingRecipes::IsNewCraftableRecipe(const cRecipe * a_Recipe, const cItem & a_Item, const std::set<cItem, cItem::sItemCompare> & a_KnownItems)
+{
+ bool ContainsNewItem = false;
+ for (const auto & Ingredient : a_Recipe->m_Ingredients)
+ {
+ if (
+ (Ingredient.m_Item.m_ItemType == a_Item.m_ItemType) &&
+ (
+ (Ingredient.m_Item.m_ItemDamage == a_Item.m_ItemDamage) ||
+ (Ingredient.m_Item.m_ItemDamage == -1)
+ )
+ )
+ {
+ ContainsNewItem = true;
+ }
+ if (a_KnownItems.find(Ingredient.m_Item) == a_KnownItems.end())
+ {
+ return false;
+ }
+ }
+ return ContainsNewItem;
+}
+
+
+
+
+
+std::vector<UInt32> cCraftingRecipes::FindNewRecipesForItem(const cItem & a_Item, const std::set<cItem, cItem::sItemCompare> & a_KnownItems)
+{
+ std::vector<UInt32> Recipes;
+ for (UInt32 i = 0; i < m_Recipes.size(); i++)
+ {
+ if (m_Recipes[i]->m_RecipeName.empty())
+ {
+ continue;
+ }
+ if (IsNewCraftableRecipe(m_Recipes[i], a_Item, a_KnownItems))
+ {
+ Recipes.push_back(i);
+ }
+ }
+ return Recipes;
+}
+
+
+
+
+
+const std::map<AString, UInt32> & cCraftingRecipes::GetRecipeNameMap()
+{
+ return m_RecipeNameMap;
+}
+
+
+
+
+
+cCraftingRecipes::cRecipe * cCraftingRecipes::GetRecipeById(UInt32 a_RecipeId)
+{
+ return m_Recipes[a_RecipeId];
+}
+
+
+
+
+
void cCraftingRecipes::GetRecipe(cPlayer & a_Player, cCraftingGrid & a_CraftingGrid, cCraftingRecipe & a_Recipe)
{
// Allow plugins to intercept recipes using a pre-craft hook:
@@ -355,6 +422,21 @@ void cCraftingRecipes::LoadRecipes(void)
+void cCraftingRecipes::PopulateRecipeNameMap(void)
+{
+ for (UInt32 i = 0; i < m_Recipes.size(); i++)
+ {
+ if (!m_Recipes[i]->m_RecipeName.empty())
+ {
+ m_RecipeNameMap.emplace(m_Recipes[i]->m_RecipeName, i);
+ }
+ }
+}
+
+
+
+
+
void cCraftingRecipes::ClearRecipes(void)
{
for (cRecipes::iterator itr = m_Recipes.begin(); itr != m_Recipes.end(); ++itr)
@@ -384,8 +466,15 @@ void cCraftingRecipes::AddRecipeLine(int a_LineNum, const AString & a_RecipeLine
std::unique_ptr<cCraftingRecipes::cRecipe> Recipe = cpp14::make_unique<cCraftingRecipes::cRecipe>();
+ AStringVector RecipeSplit = StringSplit(Sides[0], ":");
+ const auto * resultPart = &RecipeSplit[0];
+ if (RecipeSplit.size() > 1)
+ {
+ resultPart = &RecipeSplit[1];
+ Recipe->m_RecipeName = RecipeSplit[0];
+ }
// Parse the result:
- AStringVector ResultSplit = StringSplit(Sides[0], ",");
+ AStringVector ResultSplit = StringSplit(*resultPart, ",");
if (ResultSplit.empty())
{
LOGWARNING("crafting.txt: line %d: Result is empty, ignoring the recipe.", a_LineNum);
@@ -1059,7 +1148,3 @@ void cCraftingRecipes::HandleDyedLeather(const cItem * a_CraftingGrid, cCrafting
a_Recipe->m_Result.m_ItemColor.SetColor(result_red, result_green, result_blue);
}
}
-
-
-
-
diff --git a/src/CraftingRecipes.h b/src/CraftingRecipes.h
index 9659e53fc..7e4ac86ae 100644
--- a/src/CraftingRecipes.h
+++ b/src/CraftingRecipes.h
@@ -10,10 +10,6 @@
#include "Item.h"
-
-
-
-
// fwd: cPlayer.h
class cPlayer;
@@ -104,7 +100,20 @@ protected:
+/**
+The crafting recipes are the configurations to build a result item out of a set
+of ingredient items.
+
+The recipes are configured in the `crafting.txt`. When populating the crafting
+grid in game (inventory or crafting table), the items are compared to the
+ingredients to find a matching recipe and show and craft the result.
+Each recipe is defined via the result, the ingredients and the minecraft recipe
+name.
+
+To handle the crafting recipes internally efficient the vector index of the
+`cRecipes` is used as `RecipeId`.
+*/
class cCraftingRecipes
{
public:
@@ -117,7 +126,8 @@ public:
/** Returns the recipe for current crafting grid. Doesn't modify the grid. Clears a_Recipe if no recipe found. */
void GetRecipe(cPlayer & a_Player, cCraftingGrid & a_CraftingGrid, cCraftingRecipe & a_Recipe);
-protected:
+ /** Find recipes and returns the RecipeIds which contain the new item and all ingredients are in the known items */
+ std::vector<UInt32> FindNewRecipesForItem(const cItem & a_Item, const std::set<cItem, cItem::sItemCompare> & a_KnownItems);
struct cRecipeSlot
{
@@ -132,11 +142,21 @@ protected:
{
cRecipeSlots m_Ingredients;
cItem m_Result;
+ AString m_RecipeName;
// Size of the regular items in the recipe; "anywhere" items are excluded:
int m_Width;
int m_Height;
} ;
+
+ /** Returns the recipe by id */
+ cRecipe * GetRecipeById(UInt32 a_RecipeId);
+
+ /** Gets a map of all recipes with name and recipe id */
+ const std::map<AString, UInt32> & GetRecipeNameMap();
+
+protected:
+
typedef std::vector<cRecipe *> cRecipes;
cRecipes m_Recipes;
@@ -170,8 +190,22 @@ protected:
/** Searches for anything dye related for leather, calculates the appropriate color value, and sets the resulting value. */
void HandleDyedLeather(const cItem * a_CraftingGrid, cCraftingRecipes::cRecipe * a_Recipe, int a_GridStride, int a_GridWidth, int a_GridHeight);
-} ;
-
-
-
+private:
+ /** Mapping the minecraft recipe names to the internal cuberite recipe Ids */
+ std::map<AString, UInt32> m_RecipeNameMap;
+
+ /**
+ Checks if all ingredients of the a_Recipe are within the a_KnownItems list and
+ if the a_NewItem is part of the ingredients.
+ This makes sure to only find 'newly discovered' recipes.
+ */
+ bool IsNewCraftableRecipe(
+ const cRecipe * a_Recipe,
+ const cItem & a_NewItem,
+ const std::set<cItem, cItem::sItemCompare> & a_KnownItems
+ );
+
+ /** Populates the RecipeNameMap */
+ void PopulateRecipeNameMap(void);
+} ;
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index d5d9f49af..df410575e 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -31,6 +31,8 @@
#include "../JsonUtils.h"
#include "json/json.h"
+#include "../CraftingRecipes.h"
+
// 6000 ticks or 5 minutes
#define PLAYER_INVENTORY_SAVE_INTERVAL 6000
@@ -194,6 +196,18 @@ bool cPlayer::Initialize(OwnedEntity a_Self, cWorld & a_World)
cPluginManager::Get()->CallHookSpawnedEntity(*GetWorld(), *this);
+ if (m_KnownRecipes.empty())
+ {
+ m_ClientHandle->SendInitRecipes(0);
+ }
+ else
+ {
+ for (const auto KnownRecipe : m_KnownRecipes)
+ {
+ m_ClientHandle->SendInitRecipes(KnownRecipe);
+ }
+ }
+
return true;
}
@@ -201,6 +215,47 @@ bool cPlayer::Initialize(OwnedEntity a_Self, cWorld & a_World)
+void cPlayer::AddKnownItem(const cItem & a_Item)
+{
+ if (a_Item.m_ItemType < 0)
+ {
+ return;
+ }
+
+ auto Response = m_KnownItems.insert(a_Item.CopyOne());
+ if (!Response.second)
+ {
+ // The item was already known, bail out:
+ return;
+ }
+
+ // Process the recipes that got unlocked by this newly-known item:
+ auto Recipes = cRoot::Get()->GetCraftingRecipes()->FindNewRecipesForItem(a_Item, m_KnownItems);
+ for (const auto & RecipeId : Recipes)
+ {
+ AddKnownRecipe(RecipeId);
+ }
+}
+
+
+
+
+
+void cPlayer::AddKnownRecipe(UInt32 a_RecipeId)
+{
+ auto Response = m_KnownRecipes.insert(a_RecipeId);
+ if (!Response.second)
+ {
+ // The recipe was already known, bail out:
+ return;
+ }
+ m_ClientHandle->SendUnlockRecipe(a_RecipeId);
+}
+
+
+
+
+
cPlayer::~cPlayer(void)
{
if (!cRoot::Get()->GetPluginManager()->CallHookPlayerDestroyed(*this))
@@ -2229,6 +2284,26 @@ bool cPlayer::LoadFromFile(const AString & a_FileName, cWorldPtr & a_World)
m_CurrentXp = root.get("xpCurrent", 0).asInt();
m_IsFlying = root.get("isflying", 0).asBool();
+ Json::Value & JSON_KnownItems = root["knownItems"];
+ for (UInt32 i = 0; i < JSON_KnownItems.size(); i++)
+ {
+ cItem Item;
+ Item.FromJson(JSON_KnownItems[i]);
+ m_KnownItems.insert(Item);
+ }
+
+ const auto & RecipeNameMap = cRoot::Get()->GetCraftingRecipes()->GetRecipeNameMap();
+
+ Json::Value & JSON_KnownRecipes = root["knownRecipes"];
+ for (UInt32 i = 0; i < JSON_KnownRecipes.size(); i++)
+ {
+ auto RecipeId = RecipeNameMap.find(JSON_KnownRecipes[i].asString());
+ if (RecipeId != RecipeNameMap.end())
+ {
+ m_KnownRecipes.insert(RecipeId->second);
+ }
+ }
+
m_GameMode = static_cast<eGameMode>(root.get("gamemode", eGameMode_NotSet).asInt());
if (m_GameMode == eGameMode_Creative)
@@ -2327,10 +2402,27 @@ bool cPlayer::SaveToDisk()
Json::Value JSON_EnderChestInventory;
cEnderChestEntity::SaveToJson(JSON_EnderChestInventory, m_EnderChestContents);
+ Json::Value JSON_KnownItems;
+ for (const auto & KnownItem : m_KnownItems)
+ {
+ Json::Value JSON_Item;
+ KnownItem.GetJson(JSON_Item);
+ JSON_KnownItems.append(JSON_Item);
+ }
+
+ Json::Value JSON_KnownRecipes;
+ for (auto KnownRecipe : m_KnownRecipes)
+ {
+ auto Recipe = cRoot::Get()->GetCraftingRecipes()->GetRecipeById(KnownRecipe);
+ JSON_KnownRecipes.append(Recipe->m_RecipeName);
+ }
+
Json::Value root;
root["position"] = JSON_PlayerPosition;
root["rotation"] = JSON_PlayerRotation;
root["inventory"] = JSON_Inventory;
+ root["knownItems"] = JSON_KnownItems;
+ root["knownRecipes"] = JSON_KnownRecipes;
root["equippedItemSlot"] = m_Inventory.GetEquippedSlotNum();
root["enderchestinventory"] = JSON_EnderChestInventory;
root["health"] = m_Health;
@@ -3095,13 +3187,3 @@ float cPlayer::GetExplosionExposureRate(Vector3d a_ExplosionPosition, float a_Ex
return Super::GetExplosionExposureRate(a_ExplosionPosition, a_ExlosionPower) / 30.0f;
}
-
-
-
-
-
-
-
-
-
-
diff --git a/src/Entities/Player.h b/src/Entities/Player.h
index 11d448b11..c52d6bbdc 100644
--- a/src/Entities/Player.h
+++ b/src/Entities/Player.h
@@ -600,6 +600,10 @@ public:
/** get player explosion exposure rate */
virtual float GetExplosionExposureRate(Vector3d a_ExplosionPosition, float a_ExlosionPower) override;
+ /** Adds an Item to the list of known items.
+ If the item is already known, does nothing. */
+ void AddKnownItem(const cItem & a_Item);
+
protected:
typedef std::vector<std::vector<AString> > AStringVectorVector;
@@ -753,6 +757,12 @@ protected:
/** The main hand of the player */
eMainHand m_MainHand;
+ /** List on known recipes as Ids */
+ std::set<UInt32> m_KnownRecipes;
+
+ /** List of known items as Ids */
+ std::set<cItem, cItem::sItemCompare> m_KnownItems;
+
virtual void DoMoveToWorld(const cEntity::sWorldChangeInfo & a_WorldChangeInfo) override;
/** Sets the speed and sends it to the client, so that they are forced to move so. */
@@ -795,4 +805,8 @@ private:
If he is not on ground it also gets divided by 5. */
float GetDigSpeed(BLOCKTYPE a_Block);
+ /** Add the recipe Id to the known recipes.
+ If the recipe is already known, does nothing. */
+ void AddKnownRecipe(UInt32 RecipeId);
+
} ; // tolua_export
diff --git a/src/Inventory.cpp b/src/Inventory.cpp
index 42c243f17..6509dfe5d 100644
--- a/src/Inventory.cpp
+++ b/src/Inventory.cpp
@@ -105,6 +105,8 @@ int cInventory::HowManyCanFit(const cItem & a_ItemStack, int a_BeginSlotNum, int
int cInventory::AddItem(const cItem & a_Item, bool a_AllowNewStacks)
{
+ m_Owner.AddKnownItem(a_Item);
+
cItem ToAdd(a_Item);
int res = 0;
@@ -207,6 +209,26 @@ int cInventory::RemoveItem(const cItem & a_ItemStack)
+cItem * cInventory::FindItem(const cItem & a_RecipeItem)
+{
+ cItem * Item = m_ShieldSlots.FindItem(a_RecipeItem);
+ if (Item != nullptr)
+ {
+ return Item;
+ }
+ Item = m_HotbarSlots.FindItem(a_RecipeItem);
+ if (Item != nullptr)
+ {
+ return Item;
+ }
+
+ return m_InventorySlots.FindItem(a_RecipeItem);
+}
+
+
+
+
+
bool cInventory::RemoveOneEquippedItem(void)
{
if (m_HotbarSlots.GetSlot(m_EquippedSlotNum).IsEmpty())
@@ -863,7 +885,3 @@ void cInventory::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum)
SendSlot(Base + a_SlotNum);
}
-
-
-
-
diff --git a/src/Inventory.h b/src/Inventory.h
index 7436d7528..7221ded00 100644
--- a/src/Inventory.h
+++ b/src/Inventory.h
@@ -88,6 +88,9 @@ public:
Returns the number of items that were removed. */
int RemoveItem(const cItem & a_ItemStack);
+ /** Finds an item based on ItemType and ItemDamage (<- defines the itemType, too) */
+ cItem * FindItem(const cItem & a_RecipeItem);
+
/** Removes one item out of the currently equipped item stack, returns true if successful, false if empty-handed */
bool RemoveOneEquippedItem(void);
@@ -210,7 +213,3 @@ protected:
// cItemGrid::cListener override:
virtual void OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) override;
}; // tolua_export
-
-
-
-
diff --git a/src/Item.h b/src/Item.h
index 175f044b5..2f7b1a238 100644
--- a/src/Item.h
+++ b/src/Item.h
@@ -169,6 +169,31 @@ public:
AStringVector m_LoreTable; // Exported in ManualBindings.cpp
+ /**
+ Compares two items for the same type or category. Type of item is defined
+ via `m_ItemType` and `m_ItemDamage`. Some items (e.g. planks) have the same
+ `m_ItemType` and the wood kind is defined via `m_ItemDamage`. `-1` is used
+ as placeholder for all kinds (e.g. all kind of planks).
+
+ Items are different when the `ItemType` is different or the `ItemDamage`
+ is different and unequal -1.
+ */
+ struct sItemCompare
+ {
+ bool operator() (const cItem & a_Lhs, const cItem & a_Rhs) const
+ {
+ if (a_Lhs.m_ItemType != a_Rhs.m_ItemType)
+ {
+ return (a_Lhs.m_ItemType < a_Rhs.m_ItemType);
+ }
+ if ((a_Lhs.m_ItemDamage == -1) || (a_Rhs.m_ItemDamage == -1))
+ {
+ return false; // -1 is a wildcard, damage of -1 alway compares equal
+ }
+ return (a_Lhs.m_ItemDamage < a_Rhs.m_ItemDamage);
+ }
+ };
+
// tolua_begin
int m_RepairCost;
diff --git a/src/ItemGrid.cpp b/src/ItemGrid.cpp
index 045f083c8..790f078fc 100644
--- a/src/ItemGrid.cpp
+++ b/src/ItemGrid.cpp
@@ -440,6 +440,31 @@ int cItemGrid::RemoveItem(const cItem & a_ItemStack)
+cItem * cItemGrid::FindItem(const cItem & a_RecipeItem)
+{
+ if (!m_Slots.IsStorageAllocated())
+ {
+ return nullptr;
+ }
+
+ for (int i = 0; i < m_Slots.size(); i++)
+ {
+ // Items are equal if none is greater the other
+ auto compare = cItem::sItemCompare{};
+ if (!compare(a_RecipeItem, m_Slots[i]) &&
+ !compare(m_Slots[i], a_RecipeItem))
+ {
+ return &m_Slots[i];
+ }
+ }
+
+ return nullptr;
+}
+
+
+
+
+
int cItemGrid::ChangeSlotCount(int a_SlotNum, int a_AddToCount)
{
if (!IsValidSlotNum(a_SlotNum))
@@ -825,7 +850,3 @@ void cItemGrid::TriggerListeners(int a_SlotNum)
} // for itr - m_Listeners[]
m_IsInTriggerListeners = false;
}
-
-
-
-
diff --git a/src/ItemGrid.h b/src/ItemGrid.h
index ee2dc79f3..52cfbc84a 100644
--- a/src/ItemGrid.h
+++ b/src/ItemGrid.h
@@ -102,6 +102,9 @@ public:
Returns the number of items that were removed. */
int RemoveItem(const cItem & a_ItemStack);
+ /** Finds an item based on ItemType and ItemDamage (<- defines the itemType, too) */
+ cItem * FindItem(const cItem & a_RecipeItem);
+
/** Adds (or subtracts, if a_AddToCount is negative) to the count of items in the specified slot.
If the slot is empty, ignores the call.
Returns the new count.
@@ -198,6 +201,3 @@ protected:
int AddItemToSlot(const cItem & a_ItemStack, int a_Slot, int a_Num, int a_MaxStack);
} ;
// tolua_end
-
-
-
diff --git a/src/Protocol/CMakeLists.txt b/src/Protocol/CMakeLists.txt
index e197853cb..40eecde07 100644
--- a/src/Protocol/CMakeLists.txt
+++ b/src/Protocol/CMakeLists.txt
@@ -14,6 +14,7 @@ target_sources(
Protocol_1_13.cpp
ProtocolPalettes.cpp
ProtocolRecognizer.cpp
+ RecipeMapper.cpp
Authenticator.h
ChunkDataSerializer.h
@@ -29,4 +30,5 @@ target_sources(
Protocol_1_13.h
ProtocolPalettes.h
ProtocolRecognizer.h
+ RecipeMapper.h
)
diff --git a/src/Protocol/Packetizer.cpp b/src/Protocol/Packetizer.cpp
index 6afea8a36..12bfcc0dd 100644
--- a/src/Protocol/Packetizer.cpp
+++ b/src/Protocol/Packetizer.cpp
@@ -121,6 +121,7 @@ AString cPacketizer::PacketTypeToStr(cProtocol::ePacketType a_PacketType)
case cProtocol::pktTimeUpdate: return "pktTimeUpdate";
case cProtocol::pktTitle: return "pktTitle";
case cProtocol::pktUnloadChunk: return "pktUnloadChunk";
+ case cProtocol::pktUnlockRecipe: return "pktUnlockRecipe";
case cProtocol::pktUpdateBlockEntity: return "pktUpdateBlockEntity";
case cProtocol::pktUpdateHealth: return "pktUpdateHealth";
case cProtocol::pktUpdateScore: return "pktUpdateScore";
@@ -134,7 +135,3 @@ AString cPacketizer::PacketTypeToStr(cProtocol::ePacketType a_PacketType)
}
return Printf("Unknown packet type: 0x%02x", a_PacketType);
}
-
-
-
-
diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h
index 12382b954..e1d901321 100644
--- a/src/Protocol/Protocol.h
+++ b/src/Protocol/Protocol.h
@@ -132,6 +132,7 @@ public:
pktTimeUpdate,
pktTitle,
pktUnloadChunk,
+ pktUnlockRecipe,
pktUpdateBlockEntity,
pktUpdateHealth,
pktUpdateScore,
@@ -225,6 +226,8 @@ public:
virtual void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity) = 0;
virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) = 0;
virtual void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ) = 0;
+ virtual void SendUnlockRecipe (UInt32 a_RecipeID) = 0;
+ virtual void SendInitRecipes (UInt32 a_RecipeID) = 0;
virtual void SendWeather (eWeather a_Weather) = 0;
virtual void SendWholeInventory (const cWindow & a_Window) = 0;
virtual void SendWindowClose (const cWindow & a_Window) = 0;
diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp
index 73f8e0ff1..3f3982c90 100644
--- a/src/Protocol/ProtocolRecognizer.cpp
+++ b/src/Protocol/ProtocolRecognizer.cpp
@@ -51,6 +51,7 @@ AString cProtocolRecognizer::GetVersionTextFromInt(int a_ProtocolVersion)
case PROTO_VERSION_1_11_1: return "1.11.1";
case PROTO_VERSION_1_12: return "1.12";
case PROTO_VERSION_1_12_1: return "1.12.1";
+ case PROTO_VERSION_1_12_2: return "1.12.2";
case PROTO_VERSION_1_13: return "1.13";
}
ASSERT(!"Unknown protocol version");
@@ -921,6 +922,26 @@ void cProtocolRecognizer::SendUseBed(const cEntity & a_Entity, int a_BlockX, int
+void cProtocolRecognizer::SendUnlockRecipe(UInt32 a_RecipeID)
+{
+ ASSERT(m_Protocol != nullptr);
+ m_Protocol->SendUnlockRecipe(a_RecipeID);
+}
+
+
+
+
+
+void cProtocolRecognizer::SendInitRecipes(UInt32 a_RecipeID)
+{
+ ASSERT(m_Protocol != nullptr);
+ m_Protocol->SendInitRecipes(a_RecipeID);
+}
+
+
+
+
+
void cProtocolRecognizer::SendWeather(eWeather a_Weather)
{
ASSERT(m_Protocol != nullptr);
diff --git a/src/Protocol/ProtocolRecognizer.h b/src/Protocol/ProtocolRecognizer.h
index f82dab08a..c5d180b44 100644
--- a/src/Protocol/ProtocolRecognizer.h
+++ b/src/Protocol/ProtocolRecognizer.h
@@ -127,6 +127,8 @@ public:
virtual void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity) override;
virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) override;
virtual void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ) override;
+ virtual void SendUnlockRecipe (UInt32 a_RecipeID) override;
+ virtual void SendInitRecipes (UInt32 a_RecipeID) override;
virtual void SendWeather (eWeather a_Weather) override;
virtual void SendWholeInventory (const cWindow & a_Window) override;
virtual void SendWindowClose (const cWindow & a_Window) override;
diff --git a/src/Protocol/Protocol_1_12.cpp b/src/Protocol/Protocol_1_12.cpp
index dba85435b..6998f73bf 100644
--- a/src/Protocol/Protocol_1_12.cpp
+++ b/src/Protocol/Protocol_1_12.cpp
@@ -25,6 +25,7 @@ Implements the 1.12 protocol classes:
#include "../Root.h"
#include "../Server.h"
#include "../ClientHandle.h"
+#include "../CraftingRecipes.h"
#include "../Bindings/PluginManager.h"
#include "../JsonUtils.h"
@@ -1007,6 +1008,7 @@ UInt32 cProtocol_1_12::GetPacketID(cProtocol::ePacketType a_Packet)
case pktTeleportEntity: return 0x4b;
case pktTimeUpdate: return 0x46;
case pktTitle: return 0x47;
+ case pktUnlockRecipe: return 0x30;
case pktUpdateBlockEntity: return 0x09;
case pktUpdateHealth: return 0x40;
case pktUpdateScore: return 0x44;
@@ -1019,10 +1021,27 @@ UInt32 cProtocol_1_12::GetPacketID(cProtocol::ePacketType a_Packet)
+void cProtocol_1_12::HandleCraftRecipe(cByteBuffer & a_ByteBuffer)
+{
+ HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, WindowID);
+ HANDLE_READ(a_ByteBuffer, ReadVarInt, UInt32, RecipeID);
+ HANDLE_READ(a_ByteBuffer, ReadBool, bool, MakeAll);
+ auto CuberiteRecipeId = cRoot::Get()->GetRecipeMapper()->GetCuberiteRecipeId(RecipeID, m_Client->GetProtocolVersion());
+ if (CuberiteRecipeId.has_value())
+ {
+ m_Client->HandleCraftRecipe(CuberiteRecipeId.value());
+ }
+}
+
+
+
+
+
void cProtocol_1_12::HandlePacketCraftingBookData(cByteBuffer & a_ByteBuffer)
{
+ // TODO not yet used, not sure if it is needed
+ // https://wiki.vg/index.php?title=Protocol&oldid=14204#Crafting_Book_Data
a_ByteBuffer.SkipRead(a_ByteBuffer.GetReadableSpace() - 1);
- m_Client->GetPlayer()->SendMessageInfo("The green crafting book feature is not implemented yet.");
}
@@ -1170,6 +1189,7 @@ UInt32 cProtocol_1_12_1::GetPacketID(ePacketType a_Packet)
case pktRespawn: return 0x35;
case pktScoreboardObjective: return 0x42;
case pktSpawnPosition: return 0x46;
+ case pktUnlockRecipe: return 0x31;
case pktUpdateHealth: return 0x41;
case pktUpdateScore: return 0x45;
case pktUseBed: return 0x30;
@@ -1277,7 +1297,7 @@ bool cProtocol_1_12_1::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketT
case 0x0f: HandlePacketPlayerLook(a_ByteBuffer); return true;
case 0x10: HandlePacketVehicleMove(a_ByteBuffer); return true;
case 0x11: HandlePacketBoatSteer(a_ByteBuffer); return true;
- case 0x12: break; // Craft Recipe Request - not yet implemented
+ case 0x12: HandleCraftRecipe(a_ByteBuffer); return true;
case 0x13: HandlePacketPlayerAbilities(a_ByteBuffer); return true;
case 0x14: HandlePacketBlockDig(a_ByteBuffer); return true;
case 0x15: HandlePacketEntityAction(a_ByteBuffer); return true;
@@ -1397,3 +1417,55 @@ void cProtocol_1_12_2::SendKeepAlive(UInt32 a_PingID)
cPacketizer Pkt(*this, pktKeepAlive);
Pkt.WriteBEInt64(a_PingID);
}
+
+
+
+
+
+void cProtocol_1_12_2::SendUnlockRecipe(UInt32 a_RecipeID)
+{
+ ASSERT(m_State == 3); // In game mode?
+
+ auto ProtocolRecipeId = cRoot::Get()->GetRecipeMapper()->GetProtocolRecipeId(a_RecipeID, m_Client->GetProtocolVersion());
+ if (ProtocolRecipeId.has_value())
+ {
+ cPacketizer Pkt(*this, pktUnlockRecipe);
+ Pkt.WriteVarInt32(1);
+ Pkt.WriteBool(true);
+ Pkt.WriteBool(false);
+ Pkt.WriteVarInt32(1);
+ Pkt.WriteVarInt32(ProtocolRecipeId.value());
+ }
+}
+
+
+
+
+
+void cProtocol_1_12_2::SendInitRecipes(UInt32 a_RecipeID)
+{
+ ASSERT(m_State == 3); // In game mode?
+
+ auto ProtocolRecipeId = cRoot::Get()->GetRecipeMapper()->GetProtocolRecipeId(a_RecipeID, m_Client->GetProtocolVersion());
+ if (!ProtocolRecipeId.has_value())
+ {
+ return;
+ }
+
+ cPacketizer Pkt(*this, pktUnlockRecipe);
+ Pkt.WriteVarInt32(0);
+ Pkt.WriteBool(true);
+ Pkt.WriteBool(false);
+ if (a_RecipeID == 0)
+ {
+ Pkt.WriteVarInt32(0);
+ Pkt.WriteVarInt32(0);
+ }
+ else
+ {
+ Pkt.WriteVarInt32(1);
+ Pkt.WriteVarInt32(ProtocolRecipeId.value());
+ Pkt.WriteVarInt32(1);
+ Pkt.WriteVarInt32(ProtocolRecipeId.value());
+ }
+}
diff --git a/src/Protocol/Protocol_1_12.h b/src/Protocol/Protocol_1_12.h
index 38c025e9e..c1b81955a 100644
--- a/src/Protocol/Protocol_1_12.h
+++ b/src/Protocol/Protocol_1_12.h
@@ -20,7 +20,7 @@ Declares the 1.12 protocol classes:
#include "Protocol_1_11.h"
-
+#include "RecipeMapper.h"
@@ -36,6 +36,7 @@ public:
protected:
virtual bool HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType) override;
virtual void HandlePacketAdvancementTab(cByteBuffer & a_ByteBuffer);
+ virtual void HandleCraftRecipe(cByteBuffer & a_ByteBuffer);
virtual void HandlePacketCraftingBookData(cByteBuffer & a_ByteBuffer);
virtual void HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer) override;
virtual void WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a_Entity) override;
@@ -86,8 +87,6 @@ protected:
virtual void HandlePacketKeepAlive(cByteBuffer & a_ByteBuffer) override;
virtual void HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer) override;
virtual void SendKeepAlive(UInt32 a_PingID) override;
+ virtual void SendUnlockRecipe(UInt32 a_RecipeID) override;
+ virtual void SendInitRecipes(UInt32 a_RecipeID) override;
};
-
-
-
-
diff --git a/src/Protocol/Protocol_1_13.cpp b/src/Protocol/Protocol_1_13.cpp
index fc048fe70..1dcecaa4b 100644
--- a/src/Protocol/Protocol_1_13.cpp
+++ b/src/Protocol/Protocol_1_13.cpp
@@ -140,6 +140,7 @@ UInt32 cProtocol_1_13::GetPacketID(ePacketType a_PacketType)
case pktTimeUpdate: return 0x4a;
case pktTitle: return 0x4b;
case pktUnloadChunk: return 0x1f;
+ case pktUnlockRecipe: return 0x32;
case pktUpdateHealth: return 0x44;
case pktUpdateScore: return 0x48;
case pktUpdateSign: return GetPacketID(pktUpdateBlockEntity);
diff --git a/src/Protocol/Protocol_1_8.cpp b/src/Protocol/Protocol_1_8.cpp
index b5d78e457..469f01c39 100644
--- a/src/Protocol/Protocol_1_8.cpp
+++ b/src/Protocol/Protocol_1_8.cpp
@@ -1587,6 +1587,26 @@ void cProtocol_1_8_0::SendUseBed(const cEntity & a_Entity, int a_BlockX, int a_B
+void cProtocol_1_8_0::SendUnlockRecipe(UInt32 a_RecipeID)
+{
+ // Client doesn't support this feature
+ return;
+}
+
+
+
+
+
+void cProtocol_1_8_0::SendInitRecipes(UInt32 a_RecipeID)
+{
+ // Client doesn't support this feature
+ return;
+}
+
+
+
+
+
void cProtocol_1_8_0::SendWeather(eWeather a_Weather)
{
ASSERT(m_State == 3); // In game mode?
diff --git a/src/Protocol/Protocol_1_8.h b/src/Protocol/Protocol_1_8.h
index 42903a921..a8232104b 100644
--- a/src/Protocol/Protocol_1_8.h
+++ b/src/Protocol/Protocol_1_8.h
@@ -114,6 +114,8 @@ public:
virtual void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity) override;
virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) override;
virtual void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ) override;
+ virtual void SendUnlockRecipe (UInt32 a_RecipeID) override;
+ virtual void SendInitRecipes (UInt32 a_RecipeID) override;
virtual void SendWeather (eWeather a_Weather) override;
virtual void SendWholeInventory (const cWindow & a_Window) override;
virtual void SendWindowClose (const cWindow & a_Window) override;
diff --git a/src/Protocol/Protocol_1_9.cpp b/src/Protocol/Protocol_1_9.cpp
index 8327eaf40..784c26f34 100644
--- a/src/Protocol/Protocol_1_9.cpp
+++ b/src/Protocol/Protocol_1_9.cpp
@@ -567,6 +567,12 @@ UInt32 cProtocol_1_9_0::GetPacketID(cProtocol::ePacketType a_Packet)
case pktWindowItems: return 0x14;
case pktWindowOpen: return 0x13;
case pktWindowProperty: return 0x15;
+
+ // Unsupported packets
+ case pktUnlockRecipe:
+ {
+ break;
+ }
}
UNREACHABLE("Unsupported outgoing packet type");
}
diff --git a/src/Protocol/RecipeMapper.cpp b/src/Protocol/RecipeMapper.cpp
new file mode 100644
index 000000000..2757fdfd6
--- /dev/null
+++ b/src/Protocol/RecipeMapper.cpp
@@ -0,0 +1,128 @@
+#include "Globals.h"
+#include "RecipeMapper.h"
+#include "../Root.h"
+
+cRecipeMapper::cRecipeMapper(void)
+{
+ AString path = "Protocol";
+ auto contents = cFile::GetFolderContents(path);
+ for (const auto & content: contents)
+ {
+ auto fullName = path + cFile::PathSeparator() + content;
+ if (cFile::IsFolder(fullName))
+ {
+ loadRecipes(content);
+ }
+ }
+}
+
+
+
+
+
+void cRecipeMapper::loadRecipes(const AString & a_ProtocolVersion)
+{
+ cFile f;
+ if (!f.Open("Protocol/" + a_ProtocolVersion + "/base.recipes.txt", cFile::fmRead))
+ {
+ LOGWARNING("Cannot open file \"Protocol/%s/base.recipes.txt\", no recipe book recipes will be available!", a_ProtocolVersion);
+ return;
+ }
+ AString Everything;
+ if (!f.ReadRestOfFile(Everything))
+ {
+ LOGWARNING("Cannot read file \"Protocol/%s/base.recipes.txt\", no recipe book recipes will be available!", a_ProtocolVersion);
+ return;
+ }
+ f.Close();
+
+ // Split it into lines, then process each line as a single recipe:
+ AStringVector Split = StringSplit(Everything, "\n");
+ m_ProtocolVersionMap[a_ProtocolVersion] = {};
+ const auto & RecipeNameMap = cRoot::Get()->GetCraftingRecipes()->GetRecipeNameMap();
+
+ int LineNum = 1;
+ for (AStringVector::const_iterator itr = Split.begin(); itr != Split.end(); ++itr, ++LineNum)
+ {
+ // Remove anything after a '#' sign and trim away the whitespace:
+ AString Recipe = TrimString(itr->substr(0, itr->find('#')));
+ if (Recipe.empty())
+ {
+ // Empty recipe
+ continue;
+ }
+ AddRecipeLine(a_ProtocolVersion, LineNum, Recipe, RecipeNameMap);
+ }
+ LOG("Loaded %s %zu recipe book", a_ProtocolVersion, m_ProtocolVersionMap[a_ProtocolVersion].size());
+}
+
+
+
+
+
+cRecipeMapper::~cRecipeMapper()
+{
+}
+
+
+
+
+
+void cRecipeMapper::AddRecipeLine(const AString & a_ProtocolVersion, int a_LineNum, const AString & a_RecipeLine, const std::map<AString, UInt32> & a_RecipeNameMap)
+{
+ AStringVector Sides = StringSplit(a_RecipeLine, " ");
+ UInt32 Id;
+ if (Sides.size() != 2)
+ {
+ LOGINFO("Recipe incompletely configured %s", a_RecipeLine);
+ return;
+ }
+ StringToInteger<UInt32>(Sides[0], Id);
+
+ auto RecipeIndex = a_RecipeNameMap.find(Sides[1]);
+ if (RecipeIndex == a_RecipeNameMap.end())
+ {
+ return;
+ }
+ m_ProtocolVersionMap[a_ProtocolVersion].emplace(Id, RecipeIndex->second);
+}
+
+
+
+
+
+std::optional<UInt32> cRecipeMapper::GetProtocolRecipeId(UInt32 a_RecipeId, UInt32 a_ProtocolVersion)
+{
+ auto ProtocolMap = m_ProtocolVersionMap.find(cRoot::Get()->GetProtocolVersionTextFromInt(static_cast<int>(a_ProtocolVersion)));
+ if (ProtocolMap == m_ProtocolVersionMap.end())
+ {
+ return {};
+ }
+ for (const auto & item: ProtocolMap->second)
+ {
+ if (item.second == a_RecipeId)
+ {
+ return item.first;
+ }
+ }
+ return {};
+}
+
+
+
+
+
+std::optional<UInt32> cRecipeMapper::GetCuberiteRecipeId(UInt32 a_ProtocolRecipeId, UInt32 a_ProtocolVersion)
+{
+ auto ProtocolMap = m_ProtocolVersionMap.find(cRoot::Get()->GetProtocolVersionTextFromInt(static_cast<int>(a_ProtocolVersion)));
+ if (ProtocolMap == m_ProtocolVersionMap.end())
+ {
+ return {};
+ }
+ auto Element = ProtocolMap->second.find(a_ProtocolRecipeId);
+ if (Element != ProtocolMap->second.end())
+ {
+ return Element->second;
+ }
+ return {};
+}
diff --git a/src/Protocol/RecipeMapper.h b/src/Protocol/RecipeMapper.h
new file mode 100644
index 000000000..1cac62f92
--- /dev/null
+++ b/src/Protocol/RecipeMapper.h
@@ -0,0 +1,35 @@
+#pragma once
+
+#include "../CraftingRecipes.h"
+#include <optional>
+
+/**
+The RecipeMapper handles the translation of crafting recipes into protocol
+specific recipe Ids.
+The crafting recipes are identified by the RecipeId.
+The actual configuration is stored in the protocol specific configuration
+directory, e.g. `Server/Protocol/1.12.2/base.recipes.txt`
+*/
+class cRecipeMapper
+{
+public:
+ cRecipeMapper(void);
+ ~cRecipeMapper();
+
+ /** Translates the cuberite RecipeId to the protocol specific RecipeId */
+ std::optional<UInt32> GetProtocolRecipeId(UInt32 a_RecipeId, UInt32 a_ProtocolVersion);
+
+ /** Translates the protocol specific RecipeId to the cuberite RecipeId */
+ std::optional<UInt32> GetCuberiteRecipeId(UInt32 a_ProtocolRecipeId, UInt32 a_ProtocolVersion);
+
+private:
+ /** A mapping for each protocol from the protocol specific RecipeId and the cuberite RecipeId */
+ std::map<AString, std::map<UInt32, UInt32>> m_ProtocolVersionMap;
+
+ /** Load Recipes from the protocol specific mapping file */
+ void loadRecipes(const AString & a_ProtocolVersion);
+
+ /** Handles a single line of the protocol specific mapping file */
+ void AddRecipeLine(const AString & a_ProtocolVersion, int a_LineNum, const AString & a_RecipeLine, const std::map<AString, UInt32> & a_RecipeNameMap);
+
+};
diff --git a/src/Root.cpp b/src/Root.cpp
index 0cece9e6d..b3e7f61ee 100644
--- a/src/Root.cpp
+++ b/src/Root.cpp
@@ -24,6 +24,7 @@
#include "BrewingRecipes.h"
#include "FurnaceRecipe.h"
#include "CraftingRecipes.h"
+#include "Protocol/RecipeMapper.h"
#include "Bindings/PluginManager.h"
#include "MonsterConfig.h"
#include "Entities/Player.h"
@@ -213,6 +214,7 @@ void cRoot::Start(std::unique_ptr<cSettingsRepositoryInterface> a_OverridesRepo)
m_RankManager.reset(new cRankManager());
m_RankManager->Initialize(*m_MojangAPI);
m_CraftingRecipes = new cCraftingRecipes();
+ m_RecipeMapper.reset(new cRecipeMapper());
m_FurnaceRecipe = new cFurnaceRecipe();
m_BrewingRecipes.reset(new cBrewingRecipes());
diff --git a/src/Root.h b/src/Root.h
index 6c84e6bf7..2393871da 100644
--- a/src/Root.h
+++ b/src/Root.h
@@ -18,6 +18,7 @@ class cItem;
class cMonsterConfig;
class cBrewingRecipes;
class cCraftingRecipes;
+class cRecipeMapper;
class cFurnaceRecipe;
class cWebAdmin;
class cPluginManager;
@@ -89,6 +90,7 @@ public:
cMonsterConfig * GetMonsterConfig(void) { return m_MonsterConfig; }
cCraftingRecipes * GetCraftingRecipes(void) { return m_CraftingRecipes; } // tolua_export
+ cRecipeMapper * GetRecipeMapper(void) { return m_RecipeMapper.get(); }
cFurnaceRecipe * GetFurnaceRecipe (void) { return m_FurnaceRecipe; } // Exported in ManualBindings.cpp with quite a different signature
cBrewingRecipes * GetBrewingRecipes (void) { return m_BrewingRecipes.get(); } // Exported in ManualBindings.cpp
@@ -229,6 +231,7 @@ private:
cMonsterConfig * m_MonsterConfig;
cCraftingRecipes * m_CraftingRecipes;
+ std::unique_ptr<cRecipeMapper> m_RecipeMapper;
cFurnaceRecipe * m_FurnaceRecipe;
std::unique_ptr<cBrewingRecipes> m_BrewingRecipes;
cWebAdmin * m_WebAdmin;
@@ -275,8 +278,3 @@ private:
static void InputThread(cRoot & a_Params);
}; // tolua_export
-
-
-
-
-
diff --git a/src/UI/CraftingWindow.cpp b/src/UI/CraftingWindow.cpp
index 34599788c..d72e13729 100644
--- a/src/UI/CraftingWindow.cpp
+++ b/src/UI/CraftingWindow.cpp
@@ -59,3 +59,9 @@ void cCraftingWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer &
+
+void cCraftingWindow::LoadRecipe(cPlayer & a_Player, UInt32 a_RecipeId)
+{
+ auto slotAreaCrafting = static_cast<cSlotAreaCrafting *>(m_SlotAreas[0]);
+ slotAreaCrafting->LoadRecipe(a_Player, a_RecipeId);
+}
diff --git a/src/UI/CraftingWindow.h b/src/UI/CraftingWindow.h
index 75026dc67..b0de69704 100644
--- a/src/UI/CraftingWindow.h
+++ b/src/UI/CraftingWindow.h
@@ -25,8 +25,7 @@ public:
cCraftingWindow();
virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override;
-};
-
-
-
+ /** Loads the given Recipe into the crafting grid */
+ void LoadRecipe(cPlayer & a_Player, UInt32 a_RecipeId);
+};
diff --git a/src/UI/InventoryWindow.cpp b/src/UI/InventoryWindow.cpp
index 3c787ff7c..a3122d2d9 100644
--- a/src/UI/InventoryWindow.cpp
+++ b/src/UI/InventoryWindow.cpp
@@ -72,3 +72,9 @@ void cInventoryWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer
+
+void cInventoryWindow::LoadRecipe(cPlayer & a_Player, UInt32 a_RecipeId)
+{
+ auto slotAreaCrafting = static_cast<cSlotAreaCrafting *>(m_SlotAreas[0]);
+ slotAreaCrafting->LoadRecipe(a_Player, a_RecipeId);
+}
diff --git a/src/UI/InventoryWindow.h b/src/UI/InventoryWindow.h
index 108f58fa0..052439f40 100644
--- a/src/UI/InventoryWindow.h
+++ b/src/UI/InventoryWindow.h
@@ -26,10 +26,8 @@ public:
virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override;
+ /** Loads the given Recipe into the crafting grid */
+ void LoadRecipe(cPlayer & a_Player, UInt32 a_RecipeId);
protected:
cPlayer & m_Player;
};
-
-
-
-
diff --git a/src/UI/SlotArea.cpp b/src/UI/SlotArea.cpp
index 0bbfb4b12..1552d4bfe 100644
--- a/src/UI/SlotArea.cpp
+++ b/src/UI/SlotArea.cpp
@@ -665,6 +665,7 @@ void cSlotAreaCrafting::ShiftClickedResult(cPlayer & a_Player)
{
return;
}
+ a_Player.AddKnownItem(Result);
cItem * PlayerSlots = GetPlayerSlots(a_Player) + 1;
for (;;)
{
@@ -780,6 +781,70 @@ void cSlotAreaCrafting::HandleCraftItem(const cItem & a_Result, cPlayer & a_Play
+void cSlotAreaCrafting::LoadRecipe(cPlayer & a_Player, UInt32 a_RecipeId)
+{
+ if (a_RecipeId == 0)
+ {
+ return;
+ }
+ auto Recipe = cRoot::Get()->GetCraftingRecipes()->GetRecipeById(a_RecipeId);
+
+ int NumItems = 0;
+ ClearCraftingGrid(a_Player);
+
+ for (auto itrS = Recipe->m_Ingredients.begin(); itrS != Recipe->m_Ingredients.end(); ++itrS)
+ {
+ cItem * FoundItem = a_Player.GetInventory().FindItem(itrS->m_Item);
+ if (FoundItem == nullptr)
+ {
+ ClearCraftingGrid(a_Player);
+ break;
+ }
+ cItem Item = FoundItem->CopyOne();
+ ++NumItems;
+ int pos = 1 + itrS->x + m_GridSize * itrS->y;
+ // Assuming there are ether shaped or unshaped recipes, no mixed ones
+ if ((itrS->x == -1) && (itrS->y == -1))
+ {
+ pos = NumItems;
+ }
+ // Handle x wildcard
+ else if (itrS->x == -1)
+ {
+ for (int i = 0; i < m_GridSize; i++)
+ {
+ pos = 1 + i + m_GridSize * itrS->y;
+ auto itemCheck = GetSlot(pos, a_Player);
+ if (itemCheck->IsEmpty())
+ {
+ break;
+ }
+ }
+ }
+ SetSlot(pos, a_Player, Item);
+ a_Player.GetInventory().RemoveItem(Item);
+ }
+}
+
+
+
+
+
+void cSlotAreaCrafting::ClearCraftingGrid(cPlayer & a_Player)
+{
+ for (int pos = 1; pos <= m_GridSize * m_GridSize; pos++)
+ {
+ auto Item = GetSlot(pos, a_Player);
+ if (Item->m_ItemCount > 0)
+ {
+ a_Player.GetInventory().AddItem(*Item);
+ SetSlot(pos, a_Player, cItem());
+ }
+ }
+}
+
+
+
////////////////////////////////////////////////////////////////////////////////
// cSlotAreaAnvil:
@@ -2749,8 +2814,3 @@ void cSlotAreaHorse::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bo
--a_ItemStack.m_ItemCount;
}
}
-
-
-
-
-
diff --git a/src/UI/SlotArea.h b/src/UI/SlotArea.h
index 86c0afd51..d363a72e6 100644
--- a/src/UI/SlotArea.h
+++ b/src/UI/SlotArea.h
@@ -273,6 +273,11 @@ public:
// Distributing items into this area is completely disabled
virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill) override;
+ /** Clear the crafting grid */
+ void ClearCraftingGrid(cPlayer & a_Player);
+
+ /** Loads the given Recipe into the crafting grid */
+ void LoadRecipe(cPlayer & a_Player, UInt32 a_RecipeId);
protected:
/** Maps player's EntityID -> current recipe.
@@ -555,7 +560,3 @@ public:
private:
cHorse & m_Horse;
};
-
-
-
-