Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make things in ML visible so that it can be used by FML in a library-like fashion #130

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ plugins {
id 'java-library'
id 'eclipse'
id 'com.github.ben-manes.versions' version '0.48.0'
id 'net.neoforged.gradleutils' version '3.0.0-alpha.4'
id 'net.neoforged.gradleutils' version '3.0.0'
id 'org.gradlex.extra-java-module-info' version '1.4.2'
id 'maven-publish'
}
Expand Down
3 changes: 3 additions & 0 deletions gradle/daemon-jvm.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

#This file is generated by updateDaemonJvm
toolchainVersion=21
2 changes: 1 addition & 1 deletion settings.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
plugins {
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.6.0'
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.8.0'
}

rootProject.name = "modlauncher"
12 changes: 2 additions & 10 deletions src/main/java/cpw/mods/modlauncher/ArgumentHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
import java.util.function.*;

public class ArgumentHandler {
private String[] args;
private final String[] args;
private OptionSet optionSet;
private OptionSpec<String> profileOption;
private OptionSpec<Path> gameDirOption;
Expand All @@ -37,16 +37,8 @@ public class ArgumentHandler {
private OptionSpec<String> launchTarget;
private OptionSpec<String> uuidOption;

record DiscoveryData(Path gameDir, String launchTarget, String[] arguments) {}

DiscoveryData setArgs(String[] args) {
public ArgumentHandler(String[] args) {
this.args = args;
final OptionParser parser = new OptionParser();
final var gameDir = parser.accepts("gameDir", "Alternative game directory").withRequiredArg().withValuesConvertedBy(new PathConverter(PathProperties.DIRECTORY_EXISTING)).defaultsTo(Path.of("."));
final var launchTarget = parser.accepts("launchTarget", "LauncherService target to launch").withRequiredArg();
parser.allowsUnrecognizedOptions();
final OptionSet optionSet = parser.parse(args);
return new DiscoveryData(optionSet.valueOf(gameDir), optionSet.valueOf(launchTarget), args);
}

void processArguments(Environment env, Consumer<OptionParser> parserConsumer, BiConsumer<OptionSet, BiFunction<String, OptionSet, ITransformationService.OptionResult>> resultConsumer) {
Expand Down
19 changes: 19 additions & 0 deletions src/main/java/cpw/mods/modlauncher/DiscoveryData.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package cpw.mods.modlauncher;

import joptsimple.OptionParser;
import joptsimple.OptionSet;
import joptsimple.util.PathConverter;
import joptsimple.util.PathProperties;

import java.nio.file.Path;

public record DiscoveryData(Path gameDir, String launchTarget, String[] arguments) {
public static DiscoveryData create(String[] programArgs) {
final OptionParser parser = new OptionParser();
final var gameDir = parser.accepts("gameDir", "Alternative game directory").withRequiredArg().withValuesConvertedBy(new PathConverter(PathProperties.DIRECTORY_EXISTING)).defaultsTo(Path.of("."));
final var launchTarget = parser.accepts("launchTarget", "LauncherService target to launch").withRequiredArg();
parser.allowsUnrecognizedOptions();
final OptionSet optionSet = parser.parse(programArgs);
return new DiscoveryData(optionSet.valueOf(gameDir), optionSet.valueOf(launchTarget), programArgs);
}
}
21 changes: 13 additions & 8 deletions src/main/java/cpw/mods/modlauncher/Environment.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,17 @@
* Environment implementation class
*/
public final class Environment implements IEnvironment {
private final TypesafeMap environment;
private final Launcher launcher;
private final TypesafeMap environment = new TypesafeMap(IEnvironment.class);
private final Function<String, Optional<ILaunchPluginService>> launchPlugins;
private final Function<String, Optional<ILaunchHandlerService>> launchService;
private final IModuleLayerManager moduleLayerHandler;

Environment(Launcher launcher) {
environment = new TypesafeMap(IEnvironment.class);
this.launcher = launcher;
public Environment(Function<String, Optional<ILaunchPluginService>> launchPlugins,
Function<String, Optional<ILaunchHandlerService>> launchService,
IModuleLayerManager moduleLayerHandler) {
this.launchPlugins = launchPlugins;
this.launchService = launchService;
this.moduleLayerHandler = moduleLayerHandler;
}

@Override
Expand All @@ -43,17 +48,17 @@ public final <T> Optional<T> getProperty(TypesafeMap.Key<T> key) {

@Override
public Optional<ILaunchPluginService> findLaunchPlugin(final String name) {
return launcher.findLaunchPlugin(name);
return launchPlugins.apply(name);
}

@Override
public Optional<ILaunchHandlerService> findLaunchHandler(final String name) {
return launcher.findLaunchHandler(name);
return launchService.apply(name);
}

@Override
public Optional<IModuleLayerManager> findModuleLayerManager() {
return launcher.findLayerManager();
return Optional.of(this.moduleLayerHandler);
}

@Override
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/cpw/mods/modlauncher/LaunchPluginHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public EnumMap<ILaunchPluginService.Phase, List<ILaunchPluginService>> computeLa
return phaseObjectEnumMap;
}

void offerScanResultsToPlugins(List<SecureJar> scanResults) {
public void offerScanResultsToPlugins(List<SecureJar> scanResults) {
plugins.forEach((n,p)->p.addResources(scanResults));
}

Expand All @@ -102,7 +102,7 @@ int offerClassNodeToPlugins(final ILaunchPluginService.Phase phase, final List<I
return flags;
}

void announceLaunch(final TransformingClassLoader transformerLoader, final NamedPath[] specialPaths) {
public void announceLaunch(final TransformingClassLoader transformerLoader, final NamedPath[] specialPaths) {
plugins.forEach((k, p)->p.initializeLaunch((s->transformerLoader.buildTransformedClassNodeFor(s, k)), specialPaths));
}
}
12 changes: 8 additions & 4 deletions src/main/java/cpw/mods/modlauncher/LaunchServiceHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,16 @@
/**
* Identifies the launch target and dispatches to it
*/
class LaunchServiceHandler {
public class LaunchServiceHandler {
private static final Logger LOGGER = LogManager.getLogger();
private final Map<String, LaunchServiceHandlerDecorator> launchHandlerLookup;

public LaunchServiceHandler(final ModuleLayerHandler layerHandler) {
this.launchHandlerLookup = ServiceLoaderUtils.streamServiceLoader(()->ServiceLoader.load(layerHandler.getLayer(IModuleLayerManager.Layer.BOOT).orElseThrow(), ILaunchHandlerService.class), sce -> LOGGER.fatal("Encountered serious error loading transformation service, expect problems", sce))
this(ServiceLoaderUtils.streamServiceLoader(()->ServiceLoader.load(layerHandler.getLayer(IModuleLayerManager.Layer.BOOT).orElseThrow(), ILaunchHandlerService.class), sce -> LOGGER.fatal("Encountered serious error loading transformation service, expect problems", sce)));
}

public LaunchServiceHandler(Stream<ILaunchHandlerService> launchHandlers) {
this.launchHandlerLookup = launchHandlers
.collect(Collectors.toMap(ILaunchHandlerService::name, LaunchServiceHandlerDecorator::new));
LOGGER.debug(MODLAUNCHER,"Found launch services [{}]", () -> String.join(",",launchHandlerLookup.keySet()));
}
Expand All @@ -45,7 +49,7 @@ public Optional<ILaunchHandlerService> findLaunchHandler(final String name) {
return Optional.ofNullable(launchHandlerLookup.getOrDefault(name, null)).map(LaunchServiceHandlerDecorator::service);
}

private void launch(String target, String[] arguments, ModuleLayer gameLayer, TransformingClassLoader classLoader, final LaunchPluginHandler launchPluginHandler) {
public void launch(String target, String[] arguments, ModuleLayer gameLayer, TransformingClassLoader classLoader, final LaunchPluginHandler launchPluginHandler) {
final LaunchServiceHandlerDecorator launchServiceHandlerDecorator = launchHandlerLookup.get(target);
final NamedPath[] paths = launchServiceHandlerDecorator.service().getPaths();
launchPluginHandler.announceLaunch(classLoader, paths);
Expand All @@ -71,7 +75,7 @@ public void launch(ArgumentHandler argumentHandler, ModuleLayer gameLayer, Trans
launch(launchTarget, args, gameLayer, classLoader, launchPluginHandler);
}

void validateLaunchTarget(final ArgumentHandler argumentHandler) {
public void validateLaunchTarget(final ArgumentHandler argumentHandler) {
if (!launchHandlerLookup.containsKey(argumentHandler.getLaunchTarget())) {
LOGGER.error(MODLAUNCHER, "Cannot find launch target {}, unable to launch",
argumentHandler.getLaunchTarget());
Expand Down
50 changes: 30 additions & 20 deletions src/main/java/cpw/mods/modlauncher/Launcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import cpw.mods.jarhandling.SecureJar;
import cpw.mods.modlauncher.api.*;
import org.apache.logging.log4j.LogManager;
import cpw.mods.modlauncher.serviceapi.ILaunchPluginService;

import java.util.*;
import java.util.stream.Collectors;
Expand All @@ -38,26 +37,43 @@ public class Launcher {
private final TransformationServicesHandler transformationServicesHandler;
private final Environment environment;
private final TransformStore transformStore;
private final ArgumentHandler argumentHandler;
private final LaunchServiceHandler launchService;
private final LaunchPluginHandler launchPlugins;
private final ModuleLayerHandler moduleLayerHandler;
private TransformingClassLoader classLoader;
private ArgumentHandler argumentHandler;

private Launcher() {
INSTANCE = this;
public Launcher() {
LogManager.getLogger().info(MODLAUNCHER,"ModLauncher {} starting: java version {} by {}; OS {} arch {} version {}", ()->IEnvironment.class.getPackage().getImplementationVersion(), () -> System.getProperty("java.version"), ()->System.getProperty("java.vendor"), ()->System.getProperty("os.name"), ()->System.getProperty("os.arch"), ()->System.getProperty("os.version"));
this.moduleLayerHandler = new ModuleLayerHandler();
this.launchService = new LaunchServiceHandler(this.moduleLayerHandler);
this.blackboard = new TypesafeMap();
this.environment = new Environment(this);
environment.computePropertyIfAbsent(IEnvironment.Keys.MLSPEC_VERSION.get(), s->IEnvironment.class.getPackage().getSpecificationVersion());
environment.computePropertyIfAbsent(IEnvironment.Keys.MLIMPL_VERSION.get(), s->IEnvironment.class.getPackage().getImplementationVersion());
environment.computePropertyIfAbsent(IEnvironment.Keys.MODLIST.get(), s->new ArrayList<>());
this.transformStore = new TransformStore();
this.transformationServicesHandler = new TransformationServicesHandler(this.transformStore, this.moduleLayerHandler);
this.argumentHandler = new ArgumentHandler();
this.launchPlugins = new LaunchPluginHandler(this.moduleLayerHandler);
this.environment = new Environment(
launchPlugins::get,
launchService::findLaunchHandler,
moduleLayerHandler
);
environment.computePropertyIfAbsent(IEnvironment.Keys.MLSPEC_VERSION.get(), s->IEnvironment.class.getPackage().getSpecificationVersion());
environment.computePropertyIfAbsent(IEnvironment.Keys.MLIMPL_VERSION.get(), s->IEnvironment.class.getPackage().getImplementationVersion());
environment.computePropertyIfAbsent(IEnvironment.Keys.MODLIST.get(), s->new ArrayList<>());
}

public Launcher(TransformationServicesHandler transformationServicesHandler,
Environment environment,
TransformStore transformStore,
LaunchServiceHandler launchService,
LaunchPluginHandler launchPlugins,
ModuleLayerHandler moduleLayerHandler) {
this.blackboard = new TypesafeMap();
this.transformationServicesHandler = transformationServicesHandler;
this.environment = environment;
this.transformStore = transformStore;
this.launchService = launchService;
this.launchPlugins = launchPlugins;
this.moduleLayerHandler = moduleLayerHandler;
}

public static void main(String... args) {
Expand All @@ -71,16 +87,18 @@ public static void main(String... args) {
}
LogManager.getLogger().info(MODLAUNCHER,"ModLauncher running: args {}", () -> LaunchServiceHandler.hideAccessToken(args));
LogManager.getLogger().info(MODLAUNCHER, "JVM identified as {} {} {}", props.getProperty("java.vm.vendor"), props.getProperty("java.vm.name"), props.getProperty("java.vm.version"));
new Launcher().run(args);
var launcher = new Launcher();
INSTANCE = launcher;
launcher.run(args);
}

public final TypesafeMap blackboard() {
return blackboard;
}

private void run(String... args) {
final ArgumentHandler.DiscoveryData discoveryData = this.argumentHandler.setArgs(args);
this.transformationServicesHandler.discoverServices(discoveryData);
this.argumentHandler = new ArgumentHandler(args);
this.transformationServicesHandler.discoverServices(DiscoveryData.create(args));
final var scanResults = this.transformationServicesHandler.initializeTransformationServices(this.argumentHandler, this.environment)
.stream().collect(Collectors.groupingBy(ITransformationService.Resource::target));
scanResults.getOrDefault(IModuleLayerManager.Layer.PLUGIN, List.of())
Expand All @@ -107,14 +125,6 @@ public Environment environment() {
return this.environment;
}

Optional<ILaunchPluginService> findLaunchPlugin(final String name) {
return launchPlugins.get(name);
}

Optional<ILaunchHandlerService> findLaunchHandler(final String name) {
return launchService.findLaunchHandler(name);
}

public Optional<IModuleLayerManager> findLayerManager() {
return Optional.ofNullable(this.moduleLayerHandler);
}
Expand Down
9 changes: 5 additions & 4 deletions src/main/java/cpw/mods/modlauncher/ModuleLayerHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
import java.util.function.Consumer;

public final class ModuleLayerHandler implements IModuleLayerManager {
record LayerInfo(ModuleLayer layer, ModuleClassLoader cl) {}
public record LayerInfo(ModuleLayer layer, ModuleClassLoader cl) {}

private record PathOrJar(NamedPath path, SecureJar jar) {
static PathOrJar from(SecureJar jar) {
Expand All @@ -48,16 +48,17 @@ SecureJar build() {
private final EnumMap<Layer, List<PathOrJar>> layers = new EnumMap<>(Layer.class);
private final EnumMap<Layer, LayerInfo> completedLayers = new EnumMap<>(Layer.class);

ModuleLayerHandler() {
public ModuleLayerHandler() {
ClassLoader classLoader = getClass().getClassLoader();
// Create a new ModuleClassLoader from the boot module layer if it doesn't exist already.
// This allows us to launch without BootstrapLauncher.
ModuleClassLoader cl = classLoader instanceof ModuleClassLoader moduleCl ? moduleCl
: new ModuleClassLoader("BOOT", ModuleLayer.boot().configuration(), List.of());
completedLayers.put(Layer.BOOT, new LayerInfo(getClass().getModule().getLayer(), cl));
var ownLayer = Objects.requireNonNullElse(getClass().getModule().getLayer(), ModuleLayer.boot());
completedLayers.put(Layer.BOOT, new LayerInfo(ownLayer, cl));
}

void addToLayer(final Layer layer, final SecureJar jar) {
public void addToLayer(final Layer layer, final SecureJar jar) {
if (completedLayers.containsKey(layer)) throw new IllegalStateException("Layer already populated");
layers.computeIfAbsent(layer, l->new ArrayList<>()).add(PathOrJar.from(jar));
}
Expand Down
30 changes: 25 additions & 5 deletions src/main/java/cpw/mods/modlauncher/TransformStore.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.objectweb.asm.tree.*;

import java.util.*;
import java.util.stream.Collectors;

import static cpw.mods.modlauncher.LogMarkers.*;

Expand All @@ -41,30 +42,49 @@ public TransformStore() {
transformers.put(type, new TransformList<>(type.getNodeType()));
}

List<ITransformer<FieldNode>> getTransformersFor(String className, FieldNode field) {
public List<ITransformer<FieldNode>> getTransformersFor(String className, FieldNode field) {
TransformTargetLabel tl = new TransformTargetLabel(className, field.name);
TransformList<FieldNode> transformerlist = TargetType.FIELD.get(this.transformers);
return transformerlist.getTransformersForLabel(tl);
}

List<ITransformer<MethodNode>> getTransformersFor(String className, MethodNode method) {
public List<ITransformer<MethodNode>> getTransformersFor(String className, MethodNode method) {
TransformTargetLabel tl = new TransformTargetLabel(className, method.name, method.desc);
TransformList<MethodNode> transformerlist = TargetType.METHOD.get(this.transformers);
return transformerlist.getTransformersForLabel(tl);
}

List<ITransformer<ClassNode>> getTransformersFor(String className, TargetType<ClassNode> classType) {
public List<ITransformer<ClassNode>> getTransformersFor(String className, TargetType<ClassNode> classType) {
TransformTargetLabel tl = new TransformTargetLabel(className, classType);
TransformList<ClassNode> transformerlist = classType.get(this.transformers);
return transformerlist.getTransformersForLabel(tl);
}

public void addTransformer(ITransformer<?> xform, ITransformationService owner) {
final TargetType<?> targetType = xform.getTargetType();
Objects.requireNonNull(targetType, "Transformer type must not be null");
final Set<? extends ITransformer.Target<?>> targets = xform.targets();
if (!targets.isEmpty()) {
final Map<TargetType<?>, List<TransformTargetLabel>> targetTypeListMap = targets.stream()
.map(TransformTargetLabel::new)
.collect(Collectors.groupingBy(TransformTargetLabel::getTargetType));
if (targetTypeListMap.keySet().size() > 1 || !targetTypeListMap.containsKey(targetType)) {
LOGGER.error("Invalid target {} for transformer {}", targetType, xform);
throw new IllegalArgumentException("The transformer contains invalid targets");
}
targetTypeListMap.values()
.stream()
.flatMap(Collection::stream)
.forEach(target -> addTransformer(target, xform, owner));
}
}

@SuppressWarnings("unchecked")
<T> void addTransformer(TransformTargetLabel targetLabel, ITransformer<T> transformer, ITransformationService service) {
public <T> void addTransformer(TransformTargetLabel targetLabel, ITransformer<T> transformer, ITransformationService owner) {
LOGGER.debug(MODLAUNCHER,"Adding transformer {} to {}", () -> transformer, () -> targetLabel);
classNeedsTransforming.add(targetLabel.getClassName().getInternalName());
final TransformList<T> transformList = (TransformList<T>) this.transformers.get(targetLabel.getTargetType());
transformList.addTransformer(targetLabel, new TransformerHolder<>(transformer, service));
transformList.addTransformer(targetLabel, new TransformerHolder<>(transformer, owner));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public final Type getElementDescriptor() {
return this.elementDescriptor;
}

final TargetType<?> getTargetType() {
public TargetType<?> getTargetType() {
return this.labelType;
}

Expand Down
Loading
Loading