diff --git a/README.md b/README.md index c33a383..90b4d67 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,2 @@ -# Java 8 mod launcher for Minecraft -Intended as a replacement for LegacyLauncher, using Java 8 and 9 compatible constructs \ No newline at end of file +# Java 21 mod launcher for Minecraft +Intended as a replacement for LegacyLauncher, using Java 8 and 9+ compatible constructs diff --git a/build.gradle b/build.gradle index a592342..3c83e49 100644 --- a/build.gradle +++ b/build.gradle @@ -11,7 +11,7 @@ plugins { } java { - toolchain.languageVersion = JavaLanguageVersion.of(16) + toolchain.languageVersion = JavaLanguageVersion.of(21) withSourcesJar() } @@ -48,7 +48,6 @@ configurations.all { extraJavaModuleInfo { failOnMissingModuleInfo = false - automaticModule('net.sf.jopt-simple:jopt-simple', 'jopt.simple') } license { @@ -133,15 +132,15 @@ eclipse.classpath { allprojects { ext.VALID_VMS = [ - 'Adoptium': [16, 17, 18, 19, 20, 21], - 'Amazon': [16, 17, 18, 19, 20, 21], - 'Azul': (16..21), - 'BellSoft': (16..21), - 'Graal_VM': [16, 17, 19, 20, 21], - 'IBM': [16, 17, 18, 19, 20 ], - 'Microsoft': [16, 17, 21], - 'Oracle': (16..21), - 'SAP': (16..20) + 'Adoptium': (21..23), + 'Amazon': (21..23), + 'Azul': (21..23), + 'BellSoft': (21..23), + 'Graal_VM': [21, 23], +// 'IBM': [16, 17, 18, 19, 20 ], + 'Microsoft': [21], + 'Oracle': (21..23), +// 'SAP': (16..20) ] //ext.VALID_VMS = [ 'Adoptium': [16] ] -} \ No newline at end of file +} diff --git a/ml-jmh/build.gradle b/ml-jmh/build.gradle index 54eb05d..e0be305 100644 --- a/ml-jmh/build.gradle +++ b/ml-jmh/build.gradle @@ -14,7 +14,7 @@ repositories { } java { - toolchain.languageVersion = JavaLanguageVersion.of(16) + toolchain.languageVersion = JavaLanguageVersion.of(21) } license { diff --git a/ml-jmh/src/main/java/net/minecraftforge/modlauncher/jmh/TransformBenchmark.java b/ml-jmh/src/main/java/net/minecraftforge/modlauncher/jmh/TransformBenchmark.java index 8cd3658..784308a 100644 --- a/ml-jmh/src/main/java/net/minecraftforge/modlauncher/jmh/TransformBenchmark.java +++ b/ml-jmh/src/main/java/net/minecraftforge/modlauncher/jmh/TransformBenchmark.java @@ -21,7 +21,7 @@ import java.util.List; import java.util.Map; -import static cpw.mods.modlauncher.api.LamdbaExceptionUtils.uncheck; +import static cpw.mods.modlauncher.api.LambdaExceptionUtils.uncheck; @State(Scope.Benchmark) public class TransformBenchmark { diff --git a/ml-test-jar/build.gradle b/ml-test-jar/build.gradle index 7da0b61..c8bfa5c 100644 --- a/ml-test-jar/build.gradle +++ b/ml-test-jar/build.gradle @@ -12,7 +12,7 @@ repositories { } java { - toolchain.languageVersion = JavaLanguageVersion.of(16) + toolchain.languageVersion = JavaLanguageVersion.of(21) } license { diff --git a/ml-test/build.gradle b/ml-test/build.gradle index ea447ff..d93ff87 100644 --- a/ml-test/build.gradle +++ b/ml-test/build.gradle @@ -13,7 +13,7 @@ repositories { } java { - toolchain.languageVersion = JavaLanguageVersion.of(16) + toolchain.languageVersion = JavaLanguageVersion.of(21) } license { diff --git a/ml-test/src/test/java/net/minecraftforge/modlauncher/test/EnumerationHelperTest.java b/ml-test/src/test/java/net/minecraftforge/modlauncher/test/EnumerationHelperTest.java deleted file mode 100644 index fc63b1c..0000000 --- a/ml-test/src/test/java/net/minecraftforge/modlauncher/test/EnumerationHelperTest.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) Forge Development LLC - * SPDX-License-Identifier: LGPL-3.0-only - */ - -package net.minecraftforge.modlauncher.test; - -import cpw.mods.modlauncher.EnumerationHelper; -import org.junit.jupiter.api.Test; - -import java.util.*; -import java.util.function.Function; -import java.util.stream.Stream; - -import static org.junit.jupiter.api.Assertions.*; - -class EnumerationHelperTest { - - @Test - void merge() { - final List strs1 = Arrays.asList("one", "two", "three"); - Vector str1 = new Vector<>(strs1); - final List strs2 = Arrays.asList("four", "five", "six"); - Vector str2 = new Vector<>(strs2); - final ArrayList result = Collections.list(EnumerationHelper.merge(str1.elements(), str2.elements())); - assertArrayEquals(Stream.concat(strs1.stream(), strs2.stream()).toArray(String[]::new), result.toArray(new String[0])); - } - - @Test - void fromOptional() { - final Function> function = EnumerationHelper.fromOptional(Optional::ofNullable); - assertTrue(function.apply("result").hasMoreElements(), "has more"); - assertFalse(function.apply(null).hasMoreElements(), "has no more"); - assertEquals("result", function.apply("result").nextElement(),"returns element as first result"); - final Enumeration result = function.apply("result"); - result.nextElement(); - assertFalse(result.hasMoreElements(), "has no more"); - } -} \ No newline at end of file diff --git a/ml-test/src/test/java/net/minecraftforge/modlauncher/test/MockLauncherHandlerService.java b/ml-test/src/test/java/net/minecraftforge/modlauncher/test/MockLauncherHandlerService.java index 9498bdc..3883b69 100644 --- a/ml-test/src/test/java/net/minecraftforge/modlauncher/test/MockLauncherHandlerService.java +++ b/ml-test/src/test/java/net/minecraftforge/modlauncher/test/MockLauncherHandlerService.java @@ -19,12 +19,5 @@ public String name() { } @Override - public void configureTransformationClassLoader(final ITransformingClassLoaderBuilder builder) { - - } - - @Override - public ServiceRunner launchService(String[] arguments, ModuleLayer gameLayer) { - return ServiceRunner.NOOP; - } + public void launchService(String[] arguments, ModuleLayer gameLayer) {} } diff --git a/ml-test/src/test/java/net/minecraftforge/modlauncher/test/MockTransformerService.java b/ml-test/src/test/java/net/minecraftforge/modlauncher/test/MockTransformerService.java index ec3062f..9d69896 100644 --- a/ml-test/src/test/java/net/minecraftforge/modlauncher/test/MockTransformerService.java +++ b/ml-test/src/test/java/net/minecraftforge/modlauncher/test/MockTransformerService.java @@ -77,7 +77,7 @@ private static List getTestJars() { var ret = new ArrayList(); for (var strings : harness.split(",")) { - var paths = Arrays.stream(strings.split("\0")).map(p -> Path.of(p)).toArray(Path[]::new); + var paths = Arrays.stream(strings.split("\0")).map(Path::of).toArray(Path[]::new); var jar = SecureJar.from(paths); ret.add(jar); } diff --git a/ml-test/src/test/java/net/minecraftforge/modlauncher/test/TransformationServiceDecoratorTests.java b/ml-test/src/test/java/net/minecraftforge/modlauncher/test/TransformationServiceDecoratorTests.java index 112a0fa..0dec7a2 100644 --- a/ml-test/src/test/java/net/minecraftforge/modlauncher/test/TransformationServiceDecoratorTests.java +++ b/ml-test/src/test/java/net/minecraftforge/modlauncher/test/TransformationServiceDecoratorTests.java @@ -51,10 +51,10 @@ public List transformers() { Set targettedClasses = Whitebox.getInternalState(store, "classNeedsTransforming"); assertAll( () -> assertTrue(transformers.containsKey(TransformTargetLabel.LabelType.CLASS), "transformers contains class"), - () -> assertTrue(getTransformers(transformers.get(TransformTargetLabel.LabelType.CLASS)).values().stream().flatMap(Collection::stream).allMatch(s -> Whitebox.getInternalState(s,"wrapped") == classNodeTransformer), "transformers contains classTransformer"), + () -> assertTrue(getTransformers(transformers.get(TransformTargetLabel.LabelType.CLASS)).values().stream().flatMap(Collection::stream).allMatch(s -> Whitebox.getInternalState(s,"delegate") == classNodeTransformer), "transformers contains classTransformer"), () -> assertTrue(targettedClasses.contains("cheese/Puffs"), "targetted classes contains class name cheese/Puffs"), () -> assertTrue(transformers.containsKey(TransformTargetLabel.LabelType.METHOD), "transformers contains method"), - () -> assertTrue(getTransformers(transformers.get(TransformTargetLabel.LabelType.METHOD)).values().stream().flatMap(Collection::stream).allMatch(s -> Whitebox.getInternalState(s,"wrapped") == methodNodeTransformer), "transformers contains methodTransformer"), + () -> assertTrue(getTransformers(transformers.get(TransformTargetLabel.LabelType.METHOD)).values().stream().flatMap(Collection::stream).allMatch(s -> Whitebox.getInternalState(s,"delegate") == methodNodeTransformer), "transformers contains methodTransformer"), () -> assertTrue(targettedClasses.contains("cheesy/PuffMethod"), "targetted classes contains class name cheesy/PuffMethod") ); } diff --git a/src/main/java/cpw/mods/modlauncher/ArgumentHandler.java b/src/main/java/cpw/mods/modlauncher/ArgumentHandler.java index ca23431..90d1a1c 100644 --- a/src/main/java/cpw/mods/modlauncher/ArgumentHandler.java +++ b/src/main/java/cpw/mods/modlauncher/ArgumentHandler.java @@ -6,94 +6,85 @@ package cpw.mods.modlauncher; import cpw.mods.modlauncher.api.*; +import cpw.mods.modlauncher.internal.GuardedOptionResult; import joptsimple.*; import joptsimple.util.*; -import org.jetbrains.annotations.NotNull; import java.nio.file.*; import java.util.*; import java.util.function.*; -public class ArgumentHandler { - private String[] args; +public final class ArgumentHandler { + private static final OptionParser PARSER = new OptionParser(); + + private static final OptionSpec PROFILE_OPTION = PARSER + .accepts("version", "The version we launched with") + .withRequiredArg(); + + private static final OptionSpec GAME_DIR_OPTION = PARSER + .accepts("gameDir", "Alternative game directory") + .withRequiredArg() + .withValuesConvertedBy(new PathConverter(PathProperties.DIRECTORY_EXISTING)) + .defaultsTo(Path.of(".")); + + private static final OptionSpec ASSETS_DIR_OPTION = PARSER + .accepts("assetsDir", "Assets directory") + .withRequiredArg() + .withValuesConvertedBy(new PathConverter(PathProperties.DIRECTORY_EXISTING)); + + private static final OptionSpec LAUNCH_TARGET_OPTION = PARSER + .accepts("launchTarget", "LauncherService target to launch") + .withRequiredArg(); + + private static final OptionSpec UUID_OPTION = PARSER + .accepts("uuid", "The UUID of the logging in player") + .withRequiredArg(); + + static { + PARSER.allowsUnrecognizedOptions(); + } + + private final String[] args; + private final DiscoveryData discoveryData; private OptionSet optionSet; - private OptionSpec profileOption; - private OptionSpec gameDirOption; - private OptionSpec assetsDirOption; - private OptionSpec minecraftJarOption; - private OptionSpec nonOption; - private OptionSpec launchTarget; - private OptionSpec uuidOption; record DiscoveryData(Path gameDir, String launchTarget, String[] arguments) {} - DiscoveryData setArgs(String[] args) { + 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); + this.optionSet = PARSER.parse(args); + this.discoveryData = new DiscoveryData(optionSet.valueOf(GAME_DIR_OPTION), optionSet.valueOf(LAUNCH_TARGET_OPTION), args); } - void processArguments(Environment env, Consumer parserConsumer, BiConsumer> resultConsumer) { - final OptionParser parser = new OptionParser(); - parser.allowsUnrecognizedOptions(); - profileOption = parser.accepts("version", "The version we launched with").withRequiredArg(); - gameDirOption = parser.accepts("gameDir", "Alternative game directory").withRequiredArg().withValuesConvertedBy(new PathConverter(PathProperties.DIRECTORY_EXISTING)).defaultsTo(Path.of(".")); - assetsDirOption = parser.accepts("assetsDir", "Assets directory").withRequiredArg().withValuesConvertedBy(new PathConverter(PathProperties.DIRECTORY_EXISTING)); - minecraftJarOption = parser.accepts("minecraftJar", "Path to minecraft jar").withRequiredArg().withValuesConvertedBy(new PathConverter(PathProperties.READABLE)).withValuesSeparatedBy(','); - uuidOption = parser.accepts("uuid", "The UUID of the logging in player").withRequiredArg(); - launchTarget = parser.accepts("launchTarget", "LauncherService target to launch").withRequiredArg(); - - parserConsumer.accept(parser); - nonOption = parser.nonOptions(); - this.optionSet = parser.parse(this.args); - env.computePropertyIfAbsent(IEnvironment.Keys.VERSION.get(), s -> this.optionSet.valueOf(profileOption)); - env.computePropertyIfAbsent(IEnvironment.Keys.GAMEDIR.get(), f -> this.optionSet.valueOf(gameDirOption)); - env.computePropertyIfAbsent(IEnvironment.Keys.ASSETSDIR.get(), f -> this.optionSet.valueOf(assetsDirOption)); - env.computePropertyIfAbsent(IEnvironment.Keys.LAUNCHTARGET.get(), f -> this.optionSet.valueOf(launchTarget)); - env.computePropertyIfAbsent(IEnvironment.Keys.UUID.get(), f -> this.optionSet.valueOf(uuidOption)); - resultConsumer.accept(this.optionSet, ArgumentHandler::optionResults); + DiscoveryData getDiscoveryData() { + return this.discoveryData; } - Path[] getSpecialJars() { - return this.optionSet.valuesOf(minecraftJarOption).toArray(new Path[0]); + void processArguments(Environment env, Consumer parserConsumer, BiConsumer> resultConsumer) { + parserConsumer.accept(PARSER); + this.optionSet = PARSER.parse(this.args); + env.computePropertyIfAbsent(IEnvironment.Keys.VERSION.get(), s -> this.optionSet.valueOf(PROFILE_OPTION)); + env.computePropertyIfAbsent(IEnvironment.Keys.GAMEDIR.get(), f -> this.discoveryData.gameDir); + env.computePropertyIfAbsent(IEnvironment.Keys.ASSETSDIR.get(), f -> this.optionSet.valueOf(ASSETS_DIR_OPTION)); + env.computePropertyIfAbsent(IEnvironment.Keys.LAUNCHTARGET.get(), f -> this.discoveryData.launchTarget); + env.computePropertyIfAbsent(IEnvironment.Keys.UUID.get(), f -> this.optionSet.valueOf(UUID_OPTION)); + resultConsumer.accept(this.optionSet, ArgumentHandler::optionResults); } String getLaunchTarget() { - return this.optionSet.valueOf(launchTarget); + return this.discoveryData.launchTarget; } private static ITransformationService.OptionResult optionResults(String serviceName, OptionSet set) { - return new ITransformationService.OptionResult() { - @Override - public V value(OptionSpec option) { - checkOwnership(option); - return set.valueOf(option); - } - - @Override - public @NotNull List values(OptionSpec option) { - checkOwnership(option); - return set.valuesOf(option); - } - - private void checkOwnership(OptionSpec option) { - if (!(option.options().stream().allMatch(opt -> opt.startsWith(serviceName + ".") || !opt.contains(".")))) { - throw new IllegalArgumentException("Cannot process non-arguments"); - } - } - }; + return new GuardedOptionResult(serviceName, set); } public String[] buildArgumentList() { - ArrayList args = new ArrayList<>(); - addOptionToString(profileOption, optionSet, args); - addOptionToString(gameDirOption, optionSet, args); - addOptionToString(assetsDirOption, optionSet, args); - addOptionToString(uuidOption, optionSet, args); + var args = new ArrayList(); + addOptionToString(PROFILE_OPTION, optionSet, args); + addOptionToString(GAME_DIR_OPTION, optionSet, args); + addOptionToString(ASSETS_DIR_OPTION, optionSet, args); + addOptionToString(UUID_OPTION, optionSet, args); List nonOptionList = this.optionSet.nonOptionArguments(); args.addAll(nonOptionList.stream().map(Object::toString).toList()); return args.toArray(new String[0]); @@ -101,7 +92,7 @@ public String[] buildArgumentList() { private static void addOptionToString(OptionSpec option, OptionSet optionSet, List appendTo) { if (optionSet.has(option)) { - appendTo.add("--"+option.options().get(0)); + appendTo.add("--" + option.options().getFirst()); appendTo.add(option.value(optionSet).toString()); } } diff --git a/src/main/java/cpw/mods/modlauncher/ClassTransformer.java b/src/main/java/cpw/mods/modlauncher/ClassTransformer.java index 977e02d..bb21232 100644 --- a/src/main/java/cpw/mods/modlauncher/ClassTransformer.java +++ b/src/main/java/cpw/mods/modlauncher/ClassTransformer.java @@ -164,7 +164,7 @@ private T performVote(List> transformers, T node, VotingCont // If there's at least one YES voter, let's apply the first one we find, remove them, and continue. var yesVotes = results.get(TransformerVoteResult.YES); if (yesVotes != null) { - final ITransformer transformer = yesVotes.get(0).transformer(); + final ITransformer transformer = yesVotes.getFirst().transformer(); node = transformer.transform(node, context); auditTrail.addTransformerAuditTrail(context.getClassName(), ((TransformerHolder) transformer).owner(), transformer); transformers.remove(transformer); diff --git a/src/main/java/cpw/mods/modlauncher/DefaultLaunchHandlerService.java b/src/main/java/cpw/mods/modlauncher/DefaultLaunchHandlerService.java deleted file mode 100644 index 34bfd19..0000000 --- a/src/main/java/cpw/mods/modlauncher/DefaultLaunchHandlerService.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) Forge Development LLC - * SPDX-License-Identifier: LGPL-3.0-only - */ - -package cpw.mods.modlauncher; - -import cpw.mods.modlauncher.api.*; - -import java.lang.reflect.*; -import java.nio.file.*; - -/** - * This has not worked in years - */ -@Deprecated(forRemoval = true, since = "10.1") -public class DefaultLaunchHandlerService implements ILaunchHandlerService { - public static final String LAUNCH_PROPERTY = "minecraft.client.jar"; - public static final String LAUNCH_PATH_STRING = System.getProperty(LAUNCH_PROPERTY); - - @Override - public String name() { - return "minecraft"; - } - - @Override - public void configureTransformationClassLoader(final ITransformingClassLoaderBuilder builder) { - if (LAUNCH_PATH_STRING == null) { - throw new IllegalStateException("Missing "+ LAUNCH_PROPERTY +" environment property. Update your launcher!"); - } - builder.addTransformationPath(FileSystems.getDefault().getPath(LAUNCH_PATH_STRING)); - } - - @Override - public ServiceRunner launchService(String[] arguments, ModuleLayer gameLayer) { - - return () -> { - final Class mcClass = Class.forName(gameLayer.findModule("minecraft").orElseThrow(), "net.minecraft.client.main.Main"); - final Method mcClassMethod = mcClass.getMethod("main", String[].class); - mcClassMethod.invoke(null, (Object) arguments); - }; - } - - @Override - public NamedPath[] getPaths() { - return new NamedPath[] {new NamedPath("launch",FileSystems.getDefault().getPath(LAUNCH_PATH_STRING))}; - } -} diff --git a/src/main/java/cpw/mods/modlauncher/EnumerationHelper.java b/src/main/java/cpw/mods/modlauncher/EnumerationHelper.java deleted file mode 100644 index d88b05d..0000000 --- a/src/main/java/cpw/mods/modlauncher/EnumerationHelper.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) Forge Development LLC - * SPDX-License-Identifier: LGPL-3.0-only - */ - -package cpw.mods.modlauncher; - -import java.util.Collections; -import java.util.Enumeration; -import java.util.Optional; -import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public class EnumerationHelper { - public static Enumeration merge(Enumeration first, Enumeration second) { - return new Enumeration() { - @Override - public boolean hasMoreElements() { - return first.hasMoreElements() || second.hasMoreElements(); - } - - @Override - public T nextElement() { - return first.hasMoreElements() ? first.nextElement() : second.nextElement(); - } - }; - } - - public static Function> mergeFunctors(Function> first, Function> second) { - return input -> merge(first.apply(input), second.apply(input)); - } - - public static T firstElementOrNull(final Enumeration enumeration) { - return enumeration.hasMoreElements() ? enumeration.nextElement() : null; - } - - public static Function> fromOptional(final Function> additionalClassBytesLocator) { - return input -> Collections.enumeration(additionalClassBytesLocator.apply(input).stream().toList()); - } -} diff --git a/src/main/java/cpw/mods/modlauncher/LaunchPluginHandler.java b/src/main/java/cpw/mods/modlauncher/LaunchPluginHandler.java index 4a0a5e6..ec378c8 100644 --- a/src/main/java/cpw/mods/modlauncher/LaunchPluginHandler.java +++ b/src/main/java/cpw/mods/modlauncher/LaunchPluginHandler.java @@ -8,7 +8,6 @@ import cpw.mods.jarhandling.SecureJar; import cpw.mods.modlauncher.api.IEnvironment; import cpw.mods.modlauncher.api.IModuleLayerManager.Layer; -import cpw.mods.modlauncher.api.NamedPath; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.Nullable; @@ -40,22 +39,19 @@ public LaunchPluginHandler(ModuleLayerHandler layerHandler) { .getProperty(IEnvironment.Keys.MODLIST.get()) .orElseThrow(() -> new IllegalStateException("Invalid environment, Missing MODLIST")); - for (var itr = ServiceLoader.load(boot, ILaunchPluginService.class).iterator(); itr.hasNext(); ) { - try { - var srvc = itr.next(); - @SuppressWarnings("removal") - var file = cpw.mods.modlauncher.util.ServiceLoaderUtils.fileNameFor(srvc.getClass()); - plugins.put(srvc.name(), srvc); + try { + for (var service : ServiceLoader.load(boot, ILaunchPluginService.class)) { + plugins.put(service.name(), service); if (modlist != null) { modlist.add(Map.of( - "name", srvc.name(), + "name", service.name(), "type", "PLUGINSERVICE", - "file", file + "file", cpw.mods.modlauncher.util.ServiceLoaderUtils.fileNameFor(service.getClass()) )); } - } catch (ServiceConfigurationError e) { - LOGGER.fatal(MODLAUNCHER, "Encountered serious error loading launch plugin service. Things will not work well", e); } + } catch (ServiceConfigurationError e) { + throw new RuntimeException("Encountered serious error loading launch plugin service", e); } LOGGER.debug(MODLAUNCHER, "Found launch plugins: [{}]", () -> String.join(",", plugins.keySet())); @@ -90,7 +86,7 @@ int offerClassNodeToPlugins(Phase phase, List plugins, @Nu int flags = 0; for (var plugin : plugins) { LOGGER.debug(LAUNCHPLUGIN, "LauncherPluginService {} offering transform {}", plugin.name(), className.getClassName()); - var pluginFlags = plugin.processClassWithFlags(phase, node, className, reason); + int pluginFlags = plugin.processClassWithFlags(phase, node, className, reason); if (pluginFlags != ILaunchPluginService.ComputeFlags.NO_REWRITE) { auditTrail.addPluginAuditTrail(className.getClassName(), plugin, phase); LOGGER.debug(LAUNCHPLUGIN, "LauncherPluginService {} transformed {} with class compute flags {}", plugin.name(), className.getClassName(), pluginFlags); @@ -101,10 +97,9 @@ int offerClassNodeToPlugins(Phase phase, List plugins, @Nu return flags; } - @SuppressWarnings("removal") - void announceLaunch(final TransformingClassLoader transformerLoader, final NamedPath[] specialPaths) { + void announceLaunch(final TransformingClassLoader transformerLoader) { plugins.forEach((name, plugin) -> { - plugin.initializeLaunch(clazzName -> transformerLoader.buildTransformedClassNodeFor(clazzName, name), specialPaths); + plugin.initializeLaunch(clazzName -> transformerLoader.buildTransformedClassNodeFor(clazzName, name)); }); } } diff --git a/src/main/java/cpw/mods/modlauncher/LaunchServiceHandler.java b/src/main/java/cpw/mods/modlauncher/LaunchServiceHandler.java index 3429d2a..8a6bfc1 100644 --- a/src/main/java/cpw/mods/modlauncher/LaunchServiceHandler.java +++ b/src/main/java/cpw/mods/modlauncher/LaunchServiceHandler.java @@ -35,13 +35,12 @@ final class LaunchServiceHandler { public LaunchServiceHandler(ModuleLayerHandler layerHandler) { var services = ServiceLoader.load(layerHandler.getLayer(Layer.BOOT).orElseThrow(), ILaunchHandlerService.class); - for (var loader = services.iterator(); loader.hasNext(); ) { - try { - var srvc = loader.next(); - handlers.put(srvc.name(), srvc); - } catch (ServiceConfigurationError sce) { - LOGGER.fatal("Encountered serious error loading transformation service, expect problems", sce); + try { + for (var service : services) { + handlers.put(service.name(), service); } + } catch (ServiceConfigurationError e) { + throw new RuntimeException("Encountered serious error loading transformation service", e); } LOGGER.debug(MODLAUNCHER, "Found launch services [{}]", () -> String.join(",", handlers.keySet())); } @@ -52,29 +51,11 @@ public Optional findLaunchHandler(final String name) { private void launch(String target, String[] arguments, ModuleLayer gameLayer, TransformingClassLoader classLoader, LaunchPluginHandler launchPluginHandler) { var service = handlers.get(target); - var paths = service.getPaths(); - launchPluginHandler.announceLaunch(classLoader, paths); + launchPluginHandler.announceLaunch(classLoader); LOGGER.info(MODLAUNCHER, "Launching target '{}' with arguments {}", target, hideAccessToken(arguments)); - ServiceRunner runner = null; - try { - runner = service.launchService(arguments, gameLayer); - } catch (AbstractMethodError e) { - var lookup = MethodHandles.lookup(); - var type = MethodType.methodType(Callable.class, String[].class, ModuleLayer.class); - try { - var virtual = lookup.findVirtual(service.getClass(), "launchService", type); - Callable callable = (Callable)virtual.invokeExact(arguments, gameLayer); - runner = callable::call; - } catch (Throwable t) { - sneak(t); - } - } - - try { - - runner.run(); + service.launchService(arguments, gameLayer); } catch (Throwable e) { sneak(e); } @@ -97,13 +78,6 @@ public void launch(ArgumentHandler argumentHandler, ModuleLayer gameLayer, Trans launch(launchTarget, args, gameLayer, classLoader, launchPluginHandler); } - TransformingClassLoaderBuilder identifyTransformationTargets(final ArgumentHandler argumentHandler) { - var builder = new TransformingClassLoaderBuilder(); - for (var path : argumentHandler.getSpecialJars()) - builder.addTransformationPath(path); - return builder; - } - void validateLaunchTarget(final ArgumentHandler argumentHandler) { var target = argumentHandler.getLaunchTarget(); if (!handlers.containsKey(target)) { diff --git a/src/main/java/cpw/mods/modlauncher/Launcher.java b/src/main/java/cpw/mods/modlauncher/Launcher.java index 036260b..9b3cf85 100644 --- a/src/main/java/cpw/mods/modlauncher/Launcher.java +++ b/src/main/java/cpw/mods/modlauncher/Launcher.java @@ -19,7 +19,7 @@ import org.apache.logging.log4j.Logger; import java.util.ArrayList; -import java.util.HashMap; +import java.util.EnumMap; import java.util.List; import java.util.Optional; import java.util.function.BiFunction; @@ -32,31 +32,25 @@ public class Launcher { public static Launcher INSTANCE; private static final Logger LOGGER = LogManager.getLogger(); - private final TypesafeMap blackboard; + private static final TypesafeMap BLACKBOARD = new TypesafeMap(); private final TransformationServicesHandler transformationServicesHandler; private final Environment environment; - private final TransformStore transformStore; private final NameMappingServiceHandler nameMappingServiceHandler; - private final ArgumentHandler argumentHandler; private final LaunchServiceHandler launchService; private final LaunchPluginHandler launchPlugins; private final ModuleLayerHandler moduleLayerHandler; - private TransformingClassLoader classLoader; private Launcher() { INSTANCE = this; LOGGER.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.putPropertyIfAbsent(IEnvironment.Keys.MLSPEC_VERSION.get(), IEnvironment.class.getPackage().getSpecificationVersion()); environment.putPropertyIfAbsent(IEnvironment.Keys.MLIMPL_VERSION.get(), IEnvironment.class.getPackage().getImplementationVersion()); environment.computePropertyIfAbsent(IEnvironment.Keys.MODLIST.get(), k -> new ArrayList<>()); environment.putPropertyIfAbsent(IEnvironment.Keys.SECURED_JARS_ENABLED.get(), ProtectionDomainHelper.canHandleSecuredJars()); - this.transformStore = new TransformStore(); - this.transformationServicesHandler = new TransformationServicesHandler(this.transformStore, this.moduleLayerHandler); - this.argumentHandler = new ArgumentHandler(); + this.transformationServicesHandler = new TransformationServicesHandler(new TransformStore(), this.moduleLayerHandler); this.nameMappingServiceHandler = new NameMappingServiceHandler(this.moduleLayerHandler); this.launchPlugins = new LaunchPluginHandler(this.moduleLayerHandler); } @@ -76,14 +70,14 @@ public static void main(String... args) { } public final TypesafeMap blackboard() { - return blackboard; + return BLACKBOARD; } private void run(String... args) { - var discoveryData = argumentHandler.setArgs(args); - transformationServicesHandler.discoverServices(discoveryData); + var argumentHandler = new ArgumentHandler(args); + transformationServicesHandler.discoverServices(argumentHandler.getDiscoveryData()); - var scanResults = new HashMap>(); + var scanResults = new EnumMap>(Layer.class); for (var resource : transformationServicesHandler.initializeTransformationServices(argumentHandler, environment, nameMappingServiceHandler)) scanResults.computeIfAbsent(resource.target(), k -> new ArrayList<>()).add(resource); @@ -107,13 +101,12 @@ private void run(String... args) { this.transformationServicesHandler.initialiseServiceTransformers(); this.launchPlugins.offerScanResultsToPlugins(gameContents); - this.launchService.validateLaunchTarget(this.argumentHandler); - var classLoaderBuilder = this.launchService.identifyTransformationTargets(this.argumentHandler); - this.classLoader = this.transformationServicesHandler.buildTransformingClassLoader(this.launchPlugins, classLoaderBuilder, this.environment, this.moduleLayerHandler); + this.launchService.validateLaunchTarget(argumentHandler); + TransformingClassLoader classLoader = this.transformationServicesHandler.buildTransformingClassLoader(this.launchPlugins, this.environment, this.moduleLayerHandler); var oldCL = Thread.currentThread().getContextClassLoader(); try { - Thread.currentThread().setContextClassLoader(this.classLoader); - this.launchService.launch(this.argumentHandler, this.moduleLayerHandler.getLayer(Layer.GAME).orElseThrow(), this.classLoader, this.launchPlugins); + Thread.currentThread().setContextClassLoader(classLoader); + this.launchService.launch(argumentHandler, this.moduleLayerHandler.getLayer(Layer.GAME).orElseThrow(), classLoader, this.launchPlugins); } finally { Thread.currentThread().setContextClassLoader(oldCL); } diff --git a/src/main/java/cpw/mods/modlauncher/ModuleLayerHandler.java b/src/main/java/cpw/mods/modlauncher/ModuleLayerHandler.java index a1ef466..945b8c4 100644 --- a/src/main/java/cpw/mods/modlauncher/ModuleLayerHandler.java +++ b/src/main/java/cpw/mods/modlauncher/ModuleLayerHandler.java @@ -46,10 +46,8 @@ void addToLayer(Layer layer, SecureJar jar) { layers.computeIfAbsent(layer, l -> new ArrayList<>()).add(jar); } - /** TODO: Make package private */ - @SuppressWarnings("exports") - @Deprecated(since = "10.1") - public LayerInfo buildLayer(Layer layer, BiFunction, ClassLoader> classLoaderSupplier) { + // TODO: Consider removing because it's unused + LayerInfo buildLayer(Layer layer, BiFunction, ClassLoader> classLoaderSupplier) { return build(layer, (cfg, layers, loaders) -> classLoaderSupplier.apply(cfg, layers)); } @@ -85,17 +83,13 @@ LayerInfo build(Layer layer, ClassLoaderFactory classLoaderSupplier) { return info; } - /** TODO: Make package private */ - @SuppressWarnings("exports") - @Deprecated(since = "10.1") - public LayerInfo buildLayer(Layer layer) { + // TODO: Consider removing because it's unused + LayerInfo buildLayer(Layer layer) { return build(layer); } - /** TODO: Make package private */ - @SuppressWarnings("exports") - @Deprecated(since = "10.1") - public void updateLayer(Layer layer, Consumer action) { + // TODO: Consider removing because it's unused + void updateLayer(Layer layer, Consumer action) { action.accept(completedLayers.get(layer)); } diff --git a/src/main/java/cpw/mods/modlauncher/NameMappingServiceHandler.java b/src/main/java/cpw/mods/modlauncher/NameMappingServiceHandler.java index 3b33920..7785c6d 100644 --- a/src/main/java/cpw/mods/modlauncher/NameMappingServiceHandler.java +++ b/src/main/java/cpw/mods/modlauncher/NameMappingServiceHandler.java @@ -10,6 +10,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Objects; @@ -23,18 +24,19 @@ */ final class NameMappingServiceHandler { private static final Logger LOGGER = LogManager.getLogger(); - private final Map allKnown = new HashMap<>(); + private final Map allKnown; private final Map active = new HashMap<>(); public NameMappingServiceHandler(ModuleLayerHandler layerHandler) { var services = ServiceLoader.load(layerHandler.getLayer(Layer.BOOT).orElseThrow(), INameMappingService.class); - for (var itr = services.iterator(); itr.hasNext(); ) { - try { - var srvc = itr.next(); - allKnown.put(srvc.mappingName(), srvc); - } catch (ServiceConfigurationError sce) { - LOGGER.fatal("Encountered serious error loading naming service, expect problems", sce); + try { + var found = new HashMap(); + for (var service : services) { + found.put(service.mappingName(), service); } + this.allKnown = found.isEmpty() ? Collections.emptyMap() : found; + } catch (ServiceConfigurationError e) { + throw new RuntimeException("Encountered serious error loading naming service", e); } LOGGER.debug(LogMarkers.MODLAUNCHER, "Found naming services : [{}]", () -> String.join(", ", allKnown.keySet())); } diff --git a/src/main/java/cpw/mods/modlauncher/TestingLaunchHandlerService.java b/src/main/java/cpw/mods/modlauncher/TestingLaunchHandlerService.java index b5f5e1d..bde4ad9 100644 --- a/src/main/java/cpw/mods/modlauncher/TestingLaunchHandlerService.java +++ b/src/main/java/cpw/mods/modlauncher/TestingLaunchHandlerService.java @@ -20,12 +20,12 @@ public String name() { return "testharness"; } - public ServiceRunner launchService(String[] arguments, ModuleLayer gameLayer) { + public void launchService(String[] arguments, ModuleLayer gameLayer) { try { Class callableLaunch = Class.forName(System.getProperty("test.harness.callable"), true, Thread.currentThread().getContextClassLoader()); getClass().getModule().addReads(callableLaunch.getModule()); MethodHandle handle = MethodHandles.lookup().findStatic(callableLaunch, "supplier", MethodType.methodType(ServiceRunner.class)); - return (ServiceRunner) handle.invoke(); + handle.invokeExact(); } catch (ClassNotFoundException | NoSuchMethodException | LambdaConversionException | IllegalAccessException | InstantiationException e) { throw new RuntimeException(e); } catch (Throwable throwable) { diff --git a/src/main/java/cpw/mods/modlauncher/TransformTargetLabel.java b/src/main/java/cpw/mods/modlauncher/TransformTargetLabel.java index 051bb55..1d6c57f 100644 --- a/src/main/java/cpw/mods/modlauncher/TransformTargetLabel.java +++ b/src/main/java/cpw/mods/modlauncher/TransformTargetLabel.java @@ -123,18 +123,5 @@ private TransformList get(EnumMap> transforme public Supplier> mapSupplier(EnumMap> transformers) { return () -> (TransformList) transformers.get(this); } - - /** - * Only here for backwards compatibility with < 10.0, Nobody should ever use this. - */ - @Deprecated(forRemoval = true, since = "10.0") - public static List getTypeFor(java.lang.reflect.Type type) { - switch (type.getTypeName()) { - case "org.objectweb.asm.tree.FieldNode": return List.of(FIELD); - case "org.objectweb.asm.tree.MethodNode": return List.of(METHOD); - case "org.objectweb.asm.tree.ClassNode": return List.of(CLASS, PRE_CLASS); - } - return Collections.emptyList(); - } } } diff --git a/src/main/java/cpw/mods/modlauncher/TransformationServicesHandler.java b/src/main/java/cpw/mods/modlauncher/TransformationServicesHandler.java index 59a986a..411fb79 100644 --- a/src/main/java/cpw/mods/modlauncher/TransformationServicesHandler.java +++ b/src/main/java/cpw/mods/modlauncher/TransformationServicesHandler.java @@ -49,7 +49,7 @@ List initializeTransformationServices(ArgumentH return runScanningTransformationServices(environment); } - TransformingClassLoader buildTransformingClassLoader(LaunchPluginHandler pluginHandler, TransformingClassLoaderBuilder builder, Environment environment, ModuleLayerHandler layerHandler) { + TransformingClassLoader buildTransformingClassLoader(LaunchPluginHandler pluginHandler, Environment environment, ModuleLayerHandler layerHandler) { return (TransformingClassLoader)layerHandler.build(Layer.GAME, (cfg, layers, loaders) -> new TransformingClassLoader( "TRANSFORMER", null, cfg, layers, loaders, @@ -127,22 +127,21 @@ void discoverServices(final ArgumentHandler.DiscoveryData discoveryData) { var bootLayer = layerHandler.getLayer(Layer.BOOT).orElseThrow(); var discovery = new ArrayList(); - for (var itr = ServiceLoader.load(bootLayer, ITransformerDiscoveryService.class).iterator(); itr.hasNext(); ) { - try { - var srvc = itr.next(); - discovery.add(srvc); - var paths = srvc.candidates(discoveryData.gameDir(), discoveryData.launchTarget()); + try { + for (var service : ServiceLoader.load(bootLayer, ITransformerDiscoveryService.class)) { + discovery.add(service); + var paths = service.candidates(discoveryData.gameDir(), discoveryData.launchTarget()); if (!paths.isEmpty()) { - LOGGER.debug(MODLAUNCHER, "Found additional transformation services from discovery service: {}", srvc.getClass().getName()); + LOGGER.debug(MODLAUNCHER, "Found additional transformation services from discovery service: {}", service.getClass().getName()); for (var path : paths) { LOGGER.debug(MODLAUNCHER, "\t{}", path.toString()); layerHandler.addToLayer(Layer.SERVICE, SecureJar.from(path.paths())); } } - } catch (ServiceConfigurationError sce) { - LOGGER.fatal("Encountered serious error loading transformation discoverer service, expect problems", sce); } + } catch (ServiceConfigurationError e) { + throw new RuntimeException("Encountered serious error loading transformation discoverer service", e); } var serviceLayer = layerHandler.build(Layer.SERVICE).layer(); @@ -151,24 +150,24 @@ void discoverServices(final ArgumentHandler.DiscoveryData discoveryData) { var transformers = new HashMap(); var modlist = Launcher.INSTANCE.environment().getProperty(IEnvironment.Keys.MODLIST.get()); - for (var itr = ServiceLoader.load(serviceLayer, ITransformationService.class).iterator(); itr.hasNext(); ) { - try { - var srvc = itr.next(); - transformers.put(srvc.name(), new TransformationServiceDecorator(srvc)); + try { + for (var service : ServiceLoader.load(serviceLayer, ITransformationService.class)) { + transformers.put(service.name(), new TransformationServiceDecorator(service)); @SuppressWarnings("removal") - var file = cpw.mods.modlauncher.util.ServiceLoaderUtils.fileNameFor(srvc.getClass()); - LOGGER.debug(MODLAUNCHER, "Found transformer service: {}: {}", srvc.name(), file); + var file = cpw.mods.modlauncher.util.ServiceLoaderUtils.fileNameFor(service.getClass()); + LOGGER.debug(MODLAUNCHER, "Found transformer service: {}: {}", service.name(), file); if (modlist.isPresent()) { modlist.get().add(Map.of( - "name", srvc.name(), + "name", service.name(), "type", "TRANSFORMATIONSERVICE", "file", file )); } - } catch (ServiceConfigurationError sce) { - LOGGER.fatal(MODLAUNCHER, "Encountered serious error loading transformation service, expect problems", sce); } + } catch (ServiceConfigurationError e) { + throw new RuntimeException("Encountered serious error loading transformation service", e); } + serviceLookup = transformers; } diff --git a/src/main/java/cpw/mods/modlauncher/TransformerAuditTrail.java b/src/main/java/cpw/mods/modlauncher/TransformerAuditTrail.java index 835fe47..5c750a0 100644 --- a/src/main/java/cpw/mods/modlauncher/TransformerAuditTrail.java +++ b/src/main/java/cpw/mods/modlauncher/TransformerAuditTrail.java @@ -24,7 +24,7 @@ public List getActivityFor(final String className) { } private record TransformerActivity(String[] context, Type type) implements ITransformerActivity { - public TransformerActivity(Type type, String... context) { + private TransformerActivity(Type type, String... context) { this(context, type); } @@ -38,6 +38,7 @@ public Type getType() { return type; } + @Override public String getActivityString() { return this.type.getLabel() + ":" + String.join(":", this.context); } diff --git a/src/main/java/cpw/mods/modlauncher/TransformerHolder.java b/src/main/java/cpw/mods/modlauncher/TransformerHolder.java index cdc0ce1..5c90c4e 100644 --- a/src/main/java/cpw/mods/modlauncher/TransformerHolder.java +++ b/src/main/java/cpw/mods/modlauncher/TransformerHolder.java @@ -13,39 +13,27 @@ import org.jetbrains.annotations.NotNull; import java.util.Set; -public class TransformerHolder implements ITransformer { - private final ITransformer wrapped; - private final ITransformationService owner; - - public TransformerHolder(final ITransformer wrapped, ITransformationService owner) { - this.wrapped = wrapped; - this.owner = owner; - } - +public record TransformerHolder(ITransformer delegate, ITransformationService owner) implements ITransformer { @NotNull @Override public T transform(final T input, final ITransformerVotingContext context) { - return wrapped.transform(input, context); + return delegate.transform(input, context); } @NotNull @Override public TransformerVoteResult castVote(final ITransformerVotingContext context) { - return wrapped.castVote(context); + return delegate.castVote(context); } @NotNull @Override public Set targets() { - return wrapped.targets(); + return delegate.targets(); } @Override public String[] labels() { - return wrapped.labels(); - } - - public ITransformationService owner() { - return owner; + return delegate.labels(); } } diff --git a/src/main/java/cpw/mods/modlauncher/TransformingClassLoader.java b/src/main/java/cpw/mods/modlauncher/TransformingClassLoader.java index 90be8d9..750386a 100644 --- a/src/main/java/cpw/mods/modlauncher/TransformingClassLoader.java +++ b/src/main/java/cpw/mods/modlauncher/TransformingClassLoader.java @@ -5,10 +5,10 @@ package cpw.mods.modlauncher; -import cpw.mods.cl.ModuleClassLoader; import cpw.mods.modlauncher.api.IEnvironment; import cpw.mods.modlauncher.api.ITransformerActivity; import cpw.mods.modlauncher.api.IModuleLayerManager.Layer; +import net.minecraftforge.securemodules.SecureModuleClassLoader; import java.lang.module.Configuration; import java.util.*; @@ -16,7 +16,7 @@ /** * Module transforming class loader */ -public class TransformingClassLoader extends ModuleClassLoader { +public class TransformingClassLoader extends SecureModuleClassLoader { static { ClassLoader.registerAsParallelCapable(); } @@ -31,7 +31,7 @@ private static ModuleLayer get(ModuleLayerHandler layers, Layer layer) { } public TransformingClassLoader(TransformStore transformStore, LaunchPluginHandler pluginHandler, ModuleLayerHandler layers) { - super("TRANSFORMER", get(layers, Layer.GAME).configuration(), List.of(get(layers, Layer.SERVICE))); + super("TRANSFORMER", null, get(layers, Layer.GAME).configuration(), List.of(get(layers, Layer.SERVICE)), List.of(), true); this.classTransformer = new ClassTransformer(transformStore, pluginHandler, this); } diff --git a/src/main/java/cpw/mods/modlauncher/TransformingClassLoaderBuilder.java b/src/main/java/cpw/mods/modlauncher/TransformingClassLoaderBuilder.java deleted file mode 100644 index 44cddf2..0000000 --- a/src/main/java/cpw/mods/modlauncher/TransformingClassLoaderBuilder.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) Forge Development LLC - * SPDX-License-Identifier: LGPL-3.0-only - */ - -package cpw.mods.modlauncher; - -import cpw.mods.modlauncher.api.ITransformingClassLoaderBuilder; - -import java.net.URL; -import java.nio.file.Path; -import java.util.*; -import java.util.function.Function; - -import static cpw.mods.modlauncher.api.LamdbaExceptionUtils.rethrowFunction; - -final class TransformingClassLoaderBuilder implements ITransformingClassLoaderBuilder { - private final List transformationPaths = new ArrayList<>(); - private Function> resourcesLocator; - - URL[] getSpecialJarsAsURLs() { - return transformationPaths.stream().map(rethrowFunction(path->path.toUri().toURL())).toArray(URL[]::new); - } - - @Override - public void addTransformationPath(final Path path) { - transformationPaths.add(path); - } - - @Override - public void setClassBytesLocator(final Function> additionalClassBytesLocator) { - this.resourcesLocator = EnumerationHelper.fromOptional(additionalClassBytesLocator); - } - - @Override - public void setResourceEnumeratorLocator(final Function> resourceEnumeratorLocator) { - this.resourcesLocator = resourceEnumeratorLocator; - } - - Function> getResourceEnumeratorLocator() { - return this.resourcesLocator != null ? this.resourcesLocator : input -> Collections.emptyEnumeration(); - } -} diff --git a/src/main/java/cpw/mods/modlauncher/VotingContext.java b/src/main/java/cpw/mods/modlauncher/VotingContext.java index 5124892..2a954dc 100644 --- a/src/main/java/cpw/mods/modlauncher/VotingContext.java +++ b/src/main/java/cpw/mods/modlauncher/VotingContext.java @@ -78,13 +78,13 @@ public boolean applyInstructionPredicate(InsnPredicate insnPredicate) { } private static Object[] toObjectArray(final AbstractInsnNode insnNode) { - if (insnNode instanceof MethodInsnNode methodInsnNode) { - return new Object[] {methodInsnNode.name, methodInsnNode.desc, methodInsnNode.owner, methodInsnNode.itf}; - } - if (insnNode instanceof FieldInsnNode fieldInsnNode) { - return new Object[] {fieldInsnNode.name, fieldInsnNode.desc, fieldInsnNode.owner}; - } - return EMPTY; + return switch (insnNode) { + case MethodInsnNode methodInsnNode -> + new Object[] { methodInsnNode.name, methodInsnNode.desc, methodInsnNode.owner, methodInsnNode.itf }; + case FieldInsnNode fieldInsnNode -> + new Object[] { fieldInsnNode.name, fieldInsnNode.desc, fieldInsnNode.owner }; + default -> EMPTY; + }; } private static final class NodeHolder { diff --git a/src/main/java/cpw/mods/modlauncher/api/ILaunchHandlerService.java b/src/main/java/cpw/mods/modlauncher/api/ILaunchHandlerService.java index 489748e..05e549e 100644 --- a/src/main/java/cpw/mods/modlauncher/api/ILaunchHandlerService.java +++ b/src/main/java/cpw/mods/modlauncher/api/ILaunchHandlerService.java @@ -11,10 +11,5 @@ public interface ILaunchHandlerService { String name(); - @Deprecated(forRemoval = true, since = "10.0") - default void configureTransformationClassLoader(final ITransformingClassLoaderBuilder builder) {} - - ServiceRunner launchService(String[] arguments, ModuleLayer gameLayer); - - default NamedPath[] getPaths() { return new NamedPath[0]; } + void launchService(String[] arguments, ModuleLayer gameLayer); } diff --git a/src/main/java/cpw/mods/modlauncher/api/IModuleLayerManager.java b/src/main/java/cpw/mods/modlauncher/api/IModuleLayerManager.java index 007361d..fe00994 100644 --- a/src/main/java/cpw/mods/modlauncher/api/IModuleLayerManager.java +++ b/src/main/java/cpw/mods/modlauncher/api/IModuleLayerManager.java @@ -23,14 +23,8 @@ enum Layer { this.parents = List.of(parent); } - Layer(Layer... parent) { - this.parents = List.of(parent); - } - - /** Returning a raw array is unsafe, it used to return the backing array directly which would allow others to screw with it. */ - @Deprecated(forRemoval = true, since = "10.1") - public Layer[] getParent() { - return this.parents.toArray(Layer[]::new); + Layer(Layer... parents) { + this.parents = List.of(parents); } /** Returns a potentially empty, immutable list of parent layers. */ diff --git a/src/main/java/cpw/mods/modlauncher/api/ITransformationService.java b/src/main/java/cpw/mods/modlauncher/api/ITransformationService.java index d4e53ce..b771e03 100644 --- a/src/main/java/cpw/mods/modlauncher/api/ITransformationService.java +++ b/src/main/java/cpw/mods/modlauncher/api/ITransformationService.java @@ -6,6 +6,8 @@ package cpw.mods.modlauncher.api; import cpw.mods.jarhandling.SecureJar; +import cpw.mods.modlauncher.ArgumentHandler; +import cpw.mods.modlauncher.internal.GuardedOptionResult; import joptsimple.*; import org.jetbrains.annotations.NotNull; @@ -40,11 +42,13 @@ public interface ITransformationService { * * @param argumentBuilder a function mapping name, description to a set of JOptSimple properties for that argument */ - default void arguments(BiFunction argumentBuilder) { - } + default void arguments(BiFunction argumentBuilder) {} - default void argumentValues(OptionResult option) { - } + /** + * Access the values of your arguments defined in {@link #arguments(BiFunction)} + * @param option The result view of the parsed arguments + */ + default void argumentValues(OptionResult option) {} /** * Initialize your service. @@ -90,21 +94,20 @@ default List completeScan(IModuleLayerManager layerManager) { @NotNull List transformers(); - /** Hasn't been called in ages, will be removed in next breaking bump */ - @Deprecated(forRemoval = true, since = "10.1") - default Map.Entry,Supplier>>> additionalClassesLocator() { - return null; - } - - /** Hasn't been called in ages, will be removed in next breaking bump */ - @Deprecated(forRemoval = true, since = "10.1") - default Map.Entry,Supplier>>> additionalResourcesLocator() { - return null; - } - - interface OptionResult { - V value(OptionSpec options); + /** + * A guarded partial view of {@link OptionSet} that only allows access to options intended for your service + * @see ITransformationService#arguments(BiFunction) + * @see ITransformationService#argumentValues(OptionResult) + */ + sealed interface OptionResult permits GuardedOptionResult { + /** + * @see OptionSet#valueOf(OptionSpec) + */ + V value(OptionSpec option); + /** + * @see OptionSet#valuesOf(OptionSpec) + */ @NotNull List values(OptionSpec options); } diff --git a/src/main/java/cpw/mods/modlauncher/api/ITransformingClassLoaderBuilder.java b/src/main/java/cpw/mods/modlauncher/api/ITransformingClassLoaderBuilder.java deleted file mode 100644 index 3873ae6..0000000 --- a/src/main/java/cpw/mods/modlauncher/api/ITransformingClassLoaderBuilder.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) Forge Development LLC - * SPDX-License-Identifier: LGPL-3.0-only - */ - -package cpw.mods.modlauncher.api; - -import java.net.URL; -import java.net.URLConnection; -import java.nio.file.Path; -import java.util.Enumeration; -import java.util.Optional; -import java.util.function.Function; -import java.util.jar.Manifest; - -public interface ITransformingClassLoaderBuilder { - void addTransformationPath(Path path); - - void setClassBytesLocator(Function> additionalClassBytesLocator); - - void setResourceEnumeratorLocator(Function> resourceEnumeratorLocator); -} diff --git a/src/main/java/cpw/mods/modlauncher/api/LamdbaExceptionUtils.java b/src/main/java/cpw/mods/modlauncher/api/LambdaExceptionUtils.java similarity index 98% rename from src/main/java/cpw/mods/modlauncher/api/LamdbaExceptionUtils.java rename to src/main/java/cpw/mods/modlauncher/api/LambdaExceptionUtils.java index 1057c80..1dd2239 100644 --- a/src/main/java/cpw/mods/modlauncher/api/LamdbaExceptionUtils.java +++ b/src/main/java/cpw/mods/modlauncher/api/LambdaExceptionUtils.java @@ -10,7 +10,7 @@ /** * From stackoverflow: https://stackoverflow.com/a/27644392 */ -public class LamdbaExceptionUtils { +public class LambdaExceptionUtils { /** * .forEach(rethrowConsumer(name -> System.out.println(Class.forName(name)))); or .forEach(rethrowConsumer(ClassNameUtil::println)); @@ -108,6 +108,7 @@ public interface Consumer_WithExceptions { void accept(T t) throws E; } + @FunctionalInterface public interface BiConsumer_WithExceptions { void accept(T t, U u) throws E; } diff --git a/src/main/java/cpw/mods/modlauncher/internal/GuardedOptionResult.java b/src/main/java/cpw/mods/modlauncher/internal/GuardedOptionResult.java new file mode 100644 index 0000000..640ec8b --- /dev/null +++ b/src/main/java/cpw/mods/modlauncher/internal/GuardedOptionResult.java @@ -0,0 +1,28 @@ +package cpw.mods.modlauncher.internal; + +import cpw.mods.modlauncher.api.ITransformationService; +import joptsimple.OptionSet; +import joptsimple.OptionSpec; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public record GuardedOptionResult(String serviceName, OptionSet delegate) implements ITransformationService.OptionResult { + @Override + public V value(OptionSpec option) { + checkOwnership(option); + return delegate.valueOf(option); + } + + @Override + public @NotNull List values(OptionSpec options) { + checkOwnership(options); + return delegate.valuesOf(options); + } + + private void checkOwnership(OptionSpec option) { + if (!(option.options().stream().allMatch(opt -> opt.startsWith(serviceName + ".") || !opt.contains(".")))) { + throw new IllegalArgumentException("Cannot process non-arguments"); + } + } +} diff --git a/src/main/java/cpw/mods/modlauncher/log/ExtraDataTextRenderer.java b/src/main/java/cpw/mods/modlauncher/log/ExtraDataTextRenderer.java deleted file mode 100644 index 109c2c3..0000000 --- a/src/main/java/cpw/mods/modlauncher/log/ExtraDataTextRenderer.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) Forge Development LLC - * SPDX-License-Identifier: LGPL-3.0-only - */ - -package cpw.mods.modlauncher.log; - -import cpw.mods.modlauncher.api.ITransformerAuditTrail; -import org.apache.logging.log4j.core.pattern.TextRenderer; - -@Deprecated(forRemoval = true, since = "10.2.2") -public class ExtraDataTextRenderer implements TextRenderer { - private final TextRenderer wrapped; - private final ITransformerAuditTrail trail; - private final ThreadLocal currentClass = new ThreadLocal<>(); - - ExtraDataTextRenderer(final TextRenderer wrapped, ITransformerAuditTrail trail) { - this.wrapped = wrapped; - this.trail = trail; - } - - @Override - public void render(final String input, final StringBuilder output, final String styleName) { - if ("StackTraceElement.ClassName".equals(styleName)) { - currentClass.set(new TransformerContext()); - currentClass.get().setClassName(input); - } else if ("StackTraceElement.MethodName".equals(styleName)) { - final TransformerContext transformerContext = currentClass.get(); - if (transformerContext != null) { - transformerContext.setMethodName(input); - } - } else if ("Suffix".equals(styleName)) { - final TransformerContext classContext = currentClass.get(); - currentClass.remove(); - if (classContext != null) { - final String auditLine = trail == null ? "" : trail.getAuditString(classContext.getClassName()); - wrapped.render(" {" + auditLine + "}", output, "StackTraceElement.Transformers"); - } - return; - } - wrapped.render(input, output, styleName); - } - - @Override - public void render(final StringBuilder input, final StringBuilder output) { - wrapped.render(input, output); - } - - private static class TransformerContext { - - private String className; - private String methodName; - - public void setClassName(final String className) { - this.className = className; - } - - public String getClassName() { - return className; - } - - public void setMethodName(final String methodName) { - this.methodName = methodName; - } - - public String getMethodName() { - return methodName; - } - - @Override - public String toString() { - return getClassName()+"."+getMethodName(); - } - } -} diff --git a/src/main/java/cpw/mods/modlauncher/log/MLClassLoaderContextSelector.java b/src/main/java/cpw/mods/modlauncher/log/MLClassLoaderContextSelector.java index 60fe832..81988a1 100644 --- a/src/main/java/cpw/mods/modlauncher/log/MLClassLoaderContextSelector.java +++ b/src/main/java/cpw/mods/modlauncher/log/MLClassLoaderContextSelector.java @@ -9,6 +9,7 @@ import net.minecraftforge.securemodules.SecureModuleClassLoader; +// TODO: [ML] Check if this is still needed /** * A custom context selector to avoid initializing multiple log4j contexts due to {@link ModuleClassLoader#getParent()} always returning null (as a {@link ModuleClassLoader} can have multiple parents). * As all {@link ModuleClassLoader}s should get the same log4j context, we just return a static string with "MCL", otherwise we use the default logic diff --git a/src/main/java/cpw/mods/modlauncher/log/TransformingThrowablePatternConverter.java b/src/main/java/cpw/mods/modlauncher/log/TransformingThrowablePatternConverter.java index 8302226..05d0eef 100644 --- a/src/main/java/cpw/mods/modlauncher/log/TransformingThrowablePatternConverter.java +++ b/src/main/java/cpw/mods/modlauncher/log/TransformingThrowablePatternConverter.java @@ -23,6 +23,7 @@ import java.util.Optional; import java.util.TreeMap; +// TODO: [ML} Check if this is still needed /** * Started as a copy of {@link org.apache.logging.log4j.core.pattern.ExtendedThrowablePatternConverter} because * there is no mechanism to hook additional data into that class, which is very rubbish. @@ -128,36 +129,4 @@ private static void buildAuditMap(ITransformerAuditTrail trail, Map env.getProperty(IEnvironment.Keys.AUDITTRAIL.get())) - .orElse(null); - - var nl = Strings.LINE_SEPARATOR; - var renderer = PlainTextRenderer.getInstance(); - var suffix = ""; - //renderer = new ExtraDataTextRenderer(renderer, trail); - //suffix = SUFFIXFLAG; - proxy.formatExtendedStackTraceTo(buf, Collections.emptyList(), renderer, suffix, nl); - - if (trail != null) { - final Map> audit = new TreeMap<>(); - buildAuditMap(trail, audit, proxy); - - buf.append("Transformer Audit:").append(nl); - for (var cls : audit.keySet()) { - buf.append(" ").append(cls).append(nl); - for (var line : audit.get(cls)) - buf.append(" ").append(line).append(nl); - } - } - - return buf.toString(); - } } diff --git a/src/main/java/cpw/mods/modlauncher/serviceapi/ILaunchPluginService.java b/src/main/java/cpw/mods/modlauncher/serviceapi/ILaunchPluginService.java index 0616f7f..ee4c801 100644 --- a/src/main/java/cpw/mods/modlauncher/serviceapi/ILaunchPluginService.java +++ b/src/main/java/cpw/mods/modlauncher/serviceapi/ILaunchPluginService.java @@ -6,7 +6,6 @@ package cpw.mods.modlauncher.serviceapi; import cpw.mods.jarhandling.SecureJar; -import cpw.mods.modlauncher.api.NamedPath; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; @@ -160,15 +159,6 @@ default void addResources(List resources) {} default void initializeLaunch(ITransformerLoader transformerLoader) {} - /** Nothing ever filled the special paths, there is no reason for it to exist. - * I *think* this method is just to give access to the transforming classloader - * in a round about way, I need to review this whole class - **/ - @Deprecated(forRemoval = true, since = "10.1") - default void initializeLaunch(ITransformerLoader transformerLoader, NamedPath[] specialPaths) { - this.initializeLaunch(transformerLoader); - } - /** * Get a plugin specific extension object from the plugin. This can be used to expose proprietary interfaces * to Launchers without ModLauncher needing to understand them. diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 7e6829f..06a74c1 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -7,7 +7,7 @@ requires java.base; requires org.apache.logging.log4j; requires org.apache.logging.log4j.core; - requires jopt.simple; + requires joptsimple; requires transitive cpw.mods.securejarhandler; requires static org.jetbrains.annotations; requires org.objectweb.asm; @@ -26,7 +26,6 @@ uses cpw.mods.modlauncher.api.ILaunchHandlerService; provides cpw.mods.modlauncher.api.ILaunchHandlerService with - cpw.mods.modlauncher.DefaultLaunchHandlerService, cpw.mods.modlauncher.TestingLaunchHandlerService; requires net.minecraftforge.bootstrap.api;