001/* 002 * Forge Mod Loader 003 * Copyright (c) 2012-2013 cpw. 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser Public License v2.1 006 * which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 008 * 009 * Contributors: 010 * cpw - implementation 011 */ 012 013package cpw.mods.fml.common.discovery; 014 015import java.io.File; 016import java.util.Arrays; 017import java.util.List; 018import java.util.logging.Level; 019import java.util.regex.Matcher; 020import java.util.regex.Pattern; 021 022import com.google.common.base.Throwables; 023import com.google.common.collect.ImmutableList; 024import com.google.common.collect.Lists; 025 026import cpw.mods.fml.common.FMLLog; 027import cpw.mods.fml.common.LoaderException; 028import cpw.mods.fml.common.ModClassLoader; 029import cpw.mods.fml.common.ModContainer; 030import cpw.mods.fml.relauncher.RelaunchLibraryManager; 031 032public class ModDiscoverer 033{ 034 private static Pattern zipJar = Pattern.compile("(.+).(zip|jar)$"); 035 036 private List<ModCandidate> candidates = Lists.newArrayList(); 037 038 private ASMDataTable dataTable = new ASMDataTable(); 039 040 private List<File> nonModLibs = Lists.newArrayList(); 041 042 public void findClasspathMods(ModClassLoader modClassLoader) 043 { 044 List<String> knownLibraries = ImmutableList.<String>builder().addAll(modClassLoader.getDefaultLibraries()).addAll(RelaunchLibraryManager.getLibraries()).build(); 045 File[] minecraftSources = modClassLoader.getParentSources(); 046 if (minecraftSources.length == 1 && minecraftSources[0].isFile()) 047 { 048 FMLLog.fine("Minecraft is a file at %s, loading", minecraftSources[0].getAbsolutePath()); 049 candidates.add(new ModCandidate(minecraftSources[0], minecraftSources[0], ContainerType.JAR, true, true)); 050 } 051 else 052 { 053 for (int i = 0; i < minecraftSources.length; i++) 054 { 055 if (minecraftSources[i].isFile()) 056 { 057 if (knownLibraries.contains(minecraftSources[i].getName())) 058 { 059 FMLLog.finer("Skipping known library file %s", minecraftSources[i].getAbsolutePath()); 060 } 061 else 062 { 063 FMLLog.fine("Found a minecraft related file at %s, examining for mod candidates", minecraftSources[i].getAbsolutePath()); 064 candidates.add(new ModCandidate(minecraftSources[i], minecraftSources[i], ContainerType.JAR, i==0, true)); 065 } 066 } 067 else if (minecraftSources[i].isDirectory()) 068 { 069 FMLLog.fine("Found a minecraft related directory at %s, examining for mod candidates", minecraftSources[i].getAbsolutePath()); 070 candidates.add(new ModCandidate(minecraftSources[i], minecraftSources[i], ContainerType.DIR, i==0, true)); 071 } 072 } 073 } 074 075 } 076 077 public void findModDirMods(File modsDir) 078 { 079 File[] modList = modsDir.listFiles(); 080 // Sort the files into alphabetical order first 081 Arrays.sort(modList); 082 083 for (File modFile : modList) 084 { 085 if (modFile.isDirectory()) 086 { 087 FMLLog.fine("Found a candidate mod directory %s", modFile.getName()); 088 candidates.add(new ModCandidate(modFile, modFile, ContainerType.DIR)); 089 } 090 else 091 { 092 Matcher matcher = zipJar.matcher(modFile.getName()); 093 094 if (matcher.matches()) 095 { 096 FMLLog.fine("Found a candidate zip or jar file %s", matcher.group(0)); 097 candidates.add(new ModCandidate(modFile, modFile, ContainerType.JAR)); 098 } 099 else 100 { 101 FMLLog.fine("Ignoring unknown file %s in mods directory", modFile.getName()); 102 } 103 } 104 } 105 } 106 107 public List<ModContainer> identifyMods() 108 { 109 List<ModContainer> modList = Lists.newArrayList(); 110 111 for (ModCandidate candidate : candidates) 112 { 113 try 114 { 115 List<ModContainer> mods = candidate.explore(dataTable); 116 if (mods.isEmpty() && !candidate.isClasspath()) 117 { 118 nonModLibs.add(candidate.getModContainer()); 119 } 120 else 121 { 122 modList.addAll(mods); 123 } 124 } 125 catch (LoaderException le) 126 { 127 FMLLog.log(Level.WARNING, le, "Identified a problem with the mod candidate %s, ignoring this source", candidate.getModContainer()); 128 } 129 catch (Throwable t) 130 { 131 Throwables.propagate(t); 132 } 133 } 134 135 return modList; 136 } 137 138 public ASMDataTable getASMTable() 139 { 140 return dataTable; 141 } 142 143 public List<File> getNonModLibs() 144 { 145 return nonModLibs; 146 } 147 148}