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    }