001package cpw.mods.fml.common.network;
002
003import static cpw.mods.fml.common.network.FMLPacket.Type.MOD_LIST_REQUEST;
004import static cpw.mods.fml.common.network.FMLPacket.Type.MOD_LIST_RESPONSE;
005
006import java.util.List;
007import java.util.Map;
008import java.util.Map.Entry;
009import java.util.Set;
010
011import net.minecraft.network.INetworkManager;
012import net.minecraft.network.packet.NetHandler;
013
014import com.google.common.collect.Lists;
015import com.google.common.collect.Maps;
016import com.google.common.io.ByteArrayDataInput;
017import com.google.common.io.ByteArrayDataOutput;
018import com.google.common.io.ByteStreams;
019
020import cpw.mods.fml.common.FMLCommonHandler;
021import cpw.mods.fml.common.FMLLog;
022import cpw.mods.fml.common.Loader;
023import cpw.mods.fml.common.ModContainer;
024
025public 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}