001 package net.minecraft.network.packet;
002
003 import cpw.mods.fml.common.Side;
004 import cpw.mods.fml.common.asm.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 Deflater var5 = new Deflater(-1);
061 this.yChMax = var4.field_74581_c;
062 this.yChMin = var4.field_74580_b;
063
064 try
065 {
066 this.field_73596_g = var4.field_74582_a;
067 var5.setInput(var4.field_74582_a, 0, var4.field_74582_a.length);
068 var5.finish();
069 this.chunkData = new byte[var4.field_74582_a.length];
070 this.tempLength = var5.deflate(this.chunkData);
071 }
072 finally
073 {
074 var5.end();
075 }
076 }
077
078 /**
079 * Abstract. Reads the raw packet data from the data stream.
080 */
081 public void readPacketData(DataInputStream par1DataInputStream) throws IOException
082 {
083 this.xCh = par1DataInputStream.readInt();
084 this.zCh = par1DataInputStream.readInt();
085 this.includeInitialize = par1DataInputStream.readBoolean();
086 this.yChMin = par1DataInputStream.readShort();
087 this.yChMax = par1DataInputStream.readShort();
088 this.tempLength = par1DataInputStream.readInt();
089
090 if (temp.length < this.tempLength)
091 {
092 temp = new byte[this.tempLength];
093 }
094
095 par1DataInputStream.readFully(temp, 0, this.tempLength);
096 int var2 = 0;
097 int var3;
098
099 for (var3 = 0; var3 < 16; ++var3)
100 {
101 var2 += this.yChMin >> var3 & 1;
102 }
103
104 var3 = 12288 * var2;
105
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 for (int x = 0; x < 16; x++)
108 {
109 msb += (yChMax >> x) & 1;
110 }
111 var3 += (2048 * msb);
112
113 if (this.includeInitialize)
114 {
115 var3 += 256;
116 }
117
118 this.field_73596_g = new byte[var3];
119 Inflater var4 = new Inflater();
120 var4.setInput(temp, 0, this.tempLength);
121
122 try
123 {
124 var4.inflate(this.field_73596_g);
125 }
126 catch (DataFormatException var9)
127 {
128 throw new IOException("Bad compressed data format");
129 }
130 finally
131 {
132 var4.end();
133 }
134 }
135
136 /**
137 * Abstract. Writes the raw packet data to the data stream.
138 */
139 public void writePacketData(DataOutputStream par1DataOutputStream) throws IOException
140 {
141 par1DataOutputStream.writeInt(this.xCh);
142 par1DataOutputStream.writeInt(this.zCh);
143 par1DataOutputStream.writeBoolean(this.includeInitialize);
144 par1DataOutputStream.writeShort((short)(this.yChMin & 65535));
145 par1DataOutputStream.writeShort((short)(this.yChMax & 65535));
146 par1DataOutputStream.writeInt(this.tempLength);
147 par1DataOutputStream.write(this.chunkData, 0, this.tempLength);
148 }
149
150 /**
151 * Passes this Packet on to the NetHandler for processing.
152 */
153 public void processPacket(NetHandler par1NetHandler)
154 {
155 par1NetHandler.handleMapChunk(this);
156 }
157
158 /**
159 * Abstract. Return the size of the packet (not counting the header).
160 */
161 public int getPacketSize()
162 {
163 return 17 + this.tempLength;
164 }
165
166 public static Packet51MapChunkData getMapChunkData(Chunk par0Chunk, boolean par1, int par2)
167 {
168 int var3 = 0;
169 ExtendedBlockStorage[] var4 = par0Chunk.getBlockStorageArray();
170 int var5 = 0;
171 Packet51MapChunkData var6 = new Packet51MapChunkData();
172 byte[] var7 = temp;
173
174 if (par1)
175 {
176 par0Chunk.deferRender = true;
177 }
178
179 int var8;
180
181 for (var8 = 0; var8 < var4.length; ++var8)
182 {
183 if (var4[var8] != null && (!par1 || !var4[var8].isEmpty()) && (par2 & 1 << var8) != 0)
184 {
185 var6.field_74580_b |= 1 << var8;
186
187 if (var4[var8].getBlockMSBArray() != null)
188 {
189 var6.field_74581_c |= 1 << var8;
190 ++var5;
191 }
192 }
193 }
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 byte[] var9 = var4[var8].getBlockLSBArray();
200 System.arraycopy(var9, 0, var7, var3, var9.length);
201 var3 += var9.length;
202 }
203 }
204
205 NibbleArray var10;
206
207 for (var8 = 0; var8 < var4.length; ++var8)
208 {
209 if (var4[var8] != null && (!par1 || !var4[var8].isEmpty()) && (par2 & 1 << var8) != 0)
210 {
211 var10 = var4[var8].getMetadataArray();
212 System.arraycopy(var10.data, 0, var7, var3, var10.data.length);
213 var3 += var10.data.length;
214 }
215 }
216
217 for (var8 = 0; var8 < var4.length; ++var8)
218 {
219 if (var4[var8] != null && (!par1 || !var4[var8].isEmpty()) && (par2 & 1 << var8) != 0)
220 {
221 var10 = var4[var8].getBlocklightArray();
222 System.arraycopy(var10.data, 0, var7, var3, var10.data.length);
223 var3 += var10.data.length;
224 }
225 }
226
227 for (var8 = 0; var8 < var4.length; ++var8)
228 {
229 if (var4[var8] != null && (!par1 || !var4[var8].isEmpty()) && (par2 & 1 << var8) != 0)
230 {
231 var10 = var4[var8].getSkylightArray();
232 System.arraycopy(var10.data, 0, var7, var3, var10.data.length);
233 var3 += var10.data.length;
234 }
235 }
236
237 if (var5 > 0)
238 {
239 for (var8 = 0; var8 < var4.length; ++var8)
240 {
241 if (var4[var8] != null && (!par1 || !var4[var8].isEmpty()) && var4[var8].getBlockMSBArray() != null && (par2 & 1 << var8) != 0)
242 {
243 var10 = var4[var8].getBlockMSBArray();
244 System.arraycopy(var10.data, 0, var7, var3, var10.data.length);
245 var3 += var10.data.length;
246 }
247 }
248 }
249
250 if (par1)
251 {
252 byte[] var11 = par0Chunk.getBiomeArray();
253 System.arraycopy(var11, 0, var7, var3, var11.length);
254 var3 += var11.length;
255 }
256
257 var6.field_74582_a = new byte[var3];
258 System.arraycopy(var7, 0, var6.field_74582_a, 0, var3);
259 return var6;
260 }
261
262 @SideOnly(Side.CLIENT)
263 public byte[] func_73593_d()
264 {
265 return this.field_73596_g;
266 }
267 }