    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}