Skip to content

Commit

Permalink
Make things in ML visible so that it can be used by FML in a library-…
Browse files Browse the repository at this point in the history
…like fashion.
  • Loading branch information
shartte committed Jul 1, 2024
1 parent 0f24dec commit 76f359e
Show file tree
Hide file tree
Showing 15 changed files with 123 additions and 106 deletions.
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
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
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 Down
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
4 changes: 2 additions & 2 deletions src/main/java/cpw/mods/modlauncher/ModuleLayerHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ 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.
Expand All @@ -57,7 +57,7 @@ SecureJar build() {
completedLayers.put(Layer.BOOT, new LayerInfo(getClass().getModule().getLayer(), 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
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import org.jetbrains.annotations.VisibleForTesting;

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

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

Expand Down Expand Up @@ -67,24 +66,9 @@ public void gatherTransformers(TransformStore transformStore) {
LOGGER.debug(MODLAUNCHER,"Initializing transformers for transformation service {}", this.service::name);
final List<? extends ITransformer<?>> transformers = this.service.transformers();
Objects.requireNonNull(transformers, "The transformers list should not be null");
transformers.forEach(xform -> {
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(MODLAUNCHER,"Invalid target {} for transformer {}", targetType, xform);
throw new IllegalArgumentException("The transformer contains invalid targets");
}
targetTypeListMap.values()
.stream()
.flatMap(Collection::stream)
.forEach(target -> transformStore.addTransformer(target, xform, service));
}
});
for (ITransformer<?> xform : transformers) {
transformStore.addTransformer(xform, service);
}
LOGGER.debug(MODLAUNCHER,"Initialized transformers for transformation service {}", this.service::name);
}

Expand Down
Loading

0 comments on commit 76f359e

Please sign in to comment.