001 package cpw.mods.fml.common.network;
002
003 import static cpw.mods.fml.common.network.FMLPacket.Type.MOD_LIST_REQUEST;
004 import static cpw.mods.fml.common.network.FMLPacket.Type.MOD_LIST_RESPONSE;
005
006 import java.util.List;
007 import java.util.Map;
008 import java.util.Map.Entry;
009 import java.util.Set;
010
011 import net.minecraft.src.NetHandler;
012 import net.minecraft.src.NetworkManager;
013 import net.minecraft.src.Packet250CustomPayload;
014
015 import com.google.common.collect.Lists;
016 import com.google.common.collect.Maps;
017 import com.google.common.io.ByteArrayDataInput;
018 import com.google.common.io.ByteArrayDataOutput;
019 import com.google.common.io.ByteStreams;
020
021 import cpw.mods.fml.common.FMLCommonHandler;
022 import cpw.mods.fml.common.FMLLog;
023 import cpw.mods.fml.common.Loader;
024 import cpw.mods.fml.common.ModContainer;
025
026 public class ModListRequestPacket extends FMLPacket
027 {
028 private List<String> sentModList;
029 private byte compatibilityLevel;
030
031 public ModListRequestPacket()
032 {
033 super(MOD_LIST_REQUEST);
034 }
035
036 @Override
037 public byte[] generatePacket(Object... data)
038 {
039 ByteArrayDataOutput dat = ByteStreams.newDataOutput();
040 Set<ModContainer> activeMods = FMLNetworkHandler.instance().getNetworkModList();
041 dat.writeInt(activeMods.size());
042 for (ModContainer mc : activeMods)
043 {
044 dat.writeUTF(mc.getModId());
045 }
046 dat.writeByte(FMLNetworkHandler.getCompatibilityLevel());
047 return dat.toByteArray();
048 }
049
050 @Override
051 public FMLPacket consumePacket(byte[] data)
052 {
053 sentModList = Lists.newArrayList();
054 ByteArrayDataInput in = ByteStreams.newDataInput(data);
055 int listSize = in.readInt();
056 for (int i = 0; i < listSize; i++)
057 {
058 sentModList.add(in.readUTF());
059 }
060 try
061 {
062 compatibilityLevel = in.readByte();
063 }
064 catch (IllegalStateException e)
065 {
066 FMLLog.fine("No compatibility byte found - the server is too old");
067 }
068 return this;
069 }
070
071 /**
072 *
073 * This packet is executed on the client to evaluate the server's mod list against
074 * the client
075 *
076 * @see cpw.mods.fml.common.network.FMLPacket#execute(NetworkManager, FMLNetworkHandler, NetHandler, String)
077 */
078 @Override
079 public void execute(NetworkManager mgr, FMLNetworkHandler handler, NetHandler netHandler, String userName)
080 {
081 List<String> missingMods = Lists.newArrayList();
082 Map<String,String> modVersions = Maps.newHashMap();
083 Map<String, ModContainer> indexedModList = Maps.newHashMap(Loader.instance().getIndexedModList());
084
085 for (String m : sentModList)
086 {
087 ModContainer mc = indexedModList.get(m);
088 if (mc == null)
089 {
090 missingMods.add(m);
091 continue;
092 }
093 indexedModList.remove(m);
094 modVersions.put(m, mc.getVersion());
095 }
096
097 if (indexedModList.size()>0)
098 {
099 for (Entry<String, ModContainer> e : indexedModList.entrySet())
100 {
101 if (e.getValue().isNetworkMod())
102 {
103 NetworkModHandler missingHandler = FMLNetworkHandler.instance().findNetworkModHandler(e.getValue());
104 if (missingHandler.requiresServerSide())
105 {
106 // TODO : what should we do if a mod is marked "serverSideRequired"? Stop the connection?
107 FMLLog.warning("The mod %s was not found on the server you connected to, but requested that the server side be present", e.getKey());
108 }
109 }
110 }
111 }
112
113 FMLLog.fine("The server has compatibility level %d", compatibilityLevel);
114 FMLCommonHandler.instance().getSidedDelegate().setClientCompatibilityLevel(compatibilityLevel);
115
116 mgr.addToSendQueue(PacketDispatcher.getPacket("FML", FMLPacket.makePacket(MOD_LIST_RESPONSE, modVersions, missingMods)));
117 }
118 }