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 }