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 }