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 }