From 74323492fafdc30b9716cd0c15d633ee17b4e190 Mon Sep 17 00:00:00 2001 From: ZekerZhayard Date: Sat, 28 Dec 2019 03:23:07 +0800 Subject: first commit --- .gitignore | 3 + LICENSE | 21 +++ build.gradle | 48 ++++++ gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 56177 bytes gradle/wrapper/gradle-wrapper.properties | 5 + gradlew | 172 +++++++++++++++++++++ gradlew.bat | 84 ++++++++++ .../forgewrapper/ClientInstall4MultiMC.class | Bin 0 -> 2109 bytes .../zekerzhayard/forgewrapper/Installer$1.class | Bin 0 -> 1711 bytes .../zekerzhayard/forgewrapper/Installer.class | Bin 0 -> 3567 bytes .../io/github/zekerzhayard/forgewrapper/Main.class | Bin 0 -> 4903 bytes .../github/zekerzhayard/forgewrapper/Utils.class | Bin 0 -> 4195 bytes .../forgewrapper/installer/Download.class | Bin 0 -> 1283 bytes out/production/classes/tt.class | Bin 0 -> 908 bytes settings.gradle | 10 ++ .../io/github/zekerzhayard/forgewrapper/Main.java | 54 +++++++ .../io/github/zekerzhayard/forgewrapper/Utils.java | 41 +++++ .../installer/ClientInstall4MultiMC.java | 35 +++++ .../forgewrapper/installer/Download.java | 48 ++++++ .../forgewrapper/installer/Installer.java | 70 +++++++++ 20 files changed, 591 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 build.gradle create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat create mode 100644 out/production/classes/io/github/zekerzhayard/forgewrapper/ClientInstall4MultiMC.class create mode 100644 out/production/classes/io/github/zekerzhayard/forgewrapper/Installer$1.class create mode 100644 out/production/classes/io/github/zekerzhayard/forgewrapper/Installer.class create mode 100644 out/production/classes/io/github/zekerzhayard/forgewrapper/Main.class create mode 100644 out/production/classes/io/github/zekerzhayard/forgewrapper/Utils.class create mode 100644 out/production/classes/io/github/zekerzhayard/forgewrapper/installer/Download.class create mode 100644 out/production/classes/tt.class create mode 100644 settings.gradle create mode 100644 src/main/java/io/github/zekerzhayard/forgewrapper/Main.java create mode 100644 src/main/java/io/github/zekerzhayard/forgewrapper/Utils.java create mode 100644 src/main/java/io/github/zekerzhayard/forgewrapper/installer/ClientInstall4MultiMC.java create mode 100644 src/main/java/io/github/zekerzhayard/forgewrapper/installer/Download.java create mode 100644 src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..835e8dca81 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.gradle +.idea +build \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000..712ea35b1e --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) ZekerZhayard + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000000..44dc7b34b9 --- /dev/null +++ b/build.gradle @@ -0,0 +1,48 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * This is a general purpose Gradle build. + * Learn how to create Gradle builds at https://guides.gradle.org/creating-new-gradle-builds/ + */ + +buildscript { + repositories { + mavenCentral() + jcenter() + maven { + name = "forge" + url = "https://files.minecraftforge.net/maven" + } + } +} + +apply plugin: "base" +apply plugin: "java" +apply plugin: "idea" + +sourceCompatibility = targetCompatibility = 1.8 + +version = "1.0.0" +group = "io.github.zekerzhayard" +archivesBaseName = rootProject.name + +repositories { + mavenCentral() + jcenter() + maven { + name = "forge" + url = "https://files.minecraftforge.net/maven" + } +} + +dependencies { + compile "commons-codec:commons-codec:1.10" + compile "cpw.mods:modlauncher:5.0.0-milestone.4" + compile "net.minecraftforge:forge:1.15.1-30.0.16:installer" +} + +jar { + manifest.attributes( + "Main-Class": "io.github.zekerzhayard.forgewrapper.Main" + ) +} \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000..94336fcae9 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000..290541c738 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.3-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100644 index 0000000000..cccdd3d517 --- /dev/null +++ b/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000000..f9553162f1 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/out/production/classes/io/github/zekerzhayard/forgewrapper/ClientInstall4MultiMC.class b/out/production/classes/io/github/zekerzhayard/forgewrapper/ClientInstall4MultiMC.class new file mode 100644 index 0000000000..73d3ed00c1 Binary files /dev/null and b/out/production/classes/io/github/zekerzhayard/forgewrapper/ClientInstall4MultiMC.class differ diff --git a/out/production/classes/io/github/zekerzhayard/forgewrapper/Installer$1.class b/out/production/classes/io/github/zekerzhayard/forgewrapper/Installer$1.class new file mode 100644 index 0000000000..ca059e266a Binary files /dev/null and b/out/production/classes/io/github/zekerzhayard/forgewrapper/Installer$1.class differ diff --git a/out/production/classes/io/github/zekerzhayard/forgewrapper/Installer.class b/out/production/classes/io/github/zekerzhayard/forgewrapper/Installer.class new file mode 100644 index 0000000000..46a535c25c Binary files /dev/null and b/out/production/classes/io/github/zekerzhayard/forgewrapper/Installer.class differ diff --git a/out/production/classes/io/github/zekerzhayard/forgewrapper/Main.class b/out/production/classes/io/github/zekerzhayard/forgewrapper/Main.class new file mode 100644 index 0000000000..2819c894d2 Binary files /dev/null and b/out/production/classes/io/github/zekerzhayard/forgewrapper/Main.class differ diff --git a/out/production/classes/io/github/zekerzhayard/forgewrapper/Utils.class b/out/production/classes/io/github/zekerzhayard/forgewrapper/Utils.class new file mode 100644 index 0000000000..b10c2c30c7 Binary files /dev/null and b/out/production/classes/io/github/zekerzhayard/forgewrapper/Utils.class differ diff --git a/out/production/classes/io/github/zekerzhayard/forgewrapper/installer/Download.class b/out/production/classes/io/github/zekerzhayard/forgewrapper/installer/Download.class new file mode 100644 index 0000000000..def20077a1 Binary files /dev/null and b/out/production/classes/io/github/zekerzhayard/forgewrapper/installer/Download.class differ diff --git a/out/production/classes/tt.class b/out/production/classes/tt.class new file mode 100644 index 0000000000..084b41e2dd Binary files /dev/null and b/out/production/classes/tt.class differ diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000000..95689a11c3 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,10 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * The settings file is used to specify which projects to include in your build. + * + * Detailed information about configuring a multi-project build in Gradle can be found + * in the user guide at https://docs.gradle.org/4.10.3/userguide/multi_project_builds.html + */ + +rootProject.name = 'ForgeWrapper' diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/Main.java b/src/main/java/io/github/zekerzhayard/forgewrapper/Main.java new file mode 100644 index 0000000000..a07d467e83 --- /dev/null +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/Main.java @@ -0,0 +1,54 @@ +package io.github.zekerzhayard.forgewrapper; + +import java.io.File; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import cpw.mods.modlauncher.Launcher; +import io.github.zekerzhayard.forgewrapper.installer.Download; + +public class Main { + public static void main(String[] args) throws Exception { + URL[] urls = Utils.getURLs(new ArrayList<>()); + Pattern pattern = Pattern.compile("forge\\-(?[0-9\\.]+)\\-(?[0-9\\.]+)\\-launcher\\.jar"); + String version = ""; + for (URL url : urls) { + Matcher matcher = pattern.matcher(url.getFile()); + if (matcher.find() && url.getFile().endsWith(matcher.group(0))) { + version = matcher.group("mcVersion") + "-" + matcher.group("forgeVersion"); + String installerUrl = String.format("https://files.minecraftforge.net/maven/net/minecraftforge/forge/%s/forge-%s-installer.jar", version, version); + Download.download(installerUrl, String.format("./.forgewrapper/forge-%s-installer.jar", version)); + break; + } + } + + URLClassLoader ucl = URLClassLoader.newInstance(new URL[] { + Main.class.getProtectionDomain().getCodeSource().getLocation(), + new File(String.format("./.forgewrapper/forge-%s-installer.jar", version)).toURI().toURL() + }, null); + + Class installer = ucl.loadClass("io.github.zekerzhayard.forgewrapper.installer.Installer"); + if (!(boolean) installer.getMethod("install").invoke(null)) { + return; + } + List argsList = Stream.of(args).collect(Collectors.toList()); + argsList.add("--launchTarget"); + argsList.add("fmlclient"); + argsList.add("--fml.forgeVersion"); + argsList.add((String) installer.getMethod("getForgeVersion").invoke(null)); + argsList.add("--fml.mcVersion"); + argsList.add((String) installer.getMethod("getMcVersion").invoke(null)); + argsList.add("--fml.forgeGroup"); + argsList.add("net.minecraftforge"); + argsList.add("--fml.mcpVersion"); + argsList.add((String) installer.getMethod("getMcpVersion").invoke(null)); + + Launcher.main(argsList.toArray(new String[0])); + } +} diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/Utils.java b/src/main/java/io/github/zekerzhayard/forgewrapper/Utils.java new file mode 100644 index 0000000000..6c99888e02 --- /dev/null +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/Utils.java @@ -0,0 +1,41 @@ +package io.github.zekerzhayard.forgewrapper; + +import java.io.File; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class Utils { + public static URL[] getURLs(List blackList) { + ClassLoader cl = Utils.class.getClassLoader(); + List urls = new ArrayList<>(); + if (cl instanceof URLClassLoader) { + urls.addAll(Stream.of(((URLClassLoader) cl).getURLs()).filter(url -> blackList.stream().noneMatch(str -> url.getFile().endsWith(str))).collect(Collectors.toList())); + } else { + String[] elements = System.getProperty("java.class.path").split(File.pathSeparator); + + for (String ele : elements) { + try { + if (blackList.stream().noneMatch(ele::endsWith)) { + urls.add(new File(ele).toURI().toURL()); + } + } catch (MalformedURLException e) { + e.printStackTrace(); + } + } + } + return urls.toArray(new URL[0]); + } + + public static File getLibrariesDir() throws URISyntaxException { + File wrapper = new File(Utils.class.getProtectionDomain().getCodeSource().getLocation().toURI()); + // see https://github.com/MinecraftForge/MinecraftForge/blob/863ab2ca184cf2e2dfa134d07bfc20d6a9a6a4e8/src/main/java/net/minecraftforge/fml/relauncher/libraries/LibraryManager.java#L151 + // ForgeWrapper ZekerZhayard github com libraries + return wrapper.getParentFile().getParentFile().getParentFile().getParentFile().getParentFile().getParentFile(); + } +} diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/ClientInstall4MultiMC.java b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/ClientInstall4MultiMC.java new file mode 100644 index 0000000000..c87bfc4a6b --- /dev/null +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/ClientInstall4MultiMC.java @@ -0,0 +1,35 @@ +package io.github.zekerzhayard.forgewrapper.installer; + +import java.io.File; +import java.net.URISyntaxException; +import java.util.function.Predicate; + +import io.github.zekerzhayard.forgewrapper.Utils; +import net.minecraftforge.installer.actions.ActionCanceledException; +import net.minecraftforge.installer.actions.ClientInstall; +import net.minecraftforge.installer.actions.ProgressCallback; +import net.minecraftforge.installer.json.Install; + +public class ClientInstall4MultiMC extends ClientInstall { + public ClientInstall4MultiMC(Install profile, ProgressCallback monitor) { + super(profile, monitor); + } + + @Override + public boolean run(File target, Predicate optionals) throws ActionCanceledException { + try { + File librariesDir = Utils.getLibrariesDir(); + File clientTarget = new File(String.format("%s/com/mojang/minecraft/%s/minecraft-%s-client.jar", librariesDir.getAbsolutePath(), this.profile.getMinecraft(), this.profile.getMinecraft())); + + if (!this.downloadLibraries(librariesDir, optionals)) { + return false; + } + if (!this.processors.process(librariesDir, clientTarget)) { + return false; + } + } catch (URISyntaxException e) { + return false; + } + return true; + } +} diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Download.java b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Download.java new file mode 100644 index 0000000000..a7a75e82bc --- /dev/null +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Download.java @@ -0,0 +1,48 @@ +package io.github.zekerzhayard.forgewrapper.installer; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.util.Locale; + +import org.apache.commons.codec.digest.DigestUtils; + +public class Download { + public static void download(String url, String location) throws IOException { + File localFile = new File(location); + localFile.getParentFile().mkdirs(); + if (localFile.isFile()) { + try { + Files.copy(new URL(url + ".md5").openConnection().getInputStream(), Paths.get(location + ".md5"), StandardCopyOption.REPLACE_EXISTING); + Files.copy(new URL(url + ".sha1").openConnection().getInputStream(), Paths.get(location + ".sha1"), StandardCopyOption.REPLACE_EXISTING); + String md5 = new String(Files.readAllBytes(Paths.get(location + ".md5"))); + String sha1 = new String(Files.readAllBytes(Paths.get(location + ".sha1"))); + if (!checkMD5(location, md5) || !checkSHA1(location, sha1)) { + localFile.delete(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + if (!localFile.isFile()) { + if (localFile.isDirectory()) { + throw new RuntimeException(location + " must be a file!"); + } + Files.copy(new URL(url).openConnection().getInputStream(), Paths.get(location), StandardCopyOption.REPLACE_EXISTING); + download(url, location); + } + } + + public static boolean checkMD5(String path, String hash) throws IOException { + String md5 = DigestUtils.md5Hex(Files.readAllBytes(Paths.get(path))); + return md5.toLowerCase(Locale.ENGLISH).equals(hash.toLowerCase(Locale.ENGLISH)); + } + + public static boolean checkSHA1(String path, String hash) throws IOException { + String sha1 = DigestUtils.sha1Hex(Files.readAllBytes(Paths.get(path))); + return sha1.toLowerCase(Locale.ENGLISH).equals(hash.toLowerCase(Locale.ENGLISH)); + } +} diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java new file mode 100644 index 0000000000..826ad7462d --- /dev/null +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java @@ -0,0 +1,70 @@ +package io.github.zekerzhayard.forgewrapper.installer; + +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.regex.Pattern; + +import net.minecraftforge.installer.actions.ActionCanceledException; +import net.minecraftforge.installer.actions.ProgressCallback; +import net.minecraftforge.installer.json.Install; +import net.minecraftforge.installer.json.Util; + +public class Installer { + private static Install install; + + public static boolean install() throws ActionCanceledException { + ProgressCallback monitor = ProgressCallback.withOutputs(System.out); + install = Util.loadInstallProfile(); + if (System.getProperty("java.net.preferIPv4Stack") == null) { + System.setProperty("java.net.preferIPv4Stack", "true"); + } + String vendor = System.getProperty("java.vendor", "missing vendor"); + String javaVersion = System.getProperty("java.version", "missing java version"); + String jvmVersion = System.getProperty("java.vm.version", "missing jvm version"); + monitor.message(String.format("JVM info: %s - %s - %s", vendor, javaVersion, jvmVersion)); + monitor.message("java.net.preferIPv4Stack=" + System.getProperty("java.net.preferIPv4Stack")); + return new ClientInstall4MultiMC(install, monitor).run(null, input -> true); + } + + public static String getForgeVersion() { + return install.getVersion().substring(install.getVersion().lastIndexOf("-") + 1); + } + + public static String getMcVersion() { + return install.getMinecraft(); + } + + public static String getMcpVersion() { + return install.getData(true).get("MCP_VERSION").replace("'", ""); + } + + static void hookStdOut(ProgressCallback monitor) { + final Pattern endingWhitespace = Pattern.compile("\\r?\\n$"); + final OutputStream monitorStream = new OutputStream() { + + @Override + public void write(byte[] buf, int off, int len) { + byte[] toWrite = new byte[len]; + System.arraycopy(buf, off, toWrite, 0, len); + write(toWrite); + } + + @Override + public void write(byte[] b) { + String toWrite = new String(b); + toWrite = endingWhitespace.matcher(toWrite).replaceAll(""); + if (!toWrite.isEmpty()) { + monitor.message(toWrite); + } + } + + @Override + public void write(int b) { + write(new byte[] {(byte) b}); + } + }; + + System.setOut(new PrintStream(monitorStream)); + System.setErr(new PrintStream(monitorStream)); + } +} -- cgit 0.0.5-2-1-g0f52 From 4c26c424359356f0932ebc01ce456f0723433e86 Mon Sep 17 00:00:00 2001 From: ZekerZhayard Date: Sat, 28 Dec 2019 03:26:50 +0800 Subject: Delete unnecessary folders. --- .gitignore | 3 ++- .../forgewrapper/ClientInstall4MultiMC.class | Bin 2109 -> 0 bytes .../github/zekerzhayard/forgewrapper/Installer$1.class | Bin 1711 -> 0 bytes .../io/github/zekerzhayard/forgewrapper/Installer.class | Bin 3567 -> 0 bytes .../io/github/zekerzhayard/forgewrapper/Main.class | Bin 4903 -> 0 bytes .../io/github/zekerzhayard/forgewrapper/Utils.class | Bin 4195 -> 0 bytes .../zekerzhayard/forgewrapper/installer/Download.class | Bin 1283 -> 0 bytes out/production/classes/tt.class | Bin 908 -> 0 bytes 8 files changed, 2 insertions(+), 1 deletion(-) delete mode 100644 out/production/classes/io/github/zekerzhayard/forgewrapper/ClientInstall4MultiMC.class delete mode 100644 out/production/classes/io/github/zekerzhayard/forgewrapper/Installer$1.class delete mode 100644 out/production/classes/io/github/zekerzhayard/forgewrapper/Installer.class delete mode 100644 out/production/classes/io/github/zekerzhayard/forgewrapper/Main.class delete mode 100644 out/production/classes/io/github/zekerzhayard/forgewrapper/Utils.class delete mode 100644 out/production/classes/io/github/zekerzhayard/forgewrapper/installer/Download.class delete mode 100644 out/production/classes/tt.class diff --git a/.gitignore b/.gitignore index 835e8dca81..f4f395378f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .gradle .idea -build \ No newline at end of file +build +out \ No newline at end of file diff --git a/out/production/classes/io/github/zekerzhayard/forgewrapper/ClientInstall4MultiMC.class b/out/production/classes/io/github/zekerzhayard/forgewrapper/ClientInstall4MultiMC.class deleted file mode 100644 index 73d3ed00c1..0000000000 Binary files a/out/production/classes/io/github/zekerzhayard/forgewrapper/ClientInstall4MultiMC.class and /dev/null differ diff --git a/out/production/classes/io/github/zekerzhayard/forgewrapper/Installer$1.class b/out/production/classes/io/github/zekerzhayard/forgewrapper/Installer$1.class deleted file mode 100644 index ca059e266a..0000000000 Binary files a/out/production/classes/io/github/zekerzhayard/forgewrapper/Installer$1.class and /dev/null differ diff --git a/out/production/classes/io/github/zekerzhayard/forgewrapper/Installer.class b/out/production/classes/io/github/zekerzhayard/forgewrapper/Installer.class deleted file mode 100644 index 46a535c25c..0000000000 Binary files a/out/production/classes/io/github/zekerzhayard/forgewrapper/Installer.class and /dev/null differ diff --git a/out/production/classes/io/github/zekerzhayard/forgewrapper/Main.class b/out/production/classes/io/github/zekerzhayard/forgewrapper/Main.class deleted file mode 100644 index 2819c894d2..0000000000 Binary files a/out/production/classes/io/github/zekerzhayard/forgewrapper/Main.class and /dev/null differ diff --git a/out/production/classes/io/github/zekerzhayard/forgewrapper/Utils.class b/out/production/classes/io/github/zekerzhayard/forgewrapper/Utils.class deleted file mode 100644 index b10c2c30c7..0000000000 Binary files a/out/production/classes/io/github/zekerzhayard/forgewrapper/Utils.class and /dev/null differ diff --git a/out/production/classes/io/github/zekerzhayard/forgewrapper/installer/Download.class b/out/production/classes/io/github/zekerzhayard/forgewrapper/installer/Download.class deleted file mode 100644 index def20077a1..0000000000 Binary files a/out/production/classes/io/github/zekerzhayard/forgewrapper/installer/Download.class and /dev/null differ diff --git a/out/production/classes/tt.class b/out/production/classes/tt.class deleted file mode 100644 index 084b41e2dd..0000000000 Binary files a/out/production/classes/tt.class and /dev/null differ -- cgit 0.0.5-2-1-g0f52 From e6feb74d4809334e5f14fe3c6ca9d1cdc8c85404 Mon Sep 17 00:00:00 2001 From: ZekerZhayard Date: Sat, 28 Dec 2019 10:57:28 +0800 Subject: Clean build.gradle. --- build.gradle | 18 ------------------ .../io/github/zekerzhayard/forgewrapper/Utils.java | 2 +- 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/build.gradle b/build.gradle index 44dc7b34b9..8f41c5039a 100644 --- a/build.gradle +++ b/build.gradle @@ -1,21 +1,3 @@ -/* - * This file was generated by the Gradle 'init' task. - * - * This is a general purpose Gradle build. - * Learn how to create Gradle builds at https://guides.gradle.org/creating-new-gradle-builds/ - */ - -buildscript { - repositories { - mavenCentral() - jcenter() - maven { - name = "forge" - url = "https://files.minecraftforge.net/maven" - } - } -} - apply plugin: "base" apply plugin: "java" apply plugin: "idea" diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/Utils.java b/src/main/java/io/github/zekerzhayard/forgewrapper/Utils.java index 6c99888e02..442025313c 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/Utils.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/Utils.java @@ -35,7 +35,7 @@ public class Utils { public static File getLibrariesDir() throws URISyntaxException { File wrapper = new File(Utils.class.getProtectionDomain().getCodeSource().getLocation().toURI()); // see https://github.com/MinecraftForge/MinecraftForge/blob/863ab2ca184cf2e2dfa134d07bfc20d6a9a6a4e8/src/main/java/net/minecraftforge/fml/relauncher/libraries/LibraryManager.java#L151 - // ForgeWrapper ZekerZhayard github com libraries + // / /ForgeWrapper /ZekerZhayard /github /com /libraries return wrapper.getParentFile().getParentFile().getParentFile().getParentFile().getParentFile().getParentFile(); } } -- cgit 0.0.5-2-1-g0f52 From c45356218af0dfe119918070aab09e1323af00ca Mon Sep 17 00:00:00 2001 From: ZekerZhayard Date: Sat, 28 Dec 2019 16:35:18 +0800 Subject: Upload example instances. --- .../forge-1.14.4-28.1.109/mmc-pack.json | 38 ++++++++ .../patches/net.minecraftforge.json | 107 +++++++++++++++++++++ 2 files changed, 145 insertions(+) create mode 100644 example-instances/forge-1.14.4-28.1.109/mmc-pack.json create mode 100644 example-instances/forge-1.14.4-28.1.109/patches/net.minecraftforge.json diff --git a/example-instances/forge-1.14.4-28.1.109/mmc-pack.json b/example-instances/forge-1.14.4-28.1.109/mmc-pack.json new file mode 100644 index 0000000000..5f15ab0f45 --- /dev/null +++ b/example-instances/forge-1.14.4-28.1.109/mmc-pack.json @@ -0,0 +1,38 @@ +{ + "components": [ + { + "cachedName": "LWJGL 3", + "cachedVersion": "3.2.2", + "cachedVolatile": true, + "dependencyOnly": true, + "uid": "org.lwjgl3", + "version": "3.2.2" + }, + { + "cachedName": "Minecraft", + "cachedRequires": [ + { + "equals": "3.2.2", + "suggests": "3.2.2", + "uid": "org.lwjgl3" + } + ], + "cachedVersion": "1.14.4", + "important": true, + "uid": "net.minecraft", + "version": "1.14.4" + }, + { + "cachedName": "MinecraftForge", + "cachedRequires": [ + { + "equals": "1.14.4", + "uid": "net.minecraft" + } + ], + "cachedVersion": "1.14.4-28.1.109", + "uid": "net.minecraftforge" + } + ], + "formatVersion": 1 +} \ No newline at end of file diff --git a/example-instances/forge-1.14.4-28.1.109/patches/net.minecraftforge.json b/example-instances/forge-1.14.4-28.1.109/patches/net.minecraftforge.json new file mode 100644 index 0000000000..470bf2a709 --- /dev/null +++ b/example-instances/forge-1.14.4-28.1.109/patches/net.minecraftforge.json @@ -0,0 +1,107 @@ +{ + "formatVersion": 1, + "libraries": [ + { + "name": "com.github.ZekerZhayard:ForgeWrapper:-SNAPSHOT", + "url": "https://jitpack.io/" + }, + { + "name": "net.minecraftforge:forge:1.14.4-28.1.109:launcher", + "url": "https://files.minecraftforge.net/maven/" + }, + { + "name": "org.ow2.asm:asm:6.2", + "url": "https://files.minecraftforge.net/maven/" + }, + { + "name": "org.ow2.asm:asm-commons:6.2", + "url": "https://files.minecraftforge.net/maven/" + }, + { + "name": "org.ow2.asm:asm-tree:6.2", + "url": "https://files.minecraftforge.net/maven/" + }, + { + "name": "cpw.mods:modlauncher:4.1.0", + "url": "https://files.minecraftforge.net/maven/" + }, + { + "name": "cpw.mods:grossjava9hacks:1.1.0", + "url": "https://files.minecraftforge.net/maven/" + }, + { + "name": "net.minecraftforge:accesstransformers:1.0.1-milestone.0.1+94458e7:shadowed", + "url": "https://files.minecraftforge.net/maven/" + }, + { + "name": "net.minecraftforge:eventbus:1.0.0:service", + "url": "https://files.minecraftforge.net/maven/" + }, + { + "name": "net.minecraftforge:forgespi:1.5.0", + "url": "https://files.minecraftforge.net/maven/" + }, + { + "name": "net.minecraftforge:coremods:1.0.0", + "url": "https://files.minecraftforge.net/maven/" + }, + { + "name": "net.minecraftforge:unsafe:0.2.0", + "url": "https://files.minecraftforge.net/maven/" + }, + { + "name": "com.electronwill.night-config:core:3.6.0", + "url": "https://files.minecraftforge.net/maven/" + }, + { + "name": "com.electronwill.night-config:toml:3.6.0", + "url": "https://files.minecraftforge.net/maven/" + }, + { + "name": "org.jline:jline:3.12.1", + "url": "https://files.minecraftforge.net/maven/" + }, + { + "name": "org.apache.maven:maven-artifact:3.6.0", + "url": "https://files.minecraftforge.net/maven/" + }, + { + "name": "net.jodah:typetools:0.6.0", + "url": "https://files.minecraftforge.net/maven/" + }, + { + "name": "java3d:vecmath:1.5.2" + }, + { + "name": "org.apache.logging.log4j:log4j-api:2.11.2", + "url": "https://files.minecraftforge.net/maven/" + }, + { + "name": "org.apache.logging.log4j:log4j-core:2.11.2", + "url": "https://files.minecraftforge.net/maven/" + }, + { + "name": "net.minecrell:terminalconsoleappender:1.2.0", + "url": "https://files.minecraftforge.net/maven/" + }, + { + "name": "net.sf.jopt-simple:jopt-simple:5.0.4", + "url": "https://files.minecraftforge.net/maven/" + }, + { + "name": "cpw.mods.forge:cursepacklocator:1.2.0", + "url": "https://files.minecraftforge.net/maven/" + } + ], + "mainClass": "io.github.zekerzhayard.forgewrapper.Main", + "name": "MinecraftForge", + "requires": [ + { + "equals": "1.14.4", + "uid": "net.minecraft" + } + ], + "type": "release", + "uid": "net.minecraftforge", + "version": "1.14.4-28.1.109" +} \ No newline at end of file -- cgit 0.0.5-2-1-g0f52 From 1b50883f6d57f0ad3b53fac4afe9025d6d807a2c Mon Sep 17 00:00:00 2001 From: ZekerZhayard Date: Sun, 9 Feb 2020 11:26:14 +0800 Subject: Add converter to convert vanilla version json to MultiMC instance json. --- README.md | 15 +++ build.gradle | 19 ++- .../forge-1.14.4-28.1.109/mmc-pack.json | 38 ------ .../patches/net.minecraftforge.json | 107 ----------------- .../io/github/zekerzhayard/forgewrapper/Main.java | 3 +- .../io/github/zekerzhayard/forgewrapper/Utils.java | 16 ++- .../forgewrapper/converter/Converter.java | 132 +++++++++++++++++++++ .../zekerzhayard/forgewrapper/converter/Main.java | 37 ++++++ .../installer/ClientInstall4MultiMC.java | 24 ++-- .../forgewrapper/installer/Download.java | 3 + .../forgewrapper/installer/Installer.java | 37 +----- src/main/resources/mmc-pack.json | 13 ++ src/main/resources/patches/net.minecraftforge.json | 21 ++++ 13 files changed, 261 insertions(+), 204 deletions(-) create mode 100644 README.md delete mode 100644 example-instances/forge-1.14.4-28.1.109/mmc-pack.json delete mode 100644 example-instances/forge-1.14.4-28.1.109/patches/net.minecraftforge.json create mode 100644 src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java create mode 100644 src/main/java/io/github/zekerzhayard/forgewrapper/converter/Main.java create mode 100644 src/main/resources/mmc-pack.json create mode 100644 src/main/resources/patches/net.minecraftforge.json diff --git a/README.md b/README.md new file mode 100644 index 0000000000..c4437542f7 --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +# ForgeWrapper + +Allow MultiMC to launch Minecraft 1.13+ with Forge. + +## How to use + +1. Download Forge installer for Minecraft 1.13+ at [https://files.minecraftforge.net/]. +2. Download ForgeWrapper jar file at the [release](https://github.com/ZekerZhayard/ForgeWrapper/releases) page. +3. Run the below command in terminal: + ``` + java -jar [--installer] [--instance ] + ``` + *Notice: If you don't specify a MultiMC instance path, ForgeWrapper will create the instance folder in current working space.* +4. If the instance folder which just created is not in `MultiMC/instances` folder, you just need to move to the `MultiMC/instances` folder. +5. Run MultiMC, and you will see a new instance named `forge--`. \ No newline at end of file diff --git a/build.gradle b/build.gradle index 8f41c5039a..89794dcfa5 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ apply plugin: "idea" sourceCompatibility = targetCompatibility = 1.8 -version = "1.0.0" +version = "1.1.0" group = "io.github.zekerzhayard" archivesBaseName = rootProject.name @@ -19,12 +19,23 @@ repositories { dependencies { compile "commons-codec:commons-codec:1.10" - compile "cpw.mods:modlauncher:5.0.0-milestone.4" - compile "net.minecraftforge:forge:1.15.1-30.0.16:installer" + compile "cpw.mods:modlauncher:4.1.0" + compile "net.minecraftforge:forge:1.14.4-28.2.0:installer" } jar { manifest.attributes( - "Main-Class": "io.github.zekerzhayard.forgewrapper.Main" + "Main-Class": "io.github.zekerzhayard.forgewrapper.converter.Main" ) +} + +processResources { + inputs.property "version", project.version + from(sourceSets.main.resources.srcDirs) { + include "patches/net.minecraftforge.json" + expand "version": project.version + } + from(sourceSets.main.resources.srcDirs) { + exclude "patches/net.minecraftforge.json" + } } \ No newline at end of file diff --git a/example-instances/forge-1.14.4-28.1.109/mmc-pack.json b/example-instances/forge-1.14.4-28.1.109/mmc-pack.json deleted file mode 100644 index 5f15ab0f45..0000000000 --- a/example-instances/forge-1.14.4-28.1.109/mmc-pack.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "components": [ - { - "cachedName": "LWJGL 3", - "cachedVersion": "3.2.2", - "cachedVolatile": true, - "dependencyOnly": true, - "uid": "org.lwjgl3", - "version": "3.2.2" - }, - { - "cachedName": "Minecraft", - "cachedRequires": [ - { - "equals": "3.2.2", - "suggests": "3.2.2", - "uid": "org.lwjgl3" - } - ], - "cachedVersion": "1.14.4", - "important": true, - "uid": "net.minecraft", - "version": "1.14.4" - }, - { - "cachedName": "MinecraftForge", - "cachedRequires": [ - { - "equals": "1.14.4", - "uid": "net.minecraft" - } - ], - "cachedVersion": "1.14.4-28.1.109", - "uid": "net.minecraftforge" - } - ], - "formatVersion": 1 -} \ No newline at end of file diff --git a/example-instances/forge-1.14.4-28.1.109/patches/net.minecraftforge.json b/example-instances/forge-1.14.4-28.1.109/patches/net.minecraftforge.json deleted file mode 100644 index 470bf2a709..0000000000 --- a/example-instances/forge-1.14.4-28.1.109/patches/net.minecraftforge.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "formatVersion": 1, - "libraries": [ - { - "name": "com.github.ZekerZhayard:ForgeWrapper:-SNAPSHOT", - "url": "https://jitpack.io/" - }, - { - "name": "net.minecraftforge:forge:1.14.4-28.1.109:launcher", - "url": "https://files.minecraftforge.net/maven/" - }, - { - "name": "org.ow2.asm:asm:6.2", - "url": "https://files.minecraftforge.net/maven/" - }, - { - "name": "org.ow2.asm:asm-commons:6.2", - "url": "https://files.minecraftforge.net/maven/" - }, - { - "name": "org.ow2.asm:asm-tree:6.2", - "url": "https://files.minecraftforge.net/maven/" - }, - { - "name": "cpw.mods:modlauncher:4.1.0", - "url": "https://files.minecraftforge.net/maven/" - }, - { - "name": "cpw.mods:grossjava9hacks:1.1.0", - "url": "https://files.minecraftforge.net/maven/" - }, - { - "name": "net.minecraftforge:accesstransformers:1.0.1-milestone.0.1+94458e7:shadowed", - "url": "https://files.minecraftforge.net/maven/" - }, - { - "name": "net.minecraftforge:eventbus:1.0.0:service", - "url": "https://files.minecraftforge.net/maven/" - }, - { - "name": "net.minecraftforge:forgespi:1.5.0", - "url": "https://files.minecraftforge.net/maven/" - }, - { - "name": "net.minecraftforge:coremods:1.0.0", - "url": "https://files.minecraftforge.net/maven/" - }, - { - "name": "net.minecraftforge:unsafe:0.2.0", - "url": "https://files.minecraftforge.net/maven/" - }, - { - "name": "com.electronwill.night-config:core:3.6.0", - "url": "https://files.minecraftforge.net/maven/" - }, - { - "name": "com.electronwill.night-config:toml:3.6.0", - "url": "https://files.minecraftforge.net/maven/" - }, - { - "name": "org.jline:jline:3.12.1", - "url": "https://files.minecraftforge.net/maven/" - }, - { - "name": "org.apache.maven:maven-artifact:3.6.0", - "url": "https://files.minecraftforge.net/maven/" - }, - { - "name": "net.jodah:typetools:0.6.0", - "url": "https://files.minecraftforge.net/maven/" - }, - { - "name": "java3d:vecmath:1.5.2" - }, - { - "name": "org.apache.logging.log4j:log4j-api:2.11.2", - "url": "https://files.minecraftforge.net/maven/" - }, - { - "name": "org.apache.logging.log4j:log4j-core:2.11.2", - "url": "https://files.minecraftforge.net/maven/" - }, - { - "name": "net.minecrell:terminalconsoleappender:1.2.0", - "url": "https://files.minecraftforge.net/maven/" - }, - { - "name": "net.sf.jopt-simple:jopt-simple:5.0.4", - "url": "https://files.minecraftforge.net/maven/" - }, - { - "name": "cpw.mods.forge:cursepacklocator:1.2.0", - "url": "https://files.minecraftforge.net/maven/" - } - ], - "mainClass": "io.github.zekerzhayard.forgewrapper.Main", - "name": "MinecraftForge", - "requires": [ - { - "equals": "1.14.4", - "uid": "net.minecraft" - } - ], - "type": "release", - "uid": "net.minecraftforge", - "version": "1.14.4-28.1.109" -} \ No newline at end of file diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/Main.java b/src/main/java/io/github/zekerzhayard/forgewrapper/Main.java index a07d467e83..7ac1802e9d 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/Main.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/Main.java @@ -16,7 +16,7 @@ import io.github.zekerzhayard.forgewrapper.installer.Download; public class Main { public static void main(String[] args) throws Exception { URL[] urls = Utils.getURLs(new ArrayList<>()); - Pattern pattern = Pattern.compile("forge\\-(?[0-9\\.]+)\\-(?[0-9\\.]+)\\-launcher\\.jar"); + Pattern pattern = Pattern.compile("forge-(?[0-9.]+)-(?[0-9.]+)\\.jar"); String version = ""; for (URL url : urls) { Matcher matcher = pattern.matcher(url.getFile()); @@ -30,6 +30,7 @@ public class Main { URLClassLoader ucl = URLClassLoader.newInstance(new URL[] { Main.class.getProtectionDomain().getCodeSource().getLocation(), + Launcher.class.getProtectionDomain().getCodeSource().getLocation(), new File(String.format("./.forgewrapper/forge-%s-installer.jar", version)).toURI().toURL() }, null); diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/Utils.java b/src/main/java/io/github/zekerzhayard/forgewrapper/Utils.java index 442025313c..3d3921d8e6 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/Utils.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/Utils.java @@ -10,6 +10,8 @@ import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; +import cpw.mods.modlauncher.Launcher; + public class Utils { public static URL[] getURLs(List blackList) { ClassLoader cl = Utils.class.getClassLoader(); @@ -32,10 +34,14 @@ public class Utils { return urls.toArray(new URL[0]); } - public static File getLibrariesDir() throws URISyntaxException { - File wrapper = new File(Utils.class.getProtectionDomain().getCodeSource().getLocation().toURI()); - // see https://github.com/MinecraftForge/MinecraftForge/blob/863ab2ca184cf2e2dfa134d07bfc20d6a9a6a4e8/src/main/java/net/minecraftforge/fml/relauncher/libraries/LibraryManager.java#L151 - // / /ForgeWrapper /ZekerZhayard /github /com /libraries - return wrapper.getParentFile().getParentFile().getParentFile().getParentFile().getParentFile().getParentFile(); + public static File getLibrariesDir() { + try { + File laucnher = new File(Launcher.class.getProtectionDomain().getCodeSource().getLocation().toURI()); + // see https://github.com/MinecraftForge/MinecraftForge/blob/863ab2ca184cf2e2dfa134d07bfc20d6a9a6a4e8/src/main/java/net/minecraftforge/fml/relauncher/libraries/LibraryManager.java#L151 + // / /modlauncher /mods /cpw /libraries + return laucnher.getParentFile().getParentFile().getParentFile().getParentFile().getParentFile(); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } } } diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java b/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java new file mode 100644 index 0000000000..e3e0653c2c --- /dev/null +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java @@ -0,0 +1,132 @@ +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.nio.file.StandardOpenOption; +import java.util.ArrayList; +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) throws Exception { + JsonObject installer = getInstallerJson(installerPath); + + ArrayList arguments = new ArrayList<>(); + + getElement(installer.getAsJsonObject("arguments"), "game").getAsJsonArray().iterator().forEachRemaining(je -> arguments.add(je.getAsString())); + 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, 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 /.minecraft/.forgewrapper folder. + Path forgeWrapperPath = instancePath.resolve(".minecraft").resolve(".forgewrapper"); + Files.createDirectories(forgeWrapperPath); + Files.copy(installerPath, forgeWrapperPath.resolve(forgeFullVersion + "-installer.jar"), StandardCopyOption.REPLACE_EXISTING); + } + + private static JsonObject getInstallerJson(Path installerPath) { + try { + ZipFile zf = new ZipFile(installerPath.toFile()); + ZipEntry versionFile = zf.getEntry("version.json"); + if (versionFile == null) { + throw new RuntimeException("The forge installer is invalid!"); + } + InputStreamReader isr = new InputStreamReader(zf.getInputStream(versionFile), StandardCharsets.UTF_8); + return new JsonParser().parse(isr).getAsJsonObject(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + // Convert mmc-pack.json: + // - Replace Minecraft version + private static JsonObject convertPackJson(String mcVersion) { + JsonObject pack = new JsonParser().parse(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, String mcVersion, String forgeVersion, StringBuilder wrapperVersion) { + JsonObject patches = new JsonParser().parse(new InputStreamReader(Converter.class.getResourceAsStream("/patches/net.minecraftforge.json"))).getAsJsonObject(); + JsonArray libraries = getElement(patches, "libraries").getAsJsonArray(); + + 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()); + } + } + for (JsonElement lib : getElement(installer ,"libraries").getAsJsonArray()) { + JsonObject artifact = getElement(getElement(lib.getAsJsonObject(), "downloads").getAsJsonObject(), "artifact").getAsJsonObject(); + String path = getElement(artifact, "path").getAsString(); + if (path.startsWith("net/minecraftforge/forge/")) { + artifact.getAsJsonObject().addProperty("url", "https://files.minecraftforge.net/maven/" + path.replace(".jar", "-launcher.jar")); + } + libraries.add(lib); + } + + 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; + } +} diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Main.java b/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Main.java new file mode 100644 index 0000000000..a9d4c38e64 --- /dev/null +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Main.java @@ -0,0 +1,37 @@ +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.ArrayList; +import java.util.Arrays; + +public class Main { + public static void main(String[] args) { + ArrayList argsList = new ArrayList<>(Arrays.asList(args)); + Path installer, instance; + try { + installer = Paths.get(argsList.get(argsList.indexOf("--installer") + 1)); + instance = Paths.get("."); + if (argsList.contains("--instance")) { + instance = Paths.get(argsList.get(argsList.indexOf("--instance") + 1)); + } + } 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).invoke(null, installer, instance); + System.out.println("Successfully install Forge for MultiMC!"); + } catch (Exception e) { + System.out.println("Failed to install Forge!"); + throw new RuntimeException(e); + } + } +} diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/ClientInstall4MultiMC.java b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/ClientInstall4MultiMC.java index c87bfc4a6b..d104a18c7b 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/ClientInstall4MultiMC.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/ClientInstall4MultiMC.java @@ -1,7 +1,6 @@ package io.github.zekerzhayard.forgewrapper.installer; import java.io.File; -import java.net.URISyntaxException; import java.util.function.Predicate; import io.github.zekerzhayard.forgewrapper.Utils; @@ -16,20 +15,19 @@ public class ClientInstall4MultiMC extends ClientInstall { } @Override - public boolean run(File target, Predicate optionals) throws ActionCanceledException { - try { - File librariesDir = Utils.getLibrariesDir(); - File clientTarget = new File(String.format("%s/com/mojang/minecraft/%s/minecraft-%s-client.jar", librariesDir.getAbsolutePath(), this.profile.getMinecraft(), this.profile.getMinecraft())); + public boolean run(File target, Predicate optionals) { + File librariesDir = Utils.getLibrariesDir(); + File clientTarget = new File(String.format("%s/com/mojang/minecraft/%s/minecraft-%s-client.jar", librariesDir.getAbsolutePath(), this.profile.getMinecraft(), this.profile.getMinecraft())); - if (!this.downloadLibraries(librariesDir, optionals)) { - return false; - } - if (!this.processors.process(librariesDir, clientTarget)) { - return false; - } - } catch (URISyntaxException e) { + boolean downloadLibraries = true; // Force true when without an internet connection. + try { + downloadLibraries = this.downloadLibraries(librariesDir, optionals); + } catch (ActionCanceledException e) { + e.printStackTrace(); + } + if (!downloadLibraries) { return false; } - return true; + return this.processors.process(librariesDir, clientTarget); } } diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Download.java b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Download.java index a7a75e82bc..38846f5843 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Download.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Download.java @@ -16,11 +16,13 @@ public class Download { localFile.getParentFile().mkdirs(); if (localFile.isFile()) { try { + System.out.println("Checking Fingerprints of installer..."); Files.copy(new URL(url + ".md5").openConnection().getInputStream(), Paths.get(location + ".md5"), StandardCopyOption.REPLACE_EXISTING); Files.copy(new URL(url + ".sha1").openConnection().getInputStream(), Paths.get(location + ".sha1"), StandardCopyOption.REPLACE_EXISTING); String md5 = new String(Files.readAllBytes(Paths.get(location + ".md5"))); String sha1 = new String(Files.readAllBytes(Paths.get(location + ".sha1"))); if (!checkMD5(location, md5) || !checkSHA1(location, sha1)) { + System.out.println("Fingerprints do not match!"); localFile.delete(); } } catch (IOException e) { @@ -31,6 +33,7 @@ public class Download { if (localFile.isDirectory()) { throw new RuntimeException(location + " must be a file!"); } + System.out.println("Downloading forge installer..."); Files.copy(new URL(url).openConnection().getInputStream(), Paths.get(location), StandardCopyOption.REPLACE_EXISTING); download(url, location); } diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java index 826ad7462d..c1c7d8d145 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java @@ -1,10 +1,5 @@ package io.github.zekerzhayard.forgewrapper.installer; -import java.io.OutputStream; -import java.io.PrintStream; -import java.util.regex.Pattern; - -import net.minecraftforge.installer.actions.ActionCanceledException; import net.minecraftforge.installer.actions.ProgressCallback; import net.minecraftforge.installer.json.Install; import net.minecraftforge.installer.json.Util; @@ -12,7 +7,7 @@ import net.minecraftforge.installer.json.Util; public class Installer { private static Install install; - public static boolean install() throws ActionCanceledException { + public static boolean install() { ProgressCallback monitor = ProgressCallback.withOutputs(System.out); install = Util.loadInstallProfile(); if (System.getProperty("java.net.preferIPv4Stack") == null) { @@ -37,34 +32,4 @@ public class Installer { public static String getMcpVersion() { return install.getData(true).get("MCP_VERSION").replace("'", ""); } - - static void hookStdOut(ProgressCallback monitor) { - final Pattern endingWhitespace = Pattern.compile("\\r?\\n$"); - final OutputStream monitorStream = new OutputStream() { - - @Override - public void write(byte[] buf, int off, int len) { - byte[] toWrite = new byte[len]; - System.arraycopy(buf, off, toWrite, 0, len); - write(toWrite); - } - - @Override - public void write(byte[] b) { - String toWrite = new String(b); - toWrite = endingWhitespace.matcher(toWrite).replaceAll(""); - if (!toWrite.isEmpty()) { - monitor.message(toWrite); - } - } - - @Override - public void write(int b) { - write(new byte[] {(byte) b}); - } - }; - - System.setOut(new PrintStream(monitorStream)); - System.setErr(new PrintStream(monitorStream)); - } } diff --git a/src/main/resources/mmc-pack.json b/src/main/resources/mmc-pack.json new file mode 100644 index 0000000000..3622087e0a --- /dev/null +++ b/src/main/resources/mmc-pack.json @@ -0,0 +1,13 @@ +{ + "formatVersion": 1, + "components": [ + { + "important": true, + "uid": "net.minecraft", + "version": "{VERSION}" + }, + { + "uid": "net.minecraftforge" + } + ] +} \ No newline at end of file diff --git a/src/main/resources/patches/net.minecraftforge.json b/src/main/resources/patches/net.minecraftforge.json new file mode 100644 index 0000000000..b037e07057 --- /dev/null +++ b/src/main/resources/patches/net.minecraftforge.json @@ -0,0 +1,21 @@ +{ + "formatVersion": 1, + "mainClass": "io.github.zekerzhayard.forgewrapper.Main", + "name": "Forge", + "requires": [ + { + "equals": "{VERSION}", + "uid": "net.minecraft" + } + ], + "type": "release", + "uid": "net.minecraftforge", + "version": "{FORGE_VERSION}", + "libraries": [ + { + "name": "io.github.zekerzhayard:ForgeWrapper:${version}", + "MMC-hint": "local", + "MMC-filename": "ForgeWrapper-${version}.jar" + } + ] +} \ No newline at end of file -- cgit 0.0.5-2-1-g0f52 From 9f06151fca024df584b6cc35f3adbf4e7f6e54ee Mon Sep 17 00:00:00 2001 From: ZekerZhayard Date: Sun, 9 Feb 2020 11:34:40 +0800 Subject: Support Eclipse. --- .gitignore | 13 ++++++++++++- README.md | 9 +++++---- build.gradle | 1 + 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index f4f395378f..007587d534 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,15 @@ .gradle -.idea build + +# eclipse +.settings +.classpath +.project +bin + +# idea +.idea +*.iml +*.ipr +*.iws out \ No newline at end of file diff --git a/README.md b/README.md index c4437542f7..db9aed1db6 100644 --- a/README.md +++ b/README.md @@ -7,9 +7,10 @@ Allow MultiMC to launch Minecraft 1.13+ with Forge. 1. Download Forge installer for Minecraft 1.13+ at [https://files.minecraftforge.net/]. 2. Download ForgeWrapper jar file at the [release](https://github.com/ZekerZhayard/ForgeWrapper/releases) page. 3. Run the below command in terminal: - ``` - java -jar [--installer] [--instance ] - ``` - *Notice: If you don't specify a MultiMC instance path, ForgeWrapper will create the instance folder in current working space.* + ``` + java -jar [--installer] [--instance ] + ``` + *Notice: If you don't specify a MultiMC instance path, ForgeWrapper will create the instance folder in current working space.* + 4. If the instance folder which just created is not in `MultiMC/instances` folder, you just need to move to the `MultiMC/instances` folder. 5. Run MultiMC, and you will see a new instance named `forge--`. \ No newline at end of file diff --git a/build.gradle b/build.gradle index 89794dcfa5..fa854059d1 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,6 @@ apply plugin: "base" apply plugin: "java" +apply plugin: "eclipse" apply plugin: "idea" sourceCompatibility = targetCompatibility = 1.8 -- cgit 0.0.5-2-1-g0f52 From 7114b3e0d59ab162d934a91635d1624abc14f5e2 Mon Sep 17 00:00:00 2001 From: ZekerZhayard Date: Sun, 9 Feb 2020 12:22:30 +0800 Subject: Fix NPE when launching Forge 1.13.2. --- .../io/github/zekerzhayard/forgewrapper/Main.java | 19 +++++++------------ .../forgewrapper/converter/Converter.java | 19 ++++++++++++++----- .../forgewrapper/installer/Installer.java | 16 +--------------- 3 files changed, 22 insertions(+), 32 deletions(-) diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/Main.java b/src/main/java/io/github/zekerzhayard/forgewrapper/Main.java index 7ac1802e9d..146c970638 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/Main.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/Main.java @@ -3,6 +3,7 @@ package io.github.zekerzhayard.forgewrapper; import java.io.File; import java.net.URL; import java.net.URLClassLoader; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; @@ -11,6 +12,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import cpw.mods.modlauncher.Launcher; +import io.github.zekerzhayard.forgewrapper.converter.Converter; import io.github.zekerzhayard.forgewrapper.installer.Download; public class Main { @@ -18,12 +20,14 @@ public class Main { URL[] urls = Utils.getURLs(new ArrayList<>()); Pattern pattern = Pattern.compile("forge-(?[0-9.]+)-(?[0-9.]+)\\.jar"); String version = ""; + String installerFileStr = ""; for (URL url : urls) { Matcher matcher = pattern.matcher(url.getFile()); if (matcher.find() && url.getFile().endsWith(matcher.group(0))) { version = matcher.group("mcVersion") + "-" + matcher.group("forgeVersion"); String installerUrl = String.format("https://files.minecraftforge.net/maven/net/minecraftforge/forge/%s/forge-%s-installer.jar", version, version); - Download.download(installerUrl, String.format("./.forgewrapper/forge-%s-installer.jar", version)); + installerFileStr = String.format("./.forgewrapper/forge-%s-installer.jar", version); + Download.download(installerUrl, installerFileStr); break; } } @@ -31,7 +35,7 @@ public class Main { URLClassLoader ucl = URLClassLoader.newInstance(new URL[] { Main.class.getProtectionDomain().getCodeSource().getLocation(), Launcher.class.getProtectionDomain().getCodeSource().getLocation(), - new File(String.format("./.forgewrapper/forge-%s-installer.jar", version)).toURI().toURL() + new File(installerFileStr).toURI().toURL() }, null); Class installer = ucl.loadClass("io.github.zekerzhayard.forgewrapper.installer.Installer"); @@ -39,16 +43,7 @@ public class Main { return; } List argsList = Stream.of(args).collect(Collectors.toList()); - argsList.add("--launchTarget"); - argsList.add("fmlclient"); - argsList.add("--fml.forgeVersion"); - argsList.add((String) installer.getMethod("getForgeVersion").invoke(null)); - argsList.add("--fml.mcVersion"); - argsList.add((String) installer.getMethod("getMcVersion").invoke(null)); - argsList.add("--fml.forgeGroup"); - argsList.add("net.minecraftforge"); - argsList.add("--fml.mcpVersion"); - argsList.add((String) installer.getMethod("getMcpVersion").invoke(null)); + argsList.addAll(Converter.getAdditionalArgs(Paths.get(installerFileStr))); Launcher.main(argsList.toArray(new String[0])); } diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java b/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java index e3e0653c2c..f9737eb62e 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java @@ -10,6 +10,7 @@ import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.nio.file.StandardOpenOption; import java.util.ArrayList; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.zip.ZipEntry; @@ -24,10 +25,7 @@ import com.google.gson.JsonParser; public class Converter { public static void convert(Path installerPath, Path targetDir) throws Exception { JsonObject installer = getInstallerJson(installerPath); - - ArrayList arguments = new ArrayList<>(); - - getElement(installer.getAsJsonObject("arguments"), "game").getAsJsonArray().iterator().forEachRemaining(je -> arguments.add(je.getAsString())); + 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; @@ -60,7 +58,18 @@ public class Converter { Files.copy(installerPath, forgeWrapperPath.resolve(forgeFullVersion + "-installer.jar"), StandardCopyOption.REPLACE_EXISTING); } - private static JsonObject getInstallerJson(Path installerPath) { + public static List getAdditionalArgs(Path installerPath) { + JsonObject installer = getInstallerJson(installerPath); + return getAdditionalArgs(installer); + } + + 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 getInstallerJson(Path installerPath) { try { ZipFile zf = new ZipFile(installerPath.toFile()); ZipEntry versionFile = zf.getEntry("version.json"); diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java index c1c7d8d145..ad60ad7375 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java @@ -5,11 +5,9 @@ import net.minecraftforge.installer.json.Install; import net.minecraftforge.installer.json.Util; public class Installer { - private static Install install; - public static boolean install() { ProgressCallback monitor = ProgressCallback.withOutputs(System.out); - install = Util.loadInstallProfile(); + Install install = Util.loadInstallProfile(); if (System.getProperty("java.net.preferIPv4Stack") == null) { System.setProperty("java.net.preferIPv4Stack", "true"); } @@ -20,16 +18,4 @@ public class Installer { monitor.message("java.net.preferIPv4Stack=" + System.getProperty("java.net.preferIPv4Stack")); return new ClientInstall4MultiMC(install, monitor).run(null, input -> true); } - - public static String getForgeVersion() { - return install.getVersion().substring(install.getVersion().lastIndexOf("-") + 1); - } - - public static String getMcVersion() { - return install.getMinecraft(); - } - - public static String getMcpVersion() { - return install.getData(true).get("MCP_VERSION").replace("'", ""); - } } -- cgit 0.0.5-2-1-g0f52 From bd7373a320b90b5eb90a2fd4ca76b8d9d4f8ef28 Mon Sep 17 00:00:00 2001 From: ZekerZhayard Date: Fri, 20 Mar 2020 22:08:13 +0800 Subject: Add --cursepack argument for installing curseforge modpack. --- README.md | 20 ++- build.gradle | 3 +- gradle/wrapper/gradle-wrapper.properties | 3 +- .../cpw/mods/forge/cursepacklocator/Murmur2.java | 166 +++++++++++++++++++++ .../forgewrapper/converter/Converter.java | 72 +++++++-- .../zekerzhayard/forgewrapper/converter/Main.java | 46 ++++-- .../forgewrapper/installer/Download.java | 38 +++-- 7 files changed, 307 insertions(+), 41 deletions(-) create mode 100644 src/main/java/cpw/mods/forge/cursepacklocator/Murmur2.java diff --git a/README.md b/README.md index db9aed1db6..5e9d2b5707 100644 --- a/README.md +++ b/README.md @@ -4,13 +4,27 @@ Allow MultiMC to launch Minecraft 1.13+ with Forge. ## How to use -1. Download Forge installer for Minecraft 1.13+ at [https://files.minecraftforge.net/]. +### Install Forge Only +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. Run the below command in terminal: ``` - java -jar [--installer] [--instance ] + java -jar --installer= [--instance=] ``` *Notice: If you don't specify a MultiMC instance path, ForgeWrapper will create the instance folder in current working space.* 4. If the instance folder which just created is not in `MultiMC/instances` folder, you just need to move to the `MultiMC/instances` folder. -5. Run MultiMC, and you will see a new instance named `forge--`. \ No newline at end of file +5. Run MultiMC, and you will see a new instance named `forge--`. + +### Install CurseForge Modpack +1. Download the modpack zip file. +2. Download ForgeWrapper jar file at the [release](https://github.com/ZekerZhayard/ForgeWrapper/releases) page. +3. Run the below command in terminal: + ``` + java -jar --cursepack= [--instance=] + ``` + *Notice: If you don't specify a MultiMC instance path, ForgeWrapper will create the instance folder in current working space.* + +4. If the instance folder which just created is not in `MultiMC/instances` folder, you just need to move to the `MultiMC/instances` folder. +5. Run MultiMC, and you will see a new instance named `-`. +*Notice: CurseForge modpack will be installed on first launch by [cursepacklocator](https://github.com/cpw/cursepacklocator), it will take a few minutes.* \ No newline at end of file diff --git a/build.gradle b/build.gradle index fa854059d1..13e5703295 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ apply plugin: "idea" sourceCompatibility = targetCompatibility = 1.8 -version = "1.1.0" +version = "1.2.0" group = "io.github.zekerzhayard" archivesBaseName = rootProject.name @@ -19,7 +19,6 @@ repositories { } dependencies { - compile "commons-codec:commons-codec:1.10" compile "cpw.mods:modlauncher:4.1.0" compile "net.minecraftforge:forge:1.14.4-28.2.0:installer" } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 290541c738..d193c615fa 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ +#Thu Mar 12 20:06:29 CST 2020 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.3-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.3-all.zip diff --git a/src/main/java/cpw/mods/forge/cursepacklocator/Murmur2.java b/src/main/java/cpw/mods/forge/cursepacklocator/Murmur2.java new file mode 100644 index 0000000000..f754e18b16 --- /dev/null +++ b/src/main/java/cpw/mods/forge/cursepacklocator/Murmur2.java @@ -0,0 +1,166 @@ +/** + * Copyright 2014 Prasanth Jayachandran + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package cpw.mods.forge.cursepacklocator; + +/** + * Murmur2 32 and 64 bit variants. + * 32-bit Java port of https://code.google.com/p/smhasher/source/browse/trunk/MurmurHash2.cpp#37 + * 64-bit Java port of https://code.google.com/p/smhasher/source/browse/trunk/MurmurHash2.cpp#96 + */ +public class Murmur2 { + // Constants for 32-bit variant + private static final int M_32 = 0x5bd1e995; + private static final int R_32 = 24; + + // Constants for 64-bit variant + private static final long M_64 = 0xc6a4a7935bd1e995L; + private static final int R_64 = 47; + private static final int DEFAULT_SEED = 0; + + /** + * Murmur2 32-bit variant. + * + * @param data - input byte array + * @return - hashcode + */ + public static int hash32(byte[] data) { + return hash32(data, data.length, DEFAULT_SEED); + } + + /** + * Murmur2 32-bit variant. + * + * @param data - input byte array + * @param length - length of array + * @param seed - seed. (default 0) + * @return - hashcode + */ + public static int hash32(byte[] data, int length, int seed) { + int h = seed ^ length; + int len_4 = length >> 2; + + // body + for (int i = 0; i < len_4; i++) { + int i_4 = i << 2; + int k = (data[i_4] & 0xff) + | ((data[i_4 + 1] & 0xff) << 8) + | ((data[i_4 + 2] & 0xff) << 16) + | ((data[i_4 + 3] & 0xff) << 24); + + // mix functions + k *= M_32; + k ^= k >>> R_32; + k *= M_32; + h *= M_32; + h ^= k; + } + + // tail + int len_m = len_4 << 2; + int left = length - len_m; + if (left != 0) { + // see https://github.com/cpw/cursepacklocator/pull/3 + if (left >= 3) { + h ^= (int) data[length - (left - 2)] << 16; + } + if (left >= 2) { + h ^= (int) data[length - (left - 1)] << 8; + } + if (left >= 1) { + h ^= (int) data[length - left]; + } + + h *= M_32; + } + + // finalization + h ^= h >>> 13; + h *= M_32; + h ^= h >>> 15; + + return h; + } + + /** + * Murmur2 64-bit variant. + * + * @param data - input byte array + * @return - hashcode + */ + public static long hash64(final byte[] data) { + return hash64(data, data.length, DEFAULT_SEED); + } + + /** + * Murmur2 64-bit variant. + * + * @param data - input byte array + * @param length - length of array + * @param seed - seed. (default 0) + * @return - hashcode + */ + public static long hash64(final byte[] data, int length, int seed) { + long h = (seed & 0xffffffffl) ^ (length * M_64); + int length8 = length >> 3; + + // body + for (int i = 0; i < length8; i++) { + final int i8 = i << 3; + long k = ((long) data[i8] & 0xff) + | (((long) data[i8 + 1] & 0xff) << 8) + | (((long) data[i8 + 2] & 0xff) << 16) + | (((long) data[i8 + 3] & 0xff) << 24) + | (((long) data[i8 + 4] & 0xff) << 32) + | (((long) data[i8 + 5] & 0xff) << 40) + | (((long) data[i8 + 6] & 0xff) << 48) + | (((long) data[i8 + 7] & 0xff) << 56); + + // mix functions + k *= M_64; + k ^= k >>> R_64; + k *= M_64; + h ^= k; + h *= M_64; + } + + // tail + int tailStart = length8 << 3; + switch (length - tailStart) { + case 7: + h ^= (long) (data[tailStart + 6] & 0xff) << 48; + case 6: + h ^= (long) (data[tailStart + 5] & 0xff) << 40; + case 5: + h ^= (long) (data[tailStart + 4] & 0xff) << 32; + case 4: + h ^= (long) (data[tailStart + 3] & 0xff) << 24; + case 3: + h ^= (long) (data[tailStart + 2] & 0xff) << 16; + case 2: + h ^= (long) (data[tailStart + 1] & 0xff) << 8; + case 1: + h ^= (long) (data[tailStart] & 0xff); + h *= M_64; + } + + // finalization + h ^= h >>> R_64; + h *= M_64; + h ^= h >>> R_64; + + return h; + } +} \ No newline at end of file diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java b/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java index f9737eb62e..0fe1262b21 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java @@ -8,8 +8,8 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; -import java.nio.file.StandardOpenOption; import java.util.ArrayList; +import java.util.Enumeration; import java.util.List; import java.util.Map; import java.util.Optional; @@ -21,26 +21,32 @@ import com.google.gson.JsonElement; import com.google.gson.JsonNull; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import io.github.zekerzhayard.forgewrapper.installer.Download; public class Converter { - public static void convert(Path installerPath, Path targetDir) throws Exception { - JsonObject installer = getInstallerJson(installerPath); + public static void convert(Path installerPath, Path targetDir, String cursepack) throws Exception { + if (cursepack != null) { + installerPath = getForgeInstallerFromCursePack(cursepack); + } + + JsonObject installer = getJsonFromZip(installerPath, "version.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; + String instanceName = cursepack == null ? forgeFullVersion : installerPath.toFile().getName().replace("-installer.jar", ""); StringBuilder wrapperVersion = new StringBuilder(); JsonObject pack = convertPackJson(mcVersion); - JsonObject patches = convertPatchesJson(installer, mcVersion, forgeVersion, wrapperVersion); + JsonObject patches = convertPatchesJson(installer, mcVersion, forgeVersion, wrapperVersion, cursepack); Files.createDirectories(targetDir); // Copy mmc-pack.json and instance.cfg to folder. - Path instancePath = targetDir.resolve(forgeFullVersion); + Path instancePath = targetDir.resolve(instanceName); 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); + Files.copy(new ByteArrayInputStream(("InstanceType=OneSix\nname=" + instanceName).getBytes(StandardCharsets.UTF_8)), instancePath.resolve("instance.cfg"), StandardCopyOption.REPLACE_EXISTING); // Copy ForgeWrapper to /libraries folder. Path librariesPath = instancePath.resolve("libraries"); @@ -56,10 +62,22 @@ public class Converter { Path forgeWrapperPath = instancePath.resolve(".minecraft").resolve(".forgewrapper"); Files.createDirectories(forgeWrapperPath); Files.copy(installerPath, forgeWrapperPath.resolve(forgeFullVersion + "-installer.jar"), StandardCopyOption.REPLACE_EXISTING); + + // Extract all curse pack entries to /.minecraft folder. + if (cursepack != null) { + ZipFile zip = new ZipFile(cursepack); + Enumeration entries = zip.entries(); + while (entries.hasMoreElements()) { + ZipEntry entry = entries.nextElement(); + Path targetFolder = forgeWrapperPath.getParent().resolve(entry.getName()); + Files.createDirectories(targetFolder.getParent()); + Files.copy(zip.getInputStream(entry), targetFolder, StandardCopyOption.REPLACE_EXISTING); + } + } } public static List getAdditionalArgs(Path installerPath) { - JsonObject installer = getInstallerJson(installerPath); + JsonObject installer = getJsonFromZip(installerPath, "version.json"); return getAdditionalArgs(installer); } @@ -69,12 +87,12 @@ public class Converter { return args; } - public static JsonObject getInstallerJson(Path installerPath) { + public static JsonObject getJsonFromZip(Path path, String json) { try { - ZipFile zf = new ZipFile(installerPath.toFile()); - ZipEntry versionFile = zf.getEntry("version.json"); + ZipFile zf = new ZipFile(path.toFile()); + ZipEntry versionFile = zf.getEntry(json); if (versionFile == null) { - throw new RuntimeException("The forge installer is invalid!"); + throw new RuntimeException("The zip file is invalid!"); } InputStreamReader isr = new InputStreamReader(zf.getInputStream(versionFile), StandardCharsets.UTF_8); return new JsonParser().parse(isr).getAsJsonObject(); @@ -83,6 +101,28 @@ public class Converter { } } + private static Path getForgeInstallerFromCursePack(String cursepack) throws Exception { + JsonObject manifest = getJsonFromZip(Paths.get(cursepack), "manifest.json"); + JsonObject minecraft = getElement(manifest, "minecraft").getAsJsonObject(); + String mcVersion = getElement(minecraft, "version").getAsString(); + String forgeVersion = null; + for (JsonElement element : getElement(minecraft, "modLoaders").getAsJsonArray()) { + String id = getElement(element.getAsJsonObject(), "id").getAsString(); + if (id.startsWith("forge-")) { + forgeVersion = id.replace("forge-", ""); + break; + } + } + if (forgeVersion == null) { + throw new RuntimeException("The curse pack is invalid!"); + } + String packName = getElement(manifest, "name").getAsString(); + String packVersion = getElement(manifest, "version").getAsString(); + Path installer = Paths.get(System.getProperty("java.io.tmpdir", "."), String.format("%s-%s-installer.jar", packName, packVersion)); + Download.download(String.format("https://files.minecraftforge.net/maven/net/minecraftforge/forge/%s-%s/forge-%s-%s-installer.jar", mcVersion, forgeVersion, mcVersion, forgeVersion), installer.toString()); + return installer; + } + // Convert mmc-pack.json: // - Replace Minecraft version private static JsonObject convertPackJson(String mcVersion) { @@ -102,7 +142,7 @@ public class Converter { // - Add libraries // - Add forge-launcher url // - Replace Minecraft & Forge versions - private static JsonObject convertPatchesJson(JsonObject installer, String mcVersion, String forgeVersion, StringBuilder wrapperVersion) { + private static JsonObject convertPatchesJson(JsonObject installer, String mcVersion, String forgeVersion, StringBuilder wrapperVersion, String cursepack) { JsonObject patches = new JsonParser().parse(new InputStreamReader(Converter.class.getResourceAsStream("/patches/net.minecraftforge.json"))).getAsJsonObject(); JsonArray libraries = getElement(patches, "libraries").getAsJsonArray(); @@ -112,10 +152,16 @@ public class Converter { wrapperVersion.append(getElement(lib.getAsJsonObject(), "MMC-filename").getAsString()); } } + if (cursepack != null) { + JsonObject cursepacklocator = new JsonObject(); + cursepacklocator.addProperty("name", "cpw.mods.forge:cursepacklocator:1.2.0"); + cursepacklocator.addProperty("url", "https://files.minecraftforge.net/maven/"); + libraries.add(cursepacklocator); + } for (JsonElement lib : getElement(installer ,"libraries").getAsJsonArray()) { JsonObject artifact = getElement(getElement(lib.getAsJsonObject(), "downloads").getAsJsonObject(), "artifact").getAsJsonObject(); String path = getElement(artifact, "path").getAsString(); - if (path.startsWith("net/minecraftforge/forge/")) { + if (path.equals(String.format("net/minecraftforge/forge/%s-%s/forge-%s-%s.jar", mcVersion, forgeVersion, mcVersion, forgeVersion))) { artifact.getAsJsonObject().addProperty("url", "https://files.minecraftforge.net/maven/" + path.replace(".jar", "-launcher.jar")); } libraries.add(lib); diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Main.java b/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Main.java index a9d4c38e64..31f84be635 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Main.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Main.java @@ -4,21 +4,30 @@ import java.net.URL; import java.net.URLClassLoader; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Arrays; +import java.util.HashMap; + +import io.github.zekerzhayard.forgewrapper.installer.Download; public class Main { public static void main(String[] args) { - ArrayList argsList = new ArrayList<>(Arrays.asList(args)); - Path installer, instance; + Path installer = null, instance = Paths.get("."); + String cursepack = null; try { - installer = Paths.get(argsList.get(argsList.indexOf("--installer") + 1)); - instance = Paths.get("."); - if (argsList.contains("--instance")) { - instance = Paths.get(argsList.get(argsList.indexOf("--instance") + 1)); + HashMap argsMap = parseArgs(args); + if (argsMap.containsKey("--installer")) { + installer = Paths.get(argsMap.get("--installer")); + } else { + installer = Paths.get(System.getProperty("java.io.tmpdir", "."), "gson-2.8.6.jar"); + Download.download("https://repo1.maven.org/maven2/com/google/code/gson/gson/2.8.6/gson-2.8.6.jar", installer.toString()); + } + if (argsMap.containsKey("--instance")) { + instance = Paths.get(argsMap.get("--instance")); + } + if (argsMap.containsKey("--cursepack")) { + cursepack = argsMap.get("--cursepack"); } } catch (Exception e) { - System.out.println("Invalid arguments! Use: java -jar [--installer] [--instance ]"); + System.out.println("Invalid arguments! Use: java -jar [--installer= | --cursepack=] [--instance=]"); throw new RuntimeException(e); } @@ -27,11 +36,28 @@ public class Main { Converter.class.getProtectionDomain().getCodeSource().getLocation(), installer.toUri().toURL() }, null); - ucl.loadClass("io.github.zekerzhayard.forgewrapper.converter.Converter").getMethod("convert", Path.class, Path.class).invoke(null, installer, instance); + ucl.loadClass("io.github.zekerzhayard.forgewrapper.converter.Converter").getMethod("convert", Path.class, Path.class, String.class).invoke(null, installer, instance, cursepack); 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") && !map.containsKey("--cursepack")) { + throw new IllegalArgumentException(); + } + return map; + } } diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Download.java b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Download.java index 38846f5843..c89687fd2f 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Download.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Download.java @@ -1,26 +1,28 @@ package io.github.zekerzhayard.forgewrapper.installer; +import java.io.BufferedReader; import java.io.File; import java.io.IOException; +import java.io.InputStreamReader; import java.net.URL; import java.nio.file.Files; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.Locale; -import org.apache.commons.codec.digest.DigestUtils; - public class Download { - public static void download(String url, String location) throws IOException { + private static final char[] DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + + public static void download(String url, String location) throws Exception { File localFile = new File(location); localFile.getParentFile().mkdirs(); if (localFile.isFile()) { try { System.out.println("Checking Fingerprints of installer..."); - Files.copy(new URL(url + ".md5").openConnection().getInputStream(), Paths.get(location + ".md5"), StandardCopyOption.REPLACE_EXISTING); - Files.copy(new URL(url + ".sha1").openConnection().getInputStream(), Paths.get(location + ".sha1"), StandardCopyOption.REPLACE_EXISTING); - String md5 = new String(Files.readAllBytes(Paths.get(location + ".md5"))); - String sha1 = new String(Files.readAllBytes(Paths.get(location + ".sha1"))); + String md5 = new BufferedReader(new InputStreamReader(new URL(url + ".md5").openConnection().getInputStream())).readLine(); + String sha1 = new BufferedReader(new InputStreamReader(new URL(url + ".sha1").openConnection().getInputStream())).readLine(); if (!checkMD5(location, md5) || !checkSHA1(location, sha1)) { System.out.println("Fingerprints do not match!"); localFile.delete(); @@ -33,19 +35,31 @@ public class Download { if (localFile.isDirectory()) { throw new RuntimeException(location + " must be a file!"); } - System.out.println("Downloading forge installer..."); + System.out.println("Downloading forge installer... (" + url + " ---> " + location + ")"); Files.copy(new URL(url).openConnection().getInputStream(), Paths.get(location), StandardCopyOption.REPLACE_EXISTING); download(url, location); } } - public static boolean checkMD5(String path, String hash) throws IOException { - String md5 = DigestUtils.md5Hex(Files.readAllBytes(Paths.get(path))); + public static boolean checkMD5(String path, String hash) throws IOException, NoSuchAlgorithmException { + String md5 = new String(encodeHex(MessageDigest.getInstance("MD5").digest(Files.readAllBytes(Paths.get(path))))); + System.out.println("MD5: " + hash + " ---> " + md5); return md5.toLowerCase(Locale.ENGLISH).equals(hash.toLowerCase(Locale.ENGLISH)); } - public static boolean checkSHA1(String path, String hash) throws IOException { - String sha1 = DigestUtils.sha1Hex(Files.readAllBytes(Paths.get(path))); + public static boolean checkSHA1(String path, String hash) throws IOException, NoSuchAlgorithmException { + String sha1 = new String(encodeHex(MessageDigest.getInstance("SHA-1").digest(Files.readAllBytes(Paths.get(path))))); + System.out.println("SHA-1: " + hash + " ---> " + sha1); return sha1.toLowerCase(Locale.ENGLISH).equals(hash.toLowerCase(Locale.ENGLISH)); } + + private static char[] encodeHex(final byte[] data) { + final int l = data.length; + final char[] out = new char[l << 1]; + for (int i = 0, j = 0; i < l; i++) { + out[j++] = DIGITS[(0xF0 & data[i]) >>> 4]; + out[j++] = DIGITS[0x0F & data[i]]; + } + return out; + } } -- cgit 0.0.5-2-1-g0f52 From ee84a6bc895a6b1308fe184984df5f12f5ab9869 Mon Sep 17 00:00:00 2001 From: ZekerZhayard Date: Fri, 20 Mar 2020 22:12:33 +0800 Subject: Update README.md. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5e9d2b5707..2a8a9b5318 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # ForgeWrapper -Allow MultiMC to launch Minecraft 1.13+ with Forge. +Allow [MultiMC](https://github.com/MultiMC/MultiMC5) to launch Minecraft 1.13+ with Forge. ## How to use @@ -26,5 +26,5 @@ Allow MultiMC to launch Minecraft 1.13+ with Forge. *Notice: If you don't specify a MultiMC instance path, ForgeWrapper will create the instance folder in current working space.* 4. If the instance folder which just created is not in `MultiMC/instances` folder, you just need to move to the `MultiMC/instances` folder. -5. Run MultiMC, and you will see a new instance named `-`. +5. Run MultiMC, and you will see a new instance named `-`. *Notice: CurseForge modpack will be installed on first launch by [cursepacklocator](https://github.com/cpw/cursepacklocator), it will take a few minutes.* \ No newline at end of file -- cgit 0.0.5-2-1-g0f52 From c04ad2e036fd965bc9114d2bc8dcbfffa1174eb7 Mon Sep 17 00:00:00 2001 From: ZekerZhayard Date: Thu, 26 Mar 2020 15:12:30 +0800 Subject: Why does MultiMC target me? --- build.gradle | 2 +- .../io/github/zekerzhayard/forgewrapper/Main.java | 50 ------------- .../io/github/zekerzhayard/forgewrapper/Utils.java | 82 +++++++++++++--------- .../forgewrapper/converter/Converter.java | 23 +++--- .../zekerzhayard/forgewrapper/converter/Main.java | 4 +- .../installer/ClientInstall4MultiMC.java | 13 +++- .../forgewrapper/installer/Download.java | 65 ----------------- .../zekerzhayard/forgewrapper/installer/Main.java | 34 +++++++++ src/main/java/why/does/multimc/target/Me.java | 9 +++ src/main/resources/patches/net.minecraftforge.json | 3 +- 10 files changed, 120 insertions(+), 165 deletions(-) delete mode 100644 src/main/java/io/github/zekerzhayard/forgewrapper/Main.java delete mode 100644 src/main/java/io/github/zekerzhayard/forgewrapper/installer/Download.java create mode 100644 src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java create mode 100644 src/main/java/why/does/multimc/target/Me.java diff --git a/build.gradle b/build.gradle index 13e5703295..d5b5bc0e23 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ apply plugin: "idea" sourceCompatibility = targetCompatibility = 1.8 -version = "1.2.0" +version = "1.3.0" group = "io.github.zekerzhayard" archivesBaseName = rootProject.name diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/Main.java b/src/main/java/io/github/zekerzhayard/forgewrapper/Main.java deleted file mode 100644 index 146c970638..0000000000 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/Main.java +++ /dev/null @@ -1,50 +0,0 @@ -package io.github.zekerzhayard.forgewrapper; - -import java.io.File; -import java.net.URL; -import java.net.URLClassLoader; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import cpw.mods.modlauncher.Launcher; -import io.github.zekerzhayard.forgewrapper.converter.Converter; -import io.github.zekerzhayard.forgewrapper.installer.Download; - -public class Main { - public static void main(String[] args) throws Exception { - URL[] urls = Utils.getURLs(new ArrayList<>()); - Pattern pattern = Pattern.compile("forge-(?[0-9.]+)-(?[0-9.]+)\\.jar"); - String version = ""; - String installerFileStr = ""; - for (URL url : urls) { - Matcher matcher = pattern.matcher(url.getFile()); - if (matcher.find() && url.getFile().endsWith(matcher.group(0))) { - version = matcher.group("mcVersion") + "-" + matcher.group("forgeVersion"); - String installerUrl = String.format("https://files.minecraftforge.net/maven/net/minecraftforge/forge/%s/forge-%s-installer.jar", version, version); - installerFileStr = String.format("./.forgewrapper/forge-%s-installer.jar", version); - Download.download(installerUrl, installerFileStr); - break; - } - } - - URLClassLoader ucl = URLClassLoader.newInstance(new URL[] { - Main.class.getProtectionDomain().getCodeSource().getLocation(), - Launcher.class.getProtectionDomain().getCodeSource().getLocation(), - new File(installerFileStr).toURI().toURL() - }, null); - - Class installer = ucl.loadClass("io.github.zekerzhayard.forgewrapper.installer.Installer"); - if (!(boolean) installer.getMethod("install").invoke(null)) { - return; - } - List argsList = Stream.of(args).collect(Collectors.toList()); - argsList.addAll(Converter.getAdditionalArgs(Paths.get(installerFileStr))); - - Launcher.main(argsList.toArray(new String[0])); - } -} diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/Utils.java b/src/main/java/io/github/zekerzhayard/forgewrapper/Utils.java index 3d3921d8e6..f309d69b6c 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/Utils.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/Utils.java @@ -1,47 +1,65 @@ package io.github.zekerzhayard.forgewrapper; +import java.io.BufferedReader; import java.io.File; -import java.net.MalformedURLException; -import java.net.URISyntaxException; +import java.io.IOException; +import java.io.InputStreamReader; import java.net.URL; -import java.net.URLClassLoader; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import cpw.mods.modlauncher.Launcher; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Locale; public class Utils { - public static URL[] getURLs(List blackList) { - ClassLoader cl = Utils.class.getClassLoader(); - List urls = new ArrayList<>(); - if (cl instanceof URLClassLoader) { - urls.addAll(Stream.of(((URLClassLoader) cl).getURLs()).filter(url -> blackList.stream().noneMatch(str -> url.getFile().endsWith(str))).collect(Collectors.toList())); - } else { - String[] elements = System.getProperty("java.class.path").split(File.pathSeparator); + private static final char[] DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; - for (String ele : elements) { - try { - if (blackList.stream().noneMatch(ele::endsWith)) { - urls.add(new File(ele).toURI().toURL()); - } - } catch (MalformedURLException e) { - e.printStackTrace(); + public static void download(String url, String location) throws Exception { + File localFile = new File(location); + localFile.getParentFile().mkdirs(); + if (localFile.isFile()) { + try { + System.out.println("Checking Fingerprints of installer..."); + String md5 = new BufferedReader(new InputStreamReader(new URL(url + ".md5").openConnection().getInputStream())).readLine(); + String sha1 = new BufferedReader(new InputStreamReader(new URL(url + ".sha1").openConnection().getInputStream())).readLine(); + if (!checkMD5(location, md5) || !checkSHA1(location, sha1)) { + System.out.println("Fingerprints do not match!"); + localFile.delete(); } + } catch (IOException e) { + e.printStackTrace(); + } + } + if (!localFile.isFile()) { + if (localFile.isDirectory()) { + throw new RuntimeException(location + " must be a file!"); } + System.out.println("Downloading forge installer... (" + url + " ---> " + location + ")"); + Files.copy(new URL(url).openConnection().getInputStream(), Paths.get(location), StandardCopyOption.REPLACE_EXISTING); + download(url, location); } - return urls.toArray(new URL[0]); } - public static File getLibrariesDir() { - try { - File laucnher = new File(Launcher.class.getProtectionDomain().getCodeSource().getLocation().toURI()); - // see https://github.com/MinecraftForge/MinecraftForge/blob/863ab2ca184cf2e2dfa134d07bfc20d6a9a6a4e8/src/main/java/net/minecraftforge/fml/relauncher/libraries/LibraryManager.java#L151 - // / /modlauncher /mods /cpw /libraries - return laucnher.getParentFile().getParentFile().getParentFile().getParentFile().getParentFile(); - } catch (URISyntaxException e) { - throw new RuntimeException(e); + public static boolean checkMD5(String path, String hash) throws IOException, NoSuchAlgorithmException { + String md5 = new String(encodeHex(MessageDigest.getInstance("MD5").digest(Files.readAllBytes(Paths.get(path))))); + System.out.println("MD5: " + hash + " ---> " + md5); + return md5.toLowerCase(Locale.ENGLISH).equals(hash.toLowerCase(Locale.ENGLISH)); + } + + public static boolean checkSHA1(String path, String hash) throws IOException, NoSuchAlgorithmException { + String sha1 = new String(encodeHex(MessageDigest.getInstance("SHA-1").digest(Files.readAllBytes(Paths.get(path))))); + System.out.println("SHA-1: " + hash + " ---> " + sha1); + return sha1.toLowerCase(Locale.ENGLISH).equals(hash.toLowerCase(Locale.ENGLISH)); + } + + private static char[] encodeHex(final byte[] data) { + final int l = data.length; + final char[] out = new char[l << 1]; + for (int i = 0, j = 0; i < l; i++) { + out[j++] = DIGITS[(0xF0 & data[i]) >>> 4]; + out[j++] = DIGITS[0x0F & data[i]]; } + return out; } } diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java b/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java index 0fe1262b21..060ef77902 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java @@ -21,7 +21,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonNull; import com.google.gson.JsonObject; import com.google.gson.JsonParser; -import io.github.zekerzhayard.forgewrapper.installer.Download; +import io.github.zekerzhayard.forgewrapper.Utils; public class Converter { public static void convert(Path installerPath, Path targetDir, String cursepack) throws Exception { @@ -58,27 +58,23 @@ public class Converter { 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 /.minecraft/.forgewrapper folder. - Path forgeWrapperPath = instancePath.resolve(".minecraft").resolve(".forgewrapper"); - Files.createDirectories(forgeWrapperPath); - Files.copy(installerPath, forgeWrapperPath.resolve(forgeFullVersion + "-installer.jar"), StandardCopyOption.REPLACE_EXISTING); - // Extract all curse pack entries to /.minecraft folder. + Path minecraftPath = instancePath.resolve(".minecraft"); if (cursepack != null) { ZipFile zip = new ZipFile(cursepack); Enumeration entries = zip.entries(); while (entries.hasMoreElements()) { ZipEntry entry = entries.nextElement(); - Path targetFolder = forgeWrapperPath.getParent().resolve(entry.getName()); + Path targetFolder = minecraftPath.resolve(entry.getName()); Files.createDirectories(targetFolder.getParent()); Files.copy(zip.getInputStream(entry), targetFolder, StandardCopyOption.REPLACE_EXISTING); } } - } - public static List getAdditionalArgs(Path installerPath) { - JsonObject installer = getJsonFromZip(installerPath, "version.json"); - return getAdditionalArgs(installer); + // Copy forge installer to /.minecraft/.forgewrapper folder. + Path forgeWrapperPath = minecraftPath.resolve(".forgewrapper"); + Files.createDirectories(forgeWrapperPath); + Files.copy(installerPath, forgeWrapperPath.resolve(forgeFullVersion + "-installer.jar"), StandardCopyOption.REPLACE_EXISTING); } public static List getAdditionalArgs(JsonObject installer) { @@ -119,7 +115,7 @@ public class Converter { String packName = getElement(manifest, "name").getAsString(); String packVersion = getElement(manifest, "version").getAsString(); Path installer = Paths.get(System.getProperty("java.io.tmpdir", "."), String.format("%s-%s-installer.jar", packName, packVersion)); - Download.download(String.format("https://files.minecraftforge.net/maven/net/minecraftforge/forge/%s-%s/forge-%s-%s-installer.jar", mcVersion, forgeVersion, mcVersion, forgeVersion), installer.toString()); + Utils.download(String.format("https://files.minecraftforge.net/maven/net/minecraftforge/forge/%s-%s/forge-%s-%s-installer.jar", mcVersion, forgeVersion, mcVersion, forgeVersion), installer.toString()); return installer; } @@ -146,6 +142,9 @@ public class Converter { JsonObject patches = new JsonParser().parse(new InputStreamReader(Converter.class.getResourceAsStream("/patches/net.minecraftforge.json"))).getAsJsonObject(); 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 lib : libraries) { String name = getElement(lib.getAsJsonObject(), "name").getAsString(); if (name.startsWith("io.github.zekerzhayard:ForgeWrapper:")) { diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Main.java b/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Main.java index 31f84be635..0b4d7369b0 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Main.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Main.java @@ -6,7 +6,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.HashMap; -import io.github.zekerzhayard.forgewrapper.installer.Download; +import io.github.zekerzhayard.forgewrapper.Utils; public class Main { public static void main(String[] args) { @@ -18,7 +18,7 @@ public class Main { installer = Paths.get(argsMap.get("--installer")); } else { installer = Paths.get(System.getProperty("java.io.tmpdir", "."), "gson-2.8.6.jar"); - Download.download("https://repo1.maven.org/maven2/com/google/code/gson/gson/2.8.6/gson-2.8.6.jar", installer.toString()); + Utils.download("https://repo1.maven.org/maven2/com/google/code/gson/gson/2.8.6/gson-2.8.6.jar", installer.toString()); } if (argsMap.containsKey("--instance")) { instance = Paths.get(argsMap.get("--instance")); diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/ClientInstall4MultiMC.java b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/ClientInstall4MultiMC.java index d104a18c7b..ff61563242 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/ClientInstall4MultiMC.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/ClientInstall4MultiMC.java @@ -1,9 +1,10 @@ package io.github.zekerzhayard.forgewrapper.installer; import java.io.File; +import java.net.URISyntaxException; import java.util.function.Predicate; -import io.github.zekerzhayard.forgewrapper.Utils; +import cpw.mods.modlauncher.Launcher; import net.minecraftforge.installer.actions.ActionCanceledException; import net.minecraftforge.installer.actions.ClientInstall; import net.minecraftforge.installer.actions.ProgressCallback; @@ -16,7 +17,15 @@ public class ClientInstall4MultiMC extends ClientInstall { @Override public boolean run(File target, Predicate optionals) { - File librariesDir = Utils.getLibrariesDir(); + File librariesDir; + try { + File laucnher = new File(Launcher.class.getProtectionDomain().getCodeSource().getLocation().toURI()); + // see https://github.com/MinecraftForge/MinecraftForge/blob/863ab2ca184cf2e2dfa134d07bfc20d6a9a6a4e8/src/main/java/net/minecraftforge/fml/relauncher/libraries/LibraryManager.java#L151 + // / /modlauncher /mods /cpw /libraries + librariesDir = laucnher.getParentFile().getParentFile().getParentFile().getParentFile().getParentFile(); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } File clientTarget = new File(String.format("%s/com/mojang/minecraft/%s/minecraft-%s-client.jar", librariesDir.getAbsolutePath(), this.profile.getMinecraft(), this.profile.getMinecraft())); boolean downloadLibraries = true; // Force true when without an internet connection. diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Download.java b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Download.java deleted file mode 100644 index c89687fd2f..0000000000 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Download.java +++ /dev/null @@ -1,65 +0,0 @@ -package io.github.zekerzhayard.forgewrapper.installer; - -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Locale; - -public class Download { - private static final char[] DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; - - public static void download(String url, String location) throws Exception { - File localFile = new File(location); - localFile.getParentFile().mkdirs(); - if (localFile.isFile()) { - try { - System.out.println("Checking Fingerprints of installer..."); - String md5 = new BufferedReader(new InputStreamReader(new URL(url + ".md5").openConnection().getInputStream())).readLine(); - String sha1 = new BufferedReader(new InputStreamReader(new URL(url + ".sha1").openConnection().getInputStream())).readLine(); - if (!checkMD5(location, md5) || !checkSHA1(location, sha1)) { - System.out.println("Fingerprints do not match!"); - localFile.delete(); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - if (!localFile.isFile()) { - if (localFile.isDirectory()) { - throw new RuntimeException(location + " must be a file!"); - } - System.out.println("Downloading forge installer... (" + url + " ---> " + location + ")"); - Files.copy(new URL(url).openConnection().getInputStream(), Paths.get(location), StandardCopyOption.REPLACE_EXISTING); - download(url, location); - } - } - - public static boolean checkMD5(String path, String hash) throws IOException, NoSuchAlgorithmException { - String md5 = new String(encodeHex(MessageDigest.getInstance("MD5").digest(Files.readAllBytes(Paths.get(path))))); - System.out.println("MD5: " + hash + " ---> " + md5); - return md5.toLowerCase(Locale.ENGLISH).equals(hash.toLowerCase(Locale.ENGLISH)); - } - - public static boolean checkSHA1(String path, String hash) throws IOException, NoSuchAlgorithmException { - String sha1 = new String(encodeHex(MessageDigest.getInstance("SHA-1").digest(Files.readAllBytes(Paths.get(path))))); - System.out.println("SHA-1: " + hash + " ---> " + sha1); - return sha1.toLowerCase(Locale.ENGLISH).equals(hash.toLowerCase(Locale.ENGLISH)); - } - - private static char[] encodeHex(final byte[] data) { - final int l = data.length; - final char[] out = new char[l << 1]; - for (int i = 0, j = 0; i < l; i++) { - out[j++] = DIGITS[(0xF0 & data[i]) >>> 4]; - out[j++] = DIGITS[0x0F & data[i]]; - } - return out; - } -} diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java new file mode 100644 index 0000000000..1e8c365ba5 --- /dev/null +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java @@ -0,0 +1,34 @@ +package io.github.zekerzhayard.forgewrapper.installer; + +import java.io.File; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import cpw.mods.modlauncher.Launcher; +import io.github.zekerzhayard.forgewrapper.Utils; + +public class Main { + public static void main(String[] args) throws Exception { + List argsList = Stream.of(args).collect(Collectors.toList()); + String version = argsList.get(argsList.indexOf("--fml.mcVersion") + 1) + "-" + argsList.get(argsList.indexOf("--fml.forgeVersion") + 1); + String installerUrl = String.format("https://files.minecraftforge.net/maven/net/minecraftforge/forge/%s/forge-%s-installer.jar", version, version); + String installerFileStr = String.format("./.forgewrapper/forge-%s-installer.jar", version); + Utils.download(installerUrl, installerFileStr); + + URLClassLoader ucl = URLClassLoader.newInstance(new URL[] { + Main.class.getProtectionDomain().getCodeSource().getLocation(), + Launcher.class.getProtectionDomain().getCodeSource().getLocation(), + new File(installerFileStr).toURI().toURL() + }, null); + + Class installer = ucl.loadClass("io.github.zekerzhayard.forgewrapper.installer.Installer"); + if (!(boolean) installer.getMethod("install").invoke(null)) { + return; + } + + Launcher.main(args); + } +} diff --git a/src/main/java/why/does/multimc/target/Me.java b/src/main/java/why/does/multimc/target/Me.java new file mode 100644 index 0000000000..2d82a72b9c --- /dev/null +++ b/src/main/java/why/does/multimc/target/Me.java @@ -0,0 +1,9 @@ +package why.does.multimc.target; + +import io.github.zekerzhayard.forgewrapper.installer.Main; + +public class Me { + public static void main(String[] args) throws Exception { + Main.main(args); + } +} diff --git a/src/main/resources/patches/net.minecraftforge.json b/src/main/resources/patches/net.minecraftforge.json index b037e07057..d30c5bb32e 100644 --- a/src/main/resources/patches/net.minecraftforge.json +++ b/src/main/resources/patches/net.minecraftforge.json @@ -1,6 +1,7 @@ { "formatVersion": 1, - "mainClass": "io.github.zekerzhayard.forgewrapper.Main", + "mainClass": "why.does.multimc.target.Me", + "minecraftArguments": "", "name": "Forge", "requires": [ { -- cgit 0.0.5-2-1-g0f52 From 812a810acc6d516652310634eee5c49351796e2c Mon Sep 17 00:00:00 2001 From: ZekerZhayard Date: Thu, 26 Mar 2020 20:46:22 +0800 Subject: Skip installing forge while extract files exist. --- build.gradle | 2 +- .../installer/ClientInstall4MultiMC.java | 12 +----- .../zekerzhayard/forgewrapper/installer/Main.java | 46 ++++++++++++++++------ src/main/java/why/does/multimc/target/Me.java | 9 ----- src/main/resources/patches/net.minecraftforge.json | 4 +- 5 files changed, 37 insertions(+), 36 deletions(-) delete mode 100644 src/main/java/why/does/multimc/target/Me.java diff --git a/build.gradle b/build.gradle index d5b5bc0e23..39d82af4ce 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ apply plugin: "idea" sourceCompatibility = targetCompatibility = 1.8 -version = "1.3.0" +version = "1.3.1" group = "io.github.zekerzhayard" archivesBaseName = rootProject.name diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/ClientInstall4MultiMC.java b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/ClientInstall4MultiMC.java index ff61563242..dbe8dafd18 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/ClientInstall4MultiMC.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/ClientInstall4MultiMC.java @@ -1,10 +1,8 @@ package io.github.zekerzhayard.forgewrapper.installer; import java.io.File; -import java.net.URISyntaxException; import java.util.function.Predicate; -import cpw.mods.modlauncher.Launcher; import net.minecraftforge.installer.actions.ActionCanceledException; import net.minecraftforge.installer.actions.ClientInstall; import net.minecraftforge.installer.actions.ProgressCallback; @@ -17,15 +15,7 @@ public class ClientInstall4MultiMC extends ClientInstall { @Override public boolean run(File target, Predicate optionals) { - File librariesDir; - try { - File laucnher = new File(Launcher.class.getProtectionDomain().getCodeSource().getLocation().toURI()); - // see https://github.com/MinecraftForge/MinecraftForge/blob/863ab2ca184cf2e2dfa134d07bfc20d6a9a6a4e8/src/main/java/net/minecraftforge/fml/relauncher/libraries/LibraryManager.java#L151 - // / /modlauncher /mods /cpw /libraries - librariesDir = laucnher.getParentFile().getParentFile().getParentFile().getParentFile().getParentFile(); - } catch (URISyntaxException e) { - throw new RuntimeException(e); - } + File librariesDir = Main.getLibrariesDir(); File clientTarget = new File(String.format("%s/com/mojang/minecraft/%s/minecraft-%s-client.jar", librariesDir.getAbsolutePath(), this.profile.getMinecraft(), this.profile.getMinecraft())); boolean downloadLibraries = true; // Force true when without an internet connection. 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 1e8c365ba5..cd70fac004 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java @@ -1,8 +1,11 @@ package io.github.zekerzhayard.forgewrapper.installer; import java.io.File; +import java.net.URISyntaxException; import java.net.URL; import java.net.URLClassLoader; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -14,21 +17,38 @@ public class Main { public static void main(String[] args) throws Exception { List argsList = Stream.of(args).collect(Collectors.toList()); String version = argsList.get(argsList.indexOf("--fml.mcVersion") + 1) + "-" + argsList.get(argsList.indexOf("--fml.forgeVersion") + 1); - String installerUrl = String.format("https://files.minecraftforge.net/maven/net/minecraftforge/forge/%s/forge-%s-installer.jar", version, version); - String installerFileStr = String.format("./.forgewrapper/forge-%s-installer.jar", version); - Utils.download(installerUrl, installerFileStr); - - URLClassLoader ucl = URLClassLoader.newInstance(new URL[] { - Main.class.getProtectionDomain().getCodeSource().getLocation(), - Launcher.class.getProtectionDomain().getCodeSource().getLocation(), - new File(installerFileStr).toURI().toURL() - }, null); - - Class installer = ucl.loadClass("io.github.zekerzhayard.forgewrapper.installer.Installer"); - if (!(boolean) installer.getMethod("install").invoke(null)) { - return; + + Path forgeDir = getLibrariesDir().toPath().resolve("net").resolve("minecraftforge").resolve("forge").resolve(version); + Path clientJar = forgeDir.resolve("forge-" + version + "-client.jar"); + Path extraJar = forgeDir.resolve("forge-" + version + "-extra.jar"); + if (Files.exists(clientJar) && Files.exists(extraJar)) { + String installerUrl = String.format("https://files.minecraftforge.net/maven/net/minecraftforge/forge/%s/forge-%s-installer.jar", version, version); + String installerFileStr = String.format("./.forgewrapper/forge-%s-installer.jar", version); + Utils.download(installerUrl, installerFileStr); + + URLClassLoader ucl = URLClassLoader.newInstance(new URL[] { + Main.class.getProtectionDomain().getCodeSource().getLocation(), + Launcher.class.getProtectionDomain().getCodeSource().getLocation(), + new File(installerFileStr).toURI().toURL() + }, null); + + Class installer = ucl.loadClass("io.github.zekerzhayard.forgewrapper.installer.Installer"); + if (!(boolean) installer.getMethod("install").invoke(null)) { + return; + } } Launcher.main(args); } + + public static File getLibrariesDir() { + try { + File laucnher = new File(Launcher.class.getProtectionDomain().getCodeSource().getLocation().toURI()); + // see https://github.com/MinecraftForge/MinecraftForge/blob/863ab2ca184cf2e2dfa134d07bfc20d6a9a6a4e8/src/main/java/net/minecraftforge/fml/relauncher/libraries/LibraryManager.java#L151 + // / /modlauncher /mods /cpw /libraries + return laucnher.getParentFile().getParentFile().getParentFile().getParentFile().getParentFile(); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } } diff --git a/src/main/java/why/does/multimc/target/Me.java b/src/main/java/why/does/multimc/target/Me.java deleted file mode 100644 index 2d82a72b9c..0000000000 --- a/src/main/java/why/does/multimc/target/Me.java +++ /dev/null @@ -1,9 +0,0 @@ -package why.does.multimc.target; - -import io.github.zekerzhayard.forgewrapper.installer.Main; - -public class Me { - public static void main(String[] args) throws Exception { - Main.main(args); - } -} diff --git a/src/main/resources/patches/net.minecraftforge.json b/src/main/resources/patches/net.minecraftforge.json index d30c5bb32e..1add7375e8 100644 --- a/src/main/resources/patches/net.minecraftforge.json +++ b/src/main/resources/patches/net.minecraftforge.json @@ -1,6 +1,6 @@ { "formatVersion": 1, - "mainClass": "why.does.multimc.target.Me", + "mainClass": "io.github.zekerzhayard.forgewrapper.installer.Main", "minecraftArguments": "", "name": "Forge", "requires": [ @@ -14,7 +14,7 @@ "version": "{FORGE_VERSION}", "libraries": [ { - "name": "io.github.zekerzhayard:ForgeWrapper:${version}", + "name": "io.github.zekerzhayard:Forge-Wrapper:${version}", "MMC-hint": "local", "MMC-filename": "ForgeWrapper-${version}.jar" } -- cgit 0.0.5-2-1-g0f52 From fb8888aed984dfca9b57c5a61b622205a9578d28 Mon Sep 17 00:00:00 2001 From: ZekerZhayard Date: Fri, 27 Mar 2020 14:11:43 +0800 Subject: All libraries can be downloaded by MultiMC now. --- build.gradle | 6 +-- .../forgewrapper/converter/Converter.java | 49 +++++++++++++++------- .../zekerzhayard/forgewrapper/converter/Main.java | 5 ++- .../installer/ClientInstall4MultiMC.java | 11 ----- .../zekerzhayard/forgewrapper/installer/Main.java | 31 ++++++++------ src/main/resources/patches/net.minecraftforge.json | 8 +++- 6 files changed, 64 insertions(+), 46 deletions(-) diff --git a/build.gradle b/build.gradle index 39d82af4ce..d1dfebe8f7 100644 --- a/build.gradle +++ b/build.gradle @@ -5,16 +5,14 @@ apply plugin: "idea" sourceCompatibility = targetCompatibility = 1.8 -version = "1.3.1" +version = "1.4.0" group = "io.github.zekerzhayard" archivesBaseName = rootProject.name repositories { - mavenCentral() - jcenter() maven { name = "forge" - url = "https://files.minecraftforge.net/maven" + url = "https://files.minecraftforge.net/maven/" } } diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java b/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java index 060ef77902..983310a67d 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java @@ -10,6 +10,7 @@ import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.util.ArrayList; import java.util.Enumeration; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; @@ -24,12 +25,13 @@ import com.google.gson.JsonParser; import io.github.zekerzhayard.forgewrapper.Utils; public class Converter { - public static void convert(Path installerPath, Path targetDir, String cursepack) throws Exception { + public static void convert(Path installerPath, Path targetDir, Path multimcDir, String cursepack) throws Exception { if (cursepack != null) { installerPath = getForgeInstallerFromCursePack(cursepack); } 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); @@ -38,7 +40,7 @@ public class Converter { StringBuilder wrapperVersion = new StringBuilder(); JsonObject pack = convertPackJson(mcVersion); - JsonObject patches = convertPatchesJson(installer, mcVersion, forgeVersion, wrapperVersion, cursepack); + JsonObject patches = convertPatchesJson(installer, installProfile, mcVersion, forgeVersion, wrapperVersion, cursepack); Files.createDirectories(targetDir); @@ -71,10 +73,12 @@ public class Converter { } } - // Copy forge installer to /.minecraft/.forgewrapper folder. - Path forgeWrapperPath = minecraftPath.resolve(".forgewrapper"); - Files.createDirectories(forgeWrapperPath); - Files.copy(installerPath, forgeWrapperPath.resolve(forgeFullVersion + "-installer.jar"), StandardCopyOption.REPLACE_EXISTING); + // Copy forge installer to MultiMC/libraries/net/minecraftforge/forge/- folder. + if (multimcDir != null) { + Path targetInstallerPath = multimcDir.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) { @@ -138,13 +142,18 @@ public class Converter { // - Add libraries // - Add forge-launcher url // - Replace Minecraft & Forge versions - private static JsonObject convertPatchesJson(JsonObject installer, String mcVersion, String forgeVersion, StringBuilder wrapperVersion, String cursepack) { + private static JsonObject convertPatchesJson(JsonObject installer, JsonObject installProfile, String mcVersion, String forgeVersion, StringBuilder wrapperVersion, String cursepack) { JsonObject patches = new JsonParser().parse(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:")) { @@ -157,14 +166,13 @@ public class Converter { cursepacklocator.addProperty("url", "https://files.minecraftforge.net/maven/"); libraries.add(cursepacklocator); } - for (JsonElement lib : getElement(installer ,"libraries").getAsJsonArray()) { - JsonObject artifact = getElement(getElement(lib.getAsJsonObject(), "downloads").getAsJsonObject(), "artifact").getAsJsonObject(); - String path = getElement(artifact, "path").getAsString(); - if (path.equals(String.format("net/minecraftforge/forge/%s-%s/forge-%s-%s.jar", mcVersion, forgeVersion, mcVersion, forgeVersion))) { - artifact.getAsJsonObject().addProperty("url", "https://files.minecraftforge.net/maven/" + path.replace(".jar", "-launcher.jar")); - } - libraries.add(lib); - } + 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://files.minecraftforge.net/maven/" + 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); patches.addProperty("version", forgeVersion); for (JsonElement require : getElement(patches, "requires").getAsJsonArray()) { @@ -183,4 +191,15 @@ public class Converter { } 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/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Main.java b/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Main.java index 0b4d7369b0..312f9c31ab 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Main.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Main.java @@ -10,7 +10,7 @@ import io.github.zekerzhayard.forgewrapper.Utils; public class Main { public static void main(String[] args) { - Path installer = null, instance = Paths.get("."); + Path installer = null, instance = Paths.get("."), multimc = null; String cursepack = null; try { HashMap argsMap = parseArgs(args); @@ -22,6 +22,7 @@ public class Main { } if (argsMap.containsKey("--instance")) { instance = Paths.get(argsMap.get("--instance")); + multimc = instance.getParent(); } if (argsMap.containsKey("--cursepack")) { cursepack = argsMap.get("--cursepack"); @@ -36,7 +37,7 @@ public class Main { Converter.class.getProtectionDomain().getCodeSource().getLocation(), installer.toUri().toURL() }, null); - ucl.loadClass("io.github.zekerzhayard.forgewrapper.converter.Converter").getMethod("convert", Path.class, Path.class, String.class).invoke(null, installer, instance, cursepack); + ucl.loadClass("io.github.zekerzhayard.forgewrapper.converter.Converter").getMethod("convert", Path.class, Path.class, Path.class, String.class).invoke(null, installer, instance, multimc, cursepack); System.out.println("Successfully install Forge for MultiMC!"); } catch (Exception e) { System.out.println("Failed to install Forge!"); diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/ClientInstall4MultiMC.java b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/ClientInstall4MultiMC.java index dbe8dafd18..f2db3748cf 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/ClientInstall4MultiMC.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/ClientInstall4MultiMC.java @@ -3,7 +3,6 @@ package io.github.zekerzhayard.forgewrapper.installer; import java.io.File; import java.util.function.Predicate; -import net.minecraftforge.installer.actions.ActionCanceledException; import net.minecraftforge.installer.actions.ClientInstall; import net.minecraftforge.installer.actions.ProgressCallback; import net.minecraftforge.installer.json.Install; @@ -17,16 +16,6 @@ public class ClientInstall4MultiMC extends ClientInstall { public boolean run(File target, Predicate optionals) { File librariesDir = Main.getLibrariesDir(); File clientTarget = new File(String.format("%s/com/mojang/minecraft/%s/minecraft-%s-client.jar", librariesDir.getAbsolutePath(), this.profile.getMinecraft(), this.profile.getMinecraft())); - - boolean downloadLibraries = true; // Force true when without an internet connection. - try { - downloadLibraries = this.downloadLibraries(librariesDir, optionals); - } catch (ActionCanceledException e) { - e.printStackTrace(); - } - if (!downloadLibraries) { - return false; - } return this.processors.process(librariesDir, clientTarget); } } 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 cd70fac004..f9d534c270 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java @@ -11,25 +11,23 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import cpw.mods.modlauncher.Launcher; -import io.github.zekerzhayard.forgewrapper.Utils; public class Main { public static void main(String[] args) throws Exception { List argsList = Stream.of(args).collect(Collectors.toList()); - String version = argsList.get(argsList.indexOf("--fml.mcVersion") + 1) + "-" + argsList.get(argsList.indexOf("--fml.forgeVersion") + 1); - - Path forgeDir = getLibrariesDir().toPath().resolve("net").resolve("minecraftforge").resolve("forge").resolve(version); - Path clientJar = forgeDir.resolve("forge-" + version + "-client.jar"); - Path extraJar = forgeDir.resolve("forge-" + version + "-extra.jar"); - if (Files.exists(clientJar) && Files.exists(extraJar)) { - String installerUrl = String.format("https://files.minecraftforge.net/maven/net/minecraftforge/forge/%s/forge-%s-installer.jar", version, version); - String installerFileStr = String.format("./.forgewrapper/forge-%s-installer.jar", version); - Utils.download(installerUrl, installerFileStr); - + String mcVersion = argsList.get(argsList.indexOf("--fml.mcVersion") + 1); + String mcpFullVersion = mcVersion + "-" + argsList.get(argsList.indexOf("--fml.mcpVersion") + 1); + String forgeFullVersion = mcVersion + "-" + argsList.get(argsList.indexOf("--fml.forgeVersion") + 1); + + Path librariesDir = getLibrariesDir().toPath(); + Path minecraftDir = librariesDir.resolve("net").resolve("minecraft").resolve("client"); + Path forgeDir = librariesDir.resolve("net").resolve("minecraftforge").resolve("forge").resolve(forgeFullVersion); + if (getAdditionalLibraries(minecraftDir, forgeDir, mcVersion, forgeFullVersion, mcpFullVersion).anyMatch(path -> !Files.exists(path))) { + System.out.println("Some extra libraries are missing! Run installer to spawn them now."); URLClassLoader ucl = URLClassLoader.newInstance(new URL[] { Main.class.getProtectionDomain().getCodeSource().getLocation(), Launcher.class.getProtectionDomain().getCodeSource().getLocation(), - new File(installerFileStr).toURI().toURL() + forgeDir.resolve("forge-" + forgeFullVersion + "-installer.jar").toUri().toURL() }, null); Class installer = ucl.loadClass("io.github.zekerzhayard.forgewrapper.installer.Installer"); @@ -44,11 +42,18 @@ public class Main { public static File getLibrariesDir() { try { File laucnher = new File(Launcher.class.getProtectionDomain().getCodeSource().getLocation().toURI()); - // see https://github.com/MinecraftForge/MinecraftForge/blob/863ab2ca184cf2e2dfa134d07bfc20d6a9a6a4e8/src/main/java/net/minecraftforge/fml/relauncher/libraries/LibraryManager.java#L151 // / /modlauncher /mods /cpw /libraries return laucnher.getParentFile().getParentFile().getParentFile().getParentFile().getParentFile(); } catch (URISyntaxException e) { throw new RuntimeException(e); } } + + public static Stream getAdditionalLibraries(Path minecraftDir, Path forgeDir, String mcVersion, String forgeFullVersion, String mcpFullVersion) { + return Stream.of( + forgeDir.resolve("forge-" + forgeFullVersion + "-client.jar"), + minecraftDir.resolve(mcVersion).resolve("client-" + mcVersion + "-extra.jar"), + minecraftDir.resolve(mcpFullVersion).resolve("client-" + mcpFullVersion + "-srg.jar") + ); + } } diff --git a/src/main/resources/patches/net.minecraftforge.json b/src/main/resources/patches/net.minecraftforge.json index 1add7375e8..d170dd25e8 100644 --- a/src/main/resources/patches/net.minecraftforge.json +++ b/src/main/resources/patches/net.minecraftforge.json @@ -12,9 +12,15 @@ "type": "release", "uid": "net.minecraftforge", "version": "{FORGE_VERSION}", + "mavenFiles": [ + { + "name": "net.minecraftforge:forge:{VERSION}-{FORGE_VERSION}:installer", + "url": "https://files.minecraftforge.net/maven/" + } + ], "libraries": [ { - "name": "io.github.zekerzhayard:Forge-Wrapper:${version}", + "name": "io.github.zekerzhayard:ForgeWrapper:${version}", "MMC-hint": "local", "MMC-filename": "ForgeWrapper-${version}.jar" } -- cgit 0.0.5-2-1-g0f52 From 9f65af36b0b25292cf9455b66f7ee273fa1ff729 Mon Sep 17 00:00:00 2001 From: ZekerZhayard Date: Sun, 29 Mar 2020 02:03:57 +0800 Subject: Fix compatibility with Java 9+. Remove unnecessary functions. --- README.md | 20 +-- build.gradle | 2 +- .../cpw/mods/forge/cursepacklocator/Murmur2.java | 166 --------------------- .../io/github/zekerzhayard/forgewrapper/Utils.java | 65 -------- .../forgewrapper/converter/Converter.java | 60 +------- .../zekerzhayard/forgewrapper/converter/Main.java | 19 +-- .../zekerzhayard/forgewrapper/installer/Main.java | 16 +- 7 files changed, 29 insertions(+), 319 deletions(-) delete mode 100644 src/main/java/cpw/mods/forge/cursepacklocator/Murmur2.java delete mode 100644 src/main/java/io/github/zekerzhayard/forgewrapper/Utils.java diff --git a/README.md b/README.md index 2a8a9b5318..f490261c16 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,10 @@ Allow [MultiMC](https://github.com/MultiMC/MultiMC5) to launch Minecraft 1.13+ with Forge. -## How to use +**ForgeWrapper has been adopted by MultiMC, you do not need to perform the following steps manually. (2020-03-29)** + +## How to use (Outdated) -### Install Forge Only 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. Run the below command in terminal: @@ -14,17 +15,4 @@ Allow [MultiMC](https://github.com/MultiMC/MultiMC5) to launch Minecraft 1.13+ w *Notice: If you don't specify a MultiMC instance path, ForgeWrapper will create the instance folder in current working space.* 4. If the instance folder which just created is not in `MultiMC/instances` folder, you just need to move to the `MultiMC/instances` folder. -5. Run MultiMC, and you will see a new instance named `forge--`. - -### Install CurseForge Modpack -1. Download the modpack zip file. -2. Download ForgeWrapper jar file at the [release](https://github.com/ZekerZhayard/ForgeWrapper/releases) page. -3. Run the below command in terminal: - ``` - java -jar --cursepack= [--instance=] - ``` - *Notice: If you don't specify a MultiMC instance path, ForgeWrapper will create the instance folder in current working space.* - -4. If the instance folder which just created is not in `MultiMC/instances` folder, you just need to move to the `MultiMC/instances` folder. -5. Run MultiMC, and you will see a new instance named `-`. -*Notice: CurseForge modpack will be installed on first launch by [cursepacklocator](https://github.com/cpw/cursepacklocator), it will take a few minutes.* \ No newline at end of file +5. Run MultiMC, and you will see a new instance named `forge--`. \ No newline at end of file diff --git a/build.gradle b/build.gradle index d1dfebe8f7..c5016005c4 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ apply plugin: "idea" sourceCompatibility = targetCompatibility = 1.8 -version = "1.4.0" +version = "1.4.1" group = "io.github.zekerzhayard" archivesBaseName = rootProject.name diff --git a/src/main/java/cpw/mods/forge/cursepacklocator/Murmur2.java b/src/main/java/cpw/mods/forge/cursepacklocator/Murmur2.java deleted file mode 100644 index f754e18b16..0000000000 --- a/src/main/java/cpw/mods/forge/cursepacklocator/Murmur2.java +++ /dev/null @@ -1,166 +0,0 @@ -/** - * Copyright 2014 Prasanth Jayachandran - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package cpw.mods.forge.cursepacklocator; - -/** - * Murmur2 32 and 64 bit variants. - * 32-bit Java port of https://code.google.com/p/smhasher/source/browse/trunk/MurmurHash2.cpp#37 - * 64-bit Java port of https://code.google.com/p/smhasher/source/browse/trunk/MurmurHash2.cpp#96 - */ -public class Murmur2 { - // Constants for 32-bit variant - private static final int M_32 = 0x5bd1e995; - private static final int R_32 = 24; - - // Constants for 64-bit variant - private static final long M_64 = 0xc6a4a7935bd1e995L; - private static final int R_64 = 47; - private static final int DEFAULT_SEED = 0; - - /** - * Murmur2 32-bit variant. - * - * @param data - input byte array - * @return - hashcode - */ - public static int hash32(byte[] data) { - return hash32(data, data.length, DEFAULT_SEED); - } - - /** - * Murmur2 32-bit variant. - * - * @param data - input byte array - * @param length - length of array - * @param seed - seed. (default 0) - * @return - hashcode - */ - public static int hash32(byte[] data, int length, int seed) { - int h = seed ^ length; - int len_4 = length >> 2; - - // body - for (int i = 0; i < len_4; i++) { - int i_4 = i << 2; - int k = (data[i_4] & 0xff) - | ((data[i_4 + 1] & 0xff) << 8) - | ((data[i_4 + 2] & 0xff) << 16) - | ((data[i_4 + 3] & 0xff) << 24); - - // mix functions - k *= M_32; - k ^= k >>> R_32; - k *= M_32; - h *= M_32; - h ^= k; - } - - // tail - int len_m = len_4 << 2; - int left = length - len_m; - if (left != 0) { - // see https://github.com/cpw/cursepacklocator/pull/3 - if (left >= 3) { - h ^= (int) data[length - (left - 2)] << 16; - } - if (left >= 2) { - h ^= (int) data[length - (left - 1)] << 8; - } - if (left >= 1) { - h ^= (int) data[length - left]; - } - - h *= M_32; - } - - // finalization - h ^= h >>> 13; - h *= M_32; - h ^= h >>> 15; - - return h; - } - - /** - * Murmur2 64-bit variant. - * - * @param data - input byte array - * @return - hashcode - */ - public static long hash64(final byte[] data) { - return hash64(data, data.length, DEFAULT_SEED); - } - - /** - * Murmur2 64-bit variant. - * - * @param data - input byte array - * @param length - length of array - * @param seed - seed. (default 0) - * @return - hashcode - */ - public static long hash64(final byte[] data, int length, int seed) { - long h = (seed & 0xffffffffl) ^ (length * M_64); - int length8 = length >> 3; - - // body - for (int i = 0; i < length8; i++) { - final int i8 = i << 3; - long k = ((long) data[i8] & 0xff) - | (((long) data[i8 + 1] & 0xff) << 8) - | (((long) data[i8 + 2] & 0xff) << 16) - | (((long) data[i8 + 3] & 0xff) << 24) - | (((long) data[i8 + 4] & 0xff) << 32) - | (((long) data[i8 + 5] & 0xff) << 40) - | (((long) data[i8 + 6] & 0xff) << 48) - | (((long) data[i8 + 7] & 0xff) << 56); - - // mix functions - k *= M_64; - k ^= k >>> R_64; - k *= M_64; - h ^= k; - h *= M_64; - } - - // tail - int tailStart = length8 << 3; - switch (length - tailStart) { - case 7: - h ^= (long) (data[tailStart + 6] & 0xff) << 48; - case 6: - h ^= (long) (data[tailStart + 5] & 0xff) << 40; - case 5: - h ^= (long) (data[tailStart + 4] & 0xff) << 32; - case 4: - h ^= (long) (data[tailStart + 3] & 0xff) << 24; - case 3: - h ^= (long) (data[tailStart + 2] & 0xff) << 16; - case 2: - h ^= (long) (data[tailStart + 1] & 0xff) << 8; - case 1: - h ^= (long) (data[tailStart] & 0xff); - h *= M_64; - } - - // finalization - h ^= h >>> R_64; - h *= M_64; - h ^= h >>> R_64; - - return h; - } -} \ No newline at end of file diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/Utils.java b/src/main/java/io/github/zekerzhayard/forgewrapper/Utils.java deleted file mode 100644 index f309d69b6c..0000000000 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/Utils.java +++ /dev/null @@ -1,65 +0,0 @@ -package io.github.zekerzhayard.forgewrapper; - -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Locale; - -public class Utils { - private static final char[] DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; - - public static void download(String url, String location) throws Exception { - File localFile = new File(location); - localFile.getParentFile().mkdirs(); - if (localFile.isFile()) { - try { - System.out.println("Checking Fingerprints of installer..."); - String md5 = new BufferedReader(new InputStreamReader(new URL(url + ".md5").openConnection().getInputStream())).readLine(); - String sha1 = new BufferedReader(new InputStreamReader(new URL(url + ".sha1").openConnection().getInputStream())).readLine(); - if (!checkMD5(location, md5) || !checkSHA1(location, sha1)) { - System.out.println("Fingerprints do not match!"); - localFile.delete(); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - if (!localFile.isFile()) { - if (localFile.isDirectory()) { - throw new RuntimeException(location + " must be a file!"); - } - System.out.println("Downloading forge installer... (" + url + " ---> " + location + ")"); - Files.copy(new URL(url).openConnection().getInputStream(), Paths.get(location), StandardCopyOption.REPLACE_EXISTING); - download(url, location); - } - } - - public static boolean checkMD5(String path, String hash) throws IOException, NoSuchAlgorithmException { - String md5 = new String(encodeHex(MessageDigest.getInstance("MD5").digest(Files.readAllBytes(Paths.get(path))))); - System.out.println("MD5: " + hash + " ---> " + md5); - return md5.toLowerCase(Locale.ENGLISH).equals(hash.toLowerCase(Locale.ENGLISH)); - } - - public static boolean checkSHA1(String path, String hash) throws IOException, NoSuchAlgorithmException { - String sha1 = new String(encodeHex(MessageDigest.getInstance("SHA-1").digest(Files.readAllBytes(Paths.get(path))))); - System.out.println("SHA-1: " + hash + " ---> " + sha1); - return sha1.toLowerCase(Locale.ENGLISH).equals(hash.toLowerCase(Locale.ENGLISH)); - } - - private static char[] encodeHex(final byte[] data) { - final int l = data.length; - final char[] out = new char[l << 1]; - for (int i = 0, j = 0; i < l; i++) { - out[j++] = DIGITS[(0xF0 & data[i]) >>> 4]; - out[j++] = DIGITS[0x0F & data[i]]; - } - return out; - } -} diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java b/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java index 983310a67d..403488bd95 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java @@ -9,7 +9,6 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.util.ArrayList; -import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -22,33 +21,27 @@ import com.google.gson.JsonElement; import com.google.gson.JsonNull; import com.google.gson.JsonObject; import com.google.gson.JsonParser; -import io.github.zekerzhayard.forgewrapper.Utils; public class Converter { - public static void convert(Path installerPath, Path targetDir, Path multimcDir, String cursepack) throws Exception { - if (cursepack != null) { - installerPath = getForgeInstallerFromCursePack(cursepack); - } - + 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; - String instanceName = cursepack == null ? forgeFullVersion : installerPath.toFile().getName().replace("-installer.jar", ""); StringBuilder wrapperVersion = new StringBuilder(); JsonObject pack = convertPackJson(mcVersion); - JsonObject patches = convertPatchesJson(installer, installProfile, mcVersion, forgeVersion, wrapperVersion, cursepack); + JsonObject patches = convertPatchesJson(installer, installProfile, mcVersion, forgeVersion, wrapperVersion); Files.createDirectories(targetDir); // Copy mmc-pack.json and instance.cfg to folder. - Path instancePath = targetDir.resolve(instanceName); + 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=" + instanceName).getBytes(StandardCharsets.UTF_8)), instancePath.resolve("instance.cfg"), 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"); @@ -60,22 +53,9 @@ public class Converter { Files.createDirectories(patchesPath); Files.copy(new ByteArrayInputStream(patches.toString().getBytes(StandardCharsets.UTF_8)), patchesPath.resolve("net.minecraftforge.json"), StandardCopyOption.REPLACE_EXISTING); - // Extract all curse pack entries to /.minecraft folder. - Path minecraftPath = instancePath.resolve(".minecraft"); - if (cursepack != null) { - ZipFile zip = new ZipFile(cursepack); - Enumeration entries = zip.entries(); - while (entries.hasMoreElements()) { - ZipEntry entry = entries.nextElement(); - Path targetFolder = minecraftPath.resolve(entry.getName()); - Files.createDirectories(targetFolder.getParent()); - Files.copy(zip.getInputStream(entry), targetFolder, StandardCopyOption.REPLACE_EXISTING); - } - } - // Copy forge installer to MultiMC/libraries/net/minecraftforge/forge/- folder. if (multimcDir != null) { - Path targetInstallerPath = multimcDir.resolve("net").resolve("minecraftforge").resolve("forge").resolve(forgeVersion); + 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); } @@ -101,28 +81,6 @@ public class Converter { } } - private static Path getForgeInstallerFromCursePack(String cursepack) throws Exception { - JsonObject manifest = getJsonFromZip(Paths.get(cursepack), "manifest.json"); - JsonObject minecraft = getElement(manifest, "minecraft").getAsJsonObject(); - String mcVersion = getElement(minecraft, "version").getAsString(); - String forgeVersion = null; - for (JsonElement element : getElement(minecraft, "modLoaders").getAsJsonArray()) { - String id = getElement(element.getAsJsonObject(), "id").getAsString(); - if (id.startsWith("forge-")) { - forgeVersion = id.replace("forge-", ""); - break; - } - } - if (forgeVersion == null) { - throw new RuntimeException("The curse pack is invalid!"); - } - String packName = getElement(manifest, "name").getAsString(); - String packVersion = getElement(manifest, "version").getAsString(); - Path installer = Paths.get(System.getProperty("java.io.tmpdir", "."), String.format("%s-%s-installer.jar", packName, packVersion)); - Utils.download(String.format("https://files.minecraftforge.net/maven/net/minecraftforge/forge/%s-%s/forge-%s-%s-installer.jar", mcVersion, forgeVersion, mcVersion, forgeVersion), installer.toString()); - return installer; - } - // Convert mmc-pack.json: // - Replace Minecraft version private static JsonObject convertPackJson(String mcVersion) { @@ -142,7 +100,7 @@ public class Converter { // - Add libraries // - Add forge-launcher url // - Replace Minecraft & Forge versions - private static JsonObject convertPatchesJson(JsonObject installer, JsonObject installProfile, String mcVersion, String forgeVersion, StringBuilder wrapperVersion, String cursepack) { + private static JsonObject convertPatchesJson(JsonObject installer, JsonObject installProfile, String mcVersion, String forgeVersion, StringBuilder wrapperVersion) { JsonObject patches = new JsonParser().parse(new InputStreamReader(Converter.class.getResourceAsStream("/patches/net.minecraftforge.json"))).getAsJsonObject(); JsonArray mavenFiles = getElement(patches, "mavenFiles").getAsJsonArray(); JsonArray libraries = getElement(patches, "libraries").getAsJsonArray(); @@ -160,12 +118,6 @@ public class Converter { wrapperVersion.append(getElement(lib.getAsJsonObject(), "MMC-filename").getAsString()); } } - if (cursepack != null) { - JsonObject cursepacklocator = new JsonObject(); - cursepacklocator.addProperty("name", "cpw.mods.forge:cursepacklocator:1.2.0"); - cursepacklocator.addProperty("url", "https://files.minecraftforge.net/maven/"); - libraries.add(cursepacklocator); - } 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://files.minecraftforge.net/maven/" + path + "-universal.jar"); diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Main.java b/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Main.java index 312f9c31ab..83ecdf959e 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Main.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Main.java @@ -6,29 +6,18 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.HashMap; -import io.github.zekerzhayard.forgewrapper.Utils; - public class Main { public static void main(String[] args) { Path installer = null, instance = Paths.get("."), multimc = null; - String cursepack = null; try { HashMap argsMap = parseArgs(args); - if (argsMap.containsKey("--installer")) { - installer = Paths.get(argsMap.get("--installer")); - } else { - installer = Paths.get(System.getProperty("java.io.tmpdir", "."), "gson-2.8.6.jar"); - Utils.download("https://repo1.maven.org/maven2/com/google/code/gson/gson/2.8.6/gson-2.8.6.jar", installer.toString()); - } + installer = Paths.get(argsMap.get("--installer")); if (argsMap.containsKey("--instance")) { instance = Paths.get(argsMap.get("--instance")); multimc = instance.getParent(); } - if (argsMap.containsKey("--cursepack")) { - cursepack = argsMap.get("--cursepack"); - } } catch (Exception e) { - System.out.println("Invalid arguments! Use: java -jar [--installer= | --cursepack=] [--instance=]"); + System.out.println("Invalid arguments! Use: java -jar --installer= [--instance=]"); throw new RuntimeException(e); } @@ -37,7 +26,7 @@ public class Main { 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, String.class).invoke(null, installer, instance, multimc, cursepack); + 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!"); @@ -56,7 +45,7 @@ public class Main { String[] params = arg.split("=", 2); map.put(params[0], params[1]); } - if (!map.containsKey("--installer") && !map.containsKey("--cursepack")) { + if (!map.containsKey("--installer")) { throw new IllegalArgumentException(); } return map; 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 f9d534c270..bd97c192d1 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java @@ -23,12 +23,12 @@ public class Main { Path minecraftDir = librariesDir.resolve("net").resolve("minecraft").resolve("client"); Path forgeDir = librariesDir.resolve("net").resolve("minecraftforge").resolve("forge").resolve(forgeFullVersion); if (getAdditionalLibraries(minecraftDir, forgeDir, mcVersion, forgeFullVersion, mcpFullVersion).anyMatch(path -> !Files.exists(path))) { - System.out.println("Some extra libraries are missing! Run installer to spawn them now."); + System.out.println("Some extra libraries are missing! Run the installer to generate them now."); URLClassLoader ucl = URLClassLoader.newInstance(new URL[] { Main.class.getProtectionDomain().getCodeSource().getLocation(), Launcher.class.getProtectionDomain().getCodeSource().getLocation(), forgeDir.resolve("forge-" + forgeFullVersion + "-installer.jar").toUri().toURL() - }, null); + }, getParentClassLoader()); Class installer = ucl.loadClass("io.github.zekerzhayard.forgewrapper.installer.Installer"); if (!(boolean) installer.getMethod("install").invoke(null)) { @@ -56,4 +56,16 @@ public class Main { minecraftDir.resolve(mcpFullVersion).resolve("client-" + mcpFullVersion + "-srg.jar") ); } + + // https://github.com/MinecraftForge/Installer/blob/fe18a164b5ebb15b5f8f33f6a149cc224f446dc2/src/main/java/net/minecraftforge/installer/actions/PostProcessors.java#L287-L303 + private static ClassLoader getParentClassLoader() { + if (!System.getProperty("java.version").startsWith("1.")) { + try { + return (ClassLoader) ClassLoader.class.getDeclaredMethod("getPlatformClassLoader").invoke(null); + } catch (Exception e) { + System.out.println("No platform classloader: " + System.getProperty("java.version")); + } + } + return null; + } } -- cgit 0.0.5-2-1-g0f52 From 29f602904a3ee7c3e92c3ee2036cf42bc10addb4 Mon Sep 17 00:00:00 2001 From: ZekerZhayard Date: Tue, 14 Jul 2020 03:56:34 +0800 Subject: Improve cache file detectors. --- README.md | 8 + build.gradle | 2 +- .../installer/ClientInstall4MultiMC.java | 11 +- .../forgewrapper/installer/Installer.java | 6 +- .../zekerzhayard/forgewrapper/installer/Main.java | 55 +++--- .../installer/detector/DetectorLoader.java | 35 ++++ .../installer/detector/IFileDetector.java | 201 +++++++++++++++++++++ .../installer/detector/MultiMCFileDetector.java | 46 +++++ ...d.forgewrapper.installer.detector.IFileDetector | 1 + 9 files changed, 327 insertions(+), 38 deletions(-) create mode 100644 src/main/java/io/github/zekerzhayard/forgewrapper/installer/detector/DetectorLoader.java create mode 100644 src/main/java/io/github/zekerzhayard/forgewrapper/installer/detector/IFileDetector.java create mode 100644 src/main/java/io/github/zekerzhayard/forgewrapper/installer/detector/MultiMCFileDetector.java create mode 100644 src/main/resources/META-INF/services/io.github.zekerzhayard.forgewrapper.installer.detector.IFileDetector diff --git a/README.md b/README.md index f490261c16..21e2b9640d 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,14 @@ Allow [MultiMC](https://github.com/MultiMC/MultiMC5) to launch Minecraft 1.13+ w **ForgeWrapper has been adopted by MultiMC, you do not need to perform the following steps manually. (2020-03-29)** +## For other launchers +1. ForgeWrapper provides some java properties since 1.4.2: + - `forgewrapper.librariesDir` : a path to libraries folder (e.g. -Dforgewrapper.librariesDir=/home/xxx/.minecraft/libraries) + - `forgewrapper.installer` : a path to forge installer (e.g. -Dforgewrapper.installer=/home/xxx/forge-1.14.4-28.2.0-installer.jar) + - `forgewrapper.minecraft` : a path to the vanilla minecraft jar (e.g. -Dforgewrapper.minecraft=/home/xxx/.minecraft/versions/1.14.4/1.14.4.jar) + +2. ForgeWrapper also provides an interface [`IFileDetector`](https://github.com/ZekerZhayard/ForgeWrapper/blob/master/src/main/java/io/github/zekerzhayard/forgewrapper/installer/detector/IFileDetector.java), you can implement it and custom your own detecting rules. To load it, you should make another jar which contains `META-INF/services/io.github.zekerzhayard.forgewrapper.installer.detector.IFileDetector` within the full implementation class name and add the jar to class path. + ## How to use (Outdated) 1. Download Forge installer for Minecraft 1.13+ [here](https://files.minecraftforge.net/). diff --git a/build.gradle b/build.gradle index c5016005c4..591fddd25c 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ apply plugin: "idea" sourceCompatibility = targetCompatibility = 1.8 -version = "1.4.1" +version = "1.4.2" group = "io.github.zekerzhayard" archivesBaseName = rootProject.name diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/ClientInstall4MultiMC.java b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/ClientInstall4MultiMC.java index f2db3748cf..ea7256416c 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/ClientInstall4MultiMC.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/ClientInstall4MultiMC.java @@ -8,14 +8,17 @@ import net.minecraftforge.installer.actions.ProgressCallback; import net.minecraftforge.installer.json.Install; public class ClientInstall4MultiMC extends ClientInstall { - public ClientInstall4MultiMC(Install profile, ProgressCallback monitor) { + protected File libraryDir; + protected File minecraftJar; + + public ClientInstall4MultiMC(Install profile, ProgressCallback monitor, File libraryDir, File minecraftJar) { super(profile, monitor); + this.libraryDir = libraryDir; + this.minecraftJar = minecraftJar; } @Override public boolean run(File target, Predicate optionals) { - File librariesDir = Main.getLibrariesDir(); - File clientTarget = new File(String.format("%s/com/mojang/minecraft/%s/minecraft-%s-client.jar", librariesDir.getAbsolutePath(), this.profile.getMinecraft(), this.profile.getMinecraft())); - return this.processors.process(librariesDir, clientTarget); + return this.processors.process(this.libraryDir, this.minecraftJar); } } diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java index ad60ad7375..1a822ce06e 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java @@ -1,11 +1,13 @@ package io.github.zekerzhayard.forgewrapper.installer; +import java.io.File; + import net.minecraftforge.installer.actions.ProgressCallback; import net.minecraftforge.installer.json.Install; import net.minecraftforge.installer.json.Util; public class Installer { - public static boolean install() { + public static boolean install(File libraryDir, File minecraftJar) { ProgressCallback monitor = ProgressCallback.withOutputs(System.out); Install install = Util.loadInstallProfile(); if (System.getProperty("java.net.preferIPv4Stack") == null) { @@ -16,6 +18,6 @@ public class Installer { String jvmVersion = System.getProperty("java.vm.version", "missing jvm version"); monitor.message(String.format("JVM info: %s - %s - %s", vendor, javaVersion, jvmVersion)); monitor.message("java.net.preferIPv4Stack=" + System.getProperty("java.net.preferIPv4Stack")); - return new ClientInstall4MultiMC(install, monitor).run(null, input -> true); + return new ClientInstall4MultiMC(install, monitor, libraryDir, minecraftJar).run(null, input -> true); } } 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 bd97c192d1..c52c272493 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java @@ -1,7 +1,6 @@ package io.github.zekerzhayard.forgewrapper.installer; import java.io.File; -import java.net.URISyntaxException; import java.net.URL; import java.net.URLClassLoader; import java.nio.file.Files; @@ -11,50 +10,44 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import cpw.mods.modlauncher.Launcher; +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 { List argsList = Stream.of(args).collect(Collectors.toList()); String mcVersion = argsList.get(argsList.indexOf("--fml.mcVersion") + 1); - String mcpFullVersion = mcVersion + "-" + argsList.get(argsList.indexOf("--fml.mcpVersion") + 1); String forgeFullVersion = mcVersion + "-" + argsList.get(argsList.indexOf("--fml.forgeVersion") + 1); - Path librariesDir = getLibrariesDir().toPath(); - Path minecraftDir = librariesDir.resolve("net").resolve("minecraft").resolve("client"); - Path forgeDir = librariesDir.resolve("net").resolve("minecraftforge").resolve("forge").resolve(forgeFullVersion); - if (getAdditionalLibraries(minecraftDir, forgeDir, mcVersion, forgeFullVersion, mcpFullVersion).anyMatch(path -> !Files.exists(path))) { + IFileDetector detector = DetectorLoader.loadDetector(); + if (!detector.checkExtraFiles(forgeFullVersion)) { System.out.println("Some extra libraries are missing! Run the installer to generate them now."); - URLClassLoader ucl = URLClassLoader.newInstance(new URL[] { - Main.class.getProtectionDomain().getCodeSource().getLocation(), - Launcher.class.getProtectionDomain().getCodeSource().getLocation(), - forgeDir.resolve("forge-" + forgeFullVersion + "-installer.jar").toUri().toURL() - }, getParentClassLoader()); - Class installer = ucl.loadClass("io.github.zekerzhayard.forgewrapper.installer.Installer"); - if (!(boolean) installer.getMethod("install").invoke(null)) { - return; + // Check installer jar. + Path installerJar = detector.getInstallerJar(forgeFullVersion); + if (!IFileDetector.isFile(installerJar)) { + throw new RuntimeException("Can't detect the forge installer!"); } - } - Launcher.main(args); - } + // Check vanilla Minecraft jar. + Path minecraftJar = detector.getMinecraftJar(mcVersion); + if (!IFileDetector.isFile(minecraftJar)) { + throw new RuntimeException("Can't detect the Minecraft jar!"); + } - public static File getLibrariesDir() { - try { - File laucnher = new File(Launcher.class.getProtectionDomain().getCodeSource().getLocation().toURI()); - // / /modlauncher /mods /cpw /libraries - return laucnher.getParentFile().getParentFile().getParentFile().getParentFile().getParentFile(); - } catch (URISyntaxException e) { - throw new RuntimeException(e); + try (URLClassLoader ucl = URLClassLoader.newInstance(new URL[] { + Main.class.getProtectionDomain().getCodeSource().getLocation(), + Launcher.class.getProtectionDomain().getCodeSource().getLocation(), + installerJar.toUri().toURL() + }, getParentClassLoader())) { + Class installer = ucl.loadClass("io.github.zekerzhayard.forgewrapper.installer.Installer"); + if (!(boolean) installer.getMethod("install", File.class, File.class).invoke(null, detector.getLibraryDir().toFile(), minecraftJar.toFile())) { + return; + } + } } - } - public static Stream getAdditionalLibraries(Path minecraftDir, Path forgeDir, String mcVersion, String forgeFullVersion, String mcpFullVersion) { - return Stream.of( - forgeDir.resolve("forge-" + forgeFullVersion + "-client.jar"), - minecraftDir.resolve(mcVersion).resolve("client-" + mcVersion + "-extra.jar"), - minecraftDir.resolve(mcpFullVersion).resolve("client-" + mcpFullVersion + "-srg.jar") - ); + Launcher.main(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/detector/DetectorLoader.java b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/detector/DetectorLoader.java new file mode 100644 index 0000000000..369c4b555d --- /dev/null +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/detector/DetectorLoader.java @@ -0,0 +1,35 @@ +package io.github.zekerzhayard.forgewrapper.installer.detector; + +import java.util.HashMap; +import java.util.Map; +import java.util.ServiceLoader; + +public class DetectorLoader { + public static IFileDetector loadDetector() { + ServiceLoader sl = ServiceLoader.load(IFileDetector.class); + HashMap detectors = new HashMap<>(); + for (IFileDetector detector : sl) { + detectors.put(detector.name(), detector); + } + + boolean enabled = false; + IFileDetector temp = null; + for (Map.Entry detector : detectors.entrySet()) { + HashMap others = new HashMap<>(detectors); + others.remove(detector.getKey()); + if (!enabled) { + enabled = detector.getValue().enabled(others); + if (enabled) { + temp = detector.getValue(); + } + } else if (detector.getValue().enabled(others)) { + throw new RuntimeException("There are two or more file detectors are enabled! (" + temp.toString() + ", " + detector.toString() + ")"); + } + } + + if (temp == null) { + throw new RuntimeException("No file detector is enabled!"); + } + return temp; + } +} 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 new file mode 100644 index 0000000000..b81670840b --- /dev/null +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/detector/IFileDetector.java @@ -0,0 +1,201 @@ +package io.github.zekerzhayard.forgewrapper.installer.detector; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.math.BigInteger; +import java.net.URISyntaxException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import com.google.gson.JsonElement; +import com.google.gson.JsonNull; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import cpw.mods.modlauncher.Launcher; + +public interface IFileDetector { + /** + * @return The name of the detector. + */ + String name(); + + /** + * If there are two or more detectors are enabled, an exception will be thrown. Removing anything from the map is in vain. + * @param others Other detectors. + * @return True represents enabled. + */ + boolean enabled(HashMap others); + + /** + * @return The ".minecraft/libraries" folder for normal. It can also be defined by JVM argument "-Dforgewrapper.librariesDir=<libraries-path>". + */ + default Path getLibraryDir() { + String libraryDir = System.getProperty("forgewrapper.librariesDir"); + if (libraryDir != null) { + return Paths.get(libraryDir).toAbsolutePath(); + } + try { + Path launcher = Paths.get(Launcher.class.getProtectionDomain().getCodeSource().getLocation().toURI()).toAbsolutePath(); + // / /modlauncher/mods /cpw /libraries + return launcher.getParent().getParent().getParent().getParent().getParent().toAbsolutePath(); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } + + /** + * @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) { + String installer = System.getProperty("forgewrapper.installer"); + if (installer != null) { + return Paths.get(installer).toAbsolutePath(); + } + return null; + } + + /** + * @param mcVersion Minecraft version (e.g. 1.14.4). + * @return The minecraft client jar path. It can also be defined by JVM argument "-Dforgewrapper.minecraft=<minecraft-path>". + */ + default Path getMinecraftJar(String mcVersion) { + String minecraft = System.getProperty("forgewrapper.minecraft"); + if (minecraft != null) { + return Paths.get(minecraft).toAbsolutePath(); + } + return null; + } + + /** + * @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) { + Path installer = this.getInstallerJar(forgeFullVersion); + if (isFile(installer)) { + try (ZipFile zf = new ZipFile(installer.toFile())) { + ZipEntry ze = zf.getEntry("install_profile.json"); + if (ze != null) { + try ( + InputStream is = zf.getInputStream(ze); + InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8) + ) { + for (Map.Entry entry : new JsonParser().parse(isr).getAsJsonObject().entrySet()) { + if (entry.getKey().equals("data")) { + return entry.getValue().getAsJsonObject(); + } + } + } + } + } catch (IOException e) { + e.printStackTrace(); + } + } else { + throw new RuntimeException("Can't detect the forge installer!"); + } + return null; + } + + /** + * Check all cached files. + * @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); + if (jo != null) { + Map libsMap = new HashMap<>(); + Map hashMap = new HashMap<>(); + + // Get all "data//client" elements. + for (Map.Entry entry : jo.entrySet()) { + String clientStr = getElement(entry.getValue().getAsJsonObject(), "client").getAsString(); + if (entry.getKey().endsWith("_SHA")) { + Pattern p = Pattern.compile("^'(?[A-Za-z0-9]{40})'$"); + Matcher m = p.matcher(clientStr); + if (m.find()) { + hashMap.put(entry.getKey(), m.group("sha1")); + } + } else { + Pattern p = Pattern.compile("^\\[(?[^:]*):(?[^:]*):(?[^:@]*)(:(?[^@]*))?(@(?[^]]*))?]$"); + Matcher m = p.matcher(clientStr); + if (m.find()) { + String groupId = nullToDefault(m.group("groupId"), ""); + String artifactId = nullToDefault(m.group("artifactId"), ""); + String version = nullToDefault(m.group("version"), ""); + String prefix = nullToDefault(m.group("prefix"), ""); + String type = nullToDefault(m.group("type"), "jar"); + libsMap.put(entry.getKey(), this.getLibraryDir() + .resolve(groupId.replace('.', File.separatorChar)) + .resolve(artifactId) + .resolve(version) + .resolve(artifactId + "-" + version + (prefix.equals("") ? "" : "-") + prefix + "." + type).toAbsolutePath()); + } + } + } + + // Check all cached libraries. + boolean checked = true; + for (Map.Entry entry : libsMap.entrySet()) { + checked = checked && this.checkExtraFile(entry.getValue(), hashMap.get(entry.getKey() + "_SHA")); + } + return checked; + } + // Skip installing process if installer profile doesn't exist. + return true; + } + + /** + * Check the exact file. + * @param path The path of the file to check. + * @param sha1 The sha1 defined in installer. + * @return True represents the file is ready. + */ + default boolean checkExtraFile(Path path, String sha1) { + return Files.isRegularFile(path) && (sha1 == null || sha1.equals("") || sha1.toLowerCase(Locale.ENGLISH).equals(getFileSHA1(path))); + } + + static boolean isFile(Path path) { + 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)); + while (sha1.length() < 40) { + sha1.insert(0, "0"); + } + return sha1.toString().toLowerCase(Locale.ENGLISH); + } catch (IOException | NoSuchAlgorithmException e) { + e.printStackTrace(); + } + return null; + } + + static String nullToDefault(String string, String defaultValue) { + return string == null ? defaultValue : string; + } +} 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 new file mode 100644 index 0000000000..cb87d27825 --- /dev/null +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/detector/MultiMCFileDetector.java @@ -0,0 +1,46 @@ +package io.github.zekerzhayard.forgewrapper.installer.detector; + +import java.nio.file.Path; +import java.util.HashMap; + +public class MultiMCFileDetector implements IFileDetector { + protected Path libraryDir = null; + protected Path installerJar = null; + protected Path minecraftJar = null; + + @Override + public String name() { + return "MultiMC"; + } + + @Override + public boolean enabled(HashMap others) { + return others.size() == 0; + } + + @Override + public Path getLibraryDir() { + if (this.libraryDir == null) { + this.libraryDir = IFileDetector.super.getLibraryDir(); + } + return this.libraryDir; + } + + @Override + public Path getInstallerJar(String forgeFullVersion) { + Path path = IFileDetector.super.getInstallerJar(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()); + } + return path; + } + + @Override + public Path getMinecraftJar(String mcVersion) { + Path path = IFileDetector.super.getMinecraftJar(mcVersion); + if (path == null) { + return this.minecraftJar != null ? this.minecraftJar : (this.minecraftJar = this.getLibraryDir().resolve("com").resolve("mojang").resolve("minecraft").resolve(mcVersion).resolve("minecraft-" + mcVersion + "-client.jar").toAbsolutePath()); + } + return path; + } +} 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 new file mode 100644 index 0000000000..44375f8732 --- /dev/null +++ b/src/main/resources/META-INF/services/io.github.zekerzhayard.forgewrapper.installer.detector.IFileDetector @@ -0,0 +1 @@ +io.github.zekerzhayard.forgewrapper.installer.detector.MultiMCFileDetector \ No newline at end of file -- cgit 0.0.5-2-1-g0f52 From 3aeeada18f679232315b49044d9045a256749132 Mon Sep 17 00:00:00 2001 From: ZekerZhayard Date: Fri, 23 Jul 2021 01:14:25 +0800 Subject: Fix crash on launch with forge-1.16.5-36.1.66. Add GitHub Actions. --- .github/workflows/build.yml | 25 ++++++ .github/workflows/maven.bat | 13 +++ .github/workflows/publication.yml | 54 ++++++++++++ build.gradle | 96 ++++++++++++++++++--- gradle.properties | 4 + gradle/wrapper/gradle-wrapper.jar | Bin 56177 -> 59536 bytes gradle/wrapper/gradle-wrapper.properties | 3 +- gradlew | 55 +++++++----- gradlew.bat | 43 +++++---- legacy/build.gradle | 17 ++++ .../installer/LegacyClientInstall4MultiMC.java | 24 ++++++ .../installer/util/LegacyInstallerUtil.java | 11 +++ settings.gradle | 11 +-- .../installer/ClientInstall4MultiMC.java | 7 +- .../forgewrapper/installer/Installer.java | 8 +- .../zekerzhayard/forgewrapper/installer/Main.java | 12 +-- .../forgewrapper/installer/MainV2.java | 15 ++++ .../forgewrapper/installer/util/InstallerUtil.java | 52 +++++++++++ .../META-INF/services/java.util.function.Consumer | 1 + 19 files changed, 375 insertions(+), 76 deletions(-) create mode 100644 .github/workflows/build.yml create mode 100644 .github/workflows/maven.bat create mode 100644 .github/workflows/publication.yml create mode 100644 gradle.properties create mode 100644 legacy/build.gradle create mode 100644 legacy/src/main/java/io/github/zekerzhayard/forgewrapper/installer/LegacyClientInstall4MultiMC.java create mode 100644 legacy/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/LegacyInstallerUtil.java create mode 100644 src/main/java/io/github/zekerzhayard/forgewrapper/installer/MainV2.java create mode 100644 src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/InstallerUtil.java create mode 100644 src/main/resources/META-INF/services/java.util.function.Consumer diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000000..8d331b528b --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,25 @@ +name: Gradle Build + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + runs-on: windows-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up JDK + uses: actions/setup-java@v1 + with: + java-version: '8.0.302' + architecture: x64 + - name: Build with Gradle + run: ./gradlew.bat build -iS + - uses: actions/upload-artifact@v2 + with: + name: Package + path: build/libs diff --git a/.github/workflows/maven.bat b/.github/workflows/maven.bat new file mode 100644 index 0000000000..0d3f914a00 --- /dev/null +++ b/.github/workflows/maven.bat @@ -0,0 +1,13 @@ +@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 new file mode 100644 index 0000000000..0f6f0eb94e --- /dev/null +++ b/.github/workflows/publication.yml @@ -0,0 +1,54 @@ +name: Publication + +on: + push: + tags: + - '*' + +jobs: + build: + runs-on: windows-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up JDK + uses: actions/setup-java@v1 + with: + java-version: '8.0.302' + architecture: x64 + - name: Build with Gradle + env: + IS_PUBLICATION: true + run: ./gradlew.bat publish -iS + - uses: actions/upload-artifact@v2 + with: + name: Package + path: build/libs + - name: Get tag version + id: get_version + uses: olegtarasov/get-tag@v2.1 + - uses: actions/upload-artifact@v2 + with: + name: Package + path: build/libs + - name: Create Release + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ steps.get_version.outputs.tag }} + release_name: ${{ steps.get_version.outputs.tag }} + body: '' + draft: false + prerelease: false + - name: Upload release binaries + uses: alexellis/upload-assets@0.2.2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + asset_paths: '["./build/libs/*"]' + - name: Upload to Maven + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: ./.github/workflows/maven.bat diff --git a/build.gradle b/build.gradle index 591fddd25c..36c64069a9 100644 --- a/build.gradle +++ b/build.gradle @@ -1,39 +1,111 @@ -apply plugin: "base" -apply plugin: "java" -apply plugin: "eclipse" -apply plugin: "idea" + +plugins { + id "java" + id "eclipse" + id "maven-publish" +} sourceCompatibility = targetCompatibility = 1.8 -version = "1.4.2" +version = "${fw_version}${-> getVersionSuffix()}" group = "io.github.zekerzhayard" archivesBaseName = rootProject.name +configurations { + provided { + compileOnly.extendsFrom provided + } +} + repositories { + mavenCentral() maven { name = "forge" - url = "https://files.minecraftforge.net/maven/" + url = "https://maven.minecraftforge.net/" } } dependencies { - compile "cpw.mods:modlauncher:4.1.0" - compile "net.minecraftforge:forge:1.14.4-28.2.0:installer" + compileOnly "com.google.code.gson:gson:2.8.7" + 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") +} + +java { + withSourcesJar() } jar { - manifest.attributes( - "Main-Class": "io.github.zekerzhayard.forgewrapper.converter.Main" - ) + manifest.attributes([ + "Specification-Title": "${project.name}", + "Specification-Vendor": "ZekerZhayard", + "Specification-Version": "${project.version}".split("-")[0], + "Implementation-Title": "${project.name}", + "Implementation-Version": "${project.version}", + "Implementation-Vendor" :"ZekerZhayard", + "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"), + "Automatic-Module-Name": "${project.group}.${project.archivesBaseName}".toString().toLowerCase(), + "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" } -} \ No newline at end of file +} + +publishing { + publications { + maven(MavenPublication) { + groupId "${project.group}" + artifactId "${project.archivesBaseName}" + version "${project.version}" + + from components.java + } + } + repositories { + maven { + url = layout.buildDirectory.dir("maven") + } + } + +} +tasks.publish.dependsOn build + +static String getVersionSuffix() { + if (System.getenv("IS_PUBLICATION") != null) { + return "" + } else if (System.getenv("GITHUB_RUN_NUMBER") != null && System.getenv("GITHUB_SHA") != null) { + return "-s." + System.getenv("GITHUB_RUN_NUMBER") + "-" + System.getenv("GITHUB_SHA").substring(0, 7) + } + return "-LOCAL" +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000000..38e35016b1 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,4 @@ + +org.gradle.daemon = false + +fw_version = 1.5 \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 94336fcae9..7454180f2a 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index d193c615fa..af7be50b10 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Thu Mar 12 20:06:29 CST 2020 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.3-all.zip diff --git a/gradlew b/gradlew index cccdd3d517..744e882ed5 100644 --- a/gradlew +++ b/gradlew @@ -1,5 +1,21 @@ #!/usr/bin/env sh +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + ############################################################################## ## ## Gradle start up script for UN*X @@ -28,7 +44,7 @@ APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" @@ -56,7 +72,7 @@ case "`uname`" in Darwin* ) darwin=true ;; - MINGW* ) + MSYS* | MINGW* ) msys=true ;; NONSTOP* ) @@ -66,6 +82,7 @@ esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then @@ -109,10 +126,11 @@ if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath @@ -138,19 +156,19 @@ if $cygwin ; then else eval `echo args$i`="\"$arg\"" fi - i=$((i+1)) + i=`expr $i + 1` done case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi @@ -159,14 +177,9 @@ save () { for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done echo " " } -APP_ARGS=$(save "$@") +APP_ARGS=`save "$@"` # Collect all arguments for the java command, following the shell quoting and substitution rules eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index f9553162f1..107acd32c4 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,3 +1,19 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @@ -13,15 +29,18 @@ if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -35,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -45,28 +64,14 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell diff --git a/legacy/build.gradle b/legacy/build.gradle new file mode 100644 index 0000000000..5036489352 --- /dev/null +++ b/legacy/build.gradle @@ -0,0 +1,17 @@ + +plugins { + id "java" + id "eclipse" +} + +repositories { + mavenCentral() + maven { + name = "forge" + url = "https://maven.minecraftforge.net/" + } +} + +dependencies { + compileOnly "net.minecraftforge:installer:2.0.24" +} \ No newline at end of file diff --git a/legacy/src/main/java/io/github/zekerzhayard/forgewrapper/installer/LegacyClientInstall4MultiMC.java b/legacy/src/main/java/io/github/zekerzhayard/forgewrapper/installer/LegacyClientInstall4MultiMC.java new file mode 100644 index 0000000000..0804602087 --- /dev/null +++ b/legacy/src/main/java/io/github/zekerzhayard/forgewrapper/installer/LegacyClientInstall4MultiMC.java @@ -0,0 +1,24 @@ +package io.github.zekerzhayard.forgewrapper.installer; + +import java.io.File; +import java.util.function.Predicate; + +import net.minecraftforge.installer.actions.ClientInstall; +import net.minecraftforge.installer.actions.ProgressCallback; +import net.minecraftforge.installer.json.Install; + +public class LegacyClientInstall4MultiMC extends ClientInstall { + protected File libraryDir; + protected File minecraftJar; + + public LegacyClientInstall4MultiMC(Install profile, ProgressCallback monitor, File libraryDir, File minecraftJar) { + super(profile, monitor); + this.libraryDir = libraryDir; + this.minecraftJar = minecraftJar; + } + + @Override + public boolean run(File target, Predicate optionals) { + return this.processors.process(this.libraryDir, this.minecraftJar); + } +} diff --git a/legacy/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/LegacyInstallerUtil.java b/legacy/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/LegacyInstallerUtil.java new file mode 100644 index 0000000000..587b8c7834 --- /dev/null +++ b/legacy/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/LegacyInstallerUtil.java @@ -0,0 +1,11 @@ +package io.github.zekerzhayard.forgewrapper.installer.util; + +import net.minecraftforge.installer.json.Install; +import net.minecraftforge.installer.json.Util; + +// to compatible with forge [1.13.2-25.0.9,1.16.5-36.1.65] +public class LegacyInstallerUtil { + public static Install loadInstallProfile() { + return Util.loadInstallProfile(); + } +} diff --git a/settings.gradle b/settings.gradle index 95689a11c3..c2cb153d92 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,10 +1,3 @@ -/* - * This file was generated by the Gradle 'init' task. - * - * The settings file is used to specify which projects to include in your build. - * - * Detailed information about configuring a multi-project build in Gradle can be found - * in the user guide at https://docs.gradle.org/4.10.3/userguide/multi_project_builds.html - */ - rootProject.name = 'ForgeWrapper' + +include 'legacy' \ No newline at end of file diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/ClientInstall4MultiMC.java b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/ClientInstall4MultiMC.java index ea7256416c..6daa1e5371 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/ClientInstall4MultiMC.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/ClientInstall4MultiMC.java @@ -6,19 +6,20 @@ import java.util.function.Predicate; import net.minecraftforge.installer.actions.ClientInstall; import net.minecraftforge.installer.actions.ProgressCallback; import net.minecraftforge.installer.json.Install; +import net.minecraftforge.installer.json.InstallV1; public class ClientInstall4MultiMC extends ClientInstall { protected File libraryDir; protected File minecraftJar; public ClientInstall4MultiMC(Install profile, ProgressCallback monitor, File libraryDir, File minecraftJar) { - super(profile, monitor); + super(profile instanceof InstallV1 ? (InstallV1) profile : new InstallV1(profile), monitor); this.libraryDir = libraryDir; this.minecraftJar = minecraftJar; } @Override - public boolean run(File target, Predicate optionals) { - return this.processors.process(this.libraryDir, this.minecraftJar); + public boolean run(File target, Predicate optionals, File installer) { + return this.processors.process(this.libraryDir, this.minecraftJar, this.libraryDir.getParentFile(), installer); } } diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java index 1a822ce06e..6294c77940 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java @@ -2,14 +2,14 @@ package io.github.zekerzhayard.forgewrapper.installer; import java.io.File; +import io.github.zekerzhayard.forgewrapper.installer.util.InstallerUtil; import net.minecraftforge.installer.actions.ProgressCallback; import net.minecraftforge.installer.json.Install; -import net.minecraftforge.installer.json.Util; public class Installer { - public static boolean install(File libraryDir, File minecraftJar) { + public static boolean install(File libraryDir, File minecraftJar, File installerJar, String forgeVersion) { ProgressCallback monitor = ProgressCallback.withOutputs(System.out); - Install install = Util.loadInstallProfile(); + Install install = InstallerUtil.loadInstallProfile(forgeVersion); if (System.getProperty("java.net.preferIPv4Stack") == null) { System.setProperty("java.net.preferIPv4Stack", "true"); } @@ -18,6 +18,6 @@ public class Installer { String jvmVersion = System.getProperty("java.vm.version", "missing jvm version"); monitor.message(String.format("JVM info: %s - %s - %s", vendor, javaVersion, jvmVersion)); monitor.message("java.net.preferIPv4Stack=" + System.getProperty("java.net.preferIPv4Stack")); - return new ClientInstall4MultiMC(install, monitor, libraryDir, minecraftJar).run(null, input -> true); + return InstallerUtil.runClientInstall(forgeVersion, install, monitor, libraryDir, minecraftJar, installerJar); } } 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 c52c272493..78c2d5880c 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java @@ -3,7 +3,6 @@ package io.github.zekerzhayard.forgewrapper.installer; import java.io.File; import java.net.URL; import java.net.URLClassLoader; -import java.nio.file.Files; import java.nio.file.Path; import java.util.List; import java.util.stream.Collectors; @@ -17,7 +16,8 @@ public class Main { public static void main(String[] args) throws Exception { List argsList = Stream.of(args).collect(Collectors.toList()); String mcVersion = argsList.get(argsList.indexOf("--fml.mcVersion") + 1); - String forgeFullVersion = mcVersion + "-" + argsList.get(argsList.indexOf("--fml.forgeVersion") + 1); + String forgeVersion = argsList.get(argsList.indexOf("--fml.forgeVersion") + 1); + String forgeFullVersion = mcVersion + "-" + forgeVersion; IFileDetector detector = DetectorLoader.loadDetector(); if (!detector.checkExtraFiles(forgeFullVersion)) { @@ -26,13 +26,13 @@ public class Main { // Check installer jar. Path installerJar = detector.getInstallerJar(forgeFullVersion); if (!IFileDetector.isFile(installerJar)) { - throw new RuntimeException("Can't detect the forge installer!"); + throw new RuntimeException("Unable to detect the forge installer!"); } // Check vanilla Minecraft jar. Path minecraftJar = detector.getMinecraftJar(mcVersion); if (!IFileDetector.isFile(minecraftJar)) { - throw new RuntimeException("Can't detect the Minecraft jar!"); + throw new RuntimeException("Unable to detect the Minecraft jar!"); } try (URLClassLoader ucl = URLClassLoader.newInstance(new URL[] { @@ -41,13 +41,13 @@ public class Main { installerJar.toUri().toURL() }, getParentClassLoader())) { Class installer = ucl.loadClass("io.github.zekerzhayard.forgewrapper.installer.Installer"); - if (!(boolean) installer.getMethod("install", File.class, File.class).invoke(null, detector.getLibraryDir().toFile(), minecraftJar.toFile())) { + if (!(boolean) installer.getMethod("install", File.class, File.class, File.class, String.class).invoke(null, detector.getLibraryDir().toFile(), minecraftJar.toFile(), installerJar.toFile(), forgeVersion)) { return; } } } - Launcher.main(args); + Launcher.main(args); // TODO: this will be broken in forge 1.17 } // 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 new file mode 100644 index 0000000000..230d9fbe28 --- /dev/null +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/MainV2.java @@ -0,0 +1,15 @@ +package io.github.zekerzhayard.forgewrapper.installer; + +import java.util.function.Consumer; + +// to support forge 1.17 (bootstraplauncher) +public class MainV2 implements Consumer { + @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/util/InstallerUtil.java b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/InstallerUtil.java new file mode 100644 index 0000000000..26f11ce583 --- /dev/null +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/InstallerUtil.java @@ -0,0 +1,52 @@ +package io.github.zekerzhayard.forgewrapper.installer.util; + +import java.io.File; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import io.github.zekerzhayard.forgewrapper.installer.ClientInstall4MultiMC; +import io.github.zekerzhayard.forgewrapper.installer.LegacyClientInstall4MultiMC; +import net.minecraftforge.installer.actions.ProgressCallback; +import net.minecraftforge.installer.json.Install; +import net.minecraftforge.installer.json.Util; + +public class InstallerUtil { + public static Install loadInstallProfile(String forgeVersion) { + if (isLegacyForge(forgeVersion, "36.1.65")) { + return LegacyInstallerUtil.loadInstallProfile(); + } else { + // to prevent ClassNotFoundException + return new Object() { + public Install get() { + return Util.loadInstallProfile(); + } + }.get(); + } + } + + public static boolean runClientInstall(String forgeVersion, Install profile, ProgressCallback monitor, File libraryDir, File minecraftJar, File installerJar) { + if (isLegacyForge(forgeVersion, "36.1.65")) { + return new LegacyClientInstall4MultiMC(profile, monitor, libraryDir, minecraftJar).run(null, input -> true); + } else { + return new ClientInstall4MultiMC(profile, monitor, libraryDir, minecraftJar).run(null, input -> true, installerJar); + } + } + + private final static Pattern FORGE_VERSION_PATTERN = Pattern.compile("(?\\d+)\\.(?\\d+)\\.(?\\d+)"); + private static boolean isLegacyForge(String forgeVersion, String legacyForgeVersion) { + Matcher m0 = FORGE_VERSION_PATTERN.matcher(forgeVersion); + Matcher m1 = FORGE_VERSION_PATTERN.matcher(legacyForgeVersion); + if (m0.find() && m1.find()) { + return compareVersion(m0, m1, 0, "major", "minor", "build"); + } + throw new RuntimeException("Missing forge version!"); + } + + private static boolean compareVersion(Matcher m0, Matcher m1, int index, String... groups) { + if (index == groups.length) return true; // the same as the legacy version + int result = Integer.compare(Integer.parseInt(m0.group(groups[index])), Integer.parseInt(m1.group(groups[index]))); + if (result < 0) return true; // less than the legacy version + if (result > 0) return false; // greater than the legacy version + return compareVersion(m0, m1, index + 1, groups); + } +} diff --git a/src/main/resources/META-INF/services/java.util.function.Consumer b/src/main/resources/META-INF/services/java.util.function.Consumer new file mode 100644 index 0000000000..64cc969425 --- /dev/null +++ b/src/main/resources/META-INF/services/java.util.function.Consumer @@ -0,0 +1 @@ +io.github.zekerzhayard.forgewrapper.installer.MainV2 \ No newline at end of file -- cgit 0.0.5-2-1-g0f52 From 5fb3f01768c8a9bb1587ea0884e6d01127dbc4ac Mon Sep 17 00:00:00 2001 From: ZekerZhayard Date: Fri, 23 Jul 2021 01:47:28 +0800 Subject: Full support the installation of forge-1.16.5-36.1.66+ and partial support forge-1.17.1 --- .github/workflows/build.yml | 6 +- .github/workflows/maven.bat | 13 -- .github/workflows/publication.yml | 13 +- .gitignore | 2 +- README.md | 4 + build.gradle | 38 ++-- converter/build.gradle | 48 +++++ .../forgewrapper/converter/Converter.java | 157 +++++++++++++++++ .../zekerzhayard/forgewrapper/converter/Main.java | 53 ++++++ converter/src/main/resources/mmc-pack.json | 13 ++ .../main/resources/patches/net.minecraftforge.json | 28 +++ gradle.properties | 2 +- jigsaw/build.gradle | 28 +++ .../forgewrapper/installer/util/ModuleUtil.java | 195 +++++++++++++++++++++ legacy/build.gradle | 2 +- settings.gradle | 4 +- .../forgewrapper/converter/Converter.java | 157 ----------------- .../zekerzhayard/forgewrapper/converter/Main.java | 53 ------ .../forgewrapper/installer/Bootstrap.java | 78 +++++++++ .../zekerzhayard/forgewrapper/installer/Main.java | 6 +- .../forgewrapper/installer/MainV2.java | 15 -- .../installer/detector/IFileDetector.java | 52 ++++-- .../forgewrapper/installer/util/ModuleUtil.java | 21 +++ ...d.forgewrapper.installer.detector.IFileDetector | 2 +- .../META-INF/services/java.util.function.Consumer | 1 - src/main/resources/mmc-pack.json | 13 -- src/main/resources/patches/net.minecraftforge.json | 28 --- 27 files changed, 704 insertions(+), 328 deletions(-) delete mode 100644 .github/workflows/maven.bat create mode 100644 converter/build.gradle create mode 100644 converter/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java create mode 100644 converter/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Main.java create mode 100644 converter/src/main/resources/mmc-pack.json create mode 100644 converter/src/main/resources/patches/net.minecraftforge.json create mode 100644 jigsaw/build.gradle create mode 100644 jigsaw/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/ModuleUtil.java delete mode 100644 src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java delete mode 100644 src/main/java/io/github/zekerzhayard/forgewrapper/converter/Main.java create mode 100644 src/main/java/io/github/zekerzhayard/forgewrapper/installer/Bootstrap.java delete mode 100644 src/main/java/io/github/zekerzhayard/forgewrapper/installer/MainV2.java create mode 100644 src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/ModuleUtil.java delete mode 100644 src/main/resources/META-INF/services/java.util.function.Consumer delete mode 100644 src/main/resources/mmc-pack.json delete mode 100644 src/main/resources/patches/net.minecraftforge.json 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 --installer= [--instance=] 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/converter/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java b/converter/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java new file mode 100644 index 0000000000..0fdfc1382b --- /dev/null +++ b/converter/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java @@ -0,0 +1,157 @@ +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 new JsonParser().parse(isr).getAsJsonObject(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + // Convert mmc-pack.json: + // - Replace Minecraft version + private static JsonObject convertPackJson(String mcVersion) { + JsonObject pack = new JsonParser().parse(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 = new JsonParser().parse(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 new file mode 100644 index 0000000000..83ecdf959e --- /dev/null +++ b/converter/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Main.java @@ -0,0 +1,53 @@ +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 new file mode 100644 index 0000000000..87db08a724 --- /dev/null +++ b/converter/src/main/resources/mmc-pack.json @@ -0,0 +1,13 @@ +{ + "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 new file mode 100644 index 0000000000..8b09773bbe --- /dev/null +++ b/converter/src/main/resources/patches/net.minecraftforge.json @@ -0,0 +1,28 @@ +{ + "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://files.minecraftforge.net/maven/" + } + ], + "libraries": [ + { + "name": "io.github.zekerzhayard:ForgeWrapper:${version}", + "MMC-hint": "local", + "MMC-filename": "ForgeWrapper-${version}.jar" + } + ] +} 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> graphMap = new HashMap<>((Map>) 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>) 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 oldBootModules = ModuleLayer.boot().configuration().modules(); + MethodHandle modulesSetter = IMPL_LOOKUP.findSetter(Configuration.class, "modules", Set.class); + HashSet 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 nameToModuleMap = new HashMap<>((Map) nameToModuleGetter.invokeWithArguments(ModuleLayer.boot().configuration())); + nameToModuleMap.putAll((Map) 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) IMPL_LOOKUP.findGetter(ModuleLayer.class, "nameToModule", Map.class).invokeWithArguments(ModuleLayer.boot())).putAll((Map) IMPL_LOOKUP.findStatic(Module.class, "defineModules", MethodType.methodType(Map.class, Configuration.class, Function.class, ModuleLayer.class)).invokeWithArguments(ModuleLayer.boot().configuration(), (Function) 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 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 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 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); + } + }); + } + }); + } + + // /= + 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/converter/Converter.java b/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java deleted file mode 100644 index 403488bd95..0000000000 --- a/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 new JsonParser().parse(isr).getAsJsonObject(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - // Convert mmc-pack.json: - // - Replace Minecraft version - private static JsonObject convertPackJson(String mcVersion) { - JsonObject pack = new JsonParser().parse(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 = new JsonParser().parse(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://files.minecraftforge.net/maven/" + 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); - - 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/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Main.java b/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Main.java deleted file mode 100644 index 83ecdf959e..0000000000 --- a/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/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 jvmArgs, String minecraftJar, String libraryDir) throws Throwable { + // Replace all placeholders + List 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 addExports = new ArrayList<>(); + List 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 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 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 { - @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; @@ -81,32 +86,55 @@ public interface IFileDetector { return null; } + /** + * @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"); + List 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 getDataFromInstaller(String forgeFullVersion, String entry, Function 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 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 hashMap = new HashMap<>(); // Get all "data//client" elements. + Pattern artifactPattern = Pattern.compile("^\\[(?[^:]*):(?[^:]*):(?[^:@]*)(:(?[^@]*))?(@(?[^]]*))?]$"); for (Map.Entry 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("^\\[(?[^:]*):(?[^:]*):(?[^:@]*)(:(?[^@]*))?(@(?[^]]*))?]$"); - 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 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 exports) { + // nothing to do with Java 8 + } + + public static void addOpens(List 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 diff --git a/src/main/resources/mmc-pack.json b/src/main/resources/mmc-pack.json deleted file mode 100644 index 3622087e0a..0000000000 --- a/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" - } - ] -} \ No newline at end of file diff --git a/src/main/resources/patches/net.minecraftforge.json b/src/main/resources/patches/net.minecraftforge.json deleted file mode 100644 index d170dd25e8..0000000000 --- a/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://files.minecraftforge.net/maven/" - } - ], - "libraries": [ - { - "name": "io.github.zekerzhayard:ForgeWrapper:${version}", - "MMC-hint": "local", - "MMC-filename": "ForgeWrapper-${version}.jar" - } - ] -} \ No newline at end of file -- cgit 0.0.5-2-1-g0f52 From 3ee6633a8536fdc72395536dd98b2b5e6363240e Mon Sep 17 00:00:00 2001 From: ZekerZhayard Date: Fri, 13 Aug 2021 22:48:17 +0800 Subject: Fix defining duplicated modules. --- .github/workflows/publication.yml | 2 + README.md | 2 +- build.gradle | 7 +- common/build.gradle | 11 ++ .../forgewrapper/util/CheckedLambdaUtil.java | 40 +++++++ converter/build.gradle | 8 +- gradle.properties | 2 +- jigsaw/build.gradle | 4 + .../forgewrapper/installer/util/ModuleUtil.java | 130 ++++++++------------- settings.gradle | 1 + .../forgewrapper/installer/Bootstrap.java | 23 +--- .../zekerzhayard/forgewrapper/installer/Main.java | 5 +- .../installer/detector/IFileDetector.java | 2 - .../forgewrapper/installer/util/ModuleUtil.java | 3 +- 14 files changed, 128 insertions(+), 112 deletions(-) create mode 100644 common/build.gradle create mode 100644 common/src/main/java/io/github/zekerzhayard/forgewrapper/util/CheckedLambdaUtil.java diff --git a/.github/workflows/publication.yml b/.github/workflows/publication.yml index 15a91613fc..d141a2ecc7 100644 --- a/.github/workflows/publication.yml +++ b/.github/workflows/publication.yml @@ -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 diff --git a/README.md b/README.md index d05b57d08f..a1e855798b 100644 --- a/README.md +++ b/README.md @@ -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 --installer= [--instance=] diff --git a/build.gradle b/build.gradle index d975a08ac3..b2bbbc5c0d 100644 --- a/build.gradle +++ b/build.gradle @@ -16,10 +16,10 @@ archivesBaseName = rootProject.name configurations { provided { - compileOnly.extendsFrom provided + implementation.extendsFrom provided } multirelase { - compileOnly.extendsFrom multirelase + implementation.extendsFrom multirelase } } @@ -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") } @@ -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")) ]) @@ -87,7 +87,6 @@ publishing { url = layout.buildDirectory.dir("maven") } } - } tasks.publish.dependsOn build diff --git a/common/build.gradle b/common/build.gradle new file mode 100644 index 0000000000..abd2997bba --- /dev/null +++ b/common/build.gradle @@ -0,0 +1,11 @@ + +plugins { + id "java" + id "eclipse" + id "maven-publish" +} + +sourceCompatibility = targetCompatibility = 1.8 +compileJava { + sourceCompatibility = targetCompatibility = 1.8 +} diff --git a/common/src/main/java/io/github/zekerzhayard/forgewrapper/util/CheckedLambdaUtil.java b/common/src/main/java/io/github/zekerzhayard/forgewrapper/util/CheckedLambdaUtil.java new file mode 100644 index 0000000000..c36b8b33a7 --- /dev/null +++ b/common/src/main/java/io/github/zekerzhayard/forgewrapper/util/CheckedLambdaUtil.java @@ -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 Consumer wrapConsumer(CheckedConsumer consumer) { + return consumer; + } + + public static BiConsumer wrapBiConsumer(CheckedBiConsumer biconsumer) { + return biconsumer; + } + + public interface CheckedConsumer extends Consumer { + 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 extends BiConsumer { + 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); + } + } + } +} diff --git a/converter/build.gradle b/converter/build.gradle index 93be5a1584..d12b3e4e99 100644 --- a/converter/build.gradle +++ b/converter/build.gradle @@ -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 } } @@ -30,6 +35,7 @@ jar { ]) from configurations.provided.files.collect { + duplicatesStrategy = DuplicatesStrategy.EXCLUDE zipTree(it) } } diff --git a/gradle.properties b/gradle.properties index a0a9a4a00e..3e2c6a328c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.daemon = false -fw_version = 1.5.1 +fw_version = 1.5.2 diff --git a/jigsaw/build.gradle b/jigsaw/build.gradle index a555ec3bf3..08c394afee 100644 --- a/jigsaw/build.gradle +++ b/jigsaw/build.gradle @@ -26,3 +26,7 @@ configurations { } } } + +dependencies { + compileOnly project(":common") +} 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 ce12029b38..3e125331dd 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 @@ -5,22 +5,23 @@ 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.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 { @@ -46,39 +47,22 @@ public class ModuleUtil { */ @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> graphMap = new HashMap<>((Map>) 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>) graphGetter.invokeWithArguments(ModuleLayer.boot().configuration())); IMPL_LOOKUP.findSetter(Configuration.class, "graph", Map.class).invokeWithArguments(ModuleLayer.boot().configuration(), new HashMap<>(graphMap)); @@ -88,13 +72,13 @@ public class ModuleUtil { HashSet 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 nameToModuleMap = new HashMap<>((Map) nameToModuleGetter.invokeWithArguments(ModuleLayer.boot().configuration())); nameToModuleMap.putAll((Map) 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) IMPL_LOOKUP.findGetter(ModuleLayer.class, "nameToModule", Map.class).invokeWithArguments(ModuleLayer.boot())).putAll((Map) IMPL_LOOKUP.findStatic(Module.class, "defineModules", MethodType.methodType(Map.class, Configuration.class, Function.class, ModuleLayer.class)).invokeWithArguments(ModuleLayer.boot().configuration(), (Function) name -> ClassLoader.getSystemClassLoader(), ModuleLayer.boot())); // Add all of resolved modules @@ -107,66 +91,56 @@ public class ModuleUtil { // 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 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 exports) { + TypeToAdd.EXPORTS.implAdd(exports); + } - addExtra(exports, implAddExportsMH, implAddExportsToAllUnnamedMH); + public static void addOpens(List opens) { + TypeToAdd.OPENS.implAdd(opens); } - public static void addOpens(List 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 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 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))); + } + })))); + } } // /= - private static ParserData parseModuleExtra(String extra) { + private static Optional 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 { @@ -182,14 +156,10 @@ public class ModuleUtil { } // 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; } } diff --git a/settings.gradle b/settings.gradle index 2d5aa2f9e2..b15e75e4b3 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,5 +1,6 @@ rootProject.name = 'ForgeWrapper' +include 'common' 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 index 98e8dda209..2740b76bef 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Bootstrap.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Bootstrap.java @@ -1,11 +1,8 @@ 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; @@ -14,7 +11,7 @@ public class Bootstrap { // Replace all placeholders List 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)); + replacedJvmArgs.add(arg.replace("${classpath}", System.getProperty("java.class.path").replace(File.separator, "/")).replace("${classpath_separator}", File.pathSeparator).replace("${library_directory}", libraryDir).replace("${version_name}", minecraftJar.substring(0, minecraftJar.lastIndexOf('.')))); } jvmArgs = replacedJvmArgs; @@ -47,21 +44,8 @@ public class Bootstrap { 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 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)); + // The default ignoreList may cause some problems, so we define it more precisely. + System.setProperty(prop[0], prop[1] + ",NewLaunch.jar,ForgeWrapper-," + minecraftJar); } else { System.setProperty(prop[0], prop[1]); } @@ -73,6 +57,5 @@ public class Bootstrap { } 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 99ead7cf31..2729ef52aa 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java @@ -5,13 +5,13 @@ 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; import cpw.mods.modlauncher.Launcher; import io.github.zekerzhayard.forgewrapper.installer.detector.DetectorLoader; import io.github.zekerzhayard.forgewrapper.installer.detector.IFileDetector; +import io.github.zekerzhayard.forgewrapper.installer.util.ModuleUtil; public class Main { public static void main(String[] args) throws Throwable { @@ -49,7 +49,8 @@ public class Main { } } - Class.forName(detector.getMainClass(forgeFullVersion)).getMethod("main", String[].class).invoke(null, new Object[] { args }); + Class mainClass = ModuleUtil.setupBootstrapLauncher(Class.forName(detector.getMainClass(forgeFullVersion))); + mainClass.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/detector/IFileDetector.java b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/detector/IFileDetector.java index 2f8c976985..2cb62cc0db 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,7 +12,6 @@ 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; @@ -20,7 +19,6 @@ 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; 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 0b37945822..7461b501b0 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 @@ -15,7 +15,8 @@ public class ModuleUtil { // nothing to do with Java 8 } - public static void setupBootstrapLauncher() { + public static Class setupBootstrapLauncher(Class mainClass) { // nothing to do with Java 8 + return mainClass; } } -- cgit 0.0.5-2-1-g0f52 From e0515ed1f5fe65b55883971c8fd09f0f652a79cc Mon Sep 17 00:00:00 2001 From: ZekerZhayard Date: Wed, 17 Nov 2021 21:42:16 +0800 Subject: Remove the legacy part due to all forge installers are upgraded. --- build.gradle | 5 +-- converter/build.gradle | 2 +- .../forgewrapper/converter/Converter.java | 6 +-- .../main/resources/patches/net.minecraftforge.json | 2 +- gradle.properties | 2 +- .../forgewrapper/installer/util/ModuleUtil.java | 4 ++ legacy/build.gradle | 17 ------- .../installer/LegacyClientInstall4MultiMC.java | 24 ---------- .../installer/util/LegacyInstallerUtil.java | 11 ----- settings.gradle | 1 - .../forgewrapper/installer/Installer.java | 6 +-- .../zekerzhayard/forgewrapper/installer/Main.java | 22 +++------ .../forgewrapper/installer/util/InstallerUtil.java | 52 ---------------------- .../forgewrapper/installer/util/ModuleUtil.java | 5 +++ 14 files changed, 27 insertions(+), 132 deletions(-) delete mode 100644 legacy/build.gradle delete mode 100644 legacy/src/main/java/io/github/zekerzhayard/forgewrapper/installer/LegacyClientInstall4MultiMC.java delete mode 100644 legacy/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/LegacyInstallerUtil.java delete mode 100644 src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/InstallerUtil.java diff --git a/build.gradle b/build.gradle index b2bbbc5c0d..09570e9de7 100644 --- a/build.gradle +++ b/build.gradle @@ -32,13 +32,12 @@ repositories { } dependencies { - compileOnly "com.google.code.gson:gson:2.8.5" + compileOnly "com.google.code.gson:gson:2.8.7" compileOnly "cpw.mods:modlauncher:8.0.9" - compileOnly "net.minecraftforge:installer:2.1.4" + compileOnly "net.minecraftforge:installer:2.1.9" compileOnly "net.sf.jopt-simple:jopt-simple:5.0.4" provided project(":common") - provided project(":legacy") multirelase project(":jigsaw") } diff --git a/converter/build.gradle b/converter/build.gradle index d12b3e4e99..a3661b7d68 100644 --- a/converter/build.gradle +++ b/converter/build.gradle @@ -24,7 +24,7 @@ repositories { } dependencies { - compileOnly "com.google.code.gson:gson:2.8.5" + compileOnly "com.google.code.gson:gson:2.8.7" provided rootProject } 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 index 0fdfc1382b..ade550f0eb 100644 --- a/converter/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java +++ b/converter/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java @@ -75,7 +75,7 @@ public class Converter { throw new RuntimeException("The zip file is invalid!"); } InputStreamReader isr = new InputStreamReader(zf.getInputStream(versionFile), StandardCharsets.UTF_8); - return new JsonParser().parse(isr).getAsJsonObject(); + return JsonParser.parseReader(isr).getAsJsonObject(); } catch (IOException e) { throw new RuntimeException(e); } @@ -84,7 +84,7 @@ public class Converter { // Convert mmc-pack.json: // - Replace Minecraft version private static JsonObject convertPackJson(String mcVersion) { - JsonObject pack = new JsonParser().parse(new InputStreamReader(Converter.class.getResourceAsStream("/mmc-pack.json"))).getAsJsonObject(); + JsonObject pack = JsonParser.parseReader(new InputStreamReader(Converter.class.getResourceAsStream("/mmc-pack.json"))).getAsJsonObject(); for (JsonElement component : getElement(pack, "components").getAsJsonArray()) { JsonObject componentObject = component.getAsJsonObject(); @@ -101,7 +101,7 @@ public class Converter { // - Add forge-launcher url // - Replace Minecraft & Forge versions private static JsonObject convertPatchesJson(JsonObject installer, JsonObject installProfile, String mcVersion, String forgeVersion, StringBuilder wrapperVersion) { - JsonObject patches = new JsonParser().parse(new InputStreamReader(Converter.class.getResourceAsStream("/patches/net.minecraftforge.json"))).getAsJsonObject(); + 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(); diff --git a/converter/src/main/resources/patches/net.minecraftforge.json b/converter/src/main/resources/patches/net.minecraftforge.json index 8b09773bbe..4fac6aabd0 100644 --- a/converter/src/main/resources/patches/net.minecraftforge.json +++ b/converter/src/main/resources/patches/net.minecraftforge.json @@ -15,7 +15,7 @@ "mavenFiles": [ { "name": "net.minecraftforge:forge:{VERSION}-{FORGE_VERSION}:installer", - "url": "https://files.minecraftforge.net/maven/" + "url": "https://maven.minecraftforge.net/" } ], "libraries": [ diff --git a/gradle.properties b/gradle.properties index 3e2c6a328c..5fdd7c6ccf 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.daemon = false -fw_version = 1.5.2 +fw_version = 1.5.3 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 3e125331dd..9a49d7f0b8 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 @@ -102,6 +102,10 @@ public class ModuleUtil { TypeToAdd.OPENS.implAdd(opens); } + public static ClassLoader getPlatformClassLoader() { + return ClassLoader.getPlatformClassLoader(); + } + private enum TypeToAdd { EXPORTS("Exports"), OPENS("Opens"); diff --git a/legacy/build.gradle b/legacy/build.gradle deleted file mode 100644 index 8824390d0f..0000000000 --- a/legacy/build.gradle +++ /dev/null @@ -1,17 +0,0 @@ - -plugins { - id "java" - id "eclipse" -} - -repositories { - mavenCentral() - maven { - name = "forge" - url = "https://maven.minecraftforge.net/" - } -} - -dependencies { - compileOnly "net.minecraftforge:installer:2.0.24" -} diff --git a/legacy/src/main/java/io/github/zekerzhayard/forgewrapper/installer/LegacyClientInstall4MultiMC.java b/legacy/src/main/java/io/github/zekerzhayard/forgewrapper/installer/LegacyClientInstall4MultiMC.java deleted file mode 100644 index 0804602087..0000000000 --- a/legacy/src/main/java/io/github/zekerzhayard/forgewrapper/installer/LegacyClientInstall4MultiMC.java +++ /dev/null @@ -1,24 +0,0 @@ -package io.github.zekerzhayard.forgewrapper.installer; - -import java.io.File; -import java.util.function.Predicate; - -import net.minecraftforge.installer.actions.ClientInstall; -import net.minecraftforge.installer.actions.ProgressCallback; -import net.minecraftforge.installer.json.Install; - -public class LegacyClientInstall4MultiMC extends ClientInstall { - protected File libraryDir; - protected File minecraftJar; - - public LegacyClientInstall4MultiMC(Install profile, ProgressCallback monitor, File libraryDir, File minecraftJar) { - super(profile, monitor); - this.libraryDir = libraryDir; - this.minecraftJar = minecraftJar; - } - - @Override - public boolean run(File target, Predicate optionals) { - return this.processors.process(this.libraryDir, this.minecraftJar); - } -} diff --git a/legacy/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/LegacyInstallerUtil.java b/legacy/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/LegacyInstallerUtil.java deleted file mode 100644 index 587b8c7834..0000000000 --- a/legacy/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/LegacyInstallerUtil.java +++ /dev/null @@ -1,11 +0,0 @@ -package io.github.zekerzhayard.forgewrapper.installer.util; - -import net.minecraftforge.installer.json.Install; -import net.minecraftforge.installer.json.Util; - -// to compatible with forge [1.13.2-25.0.9,1.16.5-36.1.65] -public class LegacyInstallerUtil { - public static Install loadInstallProfile() { - return Util.loadInstallProfile(); - } -} diff --git a/settings.gradle b/settings.gradle index b15e75e4b3..d3b1da5737 100644 --- a/settings.gradle +++ b/settings.gradle @@ -3,4 +3,3 @@ rootProject.name = 'ForgeWrapper' include 'common' include 'converter' include 'jigsaw' -include 'legacy' diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java index 6294c77940..1755ce11f0 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java @@ -2,14 +2,14 @@ package io.github.zekerzhayard.forgewrapper.installer; import java.io.File; -import io.github.zekerzhayard.forgewrapper.installer.util.InstallerUtil; import net.minecraftforge.installer.actions.ProgressCallback; import net.minecraftforge.installer.json.Install; +import net.minecraftforge.installer.json.Util; public class Installer { public static boolean install(File libraryDir, File minecraftJar, File installerJar, String forgeVersion) { ProgressCallback monitor = ProgressCallback.withOutputs(System.out); - Install install = InstallerUtil.loadInstallProfile(forgeVersion); + Install profile = Util.loadInstallProfile(); if (System.getProperty("java.net.preferIPv4Stack") == null) { System.setProperty("java.net.preferIPv4Stack", "true"); } @@ -18,6 +18,6 @@ public class Installer { String jvmVersion = System.getProperty("java.vm.version", "missing jvm version"); monitor.message(String.format("JVM info: %s - %s - %s", vendor, javaVersion, jvmVersion)); monitor.message("java.net.preferIPv4Stack=" + System.getProperty("java.net.preferIPv4Stack")); - return InstallerUtil.runClientInstall(forgeVersion, install, monitor, libraryDir, minecraftJar, installerJar); + return new ClientInstall4MultiMC(profile, monitor, libraryDir, minecraftJar).run(null, input -> true, installerJar); } } 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 2729ef52aa..3d955372f0 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java @@ -21,9 +21,13 @@ public class Main { String forgeFullVersion = mcVersion + "-" + forgeVersion; IFileDetector detector = DetectorLoader.loadDetector(); - Bootstrap.bootstrap(detector.getJvmArgs(forgeFullVersion), detector.getMinecraftJar(mcVersion).getFileName().toString(), detector.getLibraryDir().toAbsolutePath().toString()); + try { + Bootstrap.bootstrap(detector.getJvmArgs(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)) { - System.out.println("Some extra libraries are missing! Run the installer to generate them now."); + System.out.println("Some extra libraries are missing! Running the installer to generate them now."); // Check installer jar. Path installerJar = detector.getInstallerJar(forgeFullVersion); @@ -41,7 +45,7 @@ public class Main { Main.class.getProtectionDomain().getCodeSource().getLocation(), Launcher.class.getProtectionDomain().getCodeSource().getLocation(), installerJar.toUri().toURL() - }, getParentClassLoader())) { + }, ModuleUtil.getPlatformClassLoader())) { Class installer = ucl.loadClass("io.github.zekerzhayard.forgewrapper.installer.Installer"); if (!(boolean) installer.getMethod("install", File.class, File.class, File.class, String.class).invoke(null, detector.getLibraryDir().toFile(), minecraftJar.toFile(), installerJar.toFile(), forgeVersion)) { return; @@ -52,16 +56,4 @@ public class Main { Class mainClass = ModuleUtil.setupBootstrapLauncher(Class.forName(detector.getMainClass(forgeFullVersion))); mainClass.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 - private static ClassLoader getParentClassLoader() { - if (!System.getProperty("java.version").startsWith("1.")) { - try { - return (ClassLoader) ClassLoader.class.getDeclaredMethod("getPlatformClassLoader").invoke(null); - } catch (Exception e) { - System.out.println("No platform classloader: " + System.getProperty("java.version")); - } - } - return null; - } } diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/InstallerUtil.java b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/InstallerUtil.java deleted file mode 100644 index 26f11ce583..0000000000 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/InstallerUtil.java +++ /dev/null @@ -1,52 +0,0 @@ -package io.github.zekerzhayard.forgewrapper.installer.util; - -import java.io.File; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import io.github.zekerzhayard.forgewrapper.installer.ClientInstall4MultiMC; -import io.github.zekerzhayard.forgewrapper.installer.LegacyClientInstall4MultiMC; -import net.minecraftforge.installer.actions.ProgressCallback; -import net.minecraftforge.installer.json.Install; -import net.minecraftforge.installer.json.Util; - -public class InstallerUtil { - public static Install loadInstallProfile(String forgeVersion) { - if (isLegacyForge(forgeVersion, "36.1.65")) { - return LegacyInstallerUtil.loadInstallProfile(); - } else { - // to prevent ClassNotFoundException - return new Object() { - public Install get() { - return Util.loadInstallProfile(); - } - }.get(); - } - } - - public static boolean runClientInstall(String forgeVersion, Install profile, ProgressCallback monitor, File libraryDir, File minecraftJar, File installerJar) { - if (isLegacyForge(forgeVersion, "36.1.65")) { - return new LegacyClientInstall4MultiMC(profile, monitor, libraryDir, minecraftJar).run(null, input -> true); - } else { - return new ClientInstall4MultiMC(profile, monitor, libraryDir, minecraftJar).run(null, input -> true, installerJar); - } - } - - private final static Pattern FORGE_VERSION_PATTERN = Pattern.compile("(?\\d+)\\.(?\\d+)\\.(?\\d+)"); - private static boolean isLegacyForge(String forgeVersion, String legacyForgeVersion) { - Matcher m0 = FORGE_VERSION_PATTERN.matcher(forgeVersion); - Matcher m1 = FORGE_VERSION_PATTERN.matcher(legacyForgeVersion); - if (m0.find() && m1.find()) { - return compareVersion(m0, m1, 0, "major", "minor", "build"); - } - throw new RuntimeException("Missing forge version!"); - } - - private static boolean compareVersion(Matcher m0, Matcher m1, int index, String... groups) { - if (index == groups.length) return true; // the same as the legacy version - int result = Integer.compare(Integer.parseInt(m0.group(groups[index])), Integer.parseInt(m1.group(groups[index]))); - if (result < 0) return true; // less than the legacy version - if (result > 0) return false; // greater than the legacy version - return compareVersion(m0, m1, index + 1, groups); - } -} 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 7461b501b0..c89d714425 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 @@ -19,4 +19,9 @@ public class ModuleUtil { // nothing to do with Java 8 return mainClass; } + + public static ClassLoader getPlatformClassLoader() { + // PlatformClassLoader does not exist in Java 8 + return null; + } } -- cgit 0.0.5-2-1-g0f52 From a1be16d07c892bfb8d636bf3ea72898e95c884ba Mon Sep 17 00:00:00 2001 From: Petr Mrázek Date: Tue, 16 Nov 2021 23:54:43 +0100 Subject: Make `gradlew` executable (cherry picked from commit 8c0032e3a5d74b52ed5b60ea42b2ebdb4ecc8fe4) --- gradlew | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 gradlew diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 -- cgit 0.0.5-2-1-g0f52 From f104aba739f7b352484eb50a4a97529c3c672bcd Mon Sep 17 00:00:00 2001 From: ZekerZhayard Date: Sat, 11 Dec 2021 14:35:56 +0800 Subject: Re-add the legacy part. --- .github/workflows/build.yml | 2 +- .github/workflows/publication.yml | 2 +- build.gradle | 1 + gradle.properties | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 257 ++++++++++++--------- legacy/build.gradle | 17 ++ .../installer/util/AbstractInstaller.java | 12 + .../forgewrapper/installer/util/InstallerV0.java | 37 +++ settings.gradle | 1 + .../installer/ClientInstall4MultiMC.java | 25 -- .../forgewrapper/installer/Installer.java | 19 +- .../zekerzhayard/forgewrapper/installer/Main.java | 2 +- .../installer/detector/IFileDetector.java | 14 +- .../forgewrapper/installer/util/InstallerV1.java | 38 +++ 15 files changed, 290 insertions(+), 141 deletions(-) create mode 100644 legacy/build.gradle create mode 100644 legacy/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/AbstractInstaller.java create mode 100644 legacy/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/InstallerV0.java delete mode 100644 src/main/java/io/github/zekerzhayard/forgewrapper/installer/ClientInstall4MultiMC.java create mode 100644 src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/InstallerV1.java diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9e2ae64ce0..809b1eca87 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,7 +15,7 @@ jobs: - name: Set up JDK uses: actions/setup-java@v1 with: - java-version: '8.0.302' + java-version: '8.0.312' architecture: x64 - name: Build with Gradle run: | diff --git a/.github/workflows/publication.yml b/.github/workflows/publication.yml index d141a2ecc7..31d4196b37 100644 --- a/.github/workflows/publication.yml +++ b/.github/workflows/publication.yml @@ -14,7 +14,7 @@ jobs: - name: Set up JDK uses: actions/setup-java@v1 with: - java-version: '8.0.302' + java-version: '8.0.312' architecture: x64 - name: Build with Gradle env: diff --git a/build.gradle b/build.gradle index 09570e9de7..45e6dee5d7 100644 --- a/build.gradle +++ b/build.gradle @@ -38,6 +38,7 @@ dependencies { compileOnly "net.sf.jopt-simple:jopt-simple:5.0.4" provided project(":common") + provided project(":legacy") multirelase project(":jigsaw") } diff --git a/gradle.properties b/gradle.properties index 5fdd7c6ccf..29b7ba0097 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.daemon = false -fw_version = 1.5.3 +fw_version = 1.5.4 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index af7be50b10..3cd8500c13 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.1-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 744e882ed5..1b6c787337 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MSYS* | MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,95 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/legacy/build.gradle b/legacy/build.gradle new file mode 100644 index 0000000000..8824390d0f --- /dev/null +++ b/legacy/build.gradle @@ -0,0 +1,17 @@ + +plugins { + id "java" + id "eclipse" +} + +repositories { + mavenCentral() + maven { + name = "forge" + url = "https://maven.minecraftforge.net/" + } +} + +dependencies { + compileOnly "net.minecraftforge:installer:2.0.24" +} diff --git a/legacy/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/AbstractInstaller.java b/legacy/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/AbstractInstaller.java new file mode 100644 index 0000000000..6b2d55072f --- /dev/null +++ b/legacy/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/AbstractInstaller.java @@ -0,0 +1,12 @@ +package io.github.zekerzhayard.forgewrapper.installer.util; + +import java.io.File; + +import net.minecraftforge.installer.actions.ProgressCallback; +import net.minecraftforge.installer.json.Install; + +public abstract class AbstractInstaller { + public abstract Install loadInstallProfile(); + + public abstract boolean runClientInstall(Install profile, ProgressCallback monitor, File libraryDir, File minecraftJar, File installerJar); +} diff --git a/legacy/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/InstallerV0.java b/legacy/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/InstallerV0.java new file mode 100644 index 0000000000..ff1cd4373b --- /dev/null +++ b/legacy/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/InstallerV0.java @@ -0,0 +1,37 @@ +package io.github.zekerzhayard.forgewrapper.installer.util; + +import java.io.File; +import java.util.function.Predicate; + +import net.minecraftforge.installer.actions.ClientInstall; +import net.minecraftforge.installer.actions.ProgressCallback; +import net.minecraftforge.installer.json.Install; +import net.minecraftforge.installer.json.Util; + +public class InstallerV0 extends AbstractInstaller { + @Override + public Install loadInstallProfile() { + return Util.loadInstallProfile(); + } + + @Override + public boolean runClientInstall(Install profile, ProgressCallback monitor, File libraryDir, File minecraftJar, File installerJar) { + return new ClientInstall4MultiMC(profile, monitor, libraryDir, minecraftJar).run(null, input -> true); + } + + public static class ClientInstall4MultiMC extends ClientInstall { + protected File libraryDir; + protected File minecraftJar; + + public ClientInstall4MultiMC(Install profile, ProgressCallback monitor, File libraryDir, File minecraftJar) { + super(profile, monitor); + this.libraryDir = libraryDir; + this.minecraftJar = minecraftJar; + } + + @Override + public boolean run(File target, Predicate optionals) { + return this.processors.process(this.libraryDir, this.minecraftJar); + } + } +} diff --git a/settings.gradle b/settings.gradle index d3b1da5737..7bda9a2e39 100644 --- a/settings.gradle +++ b/settings.gradle @@ -2,4 +2,5 @@ rootProject.name = 'ForgeWrapper' include 'common' include 'converter' +include 'legacy' include 'jigsaw' diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/ClientInstall4MultiMC.java b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/ClientInstall4MultiMC.java deleted file mode 100644 index 6daa1e5371..0000000000 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/ClientInstall4MultiMC.java +++ /dev/null @@ -1,25 +0,0 @@ -package io.github.zekerzhayard.forgewrapper.installer; - -import java.io.File; -import java.util.function.Predicate; - -import net.minecraftforge.installer.actions.ClientInstall; -import net.minecraftforge.installer.actions.ProgressCallback; -import net.minecraftforge.installer.json.Install; -import net.minecraftforge.installer.json.InstallV1; - -public class ClientInstall4MultiMC extends ClientInstall { - protected File libraryDir; - protected File minecraftJar; - - public ClientInstall4MultiMC(Install profile, ProgressCallback monitor, File libraryDir, File minecraftJar) { - super(profile instanceof InstallV1 ? (InstallV1) profile : new InstallV1(profile), monitor); - this.libraryDir = libraryDir; - this.minecraftJar = minecraftJar; - } - - @Override - public boolean run(File target, Predicate optionals, File installer) { - return this.processors.process(this.libraryDir, this.minecraftJar, this.libraryDir.getParentFile(), installer); - } -} diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java index 1755ce11f0..eecfe90f00 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java @@ -2,14 +2,17 @@ package io.github.zekerzhayard.forgewrapper.installer; import java.io.File; +import io.github.zekerzhayard.forgewrapper.installer.util.AbstractInstaller; +import io.github.zekerzhayard.forgewrapper.installer.util.InstallerV0; +import io.github.zekerzhayard.forgewrapper.installer.util.InstallerV1; import net.minecraftforge.installer.actions.ProgressCallback; import net.minecraftforge.installer.json.Install; -import net.minecraftforge.installer.json.Util; public class Installer { - public static boolean install(File libraryDir, File minecraftJar, File installerJar, String forgeVersion) { + public static boolean install(File libraryDir, File minecraftJar, File installerJar, int installerSpec) { + AbstractInstaller installer = getInstaller(installerSpec); ProgressCallback monitor = ProgressCallback.withOutputs(System.out); - Install profile = Util.loadInstallProfile(); + Install profile = installer.loadInstallProfile(); if (System.getProperty("java.net.preferIPv4Stack") == null) { System.setProperty("java.net.preferIPv4Stack", "true"); } @@ -18,6 +21,14 @@ public class Installer { String jvmVersion = System.getProperty("java.vm.version", "missing jvm version"); monitor.message(String.format("JVM info: %s - %s - %s", vendor, javaVersion, jvmVersion)); monitor.message("java.net.preferIPv4Stack=" + System.getProperty("java.net.preferIPv4Stack")); - return new ClientInstall4MultiMC(profile, monitor, libraryDir, minecraftJar).run(null, input -> true, installerJar); + return installer.runClientInstall(profile, monitor, libraryDir, minecraftJar, installerJar); + } + + private static AbstractInstaller getInstaller(int installerSpec) { + switch (installerSpec) { + case 0: return new InstallerV0(); + case 1: return new InstallerV1(); + default: throw new IllegalArgumentException("Invalid installer profile spec: " + installerSpec); + } } } 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 3d955372f0..1df9aaacc7 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java @@ -47,7 +47,7 @@ public class Main { installerJar.toUri().toURL() }, ModuleUtil.getPlatformClassLoader())) { Class installer = ucl.loadClass("io.github.zekerzhayard.forgewrapper.installer.Installer"); - if (!(boolean) installer.getMethod("install", File.class, File.class, File.class, String.class).invoke(null, detector.getLibraryDir().toFile(), minecraftJar.toFile(), installerJar.toFile(), forgeVersion)) { + if (!(boolean) installer.getMethod("install", File.class, File.class, File.class, int.class).invoke(null, detector.getLibraryDir().toFile(), minecraftJar.toFile(), installerJar.toFile(), detector.getInstallProfileSpec(forgeFullVersion))) { return; } } 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 2cb62cc0db..7e56bb4a00 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 @@ -107,6 +107,14 @@ public interface IFileDetector { 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 installer specification version. + */ + default int getInstallProfileSpec(String forgeFullVersion) { + return this.getDataFromInstaller(forgeFullVersion, "install_profile.json", e -> e.getAsJsonObject().getAsJsonPrimitive("spec").getAsInt()); + } + /** * @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. @@ -149,7 +157,7 @@ public interface IFileDetector { Map hashMap = new HashMap<>(); // Get all "data//client" elements. - Pattern artifactPattern = Pattern.compile("^\\[(?[^:]*):(?[^:]*):(?[^:@]*)(:(?[^@]*))?(@(?[^]]*))?]$"); + Pattern artifactPattern = Pattern.compile("^\\[(?[^:]*):(?[^:]*):(?[^:@]*)(:(?[^@]*))?(@(?[^]]*))?]$"); for (Map.Entry entry : jo.entrySet()) { String clientStr = getElement(entry.getValue().getAsJsonObject(), "client").getAsString(); if (entry.getKey().endsWith("_SHA")) { @@ -164,13 +172,13 @@ public interface IFileDetector { String groupId = nullToDefault(m.group("groupId"), ""); String artifactId = nullToDefault(m.group("artifactId"), ""); String version = nullToDefault(m.group("version"), ""); - String prefix = nullToDefault(m.group("prefix"), ""); + String classifier = nullToDefault(m.group("classifier"), ""); String type = nullToDefault(m.group("type"), "jar"); libsMap.put(entry.getKey(), this.getLibraryDir() .resolve(groupId.replace('.', File.separatorChar)) .resolve(artifactId) .resolve(version) - .resolve(artifactId + "-" + version + (prefix.equals("") ? "" : "-") + prefix + "." + type).toAbsolutePath()); + .resolve(artifactId + "-" + version + (classifier.equals("") ? "" : "-") + classifier + "." + type).toAbsolutePath()); } } } diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/InstallerV1.java b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/InstallerV1.java new file mode 100644 index 0000000000..014a6240ea --- /dev/null +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/InstallerV1.java @@ -0,0 +1,38 @@ +package io.github.zekerzhayard.forgewrapper.installer.util; + +import java.io.File; +import java.util.function.Predicate; + +import net.minecraftforge.installer.actions.ClientInstall; +import net.minecraftforge.installer.actions.ProgressCallback; +import net.minecraftforge.installer.json.Install; +import net.minecraftforge.installer.json.InstallV1; +import net.minecraftforge.installer.json.Util; + +public class InstallerV1 extends AbstractInstaller { + @Override + public Install loadInstallProfile() { + return Util.loadInstallProfile(); + } + + @Override + public boolean runClientInstall(Install profile, ProgressCallback monitor, File libraryDir, File minecraftJar, File installerJar) { + return new ClientInstall4MultiMC(profile, monitor, libraryDir, minecraftJar).run(null, input -> true, installerJar); + } + + public static class ClientInstall4MultiMC extends ClientInstall { + protected File libraryDir; + protected File minecraftJar; + + public ClientInstall4MultiMC(Install profile, ProgressCallback monitor, File libraryDir, File minecraftJar) { + super(profile instanceof InstallV1 ? (InstallV1) profile : new InstallV1(profile), monitor); + this.libraryDir = libraryDir; + this.minecraftJar = minecraftJar; + } + + @Override + public boolean run(File target, Predicate optionals, File installer) { + return this.processors.process(this.libraryDir, this.minecraftJar, this.libraryDir.getParentFile(), installer); + } + } +} -- cgit 0.0.5-2-1-g0f52 From ad3e7501cab36caccfc1bb1ab0987d9c3c6cdb4f Mon Sep 17 00:00:00 2001 From: ZekerZhayard Date: Sat, 11 Dec 2021 15:41:15 +0800 Subject: Temporary files that are not used at runtime are now not checked. --- .../zekerzhayard/forgewrapper/installer/detector/IFileDetector.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 7e56bb4a00..1bb024a80a 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 @@ -205,7 +205,7 @@ public interface IFileDetector { * @return True represents the file is ready. */ default boolean checkExtraFile(Path path, String sha1) { - return Files.isRegularFile(path) && (sha1 == null || sha1.equals("") || sha1.toLowerCase(Locale.ENGLISH).equals(getFileSHA1(path))); + return sha1 == null || sha1.equals("") || (isFile(path) && sha1.toLowerCase(Locale.ENGLISH).equals(getFileSHA1(path))); } static boolean isFile(Path path) { -- cgit 0.0.5-2-1-g0f52 From f0a1b27529e3512cc0a4aaf01f0fb94c5ff2fcbc Mon Sep 17 00:00:00 2001 From: Pierce Date: Wed, 22 Dec 2021 08:37:41 -0500 Subject: Choose correct installer version regardless of spec (#9) --- .../zekerzhayard/forgewrapper/installer/Installer.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java index eecfe90f00..72181dde2c 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java @@ -1,12 +1,14 @@ package io.github.zekerzhayard.forgewrapper.installer; import java.io.File; +import java.lang.reflect.Method; import io.github.zekerzhayard.forgewrapper.installer.util.AbstractInstaller; import io.github.zekerzhayard.forgewrapper.installer.util.InstallerV0; import io.github.zekerzhayard.forgewrapper.installer.util.InstallerV1; import net.minecraftforge.installer.actions.ProgressCallback; import net.minecraftforge.installer.json.Install; +import net.minecraftforge.installer.json.Util; public class Installer { public static boolean install(File libraryDir, File minecraftJar, File installerJar, int installerSpec) { @@ -26,7 +28,18 @@ public class Installer { private static AbstractInstaller getInstaller(int installerSpec) { switch (installerSpec) { - case 0: return new InstallerV0(); + case 0: { + Boolean isV1 = false; + Method[] methods = Util.class.getDeclaredMethods(); + for (Method method: methods) { + String methodName = method.toString(); + if (methodName.contains("InstallV1") && methodName.contains("loadInstallProfile")) { + isV1 = true; + break; + } + } + return isV1 ? new InstallerV1() : new InstallerV0(); + } case 1: return new InstallerV1(); default: throw new IllegalArgumentException("Invalid installer profile spec: " + installerSpec); } -- cgit 0.0.5-2-1-g0f52 From 71ac68371b30097b887bb3635ea27c4dc91bca8b Mon Sep 17 00:00:00 2001 From: ZekerZhayard Date: Wed, 22 Dec 2021 22:28:35 +0800 Subject: Use a better way to determine the installer version. --- gradle.properties | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- .../forgewrapper/installer/Installer.java | 32 ++++++++++------------ .../zekerzhayard/forgewrapper/installer/Main.java | 2 +- .../installer/detector/IFileDetector.java | 13 ++------- 5 files changed, 20 insertions(+), 31 deletions(-) diff --git a/gradle.properties b/gradle.properties index 29b7ba0097..85a1608512 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.daemon = false -fw_version = 1.5.4 +fw_version = 1.5.5 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 3cd8500c13..669386b870 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java index 72181dde2c..278688e773 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java @@ -1,18 +1,18 @@ package io.github.zekerzhayard.forgewrapper.installer; import java.io.File; -import java.lang.reflect.Method; import io.github.zekerzhayard.forgewrapper.installer.util.AbstractInstaller; import io.github.zekerzhayard.forgewrapper.installer.util.InstallerV0; import io.github.zekerzhayard.forgewrapper.installer.util.InstallerV1; import net.minecraftforge.installer.actions.ProgressCallback; import net.minecraftforge.installer.json.Install; +import net.minecraftforge.installer.json.InstallV1; import net.minecraftforge.installer.json.Util; public class Installer { - public static boolean install(File libraryDir, File minecraftJar, File installerJar, int installerSpec) { - AbstractInstaller installer = getInstaller(installerSpec); + public static boolean install(File libraryDir, File minecraftJar, File installerJar) { + AbstractInstaller installer = createInstaller(); ProgressCallback monitor = ProgressCallback.withOutputs(System.out); Install profile = installer.loadInstallProfile(); if (System.getProperty("java.net.preferIPv4Stack") == null) { @@ -26,22 +26,18 @@ public class Installer { return installer.runClientInstall(profile, monitor, libraryDir, minecraftJar, installerJar); } - private static AbstractInstaller getInstaller(int installerSpec) { - switch (installerSpec) { - case 0: { - Boolean isV1 = false; - Method[] methods = Util.class.getDeclaredMethods(); - for (Method method: methods) { - String methodName = method.toString(); - if (methodName.contains("InstallV1") && methodName.contains("loadInstallProfile")) { - isV1 = true; - break; - } - } - return isV1 ? new InstallerV1() : new InstallerV0(); + private static AbstractInstaller createInstaller() { + try { + Class installerClass = Util.class.getMethod("loadInstallProfile").getReturnType(); + if (installerClass.equals(Install.class)) { + return new InstallerV0(); + } else if (installerClass.equals(InstallV1.class)) { + return new InstallerV1(); + } else { + throw new IllegalArgumentException("Unable to determine the installer version. (" + installerClass + ")"); } - case 1: return new InstallerV1(); - default: throw new IllegalArgumentException("Invalid installer profile spec: " + installerSpec); + } catch (Throwable t) { + throw new RuntimeException(t); } } } 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 1df9aaacc7..7134ba5fff 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java @@ -47,7 +47,7 @@ public class Main { installerJar.toUri().toURL() }, ModuleUtil.getPlatformClassLoader())) { Class installer = ucl.loadClass("io.github.zekerzhayard.forgewrapper.installer.Installer"); - if (!(boolean) installer.getMethod("install", File.class, File.class, File.class, int.class).invoke(null, detector.getLibraryDir().toFile(), minecraftJar.toFile(), installerJar.toFile(), detector.getInstallProfileSpec(forgeFullVersion))) { + if (!(boolean) installer.getMethod("install", File.class, File.class, File.class).invoke(null, detector.getLibraryDir().toFile(), minecraftJar.toFile(), installerJar.toFile())) { return; } } 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 1bb024a80a..76df474631 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 @@ -107,14 +107,6 @@ public interface IFileDetector { 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 installer specification version. - */ - default int getInstallProfileSpec(String forgeFullVersion) { - return this.getDataFromInstaller(forgeFullVersion, "install_profile.json", e -> e.getAsJsonObject().getAsJsonPrimitive("spec").getAsInt()); - } - /** * @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. @@ -123,6 +115,7 @@ public interface IFileDetector { return this.getDataFromInstaller(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); if (isFile(installer)) { @@ -186,7 +179,7 @@ public interface IFileDetector { // Check all cached libraries. boolean checked = true; for (Map.Entry entry : libsMap.entrySet()) { - checked = this.checkExtraFile(entry.getValue(), hashMap.get(entry.getKey() + "_SHA")); + checked = checkExtraFile(entry.getValue(), hashMap.get(entry.getKey() + "_SHA")); if (!checked) { System.out.println("Missing: " + entry.getValue()); break; @@ -204,7 +197,7 @@ public interface IFileDetector { * @param sha1 The sha1 defined in installer. * @return True represents the file is ready. */ - default boolean checkExtraFile(Path path, String sha1) { + static boolean checkExtraFile(Path path, String sha1) { return sha1 == null || sha1.equals("") || (isFile(path) && sha1.toLowerCase(Locale.ENGLISH).equals(getFileSHA1(path))); } -- cgit 0.0.5-2-1-g0f52 From 7a8427d130ba33b274fca8df543e39765cf266fd Mon Sep 17 00:00:00 2001 From: Thomas Kain Date: Sat, 5 Aug 2023 10:46:57 -0400 Subject: Implement support for NeoForge (#13) * Fix compilation on Java versions other than 8 * Add basic support for NeoForge This uses Forge's built-in fml.forgeGroup flag to distinguish Forge and NeoForge's package names. Consequently, this flag's value needs to be passed to most installer-related functions. * Update Javadocs with Forge group parameter * Add Forge group support for manual installs * Assume we're using NeoForge if `--fml.forgeGroup` isn't specified I was hoping not to hardcode any package names here, but this is the only way to unbreak manual installs without unintuitively asking users to add the flag themselves. --- .../forgewrapper/converter/Converter.java | 47 +++++++++++++++------- converter/src/main/resources/mmc-pack.json | 2 +- .../main/resources/patches/net.minecraftforge.json | 28 ------------- converter/src/main/resources/patches/template.json | 28 +++++++++++++ legacy/build.gradle | 5 +++ .../zekerzhayard/forgewrapper/installer/Main.java | 9 +++-- .../installer/detector/IFileDetector.java | 27 ++++++++----- .../installer/detector/MultiMCFileDetector.java | 12 ++++-- 8 files changed, 96 insertions(+), 62 deletions(-) delete mode 100644 converter/src/main/resources/patches/net.minecraftforge.json create mode 100644 converter/src/main/resources/patches/template.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 index ade550f0eb..e5771bc87e 100644 --- a/converter/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java +++ b/converter/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java @@ -28,12 +28,13 @@ public class Converter { JsonObject installProfile = getJsonFromZip(installerPath, "install_profile.json"); List arguments = getAdditionalArgs(installer); String mcVersion = arguments.get(arguments.indexOf("--fml.mcVersion") + 1); + String forgeGroup = arguments.contains("--fml.forgeGroup") ? arguments.get(arguments.indexOf("--fml.forgeGroup") + 1) : "net.neoforged"; 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); + JsonObject pack = convertPackJson(mcVersion, forgeGroup); + JsonObject patches = convertPatchesJson(installer, installProfile, mcVersion, forgeGroup, forgeVersion, wrapperVersion); Files.createDirectories(targetDir); @@ -48,14 +49,17 @@ public class Converter { 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. + // Copy .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); + Files.copy(new ByteArrayInputStream(patches.toString().getBytes(StandardCharsets.UTF_8)), patchesPath.resolve(forgeGroup + ".json"), StandardCopyOption.REPLACE_EXISTING); - // Copy forge installer to MultiMC/libraries/net/minecraftforge/forge/- folder. + // Copy forge installer to MultiMC/libraries//forge/- folder. if (multimcDir != null) { - Path targetInstallerPath = multimcDir.resolve("libraries").resolve("net").resolve("minecraftforge").resolve("forge").resolve(forgeVersion); + Path targetInstallerPath = multimcDir.resolve("libraries"); + for (String dir : forgeGroup.split("\\.")) + targetInstallerPath = targetInstallerPath.resolve(dir); + targetInstallerPath = targetInstallerPath.resolve("forge").resolve(mcVersion + "-" + forgeVersion); Files.createDirectories(targetInstallerPath); Files.copy(installerPath, targetInstallerPath.resolve(forgeFullVersion + "-installer.jar"), StandardCopyOption.REPLACE_EXISTING); } @@ -83,7 +87,8 @@ public class Converter { // Convert mmc-pack.json: // - Replace Minecraft version - private static JsonObject convertPackJson(String mcVersion) { + // - Replace Forge package group + private static JsonObject convertPackJson(String mcVersion, String forgeGroup) { JsonObject pack = JsonParser.parseReader(new InputStreamReader(Converter.class.getResourceAsStream("/mmc-pack.json"))).getAsJsonObject(); for (JsonElement component : getElement(pack, "components").getAsJsonArray()) { @@ -91,26 +96,37 @@ public class Converter { JsonElement version = getElement(componentObject, "version"); if (!version.isJsonNull() && getElement(componentObject, "uid").getAsString().equals("net.minecraft")) { componentObject.addProperty("version", mcVersion); + } else if (getElement(componentObject, "uid").getAsString().equals("{FORGE_GROUP}")) { + componentObject.addProperty("uid", forgeGroup); } } return pack; } - // Convert patches/net.minecraftforge.json: + // Convert patches/.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(); + // - Replace Forge package group + private static JsonObject convertPatchesJson(JsonObject installer, JsonObject installProfile, String mcVersion, String forgeGroup, String forgeVersion, StringBuilder wrapperVersion) { + JsonObject patches = JsonParser.parseReader(new InputStreamReader(Converter.class.getResourceAsStream("/patches/template.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); + String[] forgeGroupParts = forgeGroup.split("\\."); + String[] forgeURLParts = new String[forgeGroupParts.length]; + for (int i = 0; i < forgeURLParts.length; i++) + forgeURLParts[i] = forgeGroupParts[forgeGroupParts.length - i - 1]; + String mavenURL = "https://maven." + String.join(".", forgeURLParts); + for (JsonElement mavenFile : mavenFiles) { - String name = getElement(mavenFile.getAsJsonObject(), "name").getAsString(); - mavenFile.getAsJsonObject().addProperty("name", name.replace("{VERSION}", mcVersion).replace("{FORGE_VERSION}", forgeVersion)); + JsonObject mavenJsonObj = mavenFile.getAsJsonObject(); + String name = getElement(mavenJsonObj, "name").getAsString(); + mavenJsonObj.addProperty("name", name.replace("{FORGE_GROUP}", forgeGroup).replace("{VERSION}", mcVersion).replace("{FORGE_VERSION}", forgeVersion)); + mavenJsonObj.addProperty("url", mavenURL); } for (JsonElement lib : libraries) { String name = getElement(lib.getAsJsonObject(), "name").getAsString(); @@ -119,13 +135,14 @@ public class Converter { } } 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"); + String path = String.format("%s/forge/%s-%s/forge-%s-%s", String.join("/", forgeGroupParts), mcVersion, forgeVersion, mcVersion, forgeVersion); + additionalUrls.put(path + "-universal.jar", mavenURL + "/" + path + "-universal.jar"); transformLibraries(getElement(installProfile, "libraries").getAsJsonArray(), mavenFiles, additionalUrls); additionalUrls.clear(); - additionalUrls.put(path + ".jar", "https://maven.minecraftforge.net/" + path + "-launcher.jar"); + additionalUrls.put(path + ".jar", mavenURL + "/" + path + "-launcher.jar"); transformLibraries(getElement(installer, "libraries").getAsJsonArray(), libraries, additionalUrls); + patches.addProperty("uid", forgeGroup); patches.addProperty("version", forgeVersion); for (JsonElement require : getElement(patches, "requires").getAsJsonArray()) { JsonObject requireObject = require.getAsJsonObject(); diff --git a/converter/src/main/resources/mmc-pack.json b/converter/src/main/resources/mmc-pack.json index 87db08a724..51ba0bf376 100644 --- a/converter/src/main/resources/mmc-pack.json +++ b/converter/src/main/resources/mmc-pack.json @@ -7,7 +7,7 @@ "version": "{VERSION}" }, { - "uid": "net.minecraftforge" + "uid": "{FORGE_GROUP}" } ] } 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 4fac6aabd0..0000000000 --- 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/converter/src/main/resources/patches/template.json b/converter/src/main/resources/patches/template.json new file mode 100644 index 0000000000..5a46916d28 --- /dev/null +++ b/converter/src/main/resources/patches/template.json @@ -0,0 +1,28 @@ +{ + "formatVersion": 1, + "mainClass": "io.github.zekerzhayard.forgewrapper.installer.Main", + "minecraftArguments": "", + "name": "Forge", + "requires": [ + { + "equals": "{VERSION}", + "uid": "net.minecraft" + } + ], + "type": "release", + "uid": "{FORGE_GROUP}", + "version": "{FORGE_VERSION}", + "mavenFiles": [ + { + "name": "{FORGE_GROUP}:forge:{VERSION}-{FORGE_VERSION}:installer", + "url": "{MAVEN_URL}" + } + ], + "libraries": [ + { + "name": "io.github.zekerzhayard:ForgeWrapper:${version}", + "MMC-hint": "local", + "MMC-filename": "ForgeWrapper-${version}.jar" + } + ] +} diff --git a/legacy/build.gradle b/legacy/build.gradle index 8824390d0f..4778335e0d 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/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java index 7134ba5fff..ab82cf2fc7 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java @@ -17,20 +17,21 @@ public class Main { public static void main(String[] args) throws Throwable { List argsList = Stream.of(args).collect(Collectors.toList()); String mcVersion = argsList.get(argsList.indexOf("--fml.mcVersion") + 1); + String forgeGroup = argsList.contains("--fml.forgeGroup") ? argsList.get(argsList.indexOf("--fml.forgeGroup") + 1) : "net.neoforged"; String forgeVersion = argsList.get(argsList.indexOf("--fml.forgeVersion") + 1); String forgeFullVersion = 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, 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, 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, forgeFullVersion); if (!IFileDetector.isFile(installerJar)) { throw new RuntimeException("Unable to detect the forge installer!"); } @@ -53,7 +54,7 @@ public class Main { } } - Class mainClass = ModuleUtil.setupBootstrapLauncher(Class.forName(detector.getMainClass(forgeFullVersion))); + Class mainClass = ModuleUtil.setupBootstrapLauncher(Class.forName(detector.getMainClass(forgeGroup, 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 76df474631..a007a7790a 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,11 @@ public interface IFileDetector { } /** + * @param forgeGroup Forge package group (e.g. net.minecraftforge). * @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 forgeFullVersion) { String installer = System.getProperty("forgewrapper.installer"); if (installer != null) { return Paths.get(installer).toAbsolutePath(); @@ -85,11 +86,12 @@ public interface IFileDetector { } /** + * @param forgeGroup Forge package group (e.g. net.minecraftforge). * @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 -> { + default List getJvmArgs(String forgeGroup, String forgeFullVersion) { + return this.getDataFromInstaller(forgeGroup, forgeFullVersion, "version.json", e -> { JsonElement element = getElement(e.getAsJsonObject().getAsJsonObject("arguments"), "jvm"); List args = new ArrayList<>(); if (!element.equals(JsonNull.INSTANCE)) { @@ -100,24 +102,26 @@ public interface IFileDetector { } /** + * @param forgeGroup Forge package group (e.g. net.minecraftforge). * @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 forgeFullVersion) { + return this.getDataFromInstaller(forgeGroup, forgeFullVersion, "version.json", e -> e.getAsJsonObject().getAsJsonPrimitive("mainClass").getAsString()); } /** + * @param forgeGroup Forge package group (e.g. net.minecraftforge). * @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 forgeFullVersion) { + return this.getDataFromInstaller(forgeGroup, 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 forgeFullVersion, String entry, Function function) { + Path installer = this.getInstallerJar(forgeGroup, forgeFullVersion); if (isFile(installer)) { try (ZipFile zf = new ZipFile(installer.toFile())) { ZipEntry ze = zf.getEntry(entry); @@ -140,11 +144,12 @@ public interface IFileDetector { /** * Check all cached files. + * @param forgeGroup Forge package group (e.g. net.minecraftforge). * @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 forgeFullVersion) { + JsonObject jo = this.getInstallProfileExtraData(forgeGroup, forgeFullVersion); if (jo != null) { Map libsMap = new HashMap<>(); Map hashMap = new HashMap<>(); 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 cb87d27825..7d0cf491c9 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 forgeFullVersion) { + Path path = IFileDetector.super.getInstallerJar(forgeGroup, 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("forge").resolve(forgeFullVersion).resolve("forge-" + forgeFullVersion + "-installer.jar").toAbsolutePath(); + } + return this.installerJar; } return path; } -- cgit 0.0.5-2-1-g0f52 From d7796062a4c9ff09207947d0a8a6b0a427715042 Mon Sep 17 00:00:00 2001 From: ZekerZhayard Date: Sun, 6 Aug 2023 00:42:28 +0800 Subject: 1.5.6 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 85a1608512..e96608ce6a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.daemon = false -fw_version = 1.5.5 +fw_version = 1.5.6 -- cgit 0.0.5-2-1-g0f52 From bd030afd9fa071501207becd9287666ea2a44acb Mon Sep 17 00:00:00 2001 From: Petr Mrázek Date: Sun, 2 Jan 2022 00:05:00 +0100 Subject: Workaround for MultiMC/Launcher#4400 Signed-off-by: Sefa Eyeoglu --- build.gradle | 7 +------ .../installer/detector/IFileDetector.java | 22 +++++++++++++++++++--- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/build.gradle b/build.gradle index 45e6dee5d7..a8af5dfa2a 100644 --- a/build.gradle +++ b/build.gradle @@ -91,10 +91,5 @@ publishing { tasks.publish.dependsOn build static String getVersionSuffix() { - if (System.getenv("IS_PUBLICATION") != null) { - return "" - } else if (System.getenv("GITHUB_RUN_NUMBER") != null && System.getenv("GITHUB_SHA") != null) { - return "-s." + System.getenv("GITHUB_RUN_NUMBER") + "-" + System.getenv("GITHUB_SHA").substring(0, 7) - } - return "-LOCAL" + return "" } 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 a007a7790a..f9aa328e5a 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 @@ -184,14 +184,24 @@ public interface IFileDetector { // Check all cached libraries. boolean checked = true; for (Map.Entry entry : libsMap.entrySet()) { - checked = checkExtraFile(entry.getValue(), hashMap.get(entry.getKey() + "_SHA")); + String sha1 = ""; + String entryKey = entry.getKey(); + /** + * NOTE: workaround for https://github.com/MultiMC/Launcher/issues/4400 + * We ignore the hash of the client file and instead just rely on it being 'correct, maybe' if it's present at all + */ + System.out.println("Checking: " + entryKey); + if(!entryKey.equals("PATCHED")) { + sha1 = hashMap.get(entryKey + "_SHA"); + } + checked = checkExtraFile(entry.getValue(), sha1); if (!checked) { System.out.println("Missing: " + entry.getValue()); break; } } return checked; - } + } // Skip installing process if installer profile doesn't exist. return true; } @@ -203,7 +213,13 @@ public interface IFileDetector { * @return True represents the file is ready. */ static boolean checkExtraFile(Path path, String sha1) { - return sha1 == null || sha1.equals("") || (isFile(path) && sha1.toLowerCase(Locale.ENGLISH).equals(getFileSHA1(path))); + if (!isFile(path)) { + return false; + } + if(sha1 == null || sha1.equals("")) { + return true; + } + return sha1.toLowerCase(Locale.ENGLISH).equals(getFileSHA1(path)); } static boolean isFile(Path path) { -- cgit 0.0.5-2-1-g0f52 From f7d61b020e672f6243b63411350f7cf93984bff5 Mon Sep 17 00:00:00 2001 From: Petr Mrázek Date: Tue, 4 Jan 2022 22:19:35 +0100 Subject: Ignore some random server file causing the installer to rerun --- .../zekerzhayard/forgewrapper/installer/detector/IFileDetector.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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 f9aa328e5a..3efce36429 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 @@ -186,6 +186,10 @@ public interface IFileDetector { for (Map.Entry entry : libsMap.entrySet()) { String sha1 = ""; String entryKey = entry.getKey(); + // NOTE: only used on servers, it's busted + if(entryKey.equals("MC_UNPACKED")) { + continue; + } /** * NOTE: workaround for https://github.com/MultiMC/Launcher/issues/4400 * We ignore the hash of the client file and instead just rely on it being 'correct, maybe' if it's present at all @@ -201,7 +205,7 @@ public interface IFileDetector { } } return checked; - } + } // Skip installing process if installer profile doesn't exist. return true; } -- cgit 0.0.5-2-1-g0f52 From 55537dbcdc269944ce7c08008302806cd86e1bd1 Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Sun, 6 Aug 2023 14:40:19 +0200 Subject: chore: bump version Signed-off-by: Sefa Eyeoglu --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index e96608ce6a..47096551a0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.daemon = false -fw_version = 1.5.6 +fw_version = 1.5.6-prism -- cgit 0.0.5-2-1-g0f52 From e0e202a0d08f3b104d6729475e4eb7c6eee422f4 Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Wed, 1 Nov 2023 11:54:01 +0100 Subject: Implement support for NeoForge 20.2+ Signed-off-by: Sefa Eyeoglu --- .../zekerzhayard/forgewrapper/installer/Main.java | 20 +++++++++++----- .../installer/detector/IFileDetector.java | 27 +++++++++++++--------- .../installer/detector/MultiMCFileDetector.java | 6 ++--- 3 files changed, 33 insertions(+), 20 deletions(-) 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 ab82cf2fc7..5ecd971e1f 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java @@ -15,23 +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 forgeGroup = argsList.contains("--fml.forgeGroup") ? argsList.get(argsList.indexOf("--fml.forgeGroup") + 1) : "net.neoforged"; - String forgeVersion = argsList.get(argsList.indexOf("--fml.forgeVersion") + 1); - String forgeFullVersion = mcVersion + "-" + forgeVersion; + 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(forgeGroup, 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(forgeGroup, 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(forgeGroup, forgeFullVersion); + Path installerJar = detector.getInstallerJar(forgeGroup, forgeArtifact, forgeFullVersion); if (!IFileDetector.isFile(installerJar)) { throw new RuntimeException("Unable to detect the forge installer!"); } @@ -54,7 +62,7 @@ public class Main { } } - Class mainClass = ModuleUtil.setupBootstrapLauncher(Class.forName(detector.getMainClass(forgeGroup, 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 a007a7790a..b69e9b8ec6 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 @@ -62,10 +62,11 @@ 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 forgeGroup, 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(); @@ -87,11 +88,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 list of jvm args. */ - default List getJvmArgs(String forgeGroup, String forgeFullVersion) { - return this.getDataFromInstaller(forgeGroup, forgeFullVersion, "version.json", e -> { + default List getJvmArgs(String forgeGroup, String forgeArtifact, String forgeFullVersion) { + return this.getDataFromInstaller(forgeGroup, forgeArtifact, forgeFullVersion, "version.json", e -> { JsonElement element = getElement(e.getAsJsonObject().getAsJsonObject("arguments"), "jvm"); List args = new ArrayList<>(); if (!element.equals(JsonNull.INSTANCE)) { @@ -103,25 +105,27 @@ 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 main class. */ - default String getMainClass(String forgeGroup, String forgeFullVersion) { - return this.getDataFromInstaller(forgeGroup, 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 forgeGroup, String forgeFullVersion) { - return this.getDataFromInstaller(forgeGroup, 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 forgeGroup, String forgeFullVersion, String entry, Function function) { - Path installer = this.getInstallerJar(forgeGroup, 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); @@ -145,11 +149,12 @@ 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 forgeGroup, String forgeFullVersion) { - JsonObject jo = this.getInstallProfileExtraData(forgeGroup, 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<>(); 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 7d0cf491c9..a1216f0947 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,14 +27,14 @@ public class MultiMCFileDetector implements IFileDetector { } @Override - public Path getInstallerJar(String forgeGroup, String forgeFullVersion) { - Path path = IFileDetector.super.getInstallerJar(forgeGroup, forgeFullVersion); + public Path getInstallerJar(String forgeGroup, String forgeArtifact, String forgeFullVersion) { + Path path = IFileDetector.super.getInstallerJar(forgeGroup, forgeArtifact, forgeFullVersion); if (path == null) { if (this.installerJar == null) { Path installerBase = this.getLibraryDir(); for (String dir : forgeGroup.split("\\.")) installerBase = installerBase.resolve(dir); - this.installerJar = installerBase.resolve("forge").resolve(forgeFullVersion).resolve("forge-" + forgeFullVersion + "-installer.jar").toAbsolutePath(); + this.installerJar = installerBase.resolve(forgeArtifact).resolve(forgeFullVersion).resolve(forgeArtifact + "-" + forgeFullVersion + "-installer.jar").toAbsolutePath(); } return this.installerJar; } -- cgit 0.0.5-2-1-g0f52 From 4143670005fecc2ea7a34948e6bf797ce26d983e Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Wed, 1 Nov 2023 11:58:25 +0100 Subject: chore: bump version Signed-off-by: Sefa Eyeoglu --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 47096551a0..cd09c6b268 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.daemon = false -fw_version = 1.5.6-prism +fw_version = 1.5.7-prism -- cgit 0.0.5-2-1-g0f52 From f1b006b09569ad345e0924cc7421ca2b3bc47708 Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Wed, 1 Nov 2023 13:32:07 +0100 Subject: Implement support for NeoForge 20.2+ (#16) Signed-off-by: Sefa Eyeoglu --- .../zekerzhayard/forgewrapper/installer/Main.java | 20 +++++++++++----- .../installer/detector/IFileDetector.java | 27 +++++++++++++--------- .../installer/detector/MultiMCFileDetector.java | 6 ++--- 3 files changed, 33 insertions(+), 20 deletions(-) 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 ab82cf2fc7..5ecd971e1f 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java @@ -15,23 +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 forgeGroup = argsList.contains("--fml.forgeGroup") ? argsList.get(argsList.indexOf("--fml.forgeGroup") + 1) : "net.neoforged"; - String forgeVersion = argsList.get(argsList.indexOf("--fml.forgeVersion") + 1); - String forgeFullVersion = mcVersion + "-" + forgeVersion; + 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(forgeGroup, 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(forgeGroup, 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(forgeGroup, forgeFullVersion); + Path installerJar = detector.getInstallerJar(forgeGroup, forgeArtifact, forgeFullVersion); if (!IFileDetector.isFile(installerJar)) { throw new RuntimeException("Unable to detect the forge installer!"); } @@ -54,7 +62,7 @@ public class Main { } } - Class mainClass = ModuleUtil.setupBootstrapLauncher(Class.forName(detector.getMainClass(forgeGroup, 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 a007a7790a..b69e9b8ec6 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 @@ -62,10 +62,11 @@ 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 forgeGroup, 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(); @@ -87,11 +88,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 list of jvm args. */ - default List getJvmArgs(String forgeGroup, String forgeFullVersion) { - return this.getDataFromInstaller(forgeGroup, forgeFullVersion, "version.json", e -> { + default List getJvmArgs(String forgeGroup, String forgeArtifact, String forgeFullVersion) { + return this.getDataFromInstaller(forgeGroup, forgeArtifact, forgeFullVersion, "version.json", e -> { JsonElement element = getElement(e.getAsJsonObject().getAsJsonObject("arguments"), "jvm"); List args = new ArrayList<>(); if (!element.equals(JsonNull.INSTANCE)) { @@ -103,25 +105,27 @@ 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 main class. */ - default String getMainClass(String forgeGroup, String forgeFullVersion) { - return this.getDataFromInstaller(forgeGroup, 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 forgeGroup, String forgeFullVersion) { - return this.getDataFromInstaller(forgeGroup, 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 forgeGroup, String forgeFullVersion, String entry, Function function) { - Path installer = this.getInstallerJar(forgeGroup, 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); @@ -145,11 +149,12 @@ 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 forgeGroup, String forgeFullVersion) { - JsonObject jo = this.getInstallProfileExtraData(forgeGroup, 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<>(); 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 7d0cf491c9..a1216f0947 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,14 +27,14 @@ public class MultiMCFileDetector implements IFileDetector { } @Override - public Path getInstallerJar(String forgeGroup, String forgeFullVersion) { - Path path = IFileDetector.super.getInstallerJar(forgeGroup, forgeFullVersion); + public Path getInstallerJar(String forgeGroup, String forgeArtifact, String forgeFullVersion) { + Path path = IFileDetector.super.getInstallerJar(forgeGroup, forgeArtifact, forgeFullVersion); if (path == null) { if (this.installerJar == null) { Path installerBase = this.getLibraryDir(); for (String dir : forgeGroup.split("\\.")) installerBase = installerBase.resolve(dir); - this.installerJar = installerBase.resolve("forge").resolve(forgeFullVersion).resolve("forge-" + forgeFullVersion + "-installer.jar").toAbsolutePath(); + this.installerJar = installerBase.resolve(forgeArtifact).resolve(forgeFullVersion).resolve(forgeArtifact + "-" + forgeFullVersion + "-installer.jar").toAbsolutePath(); } return this.installerJar; } -- cgit 0.0.5-2-1-g0f52 From fb7f889cd471900f29350df52d10a1babc06e863 Mon Sep 17 00:00:00 2001 From: ZekerZhayard Date: Wed, 1 Nov 2023 22:36:17 +0800 Subject: 1.5.7 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index e96608ce6a..f1db528596 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.daemon = false -fw_version = 1.5.6 +fw_version = 1.5.7 -- cgit 0.0.5-2-1-g0f52 From a3413eb5c46f0205b0aa7c0fd8cc326dbebcced2 Mon Sep 17 00:00:00 2001 From: ZekerZhayard Date: Wed, 20 Dec 2023 00:41:37 +0800 Subject: Initial support for Forge 1.20.4 (with a few minor issues). Removed the converter project. --- converter/build.gradle | 54 ------- .../forgewrapper/converter/Converter.java | 174 --------------------- .../zekerzhayard/forgewrapper/converter/Main.java | 53 ------- converter/src/main/resources/mmc-pack.json | 13 -- converter/src/main/resources/patches/template.json | 28 ---- gradle.properties | 2 +- .../forgewrapper/installer/util/ModuleUtil.java | 10 ++ settings.gradle | 1 - .../forgewrapper/installer/Bootstrap.java | 9 ++ .../zekerzhayard/forgewrapper/installer/Main.java | 1 + .../installer/detector/IFileDetector.java | 29 ++-- .../forgewrapper/installer/util/ModuleUtil.java | 13 ++ 12 files changed, 51 insertions(+), 336 deletions(-) delete mode 100644 converter/build.gradle delete mode 100644 converter/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java delete mode 100644 converter/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Main.java delete mode 100644 converter/src/main/resources/mmc-pack.json delete mode 100644 converter/src/main/resources/patches/template.json diff --git a/converter/build.gradle b/converter/build.gradle deleted file mode 100644 index a3661b7d68..0000000000 --- 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 e5771bc87e..0000000000 --- a/converter/src/main/java/io/github/zekerzhayard/forgewrapper/converter/Converter.java +++ /dev/null @@ -1,174 +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 forgeGroup = arguments.contains("--fml.forgeGroup") ? arguments.get(arguments.indexOf("--fml.forgeGroup") + 1) : "net.neoforged"; - String forgeVersion = arguments.get(arguments.indexOf("--fml.forgeVersion") + 1); - String forgeFullVersion = "forge-" + mcVersion + "-" + forgeVersion; - StringBuilder wrapperVersion = new StringBuilder(); - - JsonObject pack = convertPackJson(mcVersion, forgeGroup); - JsonObject patches = convertPatchesJson(installer, installProfile, mcVersion, forgeGroup, 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 .json to /patches folder. - Path patchesPath = instancePath.resolve("patches"); - Files.createDirectories(patchesPath); - Files.copy(new ByteArrayInputStream(patches.toString().getBytes(StandardCharsets.UTF_8)), patchesPath.resolve(forgeGroup + ".json"), StandardCopyOption.REPLACE_EXISTING); - - // Copy forge installer to MultiMC/libraries//forge/- folder. - if (multimcDir != null) { - Path targetInstallerPath = multimcDir.resolve("libraries"); - for (String dir : forgeGroup.split("\\.")) - targetInstallerPath = targetInstallerPath.resolve(dir); - targetInstallerPath = targetInstallerPath.resolve("forge").resolve(mcVersion + "-" + 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 - // - Replace Forge package group - private static JsonObject convertPackJson(String mcVersion, String forgeGroup) { - 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); - } else if (getElement(componentObject, "uid").getAsString().equals("{FORGE_GROUP}")) { - componentObject.addProperty("uid", forgeGroup); - } - } - return pack; - } - - // Convert patches/.json: - // - Add libraries - // - Add forge-launcher url - // - Replace Minecraft & Forge versions - // - Replace Forge package group - private static JsonObject convertPatchesJson(JsonObject installer, JsonObject installProfile, String mcVersion, String forgeGroup, String forgeVersion, StringBuilder wrapperVersion) { - JsonObject patches = JsonParser.parseReader(new InputStreamReader(Converter.class.getResourceAsStream("/patches/template.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); - - String[] forgeGroupParts = forgeGroup.split("\\."); - String[] forgeURLParts = new String[forgeGroupParts.length]; - for (int i = 0; i < forgeURLParts.length; i++) - forgeURLParts[i] = forgeGroupParts[forgeGroupParts.length - i - 1]; - String mavenURL = "https://maven." + String.join(".", forgeURLParts); - - for (JsonElement mavenFile : mavenFiles) { - JsonObject mavenJsonObj = mavenFile.getAsJsonObject(); - String name = getElement(mavenJsonObj, "name").getAsString(); - mavenJsonObj.addProperty("name", name.replace("{FORGE_GROUP}", forgeGroup).replace("{VERSION}", mcVersion).replace("{FORGE_VERSION}", forgeVersion)); - mavenJsonObj.addProperty("url", mavenURL); - } - 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("%s/forge/%s-%s/forge-%s-%s", String.join("/", forgeGroupParts), mcVersion, forgeVersion, mcVersion, forgeVersion); - additionalUrls.put(path + "-universal.jar", mavenURL + "/" + path + "-universal.jar"); - transformLibraries(getElement(installProfile, "libraries").getAsJsonArray(), mavenFiles, additionalUrls); - additionalUrls.clear(); - additionalUrls.put(path + ".jar", mavenURL + "/" + path + "-launcher.jar"); - transformLibraries(getElement(installer, "libraries").getAsJsonArray(), libraries, additionalUrls); - - patches.addProperty("uid", forgeGroup); - 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 83ecdf959e..0000000000 --- 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 51ba0bf376..0000000000 --- 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": "{FORGE_GROUP}" - } - ] -} diff --git a/converter/src/main/resources/patches/template.json b/converter/src/main/resources/patches/template.json deleted file mode 100644 index 5a46916d28..0000000000 --- a/converter/src/main/resources/patches/template.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": "{FORGE_GROUP}", - "version": "{FORGE_VERSION}", - "mavenFiles": [ - { - "name": "{FORGE_GROUP}:forge:{VERSION}-{FORGE_VERSION}:installer", - "url": "{MAVEN_URL}" - } - ], - "libraries": [ - { - "name": "io.github.zekerzhayard:ForgeWrapper:${version}", - "MMC-hint": "local", - "MMC-filename": "ForgeWrapper-${version}.jar" - } - ] -} diff --git a/gradle.properties b/gradle.properties index f1db528596..4fb12126f0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.daemon = false -fw_version = 1.5.7 +fw_version = 1.5.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 index 9a49d7f0b8..e15d39c410 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/settings.gradle b/settings.gradle index 7bda9a2e39..34c563d573 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 2740b76bef..3604371a14 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 5ecd971e1f..37876a6de4 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java @@ -62,6 +62,7 @@ public class Main { } } + 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 b69e9b8ec6..67d3e1d4a1 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 @@ -94,7 +94,7 @@ public interface IFileDetector { */ default List getJvmArgs(String forgeGroup, String forgeArtifact, String forgeFullVersion) { return this.getDataFromInstaller(forgeGroup, forgeArtifact, forgeFullVersion, "version.json", e -> { - JsonElement element = getElement(e.getAsJsonObject().getAsJsonObject("arguments"), "jvm"); + 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())); @@ -103,6 +103,19 @@ 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). @@ -162,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); @@ -181,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()); } } } @@ -208,21 +221,13 @@ public interface IFileDetector { * @return True represents the file is ready. */ static boolean checkExtraFile(Path path, String sha1) { - return sha1 == null || sha1.equals("") || (isFile(path) && sha1.toLowerCase(Locale.ENGLISH).equals(getFileSHA1(path))); + return sha1 == null || sha1.isEmpty() || (isFile(path) && sha1.toLowerCase(Locale.ENGLISH).equals(getFileSHA1(path))); } static boolean isFile(Path path) { 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/util/ModuleUtil.java b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/ModuleUtil.java index c89d714425..9eee574cf3 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; -- cgit 0.0.5-2-1-g0f52 From b8a61722e9b3f9e87d220a488c1dd523c6d5de97 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Thu, 29 Feb 2024 00:48:02 +0000 Subject: Fix for update to Forge installer --- build.gradle | 2 +- .../forgewrapper/installer/util/InstallerV1.java | 31 +++++++++++----------- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/build.gradle b/build.gradle index 45e6dee5d7..ebd89d45ae 100644 --- a/build.gradle +++ b/build.gradle @@ -34,7 +34,7 @@ repositories { dependencies { compileOnly "com.google.code.gson:gson:2.8.7" compileOnly "cpw.mods:modlauncher:8.0.9" - compileOnly "net.minecraftforge:installer:2.1.9" + compileOnly "net.minecraftforge:installer:2.2.7" compileOnly "net.sf.jopt-simple:jopt-simple:5.0.4" provided project(":common") diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/InstallerV1.java b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/InstallerV1.java index 014a6240ea..c9ceeaf45c 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/InstallerV1.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/InstallerV1.java @@ -1,9 +1,9 @@ package io.github.zekerzhayard.forgewrapper.installer.util; import java.io.File; -import java.util.function.Predicate; +import java.lang.reflect.Method; -import net.minecraftforge.installer.actions.ClientInstall; +import net.minecraftforge.installer.actions.PostProcessors; import net.minecraftforge.installer.actions.ProgressCallback; import net.minecraftforge.installer.json.Install; import net.minecraftforge.installer.json.InstallV1; @@ -16,23 +16,22 @@ public class InstallerV1 extends AbstractInstaller { } @Override - public boolean runClientInstall(Install profile, ProgressCallback monitor, File libraryDir, File minecraftJar, File installerJar) { - return new ClientInstall4MultiMC(profile, monitor, libraryDir, minecraftJar).run(null, input -> true, installerJar); - } + public boolean runClientInstall(Install profile, ProgressCallback monitor, File libraryDir, File minecraftJar, + File installerJar) { + PostProcessors processors = new PostProcessors( + profile instanceof InstallV1 ? (InstallV1) profile : new InstallV1(profile), true, monitor); - public static class ClientInstall4MultiMC extends ClientInstall { - protected File libraryDir; - protected File minecraftJar; + try { + Method method = processors.getClass().getMethod("process", File.class, File.class, File.class, File.class); + Object result = method.invoke(processors, libraryDir, minecraftJar, libraryDir.getParentFile(), + installerJar); - public ClientInstall4MultiMC(Install profile, ProgressCallback monitor, File libraryDir, File minecraftJar) { - super(profile instanceof InstallV1 ? (InstallV1) profile : new InstallV1(profile), monitor); - this.libraryDir = libraryDir; - this.minecraftJar = minecraftJar; - } + if (method.getReturnType() == boolean.class) + return (boolean) result; - @Override - public boolean run(File target, Predicate optionals, File installer) { - return this.processors.process(this.libraryDir, this.minecraftJar, this.libraryDir.getParentFile(), installer); + return result != null; + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); } } } -- cgit 0.0.5-2-1-g0f52 From b01612aae17d8c54f3438d78d19868213e77f366 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Thu, 29 Feb 2024 12:07:30 +0000 Subject: Use time-based versioning for now --- build.gradle | 6 +++++- gradle.properties | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index df24eafed9..9312fcd269 100644 --- a/build.gradle +++ b/build.gradle @@ -1,3 +1,4 @@ +import java.text.SimpleDateFormat plugins { id "java" @@ -91,5 +92,8 @@ publishing { tasks.publish.dependsOn build static String getVersionSuffix() { - return "" + if (System.getenv("IS_PUBLICATION") != null) + return new SimpleDateFormat("-yyyy-MM-dd").format(new Date()) + + return "-LOCAL" } diff --git a/gradle.properties b/gradle.properties index fd71edf0b0..e2b1ac4ba7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.daemon = false -fw_version = 1.5.8-prism +fw_version = prism -- cgit 0.0.5-2-1-g0f52 From 4eec3c90f41c74384957b7d3131f80065e6863ce Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Thu, 29 Feb 2024 12:17:23 +0000 Subject: Check for GITHUB_ACTIONS environment variable --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 9312fcd269..9c3464b364 100644 --- a/build.gradle +++ b/build.gradle @@ -92,7 +92,7 @@ publishing { tasks.publish.dependsOn build static String getVersionSuffix() { - if (System.getenv("IS_PUBLICATION") != null) + if (System.getenv("IS_PUBLICATION") != null || System.getenv("GITHUB_ACTIONS") == "true") return new SimpleDateFormat("-yyyy-MM-dd").format(new Date()) return "-LOCAL" -- cgit 0.0.5-2-1-g0f52 From 3c6712d64a42e4ec200909912e72749499aaca79 Mon Sep 17 00:00:00 2001 From: ZekerZhayard Date: Fri, 1 Mar 2024 14:51:26 +0800 Subject: Thanks to LexManos, he replaced all installers with the new version, so the codes for compatibility with the old installer do not need to exist. The task of checking for extra files is now done by the installer instead of ForgeWrapper itself, thus avoiding some inaccurate checking. --- build.gradle | 11 +- common/build.gradle | 11 -- .../forgewrapper/util/CheckedLambdaUtil.java | 40 ----- gradle.properties | 2 +- jigsaw/build.gradle | 4 - .../forgewrapper/installer/util/ModuleUtil.java | 60 +++++-- legacy/build.gradle | 22 --- .../installer/util/AbstractInstaller.java | 12 -- .../forgewrapper/installer/util/InstallerV0.java | 37 ----- settings.gradle | 2 - .../forgewrapper/installer/Bootstrap.java | 19 ++- .../forgewrapper/installer/Installer.java | 173 +++++++++++++++++--- .../zekerzhayard/forgewrapper/installer/Main.java | 61 ++++--- .../installer/detector/IFileDetector.java | 182 --------------------- .../forgewrapper/installer/util/InstallerV1.java | 38 ----- 15 files changed, 246 insertions(+), 428 deletions(-) delete mode 100644 common/build.gradle delete mode 100644 common/src/main/java/io/github/zekerzhayard/forgewrapper/util/CheckedLambdaUtil.java delete mode 100644 legacy/build.gradle delete mode 100644 legacy/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/AbstractInstaller.java delete mode 100644 legacy/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/InstallerV0.java delete mode 100644 src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/InstallerV1.java diff --git a/build.gradle b/build.gradle index 45e6dee5d7..b0bcf5df22 100644 --- a/build.gradle +++ b/build.gradle @@ -15,9 +15,6 @@ group = "io.github.zekerzhayard" archivesBaseName = rootProject.name configurations { - provided { - implementation.extendsFrom provided - } multirelase { implementation.extendsFrom multirelase } @@ -34,11 +31,9 @@ repositories { dependencies { compileOnly "com.google.code.gson:gson:2.8.7" compileOnly "cpw.mods:modlauncher:8.0.9" - compileOnly "net.minecraftforge:installer:2.1.9" + compileOnly "net.minecraftforge:installer:2.2.7" compileOnly "net.sf.jopt-simple:jopt-simple:5.0.4" - provided project(":common") - provided project(":legacy") multirelase project(":jigsaw") } @@ -60,10 +55,6 @@ jar { "GitCommit": String.valueOf(System.getenv("GITHUB_SHA")) ]) - from configurations.provided.files.collect { - zipTree(it) - } - into "META-INF/versions/9", { from configurations.multirelase.files.collect { zipTree(it) diff --git a/common/build.gradle b/common/build.gradle deleted file mode 100644 index abd2997bba..0000000000 --- a/common/build.gradle +++ /dev/null @@ -1,11 +0,0 @@ - -plugins { - id "java" - id "eclipse" - id "maven-publish" -} - -sourceCompatibility = targetCompatibility = 1.8 -compileJava { - sourceCompatibility = targetCompatibility = 1.8 -} diff --git a/common/src/main/java/io/github/zekerzhayard/forgewrapper/util/CheckedLambdaUtil.java b/common/src/main/java/io/github/zekerzhayard/forgewrapper/util/CheckedLambdaUtil.java deleted file mode 100644 index c36b8b33a7..0000000000 --- a/common/src/main/java/io/github/zekerzhayard/forgewrapper/util/CheckedLambdaUtil.java +++ /dev/null @@ -1,40 +0,0 @@ -package io.github.zekerzhayard.forgewrapper.util; - -import java.util.function.BiConsumer; -import java.util.function.Consumer; - -public class CheckedLambdaUtil { - public static Consumer wrapConsumer(CheckedConsumer consumer) { - return consumer; - } - - public static BiConsumer wrapBiConsumer(CheckedBiConsumer biconsumer) { - return biconsumer; - } - - public interface CheckedConsumer extends Consumer { - 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 extends BiConsumer { - 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); - } - } - } -} diff --git a/gradle.properties b/gradle.properties index 4fb12126f0..96acf9205f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.daemon = false -fw_version = 1.5.8 +fw_version = 1.6.0 diff --git a/jigsaw/build.gradle b/jigsaw/build.gradle index 08c394afee..a555ec3bf3 100644 --- a/jigsaw/build.gradle +++ b/jigsaw/build.gradle @@ -26,7 +26,3 @@ configurations { } } } - -dependencies { - compileOnly project(":common") -} 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 e15d39c410..09792b1624 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 @@ -12,6 +12,7 @@ import java.lang.reflect.Field; import java.net.URL; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -19,10 +20,8 @@ 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 { @@ -53,17 +52,27 @@ public class ModuleUtil { MethodHandle loadModuleMH = IMPL_LOOKUP.findVirtual(Class.forName("jdk.internal.loader.BuiltinClassLoader"), "loadModule", MethodType.methodType(void.class, ModuleReference.class)); // 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())); + List roots = new ArrayList<>(); + for (ModuleReference mref : finder.findAll()) { + String name = mref.descriptor().name(); + if (!ModuleLayer.boot().findModule(name).isPresent()) { + loadModuleMH.invokeWithArguments(ClassLoader.getSystemClassLoader(), mref); + roots.add(name); + } + } + Configuration config = Configuration.resolveAndBind(finder, List.of(ModuleLayer.boot().configuration()), finder, roots); // Copy the new config graph to boot module layer config MethodHandle graphGetter = IMPL_LOOKUP.findGetter(Configuration.class, "graph", Map.class); HashMap> graphMap = new HashMap<>((Map>) 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(CheckedLambdaUtil.wrapBiConsumer((k, v) -> { - cfSetter.invokeWithArguments(k, ModuleLayer.boot().configuration()); - v.forEach(CheckedLambdaUtil.wrapConsumer(m -> cfSetter.invokeWithArguments(m, ModuleLayer.boot().configuration()))); - })); + for (Map.Entry> entry : graphMap.entrySet()) { + cfSetter.invokeWithArguments(entry.getKey(), ModuleLayer.boot().configuration()); + for (ResolvedModule resolvedModule : entry.getValue()) { + cfSetter.invokeWithArguments(resolvedModule, ModuleLayer.boot().configuration()); + } + } graphMap.putAll((Map>) graphGetter.invokeWithArguments(ModuleLayer.boot().configuration())); IMPL_LOOKUP.findSetter(Configuration.class, "graph", Map.class).invokeWithArguments(ModuleLayer.boot().configuration(), new HashMap<>(graphMap)); @@ -92,7 +101,17 @@ public class ModuleUtil { // 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(CheckedLambdaUtil.wrapConsumer(bm -> implAddReadsMH.invokeWithArguments(m, bm)))))); + for (ResolvedModule resolvedModule : config.modules()) { + Module module = ModuleLayer.boot().findModule(resolvedModule.name()).orElse(null); + if (module != null) { + for (ResolvedModule bootResolvedModule : oldBootModules) { + Module bootModule = ModuleLayer.boot().findModule(bootResolvedModule.name()).orElse(null); + if (bootModule != null) { + implAddReadsMH.invokeWithArguments(module, bootModule); + } + } + } + } } public static void addExports(List exports) { @@ -124,13 +143,26 @@ public class ModuleUtil { } void implAdd(List 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))); + for (String extra : extras) { + ParserData data = ModuleUtil.parseModuleExtra(extra).orElse(null); + if (data != null) { + Module module = ModuleLayer.boot().findModule(data.module).orElse(null); + if (module != null) { + try { + if ("ALL-UNNAMED".equals(data.target)) { + this.implAddToAllUnnamedMH.invokeWithArguments(module, data.packages); + } else { + Module targetModule = ModuleLayer.boot().findModule(data.target).orElse(null); + if (targetModule != null) { + this.implAddMH.invokeWithArguments(module, data.packages, targetModule); + } + } + } catch (Throwable t) { + throw new RuntimeException(t); + } + } } - })))); + } } } diff --git a/legacy/build.gradle b/legacy/build.gradle deleted file mode 100644 index 4778335e0d..0000000000 --- a/legacy/build.gradle +++ /dev/null @@ -1,22 +0,0 @@ - -plugins { - id "java" - id "eclipse" -} - -sourceCompatibility = targetCompatibility = 1.8 -compileJava { - sourceCompatibility = targetCompatibility = 1.8 -} - -repositories { - mavenCentral() - maven { - name = "forge" - url = "https://maven.minecraftforge.net/" - } -} - -dependencies { - compileOnly "net.minecraftforge:installer:2.0.24" -} diff --git a/legacy/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/AbstractInstaller.java b/legacy/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/AbstractInstaller.java deleted file mode 100644 index 6b2d55072f..0000000000 --- a/legacy/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/AbstractInstaller.java +++ /dev/null @@ -1,12 +0,0 @@ -package io.github.zekerzhayard.forgewrapper.installer.util; - -import java.io.File; - -import net.minecraftforge.installer.actions.ProgressCallback; -import net.minecraftforge.installer.json.Install; - -public abstract class AbstractInstaller { - public abstract Install loadInstallProfile(); - - public abstract boolean runClientInstall(Install profile, ProgressCallback monitor, File libraryDir, File minecraftJar, File installerJar); -} diff --git a/legacy/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/InstallerV0.java b/legacy/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/InstallerV0.java deleted file mode 100644 index ff1cd4373b..0000000000 --- a/legacy/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/InstallerV0.java +++ /dev/null @@ -1,37 +0,0 @@ -package io.github.zekerzhayard.forgewrapper.installer.util; - -import java.io.File; -import java.util.function.Predicate; - -import net.minecraftforge.installer.actions.ClientInstall; -import net.minecraftforge.installer.actions.ProgressCallback; -import net.minecraftforge.installer.json.Install; -import net.minecraftforge.installer.json.Util; - -public class InstallerV0 extends AbstractInstaller { - @Override - public Install loadInstallProfile() { - return Util.loadInstallProfile(); - } - - @Override - public boolean runClientInstall(Install profile, ProgressCallback monitor, File libraryDir, File minecraftJar, File installerJar) { - return new ClientInstall4MultiMC(profile, monitor, libraryDir, minecraftJar).run(null, input -> true); - } - - public static class ClientInstall4MultiMC extends ClientInstall { - protected File libraryDir; - protected File minecraftJar; - - public ClientInstall4MultiMC(Install profile, ProgressCallback monitor, File libraryDir, File minecraftJar) { - super(profile, monitor); - this.libraryDir = libraryDir; - this.minecraftJar = minecraftJar; - } - - @Override - public boolean run(File target, Predicate optionals) { - return this.processors.process(this.libraryDir, this.minecraftJar); - } - } -} diff --git a/settings.gradle b/settings.gradle index 34c563d573..3444232309 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,5 +1,3 @@ rootProject.name = 'ForgeWrapper' -include 'common' -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 3604371a14..90d3325570 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Bootstrap.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Bootstrap.java @@ -7,11 +7,12 @@ import java.util.List; import io.github.zekerzhayard.forgewrapper.installer.util.ModuleUtil; public class Bootstrap { - public static void bootstrap(List jvmArgs, String minecraftJar, String libraryDir) throws Throwable { + public static void bootstrap(String[] jvmArgs, String minecraftJar, String libraryDir) throws Throwable { // Replace all placeholders - List 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).replace("${version_name}", minecraftJar.substring(0, minecraftJar.lastIndexOf('.')))); + String[] replacedJvmArgs = new String[jvmArgs.length]; + for (int i = 0; i < jvmArgs.length; i++) { + String arg = jvmArgs[i]; + replacedJvmArgs[i] = arg.replace("${classpath}", System.getProperty("java.class.path").replace(File.separator, "/")).replace("${classpath_separator}", File.pathSeparator).replace("${library_directory}", libraryDir).replace("${version_name}", minecraftJar.substring(0, minecraftJar.lastIndexOf('.'))); } jvmArgs = replacedJvmArgs; @@ -27,23 +28,23 @@ public class Bootstrap { String modulePath = null; List addExports = new ArrayList<>(); List addOpens = new ArrayList<>(); - for (int i = 0; i < jvmArgs.size(); i++) { - String arg = jvmArgs.get(i); + for (int i = 0; i < jvmArgs.length; i++) { + String arg = jvmArgs[i]; if (arg.equals("-p") || arg.equals("--module-path")) { - modulePath = jvmArgs.get(i + 1); + modulePath = jvmArgs[i + 1]; } else if (arg.startsWith("--module-path=")) { modulePath = arg.split("=", 2)[1]; } if (arg.equals("--add-exports")) { - addExports.add(jvmArgs.get(i + 1)); + addExports.add(jvmArgs[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)); + addOpens.add(jvmArgs[i + 1]); } else if (arg.startsWith("--add-opens=")) { addOpens.add(arg.split("=", 2)[1]); } diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java index 278688e773..10895b13fd 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java @@ -1,20 +1,47 @@ package io.github.zekerzhayard.forgewrapper.installer; import java.io.File; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.nio.charset.StandardCharsets; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; -import io.github.zekerzhayard.forgewrapper.installer.util.AbstractInstaller; -import io.github.zekerzhayard.forgewrapper.installer.util.InstallerV0; -import io.github.zekerzhayard.forgewrapper.installer.util.InstallerV1; +import net.minecraftforge.installer.DownloadUtils; +import net.minecraftforge.installer.actions.PostProcessors; import net.minecraftforge.installer.actions.ProgressCallback; +import net.minecraftforge.installer.json.Artifact; import net.minecraftforge.installer.json.Install; import net.minecraftforge.installer.json.InstallV1; import net.minecraftforge.installer.json.Util; +import net.minecraftforge.installer.json.Version; public class Installer { - public static boolean install(File libraryDir, File minecraftJar, File installerJar) { - AbstractInstaller installer = createInstaller(); + private static InstallV1Wrapper wrapper; + private static InstallV1Wrapper getWrapper(File librariesDir) { + if (wrapper == null) { + wrapper = new InstallV1Wrapper(Util.loadInstallProfile(), librariesDir); + } + return wrapper; + } + + public static Map getData(File librariesDir) { + Map data = new HashMap<>(); + Version0 version = Version0.loadVersion(getWrapper(librariesDir)); + data.put("mainClass", version.getMainClass()); + data.put("jvmArgs", version.getArguments().getJvm()); + data.put("extraLibraries", getExtraLibraries(version)); + return data; + } + + public static boolean install(File libraryDir, File minecraftJar, File installerJar) throws Throwable { ProgressCallback monitor = ProgressCallback.withOutputs(System.out); - Install profile = installer.loadInstallProfile(); if (System.getProperty("java.net.preferIPv4Stack") == null) { System.setProperty("java.net.preferIPv4Stack", "true"); } @@ -23,21 +50,129 @@ public class Installer { String jvmVersion = System.getProperty("java.vm.version", "missing jvm version"); monitor.message(String.format("JVM info: %s - %s - %s", vendor, javaVersion, jvmVersion)); monitor.message("java.net.preferIPv4Stack=" + System.getProperty("java.net.preferIPv4Stack")); - return installer.runClientInstall(profile, monitor, libraryDir, minecraftJar, installerJar); + monitor.message("Current Time: " + new SimpleDateFormat("dd/MM/yyyy HH:mm:ss").format(new Date())); + + // MinecraftForge has removed all old installers since 2024/2/27, but they still exist in NeoForge. + PostProcessors processors = new PostProcessors(wrapper, true, monitor); + Method processMethod = PostProcessors.class.getMethod("process", File.class, File.class, File.class, File.class); + if (boolean.class.equals(processMethod.getReturnType())) { + return (boolean) processMethod.invoke(processors, libraryDir, minecraftJar, libraryDir.getParentFile(), installerJar); + } else { + return processMethod.invoke(processors, libraryDir, minecraftJar, libraryDir.getParentFile(), installerJar) != null; + } + } + + // Some libraries in the version json are not available via direct download, + // so they are not available in the MultiMC meta json, + // so wee need to get them manually. + private static List getExtraLibraries(Version0 version) { + List paths = new ArrayList<>(); + for (Version.Library library : version.getLibraries()) { + Version.LibraryDownload artifact = library.getDownloads().getArtifact(); + if (artifact.getUrl().isEmpty()) { + paths.add(artifact.getPath()); + } + } + return paths; + } + + public static class InstallV1Wrapper extends InstallV1 { + protected Map> processors = new HashMap<>(); + protected File librariesDir; + + public InstallV1Wrapper(InstallV1 v1, File librariesDir) { + super(v1); + this.serverJarPath = v1.getServerJarPath(); + this.librariesDir = librariesDir; + } + + @Override + public List getProcessors(String side) { + List processor = this.processors.get(side); + if (processor == null) { + checkProcessorFiles(processor = super.getProcessors(side), super.getData("client".equals(side)), this.librariesDir); + this.processors.put(side, processor); + } + return processor; + } + + private static void checkProcessorFiles(List processors, Map data, File base) { + Map artifactData = new HashMap<>(); + for (Map.Entry entry : data.entrySet()) { + String value = entry.getValue(); + if (value.charAt(0) == '[' && value.charAt(value.length() - 1) == ']') { + artifactData.put("{" + entry.getKey() + "}", Artifact.from(value.substring(1, value.length() - 1)).getLocalPath(base)); + } + } + + Map> outputsMap = new HashMap<>(); + label: + for (Processor processor : processors) { + Map outputs = new HashMap<>(); + if (processor.getOutputs().isEmpty()) { + String[] args = processor.getArgs(); + for (int i = 0; i < args.length; i++) { + for (Map.Entry entry : artifactData.entrySet()) { + if (args[i].contains(entry.getKey())) { + // We assume that all files that exist but don't have the sha1 checksum are valid. + if (entry.getValue().exists()) { + outputs.put(entry.getKey(), DownloadUtils.getSha1(entry.getValue())); + } else { + outputsMap.clear(); + break label; + } + } + } + } + outputsMap.put(processor, outputs); + } + } + for (Map.Entry> entry : outputsMap.entrySet()) { + setOutputs(entry.getKey(), entry.getValue()); + } + } + + private static Field outputsField; + private static void setOutputs(Processor processor, Map outputs) { + try { + if (outputsField == null) { + outputsField = Processor.class.getDeclaredField("outputs"); + outputsField.setAccessible(true); + } + outputsField.set(processor, outputs); + } catch (Throwable t) { + throw new RuntimeException(t); + } + } } - private static AbstractInstaller createInstaller() { - try { - Class installerClass = Util.class.getMethod("loadInstallProfile").getReturnType(); - if (installerClass.equals(Install.class)) { - return new InstallerV0(); - } else if (installerClass.equals(InstallV1.class)) { - return new InstallerV1(); - } else { - throw new IllegalArgumentException("Unable to determine the installer version. (" + installerClass + ")"); - } - } catch (Throwable t) { - throw new RuntimeException(t); + public static class Version0 extends Version { + + public static Version0 loadVersion(Install profile) { + try (InputStream stream = Util.class.getResourceAsStream(profile.getJson())) { + return Util.GSON.fromJson(new InputStreamReader(stream, StandardCharsets.UTF_8), Version0.class); + } catch (Throwable t) { + throw new RuntimeException(t); + } + } + + protected String mainClass; + protected Version0.Arguments arguments; + + public String getMainClass() { + return mainClass; + } + + public Version0.Arguments getArguments() { + return arguments; + } + + public static class Arguments { + protected String[] jvm; + + public String[] getJvm() { + return jvm; + } } } } 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 37876a6de4..f15a2a842c 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java @@ -3,8 +3,10 @@ package io.github.zekerzhayard.forgewrapper.installer; import java.io.File; import java.net.URL; import java.net.URLClassLoader; +import java.nio.file.Files; import java.nio.file.Path; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -14,6 +16,7 @@ import io.github.zekerzhayard.forgewrapper.installer.detector.IFileDetector; import io.github.zekerzhayard.forgewrapper.installer.util.ModuleUtil; public class Main { + @SuppressWarnings("unchecked") 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 @@ -30,40 +33,44 @@ public class Main { String forgeFullVersion = isNeoForge ? forgeVersion : mcVersion + "-" + forgeVersion; IFileDetector detector = DetectorLoader.loadDetector(); - try { - 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. + // Check installer jar. + Path installerJar = detector.getInstallerJar(forgeGroup, forgeArtifact, forgeFullVersion); + if (!isFile(installerJar)) { + throw new RuntimeException("Unable to detect the forge installer!"); } - 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(forgeGroup, forgeArtifact, forgeFullVersion); - if (!IFileDetector.isFile(installerJar)) { - throw new RuntimeException("Unable to detect the forge installer!"); - } + // Check vanilla Minecraft jar. + Path minecraftJar = detector.getMinecraftJar(mcVersion); + if (!isFile(minecraftJar)) { + throw new RuntimeException("Unable to detect the Minecraft jar!"); + } + + try (URLClassLoader ucl = URLClassLoader.newInstance(new URL[] { + Main.class.getProtectionDomain().getCodeSource().getLocation(), + Launcher.class.getProtectionDomain().getCodeSource().getLocation(), + installerJar.toUri().toURL() + }, ModuleUtil.getPlatformClassLoader())) { + Class installer = ucl.loadClass("io.github.zekerzhayard.forgewrapper.installer.Installer"); - // Check vanilla Minecraft jar. - Path minecraftJar = detector.getMinecraftJar(mcVersion); - if (!IFileDetector.isFile(minecraftJar)) { - throw new RuntimeException("Unable to detect the Minecraft jar!"); + Map data = (Map) installer.getMethod("getData", File.class).invoke(null, detector.getLibraryDir().toFile()); + try { + Bootstrap.bootstrap((String[]) data.get("jvmArgs"), detector.getMinecraftJar(mcVersion).getFileName().toString(), detector.getLibraryDir().toAbsolutePath().toString()); + } catch (Throwable t) { + // Avoid this bunch of hacks that nuke the whole wrapper. + t.printStackTrace(); } - try (URLClassLoader ucl = URLClassLoader.newInstance(new URL[] { - Main.class.getProtectionDomain().getCodeSource().getLocation(), - Launcher.class.getProtectionDomain().getCodeSource().getLocation(), - installerJar.toUri().toURL() - }, ModuleUtil.getPlatformClassLoader())) { - Class installer = ucl.loadClass("io.github.zekerzhayard.forgewrapper.installer.Installer"); - if (!(boolean) installer.getMethod("install", File.class, File.class, File.class).invoke(null, detector.getLibraryDir().toFile(), minecraftJar.toFile(), installerJar.toFile())) { - return; - } + if (!((boolean) installer.getMethod("install", File.class, File.class, File.class).invoke(null, detector.getLibraryDir().toFile(), minecraftJar.toFile(), installerJar.toFile()))) { + return; } + + ModuleUtil.setupClassPath(detector.getLibraryDir(), (List) data.get("extraLibraries")); + Class mainClass = ModuleUtil.setupBootstrapLauncher(Class.forName((String) data.get("mainClass"))); + mainClass.getMethod("main", String[].class).invoke(null, new Object[] {args}); } + } - 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 }); + private static boolean isFile(Path path) { + return path != null && Files.isRegularFile(path); } } 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 67d3e1d4a1..29b7179194 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 @@ -1,33 +1,10 @@ package io.github.zekerzhayard.forgewrapper.installer.detector; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.math.BigInteger; import java.net.URISyntaxException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -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.regex.Matcher; -import java.util.regex.Pattern; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; -import com.google.gson.JsonElement; -import com.google.gson.JsonNull; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; import cpw.mods.modlauncher.Launcher; public interface IFileDetector { @@ -85,163 +62,4 @@ public interface IFileDetector { } return null; } - - /** - * @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 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())); - } - return args; - }); - } - - 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 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 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 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); - if (ze != null) { - try ( - InputStream is = zf.getInputStream(ze); - InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8) - ) { - return function.apply(new JsonParser().parse(isr)); - } - } - } catch (IOException e) { - e.printStackTrace(); - } - } else { - throw new RuntimeException("Unable to detect the forge installer!"); - } - return null; - } - - /** - * 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 forgeGroup, String forgeArtifact, String forgeFullVersion) { - JsonObject jo = this.getInstallProfileExtraData(forgeGroup, forgeArtifact, forgeFullVersion); - if (jo != null) { - Map libsMap = new HashMap<>(); - Map hashMap = new HashMap<>(); - - // Get all "data//client" elements. - Pattern artifactPattern = Pattern.compile("^\\[(?[^:]*):(?[^:]*):(?[^:@]*)(:(?[^@]*))?(@(?[^]]*))?]$"); - for (Map.Entry entry : jo.entrySet()) { - 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); - if (m.find()) { - hashMap.put(entry.getKey(), m.group("sha1")); - } - } else { - Matcher m = artifactPattern.matcher(clientStr); - if (m.find()) { - String groupId = nullToDefault(m.group("groupId"), ""); - String artifactId = nullToDefault(m.group("artifactId"), ""); - String version = nullToDefault(m.group("version"), ""); - String classifier = nullToDefault(m.group("classifier"), ""); - String type = nullToDefault(m.group("type"), "jar"); - libsMap.put(entry.getKey(), this.getLibraryDir() - .resolve(groupId.replace('.', File.separatorChar)) - .resolve(artifactId) - .resolve(version) - .resolve(artifactId + "-" + version + (classifier.isEmpty() ? "" : "-") + classifier + "." + type).toAbsolutePath()); - } - } - } - - // Check all cached libraries. - boolean checked = true; - for (Map.Entry entry : libsMap.entrySet()) { - checked = checkExtraFile(entry.getValue(), hashMap.get(entry.getKey() + "_SHA")); - if (!checked) { - System.out.println("Missing: " + entry.getValue()); - break; - } - } - return checked; - } - // Skip installing process if installer profile doesn't exist. - return true; - } - - /** - * Check the exact file. - * @param path The path of the file to check. - * @param sha1 The sha1 defined in installer. - * @return True represents the file is ready. - */ - static boolean checkExtraFile(Path path, String sha1) { - return sha1 == null || sha1.isEmpty() || (isFile(path) && sha1.toLowerCase(Locale.ENGLISH).equals(getFileSHA1(path))); - } - - static boolean isFile(Path path) { - return path != null && Files.isRegularFile(path); - } - - static String getFileSHA1(Path path) { - try { - StringBuilder sha1 = new StringBuilder(new BigInteger(1, MessageDigest.getInstance("SHA-1").digest(Files.readAllBytes(path))).toString(16)); - while (sha1.length() < 40) { - sha1.insert(0, "0"); - } - return sha1.toString().toLowerCase(Locale.ENGLISH); - } catch (IOException | NoSuchAlgorithmException e) { - e.printStackTrace(); - } - return null; - } - - static String nullToDefault(String string, String defaultValue) { - return string == null ? defaultValue : string; - } } diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/InstallerV1.java b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/InstallerV1.java deleted file mode 100644 index 014a6240ea..0000000000 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/InstallerV1.java +++ /dev/null @@ -1,38 +0,0 @@ -package io.github.zekerzhayard.forgewrapper.installer.util; - -import java.io.File; -import java.util.function.Predicate; - -import net.minecraftforge.installer.actions.ClientInstall; -import net.minecraftforge.installer.actions.ProgressCallback; -import net.minecraftforge.installer.json.Install; -import net.minecraftforge.installer.json.InstallV1; -import net.minecraftforge.installer.json.Util; - -public class InstallerV1 extends AbstractInstaller { - @Override - public Install loadInstallProfile() { - return Util.loadInstallProfile(); - } - - @Override - public boolean runClientInstall(Install profile, ProgressCallback monitor, File libraryDir, File minecraftJar, File installerJar) { - return new ClientInstall4MultiMC(profile, monitor, libraryDir, minecraftJar).run(null, input -> true, installerJar); - } - - public static class ClientInstall4MultiMC extends ClientInstall { - protected File libraryDir; - protected File minecraftJar; - - public ClientInstall4MultiMC(Install profile, ProgressCallback monitor, File libraryDir, File minecraftJar) { - super(profile instanceof InstallV1 ? (InstallV1) profile : new InstallV1(profile), monitor); - this.libraryDir = libraryDir; - this.minecraftJar = minecraftJar; - } - - @Override - public boolean run(File target, Predicate optionals, File installer) { - return this.processors.process(this.libraryDir, this.minecraftJar, this.libraryDir.getParentFile(), installer); - } - } -} -- cgit 0.0.5-2-1-g0f52 From 4f57cae5ef6ffa9aa198be06ac843df9ca1d6261 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Sun, 8 Sep 2024 21:28:01 +0100 Subject: Revert "Merge pull request #1 from TheKodeToad/fix-new-forge-installer" This reverts commit c2a65dd98f5e405bc7997b1fee62c89a0414fa67, reversing changes made to 271bf51f809de6f2f47a1129b86df3a1594e1d6b. --- build.gradle | 2 +- .../forgewrapper/installer/util/InstallerV1.java | 31 +++++++++++----------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/build.gradle b/build.gradle index 9c3464b364..aa71402bd3 100644 --- a/build.gradle +++ b/build.gradle @@ -35,7 +35,7 @@ repositories { dependencies { compileOnly "com.google.code.gson:gson:2.8.7" compileOnly "cpw.mods:modlauncher:8.0.9" - compileOnly "net.minecraftforge:installer:2.2.7" + compileOnly "net.minecraftforge:installer:2.1.9" compileOnly "net.sf.jopt-simple:jopt-simple:5.0.4" provided project(":common") diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/InstallerV1.java b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/InstallerV1.java index c9ceeaf45c..014a6240ea 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/InstallerV1.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/util/InstallerV1.java @@ -1,9 +1,9 @@ package io.github.zekerzhayard.forgewrapper.installer.util; import java.io.File; -import java.lang.reflect.Method; +import java.util.function.Predicate; -import net.minecraftforge.installer.actions.PostProcessors; +import net.minecraftforge.installer.actions.ClientInstall; import net.minecraftforge.installer.actions.ProgressCallback; import net.minecraftforge.installer.json.Install; import net.minecraftforge.installer.json.InstallV1; @@ -16,22 +16,23 @@ public class InstallerV1 extends AbstractInstaller { } @Override - public boolean runClientInstall(Install profile, ProgressCallback monitor, File libraryDir, File minecraftJar, - File installerJar) { - PostProcessors processors = new PostProcessors( - profile instanceof InstallV1 ? (InstallV1) profile : new InstallV1(profile), true, monitor); + public boolean runClientInstall(Install profile, ProgressCallback monitor, File libraryDir, File minecraftJar, File installerJar) { + return new ClientInstall4MultiMC(profile, monitor, libraryDir, minecraftJar).run(null, input -> true, installerJar); + } - try { - Method method = processors.getClass().getMethod("process", File.class, File.class, File.class, File.class); - Object result = method.invoke(processors, libraryDir, minecraftJar, libraryDir.getParentFile(), - installerJar); + public static class ClientInstall4MultiMC extends ClientInstall { + protected File libraryDir; + protected File minecraftJar; - if (method.getReturnType() == boolean.class) - return (boolean) result; + public ClientInstall4MultiMC(Install profile, ProgressCallback monitor, File libraryDir, File minecraftJar) { + super(profile instanceof InstallV1 ? (InstallV1) profile : new InstallV1(profile), monitor); + this.libraryDir = libraryDir; + this.minecraftJar = minecraftJar; + } - return result != null; - } catch (ReflectiveOperationException e) { - throw new RuntimeException(e); + @Override + public boolean run(File target, Predicate optionals, File installer) { + return this.processors.process(this.libraryDir, this.minecraftJar, this.libraryDir.getParentFile(), installer); } } } -- cgit 0.0.5-2-1-g0f52 From 9e2311b0eaf6ccdc43be63ea944acb452c0730df Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sun, 4 May 2025 12:07:45 +0300 Subject: update actions workflows Signed-off-by: Trial97 --- .github/workflows/build.yml | 13 +++++++------ .github/workflows/publication.yml | 15 ++++++++------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 809b1eca87..971e891add 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,26 +2,27 @@ name: Gradle Build on: push: - branches: [ master ] + branches: [master] pull_request: - branches: [ master ] + branches: [master] jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up JDK - uses: actions/setup-java@v1 + uses: actions/setup-java@v4 with: - java-version: '8.0.312' + distribution: "temurin" + java-version: "8.0.312" architecture: x64 - name: Build with Gradle run: | chmod +x ./gradlew ./gradlew build -iS - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 with: name: Package path: build/libs diff --git a/.github/workflows/publication.yml b/.github/workflows/publication.yml index 31d4196b37..eeaed812c5 100644 --- a/.github/workflows/publication.yml +++ b/.github/workflows/publication.yml @@ -3,18 +3,19 @@ name: Publication on: push: tags: - - '*' + - "*" jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up JDK - uses: actions/setup-java@v1 + uses: actions/setup-java@v4 with: - java-version: '8.0.312' + distribution: "temurin" + java-version: "8.0.312" architecture: x64 - name: Build with Gradle env: @@ -24,14 +25,14 @@ jobs: rm -rf ./build/maven/.git/* chmod +x ./gradlew ./gradlew publish -iS - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 with: name: Package path: build/libs - name: Get tag version id: get_version uses: olegtarasov/get-tag@v2.1 - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 with: name: Package path: build/libs @@ -43,7 +44,7 @@ jobs: with: tag_name: ${{ steps.get_version.outputs.tag }} release_name: ${{ steps.get_version.outputs.tag }} - body: '' + body: "" draft: false prerelease: false - name: Upload release binaries -- cgit 0.0.5-2-1-g0f52 From d36485185be6ef6e580a0664a5a4a5ac8748b707 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Mon, 30 Jun 2025 20:36:21 +0100 Subject: Improve libraries folder detection --- .../forgewrapper/installer/detector/IFileDetector.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) 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 4f1b7c3558..1d3fb1f274 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 @@ -29,9 +29,17 @@ public interface IFileDetector { return Paths.get(libraryDir).toAbsolutePath(); } try { - Path launcher = Paths.get(Launcher.class.getProtectionDomain().getCodeSource().getLocation().toURI()).toAbsolutePath(); - // / /modlauncher/mods /cpw /libraries - return launcher.getParent().getParent().getParent().getParent().getParent().toAbsolutePath(); + Path launcher = Paths.get(Launcher.class.getProtectionDomain().getCodeSource().getLocation().toURI()); + + while (!launcher.getFileName().toString().equals("libraries")) { + launcher = launcher.getParent(); + + if (launcher == null || launcher.getFileName() == null) { + throw new UnsupportedOperationException("Could not detect the libraries folder - it can be manually specified with `-Dforgewrapper.librariesDir=` (Java runtime argument)"); + } + } + + return launcher.toAbsolutePath(); } catch (URISyntaxException e) { throw new RuntimeException(e); } -- cgit 0.0.5-2-1-g0f52 From 6f46a6f14278d69ebdb013a0c68d39f967a2fcf2 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sat, 4 Oct 2025 00:06:37 +0300 Subject: fix: noeforge 1.21.9 Signed-off-by: Trial97 --- .../zekerzhayard/forgewrapper/installer/Main.java | 2 -- .../installer/detector/IFileDetector.java | 26 +++++++++++++++++++--- 2 files changed, 23 insertions(+), 5 deletions(-) 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 f15a2a842c..2c0f4cfc29 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Main.java @@ -10,7 +10,6 @@ import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; -import cpw.mods.modlauncher.Launcher; import io.github.zekerzhayard.forgewrapper.installer.detector.DetectorLoader; import io.github.zekerzhayard.forgewrapper.installer.detector.IFileDetector; import io.github.zekerzhayard.forgewrapper.installer.util.ModuleUtil; @@ -47,7 +46,6 @@ public class Main { try (URLClassLoader ucl = URLClassLoader.newInstance(new URL[] { Main.class.getProtectionDomain().getCodeSource().getLocation(), - Launcher.class.getProtectionDomain().getCodeSource().getLocation(), installerJar.toUri().toURL() }, ModuleUtil.getPlatformClassLoader())) { Class installer = ucl.loadClass("io.github.zekerzhayard.forgewrapper.installer.Installer"); 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 1d3fb1f274..fc5f320539 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 @@ -1,12 +1,11 @@ package io.github.zekerzhayard.forgewrapper.installer.detector; +import java.net.URL; import java.net.URISyntaxException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.HashMap; -import cpw.mods.modlauncher.Launcher; - public interface IFileDetector { /** * @return The name of the detector. @@ -29,7 +28,28 @@ public interface IFileDetector { return Paths.get(libraryDir).toAbsolutePath(); } try { - Path launcher = Paths.get(Launcher.class.getProtectionDomain().getCodeSource().getLocation().toURI()); + URL launcherLocation = null; + String[] classNames = { + "cpw.mods.modlauncher.Launcher", + "net.neoforged.fml.loading.FMLLoader" + }; + + for (String className : classNames) { + try { + Class clazz = Class.forName(className); + // Return the location of the loaded class + if (clazz.getProtectionDomain().getCodeSource() != null) { + launcherLocation = clazz.getProtectionDomain().getCodeSource().getLocation(); + } + } catch (ClassNotFoundException e) { + // ignore and try next + } + } + + if (launcherLocation == null) { + throw new UnsupportedOperationException("Could not detect the libraries folder - it can be manually specified with `-Dforgewrapper.librariesDir=` (Java runtime argument)"); + } + Path launcher = Paths.get(launcherLocation.toURI()); while (!launcher.getFileName().toString().equals("libraries")) { launcher = launcher.getParent(); -- cgit 0.0.5-2-1-g0f52 From 69d7b0e5a4c6ca0776ddd0b0cb495569f5b3eb0a Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sat, 4 Oct 2025 21:25:40 +0300 Subject: fix: noeforge Signed-off-by: Trial97 --- .../installer/detector/IFileDetector.java | 26 +++++++++++++--------- 1 file changed, 16 insertions(+), 10 deletions(-) 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 fc5f320539..6f695ff884 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 @@ -2,6 +2,7 @@ package io.github.zekerzhayard.forgewrapper.installer.detector; import java.net.URL; import java.net.URISyntaxException; +import java.net.MalformedURLException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.HashMap; @@ -30,19 +31,24 @@ public interface IFileDetector { try { URL launcherLocation = null; String[] classNames = { - "cpw.mods.modlauncher.Launcher", - "net.neoforged.fml.loading.FMLLoader" + "cpw/mods/modlauncher/Launcher.class", + "net/neoforged/fml/loading/FMLLoader.class" }; - for (String className : classNames) { - try { - Class clazz = Class.forName(className); - // Return the location of the loaded class - if (clazz.getProtectionDomain().getCodeSource() != null) { - launcherLocation = clazz.getProtectionDomain().getCodeSource().getLocation(); + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + for (String classResource : classNames) { + URL url = cl.getResource(classResource); + if (url != null) { + String path = url.toString(); + if (path.startsWith("jar:") && path.contains("!")) { + path = path.substring(4, path.indexOf('!')); + try { + launcherLocation = new URL(path); + break; + } catch (MalformedURLException e) { + // ignore and try next + } } - } catch (ClassNotFoundException e) { - // ignore and try next } } -- cgit 0.0.5-2-1-g0f52 From 7fe93cc8cd2c8e9859f911b1ef2bd6794c2bc3fa Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sun, 4 May 2025 11:43:42 +0300 Subject: add system property to skip hash checks Signed-off-by: Trial97 --- .../java/io/github/zekerzhayard/forgewrapper/installer/Installer.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java index 10895b13fd..98b9d1afa3 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Installer.java @@ -93,6 +93,10 @@ public class Installer { checkProcessorFiles(processor = super.getProcessors(side), super.getData("client".equals(side)), this.librariesDir); this.processors.put(side, processor); } + // It can also be defined by JVM argument "-Dforgewrapper.skipHashCheck=true". + if (Boolean.getBoolean("forgewrapper.skipHashCheck")){ + processor.forEach(proc -> proc.getOutputs().clear()); + } return processor; } -- cgit 0.0.5-2-1-g0f52 From 0bdcdfbaf5655987df876b648f0b988ca795ca92 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Sun, 7 Dec 2025 23:15:11 +0000 Subject: Make sure we always set libraryDirectory --- .../java/io/github/zekerzhayard/forgewrapper/installer/Bootstrap.java | 4 ++++ 1 file changed, 4 insertions(+) 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 90d3325570..88c3a00742 100644 --- a/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Bootstrap.java +++ b/src/main/java/io/github/zekerzhayard/forgewrapper/installer/Bootstrap.java @@ -62,6 +62,10 @@ public class Bootstrap { } } + if (System.getProperty("libraryDirectory") == null) { + System.setProperty("libraryDirectory", libraryDir); + } + if (modulePath != null) { ModuleUtil.addModules(modulePath); } -- cgit 0.0.5-2-1-g0f52