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