001package cpw.mods.fml.common.network;
002
003import static cpw.mods.fml.common.network.FMLPacket.Type.MOD_IDENTIFIERS;
004import static cpw.mods.fml.common.network.FMLPacket.Type.MOD_LIST_RESPONSE;
005import static cpw.mods.fml.common.network.FMLPacket.Type.MOD_MISSING;
006import static cpw.mods.fml.common.network.FMLPacket.Type.MOD_IDMAP;
007
008import java.util.List;
009import java.util.Map;
010import java.util.Map.Entry;
011import java.util.logging.Logger;
012
013import net.minecraft.nbt.NBTTagList;
014import net.minecraft.network.*;
015import net.minecraft.network.packet.*;
016
017import com.google.common.collect.Lists;
018import com.google.common.collect.Maps;
019import com.google.common.io.ByteArrayDataInput;
020import com.google.common.io.ByteArrayDataOutput;
021import com.google.common.io.ByteStreams;
022
023import cpw.mods.fml.common.FMLLog;
024import cpw.mods.fml.common.Loader;
025import cpw.mods.fml.common.ModContainer;
026import cpw.mods.fml.common.registry.GameData;
027import cpw.mods.fml.common.registry.GameRegistry;
028
029public class ModListResponsePacket extends FMLPacket
030{
031    private Map<String,String> modVersions;
032    private List<String> missingMods;
033
034    public ModListResponsePacket()
035    {
036        super(MOD_LIST_RESPONSE);
037    }
038
039    @Override
040    public byte[] generatePacket(Object... data)
041    {
042        Map<String,String> modVersions = (Map<String, String>) data[0];
043        List<String> missingMods = (List<String>) data[1];
044        ByteArrayDataOutput dat = ByteStreams.newDataOutput();
045        dat.writeInt(modVersions.size());
046        for (Entry<String, String> version : modVersions.entrySet())
047        {
048            dat.writeUTF(version.getKey());
049            dat.writeUTF(version.getValue());
050        }
051        dat.writeInt(missingMods.size());
052        for (String missing : missingMods)
053        {
054            dat.writeUTF(missing);
055        }
056        return dat.toByteArray();
057    }
058
059    @Override
060    public FMLPacket consumePacket(byte[] data)
061    {
062        ByteArrayDataInput dat = ByteStreams.newDataInput(data);
063        int versionListSize = dat.readInt();
064        modVersions = Maps.newHashMapWithExpectedSize(versionListSize);
065        for (int i = 0; i < versionListSize; i++)
066        {
067            String modName = dat.readUTF();
068            String modVersion = dat.readUTF();
069            modVersions.put(modName, modVersion);
070        }
071
072        int missingModSize = dat.readInt();
073        missingMods = Lists.newArrayListWithExpectedSize(missingModSize);
074
075        for (int i = 0; i < missingModSize; i++)
076        {
077            missingMods.add(dat.readUTF());
078        }
079        return this;
080    }
081
082    @Override
083    public void execute(INetworkManager network, FMLNetworkHandler handler, NetHandler netHandler, String userName)
084    {
085        Map<String, ModContainer> indexedModList = Maps.newHashMap(Loader.instance().getIndexedModList());
086        List<String> missingClientMods = Lists.newArrayList();
087        List<String> versionIncorrectMods = Lists.newArrayList();
088
089        for (String m : missingMods)
090        {
091            ModContainer mc = indexedModList.get(m);
092            NetworkModHandler networkMod = handler.findNetworkModHandler(mc);
093            if (networkMod.requiresClientSide())
094            {
095                missingClientMods.add(m);
096            }
097        }
098
099        for (Entry<String,String> modVersion : modVersions.entrySet())
100        {
101            ModContainer mc = indexedModList.get(modVersion.getKey());
102            NetworkModHandler networkMod = handler.findNetworkModHandler(mc);
103            if (!networkMod.acceptVersion(modVersion.getValue()))
104            {
105                versionIncorrectMods.add(modVersion.getKey());
106            }
107        }
108
109        Packet250CustomPayload pkt = new Packet250CustomPayload();
110        pkt.channel = "FML";
111        if (missingClientMods.size()>0 || versionIncorrectMods.size() > 0)
112        {
113            pkt.data = FMLPacket.makePacket(MOD_MISSING, missingClientMods, versionIncorrectMods);
114            Logger.getLogger("Minecraft").info(String.format("User %s connection failed: missing %s, bad versions %s", userName, missingClientMods, versionIncorrectMods));
115            FMLLog.info("User %s connection failed: missing %s, bad versions %s", userName, missingClientMods, versionIncorrectMods);
116            // Mark this as bad
117            FMLNetworkHandler.setHandlerState((NetLoginHandler) netHandler, FMLNetworkHandler.MISSING_MODS_OR_VERSIONS);
118            pkt.length = pkt.data.length;
119            network.addToSendQueue(pkt);
120        }
121        else
122        {
123            pkt.data = FMLPacket.makePacket(MOD_IDENTIFIERS, netHandler);
124            Logger.getLogger("Minecraft").info(String.format("User %s connecting with mods %s", userName, modVersions.keySet()));
125            FMLLog.info("User %s connecting with mods %s", userName, modVersions.keySet());
126            pkt.length = pkt.data.length;
127            network.addToSendQueue(pkt);
128            NBTTagList itemList = new NBTTagList();
129            GameData.writeItemData(itemList);
130            byte[][] registryPackets = FMLPacket.makePacketSet(MOD_IDMAP, itemList);
131            for (int i = 0; i < registryPackets.length; i++)
132            {
133                network.addToSendQueue(PacketDispatcher.getPacket("FML", registryPackets[i]));
134            }
135        }
136
137        // reset the continuation flag - we have completed extra negotiation and the login should complete now
138        NetLoginHandler.func_72531_a((NetLoginHandler) netHandler, true);
139    }
140
141}