    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.finer("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}