Java tutorial
/* * This file is part of Applied Energistics 2. * Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved. * * Applied Energistics 2 is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Applied Energistics 2 is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>. */ package appeng.core.sync.packets; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.BufferOverflowException; import java.util.LinkedList; import java.util.List; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; import javax.annotation.Nullable; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiScreen; import net.minecraft.entity.player.EntityPlayer; import net.minecraftforge.fml.common.network.internal.FMLProxyPacket; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import appeng.api.storage.data.IAEItemStack; import appeng.client.gui.implementations.GuiCraftConfirm; import appeng.client.gui.implementations.GuiCraftingCPU; import appeng.client.gui.implementations.GuiMEMonitorable; import appeng.client.gui.implementations.GuiNetworkStatus; import appeng.core.AELog; import appeng.core.sync.AppEngPacket; import appeng.core.sync.network.INetworkInfo; import appeng.util.item.AEItemStack; public class PacketMEInventoryUpdate extends AppEngPacket { private static final int UNCOMPRESSED_PACKET_BYTE_LIMIT = 16 * 1024 * 1024; private static final int OPERATION_BYTE_LIMIT = 2 * 1024; private static final int TEMP_BUFFER_SIZE = 1024; private static final int STREAM_MASK = 0xff; // input. @Nullable private final List<IAEItemStack> list; // output... private final byte ref; @Nullable private final ByteBuf data; @Nullable private final GZIPOutputStream compressFrame; private int writtenBytes = 0; private boolean empty = true; // automatic. public PacketMEInventoryUpdate(final ByteBuf stream) throws IOException { this.data = null; this.compressFrame = null; this.list = new LinkedList<IAEItemStack>(); this.ref = stream.readByte(); // int originalBytes = stream.readableBytes(); final GZIPInputStream gzReader = new GZIPInputStream(new InputStream() { @Override public int read() throws IOException { if (stream.readableBytes() <= 0) { return -1; } return stream.readByte() & STREAM_MASK; } }); final ByteBuf uncompressed = Unpooled.buffer(stream.readableBytes()); final byte[] tmp = new byte[TEMP_BUFFER_SIZE]; while (gzReader.available() != 0) { final int bytes = gzReader.read(tmp); if (bytes > 0) { uncompressed.writeBytes(tmp, 0, bytes); } } gzReader.close(); // int uncompressedBytes = uncompressed.readableBytes(); // AELog.info( "Receiver: " + originalBytes + " -> " + uncompressedBytes ); while (uncompressed.readableBytes() > 0) { this.list.add(AEItemStack.loadItemStackFromPacket(uncompressed)); } this.empty = this.list.isEmpty(); } // api public PacketMEInventoryUpdate() throws IOException { this((byte) 0); } // api public PacketMEInventoryUpdate(final byte ref) throws IOException { this.ref = ref; this.data = Unpooled.buffer(OPERATION_BYTE_LIMIT); this.data.writeInt(this.getPacketID()); this.data.writeByte(this.ref); this.compressFrame = new GZIPOutputStream(new OutputStream() { @Override public void write(final int value) throws IOException { PacketMEInventoryUpdate.this.data.writeByte(value); } }); this.list = null; } @Override @SideOnly(Side.CLIENT) public void clientPacketData(final INetworkInfo network, final AppEngPacket packet, final EntityPlayer player) { final GuiScreen gs = Minecraft.getMinecraft().currentScreen; if (gs instanceof GuiCraftConfirm) { ((GuiCraftConfirm) gs).postUpdate(this.list, this.ref); } if (gs instanceof GuiCraftingCPU) { ((GuiCraftingCPU) gs).postUpdate(this.list, this.ref); } if (gs instanceof GuiMEMonitorable) { ((GuiMEMonitorable) gs).postUpdate(this.list); } if (gs instanceof GuiNetworkStatus) { ((GuiNetworkStatus) gs).postUpdate(this.list); } } @Nullable @Override public FMLProxyPacket getProxy() { try { this.compressFrame.close(); this.configureWrite(this.data); return super.getProxy(); } catch (final IOException e) { AELog.debug(e); } return null; } public void appendItem(final IAEItemStack is) throws IOException, BufferOverflowException { final ByteBuf tmp = Unpooled.buffer(OPERATION_BYTE_LIMIT); is.writeToPacket(tmp); this.compressFrame.flush(); if (this.writtenBytes + tmp.readableBytes() > UNCOMPRESSED_PACKET_BYTE_LIMIT) { throw new BufferOverflowException(); } else { this.writtenBytes += tmp.readableBytes(); this.compressFrame.write(tmp.array(), 0, tmp.readableBytes()); this.empty = false; } } public int getLength() { return this.data.readableBytes(); } public boolean isEmpty() { return this.empty; } }