diff --git a/build.gradle b/build.gradle index 41bcfe9..aa7259e 100644 --- a/build.gradle +++ b/build.gradle @@ -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' } diff --git a/gradle/daemon-jvm.properties b/gradle/daemon-jvm.properties new file mode 100644 index 0000000..ebc8101 --- /dev/null +++ b/gradle/daemon-jvm.properties @@ -0,0 +1,3 @@ + +#This file is generated by updateDaemonJvm +toolchainVersion=21 diff --git a/settings.gradle b/settings.gradle index 08664b0..7c8cbff 100644 --- a/settings.gradle +++ b/settings.gradle @@ -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" \ No newline at end of file diff --git a/src/main/java/cpw/mods/modlauncher/ArgumentHandler.java b/src/main/java/cpw/mods/modlauncher/ArgumentHandler.java index 3b2d735..0363c26 100644 --- a/src/main/java/cpw/mods/modlauncher/ArgumentHandler.java +++ b/src/main/java/cpw/mods/modlauncher/ArgumentHandler.java @@ -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; @@ -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) { diff --git a/src/main/java/cpw/mods/modlauncher/DiscoveryData.java b/src/main/java/cpw/mods/modlauncher/DiscoveryData.java new file mode 100644 index 0000000..2b70701 --- /dev/null +++ b/src/main/java/cpw/mods/modlauncher/DiscoveryData.java @@ -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); + } +} diff --git a/src/main/java/cpw/mods/modlauncher/Environment.java b/src/main/java/cpw/mods/modlauncher/Environment.java index 1c09e34..b4310d1 100644 --- a/src/main/java/cpw/mods/modlauncher/Environment.java +++ b/src/main/java/cpw/mods/modlauncher/Environment.java @@ -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 @@ -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 diff --git a/src/main/java/cpw/mods/modlauncher/LaunchPluginHandler.java b/src/main/java/cpw/mods/modlauncher/LaunchPluginHandler.java index f395314..cb0cff7 100644 --- a/src/main/java/cpw/mods/modlauncher/LaunchPluginHandler.java +++ b/src/main/java/cpw/mods/modlauncher/LaunchPluginHandler.java @@ -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)); } @@ -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)); } } diff --git a/src/main/java/cpw/mods/modlauncher/LaunchServiceHandler.java b/src/main/java/cpw/mods/modlauncher/LaunchServiceHandler.java index 00c882e..47c63cc 100644 --- a/src/main/java/cpw/mods/modlauncher/LaunchServiceHandler.java +++ b/src/main/java/cpw/mods/modlauncher/LaunchServiceHandler.java @@ -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())); } @@ -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); @@ -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()); diff --git a/src/main/java/cpw/mods/modlauncher/Launcher.java b/src/main/java/cpw/mods/modlauncher/Launcher.java index a247d65..4828957 100644 --- a/src/main/java/cpw/mods/modlauncher/Launcher.java +++ b/src/main/java/cpw/mods/modlauncher/Launcher.java @@ -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; @@ -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) { @@ -71,7 +87,9 @@ 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() { @@ -79,8 +97,8 @@ public final TypesafeMap 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()) @@ -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); } diff --git a/src/main/java/cpw/mods/modlauncher/ModuleLayerHandler.java b/src/main/java/cpw/mods/modlauncher/ModuleLayerHandler.java index 4bb7bfb..2275877 100644 --- a/src/main/java/cpw/mods/modlauncher/ModuleLayerHandler.java +++ b/src/main/java/cpw/mods/modlauncher/ModuleLayerHandler.java @@ -23,6 +23,7 @@ import cpw.mods.jarhandling.SecureJar; import cpw.mods.modlauncher.api.IModuleLayerManager; import cpw.mods.modlauncher.api.NamedPath; +import org.jetbrains.annotations.Nullable; import java.lang.module.Configuration; import java.lang.module.ModuleFinder; @@ -31,7 +32,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) { @@ -48,16 +49,21 @@ 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() { + this(null); + } + + public ModuleLayerHandler(@Nullable ClassLoader parentLoader) { 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)); + : new ModuleClassLoader("BOOT", ModuleLayer.boot().configuration(), List.of(), parentLoader); + 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)); } diff --git a/src/main/java/cpw/mods/modlauncher/TransformStore.java b/src/main/java/cpw/mods/modlauncher/TransformStore.java index fd52cb3..0608b2c 100644 --- a/src/main/java/cpw/mods/modlauncher/TransformStore.java +++ b/src/main/java/cpw/mods/modlauncher/TransformStore.java @@ -24,6 +24,7 @@ import org.objectweb.asm.tree.*; import java.util.*; +import java.util.stream.Collectors; import static cpw.mods.modlauncher.LogMarkers.*; @@ -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)); } /** diff --git a/src/main/java/cpw/mods/modlauncher/TransformTargetLabel.java b/src/main/java/cpw/mods/modlauncher/TransformTargetLabel.java index df9ac70..109b16d 100644 --- a/src/main/java/cpw/mods/modlauncher/TransformTargetLabel.java +++ b/src/main/java/cpw/mods/modlauncher/TransformTargetLabel.java @@ -74,7 +74,7 @@ public final Type getElementDescriptor() { return this.elementDescriptor; } - final TargetType<?> getTargetType() { + public TargetType<?> getTargetType() { return this.labelType; } diff --git a/src/main/java/cpw/mods/modlauncher/TransformationServiceDecorator.java b/src/main/java/cpw/mods/modlauncher/TransformationServiceDecorator.java index 404a51e..88f0f00 100644 --- a/src/main/java/cpw/mods/modlauncher/TransformationServiceDecorator.java +++ b/src/main/java/cpw/mods/modlauncher/TransformationServiceDecorator.java @@ -24,7 +24,6 @@ import org.jetbrains.annotations.VisibleForTesting; import java.util.*; -import java.util.stream.*; import static cpw.mods.modlauncher.LogMarkers.*; @@ -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); } diff --git a/src/main/java/cpw/mods/modlauncher/TransformationServicesHandler.java b/src/main/java/cpw/mods/modlauncher/TransformationServicesHandler.java index 6b4209e..ed7be6a 100644 --- a/src/main/java/cpw/mods/modlauncher/TransformationServicesHandler.java +++ b/src/main/java/cpw/mods/modlauncher/TransformationServicesHandler.java @@ -31,18 +31,24 @@ import static cpw.mods.modlauncher.LogMarkers.*; -class TransformationServicesHandler { +public class TransformationServicesHandler { private static final Logger LOGGER = LogManager.getLogger(); private Map<String, TransformationServiceDecorator> serviceLookup; private final TransformStore transformStore; private final ModuleLayerHandler layerHandler; - TransformationServicesHandler(TransformStore transformStore, ModuleLayerHandler layerHandler) { + public TransformationServicesHandler(TransformStore transformStore, ModuleLayerHandler layerHandler) { this.transformStore = transformStore; this.layerHandler = layerHandler; } - List<ITransformationService.Resource> initializeTransformationServices(ArgumentHandler argumentHandler, Environment environment) { + public TransformationServicesHandler(TransformStore transformStore, ModuleLayerHandler layerHandler, Environment environment, Collection<ITransformationService> services) { + this.transformStore = transformStore; + this.layerHandler = layerHandler; + setTransformationServices(services, environment); + } + + public List<ITransformationService.Resource> initializeTransformationServices(ArgumentHandler argumentHandler, Environment environment) { loadTransformationServices(environment); validateTransformationServices(); processArguments(argumentHandler, environment); @@ -50,7 +56,9 @@ List<ITransformationService.Resource> initializeTransformationServices(ArgumentH return runScanningTransformationServices(environment); } - TransformingClassLoader buildTransformingClassLoader(final LaunchPluginHandler pluginHandler, final Environment environment, final ModuleLayerHandler layerHandler) { + public TransformingClassLoader buildTransformingClassLoader(final LaunchPluginHandler pluginHandler, + final Environment environment, + final ModuleLayerHandler layerHandler) { final var layerInfo = layerHandler.buildLayer(IModuleLayerManager.Layer.GAME, (cf, parents)->new TransformingClassLoader(transformStore, pluginHandler, environment, cf, parents)); layerHandler.updateLayer(IModuleLayerManager.Layer.PLUGIN, li->li.cl().setFallbackClassLoader(layerInfo.cl())); return (TransformingClassLoader) layerInfo.cl(); @@ -74,7 +82,7 @@ private void offerArgumentResultsToServices(OptionSet optionSet, BiFunction<Stri .forEach(service -> service.argumentValues(resultHandler.apply(service.name(), optionSet))); } - void initialiseServiceTransformers() { + public void initialiseServiceTransformers() { LOGGER.debug(MODLAUNCHER,"Transformation services loading transformers"); serviceLookup.values().forEach(s -> s.gatherTransformers(transformStore)); @@ -110,7 +118,7 @@ private void loadTransformationServices(Environment environment) { serviceLookup.values().forEach(s -> s.onLoad(environment, serviceLookup.keySet())); } - void discoverServices(final ArgumentHandler.DiscoveryData discoveryData) { + public void discoverServices(final DiscoveryData discoveryData) { LOGGER.debug(MODLAUNCHER, "Discovering transformation services"); var bootLayer = layerHandler.getLayer(IModuleLayerManager.Layer.BOOT).orElseThrow(); var earlyDiscoveryServices = ServiceLoaderUtils.streamServiceLoader(()->ServiceLoader.load(bootLayer, ITransformerDiscoveryService.class), sce -> LOGGER.fatal(MODLAUNCHER, "Encountered serious error loading transformation discoverer, expect problems", sce)) @@ -123,14 +131,18 @@ void discoverServices(final ArgumentHandler.DiscoveryData discoveryData) { additionalPaths.forEach(np->layerHandler.addToLayer(IModuleLayerManager.Layer.SERVICE, np)); var serviceLayer = layerHandler.buildLayer(IModuleLayerManager.Layer.SERVICE); earlyDiscoveryServices.forEach(s->s.earlyInitialization(discoveryData.launchTarget(), discoveryData.arguments())); - serviceLookup = ServiceLoaderUtils.streamServiceLoader(()->ServiceLoader.load(serviceLayer.layer(), ITransformationService.class), sce -> LOGGER.fatal(MODLAUNCHER, "Encountered serious error loading transformation service, expect problems", sce)) - .collect(Collectors.toMap(ITransformationService::name, TransformationServiceDecorator::new)); + setTransformationServices(ServiceLoaderUtils.streamServiceLoader(()->ServiceLoader.load(serviceLayer.layer(), ITransformationService.class), sce -> LOGGER.fatal(MODLAUNCHER, "Encountered serious error loading transformation service, expect problems", sce)) + .toList(), Launcher.INSTANCE.environment()); + } + + private void setTransformationServices(Collection<ITransformationService> services, Environment environment) { + serviceLookup = services.stream().collect(Collectors.toMap(ITransformationService::name, TransformationServiceDecorator::new)); var modlist = serviceLookup.entrySet().stream().map(e->Map.of( "name", e.getKey(), "type", "TRANSFORMATIONSERVICE", "file", ServiceLoaderUtils.fileNameFor(e.getValue().getClass()) )).toList(); - Launcher.INSTANCE.environment().getProperty(IEnvironment.Keys.MODLIST.get()).ifPresent(ml->ml.addAll(modlist)); + environment.getProperty(IEnvironment.Keys.MODLIST.get()).ifPresent(ml->ml.addAll(modlist)); LOGGER.debug(MODLAUNCHER,"Found transformer services : [{}]", () -> String.join(",",serviceLookup.keySet())); } diff --git a/src/main/resources/META-INF/MANIFEST.MF b/src/main/resources/META-INF/MANIFEST.MF deleted file mode 100644 index 5a898d3..0000000 --- a/src/main/resources/META-INF/MANIFEST.MF +++ /dev/null @@ -1,26 +0,0 @@ -Manifest-Version: 1.0 - -Name: cpw/mods/modlauncher/api/ -Specification-Title: modlauncher -Specification-Vendor: forge -Specification-Version: 7.0 -Implementation-Title: modlauncher -Implementation-Version: 9.0.1+0+master.09c65e8 -Implementation-Vendor: forge -Implementation-Timestamp: 2021-06-09T01:29:30.431684967Z -Git-Commit: 09c65e8 -Git-Branch: master -Build-Number: 0 - -Name: cpw/mods/modlauncher/cpw.mods.modlauncher.serviceapi/ -Specification-Title: modlauncherserviceapi -Specification-Vendor: forge -Specification-Version: 7.0 -Implementation-Title: modlauncher -Implementation-Version: 9.0.1+0+master.09c65e8 -Implementation-Vendor: forge -Implementation-Timestamp: 2021-06-09T01:29:30.433729643Z -Git-Commit: 09c65e8 -Git-Branch: master -Build-Number: 0 - diff --git a/src/main/resources/cpw.mods.modlauncher.resourceroot b/src/main/resources/cpw.mods.modlauncher.resourceroot new file mode 100644 index 0000000..e69de29 diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml index 78aa13c..78664cb 100644 --- a/src/main/resources/log4j2.xml +++ b/src/main/resources/log4j2.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<Configuration status="warn" packages="cpw.mods.modlauncher.log"> +<Configuration status="warn"> <filters> <MarkerFilter marker="NETWORK_PACKETS" onMatch="DENY" onMismatch="NEUTRAL"/> <MarkerFilter marker="CLASSLOADING" onMatch="DENY" onMismatch="NEUTRAL"/> diff --git a/src/test/java/cpw/mods/modlauncher/test/TransformingClassLoaderTests.java b/src/test/java/cpw/mods/modlauncher/test/TransformingClassLoaderTests.java index ac0d125..e55719d 100644 --- a/src/test/java/cpw/mods/modlauncher/test/TransformingClassLoaderTests.java +++ b/src/test/java/cpw/mods/modlauncher/test/TransformingClassLoaderTests.java @@ -33,6 +33,7 @@ import java.lang.reflect.Constructor; import java.nio.file.Path; import java.util.List; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -56,16 +57,19 @@ public List<? extends ITransformer<?>> transformers() { }; TransformStore transformStore = new TransformStore(); - ModuleLayerHandler layerHandler = Whitebox.invokeConstructor(ModuleLayerHandler.class); + ModuleLayerHandler layerHandler = new ModuleLayerHandler(); LaunchPluginHandler lph = new LaunchPluginHandler(layerHandler); TransformationServiceDecorator sd = Whitebox.invokeConstructor(TransformationServiceDecorator.class, mockTransformerService); sd.gatherTransformers(transformStore); - Environment environment = Whitebox.invokeConstructor(Environment.class, new Class[]{ Launcher.class }, new Object[]{ null }); + Environment environment = new Environment( + s -> Optional.empty(), + s -> Optional.empty(), + layerHandler + ); new TypesafeMap(IEnvironment.class); - Constructor<TransformingClassLoader> constructor = Whitebox.getConstructor(TransformingClassLoader.class, TransformStore.class, LaunchPluginHandler.class, Environment.class, Configuration.class, List.class); Configuration configuration = createTestJarsConfiguration(); - TransformingClassLoader tcl = constructor.newInstance(transformStore, lph, environment, configuration, List.of(ModuleLayer.boot())); + TransformingClassLoader tcl = new TransformingClassLoader(transformStore, lph, environment, configuration, List.of(ModuleLayer.boot())); ModuleLayer.boot().defineModules(configuration, s -> tcl); final Class<?> aClass = Class.forName(TARGET_CLASS, true, tcl); diff --git a/src/test/resources/log4j2.xml b/src/test/resources/log4j2.xml index 2bd065a..a43313e 100644 --- a/src/test/resources/log4j2.xml +++ b/src/test/resources/log4j2.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<Configuration status="warn" packages="cpw.mods.modlauncher.log"> +<Configuration status="warn"> <filters> <MarkerFilter marker="NETWORK_PACKETS" onMatch="DENY" onMismatch="NEUTRAL"/> <MarkerFilter marker="CLASSLOADING" onMatch="DENY" onMismatch="NEUTRAL"/>