/** @param mod */
 public void loadMetadataFor(ModContainer mod) {
   if (mod.getSourceType() == SourceType.JAR) {
     try {
       ZipFile jar = new ZipFile(mod.getSource());
       ZipEntry infoFile = jar.getEntry("mcmod.info");
       if (infoFile != null) {
         InputStream input = jar.getInputStream(infoFile);
         ModMetadata data = sidedDelegate.readMetadataFrom(input, mod);
         mod.setMetadata(data);
       } else {
         getFMLLogger()
             .fine(
                 String.format(
                     "Failed to find mcmod.info file in %s for %s",
                     mod.getSource().getName(), mod.getName()));
       }
     } catch (Exception e) {
       // Something wrong but we don't care
       getFMLLogger()
           .fine(
               String.format(
                   "Failed to find mcmod.info file in %s for %s",
                   mod.getSource().getName(), mod.getName()));
       getFMLLogger().throwing("FMLCommonHandler", "loadMetadataFor", e);
     }
   } else {
     try {
       InputStream input =
           Loader.instance().getModClassLoader().getResourceAsStream(mod.getName() + ".info");
       if (input == null) {
         input =
             Loader.instance()
                 .getModClassLoader()
                 .getResourceAsStream("net/minecraft/src/" + mod.getName() + ".info");
       }
       if (input != null) {
         ModMetadata data = sidedDelegate.readMetadataFrom(input, mod);
         mod.setMetadata(data);
       }
     } catch (Exception e) {
       // Something wrong but we don't care
       getFMLLogger()
           .fine(
               String.format(
                   "Failed to find %s.info file in %s for %s",
                   mod.getName(), mod.getSource().getName(), mod.getName()));
       getFMLLogger().throwing("FMLCommonHandler", "loadMetadataFor", e);
     }
   }
 }
Beispiel #2
0
 public void printModStates(StringBuilder ret) {
   for (ModContainer mc : loader.getModList()) {
     ret.append("\n\t")
         .append(mc.getModId())
         .append(" [")
         .append(mc.getName())
         .append("] (")
         .append(mc.getSource().getName())
         .append(") ");
     Joiner.on("->").appendTo(ret, modStates.get(mc.getModId()));
   }
 }
Beispiel #3
0
  private void identifyDuplicates(List<ModContainer> mods) {
    TreeMultimap<ModContainer, File> dupsearch =
        TreeMultimap.create(new ModIdComparator(), Ordering.arbitrary());
    for (ModContainer mc : mods) {
      if (mc.getSource() != null) {
        dupsearch.put(mc, mc.getSource());
      }
    }

    ImmutableMultiset<ModContainer> duplist = Multisets.copyHighestCountFirst(dupsearch.keys());
    SetMultimap<ModContainer, File> dupes = LinkedHashMultimap.create();
    for (Entry<ModContainer> e : duplist.entrySet()) {
      if (e.getCount() > 1) {
        FMLLog.severe(
            "Found a duplicate mod %s at %s",
            e.getElement().getModId(), dupsearch.get(e.getElement()));
        dupes.putAll(e.getElement(), dupsearch.get(e.getElement()));
      }
    }
    if (!dupes.isEmpty()) {
      throw new DuplicateModsFoundException(dupes);
    }
  }
Beispiel #4
0
  /**
   * The primary loading code
   *
   * <p>The found resources are first loaded into the {@link #modClassLoader} (always) then scanned
   * for class resources matching the specification above.
   *
   * <p>If they provide the {@link Mod} annotation, they will be loaded as "FML mods"
   *
   * <p>Finally, if they are successfully loaded as classes, they are then added to the available
   * mod list.
   */
  private ModDiscoverer identifyMods() {
    FMLLog.fine("Building injected Mod Containers %s", injectedContainers);
    // Add in the MCP mod container
    mods.add(new InjectedModContainer(mcp, new File("minecraft.jar")));
    for (String cont : injectedContainers) {
      ModContainer mc;
      try {
        mc = (ModContainer) Class.forName(cont, true, modClassLoader).newInstance();
      } catch (Exception e) {
        FMLLog.log(
            Level.ERROR, e, "A problem occured instantiating the injected mod container %s", cont);
        throw new LoaderException(e);
      }
      mods.add(new InjectedModContainer(mc, mc.getSource()));
    }
    ModDiscoverer discoverer = new ModDiscoverer();
    FMLLog.fine(
        "Attempting to load mods contained in the minecraft jar file and associated classes");
    discoverer.findClasspathMods(modClassLoader);
    FMLLog.fine("Minecraft jar mods loaded successfully");

    FMLLog.getLogger()
        .log(
            Level.INFO,
            "Found {} mods from the command line. Injecting into mod discoverer",
            ModListHelper.additionalMods.size());
    FMLLog.info("Searching %s for mods", canonicalModsDir.getAbsolutePath());
    discoverer.findModDirMods(
        canonicalModsDir, ModListHelper.additionalMods.values().toArray(new File[0]));
    File versionSpecificModsDir = new File(canonicalModsDir, mccversion);
    if (versionSpecificModsDir.isDirectory()) {
      FMLLog.info("Also searching %s for mods", versionSpecificModsDir);
      discoverer.findModDirMods(versionSpecificModsDir);
    }

    mods.addAll(discoverer.identifyMods());
    identifyDuplicates(mods);
    namedMods = Maps.uniqueIndex(mods, new ModIdFunction());
    FMLLog.info(
        "Forge Mod Loader has identified %d mod%s to load",
        mods.size(), mods.size() != 1 ? "s" : "");
    return discoverer;
  }
Beispiel #5
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);
  }
Beispiel #6
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");
      }
    }
  }