Check in a lot of recent work

This commit is contained in:
Christian 2012-07-22 11:56:38 -02:30
parent 3115f92ee4
commit 2a19eca517
49 changed files with 2040 additions and 1560 deletions

View File

@ -82,7 +82,7 @@ import net.minecraft.src.WorldType;
import argo.jdom.JdomParser;
import argo.jdom.JsonNode;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.FMLModLoaderContainer;
import cpw.mods.fml.common.FMLDummyContainer;
import cpw.mods.fml.common.IFMLSidedHandler;
import cpw.mods.fml.common.IKeyHandler;
import cpw.mods.fml.common.Loader;
@ -90,7 +90,7 @@ import cpw.mods.fml.common.LoaderException;
import cpw.mods.fml.common.ModContainer;
import cpw.mods.fml.common.ModMetadata;
import cpw.mods.fml.common.ProxyInjector;
import cpw.mods.fml.common.ReflectionHelper;
import cpw.mods.fml.common.ObfuscationReflectionHelper;
import cpw.mods.fml.common.Side;
import cpw.mods.fml.common.TickType;
import cpw.mods.fml.common.modloader.ModLoaderHelper;
@ -167,7 +167,7 @@ public class FMLClientHandler implements IFMLSidedHandler
public void onPreLoad(Minecraft minecraft)
{
client = minecraft;
ReflectionHelper.detectObfuscation(World.class);
ObfuscationReflectionHelper.detectObfuscation(World.class);
FMLCommonHandler.instance().beginLoading(this);
FMLRegistry.registerRegistry(new ClientRegistry());
try
@ -1159,7 +1159,7 @@ public class FMLClientHandler implements IFMLSidedHandler
*/
public void addSpecialModEntries(ArrayList<ModContainer> mods)
{
mods.add(new FMLModLoaderContainer());
mods.add(new FMLDummyContainer());
if (optifineContainer!=null) {
mods.add(optifineContainer);
}

View File

@ -22,7 +22,7 @@ import java.util.Map;
import org.lwjgl.opengl.GL11;
import cpw.mods.fml.common.FMLModContainer;
import cpw.mods.fml.common.FMLModLoaderContainer;
import cpw.mods.fml.common.FMLDummyContainer;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.common.ModContainer;
import net.minecraft.client.Minecraft;

View File

@ -19,6 +19,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import cpw.mods.fml.common.DummyModContainer;
import cpw.mods.fml.common.FMLModContainer;
import cpw.mods.fml.common.IConsoleHandler;
import cpw.mods.fml.common.ICraftingHandler;
@ -35,7 +36,7 @@ import cpw.mods.fml.common.ModMetadata;
* @author cpw
*
*/
public class OptifineModContainer extends FMLModContainer
public class OptifineModContainer extends DummyModContainer
{
private String optifineVersion;
private ModMetadata metadata;
@ -44,7 +45,7 @@ public class OptifineModContainer extends FMLModContainer
*/
public OptifineModContainer(Class<?> optifineConfig)
{
super("Optifine");
super();
try
{
optifineVersion = (String) optifineConfig.getField("VERSION").get(null);

View File

@ -29,7 +29,7 @@ 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.registry.FMLRegistry;
import cpw.mods.fml.common.ReflectionHelper;
import cpw.mods.fml.common.ObfuscationReflectionHelper;
public class ModLoader
{
@ -375,7 +375,7 @@ public class ModLoader
/**
* Get a value from a field using reflection
* {@link ReflectionHelper#getPrivateValue(Class, Object, int)}
* {@link ObfuscationReflectionHelper#getPrivateValue(Class, Object, int)}
*
* @param instanceclass
* @param instance
@ -384,12 +384,12 @@ public class ModLoader
*/
public static <T, E> T getPrivateValue(Class<? super E> instanceclass, E instance, int fieldindex)
{
return ReflectionHelper.getPrivateValue(instanceclass, instance, fieldindex);
return ObfuscationReflectionHelper.getPrivateValue(instanceclass, instance, fieldindex);
}
/**
* Get a value from a field using reflection
* {@link ReflectionHelper#getPrivateValue(Class, Object, String)}
* {@link ObfuscationReflectionHelper#getPrivateValue(Class, Object, String)}
*
* @param instanceclass
* @param instance
@ -398,7 +398,7 @@ public class ModLoader
*/
public static <T, E> T getPrivateValue(Class<? super E> instanceclass, E instance, String field)
{
return ReflectionHelper.getPrivateValue(instanceclass, instance, field);
return ObfuscationReflectionHelper.getPrivateValue(instanceclass, instance, field);
}
/**
@ -724,7 +724,7 @@ public class ModLoader
/**
* Set a private field to a value using reflection
* {@link ReflectionHelper#setPrivateValue(Class, Object, int, Object)}
* {@link ObfuscationReflectionHelper#setPrivateValue(Class, Object, int, Object)}
*
* @param instanceclass
* @param instance
@ -733,12 +733,12 @@ public class ModLoader
*/
public static <T, E> void setPrivateValue(Class<? super T> instanceclass, T instance, int fieldindex, E value)
{
ReflectionHelper.setPrivateValue(instanceclass, instance, value, fieldindex);
ObfuscationReflectionHelper.setPrivateValue(instanceclass, instance, value, fieldindex);
}
/**
* Set a private field to a value using reflection
* {@link ReflectionHelper#setPrivateValue(Class, Object, String, Object)}
* {@link ObfuscationReflectionHelper#setPrivateValue(Class, Object, String, Object)}
*
* @param instanceclass
* @param instance
@ -747,7 +747,7 @@ public class ModLoader
*/
public static <T, E> void setPrivateValue(Class<? super T> instanceclass, T instance, String field, E value)
{
ReflectionHelper.setPrivateValue(instanceclass, instance, value, field);
ObfuscationReflectionHelper.setPrivateValue(instanceclass, instance, value, field);
}
/**

View File

@ -0,0 +1,113 @@
package cpw.mods.fml.common;
import java.io.File;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import com.google.common.eventbus.EventBus;
import cpw.mods.fml.common.LoaderState.ModState;
import cpw.mods.fml.common.discovery.ContainerType;
public class DummyModContainer implements ModContainer
{
private ModMetadata md;
public DummyModContainer(ModMetadata md)
{
this.md = md;
}
public DummyModContainer()
{
}
@Override
public void bindMetadata(MetadataCollection mc)
{
}
@Override
public ProxyInjector findSidedProxy()
{
return null;
}
@Override
public List<String> getDependants()
{
return Collections.emptyList();
}
@Override
public List<String> getDependencies()
{
return Collections.emptyList();
}
@Override
public List<String> getRequirements()
{
return Collections.emptyList();
}
@Override
public ModMetadata getMetadata()
{
return md;
}
@Override
public Object getMod()
{
return null;
}
@Override
public String getModId()
{
return md.modId;
}
@Override
public String getName()
{
return md.name;
}
@Override
public String getSortingRules()
{
return "";
}
@Override
public File getSource()
{
return null;
}
@Override
public String getVersion()
{
return md.version;
}
public boolean matches(Object mod)
{
return false;
}
@Override
public void setEnabledState(boolean enabled)
{
}
@Override
public boolean registerBus(EventBus bus, LoadController controller)
{
return false;
}
}

View File

@ -38,7 +38,8 @@ import java.util.zip.ZipException;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import cpw.mods.fml.common.ModContainer.SourceType;
import cpw.mods.fml.common.discovery.ContainerType;
/**
* The main class for non-obfuscated hook handling code
@ -550,66 +551,6 @@ public class FMLCommonHandler
return brandings.toArray(new String[brandings.size()]);
}
/**
* @param mod
*/
public void loadMetadataFor(ModContainer mod)
{
if (mod.getSourceType()==SourceType.JAR) {
ZipFile jar = null;
try
{
jar = new ZipFile(mod.getSource());
ZipEntry infoFile=jar.getEntry("mcmod.info");
if (infoFile!=null) {
InputStream input=jar.getInputStream(infoFile);
ModMetadata data=sidedDelegate.readMetadataFrom(input, mod);
mod.setMetadata(data);
} else {
getFMLLogger().fine(String.format("Failed to find mcmod.info file in %s for %s", mod.getSource().getName(), mod.getName()));
}
}
catch (Exception e)
{
// Something wrong but we don't care
getFMLLogger().fine(String.format("Failed to find mcmod.info file in %s for %s", mod.getSource().getName(), mod.getName()));
getFMLLogger().throwing("FMLCommonHandler", "loadMetadataFor", e);
}
finally
{
if (jar!=null)
{
try
{
jar.close();
}
catch (IOException e)
{
// GO AWAY
}
}
}
} else {
try
{
InputStream input=Loader.instance().getModClassLoader().getResourceAsStream(mod.getName()+".info");
if (input==null) {
input=Loader.instance().getModClassLoader().getResourceAsStream("net/minecraft/src/"+mod.getName()+".info");
}
if (input!=null) {
ModMetadata data=sidedDelegate.readMetadataFrom(input, mod);
mod.setMetadata(data);
}
}
catch (Exception e)
{
// Something wrong but we don't care
getFMLLogger().fine(String.format("Failed to find %s.info file in %s for %s", mod.getName(), mod.getSource().getName(), mod.getName()));
getFMLLogger().throwing("FMLCommonHandler", "loadMetadataFor", e);
}
}
}
/**
* @return
*/

View File

@ -0,0 +1,44 @@
/*
* The FML Forge Mod Loader suite.
* Copyright (C) 2012 cpw
*
* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package cpw.mods.fml.common;
import java.util.Arrays;
/**
* @author cpw
*
*/
public class FMLDummyContainer extends DummyModContainer
{
public FMLDummyContainer()
{
super(new ModMetadata());
ModMetadata meta = getMetadata();
meta.modId="FML";
meta.name="Forge Mod Loader";
meta.version=Loader.instance().getFMLVersionString();
meta.credits="Made possible with help from many people";
meta.authorList=Arrays.asList("cpw, LexManos");
meta.description="The Forge Mod Loader provides the ability for systems to load mods " +
"from the file system. It also provides key capabilities for mods to be able " +
"to cooperate and provide a good modding environment. " +
"The mod loading system is compatible with ModLoader, all your ModLoader " +
"mods should work.";
meta.url="https://github.com/cpw/FML/wiki";
meta.updateUrl="https://github.com/cpw/FML/wiki";
meta.screenshots=new String[0];
meta.logoFile="";
}
}

View File

@ -17,95 +17,55 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import com.google.common.base.Throwables;
import com.google.common.collect.Lists;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import cpw.mods.fml.common.LoaderState.ModState;
import cpw.mods.fml.common.discovery.ContainerType;
import cpw.mods.fml.common.event.FMLConstructionEvent;
public class FMLModContainer implements ModContainer
{
private Mod modDescriptor;
private Object modInstance;
private File source;
private ModMetadata modMetadata;
private String className;
private String modId;
private Map<String, Object> descriptor;
private boolean enabled;
private List<String> requirements;
private List<String> dependencies;
private List<String> dependants;
private boolean overridesMetadata;
private EventBus eventBus;
private LoadController controller;
public FMLModContainer(String dummy)
public FMLModContainer(String className, File modSource, Map<String,Object> modDescriptor)
{
this(new File(dummy));
}
public FMLModContainer(File source)
{
this.source = source;
}
public FMLModContainer(Class<?> clazz)
{
if (clazz == null)
{
return;
}
modDescriptor = clazz.getAnnotation(Mod.class);
try
{
modInstance = clazz.newInstance();
}
catch (Exception e)
{
throw new RuntimeException(e);
}
this.className = className;
this.source = modSource;
this.descriptor = modDescriptor;
}
@Override
public void preInit()
public String getModId()
{
}
@Override
public void init()
{
// TODO Auto-generated method stub
}
@Override
public void postInit()
{
// TODO Auto-generated method stub
}
public static ModContainer buildFor(Class<?> clazz)
{
return new FMLModContainer(clazz);
return (String) descriptor.get("modid");
}
@Override
public String getName()
{
// TODO Auto-generated method stub
return null;
return modMetadata.name;
}
@Override
public LoaderState.ModState getModState()
public String getVersion()
{
// TODO Auto-generated method stub
return null;
}
@Override
public void nextState()
{
// TODO Auto-generated method stub
}
@Override
public String getSortingRules()
{
// TODO Auto-generated method stub
return null;
}
@Override
public boolean matches(Object mod)
{
// TODO Auto-generated method stub
return false;
return modMetadata.version;
}
@Override
@ -114,210 +74,112 @@ public class FMLModContainer implements ModContainer
return source;
}
@Override
public Object getMod()
{
// TODO Auto-generated method stub
return null;
}
@Override
public int lookupFuelValue(int itemId, int itemDamage)
{
// TODO Auto-generated method stub
return 0;
}
@Override
public IPickupNotifier getPickupNotifier()
{
// TODO Auto-generated method stub
return null;
}
/* (non-Javadoc)
* @see cpw.mods.fml.common.ModContainer#getDispenseHandler()
*/
@Override
public IDispenseHandler getDispenseHandler()
{
// TODO Auto-generated method stub
return null;
}
/* (non-Javadoc)
* @see cpw.mods.fml.common.ModContainer#getCraftingHandler()
*/
@Override
public ICraftingHandler getCraftingHandler()
{
// TODO Auto-generated method stub
return null;
}
/* (non-Javadoc)
* @see cpw.mods.fml.common.ModContainer#getDependencies()
*/
@Override
public List<String> getDependencies()
{
// TODO Auto-generated method stub
return new ArrayList<String>(0);
}
/* (non-Javadoc)
* @see cpw.mods.fml.common.ModContainer#getPreDepends()
*/
@Override
public List<String> getPreDepends()
{
// TODO Auto-generated method stub
return new ArrayList<String>(0);
}
/* (non-Javadoc)
* @see cpw.mods.fml.common.ModContainer#getPostDepends()
*/
@Override
public List<String> getPostDepends()
{
// TODO Auto-generated method stub
return new ArrayList<String>(0);
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString()
{
return getSource().getName();
}
/* (non-Javadoc)
* @see cpw.mods.fml.common.ModContainer#getNetworkHandler()
*/
@Override
public INetworkHandler getNetworkHandler()
{
// TODO Auto-generated method stub
return null;
}
/* (non-Javadoc)
* @see cpw.mods.fml.common.ModContainer#ownsNetworkChannel(java.lang.String)
*/
@Override
public boolean ownsNetworkChannel(String channel)
{
// TODO Auto-generated method stub
return false;
}
/* (non-Javadoc)
* @see cpw.mods.fml.common.ModContainer#getConsoleHandler()
*/
@Override
public IConsoleHandler getConsoleHandler()
{
// TODO Auto-generated method stub
return null;
}
/* (non-Javadoc)
* @see cpw.mods.fml.common.ModContainer#getPlayerTracker()
*/
@Override
public IPlayerTracker getPlayerTracker()
{
// TODO Auto-generated method stub
return null;
}
/* (non-Javadoc)
* @see cpw.mods.fml.common.ModContainer#getKeys()
*/
@Override
public List<IKeyHandler> getKeys()
{
// TODO Auto-generated method stub
return null;
}
/* (non-Javadoc)
* @see cpw.mods.fml.common.ModContainer#getSourceType()
*/
@Override
public SourceType getSourceType()
{
// TODO Auto-generated method stub
return null;
}
/* (non-Javadoc)
* @see cpw.mods.fml.common.ModContainer#setSourceType(cpw.mods.fml.common.ModContainer.SourceType)
*/
@Override
public void setSourceType(SourceType type)
{
// TODO Auto-generated method stub
}
/* (non-Javadoc)
* @see cpw.mods.fml.common.ModContainer#getMetadata()
*/
@Override
public ModMetadata getMetadata()
{
return modMetadata;
}
/* (non-Javadoc)
* @see cpw.mods.fml.common.ModContainer#setMetadata(cpw.mods.fml.common.ModMetadata)
*/
@Override
public void setMetadata(ModMetadata meta)
{
this.modMetadata=meta;
}
/* (non-Javadoc)
* @see cpw.mods.fml.common.ModContainer#gatherRenderers(java.util.Map)
*/
@Override
public void gatherRenderers(Map renderers)
{
// TODO Auto-generated method stub
}
/* (non-Javadoc)
* @see cpw.mods.fml.common.ModContainer#requestAnimations()
*/
@Override
public void requestAnimations()
public void bindMetadata(MetadataCollection mc)
{
// TODO Auto-generated method stub
modMetadata = mc.getMetadataForId(getModId());
if (descriptor.containsKey("usesMetadata"))
{
overridesMetadata = !((Boolean)descriptor.get("usesMetadata")).booleanValue();
}
if (overridesMetadata || !modMetadata.useDependencyInformation)
{
List<String> requirements = Lists.newArrayList();
List<String> dependencies = Lists.newArrayList();
List<String> dependants = Lists.newArrayList();
Loader.instance().computeDependencies((String) descriptor.get("dependencies"), requirements, dependencies, dependants);
modMetadata.requiredMods = requirements;
modMetadata.dependencies = dependencies;
modMetadata.dependants = dependants;
}
}
}
/* (non-Javadoc)
* @see cpw.mods.fml.common.ModContainer#getVersion()
*/
@Override
public String getVersion()
public void setEnabledState(boolean enabled)
{
// TODO Auto-generated method stub
return null;
this.enabled = enabled;
}
/* (non-Javadoc)
* @see cpw.mods.fml.common.ModContainer#findSidedProxy()
*/
@Override
public List<String> getRequirements()
{
return modMetadata.requiredMods;
}
@Override
public List<String> getDependencies()
{
return modMetadata.dependencies;
}
@Override
public List<String> getDependants()
{
return modMetadata.dependants;
}
@Override
public String getSortingRules()
{
return modMetadata.printableSortingRules();
}
@Override
public boolean matches(Object mod)
{
return mod == modInstance;
}
@Override
public Object getMod()
{
return modInstance;
}
@Override
public ProxyInjector findSidedProxy()
{
// TODO Auto-generated method stub
return null;
}
/* (non-Javadoc)
* @see cpw.mods.fml.common.ModContainer#keyBindEvernt(java.lang.Object)
*/
@Override
public void keyBindEvent(Object keyBinding)
public boolean registerBus(EventBus bus, LoadController controller)
{
// TODO Auto-generated method stub
if (this.enabled)
{
this.eventBus = bus;
this.controller = controller;
eventBus.register(this);
return true;
}
else
{
return false;
}
}
@Subscribe
void constructMod(FMLConstructionEvent event)
{
try
{
ModClassLoader modClassLoader = event.getModClassLoader();
modClassLoader.addFile(source);
modInstance = Class.forName(className, true, modClassLoader).newInstance();
}
catch (Exception e)
{
controller.errorOccurred(this, e);
Throwables.propagateIfPossible(e);
}
}
}

View File

@ -1,77 +0,0 @@
/*
* The FML Forge Mod Loader suite.
* Copyright (C) 2012 cpw
*
* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package cpw.mods.fml.common;
import java.util.Arrays;
/**
* @author cpw
*
*/
public class FMLModLoaderContainer extends FMLModContainer
{
/**
* @param dummy
*/
public FMLModLoaderContainer()
{
super("Forge Mod Loader");
}
/* (non-Javadoc)
* @see cpw.mods.fml.common.FMLModContainer#getMetadata()
*/
@Override
public ModMetadata getMetadata()
{
if (super.getMetadata()==null) {
ModMetadata md=new ModMetadata(this);
setMetadata(md);
md.name="Forge Mod Loader";
md.version=Loader.instance().getFMLVersionString();
md.credits="Made possible with help from many people";
md.authorList=Arrays.asList("cpw, LexManos");
md.description="The Forge Mod Loader provides the ability for systems to load mods " +
"from the file system. It also provides key capabilities for mods to be able " +
"to cooperate and provide a good modding environment. " +
"The mod loading system is compatible with ModLoader, all your ModLoader " +
"mods should work.";
md.url="https://github.com/cpw/FML/wiki";
md.updateUrl="https://github.com/cpw/FML/wiki";
md.screenshots=new String[0];
md.logoFile="";
}
return super.getMetadata();
}
/* (non-Javadoc)
* @see cpw.mods.fml.common.FMLModContainer#getName()
*/
@Override
public String getName()
{
return "Forge Mod Loader";
}
/* (non-Javadoc)
* @see cpw.mods.fml.common.FMLModContainer#getVersion()
*/
@Override
public String getVersion()
{
return Loader.instance().getFMLVersionString();
}
}

View File

@ -1,16 +1,117 @@
package cpw.mods.fml.common;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.google.common.base.Joiner;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import cpw.mods.fml.common.LoaderState.ModState;
import cpw.mods.fml.common.event.FMLConstructionEvent;
import cpw.mods.fml.common.event.FMLStateEvent;
public class LoadController
{
private static LoadController instance;
@Subscribe
public void loadController(FMLStateEvent event)
private Loader loader;
private EventBus masterChannel;
private ImmutableMap<String,EventBus> eventChannels;
private LoaderState state;
private Multimap<String, ModState> modStates = HashMultimap.create();
private Multimap<ModContainer, Throwable> errors = HashMultimap.create();
private Logger log;
private Map<String, ModContainer> modList;
public LoadController(Loader loader)
{
this.loader = loader;
this.modList = loader.getIndexedModList();
this.masterChannel = new EventBus("FMLMainChannel");
this.masterChannel.register(this);
this.log = Loader.log;
Builder<String, EventBus> eventBus = ImmutableMap.builder();
for (ModContainer mod : Loader.getModList())
{
EventBus bus = new EventBus(mod.getModId());
boolean isActive = mod.registerBus(bus, this);
if (isActive)
{
modStates.put(mod.getModId(), ModState.UNLOADED);
eventBus.put(mod.getModId(), bus);
}
else
{
modStates.put(mod.getModId(), ModState.UNLOADED);
modStates.put(mod.getModId(), ModState.DISABLED);
}
}
eventChannels = eventBus.build();
state = LoaderState.CONSTRUCTING;
}
public void runNextPhase(Object... eventData)
{
if (state.hasEvent())
{
masterChannel.post(state.getEvent(eventData));
}
}
public void transition()
{
state = state.transition(!errors.isEmpty());
}
@Subscribe
void propogateStateMessage(FMLStateEvent stateEvent)
{
for (Map.Entry<String,EventBus> entry : eventChannels.entrySet())
{
entry.getValue().post(stateEvent);
if (errors.isEmpty())
{
modStates.put(entry.getKey(), stateEvent.getModState());
}
else
{
modStates.put(entry.getKey(), ModState.ERRORED);
}
}
}
public void errorOccurred(ModContainer modContainer, Throwable exception)
{
errors.put(modContainer, exception);
}
public void log(Level level, String message, Object... rest)
{
log.log(level, String.format(message,rest));
}
public void log(Level level, Throwable error, String message, Object... rest)
{
log.log(level, String.format(message,rest), error);
}
public void printModStates(StringBuilder ret)
{
for (String modId : modStates.keySet())
{
ModContainer mod = modList.get(modId);
ret.append("\n\t").append(mod.getName()).append(" (").append(mod.getSource().getName()).append(") ");
Joiner.on("->"). appendTo(ret, modStates.get(modId));
}
}
}

View File

@ -14,6 +14,8 @@
package cpw.mods.fml.common;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
@ -30,45 +32,69 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import cpw.mods.fml.common.ModContainer.SourceType;
import com.google.common.base.CharMatcher;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.base.Splitter.MapSplitter;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import cpw.mods.fml.common.discovery.ContainerType;
import cpw.mods.fml.common.discovery.ModDiscoverer;
import cpw.mods.fml.common.functions.ModIdFunction;
import cpw.mods.fml.common.toposort.ModSorter;
import cpw.mods.fml.common.toposort.ModSortingException;
import cpw.mods.fml.common.toposort.TopologicalSort;
/**
* The loader class performs the actual loading of the mod code from disk.
*
* <p>There are several {@link LoaderState}s to mod loading, triggered in two different stages from the FML handler code's hooks into the
* minecraft code.</p>
*
*
* <p>
* There are several {@link LoaderState}s to mod loading, triggered in two
* different stages from the FML handler code's hooks into the minecraft code.
* </p>
*
* <ol>
* <li>LOADING. Scanning the filesystem for mod containers to load (zips, jars, directories), adding them to the {@link #modClassLoader}
* Scanning, the loaded containers for mod classes to load and registering them appropriately.</li>
* <li>PREINIT. The mod classes are configured, they are sorted into a load order, and instances of the mods are constructed.</li>
* <li>INIT. The mod instances are initialized. For BaseMod mods, this involves calling the load method.</li>
* <li>POSTINIT. The mod instances are post initialized. For BaseMod mods this involves calling the modsLoaded method.</li>
* <li>LOADING. Scanning the filesystem for mod containers to load (zips, jars,
* directories), adding them to the {@link #modClassLoader} Scanning, the loaded
* containers for mod classes to load and registering them appropriately.</li>
* <li>PREINIT. The mod classes are configured, they are sorted into a load
* order, and instances of the mods are constructed.</li>
* <li>INIT. The mod instances are initialized. For BaseMod mods, this involves
* calling the load method.</li>
* <li>POSTINIT. The mod instances are post initialized. For BaseMod mods this
* involves calling the modsLoaded method.</li>
* <li>UP. The Loader is complete</li>
* <li>ERRORED. The loader encountered an error during the LOADING phase and dropped to this state instead. It will not complete
* loading from this state, but it attempts to continue loading before abandoning and giving a fatal error.</li>
* <li>ERRORED. The loader encountered an error during the LOADING phase and
* dropped to this state instead. It will not complete loading from this state,
* but it attempts to continue loading before abandoning and giving a fatal
* error.</li>
* </ol>
*
* Phase 1 code triggers the LOADING and PREINIT states. Phase 2 code triggers the INIT and POSTINIT states.
*
*
* Phase 1 code triggers the LOADING and PREINIT states. Phase 2 code triggers
* the INIT and POSTINIT states.
*
* @author cpw
*
*
*/
public class Loader
{
private static final Splitter DEPENDENCYPARTSPLITTER = Splitter.on(":").omitEmptyStrings().trimResults();
private static final Splitter DEPENDENCYSPLITTER = Splitter.on(";").omitEmptyStrings().trimResults();
/**
* The singleton instance
*/
private static Loader instance;
/**
* Our special logger for logging issues to. We copy various assets from the Minecraft logger to acheive a similar appearance.
* Our special logger for logging issues to. We copy various assets from the
* Minecraft logger to acheive a similar appearance.
*/
public static Logger log = Logger.getLogger("ForgeModLoader");
/**
* Build information for tracking purposes.
*/
@ -107,7 +133,8 @@ public class Loader
* The captured error
*/
private Exception capturedError;
private File canonicalModsDir;
private LoadController modController;
public static Loader instance()
{
@ -122,25 +149,32 @@ public class Loader
private Loader()
{
configureLogging();
InputStream stream = Loader.class.getClassLoader().getResourceAsStream("fmlversion.properties");
InputStream stream = getClass().getClassLoader().getResourceAsStream("fmlversion.properties");
Properties properties = new Properties();
if (stream != null) {
try {
if (stream != null)
{
try
{
properties.load(stream);
major = properties.getProperty("fmlbuild.major.number","none");
minor = properties.getProperty("fmlbuild.minor.number","none");
rev = properties.getProperty("fmlbuild.revision.number","none");
build = properties.getProperty("fmlbuild.build.number","none");
mccversion = properties.getProperty("fmlbuild.mcclientversion","none");
mcsversion = properties.getProperty("fmlbuild.mcserverversion","none");
} catch (IOException ex) {
Loader.log.log(Level.SEVERE,"Could not get FML version information - corrupted installation detected!", ex);
}
catch (IOException ex)
{
Loader.log.log(Level.SEVERE, "Could not get FML version information - corrupted installation detected!", ex);
throw new LoaderException(ex);
}
}
major = properties.getProperty("fmlbuild.major.number", "missing");
minor = properties.getProperty("fmlbuild.minor.number", "missing");
rev = properties.getProperty("fmlbuild.revision.number", "missing");
build = properties.getProperty("fmlbuild.build.number", "missing");
mccversion = properties.getProperty("fmlbuild.mcclientversion", "missing");
mcsversion = properties.getProperty("fmlbuild.mcserverversion", "missing");
log.info(String.format("Forge Mod Loader version %s.%s.%s.%s for Minecraft c:%s, s:%s loading", major, minor, rev, build, mccversion, mcsversion));
modClassLoader = new ModClassLoader(getClass().getClassLoader());
}
@ -149,11 +183,14 @@ public class Loader
*/
private static void configureLogging()
{
FMLLogFormatter formatter=new FMLLogFormatter();
if (FMLCommonHandler.instance().getMinecraftLogger()!=null) {
FMLLogFormatter formatter = new FMLLogFormatter();
if (FMLCommonHandler.instance().getMinecraftLogger() != null)
{
Loader.log.setParent(FMLCommonHandler.instance().getMinecraftLogger());
} else {
ConsoleHandler ch=new ConsoleHandler();
}
else
{
ConsoleHandler ch = new ConsoleHandler();
Loader.log.setUseParentHandlers(false);
Loader.log.addHandler(ch);
ch.setFormatter(formatter);
@ -162,9 +199,8 @@ public class Loader
Loader.log.setLevel(Level.ALL);
try
{
File logPath=new File(FMLCommonHandler.instance().getMinecraftRootDirectory().getCanonicalPath(),"ForgeModLoader-%g.log");
File logPath = new File(FMLCommonHandler.instance().getMinecraftRootDirectory().getCanonicalPath(), "ForgeModLoader-%g.log");
FileHandler fileHandler = new FileHandler(logPath.getPath(), 0, 3);
// We're stealing minecraft's log formatter
fileHandler.setFormatter(new FMLLogFormatter());
fileHandler.setLevel(Level.ALL);
Loader.log.addHandler(fileHandler);
@ -176,38 +212,39 @@ public class Loader
}
/**
* Sort the mods into a sorted list, using dependency information from the containers. The sorting is performed
* using a {@link TopologicalSort} based on the pre- and post- dependency information provided by the mods.
* Sort the mods into a sorted list, using dependency information from the
* containers. The sorting is performed using a {@link TopologicalSort}
* based on the pre- and post- dependency information provided by the mods.
*/
private void sortModList()
{
log.fine("Verifying mod dependencies are satisfied");
log.fine("Verifying mod requirements are satisfied");
try
{
for (ModContainer mod : mods)
{
if (!namedMods.keySet().containsAll(mod.getDependencies()))
if (!namedMods.keySet().containsAll(mod.getRequirements()))
{
log.severe(String.format("The mod %s requires mods %s to be available, one or more are not", mod.getName(), mod.getDependencies()));
LoaderException le = new LoaderException();
log.throwing("Loader", "sortModList", le);
log.log(Level.SEVERE, String.format("The mod %s (%s) requires mods %s to be available, one or more are not", mod.getModId(), mod.getName(), mod.getRequirements()));
throw new LoaderException();
}
}
log.fine("All dependencies are satisfied");
log.fine("All mod requirements are satisfied");
ModSorter sorter = new ModSorter(mods, namedMods);
try
{
log.fine("Sorting mods into an ordered list");
mods = sorter.sort();
log.fine("Mod sorting completed successfully");
}
catch (ModSortingException sortException)
{
log.severe("A dependency cycle was detected in the input mod set so an ordering cannot be determined");
log.severe(String.format("The visited mod list is %s",sortException.getExceptionData().getVisitedNodes()));
log.severe(String.format("The first mod in the cycle is %s",sortException.getExceptionData().getFirstBadNode()));
log.severe(String.format("The visited mod list is %s", sortException.getExceptionData().getVisitedNodes()));
log.severe(String.format("The first mod in the cycle is %s", sortException.getExceptionData().getFirstBadNode()));
log.throwing("Loader", "sortModList", sortException);
throw new LoaderException(sortException);
}
@ -217,98 +254,52 @@ public class Loader
log.fine("Mod sorting data:");
for (ModContainer mod : mods)
{
log.fine(String.format("\t%s: %s (%s)", mod.getName(), mod.getSource().getName(), mod.getSortingRules()));
log.fine(String.format("\t%s(%s): %s (%s)", mod.getModId(), mod.getName(), mod.getSource().getName(), mod.getSortingRules()));
}
}
}
/**
* The first mod initialization stage, performed immediately after the jar files and mod classes are loaded,
* {@link LoaderState#PREINIT}. The mods are configured from their configuration data and instantiated (for BaseMod mods).
*/
private void preModInit()
{
state = state.transition(false);
log.fine("Beginning mod pre-initialization");
for (ModContainer mod : mods)
{
log.finer(String.format("Pre-initializing %s", mod.getSource()));
try
{
mod.preInit();
}
catch (Throwable t)
{
log.log(Level.SEVERE, String.format("The mod from file %s has failed to load. This is likely a mod installation error.", mod.getSource().getName()), t);
throw new LoaderException(t);
}
namedMods.put(mod.getName(), mod);
mod.nextState();
}
// Link up mod metadatas
for (ModContainer mod : mods) {
if (mod.getMetadata()!=null) {
mod.getMetadata().associate(namedMods);
}
FMLCommonHandler.instance().injectSidedProxyDelegate(mod);
}
log.fine("Mod pre-initialization complete");
}
/**
* The main mod initialization stage, performed on the sorted mod list.
*/
private void modInit()
{
state = LoaderState.INIT;
log.fine("Beginning mod initialization");
for (ModContainer mod : mods)
{
log.finer(String.format("Initializing %s", mod.getName()));
mod.init();
mod.nextState();
}
log.fine("Mod initialization complete");
}
private void postModInit()
{
state = LoaderState.POSTINIT;
log.fine("Beginning mod post-initialization");
for (ModContainer mod : mods)
{
log.finer(String.format("Post-initializing %s", mod.getName()));
mod.postInit();
mod.nextState();
}
log.fine("Mod post-initialization complete");
}
/**
* The primary loading code
*
* This is visited during first initialization by Minecraft to scan and load the mods
* from all sources
* 1. The minecraft jar itself (for loading of in jar mods- I would like to remove this if possible but forge depends on it at present)
* 2. The mods directory with expanded subdirs, searching for mods named mod_*.class
* 3. The mods directory for zip and jar files, searching for mod classes named mod_*.class again
*
* The found resources are first loaded into the {@link #modClassLoader} (always) then scanned for class resources matching the specification above.
*
* If they provide the {@link Mod} annotation, they will be loaded as "FML mods", which currently is effectively a NO-OP.
* If they are determined to be {@link BaseMod} subclasses they are loaded as such.
*
* Finally, if they are successfully loaded as classes, they are then added to the available mod list.
*
* This is visited during first initialization by Minecraft to scan and load
* the mods from all sources 1. The minecraft jar itself (for loading of in
* jar mods- I would like to remove this if possible but forge depends on it
* at present) 2. The mods directory with expanded subdirs, searching for
* mods named mod_*.class 3. The mods directory for zip and jar files,
* searching for mod classes named mod_*.class again
*
* The found resources are first loaded into the {@link #modClassLoader}
* (always) then scanned for class resources matching the specification
* above.
*
* If they provide the {@link Mod} annotation, they will be loaded as
* "FML mods", which currently is effectively a NO-OP. If they are
* determined to be {@link BaseMod} subclasses they are loaded as such.
*
* Finally, if they are successfully loaded as classes, they are then added
* to the available mod list.
*/
private void load()
private void identifyMods()
{
ModDiscoverer discoverer = new ModDiscoverer();
log.fine("Attempting to load mods contained in the minecraft jar file and associated classes");
discoverer.findClasspathMods(modClassLoader);
log.fine("Minecraft jar mods loaded successfully");
log.info(String.format("Searching %s for mods", canonicalModsDir.getAbsolutePath()));
discoverer.findModDirMods(canonicalModsDir);
mods = discoverer.identifyMods();
namedMods = Maps.uniqueIndex(mods, new ModIdFunction());
log.info(String.format("Forge Mod Loader has identified %d mod%s to load", mods.size(), mods.size() != 0 ? "s" : ""));
}
/**
* @return
*/
private void initializeLoader()
{
File minecraftDir = FMLCommonHandler.instance().getMinecraftRootDirectory();
File modsDir = new File(minecraftDir, "mods");
@ -322,222 +313,129 @@ public class Loader
canonicalModsPath = modsDir.getCanonicalPath();
canonicalConfigPath = configDir.getCanonicalPath();
canonicalConfigDir = configDir.getCanonicalFile();
canonicalModsDir = modsDir.getCanonicalFile();
}
catch (IOException ioe)
{
log.severe(String.format("Failed to resolve mods directory mods %s", modsDir.getAbsolutePath()));
log.throwing("fml.server.Loader", "initialize", ioe);
log.log(Level.SEVERE,
String.format("Failed to resolve loader directories: mods : %s ; config %s", canonicalModsDir.getAbsolutePath(),
configDir.getAbsolutePath()), ioe);
throw new LoaderException(ioe);
}
if (!modsDir.exists())
if (!canonicalModsDir.exists())
{
log.fine(String.format("No mod directory found, creating one: %s", canonicalModsPath));
try
log.log(Level.INFO, String.format("No mod directory found, creating one: %s", canonicalModsPath));
boolean dirMade = canonicalModsDir.mkdir();
if (!dirMade)
{
modsDir.mkdir();
}
catch (Exception e)
{
log.throwing("fml.server.Loader", "initialize", e);
throw new LoaderException(e);
log.log(Level.SEVERE, String.format("Unable to create the mod directory %s", canonicalModsPath));
throw new LoaderException();
}
log.log(Level.INFO, "Mod directory created successfully");
}
if (!configDir.exists())
if (!canonicalConfigDir.exists())
{
log.fine(String.format("No config directory found, creating one: %s", canonicalConfigPath));
try
boolean dirMade = canonicalConfigDir.mkdir();
if (!dirMade)
{
configDir.mkdir();
}
catch (Exception e)
{
log.throwing("fml.server.Loader", "initialize", e);
throw new LoaderException(e);
log.log(Level.SEVERE, String.format("Unable to create the config directory %s", canonicalConfigPath));
throw new LoaderException();
}
log.log(Level.INFO, "Config directory created successfully");
}
if (!modsDir.isDirectory())
if (!canonicalModsDir.isDirectory())
{
log.severe(String.format("Attempting to load mods from %s, which is not a directory", canonicalModsPath));
LoaderException loaderException = new LoaderException();
log.throwing("fml.server.Loader", "initialize", loaderException);
throw loaderException;
log.log(Level.SEVERE, String.format("Attempting to load mods from %s, which is not a directory", canonicalModsPath));
throw new LoaderException();
}
if (!configDir.isDirectory())
{
log.severe(String.format("Attempting to load configuration from %s, which is not a directory", canonicalConfigPath));
LoaderException loaderException = new LoaderException();
log.throwing("fml.server.Loader", "initialize", loaderException);
throw loaderException;
}
state = LoaderState.LOADING;
log.fine("Attempting to load mods contained in the minecraft jar file and associated classes");
File[] minecraftSources=modClassLoader.getParentSources();
if (minecraftSources.length==1 && minecraftSources[0].isFile()) {
log.fine(String.format("Minecraft is a file at %s, loading",minecraftSources[0].getAbsolutePath()));
attemptFileLoad(minecraftSources[0], SourceType.CLASSPATH);
} else {
for (int i=0; i<minecraftSources.length; i++) {
if (minecraftSources[i].isFile()) {
log.fine(String.format("Found a minecraft related file at %s, loading",minecraftSources[i].getAbsolutePath()));
attemptFileLoad(minecraftSources[i], SourceType.CLASSPATH);
} else if (minecraftSources[i].isDirectory()) {
log.fine(String.format("Found a minecraft related directory at %s, loading",minecraftSources[i].getAbsolutePath()));
attemptDirLoad(minecraftSources[i],"",SourceType.CLASSPATH);
}
}
}
log.fine("Minecraft jar mods loaded successfully");
log.info(String.format("Loading mods from %s", canonicalModsPath));
File[] modList = modsDir.listFiles();
// Sort the files into alphabetical order first
Arrays.sort(modList);
for (File modFile : modList)
{
if (modFile.isDirectory())
{
log.fine(String.format("Found a directory %s, attempting to load it", modFile.getName()));
boolean modFound = attemptDirLoad(modFile,"", SourceType.DIR);
if (modFound)
{
log.fine(String.format("Directory %s loaded successfully", modFile.getName()));
}
else
{
log.info(String.format("Directory %s contained no mods", modFile.getName()));
}
}
else
{
Matcher matcher = ModDiscoverer.zipJar.matcher(modFile.getName());
if (matcher.matches())
{
log.fine(String.format("Found a zip or jar file %s, attempting to load it", matcher.group(0)));
boolean modFound = attemptFileLoad(modFile, SourceType.JAR);
if (modFound)
{
log.fine(String.format("File %s loaded successfully", matcher.group(0)));
}
else
{
log.info(String.format("File %s contained no mods", matcher.group(0)));
}
}
}
}
if (state == LoaderState.ERRORED)
{
log.severe("A problem has occured during mod loading. Likely a corrupt jar is located in your mods directory");
throw new LoaderException(capturedError);
}
log.info(String.format("Forge Mod Loader has identified %d mod%s to load", mods.size(), mods.size()!=0 ? "s": ""));
}
private void loadModClass(File classSource, String classFileName, String clazzName, SourceType sourceType)
{
try
{
ModHandler handler = modClassLoader.obtainClassHandlerFor(clazzName);
Class<?> clazz = Class.forName(clazzName, false, modClassLoader);
ModContainer mod=null;
if (clazz.isAnnotationPresent(Mod.class))
{
// an FML mod
log.severe("Currently, the FML mod type is disabled");
throw new LoaderException();
// log.fine(String.format("FML mod class %s found, loading", clazzName));
// mod = FMLModContainer.buildFor(clazz);
// log.fine(String.format("FML mod class %s loaded", clazzName));
}
else if (FMLCommonHandler.instance().isModLoaderMod(clazz))
{
log.fine(String.format("ModLoader BaseMod class %s found, loading", clazzName));
mod = FMLCommonHandler.instance().loadBaseModMod(clazz, classSource.getCanonicalFile());
log.fine(String.format("ModLoader BaseMod class %s loaded", clazzName));
}
else
{
// Unrecognized
}
if (mod!=null) {
mod.setSourceType(sourceType);
FMLCommonHandler.instance().loadMetadataFor(mod);
mods.add(mod);
mod.nextState();
}
}
catch (Throwable e)
{
log.warning(String.format("Failed to load mod class %s in %s", classFileName, classSource.getAbsoluteFile()));
log.throwing("fml.server.Loader", "attemptLoad", e);
throw new LoaderException(e);
}
}
private void extendClassLoader(File file)
{
try
{
modClassLoader.addFile(file);
}
catch (MalformedURLException e)
{
throw new LoaderException(e);
log.log(Level.SEVERE, String.format("Attempting to load configuration from %s, which is not a directory", canonicalConfigPath));
throw new LoaderException();
}
}
public static List<ModContainer> getModList()
{
return instance().mods;
return ImmutableList.copyOf(instance().mods);
}
/**
* Called from the hook to start mod loading. We trigger the {@link #load()} and {@link #preModInit()} phases here.
* Finally, the mod list is frozen completely and is consider immutable from then on.
* Called from the hook to start mod loading. We trigger the
* {@link #identifyMods()} and {@link #preModInit()} phases here. Finally,
* the mod list is frozen completely and is consider immutable from then on.
*/
public void loadMods()
{
initializeLoader();
state = LoaderState.NOINIT;
mods = new ArrayList<ModContainer>();
namedMods = new HashMap<String, ModContainer>();
load();
preModInit();
state = LoaderState.LOADING;
identifyMods();
disableRequestedMods();
sortModList();
// Make mod list immutable
mods = Collections.unmodifiableList(mods);
mods = ImmutableList.copyOf(mods);
modController = new LoadController(this);
modController.runNextPhase(modClassLoader);
}
/**
* Complete the initialization of the mods {@link #initializeMods()} and {@link #postModInit()} and mark ourselves up and ready to run.
*/
public void initializeMods()
private void disableRequestedMods()
{
modInit();
postModInit();
for (ModContainer mod : getModList()) {
mod.nextState();
String disabledModList = System.getProperty("fml.disabledMods", "");
log.log(Level.FINE, String.format("Received a system property request \'%s\'",disabledModList));
Map<String, String> sysPropertyStateList = Splitter.on(CharMatcher.anyOf(";:"))
.omitEmptyStrings().trimResults().withKeyValueSeparator("=")
.split(disabledModList);
log.log(Level.FINE, String.format("System property request managing the state of %d mods", sysPropertyStateList.size()));
Map<String, String> modStates = Maps.newHashMap();
File disabledModFile = new File(canonicalConfigDir, "fmlModState.properties");
Properties disabledModListProperties = new Properties();
if (disabledModFile.exists() && disabledModFile.isFile())
{
log.log(Level.FINE, String.format("Found a mod state file %s", disabledModFile.getName()));
try
{
disabledModListProperties.load(new FileReader(disabledModFile));
log.log(Level.FINE, String.format("Loaded states for %d mods from file", disabledModListProperties.size()));
}
catch (Exception e)
{
log.log(Level.INFO, "An error occurred reading the fmlModState.properties file", e);
}
log.log(Level.FINE, String.format("Found a mod state file %s", disabledModFile.getName()));
}
modStates.putAll(Maps.fromProperties(disabledModListProperties));
modStates.putAll(sysPropertyStateList);
log.log(Level.FINE, String.format("After merging, found state information for %d mods", modStates.size()));
Map<String, Boolean> isEnabled = Maps.transformValues(modStates, new Function<String, Boolean>()
{
public Boolean apply(String input)
{
return !Boolean.parseBoolean(input);
}
});
for (Map.Entry<String, Boolean> entry : isEnabled.entrySet())
{
if (namedMods.containsKey(entry.getKey()))
{
log.log(Level.INFO, String.format("Setting mod %s to enabled state %b", entry.getKey(), entry.getValue()));
namedMods.get(entry.getKey()).setEnabledState(entry.getValue());
}
}
state = LoaderState.UP;
log.info(String.format("Forge Mod Loader load complete, %d mods loaded", mods.size()));
}
/**
* Query if we know of a mod named modname
*
*
* @param modname
* @return
*/
@ -556,14 +454,9 @@ public class Loader
public String getCrashInformation()
{
StringBuffer ret = new StringBuffer();
for (String brand : FMLCommonHandler.instance().getBrandingStrings(String.format("Forge Mod Loader version %s.%s.%s.%s for Minecraft %s", major, minor, rev, build, mccversion))) {
ret.append(brand).append("\n");
}
for (ModContainer mod : mods)
{
ret.append(String.format("\t%s : %s (%s)\n",mod.getName(), mod.getModState(), mod.getSource().getName()));
}
StringBuilder ret = new StringBuilder();
Joiner.on('\n').appendTo(ret, FMLCommonHandler.instance().getBrandingStrings(getFMLVersionString()));
modController.printModStates(ret);
return ret.toString();
}
@ -582,4 +475,68 @@ public class Loader
{
return modClassLoader;
}
public void computeDependencies(String dependencyString, List<String> requirements, List<String> dependencies, List<String> dependants)
{
if (dependencyString == null || dependencyString.length() == 0)
{
return;
}
boolean parseFailure=false;
for (String dep : DEPENDENCYSPLITTER.split(dependencyString))
{
List<String> depparts = Lists.newArrayList(DEPENDENCYPARTSPLITTER.split(dep));
String instruction = depparts.get(0);
String target = depparts.get(1);
boolean targetIsAll = target.equals("*");
// If we don't have two parts to each substring, this is an invalid dependency string
if (depparts.size() != 2)
{
parseFailure=true;
continue;
}
// If this is a required element, add it to the required list
if ("required-before".equals(instruction) || "required-after".equals(instruction))
{
// You can't require everything
if (!targetIsAll)
{
requirements.add(target);
}
else
{
parseFailure=true;
continue;
}
}
// before elements are things we are loaded before (so they are our dependants)
if ("required-before".equals(instruction) || "before".equals(instruction))
{
dependants.add(target);
}
// after elements are things that load before we do (so they are out dependencies)
else if ("required-after".equals(instruction) || "after".equals(instruction))
{
dependencies.add(target);
}
else
{
parseFailure=true;
}
}
if (parseFailure)
{
throw new LoaderException();
}
}
public Map<String,ModContainer> getIndexedModList()
{
return ImmutableMap.copyOf(namedMods);
}
}

View File

@ -1,5 +1,8 @@
package cpw.mods.fml.common;
import com.google.common.base.Throwables;
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;
@ -14,7 +17,7 @@ public enum LoaderState
{
NOINIT("Uninitialized",null),
LOADING("Loading",null),
CONSTRUCTING("Constructing mods",null),
CONSTRUCTING("Constructing mods",FMLConstructionEvent.class),
PREINITIALIZATION("Pre-initializing mods", FMLPreInitializationEvent.class),
INITIALIZATION("Initializing mods", FMLInitializationEvent.class),
POSTINITIALIZATION("Post-initializing mods", FMLPostInitializationEvent.class),
@ -39,6 +42,22 @@ public enum LoaderState
return values()[ordinal() < values().length ? ordinal()+1 : ordinal()];
}
public boolean hasEvent()
{
return eventClass != null;
}
public FMLStateEvent getEvent(Object... eventData)
{
try
{
return eventClass.getConstructor(Object[].class).newInstance(eventData);
}
catch (Exception e)
{
throw Throwables.propagate(e);
}
}
public enum ModState
{
UNLOADED("Unloaded"),
@ -47,7 +66,10 @@ public enum LoaderState
PREINITIALIZED("Pre-initialized"),
INITIALIZED("Initialized"),
POSTINITIALIZED("Post-initialized"),
AVAILABLE("Available");
AVAILABLE("Available"),
DISABLED("Disabled"),
ERRORED("Errored");
private String label;
private ModState(String label)

View File

@ -0,0 +1,77 @@
package cpw.mods.fml.common;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import argo.jdom.JdomParser;
import argo.jdom.JsonNode;
import argo.jdom.JsonRootNode;
import argo.saj.InvalidSyntaxException;
import com.google.common.base.Throwables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
public class MetadataCollection
{
private static Logger log = Loader.log;
private static JdomParser parser = new JdomParser();
private Map<String, ModMetadata> metadatas = Maps.newHashMap();
private int metadataVersion = 1;
public static MetadataCollection from(InputStream inputStream)
{
InputStreamReader reader = new InputStreamReader(inputStream);
try
{
JsonRootNode root = parser.parse(reader);
if (root.hasElements())
{
return parse10ModInfo(root);
}
else
{
return parseModInfo(root);
}
}
catch (Exception e)
{
throw Throwables.propagate(e);
}
}
private static MetadataCollection parseModInfo(JsonRootNode root)
{
MetadataCollection mc = new MetadataCollection();
mc.metadataVersion = Integer.parseInt(root.getNumberValue("modinfoversion"));
mc.parseModMetadataList(root.getNode("modlist"));
return mc;
}
private static MetadataCollection parse10ModInfo(JsonRootNode root)
{
MetadataCollection mc = new MetadataCollection();
mc.parseModMetadataList(root);
return mc;
}
private void parseModMetadataList(JsonNode metadataList)
{
for (JsonNode node : metadataList.getElements())
{
ModMetadata mmd = new ModMetadata(node);
metadatas.put(mmd.modId, mmd);
}
}
public ModMetadata getMetadataForId(String modId)
{
return metadatas.get(modId);
}
}

View File

@ -44,10 +44,10 @@ public @interface Mod
*/
String version() default "";
/**
* A simple dependency string for this mod
* A simple dependency string for this mod (see modloader's "priorities" string specification)
* @return
*/
String dependsOn() default "";
String dependencies() default "";
/**
* Whether to use the mcmod.info metadata by default for this mod.
* If true, settings in the mcmod.info file will override settings in these annotations.

View File

@ -15,9 +15,8 @@ package cpw.mods.fml.common;
import java.io.File;
import java.util.List;
import java.util.Map;
import cpw.mods.fml.common.ModContainer.SourceType;
import com.google.common.eventbus.EventBus;
/**
* The container that wraps around mods in the system.
@ -27,183 +26,121 @@ import cpw.mods.fml.common.ModContainer.SourceType;
* a mechanism by which we can wrap actual mod code so that the loader and other
* facilities can treat mods at arms length.
* </p>
*
*
* @author cpw
*
*
*/
public interface ModContainer
{
public enum SourceType
{
JAR, CLASSPATH, DIR;
}
/**
* Called when pre-initialization occurs.
*/
void preInit();
/**
* Called when main initialization occurs.
*/
void init();
/**
* Called when post-initialization occurs.
*/
void postInit();
/**
* The name of the mod
*
* The globally unique modid for this mod
*
* @return
*/
String getModId();
/**
* A human readable name
*
* @return
*/
String getName();
/**
* The state of the mod
*
* A human readable version identifier
*
* @return
*/
LoaderState.ModState getModState();
String getVersion();
/**
* Move to the next mod state
* The location on the file system which this mod came from
*
* @return
*/
void nextState();
File getSource();
/**
* Does this mod match the supplied mod?
*
* The metadata for this mod
*
* @return
*/
ModMetadata getMetadata();
/**
* Attach this mod to it's metadata from the supplied metadata collection
*
* @param mc
*/
void bindMetadata(MetadataCollection mc);
/**
* Set the enabled/disabled state of this mod
*
* @param enabled
*/
void setEnabledState(boolean enabled);
/**
* A list of the modids that this mod requires loaded prior to loading
*
* @return
*/
List<String> getRequirements();
/**
* A list of modids that should be loaded prior to this one. The special
* value <strong>*</strong> indicates to load <em>before</em> any other mod.
*
* @return
*/
List<String> getDependencies();
/**
* A list of modids that should be loaded <em>after</em> this one. The
* special value <strong>*</strong> indicates to load <em>after</em> any
* other mod.
*
* @return
*/
List<String> getDependants();
/**
* A representative string encapsulating the sorting preferences for this
* mod
*
* @return
*/
String getSortingRules();
/**
* Register the event bus for the mod and the controller for error handling
* Returns if this bus was successfully registered - disabled mods and other
* mods that don't need real events should return false and avoid further
* processing
*
* @param bus
* @param controller
* @return
*/
boolean registerBus(EventBus bus, LoadController controller);
/**
* Does this mod match the supplied mod
*
* @param mod
* @return
*/
boolean matches(Object mod);
/**
* The source of this mod: the file on the file system
*
* @return
*/
File getSource();
/**
* Returns the sorting rules as a string for printing
*
* @return
*/
String getSortingRules();
/**
* The actual mod object itself
*
* Get the actual mod object
*
* @return
*/
Object getMod();
/**
* Lookup the fuel value for the supplied item/damage with this mod.
*
* @param itemId
* @param itemDamage
* @return
*/
int lookupFuelValue(int itemId, int itemDamage);
/**
* The pickup notifier for this mod.
*
* @return
*/
IPickupNotifier getPickupNotifier();
/**
* The dispensing handler.
*
* @return
*/
IDispenseHandler getDispenseHandler();
/**
* The crafting and smelting handler for this mod.
*
* @return
*/
ICraftingHandler getCraftingHandler();
/**
* The strong dependencies of this mod. If the named mods in this list are
* not present, the game will abort.
*
* @return
*/
List<String> getDependencies();
/**
* Get a list of mods to load before this one. The special value "*"
* indicates to load <i>after</i> all other mods (except other "*" mods).
*
* @return
*/
List<String> getPreDepends();
/**
* Get a list of mods to load after this one. The special value "*"
* indicates to load <i>before</i> all other mods (except other "*" mods).
*
* @return
*/
List<String> getPostDepends();
/**
* The network handler for this mod.
*
* @return
*/
INetworkHandler getNetworkHandler();
/**
* Does this mod own this channel?
*
* @param channel
* @return
*/
boolean ownsNetworkChannel(String channel);
IConsoleHandler getConsoleHandler();
IPlayerTracker getPlayerTracker();
List<IKeyHandler> getKeys();
SourceType getSourceType();
void setSourceType(SourceType type);
ModMetadata getMetadata();
void setMetadata(ModMetadata meta);
/**
*
*/
void gatherRenderers(Map renderers);
/**
*
*/
void requestAnimations();
/**
* @return
*/
String getVersion();
/**
* @return
*/
ProxyInjector findSidedProxy();
void keyBindEvent(Object keyBinding);
}

View File

@ -0,0 +1,34 @@
package cpw.mods.fml.common;
import java.io.File;
import org.objectweb.asm.Type;
import cpw.mods.fml.common.discovery.asm.ASMModParser;
import cpw.mods.fml.common.discovery.asm.ModAnnotation;
import cpw.mods.fml.common.modloader.ModLoaderModContainer;
public class ModContainerFactory
{
private static ModContainerFactory INSTANCE = new ModContainerFactory();
public static ModContainerFactory instance() {
return INSTANCE;
}
public ModContainer build(ASMModParser modParser, File modSource)
{
if (modParser.getASMSuperType().equals(Type.getType("BaseMod")))
{
return new ModLoaderModContainer(modParser.getASMType().getClassName(), modSource);
}
for (ModAnnotation ann : modParser.getAnnotations())
{
if (ann.getASMType().equals(Type.getType(Mod.class)))
{
return new FMLModContainer(modParser.getASMType().getClassName(), modSource, ann.getValues());
}
}
return null;
}
}

View File

@ -1,220 +0,0 @@
package cpw.mods.fml.common;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.nio.channels.FileChannel;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Opcodes;
import com.google.common.collect.Lists;
import cpw.mods.fml.common.ModContainer.SourceType;
public class ModDiscoverer
{
private class ClassFilter implements FileFilter
{
@Override
public boolean accept(File file)
{
return (file.isFile() && modClass.matcher(file.getName()).find()) || file.isDirectory();
}
}
private class ModCandidate
{
private File classPathRoot;
private File modContainer;
private String className;
private SourceType sourceType;
public ModCandidate(File classPathRoot, File modContainer, String className, SourceType sourceType)
{
this.classPathRoot = classPathRoot;
this.modContainer = modContainer;
this.className = className;
this.sourceType = sourceType;
}
}
private Logger log;
private File modsDir;
private static Pattern zipJar = Pattern.compile("(.+).(zip|jar)$");
private static Pattern classFile = Pattern.compile("([^\\s$]+).class$");
private static Pattern modClass = Pattern.compile("(.+/|)(mod\\_[^\\s$]+).class$");
private List<ModCandidate> candidates = Lists.newArrayList();
private void attemptDirLoad(File modDir, String path, SourceType sourceType, File dirRoot)
{
if (path.length() == 0)
{
dirRoot = modDir;
}
boolean foundAModClass = false;
File[] content = modDir.listFiles(new ClassFilter());
// Always sort our content
Arrays.sort(content);
for (File file : content)
{
if (file.isDirectory())
{
log.finest(String.format("Recursing into package %s", path + file.getName()));
attemptDirLoad(file, path + file.getName() + ".", sourceType, dirRoot);
continue;
}
Matcher fname = modClass.matcher(file.getName());
if (!fname.find())
{
continue;
}
String clazzName = path + fname.group(2);
log.fine(String.format("Candidate mod %s found in directory %s", clazzName, dirRoot.getName()));
candidates.add(new ModCandidate(dirRoot, dirRoot, clazzName, sourceType));
foundAModClass = true;
}
}
private void attemptFileLoad(File modFile, SourceType sourceType)
{
ZipFile jar = null;
try
{
jar = new ZipFile(modFile);
ZipEntry modInfo = jar.getEntry("mcmod.info");
if (modInfo != null)
{
}
for (ZipEntry ze : Collections.list(jar.entries()))
{
Matcher match = classFile.matcher(ze.getName());
if (match.matches())
{
AnnotationFinder finder = new AnnotationFinder(jar.getInputStream(ze));
}
match = modClass.matcher(ze.getName());
if (match.matches())
{
String pkg = match.group(1).replace('/', '.');
String clazzName = pkg + match.group(2);
log.fine(String.format("Candidate mod %s found in mod file %s", clazzName, modFile.getName()));
candidates.add(new ModCandidate(modFile, modFile, clazzName, sourceType));
}
}
}
catch (Exception e)
{
log.warning(String.format("Zip file %s failed to read properly, it will be ignored", modFile.getName()));
}
finally
{
if (jar != null)
{
try
{
jar.close();
}
catch (Exception e)
{
}
}
}
}
public static class AnnotationFinder extends ClassVisitor
{
public AnnotationFinder(InputStream stream) throws IOException
{
super(Opcodes.ASM4);
ClassReader reader = new ClassReader(stream);
reader.accept(this, ClassReader.SKIP_CODE);
}
@Override
public void visit(int arg0, int arg1, String arg2, String arg3, String arg4, String[] arg5)
{
System.out.printf("ClassVisit.visit %d %d %s %s %s %s\n", arg0, arg1, arg2, arg3, arg4, Arrays.asList(arg5));
super.visit(arg0, arg1, arg2, arg3, arg4, arg5);
}
@Override
public void visitOuterClass(String arg0, String arg1, String arg2)
{
System.out.printf("ClassVisit.visitOuterClass %s %s %s\n", arg0, arg1, arg2);
super.visitOuterClass(arg0, arg1, arg2);
}
@Override
public void visitAttribute(Attribute arg0)
{
System.out.printf("ClassVisit.visitAttribute %s\n", arg0);
super.visitAttribute(arg0);
}
@Override
public FieldVisitor visitField(int arg0, String arg1, String arg2, String arg3, Object arg4)
{
System.out.printf("ClassVisit.visitField %d %s %s %s %s\n", arg0, arg1, arg2, arg3, arg4);
return new FieldVisitor(Opcodes.ASM4)
{
@Override
public AnnotationVisitor visitAnnotation(String arg0, boolean arg1)
{
System.out.printf("FieldVisitor.visit %s %s\n", arg0, arg1);
return new AnnotationVisitor(Opcodes.ASM4)
{
@Override
public void visit(String arg0, Object arg1)
{
System.out.printf("FieldAnnotationVisitor.visit %s %s\n", arg0, arg1);
super.visit(arg0, arg1);
}
};
}
};
}
@Override
public AnnotationVisitor visitAnnotation(String arg0, boolean arg1)
{
System.out.printf("ClassVisit.visitAnnotation %s %b\n", arg0, arg1);
return new AnnotationVisitor(Opcodes.ASM4)
{
@Override
public void visit(String arg0, Object arg1)
{
System.out.printf("ClassAnnotationVisitor.visit %s %s\n", arg0, arg1);
super.visit(arg0, arg1);
}
};
}
}
}

View File

@ -20,53 +20,101 @@ import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.zip.ZipInputStream;
import argo.jdom.JsonNode;
import argo.jdom.JsonStringNode;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Objects;
import com.google.common.base.Optional;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import cpw.mods.fml.common.functions.ModNameFunction;
import cpw.mods.fml.common.modloader.ModLoaderModContainer;
import static argo.jdom.JsonNodeBuilders.*;
/**
* @author cpw
*
*
*/
public class ModMetadata
{
public enum ModType { MODLOADER, FML };
public ModContainer mod;
public ModType type;
private static final class JsonStringConverter implements Function<JsonNode, Object>
{
public Object apply(JsonNode arg0)
{
if (arg0.hasElements())
{
return Lists.transform(arg0.getElements(), new JsonArrayConverter());
}
else
{
return arg0.getText();
}
}
}
private static final class JsonArrayConverter implements Function<JsonNode, String>
{
public String apply(JsonNode arg0)
{
return arg0.getText();
}
}
public String modId;
public String name;
public String description;
public String url="";
public String updateUrl="";
public String logoFile="";
public String version="";
public List<String> authorList=new ArrayList<String>(1);
public String credits="";
public String parent="";
public String url = "";
public String updateUrl = "";
public String logoFile = "";
public String version = "";
public List<String> authorList = Lists.newArrayList();
public String credits = "";
public String parent = "";
public String[] screenshots;
public ModContainer parentMod;
public List<ModContainer> childMods = new ArrayList<ModContainer>(1);
public List<ModContainer> childMods = Lists.newArrayList();
public boolean useDependencyInformation;
public List<String> requiredMods = Lists.newArrayList();
public List<String> dependencies = Lists.newArrayList();
public List<String> dependants = Lists.newArrayList();
/**
* @param mod2
* @param type2
*/
public ModMetadata(ModContainer mod)
public ModMetadata(JsonNode node)
{
this.mod=mod;
this.type=(mod instanceof FMLModContainer ? ModType.FML : ModType.MODLOADER);
Map<JsonStringNode, Object> processedFields = Maps.transformValues(node.getFields(), new JsonStringConverter());
modId = (String)processedFields.get(aStringBuilder("modid"));
name = Strings.nullToEmpty((String)processedFields.get(aStringBuilder("name")));
description = Strings.nullToEmpty((String)processedFields.get(aStringBuilder("description")));
url = Strings.nullToEmpty((String)processedFields.get(aStringBuilder("url")));
updateUrl = Strings.nullToEmpty((String)processedFields.get(aStringBuilder("updateUrl")));
logoFile = Strings.nullToEmpty((String)processedFields.get(aStringBuilder("logoFile")));
version = Strings.nullToEmpty((String)processedFields.get(aStringBuilder("version")));
credits = Strings.nullToEmpty((String)processedFields.get(aStringBuilder("credits")));
parent = Strings.nullToEmpty((String)processedFields.get(aStringBuilder("parent")));
authorList = Optional.fromNullable((List<String>)processedFields.get(aStringBuilder("authorList"))).or(authorList);
requiredMods = Optional.fromNullable((List<String>)processedFields.get(aStringBuilder("requiredMods"))).or(requiredMods);
dependencies = Optional.fromNullable((List<String>)processedFields.get(aStringBuilder("dependencies"))).or(dependencies);
dependants = Optional.fromNullable((List<String>)processedFields.get(aStringBuilder("dependants"))).or(dependants);
useDependencyInformation = Boolean.parseBoolean(Strings.nullToEmpty((String)processedFields.get(aStringBuilder("useDependencyInformation"))));
}
public void associate(Map<String, ModContainer> mods) {
if (parent!=null && parent.length() > 0) {
ModContainer mc=mods.get(parent);
if (mc!=null && mc.getMetadata()!=null) {
mc.getMetadata().childMods.add(mod);
parentMod = mc;
}
}
ModMetadata()
{
}
/**
@ -74,31 +122,24 @@ public class ModMetadata
*/
public String getChildModCountString()
{
return String.format("%d child mod%s", childMods.size(), childMods.size()!=1 ? "s" : "");
return String.format("%d child mod%s", childMods.size(), childMods.size() != 1 ? "s" : "");
}
public String getAuthorList() {
StringBuilder sb=new StringBuilder();
for (int i=0; i<authorList.size(); i++) {
sb.append(authorList.get(i));
if (i<authorList.size()-1) {
sb.append(", ");
}
}
return sb.toString();
public String getAuthorList()
{
return Joiner.on(", ").join(authorList);
}
/**
* @return
*/
public String getChildModList()
{
StringBuilder sb=new StringBuilder();
for (int i=0; i<childMods.size(); i++) {
sb.append(childMods.get(i).getMetadata().name);
if (i<childMods.size()-1) {
sb.append(", ");
}
}
return sb.toString();
return Joiner.on(", ").join(Lists.transform(childMods, new ModNameFunction()));
}
public String printableSortingRules()
{
return null;
}
}

View File

@ -0,0 +1,122 @@
/*
* The FML Forge Mod Loader suite. Copyright (C) 2012 cpw
*
* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package cpw.mods.fml.common;
import java.util.Arrays;
import java.util.logging.Level;
import cpw.mods.fml.relauncher.ReflectionHelper;
import cpw.mods.fml.relauncher.ReflectionHelper.UnableToAccessFieldException;
import cpw.mods.fml.relauncher.ReflectionHelper.UnableToFindFieldException;
/**
* Some reflection helper code.
*
* @author cpw
*
*/
public class ObfuscationReflectionHelper
{
public static boolean obfuscation;
@SuppressWarnings("unchecked")
public static <T, E> T getPrivateValue(Class<? super E> classToAccess, E instance, int fieldIndex)
{
try
{
return ReflectionHelper.getPrivateValue(classToAccess, instance, fieldIndex);
}
catch (UnableToAccessFieldException e)
{
FMLCommonHandler.instance().getFMLLogger()
.log(Level.SEVERE, String.format("There was a problem getting field index %d from %s", fieldIndex, classToAccess.getName()), e);
throw e;
}
}
@SuppressWarnings("unchecked")
public static <T, E> T getPrivateValue(Class<? super E> classToAccess, E instance, String... fieldNames)
{
try
{
return ReflectionHelper.getPrivateValue(classToAccess, instance, fieldNames);
}
catch (UnableToFindFieldException e)
{
FMLCommonHandler.instance().getFMLLogger()
.log(Level.SEVERE, String.format("Unable to locate any field %s on type %s", Arrays.toString(fieldNames), classToAccess.getName()), e);
throw e;
}
catch (UnableToAccessFieldException e)
{
FMLCommonHandler.instance().getFMLLogger()
.log(Level.SEVERE, String.format("Unable to access any field %s on type %s", Arrays.toString(fieldNames), classToAccess.getName()), e);
throw e;
}
}
@Deprecated
public static <T, E> void setPrivateValue(Class<? super T> classToAccess, T instance, int fieldIndex, E value)
{
setPrivateValue(classToAccess, instance, value, fieldIndex);
}
public static <T, E> void setPrivateValue(Class<? super T> classToAccess, T instance, E value, int fieldIndex)
{
try
{
ReflectionHelper.setPrivateValue(classToAccess, instance, value, fieldIndex);
}
catch (UnableToAccessFieldException e)
{
FMLCommonHandler.instance().getFMLLogger()
.log(Level.SEVERE, String.format("There was a problem setting field index %d on type %s", fieldIndex, classToAccess.getName()));
throw e;
}
}
@Deprecated
public static <T, E> void setPrivateValue(Class<? super T> classToAccess, T instance, String fieldName, E value)
{
setPrivateValue(classToAccess, instance, value, fieldName);
}
public static <T, E> void setPrivateValue(Class<? super T> classToAccess, T instance, E value, String... fieldNames)
{
try
{
ReflectionHelper.setPrivateValue(classToAccess, instance, value, fieldNames);
}
catch (UnableToFindFieldException e)
{
FMLCommonHandler.instance().getFMLLogger()
.log(Level.SEVERE, String.format("Unable to locate any field %s on type %s", Arrays.toString(fieldNames), classToAccess.getName()), e);
throw e;
}
catch (UnableToAccessFieldException e)
{
FMLCommonHandler.instance().getFMLLogger()
.log(Level.SEVERE, String.format("Unable to set any field %s on type %s", Arrays.toString(fieldNames), classToAccess.getName()), e);
throw e;
}
}
/**
*
*/
public static void detectObfuscation(Class<?> clazz)
{
obfuscation = !clazz.getSimpleName().equals("World");
}
}

View File

@ -1,117 +0,0 @@
/*
* The FML Forge Mod Loader suite. Copyright (C) 2012 cpw
*
* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package cpw.mods.fml.common;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.logging.Level;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.relauncher.ReflectionHelper.UnableToAccessFieldException;
import cpw.mods.fml.relauncher.ReflectionHelper.UnableToFindFieldException;
/**
* Some reflection helper code.
*
* @author cpw
*
*/
public class ReflectionHelper
{
public static boolean obfuscation;
@SuppressWarnings("unchecked")
public static <T, E> T getPrivateValue(Class <? super E > classToAccess, E instance, int fieldIndex)
{
try
{
return cpw.mods.fml.relauncher.ReflectionHelper.getPrivateValue(classToAccess, instance, fieldIndex);
}
catch (UnableToAccessFieldException e)
{
FMLCommonHandler.instance().getFMLLogger().log(Level.SEVERE, String.format("There was a problem getting field index %d from %s", fieldIndex, classToAccess.getName()), e);
throw e;
}
}
@SuppressWarnings("unchecked")
public static <T, E> T getPrivateValue(Class <? super E > classToAccess, E instance, String... fieldNames)
{
try
{
return cpw.mods.fml.relauncher.ReflectionHelper.getPrivateValue(classToAccess, instance, fieldNames);
}
catch (UnableToFindFieldException e)
{
FMLCommonHandler.instance().getFMLLogger().log(Level.SEVERE, String.format("Unable to locate any field %s on type %s", Arrays.toString(fieldNames), classToAccess.getName()), e);
throw e;
}
catch (UnableToAccessFieldException e)
{
FMLCommonHandler.instance().getFMLLogger().log(Level.SEVERE, String.format("Unable to access any field %s on type %s", Arrays.toString(fieldNames), classToAccess.getName()), e);
throw e;
}
}
@Deprecated
public static <T, E> void setPrivateValue(Class <? super T > classToAccess, T instance, int fieldIndex, E value)
{
setPrivateValue(classToAccess, instance, value, fieldIndex);
}
public static <T, E> void setPrivateValue(Class <? super T > classToAccess, T instance, E value, int fieldIndex)
{
try
{
cpw.mods.fml.relauncher.ReflectionHelper.setPrivateValue(classToAccess, instance, value, fieldIndex);
}
catch (UnableToAccessFieldException e)
{
FMLCommonHandler.instance().getFMLLogger().log(Level.SEVERE, String.format("There was a problem setting field index %d on type %s", fieldIndex, classToAccess.getName()));
throw e;
}
}
@Deprecated
public static <T, E> void setPrivateValue(Class <? super T > classToAccess, T instance, String fieldName, E value)
{
setPrivateValue(classToAccess, instance, value, fieldName);
}
public static <T, E> void setPrivateValue(Class <? super T > classToAccess, T instance, E value, String... fieldNames)
{
try
{
cpw.mods.fml.relauncher.ReflectionHelper.setPrivateValue(classToAccess, instance, value, fieldNames);
}
catch (UnableToFindFieldException e)
{
FMLCommonHandler.instance().getFMLLogger().log(Level.SEVERE, String.format("Unable to locate any field %s on type %s", Arrays.toString(fieldNames), classToAccess.getName()), e);
throw e;
}
catch (UnableToAccessFieldException e)
{
FMLCommonHandler.instance().getFMLLogger().log(Level.SEVERE, String.format("Unable to set any field %s on type %s", Arrays.toString(fieldNames), classToAccess.getName()), e);
throw e;
}
}
/**
*
*/
public static void detectObfuscation(Class<?> clazz)
{
obfuscation=!clazz.getSimpleName().equals("World");
}
}

View File

@ -0,0 +1,32 @@
package cpw.mods.fml.common.discovery;
import java.util.List;
import com.google.common.base.Throwables;
import cpw.mods.fml.common.ModContainer;
public enum ContainerType
{
JAR(JarDiscoverer.class),
DIR(DirectoryDiscoverer.class);
private ITypeDiscoverer discoverer;
private ContainerType(Class<? extends ITypeDiscoverer> discovererClass)
{
try
{
this.discoverer = discovererClass.newInstance();
}
catch (Exception e)
{
throw Throwables.propagate(e);
}
}
public List<ModContainer> findMods(ModCandidate candidate)
{
return discoverer.discover(candidate);
}
}

View File

@ -0,0 +1,57 @@
package cpw.mods.fml.common.discovery;
import java.io.File;
import java.io.FileFilter;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import cpw.mods.fml.common.ModContainer;
public class DirectoryDiscoverer implements ITypeDiscoverer
{
private class ClassFilter implements FileFilter
{
@Override
public boolean accept(File file)
{
return (file.isFile() && modClass.matcher(file.getName()).find()) || file.isDirectory();
}
}
@Override
public List<ModContainer> discover(ModCandidate candidate)
{
if (path.length() == 0)
{
dirRoot = modDir;
}
boolean foundAModClass = false;
File[] content = modDir.listFiles(new ClassFilter());
// Always sort our content
Arrays.sort(content);
for (File file : content)
{
if (file.isDirectory())
{
log.finest(String.format("Recursing into package %s", path + file.getName()));
attemptDirLoad(file, path + file.getName() + ".", sourceType, dirRoot);
continue;
}
Matcher fname = modClass.matcher(file.getName());
if (!fname.find())
{
continue;
}
String clazzName = path + fname.group(2);
log.fine(String.format("Candidate mod %s found in directory %s", clazzName, dirRoot.getName()));
candidates.add(new ModCandidate(sourceType, dirRoot, dirRoot, clazzName, sourceType));
foundAModClass = true;
}
// TODO Auto-generated method stub
return null;
}
}

View File

@ -0,0 +1,14 @@
package cpw.mods.fml.common.discovery;
import java.util.List;
import java.util.regex.Pattern;
import cpw.mods.fml.common.ModContainer;
public interface ITypeDiscoverer
{
public static Pattern classFile = Pattern.compile("([^\\s$]+).class$");
public static Pattern modClass = Pattern.compile("(.+/|)(mod\\_[^\\s$]+).class$");
public List<ModContainer> discover(ModCandidate candidate);
}

View File

@ -0,0 +1,84 @@
package cpw.mods.fml.common.discovery;
import java.util.Collections;
import java.util.List;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import com.google.common.collect.Lists;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.common.MetadataCollection;
import cpw.mods.fml.common.ModContainer;
import cpw.mods.fml.common.ModContainerFactory;
import cpw.mods.fml.common.discovery.asm.ASMModParser;
public class JarDiscoverer implements ITypeDiscoverer
{
private static Logger log = Loader.log;
@Override
public List<ModContainer> discover(ModCandidate candidate)
{
List<ModContainer> foundMods = Lists.newArrayList();
log.fine(String.format("Examining file %s for potential mods", candidate.getModContainer().getName()));
ZipFile jar = null;
try
{
jar = new ZipFile(candidate.getModContainer());
ZipEntry modInfo = jar.getEntry("mcmod.info");
MetadataCollection mc = null;
if (modInfo != null)
{
log.finer(String.format("Located mcmod.info file in file %s", candidate.getModContainer().getName()));
mc = MetadataCollection.from(jar.getInputStream(modInfo));
}
for (ZipEntry ze : Collections.list(jar.entries()))
{
Matcher match = classFile.matcher(ze.getName());
if (match.matches())
{
ASMModParser modParser = new ASMModParser(jar.getInputStream(ze));
modParser.validate();
ModContainer container = ModContainerFactory.instance().build(modParser, candidate.getModContainer());
if (container!=null)
{
foundMods.add(container);
if (mc!=null)
{
container.bindMetadata(mc);
}
}
}
match = modClass.matcher(ze.getName());
if (match.matches())
{
log.warning(String.format("Candidate mod %s found in mod file %s but is missing mod information", ze.getName().replace("/","."), candidate.getModContainer().getName()));
}
}
}
catch (Exception e)
{
log.warning(String.format("Zip file %s failed to read properly, it will be ignored", candidate.getModContainer().getName()));
}
finally
{
if (jar != null)
{
try
{
jar.close();
}
catch (Exception e)
{
}
}
}
return foundMods;
}
}

View File

@ -0,0 +1,46 @@
package cpw.mods.fml.common.discovery;
import java.io.File;
import java.util.List;
import cpw.mods.fml.common.ModContainer;
public class ModCandidate
{
private File classPathRoot;
private File modContainer;
private ContainerType sourceType;
private boolean classpath;
public ModCandidate(File classPathRoot, File modContainer, ContainerType sourceType)
{
this(classPathRoot, modContainer, sourceType, false);
}
public ModCandidate(File classPathRoot, File modContainer, ContainerType sourceType, boolean classpath)
{
this.classPathRoot = classPathRoot;
this.modContainer = modContainer;
this.sourceType = sourceType;
this.classpath = classpath;
}
public File getClassPathRoot()
{
return classPathRoot;
}
public File getModContainer()
{
return modContainer;
}
public ContainerType getSourceType()
{
return sourceType;
}
public List<ModContainer> explore()
{
return sourceType.findMods(this);
}
}

View File

@ -0,0 +1,110 @@
package cpw.mods.fml.common.discovery;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.nio.channels.FileChannel;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Opcodes;
import com.google.common.collect.Lists;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.common.ModClassLoader;
import cpw.mods.fml.common.ModContainer;
public class ModDiscoverer
{
private Logger log = Loader.log;
private static Pattern zipJar = Pattern.compile("(.+).(zip|jar)$");
private List<ModCandidate> candidates = Lists.newArrayList();
public void findClasspathMods(ModClassLoader modClassLoader)
{
File[] minecraftSources = modClassLoader.getParentSources();
if (minecraftSources.length == 1 && minecraftSources[0].isFile())
{
log.fine(String.format("Minecraft is a file at %s, loading", minecraftSources[0].getAbsolutePath()));
candidates.add(new ModCandidate(minecraftSources[0], minecraftSources[0], ContainerType.JAR));
}
else
{
for (int i = 0; i < minecraftSources.length; i++)
{
if (minecraftSources[i].isFile())
{
log.fine(String.format("Found a minecraft related file at %s, examining for mod candidates", minecraftSources[i].getAbsolutePath()));
candidates.add(new ModCandidate(minecraftSources[i], minecraftSources[i], ContainerType.JAR, true));
}
else if (minecraftSources[i].isDirectory())
{
log.fine(String.format("Found a minecraft related directory at %s, examining for mod candidates", minecraftSources[i].getAbsolutePath()));
candidates.add(new ModCandidate(minecraftSources[i], minecraftSources[i], ContainerType.DIR, true));
}
}
}
}
public void findModDirMods(File modsDir)
{
File[] modList = modsDir.listFiles();
// Sort the files into alphabetical order first
Arrays.sort(modList);
for (File modFile : modList)
{
if (modFile.isDirectory())
{
log.fine(String.format("Found a candidate mod directory %s", modFile.getName()));
candidates.add(new ModCandidate(modFile, modFile, ContainerType.DIR));
}
else
{
Matcher matcher = zipJar.matcher(modFile.getName());
if (matcher.matches())
{
log.fine(String.format("Found a candidate zip or jar file %s", matcher.group(0)));
candidates.add(new ModCandidate(modFile, modFile, ContainerType.JAR));
}
else
{
log.fine(String.format("Ignoring unknown file %s in mods directory", modFile.getName()));
}
}
}
}
public List<ModContainer> identifyMods()
{
List<ModContainer> modList = Lists.newArrayList();
for (ModCandidate candidate : candidates)
{
List<ModContainer> mods = candidate.explore();
modList.addAll(mods);
}
return modList;
}
}

View File

@ -0,0 +1,113 @@
package cpw.mods.fml.common.discovery.asm;
import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedList;
import java.util.List;
import net.minecraft.src.BaseMod;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.Type;
import com.google.common.base.Objects;
import com.google.common.collect.Lists;
import cpw.mods.fml.common.LoaderException;
public class ASMModParser
{
private Type asmType;
private int classVersion;
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);
this.classVersion = classVersion;
this.asmSuperType = Type.getObjectType(superClassQName);
}
public void startClassAnnotation(String annotationName)
{
ModAnnotation ann = new ModAnnotation(AnnotationType.CLASS, Type.getType(annotationName), this.asmType.getClassName());
annotations.addFirst(ann);
}
public void addAnnotationProperty(String key, Object value)
{
annotations.getFirst().values.put(key, value);
}
public void startFieldAnnotation(String fieldName, String annotationName)
{
ModAnnotation ann = new ModAnnotation(AnnotationType.FIELD, Type.getType(annotationName), fieldName);
annotations.addFirst(ann);
}
@Override
public String toString()
{
return Objects.toStringHelper("ASMAnnotationDiscoverer")
.add("className", asmType.getClassName())
.add("classVersion", classVersion)
.add("superName", asmSuperType.getClassName())
.add("annotations", annotations)
.add("isBaseMod", isBaseMod())
.add("baseModProperties", baseModProperties)
.toString();
}
public Type getASMType()
{
return asmType;
}
public int getClassVersion()
{
return classVersion;
}
public Type getASMSuperType()
{
return asmSuperType;
}
public LinkedList<ModAnnotation> getAnnotations()
{
return annotations;
}
public void validate()
{
// if (classVersion > 50.0)
// {
//
// throw new LoaderException(new RuntimeException("Mod compiled for Java 7 detected"));
// }
}
public boolean isBaseMod()
{
return getASMSuperType().equals(Type.getType(BaseMod.class));
}
public void setBaseModProperties(String foundProperties)
{
this.baseModProperties = foundProperties;
}
}

View File

@ -0,0 +1,50 @@
package cpw.mods.fml.common.discovery.asm;
import java.util.Map;
import org.objectweb.asm.Type;
import com.google.common.base.Objects;
import com.google.common.collect.Maps;
import cpw.mods.fml.common.discovery.asm.ASMModParser.AnnotationType;
public class ModAnnotation
{
AnnotationType type;
Type asmType;
String member;
Map<String,Object> values = Maps.newHashMap();
public ModAnnotation(AnnotationType type, Type asmType, String member)
{
this.type = type;
this.asmType = asmType;
this.member = member;
}
@Override
public String toString()
{
return Objects.toStringHelper("Annotation")
.add("type",type)
.add("name",asmType.getClassName())
.add("member",member)
.add("values", values)
.toString();
}
public AnnotationType getType()
{
return type;
}
public Type getASMType()
{
return asmType;
}
public String getMember()
{
return member;
}
public Map<String, Object> getValues()
{
return values;
}
}

View File

@ -0,0 +1,21 @@
package cpw.mods.fml.common.discovery.asm;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Opcodes;
public class ModAnnotationVisitor extends AnnotationVisitor
{
private ASMModParser discoverer;
public ModAnnotationVisitor(ASMModParser discoverer)
{
super(Opcodes.ASM4);
this.discoverer = discoverer;
}
@Override
public void visit(String key, Object value)
{
discoverer.addAnnotationProperty(key, value);
}
}

View File

@ -0,0 +1,50 @@
package cpw.mods.fml.common.discovery.asm;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
public class ModClassVisitor extends ClassVisitor
{
private ASMModParser discoverer;
public ModClassVisitor(ASMModParser discoverer)
{
super(Opcodes.ASM4);
this.discoverer = discoverer;
}
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces)
{
discoverer.beginNewTypeName(name, version, superName);
}
@Override
public AnnotationVisitor visitAnnotation(String annotationName, boolean runtimeVisible)
{
discoverer.startClassAnnotation(annotationName);
return new ModAnnotationVisitor(discoverer);
}
@Override
public FieldVisitor visitField(int access, String name, String desc, String signature, Object value)
{
return new ModFieldVisitor(name, discoverer);
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions)
{
if (discoverer.isBaseMod() && name.equals("getPriorities") && desc.equals(Type.getMethodDescriptor(Type.getType(String.class))))
{
return new ModMethodVisitor(name, discoverer);
}
return null;
}
}

View File

@ -0,0 +1,25 @@
package cpw.mods.fml.common.discovery.asm;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Opcodes;
public class ModFieldVisitor extends FieldVisitor
{
private String fieldName;
private ASMModParser discoverer;
public ModFieldVisitor(String name, ASMModParser discoverer)
{
super(Opcodes.ASM4);
this.fieldName = name;
this.discoverer = discoverer;
}
@Override
public AnnotationVisitor visitAnnotation(String annotationName, boolean runtimeVisible)
{
discoverer.startFieldAnnotation(fieldName, annotationName);
return new ModAnnotationVisitor(discoverer);
}
}

View File

@ -0,0 +1,62 @@
package cpw.mods.fml.common.discovery.asm;
import java.util.LinkedList;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import com.google.common.collect.Lists;
public class ModMethodVisitor extends MethodVisitor
{
private ASMModParser discoverer;
private boolean inCode;
private LinkedList<Label> labels = Lists.newLinkedList();
private String foundProperties;
private boolean validProperties;
public ModMethodVisitor(String name, ASMModParser discoverer)
{
super(Opcodes.ASM4);
this.discoverer = discoverer;
}
@Override
public void visitCode()
{
labels.clear();
}
@Override
public void visitLdcInsn(Object cst)
{
if (cst instanceof String && labels.size() == 1)
{
foundProperties = (String) cst;
}
}
@Override
public void visitInsn(int opcode)
{
if (Opcodes.ARETURN == opcode && labels.size() == 1 && foundProperties != null)
{
validProperties = true;
}
}
@Override
public void visitLabel(Label label)
{
labels.push(label);
}
@Override
public void visitEnd()
{
if (validProperties)
{
discoverer.setBaseModProperties(foundProperties);
}
}
}

View File

@ -0,0 +1,25 @@
package cpw.mods.fml.common.event;
import cpw.mods.fml.common.LoaderState.ModState;
import cpw.mods.fml.common.ModClassLoader;
public class FMLConstructionEvent extends FMLStateEvent
{
private ModClassLoader modClassLoader;
public FMLConstructionEvent(Object... eventData)
{
this.modClassLoader = (ModClassLoader)eventData[0];
}
public ModClassLoader getModClassLoader()
{
return modClassLoader;
}
@Override
public ModState getModState()
{
return ModState.CONSTRUCTED;
}
}

View File

@ -1,6 +1,14 @@
package cpw.mods.fml.common.event;
import cpw.mods.fml.common.LoaderState.ModState;
public class FMLInitializationEvent extends FMLStateEvent
{
@Override
public ModState getModState()
{
return ModState.INITIALIZED;
}
}

View File

@ -1,6 +1,14 @@
package cpw.mods.fml.common.event;
import cpw.mods.fml.common.LoaderState.ModState;
public class FMLPostInitializationEvent extends FMLStateEvent
{
@Override
public ModState getModState()
{
return ModState.POSTINITIALIZED;
}
}

View File

@ -2,7 +2,15 @@ package cpw.mods.fml.common.event;
import com.google.common.eventbus.EventBus;
import cpw.mods.fml.common.LoaderState.ModState;
public class FMLPreInitializationEvent extends FMLStateEvent
{
@Override
public ModState getModState()
{
return ModState.PREINITIALIZED;
}
}

View File

@ -1,6 +0,0 @@
package cpw.mods.fml.common.event;
public class FMLServerInitializationEvent extends FMLStateEvent
{
}

View File

@ -1,6 +1,13 @@
package cpw.mods.fml.common.event;
public class FMLStateEvent extends FMLEvent
{
import cpw.mods.fml.common.LoaderState.ModState;
public abstract class FMLStateEvent extends FMLEvent
{
public FMLStateEvent(Object... data)
{
}
public abstract ModState getModState();
}

View File

@ -1,6 +0,0 @@
package cpw.mods.fml.common.event;
public class FMLUninitializationEvent extends FMLStateEvent
{
}

View File

@ -0,0 +1,13 @@
package cpw.mods.fml.common.functions;
import com.google.common.base.Function;
import cpw.mods.fml.common.ModContainer;
public final class ModIdFunction implements Function<ModContainer, String>
{
public String apply(ModContainer container)
{
return container.getModId();
}
}

View File

@ -0,0 +1,15 @@
package cpw.mods.fml.common.functions;
import com.google.common.base.Function;
import cpw.mods.fml.common.ModContainer;
public class ModNameFunction implements Function<ModContainer, String>
{
@Override
public String apply(ModContainer input)
{
return input.getName();
}
}

View File

@ -29,7 +29,11 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.logging.Level;
import com.google.common.base.Throwables;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.IConsoleHandler;
@ -41,12 +45,17 @@ import cpw.mods.fml.common.INetworkHandler;
import cpw.mods.fml.common.IPickupNotifier;
import cpw.mods.fml.common.IPlayerTracker;
import cpw.mods.fml.common.IWorldGenerator;
import cpw.mods.fml.common.LoadController;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.common.LoaderException;
import cpw.mods.fml.common.LoaderState;
import cpw.mods.fml.common.ModClassLoader;
import cpw.mods.fml.common.LoaderState.ModState;
import cpw.mods.fml.common.MetadataCollection;
import cpw.mods.fml.common.discovery.ContainerType;
import cpw.mods.fml.common.event.FMLConstructionEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.ModContainer;
import cpw.mods.fml.common.ModContainer.SourceType;
import cpw.mods.fml.common.ModMetadata;
import cpw.mods.fml.common.ProxyInjector;
import cpw.mods.fml.common.TickType;
@ -55,25 +64,28 @@ public class ModLoaderModContainer implements ModContainer
{
private static final ProxyInjector NULLPROXY = new ProxyInjector("","","",null);
private Class <? extends BaseMod > modClazz;
private BaseMod mod;
public BaseMod mod;
private File modSource;
private ArrayList<String> dependencies;
private ArrayList<String> preDependencies;
private ArrayList<String> postDependencies;
public ArrayList<String> requirements;
public ArrayList<String> dependencies;
public ArrayList<String> dependants;
private ArrayList<IKeyHandler> keyHandlers;
private LoaderState.ModState state;
private SourceType sourceType;
private ContainerType sourceType;
private ModMetadata metadata;
private ProxyInjector sidedProxy;
private BaseModTicker gameTickHandler;
private BaseModTicker guiTickHandler;
private String modClazzName;
private String modId;
private EventBus bus;
private LoadController controller;
private boolean enabled;
public ModLoaderModContainer(Class <? extends BaseMod > modClazz, File modSource)
public ModLoaderModContainer(String className, File modSource)
{
this.modClazz = modClazz;
this.modClazzName = className;
this.modSource = modSource;
// We are unloaded
nextState();
this.modId = className.contains(".") ? className.substring(className.lastIndexOf('.')) : className;
}
/**
@ -87,20 +99,25 @@ public class ModLoaderModContainer implements ModContainer
this.guiTickHandler = new BaseModTicker(instance, true);
}
@Override
public boolean wantsPreInit()
@Subscribe
public void constructMod(FMLConstructionEvent event)
{
return true;
try
{
ModClassLoader modClassLoader = event.getModClassLoader();
modClassLoader.addFile(modSource);
mod = (BaseMod)Class.forName(modClazzName, true, modClassLoader).newInstance();
}
catch (Exception e)
{
controller.errorOccurred(this, e);
Throwables.propagateIfPossible(e);
}
}
@Override
public boolean wantsPostInit()
{
return true;
}
@Override
public void preInit()
@Subscribe
public void preInit(FMLPreInitializationEvent event)
{
try
{
@ -120,24 +137,6 @@ public class ModLoaderModContainer implements ModContainer
throw new LoaderException(e);
}
}
@Override
public LoaderState.ModState getModState()
{
return state;
}
@Override
public void nextState()
{
if (state==null) {
state=LoaderState.ModState.UNLOADED;
return;
}
if (state.ordinal()+1<LoaderState.ModState.values().length) {
state=LoaderState.ModState.values()[state.ordinal()+1];
}
}
/**
*
*/
@ -351,17 +350,6 @@ public class ModLoaderModContainer implements ModContainer
throw new IllegalArgumentException("MLProp declared on non-standard type");
}
}
@Override
public void init()
{
mod.load();
}
@Override
public void postInit()
{
mod.modsLoaded();
}
@Override
public String getName()
@ -423,177 +411,29 @@ public class ModLoaderModContainer implements ModContainer
}
@Override
public int lookupFuelValue(int itemId, int itemDamage)
public List<String> getRequirements()
{
return mod.addFuel(itemId, itemDamage);
return requirements;
}
@Override
public boolean wantsPickupNotification()
public List<String> getDependants()
{
return true;
}
@Override
public IPickupNotifier getPickupNotifier()
{
return mod;
}
@Override
public boolean wantsToDispense()
{
return true;
}
@Override
public IDispenseHandler getDispenseHandler()
{
return mod;
}
@Override
public boolean wantsCraftingNotification()
{
return true;
}
@Override
public ICraftingHandler getCraftingHandler()
{
return mod;
}
private void computeDependencies()
{
dependencies = new ArrayList<String>();
preDependencies = new ArrayList<String>();
postDependencies = new ArrayList<String>();
if (mod.getPriorities() == null || mod.getPriorities().length() == 0)
{
return;
}
boolean parseFailure=false;
StringTokenizer st = new StringTokenizer(mod.getPriorities(), ";");
for (; st.hasMoreTokens();)
{
String dep = st.nextToken();
String[] depparts = dep.split(":");
if (depparts.length < 2)
{
parseFailure=true;
continue;
}
else if ("required-before".equals(depparts[0]) || "required-after".equals(depparts[0]))
{
if (!depparts[1].trim().equals("*")) {
dependencies.add(depparts[1]);
} else {
parseFailure=true;
continue;
}
}
if ("required-before".equals(depparts[0]) || "before".equals(depparts[0]))
{
postDependencies.add(depparts[1]);
} else if ("required-after".equals(depparts[0]) || "after".equals(depparts[0]))
{
preDependencies.add(depparts[1]);
} else {
parseFailure=true;
}
}
if (parseFailure) {
FMLCommonHandler.instance().getFMLLogger().warning(String.format("The mod %s has an incorrect dependency string {%s}", mod.getName(), mod.getPriorities()));
}
return dependants;
}
@Override
public List<String> getDependencies()
{
if (dependencies == null)
{
computeDependencies();
}
return dependencies;
}
@Override
public List<String> getPostDepends()
{
if (dependencies == null)
{
computeDependencies();
}
return postDependencies;
}
@Override
public List<String> getPreDepends()
{
if (dependencies == null)
{
computeDependencies();
}
return preDependencies;
}
public String toString()
{
return modClazz.getSimpleName();
}
@Override
public boolean wantsNetworkPackets()
{
return true;
}
@Override
public INetworkHandler getNetworkHandler()
{
return mod;
}
@Override
public boolean ownsNetworkChannel(String channel)
{
return FMLCommonHandler.instance().getChannelListFor(this).contains(channel);
}
@Override
public boolean wantsConsoleCommands()
{
return true;
}
@Override
public IConsoleHandler getConsoleHandler()
{
return mod;
}
@Override
public boolean wantsPlayerTracking()
{
return true;
}
@Override
public IPlayerTracker getPlayerTracker()
{
return mod;
}
/**
* @param keyHandler
* @param allowRepeat
@ -617,64 +457,12 @@ public class ModLoaderModContainer implements ModContainer
keyHandlers.add(handler);
}
@Override
public List<IKeyHandler> getKeys()
{
if (keyHandlers==null) {
return Collections.emptyList();
}
return keyHandlers;
}
@Override
public void setSourceType(SourceType type) {
this.sourceType=type;
}
@Override
public SourceType getSourceType()
{
return sourceType;
}
/* (non-Javadoc)
* @see cpw.mods.fml.common.ModContainer#getMetadata()
*/
@Override
public ModMetadata getMetadata()
{
return metadata;
}
/* (non-Javadoc)
* @see cpw.mods.fml.common.ModContainer#setMetadata(cpw.mods.fml.common.ModMetadata)
*/
@Override
public void setMetadata(ModMetadata meta)
{
this.metadata=meta;
}
/* (non-Javadoc)
* @see cpw.mods.fml.common.ModContainer#gatherRenderers(java.util.Map)
*/
@Override
public void gatherRenderers(Map renderers)
{
mod.onRenderHarvest(renderers);
}
/* (non-Javadoc)
* @see cpw.mods.fml.common.ModContainer#requestAnimations()
*/
@Override
public void requestAnimations()
{
mod.onRegisterAnimations();
}
/* (non-Javadoc)
* @see cpw.mods.fml.common.ModContainer#getVersion()
*/
@Override
public String getVersion()
{
@ -685,9 +473,6 @@ public class ModLoaderModContainer implements ModContainer
return mod.getVersion();
}
/* (non-Javadoc)
* @see cpw.mods.fml.common.ModContainer#findSidedProxy()
*/
@Override
public ProxyInjector findSidedProxy()
{
@ -701,15 +486,6 @@ public class ModLoaderModContainer implements ModContainer
return sidedProxy == NULLPROXY ? null : sidedProxy;
}
/* (non-Javadoc)
* @see cpw.mods.fml.common.ModContainer#keyBindEvernt(java.lang.Object)
*/
@Override
public void keyBindEvent(Object keybinding)
{
mod.keyBindingEvent(keybinding);
}
/**
* @return
*/
@ -724,4 +500,39 @@ public class ModLoaderModContainer implements ModContainer
{
return this.guiTickHandler;
}
@Override
public String getModId()
{
return modId;
}
@Override
public void bindMetadata(MetadataCollection mc)
{
this.metadata = mc.getMetadataForId(modId);
}
@Override
public void setEnabledState(boolean enabled)
{
this.enabled = enabled;
}
@Override
public boolean registerBus(EventBus bus, LoadController controller)
{
if (this.enabled)
{
controller.log(Level.FINE, "Enabling mod %s", getModId());
this.bus = bus;
this.controller = controller;
bus.register(this);
return true;
}
else
{
return false;
}
}
}

View File

@ -16,6 +16,7 @@ import java.util.Arrays;
import java.util.List;
import java.util.Map;
import cpw.mods.fml.common.DummyModContainer;
import cpw.mods.fml.common.FMLModContainer;
import cpw.mods.fml.common.ModContainer;
import cpw.mods.fml.common.toposort.TopologicalSort.DirectedGraph;
@ -28,10 +29,10 @@ public class ModSorter
{
private DirectedGraph<ModContainer> modGraph;
private ModContainer beforeAll = new FMLModContainer("DummyBeforeAll");
private ModContainer afterAll = new FMLModContainer("DummyAfterAll");
private ModContainer before = new FMLModContainer("DummyBefore");
private ModContainer after = new FMLModContainer("DummyAfter");
private ModContainer beforeAll = new DummyModContainer();
private ModContainer afterAll = new DummyModContainer();
private ModContainer before = new DummyModContainer();
private ModContainer after = new DummyModContainer();
public ModSorter(List<ModContainer> modList, Map<String, ModContainer> nameLookup)
{
@ -59,7 +60,7 @@ public class ModSorter
boolean preDepAdded = false;
boolean postDepAdded = false;
for (String dep : mod.getPreDepends())
for (String dep : mod.getDependencies())
{
preDepAdded = true;
@ -79,7 +80,7 @@ public class ModSorter
}
}
for (String dep : mod.getPostDepends())
for (String dep : mod.getDependants())
{
postDepAdded = true;

View File

@ -0,0 +1,6 @@
package cpw.mods.fml.relauncher;
public interface IClassTransformer
{
public byte[] transform(String name, byte[] bytes);
}

View File

@ -1,38 +1,90 @@
package cpw.mods.fml.relauncher;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class RelaunchClassLoader extends URLClassLoader
{
private static String[] excludedPackages = {
"java.", "sun.", "javax.",
"cpw.mods.fml.relauncher", "net.minecraftforge.classloading",
"org.objectweb.asm.", "com.google.common."
};
private List<URL> sources;
private ClassLoader parent;
private List<IClassTransformer> transformers;
private Map<String, Class> cachedClasses;
public RelaunchClassLoader(URL[] sources)
{
super(sources);
super(sources, null);
this.sources = new ArrayList<URL>(Arrays.asList(sources));
this.parent = getClass().getClassLoader();
this.cachedClasses = new HashMap<String,Class>(1000);
this.transformers = new ArrayList<IClassTransformer>(2);
ReflectionHelper.setPrivateValue(ClassLoader.class, null, this, "scl");
Thread.currentThread().setContextClassLoader(this);
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException
public void registerTransformer(String transformerClassName)
{
if (name.startsWith("cpw.mods.fml.relauncher"))
try
{
return getClass().getClassLoader().loadClass(name);
transformers.add((IClassTransformer) loadClass(transformerClassName).newInstance());
}
catch (Exception e)
{
// error registering transformer
}
}
@Override
public Class<?> findClass(String name) throws ClassNotFoundException
{
for (String st : excludedPackages)
{
if (name.startsWith(st))
{
return parent.loadClass(name);
}
}
if (cachedClasses.containsKey(name))
{
return cachedClasses.get(name);
}
try
{
return findClass(name);
byte[] basicClass = readFully(findResource(name.replace('.', '/').concat(".class")).openStream());
byte[] transformedClass = runTransformers(name, basicClass);
Class<?> cl = defineClass(name, transformedClass, 0, transformedClass.length);
cachedClasses.put(name, cl);
return cl;
}
catch (ClassNotFoundException cnfe)
catch (Throwable e)
{
return getClass().getClassLoader().loadClass(name);
throw new ClassNotFoundException(name, e);
}
}
private byte[] runTransformers(String name, byte[] basicClass)
{
for (IClassTransformer transformer : transformers)
{
basicClass = transformer.transform(name, basicClass);
}
return basicClass;
}
@Override
public void addURL(URL url)
{
@ -44,4 +96,25 @@ public class RelaunchClassLoader extends URLClassLoader
{
return sources;
}
private byte[] readFully(InputStream stream)
{
try
{
ByteArrayOutputStream bos = new ByteArrayOutputStream(stream.available());
int r;
while ((r = stream.read()) != -1)
{
bos.write(r);
}
return bos.toByteArray();
}
catch (Throwable t)
{
/// HMMM
return new byte[0];
}
}
}

View File

@ -79,7 +79,11 @@ public class RelaunchLibraryManager
}
}
// Register our class loading transformer now we have everything we need
actualClassLoader.registerTransformer("cpw.mods.fml.common.asm.ASMTransformer");
// Register the forge class loading transformer now we have everything we need
actualClassLoader.registerTransformer("net.minecraftforge.asm.ASMTransformer");
try
{
Class<?> loaderClazz = Class.forName("cpw.mods.fml.common.Loader", true, actualClassLoader);

View File

@ -21,7 +21,7 @@
</classpathentry>
<classpathentry exported="true" kind="lib" path="jars/bin/minecraft.jar"/>
<classpathentry exported="true" kind="lib" path="lib/argo-2.25.jar"/>
<classpathentry exported="true" kind="lib" path="lib/asm-all-4.0.jar"/>
<classpathentry exported="true" kind="lib" path="lib/guava-12.0.jar"/>
<classpathentry exported="true" kind="lib" path="lib/asm-all-4.0.jar" sourcepath="lib/asm-4.0"/>
<classpathentry exported="true" kind="lib" path="lib/guava-12.0.jar" sourcepath="lib/guava-12.0-sources.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View File

@ -1,3 +1,8 @@
java.io.FileInputStream fis = new java.io.FileInputStream(new java.io.File("/home/cpw/projects/FML/mcsnapshot/FML/eclipse/FML-MockMod/bin/cpw/mods/mockmod/MockMod.class"));
cpw.mods.fml.common.ModDiscoverer.AnnotationFinder ann = new cpw.mods.fml.common.ModDiscoverer.AnnotationFinder(fis);
System.out.println(new cpw.mods.fml.common.asm.ASMModParser(fis));
java.io.FileInputStream fis = new java.io.FileInputStream(new java.io.File("/home/cpw/projects/FML/mcsnapshot/FML/eclipse/simpletestmod/bin/net/minecraft/src/mod_testMod.class"));
System.out.println(new cpw.mods.fml.common.asm.ASMModParser(fis));

View File

@ -90,4 +90,10 @@ public class mod_testMod extends BaseMod {
return interval;
}
}
@Override
public String getPriorities()
{
return "TESTString";
}
}