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        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 false, processPacket is deffered for processReadPackets to handle
277         */
278        public boolean isWritePacket()
279        {
280            return false;
281        }
282    
283        public String toString()
284        {
285            String var1 = this.getClass().getSimpleName();
286            return var1;
287        }
288    
289        /**
290         * Reads a ItemStack from the InputStream
291         */
292        public static ItemStack readItemStack(DataInputStream par0DataInputStream) throws IOException
293        {
294            ItemStack var1 = null;
295            short var2 = par0DataInputStream.readShort();
296    
297            if (var2 >= 0)
298            {
299                byte var3 = par0DataInputStream.readByte();
300                short var4 = par0DataInputStream.readShort();
301                var1 = new ItemStack(var2, var3, var4);
302                var1.stackTagCompound = readNBTTagCompound(par0DataInputStream);
303            }
304    
305            return var1;
306        }
307    
308        /**
309         * Writes the ItemStack's ID (short), then size (byte), then damage. (short)
310         */
311        public static void writeItemStack(ItemStack par0ItemStack, DataOutputStream par1DataOutputStream) throws IOException
312        {
313            if (par0ItemStack == null)
314            {
315                par1DataOutputStream.writeShort(-1);
316            }
317            else
318            {
319                par1DataOutputStream.writeShort(par0ItemStack.itemID);
320                par1DataOutputStream.writeByte(par0ItemStack.stackSize);
321                par1DataOutputStream.writeShort(par0ItemStack.getItemDamage());
322                NBTTagCompound var2 = null;
323    
324                if (par0ItemStack.getItem().isDamageable() || par0ItemStack.getItem().getShareTag())
325                {
326                    var2 = par0ItemStack.stackTagCompound;
327                }
328    
329                writeNBTTagCompound(var2, par1DataOutputStream);
330            }
331        }
332    
333        /**
334         * Reads a compressed NBTTagCompound from the InputStream
335         */
336        public static NBTTagCompound readNBTTagCompound(DataInputStream par0DataInputStream) throws IOException
337        {
338            short var1 = par0DataInputStream.readShort();
339    
340            if (var1 < 0)
341            {
342                return null;
343            }
344            else
345            {
346                byte[] var2 = new byte[var1];
347                par0DataInputStream.readFully(var2);
348                return CompressedStreamTools.decompress(var2);
349            }
350        }
351    
352        /**
353         * Writes a compressed NBTTagCompound to the OutputStream
354         */
355        protected static void writeNBTTagCompound(NBTTagCompound par0NBTTagCompound, DataOutputStream par1DataOutputStream) throws IOException
356        {
357            if (par0NBTTagCompound == null)
358            {
359                par1DataOutputStream.writeShort(-1);
360            }
361            else
362            {
363                byte[] var2 = CompressedStreamTools.compress(par0NBTTagCompound);
364                par1DataOutputStream.writeShort((short)var2.length);
365                par1DataOutputStream.write(var2);
366            }
367        }
368    
369        static
370        {
371            addIdClassMapping(0, true, true, Packet0KeepAlive.class);
372            addIdClassMapping(1, true, true, Packet1Login.class);
373            addIdClassMapping(2, false, true, Packet2ClientProtocol.class);
374            addIdClassMapping(3, true, true, Packet3Chat.class);
375            addIdClassMapping(4, true, false, Packet4UpdateTime.class);
376            addIdClassMapping(5, true, false, Packet5PlayerInventory.class);
377            addIdClassMapping(6, true, false, Packet6SpawnPosition.class);
378            addIdClassMapping(7, false, true, Packet7UseEntity.class);
379            addIdClassMapping(8, true, false, Packet8UpdateHealth.class);
380            addIdClassMapping(9, true, true, Packet9Respawn.class);
381            addIdClassMapping(10, true, true, Packet10Flying.class);
382            addIdClassMapping(11, true, true, Packet11PlayerPosition.class);
383            addIdClassMapping(12, true, true, Packet12PlayerLook.class);
384            addIdClassMapping(13, true, true, Packet13PlayerLookMove.class);
385            addIdClassMapping(14, false, true, Packet14BlockDig.class);
386            addIdClassMapping(15, false, true, Packet15Place.class);
387            addIdClassMapping(16, true, true, Packet16BlockItemSwitch.class);
388            addIdClassMapping(17, true, false, Packet17Sleep.class);
389            addIdClassMapping(18, true, true, Packet18Animation.class);
390            addIdClassMapping(19, false, true, Packet19EntityAction.class);
391            addIdClassMapping(20, true, false, Packet20NamedEntitySpawn.class);
392            addIdClassMapping(22, true, false, Packet22Collect.class);
393            addIdClassMapping(23, true, false, Packet23VehicleSpawn.class);
394            addIdClassMapping(24, true, false, Packet24MobSpawn.class);
395            addIdClassMapping(25, true, false, Packet25EntityPainting.class);
396            addIdClassMapping(26, true, false, Packet26EntityExpOrb.class);
397            addIdClassMapping(28, true, false, Packet28EntityVelocity.class);
398            addIdClassMapping(29, true, false, Packet29DestroyEntity.class);
399            addIdClassMapping(30, true, false, Packet30Entity.class);
400            addIdClassMapping(31, true, false, Packet31RelEntityMove.class);
401            addIdClassMapping(32, true, false, Packet32EntityLook.class);
402            addIdClassMapping(33, true, false, Packet33RelEntityMoveLook.class);
403            addIdClassMapping(34, true, false, Packet34EntityTeleport.class);
404            addIdClassMapping(35, true, false, Packet35EntityHeadRotation.class);
405            addIdClassMapping(38, true, false, Packet38EntityStatus.class);
406            addIdClassMapping(39, true, false, Packet39AttachEntity.class);
407            addIdClassMapping(40, true, false, Packet40EntityMetadata.class);
408            addIdClassMapping(41, true, false, Packet41EntityEffect.class);
409            addIdClassMapping(42, true, false, Packet42RemoveEntityEffect.class);
410            addIdClassMapping(43, true, false, Packet43Experience.class);
411            addIdClassMapping(51, true, false, Packet51MapChunk.class);
412            addIdClassMapping(52, true, false, Packet52MultiBlockChange.class);
413            addIdClassMapping(53, true, false, Packet53BlockChange.class);
414            addIdClassMapping(54, true, false, Packet54PlayNoteBlock.class);
415            addIdClassMapping(55, true, false, Packet55BlockDestroy.class);
416            addIdClassMapping(56, true, false, Packet56MapChunks.class);
417            addIdClassMapping(60, true, false, Packet60Explosion.class);
418            addIdClassMapping(61, true, false, Packet61DoorChange.class);
419            addIdClassMapping(62, true, false, Packet62LevelSound.class);
420            addIdClassMapping(70, true, false, Packet70GameEvent.class);
421            addIdClassMapping(71, true, false, Packet71Weather.class);
422            addIdClassMapping(100, true, false, Packet100OpenWindow.class);
423            addIdClassMapping(101, true, true, Packet101CloseWindow.class);
424            addIdClassMapping(102, false, true, Packet102WindowClick.class);
425            addIdClassMapping(103, true, false, Packet103SetSlot.class);
426            addIdClassMapping(104, true, false, Packet104WindowItems.class);
427            addIdClassMapping(105, true, false, Packet105UpdateProgressbar.class);
428            addIdClassMapping(106, true, true, Packet106Transaction.class);
429            addIdClassMapping(107, true, true, Packet107CreativeSetSlot.class);
430            addIdClassMapping(108, false, true, Packet108EnchantItem.class);
431            addIdClassMapping(130, true, true, Packet130UpdateSign.class);
432            addIdClassMapping(131, true, true, Packet131MapData.class);
433            addIdClassMapping(132, true, false, Packet132TileEntityData.class);
434            addIdClassMapping(200, true, false, Packet200Statistic.class);
435            addIdClassMapping(201, true, false, Packet201PlayerInfo.class);
436            addIdClassMapping(202, true, true, Packet202PlayerAbilities.class);
437            addIdClassMapping(203, true, true, Packet203AutoComplete.class);
438            addIdClassMapping(204, false, true, Packet204ClientInfo.class);
439            addIdClassMapping(205, false, true, Packet205ClientCommand.class);
440            addIdClassMapping(250, true, true, Packet250CustomPayload.class);
441            addIdClassMapping(252, true, true, Packet252SharedKey.class);
442            addIdClassMapping(253, true, false, Packet253ServerAuthData.class);
443            addIdClassMapping(254, false, true, Packet254ServerPing.class);
444            addIdClassMapping(255, true, true, Packet255KickDisconnect.class);
445        }
446    }