public ImmutableBiMap<ModContainer, Object> buildModObjectList() { ImmutableBiMap.Builder<ModContainer, Object> builder = ImmutableBiMap.<ModContainer, Object>builder(); for (ModContainer mc : activeModList) { if (!mc.isImmutable() && mc.getMod() != null) { builder.put(mc, mc.getMod()); } if (mc.getMod() == null && !mc.isImmutable() && state != LoaderState.CONSTRUCTING) { FMLLog.severe( "There is a severe problem with %s - it appears not to have constructed correctly", mc.getModId()); if (state != LoaderState.CONSTRUCTING) { this.errorOccurred(mc, new RuntimeException()); } } } return builder.build(); }
/** * Sort the mods into a sorted list, using dependency information from the containers. The sorting * is performed using a {@link TopologicalSort} based on the pre- and post- dependency information * provided by the mods. */ private void sortModList() { FMLLog.finer("Verifying mod requirements are satisfied"); try { BiMap<String, ArtifactVersion> modVersions = HashBiMap.create(); for (ModContainer mod : Iterables.concat(getActiveModList(), ModAPIManager.INSTANCE.getAPIList())) { modVersions.put(mod.getModId(), mod.getProcessedVersion()); } ArrayListMultimap<String, String> reqList = ArrayListMultimap.create(); for (ModContainer mod : getActiveModList()) { if (!mod.acceptableMinecraftVersionRange() .containsVersion(minecraft.getProcessedVersion())) { FMLLog.severe( "The mod %s does not wish to run in Minecraft version %s. You will have to remove it to play.", mod.getModId(), getMCVersionString()); throw new WrongMinecraftVersionException(mod); } Map<String, ArtifactVersion> names = Maps.uniqueIndex(mod.getRequirements(), new ArtifactVersionNameFunction()); Set<ArtifactVersion> versionMissingMods = Sets.newHashSet(); Set<String> missingMods = Sets.difference(names.keySet(), modVersions.keySet()); if (!missingMods.isEmpty()) { FMLLog.severe( "The mod %s (%s) requires mods %s to be available", mod.getModId(), mod.getName(), missingMods); for (String modid : missingMods) { versionMissingMods.add(names.get(modid)); } throw new MissingModsException(versionMissingMods, mod.getModId(), mod.getName()); } reqList.putAll(mod.getModId(), names.keySet()); ImmutableList<ArtifactVersion> allDeps = ImmutableList.<ArtifactVersion>builder() .addAll(mod.getDependants()) .addAll(mod.getDependencies()) .build(); for (ArtifactVersion v : allDeps) { if (modVersions.containsKey(v.getLabel())) { if (!v.containsVersion(modVersions.get(v.getLabel()))) { versionMissingMods.add(v); } } } if (!versionMissingMods.isEmpty()) { FMLLog.severe( "The mod %s (%s) requires mod versions %s to be available", mod.getModId(), mod.getName(), versionMissingMods); throw new MissingModsException(versionMissingMods, mod.getModId(), mod.getName()); } } FMLLog.finer("All mod requirements are satisfied"); reverseDependencies = Multimaps.invertFrom(reqList, ArrayListMultimap.<String, String>create()); ModSorter sorter = new ModSorter(getActiveModList(), namedMods); try { FMLLog.finer("Sorting mods into an ordered list"); List<ModContainer> sortedMods = sorter.sort(); // Reset active list to the sorted list modController.getActiveModList().clear(); modController.getActiveModList().addAll(sortedMods); // And inject the sorted list into the overall list mods.removeAll(sortedMods); sortedMods.addAll(mods); mods = sortedMods; FMLLog.finer("Mod sorting completed successfully"); } catch (ModSortingException sortException) { FMLLog.severe( "A dependency cycle was detected in the input mod set so an ordering cannot be determined"); SortingExceptionData<ModContainer> exceptionData = sortException.getExceptionData(); FMLLog.severe("The first mod in the cycle is %s", exceptionData.getFirstBadNode()); FMLLog.severe("The mod cycle involves"); for (ModContainer mc : exceptionData.getVisitedNodes()) { FMLLog.severe( "%s : before: %s, after: %s", mc.toString(), mc.getDependants(), mc.getDependencies()); } FMLLog.log(Level.ERROR, sortException, "The full error"); throw sortException; } } finally { FMLLog.fine("Mod sorting data"); int unprintedMods = mods.size(); for (ModContainer mod : getActiveModList()) { if (!mod.isImmutable()) { FMLLog.fine( "\t%s(%s:%s): %s (%s)", mod.getModId(), mod.getName(), mod.getVersion(), mod.getSource().getName(), mod.getSortingRules()); unprintedMods--; } } if (unprintedMods == mods.size()) { FMLLog.fine("No user mods found to sort"); } } }