Skip to content

Commit

Permalink
Full support the installation of forge-1.16.5-36.1.66+ and partial su…
Browse files Browse the repository at this point in the history
…pport forge-1.17.1
ZekerZhayard committed Jul 24, 2021
1 parent 3aeeada commit 5fb3f01
Showing 23 changed files with 458 additions and 82 deletions.
6 changes: 4 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -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
13 changes: 0 additions & 13 deletions .github/workflows/maven.bat

This file was deleted.

13 changes: 8 additions & 5 deletions .github/workflows/publication.yml
Original file line number Diff line number Diff line change
@@ -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/[email protected]
with:
branch: maven
folder: build/maven
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -12,4 +12,4 @@ bin
*.iml
*.ipr
*.iws
out
out
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -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>]
38 changes: 14 additions & 24 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -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,37 +55,20 @@ 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"))
])

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/**"
}
}

48 changes: 48 additions & 0 deletions converter/build.gradle
Original file line number Diff line number Diff line change
@@ -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"
}
}
Original file line number Diff line number Diff line change
@@ -120,11 +120,11 @@ private static JsonObject convertPatchesJson(JsonObject installer, JsonObject in
}
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()) {
Original file line number Diff line number Diff line change
@@ -10,4 +10,4 @@
"uid": "net.minecraftforge"
}
]
}
}
Original file line number Diff line number Diff line change
@@ -25,4 +25,4 @@
"MMC-filename": "ForgeWrapper-${version}.jar"
}
]
}
}
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
fw_version = 1.5.1
28 changes: 28 additions & 0 deletions jigsaw/build.gradle
Original file line number Diff line number Diff line change
@@ -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
}
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
});
}
}
2 changes: 1 addition & 1 deletion legacy/build.gradle
Original file line number Diff line number Diff line change
@@ -14,4 +14,4 @@ repositories {

dependencies {
compileOnly "net.minecraftforge:installer:2.0.24"
}
}
4 changes: 3 additions & 1 deletion settings.gradle
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
rootProject.name = 'ForgeWrapper'

include 'legacy'
include 'converter'
include 'jigsaw'
include 'legacy'
Original file line number Diff line number Diff line change
@@ -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();
}
}
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@
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.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 static void main(String[] args) throws Exception {
}
}

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

This file was deleted.

Original file line number Diff line number Diff line change
@@ -12,10 +12,15 @@
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;
@@ -81,32 +86,55 @@ default Path getMinecraftJar(String mcVersion) {
return null;
}

/**
* @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 @@ default boolean checkExtraFiles(String forgeFullVersion) {
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 @@ default boolean checkExtraFiles(String forgeFullVersion) {
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 @@ default boolean checkExtraFiles(String forgeFullVersion) {
// 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;
}
Original file line number Diff line number Diff line change
@@ -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
}
}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
io.github.zekerzhayard.forgewrapper.installer.detector.MultiMCFileDetector
io.github.zekerzhayard.forgewrapper.installer.detector.MultiMCFileDetector

This file was deleted.

0 comments on commit 5fb3f01

Please sign in to comment.