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