@Subscribe public void buildModList(FMLLoadEvent event) { this.modList = loader.getIndexedModList(); Builder<String, EventBus> eventBus = ImmutableMap.builder(); for (ModContainer mod : loader.getModList()) { EventBus bus = new EventBus(mod.getModId()); boolean isActive = mod.registerBus(bus, this); if (isActive) { Level level = Logger.getLogger(mod.getModId()).getLevel(); FMLLog.log( mod.getModId(), Level.FINE, "Mod Logging channel %s configured at %s level.", level == null ? "default" : level); FMLLog.log(mod.getModId(), Level.INFO, "Activating mod %s", mod.getModId()); activeModList.add(mod); modStates.put(mod.getModId(), ModState.UNLOADED); eventBus.put(mod.getModId(), bus); } else { FMLLog.log( mod.getModId(), Level.WARNING, "Mod %s has been disabled through configuration", mod.getModId()); modStates.put(mod.getModId(), ModState.UNLOADED); modStates.put(mod.getModId(), ModState.DISABLED); } } eventChannels = eventBus.build(); }
private void parseSimpleFieldAnnotation( SetMultimap<String, ASMData> annotations, String annotationClassName, Function<ModContainer, Object> retreiver) throws IllegalAccessException { String[] annName = annotationClassName.split("\\."); String annotationName = annName[annName.length - 1]; for (ASMData targets : annotations.get(annotationClassName)) { String targetMod = (String) targets.getAnnotationInfo().get("value"); Field f = null; Object injectedMod = null; ModContainer mc = this; boolean isStatic = false; Class<?> clz = modInstance.getClass(); if (!Strings.isNullOrEmpty(targetMod)) { if (Loader.isModLoaded(targetMod)) { mc = Loader.instance().getIndexedModList().get(targetMod); } else { mc = null; } } if (mc != null) { try { clz = Class.forName(targets.getClassName(), true, Loader.instance().getModClassLoader()); f = clz.getDeclaredField(targets.getObjectName()); f.setAccessible(true); isStatic = Modifier.isStatic(f.getModifiers()); injectedMod = retreiver.apply(mc); } catch (Exception e) { Throwables.propagateIfPossible(e); FMLLog.log( getModId(), Level.WARNING, e, "Attempting to load @%s in class %s for %s and failing", annotationName, targets.getClassName(), mc.getModId()); } } if (f != null) { Object target = null; if (!isStatic) { target = modInstance; if (!modInstance.getClass().equals(clz)) { FMLLog.log( getModId(), Level.WARNING, "Unable to inject @%s in non-static field %s.%s for %s as it is NOT the primary mod instance", annotationName, targets.getClassName(), targets.getObjectName(), mc.getModId()); continue; } } f.set(target, injectedMod); } } }
public void errorOccurred(ModContainer modContainer, Throwable exception) { if (exception instanceof InvocationTargetException) { errors.put(modContainer.getModId(), ((InvocationTargetException) exception).getCause()); } else { errors.put(modContainer.getModId(), exception); } }
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); }
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())); } }
public void handleWorldDataSave( SaveHandler handler, WorldInfo worldInfo, NBTTagCompound tagCompound) { for (ModContainer mc : Loader.instance().getModList()) { if (mc instanceof InjectedModContainer) { WorldAccessContainer wac = ((InjectedModContainer) mc).getWrappedWorldAccessContainer(); if (wac != null) { NBTTagCompound dataForWriting = wac.getDataForWriting(handler, worldInfo); tagCompound.func_74766_a(mc.getModId(), dataForWriting); } } } }
@Override public NBTTagCompound getDataForWriting(SaveHandler handler, WorldInfo info) { NBTTagCompound fmlData = new NBTTagCompound(); NBTTagList list = new NBTTagList(); for (ModContainer mc : Loader.instance().getActiveModList()) { NBTTagCompound mod = new NBTTagCompound(); mod.setString("ModId", mc.getModId()); mod.setString("ModVersion", mc.getVersion()); list.appendTag(mod); } fmlData.setTag("ModList", list); NBTTagList itemList = new NBTTagList(); GameData.writeItemData(itemList); fmlData.setTag("ModItemData", itemList); return fmlData; }
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(); }
public void handleWorldDataLoad( SaveHandler handler, WorldInfo worldInfo, NBTTagCompound tagCompound) { if (getEffectiveSide() != Side.SERVER) { return; } if (handlerSet.contains(handler)) { return; } handlerSet.add(handler); Map<String, NBTBase> additionalProperties = Maps.newHashMap(); worldInfo.setAdditionalProperties(additionalProperties); for (ModContainer mc : Loader.instance().getModList()) { if (mc instanceof InjectedModContainer) { WorldAccessContainer wac = ((InjectedModContainer) mc).getWrappedWorldAccessContainer(); if (wac != null) { wac.readData( handler, worldInfo, additionalProperties, tagCompound.func_74775_l(mc.getModId())); } } } }
@Subscribe public void propogateStateMessage(FMLEvent stateEvent) { if (stateEvent instanceof FMLPreInitializationEvent) { modObjectList = buildModObjectList(); } for (ModContainer mc : activeModList) { activeContainer = mc; String modId = mc.getModId(); stateEvent.applyModContainer(activeContainer()); FMLLog.log( modId, Level.FINEST, "Sending event %s to mod %s", stateEvent.getEventType(), modId); eventChannels.get(modId).post(stateEvent); FMLLog.log(modId, Level.FINEST, "Sent event %s to mod %s", stateEvent.getEventType(), modId); activeContainer = null; if (stateEvent instanceof FMLStateEvent) { if (!errors.containsKey(modId)) { modStates.put(modId, ((FMLStateEvent) stateEvent).getModState()); } else { modStates.put(modId, ModState.ERRORED); } } } }
/** * 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); }
@Override public int compare(ModContainer o1, ModContainer o2) { return o1.getModId().compareTo(o2.getModId()); }
/** * 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"); } } }
public ModState getModState(ModContainer selectedMod) { return Iterables.getLast(modStates.get(selectedMod.getModId()), ModState.AVAILABLE); }