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    }