    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}