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