Add in a lot of network handler stuff - also, expose the asm harvested data

This commit is contained in:
Christian 2012-08-06 09:52:42 -04:00
parent 09098f8a0f
commit 8bda53cb77
37 changed files with 1195 additions and 160 deletions

View file

@ -36,6 +36,8 @@ import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.common.modloader.ModLoaderHelper;
import cpw.mods.fml.common.modloader.ModLoaderModContainer;
import cpw.mods.fml.common.network.NetworkRegistry;
import cpw.mods.fml.common.network.Player;
import cpw.mods.fml.common.registry.EntityRegistry;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.common.ObfuscationReflectionHelper;
@ -446,7 +448,7 @@ public class ModLoader
*/
public static boolean isChannelActive(EntityPlayer player, String channel)
{
return FMLCommonHandler.instance().isChannelActive(channel, player);
return NetworkRegistry.instance().isChannelActive(channel, (Player)player);
}
public static boolean isGUIOpen(Class<? extends GuiScreen> gui)
@ -592,7 +594,7 @@ public class ModLoader
*/
public static void registerPacketChannel(BaseMod mod, String channel)
{
FMLCommonHandler.instance().registerChannel(FMLCommonHandler.instance().findContainerFor(mod), channel);
NetworkRegistry.instance().registerChannel(FMLCommonHandler.instance().findContainerFor(mod), channel);
}
/**

View file

@ -122,4 +122,10 @@ public class DummyModContainer implements ModContainer
{
return false;
}
@Override
public boolean isNetworkMod()
{
return false;
}
}

View file

@ -16,20 +16,16 @@ package cpw.mods.fml.common;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Random;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -69,19 +65,6 @@ public class FMLCommonHandler
* The singleton
*/
private static final FMLCommonHandler INSTANCE = new FMLCommonHandler();
private static final Pattern metadataFile = Pattern.compile("$/modinfo.json$");;
/**
* A map of mods to their network channels
*/
private Map<ModContainer, Set<String>> channelList = new HashMap<ModContainer, Set<String>>();
/**
* A map of channels to mods
*/
private Map<String, ModContainer> modChannels = new HashMap<String, ModContainer>();
/**
* A map of active channels per player
*/
private Map<Object, Set<String>> activeChannels = new HashMap<Object, Set<String>>();
/**
* The delegate for side specific data and functions
*/
@ -89,8 +72,6 @@ public class FMLCommonHandler
private int uniqueEntityListId = 220;
private List<ModContainer> auxilliaryContainers = new ArrayList<ModContainer>();
private Map<String,Properties> modLanguageData=new HashMap<String,Properties>();
private List<IScheduledTickHandler> scheduledTicks = new ArrayList<IScheduledTickHandler>();
@ -174,119 +155,6 @@ public class FMLCommonHandler
}
return null;
}
/**
* Lookup the mod for a channel
* @param channel
* @return
*/
public ModContainer getModForChannel(String channel)
{
return modChannels.get(channel);
}
/**
* Get the channel list for a mod
* @param modLoaderModContainer
* @return
*/
public Set<String> getChannelListFor(ModContainer container)
{
return channelList.get(container);
}
/**
* register a channel to a mod
* @param container
* @param channelName
*/
public void registerChannel(ModContainer container, String channelName)
{
if (modChannels.containsKey(channelName))
{
// NOOP
}
Set<String> list = channelList.get(container);
if (list == null)
{
list = new HashSet<String>();
channelList.put(container, list);
}
list.add(channelName);
modChannels.put(channelName, container);
}
/**
* Activate the channel for the player
* @param player
*/
public void activateChannel(Object player, String channel)
{
Set<String> active = activeChannels.get(player);
if (active == null)
{
active = new HashSet<String>();
activeChannels.put(player, active);
}
active.add(channel);
}
/**
* Deactivate the channel for the player
* @param player
* @param channel
*/
public void deactivateChannel(Object player, String channel)
{
Set<String> active = activeChannels.get(player);
if (active == null)
{
active = new HashSet<String>();
activeChannels.put(player, active);
}
active.remove(channel);
}
/**
* Get the packet 250 channel registration string
* @return
*/
public byte[] getPacketRegistry()
{
StringBuffer sb = new StringBuffer();
for (String chan : modChannels.keySet())
{
sb.append(chan).append("\0");
}
try
{
return sb.toString().getBytes("UTF8");
}
catch (UnsupportedEncodingException e)
{
FMLLog.log(Level.WARNING, e, "Error building registration list");
return new byte[0];
}
}
/**
* Is the specified channel active for the player?
* @param channel
* @param player
* @return
*/
public boolean isChannelActive(String channel, Object player)
{
return activeChannels.get(player).contains(channel);
}
/**
* Get the forge mod loader logging instance (goes to the forgemodloader log file)
* @return
@ -409,6 +277,7 @@ public class FMLCommonHandler
private Class<?> forge;
private boolean noForge;
private List<String> brandings;
private List<ModContainer> auxilliaryContainers = new ArrayList<ModContainer>();
private Class<?> findMinecraftForge()
{
@ -531,17 +400,17 @@ public class FMLCommonHandler
{
tickStart(EnumSet.of(TickType.WORLDLOAD));
}
public void handleServerStarting(MinecraftServer server)
{
Loader.instance().serverStarting(server);
}
public void handleServerStarted()
{
Loader.instance().serverStarted();
}
public void handleServerStopping()
{
Loader.instance().serverStopping();

View file

@ -31,6 +31,7 @@ import com.google.common.collect.ImmutableBiMap.Builder;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.common.collect.Table;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
@ -38,6 +39,8 @@ import cpw.mods.fml.common.LoaderState.ModState;
import cpw.mods.fml.common.Mod.Block;
import cpw.mods.fml.common.Mod.Instance;
import cpw.mods.fml.common.Mod.Metadata;
import cpw.mods.fml.common.discovery.ASMDataTable;
import cpw.mods.fml.common.discovery.ASMDataTable.ASMData;
import cpw.mods.fml.common.discovery.ContainerType;
import cpw.mods.fml.common.event.FMLConstructionEvent;
import cpw.mods.fml.common.event.FMLInitializationEvent;
@ -68,6 +71,7 @@ public class FMLModContainer implements ModContainer
private LoadController controller;
private Multimap<Class<? extends Annotation>, Object> annotations;
private DefaultArtifactVersion processedVersion;
private boolean isNetworkMod;
private static final BiMap<Class<? extends FMLStateEvent>, Class<? extends Annotation>> modAnnotationTypes = ImmutableBiMap.<Class<? extends FMLStateEvent>, Class<? extends Annotation>>builder()
.put(FMLPreInitializationEvent.class, Mod.PreInit.class)
@ -268,6 +272,8 @@ public class FMLModContainer implements ModContainer
ModClassLoader modClassLoader = event.getModClassLoader();
modClassLoader.addFile(source);
Class<?> clazz = Class.forName(className, true, modClassLoader);
ASMDataTable asmHarvestedAnnotations = event.getASMHarvestedData();
asmHarvestedAnnotations.getAnnotationsFor(this);
annotations = gatherAnnotations(clazz);
modInstance = clazz.newInstance();
processFieldAnnotations();
@ -316,4 +322,10 @@ public class FMLModContainer implements ModContainer
{
return false;
}
@Override
public boolean isNetworkMod()
{
return isNetworkMod;
}
}

View file

@ -97,6 +97,11 @@ public class InjectedModContainer implements ModContainer
return wrappedContainer.findSidedProxy();
}
@Override
public boolean isNetworkMod()
{
return wrappedContainer.isNetworkMod();
}
@Override
public boolean isImmutable()
{

View file

@ -19,6 +19,7 @@ import com.google.common.eventbus.Subscribe;
import cpw.mods.fml.common.LoaderState.ModState;
import cpw.mods.fml.common.event.FMLLoadEvent;
import cpw.mods.fml.common.event.FMLStateEvent;
import cpw.mods.fml.common.network.FMLNetworkHandler;
public class LoadController
{
@ -67,6 +68,7 @@ public class LoadController
}
eventChannels = eventBus.build();
FMLNetworkHandler.instance().freezeModList(activeModList);
}
public void distributeStateMessage(LoaderState state, Object... eventData)

View file

@ -251,7 +251,7 @@ public class Loader
* Finally, if they are successfully loaded as classes, they are then added
* to the available mod list.
*/
private void identifyMods()
private ModDiscoverer identifyMods()
{
FMLLog.fine("Building injected Mod Containers %s", injectedContainers);
for (String cont : injectedContainers)
@ -279,6 +279,7 @@ public class Loader
mods.addAll(discoverer.identifyMods());
namedMods = Maps.uniqueIndex(mods, new ModIdFunction());
FMLLog.info("Forge Mod Loader has identified %d mod%s to load", mods.size(), mods.size() != 1 ? "s" : "");
return discoverer;
}
/**
@ -360,15 +361,15 @@ public class Loader
namedMods = Maps.newHashMap();
modController = new LoadController(this);
modController.transition(LoaderState.LOADING);
identifyMods();
ModDiscoverer disc = identifyMods();
disableRequestedMods();
sortModList();
mods = ImmutableList.copyOf(mods);
modController.distributeStateMessage(FMLLoadEvent.class);
modController.transition(LoaderState.CONSTRUCTING);
modController.distributeStateMessage(LoaderState.CONSTRUCTING, modClassLoader);
modController.distributeStateMessage(LoaderState.CONSTRUCTING, modClassLoader, disc.getASMTable());
modController.transition(LoaderState.PREINITIALIZATION);
modController.distributeStateMessage(LoaderState.PREINITIALIZATION);
modController.distributeStateMessage(LoaderState.PREINITIALIZATION, disc.getASMTable());
modController.transition(LoaderState.INITIALIZATION);
}

View file

@ -150,4 +150,6 @@ public interface ModContainer
ProxyInjector findSidedProxy();
boolean isImmutable();
boolean isNetworkMod();
}

View file

@ -0,0 +1,106 @@
package cpw.mods.fml.common.discovery;
import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.google.common.base.Predicate;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import com.google.common.collect.SetMultimap;
import com.google.common.collect.ImmutableBiMap.Builder;
import cpw.mods.fml.common.ModContainer;
public class ASMDataTable
{
public static class ASMData
{
private ModCandidate candidate;
private String annotationName;
private String className;
private String objectName;
private Map<String,Object> annotationInfo;
public ASMData(ModCandidate candidate, String annotationName, String className, String objectName, Map<String,Object> info)
{
this.candidate = candidate;
this.annotationName = annotationName;
this.className = className;
this.objectName = objectName;
this.annotationInfo = info;
}
public ModCandidate getCandidate()
{
return candidate;
}
public String getAnnotationName()
{
return annotationName;
}
public String getClassName()
{
return className;
}
public String getObjectName()
{
return objectName;
}
public Map<String, Object> getAnnotationInfo()
{
return annotationInfo;
}
}
private static class ModContainerPredicate implements Predicate<ASMData>
{
private ModContainer container;
public ModContainerPredicate(ModContainer container)
{
this.container = container;
}
public boolean apply(ASMData data)
{
return container.getSource().equals(data.candidate.getModContainer());
}
}
private SetMultimap<String, ASMData> globalAnnotationData;
private Map<ModContainer, SetMultimap<String,ASMData>> containerAnnotationData;
private List<ModContainer> containers = Lists.newArrayList();
public SetMultimap<String,ASMData> getAnnotationsFor(ModContainer container)
{
if (containerAnnotationData == null)
{
ImmutableMap.Builder<ModContainer, SetMultimap<String, ASMData>> mapBuilder = ImmutableMap.<ModContainer, SetMultimap<String,ASMData>>builder();
for (ModContainer cont : containers)
{
Multimap<String, ASMData> values = Multimaps.filterValues(globalAnnotationData, new ModContainerPredicate(cont));
mapBuilder.put(cont, ImmutableSetMultimap.copyOf(values));
}
containerAnnotationData = mapBuilder.build();
}
return containerAnnotationData.get(container);
}
public Set<ASMData> getAll(String annotation)
{
return globalAnnotationData.get(annotation);
}
public void addASMData(ModCandidate candidate, String annotation, String className, String objectName, Map<String,Object> annotationInfo)
{
globalAnnotationData.put(annotation, new ASMData(candidate, annotation, className, objectName, annotationInfo));
}
public void addContainer(ModContainer container)
{
this.containers.add(container);
}
}

View file

@ -10,7 +10,7 @@ public enum ContainerType
{
JAR(JarDiscoverer.class),
DIR(DirectoryDiscoverer.class);
private ITypeDiscoverer discoverer;
private ContainerType(Class<? extends ITypeDiscoverer> discovererClass)
@ -24,9 +24,9 @@ public enum ContainerType
throw Throwables.propagate(e);
}
}
public List<ModContainer> findMods(ModCandidate candidate)
public List<ModContainer> findMods(ModCandidate candidate, ASMDataTable table)
{
return discoverer.discover(candidate);
return discoverer.discover(candidate, table);
}
}

View file

@ -30,12 +30,19 @@ public class DirectoryDiscoverer implements ITypeDiscoverer
}
}
private ASMDataTable table;
@Override
public List<ModContainer> discover(ModCandidate candidate)
public List<ModContainer> discover(ModCandidate candidate, ASMDataTable table)
{
this.table = table;
List<ModContainer> found = Lists.newArrayList();
FMLLog.fine("Examining directory %s for potential mods", candidate.getModContainer().getName());
exploreFileSystem("", candidate.getModContainer(), found, candidate, null);
for (ModContainer mc : found)
{
table.addContainer(mc);
}
return found;
}
@ -85,6 +92,7 @@ public class DirectoryDiscoverer implements ITypeDiscoverer
}
modParser.validate();
modParser.sendToTable(table, candidate);
ModContainer container = ModContainerFactory.instance().build(modParser, candidate.getModContainer());
if (container!=null)
{

View file

@ -9,5 +9,5 @@ public interface ITypeDiscoverer
{
public static Pattern classFile = Pattern.compile("([^\\s$]+).class$");
public List<ModContainer> discover(ModCandidate candidate);
public List<ModContainer> discover(ModCandidate candidate, ASMDataTable table);
}

View file

@ -18,7 +18,7 @@ import cpw.mods.fml.common.discovery.asm.ASMModParser;
public class JarDiscoverer implements ITypeDiscoverer
{
@Override
public List<ModContainer> discover(ModCandidate candidate)
public List<ModContainer> discover(ModCandidate candidate, ASMDataTable table)
{
List<ModContainer> foundMods = Lists.newArrayList();
FMLLog.fine("Examining file %s for potential mods", candidate.getModContainer().getName());
@ -41,9 +41,11 @@ public class JarDiscoverer implements ITypeDiscoverer
{
ASMModParser modParser = new ASMModParser(jar.getInputStream(ze));
modParser.validate();
modParser.sendToTable(table, candidate);
ModContainer container = ModContainerFactory.instance().build(modParser, candidate.getModContainer());
if (container!=null)
{
table.addContainer(container);
foundMods.add(container);
container.bindMetadata(mc);
}

View file

@ -39,8 +39,8 @@ public class ModCandidate
{
return sourceType;
}
public List<ModContainer> explore()
public List<ModContainer> explore(ASMDataTable table)
{
return sourceType.findMods(this);
return sourceType.findMods(this, table);
}
}

View file

@ -8,7 +8,9 @@ import java.io.IOException;
import java.io.InputStream;
import java.nio.channels.FileChannel;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
@ -25,9 +27,18 @@ import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Opcodes;
import com.google.common.base.Supplier;
import com.google.common.base.Throwables;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableTable;
import com.google.common.collect.Tables;
import com.google.common.collect.ImmutableTable.Builder;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.common.collect.Table;
import com.google.common.collect.Table.Cell;
import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.common.LoaderException;
@ -41,6 +52,8 @@ public class ModDiscoverer
private List<ModCandidate> candidates = Lists.newArrayList();
private ASMDataTable dataTable = new ASMDataTable();
public void findClasspathMods(ModClassLoader modClassLoader)
{
List<String> knownLibraries = ImmutableList.<String>builder().addAll(modClassLoader.getDefaultLibraries()).addAll(RelaunchLibraryManager.getLibraries()).build();
@ -114,7 +127,7 @@ public class ModDiscoverer
{
try
{
List<ModContainer> mods = candidate.explore();
List<ModContainer> mods = candidate.explore(dataTable);
modList.addAll(mods);
}
catch (LoaderException le)
@ -129,4 +142,10 @@ public class ModDiscoverer
return modList;
}
public ASMDataTable getASMTable()
{
return dataTable;
}
}

View file

@ -14,6 +14,9 @@ import com.google.common.base.Objects;
import com.google.common.collect.Lists;
import cpw.mods.fml.common.LoaderException;
import cpw.mods.fml.common.discovery.ASMDataTable;
import cpw.mods.fml.common.discovery.ModCandidate;
import cpw.mods.fml.common.discovery.ModDiscoverer;
public class ASMModParser
{
@ -23,18 +26,18 @@ public class ASMModParser
private Type asmSuperType;
private LinkedList<ModAnnotation> annotations = Lists.newLinkedList();
private String baseModProperties;
static enum AnnotationType
{
CLASS, FIELD, METHOD;
}
public ASMModParser(InputStream stream) throws IOException
{
ClassReader reader = new ClassReader(stream);
reader.accept(new ModClassVisitor(this), 0);
}
public void beginNewTypeName(String typeQName, int classVersion, String superClassQName)
{
this.asmType = Type.getObjectType(typeQName);
@ -58,7 +61,7 @@ public class ASMModParser
ModAnnotation ann = new ModAnnotation(AnnotationType.FIELD, Type.getType(annotationName), fieldName);
annotations.addFirst(ann);
}
@Override
public String toString()
{
@ -91,12 +94,12 @@ public class ASMModParser
{
return annotations;
}
public void validate()
{
// if (classVersion > 50.0)
// {
//
//
// throw new LoaderException(new RuntimeException("Mod compiled for Java 7 detected"));
// }
}
@ -115,4 +118,12 @@ public class ASMModParser
{
return this.baseModProperties;
}
public void sendToTable(ASMDataTable table, ModCandidate candidate)
{
for (ModAnnotation ma : annotations)
{
table.addASMData(candidate, ma.asmType.getClassName(), this.asmType.getClassName(), ma.member, ma.values);
}
}
}

View file

@ -1,17 +1,28 @@
package cpw.mods.fml.common.event;
import java.util.List;
import java.util.Map;
import com.google.common.collect.Table;
import cpw.mods.fml.common.LoaderState.ModState;
import cpw.mods.fml.common.ModClassLoader;
import cpw.mods.fml.common.ModContainer;
import cpw.mods.fml.common.discovery.ASMDataTable;
import cpw.mods.fml.common.discovery.ASMDataTable.ASMData;
import cpw.mods.fml.common.discovery.ModDiscoverer;
public class FMLConstructionEvent extends FMLStateEvent
{
private ModClassLoader modClassLoader;
private ASMDataTable asmData;
public FMLConstructionEvent(Object... eventData)
{
this.modClassLoader = (ModClassLoader)eventData[0];
this.asmData = (ASMDataTable) eventData[1];
}
public ModClassLoader getModClassLoader()
{
return modClassLoader;
@ -22,4 +33,9 @@ public class FMLConstructionEvent extends FMLStateEvent
{
return ModState.CONSTRUCTED;
}
public ASMDataTable getASMHarvestedData()
{
return asmData;
}
}

View file

@ -1,7 +1,9 @@
package cpw.mods.fml.common.event;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.LoaderState.ModState;
import cpw.mods.fml.common.ModContainer;
import cpw.mods.fml.common.Side;
public abstract class FMLStateEvent extends FMLEvent
{
@ -16,4 +18,9 @@ public abstract class FMLStateEvent extends FMLEvent
{
// NO OP
}
public Side getSide()
{
return FMLCommonHandler.instance().getSide();
}
}

View file

@ -59,6 +59,8 @@ import cpw.mods.fml.common.event.FMLConstructionEvent;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.event.FMLPostInitializationEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.network.FMLNetworkHandler;
import cpw.mods.fml.common.network.NetworkMod;
import cpw.mods.fml.common.registry.TickRegistry;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.common.versioning.ArtifactVersion;
@ -88,6 +90,7 @@ public class ModLoaderModContainer implements ModContainer
private boolean enabled = true;
private String sortingProperties;
private ArtifactVersion processedVersion;
private boolean isNetworkMod;
public ModLoaderModContainer(String className, File modSource, String sortingProperties)
{
@ -490,6 +493,7 @@ public class ModLoaderModContainer implements ModContainer
modClassLoader.addFile(modSource);
Class<? extends BaseMod> modClazz = (Class<? extends BaseMod>) Class.forName(modClazzName, true, modClassLoader);
configureMod(modClazz);
isNetworkMod = FMLNetworkHandler.instance().registerNetworkMod(this, modClazz, event.getASMHarvestedData());
mod = (BaseMod)modClazz.newInstance();
}
catch (Exception e)
@ -564,4 +568,10 @@ public class ModLoaderModContainer implements ModContainer
{
return false;
}
@Override
public boolean isNetworkMod()
{
return this.isNetworkMod;
}
}

View file

@ -0,0 +1,10 @@
package cpw.mods.fml.common.network;
public class FMLNetworkException extends RuntimeException
{
public FMLNetworkException(Exception e)
{
super(e);
}
}

View file

@ -0,0 +1,164 @@
package cpw.mods.fml.common.network;
import static cpw.mods.fml.common.network.FMLPacket.Type.*;
import java.net.SocketAddress;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.BiMap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import com.google.common.hash.Hashing;
import com.google.common.io.ByteStreams;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.common.ModContainer;
import cpw.mods.fml.common.discovery.ASMDataTable;
import cpw.mods.fml.common.discovery.ASMDataTable.ASMData;
import net.minecraft.server.MinecraftServer;
import net.minecraft.src.NetHandler;
import net.minecraft.src.NetLoginHandler;
import net.minecraft.src.NetworkManager;
import net.minecraft.src.Packet;
import net.minecraft.src.Packet1Login;
import net.minecraft.src.Packet250CustomPayload;
import net.minecraft.src.ServerConfigurationManager;
import net.minecraft.src.TcpConnection;
public class FMLNetworkHandler
{
private static final int FML_HASH = Hashing.murmur3_32().hashString("FML").asInt();
private static final int PROTOCOL_VERSION = 0x1;
private static final FMLNetworkHandler INSTANCE = new FMLNetworkHandler();
private Map<NetLoginHandler, Integer> loginStates = Maps.newHashMap();
private Map<ModContainer, NetworkModHandler> networkModHandlers = Maps.newHashMap();
private Map<Integer, NetworkModHandler> networkIdLookup = Maps.newHashMap();
public static void handlePacket250Packet(Packet250CustomPayload packet, NetworkManager network, NetHandler handler)
{
String target = packet.field_73630_a;
if (target.startsWith("MC|"))
{
handler.handleVanilla250Packet(packet);
return;
}
if (target.equals("FML"))
{
instance().handleFMLPacket(packet, network);
}
}
private void handleFMLPacket(Packet250CustomPayload packet, NetworkManager network)
{
FMLPacket pkt = FMLPacket.readPacket(packet.field_73629_c);
pkt.execute(network, this);
}
public static void onClientConnectToServer(NetLoginHandler netLoginHandler, MinecraftServer server, SocketAddress address, String userName)
{
instance().handleClientConnection(netLoginHandler, server, address, userName);
}
private void handleClientConnection(NetLoginHandler netLoginHandler, MinecraftServer server, SocketAddress address, String userName)
{
if (!loginStates.containsKey(netLoginHandler))
{
// Vanilla reasons first
ServerConfigurationManager playerList = server.func_71203_ab();
String kickReason = playerList.func_72399_a(address, userName);
if (kickReason!=null)
{
netLoginHandler.completeConnection(kickReason);
}
// No FML on the client
netLoginHandler.completeConnection("You don't have FML installed, or your installation is too old");
return;
}
// Are we ready to negotiate with the client?
if (loginStates.get(netLoginHandler) == 1)
{
// Reset the "connection completed" flag so processing can continue
NetLoginHandler.func_72531_a(netLoginHandler, false);
// Send the mod list request packet to the client from the server
netLoginHandler.field_72538_b.func_74429_a(getModListRequestPacket());
loginStates.put(netLoginHandler, 2);
}
// We must be good to go - the ModIdentifiers packet was sent and the continuation signal was indicated
else if (loginStates.get(netLoginHandler) == 2)
{
netLoginHandler.completeConnection(null);
loginStates.remove(netLoginHandler);
}
// We have to abort this connection - there was a negotiation problem (most likely missing mods)
else
{
netLoginHandler.completeConnection("There was a problem during FML negotiation");
loginStates.remove(netLoginHandler);
}
}
public static void handleLoginPacketOnServer(NetLoginHandler handler, Packet1Login login)
{
if (login.field_73561_a == FML_HASH && login.field_73558_e == PROTOCOL_VERSION)
{
instance().loginStates.put(handler,1);
}
}
public static FMLNetworkHandler instance()
{
return INSTANCE;
}
public static Packet1Login getFMLFakeLoginPacket()
{
Packet1Login fake = new Packet1Login();
// Hash FML using a simple function
fake.field_73561_a = FML_HASH;
// The FML protocol version
fake.field_73558_e = PROTOCOL_VERSION;
return fake;
}
public static Packet250CustomPayload getModListRequestPacket()
{
Packet250CustomPayload pkt = new Packet250CustomPayload();
pkt.field_73630_a = "FML";
pkt.field_73629_c = FMLPacket.makePacket(MOD_LIST_REQUEST);
pkt.field_73628_b = pkt.field_73629_c.length;
return pkt;
}
public boolean registerNetworkMod(ModContainer container, Class<?> networkModClass, ASMDataTable asmData)
{
NetworkModHandler handler = new NetworkModHandler(container, networkModClass, asmData);
if (handler.isNetworkMod())
{
networkModHandlers.put(container, handler);
networkIdLookup.put(handler.getNetworkId(), handler);
}
return handler.isNetworkMod();
}
public NetworkModHandler findNetworkModHandler(ModContainer mc)
{
return networkModHandlers.get(mc);
}
public List<ModContainer> getNetworkModList()
{
return null;
}
}

View file

@ -0,0 +1,90 @@
package cpw.mods.fml.common.network;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import net.minecraft.src.NetHandler;
import net.minecraft.src.NetworkManager;
import com.google.common.base.Throwables;
import com.google.common.io.ByteStreams;
import com.google.common.primitives.Bytes;
import com.google.common.primitives.Primitives;
import com.google.common.primitives.UnsignedBytes;
import cpw.mods.fml.common.FMLLog;
public abstract class FMLPacket
{
enum Type
{
/**
* Opening salutation from the server to the client -> request all mods from the client
*/
MOD_LIST_REQUEST(ModListRequestPacket.class),
/**
* The client responds with the list of mods and versions it has. This is verified by the server.
*/
MOD_LIST_RESPONSE(ModListResponsePacket.class),
/**
* At which point the server tells the client the mod identifiers for this session.
*/
MOD_IDENTIFIERS(ModIdentifiersPacket.class),
/**
* Or, if there is missing stuff, the server tells the client what's missing and drops the connection.
*/
MOD_MISSING(ModMissingPacket.class);
private Class<? extends FMLPacket> packetType;
private Type(Class<? extends FMLPacket> clazz)
{
this.packetType = clazz;
}
FMLPacket make()
{
try
{
return this.packetType.newInstance();
}
catch (Exception e)
{
Throwables.propagateIfPossible(e);
FMLLog.log(Level.SEVERE, e, "A bizarre critical error occured during packet encoding");
throw new FMLNetworkException(e);
}
}
}
private Type type;
public static byte[] makePacket(Type type, Object... data)
{
byte[] packetData = type.make().generatePacket(data);
return Bytes.concat(new byte[] { UnsignedBytes.checkedCast(type.ordinal()) }, packetData );
}
public static FMLPacket readPacket(byte[] payload)
{
int type = UnsignedBytes.toInt(payload[0]);
return Type.values()[type].make().consumePacket(Arrays.copyOfRange(payload, 1, payload.length));
}
public FMLPacket(Type type)
{
this.type = type;
}
public abstract byte[] generatePacket(Object... data);
public abstract FMLPacket consumePacket(byte[] data);
public abstract void execute(NetworkManager network, FMLNetworkHandler handler, NetHandler netHandler);
{
// TODO Auto-generated method stub
}
}

View file

@ -0,0 +1,35 @@
package cpw.mods.fml.common.network;
import static cpw.mods.fml.common.network.FMLPacket.Type.*;
import net.minecraft.src.NetHandler;
import net.minecraft.src.NetworkManager;
public class ModIdentifiersPacket extends FMLPacket
{
public ModIdentifiersPacket()
{
super(MOD_IDENTIFIERS);
}
@Override
public byte[] generatePacket(Object... data)
{
// TODO Auto-generated method stub
return null;
}
@Override
public FMLPacket consumePacket(byte[] data)
{
// TODO Auto-generated method stub
return null;
}
@Override
public void execute(NetworkManager network, FMLNetworkHandler handler, NetHandler netHandler)
{
// TODO Auto-generated method stub
}
}

View file

@ -0,0 +1,96 @@
package cpw.mods.fml.common.network;
import static cpw.mods.fml.common.network.FMLPacket.Type.*;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import net.minecraft.src.NetHandler;
import net.minecraft.src.NetworkManager;
import net.minecraft.src.Packet250CustomPayload;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;
import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.common.ModContainer;
public class ModListRequestPacket extends FMLPacket
{
private List<String> sentModList;
public ModListRequestPacket()
{
super(MOD_LIST_REQUEST);
}
@Override
public byte[] generatePacket(Object... data)
{
ByteArrayDataOutput dat = ByteStreams.newDataOutput();
List<ModContainer> activeMods = FMLNetworkHandler.instance().getNetworkModList();
dat.writeInt(activeMods.size());
for (ModContainer mc : activeMods)
{
dat.writeUTF(mc.getModId());
}
return dat.toByteArray();
}
@Override
public FMLPacket consumePacket(byte[] data)
{
sentModList = Lists.newArrayList();
ByteArrayDataInput in = ByteStreams.newDataInput(data);
int listSize = in.readInt();
for (int i = 0; i < listSize; i++)
{
sentModList.add(in.readUTF());
}
return this;
}
/**
*
* This packet is executed on the client to evaluate the server's mod list against
* the client
*
* @see cpw.mods.fml.common.network.FMLPacket#execute()
*/
@Override
public void execute(NetworkManager mgr, FMLNetworkHandler handler, NetHandler netHandler)
{
List<String> missingMods = Lists.newArrayList();
Map<String,String> modVersions = Maps.newHashMap();
Map<String, ModContainer> indexedModList = Maps.newHashMap(Loader.instance().getIndexedModList());
for (String m : sentModList)
{
ModContainer mc = indexedModList.get(m);
if (mc == null)
{
missingMods.add(m);
continue;
}
indexedModList.remove(m);
modVersions.put(m, mc.getVersion());
}
if (indexedModList.size()>0)
{
// TODO : handle client present but server absent mods
}
Packet250CustomPayload pkt = new Packet250CustomPayload();
pkt.field_73630_a = "FML";
pkt.field_73629_c = FMLPacket.makePacket(MOD_LIST_RESPONSE, modVersions, missingMods);
pkt.field_73628_b = pkt.field_73629_c.length;
mgr.func_74429_a(pkt);
}
}

View file

@ -0,0 +1,117 @@
package cpw.mods.fml.common.network;
import static cpw.mods.fml.common.network.FMLPacket.Type.*;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.common.ModContainer;
import net.minecraft.src.NetHandler;
import net.minecraft.src.NetLoginHandler;
import net.minecraft.src.NetworkManager;
import net.minecraft.src.Packet250CustomPayload;
public class ModListResponsePacket extends FMLPacket
{
private Map<String,String> modVersions;
private List<String> missingMods;
public ModListResponsePacket()
{
super(MOD_LIST_RESPONSE);
}
@Override
public byte[] generatePacket(Object... data)
{
Map<String,String> modVersions = (Map<String, String>) data[0];
List<String> missingMods = (List<String>) data[1];
ByteArrayDataOutput dat = ByteStreams.newDataOutput();
dat.writeInt(modVersions.size());
for (Entry<String, String> version : modVersions.entrySet())
{
dat.writeUTF(version.getKey());
dat.writeUTF(version.getValue());
}
dat.writeInt(missingMods.size());
for (String missing : missingMods)
{
dat.writeUTF(missing);
}
return dat.toByteArray();
}
@Override
public FMLPacket consumePacket(byte[] data)
{
ByteArrayDataInput dat = ByteStreams.newDataInput(data);
int versionListSize = dat.readInt();
modVersions = Maps.newHashMapWithExpectedSize(versionListSize);
for (int i = 0; i < versionListSize; i++)
{
String modName = dat.readUTF();
String modVersion = dat.readUTF();
modVersions.put(modName, modVersion);
}
int missingModSize = dat.readInt();
missingMods = Lists.newArrayListWithExpectedSize(missingModSize);
for (int i = 0; i < missingModSize; i++)
{
missingMods.add(dat.readUTF());
}
return this;
}
@Override
public void execute(NetworkManager network, FMLNetworkHandler handler, NetHandler netHandler)
{
Map<String, ModContainer> indexedModList = Maps.newHashMap(Loader.instance().getIndexedModList());
List<String> missingClientMods = Lists.newArrayList();
List<String> versionIncorrectMods = Lists.newArrayList();
for (String m : missingMods)
{
ModContainer mc = indexedModList.get(m);
NetworkModHandler networkMod = handler.findNetworkModHandler(mc);
if (networkMod.requiresClientSide())
{
missingClientMods.add(m);
}
}
for (Entry<String,String> modVersion : modVersions.entrySet())
{
ModContainer mc = indexedModList.get(modVersion.getKey());
NetworkModHandler networkMod = handler.findNetworkModHandler(mc);
if (!networkMod.acceptVersion(modVersion.getValue()))
{
versionIncorrectMods.add(modVersion.getKey());
}
}
if (missingClientMods.size()>0 || versionIncorrectMods.size() > 0)
{
Packet250CustomPayload pkt = new Packet250CustomPayload();
pkt.field_73630_a = "FML";
pkt.field_73629_c = FMLPacket.makePacket(MOD_MISSING, missingClientMods, versionIncorrectMods);
pkt.field_73628_b = pkt.field_73629_c.length;
network.func_74429_a(pkt);
NetLoginHandler.func_72531_a((NetLoginHandler) netHandler, false);
return;
}
handler.generateModIdentifierData();
}
}

View file

@ -0,0 +1,34 @@
package cpw.mods.fml.common.network;
import net.minecraft.src.NetworkManager;
public class ModMissingPacket extends FMLPacket
{
public ModMissingPacket()
{
super(Type.MOD_MISSING);
}
@Override
public byte[] generatePacket(Object... data)
{
// TODO Auto-generated method stub
return null;
}
@Override
public FMLPacket consumePacket(byte[] data)
{
// TODO Auto-generated method stub
return null;
}
@Override
public void execute(NetworkManager network, FMLNetworkHandler handler)
{
// TODO Auto-generated method stub
}
}

View file

@ -0,0 +1,47 @@
package cpw.mods.fml.common.network;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.EnumSet;
import cpw.mods.fml.common.Side;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface NetworkMod
{
/**
* Does this mod require the client side to be present when installed on a server?
*
* @return
*/
boolean clientSideRequired() default false;
/**
* Does this mod require the server side to be present when installed on a client?
* @return
*/
boolean serverSideRequired() default false;
/**
* A list of Packet250 network channels to register for this mod
* @return
*/
String[] channels() default {};
/**
* An optional range check for client to server communication version compatibility
* @return
*/
String versionBounds() default "";
/**
* A marker for a method that will be offered the client's version string
* if more sophisticated version rejection handling is required:
* The method should accept a "String", a "NetworkManager" and return a boolean true
* if the version can be accepted.
* @author cpw
*
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface VersionCheckHandler { }
}

View file

@ -0,0 +1,146 @@
package cpw.mods.fml.common.network;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Set;
import java.util.logging.Level;
import org.objectweb.asm.Type;
import com.google.common.base.Strings;
import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.common.ModContainer;
import cpw.mods.fml.common.discovery.ASMDataTable;
import cpw.mods.fml.common.discovery.ASMDataTable.ASMData;
import cpw.mods.fml.common.versioning.DefaultArtifactVersion;
import cpw.mods.fml.common.versioning.InvalidVersionSpecificationException;
import cpw.mods.fml.common.versioning.VersionRange;
public class NetworkModHandler
{
private static int assignedIds = 1;
private int localId;
private int networkId;
private ModContainer container;
private NetworkMod mod;
private Method checkHandler;
private VersionRange acceptableRange;
public NetworkModHandler(ModContainer container, Class<?> networkModClass, ASMDataTable table)
{
this.container = container;
this.mod = networkModClass.getAnnotation(NetworkMod.class);
if (this.mod == null)
{
return;
}
this.localId = assignedIds++;
this.networkId = this.localId;
Set<ASMData> versionCheckHandlers = table.getAnnotationsFor(container).get(Type.getDescriptor(NetworkMod.VersionCheckHandler.class));
String versionCheckHandlerMethod = null;
for (ASMData vch : versionCheckHandlers)
{
if (vch.getClassName().equals(networkModClass.getName()))
{
versionCheckHandlerMethod = vch.getObjectName();
break;
}
}
if (versionCheckHandlerMethod != null)
{
try
{
Method checkHandlerMethod = networkModClass.getDeclaredMethod(versionCheckHandlerMethod, String.class);
if (checkHandlerMethod.isAnnotationPresent(NetworkMod.VersionCheckHandler.class))
{
this.checkHandler = checkHandlerMethod;
}
}
catch (Exception e)
{
FMLLog.log(Level.WARNING, e, "The declared version check handler method %s on network mod id %s is not accessible", versionCheckHandlerMethod, container.getModId());
}
}
if (this.checkHandler == null)
{
String versionBounds = mod.versionBounds();
if (!Strings.isNullOrEmpty(versionBounds))
{
try
{
this.acceptableRange = VersionRange.createFromVersionSpec(versionBounds);
}
catch (InvalidVersionSpecificationException e)
{
FMLLog.log(Level.WARNING, e, "Invalid bounded range %s specified for network mod id %s", versionBounds, container.getModId());
}
}
}
}
public boolean requiresClientSide()
{
return mod.clientSideRequired();
}
public boolean requiresServerSide()
{
return mod.serverSideRequired();
}
public boolean acceptVersion(String version)
{
if (checkHandler != null)
{
try
{
return (Boolean)checkHandler.invoke(container.getMod(), version);
}
catch (Exception e)
{
FMLLog.log(Level.WARNING, e, "There was a problem invoking the checkhandler method %s for network mod id %s", checkHandler.getName(), container.getModId());
return false;
}
}
if (acceptableRange!=null)
{
return acceptableRange.containsVersion(new DefaultArtifactVersion(version));
}
return container.getVersion().equals(version);
}
public int getLocalId()
{
return localId;
}
public int getNetworkId()
{
return networkId;
}
public ModContainer getContainer()
{
return container;
}
public NetworkMod getMod()
{
return mod;
}
public boolean isNetworkMod()
{
return mod != null;
}
}

View file

@ -0,0 +1,95 @@
package cpw.mods.fml.common.network;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import net.minecraft.src.EntityPlayer;
import com.google.common.base.Charsets;
import com.google.common.base.Joiner;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import com.google.common.collect.SetMultimap;
import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.common.ModContainer;
public class NetworkRegistry
{
private static final NetworkRegistry INSTANCE = new NetworkRegistry();
/**
* A map of active channels per player
*/
private Multimap<Player, String> activeChannels = ArrayListMultimap.create();
/**
* A map of mods to their network channels - the list is a set
*/
private SetMultimap<ModContainer, String> channelList = LinkedHashMultimap.create();
public static NetworkRegistry instance()
{
return INSTANCE;
}
/**
* Get the channel list for a mod
* @param modLoaderModContainer
* @return
*/
public Set<String> getChannelListFor(ModContainer container)
{
return channelList.get(container);
}
/**
* Get the packet 250 channel registration string
* @return
*/
public byte[] getPacketRegistry()
{
return Joiner.on('\0').join(channelList.values()).getBytes(Charsets.UTF_8);
}
/**
* Is the specified channel active for the player?
* @param channel
* @param player
* @return
*/
public boolean isChannelActive(String channel, Player player)
{
return activeChannels.containsEntry(player,channel);
}
/**
* register a channel to a mod
* @param container
* @param channelName
*/
public void registerChannel(ModContainer container, String channelName)
{
channelList.put(container, channelName);
// invertedChannelList = Multimaps.invertFrom(channelList, ArrayListMultimap.<String, ModContainer>create());
}
/**
* Activate the channel for the player
* @param player
*/
public void activateChannel(Player player, String channel)
{
activeChannels.put(player, channel);
}
/**
* Deactivate the channel for the player
* @param player
* @param channel
*/
public void deactivateChannel(Player player, String channel)
{
activeChannels.remove(player, channel);
}
}

View file

@ -0,0 +1,11 @@
package cpw.mods.fml.common.network;
/**
*
* @author cpw
*
*/
public interface Player
{
}

View file

@ -175,4 +175,6 @@ public ir.a
#public+f ri.c
# StatBase - Make statName public, no server side getter
public ho.a
# NetLoginHandler make the "complete connection" callback public so I can reset it during FML negotiation
public gw.a(Lgw;Z)Z

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="src-common"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
<classpathentry kind="lib" path="jars/bin/jinput.jar">
<attributes>

View file

@ -8,4 +8,9 @@ System.out.println(new cpw.mods.fml.common.asm.ASMModParser(fis));
org.objectweb.asm.Type.getDescriptor(net.minecraft.src.CraftingManager.class.getDeclaredMethods()[1])
org.objectweb.asm.Type.getDescriptor(net.minecraft.src.CraftingManager.class.getDeclaredMethods()[1])
com.google.common.collect.Tables.newCustomTable(new HashMap<String,Map<String,List<String>>(), new com.google.common.base.Supplier() {
});

View file

@ -0,0 +1,9 @@
--- ../src-base/common/net/minecraft/src/NetHandler.java
+++ ../src-work/common/net/minecraft/src/NetHandler.java
@@ -345,4 +345,6 @@
{
return false;
}
+
+ public abstract void handleVanilla250Packet(Packet250CustomPayload payload);
}

View file

@ -0,0 +1,41 @@
--- ../src-base/common/net/minecraft/src/NetLoginHandler.java
+++ ../src-work/common/net/minecraft/src/NetLoginHandler.java
@@ -9,6 +9,8 @@
import java.util.Random;
import java.util.logging.Logger;
import javax.crypto.SecretKey;
+
+import cpw.mods.fml.common.network.FMLNetworkHandler;
import net.minecraft.server.MinecraftServer;
public class NetLoginHandler extends NetHandler
@@ -129,8 +131,11 @@
public void func_72529_d()
{
- String var1 = this.field_72534_f.func_71203_ab().func_72399_a(this.field_72538_b.func_74430_c(), this.field_72543_h);
-
+ FMLNetworkHandler.onClientConnectToServer(this, this.field_72534_f, this.field_72538_b.func_74430_c(), this.field_72543_h);
+ }
+
+ public void completeConnection(String var1)
+ {
if (var1 != null)
{
this.func_72527_a(var1);
@@ -221,4 +226,15 @@
{
return p_72531_0_.field_72544_i = p_72531_1_;
}
+
+ public void func_72501_a(Packet250CustomPayload p_72501_1_)
+ {
+ FMLNetworkHandler.handlePacket250Packet(p_72501_1_, field_72538_b, this);
+ }
+
+ @Override
+ public void handleVanilla250Packet(Packet250CustomPayload payload)
+ {
+ // NOOP for login
+ }
}

View file

@ -0,0 +1,23 @@
--- ../src-base/common/net/minecraft/src/NetServerHandler.java
+++ ../src-work/common/net/minecraft/src/NetServerHandler.java
@@ -7,6 +7,8 @@
import java.util.Iterator;
import java.util.Random;
import java.util.logging.Logger;
+
+import cpw.mods.fml.common.network.FMLNetworkHandler;
import net.minecraft.server.MinecraftServer;
public class NetServerHandler extends NetHandler
@@ -956,6 +958,11 @@
public void func_72501_a(Packet250CustomPayload p_72501_1_)
{
+ FMLNetworkHandler.handlePacket250Packet(p_72501_1_, field_72575_b, this);
+ }
+
+ public void handleVanilla250Packet(Packet250CustomPayload p_72501_1_)
+ {
DataInputStream var2;
ItemStack var3;
ItemStack var4;

View file

@ -0,0 +1,32 @@
--- ../src-base/minecraft/net/minecraft/src/NetClientHandler.java
+++ ../src-work/minecraft/net/minecraft/src/NetClientHandler.java
@@ -20,6 +20,9 @@
import net.minecraft.client.Minecraft;
import org.lwjgl.input.Keyboard;
+import cpw.mods.fml.common.LoaderException;
+import cpw.mods.fml.common.network.FMLNetworkHandler;
+
public class NetClientHandler extends NetHandler
{
private boolean field_72554_f = false;
@@ -116,6 +119,7 @@
public void func_72513_a(Packet252SharedKey p_72513_1_)
{
+ this.func_72552_c(FMLNetworkHandler.getFMLFakeLoginPacket());
this.func_72552_c(new Packet205ClientCommand(0));
}
@@ -1164,6 +1168,11 @@
public void func_72501_a(Packet250CustomPayload p_72501_1_)
{
+
+ }
+
+ public void handleVanilla250Packet(Packet250CustomPayload p_72501_1_)
+ {
if ("MC|TPack".equals(p_72501_1_.field_73630_a))
{
String[] var2 = (new String(p_72501_1_.field_73629_c)).split("\u0000");