예제 #1
0
 public void transition(LoaderState desiredState) {
   LoaderState oldState = state;
   state = state.transition(!errors.isEmpty());
   if (state != desiredState) {
     Throwable toThrow = null;
     FMLLog.severe(
         "Fatal errors were detected during the transition from %s to %s. Loading cannot continue",
         oldState, desiredState);
     StringBuilder sb = new StringBuilder();
     printModStates(sb);
     FMLLog.getLogger().severe(sb.toString());
     if (errors.size() > 0) {
       FMLLog.severe("The following problems were captured during this phase");
       for (Entry<String, Throwable> error : errors.entries()) {
         FMLLog.log(Level.SEVERE, error.getValue(), "Caught exception from %s", error.getKey());
         if (error.getValue() instanceof IFMLHandledException) {
           toThrow = error.getValue();
         } else if (toThrow == null) {
           toThrow = error.getValue();
         }
       }
     } else {
       FMLLog.severe(
           "The ForgeModLoader state engine has become corrupted. Probably, a state was missed by and invalid modification to a base class"
               + "ForgeModLoader depends on. This is a critical error and not recoverable. Investigate any modifications to base classes outside of"
               + "ForgeModLoader, especially Optifine, to see if there are fixes available.");
       throw new RuntimeException("The ForgeModLoader state engine is invalid");
     }
     if (toThrow != null && toThrow instanceof RuntimeException) {
       throw (RuntimeException) toThrow;
     } else {
       throw new LoaderException(toThrow);
     }
   }
 }
  public static void inject(
      ModContainer mod, ASMDataTable data, Side side, ILanguageAdapter languageAdapter) {
    FMLLog.fine("Attempting to inject @SidedProxy classes into %s", mod.getModId());
    Set<ASMData> targets = data.getAnnotationsFor(mod).get(SidedProxy.class.getName());
    ClassLoader mcl = Loader.instance().getModClassLoader();

    for (ASMData targ : targets) {
      try {
        Class<?> proxyTarget = Class.forName(targ.getClassName(), true, mcl);
        Field target = proxyTarget.getDeclaredField(targ.getObjectName());
        if (target == null) {
          // Impossible?
          FMLLog.severe(
              "Attempted to load a proxy type into %s.%s but the field was not found",
              targ.getClassName(), targ.getObjectName());
          throw new LoaderException();
        }

        SidedProxy annotation = target.getAnnotation(SidedProxy.class);
        if (!Strings.isNullOrEmpty(annotation.modId())
            && !annotation.modId().equals(mod.getModId())) {
          FMLLog.fine(
              "Skipping proxy injection for %s.%s since it is not for mod %s",
              targ.getClassName(), targ.getObjectName(), mod.getModId());
          continue;
        }
        String targetType = side.isClient() ? annotation.clientSide() : annotation.serverSide();
        Object proxy = Class.forName(targetType, true, mcl).newInstance();

        if (languageAdapter.supportsStatics() && (target.getModifiers() & Modifier.STATIC) == 0) {
          FMLLog.severe(
              "Attempted to load a proxy type %s into %s.%s, but the field is not static",
              targetType, targ.getClassName(), targ.getObjectName());
          throw new LoaderException();
        }
        if (!target.getType().isAssignableFrom(proxy.getClass())) {
          FMLLog.severe(
              "Attempted to load a proxy type %s into %s.%s, but the types don't match",
              targetType, targ.getClassName(), targ.getObjectName());
          throw new LoaderException();
        }
        languageAdapter.setProxy(target, proxyTarget, proxy);
      } catch (Exception e) {
        FMLLog.log(
            Level.SEVERE,
            e,
            "An error occured trying to load a proxy into %s.%s",
            targ.getAnnotationInfo(),
            targ.getClassName(),
            targ.getObjectName());
        throw new LoaderException(e);
      }
    }

    // Allow language specific proxy injection.
    languageAdapter.setInternalProxies(mod, side, mcl);
  }
예제 #3
0
  private void initializeLoader() {
    File modsDir = new File(minecraftDir, "mods");
    File configDir = new File(minecraftDir, "config");
    String canonicalModsPath;
    String canonicalConfigPath;

    try {
      canonicalModsPath = modsDir.getCanonicalPath();
      canonicalConfigPath = configDir.getCanonicalPath();
      canonicalConfigDir = configDir.getCanonicalFile();
      canonicalModsDir = modsDir.getCanonicalFile();
    } catch (IOException ioe) {
      FMLLog.log(
          Level.ERROR,
          ioe,
          "Failed to resolve loader directories: mods : %s ; config %s",
          canonicalModsDir.getAbsolutePath(),
          configDir.getAbsolutePath());
      throw new LoaderException(ioe);
    }

    if (!canonicalModsDir.exists()) {
      FMLLog.info("No mod directory found, creating one: %s", canonicalModsPath);
      boolean dirMade = canonicalModsDir.mkdir();
      if (!dirMade) {
        FMLLog.severe("Unable to create the mod directory %s", canonicalModsPath);
        throw new LoaderException(
            String.format("Unable to create the mod directory %s", canonicalModsPath));
      }
      FMLLog.info("Mod directory created successfully");
    }

    if (!canonicalConfigDir.exists()) {
      FMLLog.fine("No config directory found, creating one: %s", canonicalConfigPath);
      boolean dirMade = canonicalConfigDir.mkdir();
      if (!dirMade) {
        FMLLog.severe("Unable to create the config directory %s", canonicalConfigPath);
        throw new LoaderException();
      }
      FMLLog.info("Config directory created successfully");
    }

    if (!canonicalModsDir.isDirectory()) {
      FMLLog.severe("Attempting to load mods from %s, which is not a directory", canonicalModsPath);
      throw new LoaderException();
    }

    if (!configDir.isDirectory()) {
      FMLLog.severe(
          "Attempting to load configuration from %s, which is not a directory",
          canonicalConfigPath);
      throw new LoaderException();
    }

    readInjectedDependencies();
  }
예제 #4
0
 public BiMap<ModContainer, Object> getModObjectList() {
   if (modObjectList == null) {
     FMLLog.severe(
         "Detected an attempt by a mod %s to perform game activity during mod construction. This is a serious programming error.",
         activeContainer);
     return buildModObjectList();
   }
   return ImmutableBiMap.copyOf(modObjectList);
 }
예제 #5
0
  private Loader() {
    modClassLoader = new ModClassLoader(getClass().getClassLoader());
    if (!mccversion.equals(MC_VERSION)) {
      FMLLog.severe(
          "This version of FML is built for Minecraft %s, we have detected Minecraft %s in your minecraft jar file",
          mccversion, MC_VERSION);
      throw new LoaderException(
          String.format(
              "This version of FML is built for Minecraft %s, we have detected Minecraft %s in your minecraft jar file",
              mccversion, MC_VERSION));
    }

    minecraft = new MinecraftDummyContainer(MC_VERSION);
    mcp =
        new MCPDummyContainer(
            MetadataCollection.from(getClass().getResourceAsStream("/mcpmod.info"), "MCP")
                .getMetadataForId("mcp", null));
  }
예제 #6
0
 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();
 }
예제 #7
0
  private Multimap<Class<? extends Annotation>, Object> gatherAnnotations(Class<?> clazz)
      throws Exception {
    Multimap<Class<? extends Annotation>, Object> anns = ArrayListMultimap.create();

    for (Method m : clazz.getDeclaredMethods()) {
      for (Annotation a : m.getAnnotations()) {
        if (modTypeAnnotations.containsKey(a.annotationType())) {
          Class<?>[] paramTypes = new Class[] {modTypeAnnotations.get(a.annotationType())};

          if (Arrays.equals(m.getParameterTypes(), paramTypes)) {
            m.setAccessible(true);
            anns.put(a.annotationType(), m);
          } else {
            FMLLog.severe(
                "The mod %s appears to have an invalid method annotation %s. This annotation can only apply to methods with argument types %s -it will not be called",
                getModId(), a.annotationType().getSimpleName(), Arrays.toString(paramTypes));
          }
        }
      }
    }
    return anns;
  }
예제 #8
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);
    }
  }
예제 #9
0
  /**
   * Fire a FMLMissingMappingsEvent to let mods determine how blocks/items defined in the world
   * save, but missing from the runtime, are to be handled.
   *
   * @param missing Map containing missing names with their associated id, blocks need to come
   *     before items for remapping.
   * @param isLocalWorld Whether this is executing for a world load (local/server) or a client.
   * @param gameData GameData instance where the new map's config is to be loaded into.
   * @return List with the mapping results.
   */
  public List<String> fireMissingMappingEvent(
      LinkedHashMap<String, Integer> missingBlocks,
      LinkedHashMap<String, Integer> missingItems,
      boolean isLocalWorld,
      GameData gameData,
      Map<String, Integer[]> remapBlocks,
      Map<String, Integer[]> remapItems) {
    if (missingBlocks.isEmpty() && missingItems.isEmpty()) // nothing to do
    {
      return ImmutableList.of();
    }

    FMLLog.fine(
        "There are %d mappings missing - attempting a mod remap",
        missingBlocks.size() + missingItems.size());
    ArrayListMultimap<String, MissingMapping> missingMappings = ArrayListMultimap.create();

    for (Map.Entry<String, Integer> mapping : missingBlocks.entrySet()) {
      MissingMapping m =
          new MissingMapping(GameRegistry.Type.BLOCK, mapping.getKey(), mapping.getValue());
      missingMappings.put(m.name.substring(0, m.name.indexOf(':')), m);
    }
    for (Map.Entry<String, Integer> mapping : missingItems.entrySet()) {
      MissingMapping m =
          new MissingMapping(GameRegistry.Type.ITEM, mapping.getKey(), mapping.getValue());
      missingMappings.put(m.name.substring(0, m.name.indexOf(':')), m);
    }

    FMLMissingMappingsEvent missingEvent = new FMLMissingMappingsEvent(missingMappings);
    modController.propogateStateMessage(missingEvent);

    if (isLocalWorld) // local world, warn about entries still being set to the default action
    {
      boolean didWarn = false;

      for (MissingMapping mapping : missingMappings.values()) {
        if (mapping.getAction() == FMLMissingMappingsEvent.Action.DEFAULT) {
          if (!didWarn) {
            FMLLog.severe(
                "There are unidentified mappings in this world - we are going to attempt to process anyway");
            didWarn = true;
          }

          FMLLog.severe(
              "Unidentified %s: %s, id %d",
              mapping.type == Type.BLOCK ? "block" : "item", mapping.name, mapping.id);
        }
      }
    } else // remote world, fail on entries with the default action
    {
      List<String> missedMapping = new ArrayList<String>();

      for (MissingMapping mapping : missingMappings.values()) {
        if (mapping.getAction() == FMLMissingMappingsEvent.Action.DEFAULT) {
          missedMapping.add(mapping.name);
        }
      }

      if (!missedMapping.isEmpty()) {
        return ImmutableList.copyOf(missedMapping);
      }
    }

    return GameData.processIdRematches(
        missingMappings.values(), isLocalWorld, gameData, remapBlocks, remapItems);
  }
예제 #10
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");
      }
    }
  }