001 package net.minecraft.network.packet; 002 003 import java.io.DataInputStream; 004 import java.io.DataOutputStream; 005 import java.io.EOFException; 006 import java.io.IOException; 007 import java.net.Socket; 008 import java.util.HashMap; 009 import java.util.HashSet; 010 import java.util.Map; 011 import java.util.Set; 012 import net.minecraft.item.ItemStack; 013 import net.minecraft.nbt.CompressedStreamTools; 014 import net.minecraft.nbt.NBTTagCompound; 015 import net.minecraft.util.IntHashMap; 016 017 public abstract class Packet 018 { 019 /** Maps packet id to packet class */ 020 public static IntHashMap packetIdToClassMap = new IntHashMap(); 021 022 /** Maps packet class to packet id */ 023 private static Map packetClassToIdMap = new HashMap(); 024 025 /** List of the client's packet IDs. */ 026 private static Set clientPacketIdList = new HashSet(); 027 028 /** List of the server's packet IDs. */ 029 private static Set serverPacketIdList = new HashSet(); 030 031 /** the system time in milliseconds when this packet was created. */ 032 public final long creationTimeMillis = System.currentTimeMillis(); 033 public static long receivedID; 034 public static long receivedSize; 035 036 /** Assumed to be sequential by the profiler. */ 037 public static long sentID; 038 public static long sentSize; 039 040 /** 041 * Only true for Packet51MapChunk, Packet52MultiBlockChange, Packet53BlockChange and Packet59ComplexEntity. Used to 042 * separate them into a different send queue. 043 */ 044 public boolean isChunkDataPacket = false; 045 046 /** 047 * Adds a two way mapping between the packet ID and packet class. 048 */ 049 public static void addIdClassMapping(int par0, boolean par1, boolean par2, Class par3Class) 050 { 051 if (packetIdToClassMap.containsItem(par0)) 052 { 053 throw new IllegalArgumentException("Duplicate packet id:" + par0); 054 } 055 else if (packetClassToIdMap.containsKey(par3Class)) 056 { 057 throw new IllegalArgumentException("Duplicate packet class:" + par3Class); 058 } 059 else 060 { 061 packetIdToClassMap.addKey(par0, par3Class); 062 packetClassToIdMap.put(par3Class, Integer.valueOf(par0)); 063 064 if (par1) 065 { 066 clientPacketIdList.add(Integer.valueOf(par0)); 067 } 068 069 if (par2) 070 { 071 serverPacketIdList.add(Integer.valueOf(par0)); 072 } 073 } 074 } 075 076 /** 077 * Returns a new instance of the specified Packet class. 078 */ 079 public static Packet getNewPacket(int par0) 080 { 081 try 082 { 083 Class var1 = (Class)packetIdToClassMap.lookup(par0); 084 return var1 == null ? null : (Packet)var1.newInstance(); 085 } 086 catch (Exception var2) 087 { 088 var2.printStackTrace(); 089 System.out.println("Skipping packet with id " + par0); 090 return null; 091 } 092 } 093 094 /** 095 * Writes a byte array to the DataOutputStream 096 */ 097 public static void writeByteArray(DataOutputStream par0DataOutputStream, byte[] par1ArrayOfByte) throws IOException 098 { 099 par0DataOutputStream.writeShort(par1ArrayOfByte.length); 100 par0DataOutputStream.write(par1ArrayOfByte); 101 } 102 103 /** 104 * the first short in the stream indicates the number of bytes to read 105 */ 106 public static byte[] readBytesFromStream(DataInputStream par0DataInputStream) throws IOException 107 { 108 short var1 = par0DataInputStream.readShort(); 109 110 if (var1 < 0) 111 { 112 throw new IOException("Key was smaller than nothing! Weird key!"); 113 } 114 else 115 { 116 byte[] var2 = new byte[var1]; 117 par0DataInputStream.read(var2); 118 return var2; 119 } 120 } 121 122 /** 123 * Returns the ID of this packet. 124 */ 125 public final int getPacketId() 126 { 127 return ((Integer)packetClassToIdMap.get(this.getClass())).intValue(); 128 } 129 130 /** 131 * Read a packet, prefixed by its ID, from the data stream. 132 */ 133 public static Packet readPacket(DataInputStream par0DataInputStream, boolean par1, Socket par2Socket) throws IOException 134 { 135 boolean var3 = false; 136 Packet var4 = null; 137 int var5 = par2Socket.getSoTimeout(); 138 int var8; 139 140 try 141 { 142 var8 = par0DataInputStream.read(); 143 144 if (var8 == -1) 145 { 146 return null; 147 } 148 149 if (par1 && !serverPacketIdList.contains(Integer.valueOf(var8)) || !par1 && !clientPacketIdList.contains(Integer.valueOf(var8))) 150 { 151 throw new IOException("Bad packet id " + var8); 152 } 153 154 var4 = getNewPacket(var8); 155 156 if (var4 == null) 157 { 158 throw new IOException("Bad packet id " + var8); 159 } 160 161 if (var4 instanceof Packet254ServerPing) 162 { 163 par2Socket.setSoTimeout(1500); 164 } 165 166 var4.readPacketData(par0DataInputStream); 167 ++receivedID; 168 receivedSize += (long)var4.getPacketSize(); 169 } 170 catch (EOFException var7) 171 { 172 System.out.println("Reached end of stream"); 173 return null; 174 } 175 176 PacketCount.countPacket(var8, (long)var4.getPacketSize()); 177 ++receivedID; 178 receivedSize += (long)var4.getPacketSize(); 179 par2Socket.setSoTimeout(var5); 180 return var4; 181 } 182 183 /** 184 * Writes a packet, prefixed by its ID, to the data stream. 185 */ 186 public static void writePacket(Packet par0Packet, DataOutputStream par1DataOutputStream) throws IOException 187 { 188 par1DataOutputStream.write(par0Packet.getPacketId()); 189 par0Packet.writePacketData(par1DataOutputStream); 190 ++sentID; 191 sentSize += (long)par0Packet.getPacketSize(); 192 } 193 194 /** 195 * Writes a String to the DataOutputStream 196 */ 197 public static void writeString(String par0Str, DataOutputStream par1DataOutputStream) throws IOException 198 { 199 if (par0Str.length() > 32767) 200 { 201 throw new IOException("String too big"); 202 } 203 else 204 { 205 par1DataOutputStream.writeShort(par0Str.length()); 206 par1DataOutputStream.writeChars(par0Str); 207 } 208 } 209 210 /** 211 * Reads a string from a packet 212 */ 213 public static String readString(DataInputStream par0DataInputStream, int par1) throws IOException 214 { 215 short var2 = par0DataInputStream.readShort(); 216 217 if (var2 > par1) 218 { 219 throw new IOException("Received string length longer than maximum allowed (" + var2 + " > " + par1 + ")"); 220 } 221 else if (var2 < 0) 222 { 223 throw new IOException("Received string length is less than zero! Weird string!"); 224 } 225 else 226 { 227 StringBuilder var3 = new StringBuilder(); 228 229 for (int var4 = 0; var4 < var2; ++var4) 230 { 231 var3.append(par0DataInputStream.readChar()); 232 } 233 234 return var3.toString(); 235 } 236 } 237 238 /** 239 * Abstract. Reads the raw packet data from the data stream. 240 */ 241 public abstract void readPacketData(DataInputStream var1) throws IOException; 242 243 /** 244 * Abstract. Writes the raw packet data to the data stream. 245 */ 246 public abstract void writePacketData(DataOutputStream var1) throws IOException; 247 248 /** 249 * Passes this Packet on to the NetHandler for processing. 250 */ 251 public abstract void processPacket(NetHandler var1); 252 253 /** 254 * Abstract. Return the size of the packet (not counting the header). 255 */ 256 public abstract int getPacketSize(); 257 258 /** 259 * only false for the abstract Packet class, all real packets return true 260 */ 261 public boolean isRealPacket() 262 { 263 return false; 264 } 265 266 /** 267 * eg return packet30entity.entityId == entityId; WARNING : will throw if you compare a packet to a different packet 268 * class 269 */ 270 public boolean containsSameEntityIDAs(Packet par1Packet) 271 { 272 return false; 273 } 274 275 /** 276 * If this returns true, the packet may be processed on any thread; otherwise it is queued for the main thread to 277 * handle. 278 */ 279 public boolean canProcessAsync() 280 { 281 return false; 282 } 283 284 public String toString() 285 { 286 String var1 = this.getClass().getSimpleName(); 287 return var1; 288 } 289 290 /** 291 * Reads a ItemStack from the InputStream 292 */ 293 public static ItemStack readItemStack(DataInputStream par0DataInputStream) throws IOException 294 { 295 ItemStack var1 = null; 296 short var2 = par0DataInputStream.readShort(); 297 298 if (var2 >= 0) 299 { 300 byte var3 = par0DataInputStream.readByte(); 301 short var4 = par0DataInputStream.readShort(); 302 var1 = new ItemStack(var2, var3, var4); 303 var1.stackTagCompound = readNBTTagCompound(par0DataInputStream); 304 } 305 306 return var1; 307 } 308 309 /** 310 * Writes the ItemStack's ID (short), then size (byte), then damage. (short) 311 */ 312 public static void writeItemStack(ItemStack par0ItemStack, DataOutputStream par1DataOutputStream) throws IOException 313 { 314 if (par0ItemStack == null) 315 { 316 par1DataOutputStream.writeShort(-1); 317 } 318 else 319 { 320 par1DataOutputStream.writeShort(par0ItemStack.itemID); 321 par1DataOutputStream.writeByte(par0ItemStack.stackSize); 322 par1DataOutputStream.writeShort(par0ItemStack.getItemDamage()); 323 NBTTagCompound var2 = null; 324 325 if (par0ItemStack.getItem().isDamageable() || par0ItemStack.getItem().getShareTag()) 326 { 327 var2 = par0ItemStack.stackTagCompound; 328 } 329 330 writeNBTTagCompound(var2, par1DataOutputStream); 331 } 332 } 333 334 /** 335 * Reads a compressed NBTTagCompound from the InputStream 336 */ 337 public static NBTTagCompound readNBTTagCompound(DataInputStream par0DataInputStream) throws IOException 338 { 339 short var1 = par0DataInputStream.readShort(); 340 341 if (var1 < 0) 342 { 343 return null; 344 } 345 else 346 { 347 byte[] var2 = new byte[var1]; 348 par0DataInputStream.readFully(var2); 349 return CompressedStreamTools.decompress(var2); 350 } 351 } 352 353 /** 354 * Writes a compressed NBTTagCompound to the OutputStream 355 */ 356 protected static void writeNBTTagCompound(NBTTagCompound par0NBTTagCompound, DataOutputStream par1DataOutputStream) throws IOException 357 { 358 if (par0NBTTagCompound == null) 359 { 360 par1DataOutputStream.writeShort(-1); 361 } 362 else 363 { 364 byte[] var2 = CompressedStreamTools.compress(par0NBTTagCompound); 365 par1DataOutputStream.writeShort((short)var2.length); 366 par1DataOutputStream.write(var2); 367 } 368 } 369 370 static 371 { 372 addIdClassMapping(0, true, true, Packet0KeepAlive.class); 373 addIdClassMapping(1, true, true, Packet1Login.class); 374 addIdClassMapping(2, false, true, Packet2ClientProtocol.class); 375 addIdClassMapping(3, true, true, Packet3Chat.class); 376 addIdClassMapping(4, true, false, Packet4UpdateTime.class); 377 addIdClassMapping(5, true, false, Packet5PlayerInventory.class); 378 addIdClassMapping(6, true, false, Packet6SpawnPosition.class); 379 addIdClassMapping(7, false, true, Packet7UseEntity.class); 380 addIdClassMapping(8, true, false, Packet8UpdateHealth.class); 381 addIdClassMapping(9, true, true, Packet9Respawn.class); 382 addIdClassMapping(10, true, true, Packet10Flying.class); 383 addIdClassMapping(11, true, true, Packet11PlayerPosition.class); 384 addIdClassMapping(12, true, true, Packet12PlayerLook.class); 385 addIdClassMapping(13, true, true, Packet13PlayerLookMove.class); 386 addIdClassMapping(14, false, true, Packet14BlockDig.class); 387 addIdClassMapping(15, false, true, Packet15Place.class); 388 addIdClassMapping(16, true, true, Packet16BlockItemSwitch.class); 389 addIdClassMapping(17, true, false, Packet17Sleep.class); 390 addIdClassMapping(18, true, true, Packet18Animation.class); 391 addIdClassMapping(19, false, true, Packet19EntityAction.class); 392 addIdClassMapping(20, true, false, Packet20NamedEntitySpawn.class); 393 addIdClassMapping(22, true, false, Packet22Collect.class); 394 addIdClassMapping(23, true, false, Packet23VehicleSpawn.class); 395 addIdClassMapping(24, true, false, Packet24MobSpawn.class); 396 addIdClassMapping(25, true, false, Packet25EntityPainting.class); 397 addIdClassMapping(26, true, false, Packet26EntityExpOrb.class); 398 addIdClassMapping(28, true, false, Packet28EntityVelocity.class); 399 addIdClassMapping(29, true, false, Packet29DestroyEntity.class); 400 addIdClassMapping(30, true, false, Packet30Entity.class); 401 addIdClassMapping(31, true, false, Packet31RelEntityMove.class); 402 addIdClassMapping(32, true, false, Packet32EntityLook.class); 403 addIdClassMapping(33, true, false, Packet33RelEntityMoveLook.class); 404 addIdClassMapping(34, true, false, Packet34EntityTeleport.class); 405 addIdClassMapping(35, true, false, Packet35EntityHeadRotation.class); 406 addIdClassMapping(38, true, false, Packet38EntityStatus.class); 407 addIdClassMapping(39, true, false, Packet39AttachEntity.class); 408 addIdClassMapping(40, true, false, Packet40EntityMetadata.class); 409 addIdClassMapping(41, true, false, Packet41EntityEffect.class); 410 addIdClassMapping(42, true, false, Packet42RemoveEntityEffect.class); 411 addIdClassMapping(43, true, false, Packet43Experience.class); 412 addIdClassMapping(51, true, false, Packet51MapChunk.class); 413 addIdClassMapping(52, true, false, Packet52MultiBlockChange.class); 414 addIdClassMapping(53, true, false, Packet53BlockChange.class); 415 addIdClassMapping(54, true, false, Packet54PlayNoteBlock.class); 416 addIdClassMapping(55, true, false, Packet55BlockDestroy.class); 417 addIdClassMapping(56, true, false, Packet56MapChunks.class); 418 addIdClassMapping(60, true, false, Packet60Explosion.class); 419 addIdClassMapping(61, true, false, Packet61DoorChange.class); 420 addIdClassMapping(62, true, false, Packet62LevelSound.class); 421 addIdClassMapping(70, true, false, Packet70GameEvent.class); 422 addIdClassMapping(71, true, false, Packet71Weather.class); 423 addIdClassMapping(100, true, false, Packet100OpenWindow.class); 424 addIdClassMapping(101, true, true, Packet101CloseWindow.class); 425 addIdClassMapping(102, false, true, Packet102WindowClick.class); 426 addIdClassMapping(103, true, false, Packet103SetSlot.class); 427 addIdClassMapping(104, true, false, Packet104WindowItems.class); 428 addIdClassMapping(105, true, false, Packet105UpdateProgressbar.class); 429 addIdClassMapping(106, true, true, Packet106Transaction.class); 430 addIdClassMapping(107, true, true, Packet107CreativeSetSlot.class); 431 addIdClassMapping(108, false, true, Packet108EnchantItem.class); 432 addIdClassMapping(130, true, true, Packet130UpdateSign.class); 433 addIdClassMapping(131, true, true, Packet131MapData.class); 434 addIdClassMapping(132, true, false, Packet132TileEntityData.class); 435 addIdClassMapping(200, true, false, Packet200Statistic.class); 436 addIdClassMapping(201, true, false, Packet201PlayerInfo.class); 437 addIdClassMapping(202, true, true, Packet202PlayerAbilities.class); 438 addIdClassMapping(203, true, true, Packet203AutoComplete.class); 439 addIdClassMapping(204, false, true, Packet204ClientInfo.class); 440 addIdClassMapping(205, false, true, Packet205ClientCommand.class); 441 addIdClassMapping(250, true, true, Packet250CustomPayload.class); 442 addIdClassMapping(252, true, true, Packet252SharedKey.class); 443 addIdClassMapping(253, true, false, Packet253ServerAuthData.class); 444 addIdClassMapping(254, false, true, Packet254ServerPing.class); 445 addIdClassMapping(255, true, true, Packet255KickDisconnect.class); 446 } 447 }