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 public void findClasspathMods(ModClassLoader modClassLoader) 029 { 030 List<String> knownLibraries = ImmutableList.<String>builder().addAll(modClassLoader.getDefaultLibraries()).addAll(RelaunchLibraryManager.getLibraries()).build(); 031 File[] minecraftSources = modClassLoader.getParentSources(); 032 if (minecraftSources.length == 1 && minecraftSources[0].isFile()) 033 { 034 FMLLog.fine("Minecraft is a file at %s, loading", minecraftSources[0].getAbsolutePath()); 035 candidates.add(new ModCandidate(minecraftSources[0], minecraftSources[0], ContainerType.JAR)); 036 } 037 else 038 { 039 for (int i = 0; i < minecraftSources.length; i++) 040 { 041 if (minecraftSources[i].isFile()) 042 { 043 if (knownLibraries.contains(minecraftSources[i].getName())) 044 { 045 FMLLog.fine("Skipping known library file %s", minecraftSources[i].getAbsolutePath()); 046 } 047 else 048 { 049 FMLLog.fine("Found a minecraft related file at %s, examining for mod candidates", minecraftSources[i].getAbsolutePath()); 050 candidates.add(new ModCandidate(minecraftSources[i], minecraftSources[i], ContainerType.JAR, i!=0)); 051 } 052 } 053 else if (minecraftSources[i].isDirectory()) 054 { 055 FMLLog.fine("Found a minecraft related directory at %s, examining for mod candidates", minecraftSources[i].getAbsolutePath()); 056 candidates.add(new ModCandidate(minecraftSources[i], minecraftSources[i], ContainerType.DIR, i!=0)); 057 } 058 } 059 } 060 061 } 062 063 public void findModDirMods(File modsDir) 064 { 065 File[] modList = modsDir.listFiles(); 066 // Sort the files into alphabetical order first 067 Arrays.sort(modList); 068 069 for (File modFile : modList) 070 { 071 if (modFile.isDirectory()) 072 { 073 FMLLog.fine("Found a candidate mod directory %s", modFile.getName()); 074 candidates.add(new ModCandidate(modFile, modFile, ContainerType.DIR)); 075 } 076 else 077 { 078 Matcher matcher = zipJar.matcher(modFile.getName()); 079 080 if (matcher.matches()) 081 { 082 FMLLog.fine("Found a candidate zip or jar file %s", matcher.group(0)); 083 candidates.add(new ModCandidate(modFile, modFile, ContainerType.JAR)); 084 } 085 else 086 { 087 FMLLog.fine("Ignoring unknown file %s in mods directory", modFile.getName()); 088 } 089 } 090 } 091 } 092 093 public List<ModContainer> identifyMods() 094 { 095 List<ModContainer> modList = Lists.newArrayList(); 096 097 for (ModCandidate candidate : candidates) 098 { 099 try 100 { 101 List<ModContainer> mods = candidate.explore(dataTable); 102 modList.addAll(mods); 103 } 104 catch (LoaderException le) 105 { 106 FMLLog.log(Level.WARNING, le, "Identified a problem with the mod candidate %s, ignoring this source", candidate.getModContainer()); 107 } 108 catch (Throwable t) 109 { 110 Throwables.propagate(t); 111 } 112 } 113 114 return modList; 115 } 116 117 public ASMDataTable getASMTable() 118 { 119 return dataTable; 120 } 121 122 }