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