    001/*
    002 * The FML Forge Mod Loader suite. Copyright (C) 2012 cpw
    003 *
    004 * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free
    005 * Software Foundation; either version 2.1 of the License, or any later version.
    006 *
    007 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
    008 * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
    009 *
    010 * You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51
    011 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
    012 */
    013package cpw.mods.fml.common.toposort;
    014
    015import java.util.Arrays;
    016import java.util.List;
    017import java.util.Map;
    018
    019import com.google.common.collect.Lists;
    020
    021import cpw.mods.fml.common.DummyModContainer;
    022import cpw.mods.fml.common.Loader;
    023import cpw.mods.fml.common.ModContainer;
    024import cpw.mods.fml.common.toposort.TopologicalSort.DirectedGraph;
    025import cpw.mods.fml.common.versioning.ArtifactVersion;
    026
    027/**
    028 * @author cpw
    029 *
    030 */
    031public class ModSorter
    032{
    033    private DirectedGraph<ModContainer> modGraph;
    034
    035    private ModContainer beforeAll = new DummyModContainer();
    036    private ModContainer afterAll = new DummyModContainer();
    037    private ModContainer before = new DummyModContainer();
    038    private ModContainer after = new DummyModContainer();
    039
    040    public ModSorter(List<ModContainer> modList, Map<String, ModContainer> nameLookup)
    041    {
    042        buildGraph(modList, nameLookup);
    043    }
    044
    045    private void buildGraph(List<ModContainer> modList, Map<String, ModContainer> nameLookup)
    046    {
    047        modGraph = new DirectedGraph<ModContainer>();
    048        modGraph.addNode(beforeAll);
    049        modGraph.addNode(before);
    050        modGraph.addNode(afterAll);
    051        modGraph.addNode(after);
    052        modGraph.addEdge(before, after);
    053        modGraph.addEdge(beforeAll, before);
    054        modGraph.addEdge(after, afterAll);
    055
    056        for (ModContainer mod : modList)
    057        {
    058            modGraph.addNode(mod);
    059        }
    060
    061        for (ModContainer mod : modList)
    062        {
    063            if (mod.isImmutable())
    064            {
    065                // Immutable mods are always before everything
    066                modGraph.addEdge(beforeAll, mod);
    067                modGraph.addEdge(mod, before);
    068                continue;
    069            }
    070            boolean preDepAdded = false;
    071            boolean postDepAdded = false;
    072
    073            for (ArtifactVersion dep : mod.getDependencies())
    074            {
    075                preDepAdded = true;
    076
    077                String modid = dep.getLabel();
    078                if (modid.equals("*"))
    079                {
    080                    // We are "after" everything
    081                    modGraph.addEdge(mod, afterAll);
    082                    modGraph.addEdge(after, mod);
    083                    postDepAdded = true;
    084                }
    085                else
    086                {
    087                    modGraph.addEdge(before, mod);
    088                    if (Loader.isModLoaded(modid)) {
    089                        modGraph.addEdge(nameLookup.get(modid), mod);
    090                    }
    091                }
    092            }
    093
    094            for (ArtifactVersion dep : mod.getDependants())
    095            {
    096                postDepAdded = true;
    097
    098                String modid = dep.getLabel();
    099                if (modid.equals("*"))
    100                {
    101                    // We are "before" everything
    102                    modGraph.addEdge(beforeAll, mod);
    103                    modGraph.addEdge(mod, before);
    104                    preDepAdded = true;
    105                }
    106                else
    107                {
    108                    modGraph.addEdge(mod, after);
    109                    if (Loader.isModLoaded(modid)) {
    110                        modGraph.addEdge(mod, nameLookup.get(modid));
    111                    }
    112                }
    113            }
    114
    115            if (!preDepAdded)
    116            {
    117                modGraph.addEdge(before, mod);
    118            }
    119
    120            if (!postDepAdded)
    121            {
    122                modGraph.addEdge(mod, after);
    123            }
    124        }
    125    }
    126
    127    public List<ModContainer> sort()
    128    {
    129        List<ModContainer> sortedList = TopologicalSort.topologicalSort(modGraph);
    130        sortedList.removeAll(Arrays.asList(new ModContainer[] {beforeAll, before, after, afterAll}));
    131        return sortedList;
    132    }
    133}