diff --git a/converter/build.gradle b/converter/build.gradle deleted file mode 100644 index a3661b7..0000000 --- a/converter/build.gradle +++ /dev/null @@ -1,54 +0,0 @@ - -plugins { - id "java" - id "eclipse" -} - -version = "${rootProject.fw_version}${-> getVersionSuffix()}" -group = "io.github.zekerzhayard" -archivesBaseName = rootProject.name + "Converter" - -sourceCompatibility = targetCompatibility = 1.8 -compileJava { - sourceCompatibility = targetCompatibility = 1.8 -} - -configurations { - provided { - implementation.extendsFrom provided - } -} - -repositories { - mavenCentral() -} - -dependencies { - compileOnly "com.google.code.gson:gson:2.8.7" - provided rootProject -} - -jar { - manifest.attributes rootProject.jar.manifest.attributes - manifest.attributes([ - "Main-Class": "io.github.zekerzhayard.forgewrapper.converter.Main" - ]) - - from configurations.provided.files.collect { - duplicatesStrategy = DuplicatesStrategy.EXCLUDE - 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/converter/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java b/converter/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java deleted file mode 100644 index ade550f..0000000 --- a/converter/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java +++ /dev/null @@ -1,157 +0,0 @@ -package io.github.zekerzhayard.forgewrapper.converter; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; - -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonNull; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; - -public class Converter { - public static void convert(Path installerPath, Path targetDir, Path multimcDir) throws Exception { - JsonObject installer = getJsonFromZip(installerPath, "version.json"); - JsonObject installProfile = getJsonFromZip(installerPath, "install_profile.json"); - List arguments = getAdditionalArgs(installer); - String mcVersion = arguments.get(arguments.indexOf("--fml.mcVersion") + 1); - String forgeVersion = arguments.get(arguments.indexOf("--fml.forgeVersion") + 1); - String forgeFullVersion = "forge-" + mcVersion + "-" + forgeVersion; - StringBuilder wrapperVersion = new StringBuilder(); - - JsonObject pack = convertPackJson(mcVersion); - JsonObject patches = convertPatchesJson(installer, installProfile, mcVersion, forgeVersion, wrapperVersion); - - Files.createDirectories(targetDir); - - // Copy mmc-pack.json and instance.cfg to folder. - Path instancePath = targetDir.resolve(forgeFullVersion); - Files.createDirectories(instancePath); - Files.copy(new ByteArrayInputStream(pack.toString().getBytes(StandardCharsets.UTF_8)), instancePath.resolve("mmc-pack.json"), StandardCopyOption.REPLACE_EXISTING); - Files.copy(new ByteArrayInputStream(("InstanceType=OneSix\nname=" + forgeFullVersion).getBytes(StandardCharsets.UTF_8)), instancePath.resolve("instance.cfg"), StandardCopyOption.REPLACE_EXISTING); - - // Copy ForgeWrapper to /libraries folder. - Path librariesPath = instancePath.resolve("libraries"); - Files.createDirectories(librariesPath); - Files.copy(Paths.get(Converter.class.getProtectionDomain().getCodeSource().getLocation().toURI()), librariesPath.resolve(wrapperVersion.toString()), StandardCopyOption.REPLACE_EXISTING); - - // Copy net.minecraftforge.json to /patches folder. - Path patchesPath = instancePath.resolve("patches"); - Files.createDirectories(patchesPath); - Files.copy(new ByteArrayInputStream(patches.toString().getBytes(StandardCharsets.UTF_8)), patchesPath.resolve("net.minecraftforge.json"), StandardCopyOption.REPLACE_EXISTING); - - // Copy forge installer to MultiMC/libraries/net/minecraftforge/forge/- folder. - if (multimcDir != null) { - Path targetInstallerPath = multimcDir.resolve("libraries").resolve("net").resolve("minecraftforge").resolve("forge").resolve(forgeVersion); - Files.createDirectories(targetInstallerPath); - Files.copy(installerPath, targetInstallerPath.resolve(forgeFullVersion + "-installer.jar"), StandardCopyOption.REPLACE_EXISTING); - } - } - - public static List getAdditionalArgs(JsonObject installer) { - List args = new ArrayList<>(); - getElement(installer.getAsJsonObject("arguments"), "game").getAsJsonArray().iterator().forEachRemaining(je -> args.add(je.getAsString())); - return args; - } - - public static JsonObject getJsonFromZip(Path path, String json) { - try { - ZipFile zf = new ZipFile(path.toFile()); - ZipEntry versionFile = zf.getEntry(json); - if (versionFile == null) { - throw new RuntimeException("The zip file is invalid!"); - } - InputStreamReader isr = new InputStreamReader(zf.getInputStream(versionFile), StandardCharsets.UTF_8); - return JsonParser.parseReader(isr).getAsJsonObject(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - // Convert mmc-pack.json: - // - Replace Minecraft version - private static JsonObject convertPackJson(String mcVersion) { - JsonObject pack = JsonParser.parseReader(new InputStreamReader(Converter.class.getResourceAsStream("/mmc-pack.json"))).getAsJsonObject(); - - for (JsonElement component : getElement(pack, "components").getAsJsonArray()) { - JsonObject componentObject = component.getAsJsonObject(); - JsonElement version = getElement(componentObject, "version"); - if (!version.isJsonNull() && getElement(componentObject, "uid").getAsString().equals("net.minecraft")) { - componentObject.addProperty("version", mcVersion); - } - } - return pack; - } - - // Convert patches/net.minecraftforge.json: - // - Add libraries - // - Add forge-launcher url - // - Replace Minecraft & Forge versions - private static JsonObject convertPatchesJson(JsonObject installer, JsonObject installProfile, String mcVersion, String forgeVersion, StringBuilder wrapperVersion) { - JsonObject patches = JsonParser.parseReader(new InputStreamReader(Converter.class.getResourceAsStream("/patches/net.minecraftforge.json"))).getAsJsonObject(); - JsonArray mavenFiles = getElement(patches, "mavenFiles").getAsJsonArray(); - JsonArray libraries = getElement(patches, "libraries").getAsJsonArray(); - - String minecraftArguments = String.join(" ", getElement(patches, "minecraftArguments").getAsString(), "--username ${auth_player_name} --version ${version_name} --gameDir ${game_directory} --assetsDir ${assets_root} --assetIndex ${assets_index_name} --uuid ${auth_uuid} --accessToken ${auth_access_token} --userType ${user_type} --versionType ${version_type}", String.join(" ", getAdditionalArgs(installer))).trim(); - patches.addProperty("minecraftArguments", minecraftArguments); - - for (JsonElement mavenFile : mavenFiles) { - String name = getElement(mavenFile.getAsJsonObject(), "name").getAsString(); - mavenFile.getAsJsonObject().addProperty("name", name.replace("{VERSION}", mcVersion).replace("{FORGE_VERSION}", forgeVersion)); - } - for (JsonElement lib : libraries) { - String name = getElement(lib.getAsJsonObject(), "name").getAsString(); - if (name.startsWith("io.github.zekerzhayard:ForgeWrapper:")) { - wrapperVersion.append(getElement(lib.getAsJsonObject(), "MMC-filename").getAsString()); - } - } - Map 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://maven.minecraftforge.net/" + path + "-universal.jar"); - transformLibraries(getElement(installProfile, "libraries").getAsJsonArray(), mavenFiles, additionalUrls); - additionalUrls.clear(); - 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()) { - JsonObject requireObject = require.getAsJsonObject(); - if (getElement(requireObject, "uid").getAsString().equals("net.minecraft")) { - requireObject.addProperty("equals", mcVersion); - } - } - return patches; - } - - private static JsonElement getElement(JsonObject object, String property) { - Optional> first = object.entrySet().stream().filter(e -> e.getKey().equals(property)).findFirst(); - if (first.isPresent()) { - return first.get().getValue(); - } - return JsonNull.INSTANCE; - } - - private static void transformLibraries(JsonArray source, JsonArray target, Map additionalUrls) { - for (JsonElement lib : source) { - JsonObject artifact = getElement(getElement(lib.getAsJsonObject(), "downloads").getAsJsonObject(), "artifact").getAsJsonObject(); - String path = getElement(artifact, "path").getAsString(); - if (additionalUrls.containsKey(path)) { - artifact.getAsJsonObject().addProperty("url", additionalUrls.get(path)); - } - target.add(lib); - } - } -} diff --git a/converter/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Main.java b/converter/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Main.java deleted file mode 100644 index 83ecdf9..0000000 --- a/converter/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Main.java +++ /dev/null @@ -1,53 +0,0 @@ -package io.github.zekerzhayard.forgewrapper.converter; - -import java.net.URL; -import java.net.URLClassLoader; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.HashMap; - -public class Main { - public static void main(String[] args) { - Path installer = null, instance = Paths.get("."), multimc = null; - try { - HashMap argsMap = parseArgs(args); - installer = Paths.get(argsMap.get("--installer")); - if (argsMap.containsKey("--instance")) { - instance = Paths.get(argsMap.get("--instance")); - multimc = instance.getParent(); - } - } catch (Exception e) { - System.out.println("Invalid arguments! Use: java -jar --installer= [--instance=]"); - throw new RuntimeException(e); - } - - try { - URLClassLoader ucl = URLClassLoader.newInstance(new URL[] { - Converter.class.getProtectionDomain().getCodeSource().getLocation(), - installer.toUri().toURL() - }, null); - ucl.loadClass("io.github.zekerzhayard.forgewrapper.converter.Converter").getMethod("convert", Path.class, Path.class, Path.class).invoke(null, installer, instance, multimc); - System.out.println("Successfully install Forge for MultiMC!"); - } catch (Exception e) { - System.out.println("Failed to install Forge!"); - throw new RuntimeException(e); - } - } - - /** - * @return installer -- The path of forge installer.
- * instance -- The instance folder of MultiMC.
- * cursepack -- The version of cursepacklocator.
- */ - private static HashMap parseArgs(String[] args) { - HashMap map = new HashMap<>(); - for (String arg : args) { - String[] params = arg.split("=", 2); - map.put(params[0], params[1]); - } - if (!map.containsKey("--installer")) { - throw new IllegalArgumentException(); - } - return map; - } -} diff --git a/converter/src/main/resources/mmc-pack.json b/converter/src/main/resources/mmc-pack.json deleted file mode 100644 index 87db08a..0000000 --- a/converter/src/main/resources/mmc-pack.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "formatVersion": 1, - "components": [ - { - "important": true, - "uid": "net.minecraft", - "version": "{VERSION}" - }, - { - "uid": "net.minecraftforge" - } - ] -} diff --git a/converter/src/main/resources/patches/net.minecraftforge.json b/converter/src/main/resources/patches/net.minecraftforge.json deleted file mode 100644 index 4fac6aa..0000000 --- a/converter/src/main/resources/patches/net.minecraftforge.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "formatVersion": 1, - "mainClass": "io.github.zekerzhayard.forgewrapper.installer.Main", - "minecraftArguments": "", - "name": "Forge", - "requires": [ - { - "equals": "{VERSION}", - "uid": "net.minecraft" - } - ], - "type": "release", - "uid": "net.minecraftforge", - "version": "{FORGE_VERSION}", - "mavenFiles": [ - { - "name": "net.minecraftforge:forge:{VERSION}-{FORGE_VERSION}:installer", - "url": "https://maven.minecraftforge.net/" - } - ], - "libraries": [ - { - "name": "io.github.zekerzhayard:ForgeWrapper:${version}", - "MMC-hint": "local", - "MMC-filename": "ForgeWrapper-${version}.jar" - } - ] -} diff --git a/gradle.properties b/gradle.properties index 677a8cd..6202251 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.daemon = false -fw_version = mmc3 +fw_version = mmc4 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 index 9a49d7f..e15d39c 100644 --- 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 @@ -9,6 +9,7 @@ import java.lang.module.ModuleFinder; import java.lang.module.ModuleReference; import java.lang.module.ResolvedModule; import java.lang.reflect.Field; +import java.net.URL; import java.nio.file.Path; import java.nio.file.Paths; import java.util.HashMap; @@ -159,6 +160,15 @@ public class ModuleUtil { } } + public static void setupClassPath(Path libraryDir, List paths) throws Throwable { + Class urlClassPathClass = Class.forName("jdk.internal.loader.URLClassPath"); + Object ucp = IMPL_LOOKUP.findGetter(Class.forName("jdk.internal.loader.BuiltinClassLoader"), "ucp", urlClassPathClass).invokeWithArguments(ClassLoader.getSystemClassLoader()); + MethodHandle addURLMH = IMPL_LOOKUP.findVirtual(urlClassPathClass, "addURL", MethodType.methodType(void.class, URL.class)); + for (String path : paths) { + addURLMH.invokeWithArguments(ucp, libraryDir.resolve(path).toUri().toURL()); + } + } + // ForgeWrapper need some extra settings to invoke BootstrapLauncher. public static Class setupBootstrapLauncher(Class mainClass) throws Throwable { if (!mainClass.getModule().isOpen(mainClass.getPackageName(), ModuleUtil.class.getModule())) { diff --git a/legacy/build.gradle b/legacy/build.gradle index 8824390..4778335 100644 --- a/legacy/build.gradle +++ b/legacy/build.gradle @@ -4,6 +4,11 @@ plugins { id "eclipse" } +sourceCompatibility = targetCompatibility = 1.8 +compileJava { + sourceCompatibility = targetCompatibility = 1.8 +} + repositories { mavenCentral() maven { diff --git a/settings.gradle b/settings.gradle index 7bda9a2..34c563d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,6 +1,5 @@ rootProject.name = 'ForgeWrapper' include 'common' -include 'converter' include 'legacy' include 'jigsaw' diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Bootstrap.java b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Bootstrap.java index 2740b76..3604371 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Bootstrap.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Bootstrap.java @@ -15,6 +15,15 @@ public class Bootstrap { } jvmArgs = replacedJvmArgs; + // Remove NewLaunch.jar from property to prevent Forge from adding it to the module path + StringBuilder newCP = new StringBuilder(); + for (String path : System.getProperty("java.class.path").split(File.pathSeparator)) { + if (!path.endsWith("NewLaunch.jar")) { + newCP.append(path).append(File.pathSeparator); + } + } + System.setProperty("java.class.path", newCP.substring(0, newCP.length() - 1)); + String modulePath = null; List addExports = new ArrayList<>(); List addOpens = new ArrayList<>(); 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 7134ba5..37876a6 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java @@ -15,22 +15,31 @@ import io.github.zekerzhayard.forgewrapper.installer.util.ModuleUtil; public class Main { public static void main(String[] args) throws Throwable { + // --fml.neoForgeVersion 20.2.20-beta --fml.fmlVersion 1.0.2 --fml.mcVersion 1.20.2 --fml.neoFormVersion 20231019.002635 --launchTarget forgeclient + List argsList = Stream.of(args).collect(Collectors.toList()); + // NOTE: this is only true for NeoForge versions past 20.2.x + // early versions of NeoForge (for 1.20.1) are not supposed to be covered here + boolean isNeoForge = argsList.contains("--fml.neoForgeVersion"); + String mcVersion = argsList.get(argsList.indexOf("--fml.mcVersion") + 1); - String forgeVersion = argsList.get(argsList.indexOf("--fml.forgeVersion") + 1); - String forgeFullVersion = mcVersion + "-" + forgeVersion; + String forgeGroup = argsList.contains("--fml.forgeGroup") ? argsList.get(argsList.indexOf("--fml.forgeGroup") + 1) : "net.neoforged"; + String forgeArtifact = isNeoForge ? "neoforge" : "forge"; + String forgeVersionKey = isNeoForge ? "--fml.neoForgeVersion" : "--fml.forgeVersion"; + String forgeVersion = argsList.get(argsList.indexOf(forgeVersionKey) + 1); + String forgeFullVersion = isNeoForge ? forgeVersion : mcVersion + "-" + forgeVersion; IFileDetector detector = DetectorLoader.loadDetector(); try { - Bootstrap.bootstrap(detector.getJvmArgs(forgeFullVersion), detector.getMinecraftJar(mcVersion).getFileName().toString(), detector.getLibraryDir().toAbsolutePath().toString()); + Bootstrap.bootstrap(detector.getJvmArgs(forgeGroup, forgeArtifact, forgeFullVersion), detector.getMinecraftJar(mcVersion).getFileName().toString(), detector.getLibraryDir().toAbsolutePath().toString()); } catch (Throwable ignored) { // Avoid this bunch of hacks that nuke the whole wrapper. } - if (!detector.checkExtraFiles(forgeFullVersion)) { + if (!detector.checkExtraFiles(forgeGroup, forgeArtifact, forgeFullVersion)) { System.out.println("Some extra libraries are missing! Running the installer to generate them now."); // Check installer jar. - Path installerJar = detector.getInstallerJar(forgeFullVersion); + Path installerJar = detector.getInstallerJar(forgeGroup, forgeArtifact, forgeFullVersion); if (!IFileDetector.isFile(installerJar)) { throw new RuntimeException("Unable to detect the forge installer!"); } @@ -53,7 +62,8 @@ public class Main { } } - Class mainClass = ModuleUtil.setupBootstrapLauncher(Class.forName(detector.getMainClass(forgeFullVersion))); + ModuleUtil.setupClassPath(detector.getLibraryDir(), detector.getExtraLibraries(forgeGroup, forgeArtifact, forgeFullVersion)); + Class mainClass = ModuleUtil.setupBootstrapLauncher(Class.forName(detector.getMainClass(forgeGroup, forgeArtifact, forgeFullVersion))); mainClass.getMethod("main", String[].class).invoke(null, new Object[] { args }); } } 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 cfb926e..c10a796 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 @@ -61,10 +61,12 @@ public interface IFileDetector { } /** + * @param forgeGroup Forge package group (e.g. net.minecraftforge). + * @param forgeArtifact Forge package artifact (e.g. forge). * @param forgeFullVersion Forge full version (e.g. 1.14.4-28.2.0). * @return The forge installer jar path. It can also be defined by JVM argument "-Dforgewrapper.installer=<installer-path>". */ - default Path getInstallerJar(String forgeFullVersion) { + default Path getInstallerJar(String forgeGroup, String forgeArtifact, String forgeFullVersion) { String installer = System.getProperty("forgewrapper.installer"); if (installer != null) { return Paths.get(installer).toAbsolutePath(); @@ -85,12 +87,14 @@ public interface IFileDetector { } /** + * @param forgeGroup Forge package group (e.g. net.minecraftforge). + * @param forgeArtifact Forge package artifact (e.g. forge). * @param forgeFullVersion Forge full version (e.g. 1.14.4-28.2.0). * @return The list of jvm args. */ - default List getJvmArgs(String forgeFullVersion) { - return this.getDataFromInstaller(forgeFullVersion, "version.json", e -> { - JsonElement element = getElement(e.getAsJsonObject().getAsJsonObject("arguments"), "jvm"); + default List getJvmArgs(String forgeGroup, String forgeArtifact, String forgeFullVersion) { + return this.getDataFromInstaller(forgeGroup, forgeArtifact, forgeFullVersion, "version.json", e -> { + JsonElement element = e.getAsJsonObject().get("arguments").getAsJsonObject().get("jvm"); List args = new ArrayList<>(); if (!element.equals(JsonNull.INSTANCE)) { element.getAsJsonArray().iterator().forEachRemaining(je -> args.add(je.getAsString())); @@ -99,25 +103,42 @@ public interface IFileDetector { }); } + default List getExtraLibraries(String forgeGroup, String forgeArtifact, String forgeFullVersion) { + return this.getDataFromInstaller(forgeGroup, forgeArtifact, forgeFullVersion, "version.json", e -> { + List paths = new ArrayList<>(); + e.getAsJsonObject().getAsJsonArray("libraries").iterator().forEachRemaining(je -> { + JsonObject artifact = je.getAsJsonObject().get("downloads").getAsJsonObject().get("artifact").getAsJsonObject(); + if (artifact.get("url").getAsString().isEmpty()) { + paths.add(artifact.get("path").getAsString()); + } + }); + return paths; + }); + } + /** + * @param forgeGroup Forge package group (e.g. net.minecraftforge). + * @param forgeArtifact Forge package artifact (e.g. forge). * @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()); + default String getMainClass(String forgeGroup, String forgeArtifact, String forgeFullVersion) { + return this.getDataFromInstaller(forgeGroup, forgeArtifact, forgeFullVersion, "version.json", e -> e.getAsJsonObject().getAsJsonPrimitive("mainClass").getAsString()); } /** + * @param forgeGroup Forge package group (e.g. net.minecraftforge). + * @param forgeArtifact Forge package artifact (e.g. forge). * @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 JsonObject getInstallProfileExtraData(String forgeGroup, String forgeArtifact, String forgeFullVersion) { + return this.getDataFromInstaller(forgeGroup, forgeArtifact, forgeFullVersion, "install_profile.json", e -> e.getAsJsonObject().getAsJsonObject("data")); } @SuppressWarnings("deprecation") - default R getDataFromInstaller(String forgeFullVersion, String entry, Function function) { - Path installer = this.getInstallerJar(forgeFullVersion); + default R getDataFromInstaller(String forgeGroup, String forgeArtifact, String forgeFullVersion, String entry, Function function) { + Path installer = this.getInstallerJar(forgeGroup, forgeArtifact, forgeFullVersion); if (isFile(installer)) { try (ZipFile zf = new ZipFile(installer.toFile())) { ZipEntry ze = zf.getEntry(entry); @@ -140,11 +161,13 @@ public interface IFileDetector { /** * Check all cached files. + * @param forgeGroup Forge package group (e.g. net.minecraftforge). + * @param forgeArtifact Forge package artifact (e.g. forge). * @param forgeFullVersion Forge full version (e.g. 1.14.4-28.2.0). * @return True represents all files are ready. */ - default boolean checkExtraFiles(String forgeFullVersion) { - JsonObject jo = this.getInstallProfileExtraData(forgeFullVersion); + default boolean checkExtraFiles(String forgeGroup, String forgeArtifact, String forgeFullVersion) { + JsonObject jo = this.getInstallProfileExtraData(forgeGroup, forgeArtifact, forgeFullVersion); if (jo != null) { Map libsMap = new HashMap<>(); Map hashMap = new HashMap<>(); @@ -152,7 +175,7 @@ public interface IFileDetector { // Get all "data//client" elements. Pattern artifactPattern = Pattern.compile("^\\[(?[^:]*):(?[^:]*):(?[^:@]*)(:(?[^@]*))?(@(?[^]]*))?]$"); for (Map.Entry entry : jo.entrySet()) { - String clientStr = getElement(entry.getValue().getAsJsonObject(), "client").getAsString(); + String clientStr = entry.getValue().getAsJsonObject().get("client").getAsString(); if (entry.getKey().endsWith("_SHA")) { Pattern p = Pattern.compile("^'(?[A-Za-z0-9]{40})'$"); Matcher m = p.matcher(clientStr); @@ -171,7 +194,7 @@ public interface IFileDetector { .resolve(groupId.replace('.', File.separatorChar)) .resolve(artifactId) .resolve(version) - .resolve(artifactId + "-" + version + (classifier.equals("") ? "" : "-") + classifier + "." + type).toAbsolutePath()); + .resolve(artifactId + "-" + version + (classifier.isEmpty() ? "" : "-") + classifier + "." + type).toAbsolutePath()); } } } @@ -225,14 +248,6 @@ public interface IFileDetector { return path != null && Files.isRegularFile(path); } - static JsonElement getElement(JsonObject object, String property) { - Optional> first = object.entrySet().stream().filter(e -> e.getKey().equals(property)).findFirst(); - if (first.isPresent()) { - return first.get().getValue(); - } - return JsonNull.INSTANCE; - } - static String getFileSHA1(Path path) { try { StringBuilder sha1 = new StringBuilder(new BigInteger(1, MessageDigest.getInstance("SHA-1").digest(Files.readAllBytes(path))).toString(16)); diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/detector/MultiMCFileDetector.java b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/detector/MultiMCFileDetector.java index cb87d27..a1216f0 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/detector/MultiMCFileDetector.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/detector/MultiMCFileDetector.java @@ -27,10 +27,16 @@ public class MultiMCFileDetector implements IFileDetector { } @Override - public Path getInstallerJar(String forgeFullVersion) { - Path path = IFileDetector.super.getInstallerJar(forgeFullVersion); + public Path getInstallerJar(String forgeGroup, String forgeArtifact, String forgeFullVersion) { + Path path = IFileDetector.super.getInstallerJar(forgeGroup, forgeArtifact, forgeFullVersion); if (path == null) { - return this.installerJar != null ? this.installerJar : (this.installerJar = this.getLibraryDir().resolve("net").resolve("minecraftforge").resolve("forge").resolve(forgeFullVersion).resolve("forge-" + forgeFullVersion + "-installer.jar").toAbsolutePath()); + if (this.installerJar == null) { + Path installerBase = this.getLibraryDir(); + for (String dir : forgeGroup.split("\\.")) + installerBase = installerBase.resolve(dir); + this.installerJar = installerBase.resolve(forgeArtifact).resolve(forgeFullVersion).resolve(forgeArtifact + "-" + forgeFullVersion + "-installer.jar").toAbsolutePath(); + } + return this.installerJar; } return path; } 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 index c89d714..9eee574 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/ModuleUtil.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/ModuleUtil.java @@ -1,5 +1,10 @@ package io.github.zekerzhayard.forgewrapper.installer.util; +import java.io.File; +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Path; import java.util.List; public class ModuleUtil { @@ -15,6 +20,14 @@ public class ModuleUtil { // nothing to do with Java 8 } + public static void setupClassPath(Path libraryDir, List paths) throws Throwable { + Method addURLMethod = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); + addURLMethod.setAccessible(true); + for (String path : paths) { + addURLMethod.invoke(ClassLoader.getSystemClassLoader(), libraryDir.resolve(path).toUri().toURL()); + } + } + public static Class setupBootstrapLauncher(Class mainClass) { // nothing to do with Java 8 return mainClass;