Example #1
0
  /**
   * Called from the hook to start mod loading. We trigger the {@link #identifyMods()} and
   * Constructing, Preinitalization, and Initalization phases here. Finally, the mod list is frozen
   * completely and is consider immutable from then on.
   */
  public void loadMods() {
    progressBar = ProgressManager.push("Loading", 7);
    progressBar.step("Constructing Mods");
    initializeLoader();
    mods = Lists.newArrayList();
    namedMods = Maps.newHashMap();
    modController = new LoadController(this);
    modController.transition(LoaderState.LOADING, false);
    discoverer = identifyMods();
    ModAPIManager.INSTANCE.manageAPI(modClassLoader, discoverer);
    disableRequestedMods();
    modController.distributeStateMessage(FMLLoadEvent.class);
    sortModList();
    ModAPIManager.INSTANCE.cleanupAPIContainers(modController.getActiveModList());
    ModAPIManager.INSTANCE.cleanupAPIContainers(mods);
    mods = ImmutableList.copyOf(mods);
    for (File nonMod : discoverer.getNonModLibs()) {
      if (nonMod.isFile()) {
        FMLLog.info(
            "FML has found a non-mod file %s in your mods directory. It will now be injected into your classpath. This could severe stability issues, it should be removed if possible.",
            nonMod.getName());
        try {
          modClassLoader.addFile(nonMod);
        } catch (MalformedURLException e) {
          FMLLog.log(
              Level.ERROR,
              e,
              "Encountered a weird problem with non-mod file injection : %s",
              nonMod.getName());
        }
      }
    }
    modController.transition(LoaderState.CONSTRUCTING, false);
    modController.distributeStateMessage(
        LoaderState.CONSTRUCTING, modClassLoader, discoverer.getASMTable(), reverseDependencies);

    List<ModContainer> mods = Lists.newArrayList();
    mods.addAll(getActiveModList());
    Collections.sort(
        mods,
        new Comparator<ModContainer>() {
          @Override
          public int compare(ModContainer o1, ModContainer o2) {
            return o1.getModId().compareTo(o2.getModId());
          }
        });

    FMLLog.fine("Mod signature data");
    FMLLog.fine(" \tValid Signatures:");
    for (ModContainer mod : getActiveModList()) {
      if (mod.getSigningCertificate() != null)
        FMLLog.fine(
            "\t\t(%s) %s\t(%s\t%s)\t%s",
            CertificateHelper.getFingerprint(mod.getSigningCertificate()),
            mod.getModId(),
            mod.getName(),
            mod.getVersion(),
            mod.getSource().getName());
    }
    FMLLog.fine(" \tMissing Signatures:");
    for (ModContainer mod : getActiveModList()) {
      if (mod.getSigningCertificate() == null)
        FMLLog.fine(
            "\t\t%s\t(%s\t%s)\t%s",
            mod.getModId(), mod.getName(), mod.getVersion(), mod.getSource().getName());
    }
    if (getActiveModList().isEmpty()) {
      FMLLog.fine("No user mod signature data found");
    }
    progressBar.step("Initializing mods Phase 1");
    modController.transition(LoaderState.PREINITIALIZATION, false);
  }
Example #2
0
  /**
   * 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");
      }
    }
  }