/* * The FML Forge Mod Loader suite. Copyright (C) 2012 cpw * * 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 * Software Foundation; either version 2.1 of the License, or any later version. * * 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 * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. * * 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 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ package cpw.mods.fml.common.toposort; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import com.google.common.collect.Maps; import cpw.mods.fml.common.DummyModContainer; import cpw.mods.fml.common.Loader; import cpw.mods.fml.common.ModAPIManager; import cpw.mods.fml.common.ModContainer; import cpw.mods.fml.common.toposort.TopologicalSort.DirectedGraph; import cpw.mods.fml.common.versioning.ArtifactVersion; /** * @author cpw * */ public class ModSorter { private DirectedGraph<ModContainer> modGraph; private ModContainer beforeAll = new DummyModContainer("BeforeAll"); private ModContainer afterAll = new DummyModContainer("AfterAll"); private ModContainer before = new DummyModContainer("Before"); private ModContainer after = new DummyModContainer("After"); public ModSorter(List<ModContainer> modList, Map<String, ModContainer> nameLookup) { HashMap<String, ModContainer> sortingNameLookup = Maps.newHashMap(nameLookup); ModAPIManager.INSTANCE.injectAPIModContainers(modList, sortingNameLookup); buildGraph(modList, sortingNameLookup); } private void buildGraph(List<ModContainer> modList, Map<String, ModContainer> nameLookup) { modGraph = new DirectedGraph<ModContainer>(); modGraph.addNode(beforeAll); modGraph.addNode(before); modGraph.addNode(afterAll); modGraph.addNode(after); modGraph.addEdge(before, after); modGraph.addEdge(beforeAll, before); modGraph.addEdge(after, afterAll); for (ModContainer mod : modList) { modGraph.addNode(mod); } for (ModContainer mod : modList) { if (mod.isImmutable()) { // Immutable mods are always before everything modGraph.addEdge(beforeAll, mod); modGraph.addEdge(mod, before); continue; } boolean preDepAdded = false; boolean postDepAdded = false; for (ArtifactVersion dep : mod.getDependencies()) { preDepAdded = true; String modid = dep.getLabel(); if (modid.equals("*")) { // We are "after" everything modGraph.addEdge(mod, afterAll); modGraph.addEdge(after, mod); postDepAdded = true; } else { modGraph.addEdge(before, mod); if (nameLookup.containsKey(modid) || Loader.isModLoaded(modid)) { modGraph.addEdge(nameLookup.get(modid), mod); } } } for (ArtifactVersion dep : mod.getDependants()) { postDepAdded = true; String modid = dep.getLabel(); if (modid.equals("*")) { // We are "before" everything modGraph.addEdge(beforeAll, mod); modGraph.addEdge(mod, before); preDepAdded = true; } else { modGraph.addEdge(mod, after); if (Loader.isModLoaded(modid)) { modGraph.addEdge(mod, nameLookup.get(modid)); } } } if (!preDepAdded) { modGraph.addEdge(before, mod); } if (!postDepAdded) { modGraph.addEdge(mod, after); } } } public List<ModContainer> sort() { List<ModContainer> sortedList = TopologicalSort.topologicalSort(modGraph); sortedList.removeAll(Arrays.asList(new ModContainer[] {beforeAll, before, after, afterAll})); return sortedList; } }