Goodbye @Mod, it was lovely knowing you!

This commit is contained in:
cpw 2018-03-25 11:59:43 -04:00 committed by LexManos
parent d23850ff98
commit 14ac77e444
37 changed files with 1541 additions and 176 deletions

Binary file not shown.

View file

@ -1,6 +1,6 @@
#Mon Sep 14 12:28:28 PDT 2015 #Sat Mar 10 11:15:39 EST 2018
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-bin.zip

52
gradlew vendored
View file

@ -6,12 +6,30 @@
## ##
############################################################################## ##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. # Attempt to set APP_HOME
DEFAULT_JVM_OPTS="" # 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\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle" APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"` 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. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum" MAX_FD="maximum"
@ -30,6 +48,7 @@ die ( ) {
cygwin=false cygwin=false
msys=false msys=false
darwin=false darwin=false
nonstop=false
case "`uname`" in case "`uname`" in
CYGWIN* ) CYGWIN* )
cygwin=true cygwin=true
@ -40,31 +59,11 @@ case "`uname`" in
MINGW* ) MINGW* )
msys=true msys=true
;; ;;
NONSTOP* )
nonstop=true
;;
esac 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 CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM. # Determine the Java command to use to start the JVM.
@ -90,7 +89,7 @@ location of your Java installation."
fi fi
# Increase the maximum file descriptors if we can. # 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` MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
@ -114,6 +113,7 @@ fi
if $cygwin ; then if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"` APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath # We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`

8
gradlew.bat vendored
View file

@ -8,14 +8,14 @@
@rem Set local scope for the variables with windows NT shell @rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal 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 set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=. if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0 set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME% 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 @rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome if defined JAVA_HOME goto findJavaFromJavaHome
@ -46,7 +46,7 @@ echo location of your Java installation.
goto fail goto fail
:init :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 not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args if "%@eval[2+2]" == "4" goto 4NT_args

View file

@ -41,7 +41,7 @@ import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.LoaderException; import net.minecraftforge.fml.common.LoaderException;
import net.minecraftforge.fml.common.discovery.ASMDataTable; import net.minecraftforge.fml.common.discovery.ASMDataTable;
import net.minecraftforge.fml.common.discovery.ASMDataTable.ASMData; 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; import org.apache.commons.lang3.StringUtils;

View file

@ -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<String, String> configData = new HashMap<>();
private FMLConfig() {
configData.putAll(defaultValues());
}
private Map<String,String> defaultValues() {
final Map<String,String> result = new HashMap<>();
result.put("splashscreen", "true");
return result;
}
private void loadFrom(final Path configFile) throws IOException
{
final Type type = new TypeToken<Map<String, String>>() {}.getType();
final Gson gson = new Gson();
final Map<String,String> 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<Map<String, String>>() {}.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);
}
}
}

View file

@ -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;
}
}

View file

@ -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");
}
}

View file

@ -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");
}

View file

@ -25,9 +25,8 @@ import com.google.common.collect.SetMultimap;
import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.common.discovery.ASMDataTable; import net.minecraftforge.fml.common.discovery.ASMDataTable;
import net.minecraftforge.fml.common.discovery.ASMDataTable.ASMData; 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 net.minecraftforge.fml.relauncher.Side;
import org.apache.logging.log4j.Level;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.List; import java.util.List;

View file

@ -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;
}
}

View file

@ -22,11 +22,10 @@ package net.minecraftforge.fml.common;
import java.io.File; import java.io.File;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.util.Map; import java.util.Map;
import java.util.regex.Pattern;
import net.minecraftforge.fml.common.discovery.ModCandidate; import net.minecraftforge.fml.common.discovery.ModCandidate;
import net.minecraftforge.fml.common.discovery.asm.ASMModParser; 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; import org.objectweb.asm.Type;

View file

@ -29,6 +29,8 @@ import net.minecraftforge.fml.common.LoaderException;
import net.minecraftforge.fml.common.discovery.ASMDataTable; import net.minecraftforge.fml.common.discovery.ASMDataTable;
import net.minecraftforge.fml.common.discovery.ModCandidate; 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.ClassReader;
import org.objectweb.asm.Type; import org.objectweb.asm.Type;

View file

@ -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);
}
}

View file

@ -23,7 +23,6 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Function; import java.util.function.Function;
import org.apache.commons.lang3.Validate;
import org.objectweb.asm.Type; import org.objectweb.asm.Type;
import com.google.common.base.MoreObjects; import com.google.common.base.MoreObjects;
@ -31,7 +30,7 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import net.minecraftforge.fml.common.FMLLog; 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. //Package private, modders shouldn't access this. Do it through ASMDataTable.
class ASMInfo class ASMInfo

View file

@ -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<Void> launchService(String[] arguments, ClassLoader launchClassLoader)
{
return () -> { return null; };
}
}

View file

@ -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<String> 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();
}
}

View file

@ -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<String> modsOption;
private ArgumentAcceptingOptionSpec<String> modListsOption;
private List<String> modsArgumentList;
private List<String> 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<String> otherServices) throws IncompatibleEnvironmentException
{
FMLLoader.initialize(environment, otherServices);
}
@Override
public void arguments(BiFunction<String, String, OptionSpecBuilder> 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<ITransformer> transformers()
{
return Collections.emptyList();
}
}

View file

@ -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<ModFile> pendingFiles;
private final List<ModFile> scannedFiles;
private final List<ModFile> 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<ScanResult> 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<ModFile> getScannedFiles() {
if (!pendingFiles.isEmpty()) {
modContentScanner.shutdown();
try {
modContentScanner.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
} catch (InterruptedException e) {
}
}
return scannedFiles;
}
public List<ModFile> getAllFiles() {
return allFiles;
}
}

View file

@ -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;
}
}

View file

@ -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<ModFile> 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<Path> pathConsumer) {
fmlLog.debug("Scanning directory {}", rootDir);
try (Stream<Path> 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);
}
}

View file

@ -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<ModFile> scanMods();
String name();
Path findPath(ModFile modFile, String... path);
void scanFile(final ModFile modFile, Consumer<Path> pathConsumer);
Optional<Manifest> findManifest(Path file);
}

View file

@ -17,13 +17,12 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * 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.ArrayList;
import java.util.Map; import java.util.Map;
import net.minecraftforge.fml.common.discovery.asm.ASMModParser.AnnotationType;
import org.objectweb.asm.Type; import org.objectweb.asm.Type;
import com.google.common.base.MoreObjects; import com.google.common.base.MoreObjects;
@ -53,20 +52,21 @@ public class ModAnnotation
return value; return value;
} }
} }
AnnotationType type; ElementType type;
Type asmType; Type asmType;
String member; String member;
Map<String,Object> values = Maps.newHashMap(); Map<String,Object> values = Maps.newHashMap();
private ArrayList<Object> arrayList; private ArrayList<Object> arrayList;
private String arrayName; private String arrayName;
public ModAnnotation(AnnotationType type, Type asmType, String member) public ModAnnotation(ElementType type, Type asmType, String member)
{ {
this.type = type; this.type = type;
this.asmType = asmType; this.asmType = asmType;
this.member = member; this.member = member;
} }
public ModAnnotation(AnnotationType type, Type asmType, ModAnnotation parent) public ModAnnotation(ElementType type, Type asmType, ModAnnotation parent)
{ {
this.type = type; this.type = type;
this.asmType = asmType; this.asmType = asmType;
@ -81,7 +81,8 @@ public class ModAnnotation
.add("values", values) .add("values", values)
.toString(); .toString();
} }
public AnnotationType getType()
public ElementType getType()
{ {
return type; return type;
} }
@ -126,7 +127,7 @@ public class ModAnnotation
} }
public ModAnnotation addChildAnnotation(String name, String desc) 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()); addProperty(name, child.getValues());
return child; return child;
} }

View file

@ -17,72 +17,79 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * 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.AnnotationVisitor;
import org.objectweb.asm.Opcodes; import org.objectweb.asm.Opcodes;
import java.util.LinkedList;
public class ModAnnotationVisitor extends AnnotationVisitor public class ModAnnotationVisitor extends AnnotationVisitor
{ {
private ASMModParser discoverer; private final ModAnnotation annotation;
private LinkedList<ModAnnotation> annotations;
private boolean array; private boolean array;
private String name; private String name;
private boolean isSubAnnotation; private boolean isSubAnnotation;
public ModAnnotationVisitor(ASMModParser discoverer) public ModAnnotationVisitor(LinkedList<ModAnnotation> annotations, ModAnnotation annotation)
{ {
super(Opcodes.ASM5); super(Opcodes.ASM5);
this.discoverer = discoverer; this.annotations = annotations;
this.annotation = annotation;
} }
public ModAnnotationVisitor(ASMModParser discoverer, String name) public ModAnnotationVisitor(LinkedList<ModAnnotation> annotations, ModAnnotation annotation, String name)
{ {
this(discoverer); this(annotations, annotation);
this.array = true; this.array = true;
this.name = name; this.name = name;
discoverer.addAnnotationArray(name); annotation.addArray(name);
} }
public ModAnnotationVisitor(ASMModParser discoverer, boolean isSubAnnotation) public ModAnnotationVisitor(LinkedList<ModAnnotation> annotations, ModAnnotation annotation, boolean isSubAnnotation)
{ {
this(discoverer); this(annotations, annotation);
this.isSubAnnotation = true; this.isSubAnnotation = true;
} }
@Override @Override
public void visit(String key, Object value) public void visit(String key, Object value)
{ {
discoverer.addAnnotationProperty(key, value); annotation.addProperty(key, value);
} }
@Override @Override
public void visitEnum(String name, String desc, String value) public void visitEnum(String name, String desc, String value)
{ {
discoverer.addAnnotationEnumProperty(name, desc, value); annotation.addEnumProperty(name, desc, value);
} }
@Override @Override
public AnnotationVisitor visitArray(String name) public AnnotationVisitor visitArray(String name)
{ {
return new ModAnnotationVisitor(discoverer, name); return new ModAnnotationVisitor(annotations, annotation, name);
} }
@Override @Override
public AnnotationVisitor visitAnnotation(String name, String desc) public AnnotationVisitor visitAnnotation(String name, String desc)
{ {
discoverer.addSubAnnotation(name, desc); ModAnnotation ma = annotations.getFirst();
return new ModAnnotationVisitor(discoverer, true); final ModAnnotation childAnnotation = ma.addChildAnnotation(name, desc);
annotations.addFirst(childAnnotation);
return new ModAnnotationVisitor(annotations, childAnnotation,true);
} }
@Override @Override
public void visitEnd() public void visitEnd()
{ {
if (array) if (array)
{ {
discoverer.endArray(); annotation.endArray();
} }
if (isSubAnnotation) if (isSubAnnotation)
{ {
discoverer.endSubAnnotation(); ModAnnotation child = annotations.removeFirst();
annotations.addLast(child);
} }
} }
} }

View file

@ -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<Type> interfaces;
private final LinkedList<ModAnnotation> 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<ScanResult.ClassData> classes, final List<ScanResult.AnnotationData> annotations) {
classes.add(new ScanResult.ClassData(this.asmType, this.asmSuperType, this.interfaces));
final List<ScanResult.AnnotationData> collect = this.annotations.stream().filter(ScanResult::interestingAnnotations).
map(a -> ScanResult.AnnotationData.fromModAnnotation(this.asmType, a)).collect(Collectors.toList());
annotations.addAll(collect);
}
}

View file

@ -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<IModLocator> locators;
private final List<IModLocator> 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<IModLocator> 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<ModFile.Type, List<ModFile>> 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<ModFile> 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;
}
}

View file

@ -17,29 +17,33 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * 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.AnnotationVisitor;
import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Opcodes; import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import java.lang.annotation.ElementType;
import java.util.LinkedList;
public class ModFieldVisitor extends FieldVisitor public class ModFieldVisitor extends FieldVisitor
{ {
private final LinkedList<ModAnnotation> annotations;
private final String fieldName;
private String fieldName; public ModFieldVisitor(String name, final LinkedList<ModAnnotation> annotations)
private ASMModParser discoverer;
public ModFieldVisitor(String name, ASMModParser discoverer)
{ {
super(Opcodes.ASM5); super(Opcodes.ASM5);
this.fieldName = name; this.fieldName = name;
this.discoverer = discoverer; this.annotations = annotations;
} }
@Override @Override
public AnnotationVisitor visitAnnotation(String annotationName, boolean runtimeVisible) public AnnotationVisitor visitAnnotation(String annotationName, boolean runtimeVisible)
{ {
discoverer.startFieldAnnotation(fieldName, annotationName); ModAnnotation ann = new ModAnnotation(ElementType.FIELD, Type.getType(annotationName), fieldName);
return new ModAnnotationVisitor(discoverer); annotations.addFirst(ann);
return new ModAnnotationVisitor(annotations, ann);
} }
} }

View file

@ -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<ModInfo> modInfos;
private final IModLocator locator;
private ScanResult fileScanResult;
private CompletableFuture<ScanResult> futureScanResult;
private List<CoreModFile> 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<ModInfo> 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<CoreModFile> 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<Path> pathConsumer) {
locator.scanFile(this, pathConsumer);
}
public void setFutureScanResult(CompletableFuture<ScanResult> 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;
}
}

View file

@ -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<net.minecraftforge.fml.loading.moddiscovery.ModInfo> 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<ModInfo>)ic -> new ModInfo(modFile, null, null, null, null, null, null, null));
gsonBuilder.registerTypeAdapter(ArtifactVersion.class, (JsonDeserializer<ArtifactVersion>) (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<CoreModFile> getCoreMods(final ModFile modFile) {
java.util.Map<String,String> 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<Map<String, String>>() {}.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());
}
}

View file

@ -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<net.minecraftforge.fml.loading.moddiscovery.ModInfo.ModVersion> 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<net.minecraftforge.fml.loading.moddiscovery.ModInfo.ModVersion> 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;
}
}
}

View file

@ -17,31 +17,36 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * 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.AnnotationVisitor;
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes; import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import java.lang.annotation.ElementType;
import java.util.LinkedList;
public class ModMethodVisitor extends MethodVisitor { public class ModMethodVisitor extends MethodVisitor {
private final LinkedList<ModAnnotation> annotations;
private String methodName; private String methodName;
private String methodDescriptor; private String methodDescriptor;
private ASMModParser discoverer;
public ModMethodVisitor(String name, String desc, ASMModParser discoverer) public ModMethodVisitor(String name, String desc, final LinkedList<ModAnnotation> annotations)
{ {
super(Opcodes.ASM5); super(Opcodes.ASM5);
this.methodName = name; this.methodName = name;
this.methodDescriptor = desc; this.methodDescriptor = desc;
this.discoverer = discoverer; this.annotations = annotations;
} }
@Override @Override
public AnnotationVisitor visitAnnotation(String annotationName, boolean runtimeVisible) public AnnotationVisitor visitAnnotation(String annotationName, boolean runtimeVisible)
{ {
discoverer.startMethodAnnotation(methodName, methodDescriptor, annotationName); ModAnnotation ann = new ModAnnotation(ElementType.METHOD, Type.getType(annotationName), methodName+methodDescriptor);
return new ModAnnotationVisitor(discoverer); annotations.addFirst(ann);
return new ModAnnotationVisitor(annotations, ann);
} }
} }

View file

@ -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<ModFile, FileSystem> modJars;
public ModsFolderLocator() {
this(FMLPaths.MODSDIR.get());
}
ModsFolderLocator(Path modFolder) {
this.modFolder = modFolder;
this.modJars = new HashMap<>();
}
@Override
public List<ModFile> 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<Path> pathConsumer) {
fmlLog.debug("Scan started: {}", file);
FileSystem fs = modJars.get(file);
fs.getRootDirectories().forEach(path -> {
try (Stream<Path> 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+"}";
}
}

View file

@ -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<net.minecraftforge.fml.loading.moddiscovery.ScanResult.AnnotationData> annotations = new java.util.ArrayList<>();
private final java.util.List<net.minecraftforge.fml.loading.moddiscovery.ScanResult.ClassData> 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<net.minecraftforge.fml.loading.moddiscovery.ScanResult.ClassData> getClasses() {
return classes;
}
public java.util.List<net.minecraftforge.fml.loading.moddiscovery.ScanResult.AnnotationData> getAnnotations() {
return annotations;
}
public static class ClassData {
private final Type clazz;
private final Type parent;
private final Set<Type> interfaces;
public ClassData(final Type clazz, final Type parent, final Set<Type> 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<String,Object> annotationData;
public AnnotationData(final Type annotationType, final Type clazz, final String memberName, final Map<String, Object> 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<String, Object> getAnnotationData() {
return annotationData;
}
public static ScanResult.AnnotationData fromModAnnotation(final Type clazz, final ModAnnotation annotation) {
return new AnnotationData(annotation.asmType, clazz, annotation.member, annotation.values);
}
}
}

View file

@ -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
}
}
}

View file

@ -0,0 +1 @@
net.minecraftforge.fml.loading.FMLLaunchProvider

View file

@ -0,0 +1 @@
net.minecraftforge.fml.loading.FMLServiceProvider

View file

@ -1,52 +1,59 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" packages="net.minecraftforge.server.terminalconsole.util"> <Configuration status="WARN" packages="com.mojang.util">
<Appenders> <Appenders>
<Console name="FmlSysOut" target="SYSTEM_OUT">
<PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level] [%logger]: %msg%n" />
</Console>
<Console name="SysOut" target="SYSTEM_OUT"> <Console name="SysOut" target="SYSTEM_OUT">
<PatternLayout> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" />
<LoggerNamePatternSelector defaultPattern="[%d{HH:mm:ss}] [%t/%level] [%logger]: %msg%n">
<!-- don't include the full logger name for Mojang's logs since they use full class names and it's very verbose -->
<PatternMatch key="net.minecraft." pattern="[%d{HH:mm:ss}] [%t/%level] [minecraft/%logger{1}]: %msg%n"/>
<PatternMatch key="com.mojang." pattern="[%d{HH:mm:ss}] [%t/%level] [mojang/%logger{1}]: %msg%n"/>
</LoggerNamePatternSelector>
</PatternLayout>
</Console> </Console>
<Queue name="ServerGuiConsole" ignoreExceptions="true"> <Queue name="ServerGuiConsole" ignoreExceptions="true">
<PatternLayout> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level] [%logger]: %msg%n" />
<LoggerNamePatternSelector defaultPattern="[%d{HH:mm:ss}] [%t/%level] [%logger]: %msg%n">
<!-- don't include the full logger name for Mojang's logs since they use full class names and it's very verbose -->
<PatternMatch key="net.minecraft." pattern="[%d{HH:mm:ss}] [%t/%level] [minecraft/%logger{1}]: %msg%n"/>
<PatternMatch key="com.mojang." pattern="[%d{HH:mm:ss}] [%t/%level] [mojang/%logger{1}]: %msg%n"/>
</LoggerNamePatternSelector>
</PatternLayout>
</Queue> </Queue>
<RollingRandomAccessFile name="File" fileName="logs/latest.log" filePattern="logs/%d{yyyy-MM-dd}-%i.log.gz"> <RollingRandomAccessFile name="File" fileName="logs/latest.log" filePattern="logs/%d{yyyy-MM-dd}-%i.log.gz">
<PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level] [%logger]: %msg%n"/> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" />
<Policies> <Policies>
<TimeBasedTriggeringPolicy/> <TimeBasedTriggeringPolicy />
<OnStartupTriggeringPolicy/> <OnStartupTriggeringPolicy />
</Policies> </Policies>
</RollingRandomAccessFile> </RollingRandomAccessFile>
<RollingRandomAccessFile name="DebugFile" fileName="logs/debug.log" filePattern="logs/debug-%i.log.gz"> <Routing name="FmlFile">
<PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level] [%logger]: %msg%n"/> <Routes pattern="$${ctx:side}">
<Policies> <Route>
<OnStartupTriggeringPolicy/> <RollingRandomAccessFile name="FmlFile" fileName="logs/fml-${ctx:side}-latest.log" filePattern="logs/fml-${ctx:side}-%i.log">
<SizeBasedTriggeringPolicy size="200MB"/> <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level] [%logger/%X{mod}]: %msg%n" />
</Policies> <DefaultRolloverStrategy max="3" fileIndex="max" />
<DefaultRolloverStrategy max="5" fileIndex="min"/> <Policies>
</RollingRandomAccessFile> <OnStartupTriggeringPolicy />
</Policies>
</RollingRandomAccessFile>
</Route>
<Route key="$${ctx:side}">
<RandomAccessFile name="FmlFile" fileName="logs/fml-junk-earlystartup.log" >
<PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level] [%logger]: %msg%n" />
</RandomAccessFile>
</Route>
</Routes>
</Routing>
</Appenders> </Appenders>
<Loggers> <Loggers>
<!-- make sure mojang's logging is set to 'info' so that their LOGGER.isDebugEnabled() behavior isn't active --> <Logger level="info" name="com.mojang" additivity="false">
<Logger level="${sys:forge.logging.mojang.level:-info}" name="com.mojang"/> <AppenderRef ref="SysOut" level="INFO" />
<Logger level="${sys:forge.logging.mojang.level:-info}" name="net.minecraft"/> <AppenderRef ref="File" />
<Root level="all"> <AppenderRef ref="ServerGuiConsole" level="INFO" />
</Logger>
<Logger level="info" name="net.minecraft" additivity="false">
<filters> <filters>
<MarkerFilter marker="NETWORK_PACKETS" onMatch="DENY" onMismatch="NEUTRAL"/> <MarkerFilter marker="NETWORK_PACKETS" onMatch="DENY" onMismatch="NEUTRAL" />
</filters> </filters>
<AppenderRef ref="SysOut" level="${sys:forge.logging.console.level:-info}"/> <AppenderRef ref="SysOut" level="INFO" />
<AppenderRef ref="ServerGuiConsole" level="${sys:forge.logging.console.level:-info}"/> <AppenderRef ref="File" />
<AppenderRef ref="File" level="${sys:forge.logging.file.level:-info}"/> <AppenderRef ref="ServerGuiConsole" level="INFO" />
<AppenderRef ref="DebugFile" level="${sys:forge.logging.debugFile.level:-trace}"/> </Logger>
<Root level="INFO">
<AppenderRef ref="FmlSysOut"/>
<AppenderRef ref="ServerGuiConsole" level="INFO" />
<AppenderRef ref="FmlFile"/>
</Root> </Root>
</Loggers> </Loggers>
</Configuration> </Configuration>