001    package net.minecraft.network.packet;
002    
003    import cpw.mods.fml.relauncher.Side;
004    import cpw.mods.fml.relauncher.SideOnly;
005    import java.io.DataInputStream;
006    import java.io.DataOutputStream;
007    import java.io.IOException;
008    import java.util.concurrent.Semaphore;
009    import java.util.zip.DataFormatException;
010    import java.util.zip.Deflater;
011    import java.util.zip.Inflater;
012    import net.minecraft.world.chunk.Chunk;
013    import net.minecraft.world.chunk.NibbleArray;
014    import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
015    
016    public class Packet51MapChunk extends Packet
017    {
018        /** The x-position of the transmitted chunk, in chunk coordinates. */
019        public int xCh;
020    
021        /** The z-position of the transmitted chunk, in chunk coordinates. */
022        public int zCh;
023    
024        /**
025         * The y-position of the lowest chunk Section in the transmitted chunk, in chunk coordinates.
026         */
027        public int yChMin;
028    
029        /**
030         * The y-position of the highest chunk Section in the transmitted chunk, in chunk coordinates.
031         */
032        public int yChMax;
033    
034        /** The transmitted chunk data, decompressed. */
035        private byte[] chunkData;
036        private byte[] field_73596_g;
037    
038        /**
039         * Whether to initialize the Chunk before applying the effect of the Packet51MapChunk.
040         */
041        public boolean includeInitialize;
042    
043        /** The length of the compressed chunk data byte array. */
044        private int tempLength;
045    
046        /** A temporary storage for the compressed chunk data byte array. */
047        private static byte[] temp = new byte[196864];
048    
049        private Semaphore deflateGate;
050    
051        public Packet51MapChunk()
052        {
053            this.isChunkDataPacket = true;
054        }
055    
056        public Packet51MapChunk(Chunk par1Chunk, boolean par2, int par3)
057        {
058            this.isChunkDataPacket = true;
059            this.xCh = par1Chunk.xPosition;
060            this.zCh = par1Chunk.zPosition;
061            this.includeInitialize = par2;
062            Packet51MapChunkData var4 = getMapChunkData(par1Chunk, par2, par3);
063            this.yChMax = var4.field_74581_c;
064            this.yChMin = var4.field_74580_b;
065            this.field_73596_g = var4.field_74582_a;
066            this.deflateGate = new Semaphore(1);
067        }
068    
069        private void deflate()
070        {
071            Deflater var5 = new Deflater(-1);
072            try
073            {
074                var5.setInput(field_73596_g, 0, field_73596_g.length);
075                var5.finish();
076                this.chunkData = new byte[field_73596_g.length];
077                this.tempLength = var5.deflate(this.chunkData);
078            }
079            finally
080            {
081                var5.end();
082            }
083        }
084    
085        /**
086         * Abstract. Reads the raw packet data from the data stream.
087         */
088        public void readPacketData(DataInputStream par1DataInputStream) throws IOException
089        {
090            this.xCh = par1DataInputStream.readInt();
091            this.zCh = par1DataInputStream.readInt();
092            this.includeInitialize = par1DataInputStream.readBoolean();
093            this.yChMin = par1DataInputStream.readShort();
094            this.yChMax = par1DataInputStream.readShort();
095            this.tempLength = par1DataInputStream.readInt();
096    
097            if (temp.length < this.tempLength)
098            {
099                temp = new byte[this.tempLength];
100            }
101    
102            par1DataInputStream.readFully(temp, 0, this.tempLength);
103            int var2 = 0;
104            int var3;
105            int msb = 0; //BugFix: MC does not read the MSB array from the packet properly, causing issues for servers that use blocks > 256
106    
107            for (var3 = 0; var3 < 16; ++var3)
108            {
109                var2 += this.yChMin >> var3 & 1;
110                msb  += this.yChMax >> var3 & 1;
111            }
112    
113            var3 = 12288 * var2;
114            var3 += 2048 * msb;
115    
116            if (this.includeInitialize)
117            {
118                var3 += 256;
119            }
120    
121            this.field_73596_g = new byte[var3];
122            Inflater var4 = new Inflater();
123            var4.setInput(temp, 0, this.tempLength);
124    
125            try
126            {
127                var4.inflate(this.field_73596_g);
128            }
129            catch (DataFormatException var9)
130            {
131                throw new IOException("Bad compressed data format");
132            }
133            finally
134            {
135                var4.end();
136            }
137        }
138    
139        /**
140         * Abstract. Writes the raw packet data to the data stream.
141         */
142        public void writePacketData(DataOutputStream par1DataOutputStream) throws IOException
143        {
144            if (chunkData == null)
145            {
146                deflateGate.acquireUninterruptibly();
147                if (chunkData == null)
148                {
149                    deflate();
150                }
151                deflateGate.release();
152            }
153    
154            par1DataOutputStream.writeInt(this.xCh);
155            par1DataOutputStream.writeInt(this.zCh);
156            par1DataOutputStream.writeBoolean(this.includeInitialize);
157            par1DataOutputStream.writeShort((short)(this.yChMin & 65535));
158            par1DataOutputStream.writeShort((short)(this.yChMax & 65535));
159            par1DataOutputStream.writeInt(this.tempLength);
160            par1DataOutputStream.write(this.chunkData, 0, this.tempLength);
161        }
162    
163        /**
164         * Passes this Packet on to the NetHandler for processing.
165         */
166        public void processPacket(NetHandler par1NetHandler)
167        {
168            par1NetHandler.handleMapChunk(this);
169        }
170    
171        /**
172         * Abstract. Return the size of the packet (not counting the header).
173         */
174        public int getPacketSize()
175        {
176            return 17 + this.tempLength;
177        }
178    
179        public static Packet51MapChunkData getMapChunkData(Chunk par0Chunk, boolean par1, int par2)
180        {
181            int var3 = 0;
182            ExtendedBlockStorage[] var4 = par0Chunk.getBlockStorageArray();
183            int var5 = 0;
184            Packet51MapChunkData var6 = new Packet51MapChunkData();
185            byte[] var7 = temp;
186    
187            if (par1)
188            {
189                par0Chunk.deferRender = true;
190            }
191    
192            int var8;
193    
194            for (var8 = 0; var8 < var4.length; ++var8)
195            {
196                if (var4[var8] != null && (!par1 || !var4[var8].isEmpty()) && (par2 & 1 << var8) != 0)
197                {
198                    var6.field_74580_b |= 1 << var8;
199    
200                    if (var4[var8].getBlockMSBArray() != null)
201                    {
202                        var6.field_74581_c |= 1 << var8;
203                        ++var5;
204                    }
205                }
206            }
207    
208            for (var8 = 0; var8 < var4.length; ++var8)
209            {
210                if (var4[var8] != null && (!par1 || !var4[var8].isEmpty()) && (par2 & 1 << var8) != 0)
211                {
212                    byte[] var9 = var4[var8].getBlockLSBArray();
213                    System.arraycopy(var9, 0, var7, var3, var9.length);
214                    var3 += var9.length;
215                }
216            }
217    
218            NibbleArray var10;
219    
220            for (var8 = 0; var8 < var4.length; ++var8)
221            {
222                if (var4[var8] != null && (!par1 || !var4[var8].isEmpty()) && (par2 & 1 << var8) != 0)
223                {
224                    var10 = var4[var8].getMetadataArray();
225                    System.arraycopy(var10.data, 0, var7, var3, var10.data.length);
226                    var3 += var10.data.length;
227                }
228            }
229    
230            for (var8 = 0; var8 < var4.length; ++var8)
231            {
232                if (var4[var8] != null && (!par1 || !var4[var8].isEmpty()) && (par2 & 1 << var8) != 0)
233                {
234                    var10 = var4[var8].getBlocklightArray();
235                    System.arraycopy(var10.data, 0, var7, var3, var10.data.length);
236                    var3 += var10.data.length;
237                }
238            }
239    
240            if (!par0Chunk.worldObj.provider.hasNoSky)
241            {
242                for (var8 = 0; var8 < var4.length; ++var8)
243                {
244                    if (var4[var8] != null && (!par1 || !var4[var8].isEmpty()) && (par2 & 1 << var8) != 0)
245                    {
246                        var10 = var4[var8].getSkylightArray();
247                        System.arraycopy(var10.data, 0, var7, var3, var10.data.length);
248                        var3 += var10.data.length;
249                    }
250                }
251            }
252    
253            if (var5 > 0)
254            {
255                for (var8 = 0; var8 < var4.length; ++var8)
256                {
257                    if (var4[var8] != null && (!par1 || !var4[var8].isEmpty()) && var4[var8].getBlockMSBArray() != null && (par2 & 1 << var8) != 0)
258                    {
259                        var10 = var4[var8].getBlockMSBArray();
260                        System.arraycopy(var10.data, 0, var7, var3, var10.data.length);
261                        var3 += var10.data.length;
262                    }
263                }
264            }
265    
266            if (par1)
267            {
268                byte[] var11 = par0Chunk.getBiomeArray();
269                System.arraycopy(var11, 0, var7, var3, var11.length);
270                var3 += var11.length;
271            }
272    
273            var6.field_74582_a = new byte[var3];
274            System.arraycopy(var7, 0, var6.field_74582_a, 0, var3);
275            return var6;
276        }
277    
278        @SideOnly(Side.CLIENT)
279        public byte[] func_73593_d()
280        {
281            return this.field_73596_g;
282        }
283    }