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