From 14ac77e4445600a655c81c3e0ba0e65b7ffb39b3 Mon Sep 17 00:00:00 2001 From: cpw Date: Sun, 25 Mar 2018 11:59:43 -0400 Subject: [PATCH] Goodbye @Mod, it was lovely knowing you! --- gradle/wrapper/gradle-wrapper.jar | Bin 52271 -> 53319 bytes gradle/wrapper/gradle-wrapper.properties | 4 +- gradlew | 52 +++---- gradlew.bat | 8 +- .../common/config/ConfigManager.java | 2 +- .../net/minecraftforge/fml/FMLConfig.java | 85 +++++++++++ .../net/minecraftforge/fml/FileUtils.java | 51 +++++++ .../net/minecraftforge/fml/LaunchTesting.java | 33 +++++ .../java/net/minecraftforge/fml/Logging.java | 30 ++++ .../fml/common/AutomaticEventSubscriber.java | 3 +- .../minecraftforge/fml/common/FMLPaths.java | 84 +++++++++++ .../fml/common/ModContainerFactory.java | 3 +- .../common/discovery/asm/ASMModParser.java | 2 + .../common/discovery/asm/ModClassVisitor.java | 64 --------- .../fml/common/discovery/json/ASMInfo.java | 3 +- .../fml/loading/FMLLaunchProvider.java | 46 ++++++ .../minecraftforge/fml/loading/FMLLoader.java | 62 ++++++++ .../fml/loading/FMLServiceProvider.java | 90 ++++++++++++ .../moddiscovery/BackgroundScanHandler.java | 79 +++++++++++ .../fml/loading/moddiscovery/CoreModFile.java | 42 ++++++ .../ExplodedDirectoryLocator.java | 70 ++++++++++ .../fml/loading/moddiscovery/IModLocator.java | 42 ++++++ .../moddiscovery}/ModAnnotation.java | 17 +-- .../moddiscovery}/ModAnnotationVisitor.java | 39 +++--- .../loading/moddiscovery/ModClassVisitor.java | 84 +++++++++++ .../loading/moddiscovery/ModDiscoverer.java | 66 +++++++++ .../moddiscovery}/ModFieldVisitor.java | 20 +-- .../fml/loading/moddiscovery/ModFile.java | 132 ++++++++++++++++++ .../loading/moddiscovery/ModFileParser.java | 71 ++++++++++ .../fml/loading/moddiscovery/ModInfo.java | 84 +++++++++++ .../moddiscovery}/ModMethodVisitor.java | 17 ++- .../moddiscovery/ModsFolderLocator.java | 108 ++++++++++++++ .../fml/loading/moddiscovery/ScanResult.java | 95 +++++++++++++ .../fml/loading/moddiscovery/Scanner.java | 50 +++++++ ...mods.modlauncher.api.ILaunchHandlerService | 1 + ...ods.modlauncher.api.ITransformationService | 1 + src/main/resources/log4j2.xml | 77 +++++----- 37 files changed, 1541 insertions(+), 176 deletions(-) create mode 100644 src/main/java/net/minecraftforge/fml/FMLConfig.java create mode 100644 src/main/java/net/minecraftforge/fml/FileUtils.java create mode 100644 src/main/java/net/minecraftforge/fml/LaunchTesting.java create mode 100644 src/main/java/net/minecraftforge/fml/Logging.java create mode 100644 src/main/java/net/minecraftforge/fml/common/FMLPaths.java delete mode 100644 src/main/java/net/minecraftforge/fml/common/discovery/asm/ModClassVisitor.java create mode 100644 src/main/java/net/minecraftforge/fml/loading/FMLLaunchProvider.java create mode 100644 src/main/java/net/minecraftforge/fml/loading/FMLLoader.java create mode 100644 src/main/java/net/minecraftforge/fml/loading/FMLServiceProvider.java create mode 100644 src/main/java/net/minecraftforge/fml/loading/moddiscovery/BackgroundScanHandler.java create mode 100644 src/main/java/net/minecraftforge/fml/loading/moddiscovery/CoreModFile.java create mode 100644 src/main/java/net/minecraftforge/fml/loading/moddiscovery/ExplodedDirectoryLocator.java create mode 100644 src/main/java/net/minecraftforge/fml/loading/moddiscovery/IModLocator.java rename src/main/java/net/minecraftforge/fml/{common/discovery/asm => loading/moddiscovery}/ModAnnotation.java (87%) rename src/main/java/net/minecraftforge/fml/{common/discovery/asm => loading/moddiscovery}/ModAnnotationVisitor.java (56%) create mode 100644 src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModClassVisitor.java create mode 100644 src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModDiscoverer.java rename src/main/java/net/minecraftforge/fml/{common/discovery/asm => loading/moddiscovery}/ModFieldVisitor.java (66%) create mode 100644 src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModFile.java create mode 100644 src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModFileParser.java create mode 100644 src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModInfo.java rename src/main/java/net/minecraftforge/fml/{common/discovery/asm => loading/moddiscovery}/ModMethodVisitor.java (68%) create mode 100644 src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModsFolderLocator.java create mode 100644 src/main/java/net/minecraftforge/fml/loading/moddiscovery/ScanResult.java create mode 100644 src/main/java/net/minecraftforge/fml/loading/moddiscovery/Scanner.java create mode 100644 src/main/resources/META-INF/services/cpw.mods.modlauncher.api.ILaunchHandlerService create mode 100644 src/main/resources/META-INF/services/cpw.mods.modlauncher.api.ITransformationService diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 30d399d8d2bf522ff5de94bf434a7cc43a9a74b5..d3b83982b9b1bccad955349d702be9b884c6e049 100644 GIT binary patch delta 15577 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 \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" @@ -30,6 +48,7 @@ die ( ) { cygwin=false msys=false darwin=false +nonstop=false case "`uname`" in CYGWIN* ) cygwin=true @@ -40,31 +59,11 @@ case "`uname`" in MINGW* ) msys=true ;; + NONSTOP* ) + nonstop=true + ;; esac -# For Cygwin, ensure paths are in UNIX format before anything is touched. -if $cygwin ; then - [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` -fi - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >&- -APP_HOME="`pwd -P`" -cd "$SAVED" >&- - CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -90,7 +89,7 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then @@ -114,6 +113,7 @@ fi if $cygwin ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` diff --git a/gradlew.bat b/gradlew.bat index 8a0b282aa..832fdb607 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -8,14 +8,14 @@ @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome @@ -46,7 +46,7 @@ echo location of your Java installation. goto fail :init -@rem Get command-line arguments, handling Windowz variants +@rem Get command-line arguments, handling Windows variants if not "%OS%" == "Windows_NT" goto win9xME_args if "%@eval[2+2]" == "4" goto 4NT_args diff --git a/src/main/java/net/minecraftforge/common/config/ConfigManager.java b/src/main/java/net/minecraftforge/common/config/ConfigManager.java index 750f461d1..5eb752c34 100644 --- a/src/main/java/net/minecraftforge/common/config/ConfigManager.java +++ b/src/main/java/net/minecraftforge/common/config/ConfigManager.java @@ -41,7 +41,7 @@ import net.minecraftforge.fml.common.Loader; import net.minecraftforge.fml.common.LoaderException; import net.minecraftforge.fml.common.discovery.ASMDataTable; import net.minecraftforge.fml.common.discovery.ASMDataTable.ASMData; -import net.minecraftforge.fml.common.discovery.asm.ModAnnotation.EnumHolder; +import net.minecraftforge.fml.loading.moddiscovery.ModAnnotation.EnumHolder; import org.apache.commons.lang3.StringUtils; diff --git a/src/main/java/net/minecraftforge/fml/FMLConfig.java b/src/main/java/net/minecraftforge/fml/FMLConfig.java new file mode 100644 index 000000000..ba9b33d07 --- /dev/null +++ b/src/main/java/net/minecraftforge/fml/FMLConfig.java @@ -0,0 +1,85 @@ +/* + * Minecraft Forge + * Copyright (c) 2018. + * + * 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; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import net.minecraftforge.fml.common.FMLPaths; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.lang.reflect.Type; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; + +import static net.minecraftforge.fml.Logging.fmlLog; + +public class FMLConfig +{ + private static FMLConfig INSTANCE; + private final Map configData = new HashMap<>(); + + private FMLConfig() { + configData.putAll(defaultValues()); + } + + private Map defaultValues() { + final Map result = new HashMap<>(); + result.put("splashscreen", "true"); + return result; + } + + private void loadFrom(final Path configFile) throws IOException + { + final Type type = new TypeToken>() {}.getType(); + final Gson gson = new Gson(); + final Map loadedConfig = gson.fromJson(Files.newBufferedReader(configFile), type); + if (loadedConfig != null) + configData.putAll(loadedConfig); + } + + private void saveConfigIfNecessary(final Path configFile) throws IOException { + final Type type = new TypeToken>() {}.getType(); + final Gson gson = new Gson(); + final BufferedWriter writer = Files.newBufferedWriter(configFile); + gson.toJson(configData, type, writer); + writer.flush(); + } + public static void load() + { + final Path configFile = FMLPaths.FMLCONFIG.get(); + INSTANCE = new FMLConfig(); + try + { + if (Files.exists(configFile)) + { + INSTANCE.loadFrom(configFile); + } + INSTANCE.saveConfigIfNecessary(configFile); + } + catch (IOException ioe) + { + fmlLog.error("Unable to read FML config at {}", configFile, ioe); + throw new RuntimeException("Unable to read FML config", ioe); + } + } +} diff --git a/src/main/java/net/minecraftforge/fml/FileUtils.java b/src/main/java/net/minecraftforge/fml/FileUtils.java new file mode 100644 index 000000000..e33ab2d91 --- /dev/null +++ b/src/main/java/net/minecraftforge/fml/FileUtils.java @@ -0,0 +1,51 @@ +/* + * Minecraft Forge + * Copyright (c) 2018. + * + * 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; + +import java.io.IOException; +import java.nio.file.FileAlreadyExistsException; +import java.nio.file.Files; +import java.nio.file.Path; + +import static net.minecraftforge.fml.Logging.fmlLog; + +public class FileUtils +{ + public static Path getOrCreateDirectory(Path dirPath, String dirLabel) { + if (!Files.isDirectory(dirPath)) + { + fmlLog.debug("Making {} directory : {}", dirLabel, dirPath); + try { + Files.createDirectory(dirPath); + } catch (IOException e) { + if (e instanceof FileAlreadyExistsException) { + fmlLog.error("Failed to create {} directory - there is a file in the way", dirLabel); + } else { + fmlLog.error("Problem with creating {} directory (Permissions?)", dirLabel, e); + } + throw new RuntimeException("Problem creating directory", e); + } + fmlLog.debug("Created {} directory : {}", dirLabel, dirPath); + } else { + fmlLog.debug("Found existing {} directory : {}", dirLabel, dirPath); + } + return dirPath; + } +} diff --git a/src/main/java/net/minecraftforge/fml/LaunchTesting.java b/src/main/java/net/minecraftforge/fml/LaunchTesting.java new file mode 100644 index 000000000..c34b865a3 --- /dev/null +++ b/src/main/java/net/minecraftforge/fml/LaunchTesting.java @@ -0,0 +1,33 @@ +/* + * Minecraft Forge + * Copyright (c) 2018. + * + * 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; + +import cpw.mods.modlauncher.Launcher; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.core.config.Configurator; + +public class LaunchTesting +{ + public static void main(String... args) + { + Configurator.setRootLevel(Level.DEBUG); + Launcher.main("--launchTarget", "fml","--gameDir", "projects/run"); + } +} diff --git a/src/main/java/net/minecraftforge/fml/Logging.java b/src/main/java/net/minecraftforge/fml/Logging.java new file mode 100644 index 000000000..e97b6b782 --- /dev/null +++ b/src/main/java/net/minecraftforge/fml/Logging.java @@ -0,0 +1,30 @@ +/* + * Minecraft Forge + * Copyright (c) 2018. + * + * 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; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.config.Configurator; + +public class Logging +{ + public static final Logger fmlLog = LogManager.getLogger("FML"); +} diff --git a/src/main/java/net/minecraftforge/fml/common/AutomaticEventSubscriber.java b/src/main/java/net/minecraftforge/fml/common/AutomaticEventSubscriber.java index f53898838..791f3544e 100644 --- a/src/main/java/net/minecraftforge/fml/common/AutomaticEventSubscriber.java +++ b/src/main/java/net/minecraftforge/fml/common/AutomaticEventSubscriber.java @@ -25,9 +25,8 @@ import com.google.common.collect.SetMultimap; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.fml.common.discovery.ASMDataTable; import net.minecraftforge.fml.common.discovery.ASMDataTable.ASMData; -import net.minecraftforge.fml.common.discovery.asm.ModAnnotation; +import net.minecraftforge.fml.loading.moddiscovery.ModAnnotation; import net.minecraftforge.fml.relauncher.Side; -import org.apache.logging.log4j.Level; import java.util.EnumSet; import java.util.List; diff --git a/src/main/java/net/minecraftforge/fml/common/FMLPaths.java b/src/main/java/net/minecraftforge/fml/common/FMLPaths.java new file mode 100644 index 000000000..f53e9e2a0 --- /dev/null +++ b/src/main/java/net/minecraftforge/fml/common/FMLPaths.java @@ -0,0 +1,84 @@ +/* + * Minecraft Forge + * Copyright (c) 2018. + * + * 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.common; + +import cpw.mods.modlauncher.api.IEnvironment; +import net.minecraftforge.fml.FileUtils; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Objects; + +import static net.minecraftforge.fml.Logging.fmlLog; + +public enum FMLPaths +{ + GAMEDIR(), + MODSDIR("mods"), + CONFIGDIR("config"), + FMLCONFIG(false, CONFIGDIR, "fml.cfg"); + + private final Path relativePath; + private final boolean isDirectory; + private Path absolutePath; + + FMLPaths() { + this(""); + } + + FMLPaths(String... path) { + relativePath = computePath(path); + this.isDirectory = true; + } + + private Path computePath(String... path) + { + return Paths.get(path[0], Arrays.copyOfRange(path, 1, path.length)); + } + + FMLPaths(boolean isDir, FMLPaths parent, String... path) { + this.relativePath = parent.relativePath.resolve(computePath(path)); + this.isDirectory = isDir; + } + + public static void setup(IEnvironment env) { + final Path rootPath = env.getProperty(IEnvironment.Keys.GAMEDIR.get()).orElseThrow(() -> new RuntimeException("No game path found")); + + loadAbsolutePaths(rootPath); + } + + public static void loadAbsolutePaths(Path rootPath) + { + for (FMLPaths path : FMLPaths.values()) + { + path.absolutePath = rootPath.resolve(path.relativePath).toAbsolutePath(); + fmlLog.debug("Path {} is {}", ()-> path, ()-> path.absolutePath); + if (path.isDirectory) + { + FileUtils.getOrCreateDirectory(path.absolutePath, path.name()); + } + } + } + + public Path get() { + return absolutePath; + } +} diff --git a/src/main/java/net/minecraftforge/fml/common/ModContainerFactory.java b/src/main/java/net/minecraftforge/fml/common/ModContainerFactory.java index bed362f78..1df9a3b85 100644 --- a/src/main/java/net/minecraftforge/fml/common/ModContainerFactory.java +++ b/src/main/java/net/minecraftforge/fml/common/ModContainerFactory.java @@ -22,11 +22,10 @@ package net.minecraftforge.fml.common; import java.io.File; import java.lang.reflect.Constructor; import java.util.Map; -import java.util.regex.Pattern; import net.minecraftforge.fml.common.discovery.ModCandidate; import net.minecraftforge.fml.common.discovery.asm.ASMModParser; -import net.minecraftforge.fml.common.discovery.asm.ModAnnotation; +import net.minecraftforge.fml.loading.moddiscovery.ModAnnotation; import org.objectweb.asm.Type; diff --git a/src/main/java/net/minecraftforge/fml/common/discovery/asm/ASMModParser.java b/src/main/java/net/minecraftforge/fml/common/discovery/asm/ASMModParser.java index 96b09d52f..68f1ca7e1 100644 --- a/src/main/java/net/minecraftforge/fml/common/discovery/asm/ASMModParser.java +++ b/src/main/java/net/minecraftforge/fml/common/discovery/asm/ASMModParser.java @@ -29,6 +29,8 @@ import net.minecraftforge.fml.common.LoaderException; import net.minecraftforge.fml.common.discovery.ASMDataTable; import net.minecraftforge.fml.common.discovery.ModCandidate; +import net.minecraftforge.fml.loading.moddiscovery.ModAnnotation; +import net.minecraftforge.fml.loading.moddiscovery.ModClassVisitor; import org.objectweb.asm.ClassReader; import org.objectweb.asm.Type; diff --git a/src/main/java/net/minecraftforge/fml/common/discovery/asm/ModClassVisitor.java b/src/main/java/net/minecraftforge/fml/common/discovery/asm/ModClassVisitor.java deleted file mode 100644 index 2192fb054..000000000 --- a/src/main/java/net/minecraftforge/fml/common/discovery/asm/ModClassVisitor.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Minecraft Forge - * Copyright (c) 2016-2018. - * - * 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.common.discovery.asm; - -import org.objectweb.asm.AnnotationVisitor; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.FieldVisitor; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; - -public class ModClassVisitor extends ClassVisitor -{ - private ASMModParser discoverer; - - public ModClassVisitor(ASMModParser discoverer) - { - super(Opcodes.ASM5); - this.discoverer = discoverer; - } - - - @Override - public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) - { - discoverer.beginNewTypeName(name, version, superName, interfaces); - } - - @Override - public AnnotationVisitor visitAnnotation(String annotationName, boolean runtimeVisible) - { - discoverer.startClassAnnotation(annotationName); - return new ModAnnotationVisitor(discoverer); - } - - - @Override - public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) - { - return new ModFieldVisitor(name, discoverer); - } - - @Override - public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) - { - return new ModMethodVisitor(name, desc, discoverer); - } -} diff --git a/src/main/java/net/minecraftforge/fml/common/discovery/json/ASMInfo.java b/src/main/java/net/minecraftforge/fml/common/discovery/json/ASMInfo.java index 4afa6e348..5a740d00a 100644 --- a/src/main/java/net/minecraftforge/fml/common/discovery/json/ASMInfo.java +++ b/src/main/java/net/minecraftforge/fml/common/discovery/json/ASMInfo.java @@ -23,7 +23,6 @@ import java.util.List; import java.util.Map; import java.util.function.Function; -import org.apache.commons.lang3.Validate; import org.objectweb.asm.Type; import com.google.common.base.MoreObjects; @@ -31,7 +30,7 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import net.minecraftforge.fml.common.FMLLog; -import net.minecraftforge.fml.common.discovery.asm.ModAnnotation.EnumHolder; +import net.minecraftforge.fml.loading.moddiscovery.ModAnnotation.EnumHolder; //Package private, modders shouldn't access this. Do it through ASMDataTable. class ASMInfo diff --git a/src/main/java/net/minecraftforge/fml/loading/FMLLaunchProvider.java b/src/main/java/net/minecraftforge/fml/loading/FMLLaunchProvider.java new file mode 100644 index 000000000..09fd12ec3 --- /dev/null +++ b/src/main/java/net/minecraftforge/fml/loading/FMLLaunchProvider.java @@ -0,0 +1,46 @@ +/* + * Minecraft Forge + * Copyright (c) 2018. + * + * 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.api.ILaunchHandlerService; + +import java.nio.file.Path; +import java.util.concurrent.Callable; + +public class FMLLaunchProvider implements ILaunchHandlerService +{ + @Override + public String name() + { + return "fml"; + } + + @Override + public Path[] identifyTransformationTargets() + { + return new Path[0]; + } + + @Override + public Callable launchService(String[] arguments, ClassLoader launchClassLoader) + { + return () -> { return null; }; + } +} diff --git a/src/main/java/net/minecraftforge/fml/loading/FMLLoader.java b/src/main/java/net/minecraftforge/fml/loading/FMLLoader.java new file mode 100644 index 000000000..48db48ceb --- /dev/null +++ b/src/main/java/net/minecraftforge/fml/loading/FMLLoader.java @@ -0,0 +1,62 @@ +/* + * Minecraft Forge + * Copyright (c) 2018. + * + * 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.api.IEnvironment; +import cpw.mods.modlauncher.api.ITransformationService; +import cpw.mods.modlauncher.api.IncompatibleEnvironmentException; +import cpw.mods.modlauncher.serviceapi.ILaunchPluginService; +import net.minecraftforge.common.ForgeVersion; +import net.minecraftforge.fml.loading.moddiscovery.ModDiscoverer; + +import java.util.Set; + +import static net.minecraftforge.fml.Logging.fmlLog; + +public class FMLLoader +{ + + private static ILaunchPluginService accessTransformer; + private static ModDiscoverer modDiscoverer; + + static void initialize(IEnvironment environment, Set otherServices) throws IncompatibleEnvironmentException + { + final String version = ForgeVersion.getVersion(); + fmlLog.debug("FML {} loading", version); + final Package modLauncherPackage = ITransformationService.class.getPackage(); + fmlLog.debug("FML found ModLauncher version : {}", modLauncherPackage.getImplementationVersion()); + if (!modLauncherPackage.isCompatibleWith("1.0")) { + fmlLog.error("Found incompatible ModLauncher specification : {}, version {} from {}", modLauncherPackage.getSpecificationVersion(), modLauncherPackage.getImplementationVersion(), modLauncherPackage.getImplementationVendor()); + throw new IncompatibleEnvironmentException("Incompatible modlauncher found "+modLauncherPackage.getSpecificationVersion()); + } + + accessTransformer = environment.findLaunchPlugin("accesstransformer").orElseThrow(()-> new IncompatibleEnvironmentException("Missing AccessTransformer, cannot run")); + + final Package atPackage = accessTransformer.getClass().getPackage(); + fmlLog.debug("FML found AccessTransformer version : {}", atPackage.getImplementationVersion()); + if (!atPackage.isCompatibleWith("1.0")) { + fmlLog.error("Found incompatible AccessTransformer specification : {}, version {} from {}", atPackage.getSpecificationVersion(), atPackage.getImplementationVersion(), atPackage.getImplementationVendor()); + } +// final ILaunchPluginService coreMod = environment.findLaunchPlugin("coremod").orElseThrow(()-> new IncompatibleEnvironmentException("Missing CoreMod, cannot run")); + + fmlLog.debug("Scanning for Mod Locators"); + modDiscoverer = new ModDiscoverer(); + } +} diff --git a/src/main/java/net/minecraftforge/fml/loading/FMLServiceProvider.java b/src/main/java/net/minecraftforge/fml/loading/FMLServiceProvider.java new file mode 100644 index 000000000..4cda27b40 --- /dev/null +++ b/src/main/java/net/minecraftforge/fml/loading/FMLServiceProvider.java @@ -0,0 +1,90 @@ +/* + * Minecraft Forge + * Copyright (c) 2018. + * + * 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.api.IEnvironment; +import cpw.mods.modlauncher.api.ITransformationService; +import cpw.mods.modlauncher.api.ITransformer; +import cpw.mods.modlauncher.api.IncompatibleEnvironmentException; +import joptsimple.ArgumentAcceptingOptionSpec; +import joptsimple.OptionSpecBuilder; +import net.minecraftforge.fml.FMLConfig; +import net.minecraftforge.fml.common.FMLPaths; + +import javax.annotation.Nonnull; +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.function.BiFunction; + +import static net.minecraftforge.fml.Logging.fmlLog; + +public class FMLServiceProvider implements ITransformationService +{ + + private ArgumentAcceptingOptionSpec modsOption; + private ArgumentAcceptingOptionSpec modListsOption; + private List modsArgumentList; + private List modListsArgumentList; + + @Override + public String name() + { + return "fml"; + } + + @Override + public void initialize(IEnvironment environment) + { + fmlLog.debug("Setting up basic FML game directories"); + FMLPaths.setup(environment); + fmlLog.debug("Loading configuration"); + FMLConfig.load(); + } + + @Override + public void onLoad(IEnvironment environment, Set otherServices) throws IncompatibleEnvironmentException + { + FMLLoader.initialize(environment, otherServices); + } + + @Override + public void arguments(BiFunction argumentBuilder) + { + modsOption = argumentBuilder.apply("mods", "List of mods to add").withRequiredArg().ofType(String.class).withValuesSeparatedBy(","); + modListsOption = argumentBuilder.apply("modLists", "JSON modlists").withRequiredArg().ofType(String.class).withValuesSeparatedBy(","); + } + + @Override + public void argumentValues(OptionResult option) + { + modsArgumentList = option.values(modsOption); + modListsArgumentList = option.values(modListsOption); + } + + @Nonnull + @Override + public List transformers() + { + return Collections.emptyList(); + } + +} diff --git a/src/main/java/net/minecraftforge/fml/loading/moddiscovery/BackgroundScanHandler.java b/src/main/java/net/minecraftforge/fml/loading/moddiscovery/BackgroundScanHandler.java new file mode 100644 index 000000000..2e870f25c --- /dev/null +++ b/src/main/java/net/minecraftforge/fml/loading/moddiscovery/BackgroundScanHandler.java @@ -0,0 +1,79 @@ +/* + * Minecraft Forge + * Copyright (c) 2018. + * + * 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.moddiscovery; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import static net.minecraftforge.fml.Logging.fmlLog; + +public class BackgroundScanHandler +{ + private final ExecutorService modContentScanner; + private final List pendingFiles; + private final List scannedFiles; + private final List allFiles; + + public BackgroundScanHandler() { + modContentScanner = Executors.newCachedThreadPool(); + scannedFiles = new ArrayList<>(); + pendingFiles = new ArrayList<>(); + allFiles = new ArrayList<>(); + } + + public void submitForScanning(final ModFile file) { + if (modContentScanner.isShutdown()) { + throw new IllegalStateException("Scanner has shutdown"); + } + allFiles.add(file); + pendingFiles.add(file); + final CompletableFuture future = CompletableFuture.supplyAsync(file::compileContent, modContentScanner) + .whenComplete(file::setScanResult) + .whenComplete((r,t)-> this.addCompletedFile(file,r,t)); + file.setFutureScanResult(future); + } + + private void addCompletedFile(final ModFile file, final ScanResult scanResult, final Throwable throwable) { + if (throwable != null) { + fmlLog.error("An error occurred scanning file {}", file, throwable); + } + pendingFiles.remove(file); + scannedFiles.add(file); + } + + public List getScannedFiles() { + if (!pendingFiles.isEmpty()) { + modContentScanner.shutdown(); + try { + modContentScanner.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS); + } catch (InterruptedException e) { + } + } + return scannedFiles; + } + + public List getAllFiles() { + return allFiles; + } +} diff --git a/src/main/java/net/minecraftforge/fml/loading/moddiscovery/CoreModFile.java b/src/main/java/net/minecraftforge/fml/loading/moddiscovery/CoreModFile.java new file mode 100644 index 000000000..241055978 --- /dev/null +++ b/src/main/java/net/minecraftforge/fml/loading/moddiscovery/CoreModFile.java @@ -0,0 +1,42 @@ +/* + * Minecraft Forge + * Copyright (c) 2018. + * + * 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.moddiscovery; + +public class CoreModFile implements net.minecraftforge.forgespi.ICoreModFile { + private final java.nio.file.Path internalPath; + private final ModFile file; + private final String name; + + CoreModFile(final String name, final java.nio.file.Path path, final ModFile file) { + this.name = name; + this.internalPath = path; + this.file = file; + } + + @Override + public java.io.Reader readCoreMod() throws java.io.IOException { + return java.nio.file.Files.newBufferedReader(this.internalPath); + } + + @Override + public java.nio.file.Path getPath() { + return this.internalPath; + } +} diff --git a/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ExplodedDirectoryLocator.java b/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ExplodedDirectoryLocator.java new file mode 100644 index 000000000..cb5d10b76 --- /dev/null +++ b/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ExplodedDirectoryLocator.java @@ -0,0 +1,70 @@ +/* + * Minecraft Forge + * Copyright (c) 2018. + * + * 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.moddiscovery; + +import java.io.IOException; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.function.Consumer; +import java.util.stream.Stream; + +import static net.minecraftforge.fml.Logging.fmlLog; + +public class ExplodedDirectoryLocator implements IModLocator { + private static final String DIR = System.getProperty("fml.explodedDir", "modclasses"); + private final Path rootDir; + + ExplodedDirectoryLocator() { + this.rootDir = FileSystems.getDefault().getPath(DIR); + } + + @Override + public List scanMods() { + return Collections.singletonList(new ModFile(rootDir, this)); + } + + @Override + public String name() { + return "exploded directory"; + } + + @Override + public Path findPath(final ModFile modFile, final String... path) { + if (path.length < 1) { + throw new IllegalArgumentException("Missing path"); + } + return rootDir.resolve(FileSystems.getDefault().getPath(path[0], Arrays.copyOfRange(path, 1, path.length))); + } + + @Override + public void scanFile(final ModFile modFile, final Consumer pathConsumer) { + fmlLog.debug("Scanning directory {}", rootDir); + try (Stream files = Files.find(rootDir, Integer.MAX_VALUE, (p, a) -> p.getNameCount() > 0 && p.getFileName().toString().endsWith(".class"))) { + files.forEach(pathConsumer); + } catch (IOException e) { + e.printStackTrace(); + } + fmlLog.debug("Directory scan complete {}", rootDir); + } +} diff --git a/src/main/java/net/minecraftforge/fml/loading/moddiscovery/IModLocator.java b/src/main/java/net/minecraftforge/fml/loading/moddiscovery/IModLocator.java new file mode 100644 index 000000000..7ae91a3f6 --- /dev/null +++ b/src/main/java/net/minecraftforge/fml/loading/moddiscovery/IModLocator.java @@ -0,0 +1,42 @@ +/* + * Minecraft Forge + * Copyright (c) 2018. + * + * 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.moddiscovery; + +import java.nio.file.Path; +import java.util.List; +import java.util.Optional; +import java.util.function.Consumer; +import java.util.jar.Manifest; + +/** + * Loaded as a ServiceLoader. Takes mechanisms for locating candidate "mods" + * and transforms them into {@link ModFile} objects. + */ +public interface IModLocator { + List scanMods(); + + String name(); + + Path findPath(ModFile modFile, String... path); + + void scanFile(final ModFile modFile, Consumer pathConsumer); + + Optional findManifest(Path file); +} diff --git a/src/main/java/net/minecraftforge/fml/common/discovery/asm/ModAnnotation.java b/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModAnnotation.java similarity index 87% rename from src/main/java/net/minecraftforge/fml/common/discovery/asm/ModAnnotation.java rename to src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModAnnotation.java index 173a8f9d2..8fa21037a 100644 --- a/src/main/java/net/minecraftforge/fml/common/discovery/asm/ModAnnotation.java +++ b/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModAnnotation.java @@ -17,13 +17,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -package net.minecraftforge.fml.common.discovery.asm; +package net.minecraftforge.fml.loading.moddiscovery; +import java.lang.annotation.ElementType; import java.util.ArrayList; import java.util.Map; -import net.minecraftforge.fml.common.discovery.asm.ASMModParser.AnnotationType; - import org.objectweb.asm.Type; import com.google.common.base.MoreObjects; @@ -53,20 +52,21 @@ public class ModAnnotation return value; } } - AnnotationType type; + ElementType type; Type asmType; String member; Map values = Maps.newHashMap(); + private ArrayList arrayList; private String arrayName; - public ModAnnotation(AnnotationType type, Type asmType, String member) + public ModAnnotation(ElementType type, Type asmType, String member) { this.type = type; this.asmType = asmType; this.member = member; } - public ModAnnotation(AnnotationType type, Type asmType, ModAnnotation parent) + public ModAnnotation(ElementType type, Type asmType, ModAnnotation parent) { this.type = type; this.asmType = asmType; @@ -81,7 +81,8 @@ public class ModAnnotation .add("values", values) .toString(); } - public AnnotationType getType() + + public ElementType getType() { return type; } @@ -126,7 +127,7 @@ public class ModAnnotation } public ModAnnotation addChildAnnotation(String name, String desc) { - ModAnnotation child = new ModAnnotation(AnnotationType.SUBTYPE, Type.getType(desc), this); + ModAnnotation child = new ModAnnotation(ElementType.PARAMETER, Type.getType(desc), this); addProperty(name, child.getValues()); return child; } diff --git a/src/main/java/net/minecraftforge/fml/common/discovery/asm/ModAnnotationVisitor.java b/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModAnnotationVisitor.java similarity index 56% rename from src/main/java/net/minecraftforge/fml/common/discovery/asm/ModAnnotationVisitor.java rename to src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModAnnotationVisitor.java index 86e834717..2ed0a6587 100644 --- a/src/main/java/net/minecraftforge/fml/common/discovery/asm/ModAnnotationVisitor.java +++ b/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModAnnotationVisitor.java @@ -17,72 +17,79 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -package net.minecraftforge.fml.common.discovery.asm; +package net.minecraftforge.fml.loading.moddiscovery; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Opcodes; +import java.util.LinkedList; + public class ModAnnotationVisitor extends AnnotationVisitor { - private ASMModParser discoverer; + private final ModAnnotation annotation; + private LinkedList annotations; private boolean array; private String name; private boolean isSubAnnotation; - public ModAnnotationVisitor(ASMModParser discoverer) + public ModAnnotationVisitor(LinkedList annotations, ModAnnotation annotation) { super(Opcodes.ASM5); - this.discoverer = discoverer; + this.annotations = annotations; + this.annotation = annotation; } - public ModAnnotationVisitor(ASMModParser discoverer, String name) + public ModAnnotationVisitor(LinkedList annotations, ModAnnotation annotation, String name) { - this(discoverer); + this(annotations, annotation); this.array = true; this.name = name; - discoverer.addAnnotationArray(name); + annotation.addArray(name); } - public ModAnnotationVisitor(ASMModParser discoverer, boolean isSubAnnotation) + public ModAnnotationVisitor(LinkedList annotations, ModAnnotation annotation, boolean isSubAnnotation) { - this(discoverer); + this(annotations, annotation); this.isSubAnnotation = true; } @Override public void visit(String key, Object value) { - discoverer.addAnnotationProperty(key, value); + annotation.addProperty(key, value); } @Override public void visitEnum(String name, String desc, String value) { - discoverer.addAnnotationEnumProperty(name, desc, value); + annotation.addEnumProperty(name, desc, value); } @Override public AnnotationVisitor visitArray(String name) { - return new ModAnnotationVisitor(discoverer, name); + return new ModAnnotationVisitor(annotations, annotation, name); } @Override public AnnotationVisitor visitAnnotation(String name, String desc) { - discoverer.addSubAnnotation(name, desc); - return new ModAnnotationVisitor(discoverer, true); + ModAnnotation ma = annotations.getFirst(); + final ModAnnotation childAnnotation = ma.addChildAnnotation(name, desc); + annotations.addFirst(childAnnotation); + return new ModAnnotationVisitor(annotations, childAnnotation,true); } @Override public void visitEnd() { if (array) { - discoverer.endArray(); + annotation.endArray(); } if (isSubAnnotation) { - discoverer.endSubAnnotation(); + ModAnnotation child = annotations.removeFirst(); + annotations.addLast(child); } } } diff --git a/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModClassVisitor.java b/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModClassVisitor.java new file mode 100644 index 000000000..f86263e2f --- /dev/null +++ b/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModClassVisitor.java @@ -0,0 +1,84 @@ +/* + * Minecraft Forge + * Copyright (c) 2018. + * + * 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.moddiscovery; + +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.FieldVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; + +import java.lang.annotation.ElementType; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class ModClassVisitor extends ClassVisitor +{ + private Type asmType; + private Type asmSuperType; + private Set interfaces; + private final LinkedList annotations = new LinkedList<>(); + public ModClassVisitor() + { + super(Opcodes.ASM5); + } + + + @Override + public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) + { + this.asmType = Type.getObjectType(name); + this.asmSuperType = superName != null && superName.length() > 0 ? Type.getObjectType(superName) : null; + this.interfaces = Stream.of(interfaces).map(Type::getObjectType).collect(Collectors.toSet()); + } + + @Override + public AnnotationVisitor visitAnnotation(final String annotationName, final boolean runtimeVisible) + { + ModAnnotation ann = new ModAnnotation(ElementType.TYPE, Type.getType(annotationName), this.asmType.getClassName()); + annotations.addFirst(ann); + return new ModAnnotationVisitor(annotations, ann); + } + + + @Override + public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) + { + return new ModFieldVisitor(name, annotations); + } + + @Override + public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) + { + return new ModMethodVisitor(name, desc, annotations); + } + + public void buildData(final List classes, final List annotations) { + classes.add(new ScanResult.ClassData(this.asmType, this.asmSuperType, this.interfaces)); + final List collect = this.annotations.stream().filter(ScanResult::interestingAnnotations). + map(a -> ScanResult.AnnotationData.fromModAnnotation(this.asmType, a)).collect(Collectors.toList()); + annotations.addAll(collect); + } + +} diff --git a/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModDiscoverer.java b/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModDiscoverer.java new file mode 100644 index 000000000..599891279 --- /dev/null +++ b/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModDiscoverer.java @@ -0,0 +1,66 @@ +/* + * Minecraft Forge + * Copyright (c) 2018. + * + * 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.moddiscovery; + +import cpw.mods.modlauncher.ServiceLoaderStreamUtils; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.ServiceLoader; +import java.util.stream.Collectors; + +import static net.minecraftforge.fml.Logging.fmlLog; + +public class ModDiscoverer { + private final ServiceLoader locators; + private final List locatorList; + + public ModDiscoverer() { + locators = ServiceLoader.load(IModLocator.class); + locatorList = ServiceLoaderStreamUtils.toList(this.locators); + fmlLog.debug("Found Mod Locators : {}", ()->locatorList.stream().map(IModLocator::name).collect(Collectors.joining(","))); + } + + ModDiscoverer(List locatorList) { + this.locatorList = locatorList; + this.locators = null; + } + + public BackgroundScanHandler discoverMods() { + fmlLog.debug("Scanning for mods and other resources to load. We know {} ways to find mods", locatorList.size()); + final Map> modFiles = locatorList.stream() + .peek(loc -> fmlLog.debug("Trying locator {}", loc)) + .map(IModLocator::scanMods) + .flatMap(Collection::stream) + .peek(mf -> fmlLog.debug("Found mod file {} of type {} with locator {}", mf.getFileName(), mf.getType(), mf.getLocator())) + .collect(Collectors.groupingBy(ModFile::getType)); + + ModLanguageProvider.loadAdditionalLanguages(modFiles.get(ModFile.Type.LANGPROVIDER)); + BackgroundScanHandler backgroundScanHandler = new BackgroundScanHandler(); + final List mods = modFiles.get(ModFile.Type.MOD); + mods.forEach(ModFile::identifyMods); + fmlLog.debug("Found {} mod files with {} mods", mods::size, ()->mods.stream().mapToInt(mf -> mf.getModInfos().size()).sum()); + mods.stream().map(ModFile::getCoreMods).flatMap(List::stream).forEach(ServiceProviders.getCoreModProvider()::addCoreMod); + mods.forEach(backgroundScanHandler::submitForScanning); + return backgroundScanHandler; + } + +} diff --git a/src/main/java/net/minecraftforge/fml/common/discovery/asm/ModFieldVisitor.java b/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModFieldVisitor.java similarity index 66% rename from src/main/java/net/minecraftforge/fml/common/discovery/asm/ModFieldVisitor.java rename to src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModFieldVisitor.java index ba5ef281c..993ee79c8 100644 --- a/src/main/java/net/minecraftforge/fml/common/discovery/asm/ModFieldVisitor.java +++ b/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModFieldVisitor.java @@ -17,29 +17,33 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -package net.minecraftforge.fml.common.discovery.asm; +package net.minecraftforge.fml.loading.moddiscovery; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; + +import java.lang.annotation.ElementType; +import java.util.LinkedList; public class ModFieldVisitor extends FieldVisitor { + private final LinkedList annotations; + private final String fieldName; - private String fieldName; - private ASMModParser discoverer; - - public ModFieldVisitor(String name, ASMModParser discoverer) + public ModFieldVisitor(String name, final LinkedList annotations) { super(Opcodes.ASM5); this.fieldName = name; - this.discoverer = discoverer; + this.annotations = annotations; } @Override public AnnotationVisitor visitAnnotation(String annotationName, boolean runtimeVisible) { - discoverer.startFieldAnnotation(fieldName, annotationName); - return new ModAnnotationVisitor(discoverer); + ModAnnotation ann = new ModAnnotation(ElementType.FIELD, Type.getType(annotationName), fieldName); + annotations.addFirst(ann); + return new ModAnnotationVisitor(annotations, ann); } } diff --git a/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModFile.java b/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModFile.java new file mode 100644 index 000000000..8d995f513 --- /dev/null +++ b/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModFile.java @@ -0,0 +1,132 @@ +/* + * Minecraft Forge + * Copyright (c) 2018. + * + * 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.moddiscovery; + +import java.nio.file.Path; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.function.Consumer; +import java.util.jar.Attributes; +import java.util.jar.Manifest; + +import static net.minecraftforge.fml.Logging.fmlLog; + +public class ModFile +{ + private static final Manifest DEFAULTMANIFEST; + static { + DEFAULTMANIFEST = new Manifest(); + DEFAULTMANIFEST.getMainAttributes().putValue("FMLModType", "MOD"); + } + + public enum Type { + MOD, LIBRARY, LANGPROVIDER + } + private final Path filePath; + private final Type modFileType; + private final Manifest manifest; + private List modInfos; + private final IModLocator locator; + private ScanResult fileScanResult; + private CompletableFuture futureScanResult; + private List coreMods; + + private static final Attributes.Name TYPE = new Attributes.Name("FMLModType"); + + public ModFile(final Path file, final IModLocator locator) { + this.locator = locator; + this.filePath = file; + manifest = locator.findManifest(file).orElse(DEFAULTMANIFEST); + if (manifest != DEFAULTMANIFEST) fmlLog.debug("Mod file {} has a manifest", file); + else fmlLog.debug("Mod file {} is missing a manifest", file); + modFileType = Type.valueOf(manifest.getMainAttributes().getValue(TYPE)); + } + + public Type getType() { + return modFileType; + } + + public Path getFilePath() { + return filePath; + } + + public List getModInfos() { + return modInfos; + } + + public void identifyMods() { + this.modInfos = ModFileParser.readModList(this); + this.modInfos.forEach(mi-> fmlLog.debug("Found mod {} for language {}", mi.getModId(), mi.getModLoader())); + this.coreMods = ModFileParser.getCoreMods(this); + this.coreMods.forEach(mi-> fmlLog.debug("Found coremod {}", mi.getPath())); + } + + + public List getCoreMods() { + return coreMods; + } + + /** + * Run in an executor thread to harvest the class and annotation list + */ + public ScanResult compileContent() { + return new Scanner(this).scan(); + } + + public void scanFile(Consumer pathConsumer) { + locator.scanFile(this, pathConsumer); + } + + public void setFutureScanResult(CompletableFuture future) + { + this.futureScanResult = future; + } + + public ScanResult getScanResult() { + if (this.futureScanResult != null) { + try { + this.futureScanResult.get(); + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + } + } + return this.fileScanResult; + } + + public void setScanResult(final ScanResult scanResult, final Throwable throwable) { + this.futureScanResult = null; + this.fileScanResult = scanResult; + } + + @Override + public String toString() { + return "Mod File: " + Objects.toString(this.filePath); + } + + public String getFileName() { + return getFilePath().getFileName().toString(); + } + + public IModLocator getLocator() { + return locator; + } +} diff --git a/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModFileParser.java b/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModFileParser.java new file mode 100644 index 000000000..1ab2163ba --- /dev/null +++ b/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModFileParser.java @@ -0,0 +1,71 @@ +/* + * Minecraft Forge + * Copyright (c) 2018. + * + * 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.moddiscovery; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.InstanceCreator; +import com.google.gson.JsonDeserializer; +import com.google.gson.reflect.TypeToken; +import net.minecraftforge.fml.common.versioning.ArtifactVersion; +import net.minecraftforge.fml.common.versioning.DefaultArtifactVersion; + +import java.util.Map; + +import static net.minecraftforge.fml.Logging.fmlLog; + +public class ModFileParser { + protected static java.util.List readModList(final ModFile modFile) { + fmlLog.debug("Parsing mod file candidate {}", modFile.getFilePath()); + try { + final java.nio.file.Path modsjson = modFile.getLocator().findPath(modFile, "META-INF", "mods.json"); + GsonBuilder gsonBuilder = new GsonBuilder(); + gsonBuilder.registerTypeAdapter(ModInfo.class, (InstanceCreator)ic -> new ModInfo(modFile, null, null, null, null, null, null, null)); + gsonBuilder.registerTypeAdapter(ArtifactVersion.class, (JsonDeserializer) (element, type, context) -> new DefaultArtifactVersion(element.getAsString())); + Gson gson = gsonBuilder.create(); + final ModInfo[] modInfos = gson.fromJson(java.nio.file.Files.newBufferedReader(modsjson), ModInfo[].class); + return java.util.stream.Stream.of(modInfos).collect(java.util.stream.Collectors.toList()); + } catch (java.io.IOException e) { + fmlLog.debug("Ignoring invalid JAR file {}", modFile.getFilePath()); + return java.util.Collections.emptyList(); + } + } + + protected static java.util.List getCoreMods(final ModFile modFile) { + java.util.Map coreModPaths; + try { + final java.nio.file.Path coremodsjson = modFile.getLocator().findPath(modFile, "META-INF", "coremods.json"); + if (!java.nio.file.Files.exists(coremodsjson)) { + return java.util.Collections.emptyList(); + } + final java.lang.reflect.Type type = new TypeToken>() {}.getType(); + final Gson gson = new Gson(); + coreModPaths = gson.fromJson(java.nio.file.Files.newBufferedReader(coremodsjson), type); + } catch (java.io.IOException e) { + fmlLog.debug("Failed to read coremod list coremods.json", e); + return java.util.Collections.emptyList(); + } + + return coreModPaths.entrySet().stream(). + peek(e-> fmlLog.debug("Found coremod {} with Javascript path {}", e.getKey(), e.getValue())). + map(e -> new CoreModFile(e.getKey(), modFile.getLocator().findPath(modFile, e.getValue()),modFile)). + collect(java.util.stream.Collectors.toList()); + } +} \ No newline at end of file diff --git a/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModInfo.java b/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModInfo.java new file mode 100644 index 000000000..2a3c1dea0 --- /dev/null +++ b/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModInfo.java @@ -0,0 +1,84 @@ +/* + * Minecraft Forge + * Copyright (c) 2018. + * + * 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.moddiscovery; + +import net.minecraftforge.fml.common.versioning.ArtifactVersion; + +public class ModInfo { + private final ModFile owningFile; + private final String modId; + private final ArtifactVersion version; + private final String displayName; + private final String description; + private final java.net.URL updateJSONURL; + private final String modLoader; + private final java.util.List dependencies; + + public ModInfo(final ModFile owningFile, final String modLoader, final String modId, final String displayName, final ArtifactVersion version, final String description, final java.net.URL updateJSONURL, final java.util.List dependencies) { + this.owningFile = owningFile; + this.modLoader = modLoader; + this.modId = modId; + this.displayName = displayName; + this.version = version; + this.description = description; + this.updateJSONURL = updateJSONURL; + this.dependencies = dependencies; + } + + public ModFile getOwningFile() { + return owningFile; + } + + public String getModLoader() { + return modLoader; + } + + public String getModId() { + return modId; + } + + public ArtifactVersion getVersion() { + return version; + } + + public enum Ordering { + BEFORE, AFTER, NONE; + } + + public enum DependencySide { + CLIENT, SERVER, BOTH; + } + + public static class ModVersion { + private final String modId; + private final ArtifactVersion version; + private final boolean mandatory; + private final Ordering ordering; + private final DependencySide side; + + public ModVersion(final String modId, final ArtifactVersion version, final boolean mandatory, final Ordering ordering, final DependencySide side) { + this.modId = modId; + this.version = version; + this.mandatory = mandatory; + this.ordering = ordering; + this.side = side; + } + } +} diff --git a/src/main/java/net/minecraftforge/fml/common/discovery/asm/ModMethodVisitor.java b/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModMethodVisitor.java similarity index 68% rename from src/main/java/net/minecraftforge/fml/common/discovery/asm/ModMethodVisitor.java rename to src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModMethodVisitor.java index fd372fc4b..123777664 100644 --- a/src/main/java/net/minecraftforge/fml/common/discovery/asm/ModMethodVisitor.java +++ b/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModMethodVisitor.java @@ -17,31 +17,36 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -package net.minecraftforge.fml.common.discovery.asm; +package net.minecraftforge.fml.loading.moddiscovery; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; + +import java.lang.annotation.ElementType; +import java.util.LinkedList; public class ModMethodVisitor extends MethodVisitor { + private final LinkedList annotations; private String methodName; private String methodDescriptor; - private ASMModParser discoverer; - public ModMethodVisitor(String name, String desc, ASMModParser discoverer) + public ModMethodVisitor(String name, String desc, final LinkedList annotations) { super(Opcodes.ASM5); this.methodName = name; this.methodDescriptor = desc; - this.discoverer = discoverer; + this.annotations = annotations; } @Override public AnnotationVisitor visitAnnotation(String annotationName, boolean runtimeVisible) { - discoverer.startMethodAnnotation(methodName, methodDescriptor, annotationName); - return new ModAnnotationVisitor(discoverer); + ModAnnotation ann = new ModAnnotation(ElementType.METHOD, Type.getType(annotationName), methodName+methodDescriptor); + annotations.addFirst(ann); + return new ModAnnotationVisitor(annotations, ann); } } diff --git a/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModsFolderLocator.java b/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModsFolderLocator.java new file mode 100644 index 000000000..8ab977d28 --- /dev/null +++ b/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModsFolderLocator.java @@ -0,0 +1,108 @@ +/* + * Minecraft Forge + * Copyright (c) 2018. + * + * 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.moddiscovery; + +import net.minecraftforge.fml.common.FMLPaths; + +import java.io.IOException; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.zip.ZipError; + +import static cpw.mods.modlauncher.api.LamdbaExceptionUtils.uncheck; +import static net.minecraftforge.fml.Logging.fmlLog; + +/** + * Support loading mods located in JAR files in the mods folder + */ +public class ModsFolderLocator implements IModLocator { + private static final String SUFFIX = ".jar"; + private final Path modFolder; + private final Map modJars; + public ModsFolderLocator() { + this(FMLPaths.MODSDIR.get()); + } + + ModsFolderLocator(Path modFolder) { + this.modFolder = modFolder; + this.modJars = new HashMap<>(); + } + + @Override + public List scanMods() { + return uncheck(()-> Files.list(this.modFolder)). + sorted(Comparator.comparing(path-> StringUtils.toLowerCase(path.getFileName().toString()))). + filter(p->StringUtils.toLowerCase(p.getFileName().toString()).endsWith(SUFFIX)). + map(p->new ModFile(p, this)). + peek(f->modJars.compute(f, (mf, fs)->createFileSystem(mf))). + collect(Collectors.toList()); + } + + @Override + public String name() { + return "mods folder"; + } + + private FileSystem createFileSystem(ModFile modFile) { + try { + return FileSystems.newFileSystem(modFile.getFilePath(), modFile.getClass().getClassLoader()); + } catch (ZipError | IOException e) { + fmlLog.debug("Ignoring invalid JAR file {}", modFile.getFilePath()); + return null; + } + } + + @Override + public Path findPath(final ModFile modFile, final String... path) { + if (path.length < 1) { + throw new IllegalArgumentException("Missing path"); + } + return modJars.get(modFile).getPath(path[0], Arrays.copyOfRange(path, 1, path.length)); + } + + @Override + public void scanFile(final ModFile file, final Consumer pathConsumer) { + fmlLog.debug("Scan started: {}", file); + FileSystem fs = modJars.get(file); + fs.getRootDirectories().forEach(path -> { + try (Stream files = Files.find(path, Integer.MAX_VALUE, (p, a) -> p.getNameCount() > 0 && p.getFileName().toString().endsWith(".class"))) { + files.forEach(pathConsumer); + } catch (IOException e) { + e.printStackTrace(); + } + }); + fmlLog.debug("Scan finished: {}", file); + } + + @Override + public String toString() { + return "{FolderJar locator at "+this.modFolder+"}"; + } +} diff --git a/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ScanResult.java b/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ScanResult.java new file mode 100644 index 000000000..f35f6269c --- /dev/null +++ b/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ScanResult.java @@ -0,0 +1,95 @@ +/* + * Minecraft Forge + * Copyright (c) 2018. + * + * 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.moddiscovery; + + +import org.objectweb.asm.Type; + +import java.util.Map; +import java.util.Set; + +public class ScanResult { + private final ModFile file; + private final java.util.List annotations = new java.util.ArrayList<>(); + private final java.util.List classes = new java.util.ArrayList<>(); + + public ScanResult(final ModFile file) { + this.file = file; + } + + public static boolean interestingAnnotations(final ModAnnotation annotation) { + return true; + } + + public java.util.List getClasses() { + return classes; + } + + public java.util.List getAnnotations() { + return annotations; + } + + public static class ClassData { + private final Type clazz; + private final Type parent; + private final Set interfaces; + + public ClassData(final Type clazz, final Type parent, final Set interfaces) { + this.clazz = clazz; + this.parent = parent; + this.interfaces = interfaces; + } + + } + public static class AnnotationData { + private final Type annotationType; + private final Type clazz; + private final String memberName; + private final Map annotationData; + + + public AnnotationData(final Type annotationType, final Type clazz, final String memberName, final Map annotationData) { + this.annotationType = annotationType; + this.clazz = clazz; + this.memberName = memberName; + this.annotationData = annotationData; + } + + public Type getAnnotationType() { + return annotationType; + } + + public Type getClassType() { + return clazz; + } + + public String getMemberName() { + return memberName; + } + + public Map getAnnotationData() { + return annotationData; + } + public static ScanResult.AnnotationData fromModAnnotation(final Type clazz, final ModAnnotation annotation) { + return new AnnotationData(annotation.asmType, clazz, annotation.member, annotation.values); + } + + } +} diff --git a/src/main/java/net/minecraftforge/fml/loading/moddiscovery/Scanner.java b/src/main/java/net/minecraftforge/fml/loading/moddiscovery/Scanner.java new file mode 100644 index 000000000..58456fa14 --- /dev/null +++ b/src/main/java/net/minecraftforge/fml/loading/moddiscovery/Scanner.java @@ -0,0 +1,50 @@ +/* + * Minecraft Forge + * Copyright (c) 2018. + * + * 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.moddiscovery; + +import org.objectweb.asm.ClassReader; + +import static net.minecraftforge.fml.Logging.fmlLog; + +public class Scanner { + private final ModFile fileToScan; + + public Scanner(final ModFile fileToScan) { + this.fileToScan = fileToScan; + } + + public ScanResult scan() { + ScanResult result = new ScanResult(fileToScan); + fileToScan.scanFile(p -> fileVisitor(p, result)); + return result; + } + + private void fileVisitor(final java.nio.file.Path path, final ScanResult result) { + try { + fmlLog.debug("Scanning {} path {}", fileToScan, path); + ModClassVisitor mcv = new ModClassVisitor(); + org.objectweb.asm.ClassReader cr = new ClassReader(java.nio.file.Files.newInputStream(path)); + cr.accept(mcv, 0); + mcv.buildData(result.getClasses(), result.getAnnotations()); + } catch (java.io.IOException e) { + // mark path bad + } + } +} diff --git a/src/main/resources/META-INF/services/cpw.mods.modlauncher.api.ILaunchHandlerService b/src/main/resources/META-INF/services/cpw.mods.modlauncher.api.ILaunchHandlerService new file mode 100644 index 000000000..6b6ff6274 --- /dev/null +++ b/src/main/resources/META-INF/services/cpw.mods.modlauncher.api.ILaunchHandlerService @@ -0,0 +1 @@ +net.minecraftforge.fml.loading.FMLLaunchProvider \ No newline at end of file diff --git a/src/main/resources/META-INF/services/cpw.mods.modlauncher.api.ITransformationService b/src/main/resources/META-INF/services/cpw.mods.modlauncher.api.ITransformationService new file mode 100644 index 000000000..99a564596 --- /dev/null +++ b/src/main/resources/META-INF/services/cpw.mods.modlauncher.api.ITransformationService @@ -0,0 +1 @@ +net.minecraftforge.fml.loading.FMLServiceProvider \ No newline at end of file diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml index 1e2fe026b..3254c08bd 100644 --- a/src/main/resources/log4j2.xml +++ b/src/main/resources/log4j2.xml @@ -1,52 +1,59 @@ - + + + + - - - - - - - + - - - - - - - + - + - - + + - - - - - - - - + + + + + + + + + + + + + + + + + + - - - - + + + + + + - + - - - - + + + + + + + +