    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}