Support fabric detection
This commit is contained in:
@@ -158,9 +158,9 @@ public class HMCLGameRepository extends DefaultGameRepository {
|
|||||||
File iconFile = getVersionIconFile(id);
|
File iconFile = getVersionIconFile(id);
|
||||||
if (iconFile.exists())
|
if (iconFile.exists())
|
||||||
return new Image("file:" + iconFile.getAbsolutePath());
|
return new Image("file:" + iconFile.getAbsolutePath());
|
||||||
else if ("net.minecraft.launchwrapper.Launch".equals(version.getMainClass()))
|
else if ("net.minecraft.launchwrapper.Launch".equals(version.getMainClass())
|
||||||
return newImage("/assets/img/furnace.png");
|
|| version.getMainClass().startsWith("net.fabricmc")
|
||||||
else if ("cpw.mods.modlauncher.Launcher".equals(version.getMainClass()))
|
|| "cpw.mods.modlauncher.Launcher".equals(version.getMainClass()))
|
||||||
return newImage("/assets/img/furnace.png");
|
return newImage("/assets/img/furnace.png");
|
||||||
else
|
else
|
||||||
return newImage("/assets/img/grass.png");
|
return newImage("/assets/img/grass.png");
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ import org.jackhuang.hmcl.util.io.ResponseCodeException;
|
|||||||
import java.net.SocketTimeoutException;
|
import java.net.SocketTimeoutException;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static org.jackhuang.hmcl.download.LibraryAnalyzer.LibraryType.*;
|
||||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||||
|
|
||||||
public final class InstallerWizardProvider implements WizardProvider {
|
public final class InstallerWizardProvider implements WizardProvider {
|
||||||
@@ -56,9 +57,9 @@ public final class InstallerWizardProvider implements WizardProvider {
|
|||||||
this.version = version;
|
this.version = version;
|
||||||
|
|
||||||
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(version);
|
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(version);
|
||||||
forge = analyzer.getForge().map(Library::getVersion).orElse(null);
|
forge = analyzer.get(FORGE).map(Library::getVersion).orElse(null);
|
||||||
liteLoader = analyzer.getLiteLoader().map(Library::getVersion).orElse(null);
|
liteLoader = analyzer.get(LITELOADER).map(Library::getVersion).orElse(null);
|
||||||
optiFine = analyzer.getOptiFine().map(Library::getVersion).orElse(null);
|
optiFine = analyzer.get(OPTIFINE).map(Library::getVersion).orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Profile getProfile() {
|
public Profile getProfile() {
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import org.jackhuang.hmcl.download.LibraryAnalyzer;
|
|||||||
import org.jackhuang.hmcl.game.GameVersion;
|
import org.jackhuang.hmcl.game.GameVersion;
|
||||||
import org.jackhuang.hmcl.setting.Profile;
|
import org.jackhuang.hmcl.setting.Profile;
|
||||||
|
|
||||||
|
import static org.jackhuang.hmcl.download.LibraryAnalyzer.LibraryType.*;
|
||||||
import static org.jackhuang.hmcl.util.Lang.handleUncaught;
|
import static org.jackhuang.hmcl.util.Lang.handleUncaught;
|
||||||
import static org.jackhuang.hmcl.util.Lang.threadPool;
|
import static org.jackhuang.hmcl.util.Lang.threadPool;
|
||||||
import static org.jackhuang.hmcl.util.StringUtils.removePrefix;
|
import static org.jackhuang.hmcl.util.StringUtils.removePrefix;
|
||||||
@@ -55,9 +56,9 @@ public class GameItem extends Control {
|
|||||||
.thenAcceptAsync(game -> {
|
.thenAcceptAsync(game -> {
|
||||||
StringBuilder libraries = new StringBuilder(game);
|
StringBuilder libraries = new StringBuilder(game);
|
||||||
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(profile.getRepository().getVersion(id));
|
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(profile.getRepository().getVersion(id));
|
||||||
analyzer.getForge().ifPresent(library -> libraries.append(", ").append(i18n("install.installer.forge")).append(": ").append(modifyVersion(game, library.getVersion().replaceAll("(?i)forge", ""))));
|
analyzer.get(FORGE).ifPresent(library -> libraries.append(", ").append(i18n("install.installer.forge")).append(": ").append(modifyVersion(game, library.getVersion().replaceAll("(?i)forge", ""))));
|
||||||
analyzer.getLiteLoader().ifPresent(library -> libraries.append(", ").append(i18n("install.installer.liteloader")).append(": ").append(modifyVersion(game, library.getVersion().replaceAll("(?i)liteloader", ""))));
|
analyzer.get(LITELOADER).ifPresent(library -> libraries.append(", ").append(i18n("install.installer.liteloader")).append(": ").append(modifyVersion(game, library.getVersion().replaceAll("(?i)liteloader", ""))));
|
||||||
analyzer.getOptiFine().ifPresent(library -> libraries.append(", ").append(i18n("install.installer.optifine")).append(": ").append(modifyVersion(game, library.getVersion().replaceAll("(?i)optifine", ""))));
|
analyzer.get(OPTIFINE).ifPresent(library -> libraries.append(", ").append(i18n("install.installer.optifine")).append(": ").append(modifyVersion(game, library.getVersion().replaceAll("(?i)optifine", ""))));
|
||||||
subtitle.set(libraries.toString());
|
subtitle.set(libraries.toString());
|
||||||
}, Platform::runLater)
|
}, Platform::runLater)
|
||||||
.exceptionally(handleUncaught);
|
.exceptionally(handleUncaught);
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import java.util.LinkedList;
|
|||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import static org.jackhuang.hmcl.download.LibraryAnalyzer.LibraryType.*;
|
||||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||||
|
|
||||||
public class InstallerListPage extends ListPage<InstallerItem> {
|
public class InstallerListPage extends ListPage<InstallerItem> {
|
||||||
@@ -66,15 +67,15 @@ public class InstallerListPage extends ListPage<InstallerItem> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
itemsProperty().clear();
|
itemsProperty().clear();
|
||||||
analyzer.getForge().ifPresent(library -> itemsProperty().add(
|
analyzer.get(FORGE).ifPresent(library -> itemsProperty().add(
|
||||||
new InstallerItem("Forge", library.getVersion(), () -> {
|
new InstallerItem("Forge", library.getVersion(), () -> {
|
||||||
Controllers.getDecorator().startWizard(new UpdateInstallerWizardProvider(profile, gameVersion, version, "forge", library));
|
Controllers.getDecorator().startWizard(new UpdateInstallerWizardProvider(profile, gameVersion, version, "forge", library));
|
||||||
}, removeAction.apply(library))));
|
}, removeAction.apply(library))));
|
||||||
analyzer.getLiteLoader().ifPresent(library -> itemsProperty().add(
|
analyzer.get(LITELOADER).ifPresent(library -> itemsProperty().add(
|
||||||
new InstallerItem("LiteLoader", library.getVersion(), () -> {
|
new InstallerItem("LiteLoader", library.getVersion(), () -> {
|
||||||
Controllers.getDecorator().startWizard(new UpdateInstallerWizardProvider(profile, gameVersion, version, "liteloader", library));
|
Controllers.getDecorator().startWizard(new UpdateInstallerWizardProvider(profile, gameVersion, version, "liteloader", library));
|
||||||
}, removeAction.apply(library))));
|
}, removeAction.apply(library))));
|
||||||
analyzer.getOptiFine().ifPresent(library -> itemsProperty().add(
|
analyzer.get(OPTIFINE).ifPresent(library -> itemsProperty().add(
|
||||||
new InstallerItem("OptiFine", library.getVersion(), () -> {
|
new InstallerItem("OptiFine", library.getVersion(), () -> {
|
||||||
Controllers.getDecorator().startWizard(new UpdateInstallerWizardProvider(profile, gameVersion, version, "optifine", library));
|
Controllers.getDecorator().startWizard(new UpdateInstallerWizardProvider(profile, gameVersion, version, "optifine", library));
|
||||||
}, removeAction.apply(library))));
|
}, removeAction.apply(library))));
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ public final class ModListPage extends ListPageBase<ModListPageSkin.ModInfoObjec
|
|||||||
|
|
||||||
public void loadVersion(Profile profile, String id) {
|
public void loadVersion(Profile profile, String id) {
|
||||||
libraryAnalyzer = LibraryAnalyzer.analyze(profile.getRepository().getResolvedVersion(id));
|
libraryAnalyzer = LibraryAnalyzer.analyze(profile.getRepository().getResolvedVersion(id));
|
||||||
modded.set(libraryAnalyzer.hasForge() || libraryAnalyzer.hasLiteLoader());
|
modded.set(libraryAnalyzer.hasModLoader());
|
||||||
loadMods(profile.getRepository().getModManager(id));
|
loadMods(profile.getRepository().getModManager(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,59 +20,68 @@ package org.jackhuang.hmcl.download;
|
|||||||
import org.jackhuang.hmcl.game.Library;
|
import org.jackhuang.hmcl.game.Library;
|
||||||
import org.jackhuang.hmcl.game.Version;
|
import org.jackhuang.hmcl.game.Version;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.EnumMap;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
public final class LibraryAnalyzer {
|
public final class LibraryAnalyzer {
|
||||||
private final Library forge;
|
private final Map<LibraryType, Library> libraries;
|
||||||
private final Library liteLoader;
|
|
||||||
private final Library optiFine;
|
|
||||||
|
|
||||||
public LibraryAnalyzer(Library forge, Library liteLoader, Library optiFine) {
|
private LibraryAnalyzer(Map<LibraryType, Library> libraries) {
|
||||||
this.forge = forge;
|
this.libraries = libraries;
|
||||||
this.liteLoader = liteLoader;
|
|
||||||
this.optiFine = optiFine;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<Library> getForge() {
|
public Optional<Library> get(LibraryType type) {
|
||||||
return Optional.ofNullable(forge);
|
return Optional.ofNullable(libraries.get(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasForge() {
|
public boolean has(LibraryType type) {
|
||||||
return forge != null;
|
return libraries.containsKey(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<Library> getLiteLoader() {
|
public boolean hasModLoader() {
|
||||||
return Optional.ofNullable(liteLoader);
|
return Arrays.stream(LibraryType.values())
|
||||||
}
|
.filter(LibraryType::isModLoader)
|
||||||
|
.anyMatch(this::has);
|
||||||
public boolean hasLiteLoader() {
|
|
||||||
return liteLoader != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Optional<Library> getOptiFine() {
|
|
||||||
return Optional.ofNullable(optiFine);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasOptiFine() {
|
|
||||||
return optiFine != null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LibraryAnalyzer analyze(Version version) {
|
public static LibraryAnalyzer analyze(Version version) {
|
||||||
Library forge = null, liteLoader = null, optiFine = null;
|
Map<LibraryType, Library> libraries = new EnumMap<>(LibraryType.class);
|
||||||
|
|
||||||
for (Library library : version.getLibraries()) {
|
for (Library library : version.getLibraries()) {
|
||||||
String groupId = library.getGroupId();
|
String groupId = library.getGroupId();
|
||||||
String artifactId = library.getArtifactId();
|
String artifactId = library.getArtifactId();
|
||||||
if (groupId.equalsIgnoreCase("net.minecraftforge") && artifactId.equalsIgnoreCase("forge"))
|
|
||||||
forge = library;
|
|
||||||
|
|
||||||
if (groupId.equalsIgnoreCase("com.mumfrey") && artifactId.equalsIgnoreCase("liteloader"))
|
for (LibraryType type : LibraryType.values()) {
|
||||||
liteLoader = library;
|
if (type.group.matcher(groupId).matches() && type.artifact.matcher(artifactId).matches()) {
|
||||||
|
libraries.put(type, library);
|
||||||
if ((groupId.equalsIgnoreCase("optifine") || groupId.equalsIgnoreCase("net.optifine")) && artifactId.equalsIgnoreCase("optifine"))
|
break;
|
||||||
optiFine = library;
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new LibraryAnalyzer(forge, liteLoader, optiFine);
|
return new LibraryAnalyzer(libraries);
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum LibraryType {
|
||||||
|
FORGE(true, Pattern.compile("net\\.minecraftforge"), Pattern.compile("forge")),
|
||||||
|
LITELOADER(true, Pattern.compile("com\\.mumfrey"), Pattern.compile("liteloader")),
|
||||||
|
OPTIFINE(false, Pattern.compile("(net\\.)?optifine"), Pattern.compile(".*")),
|
||||||
|
FABRIC(true, Pattern.compile("net\\.fabricmc"), Pattern.compile(".*"));
|
||||||
|
|
||||||
|
private final Pattern group, artifact;
|
||||||
|
private final boolean modLoader;
|
||||||
|
|
||||||
|
LibraryType(boolean modLoader, Pattern group, Pattern artifact) {
|
||||||
|
this.modLoader = modLoader;
|
||||||
|
this.group = group;
|
||||||
|
this.artifact = artifact;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isModLoader() {
|
||||||
|
return modLoader;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ package org.jackhuang.hmcl.download;
|
|||||||
import org.jackhuang.hmcl.game.*;
|
import org.jackhuang.hmcl.game.*;
|
||||||
import org.jackhuang.hmcl.task.TaskResult;
|
import org.jackhuang.hmcl.task.TaskResult;
|
||||||
|
|
||||||
|
import static org.jackhuang.hmcl.download.LibraryAnalyzer.LibraryType.*;
|
||||||
|
|
||||||
public class MaintainTask extends TaskResult<Version> {
|
public class MaintainTask extends TaskResult<Version> {
|
||||||
|
|
||||||
private final Version version;
|
private final Version version;
|
||||||
@@ -47,20 +49,20 @@ public class MaintainTask extends TaskResult<Version> {
|
|||||||
LibraryAnalyzer libraryAnalyzer = LibraryAnalyzer.analyze(version);
|
LibraryAnalyzer libraryAnalyzer = LibraryAnalyzer.analyze(version);
|
||||||
VersionLibraryBuilder builder = new VersionLibraryBuilder(version);
|
VersionLibraryBuilder builder = new VersionLibraryBuilder(version);
|
||||||
|
|
||||||
if (!libraryAnalyzer.hasForge()) {
|
if (!libraryAnalyzer.has(FORGE)) {
|
||||||
builder.removeTweakClass("forge");
|
builder.removeTweakClass("forge");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Installing Forge will override the Minecraft arguments in json, so LiteLoader and OptiFine Tweaker are being re-added.
|
// Installing Forge will override the Minecraft arguments in json, so LiteLoader and OptiFine Tweaker are being re-added.
|
||||||
|
|
||||||
builder.removeTweakClass("liteloader");
|
builder.removeTweakClass("liteloader");
|
||||||
if (libraryAnalyzer.hasLiteLoader()) {
|
if (libraryAnalyzer.has(LITELOADER)) {
|
||||||
builder.addArgument("--tweakClass", "com.mumfrey.liteloader.launch.LiteLoaderTweaker");
|
builder.addArgument("--tweakClass", "com.mumfrey.liteloader.launch.LiteLoaderTweaker");
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.removeTweakClass("optifine");
|
builder.removeTweakClass("optifine");
|
||||||
if (libraryAnalyzer.hasOptiFine()) {
|
if (libraryAnalyzer.has(OPTIFINE)) {
|
||||||
if (!libraryAnalyzer.hasLiteLoader() && !libraryAnalyzer.hasForge()) {
|
if (!libraryAnalyzer.has(LITELOADER) && !libraryAnalyzer.has(FORGE)) {
|
||||||
builder.addArgument("--tweakClass", "optifine.OptiFineTweaker");
|
builder.addArgument("--tweakClass", "optifine.OptiFineTweaker");
|
||||||
} else {
|
} else {
|
||||||
// If forge or LiteLoader installed, OptiFine Forge Tweaker is needed.
|
// If forge or LiteLoader installed, OptiFine Forge Tweaker is needed.
|
||||||
|
|||||||
@@ -25,7 +25,9 @@ import org.jackhuang.hmcl.game.Version;
|
|||||||
import org.jackhuang.hmcl.task.Task;
|
import org.jackhuang.hmcl.task.Task;
|
||||||
import org.jackhuang.hmcl.task.TaskResult;
|
import org.jackhuang.hmcl.task.TaskResult;
|
||||||
import org.jackhuang.hmcl.util.Lang;
|
import org.jackhuang.hmcl.util.Lang;
|
||||||
|
import org.jackhuang.hmcl.util.StringUtils;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -66,7 +68,9 @@ public final class OptiFineInstallTask extends TaskResult<Version> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute() {
|
public void execute() {
|
||||||
if ("cpw.mods.modlauncher.Launcher".equals(version.getMainClass()))
|
if (!Arrays.asList("net.minecraft.client.main.Main",
|
||||||
|
"net.minecraft.launchwrapper.Launch")
|
||||||
|
.contains(version.getMainClass()))
|
||||||
throw new UnsupportedOptiFineInstallationException();
|
throw new UnsupportedOptiFineInstallationException();
|
||||||
|
|
||||||
String remoteVersion = remote.getGameVersion() + "_" + remote.getSelfVersion();
|
String remoteVersion = remote.getGameVersion() + "_" + remote.getSelfVersion();
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
package org.jackhuang.hmcl.mod;
|
package org.jackhuang.hmcl.mod;
|
||||||
|
|
||||||
import com.google.gson.JsonParseException;
|
import com.google.gson.JsonParseException;
|
||||||
import com.google.gson.annotations.SerializedName;
|
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.beans.property.BooleanProperty;
|
import javafx.beans.property.BooleanProperty;
|
||||||
import javafx.beans.property.SimpleBooleanProperty;
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
@@ -27,7 +26,6 @@ import javafx.collections.ObservableList;
|
|||||||
import org.jackhuang.hmcl.util.Logging;
|
import org.jackhuang.hmcl.util.Logging;
|
||||||
import org.jackhuang.hmcl.util.StringUtils;
|
import org.jackhuang.hmcl.util.StringUtils;
|
||||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||||
import org.jackhuang.hmcl.util.gson.Validation;
|
|
||||||
import org.jackhuang.hmcl.util.io.CompressingUtils;
|
import org.jackhuang.hmcl.util.io.CompressingUtils;
|
||||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||||
import org.jackhuang.hmcl.util.io.Unzipper;
|
import org.jackhuang.hmcl.util.io.Unzipper;
|
||||||
@@ -254,54 +252,6 @@ public class Datapack {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class PackMcMeta implements Validation {
|
|
||||||
|
|
||||||
@SerializedName("pack")
|
|
||||||
private final PackInfo pack;
|
|
||||||
|
|
||||||
public PackMcMeta() {
|
|
||||||
this(new PackInfo());
|
|
||||||
}
|
|
||||||
|
|
||||||
public PackMcMeta(PackInfo packInfo) {
|
|
||||||
this.pack = packInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PackInfo getPackInfo() {
|
|
||||||
return pack;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void validate() throws JsonParseException {
|
|
||||||
if (pack == null)
|
|
||||||
throw new JsonParseException("pack cannot be null");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class PackInfo {
|
|
||||||
@SerializedName("pack_format")
|
|
||||||
private final int packFormat;
|
|
||||||
|
|
||||||
@SerializedName("description")
|
|
||||||
private final String description;
|
|
||||||
|
|
||||||
public PackInfo() {
|
|
||||||
this(0, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
public PackInfo(int packFormat, String description) {
|
|
||||||
this.packFormat = packFormat;
|
|
||||||
this.description = description;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getPackFormat() {
|
|
||||||
return packFormat;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDescription() {
|
|
||||||
return description;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final String DISABLED_EXT = "disabled";
|
private static final String DISABLED_EXT = "disabled";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* Hello Minecraft! Launcher
|
||||||
|
* Copyright (C) 2019 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.mod;
|
||||||
|
|
||||||
|
import com.google.gson.*;
|
||||||
|
import com.google.gson.annotations.JsonAdapter;
|
||||||
|
import org.jackhuang.hmcl.util.Immutable;
|
||||||
|
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||||
|
import org.jackhuang.hmcl.util.io.CompressingUtils;
|
||||||
|
import org.jackhuang.hmcl.util.io.IOUtils;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.nio.file.FileSystem;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
public final class FabricModMetadata {
|
||||||
|
private final String name;
|
||||||
|
private final String version;
|
||||||
|
private final String description;
|
||||||
|
private final List<FabricModAuthor> authors;
|
||||||
|
private final Map<String, String> contact;
|
||||||
|
|
||||||
|
public FabricModMetadata() {
|
||||||
|
this("", "", "", Collections.emptyList(), Collections.emptyMap());
|
||||||
|
}
|
||||||
|
|
||||||
|
public FabricModMetadata(String name, String version, String description, List<FabricModAuthor> authors, Map<String, String> contact) {
|
||||||
|
this.name = name;
|
||||||
|
this.version = version;
|
||||||
|
this.description = description;
|
||||||
|
this.authors = authors;
|
||||||
|
this.contact = contact;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ModInfo fromFile(ModManager modManager, File modFile) throws IOException, JsonParseException {
|
||||||
|
try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(modFile.toPath())) {
|
||||||
|
Path mcmod = fs.getPath("fabric.mod.json");
|
||||||
|
if (Files.notExists(mcmod))
|
||||||
|
throw new IOException("File " + modFile + " is not a Fabric mod.");
|
||||||
|
FabricModMetadata metadata = JsonUtils.fromNonNullJson(IOUtils.readFullyAsString(Files.newInputStream(mcmod)), FabricModMetadata.class);
|
||||||
|
String authors = metadata.authors == null ? "" : metadata.authors.stream().map(author -> author.name).collect(Collectors.joining(", "));
|
||||||
|
return new ModInfo(modManager, modFile, metadata.name, metadata.description,
|
||||||
|
authors, metadata.version, "", metadata.contact != null ? metadata.contact.getOrDefault("homepage", "") : "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonAdapter(FabricModAuthorSerializer.class)
|
||||||
|
public static final class FabricModAuthor {
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
public FabricModAuthor() {
|
||||||
|
this("");
|
||||||
|
}
|
||||||
|
|
||||||
|
public FabricModAuthor(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class FabricModAuthorSerializer implements JsonSerializer<FabricModAuthor>, JsonDeserializer<FabricModAuthor> {
|
||||||
|
@Override
|
||||||
|
public FabricModAuthor deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
||||||
|
return json.isJsonPrimitive() ? new FabricModAuthor(json.getAsString()) : new FabricModAuthor(json.getAsJsonObject().getAsJsonPrimitive("name").getAsString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JsonElement serialize(FabricModAuthor src, Type typeOfSrc, JsonSerializationContext context) {
|
||||||
|
return src == null ? JsonNull.INSTANCE : new JsonPrimitive(src.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -64,7 +64,12 @@ public final class ModManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return RiftModMetadata.fromFile(this, modFile);
|
return FabricModMetadata.fromFile(this, modFile);
|
||||||
|
} catch (Exception ignore) {
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return PackMcMeta.fromFile(this, modFile);
|
||||||
} catch (Exception ignore) {
|
} catch (Exception ignore) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* Hello Minecraft! Launcher
|
||||||
|
* Copyright (C) 2019 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.mod;
|
||||||
|
|
||||||
|
import com.google.gson.*;
|
||||||
|
import com.google.gson.annotations.JsonAdapter;
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
import org.jackhuang.hmcl.util.Immutable;
|
||||||
|
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||||
|
import org.jackhuang.hmcl.util.gson.Validation;
|
||||||
|
import org.jackhuang.hmcl.util.io.CompressingUtils;
|
||||||
|
import org.jackhuang.hmcl.util.io.IOUtils;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.nio.file.FileSystem;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
public class PackMcMeta implements Validation {
|
||||||
|
|
||||||
|
@SerializedName("pack")
|
||||||
|
private final PackInfo pack;
|
||||||
|
|
||||||
|
public PackMcMeta() {
|
||||||
|
this(new PackInfo());
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackMcMeta(PackInfo packInfo) {
|
||||||
|
this.pack = packInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackInfo getPackInfo() {
|
||||||
|
return pack;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validate() throws JsonParseException {
|
||||||
|
if (pack == null)
|
||||||
|
throw new JsonParseException("pack cannot be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PackInfo {
|
||||||
|
@SerializedName("pack_format")
|
||||||
|
private final int packFormat;
|
||||||
|
|
||||||
|
@SerializedName("description")
|
||||||
|
private final String description;
|
||||||
|
|
||||||
|
public PackInfo() {
|
||||||
|
this(0, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackInfo(int packFormat, String description) {
|
||||||
|
this.packFormat = packFormat;
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPackFormat() {
|
||||||
|
return packFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ModInfo fromFile(ModManager modManager, File modFile) throws IOException, JsonParseException {
|
||||||
|
try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(modFile.toPath())) {
|
||||||
|
Path mcmod = fs.getPath("pack.mcmeta");
|
||||||
|
if (Files.notExists(mcmod))
|
||||||
|
throw new IOException("File " + modFile + " is not a resource pack.");
|
||||||
|
PackMcMeta metadata = JsonUtils.fromNonNullJson(IOUtils.readFullyAsString(Files.newInputStream(mcmod)), PackMcMeta.class);
|
||||||
|
return new ModInfo(modManager, modFile, metadata.pack.description, "", "", "", "", "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
/*
|
|
||||||
* Hello Minecraft! Launcher
|
|
||||||
* Copyright (C) 2019 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.mod;
|
|
||||||
|
|
||||||
import com.google.gson.JsonParseException;
|
|
||||||
|
|
||||||
import org.jackhuang.hmcl.util.Immutable;
|
|
||||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
|
||||||
import org.jackhuang.hmcl.util.io.CompressingUtils;
|
|
||||||
import org.jackhuang.hmcl.util.io.IOUtils;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.FileSystem;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Immutable
|
|
||||||
public final class RiftModMetadata {
|
|
||||||
private final String id;
|
|
||||||
private final String name;
|
|
||||||
private final List<String> authors;
|
|
||||||
|
|
||||||
public RiftModMetadata() {
|
|
||||||
this("", "", Collections.emptyList());
|
|
||||||
}
|
|
||||||
|
|
||||||
public RiftModMetadata(String id, String name, List<String> authors) {
|
|
||||||
this.id = id;
|
|
||||||
this.name = name;
|
|
||||||
this.authors = authors;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getAuthors() {
|
|
||||||
return authors;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ModInfo fromFile(ModManager modManager, File modFile) throws IOException, JsonParseException {
|
|
||||||
try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(modFile.toPath())) {
|
|
||||||
Path mcmod = fs.getPath("riftmod.json");
|
|
||||||
if (Files.notExists(mcmod))
|
|
||||||
throw new IOException("File " + modFile + " is not a Forge mod.");
|
|
||||||
RiftModMetadata metadata = JsonUtils.fromNonNullJson(IOUtils.readFullyAsString(Files.newInputStream(mcmod)), RiftModMetadata.class);
|
|
||||||
String authors = metadata.getAuthors() == null ? "" : String.join(", ", metadata.getAuthors());
|
|
||||||
return new ModInfo(modManager, modFile, metadata.getName(), "",
|
|
||||||
authors, "", "", "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user