// In line decoding and handling of the packet
  @Override
  protected void decode(ChannelHandlerContext ctx, FMLProxyPacket msg, List<Object> out)
      throws Exception {
    ByteBuf payload = msg.payload();
    byte discriminator = payload.readByte();
    Class<? extends AbstractPacket> clazz = this.packets.get(discriminator);
    if (clazz == null) {
      throw new NullPointerException("No packet registered for discriminator: " + discriminator);
    }

    AbstractPacket pkt = clazz.newInstance();
    pkt.decodeInto(ctx, payload.slice());

    EntityPlayer player;
    switch (FMLCommonHandler.instance().getEffectiveSide()) {
      case CLIENT:
        player = this.getClientPlayer();
        pkt.handleClientSide(player);
        break;

      case SERVER:
        INetHandler netHandler = ctx.channel().attr(NetworkRegistry.NET_HANDLER).get();
        player = ((NetHandlerPlayServer) netHandler).playerEntity;
        pkt.handleServerSide(player);
        break;

      default:
    }

    out.add(pkt);
  }
  // In line encoding of the packet, including discriminator setting
  @Override
  protected void encode(ChannelHandlerContext ctx, AbstractPacket msg, List<Object> out)
      throws Exception {
    ByteBuf buffer = Unpooled.buffer();
    Class<? extends AbstractPacket> clazz = msg.getClass();
    if (!this.packets.contains(msg.getClass())) {
      throw new NullPointerException(
          "No Packet Registered for: " + msg.getClass().getCanonicalName());
    }

    byte discriminator = (byte) this.packets.indexOf(clazz);
    buffer.writeByte(discriminator);
    msg.encodeInto(ctx, buffer);
    FMLProxyPacket proxyPacket =
        new FMLProxyPacket(buffer.copy(), ctx.channel().attr(NetworkRegistry.FML_CHANNEL).get());
    out.add(proxyPacket);
  }
  /**
   * 申请一个 指定类型的空包。
   *
   * @param clazz
   */
  @SuppressWarnings("unchecked")
  public static <E> E newPacket(Class<? extends IPacket> clazz) {

    int packetId = Singleton.INSTANCE.getPacketId(clazz);
    if (packetId > 0) {
      try {
        AbstractPacket newInstance = (AbstractPacket) clazz.newInstance();

        newInstance.setPacketId(packetId);
        // TODO 根据PacketId 编号,决定数据包类型
        return (E) newInstance;
      } catch (InstantiationException e) {
        e.printStackTrace();
      } catch (IllegalAccessException e) {
        e.printStackTrace();
      }
    }
    return null;
  }