mirror of
https://github.com/HMCL-dev/HMCL.git
synced 2025-09-22 02:31:22 -04:00
Fix: 无法安装带有 Fabric 的非标准 MMC 整合包 (#4034)
- 修复无法安装带有 Fabric 的非标准 MMC 整合包的漏洞 - 在安装时写入当前安装器实现信息和启动器信息,以在后续调试时获得更多信息 Fix #4049
This commit is contained in:
parent
a10e9a04b1
commit
a39a23f938
4
.gitignore
vendored
4
.gitignore
vendored
@ -20,8 +20,8 @@ hmcl-exported-logs-*
|
||||
/HMCL/build/
|
||||
/HMCLCore/build/
|
||||
/HMCLBoot/build/
|
||||
/HMCLTransformerDiscoveryService/build/
|
||||
/minecraft/libraries/HMCLTransformerDiscoveryService/build/
|
||||
/minecraft/libraries/HMCLMultiMCBootstrap/build/
|
||||
/buildSrc/build/
|
||||
|
||||
# idea
|
||||
@ -30,12 +30,14 @@ hmcl-exported-logs-*
|
||||
/HMCL/out/
|
||||
/HMCLCore/out/
|
||||
/minecraft/libraries/HMCLTransformerDiscoveryService/out/
|
||||
/minecraft/libraries/HMCLMultiMCBootstrap/out/
|
||||
|
||||
# eclipse
|
||||
/bin/
|
||||
/HMCL/bin/
|
||||
/HMCLCore/bin/
|
||||
/minecraft/libraries/HMCLTransformerDiscoveryService/bin/
|
||||
/minecraft/libraries/HMCLMultiMCBootstrap/bin/
|
||||
.classpath
|
||||
.project
|
||||
.settings
|
||||
|
@ -19,11 +19,13 @@ package org.jackhuang.hmcl.game;
|
||||
|
||||
import com.google.gson.JsonParseException;
|
||||
import kala.compress.archivers.zip.ZipArchiveReader;
|
||||
import org.jackhuang.hmcl.Metadata;
|
||||
import org.jackhuang.hmcl.mod.*;
|
||||
import org.jackhuang.hmcl.mod.curse.CurseModpackProvider;
|
||||
import org.jackhuang.hmcl.mod.mcbbs.McbbsModpackManifest;
|
||||
import org.jackhuang.hmcl.mod.mcbbs.McbbsModpackProvider;
|
||||
import org.jackhuang.hmcl.mod.modrinth.ModrinthModpackProvider;
|
||||
import org.jackhuang.hmcl.mod.multimc.MultiMCComponents;
|
||||
import org.jackhuang.hmcl.mod.multimc.MultiMCInstanceConfiguration;
|
||||
import org.jackhuang.hmcl.mod.multimc.MultiMCModpackProvider;
|
||||
import org.jackhuang.hmcl.mod.server.ServerModpackManifest;
|
||||
@ -69,6 +71,10 @@ public final class ModpackHelper {
|
||||
pair(HMCLModpackProvider.INSTANCE.getName(), HMCLModpackProvider.INSTANCE)
|
||||
);
|
||||
|
||||
static {
|
||||
MultiMCComponents.setImplementation(Metadata.FULL_TITLE);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ModpackProvider getProviderByType(String type) {
|
||||
return providers.get(type);
|
||||
|
@ -32,3 +32,16 @@ dependencies {
|
||||
testImplementation(libs.jna.platform)
|
||||
testImplementation(libs.jimfs)
|
||||
}
|
||||
|
||||
tasks.processResources {
|
||||
listOf(
|
||||
"HMCLTransformerDiscoveryService",
|
||||
"HMCLMultiMCBootstrap"
|
||||
).map { project(":$it").tasks["jar"] as Jar }.forEach { task ->
|
||||
dependsOn(task)
|
||||
|
||||
into("assets/game") {
|
||||
from(task.outputs.files)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -241,6 +241,10 @@ public class Library implements Comparable<Library>, Validation {
|
||||
return hint;
|
||||
}
|
||||
|
||||
public Library withoutCommunityFields() {
|
||||
return new Library(artifact, url, downloads, checksums, extract, natives, rules, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Available when hint is "local"
|
||||
*
|
||||
|
@ -4,7 +4,9 @@ import org.jackhuang.hmcl.download.LibraryAnalyzer;
|
||||
import org.jackhuang.hmcl.util.io.NetworkUtils;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public final class MultiMCComponents {
|
||||
@ -12,6 +14,41 @@ public final class MultiMCComponents {
|
||||
private MultiMCComponents() {
|
||||
}
|
||||
|
||||
private static final Map<String, String> INSTALLER_PROFILE = new ConcurrentHashMap<>();
|
||||
|
||||
static {
|
||||
// Please append a phrase below while fixing bugs or implementing new features for Instance Format transformer
|
||||
INSTALLER_PROFILE.put("Patches", "recursive install, fabric & quilt intermediary");
|
||||
|
||||
// Check whether MultiMCComponents is 'org.jackhuang.hmcl.mod.multimc.MultiMCComponents'.
|
||||
// We use a base64-encoded value here to prevent string literals from being replaced by IDE if users trigger the 'Refactor' feature.
|
||||
if (new String(
|
||||
Base64.getDecoder().decode("b3JnLmphY2todWFuZy5obWNsLm1vZC5tdWx0aW1jLk11bHRpTUNDb21wb25lbnRz"),
|
||||
StandardCharsets.UTF_8
|
||||
).equals(MultiMCComponents.class.getName())) {
|
||||
INSTALLER_PROFILE.put("Implementation", "Probably vanilla. Class location is not modified (org.jackhuang.hmcl.mod.multimc.MultiMCComponents).");
|
||||
} else {
|
||||
INSTALLER_PROFILE.put("Implementation", "Not vanilla. Class location is " + MultiMCComponents.class.getName());
|
||||
}
|
||||
}
|
||||
|
||||
public static void setImplementation(String implementation) {
|
||||
INSTALLER_PROFILE.put("Implementation", implementation);
|
||||
}
|
||||
|
||||
public static String getInstallerProfile() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (Map.Entry<String, String> entry : INSTALLER_PROFILE.entrySet()) {
|
||||
builder.append(entry.getKey()).append(": ").append(entry.getValue()).append("\n");
|
||||
}
|
||||
|
||||
if (builder.length() != 0) {
|
||||
builder.setLength(builder.length() - 1);
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private static final Map<String, LibraryAnalyzer.LibraryType> ID_TYPE = new HashMap<>();
|
||||
|
||||
static {
|
||||
@ -46,7 +83,25 @@ public final class MultiMCComponents {
|
||||
return PAIRS;
|
||||
}
|
||||
|
||||
public static URI getMetaURL(String componentID, String version) {
|
||||
public static URI getMetaURL(String componentID, String version, String mcVersion) {
|
||||
if (version == null) {
|
||||
switch (componentID) {
|
||||
case "org.lwjgl": {
|
||||
version = "2.9.1";
|
||||
break;
|
||||
}
|
||||
case "org.lwjgl3": {
|
||||
version = "3.1.2";
|
||||
break;
|
||||
}
|
||||
case "net.fabricmc.intermediary":
|
||||
case "org.quiltmc.hashed": {
|
||||
version = mcVersion;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NetworkUtils.toURI(String.format("https://meta.multimc.org/v1/%s/%s.json", componentID, version));
|
||||
}
|
||||
}
|
||||
|
@ -37,6 +37,7 @@ import org.jackhuang.hmcl.util.Lang;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
import org.jackhuang.hmcl.util.gson.JsonMap;
|
||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||
import org.jackhuang.hmcl.util.io.NetworkUtils;
|
||||
import org.jackhuang.hmcl.util.logging.Logger;
|
||||
import org.jackhuang.hmcl.util.platform.OperatingSystem;
|
||||
|
||||
@ -45,6 +46,7 @@ import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
@ -54,6 +56,8 @@ import java.util.stream.Collectors;
|
||||
*/
|
||||
@Immutable
|
||||
public final class MultiMCInstancePatch {
|
||||
public static final Library BOOTSTRAP_LIBRARY = new Library(new Artifact("org.jackhuang.hmcl", "mmc-bootstrap", "1.0"));
|
||||
|
||||
private final int formatVersion;
|
||||
|
||||
@SerializedName("uid")
|
||||
@ -390,6 +394,15 @@ public final class MultiMCInstancePatch {
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
libraries.add(0, BOOTSTRAP_LIBRARY);
|
||||
jvmArguments.add(new StringArgument("-Dhmcl.mmc.bootstrap=" + NetworkUtils.withQuery("hmcl:///bootstrap_profile_v1/", Map.of(
|
||||
"main_class", mainClass,
|
||||
"installer", MultiMCComponents.getInstallerProfile()
|
||||
))));
|
||||
mainClass = "org.jackhuang.hmcl.HMCLMultiMCBootstrap";
|
||||
}
|
||||
|
||||
Version version = new Version(versionID)
|
||||
.setArguments(new Arguments().addGameArguments(minecraftArguments).addJVMArgumentsDirect(jvmArguments))
|
||||
.setMainClass(mainClass)
|
||||
|
@ -19,11 +19,14 @@ package org.jackhuang.hmcl.mod.multimc;
|
||||
|
||||
import com.google.gson.JsonParseException;
|
||||
import org.jackhuang.hmcl.download.DefaultDependencyManager;
|
||||
import org.jackhuang.hmcl.download.LibraryAnalyzer;
|
||||
import org.jackhuang.hmcl.download.MaintainTask;
|
||||
import org.jackhuang.hmcl.download.game.GameAssetDownloadTask;
|
||||
import org.jackhuang.hmcl.download.game.GameDownloadTask;
|
||||
import org.jackhuang.hmcl.download.game.GameLibrariesTask;
|
||||
import org.jackhuang.hmcl.game.Artifact;
|
||||
import org.jackhuang.hmcl.game.DefaultGameRepository;
|
||||
import org.jackhuang.hmcl.game.Library;
|
||||
import org.jackhuang.hmcl.game.Version;
|
||||
import org.jackhuang.hmcl.mod.MinecraftInstanceTask;
|
||||
import org.jackhuang.hmcl.mod.Modpack;
|
||||
@ -38,14 +41,16 @@ import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
@ -54,16 +59,20 @@ import java.util.Objects;
|
||||
* <p>A task transforming MultiMC Modpack Scheme to Official Launcher Scheme.
|
||||
* The transforming process contains 7 stage:
|
||||
* <ul>
|
||||
* <li>General Setup</li>
|
||||
* <li>Load Components</li>
|
||||
* <li>Resolve Json-Patch</li>
|
||||
* <li>Build Artifact</li>
|
||||
* <li>Copy Embedded Files</li>
|
||||
* <li>Assemble Game</li>
|
||||
* <li>Download Game</li>
|
||||
* <li>Apply JAR mods</li>
|
||||
* <li>General Setup: Compute checksum and copy 'overrides' files.</li>
|
||||
* <li>Load Components: Parse all local Json-Patch and prepare to fetch others from Internet.</li>
|
||||
* <li>Resolve Json-Patch: Fetch remote Json-Patch and their dependencies.</li>
|
||||
* <li>Build Artifact: Transform Json-Patch to Official Scheme lossily, without original structure.</li>
|
||||
* <li>Copy Embedded Files: Copy embedded libraries and icon.</li>
|
||||
* <li>Assemble Game: Prepare to download main jar, libraries and assets.</li>
|
||||
* <li>Download Game: Download files.</li>
|
||||
* <li>Apply JAR mods: Apply JAR mods into main jar.</li>
|
||||
* </ul>
|
||||
* See codes below for detailed implementation.
|
||||
*
|
||||
* @implNote To guarantee all features of MultiMC Modpack Scheme is super hard.
|
||||
* As f*** MMC never provides a detailed API docs, most codes below is guessed from its source code.
|
||||
* <b>FUNCTIONS OF GAMES MIGHT NOT BE COMPLETELY THE SAME WITH MMC.</b>
|
||||
* </p>
|
||||
*/
|
||||
public final class MultiMCModpackInstallTask extends Task<MultiMCInstancePatch.ResolvedInstance> {
|
||||
@ -133,10 +142,23 @@ public final class MultiMCModpackInstallTask extends Task<MultiMCInstancePatch.R
|
||||
try (FileSystem fs = openModpack()) {
|
||||
Path root = getRootPath(fs);
|
||||
|
||||
List<Task<MultiMCInstancePatch>> patches = new ArrayList<>();
|
||||
for (MultiMCManifest.MultiMCManifestComponent component : Objects.requireNonNull(
|
||||
List<MultiMCManifest.MultiMCManifestComponent> components = Objects.requireNonNull(
|
||||
Objects.requireNonNull(manifest.getMmcPack(), "mmc-pack.json").getComponents(), "components"
|
||||
)) {
|
||||
);
|
||||
List<Task<MultiMCInstancePatch>> patches = new ArrayList<>();
|
||||
|
||||
String mcVersion = null;
|
||||
for (MultiMCManifest.MultiMCManifestComponent component : components) {
|
||||
if (MultiMCComponents.getComponent(component.getUid()) == LibraryAnalyzer.LibraryType.MINECRAFT) {
|
||||
mcVersion = component.getVersion();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mcVersion == null) {
|
||||
throw new IllegalStateException("Cannot load modpacks without Minecraft.");
|
||||
}
|
||||
|
||||
for (MultiMCManifest.MultiMCManifestComponent component : components) {
|
||||
String componentID = Objects.requireNonNull(component.getUid(), "Component ID");
|
||||
Path patchPath = root.resolve(String.format("patches/%s.json", componentID));
|
||||
|
||||
@ -149,20 +171,22 @@ public final class MultiMCModpackInstallTask extends Task<MultiMCInstancePatch.R
|
||||
patches.add(Task.supplyAsync(() -> patch)); // TODO: Task.completed has unclear compatibility issue.
|
||||
} else {
|
||||
patches.add(
|
||||
new GetTask(MultiMCComponents.getMetaURL(componentID, component.getVersion()))
|
||||
new GetTask(MultiMCComponents.getMetaURL(componentID, component.getVersion(), mcVersion))
|
||||
.thenApplyAsync(s -> MultiMCInstancePatch.read(componentID, s))
|
||||
);
|
||||
}
|
||||
}
|
||||
dependents.add(new MMCInstancePatchesAssembleTask(patches));
|
||||
dependents.add(new MMCInstancePatchesAssembleTask(patches, mcVersion));
|
||||
}
|
||||
}
|
||||
|
||||
private static final class MMCInstancePatchesAssembleTask extends Task<List<MultiMCInstancePatch>> {
|
||||
private final List<Task<MultiMCInstancePatch>> patches;
|
||||
private final String mcVersion;
|
||||
|
||||
public MMCInstancePatchesAssembleTask(List<Task<MultiMCInstancePatch>> patches) {
|
||||
public MMCInstancePatchesAssembleTask(List<Task<MultiMCInstancePatch>> patches, String mcVersion) {
|
||||
this.patches = patches;
|
||||
this.mcVersion = mcVersion;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -172,7 +196,7 @@ public final class MultiMCModpackInstallTask extends Task<MultiMCInstancePatch.R
|
||||
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
Map<String, MultiMCInstancePatch> existed = new HashMap<>();
|
||||
Map<String, MultiMCInstancePatch> existed = new LinkedHashMap<>();
|
||||
for (Task<MultiMCInstancePatch> patch : patches) {
|
||||
MultiMCInstancePatch result = patch.getResult();
|
||||
|
||||
@ -186,7 +210,7 @@ public final class MultiMCModpackInstallTask extends Task<MultiMCInstancePatch.R
|
||||
String componentID = require.getID();
|
||||
if (!existed.containsKey(componentID)) {
|
||||
Task<MultiMCInstancePatch> task = new GetTask(MultiMCComponents.getMetaURL(
|
||||
componentID, Lang.requireNonNullElse(require.getEqualsVersion(), require.getSuggests())
|
||||
componentID, Lang.requireNonNullElse(require.getEqualsVersion(), require.getSuggests()), mcVersion
|
||||
)).thenApplyAsync(s -> MultiMCInstancePatch.read(componentID, s));
|
||||
task.run();
|
||||
|
||||
@ -231,6 +255,26 @@ public final class MultiMCModpackInstallTask extends Task<MultiMCInstancePatch.R
|
||||
if (Files.exists(libraries))
|
||||
FileUtils.copyDirectory(libraries, repository.getVersionRoot(name).toPath().resolve("libraries"));
|
||||
|
||||
for (Library library : artifact.getVersion().getLibraries()) {
|
||||
if ("local".equals(library.getHint())) {
|
||||
/* TODO: Determine whether we should erase community fields, like 'hint' and 'filename' from version json.
|
||||
Retain them will facilitate compatibility, as some embedded libraries may check where their JAR is.
|
||||
Meanwhile, potential compatibility issue with other launcher which never supports these fields might occur.
|
||||
Here, we make the file stored twice, to keep maximum compatibility. */
|
||||
Path from = repository.getLibraryFile(artifact.getVersion(), library).toPath();
|
||||
Path target = repository.getLibraryFile(artifact.getVersion(), library.withoutCommunityFields()).toPath();
|
||||
Files.createDirectories(target.getParent());
|
||||
Files.copy(from, target, StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
}
|
||||
|
||||
try (InputStream input = MaintainTask.class.getResourceAsStream("/assets/game/HMCLMultiMCBootstrap-1.0.jar")) {
|
||||
Path libraryPath = repository.getLibraryFile(artifact.getVersion(), MultiMCInstancePatch.BOOTSTRAP_LIBRARY).toPath();
|
||||
|
||||
Files.createDirectories(libraryPath.getParent());
|
||||
Files.copy(Objects.requireNonNull(input, "Bundled HMCLMultiMCBootstrap is missing."), libraryPath, StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
|
||||
String iconKey = this.manifest.getIconKey();
|
||||
if (iconKey != null) {
|
||||
Path iconFile = root.resolve(iconKey + ".png");
|
||||
|
Binary file not shown.
15
minecraft/libraries/HMCLMultiMCBootstrap/build.gradle.kts
Normal file
15
minecraft/libraries/HMCLMultiMCBootstrap/build.gradle.kts
Normal file
@ -0,0 +1,15 @@
|
||||
version = "1.0"
|
||||
|
||||
tasks.compileJava {
|
||||
sourceCompatibility = "1.8"
|
||||
targetCompatibility = "1.8"
|
||||
}
|
||||
|
||||
tasks.jar {
|
||||
manifest {
|
||||
attributes(
|
||||
"Created-By" to "Copyright(c) 2013-2025 huangyuhui.",
|
||||
"Implementation-Version" to project.version
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher
|
||||
* Copyright (C) 2020 huangyuhui <huanghongxun2008@126.com> and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.jackhuang.hmcl;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.net.URI;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Scanner;
|
||||
|
||||
public final class HMCLMultiMCBootstrap {
|
||||
private HMCLMultiMCBootstrap() {
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
String profile = System.getProperty("hmcl.mmc.bootstrap");
|
||||
if (profile == null) {
|
||||
launchLegacy(args);
|
||||
return;
|
||||
}
|
||||
|
||||
URI uri = URI.create(profile);
|
||||
if (Objects.equals(uri.getPath(), "/bootstrap_profile_v1/")) {
|
||||
launchV1(parseQuery(uri.getRawQuery()), args);
|
||||
}
|
||||
}
|
||||
|
||||
private static void launchV1(Map<String, String> arguments, String[] args) throws Throwable {
|
||||
String mainClass = arguments.get("main_class");
|
||||
String installerInfo = arguments.get("installer");
|
||||
|
||||
launch(installerInfo, mainClass, args);
|
||||
}
|
||||
|
||||
private static void launchLegacy(String[] args) throws Throwable {
|
||||
String mainClass = new String(Base64.getUrlDecoder().decode(System.getProperty("hmcl.mmc.bootstrap.main")), StandardCharsets.UTF_8);
|
||||
String installerInfo = new String(Base64.getUrlDecoder().decode(System.getProperty("hmcl.mmc.bootstrap.installer")), StandardCharsets.UTF_8);
|
||||
|
||||
launch(installerInfo, mainClass, args);
|
||||
}
|
||||
|
||||
private static void launch(String installerInfo, String mainClass, String[] args) throws Throwable {
|
||||
System.out.println("This version is installed by HMCLCore's MultiMC combat layer.");
|
||||
System.out.println("Installer Properties:");
|
||||
System.out.println(installerInfo);
|
||||
System.out.println("Main Class: " + mainClass);
|
||||
System.out.println("GAME MAY CRASH DUE TO BUGS. TEST YOUR GAME ON OFFICIAL MMC BEFORE REPORTING BUGS TO AUTHORS.");
|
||||
|
||||
Method[] methods = Class.forName(mainClass).getMethods();
|
||||
for (Method method : methods) {
|
||||
// https://docs.oracle.com/javase/specs/jls/se21/html/jls-12.html#jls-12.1.4
|
||||
if ("main".equals(method.getName()) &&
|
||||
Modifier.isStatic(method.getModifiers()) &&
|
||||
method.getReturnType() == void.class &&
|
||||
method.getParameterCount() == 1 &&
|
||||
method.getParameters()[0].getType() == String[].class
|
||||
) {
|
||||
method.invoke(null, (Object) args);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Cannot find method 'main(String[])' in " + mainClass);
|
||||
}
|
||||
|
||||
private static Map<String, String> parseQuery(String queryParameterString) {
|
||||
if (queryParameterString == null) return Collections.emptyMap();
|
||||
|
||||
Map<String, String> result = new HashMap<>();
|
||||
|
||||
try (Scanner scanner = new Scanner(queryParameterString)) {
|
||||
scanner.useDelimiter("&");
|
||||
while (scanner.hasNext()) {
|
||||
String[] nameValue = scanner.next().split("=");
|
||||
if (nameValue.length == 0 || nameValue.length > 2) {
|
||||
throw new IllegalArgumentException("bad query string");
|
||||
}
|
||||
|
||||
String name = decodeURL(nameValue[0]);
|
||||
String value = nameValue.length == 2 ? decodeURL(nameValue[1]) : null;
|
||||
result.put(name, value);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static String decodeURL(String value) {
|
||||
try {
|
||||
return URLDecoder.decode(value, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
}
|
@ -2,11 +2,11 @@ rootProject.name = "HMCL3"
|
||||
include(
|
||||
"HMCL",
|
||||
"HMCLCore",
|
||||
"HMCLBoot",
|
||||
"HMCLTransformerDiscoveryService"
|
||||
"HMCLBoot"
|
||||
)
|
||||
|
||||
val minecraftLibraries = listOf("HMCLTransformerDiscoveryService")
|
||||
val minecraftLibraries = listOf("HMCLTransformerDiscoveryService", "HMCLMultiMCBootstrap")
|
||||
include(minecraftLibraries)
|
||||
|
||||
for (library in minecraftLibraries) {
|
||||
project(":$library").projectDir = file("minecraft/libraries/$library")
|
||||
|
Loading…
x
Reference in New Issue
Block a user