    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, false, 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(21, true, false, Packet21PickupSpawn.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    }