001package cpw.mods.fml.common.discovery;
002
003import java.io.File;
004import java.util.Arrays;
005import java.util.List;
006import java.util.logging.Level;
007import java.util.regex.Matcher;
008import java.util.regex.Pattern;
009
010import com.google.common.base.Throwables;
011import com.google.common.collect.ImmutableList;
012import com.google.common.collect.Lists;
013
014import cpw.mods.fml.common.FMLLog;
015import cpw.mods.fml.common.LoaderException;
016import cpw.mods.fml.common.ModClassLoader;
017import cpw.mods.fml.common.ModContainer;
018import cpw.mods.fml.relauncher.RelaunchLibraryManager;
019
020public 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}