Early signs of modloading

This commit is contained in:
cpw 2018-04-07 11:48:43 -04:00 committed by LexManos
parent 66b6150027
commit c38d2e48cd
13 changed files with 288 additions and 25 deletions

View File

@ -25,9 +25,10 @@ import org.apache.logging.log4j.core.config.Configurator;
public class LaunchTesting
{
public static void main(String... args)
public static void main(String... args) throws InterruptedException
{
Configurator.setRootLevel(Level.DEBUG);
Launcher.main("--launchTarget", "fml","--gameDir", "projects/run");
Thread.sleep(10000);
}
}

View File

@ -0,0 +1,86 @@
/*
* 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 net.minecraftforge.fml.common.ModContainer;
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
import net.minecraftforge.fml.loading.moddiscovery.ScanResult;
import org.objectweb.asm.Type;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import static net.minecraftforge.fml.Logging.SCAN;
import static net.minecraftforge.fml.Logging.fmlLog;
public class FMLJavaModLanguageProvider implements IModLanguageProvider
{
private static class FMLModTarget implements IModLanguageProvider.IModLanguageLoader {
private final String className;
private final String modId;
private FMLModTarget(String className, String modId)
{
this.className = className;
this.modId = modId;
}
public String getModId()
{
return modId;
}
@Override
public ModContainer loadMod(ModFile file, ClassLoader modClassLoader)
{
return null;
}
}
public static final Type MODANNOTATION = Type.getType("Lnet/minecraftforge/fml/common/Mod;");
@Override
public String name()
{
return "javafml";
}
@Override
public Consumer<ScanResult> getFileVisitor() {
return scanResult -> {
final Map<String, FMLModTarget> modTargetMap = scanResult.getAnnotations().stream()
.filter(ad -> ad.getAnnotationType().equals(MODANNOTATION))
.peek(ad -> fmlLog.debug(SCAN, "Found @Mod class {} with id {}", ad.getClassType().getClassName(), ad.getAnnotationData().get("modid")))
.map(ad -> new FMLModTarget(ad.getClassType().getClassName(), (String)ad.getAnnotationData().get("modid")))
.collect(Collectors.toMap(FMLModTarget::getModId, Function.identity()));
modTargetMap.forEach((key, value) -> scanResult.getFile().claimLanguage(key, value));
};
}
@Override
public List<ModContainer> buildModContainers(List<ModInfo> modFiles, ClassLoader modClassLoader)
{
return null;
}
}

View File

@ -28,25 +28,20 @@ import net.minecraftforge.fml.loading.moddiscovery.ModDiscoverer;
import net.minecraftforge.forgespi.ICoreModProvider;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.stream.Collectors;
import static net.minecraftforge.fml.Logging.CORE;
import static net.minecraftforge.fml.Logging.LOADING;
import static net.minecraftforge.fml.Logging.SCAN;
import static net.minecraftforge.fml.Logging.fmlLog;
public class FMLLoader
{
private static ILaunchPluginService accessTransformer;
private static ModDiscoverer modDiscoverer;
private static ICoreModProvider coreMod;
private static ICoreModProvider coreModProvider;
private static LanguageLoadingProvider languageLoadingProvider;
static void onInitialLoad(IEnvironment environment, Set<String> otherServices) throws IncompatibleEnvironmentException
{
@ -79,9 +74,11 @@ public class FMLLoader
throw new IncompatibleEnvironmentException("Multiple coremod libraries found");
}
coreMod = coreModProviders.get(0);
final Package coremodPackage = coreMod.getClass().getPackage();
coreModProvider = coreModProviders.get(0);
final Package coremodPackage = coreModProvider.getClass().getPackage();
fmlLog.debug(CORE,"FML found CoreMod version : {}", coremodPackage.getImplementationVersion());
languageLoadingProvider = new LanguageLoadingProvider();
}
public static void load()
@ -90,4 +87,13 @@ public class FMLLoader
modDiscoverer = new ModDiscoverer();
modDiscoverer.discoverMods();
}
public static ICoreModProvider getCoreModProvider() {
return coreModProvider;
}
public static LanguageLoadingProvider getLanguageLoadingProvider()
{
return languageLoadingProvider;
}
}

View File

@ -25,14 +25,17 @@ import cpw.mods.modlauncher.api.ITransformer;
import cpw.mods.modlauncher.api.IncompatibleEnvironmentException;
import joptsimple.ArgumentAcceptingOptionSpec;
import joptsimple.OptionSpecBuilder;
import net.minecraftforge.coremod.CoreModEngine;
import net.minecraftforge.fml.FMLConfig;
import net.minecraftforge.fml.common.FMLPaths;
import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.stream.Collectors;
import static net.minecraftforge.fml.Logging.CORE;
import static net.minecraftforge.fml.Logging.fmlLog;
@ -86,7 +89,8 @@ public class FMLServiceProvider implements ITransformationService
@Override
public List<ITransformer> transformers()
{
return Collections.emptyList();
fmlLog.debug(CORE, "Loading coremod transformers");
return new ArrayList<>(FMLLoader.getCoreModProvider().getCoreModTransformers());
}
}

View File

@ -0,0 +1,47 @@
/*
* 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 net.minecraftforge.fml.common.ModContainer;
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
import net.minecraftforge.fml.loading.moddiscovery.ScanResult;
import java.util.List;
import java.util.function.Consumer;
/**
* Loaded as a ServiceLoader, from the classpath. Extensions are loaded from
* the mods directory, with the FMLType META-INF of LANGPROVIDER.
*
* Version data is read from the manifest's implementation version.
*/
public interface IModLanguageProvider
{
String name();
Consumer<ScanResult> getFileVisitor();
interface IModLanguageLoader {
ModContainer loadMod(ModFile file, ClassLoader modClassLoader);
}
List<ModContainer> buildModContainers(List<ModInfo> modFiles, ClassLoader modClassLoader);
}

View File

@ -0,0 +1,64 @@
/*
* 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 net.minecraftforge.fml.loading.moddiscovery.ModFile;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.stream.Stream;
import static net.minecraftforge.fml.Logging.CORE;
import static net.minecraftforge.fml.Logging.fmlLog;
public class LanguageLoadingProvider
{
private final List<IModLanguageProvider> languageProviders = new ArrayList<>();
private final ServiceLoader<IModLanguageProvider> serviceLoader;
private final Map<String, IModLanguageProvider> languageProviderMap = new HashMap<>();
LanguageLoadingProvider() {
serviceLoader = ServiceLoader.load(IModLanguageProvider.class);
serviceLoader.forEach(languageProviders::add);
languageProviders.forEach(lp -> {
final Package pkg = lp.getClass().getPackage();
fmlLog.debug(CORE, "Found system classpath language provider {}, version {}", lp.name(), pkg.getImplementationVersion());
});
languageProviders.forEach(lp->languageProviderMap.put(lp.name(), lp));
}
public void addAdditionalLanguages(List<ModFile> modFiles)
{
if (modFiles==null) return;
Stream<Path> langPaths = modFiles.stream().map(ModFile::getFilePath);
serviceLoader.reload();
}
public IModLanguageProvider getLanguage(String name)
{
return languageProviderMap.get(name);
}
}

View File

@ -19,11 +19,14 @@
package net.minecraftforge.fml.loading.moddiscovery;
import com.google.common.util.concurrent.MoreExecutors;
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.ThreadFactory;
import java.util.concurrent.TimeUnit;
import static net.minecraftforge.fml.Logging.SCAN;
@ -37,7 +40,11 @@ public class BackgroundScanHandler
private final List<ModFile> allFiles;
public BackgroundScanHandler() {
modContentScanner = Executors.newCachedThreadPool();
modContentScanner = Executors.newSingleThreadExecutor(r -> {
final Thread thread = Executors.defaultThreadFactory().newThread(r);
thread.setDaemon(true);
return thread;
});
scannedFiles = new ArrayList<>();
pendingFiles = new ArrayList<>();
allFiles = new ArrayList<>();

View File

@ -20,6 +20,8 @@
package net.minecraftforge.fml.loading.moddiscovery;
import cpw.mods.modlauncher.ServiceLoaderStreamUtils;
import net.minecraftforge.fml.loading.FMLLoader;
import net.minecraftforge.fml.loading.LanguageLoadingProvider;
import java.util.Collection;
import java.util.List;
@ -54,12 +56,12 @@ public class ModDiscoverer {
.peek(mf -> fmlLog.debug(SCAN,"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));
FMLLoader.getLanguageLoadingProvider().addAdditionalLanguages(modFiles.get(ModFile.Type.LANGPROVIDER));
BackgroundScanHandler backgroundScanHandler = new BackgroundScanHandler();
final List<ModFile> mods = modFiles.get(ModFile.Type.MOD);
mods.forEach(ModFile::identifyMods);
fmlLog.debug(SCAN,"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.stream().map(ModFile::getCoreMods).flatMap(List::stream).forEach(FMLLoader.getCoreModProvider()::addCoreMod);
mods.forEach(backgroundScanHandler::submitForScanning);
return backgroundScanHandler;
}

View File

@ -19,14 +19,21 @@
package net.minecraftforge.fml.loading.moddiscovery;
import net.minecraftforge.fml.loading.IModLanguageProvider;
import javax.swing.text.html.Option;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
import java.util.stream.Collectors;
import static net.minecraftforge.fml.Logging.LOADING;
import static net.minecraftforge.fml.Logging.SCAN;
@ -40,6 +47,11 @@ public class ModFile
DEFAULTMANIFEST.getMainAttributes().putValue("FMLModType", "MOD");
}
public void claimLanguage(String modId, IModLanguageProvider.IModLanguageLoader loader)
{
this.modInfoMap.get(modId).setLoader(loader);
}
public enum Type {
MOD, LIBRARY, LANGPROVIDER
}
@ -47,6 +59,7 @@ public class ModFile
private final Type modFileType;
private final Manifest manifest;
private List<ModInfo> modInfos;
private Map<String, ModInfo> modInfoMap;
private final IModLocator locator;
private ScanResult fileScanResult;
private CompletableFuture<ScanResult> futureScanResult;
@ -60,7 +73,8 @@ public class ModFile
manifest = locator.findManifest(file).orElse(DEFAULTMANIFEST);
if (manifest != DEFAULTMANIFEST) fmlLog.debug(SCAN,"Mod file {} has a manifest", file);
else fmlLog.debug(SCAN,"Mod file {} is missing a manifest", file);
modFileType = Type.valueOf(manifest.getMainAttributes().getValue(TYPE));
final Optional<String> value = Optional.ofNullable(manifest.getMainAttributes().getValue(TYPE));
modFileType = Type.valueOf(value.orElse("MOD"));
}
public Type getType() {
@ -78,6 +92,7 @@ public class ModFile
public void identifyMods() {
this.modInfos = ModFileParser.readModList(this);
this.modInfos.forEach(mi-> fmlLog.debug(LOADING,"Found mod {} for language {}", mi.getModId(), mi.getModLoader()));
this.modInfoMap = this.modInfos.stream().collect(Collectors.toMap(ModInfo::getModId, Function.identity()));
this.coreMods = ModFileParser.getCoreMods(this);
this.coreMods.forEach(mi-> fmlLog.debug(LOADING,"Found coremod {}", mi.getPath()));
}

View File

@ -20,6 +20,10 @@
package net.minecraftforge.fml.loading.moddiscovery;
import net.minecraftforge.fml.common.versioning.ArtifactVersion;
import net.minecraftforge.fml.loading.IModLanguageProvider;
import java.net.URL;
import java.util.List;
public class ModInfo {
private final ModFile owningFile;
@ -27,11 +31,12 @@ public class ModInfo {
private final ArtifactVersion version;
private final String displayName;
private final String description;
private final java.net.URL updateJSONURL;
private final URL updateJSONURL;
private final String modLoader;
private final java.util.List<net.minecraftforge.fml.loading.moddiscovery.ModInfo.ModVersion> dependencies;
private final List<ModInfo.ModVersion> dependencies;
private IModLanguageProvider.IModLanguageLoader loader;
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) {
public ModInfo(final ModFile owningFile, final String modLoader, final String modId, final String displayName, final ArtifactVersion version, final String description, final URL updateJSONURL, final List<ModInfo.ModVersion> dependencies) {
this.owningFile = owningFile;
this.modLoader = modLoader;
this.modId = modId;
@ -58,6 +63,11 @@ public class ModInfo {
return version;
}
public void setLoader(IModLanguageProvider.IModLanguageLoader loader)
{
this.loader = loader;
}
public enum Ordering {
BEFORE, AFTER, NONE;
}

View File

@ -22,27 +22,33 @@ package net.minecraftforge.fml.loading.moddiscovery;
import org.objectweb.asm.Type;
import java.util.ArrayList;
import java.util.List;
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<>();
private final List<ScanResult.AnnotationData> annotations = new ArrayList<>();
private final List<ScanResult.ClassData> classes = new ArrayList<>();
public ScanResult(final ModFile file) {
this.file = file;
}
public ModFile getFile() {
return file;
}
public static boolean interestingAnnotations(final ModAnnotation annotation) {
return true;
}
public java.util.List<net.minecraftforge.fml.loading.moddiscovery.ScanResult.ClassData> getClasses() {
public List<ScanResult.ClassData> getClasses() {
return classes;
}
public java.util.List<net.minecraftforge.fml.loading.moddiscovery.ScanResult.AnnotationData> getAnnotations() {
public List<ScanResult.AnnotationData> getAnnotations() {
return annotations;
}

View File

@ -19,8 +19,19 @@
package net.minecraftforge.fml.loading.moddiscovery;
import net.minecraftforge.fml.loading.FMLLoader;
import net.minecraftforge.fml.loading.IModLanguageProvider;
import net.minecraftforge.fml.loading.LanguageLoadingProvider;
import org.objectweb.asm.ClassReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import static net.minecraftforge.fml.Logging.LOADING;
import static net.minecraftforge.fml.Logging.SCAN;
import static net.minecraftforge.fml.Logging.fmlLog;
@ -34,17 +45,20 @@ public class Scanner {
public ScanResult scan() {
ScanResult result = new ScanResult(fileToScan);
fileToScan.scanFile(p -> fileVisitor(p, result));
final Set<IModLanguageProvider> modLoaders = fileToScan.getModInfos().stream().map(ModInfo::getModLoader).map(FMLLoader.getLanguageLoadingProvider()::getLanguage).collect(Collectors.toSet());
modLoaders.stream().peek(ml-> fmlLog.debug(SCAN, "Scanning {} with language loader {}", fileToScan.getFilePath(), ml.name()))
.map(IModLanguageProvider::getFileVisitor).forEach(c->c.accept(result));
return result;
}
private void fileVisitor(final java.nio.file.Path path, final ScanResult result) {
private void fileVisitor(final Path path, final ScanResult result) {
try {
fmlLog.debug(SCAN,"Scanning {} path {}", fileToScan, path);
ModClassVisitor mcv = new ModClassVisitor();
org.objectweb.asm.ClassReader cr = new ClassReader(java.nio.file.Files.newInputStream(path));
ClassReader cr = new ClassReader(Files.newInputStream(path));
cr.accept(mcv, 0);
mcv.buildData(result.getClasses(), result.getAnnotations());
} catch (java.io.IOException e) {
} catch (IOException e) {
// mark path bad
}
}

View File

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