From 618243350e1af1b76c3a191ba8513bf04b8a5e62 Mon Sep 17 00:00:00 2001 From: Glavo Date: Wed, 26 Feb 2025 01:40:36 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=20NBT=20=E6=9F=A5=E7=9C=8B?= =?UTF-8?q?=E5=99=A8=20(#3653)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * update * update * update --- .../hmcl/ui/construct/SpinnerPane.java | 18 ------ .../org/jackhuang/hmcl/ui/main/RootPage.java | 8 +-- .../jackhuang/hmcl/ui/nbt/NBTEditorPage.java | 59 +++++++++++++------ .../jackhuang/hmcl/ui/nbt/NBTFileType.java | 55 +++++++++++++---- .../org/jackhuang/hmcl/ui/nbt/NBTHelper.java | 12 ---- .../org/jackhuang/hmcl/ui/nbt/NBTTagType.java | 20 +++++++ .../jackhuang/hmcl/ui/nbt/NBTTreeView.java | 22 ++++++- 7 files changed, 127 insertions(+), 67 deletions(-) delete mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/ui/nbt/NBTHelper.java diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/SpinnerPane.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/SpinnerPane.java index 2d6ee81f8..c8d0ec920 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/SpinnerPane.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/SpinnerPane.java @@ -157,23 +157,5 @@ public class SpinnerPane extends Control { } } - public interface State {} - - public static class LoadedState implements State {} - - public static class LoadingState implements State {} - - public static class FailedState implements State { - private final String reason; - - public FailedState(String reason) { - this.reason = reason; - } - - public String getReason() { - return reason; - } - } - public static final EventType FAILED_ACTION = new EventType<>(Event.ANY, "FAILED_ACTION"); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/RootPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/RootPage.java index 21301dee7..515b009cc 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/RootPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/RootPage.java @@ -39,7 +39,7 @@ import org.jackhuang.hmcl.ui.decorator.DecoratorAnimatedPage; import org.jackhuang.hmcl.ui.decorator.DecoratorPage; import org.jackhuang.hmcl.ui.download.ModpackInstallWizardProvider; import org.jackhuang.hmcl.ui.nbt.NBTEditorPage; -import org.jackhuang.hmcl.ui.nbt.NBTHelper; +import org.jackhuang.hmcl.ui.nbt.NBTFileType; import org.jackhuang.hmcl.ui.versions.GameAdvancedListItem; import org.jackhuang.hmcl.ui.versions.Versions; import org.jackhuang.hmcl.upgrade.UpdateChecker; @@ -90,16 +90,16 @@ public class RootPage extends DecoratorAnimatedPage implements DecoratorPage { if (mainPage == null) { MainPage mainPage = new MainPage(); FXUtils.applyDragListener(mainPage, - file -> ModpackHelper.isFileModpackByExtension(file) || NBTHelper.isNBTFileByExtension(file), + file -> ModpackHelper.isFileModpackByExtension(file) || NBTFileType.isNBTFileByExtension(file.toPath()), modpacks -> { File file = modpacks.get(0); if (ModpackHelper.isFileModpackByExtension(file)) { Controllers.getDecorator().startWizard( new ModpackInstallWizardProvider(Profiles.getSelectedProfile(), file), i18n("install.modpack")); - } else if (NBTHelper.isNBTFileByExtension(file)) { + } else if (NBTFileType.isNBTFileByExtension(file.toPath())) { try { - Controllers.navigate(new NBTEditorPage(file)); + Controllers.navigate(new NBTEditorPage(file.toPath())); } catch (Throwable e) { LOG.warning("Fail to open nbt file", e); Controllers.dialog(i18n("nbt.open.failed") + "\n\n" + StringUtils.getStackTrace(e), diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/nbt/NBTEditorPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/nbt/NBTEditorPage.java index 3874102d3..74c8a612a 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/nbt/NBTEditorPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/nbt/NBTEditorPage.java @@ -1,3 +1,20 @@ +/* + * Hello Minecraft! Launcher + * Copyright (C) 2025 huangyuhui 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 . + */ package org.jackhuang.hmcl.ui.nbt; import com.jfoenix.controls.JFXButton; @@ -5,33 +22,38 @@ import javafx.beans.property.ReadOnlyObjectProperty; import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.geometry.Insets; import javafx.geometry.Pos; -import javafx.scene.control.ProgressIndicator; import javafx.scene.layout.BorderPane; import javafx.scene.layout.HBox; import org.jackhuang.hmcl.task.Schedulers; +import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.ui.Controllers; import org.jackhuang.hmcl.ui.construct.MessageDialogPane; import org.jackhuang.hmcl.ui.construct.PageCloseEvent; +import org.jackhuang.hmcl.ui.construct.SpinnerPane; import org.jackhuang.hmcl.ui.decorator.DecoratorPage; -import org.jackhuang.hmcl.util.Lang; import org.jackhuang.hmcl.util.StringUtils; import java.io.*; -import java.util.concurrent.CompletableFuture; +import java.nio.file.Path; import static org.jackhuang.hmcl.ui.FXUtils.onEscPressed; import static org.jackhuang.hmcl.util.logging.Logger.LOG; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; -public class NBTEditorPage extends BorderPane implements DecoratorPage { +/** + * @author Glavo + */ +public final class NBTEditorPage extends SpinnerPane implements DecoratorPage { private final ReadOnlyObjectWrapper state; - private final File file; + private final Path file; private final NBTFileType type; - public NBTEditorPage(File file) throws IOException { + private final BorderPane root = new BorderPane(); + + public NBTEditorPage(Path file) throws IOException { getStyleClass().add("gray-background"); - this.state = new ReadOnlyObjectWrapper<>(DecoratorPage.State.fromTitle(i18n("nbt.title", file.getAbsolutePath()))); + this.state = new ReadOnlyObjectWrapper<>(State.fromTitle(i18n("nbt.title", file.toString()))); this.file = file; this.type = NBTFileType.ofFile(file); @@ -39,7 +61,8 @@ public class NBTEditorPage extends BorderPane implements DecoratorPage { throw new IOException("Unknown type of file " + file); } - setCenter(new ProgressIndicator()); + setContent(root); + setLoading(true); HBox actions = new HBox(8); actions.setPadding(new Insets(8)); @@ -65,18 +88,16 @@ public class NBTEditorPage extends BorderPane implements DecoratorPage { actions.getChildren().setAll(saveButton, cancelButton); - CompletableFuture.supplyAsync(Lang.wrap(() -> type.readAsTree(file))) - .thenAcceptAsync(tree -> { - setCenter(new NBTTreeView(tree)); - // setBottom(actions); - }, Schedulers.javafx()) - .handleAsync((result, e) -> { - if (e != null) { - LOG.warning("Fail to open nbt file", e); - Controllers.dialog(i18n("nbt.open.failed") + "\n\n" + StringUtils.getStackTrace(e), null, MessageDialogPane.MessageType.WARNING, cancelButton::fire); + Task.supplyAsync(() -> type.readAsTree(file)) + .whenComplete(Schedulers.javafx(), (result, exception) -> { + if (exception == null) { + setLoading(false); + root.setCenter(new NBTTreeView(result)); + } else { + LOG.warning("Fail to open nbt file", exception); + Controllers.dialog(i18n("nbt.open.failed") + "\n\n" + StringUtils.getStackTrace(exception), null, MessageDialogPane.MessageType.WARNING, cancelButton::fire); } - return null; - }, Schedulers.javafx()); + }).start(); } public void save() throws IOException { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/nbt/NBTFileType.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/nbt/NBTFileType.java index 02dbbb844..bc7f9126e 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/nbt/NBTFileType.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/nbt/NBTFileType.java @@ -1,3 +1,20 @@ +/* + * Hello Minecraft! Launcher + * Copyright (C) 2025 huangyuhui 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 . + */ package org.jackhuang.hmcl.ui.nbt; import com.github.steveice10.opennbt.NBTIO; @@ -9,16 +26,21 @@ import org.apache.commons.compress.utils.BoundedInputStream; import org.jackhuang.hmcl.util.io.FileUtils; import java.io.*; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Arrays; import java.util.zip.GZIPInputStream; import java.util.zip.Inflater; import java.util.zip.InflaterInputStream; +/** + * @author Glavo + */ public enum NBTFileType { COMPRESSED("dat", "dat_old") { @Override - public Tag read(File file) throws IOException { - try (BufferedInputStream fileInputStream = new BufferedInputStream(new FileInputStream(file))) { + public Tag read(Path file) throws IOException { + try (BufferedInputStream fileInputStream = new BufferedInputStream(Files.newInputStream(file))) { fileInputStream.mark(3); byte[] header = new byte[3]; if (fileInputStream.read(header) < 3) { @@ -42,25 +64,28 @@ public enum NBTFileType { }, ANVIL("mca") { @Override - public Tag read(File file) throws IOException { + public Tag read(Path file) throws IOException { return REGION.read(file); } @Override - public NBTTreeView.Item readAsTree(File file) throws IOException { + public NBTTreeView.Item readAsTree(Path file) throws IOException { return REGION.readAsTree(file); } }, REGION("mcr") { @Override - public Tag read(File file) throws IOException { - try (RandomAccessFile r = new RandomAccessFile(file, "r")) { + public Tag read(Path file) throws IOException { + try (RandomAccessFile r = new RandomAccessFile(file.toFile(), "r")) { + ListTag tag = new ListTag(file.getFileName().toString(), CompoundTag.class); + if (r.length() == 0) { + return tag; + } + byte[] header = new byte[4096]; byte[] buffer = new byte[1 * 1024 * 1024]; // The maximum size of each chunk is 1MiB Inflater inflater = new Inflater(); - ListTag tag = new ListTag(file.getName(), CompoundTag.class); - r.readFully(header); for (int i = 0; i < 4096; i += 4) { int offset = ((header[i] & 0xff) << 16) + ((header[i + 1] & 0xff) << 8) + (header[i + 2] & 0xff); @@ -109,7 +134,7 @@ public enum NBTFileType { } @Override - public NBTTreeView.Item readAsTree(File file) throws IOException { + public NBTTreeView.Item readAsTree(Path file) throws IOException { NBTTreeView.Item item = new NBTTreeView.Item(read(file)); for (Tag tag : ((ListTag) item.getValue())) { @@ -135,7 +160,11 @@ public enum NBTFileType { static final NBTFileType[] types = values(); - public static NBTFileType ofFile(File file) { + public static boolean isNBTFileByExtension(Path file) { + return NBTFileType.ofFile(file) != null; + } + + public static NBTFileType ofFile(Path file) { String ext = FileUtils.getExtension(file); for (NBTFileType type : types) { for (String extension : type.extensions) { @@ -153,11 +182,11 @@ public enum NBTFileType { this.extensions = extensions; } - public abstract Tag read(File file) throws IOException; + public abstract Tag read(Path file) throws IOException; - public NBTTreeView.Item readAsTree(File file) throws IOException { + public NBTTreeView.Item readAsTree(Path file) throws IOException { NBTTreeView.Item root = NBTTreeView.buildTree(read(file)); - root.setName(file.getName()); + root.setName(file.getFileName().toString()); return root; } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/nbt/NBTHelper.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/nbt/NBTHelper.java deleted file mode 100644 index 84a533a07..000000000 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/nbt/NBTHelper.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.jackhuang.hmcl.ui.nbt; - -import java.io.File; - -public final class NBTHelper { - private NBTHelper() { - } - - public static boolean isNBTFileByExtension(File file) { - return NBTFileType.ofFile(file) != null; - } -} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/nbt/NBTTagType.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/nbt/NBTTagType.java index 65c4de7b9..f6084a037 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/nbt/NBTTagType.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/nbt/NBTTagType.java @@ -1,3 +1,20 @@ +/* + * Hello Minecraft! Launcher + * Copyright (C) 2025 huangyuhui 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 . + */ package org.jackhuang.hmcl.ui.nbt; import com.github.steveice10.opennbt.tag.builtin.Tag; @@ -6,6 +23,9 @@ import java.util.HashMap; import java.util.Locale; import java.util.Map; +/** + * @author Glavo + */ public enum NBTTagType { BYTE, SHORT, INT, LONG, FLOAT, DOUBLE, BYTE_ARRAY, INT_ARRAY, LONG_ARRAY, diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/nbt/NBTTreeView.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/nbt/NBTTreeView.java index ff61fb57c..86a5594c5 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/nbt/NBTTreeView.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/nbt/NBTTreeView.java @@ -1,3 +1,20 @@ +/* + * Hello Minecraft! Launcher + * Copyright (C) 2025 huangyuhui 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 . + */ package org.jackhuang.hmcl.ui.nbt; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; @@ -14,7 +31,10 @@ import java.util.EnumMap; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; -public class NBTTreeView extends TreeView { +/** + * @author Glavo + */ +public final class NBTTreeView extends TreeView { public NBTTreeView(NBTTreeView.Item tree) { this.setRoot(tree);