/* * Minecraft Forge * Copyright (c) 2016-2019. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation version 2.1 * of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ package net.minecraftforge.fml.loading; import cpw.mods.modlauncher.TransformingClassLoader; import cpw.mods.modlauncher.api.IEnvironment; import cpw.mods.modlauncher.api.ILaunchHandlerService; import cpw.mods.modlauncher.api.ITransformationService; import cpw.mods.modlauncher.api.ITransformingClassLoader; import cpw.mods.modlauncher.api.IncompatibleEnvironmentException; import cpw.mods.modlauncher.serviceapi.ILaunchPluginService; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.fml.loading.moddiscovery.BackgroundScanHandler; import net.minecraftforge.fml.loading.moddiscovery.ModDiscoverer; import net.minecraftforge.fml.loading.moddiscovery.ModFile; import net.minecraftforge.forgespi.coremod.ICoreModProvider; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.net.URL; import java.nio.file.Path; import java.nio.file.Paths; import java.util.*; import java.util.function.Predicate; import java.util.stream.Collectors; import static net.minecraftforge.fml.loading.LogMarkers.CORE; import static net.minecraftforge.fml.loading.LogMarkers.SCAN; public class FMLLoader { private static final Logger LOGGER = LogManager.getLogger(); private static ILaunchPluginService accessTransformer; private static ModDiscoverer modDiscoverer; private static ICoreModProvider coreModProvider; private static ILaunchPluginService eventBus; private static LanguageLoadingProvider languageLoadingProvider; private static Dist dist; private static LoadingModList loadingModList; private static TransformingClassLoader launchClassLoader; private static RuntimeDistCleaner runtimeDistCleaner; private static Path gamePath; private static Path forgePath; private static Path[] mcPaths; static String mcVersion; private static String mcpVersion; static String forgeVersion; private static String forgeGroup; private static Predicate classLoaderExclusions; static void onInitialLoad(IEnvironment environment, Set otherServices) throws IncompatibleEnvironmentException { final String version = LauncherVersion.getVersion(); LOGGER.debug(CORE,"FML {} loading", version); final Package modLauncherPackage = ITransformationService.class.getPackage(); LOGGER.debug(CORE,"FML found ModLauncher version : {}", modLauncherPackage.getImplementationVersion()); if (!modLauncherPackage.isCompatibleWith("1.0")) { LOGGER.fatal(CORE,"Found incompatible ModLauncher specification : {}, version {} from {}", modLauncherPackage.getSpecificationVersion(), modLauncherPackage.getImplementationVersion(), modLauncherPackage.getImplementationVendor()); throw new IncompatibleEnvironmentException("Incompatible modlauncher found "+modLauncherPackage.getSpecificationVersion()); } LOGGER.debug(CORE, "Initializing modjar URL handler"); URL.setURLStreamHandlerFactory(p->p.equals("modjar") ? new ModJarURLHandler() : null); accessTransformer = environment.findLaunchPlugin("accesstransformer").orElseThrow(()-> new IncompatibleEnvironmentException("Missing AccessTransformer, cannot run")); final Package atPackage = accessTransformer.getClass().getPackage(); LOGGER.debug(CORE,"FML found AccessTransformer version : {}", atPackage.getImplementationVersion()); if (!atPackage.isCompatibleWith("1.0")) { LOGGER.fatal(CORE,"Found incompatible AccessTransformer specification : {}, version {} from {}", atPackage.getSpecificationVersion(), atPackage.getImplementationVersion(), atPackage.getImplementationVendor()); throw new IncompatibleEnvironmentException("Incompatible accesstransformer found "+atPackage.getSpecificationVersion()); } eventBus = environment.findLaunchPlugin("eventbus").orElseThrow(()-> new IncompatibleEnvironmentException("Missing EventBus, cannot run")); final Package eventBusPackage = eventBus.getClass().getPackage(); LOGGER.debug(CORE,"FML found EventBus version : {}", eventBusPackage.getImplementationVersion()); if (!eventBusPackage.isCompatibleWith("1.0")) { LOGGER.fatal(CORE,"Found incompatible EventBus specification : {}, version {} from {}", eventBusPackage.getSpecificationVersion(), eventBusPackage.getImplementationVersion(), eventBusPackage.getImplementationVendor()); throw new IncompatibleEnvironmentException("Incompatible eventbus found "+eventBusPackage.getSpecificationVersion()); } runtimeDistCleaner = (RuntimeDistCleaner)environment.findLaunchPlugin("runtimedistcleaner").orElseThrow(()->new IncompatibleEnvironmentException("Missing RuntimeDistCleaner, cannot run!")); LOGGER.debug(CORE, "Found Runtime Dist Cleaner"); final ArrayList coreModProviders = new ArrayList<>(); ServiceLoader.load(ICoreModProvider.class).forEach(coreModProviders::add); if (coreModProviders.isEmpty()) { LOGGER.fatal(CORE, "Found no coremod provider. Cannot run"); throw new IncompatibleEnvironmentException("No coremod library found"); } else if (coreModProviders.size() > 1) { LOGGER.fatal(CORE, "Found multiple coremod providers : {}. Cannot run", coreModProviders.stream().map(p -> p.getClass().getName()).collect(Collectors.toList())); throw new IncompatibleEnvironmentException("Multiple coremod libraries found"); } coreModProvider = coreModProviders.get(0); final Package coremodPackage = coreModProvider.getClass().getPackage(); LOGGER.debug(CORE,"FML found CoreMod version : {}", coremodPackage.getImplementationVersion()); } static void setupLaunchHandler(final IEnvironment environment, final Map arguments) { final String launchTarget = environment.getProperty(IEnvironment.Keys.LAUNCHTARGET.get()).orElse("MISSING"); final Optional launchHandler = environment.findLaunchHandler(launchTarget); LOGGER.debug(CORE, "Using {} as launch service", launchTarget); if (!launchHandler.isPresent()) { LOGGER.fatal(CORE,"Missing LaunchHandler {}, cannot continue", launchTarget); throw new RuntimeException("Missing launch handler"); } if (!(launchHandler.get() instanceof FMLCommonLaunchHandler)) { LOGGER.fatal(CORE, "Incompatible Launch handler found - type {}, cannot continue", launchHandler.get().getClass().getName()); throw new RuntimeException("Incompatible launch handler found"); } gamePath = environment.getProperty(IEnvironment.Keys.GAMEDIR.get()).orElse(Paths.get(".").toAbsolutePath()); FMLCommonLaunchHandler commonLaunchHandler = (FMLCommonLaunchHandler)launchHandler.get(); dist = commonLaunchHandler.getDist(); mcVersion = (String) arguments.get("mcVersion"); mcpVersion = (String) arguments.get("mcpVersion"); forgeVersion = (String) arguments.get("forgeVersion"); forgeGroup = (String) arguments.get("forgeGroup"); LOGGER.debug(CORE,"Received command line version data : MC Version: '{}' MCP Version: '{}' Forge Version: '{}' Forge group: '{}'", mcVersion, mcpVersion, forgeVersion, forgeGroup); forgePath = commonLaunchHandler.getForgePath(mcVersion, forgeVersion, forgeGroup); mcPaths = commonLaunchHandler.getMCPaths(mcVersion, mcpVersion, forgeVersion, forgeGroup); commonLaunchHandler.validatePaths(forgePath, mcPaths, forgeVersion, mcVersion, mcpVersion); commonLaunchHandler.setup(environment, arguments); classLoaderExclusions = commonLaunchHandler.getPackagePredicate(); languageLoadingProvider = new LanguageLoadingProvider(); languageLoadingProvider.addForgeLanguage(forgePath); runtimeDistCleaner.getExtension().accept(dist); } public static void beginModScan(final Map arguments) { LOGGER.debug(SCAN,"Scanning for Mod Locators"); modDiscoverer = new ModDiscoverer(arguments); final BackgroundScanHandler backgroundScanHandler = modDiscoverer.discoverMods(); loadingModList = backgroundScanHandler.getLoadingModList(); } public static ICoreModProvider getCoreModProvider() { return coreModProvider; } public static LanguageLoadingProvider getLanguageLoadingProvider() { return languageLoadingProvider; } static ModDiscoverer getModDiscoverer() { return modDiscoverer; } public static void addAccessTransformer(Path atPath, ModFile modName) { LOGGER.debug(SCAN, "Adding Access Transformer in {}", modName.getFilePath()); accessTransformer.addResource(atPath, modName.getFileName()); } public static Dist getDist() { return dist; } public static void beforeStart(ITransformingClassLoader launchClassLoader) { FMLLoader.launchClassLoader = (TransformingClassLoader) launchClassLoader.getInstance(); } public static LoadingModList getLoadingModList() { return loadingModList; } public static TransformingClassLoader getLaunchClassLoader() { return launchClassLoader; } public static Path getGamePath() { return gamePath; } public static Path getForgePath() { return forgePath; } public static Path[] getMCPaths() { return mcPaths; } public static Predicate getClassLoaderExclusions() { return classLoaderExclusions; } }