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