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    }