@Override
  public void detectAndSendChanges() {
    super.detectAndSendChanges();

    boolean allFieldsHaveChanged = false;
    boolean fieldHasChanged[] = new boolean[te.getFieldCount()];
    if (cachedFields == null) {
      cachedFields = new int[te.getFieldCount()];
      allFieldsHaveChanged = true;
    }
    for (int i = 0; i < cachedFields.length; i++) {
      if (allFieldsHaveChanged || cachedFields[i] != te.getField(i)) {
        cachedFields[i] = te.getField(i);
        fieldHasChanged[i] = true;
      }
    }

    for (int i = 0; i < this.crafters.size(); i++) {
      ICrafting icrafting = (ICrafting) this.crafters.get(i);
      for (int fieldID = 0; fieldID < te.getFieldCount(); fieldID++) {
        if (fieldHasChanged[fieldID]) {
          icrafting.sendProgressBarUpdate(this, fieldID, cachedFields[fieldID]);
        }
      }
    }
  }
  @Override
  public ItemStack transferStackInSlot(EntityPlayer playerIn, int fromSlot) {
    Slot slot = (Slot) this.inventorySlots.get(fromSlot);
    if (slot == null || !slot.getHasStack()) {
      return null;
    }
    ItemStack stack = slot.getStack();
    ItemStack stackCopy = stack.copy();

    if (fromSlot >= FIRST_VANILLA_SLOT_INDEX
        && fromSlot < FIRST_VANILLA_SLOT_INDEX + VANILLA_SLOT_COUNT) {
      // Merge from player inventory into tile entity
      if (te.getSmeltingResultForItem(stack) != null) {
        if (!this.mergeItemStack(
            stack, FIRST_INPUT_SLOT_INDEX, FIRST_INPUT_SLOT_INDEX + INPUT_SLOTS_COUNT, false)) {
          return null;
        }
      } else if (te.getItemBurnTime(stack) > 0) {
        if (!this.mergeItemStack(
            stack, FIRST_FUEL_SLOT_INDEX, FIRST_FUEL_SLOT_INDEX + FUEL_SLOTS_COUNT, true)) {
          return null;
        }
      } else {
        return null;
      }
    } else if (fromSlot >= FIRST_FUEL_SLOT_INDEX
        && fromSlot < FIRST_FUEL_SLOT_INDEX + FURNACE_SLOTS_COUNT) {
      if (!this.mergeItemStack(
          stack, FIRST_VANILLA_SLOT_INDEX, FIRST_VANILLA_SLOT_INDEX + VANILLA_SLOT_COUNT, false)) {
        return null;
      }
    } else {
      System.err.print("Invalid slotIndex: " + fromSlot);
    }

    if (stack.stackSize == 0) {
      slot.putStack(null);
    } else {
      slot.onSlotChanged();
    }

    slot.onPickupFromSlot(playerIn, stack);
    return stackCopy;
  }
 @SideOnly(Side.CLIENT)
 @Override
 public void updateProgressBar(int id, int data) {
   te.setField(id, data);
 }