    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                byte[] deflated = new byte[field_73596_g.length];
    077                this.tempLength = var5.deflate(deflated);
    078                this.chunkData = deflated;
    079            }
    080            finally
    081            {
    082                var5.end();
    083            }
    084        }
    085
    086        /**
    087         * Abstract. Reads the raw packet data from the data stream.
    088         */
    089        public void readPacketData(DataInputStream par1DataInputStream) throws IOException
    090        {
    091            this.xCh = par1DataInputStream.readInt();
    092            this.zCh = par1DataInputStream.readInt();
    093            this.includeInitialize = par1DataInputStream.readBoolean();
    094            this.yChMin = par1DataInputStream.readShort();
    095            this.yChMax = par1DataInputStream.readShort();
    096            this.tempLength = par1DataInputStream.readInt();
    097
    098            if (temp.length < this.tempLength)
    099            {
    100                temp = new byte[this.tempLength];
    101            }
    102
    103            par1DataInputStream.readFully(temp, 0, this.tempLength);
    104            int var2 = 0;
    105            int var3;
    106            int msb = 0; //BugFix: MC does not read the MSB array from the packet properly, causing issues for servers that use blocks > 256
    107
    108            for (var3 = 0; var3 < 16; ++var3)
    109            {
    110                var2 += this.yChMin >> var3 & 1;
    111                msb  += this.yChMax >> var3 & 1;
    112            }
    113
    114            var3 = 12288 * var2;
    115            var3 += 2048 * msb;
    116
    117            if (this.includeInitialize)
    118            {
    119                var3 += 256;
    120            }
    121
    122            this.field_73596_g = new byte[var3];
    123            Inflater var4 = new Inflater();
    124            var4.setInput(temp, 0, this.tempLength);
    125
    126            try
    127            {
    128                var4.inflate(this.field_73596_g);
    129            }
    130            catch (DataFormatException var9)
    131            {
    132                throw new IOException("Bad compressed data format");
    133            }
    134            finally
    135            {
    136                var4.end();
    137            }
    138        }
    139
    140        /**
    141         * Abstract. Writes the raw packet data to the data stream.
    142         */
    143        public void writePacketData(DataOutputStream par1DataOutputStream) throws IOException
    144        {
    145            if (chunkData == null)
    146            {
    147                deflateGate.acquireUninterruptibly();
    148                if (chunkData == null)
    149                {
    150                    deflate();
    151                }
    152                deflateGate.release();
    153            }
    154
    155            par1DataOutputStream.writeInt(this.xCh);
    156            par1DataOutputStream.writeInt(this.zCh);
    157            par1DataOutputStream.writeBoolean(this.includeInitialize);
    158            par1DataOutputStream.writeShort((short)(this.yChMin & 65535));
    159            par1DataOutputStream.writeShort((short)(this.yChMax & 65535));
    160            par1DataOutputStream.writeInt(this.tempLength);
    161            par1DataOutputStream.write(this.chunkData, 0, this.tempLength);
    162        }
    163
    164        /**
    165         * Passes this Packet on to the NetHandler for processing.
    166         */
    167        public void processPacket(NetHandler par1NetHandler)
    168        {
    169            par1NetHandler.handleMapChunk(this);
    170        }
    171
    172        /**
    173         * Abstract. Return the size of the packet (not counting the header).
    174         */
    175        public int getPacketSize()
    176        {
    177            return 17 + this.tempLength;
    178        }
    179
    180        public static Packet51MapChunkData getMapChunkData(Chunk par0Chunk, boolean par1, int par2)
    181        {
    182            int var3 = 0;
    183            ExtendedBlockStorage[] var4 = par0Chunk.getBlockStorageArray();
    184            int var5 = 0;
    185            Packet51MapChunkData var6 = new Packet51MapChunkData();
    186            byte[] var7 = temp;
    187
    188            if (par1)
    189            {
    190                par0Chunk.deferRender = true;
    191            }
    192
    193            int var8;
    194
    195            for (var8 = 0; var8 < var4.length; ++var8)
    196            {
    197                if (var4[var8] != null && (!par1 || !var4[var8].isEmpty()) && (par2 & 1 << var8) != 0)
    198                {
    199                    var6.field_74580_b |= 1 << var8;
    200
    201                    if (var4[var8].getBlockMSBArray() != null)
    202                    {
    203                        var6.field_74581_c |= 1 << var8;
    204                        ++var5;
    205                    }
    206                }
    207            }
    208
    209            for (var8 = 0; var8 < var4.length; ++var8)
    210            {
    211                if (var4[var8] != null && (!par1 || !var4[var8].isEmpty()) && (par2 & 1 << var8) != 0)
    212                {
    213                    byte[] var9 = var4[var8].getBlockLSBArray();
    214                    System.arraycopy(var9, 0, var7, var3, var9.length);
    215                    var3 += var9.length;
    216                }
    217            }
    218
    219            NibbleArray var10;
    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].getMetadataArray();
    226                    System.arraycopy(var10.data, 0, var7, var3, var10.data.length);
    227                    var3 += var10.data.length;
    228                }
    229            }
    230
    231            for (var8 = 0; var8 < var4.length; ++var8)
    232            {
    233                if (var4[var8] != null && (!par1 || !var4[var8].isEmpty()) && (par2 & 1 << var8) != 0)
    234                {
    235                    var10 = var4[var8].getBlocklightArray();
    236                    System.arraycopy(var10.data, 0, var7, var3, var10.data.length);
    237                    var3 += var10.data.length;
    238                }
    239            }
    240
    241            if (!par0Chunk.worldObj.provider.hasNoSky)
    242            {
    243                for (var8 = 0; var8 < var4.length; ++var8)
    244                {
    245                    if (var4[var8] != null && (!par1 || !var4[var8].isEmpty()) && (par2 & 1 << var8) != 0)
    246                    {
    247                        var10 = var4[var8].getSkylightArray();
    248                        System.arraycopy(var10.data, 0, var7, var3, var10.data.length);
    249                        var3 += var10.data.length;
    250                    }
    251                }
    252            }
    253
    254            if (var5 > 0)
    255            {
    256                for (var8 = 0; var8 < var4.length; ++var8)
    257                {
    258                    if (var4[var8] != null && (!par1 || !var4[var8].isEmpty()) && var4[var8].getBlockMSBArray() != null && (par2 & 1 << var8) != 0)
    259                    {
    260                        var10 = var4[var8].getBlockMSBArray();
    261                        System.arraycopy(var10.data, 0, var7, var3, var10.data.length);
    262                        var3 += var10.data.length;
    263                    }
    264                }
    265            }
    266
    267            if (par1)
    268            {
    269                byte[] var11 = par0Chunk.getBiomeArray();
    270                System.arraycopy(var11, 0, var7, var3, var11.length);
    271                var3 += var11.length;
    272            }
    273
    274            var6.field_74582_a = new byte[var3];
    275            System.arraycopy(var7, 0, var6.field_74582_a, 0, var3);
    276            return var6;
    277        }
    278
    279        @SideOnly(Side.CLIENT)
    280        public byte[] func_73593_d()
    281        {
    282            return this.field_73596_g;
    283        }
    284    }