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