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.INetworkManager; 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(INetworkManager, FMLNetworkHandler, NetHandler, String) 077 */ 078 @Override 079 public void execute(INetworkManager 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 }