feat: show more friendly message if installing mod in InstallerListPage. Closes #996.

This commit is contained in:
huanghongxun 2021-09-20 21:55:07 +08:00
parent ae8600c882
commit b95119bb0e
10 changed files with 63 additions and 36 deletions

View File

@ -346,7 +346,7 @@ install.failed=Version failed to install
install.failed.downloading=Failed to install due to some files not downloaded successfully
install.failed.downloading.detail=Failed to download file: %s
install.failed.downloading.timeout=Timed out while downloading the file: %s
install.failed.install_online=Unable to recognize the provided installer file
install.failed.install_online=Unable to recognize the provided installer file. If you are installing a mod, go to "Mods" page.
install.failed.malformed=The files just downloaded a moment ago is malformed. You may switch to other download provider to resolve this problem.
install.failed.optifine_conflict=Fabric, OptiFine and Forge are installed simultaneously on Minecraft 1.13
install.failed.version_mismatch=The library requires the game version %s, but the actual version is %s.

View File

@ -346,7 +346,7 @@ install.failed=安裝失敗
install.failed.downloading=安裝失敗,部分檔案未能完成下載
install.failed.downloading.detail=未能下載檔案: %s
install.failed.downloading.timeout=下載逾時: %s
install.failed.install_online=無法識別要安裝的軟體
install.failed.install_online=無法識別要安裝的軟體。如果你要安裝 Mod你需要在模組管理頁面安裝模組。
install.failed.malformed=剛才下載的檔案格式損壞。您可以切換到其他下載來源以解決此問題。
install.failed.optifine_conflict=暫不支援 OptiFine 與 Forge 同時安裝在 Minecraft 1.13 上
install.failed.version_mismatch=該軟體需要的遊戲版本為 %s但實際的遊戲版本為 %s。

View File

@ -346,7 +346,7 @@ install.failed=安装失败
install.failed.downloading=安装失败,部分文件未能完成下载
install.failed.downloading.detail=未能下载文件:%s
install.failed.downloading.timeout=下载超时:%s
install.failed.install_online=无法识别要安装的软件
install.failed.install_online=无法识别要安装的软件。如果你要安装 Mod你需要在模组管理页面安装模组。
install.failed.malformed=下载的文件格式损坏。您可以切换到其他下载源来解决此问题。
install.failed.optifine_conflict=暂不支持 OptiFine, Fabric 与 Forge 同时安装在 Minecraft 1.13 及以上版本
install.failed.version_mismatch=该软件需要的游戏版本为 %s但实际的游戏版本为 %s。

View File

@ -64,14 +64,14 @@ public final class FabricModMetadata {
this.contact = contact;
}
public static ModInfo fromFile(ModManager modManager, File modFile) throws IOException, JsonParseException {
public static ModInfo fromFile(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(FileUtils.readText(mcmod), FabricModMetadata.class);
String authors = metadata.authors == null ? "" : metadata.authors.stream().map(author -> author.name).collect(Collectors.joining(", "));
return new ModInfo(modManager, modFile, metadata.id, metadata.name, new ModInfo.Description(metadata.description),
return new ModInfo(modFile, metadata.id, metadata.name, new ModInfo.Description(metadata.description),
authors, metadata.version, "", metadata.contact != null ? metadata.contact.getOrDefault("homepage", "") : "", metadata.icon);
}
}

View File

@ -116,7 +116,7 @@ public final class ForgeNewModMetadata {
}
}
public static ModInfo fromFile(ModManager modManager, File modFile) throws IOException, JsonParseException {
public static ModInfo fromFile(File modFile) throws IOException, JsonParseException {
try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(modFile.toPath())) {
Path modstoml = fs.getPath("META-INF/mods.toml");
if (Files.notExists(modstoml))
@ -135,7 +135,7 @@ public final class ForgeNewModMetadata {
LOG.log(Level.WARNING, "Failed to parse MANIFEST.MF in file " + modFile.getPath());
}
}
return new ModInfo(modManager, modFile, mod.getModId(), mod.getDisplayName(), new ModInfo.Description(mod.getDescription()),
return new ModInfo(modFile, mod.getModId(), mod.getDisplayName(), new ModInfo.Description(mod.getDescription()),
mod.getAuthors(), mod.getVersion().replace("${file.jarVersion}", jarVersion), "",
mod.getDisplayURL(),
metadata.getLogoFile());

View File

@ -120,7 +120,7 @@ public final class ForgeOldModMetadata {
return authors;
}
public static ModInfo fromFile(ModManager modManager, File modFile) throws IOException, JsonParseException {
public static ModInfo fromFile(File modFile) throws IOException, JsonParseException {
try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(modFile.toPath())) {
Path mcmod = fs.getPath("mcmod.info");
if (Files.notExists(mcmod))
@ -138,7 +138,7 @@ public final class ForgeOldModMetadata {
authors = String.join(", ", metadata.getAuthorList());
if (StringUtils.isBlank(authors))
authors = metadata.getCredits();
return new ModInfo(modManager, modFile, metadata.getModId(), metadata.getName(), new ModInfo.Description(metadata.getDescription()),
return new ModInfo(modFile, metadata.getModId(), metadata.getName(), new ModInfo.Description(metadata.getDescription()),
authors, metadata.getVersion(), metadata.getGameVersion(),
StringUtils.isBlank(metadata.getUrl()) ? metadata.getUpdateUrl() : metadata.url,
metadata.getLogoFile());

View File

@ -108,7 +108,7 @@ public final class LiteModMetadata {
return updateURI;
}
public static ModInfo fromFile(ModManager modManager, File modFile) throws IOException, JsonParseException {
public static ModInfo fromFile(File modFile) throws IOException, JsonParseException {
try (ZipFile zipFile = new ZipFile(modFile)) {
ZipEntry entry = zipFile.getEntry("litemod.json");
if (entry == null)
@ -116,7 +116,7 @@ public final class LiteModMetadata {
LiteModMetadata metadata = JsonUtils.GSON.fromJson(IOUtils.readFullyAsString(zipFile.getInputStream(entry)), LiteModMetadata.class);
if (metadata == null)
throw new IOException("Mod " + modFile + " `litemod.json` is malformed.");
return new ModInfo(modManager, modFile, null, metadata.getName(), new ModInfo.Description(metadata.getDescription()), metadata.getAuthor(),
return new ModInfo(modFile, null, metadata.getName(), new ModInfo.Description(metadata.getDescription()), metadata.getAuthor(),
metadata.getVersion(), metadata.getGameVersion(), metadata.getUpdateURI(), "");
}
}

View File

@ -49,11 +49,11 @@ public final class ModInfo implements Comparable<ModInfo> {
private final String logoPath;
private final BooleanProperty activeProperty;
public ModInfo(ModManager modManager, File file, String id, String name, Description description) {
this(modManager, file, id, name, description, "", "", "", "", "");
public ModInfo(File file, String id, String name, Description description) {
this(file, id, name, description, "", "", "", "", "");
}
public ModInfo(ModManager modManager, File file, String id, String name, Description description, String authors, String version, String gameVersion, String url, String logoPath) {
public ModInfo(File file, String id, String name, Description description, String authors, String version, String gameVersion, String url, String logoPath) {
this.file = file.toPath();
this.id = id;
this.name = name;
@ -64,16 +64,16 @@ public final class ModInfo implements Comparable<ModInfo> {
this.url = url;
this.logoPath = logoPath;
activeProperty = new SimpleBooleanProperty(this, "active", !modManager.isDisabled(file)) {
activeProperty = new SimpleBooleanProperty(this, "active", !ModManager.isDisabled(file)) {
@Override
protected void invalidated() {
Path path = ModInfo.this.file.toAbsolutePath();
try {
if (get())
ModInfo.this.file = modManager.enableMod(path);
ModInfo.this.file = ModManager.enableMod(path);
else
ModInfo.this.file = modManager.disableMod(path);
ModInfo.this.file = ModManager.disableMod(path);
} catch (IOException e) {
Logging.LOG.log(Level.SEVERE, "Unable to invert state of mod file " + path, e);
}

View File

@ -19,16 +19,15 @@ package org.jackhuang.hmcl.mod;
import org.jackhuang.hmcl.game.GameRepository;
import org.jackhuang.hmcl.util.StringUtils;
import org.jackhuang.hmcl.util.io.CompressingUtils;
import org.jackhuang.hmcl.util.io.FileUtils;
import org.jackhuang.hmcl.util.versioning.VersionNumber;
import java.io.File;
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.*;
import java.nio.file.*;
import java.util.Collection;
import java.util.TreeSet;
public final class ModManager {
private final GameRepository repository;
@ -61,29 +60,29 @@ public final class ModManager {
}
}
public ModInfo getModInfo(File modFile) {
public static ModInfo getModInfo(File modFile) {
File file = isDisabled(modFile) ? new File(modFile.getAbsoluteFile().getParentFile(), FileUtils.getNameWithoutExtension(modFile)) : modFile;
String description, extension = FileUtils.getExtension(file);
switch (extension) {
case "zip":
case "jar":
try {
return ForgeOldModMetadata.fromFile(this, modFile);
return ForgeOldModMetadata.fromFile(modFile);
} catch (Exception ignore) {
}
try {
return ForgeNewModMetadata.fromFile(this, modFile);
return ForgeNewModMetadata.fromFile(modFile);
} catch (Exception ignore) {
}
try {
return FabricModMetadata.fromFile(this, modFile);
return FabricModMetadata.fromFile(modFile);
} catch (Exception ignore) {
}
try {
return PackMcMeta.fromFile(this, modFile);
return PackMcMeta.fromFile(modFile);
} catch (Exception ignore) {
}
@ -91,7 +90,7 @@ public final class ModManager {
break;
case "litemod":
try {
return LiteModMetadata.fromFile(this, modFile);
return LiteModMetadata.fromFile(modFile);
} catch (Exception ignore) {
description = "LiteLoader Mod";
}
@ -99,7 +98,7 @@ public final class ModManager {
default:
throw new IllegalArgumentException("File " + modFile + " is not a mod file.");
}
return new ModInfo(this, modFile, null, FileUtils.getNameWithoutExtension(modFile), new ModInfo.Description(description));
return new ModInfo(modFile, null, FileUtils.getNameWithoutExtension(modFile), new ModInfo.Description(description));
}
public void refreshMods() throws IOException {
@ -130,7 +129,7 @@ public final class ModManager {
}
public void addMod(File file) throws IOException {
if (!isFileMod(file))
if (!isFileNameMod(file))
throw new IllegalArgumentException("File " + file + " is not a valid mod file.");
if (!loaded)
@ -152,31 +151,59 @@ public final class ModManager {
}
}
public Path disableMod(Path file) throws IOException {
public static Path disableMod(Path file) throws IOException {
Path disabled = file.getParent().resolve(StringUtils.addSuffix(FileUtils.getName(file), DISABLED_EXTENSION));
if (Files.exists(file))
Files.move(file, disabled, StandardCopyOption.REPLACE_EXISTING);
return disabled;
}
public Path enableMod(Path file) throws IOException {
public static Path enableMod(Path file) throws IOException {
Path enabled = file.getParent().resolve(StringUtils.removeSuffix(FileUtils.getName(file), DISABLED_EXTENSION));
if (Files.exists(file))
Files.move(file, enabled, StandardCopyOption.REPLACE_EXISTING);
return enabled;
}
public boolean isDisabled(File file) {
public static boolean isDisabled(File file) {
return file.getPath().endsWith(DISABLED_EXTENSION);
}
public boolean isFileMod(File file) {
public static boolean isFileNameMod(File file) {
String name = file.getName();
if (isDisabled(file))
name = FileUtils.getNameWithoutExtension(file);
return name.endsWith(".zip") || name.endsWith(".jar") || name.endsWith(".litemod");
}
public static boolean isFileMod(Path modFile) {
try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(modFile)) {
if (Files.exists(fs.getPath("mcmod.info")) || Files.exists(fs.getPath("META-INF/mods.toml"))) {
// Forge mod
return true;
}
if (Files.exists(fs.getPath("fabric.mod.json"))) {
// Fabric mod
return true;
}
if (Files.exists(fs.getPath("litemod.json"))) {
// Liteloader mod
return true;
}
if (Files.exists(fs.getPath("pack.mcmeta"))) {
// resource pack, data pack
return true;
}
return false;
} catch (IOException e) {
return false;
}
}
/**
* Check if "mods" directory has mod file named "fileName" no matter the mod is disabled or not
*

View File

@ -144,13 +144,13 @@ public class PackMcMeta implements Validation {
}
}
public static ModInfo fromFile(ModManager modManager, File modFile) throws IOException, JsonParseException {
public static ModInfo fromFile(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(FileUtils.readText(mcmod), PackMcMeta.class);
return new ModInfo(modManager, modFile, null, FileUtils.getNameWithoutExtension(modFile), metadata.pack.description, "", "", "", "", "");
return new ModInfo(modFile, null, FileUtils.getNameWithoutExtension(modFile), metadata.pack.description, "", "", "", "", "");
}
}
}