diff --git a/game/client/src/main/java/net/minecraft/client/entity/player/PlayerLocal.java b/game/client/src/main/java/net/minecraft/client/entity/player/PlayerLocal.java
index 0d00d3633..c6e105117 100644
--- a/game/client/src/main/java/net/minecraft/client/entity/player/PlayerLocal.java
+++ b/game/client/src/main/java/net/minecraft/client/entity/player/PlayerLocal.java
@@ -6,18 +6,11 @@ import com.mojang.nbt.tags.CompoundTag;
 
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.entity.particle.ParticlePickupAnimation;
-import net.minecraft.client.gui.container.ScreenActivator;
-import net.minecraft.client.gui.container.ScreenContainer;
-import net.minecraft.client.gui.container.ScreenContainerAbstract;
-import net.minecraft.client.gui.container.ScreenCrafting;
-import net.minecraft.client.gui.container.ScreenDispenser;
-import net.minecraft.client.gui.container.ScreenFlagEditor;
+import net.minecraft.client.gui.container.*;
 import net.minecraft.client.gui.ScreenLabelEditor;
 import net.minecraft.client.gui.ScreenSignEditor;
-import net.minecraft.client.gui.container.ScreenFurnace;
 import net.minecraft.client.gui.ScreenPaintingPicker;
 import net.minecraft.client.gui.ScreenMobPicker;
-import net.minecraft.client.gui.container.ScreenTrommel;
 import net.minecraft.client.gui.ScreenWandMobPicker;
 import net.minecraft.client.gui.guidebook.ScreenGuidebook;
 import net.minecraft.client.gui.nbteditor.ScreenNBTEditor;
@@ -30,13 +23,7 @@ import net.minecraft.core.achievement.stat.StatList;
 import net.minecraft.client.gui.toasts.AchievementToast;
 import net.minecraft.core.block.BlockLogicPortal;
 import net.minecraft.core.block.Blocks;
-import net.minecraft.core.block.entity.TileEntityActivator;
-import net.minecraft.core.block.entity.TileEntityDispenser;
-import net.minecraft.core.block.entity.TileEntityFlag;
-import net.minecraft.core.block.entity.TileEntityFurnace;
-import net.minecraft.core.block.entity.TileEntityMobSpawner;
-import net.minecraft.core.block.entity.TileEntitySign;
-import net.minecraft.core.block.entity.TileEntityTrommel;
+import net.minecraft.core.block.entity.*;
 import net.minecraft.core.data.gamerule.GameRules;
 import net.minecraft.core.entity.Entity;
 import net.minecraft.core.entity.player.Player;
@@ -339,6 +326,11 @@ public class PlayerLocal extends Player
         mc.displayScreen(new ScreenFurnace(inventory, tileEntity));
     }
 
+    @Override
+    public void displayBlastFurnaceScreen(final TileEntityFurnaceBlast tileEntity) {
+        mc.displayScreen(new ScreenFurnaceBlast(inventory, tileEntity));
+    }
+
     @Override
     public void displayTrommelScreen(TileEntityTrommel tileEntity)
     {
diff --git a/game/client/src/main/java/net/minecraft/client/gui/container/ScreenContainerAbstract.java b/game/client/src/main/java/net/minecraft/client/gui/container/ScreenContainerAbstract.java
index 970ce5186..ab11bcba0 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/container/ScreenContainerAbstract.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/container/ScreenContainerAbstract.java
@@ -18,6 +18,7 @@ import net.minecraft.core.block.entity.TileEntityFurnaceBlast;
 import net.minecraft.core.crafting.LookupFuelFurnace;
 import net.minecraft.core.crafting.LookupFuelFurnaceBlast;
 import net.minecraft.core.data.registry.Registries;
+import net.minecraft.core.data.registry.recipe.RecipeSymbol;
 import net.minecraft.core.data.registry.recipe.SearchQuery;
 import net.minecraft.core.data.registry.recipe.entry.RecipeEntryBlastFurnace;
 import net.minecraft.core.data.registry.recipe.entry.RecipeEntryFurnace;
@@ -401,30 +402,37 @@ public abstract class ScreenContainerAbstract extends Screen
 			}
 		}
 		if(inventorySlots instanceof MenuFurnace) {
-			// Furnace behavior
-			MenuFurnace furnace = (MenuFurnace) inventorySlots;
-			
-			boolean isBlastFurnace = furnace.furnace instanceof TileEntityFurnaceBlast;
 			boolean isFuel, isIngredient = false;
-			
-			if(isBlastFurnace) {
-				for (RecipeEntryBlastFurnace recipe : Registries.RECIPES.getAllBlastFurnaceRecipes()) {
-					isIngredient = recipe.matches(stackInSlot);
-					if(isIngredient){
-						break;
-					}
+
+			for (RecipeEntryFurnace recipe : Registries.RECIPES.getAllFurnaceRecipes()) {
+				isIngredient = recipe.matches(stackInSlot);
+				if(isIngredient){
+					break;
 				}
-				isFuel = LookupFuelFurnaceBlast.instance.getFuelYield(clickedItemId) > 0;
-			}else {
-				for (RecipeEntryFurnace recipe : Registries.RECIPES.getAllFurnaceRecipes()) {
-					isIngredient = recipe.matches(stackInSlot);
-					if(isIngredient){
-						break;
-					}
+			}
+			isFuel = LookupFuelFurnace.instance.getFuelYield(clickedItemId) > 0;
+
+			if(isIngredient) {
+				target = 1; // Into the ingredient slot
+			}else if(isFuel) {
+				target = 2; // Into the fuel slot
+			}
+		}
+		if(inventorySlots instanceof MenuFurnaceBlast) {
+			boolean isFuel, isIngredient = false;
+
+			for (RecipeEntryBlastFurnace recipe : Registries.RECIPES.getAllBlastFurnaceRecipes()) {
+				RecipeSymbol[] input = recipe.getInput();
+				isIngredient = input[0].matches(stackInSlot);
+				if (input.length == 2) {
+					isIngredient |= input[1].matches(stackInSlot);
+				}
+				if(isIngredient){
+					break;
 				}
-				isFuel = LookupFuelFurnace.instance.getFuelYield(clickedItemId) > 0;
 			}
-			
+			isFuel = LookupFuelFurnaceBlast.instance.getFuelYield(clickedItemId) > 0;
+
 			if(isIngredient) {
 				target = 1; // Into the ingredient slot
 			}else if(isFuel) {
diff --git a/game/client/src/main/java/net/minecraft/client/gui/container/ScreenFurnace.java b/game/client/src/main/java/net/minecraft/client/gui/container/ScreenFurnace.java
index 7b4cbf4c2..e7c32aa16 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/container/ScreenFurnace.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/container/ScreenFurnace.java
@@ -21,40 +21,24 @@ public class ScreenFurnace extends ScreenContainerAbstract
 	protected void drawGuiContainerForegroundLayer()
     {
         I18n i18n = I18n.getInstance();
-        if(furnaceInventory instanceof TileEntityFurnaceBlast) {
-            drawStringNoShadow(this.fontRenderer, i18n.translateKey("gui.furnace.blast.label.blast_furnace"), 60, 6, 0x404040);
-        } else {
-            drawStringNoShadow(this.fontRenderer, i18n.translateKey("gui.furnace.label.furnace"), 60, 6, 0x404040);
-        }
+        drawStringNoShadow(this.fontRenderer, i18n.translateKey("gui.furnace.label.furnace"), 60, 6, 0x404040);
         drawStringNoShadow(this.fontRenderer, i18n.translateKey("gui.furnace.label.inventory"), 8, (ySize - 96) + 2, 0x404040);
     }
 
     @Override
 	protected void drawGuiContainerBackgroundLayer(float f)
     {
-        if(furnaceInventory instanceof TileEntityFurnaceBlast) {
-            mc.textureManager.loadTexture("/assets/minecraft/textures/gui/container/blastfurnace.png").bind();
-        } else {
-            mc.textureManager.loadTexture("/assets/minecraft/textures/gui/container/furnace.png").bind();
-        }
+        mc.textureManager.loadTexture("/assets/minecraft/textures/gui/container/furnace.png").bind();
         GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
         int x = (width - xSize) / 2;
         int y = (height - ySize) / 2;
         drawTexturedModalRect(x, y, 0, 0, xSize, ySize);
         if(furnaceInventory.isBurning())
         {
-            if (furnaceInventory instanceof TileEntityFurnaceBlast) {
-                int fireHeight = furnaceInventory.getBurnTimeRemainingScaled(14);
-                drawTexturedModalRect(x + 56, y + 35 + 14 - fireHeight, 176, 14 - fireHeight, 14, fireHeight + 2);
-                int arrowWidth = furnaceInventory.getCookProgressScaled(24);
-                drawTexturedModalRect(x + 79, y + 34, 176, 15, arrowWidth + 1, 16);
-            } else {
-                int fireHeight = furnaceInventory.getBurnTimeRemainingScaled(12);
-                drawTexturedModalRect(x + 56, y + 36 + 12 - fireHeight, 176, 12 - fireHeight, 14, fireHeight + 2);
-                int arrowWidth = furnaceInventory.getCookProgressScaled(24);
-                drawTexturedModalRect(x + 79, y + 34, 176, 14, arrowWidth + 1, 16);
-            }
-
+            int fireHeight = furnaceInventory.getBurnTimeRemainingScaled(12);
+            drawTexturedModalRect(x + 56, y + 36 + 12 - fireHeight, 176, 12 - fireHeight, 14, fireHeight + 2);
+            int arrowWidth = furnaceInventory.getCookProgressScaled(24);
+            drawTexturedModalRect(x + 79, y + 34, 176, 14, arrowWidth + 1, 16);
         }
     }
     @Override
diff --git a/game/client/src/main/java/net/minecraft/client/gui/container/ScreenFurnaceBlast.java b/game/client/src/main/java/net/minecraft/client/gui/container/ScreenFurnaceBlast.java
new file mode 100644
index 000000000..68a4b9e58
--- /dev/null
+++ b/game/client/src/main/java/net/minecraft/client/gui/container/ScreenFurnaceBlast.java
@@ -0,0 +1,50 @@
+package net.minecraft.client.gui.container;
+
+import net.minecraft.client.input.controller.ControllerInput;
+import net.minecraft.core.block.entity.TileEntityFurnace;
+import net.minecraft.core.block.entity.TileEntityFurnaceBlast;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.player.inventory.container.ContainerInventory;
+import net.minecraft.core.player.inventory.menu.MenuFurnace;
+import net.minecraft.core.player.inventory.menu.MenuFurnaceBlast;
+import org.jetbrains.annotations.NotNull;
+import org.lwjgl.opengl.GL11;
+
+public class ScreenFurnaceBlast
+    extends ScreenContainerAbstract
+{
+    private final TileEntityFurnaceBlast tileEntity;
+
+    public ScreenFurnaceBlast(final @NotNull ContainerInventory inventory, final @NotNull TileEntityFurnaceBlast tileEntity) {
+        super(new MenuFurnaceBlast(inventory, tileEntity));
+        this.tileEntity = tileEntity;
+    }
+
+    @Override
+    protected void drawGuiContainerForegroundLayer() {
+        final I18n i18n = I18n.getInstance();
+        drawStringNoShadow(this.fontRenderer, i18n.translateKey("gui.furnace.blast.label.blast_furnace"), 60, 6, 0x404040);
+        drawStringNoShadow(this.fontRenderer, i18n.translateKey("gui.furnace.label.inventory"), 8, (this.ySize - 96) + 2, 0x404040);
+    }
+
+    @Override
+    protected void drawGuiContainerBackgroundLayer(final float f) {
+        this.mc.textureManager.loadTexture("/assets/minecraft/textures/gui/container/blastfurnace.png").bind();
+        GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
+        final int x = (this.width - this.xSize) / 2;
+        final int y = (this.height - this.ySize) / 2;
+        drawTexturedModalRect(x, y, 0, 0, this.xSize, this.ySize);
+        if (this.tileEntity.isBurning()) {
+            final int fireHeight = this.tileEntity.getBurnTimeRemainingScaled(14);
+            drawTexturedModalRect(x + 56, y + 35 + 14 - fireHeight, 176, 14 - fireHeight, 14, fireHeight + 2);
+            final int arrowWidth = this.tileEntity.getCookProgressScaled(24);
+            drawTexturedModalRect(x + 79, y + 34, 176, 15, arrowWidth + 1, 16);
+        }
+    }
+
+    @Override
+    public void guiSpecificControllerInput(final ControllerInput controller) {
+        super.guiSpecificControllerInput(controller);
+        controller.inventoryHandler.handleFurnaceBlast(this);
+    }
+}
diff --git a/game/client/src/main/java/net/minecraft/client/gui/guidebook/smelting/RecipePageBlastSmelting.java b/game/client/src/main/java/net/minecraft/client/gui/guidebook/smelting/RecipePageBlastSmelting.java
index 8329a933b..c1770801b 100644
--- a/game/client/src/main/java/net/minecraft/client/gui/guidebook/smelting/RecipePageBlastSmelting.java
+++ b/game/client/src/main/java/net/minecraft/client/gui/guidebook/smelting/RecipePageBlastSmelting.java
@@ -47,8 +47,13 @@ public class RecipePageBlastSmelting
 
         for (RecipeEntryBlastFurnace recipe : recipes) {
             List<SlotGuidebook> recipeSlots = new ArrayList<>();
-            recipeSlots.add(new SlotGuidebook(0, (width/2)-32, 32*(map.size()+1)-16, recipe.getInput(), false,recipe));
-            recipeSlots.add(new SlotGuidebook(1, (width/2)+24, 32*(map.size()+1)-16, new RecipeSymbol(recipe.getOutput()), false,recipe));
+            recipeSlots.add(new SlotGuidebook(0, (width/2)-52, 32*(map.size()+1)-16, recipe.getInput()[0], false,recipe));
+            if (recipe.getInput().length == 2) {
+                recipeSlots.add(new SlotGuidebook(1, (width/2)-32, 32*(map.size()+1)-16, recipe.getInput()[1], false,recipe));
+            } else {
+                recipeSlots.add(new SlotGuidebook(0, (width/2)-32, 32*(map.size()+1)-16, null, false,recipe));
+            }
+            recipeSlots.add(new SlotGuidebook(2, (width/2)+24, 32*(map.size()+1)-16, new RecipeSymbol(recipe.getOutput()), false,recipe));
             map.put(recipe,recipeSlots);
             slots.addAll(recipeSlots);
         }
diff --git a/game/client/src/main/java/net/minecraft/client/input/controller/ControllerInventoryHandler.java b/game/client/src/main/java/net/minecraft/client/input/controller/ControllerInventoryHandler.java
index d37ea7cf3..a0b65ef56 100644
--- a/game/client/src/main/java/net/minecraft/client/input/controller/ControllerInventoryHandler.java
+++ b/game/client/src/main/java/net/minecraft/client/input/controller/ControllerInventoryHandler.java
@@ -2,10 +2,7 @@ package net.minecraft.client.input.controller;
 
 import com.b100.utils.interfaces.Condition;
 import com.mojang.logging.LogUtils;
-import net.minecraft.client.gui.container.ScreenContainerAbstract;
-import net.minecraft.client.gui.container.ScreenCrafting;
-import net.minecraft.client.gui.container.ScreenFurnace;
-import net.minecraft.client.gui.container.ScreenInventory;
+import net.minecraft.client.gui.container.*;
 import net.minecraft.core.player.inventory.slot.Slot;
 import org.slf4j.Logger;
 
@@ -80,6 +77,10 @@ public class ControllerInventoryHandler {
 	public void handleFurnace(ScreenFurnace furnace) {
 		handleAbstractCrafting(furnace, (e) -> e.index >= 3 && e.index <= 38, (e) -> e.index >= 0 && e.index <= 1, (e) -> e.index == 2, 0, 2, 16);
 	}
+
+	public void handleFurnaceBlast(ScreenFurnaceBlast furnace) {
+		handleAbstractCrafting(furnace, (e) -> e.index >= 4 && e.index <= 39, (e) -> e.index >= 0 && e.index <= 2, (e) -> e.index == 3, 0, 3, 16);
+	}
 	
 	public void click(ScreenContainerAbstract screen, int button) {
 		screen.mouseClicked((int)controllerInput.cursorX, (int)controllerInput.cursorY, button);
diff --git a/game/client/src/main/java/net/minecraft/client/net/handler/PacketHandlerClient.java b/game/client/src/main/java/net/minecraft/client/net/handler/PacketHandlerClient.java
index cf715c1f8..f599adb45 100644
--- a/game/client/src/main/java/net/minecraft/client/net/handler/PacketHandlerClient.java
+++ b/game/client/src/main/java/net/minecraft/client/net/handler/PacketHandlerClient.java
@@ -915,7 +915,7 @@ public class PacketHandlerClient extends PacketHandler
             }
             case PacketContainerOpen.TYPE_BLAST_FURNACE: {
                 TileEntityFurnaceBlast tileEntityFurnaceBlast = new TileEntityFurnaceBlast();
-                mc.thePlayer.displayFurnaceScreen(tileEntityFurnaceBlast);
+                mc.thePlayer.displayBlastFurnaceScreen(tileEntityFurnaceBlast);
                 mc.thePlayer.craftingInventory.containerId = containerOpenPacket.windowId;
                 break;
             }
diff --git a/game/client/src/main/resources/assets/minecraft/textures/gui/container/blastfurnace.png b/game/client/src/main/resources/assets/minecraft/textures/gui/container/blastfurnace.png
index 747cdbe93..2cc941da6 100644
Binary files a/game/client/src/main/resources/assets/minecraft/textures/gui/container/blastfurnace.png and b/game/client/src/main/resources/assets/minecraft/textures/gui/container/blastfurnace.png differ
diff --git a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFurnaceBlast.java b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFurnaceBlast.java
index 85a8210c5..37fc47095 100644
--- a/game/core/src/main/java/net/minecraft/core/block/BlockLogicFurnaceBlast.java
+++ b/game/core/src/main/java/net/minecraft/core/block/BlockLogicFurnaceBlast.java
@@ -4,6 +4,7 @@ import com.mojang.logging.LogUtils;
 import net.minecraft.core.Global;
 import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.block.entity.TileEntityFurnaceBlast;
+import net.minecraft.core.block.material.Material;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.item.ItemStack;
@@ -13,13 +14,18 @@ import org.slf4j.Logger;
 
 import java.util.Random;
 
-public class BlockLogicFurnaceBlast extends BlockLogicFurnace
+public class BlockLogicFurnaceBlast extends BlockLogicRotatable
 {
     private static final Logger LOGGER = LogUtils.getLogger();
 
-	public BlockLogicFurnaceBlast(Block<?> block, boolean flag)
+    protected Random furnaceRand;
+    protected final boolean isActive;
+    public static boolean keepFurnaceInventory = false;
+
+    public BlockLogicFurnaceBlast(Block<?> block, boolean active)
     {
-        super(block, flag);
+        super(block, Material.metal);
+        isActive = active;
         block.withEntity(TileEntityFurnaceBlast::new);
     }
 
@@ -38,16 +44,6 @@ public class BlockLogicFurnaceBlast extends BlockLogicFurnace
         }
     }
 
-    @Override
-    public boolean onBlockRightClicked(World world, int x, int y, int z, Player player, Side side, double xPlaced, double yPlaced)
-    {
-        if (!world.isClientSide) {
-            TileEntityFurnaceBlast furnaceBlast = (TileEntityFurnaceBlast) world.getTileEntity(x, y, z);
-            player.displayFurnaceScreen(furnaceBlast);
-        }
-        return true;
-    }
-
     @Override
 	public void animationTick(World world, int x, int y, int z, Random rand)
     {
@@ -83,6 +79,16 @@ public class BlockLogicFurnaceBlast extends BlockLogicFurnace
         }
     }
 
+    @Override
+    public boolean onBlockRightClicked(World world, int x, int y, int z, Player player, Side side, double xPlaced, double yPlaced)
+    {
+        if (!world.isClientSide) {
+            TileEntityFurnaceBlast furnaceBlast = (TileEntityFurnaceBlast) world.getTileEntity(x, y, z);
+            player.displayBlastFurnaceScreen(furnaceBlast);
+        }
+        return true;
+    }
+
 	public static void updateFurnaceBlockState(boolean lit, World world, int x, int y, int z) {
 		int meta = world.getBlockMetadata(x, y, z);
 		TileEntity tileEntity = world.getTileEntity(x, y, z);
diff --git a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityFurnaceBlast.java b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityFurnaceBlast.java
index 07e248c08..28a6353cf 100644
--- a/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityFurnaceBlast.java
+++ b/game/core/src/main/java/net/minecraft/core/block/entity/TileEntityFurnaceBlast.java
@@ -2,175 +2,363 @@ package net.minecraft.core.block.entity;
 
 import com.mojang.nbt.tags.CompoundTag;
 import com.mojang.nbt.tags.ListTag;
+import net.minecraft.core.block.Block;
+import net.minecraft.core.block.BlockLogicFurnace;
 import net.minecraft.core.block.BlockLogicFurnaceBlast;
 import net.minecraft.core.block.Blocks;
+import net.minecraft.core.block.motion.CarriedBlock;
 import net.minecraft.core.crafting.LookupFuelFurnaceBlast;
 import net.minecraft.core.data.registry.Registries;
 import net.minecraft.core.data.registry.recipe.entry.RecipeEntryBlastFurnace;
+import net.minecraft.core.entity.Entity;
+import net.minecraft.core.entity.EntityItem;
+import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.item.ItemStack;
+import net.minecraft.core.net.packet.Packet;
+import net.minecraft.core.net.packet.PacketTileEntityData;
 import net.minecraft.core.player.inventory.container.Container;
+import net.minecraft.core.util.helper.Side;
+import net.minecraft.core.world.World;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.util.List;
+import java.util.Random;
 
-public class TileEntityFurnaceBlast extends TileEntityFurnace
-        implements Container
+public class TileEntityFurnaceBlast extends TileEntity
+    implements Container
 {
+    public static final int SLOT_LEFT = 0;
+    public static final int SLOT_RIGHT = 1;
+    public static final int SLOT_FUEL = 2;
+    public static final int SLOT_RESULT = 3;
 
+    private final Random random;
 
-    public TileEntityFurnaceBlast()
-    {
-        super();
-        maxCookTime = 100;
+    protected ItemStack[] inventory;
+    public int maxBurnTime;
+    public int currentCookTime;
+    public int maxCookTime;
+    public int currentBurnTime;
+
+    public TileEntityFurnaceBlast() {
+        this.random = new Random();
+        this.inventory = new ItemStack[4];
+        this.currentBurnTime = 0;
+        this.maxBurnTime = 0;
+        this.currentCookTime = 0;
+        this.maxCookTime = 100;
+    }
+
+    @Override
+    public int getContainerSize() {
+        return this.inventory.length;
+    }
+
+    @Override
+    public @Nullable ItemStack getItem(final int index) {
+        return this.inventory[index];
+    }
+
+    @Override
+    public @Nullable ItemStack removeItem(final int index, final int takeAmount) {
+        if (this.inventory[index] != null) {
+            if (this.inventory[index].stackSize <= takeAmount) {
+                final ItemStack itemstack = this.inventory[index];
+                this.inventory[index] = null;
+                if (this.worldObj != null && index == SLOT_RESULT) {
+                    this.worldObj.markBlockNeedsUpdate(this.x, this.y, this.z);
+                }
+                return itemstack;
+            }
+            final ItemStack itemstack1 = this.inventory[index].splitStack(takeAmount);
+            if (this.inventory[index].stackSize <= 0) {
+                this.inventory[index] = null;
+                if (this.worldObj != null && index == SLOT_RESULT) {
+                    this.worldObj.markBlockNeedsUpdate(this.x, this.y, this.z);
+                }
+            }
+            return itemstack1;
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public void setItem(final int index, @Nullable final ItemStack itemstack) {
+        this.inventory[index] = itemstack;
+        if (itemstack != null && itemstack.stackSize > getMaxStackSize()) {
+            itemstack.stackSize = getMaxStackSize();
+        }
+        if (this.worldObj != null && index == SLOT_RESULT && itemstack == null) {
+            this.worldObj.markBlockNeedsUpdate(this.x, this.y, this.z);
+        }
     }
 
     @Override
-	public String getNameTranslationKey()
-    {
+    public String getNameTranslationKey() {
         return "container.furnace_blast.name";
     }
 
     @Override
-	public void tick()
-    {
-        boolean isBurnTimeHigherThan0 = currentBurnTime > 0;
+    public void readAdditionalData(@NotNull final CompoundTag compoundTag) {
+        final ListTag itemsTag = compoundTag.getList("Items");
+        this.inventory = new ItemStack[getContainerSize()];
+
+        for (int i = 0; i < itemsTag.tagCount(); i++) {
+            final CompoundTag itemTag = (CompoundTag) itemsTag.tagAt(i);
+            final byte slot = itemTag.getByte("Slot");
+            if (slot >= 0 && slot < this.inventory.length) {
+                this.inventory[slot] = ItemStack.readItemStackFromNbt(itemTag);
+            }
+        }
+
+        this.currentBurnTime = compoundTag.getShort("BurnTime");
+        this.currentCookTime = compoundTag.getShort("CookTime");
+        this.maxBurnTime = compoundTag.getShort("MaxBurnTime");
+    }
+
+    @Override
+    public void writeAdditionalData(@NotNull final CompoundTag compoundTag) {
+        compoundTag.putShort("BurnTime", (short) this.currentBurnTime);
+        compoundTag.putShort("CookTime", (short) this.currentCookTime);
+        compoundTag.putShort("MaxBurnTime", (short) this.maxBurnTime);
+
+        final ListTag itemsTag = new ListTag();
+        for (int slot = 0; slot < this.inventory.length; slot++) {
+            if (this.inventory[slot] != null) {
+                final CompoundTag itemTag = new CompoundTag();
+                itemTag.putByte("Slot", (byte) slot);
+                this.inventory[slot].writeToNBT(itemTag);
+                itemsTag.addTag(itemTag);
+            }
+        }
+
+        compoundTag.put("Items", itemsTag);
+    }
+
+    @Override
+    public int getMaxStackSize() {
+        return 64;
+    }
+
+    public int getCookProgressScaled(final int i) {
+        if (this.maxCookTime == 0)
+            return 0;
+        return (this.currentCookTime * i) / this.maxCookTime;
+    }
+
+    public int getBurnTimeRemainingScaled(final int i) {
+        if (this.maxBurnTime == 0)
+            return 0;
+        return (this.currentBurnTime * i) / this.maxBurnTime;
+    }
+
+    public boolean isBurning() {
+        return this.currentBurnTime > 0;
+    }
+
+    @Override
+    public void tick() {
+        final boolean isBurnTimeHigherThan0 = this.currentBurnTime > 0;
         boolean furnaceUpdated = false;
 
-        if(currentBurnTime > 0)
-        {
-            currentBurnTime--;
-        }
-        if(worldObj == null || !worldObj.isClientSide)
-        {
-        	if(worldObj == null || worldObj.getBlockId(x, y, z) == Blocks.FURNACE_BLAST_IDLE.id()) {
-            	if(currentBurnTime == 0 && furnaceItemStacks[0] == null) {
-            		if(furnaceItemStacks[1] != null && furnaceItemStacks[1].itemID == Blocks.COBBLE_NETHERRACK.id()) {
-            			furnaceItemStacks[1].stackSize--;
-            			if(furnaceItemStacks[1].stackSize <= 0) furnaceItemStacks[1] = null;
-            			updateFurnace(true);
-            			furnaceUpdated = true;
-            		}
-            	}
-        	}
-            if(currentBurnTime == 0 && canSmelt())
-            {
-                maxBurnTime = currentBurnTime = getBurnTimeFromItem(furnaceItemStacks[1]);
-                if(currentBurnTime > 0)
-                {
+        if (this.currentBurnTime > 0) {
+            this.currentBurnTime--;
+        }
+        if (this.worldObj == null || !this.worldObj.isClientSide) {
+            if (this.worldObj == null || this.worldObj.getBlockId(this.x, this.y, this.z) == Blocks.FURNACE_BLAST_IDLE.id()) {
+                if (this.currentBurnTime == 0 && this.inventory[SLOT_LEFT] == null && this.inventory[SLOT_RIGHT] == null) {
+                    if (this.inventory[SLOT_FUEL] != null && this.inventory[SLOT_FUEL].itemID == Blocks.COBBLE_NETHERRACK.id()) {
+                        this.inventory[SLOT_FUEL].stackSize--;
+                        if (this.inventory[SLOT_FUEL].stackSize <= 0) this.inventory[SLOT_FUEL] = null;
+                        updateFurnace(true);
+                        furnaceUpdated = true;
+                    }
+                }
+            }
+            if (this.currentBurnTime == 0 && canSmelt()) {
+                this.maxBurnTime = this.currentBurnTime = getBurnTimeFromItem(this.inventory[SLOT_FUEL]);
+                if (this.currentBurnTime > 0) {
                     furnaceUpdated = true;
-                    if(furnaceItemStacks[1] != null)
-                    {
-                        furnaceItemStacks[1].stackSize--;
-                        if(furnaceItemStacks[1].stackSize <= 0)
-                        {
-                            furnaceItemStacks[1] = null;
+                    if (this.inventory[SLOT_FUEL] != null) {
+                        this.inventory[SLOT_FUEL].stackSize--;
+                        if (this.inventory[SLOT_FUEL].stackSize <= 0) {
+                            this.inventory[SLOT_FUEL] = null;
                         }
                     }
                 }
             }
 
-            if(isBurning() && canSmelt())
-            {
-                currentCookTime++;
-                if(currentCookTime == maxCookTime)
-                {
-                    currentCookTime = 0;
+            if (isBurning() && canSmelt()) {
+                this.currentCookTime++;
+                if (this.currentCookTime == this.maxCookTime) {
+                    this.currentCookTime = 0;
                     smeltItem();
                     furnaceUpdated = true;
                 }
             } else
-                currentCookTime = 0;
+                this.currentCookTime = 0;
 
-            if(isBurnTimeHigherThan0 != (currentBurnTime > 0))
-            {
+            if (isBurnTimeHigherThan0 != (this.currentBurnTime > 0)) {
                 furnaceUpdated = true;
                 updateFurnace(false);
             }
         }
-        if(furnaceUpdated)
-        {
+        if (furnaceUpdated) {
             setChanged();
         }
     }
 
-    @Override
-    protected void updateFurnace(boolean forceLit){
-        if (worldObj != null) {
-            BlockLogicFurnaceBlast.updateFurnaceBlockState(forceLit | (currentBurnTime > 0), worldObj, x, y, z);
-        } else if (carriedBlock != null) {
-            carriedBlock.blockId = (forceLit | (currentBurnTime > 0)) ? Blocks.FURNACE_BLAST_ACTIVE.id() : Blocks.FURNACE_BLAST_IDLE.id();
-        }
-    }
-
-    private boolean canSmelt()
-    {
-        if(furnaceItemStacks[0] == null)
-        {
+    private boolean canSmelt() {
+        if (this.inventory[SLOT_LEFT] == null && this.inventory[SLOT_RIGHT] == null) {
             return false;
         }
-        List<RecipeEntryBlastFurnace> list = Registries.RECIPES.getAllBlastFurnaceRecipes();
+        final List<RecipeEntryBlastFurnace> list = Registries.RECIPES.getAllBlastFurnaceRecipes();
         ItemStack itemstack = null;
-        for (RecipeEntryBlastFurnace recipeEntryBase : list) {
-            if(recipeEntryBase != null){
-                if(recipeEntryBase.matches(furnaceItemStacks[0])){
+        for (final RecipeEntryBlastFurnace recipeEntryBase : list) {
+            if (recipeEntryBase != null) {
+                if (recipeEntryBase.matches(this.inventory[SLOT_LEFT], this.inventory[SLOT_RIGHT])) {
                     itemstack = recipeEntryBase.getOutput();
                 }
             }
         }
-        if(itemstack == null)
-        {
+        if (itemstack == null) {
             return false;
         }
-        if(furnaceItemStacks[2] == null)
-        {
+        if (this.inventory[SLOT_RESULT] == null) {
             return true;
         }
-        if(!furnaceItemStacks[2].isItemEqual(itemstack))
-        {
+        if (!this.inventory[SLOT_RESULT].isItemEqual(itemstack)) {
             return false;
         }
-        if(furnaceItemStacks[2].stackSize < getMaxStackSize() && furnaceItemStacks[2].stackSize < furnaceItemStacks[2].getMaxStackSize())
-        {
+        if (this.inventory[SLOT_RESULT].stackSize < getMaxStackSize() && this.inventory[SLOT_RESULT].stackSize < this.inventory[SLOT_RESULT].getMaxStackSize()) {
             return true;
         }
-        return furnaceItemStacks[2].stackSize < itemstack.getMaxStackSize();
+        return this.inventory[SLOT_RESULT].stackSize < itemstack.getMaxStackSize();
     }
 
-    @Override
-	public void smeltItem()
-    {
-        if(!canSmelt())
-        {
+    public void smeltItem() {
+        if (!canSmelt()) {
             return;
         }
-        List<RecipeEntryBlastFurnace> list = Registries.RECIPES.getAllBlastFurnaceRecipes();
+        final List<RecipeEntryBlastFurnace> list = Registries.RECIPES.getAllBlastFurnaceRecipes();
         ItemStack itemstack = null;
-        for (RecipeEntryBlastFurnace recipeEntryBase : list) {
-            if(recipeEntryBase != null){
-                if(recipeEntryBase.matches(furnaceItemStacks[0])){
+        for (final RecipeEntryBlastFurnace recipeEntryBase : list) {
+            if (recipeEntryBase != null) {
+                if (recipeEntryBase.matches(this.inventory[SLOT_LEFT], this.inventory[SLOT_RIGHT])) {
                     itemstack = recipeEntryBase.getOutput();
                 }
             }
         }
-        if(furnaceItemStacks[2] == null && itemstack != null)
-        {
-            furnaceItemStacks[2] = itemstack.copy();
-        } else if(furnaceItemStacks[2] != null && itemstack != null && furnaceItemStacks[2].itemID == itemstack.itemID)
-        {
-            furnaceItemStacks[2].stackSize += itemstack.stackSize;
+        if (this.inventory[SLOT_RESULT] == null && itemstack != null) {
+            this.inventory[SLOT_RESULT] = itemstack.copy();
+        } else if (this.inventory[SLOT_RESULT] != null && itemstack != null && this.inventory[SLOT_RESULT].itemID == itemstack.itemID) {
+            this.inventory[SLOT_RESULT].stackSize += itemstack.stackSize;
+        }
+
+        if (this.inventory[SLOT_LEFT] != null) {
+            this.inventory[SLOT_LEFT].stackSize--;
+            if (this.inventory[SLOT_LEFT].stackSize <= 0) {
+                this.inventory[SLOT_LEFT] = null;
+            }
         }
-        furnaceItemStacks[0].stackSize--;
-        if(furnaceItemStacks[0].stackSize <= 0)
-        {
-            furnaceItemStacks[0] = null;
+        if (this.inventory[SLOT_RIGHT] != null) {
+            this.inventory[SLOT_RIGHT].stackSize--;
+            if (this.inventory[SLOT_RIGHT].stackSize <= 0) {
+                this.inventory[SLOT_RIGHT] = null;
+            }
         }
     }
 
-    private int getBurnTimeFromItem(ItemStack itemStack)
-    {
-        if(itemStack == null)
+    protected void updateFurnace(final boolean forceLit) {
+        if (this.worldObj != null) {
+            BlockLogicFurnaceBlast.updateFurnaceBlockState(forceLit | (this.currentBurnTime > 0), this.worldObj, this.x, this.y, this.z);
+        } else if (this.carriedBlock != null) {
+            this.carriedBlock.blockId = (forceLit | (this.currentBurnTime > 0)) ? Blocks.FURNACE_BLAST_ACTIVE.id() : Blocks.FURNACE_BLAST_IDLE.id();
+        }
+    }
+
+    private int getBurnTimeFromItem(final ItemStack itemStack) {
+        if (itemStack == null)
             return 0;
         return LookupFuelFurnaceBlast.instance.getFuelYield(itemStack.getItem().id);
     }
 
+    @Override
+    public boolean stillValid(final Player entityplayer) {
+        if (this.worldObj == null || this.worldObj.getTileEntity(this.x, this.y, this.z) != this) {
+            return false;
+        }
+        return entityplayer.distanceToSqr((double) this.x + 0.5D, (double) this.y + 0.5D, (double) this.z + 0.5D) <= 64D;
+    }
+
+    @Override
+    public void dropContents(final World world, final int x, final int y, final int z) {
+        super.dropContents(world, x, y, z);
+        if (!BlockLogicFurnaceBlast.keepFurnaceInventory) {
+slotLoop:   for (int slot = 0; slot < this.getContainerSize(); slot++) {
+                final ItemStack item = this.getItem(slot);
+                if (item == null) {
+                    continue;
+                }
+                final float rx = this.random.nextFloat() * 0.8F + 0.1F;
+                final float ry = this.random.nextFloat() * 0.8F + 0.1F;
+                final float rz = this.random.nextFloat() * 0.8F + 0.1F;
+                do {
+                    if (item.stackSize <= 0) {
+                        continue slotLoop;
+                    }
+                    int stackSize = this.random.nextInt(21) + 10;
+                    if (stackSize > item.stackSize) {
+                        stackSize = item.stackSize;
+                    }
+                    item.stackSize -= stackSize;
+                    final EntityItem entityItem = new EntityItem(world, (float) x + rx, (float) y + ry, (float) z + rz, new ItemStack(item.itemID, stackSize, item.getMetadata()));
+                    final float velocityScale = 0.05F;
+                    entityItem.xd = (float) this.random.nextGaussian() * velocityScale;
+                    entityItem.yd = (float) this.random.nextGaussian() * velocityScale + 0.2F;
+                    entityItem.zd = (float) this.random.nextGaussian() * velocityScale;
+                    world.entityJoinedWorld(entityItem);
+                } while (true);
+            }
+        }
+    }
+
+    @Override
+    public Packet getDescriptionPacket() {
+        if (this.inventory[SLOT_RESULT] != null) {
+            return new PacketTileEntityData(this);
+        }
+        return null;
+    }
+
+    @Override
+    public void sortContainer() {
+        // Do nothing
+    }
+
+    @Override
+    public void heldTick(final World world, final Entity holder) {
+        tick();
+    }
+
+    @Override
+    public boolean tryPlace(final World world, final Entity holder, final int blockX, final int blockY, final int blockZ, final Side side, final double xPlaced, final double yPlaced) {
+        final boolean success = super.tryPlace(world, holder, blockX, blockY, blockZ, side, xPlaced, yPlaced);
+        if (success) {
+            updateFurnace(false);
+        }
+        return success;
+    }
+
+    @Override
+    public boolean canBeCarried(final World world, final Entity potentialHolder) {
+        return true;
+    }
+
+    @Override
+    public CarriedBlock getCarriedEntry(final World world, final Entity holder, final Block<?> currentBlock, final int currentMeta) {
+        return super.getCarriedEntry(world, holder, currentBlock, (currentMeta & ~0b111) | 0b010 /*Reset rotation, primarily to make it render in hand properly*/);
+    }
 }
\ No newline at end of file
diff --git a/game/core/src/main/java/net/minecraft/core/data/registry/recipe/RecipeRegistry.java b/game/core/src/main/java/net/minecraft/core/data/registry/recipe/RecipeRegistry.java
index daba7734f..b19956171 100644
--- a/game/core/src/main/java/net/minecraft/core/data/registry/recipe/RecipeRegistry.java
+++ b/game/core/src/main/java/net/minecraft/core/data/registry/recipe/RecipeRegistry.java
@@ -382,21 +382,36 @@ public class RecipeRegistry extends Registry<RecipeNamespace> {
         group.register(key,recipe);
     }
 
-    public void addBlastFurnaceRecipe(String recipeKey, ItemStack result, Object input){
+    public void addBlastFurnaceRecipe(String recipeKey, ItemStack result, Object inputA, Object inputB){
         invalidateCaches();
-        RecipeSymbol symbol;
-        if(input instanceof ItemStack) {
-            symbol = new RecipeSymbol('\0', (ItemStack) input,null);
-        }else if(input instanceof Item) {
-            symbol = new RecipeSymbol('\0', new ItemStack((Item) input),null);
-        }else if(input instanceof Block) {
-            symbol = new RecipeSymbol('\0', new ItemStack((Block<?>) input),null);
-        } else if (input instanceof String) {
-            symbol = new RecipeSymbol('\0', null, (String) input);
+        RecipeSymbol symbolA;
+        if(inputA instanceof ItemStack) {
+            symbolA = new RecipeSymbol('\0', (ItemStack) inputA,null);
+        }else if(inputA instanceof Item) {
+            symbolA = new RecipeSymbol('\0', new ItemStack((Item) inputA),null);
+        }else if(inputA instanceof Block) {
+            symbolA = new RecipeSymbol('\0', new ItemStack((Block<?>) inputA),null);
+        } else if (inputA instanceof String) {
+            symbolA = new RecipeSymbol('\0', null, (String) inputA);
         } else {
-            throw new RuntimeException("Invalid object "+input+"!");
+            throw new RuntimeException("Invalid object "+inputA+"!");
+        }
+        RecipeSymbol symbolB = null;
+        if (inputB != null) {
+            if(inputB instanceof ItemStack) {
+                symbolB = new RecipeSymbol('\0', (ItemStack) inputB,null);
+            }else if(inputB instanceof Item) {
+                symbolB = new RecipeSymbol('\0', new ItemStack((Item) inputB),null);
+            }else if(inputB instanceof Block) {
+                symbolB = new RecipeSymbol('\0', new ItemStack((Block<?>) inputB),null);
+            } else if (inputB instanceof String) {
+                symbolB = new RecipeSymbol('\0', null, (String) inputB);
+            } else {
+                throw new RuntimeException("Invalid object "+inputB+"!");
+            }
+
         }
-        RecipeEntryBlastFurnace recipe = new RecipeEntryBlastFurnace(symbol,result);
+        RecipeEntryBlastFurnace recipe = new RecipeEntryBlastFurnace(new RecipeSymbol[] { symbolA, symbolB },result);
         RecipeGroup<RecipeEntryBase<?, ?, ?>> group = getGroupFromKey(recipeKey);
         String key = deconstructKey(recipeKey)[2];
         group.register(key,recipe);
diff --git a/game/core/src/main/java/net/minecraft/core/data/registry/recipe/adapter/RecipeBlastFurnaceJsonAdapter.java b/game/core/src/main/java/net/minecraft/core/data/registry/recipe/adapter/RecipeBlastFurnaceJsonAdapter.java
index 7a0d4d73f..8eb54e0cf 100644
--- a/game/core/src/main/java/net/minecraft/core/data/registry/recipe/adapter/RecipeBlastFurnaceJsonAdapter.java
+++ b/game/core/src/main/java/net/minecraft/core/data/registry/recipe/adapter/RecipeBlastFurnaceJsonAdapter.java
@@ -5,6 +5,7 @@ import net.minecraft.core.data.registry.Registries;
 import net.minecraft.core.data.registry.recipe.RecipeSymbol;
 import net.minecraft.core.data.registry.recipe.entry.RecipeEntryBlastFurnace;
 import net.minecraft.core.item.ItemStack;
+import org.jetbrains.annotations.Nullable;
 
 import java.lang.reflect.Type;
 
@@ -12,9 +13,14 @@ public class RecipeBlastFurnaceJsonAdapter implements RecipeJsonAdapter<RecipeEn
     @Override
     public RecipeEntryBlastFurnace deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
         JsonObject obj = json.getAsJsonObject();
-        RecipeSymbol input = context.deserialize(obj.get("input").getAsJsonObject(),RecipeSymbol.class);
+        RecipeSymbol a = context.deserialize(obj.get("a").getAsJsonObject(),RecipeSymbol.class);
         ItemStack output = context.deserialize(obj.get("output").getAsJsonObject(),ItemStack.class);
-        return new RecipeEntryBlastFurnace(input,output);
+        if (obj.has("b")) {
+            RecipeSymbol b = context.deserialize(obj.get("b").getAsJsonObject(),RecipeSymbol.class);
+            return new RecipeEntryBlastFurnace(new RecipeSymbol[] { a, b },output);
+        } else {
+            return new RecipeEntryBlastFurnace(new RecipeSymbol[] { a },output);
+        }
     }
 
     @Override
@@ -22,8 +28,12 @@ public class RecipeBlastFurnaceJsonAdapter implements RecipeJsonAdapter<RecipeEn
         JsonObject obj = new JsonObject();
         obj.addProperty("name",src.toString());
         obj.addProperty("type", Registries.RECIPE_TYPES.getKey(src.getClass()));
-        obj.add("input",context.serialize(src.getInput()));
+        RecipeSymbol[] input = src.getInput();
+        obj.add("a",context.serialize(input[0]));
         obj.add("output",context.serialize(src.getOutput()));
+        if (input.length == 2) {
+            obj.add("b", context.serialize(input[1]));
+        }
         return obj;
     }
 }
diff --git a/game/core/src/main/java/net/minecraft/core/data/registry/recipe/entry/RecipeEntryBlastFurnace.java b/game/core/src/main/java/net/minecraft/core/data/registry/recipe/entry/RecipeEntryBlastFurnace.java
index abed164d7..79b93bbc1 100644
--- a/game/core/src/main/java/net/minecraft/core/data/registry/recipe/entry/RecipeEntryBlastFurnace.java
+++ b/game/core/src/main/java/net/minecraft/core/data/registry/recipe/entry/RecipeEntryBlastFurnace.java
@@ -5,12 +5,14 @@ import net.minecraft.core.data.registry.recipe.*;
 import net.minecraft.core.data.registry.recipe.adapter.RecipeBlastFurnaceJsonAdapter;
 import net.minecraft.core.data.registry.recipe.adapter.RecipeJsonAdapter;
 import net.minecraft.core.item.ItemStack;
+import org.jetbrains.annotations.NotNull;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
 
-public class RecipeEntryBlastFurnace extends RecipeEntryBase<RecipeSymbol,ItemStack,Void> implements HasJsonAdapter {
-    public RecipeEntryBlastFurnace(RecipeSymbol input, ItemStack output) {
+public class RecipeEntryBlastFurnace extends RecipeEntryBase<RecipeSymbol[],ItemStack,Void> implements HasJsonAdapter {
+    public RecipeEntryBlastFurnace(RecipeSymbol[] input, ItemStack output) {
         super(input, output, null);
     }
 
@@ -26,8 +28,14 @@ public class RecipeEntryBlastFurnace extends RecipeEntryBase<RecipeSymbol,ItemSt
         return false;
     }
 
-    public boolean matches(ItemStack stack){
-        return getInput().matches(stack);
+    public boolean matches(ItemStack left, ItemStack right) {
+        final @NotNull RecipeSymbol[] input = getInput();
+        if (input.length == 1) {
+            return (input[0].matches(left) && right == null) || (input[0].matches(right) && left == null);
+        } else if (input.length == 2) {
+            return (input[0].matches(left) && input[1].matches(right)) || (input[0].matches(right) && input[1].matches(left));
+        }
+        return false;
     }
     public boolean matchesQueryIgnoreExceptions(SearchQuery query){
         try {
@@ -71,7 +79,12 @@ public class RecipeEntryBlastFurnace extends RecipeEntryBase<RecipeSymbol,ItemSt
     }
 
     private boolean matchesUsage(SearchQuery query) {
-        List<ItemStack> stacks = getInput().resolve();
+        List<ItemStack> stacks = new ArrayList<>();
+        final @NotNull RecipeSymbol[] input = getInput();
+        for (RecipeSymbol symbol : input) {
+            stacks.addAll(symbol.resolve());
+        }
+
         for (ItemStack stack : stacks) {
             if (stack == null) continue;
             if(query.query.getLeft() == SearchQuery.QueryType.NAME) {
diff --git a/game/core/src/main/java/net/minecraft/core/entity/player/Player.java b/game/core/src/main/java/net/minecraft/core/entity/player/Player.java
index a12fe413a..1ee88b1c0 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/player/Player.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/player/Player.java
@@ -3,8 +3,7 @@ package net.minecraft.core.entity.player;
 import com.mojang.nbt.tags.CompoundTag;
 import com.mojang.nbt.tags.ListTag;
 import net.minecraft.core.block.BlockLogicBed;
-import net.minecraft.core.block.entity.TileEntityActivator;
-import net.minecraft.core.block.entity.TileEntitySign;
+import net.minecraft.core.block.entity.*;
 import net.minecraft.core.entity.*;
 import net.minecraft.core.entity.animal.MobPig;
 import net.minecraft.core.entity.animal.MobWolf;
@@ -19,11 +18,6 @@ import net.minecraft.core.achievement.stat.Stat;
 import net.minecraft.core.achievement.stat.StatList;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.block.Blocks;
-import net.minecraft.core.block.entity.TileEntity;
-import net.minecraft.core.block.entity.TileEntityDispenser;
-import net.minecraft.core.block.entity.TileEntityFlag;
-import net.minecraft.core.block.entity.TileEntityFurnace;
-import net.minecraft.core.block.entity.TileEntityTrommel;
 import net.minecraft.core.block.material.Material;
 import net.minecraft.core.data.gamerule.GameRules;
 import net.minecraft.core.entity.monster.MobGhast;
@@ -1063,6 +1057,10 @@ public abstract class Player
     {
     }
 
+    public void displayBlastFurnaceScreen(TileEntityFurnaceBlast tileEntity)
+    {
+    }
+
     public void displayTrommelScreen(TileEntityTrommel tileEntity)
     {
     }
diff --git a/game/core/src/main/java/net/minecraft/core/player/inventory/menu/MenuAbstract.java b/game/core/src/main/java/net/minecraft/core/player/inventory/menu/MenuAbstract.java
index 694159663..8b8d52e4e 100644
--- a/game/core/src/main/java/net/minecraft/core/player/inventory/menu/MenuAbstract.java
+++ b/game/core/src/main/java/net/minecraft/core/player/inventory/menu/MenuAbstract.java
@@ -41,7 +41,7 @@ public abstract class MenuAbstract
 		unSynchedPlayers = new HashSet<>();
 	}
 
-	protected void addSlot(Slot slot)
+	protected final void addSlot(Slot slot)
 	{
 		slot.index = slots.size();
 		slots.add(slot);
diff --git a/game/core/src/main/java/net/minecraft/core/player/inventory/menu/MenuFurnaceBlast.java b/game/core/src/main/java/net/minecraft/core/player/inventory/menu/MenuFurnaceBlast.java
new file mode 100644
index 000000000..e23dc5552
--- /dev/null
+++ b/game/core/src/main/java/net/minecraft/core/player/inventory/menu/MenuFurnaceBlast.java
@@ -0,0 +1,159 @@
+package net.minecraft.core.player.inventory.menu;
+
+import it.unimi.dsi.fastutil.ints.IntList;
+import net.minecraft.core.InventoryAction;
+import net.minecraft.core.block.entity.TileEntityFurnace;
+import net.minecraft.core.block.entity.TileEntityFurnaceBlast;
+import net.minecraft.core.crafting.ContainerListener;
+import net.minecraft.core.entity.player.Player;
+import net.minecraft.core.player.inventory.container.ContainerInventory;
+import net.minecraft.core.player.inventory.slot.Slot;
+import net.minecraft.core.player.inventory.slot.SlotFurnace;
+
+public class MenuFurnaceBlast extends MenuAbstract {
+	public static final int ID_CURRENT_COOK_TIME = 0;
+	public static final int ID_CURRENT_BURN_TIME = 1;
+	public static final int ID_MAX_COOK_TIME = 2;
+	public static final int ID_MAX_BURN_TIME = 3;
+
+	public TileEntityFurnaceBlast furnace;
+	private int currentCookTime;
+	private int currentBurnTime;
+	private int itemBurnTime;
+	private int itemCookTime;
+
+	public MenuFurnaceBlast(final ContainerInventory inventory, final TileEntityFurnaceBlast tileEntity) {
+        this.currentCookTime = 0;
+        this.currentBurnTime = 0;
+        this.itemCookTime = 0;
+        this.itemBurnTime = 0;
+        this.furnace = tileEntity;
+
+		addSlot(new Slot(tileEntity, TileEntityFurnaceBlast.SLOT_LEFT, 46, 17));
+		addSlot(new Slot(tileEntity, TileEntityFurnaceBlast.SLOT_RIGHT, 66, 17));
+		addSlot(new Slot(tileEntity, TileEntityFurnaceBlast.SLOT_FUEL, 56, 53));
+		addSlot(new SlotFurnace(inventory.player, tileEntity, TileEntityFurnaceBlast.SLOT_RESULT, 116, 35));
+
+		for (int row = 0; row < 3; row++) {
+			for (int col = 0; col < 9; col++) {
+				addSlot(new Slot(inventory, col + row * 9 + 9, 8 + col * 18, 84 + row * 18));
+			}
+
+		}
+
+		for (int i = 0; i < 9; i++) {
+			addSlot(new Slot(inventory, i, 8 + i * 18, 142));
+		}
+	}
+
+	@Override
+	public void broadcastChanges() {
+		super.broadcastChanges();
+		for (final ContainerListener crafter : this.containerListeners) {
+            if(this.currentCookTime != this.furnace.currentCookTime) {
+				crafter.updateCraftingInventoryInfo(this, ID_CURRENT_COOK_TIME, this.furnace.currentCookTime);
+			}
+			if(this.currentBurnTime != this.furnace.currentBurnTime) {
+				crafter.updateCraftingInventoryInfo(this, ID_CURRENT_BURN_TIME, this.furnace.currentBurnTime);
+			}
+			if(this.itemCookTime != this.furnace.maxCookTime) {
+				crafter.updateCraftingInventoryInfo(this, ID_MAX_COOK_TIME, this.furnace.maxCookTime);
+			}
+			if(this.itemBurnTime != this.furnace.maxBurnTime) {
+				crafter.updateCraftingInventoryInfo(this, ID_MAX_BURN_TIME, this.furnace.maxBurnTime);
+			}
+		}
+
+		this.currentCookTime = this.furnace.currentCookTime;
+		this.currentBurnTime = this.furnace.currentBurnTime;
+		this.itemCookTime = this.furnace.maxCookTime;
+		this.itemBurnTime = this.furnace.maxBurnTime;
+	}
+
+	@Override
+	public void setData(final int id, final int value) {
+        switch (id) {
+            case ID_CURRENT_COOK_TIME:
+                this.furnace.currentCookTime = value;
+                break;
+            case ID_CURRENT_BURN_TIME:
+                this.furnace.currentBurnTime = value;
+                break;
+            case ID_MAX_COOK_TIME:
+                this.furnace.maxCookTime = value;
+                break;
+            case ID_MAX_BURN_TIME:
+                this.furnace.maxBurnTime = value;
+                break;
+        }
+	}
+
+	@Override
+	public boolean stillValid(final Player entityplayer) {
+		return this.furnace.stillValid(entityplayer);
+	}
+
+	/**
+     * 0 Left Input
+	 * 1 Right Input
+     * 2 Fuel
+     * 3 Output
+     * 4 - 30 Main ContainerInventory (27x)
+     * 31 - 39 Hotbar (9x)
+     */
+
+	@Override
+	public IntList getMoveSlots(final InventoryAction action, final Slot slot, final int target, final Player player) {
+		if(slot.index >= 0 && slot.index < 4) return getSlots(slot.index, 1, false);
+
+		if(action == InventoryAction.MOVE_ALL) {
+			if(slot.index >= 4 && slot.index < 31) {
+				// Main ContainerInventory
+				return getSlots(4, 27, false);
+			}
+			if(slot.index >= 31 && slot.index < 40) {
+				// Hotbar
+				return getSlots(31, 9, false);
+			}
+		}
+		if(slot.index >= 4 && slot.index < 40) {
+			// Full ContainerInventory
+			return getSlots(4, 36, false);
+		}
+		return null;
+	}
+
+	@Override
+	public IntList getTargetSlots(final InventoryAction action, final Slot slot, final int target, final Player player) {
+		if(slot.index >= 4 && slot.index < 40) {
+			// Full ContainerInventory
+			if(action != InventoryAction.MOVE_ALL) {
+				if(target == 1) {
+					return getSlots(0, 2, false); // Into Ingredient Slots
+				}
+				if(target == 2) {
+					return getSlots(2, 1, false); // Into Fuel Slot
+				}
+			}
+			if(slot.index >= 4 && slot.index < 31) {
+				// Main ContainerInventory
+				return getSlots(31, 9, false); // Into Hotbar
+			}
+			if(slot.index >= 31 && slot.index < 40) {
+				// Hotbar
+				return getSlots(3, 27, false); // Into Main ContainerInventory
+			}
+		}
+		if(slot.index >= 0 && slot.index < 4) {
+			if(slot.index == 3) {
+				// Output
+				return getSlots(3, 36, true);
+			} else {
+				// Inputs and Fuel
+				return getSlots(3, 36, false);
+			}
+		}
+
+		return null;
+	}
+}
\ No newline at end of file
diff --git a/game/server/src/main/java/net/minecraft/server/entity/player/PlayerServer.java b/game/server/src/main/java/net/minecraft/server/entity/player/PlayerServer.java
index ae74d201f..c0a1ff409 100644
--- a/game/server/src/main/java/net/minecraft/server/entity/player/PlayerServer.java
+++ b/game/server/src/main/java/net/minecraft/server/entity/player/PlayerServer.java
@@ -529,20 +529,23 @@ public class PlayerServer extends Player implements ContainerListener {
 	public void displayFurnaceScreen(TileEntityFurnace tileEntity)
     {
         getNextWindowId();
-        if (tileEntity instanceof TileEntityFurnaceBlast)
-        {
-            playerNetServerHandler.sendPacket(new PacketContainerOpen(currentWindowId, PacketContainerOpen.TYPE_BLAST_FURNACE, tileEntity.getNameTranslationKey(), tileEntity.getContainerSize()));
-        }
-        else
-        {
-            playerNetServerHandler.sendPacket(new PacketContainerOpen(currentWindowId, PacketContainerOpen.TYPE_FURNACE, tileEntity.getNameTranslationKey(), tileEntity.getContainerSize()));
-        }
+        playerNetServerHandler.sendPacket(new PacketContainerOpen(currentWindowId, PacketContainerOpen.TYPE_FURNACE, tileEntity.getNameTranslationKey(), tileEntity.getContainerSize()));
         craftingInventory.onCraftGuiClosed(this);
         craftingInventory = new MenuFurnace(inventory, tileEntity);
         craftingInventory.containerId = currentWindowId;
         craftingInventory.addSlotListener(this);
     }
 
+    @Override
+    public void displayBlastFurnaceScreen(final TileEntityFurnaceBlast tileEntity) {
+        getNextWindowId();
+        playerNetServerHandler.sendPacket(new PacketContainerOpen(currentWindowId, PacketContainerOpen.TYPE_BLAST_FURNACE, tileEntity.getNameTranslationKey(), tileEntity.getContainerSize()));
+        craftingInventory.onCraftGuiClosed(this);
+        craftingInventory = new MenuFurnaceBlast(inventory, tileEntity);
+        craftingInventory.containerId = currentWindowId;
+        craftingInventory.addSlotListener(this);
+    }
+
     @Override
 	public void displayDispenserScreen(TileEntityDispenser tileEntity)
     {
diff --git a/util/datagen/src/main/java/net/minecraft/datagen/SmeltingGenerator.java b/util/datagen/src/main/java/net/minecraft/datagen/SmeltingGenerator.java
index efd246dc4..4dc285a22 100644
--- a/util/datagen/src/main/java/net/minecraft/datagen/SmeltingGenerator.java
+++ b/util/datagen/src/main/java/net/minecraft/datagen/SmeltingGenerator.java
@@ -44,7 +44,8 @@ public class SmeltingGenerator {
         blastRecipe("cobble_limestone_to_marble", Blocks.COBBLE_LIMESTONE.getDefaultStack(), Blocks.MARBLE.getDefaultStack());
         blastRecipe("cobble_permafrost_to_permafrost", Blocks.COBBLE_PERMAFROST.getDefaultStack(), Blocks.PERMAFROST.getDefaultStack());
         blastRecipe("cobble_stone_to_slate", Blocks.COBBLE_STONE.getDefaultStack(), Blocks.SLATE.getDefaultStack());
-        blastRecipe("iron_ingot_to_crude_steel", Items.INGOT_IRON.getDefaultStack(), Items.INGOT_STEEL_CRUDE.getDefaultStack());
+        blastRecipe("iron_ingot_and_coal_to_crude_steel", Items.INGOT_IRON.getDefaultStack(), Items.COAL.getDefaultStack(), Items.INGOT_STEEL_CRUDE.getDefaultStack());
+        blastRecipe("iron_ingot_and_charcoal_to_crude_steel", Items.INGOT_IRON.getDefaultStack(), new ItemStack(Items.COAL, 1, 1), Items.INGOT_STEEL_CRUDE.getDefaultStack());
         blastRecipe("cobble_netherrack_to_igneous_netherrack", Blocks.COBBLE_NETHERRACK.getDefaultStack(), Blocks.COBBLE_NETHERRACK_IGNEOUS.getDefaultStack());
     }
 
@@ -64,6 +65,14 @@ public class SmeltingGenerator {
         RecipeBuilder.BlastFurnace(RecipesGenerator.CORE_NAMESPACE).setInput(inputGroup).create(id, output);
     }
 
+    private static void blastRecipe(String id, ItemStack inputA, ItemStack inputB, ItemStack output) {
+        RecipeBuilder.BlastFurnace(RecipesGenerator.CORE_NAMESPACE).setInput(inputA, inputB).create(id, output);
+    }
+
+    private static void blastRecipe(String id, String inputGroupA, String inputGroupB, ItemStack output) {
+        RecipeBuilder.BlastFurnace(RecipesGenerator.CORE_NAMESPACE).setInput(inputGroupA, inputGroupB).create(id, output);
+    }
+
     private static void sharedRecipe(String id, ItemStack input, ItemStack output) {
         furnaceRecipe(id, input, output);
         blastRecipe(id, input, output);
diff --git a/util/datagen/src/main/java/net/minecraft/datagen/recipeBuilders/RecipeBuilderBlastFurnace.java b/util/datagen/src/main/java/net/minecraft/datagen/recipeBuilders/RecipeBuilderBlastFurnace.java
index c3df7cdcc..fc1f931f4 100644
--- a/util/datagen/src/main/java/net/minecraft/datagen/recipeBuilders/RecipeBuilderBlastFurnace.java
+++ b/util/datagen/src/main/java/net/minecraft/datagen/recipeBuilders/RecipeBuilderBlastFurnace.java
@@ -4,21 +4,135 @@ import net.minecraft.core.block.Blocks;
 import net.minecraft.core.data.registry.recipe.RecipeGroup;
 import net.minecraft.core.data.registry.recipe.RecipeSymbol;
 import net.minecraft.core.data.registry.recipe.entry.RecipeEntryBlastFurnace;
+import net.minecraft.core.data.registry.recipe.entry.RecipeEntryFurnace;
+import net.minecraft.core.item.IItemConvertible;
 import net.minecraft.core.item.ItemStack;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
-public class RecipeBuilderBlastFurnace extends RecipeBuilderFurnace{
+import java.util.Objects;
+
+public class RecipeBuilderBlastFurnace extends RecipeBuilderBase{
+    protected RecipeSymbol a;
+    protected RecipeSymbol b;
     /**
-     * Used for creating new blast furnace recipes.
+     * Used for creating new furnace recipes.
      * @param modID Namespace to create recipe under
      */
     public RecipeBuilderBlastFurnace(String modID) {
         super(modID);
     }
+
+    /**
+     * Blast furnace recipes have one or two inputs
+     * @param a Input item A
+     * @param b Input item B
+     * @return Copy of {@link RecipeBuilderBlastFurnace}
+     */
+    @SuppressWarnings({"unused"})
+    public RecipeBuilderBlastFurnace setInput(@NotNull IItemConvertible a, @Nullable IItemConvertible b){
+        if (b != null) {
+            return setInput(a, 0, b, 0);
+        } else {
+            return setInput(a, 0);
+        }
+    }
+
+    @SuppressWarnings({"unused"})
+    public RecipeBuilderBlastFurnace setInput(@NotNull IItemConvertible a){
+        return setInput(a, null);
+    }
+
+    /**
+     * Blast furnace recipes have one or two inputs
+     * @param a Input item A
+     * @param metaA Item A's required metadata
+     * @param b Input item B
+     * @param metaB Item B's required metadata
+     * @return Copy of {@link RecipeBuilderBlastFurnace}
+     */
+    @SuppressWarnings({"unused"})
+    public RecipeBuilderBlastFurnace setInput(@NotNull IItemConvertible a, int metaA, @Nullable IItemConvertible b, int metaB){
+        if (b != null) {
+            return setInput(new ItemStack(a, 1, metaA), new ItemStack(b, 1, metaB));
+        } else {
+            return setInput(new ItemStack(a, 1, metaA));
+        }
+    }
+
+    @SuppressWarnings({"unused"})
+    public RecipeBuilderBlastFurnace setInput(@NotNull IItemConvertible a, int metaA){
+        return setInput(a, metaA, null, 0);
+    }
+
+    /**
+     * Blast furnace recipes have one or two inputs
+     * @param a Input A {@link ItemStack}
+     * @param b Input B {@link ItemStack}
+     * @return Copy of {@link RecipeBuilderBlastFurnace}
+     */
+    @SuppressWarnings({"unused"})
+    public RecipeBuilderBlastFurnace setInput(@NotNull ItemStack a, @Nullable ItemStack b){
+        if (b != null) {
+            return setInput(new RecipeSymbol(a), new RecipeSymbol(b));
+        } else {
+            return setInput(new RecipeSymbol(a));
+        }
+    }
+
+    @SuppressWarnings({"unused"})
+    public RecipeBuilderBlastFurnace setInput(@NotNull ItemStack a){
+        return setInput(a, null);
+    }
+
+    /**
+     * Blast furnace recipes have one or two inputs
+     * @param itemGroupA Input item group A
+     * @param itemGroupB Input item group B
+     * @return Copy of {@link RecipeBuilderBlastFurnace}
+     */
+    @SuppressWarnings({"unused"})
+    public RecipeBuilderBlastFurnace setInput(@NotNull String itemGroupA, @Nullable String itemGroupB){
+        if (itemGroupB != null) {
+            return setInput(new RecipeSymbol(itemGroupA), new RecipeSymbol(itemGroupB));
+        } else {
+            return setInput(new RecipeSymbol(itemGroupA));
+        }
+    }
+
+    @SuppressWarnings({"unused"})
+    public RecipeBuilderBlastFurnace setInput(@NotNull String itemGroupA){
+        return setInput(itemGroupA, null);
+    }
+
+    /**
+     * Blast furnace recipes have one or two inputs
+     * @param a {@link RecipeSymbol} Input symbol
+     * @return Copy of {@link RecipeBuilderBlastFurnace}
+     */
+    @SuppressWarnings({"unused"})
+    public RecipeBuilderBlastFurnace setInput(@NotNull RecipeSymbol a, @Nullable RecipeSymbol b){
+        RecipeBuilderBlastFurnace builder = this.clone(this);
+        builder.a = Objects.requireNonNull(a, "Input symbol must not be null!");
+        builder.b = b;
+        return builder;
+    }
+
+    @SuppressWarnings({"unused"})
+    public RecipeBuilderBlastFurnace setInput(@NotNull RecipeSymbol a) {
+        return setInput(a, null);
+    }
+
     @Override
-    @SuppressWarnings({"unchecked", "unused"})
+    @SuppressWarnings({"unchecked"})
     public void create(String recipeID, ItemStack outputStack) {
-        RecipeGroup< RecipeEntryBlastFurnace> group = ((RecipeGroup< RecipeEntryBlastFurnace>) RecipeBuilder.getRecipeGroup(modID, "blast_furnace", new RecipeSymbol(Blocks.FURNACE_BLAST_ACTIVE.getDefaultStack())));
+        Objects.requireNonNull(a, "First input symbol must not be null!");
+        RecipeGroup<RecipeEntryBlastFurnace> group = ((RecipeGroup< RecipeEntryBlastFurnace>) RecipeBuilder.getRecipeGroup(modID, "blast_furnace", new RecipeSymbol(Blocks.FURNACE_BLAST_ACTIVE.getDefaultStack())));
         if (group.getItem(recipeID) != null) throw new IllegalArgumentException("RecipeID '" + recipeID + "' already exists!");
-        group.register(recipeID, new RecipeEntryBlastFurnace(input, outputStack));
+        if (b != null) {
+            group.register(recipeID, new RecipeEntryBlastFurnace(new RecipeSymbol[] { a, b }, outputStack));
+        } else {
+            group.register(recipeID, new RecipeEntryBlastFurnace(new RecipeSymbol[] { a }, outputStack));
+        }
     }
 }
