    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     */
    013    package cpw.mods.fml.common.toposort;
    014
    015    import java.util.Arrays;
    016    import java.util.List;
    017    import java.util.Map;
    018
    019    import com.google.common.collect.Lists;
    020
    021    import cpw.mods.fml.common.DummyModContainer;
    022    import cpw.mods.fml.common.Loader;
    023    import cpw.mods.fml.common.ModContainer;
    024    import cpw.mods.fml.common.toposort.TopologicalSort.DirectedGraph;
    025    import cpw.mods.fml.common.versioning.ArtifactVersion;
    026
    027    /**
    028     * @author cpw
    029     *
    030     */
    031    public 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    }