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.network.INetworkManager;
012 import net.minecraft.network.packet.NetHandler;
013
014 import com.google.common.collect.Lists;
015 import com.google.common.collect.Maps;
016 import com.google.common.io.ByteArrayDataInput;
017 import com.google.common.io.ByteArrayDataOutput;
018 import com.google.common.io.ByteStreams;
019
020 import cpw.mods.fml.common.FMLCommonHandler;
021 import cpw.mods.fml.common.FMLLog;
022 import cpw.mods.fml.common.Loader;
023 import cpw.mods.fml.common.ModContainer;
024
025 public 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 }