1
0

Introduce recipe book functionality (#4493)

* Introduce recipe book functionality

The recipe book helps especially new players. Missing it gives the
impression that cuberite is not as advanced as it is.

The handling of the recipe book uses the following functions:

- Unlock Recipes
(https://wiki.vg/index.php?title=Protocol&oldid=14204#Unlock_Recipes) to
make recipes available and show the notification for new recipes.
Initialization is done on player login for known ones, the update is done
when new items are discovered.
- Craft Recipe Request
(https://wiki.vg/index.php?title=Protocol&oldid=14204#Craft_Recipe_Request)
when the user selects a recipe from the recipe book to fill the slots.

Known recipes are initialized on player login via `Unlock Recipes` with
`Action` 0.
As soon as a new recipe is discovered this is added via `Unlock Recipes`
with `Action` 1.

To be able to know and recognize new recipes the player class is
extended with `KnownItems` and `KnownRecipes`. As soon as a player
touches an item this is compared to the list of `KnownItems`, if the
item is unknown the recipes are checked for this item and the other
ingredients are checked with the list of `KnownItems`. If a full match
is discovered the recipe is unlocked with the client and stored in the
`KnownRecipes`.

To unlock recipes the recipe ID is sent to the client. A mapping file
(for protocol 1.12.2) translated the minecraft recipe names to ids. The
crafting.txt is extended with and minecraft recipe names is possible.

Limitations:
Only a single recipe is added to the crafting area. Multiple clicks or
shift click does not increase the number of builds.

Co-authored-by: peterbell10 <peterbell10@live.co.uk>

* Address first issues mentioned by @peterbell10

- Some linting
- Extract loading of recipe specific protocol mapping into a function
- Build `RecipeNameMap` only once
- Use `std::optional`
- Extract `LoadRecipe` from `Window`

* Start to implement new suggestions

* Update with suggestions from @peterbell10

* Some minor cleanup

* Update protocol packet IDs
* Remove unused include
* Include header in cmake
* Change a vector to integer counter

* Change dromedaryCase method names to PascalCase

* Address suggestions from @madmaxoft

* Read Protocol subdirectories to load recipe books

To load all recipebooks iterate over the `Protocol` subdirectories
to find mapping files.

Co-authored-by: peterbell10 <peterbell10@live.co.uk>
This commit is contained in:
Tobias Wilken 2020-07-14 18:56:42 +02:00 committed by GitHub
parent 6e3f6d58a4
commit 36eab1b323
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 1614 additions and 457 deletions

View File

@ -63,6 +63,7 @@ Sxw1212
Taugeshtu
tigerw (Tiger Wang)
tonibm19
TooAngel
UltraCoderRU
Warmist
WebFreak001

View File

@ -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 =

View File

@ -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

View File

@ -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
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 = 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
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, *
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, *
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
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, *
yellow_wool: 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
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, *

View File

@ -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);

View File

@ -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.
*/

View File

@ -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);
}
}

View File

@ -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);
} ;

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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
)

View File

@ -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);
}

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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());
}
}

View File

@ -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;
};

View File

@ -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);

View File

@ -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?

View File

@ -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;

View File

@ -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");
}

View File

@ -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 {};
}

View File

@ -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);
};

View File

@ -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());

View File

@ -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

View File

@ -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);
}

View File

@ -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);
};

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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;
}
}

View File

@ -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;
};