Add a simple ContainedDep mechanic- mods can contain other mods or libs, and can specify them using a manifest tag: "ContainedDeps".

This is a space separated (manifest standard) list of jar files that are to be extracted into the version specific directory.

There's also a special system property "fml.skipContainedDeps" that will allow for runtime skipping of extraction of contained deps (a comma separated list, based on the file name).
This commit is contained in:
cpw 2016-01-02 17:28:35 -05:00
parent 1a31ff9f06
commit dc4dc55dcd
1 changed files with 80 additions and 32 deletions

View File

@ -14,6 +14,7 @@ package net.minecraftforge.fml.relauncher;
import java.io.File;
import java.io.FileFilter;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.lang.reflect.Method;
@ -29,8 +30,10 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import com.google.common.io.ByteStreams;
import net.minecraft.launchwrapper.ITweaker;
import net.minecraft.launchwrapper.Launch;
import net.minecraft.launchwrapper.LaunchClassLoader;
@ -59,6 +62,7 @@ public class CoreModManager {
private static final Attributes.Name COREMODCONTAINSFMLMOD = new Attributes.Name("FMLCorePluginContainsFMLMod");
private static final Attributes.Name MODTYPE = new Attributes.Name("ModType");
private static final Attributes.Name MODSIDE = new Attributes.Name("ModSide");
private static final Attributes.Name MODCONTAINSDEPS = new Attributes.Name("ContainedDeps");
private static String[] rootPlugins = { "net.minecraftforge.fml.relauncher.FMLCorePlugin", "net.minecraftforge.classloading.FMLForgePlugin" };
private static List<String> ignoredModFiles = Lists.newArrayList();
private static Map<String, List<String>> transformers = Maps.newHashMap();
@ -69,6 +73,7 @@ public class CoreModManager {
private static List<String> candidateModFiles = Lists.newArrayList();
private static List<String> accessTransformers = Lists.newArrayList();
private static Set<String> rootNames = Sets.newHashSet();
private static final List<String> skipContainedDeps = Arrays.asList(System.getProperty("fml.skipContainedDeps","").split(","));
static
{
@ -322,6 +327,7 @@ public class CoreModManager {
FMLRelaunchLog.fine("Examining for coremod candidacy %s", coreMod.getName());
JarFile jar = null;
Attributes mfAttributes;
String fmlCorePlugin;
try
{
jar = new JarFile(coreMod);
@ -332,6 +338,39 @@ public class CoreModManager {
}
ModAccessTransformer.addJar(jar);
mfAttributes = jar.getManifest().getMainAttributes();
String cascadedTweaker = mfAttributes.getValue("TweakClass");
if (cascadedTweaker != null)
{
FMLRelaunchLog.info("Loading tweaker %s from %s", cascadedTweaker, coreMod.getName());
Integer sortOrder = Ints.tryParse(Strings.nullToEmpty(mfAttributes.getValue("TweakOrder")));
sortOrder = (sortOrder == null ? Integer.valueOf(0) : sortOrder);
handleCascadingTweak(coreMod, jar, cascadedTweaker, classLoader, sortOrder);
ignoredModFiles.add(coreMod.getName());
continue;
}
List<String> modTypes = mfAttributes.containsKey(MODTYPE) ? Arrays.asList(mfAttributes.getValue(MODTYPE).split(",")) : ImmutableList.of("FML");
if (!modTypes.contains("FML"))
{
FMLRelaunchLog.fine("Adding %s to the list of things to skip. It is not an FML mod, it has types %s", coreMod.getName(), modTypes);
ignoredModFiles.add(coreMod.getName());
continue;
}
String modSide = mfAttributes.containsKey(MODSIDE) ? mfAttributes.getValue(MODSIDE) : "BOTH";
if (! ("BOTH".equals(modSide) || FMLLaunchHandler.side.name().equals(modSide)))
{
FMLRelaunchLog.fine("Mod %s has ModSide meta-inf value %s, and we're %s. It will be ignored", coreMod.getName(), modSide, FMLLaunchHandler.side.name());
ignoredModFiles.add(coreMod.getName());
continue;
}
ModListHelper.additionalMods.putAll(extractContainedDepJars(jar, versionedModDir));
fmlCorePlugin = mfAttributes.getValue("FMLCorePlugin");
if (fmlCorePlugin == null)
{
// Not a coremod
FMLRelaunchLog.fine("Not found coremod data in %s", coreMod.getName());
continue;
}
}
catch (IOException ioe)
{
@ -352,38 +391,6 @@ public class CoreModManager {
}
}
}
String cascadedTweaker = mfAttributes.getValue("TweakClass");
if (cascadedTweaker != null)
{
FMLRelaunchLog.info("Loading tweaker %s from %s", cascadedTweaker, coreMod.getName());
Integer sortOrder = Ints.tryParse(Strings.nullToEmpty(mfAttributes.getValue("TweakOrder")));
sortOrder = (sortOrder == null ? Integer.valueOf(0) : sortOrder);
handleCascadingTweak(coreMod, jar, cascadedTweaker, classLoader, sortOrder);
ignoredModFiles.add(coreMod.getName());
continue;
}
List<String> modTypes = mfAttributes.containsKey(MODTYPE) ? Arrays.asList(mfAttributes.getValue(MODTYPE).split(",")) : ImmutableList.of("FML");
if (!modTypes.contains("FML"))
{
FMLRelaunchLog.fine("Adding %s to the list of things to skip. It is not an FML mod, it has types %s", coreMod.getName(), modTypes);
ignoredModFiles.add(coreMod.getName());
continue;
}
String modSide = mfAttributes.containsKey(MODSIDE) ? mfAttributes.getValue(MODSIDE) : "BOTH";
if (! ("BOTH".equals(modSide) || FMLLaunchHandler.side.name().equals(modSide)))
{
FMLRelaunchLog.fine("Mod %s has ModSide meta-inf value %s, and we're %s. It will be ignored", coreMod.getName(), modSide, FMLLaunchHandler.side.name());
ignoredModFiles.add(coreMod.getName());
continue;
}
String fmlCorePlugin = mfAttributes.getValue("FMLCorePlugin");
if (fmlCorePlugin == null)
{
// Not a coremod
FMLRelaunchLog.fine("Not found coremod data in %s", coreMod.getName());
continue;
}
// Support things that are mod jars, but not FML mod jars
try
{
@ -409,6 +416,47 @@ public class CoreModManager {
}
}
private static Map<String,File> extractContainedDepJars(JarFile jar, File versionedModsDir) throws IOException
{
Map<String,File> result = Maps.newHashMap();
if (!jar.getManifest().getMainAttributes().containsKey(MODCONTAINSDEPS)) return result;
String deps = jar.getManifest().getMainAttributes().getValue(MODCONTAINSDEPS);
String[] depList = deps.split(" ");
for (String dep : depList)
{
if (skipContainedDeps.contains(dep))
{
FMLRelaunchLog.log(Level.ERROR, "Skipping dep at request: %s", dep);
continue;
}
final JarEntry jarEntry = jar.getJarEntry(dep);
if (jarEntry == null)
{
FMLRelaunchLog.log(Level.ERROR, "Found invalid ContainsDeps declaration %s in %s", dep, jar.getName());
continue;
}
File target = new File(versionedModsDir, dep);
if (target.exists())
{
FMLRelaunchLog.log(Level.DEBUG, "Found existing ContainsDep extracted to %s, skipping extraction", target.getCanonicalPath());
result.put(dep,target);
continue;
}
FMLRelaunchLog.log(Level.DEBUG, "Extracted ContainedDep %s from %s to %s", dep, jar.getName(), target.getCanonicalPath());
try
{
ByteStreams.copy(jar.getInputStream(jarEntry), new FileOutputStream(target));
} catch (IOException e)
{
FMLRelaunchLog.log(Level.ERROR, e, "An error occurred extracting dependency");
continue;
}
result.put(dep,target);
}
return result;
}
private static Method ADDURL;
private static void handleCascadingTweak(File coreMod, JarFile jar, String cascadedTweaker, LaunchClassLoader classLoader, Integer sortingOrder)