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