001    package cpw.mods.fml.common.network;
002    
003    import static cpw.mods.fml.common.network.FMLPacket.Type.MOD_LIST_REQUEST;
004    import static cpw.mods.fml.common.network.FMLPacket.Type.MOD_LIST_RESPONSE;
005    
006    import java.util.List;
007    import java.util.Map;
008    import java.util.Map.Entry;
009    import java.util.Set;
010    
011    import net.minecraft.network.INetworkManager;
012    import net.minecraft.network.packet.NetHandler;
013    
014    import com.google.common.collect.Lists;
015    import com.google.common.collect.Maps;
016    import com.google.common.io.ByteArrayDataInput;
017    import com.google.common.io.ByteArrayDataOutput;
018    import com.google.common.io.ByteStreams;
019    
020    import cpw.mods.fml.common.FMLCommonHandler;
021    import cpw.mods.fml.common.FMLLog;
022    import cpw.mods.fml.common.Loader;
023    import cpw.mods.fml.common.ModContainer;
024    
025    public class ModListRequestPacket extends FMLPacket
026    {
027        private List<String> sentModList;
028        private byte compatibilityLevel;
029    
030        public ModListRequestPacket()
031        {
032            super(MOD_LIST_REQUEST);
033        }
034    
035        @Override
036        public byte[] generatePacket(Object... data)
037        {
038            ByteArrayDataOutput dat = ByteStreams.newDataOutput();
039            Set<ModContainer> activeMods = FMLNetworkHandler.instance().getNetworkModList();
040            dat.writeInt(activeMods.size());
041            for (ModContainer mc : activeMods)
042            {
043                dat.writeUTF(mc.getModId());
044            }
045            dat.writeByte(FMLNetworkHandler.getCompatibilityLevel());
046            return dat.toByteArray();
047        }
048    
049        @Override
050        public FMLPacket consumePacket(byte[] data)
051        {
052            sentModList = Lists.newArrayList();
053            ByteArrayDataInput in = ByteStreams.newDataInput(data);
054            int listSize = in.readInt();
055            for (int i = 0; i < listSize; i++)
056            {
057                sentModList.add(in.readUTF());
058            }
059            try
060            {
061                compatibilityLevel = in.readByte();
062            }
063            catch (IllegalStateException e)
064            {
065                FMLLog.fine("No compatibility byte found - the server is too old");
066            }
067            return this;
068        }
069    
070        /**
071         *
072         * This packet is executed on the client to evaluate the server's mod list against
073         * the client
074         *
075         * @see cpw.mods.fml.common.network.FMLPacket#execute(INetworkManager, FMLNetworkHandler, NetHandler, String)
076         */
077        @Override
078        public void execute(INetworkManager mgr, FMLNetworkHandler handler, NetHandler netHandler, String userName)
079        {
080            List<String> missingMods = Lists.newArrayList();
081            Map<String,String> modVersions = Maps.newHashMap();
082            Map<String, ModContainer> indexedModList = Maps.newHashMap(Loader.instance().getIndexedModList());
083    
084            for (String m : sentModList)
085            {
086                ModContainer mc = indexedModList.get(m);
087                if (mc == null)
088                {
089                    missingMods.add(m);
090                    continue;
091                }
092                indexedModList.remove(m);
093                modVersions.put(m, mc.getVersion());
094            }
095    
096            if (indexedModList.size()>0)
097            {
098                for (Entry<String, ModContainer> e : indexedModList.entrySet())
099                {
100                    if (e.getValue().isNetworkMod())
101                    {
102                        NetworkModHandler missingHandler = FMLNetworkHandler.instance().findNetworkModHandler(e.getValue());
103                        if (missingHandler.requiresServerSide())
104                        {
105                            // TODO : what should we do if a mod is marked "serverSideRequired"? Stop the connection?
106                            FMLLog.warning("The mod %s was not found on the server you connected to, but requested that the server side be present", e.getKey());
107                        }
108                    }
109                }
110            }
111    
112            FMLLog.fine("The server has compatibility level %d", compatibilityLevel);
113            FMLCommonHandler.instance().getSidedDelegate().setClientCompatibilityLevel(compatibilityLevel);
114    
115            mgr.addToSendQueue(PacketDispatcher.getPacket("FML", FMLPacket.makePacket(MOD_LIST_RESPONSE, modVersions, missingMods)));
116        }
117    }