Check in a lot of recent work
This commit is contained in:
parent
3115f92ee4
commit
2a19eca517
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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="";
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
package cpw.mods.fml.common.event;
|
||||
|
||||
public class FMLServerInitializationEvent extends FMLStateEvent
|
||||
{
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
package cpw.mods.fml.common.event;
|
||||
|
||||
public class FMLUninitializationEvent extends FMLStateEvent
|
||||
{
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
package cpw.mods.fml.relauncher;
|
||||
|
||||
public interface IClassTransformer
|
||||
{
|
||||
public byte[] transform(String name, byte[] bytes);
|
||||
}
|
|
@ -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];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -90,4 +90,10 @@ public class mod_testMod extends BaseMod {
|
|||
return interval;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPriorities()
|
||||
{
|
||||
return "TESTString";
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue