Skip to content

(WIP) ModLauncher 11 #3

New issue

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

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

Already on GitHub? Sign in to your account

Draft
wants to merge 21 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
bcf3a0f
Bump to Java 21
PaintNinja Nov 23, 2024
f943569
Make the blackboard static final
PaintNinja Nov 23, 2024
8f7cf48
Minor refactor
PaintNinja Nov 23, 2024
d8fad9a
Cleanup ArgumentHandler
PaintNinja Nov 23, 2024
fc0e4ef
Remove DefaultLaunchHandlerService
PaintNinja Nov 23, 2024
f691d41
Remove `TransformTargetLabel.LabelType#getTypeFor`
PaintNinja Nov 23, 2024
671cbb0
Make ILaunchHandlerService#launchService void
PaintNinja Nov 23, 2024
0b0ad78
Remove `ILaunchHandlerService#configureTransformationClassLoader`
PaintNinja Nov 23, 2024
74ece19
Remove ILaunchHandlerService#getPaths and ILaunchPluginService#initia…
PaintNinja Nov 23, 2024
033c882
Remove IModuleLayerManager#getParent
PaintNinja Nov 23, 2024
e628000
Fail fast on ServiceConfigurationError when loading services
PaintNinja Nov 23, 2024
72f704b
Minor refactor
PaintNinja Nov 23, 2024
d8c57b8
Apply more deprecation removals
PaintNinja Nov 23, 2024
c209766
Use jopt-simple's native module name
PaintNinja Nov 23, 2024
bf14a6f
Use `SecureModuleClassLoader` directly, add some todos
PaintNinja Nov 23, 2024
60b6497
Spell LambdaExceptionUtils correctly
PaintNinja Nov 23, 2024
86ceb41
Document and seal `ITransformationService.OptionResult`
PaintNinja Nov 23, 2024
1307fe3
Make TransformerHolder a record, minor refactors
PaintNinja Nov 23, 2024
4905edb
Remove `ITransformingClassLoaderBuilder`
PaintNinja Nov 23, 2024
5507ad0
Remove `EnumerationHelper`
PaintNinja Nov 23, 2024
ddb4728
Remove ArgumentHandler#getSpecialJars
PaintNinja Nov 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# Java 8 mod launcher for Minecraft
Intended as a replacement for LegacyLauncher, using Java 8 and 9 compatible constructs
# Java 21 mod launcher for Minecraft
Intended as a replacement for LegacyLauncher, using Java 8 and 9+ compatible constructs
23 changes: 11 additions & 12 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ plugins {
}

java {
toolchain.languageVersion = JavaLanguageVersion.of(16)
toolchain.languageVersion = JavaLanguageVersion.of(21)
withSourcesJar()
}

Expand Down Expand Up @@ -48,7 +48,6 @@ configurations.all {

extraJavaModuleInfo {
failOnMissingModuleInfo = false
automaticModule('net.sf.jopt-simple:jopt-simple', 'jopt.simple')
}

license {
Expand Down Expand Up @@ -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] ]
}
}
2 changes: 1 addition & 1 deletion ml-jmh/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ repositories {
}

java {
toolchain.languageVersion = JavaLanguageVersion.of(16)
toolchain.languageVersion = JavaLanguageVersion.of(21)
}

license {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion ml-test-jar/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ repositories {
}

java {
toolchain.languageVersion = JavaLanguageVersion.of(16)
toolchain.languageVersion = JavaLanguageVersion.of(21)
}

license {
Expand Down
2 changes: 1 addition & 1 deletion ml-test/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ repositories {
}

java {
toolchain.languageVersion = JavaLanguageVersion.of(16)
toolchain.languageVersion = JavaLanguageVersion.of(21)
}

license {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -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) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ private static List<SecureJar> getTestJars() {

var ret = new ArrayList<SecureJar>();
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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,10 @@ public List<ITransformer> transformers() {
Set<String> 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")
);
}
Expand Down
119 changes: 55 additions & 64 deletions src/main/java/cpw/mods/modlauncher/ArgumentHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,102 +6,93 @@
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<String> PROFILE_OPTION = PARSER
.accepts("version", "The version we launched with")
.withRequiredArg();

private static final OptionSpec<Path> GAME_DIR_OPTION = PARSER
.accepts("gameDir", "Alternative game directory")
.withRequiredArg()
.withValuesConvertedBy(new PathConverter(PathProperties.DIRECTORY_EXISTING))
.defaultsTo(Path.of("."));

private static final OptionSpec<Path> ASSETS_DIR_OPTION = PARSER
.accepts("assetsDir", "Assets directory")
.withRequiredArg()
.withValuesConvertedBy(new PathConverter(PathProperties.DIRECTORY_EXISTING));

private static final OptionSpec<String> LAUNCH_TARGET_OPTION = PARSER
.accepts("launchTarget", "LauncherService target to launch")
.withRequiredArg();

private static final OptionSpec<String> 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<String> profileOption;
private OptionSpec<Path> gameDirOption;
private OptionSpec<Path> assetsDirOption;
private OptionSpec<Path> minecraftJarOption;
private OptionSpec<String> nonOption;
private OptionSpec<String> launchTarget;
private OptionSpec<String> 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<OptionParser> parserConsumer, BiConsumer<OptionSet, BiFunction<String, OptionSet, ITransformationService.OptionResult>> 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<OptionParser> parserConsumer, BiConsumer<OptionSet, BiFunction<String, OptionSet, ITransformationService.OptionResult>> 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> V value(OptionSpec<V> option) {
checkOwnership(option);
return set.valueOf(option);
}

@Override
public <V> @NotNull List<V> values(OptionSpec<V> option) {
checkOwnership(option);
return set.valuesOf(option);
}

private <V> void checkOwnership(OptionSpec<V> 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<String> args = new ArrayList<>();
addOptionToString(profileOption, optionSet, args);
addOptionToString(gameDirOption, optionSet, args);
addOptionToString(assetsDirOption, optionSet, args);
addOptionToString(uuidOption, optionSet, args);
var args = new ArrayList<String>();
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]);
}

private static void addOptionToString(OptionSpec<?> option, OptionSet optionSet, List<String> appendTo) {
if (optionSet.has(option)) {
appendTo.add("--"+option.options().get(0));
appendTo.add("--" + option.options().getFirst());
appendTo.add(option.value(optionSet).toString());
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/cpw/mods/modlauncher/ClassTransformer.java
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ private <T> T performVote(List<ITransformer<T>> 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<T> transformer = yesVotes.get(0).transformer();
final ITransformer<T> transformer = yesVotes.getFirst().transformer();
node = transformer.transform(node, context);
auditTrail.addTransformerAuditTrail(context.getClassName(), ((TransformerHolder<?>) transformer).owner(), transformer);
transformers.remove(transformer);
Expand Down

This file was deleted.

Loading