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 }