Skip to content

Commit

Permalink
Fix defining duplicated modules.
Browse files Browse the repository at this point in the history
  • Loading branch information
ZekerZhayard committed Aug 13, 2021
1 parent 5fb3f01 commit 3ee6633
Show file tree
Hide file tree
Showing 14 changed files with 128 additions and 112 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/publication.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ jobs:
env:
IS_PUBLICATION: true
run: |
git clone -b maven https://github.com/ZekerZhayard/ForgeWrapper.git ./build/maven
rm -rf ./build/maven/.git/*
chmod +x ./gradlew
./gradlew publish -iS
- uses: actions/upload-artifact@v2
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Allow [MultiMC](https://github.com/MultiMC/MultiMC5) to launch Minecraft 1.13+ w
3. Since ForgeWrapper 1.5.1, it no longer includes the json converter, so you need to build it by yourself:
- [Download](https://github.com/ZekerZhayard/ForgeWrapper/archive/refs/heads/master.zip) ForgeWrapper sources.
- Extract the zip and open terminal in the extracted folder.
- Run `./gradlew build` command in terminal and get the jar from `./converter/build/libs`
- Run `./gradlew converter:build` command in terminal and get the jar from `./converter/build/libs`
3. Run the below command in terminal:
```
java -jar <ForgeWrapper.jar> --installer=<forge-installer.jar> [--instance=<instance-path>]
Expand Down
7 changes: 3 additions & 4 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ archivesBaseName = rootProject.name

configurations {
provided {
compileOnly.extendsFrom provided
implementation.extendsFrom provided
}
multirelase {
compileOnly.extendsFrom multirelase
implementation.extendsFrom multirelase
}
}

Expand All @@ -37,6 +37,7 @@ dependencies {
compileOnly "net.minecraftforge:installer:2.1.4"
compileOnly "net.sf.jopt-simple:jopt-simple:5.0.4"

provided project(":common")
provided project(":legacy")
multirelase project(":jigsaw")
}
Expand All @@ -56,7 +57,6 @@ jar {
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"),
"Automatic-Module-Name": "${project.group}.${project.archivesBaseName}".toString().toLowerCase(),
"Multi-Release": "true",
"Main-Class": "io.github.zekerzhayard.forgewrapper.converter.Main",
"GitCommit": String.valueOf(System.getenv("GITHUB_SHA"))
])

Expand Down Expand Up @@ -87,7 +87,6 @@ publishing {
url = layout.buildDirectory.dir("maven")
}
}

}
tasks.publish.dependsOn build

Expand Down
11 changes: 11 additions & 0 deletions common/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

plugins {
id "java"
id "eclipse"
id "maven-publish"
}

sourceCompatibility = targetCompatibility = 1.8
compileJava {
sourceCompatibility = targetCompatibility = 1.8
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package io.github.zekerzhayard.forgewrapper.util;

import java.util.function.BiConsumer;
import java.util.function.Consumer;

public class CheckedLambdaUtil {
public static <T> Consumer<T> wrapConsumer(CheckedConsumer<T> consumer) {
return consumer;
}

public static <T, U> BiConsumer<T, U> wrapBiConsumer(CheckedBiConsumer<T, U> biconsumer) {
return biconsumer;
}

public interface CheckedConsumer<T> extends Consumer<T> {
void checkedAccept(T t) throws Throwable;

@Override
default void accept(T t) {
try {
this.checkedAccept(t);
} catch (Throwable th) {
throw new RuntimeException(th);
}
}
}

public interface CheckedBiConsumer<T, U> extends BiConsumer<T, U> {
void checkedAccept(T t, U u) throws Throwable;

@Override
default void accept(T t, U u) {
try {
this.checkedAccept(t, u);
} catch (Throwable th) {
throw new RuntimeException(th);
}
}
}
}
8 changes: 7 additions & 1 deletion converter/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,14 @@ version = "${rootProject.fw_version}${-> getVersionSuffix()}"
group = "io.github.zekerzhayard"
archivesBaseName = rootProject.name + "Converter"

sourceCompatibility = targetCompatibility = 1.8
compileJava {
sourceCompatibility = targetCompatibility = 1.8
}

configurations {
provided {
compileOnly.extendsFrom provided
implementation.extendsFrom provided
}
}

Expand All @@ -30,6 +35,7 @@ jar {
])

from configurations.provided.files.collect {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
zipTree(it)
}
}
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@

org.gradle.daemon = false

fw_version = 1.5.1
fw_version = 1.5.2
4 changes: 4 additions & 0 deletions jigsaw/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,7 @@ configurations {
}
}
}

dependencies {
compileOnly project(":common")
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,23 @@
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.module.Configuration;
import java.lang.module.ModuleDescriptor;
import java.lang.module.ModuleFinder;
import java.lang.module.ModuleReference;
import java.lang.module.ResolvedModule;
import java.lang.reflect.Field;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import io.github.zekerzhayard.forgewrapper.util.CheckedLambdaUtil;
import sun.misc.Unsafe;

public class ModuleUtil {
Expand All @@ -46,39 +47,22 @@ private static MethodHandles.Lookup getImplLookup() {
*/
@SuppressWarnings("unchecked")
public static void addModules(String modulePath) throws Throwable {
// Find all extra modules
ModuleFinder finder = ModuleFinder.of(Arrays.stream(modulePath.split(File.pathSeparator)).map(Paths::get).toArray(Path[]::new));
// Find all extra modules, exclude all existing modules
ModuleFinder finder = ModuleFinder.of(Stream.of(modulePath.split(File.pathSeparator)).map(Paths::get).filter(p -> ModuleFinder.of(p).findAll().stream().noneMatch(mref -> ModuleLayer.boot().findModule(mref.descriptor().name()).isPresent())).toArray(Path[]::new));
MethodHandle loadModuleMH = IMPL_LOOKUP.findVirtual(Class.forName("jdk.internal.loader.BuiltinClassLoader"), "loadModule", MethodType.methodType(void.class, ModuleReference.class));

// Resolve modules to a new config
Configuration config = Configuration.resolveAndBind(finder, List.of(ModuleLayer.boot().configuration()), finder, finder.findAll().stream().peek(mref -> {
try {
// Load all extra modules in system class loader (unnamed modules for now)
loadModuleMH.invokeWithArguments(ClassLoader.getSystemClassLoader(), mref);
} catch (Throwable throwable) {
throw new RuntimeException(throwable);
}
}).map(ModuleReference::descriptor).map(ModuleDescriptor::name).collect(Collectors.toList()));
// Resolve modules to a new config and load all extra modules in system class loader (unnamed modules for now)
Configuration config = Configuration.resolveAndBind(finder, List.of(ModuleLayer.boot().configuration()), finder, finder.findAll().stream().filter(mref -> !ModuleLayer.boot().findModule(mref.descriptor().name()).isPresent()).peek(CheckedLambdaUtil.wrapConsumer(mref -> loadModuleMH.invokeWithArguments(ClassLoader.getSystemClassLoader(), mref))).map(mref -> mref.descriptor().name()).collect(Collectors.toList()));

// Copy the new config graph to boot module layer config
MethodHandle graphGetter = IMPL_LOOKUP.findGetter(Configuration.class, "graph", Map.class);
HashMap<ResolvedModule, Set<ResolvedModule>> graphMap = new HashMap<>((Map<ResolvedModule, Set<ResolvedModule>>) graphGetter.invokeWithArguments(config));
MethodHandle cfSetter = IMPL_LOOKUP.findSetter(ResolvedModule.class, "cf", Configuration.class);
// Reset all extra resolved modules config to boot module layer config
graphMap.forEach((k, v) -> {
try {
cfSetter.invokeWithArguments(k, ModuleLayer.boot().configuration());
v.forEach(m -> {
try {
cfSetter.invokeWithArguments(m, ModuleLayer.boot().configuration());
} catch (Throwable throwable) {
throw new RuntimeException(throwable);
}
});
} catch (Throwable throwable) {
throw new RuntimeException(throwable);
}
});
graphMap.forEach(CheckedLambdaUtil.wrapBiConsumer((k, v) -> {
cfSetter.invokeWithArguments(k, ModuleLayer.boot().configuration());
v.forEach(CheckedLambdaUtil.wrapConsumer(m -> cfSetter.invokeWithArguments(m, ModuleLayer.boot().configuration())));
}));
graphMap.putAll((Map<ResolvedModule, Set<ResolvedModule>>) graphGetter.invokeWithArguments(ModuleLayer.boot().configuration()));
IMPL_LOOKUP.findSetter(Configuration.class, "graph", Map.class).invokeWithArguments(ModuleLayer.boot().configuration(), new HashMap<>(graphMap));

Expand All @@ -88,13 +72,13 @@ public static void addModules(String modulePath) throws Throwable {
HashSet<ResolvedModule> modulesSet = new HashSet<>(config.modules());
modulesSetter.invokeWithArguments(ModuleLayer.boot().configuration(), new HashSet<>(modulesSet));

// Prepare to add all of the new config "nameToModule" to boot module layer config
// Prepare to add all the new config "nameToModule" to boot module layer config
MethodHandle nameToModuleGetter = IMPL_LOOKUP.findGetter(Configuration.class, "nameToModule", Map.class);
HashMap<String, ResolvedModule> nameToModuleMap = new HashMap<>((Map<String, ResolvedModule>) nameToModuleGetter.invokeWithArguments(ModuleLayer.boot().configuration()));
nameToModuleMap.putAll((Map<String, ResolvedModule>) nameToModuleGetter.invokeWithArguments(config));
IMPL_LOOKUP.findSetter(Configuration.class, "nameToModule", Map.class).invokeWithArguments(ModuleLayer.boot().configuration(), new HashMap<>(nameToModuleMap));

// Define all extra modules and add all of the new config "nameToModule" to boot module layer config
// Define all extra modules and add all the new config "nameToModule" to boot module layer config
((Map<String, Module>) IMPL_LOOKUP.findGetter(ModuleLayer.class, "nameToModule", Map.class).invokeWithArguments(ModuleLayer.boot())).putAll((Map<String, Module>) IMPL_LOOKUP.findStatic(Module.class, "defineModules", MethodType.methodType(Map.class, Configuration.class, Function.class, ModuleLayer.class)).invokeWithArguments(ModuleLayer.boot().configuration(), (Function<String, ClassLoader>) name -> ClassLoader.getSystemClassLoader(), ModuleLayer.boot()));

// Add all of resolved modules
Expand All @@ -107,66 +91,56 @@ public static void addModules(String modulePath) throws Throwable {

// Add reads from extra modules to jdk modules
MethodHandle implAddReadsMH = IMPL_LOOKUP.findVirtual(Module.class, "implAddReads", MethodType.methodType(void.class, Module.class));
config.modules().forEach(rm -> ModuleLayer.boot().findModule(rm.name()).ifPresent(m -> oldBootModules.forEach(brm -> ModuleLayer.boot().findModule(brm.name()).ifPresent(bm -> {
try {
implAddReadsMH.invokeWithArguments(m, bm);
} catch (Throwable throwable) {
throw new RuntimeException(throwable);
}
}))));
config.modules().forEach(rm -> ModuleLayer.boot().findModule(rm.name()).ifPresent(m -> oldBootModules.forEach(brm -> ModuleLayer.boot().findModule(brm.name()).ifPresent(CheckedLambdaUtil.wrapConsumer(bm -> implAddReadsMH.invokeWithArguments(m, bm))))));
}

public static void addExports(List<String> exports) throws Throwable {
MethodHandle implAddExportsMH = IMPL_LOOKUP.findVirtual(Module.class, "implAddExports", MethodType.methodType(void.class, String.class, Module.class));
MethodHandle implAddExportsToAllUnnamedMH = IMPL_LOOKUP.findVirtual(Module.class, "implAddExportsToAllUnnamed", MethodType.methodType(void.class, String.class));
public static void addExports(List<String> exports) {
TypeToAdd.EXPORTS.implAdd(exports);
}

addExtra(exports, implAddExportsMH, implAddExportsToAllUnnamedMH);
public static void addOpens(List<String> opens) {
TypeToAdd.OPENS.implAdd(opens);
}

public static void addOpens(List<String> opens) throws Throwable {
MethodHandle implAddOpensMH = IMPL_LOOKUP.findVirtual(Module.class, "implAddOpens", MethodType.methodType(void.class, String.class, Module.class));
MethodHandle implAddOpensToAllUnnamedMH = IMPL_LOOKUP.findVirtual(Module.class, "implAddOpensToAllUnnamed", MethodType.methodType(void.class, String.class));
private enum TypeToAdd {
EXPORTS("Exports"),
OPENS("Opens");

addExtra(opens, implAddOpensMH, implAddOpensToAllUnnamedMH);
}
private final MethodHandle implAddMH;
private final MethodHandle implAddToAllUnnamedMH;

private static void addExtra(List<String> extras, MethodHandle implAddExtraMH, MethodHandle implAddExtraToAllUnnamedMH) {
extras.forEach(extra -> {
ParserData data = parseModuleExtra(extra);
if (data != null) {
ModuleLayer.boot().findModule(data.module).ifPresent(m -> {
try {
if ("ALL-UNNAMED".equals(data.target)) {
implAddExtraToAllUnnamedMH.invokeWithArguments(m, data.packages);
} else {
ModuleLayer.boot().findModule(data.target).ifPresent(tm -> {
try {
implAddExtraMH.invokeWithArguments(m, data.packages, tm);
} catch (Throwable t) {
throw new RuntimeException(t);
}
});
}
} catch (Throwable t) {
throw new RuntimeException(t);
}
});
TypeToAdd(String name) {
try {
this.implAddMH = IMPL_LOOKUP.findVirtual(Module.class, "implAdd" + name, MethodType.methodType(void.class, String.class, Module.class));
this.implAddToAllUnnamedMH = IMPL_LOOKUP.findVirtual(Module.class, "implAdd" + name + "ToAllUnnamed", MethodType.methodType(void.class, String.class));
} catch (Throwable t) {
throw new RuntimeException(t);
}
});
}

void implAdd(List<String> extras) {
extras.stream().map(ModuleUtil::parseModuleExtra).filter(Optional::isPresent).map(Optional::get).forEach(CheckedLambdaUtil.wrapConsumer(data -> ModuleLayer.boot().findModule(data.module).ifPresent(CheckedLambdaUtil.wrapConsumer(m -> {
if ("ALL-UNNAMED".equals(data.target)) {
this.implAddToAllUnnamedMH.invokeWithArguments(m, data.packages);
} else {
ModuleLayer.boot().findModule(data.target).ifPresent(CheckedLambdaUtil.wrapConsumer(tm -> this.implAddMH.invokeWithArguments(m, data.packages, tm)));
}
}))));
}
}

// <module>/<package>=<target>
private static ParserData parseModuleExtra(String extra) {
private static Optional<ParserData> parseModuleExtra(String extra) {
String[] all = extra.split("=", 2);
if (all.length < 2) {
return null;
return Optional.empty();
}

String[] source = all[0].split("/", 2);
if (source.length < 2) {
return null;
return Optional.empty();
}
return new ParserData(source[0], source[1], all[1]);
return Optional.of(new ParserData(source[0], source[1], all[1]));
}

private static class ParserData {
Expand All @@ -182,14 +156,10 @@ private static class ParserData {
}

// ForgeWrapper need some extra settings to invoke BootstrapLauncher.
public static void setupBootstrapLauncher() throws Throwable {
MethodHandle implAddOpensMH = IMPL_LOOKUP.findVirtual(Module.class, "implAddOpens", MethodType.methodType(void.class, String.class, Module.class));
ModuleLayer.boot().findModule("cpw.mods.bootstraplauncher").ifPresent(m -> {
try {
implAddOpensMH.invokeWithArguments(m, "cpw.mods.bootstraplauncher", ModuleUtil.class.getModule());
} catch (Throwable t) {
throw new RuntimeException(t);
}
});
public static Class<?> setupBootstrapLauncher(Class<?> mainClass) throws Throwable {
if (!mainClass.getModule().isOpen(mainClass.getPackageName(), ModuleUtil.class.getModule())) {
TypeToAdd.OPENS.implAddMH.invokeWithArguments(mainClass.getModule(), mainClass.getPackageName(), ModuleUtil.class.getModule());
}
return mainClass;
}
}
1 change: 1 addition & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
rootProject.name = 'ForgeWrapper'

include 'common'
include 'converter'
include 'jigsaw'
include 'legacy'
Loading

0 comments on commit 3ee6633

Please sign in to comment.