Add in a lot of network handler stuff - also, expose the asm harvested data
This commit is contained in:
parent
09098f8a0f
commit
8bda53cb77
37 changed files with 1195 additions and 160 deletions
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -122,4 +122,10 @@ public class DummyModContainer implements ModContainer
|
|||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNetworkMod()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -97,6 +97,11 @@ public class InjectedModContainer implements ModContainer
|
|||
return wrappedContainer.findSidedProxy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNetworkMod()
|
||||
{
|
||||
return wrappedContainer.isNetworkMod();
|
||||
}
|
||||
@Override
|
||||
public boolean isImmutable()
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -150,4 +150,6 @@ public interface ModContainer
|
|||
ProxyInjector findSidedProxy();
|
||||
|
||||
boolean isImmutable();
|
||||
|
||||
boolean isNetworkMod();
|
||||
}
|
||||
|
|
106
fml/common/cpw/mods/fml/common/discovery/ASMDataTable.java
Normal file
106
fml/common/cpw/mods/fml/common/discovery/ASMDataTable.java
Normal 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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
package cpw.mods.fml.common.network;
|
||||
|
||||
public class FMLNetworkException extends RuntimeException
|
||||
{
|
||||
|
||||
public FMLNetworkException(Exception e)
|
||||
{
|
||||
super(e);
|
||||
}
|
||||
}
|
164
fml/common/cpw/mods/fml/common/network/FMLNetworkHandler.java
Normal file
164
fml/common/cpw/mods/fml/common/network/FMLNetworkHandler.java
Normal 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;
|
||||
}
|
||||
}
|
90
fml/common/cpw/mods/fml/common/network/FMLPacket.java
Normal file
90
fml/common/cpw/mods/fml/common/network/FMLPacket.java
Normal 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
|
||||
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
34
fml/common/cpw/mods/fml/common/network/ModMissingPacket.java
Normal file
34
fml/common/cpw/mods/fml/common/network/ModMissingPacket.java
Normal 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
|
||||
|
||||
}
|
||||
|
||||
}
|
47
fml/common/cpw/mods/fml/common/network/NetworkMod.java
Normal file
47
fml/common/cpw/mods/fml/common/network/NetworkMod.java
Normal 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 { }
|
||||
}
|
146
fml/common/cpw/mods/fml/common/network/NetworkModHandler.java
Normal file
146
fml/common/cpw/mods/fml/common/network/NetworkModHandler.java
Normal 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;
|
||||
}
|
||||
}
|
95
fml/common/cpw/mods/fml/common/network/NetworkRegistry.java
Normal file
95
fml/common/cpw/mods/fml/common/network/NetworkRegistry.java
Normal 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);
|
||||
}
|
||||
}
|
11
fml/common/cpw/mods/fml/common/network/Player.java
Normal file
11
fml/common/cpw/mods/fml/common/network/Player.java
Normal file
|
@ -0,0 +1,11 @@
|
|||
package cpw.mods.fml.common.network;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author cpw
|
||||
*
|
||||
*/
|
||||
public interface Player
|
||||
{
|
||||
|
||||
}
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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() {
|
||||
|
||||
});
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
+ }
|
||||
}
|
|
@ -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;
|
|
@ -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");
|
Loading…
Reference in a new issue