summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZekerZhayard <trees1000@qq.com>2021-07-23 01:47:28 +0800
committerZekerZhayard <trees1000@qq.com>2021-07-24 19:10:41 +0800
commit5fb3f01768c8a9bb1587ea0884e6d01127dbc4ac (patch)
tree51d60600f9de8b912a533f64323a56396b8ea9d4
parent3aeeada18f679232315b49044d9045a256749132 (diff)
downloadProject-Tick-5fb3f01768c8a9bb1587ea0884e6d01127dbc4ac.tar.gz
Project-Tick-5fb3f01768c8a9bb1587ea0884e6d01127dbc4ac.zip
Full support the installation of forge-1.16.5-36.1.66+ and partial support forge-1.17.1
-rw-r--r--.github/workflows/build.yml6
-rw-r--r--.github/workflows/maven.bat13
-rw-r--r--.github/workflows/publication.yml13
-rw-r--r--.gitignore2
-rw-r--r--README.md4
-rw-r--r--build.gradle38
-rw-r--r--converter/build.gradle48
-rw-r--r--converter/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java (renamed from src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java)6
-rw-r--r--converter/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Main.java (renamed from src/main/java/io/github/zekerzhayard/forgewrapper/converter/Main.java)0
-rw-r--r--converter/src/main/resources/mmc-pack.json (renamed from src/main/resources/mmc-pack.json)2
-rw-r--r--converter/src/main/resources/patches/net.minecraftforge.json (renamed from src/main/resources/patches/net.minecraftforge.json)2
-rw-r--r--gradle.properties2
-rw-r--r--jigsaw/build.gradle28
-rw-r--r--jigsaw/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/ModuleUtil.java195
-rw-r--r--legacy/build.gradle2
-rw-r--r--settings.gradle4
-rw-r--r--src/main/java/io/github/zekerzhayard/forgewrapper/installer/Bootstrap.java78
-rw-r--r--src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java6
-rw-r--r--src/main/java/io/github/zekerzhayard/forgewrapper/installer/MainV2.java15
-rw-r--r--src/main/java/io/github/zekerzhayard/forgewrapper/installer/detector/IFileDetector.java52
-rw-r--r--src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/ModuleUtil.java21
-rw-r--r--src/main/resources/META-INF/services/io.github.zekerzhayard.forgewrapper.installer.detector.IFileDetector2
-rw-r--r--src/main/resources/META-INF/services/java.util.function.Consumer1
23 files changed, 458 insertions, 82 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 8d331b528b..9e2ae64ce0 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -8,7 +8,7 @@ on:
jobs:
build:
- runs-on: windows-latest
+ runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
@@ -18,7 +18,9 @@ jobs:
java-version: '8.0.302'
architecture: x64
- name: Build with Gradle
- run: ./gradlew.bat build -iS
+ run: |
+ chmod +x ./gradlew
+ ./gradlew build -iS
- uses: actions/upload-artifact@v2
with:
name: Package
diff --git a/.github/workflows/maven.bat b/.github/workflows/maven.bat
deleted file mode 100644
index 0d3f914a00..0000000000
--- a/.github/workflows/maven.bat
+++ /dev/null
@@ -1,13 +0,0 @@
-@ECHO OFF
-
-git clone -b maven https://github.com/ZekerZhayard/ForgeWrapper.git .\maven
-
-xcopy ".\build\maven\" ".\maven\" /S /Y
-cd ".\maven\"
-
-git config --local user.name "GitHub Actions"
-git config --local user.email "actions@github.com"
-
-git add .
-git commit -m "%GITHUB_SHA%"
-git push https://${GITHUB_TOKEN}@github.com/ZekerZhayard/ForgeWrapper.git maven
diff --git a/.github/workflows/publication.yml b/.github/workflows/publication.yml
index 0f6f0eb94e..15a91613fc 100644
--- a/.github/workflows/publication.yml
+++ b/.github/workflows/publication.yml
@@ -7,7 +7,7 @@ on:
jobs:
build:
- runs-on: windows-latest
+ runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
@@ -19,7 +19,9 @@ jobs:
- name: Build with Gradle
env:
IS_PUBLICATION: true
- run: ./gradlew.bat publish -iS
+ run: |
+ chmod +x ./gradlew
+ ./gradlew publish -iS
- uses: actions/upload-artifact@v2
with:
name: Package
@@ -49,6 +51,7 @@ jobs:
with:
asset_paths: '["./build/libs/*"]'
- name: Upload to Maven
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- run: ./.github/workflows/maven.bat
+ uses: JamesIves/github-pages-deploy-action@4.1.4
+ with:
+ branch: maven
+ folder: build/maven
diff --git a/.gitignore b/.gitignore
index 007587d534..2bcd13edda 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,4 +12,4 @@ bin
*.iml
*.ipr
*.iws
-out \ No newline at end of file
+out
diff --git a/README.md b/README.md
index 21e2b9640d..d05b57d08f 100644
--- a/README.md
+++ b/README.md
@@ -16,6 +16,10 @@ Allow [MultiMC](https://github.com/MultiMC/MultiMC5) to launch Minecraft 1.13+ w
1. Download Forge installer for Minecraft 1.13+ [here](https://files.minecraftforge.net/).
2. Download ForgeWrapper jar file at the [release](https://github.com/ZekerZhayard/ForgeWrapper/releases) page.
+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`
3. Run the below command in terminal:
```
java -jar <ForgeWrapper.jar> --installer=<forge-installer.jar> [--instance=<instance-path>]
diff --git a/build.gradle b/build.gradle
index 36c64069a9..d975a08ac3 100644
--- a/build.gradle
+++ b/build.gradle
@@ -6,6 +6,9 @@ plugins {
}
sourceCompatibility = targetCompatibility = 1.8
+compileJava {
+ sourceCompatibility = targetCompatibility = 1.8
+}
version = "${fw_version}${-> getVersionSuffix()}"
group = "io.github.zekerzhayard"
@@ -15,6 +18,9 @@ configurations {
provided {
compileOnly.extendsFrom provided
}
+ multirelase {
+ compileOnly.extendsFrom multirelase
+ }
}
repositories {
@@ -26,12 +32,13 @@ repositories {
}
dependencies {
- compileOnly "com.google.code.gson:gson:2.8.7"
+ compileOnly "com.google.code.gson:gson:2.8.5"
compileOnly "cpw.mods:modlauncher:8.0.9"
compileOnly "net.minecraftforge:installer:2.1.4"
compileOnly "net.sf.jopt-simple:jopt-simple:5.0.4"
provided project(":legacy")
+ multirelase project(":jigsaw")
}
java {
@@ -48,6 +55,7 @@ jar {
"Implementation-Vendor" :"ZekerZhayard",
"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"))
])
@@ -55,30 +63,12 @@ jar {
from configurations.provided.files.collect {
zipTree(it)
}
-}
-/*task sourcesJar(type: Jar) {
- manifest {
- attributes(jar.manifest.attributes)
- }
- from sourceSets.main.allSource
- archiveFileName = "${archivesBaseName}-${archiveVersion.get()}-sources.${archiveExtension.get()}"
-}
-
-artifacts {
- archives sourcesJar
-}*/
-
-processResources {
- inputs.property "version", project.version
- from(sourceSets.main.resources.srcDirs) {
- duplicatesStrategy = DuplicatesStrategy.INCLUDE
- include "patches/net.minecraftforge.json"
- expand "version": project.version
- }
- from(sourceSets.main.resources.srcDirs) {
- duplicatesStrategy = DuplicatesStrategy.EXCLUDE
- exclude "patches/net.minecraftforge.json"
+ into "META-INF/versions/9", {
+ from configurations.multirelase.files.collect {
+ zipTree(it)
+ }
+ exclude "META-INF/**"
}
}
diff --git a/converter/build.gradle b/converter/build.gradle
new file mode 100644
index 0000000000..93be5a1584
--- /dev/null
+++ b/converter/build.gradle
@@ -0,0 +1,48 @@
+
+plugins {
+ id "java"
+ id "eclipse"
+}
+
+version = "${rootProject.fw_version}${-> getVersionSuffix()}"
+group = "io.github.zekerzhayard"
+archivesBaseName = rootProject.name + "Converter"
+
+configurations {
+ provided {
+ compileOnly.extendsFrom provided
+ }
+}
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ compileOnly "com.google.code.gson:gson:2.8.5"
+ provided rootProject
+}
+
+jar {
+ manifest.attributes rootProject.jar.manifest.attributes
+ manifest.attributes([
+ "Main-Class": "io.github.zekerzhayard.forgewrapper.converter.Main"
+ ])
+
+ from configurations.provided.files.collect {
+ zipTree(it)
+ }
+}
+
+processResources {
+ inputs.property "version", project.version
+ from(sourceSets.main.resources.srcDirs) {
+ duplicatesStrategy = DuplicatesStrategy.INCLUDE
+ include "patches/net.minecraftforge.json"
+ expand "version": project.version
+ }
+ from(sourceSets.main.resources.srcDirs) {
+ duplicatesStrategy = DuplicatesStrategy.EXCLUDE
+ exclude "patches/net.minecraftforge.json"
+ }
+}
diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java b/converter/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java
index 403488bd95..0fdfc1382b 100644
--- a/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java
+++ b/converter/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java
@@ -120,11 +120,11 @@ public class Converter {
}
Map<String, String> additionalUrls = new HashMap<>();
String path = String.format("net/minecraftforge/forge/%s-%s/forge-%s-%s", mcVersion, forgeVersion, mcVersion, forgeVersion);
- additionalUrls.put(path + "-universal.jar", "https://files.minecraftforge.net/maven/" + path + "-universal.jar");
+ additionalUrls.put(path + "-universal.jar", "https://maven.minecraftforge.net/" + path + "-universal.jar");
transformLibraries(getElement(installProfile, "libraries").getAsJsonArray(), mavenFiles, additionalUrls);
additionalUrls.clear();
- additionalUrls.put(path + ".jar", "https://files.minecraftforge.net/maven/" + path + "-launcher.jar");
- transformLibraries(getElement(installer ,"libraries").getAsJsonArray(), libraries, additionalUrls);
+ additionalUrls.put(path + ".jar", "https://maven.minecraftforge.net/" + path + "-launcher.jar");
+ transformLibraries(getElement(installer, "libraries").getAsJsonArray(), libraries, additionalUrls);
patches.addProperty("version", forgeVersion);
for (JsonElement require : getElement(patches, "requires").getAsJsonArray()) {
diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Main.java b/converter/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Main.java
index 83ecdf959e..83ecdf959e 100644
--- a/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Main.java
+++ b/converter/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Main.java
diff --git a/src/main/resources/mmc-pack.json b/converter/src/main/resources/mmc-pack.json
index 3622087e0a..87db08a724 100644
--- a/src/main/resources/mmc-pack.json
+++ b/converter/src/main/resources/mmc-pack.json
@@ -10,4 +10,4 @@
"uid": "net.minecraftforge"
}
]
-} \ No newline at end of file
+}
diff --git a/src/main/resources/patches/net.minecraftforge.json b/converter/src/main/resources/patches/net.minecraftforge.json
index d170dd25e8..8b09773bbe 100644
--- a/src/main/resources/patches/net.minecraftforge.json
+++ b/converter/src/main/resources/patches/net.minecraftforge.json
@@ -25,4 +25,4 @@
"MMC-filename": "ForgeWrapper-${version}.jar"
}
]
-} \ No newline at end of file
+}
diff --git a/gradle.properties b/gradle.properties
index 38e35016b1..a0a9a4a00e 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,4 +1,4 @@
org.gradle.daemon = false
-fw_version = 1.5 \ No newline at end of file
+fw_version = 1.5.1
diff --git a/jigsaw/build.gradle b/jigsaw/build.gradle
new file mode 100644
index 0000000000..a555ec3bf3
--- /dev/null
+++ b/jigsaw/build.gradle
@@ -0,0 +1,28 @@
+
+plugins {
+ id "java"
+ id "eclipse"
+}
+
+compileJava {
+ if (JavaVersion.current() < JavaVersion.VERSION_1_9) {
+ javaCompiler = javaToolchains.compilerFor {
+ languageVersion = JavaLanguageVersion.of(9)
+ }
+ }
+ sourceCompatibility = 9
+ targetCompatibility = 9
+}
+
+configurations {
+ apiElements {
+ attributes {
+ attribute TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 8
+ }
+ }
+ runtimeElements {
+ attributes {
+ attribute TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 8
+ }
+ }
+}
diff --git a/jigsaw/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/ModuleUtil.java b/jigsaw/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/ModuleUtil.java
new file mode 100644
index 0000000000..ce12029b38
--- /dev/null
+++ b/jigsaw/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/ModuleUtil.java
@@ -0,0 +1,195 @@
+package io.github.zekerzhayard.forgewrapper.installer.util;
+
+import java.io.File;
+import java.lang.invoke.MethodHandle;
+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.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import sun.misc.Unsafe;
+
+public class ModuleUtil {
+ private final static MethodHandles.Lookup IMPL_LOOKUP = getImplLookup();
+
+ private static MethodHandles.Lookup getImplLookup() {
+ try {
+ // Get theUnsafe
+ Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
+ unsafeField.setAccessible(true);
+ Unsafe unsafe = (Unsafe) unsafeField.get(null);
+
+ // Get IMPL_LOOKUP
+ Field implLookupField = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP");
+ return (MethodHandles.Lookup) unsafe.getObject(unsafe.staticFieldBase(implLookupField), unsafe.staticFieldOffset(implLookupField));
+ } catch (Throwable t) {
+ throw new RuntimeException(t);
+ }
+ }
+
+ /**
+ * add module-path at runtime
+ */
+ @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));
+ 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()));
+
+ // 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.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));
+
+ // Reset boot module layer resolved modules as new config resolved modules to prepare define modules
+ Set<ResolvedModule> oldBootModules = ModuleLayer.boot().configuration().modules();
+ MethodHandle modulesSetter = IMPL_LOOKUP.findSetter(Configuration.class, "modules", Set.class);
+ 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
+ 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
+ ((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
+ modulesSet.addAll(oldBootModules);
+ modulesSetter.invokeWithArguments(ModuleLayer.boot().configuration(), new HashSet<>(modulesSet));
+
+ // Reset cache of boot module layer
+ IMPL_LOOKUP.findSetter(ModuleLayer.class, "modules", Set.class).invokeWithArguments(ModuleLayer.boot(), null);
+ IMPL_LOOKUP.findSetter(ModuleLayer.class, "servicesCatalog", Class.forName("jdk.internal.module.ServicesCatalog")).invokeWithArguments(ModuleLayer.boot(), null);
+
+ // 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);
+ }
+ }))));
+ }
+
+ 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));
+
+ addExtra(exports, implAddExportsMH, implAddExportsToAllUnnamedMH);
+ }
+
+ 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));
+
+ addExtra(opens, implAddOpensMH, implAddOpensToAllUnnamedMH);
+ }
+
+ 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);
+ }
+ });
+ }
+ });
+ }
+
+ // <module>/<package>=<target>
+ private static ParserData parseModuleExtra(String extra) {
+ String[] all = extra.split("=", 2);
+ if (all.length < 2) {
+ return null;
+ }
+
+ String[] source = all[0].split("/", 2);
+ if (source.length < 2) {
+ return null;
+ }
+ return new ParserData(source[0], source[1], all[1]);
+ }
+
+ private static class ParserData {
+ final String module;
+ final String packages;
+ final String target;
+
+ ParserData(String module, String packages, String target) {
+ this.module = module;
+ this.packages = packages;
+ this.target = target;
+ }
+ }
+
+ // 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);
+ }
+ });
+ }
+}
diff --git a/legacy/build.gradle b/legacy/build.gradle
index 5036489352..8824390d0f 100644
--- a/legacy/build.gradle
+++ b/legacy/build.gradle
@@ -14,4 +14,4 @@ repositories {
dependencies {
compileOnly "net.minecraftforge:installer:2.0.24"
-} \ No newline at end of file
+}
diff --git a/settings.gradle b/settings.gradle
index c2cb153d92..2d5aa2f9e2 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,3 +1,5 @@
rootProject.name = 'ForgeWrapper'
-include 'legacy' \ No newline at end of file
+include 'converter'
+include 'jigsaw'
+include 'legacy'
diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Bootstrap.java b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Bootstrap.java
new file mode 100644
index 0000000000..98e8dda209
--- /dev/null
+++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Bootstrap.java
@@ -0,0 +1,78 @@
+package io.github.zekerzhayard.forgewrapper.installer;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Stream;
+
+import io.github.zekerzhayard.forgewrapper.installer.util.ModuleUtil;
+
+public class Bootstrap {
+ public static void bootstrap(List<String> jvmArgs, String minecraftJar, String libraryDir) throws Throwable {
+ // Replace all placeholders
+ List<String> replacedJvmArgs = new ArrayList<>();
+ for (String arg : jvmArgs) {
+ replacedJvmArgs.add(arg.replace("${classpath}", System.getProperty("java.class.path").replace(File.separator, "/")).replace("${classpath_separator}", File.pathSeparator).replace("${library_directory}", libraryDir));
+ }
+ jvmArgs = replacedJvmArgs;
+
+ String modulePath = null;
+ List<String> addExports = new ArrayList<>();
+ List<String> addOpens = new ArrayList<>();
+ for (int i = 0; i < jvmArgs.size(); i++) {
+ String arg = jvmArgs.get(i);
+
+ if (arg.equals("-p") || arg.equals("--module-path")) {
+ modulePath = jvmArgs.get(i + 1);
+ } else if (arg.startsWith("--module-path=")) {
+ modulePath = arg.split("=", 2)[1];
+ }
+
+ if (arg.equals("--add-exports")) {
+ addExports.add(jvmArgs.get(i + 1));
+ } else if (arg.startsWith("--add-exports=")) {
+ addExports.add(arg.split("=", 2)[1]);
+ }
+
+ if (arg.equals("--add-opens")) {
+ addOpens.add(jvmArgs.get(i + 1));
+ } else if (arg.startsWith("--add-opens=")) {
+ addOpens.add(arg.split("=", 2)[1]);
+ }
+
+ // Java properties
+ if (arg.startsWith("-D")) {
+ String[] prop = arg.substring(2).split("=", 2);
+
+ if (prop[0].equals("ignoreList")) {
+ // The default ignoreList is too broad and may cause some problems, so we define it more precisely.
+ String[] ignores = (prop[1] + ",NewLaunch.jar,ForgeWrapper-," + minecraftJar).split(",");
+ List<String> ignoreList = new ArrayList<>();
+ for (String classPathName : System.getProperty("java.class.path").replace(File.separator, "/").split(File.pathSeparator)) {
+ Path classPath = Paths.get(classPathName);
+ String fileName = classPath.getFileName().toString();
+ if (Stream.of(ignores).anyMatch(fileName::contains)) {
+ String absolutePath = classPath.toAbsolutePath().toString();
+ if (absolutePath.contains(",")) {
+ absolutePath = absolutePath.substring(absolutePath.lastIndexOf(","));
+ }
+ ignoreList.add(absolutePath.replace(File.separator, "/"));
+ }
+ }
+ System.setProperty(prop[0], String.join(",", ignoreList));
+ } else {
+ System.setProperty(prop[0], prop[1]);
+ }
+ }
+ }
+
+ if (modulePath != null) {
+ ModuleUtil.addModules(modulePath);
+ }
+ ModuleUtil.addExports(addExports);
+ ModuleUtil.addOpens(addOpens);
+ ModuleUtil.setupBootstrapLauncher();
+ }
+}
diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java
index 78c2d5880c..99ead7cf31 100644
--- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java
+++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java
@@ -5,6 +5,7 @@ import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Path;
import java.util.List;
+import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -13,13 +14,14 @@ import io.github.zekerzhayard.forgewrapper.installer.detector.DetectorLoader;
import io.github.zekerzhayard.forgewrapper.installer.detector.IFileDetector;
public class Main {
- public static void main(String[] args) throws Exception {
+ public static void main(String[] args) throws Throwable {
List<String> argsList = Stream.of(args).collect(Collectors.toList());
String mcVersion = argsList.get(argsList.indexOf("--fml.mcVersion") + 1);
String forgeVersion = argsList.get(argsList.indexOf("--fml.forgeVersion") + 1);
String forgeFullVersion = mcVersion + "-" + forgeVersion;
IFileDetector detector = DetectorLoader.loadDetector();
+ Bootstrap.bootstrap(detector.getJvmArgs(forgeFullVersion), detector.getMinecraftJar(mcVersion).getFileName().toString(), detector.getLibraryDir().toAbsolutePath().toString());
if (!detector.checkExtraFiles(forgeFullVersion)) {
System.out.println("Some extra libraries are missing! Run the installer to generate them now.");
@@ -47,7 +49,7 @@ public class Main {
}
}
- Launcher.main(args); // TODO: this will be broken in forge 1.17
+ Class.forName(detector.getMainClass(forgeFullVersion)).getMethod("main", String[].class).invoke(null, new Object[] { args });
}
// https://github.com/MinecraftForge/Installer/blob/fe18a164b5ebb15b5f8f33f6a149cc224f446dc2/src/main/java/net/minecraftforge/installer/actions/PostProcessors.java#L287-L303
diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/MainV2.java b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/MainV2.java
deleted file mode 100644
index 230d9fbe28..0000000000
--- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/MainV2.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package io.github.zekerzhayard.forgewrapper.installer;
-
-import java.util.function.Consumer;
-
-// to support forge 1.17 (bootstraplauncher)
-public class MainV2 implements Consumer<String[]> {
- @Override
- public void accept(String[] args) {
- try {
- Main.main(args);
- } catch (Throwable t) {
- throw new RuntimeException(t);
- }
- }
-}
diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/detector/IFileDetector.java b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/detector/IFileDetector.java
index b81670840b..2f8c976985 100644
--- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/detector/IFileDetector.java
+++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/detector/IFileDetector.java
@@ -12,10 +12,15 @@ import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
+import java.util.AbstractMap;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
+import java.util.function.Function;
+import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
@@ -83,30 +88,53 @@ public interface IFileDetector {
/**
* @param forgeFullVersion Forge full version (e.g. 1.14.4-28.2.0).
+ * @return The list of jvm args.
+ */
+ default List<String> getJvmArgs(String forgeFullVersion) {
+ return this.getDataFromInstaller(forgeFullVersion, "version.json", e -> {
+ JsonElement element = getElement(e.getAsJsonObject().getAsJsonObject("arguments"), "jvm");
+ List<String> args = new ArrayList<>();
+ if (!element.equals(JsonNull.INSTANCE)) {
+ element.getAsJsonArray().iterator().forEachRemaining(je -> args.add(je.getAsString()));
+ }
+ return args;
+ });
+ }
+
+ /**
+ * @param forgeFullVersion Forge full version (e.g. 1.14.4-28.2.0).
+ * @return The main class.
+ */
+ default String getMainClass(String forgeFullVersion) {
+ return this.getDataFromInstaller(forgeFullVersion, "version.json", e -> e.getAsJsonObject().getAsJsonPrimitive("mainClass").getAsString());
+ }
+
+ /**
+ * @param forgeFullVersion Forge full version (e.g. 1.14.4-28.2.0).
* @return The json object in the-installer-jar-->install_profile.json-->data-->xxx-->client.
*/
default JsonObject getInstallProfileExtraData(String forgeFullVersion) {
+ return this.getDataFromInstaller(forgeFullVersion, "install_profile.json", e -> e.getAsJsonObject().getAsJsonObject("data"));
+ }
+
+ default <R> R getDataFromInstaller(String forgeFullVersion, String entry, Function<JsonElement, R> function) {
Path installer = this.getInstallerJar(forgeFullVersion);
if (isFile(installer)) {
try (ZipFile zf = new ZipFile(installer.toFile())) {
- ZipEntry ze = zf.getEntry("install_profile.json");
+ ZipEntry ze = zf.getEntry(entry);
if (ze != null) {
try (
InputStream is = zf.getInputStream(ze);
InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8)
) {
- for (Map.Entry<String, JsonElement> entry : new JsonParser().parse(isr).getAsJsonObject().entrySet()) {
- if (entry.getKey().equals("data")) {
- return entry.getValue().getAsJsonObject();
- }
- }
+ return function.apply(new JsonParser().parse(isr));
}
}
} catch (IOException e) {
e.printStackTrace();
}
} else {
- throw new RuntimeException("Can't detect the forge installer!");
+ throw new RuntimeException("Unable to detect the forge installer!");
}
return null;
}
@@ -123,6 +151,7 @@ public interface IFileDetector {
Map<String, String> hashMap = new HashMap<>();
// Get all "data/<name>/client" elements.
+ Pattern artifactPattern = Pattern.compile("^\\[(?<groupId>[^:]*):(?<artifactId>[^:]*):(?<version>[^:@]*)(:(?<prefix>[^@]*))?(@(?<type>[^]]*))?]$");
for (Map.Entry<String, JsonElement> entry : jo.entrySet()) {
String clientStr = getElement(entry.getValue().getAsJsonObject(), "client").getAsString();
if (entry.getKey().endsWith("_SHA")) {
@@ -132,8 +161,7 @@ public interface IFileDetector {
hashMap.put(entry.getKey(), m.group("sha1"));
}
} else {
- Pattern p = Pattern.compile("^\\[(?<groupId>[^:]*):(?<artifactId>[^:]*):(?<version>[^:@]*)(:(?<prefix>[^@]*))?(@(?<type>[^]]*))?]$");
- Matcher m = p.matcher(clientStr);
+ Matcher m = artifactPattern.matcher(clientStr);
if (m.find()) {
String groupId = nullToDefault(m.group("groupId"), "");
String artifactId = nullToDefault(m.group("artifactId"), "");
@@ -152,7 +180,11 @@ public interface IFileDetector {
// Check all cached libraries.
boolean checked = true;
for (Map.Entry<String, Path> entry : libsMap.entrySet()) {
- checked = checked && this.checkExtraFile(entry.getValue(), hashMap.get(entry.getKey() + "_SHA"));
+ checked = this.checkExtraFile(entry.getValue(), hashMap.get(entry.getKey() + "_SHA"));
+ if (!checked) {
+ System.out.println("Missing: " + entry.getValue());
+ break;
+ }
}
return checked;
}
diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/ModuleUtil.java b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/ModuleUtil.java
new file mode 100644
index 0000000000..0b37945822
--- /dev/null
+++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/ModuleUtil.java
@@ -0,0 +1,21 @@
+package io.github.zekerzhayard.forgewrapper.installer.util;
+
+import java.util.List;
+
+public class ModuleUtil {
+ public static void addModules(String modulePath) {
+ // nothing to do with Java 8
+ }
+
+ public static void addExports(List<String> exports) {
+ // nothing to do with Java 8
+ }
+
+ public static void addOpens(List<String> opens) {
+ // nothing to do with Java 8
+ }
+
+ public static void setupBootstrapLauncher() {
+ // nothing to do with Java 8
+ }
+}
diff --git a/src/main/resources/META-INF/services/io.github.zekerzhayard.forgewrapper.installer.detector.IFileDetector b/src/main/resources/META-INF/services/io.github.zekerzhayard.forgewrapper.installer.detector.IFileDetector
index 44375f8732..31f2c4e711 100644
--- a/src/main/resources/META-INF/services/io.github.zekerzhayard.forgewrapper.installer.detector.IFileDetector
+++ b/src/main/resources/META-INF/services/io.github.zekerzhayard.forgewrapper.installer.detector.IFileDetector
@@ -1 +1 @@
-io.github.zekerzhayard.forgewrapper.installer.detector.MultiMCFileDetector \ No newline at end of file
+io.github.zekerzhayard.forgewrapper.installer.detector.MultiMCFileDetector
diff --git a/src/main/resources/META-INF/services/java.util.function.Consumer b/src/main/resources/META-INF/services/java.util.function.Consumer
deleted file mode 100644
index 64cc969425..0000000000
--- a/src/main/resources/META-INF/services/java.util.function.Consumer
+++ /dev/null
@@ -1 +0,0 @@
-io.github.zekerzhayard.forgewrapper.installer.MainV2 \ No newline at end of file