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.nbt.CompressedStreamTools;
014import net.minecraft.nbt.NBTTagCompound;
015import net.minecraft.util.IntHashMap;
016
017public 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}