@Override
  public void invalidate() {
    if (Platform.isClient()) {
      return;
    }

    AELog.info("Released Ticket " + this.ct.toString());
    ForgeChunkManager.releaseTicket(this.ct);
  }
  void initTicket() {
    if (Platform.isClient()) {
      return;
    }

    this.ct = ForgeChunkManager.requestTicket(AppEng.instance(), this.worldObj, Type.NORMAL);

    if (this.ct == null) {
      MinecraftServer server = FMLCommonHandler.instance().getMinecraftServerInstance();
      if (server != null) {
        List<EntityPlayerMP> pl = server.getConfigurationManager().playerEntityList;
        for (EntityPlayerMP p : pl) {
          p.addChatMessage(new ChatComponentText("Can't chunk load.."));
        }
      }
      return;
    }

    AELog.info("New Ticket " + this.ct.toString());
    ForgeChunkManager.forceChunk(
        this.ct, new ChunkCoordIntPair(this.xCoord >> 4, this.zCoord >> 4));
  }
  public void queueInventory(final ICrafting c) {
    if (Platform.isServer() && c instanceof EntityPlayer && this.monitor != null) {
      try {
        PacketMEInventoryUpdate piu = new PacketMEInventoryUpdate();
        final IItemList<IAEItemStack> monitorCache = this.monitor.getStorageList();

        for (final IAEItemStack send : monitorCache) {
          try {
            piu.appendItem(send);
          } catch (final BufferOverflowException boe) {
            NetworkHandler.instance.sendTo(piu, (EntityPlayerMP) c);

            piu = new PacketMEInventoryUpdate();
            piu.appendItem(send);
          }
        }

        NetworkHandler.instance.sendTo(piu, (EntityPlayerMP) c);
      } catch (final IOException e) {
        AELog.error(e);
      }
    }
  }
  private void drawSlot(final Slot s) {
    if (s instanceof SlotME) {
      final RenderItem pIR = this.setItemRender(this.aeRenderItem);
      try {
        this.zLevel = 100.0F;
        itemRender.zLevel = 100.0F;

        if (!this.isPowered()) {
          GL11.glDisable(GL11.GL_LIGHTING);
          drawRect(
              s.xDisplayPosition,
              s.yDisplayPosition,
              16 + s.xDisplayPosition,
              16 + s.yDisplayPosition,
              0x66111111);
          GL11.glEnable(GL11.GL_LIGHTING);
        }

        this.zLevel = 0.0F;
        itemRender.zLevel = 0.0F;

        this.aeRenderItem.setAeStack(((SlotME) s).getAEStack());

        this.safeDrawSlot(s);
      } catch (final Exception err) {
        AELog.warn("[AppEng] AE prevented crash while drawing slot: " + err.toString());
      }
      this.setItemRender(pIR);
      return;
    } else {
      try {
        final ItemStack is = s.getStack();
        if (s instanceof AppEngSlot
            && (((AppEngSlot) s).renderIconWithItem() || is == null)
            && (((AppEngSlot) s).shouldDisplay())) {
          final AppEngSlot aes = (AppEngSlot) s;
          if (aes.getIcon() >= 0) {
            this.bindTexture("guis/states.png");

            GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
            final Tessellator tessellator = Tessellator.instance;
            try {
              final int uv_y = (int) Math.floor(aes.getIcon() / 16);
              final int uv_x = aes.getIcon() - uv_y * 16;

              GL11.glEnable(GL11.GL_BLEND);
              GL11.glDisable(GL11.GL_LIGHTING);
              GL11.glEnable(GL11.GL_TEXTURE_2D);
              GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
              GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
              final float par1 = aes.xDisplayPosition;
              final float par2 = aes.yDisplayPosition;
              final float par3 = uv_x * 16;
              final float par4 = uv_y * 16;

              tessellator.startDrawingQuads();
              tessellator.setColorRGBA_F(1.0f, 1.0f, 1.0f, aes.getOpacityOfIcon());
              final float f1 = 0.00390625F;
              final float f = 0.00390625F;
              final float par6 = 16;
              tessellator.addVertexWithUV(
                  par1 + 0, par2 + par6, this.zLevel, (par3 + 0) * f, (par4 + par6) * f1);
              final float par5 = 16;
              tessellator.addVertexWithUV(
                  par1 + par5, par2 + par6, this.zLevel, (par3 + par5) * f, (par4 + par6) * f1);
              tessellator.addVertexWithUV(
                  par1 + par5, par2 + 0, this.zLevel, (par3 + par5) * f, (par4 + 0) * f1);
              tessellator.addVertexWithUV(
                  par1 + 0, par2 + 0, this.zLevel, (par3 + 0) * f, (par4 + 0) * f1);
              tessellator.setColorRGBA_F(1.0f, 1.0f, 1.0f, 1.0f);
              tessellator.draw();
            } catch (final Exception err) {
            }
            GL11.glPopAttrib();
          }
        }

        if (is != null && s instanceof AppEngSlot) {
          if (((AppEngSlot) s).getIsValid() == hasCalculatedValidness.NotAvailable) {
            boolean isValid =
                s.isItemValid(is)
                    || s instanceof SlotOutput
                    || s instanceof AppEngCraftingSlot
                    || s instanceof SlotDisabled
                    || s instanceof SlotInaccessible
                    || s instanceof SlotFake
                    || s instanceof SlotRestrictedInput
                    || s instanceof SlotDisconnected;
            if (isValid && s instanceof SlotRestrictedInput) {
              try {
                isValid = ((SlotRestrictedInput) s).isValid(is, this.mc.theWorld);
              } catch (final Exception err) {
                AELog.debug(err);
              }
            }
            ((AppEngSlot) s)
                .setIsValid(
                    isValid ? hasCalculatedValidness.Valid : hasCalculatedValidness.Invalid);
          }

          if (((AppEngSlot) s).getIsValid() == hasCalculatedValidness.Invalid) {
            this.zLevel = 100.0F;
            itemRender.zLevel = 100.0F;

            GL11.glDisable(GL11.GL_LIGHTING);
            drawRect(
                s.xDisplayPosition,
                s.yDisplayPosition,
                16 + s.xDisplayPosition,
                16 + s.yDisplayPosition,
                0x66ff6666);
            GL11.glEnable(GL11.GL_LIGHTING);

            this.zLevel = 0.0F;
            itemRender.zLevel = 0.0F;
          }
        }

        if (s instanceof AppEngSlot) {
          ((AppEngSlot) s).setDisplay(true);
          this.safeDrawSlot(s);
        } else {
          this.safeDrawSlot(s);
        }

        return;
      } catch (final Exception err) {
        AELog.warn("[AppEng] AE prevented crash while drawing slot: " + err.toString());
      }
    }
    // do the usual for non-ME Slots.
    this.safeDrawSlot(s);
  }
  @Override
  protected void handleMouseClick(
      final Slot slot, final int slotIdx, final int ctrlDown, final int key) {
    final EntityPlayer player = Minecraft.getMinecraft().thePlayer;

    if (slot instanceof SlotFake) {
      final InventoryAction action =
          ctrlDown == 1
              ? InventoryAction.SPLIT_OR_PLACE_SINGLE
              : InventoryAction.PICKUP_OR_SET_DOWN;

      if (this.drag_click.size() > 1) {
        return;
      }

      final PacketInventoryAction p = new PacketInventoryAction(action, slotIdx, 0);
      NetworkHandler.instance.sendToServer(p);

      return;
    }

    if (slot instanceof SlotPatternTerm) {
      if (key == 6) {
        return; // prevent weird double clicks..
      }

      try {
        NetworkHandler.instance.sendToServer(((SlotPatternTerm) slot).getRequest(key == 1));
      } catch (final IOException e) {
        AELog.debug(e);
      }
    } else if (slot instanceof SlotCraftingTerm) {
      if (key == 6) {
        return; // prevent weird double clicks..
      }

      InventoryAction action = null;
      if (key == 1) {
        action = InventoryAction.CRAFT_SHIFT;
      } else {
        action = ctrlDown == 1 ? InventoryAction.CRAFT_STACK : InventoryAction.CRAFT_ITEM;
      }

      final PacketInventoryAction p = new PacketInventoryAction(action, slotIdx, 0);
      NetworkHandler.instance.sendToServer(p);

      return;
    }

    if (Keyboard.isKeyDown(Keyboard.KEY_SPACE)) {
      if (this.enableSpaceClicking()) {
        IAEItemStack stack = null;
        if (slot instanceof SlotME) {
          stack = ((SlotME) slot).getAEStack();
        }

        int slotNum = this.getInventorySlots().size();

        if (!(slot instanceof SlotME) && slot != null) {
          slotNum = slot.slotNumber;
        }

        ((AEBaseContainer) this.inventorySlots).setTargetStack(stack);
        final PacketInventoryAction p =
            new PacketInventoryAction(InventoryAction.MOVE_REGION, slotNum, 0);
        NetworkHandler.instance.sendToServer(p);
        return;
      }
    }

    if (slot instanceof SlotDisconnected) {
      InventoryAction action = null;

      switch (key) {
        case 0: // pickup / set-down.
          action =
              ctrlDown == 1
                  ? InventoryAction.SPLIT_OR_PLACE_SINGLE
                  : InventoryAction.PICKUP_OR_SET_DOWN;
          break;
        case 1:
          action = ctrlDown == 1 ? InventoryAction.PICKUP_SINGLE : InventoryAction.SHIFT_CLICK;
          break;

        case 3: // creative dupe:
          if (player.capabilities.isCreativeMode) {
            action = InventoryAction.CREATIVE_DUPLICATE;
          }

          break;

        default:
        case 4: // drop item:
        case 6:
      }

      if (action != null) {
        final PacketInventoryAction p =
            new PacketInventoryAction(
                action, slot.getSlotIndex(), ((SlotDisconnected) slot).getSlot().getId());
        NetworkHandler.instance.sendToServer(p);
      }

      return;
    }

    if (slot instanceof SlotME) {
      InventoryAction action = null;
      IAEItemStack stack = null;

      switch (key) {
        case 0: // pickup / set-down.
          action =
              ctrlDown == 1
                  ? InventoryAction.SPLIT_OR_PLACE_SINGLE
                  : InventoryAction.PICKUP_OR_SET_DOWN;
          stack = ((SlotME) slot).getAEStack();

          if (stack != null
              && action == InventoryAction.PICKUP_OR_SET_DOWN
              && stack.getStackSize() == 0
              && player.inventory.getItemStack() == null) {
            action = InventoryAction.AUTO_CRAFT;
          }

          break;
        case 1:
          action = ctrlDown == 1 ? InventoryAction.PICKUP_SINGLE : InventoryAction.SHIFT_CLICK;
          stack = ((SlotME) slot).getAEStack();
          break;

        case 3: // creative dupe:
          stack = ((SlotME) slot).getAEStack();
          if (stack != null && stack.isCraftable()) {
            action = InventoryAction.AUTO_CRAFT;
          } else if (player.capabilities.isCreativeMode) {
            final IAEItemStack slotItem = ((SlotME) slot).getAEStack();
            if (slotItem != null) {
              action = InventoryAction.CREATIVE_DUPLICATE;
            }
          }
          break;

        default:
        case 4: // drop item:
        case 6:
      }

      if (action != null) {
        ((AEBaseContainer) this.inventorySlots).setTargetStack(stack);
        final PacketInventoryAction p =
            new PacketInventoryAction(action, this.getInventorySlots().size(), 0);
        NetworkHandler.instance.sendToServer(p);
      }

      return;
    }

    if (!this.disableShiftClick && isShiftKeyDown()) {
      this.disableShiftClick = true;

      if (this.dbl_whichItem == null
          || this.bl_clicked != slot
          || this.dbl_clickTimer.elapsed(TimeUnit.MILLISECONDS) > 150) {
        // some simple double click logic.
        this.bl_clicked = slot;
        this.dbl_clickTimer = Stopwatch.createStarted();
        if (slot != null) {
          this.dbl_whichItem = slot.getHasStack() ? slot.getStack().copy() : null;
        } else {
          this.dbl_whichItem = null;
        }
      } else if (this.dbl_whichItem != null) {
        // a replica of the weird broken vanilla feature.

        final List<Slot> slots = this.getInventorySlots();
        for (final Slot inventorySlot : slots) {
          if (inventorySlot != null
              && inventorySlot.canTakeStack(this.mc.thePlayer)
              && inventorySlot.getHasStack()
              && inventorySlot.inventory == slot.inventory
              && Container.func_94527_a(inventorySlot, this.dbl_whichItem, true)) {
            this.handleMouseClick(inventorySlot, inventorySlot.slotNumber, ctrlDown, 1);
          }
        }
      }

      this.disableShiftClick = false;
    }

    super.handleMouseClick(slot, slotIdx, ctrlDown, key);
  }
  @Override
  public void detectAndSendChanges() {
    if (Platform.isServer()) {
      if (this.monitor != this.host.getItemInventory()) {
        this.isContainerValid = false;
      }

      for (final Settings set : this.serverCM.getSettings()) {
        final Enum<?> sideLocal = this.serverCM.getSetting(set);
        final Enum<?> sideRemote = this.clientCM.getSetting(set);

        if (sideLocal != sideRemote) {
          this.clientCM.putSetting(set, sideLocal);
          for (final Object crafter : this.crafters) {
            try {
              NetworkHandler.instance.sendTo(
                  new PacketValueConfig(set.name(), sideLocal.name()), (EntityPlayerMP) crafter);
            } catch (final IOException e) {
              AELog.error(e);
            }
          }
        }
      }

      if (!this.items.isEmpty()) {
        try {
          final IItemList<IAEItemStack> monitorCache = this.monitor.getStorageList();

          final PacketMEInventoryUpdate piu = new PacketMEInventoryUpdate();

          for (final IAEItemStack is : this.items) {
            final IAEItemStack send = monitorCache.findPrecise(is);
            if (send == null) {
              is.setStackSize(0);
              piu.appendItem(is);
            } else {
              piu.appendItem(send);
            }
          }

          if (!piu.isEmpty()) {
            this.items.resetStatus();

            for (final Object c : this.crafters) {
              if (c instanceof EntityPlayer) {
                NetworkHandler.instance.sendTo(piu, (EntityPlayerMP) c);
              }
            }
          }
        } catch (final IOException e) {
          AELog.error(e);
        }
      }

      this.updatePowerStatus();

      final boolean oldAccessible = this.canAccessViewCells;
      this.canAccessViewCells = this.hasAccess(SecurityPermissions.BUILD, false);
      if (this.canAccessViewCells != oldAccessible) {
        for (int y = 0; y < 5; y++) {
          if (this.cellView[y] != null) {
            this.cellView[y].allowEdit = this.canAccessViewCells;
          }
        }
      }

      super.detectAndSendChanges();
    }
  }