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}