package net.minecraftforge.fml.relauncher; import java.io.File; import java.io.IOException; import java.util.List; import java.util.Map; import java.util.Set; import net.minecraft.launchwrapper.Launch; import org.apache.logging.log4j.Level; import com.google.common.base.Charsets; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.google.common.io.Files; import com.google.gson.Gson; import com.google.gson.JsonSyntaxException; public class ModListHelper { public static class JsonModList { public String repositoryRoot; public List<String> modRef; public String parentList; } private static File mcDirectory; private static Set<File> visitedFiles = Sets.newHashSet(); public static final Map<String,File> additionalMods = Maps.newLinkedHashMap(); static void parseModList(File minecraftDirectory) { FMLRelaunchLog.fine("Attempting to load commandline specified mods, relative to %s", minecraftDirectory.getAbsolutePath()); mcDirectory = minecraftDirectory; @SuppressWarnings("unchecked") Map<String,String> args = (Map<String, String>) Launch.blackboard.get("launchArgs"); String listFile = args.get("--modListFile"); if (listFile != null) { parseListFile(listFile); } String extraMods = args.get("--mods"); if (extraMods != null) { String[] split = extraMods.split(","); for (String modFile : split) { tryAddFile(modFile, null, modFile); } } } private static void parseListFile(String listFile) { File f; try { f = new File(mcDirectory, listFile).getCanonicalFile(); } catch (IOException e2) { FMLRelaunchLog.log(Level.INFO, e2, "Unable to canonicalize path %s relative to %s", listFile, mcDirectory.getAbsolutePath()); return; } if (!f.exists()) { FMLRelaunchLog.info("Failed to find modList file %s", f.getAbsolutePath()); return; } if (visitedFiles.contains(f)) { FMLRelaunchLog.severe("There appears to be a loop in the modListFile hierarchy. You shouldn't do this!"); throw new RuntimeException("Loop detected, impossible to load modlistfile"); } String json; try { json = Files.asCharSource(f, Charsets.UTF_8).read(); } catch (IOException e1) { FMLRelaunchLog.log(Level.INFO, e1, "Failed to read modList json file %s.", listFile); return; } Gson gsonParser = new Gson(); JsonModList modList; try { modList = gsonParser.fromJson(json, JsonModList.class); } catch (JsonSyntaxException e) { FMLRelaunchLog.log(Level.INFO, e, "Failed to parse modList json file %s.", listFile); return; } visitedFiles.add(f); // We visit parents before children, so the additionalMods list is sorted from parent to child if (modList.parentList != null) { parseListFile(modList.parentList); } File repoRoot = new File(modList.repositoryRoot); if (!repoRoot.exists()) { FMLRelaunchLog.info("Failed to find the specified repository root %s", modList.repositoryRoot); return; } for (String s : modList.modRef) { StringBuilder fileName = new StringBuilder(); StringBuilder genericName = new StringBuilder(); String[] parts = s.split(":"); fileName.append(parts[0].replace('.', File.separatorChar)); genericName.append(parts[0]); fileName.append(File.separatorChar); fileName.append(parts[1]).append(File.separatorChar); genericName.append(":").append(parts[1]); fileName.append(parts[2]).append(File.separatorChar); fileName.append(parts[1]).append('-').append(parts[2]); if (parts.length == 4) { fileName.append('-').append(parts[3]); genericName.append(":").append(parts[3]); } fileName.append(".jar"); tryAddFile(fileName.toString(), repoRoot, genericName.toString()); } } private static void tryAddFile(String modFileName, File repoRoot, String descriptor) { File modFile = repoRoot != null ? new File(repoRoot,modFileName) : new File(mcDirectory, modFileName); if (!modFile.exists()) { FMLRelaunchLog.info("Failed to find mod file %s (%s)", descriptor, modFile.getAbsolutePath()); } else { FMLRelaunchLog.fine("Adding %s (%s) to the mod list", descriptor, modFile.getAbsolutePath()); additionalMods.put(descriptor, modFile); } } }