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 }