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 }