Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
717d628dae
14 changed files with 100 additions and 338 deletions
|
@ -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"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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<String> 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 <instance> 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 <instance>/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 <instance>/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/<mcVersion>-<forgeVersion> 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<String> getAdditionalArgs(JsonObject installer) {
|
|
||||||
List<String> args = new ArrayList<>();
|
|
||||||
getElement(installer.getAsJsonObject("arguments"), "game").getAsJsonArray().iterator().forEachRemaining(je -> args.add(je.getAsString()));
|
|
||||||
return args;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static JsonObject getJsonFromZip(Path path, String json) {
|
|
||||||
try {
|
|
||||||
ZipFile zf = new ZipFile(path.toFile());
|
|
||||||
ZipEntry versionFile = zf.getEntry(json);
|
|
||||||
if (versionFile == null) {
|
|
||||||
throw new RuntimeException("The zip file is invalid!");
|
|
||||||
}
|
|
||||||
InputStreamReader isr = new InputStreamReader(zf.getInputStream(versionFile), StandardCharsets.UTF_8);
|
|
||||||
return JsonParser.parseReader(isr).getAsJsonObject();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert mmc-pack.json:
|
|
||||||
// - Replace Minecraft version
|
|
||||||
private static JsonObject convertPackJson(String mcVersion) {
|
|
||||||
JsonObject pack = JsonParser.parseReader(new InputStreamReader(Converter.class.getResourceAsStream("/mmc-pack.json"))).getAsJsonObject();
|
|
||||||
|
|
||||||
for (JsonElement component : getElement(pack, "components").getAsJsonArray()) {
|
|
||||||
JsonObject componentObject = component.getAsJsonObject();
|
|
||||||
JsonElement version = getElement(componentObject, "version");
|
|
||||||
if (!version.isJsonNull() && getElement(componentObject, "uid").getAsString().equals("net.minecraft")) {
|
|
||||||
componentObject.addProperty("version", mcVersion);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return pack;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert patches/net.minecraftforge.json:
|
|
||||||
// - Add libraries
|
|
||||||
// - Add forge-launcher url
|
|
||||||
// - Replace Minecraft & Forge versions
|
|
||||||
private static JsonObject convertPatchesJson(JsonObject installer, JsonObject installProfile, String mcVersion, String forgeVersion, StringBuilder wrapperVersion) {
|
|
||||||
JsonObject patches = JsonParser.parseReader(new InputStreamReader(Converter.class.getResourceAsStream("/patches/net.minecraftforge.json"))).getAsJsonObject();
|
|
||||||
JsonArray mavenFiles = getElement(patches, "mavenFiles").getAsJsonArray();
|
|
||||||
JsonArray libraries = getElement(patches, "libraries").getAsJsonArray();
|
|
||||||
|
|
||||||
String minecraftArguments = String.join(" ", getElement(patches, "minecraftArguments").getAsString(), "--username ${auth_player_name} --version ${version_name} --gameDir ${game_directory} --assetsDir ${assets_root} --assetIndex ${assets_index_name} --uuid ${auth_uuid} --accessToken ${auth_access_token} --userType ${user_type} --versionType ${version_type}", String.join(" ", getAdditionalArgs(installer))).trim();
|
|
||||||
patches.addProperty("minecraftArguments", minecraftArguments);
|
|
||||||
|
|
||||||
for (JsonElement mavenFile : mavenFiles) {
|
|
||||||
String name = getElement(mavenFile.getAsJsonObject(), "name").getAsString();
|
|
||||||
mavenFile.getAsJsonObject().addProperty("name", name.replace("{VERSION}", mcVersion).replace("{FORGE_VERSION}", forgeVersion));
|
|
||||||
}
|
|
||||||
for (JsonElement lib : libraries) {
|
|
||||||
String name = getElement(lib.getAsJsonObject(), "name").getAsString();
|
|
||||||
if (name.startsWith("io.github.zekerzhayard:ForgeWrapper:")) {
|
|
||||||
wrapperVersion.append(getElement(lib.getAsJsonObject(), "MMC-filename").getAsString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Map<String, String> additionalUrls = new HashMap<>();
|
|
||||||
String path = String.format("net/minecraftforge/forge/%s-%s/forge-%s-%s", mcVersion, forgeVersion, mcVersion, forgeVersion);
|
|
||||||
additionalUrls.put(path + "-universal.jar", "https://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<Map.Entry<String, JsonElement>> 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<String, String> 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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<String, String> 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 <ForgeWrapper.jar> --installer=<forge-installer.jar> [--instance=<instance-path>]");
|
|
||||||
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.<br/>
|
|
||||||
* instance -- The instance folder of MultiMC.<br/>
|
|
||||||
* cursepack -- The version of cursepacklocator.<br/>
|
|
||||||
*/
|
|
||||||
private static HashMap<String, String> parseArgs(String[] args) {
|
|
||||||
HashMap<String, String> 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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
{
|
|
||||||
"formatVersion": 1,
|
|
||||||
"components": [
|
|
||||||
{
|
|
||||||
"important": true,
|
|
||||||
"uid": "net.minecraft",
|
|
||||||
"version": "{VERSION}"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uid": "net.minecraftforge"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -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"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
|
|
||||||
org.gradle.daemon = false
|
org.gradle.daemon = false
|
||||||
|
|
||||||
fw_version = mmc3
|
fw_version = mmc4
|
||||||
|
|
|
@ -9,6 +9,7 @@ import java.lang.module.ModuleFinder;
|
||||||
import java.lang.module.ModuleReference;
|
import java.lang.module.ModuleReference;
|
||||||
import java.lang.module.ResolvedModule;
|
import java.lang.module.ResolvedModule;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.net.URL;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -159,6 +160,15 @@ public class ModuleUtil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void setupClassPath(Path libraryDir, List<String> 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.
|
// ForgeWrapper need some extra settings to invoke BootstrapLauncher.
|
||||||
public static Class<?> setupBootstrapLauncher(Class<?> mainClass) throws Throwable {
|
public static Class<?> setupBootstrapLauncher(Class<?> mainClass) throws Throwable {
|
||||||
if (!mainClass.getModule().isOpen(mainClass.getPackageName(), ModuleUtil.class.getModule())) {
|
if (!mainClass.getModule().isOpen(mainClass.getPackageName(), ModuleUtil.class.getModule())) {
|
||||||
|
|
|
@ -4,6 +4,11 @@ plugins {
|
||||||
id "eclipse"
|
id "eclipse"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sourceCompatibility = targetCompatibility = 1.8
|
||||||
|
compileJava {
|
||||||
|
sourceCompatibility = targetCompatibility = 1.8
|
||||||
|
}
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
maven {
|
maven {
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
rootProject.name = 'ForgeWrapper'
|
rootProject.name = 'ForgeWrapper'
|
||||||
|
|
||||||
include 'common'
|
include 'common'
|
||||||
include 'converter'
|
|
||||||
include 'legacy'
|
include 'legacy'
|
||||||
include 'jigsaw'
|
include 'jigsaw'
|
||||||
|
|
|
@ -15,6 +15,15 @@ public class Bootstrap {
|
||||||
}
|
}
|
||||||
jvmArgs = replacedJvmArgs;
|
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;
|
String modulePath = null;
|
||||||
List<String> addExports = new ArrayList<>();
|
List<String> addExports = new ArrayList<>();
|
||||||
List<String> addOpens = new ArrayList<>();
|
List<String> addOpens = new ArrayList<>();
|
||||||
|
|
|
@ -15,22 +15,31 @@ import io.github.zekerzhayard.forgewrapper.installer.util.ModuleUtil;
|
||||||
|
|
||||||
public class Main {
|
public class Main {
|
||||||
public static void main(String[] args) throws Throwable {
|
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<String> argsList = Stream.of(args).collect(Collectors.toList());
|
List<String> 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 mcVersion = argsList.get(argsList.indexOf("--fml.mcVersion") + 1);
|
||||||
String forgeVersion = argsList.get(argsList.indexOf("--fml.forgeVersion") + 1);
|
String forgeGroup = argsList.contains("--fml.forgeGroup") ? argsList.get(argsList.indexOf("--fml.forgeGroup") + 1) : "net.neoforged";
|
||||||
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();
|
IFileDetector detector = DetectorLoader.loadDetector();
|
||||||
try {
|
try {
|
||||||
Bootstrap.bootstrap(detector.getJvmArgs(forgeFullVersion), detector.getMinecraftJar(mcVersion).getFileName().toString(), detector.getLibraryDir().toAbsolutePath().toString());
|
Bootstrap.bootstrap(detector.getJvmArgs(forgeGroup, forgeArtifact, forgeFullVersion), detector.getMinecraftJar(mcVersion).getFileName().toString(), detector.getLibraryDir().toAbsolutePath().toString());
|
||||||
} catch (Throwable ignored) {
|
} catch (Throwable ignored) {
|
||||||
// Avoid this bunch of hacks that nuke the whole wrapper.
|
// Avoid this bunch of hacks that nuke the whole wrapper.
|
||||||
}
|
}
|
||||||
if (!detector.checkExtraFiles(forgeFullVersion)) {
|
if (!detector.checkExtraFiles(forgeGroup, forgeArtifact, forgeFullVersion)) {
|
||||||
System.out.println("Some extra libraries are missing! Running the installer to generate them now.");
|
System.out.println("Some extra libraries are missing! Running the installer to generate them now.");
|
||||||
|
|
||||||
// Check installer jar.
|
// Check installer jar.
|
||||||
Path installerJar = detector.getInstallerJar(forgeFullVersion);
|
Path installerJar = detector.getInstallerJar(forgeGroup, forgeArtifact, forgeFullVersion);
|
||||||
if (!IFileDetector.isFile(installerJar)) {
|
if (!IFileDetector.isFile(installerJar)) {
|
||||||
throw new RuntimeException("Unable to detect the forge installer!");
|
throw new RuntimeException("Unable to detect the forge installer!");
|
||||||
}
|
}
|
||||||
|
@ -53,7 +62,8 @@ public class Main {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Class<?> mainClass = ModuleUtil.setupBootstrapLauncher(Class.forName(detector.getMainClass(forgeFullVersion)));
|
ModuleUtil.setupClassPath(detector.getLibraryDir(), detector.getExtraLibraries(forgeGroup, forgeArtifact, forgeFullVersion));
|
||||||
|
Class<?> mainClass = ModuleUtil.setupBootstrapLauncher(Class.forName(detector.getMainClass(forgeGroup, forgeArtifact, forgeFullVersion)));
|
||||||
mainClass.getMethod("main", String[].class).invoke(null, new Object[] { args });
|
mainClass.getMethod("main", String[].class).invoke(null, new Object[] { args });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,10 +61,12 @@ public interface IFileDetector {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param forgeGroup Forge package group (e.g. net.minecraftforge).
|
||||||
|
* @param forgeArtifact Forge package artifact (e.g. forge).
|
||||||
* @param forgeFullVersion Forge full version (e.g. 1.14.4-28.2.0).
|
* @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>".
|
* @return The forge installer jar path. It can also be defined by JVM argument "-Dforgewrapper.installer=<installer-path>".
|
||||||
*/
|
*/
|
||||||
default Path getInstallerJar(String forgeFullVersion) {
|
default Path getInstallerJar(String forgeGroup, String forgeArtifact, String forgeFullVersion) {
|
||||||
String installer = System.getProperty("forgewrapper.installer");
|
String installer = System.getProperty("forgewrapper.installer");
|
||||||
if (installer != null) {
|
if (installer != null) {
|
||||||
return Paths.get(installer).toAbsolutePath();
|
return Paths.get(installer).toAbsolutePath();
|
||||||
|
@ -85,12 +87,14 @@ public interface IFileDetector {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param forgeGroup Forge package group (e.g. net.minecraftforge).
|
||||||
|
* @param forgeArtifact Forge package artifact (e.g. forge).
|
||||||
* @param forgeFullVersion Forge full version (e.g. 1.14.4-28.2.0).
|
* @param forgeFullVersion Forge full version (e.g. 1.14.4-28.2.0).
|
||||||
* @return The list of jvm args.
|
* @return The list of jvm args.
|
||||||
*/
|
*/
|
||||||
default List<String> getJvmArgs(String forgeFullVersion) {
|
default List<String> getJvmArgs(String forgeGroup, String forgeArtifact, String forgeFullVersion) {
|
||||||
return this.getDataFromInstaller(forgeFullVersion, "version.json", e -> {
|
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<String> args = new ArrayList<>();
|
List<String> args = new ArrayList<>();
|
||||||
if (!element.equals(JsonNull.INSTANCE)) {
|
if (!element.equals(JsonNull.INSTANCE)) {
|
||||||
element.getAsJsonArray().iterator().forEachRemaining(je -> args.add(je.getAsString()));
|
element.getAsJsonArray().iterator().forEachRemaining(je -> args.add(je.getAsString()));
|
||||||
|
@ -99,25 +103,42 @@ public interface IFileDetector {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default List<String> getExtraLibraries(String forgeGroup, String forgeArtifact, String forgeFullVersion) {
|
||||||
|
return this.getDataFromInstaller(forgeGroup, forgeArtifact, forgeFullVersion, "version.json", e -> {
|
||||||
|
List<String> 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).
|
* @param forgeFullVersion Forge full version (e.g. 1.14.4-28.2.0).
|
||||||
* @return The main class.
|
* @return The main class.
|
||||||
*/
|
*/
|
||||||
default String getMainClass(String forgeFullVersion) {
|
default String getMainClass(String forgeGroup, String forgeArtifact, String forgeFullVersion) {
|
||||||
return this.getDataFromInstaller(forgeFullVersion, "version.json", e -> e.getAsJsonObject().getAsJsonPrimitive("mainClass").getAsString());
|
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).
|
* @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.
|
* @return The json object in the-installer-jar-->install_profile.json-->data-->xxx-->client.
|
||||||
*/
|
*/
|
||||||
default JsonObject getInstallProfileExtraData(String forgeFullVersion) {
|
default JsonObject getInstallProfileExtraData(String forgeGroup, String forgeArtifact, String forgeFullVersion) {
|
||||||
return this.getDataFromInstaller(forgeFullVersion, "install_profile.json", e -> e.getAsJsonObject().getAsJsonObject("data"));
|
return this.getDataFromInstaller(forgeGroup, forgeArtifact, forgeFullVersion, "install_profile.json", e -> e.getAsJsonObject().getAsJsonObject("data"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
default <R> R getDataFromInstaller(String forgeFullVersion, String entry, Function<JsonElement, R> function) {
|
default <R> R getDataFromInstaller(String forgeGroup, String forgeArtifact, String forgeFullVersion, String entry, Function<JsonElement, R> function) {
|
||||||
Path installer = this.getInstallerJar(forgeFullVersion);
|
Path installer = this.getInstallerJar(forgeGroup, forgeArtifact, forgeFullVersion);
|
||||||
if (isFile(installer)) {
|
if (isFile(installer)) {
|
||||||
try (ZipFile zf = new ZipFile(installer.toFile())) {
|
try (ZipFile zf = new ZipFile(installer.toFile())) {
|
||||||
ZipEntry ze = zf.getEntry(entry);
|
ZipEntry ze = zf.getEntry(entry);
|
||||||
|
@ -140,11 +161,13 @@ public interface IFileDetector {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check all cached files.
|
* 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).
|
* @param forgeFullVersion Forge full version (e.g. 1.14.4-28.2.0).
|
||||||
* @return True represents all files are ready.
|
* @return True represents all files are ready.
|
||||||
*/
|
*/
|
||||||
default boolean checkExtraFiles(String forgeFullVersion) {
|
default boolean checkExtraFiles(String forgeGroup, String forgeArtifact, String forgeFullVersion) {
|
||||||
JsonObject jo = this.getInstallProfileExtraData(forgeFullVersion);
|
JsonObject jo = this.getInstallProfileExtraData(forgeGroup, forgeArtifact, forgeFullVersion);
|
||||||
if (jo != null) {
|
if (jo != null) {
|
||||||
Map<String, Path> libsMap = new HashMap<>();
|
Map<String, Path> libsMap = new HashMap<>();
|
||||||
Map<String, String> hashMap = new HashMap<>();
|
Map<String, String> hashMap = new HashMap<>();
|
||||||
|
@ -152,7 +175,7 @@ public interface IFileDetector {
|
||||||
// Get all "data/<name>/client" elements.
|
// Get all "data/<name>/client" elements.
|
||||||
Pattern artifactPattern = Pattern.compile("^\\[(?<groupId>[^:]*):(?<artifactId>[^:]*):(?<version>[^:@]*)(:(?<classifier>[^@]*))?(@(?<type>[^]]*))?]$");
|
Pattern artifactPattern = Pattern.compile("^\\[(?<groupId>[^:]*):(?<artifactId>[^:]*):(?<version>[^:@]*)(:(?<classifier>[^@]*))?(@(?<type>[^]]*))?]$");
|
||||||
for (Map.Entry<String, JsonElement> entry : jo.entrySet()) {
|
for (Map.Entry<String, JsonElement> entry : jo.entrySet()) {
|
||||||
String clientStr = getElement(entry.getValue().getAsJsonObject(), "client").getAsString();
|
String clientStr = entry.getValue().getAsJsonObject().get("client").getAsString();
|
||||||
if (entry.getKey().endsWith("_SHA")) {
|
if (entry.getKey().endsWith("_SHA")) {
|
||||||
Pattern p = Pattern.compile("^'(?<sha1>[A-Za-z0-9]{40})'$");
|
Pattern p = Pattern.compile("^'(?<sha1>[A-Za-z0-9]{40})'$");
|
||||||
Matcher m = p.matcher(clientStr);
|
Matcher m = p.matcher(clientStr);
|
||||||
|
@ -171,7 +194,7 @@ public interface IFileDetector {
|
||||||
.resolve(groupId.replace('.', File.separatorChar))
|
.resolve(groupId.replace('.', File.separatorChar))
|
||||||
.resolve(artifactId)
|
.resolve(artifactId)
|
||||||
.resolve(version)
|
.resolve(version)
|
||||||
.resolve(artifactId + "-" + version + (classifier.equals("") ? "" : "-") + classifier + "." + type).toAbsolutePath());
|
.resolve(artifactId + "-" + version + (classifier.isEmpty() ? "" : "-") + classifier + "." + type).toAbsolutePath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -225,14 +248,6 @@ public interface IFileDetector {
|
||||||
return path != null && Files.isRegularFile(path);
|
return path != null && Files.isRegularFile(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
static JsonElement getElement(JsonObject object, String property) {
|
|
||||||
Optional<Map.Entry<String, JsonElement>> 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) {
|
static String getFileSHA1(Path path) {
|
||||||
try {
|
try {
|
||||||
StringBuilder sha1 = new StringBuilder(new BigInteger(1, MessageDigest.getInstance("SHA-1").digest(Files.readAllBytes(path))).toString(16));
|
StringBuilder sha1 = new StringBuilder(new BigInteger(1, MessageDigest.getInstance("SHA-1").digest(Files.readAllBytes(path))).toString(16));
|
||||||
|
|
|
@ -27,10 +27,16 @@ public class MultiMCFileDetector implements IFileDetector {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Path getInstallerJar(String forgeFullVersion) {
|
public Path getInstallerJar(String forgeGroup, String forgeArtifact, String forgeFullVersion) {
|
||||||
Path path = IFileDetector.super.getInstallerJar(forgeFullVersion);
|
Path path = IFileDetector.super.getInstallerJar(forgeGroup, forgeArtifact, forgeFullVersion);
|
||||||
if (path == null) {
|
if (path == null) {
|
||||||
return this.installerJar != null ? this.installerJar : (this.installerJar = this.getLibraryDir().resolve("net").resolve("minecraftforge").resolve("forge").resolve(forgeFullVersion).resolve("forge-" + forgeFullVersion + "-installer.jar").toAbsolutePath());
|
if (this.installerJar == null) {
|
||||||
|
Path installerBase = this.getLibraryDir();
|
||||||
|
for (String dir : forgeGroup.split("\\."))
|
||||||
|
installerBase = installerBase.resolve(dir);
|
||||||
|
this.installerJar = installerBase.resolve(forgeArtifact).resolve(forgeFullVersion).resolve(forgeArtifact + "-" + forgeFullVersion + "-installer.jar").toAbsolutePath();
|
||||||
|
}
|
||||||
|
return this.installerJar;
|
||||||
}
|
}
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
package io.github.zekerzhayard.forgewrapper.installer.util;
|
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;
|
import java.util.List;
|
||||||
|
|
||||||
public class ModuleUtil {
|
public class ModuleUtil {
|
||||||
|
@ -15,6 +20,14 @@ public class ModuleUtil {
|
||||||
// nothing to do with Java 8
|
// nothing to do with Java 8
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void setupClassPath(Path libraryDir, List<String> 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) {
|
public static Class<?> setupBootstrapLauncher(Class<?> mainClass) {
|
||||||
// nothing to do with Java 8
|
// nothing to do with Java 8
|
||||||
return mainClass;
|
return mainClass;
|
||||||
|
|
Loading…
Reference in a new issue