From dc4dc55dcdcb86ec800f2a9170e468673046685b Mon Sep 17 00:00:00 2001 From: cpw Date: Sat, 2 Jan 2016 17:28:35 -0500 Subject: [PATCH] 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). --- .../fml/relauncher/CoreModManager.java | 112 +++++++++++++----- 1 file changed, 80 insertions(+), 32 deletions(-) diff --git a/src/main/java/net/minecraftforge/fml/relauncher/CoreModManager.java b/src/main/java/net/minecraftforge/fml/relauncher/CoreModManager.java index 1da4ed3f0..528c4edf5 100644 --- a/src/main/java/net/minecraftforge/fml/relauncher/CoreModManager.java +++ b/src/main/java/net/minecraftforge/fml/relauncher/CoreModManager.java @@ -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 ignoredModFiles = Lists.newArrayList(); private static Map> transformers = Maps.newHashMap(); @@ -69,6 +73,7 @@ public class CoreModManager { private static List candidateModFiles = Lists.newArrayList(); private static List accessTransformers = Lists.newArrayList(); private static Set rootNames = Sets.newHashSet(); + private static final List 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 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 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 extractContainedDepJars(JarFile jar, File versionedModsDir) throws IOException + { + Map 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)