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