From b19909945655d8a07b08cf1e837f13b9935cc38b Mon Sep 17 00:00:00 2001 From: mineDiamond Date: Sat, 14 Mar 2026 14:52:51 +0800 Subject: [PATCH 1/2] =?UTF-8?q?refactor:=20Datapack=E9=87=8D=E5=91=BD?= =?UTF-8?q?=E5=90=8D=E4=B8=BADataPack?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ackListPage.java => DataPackListPage.java} | 50 +++++++++---------- ...ageSkin.java => DataPackListPageSkin.java} | 32 ++++++------ .../hmcl/ui/versions/WorldManagePage.java | 10 ++-- .../java/org/jackhuang/hmcl/game/World.java | 2 +- .../hmcl/mod/{Datapack.java => DataPack.java} | 48 +++++++++--------- 5 files changed, 71 insertions(+), 71 deletions(-) rename HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/{DatapackListPage.java => DataPackListPage.java} (73%) rename HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/{DatapackListPageSkin.java => DataPackListPageSkin.java} (94%) rename HMCLCore/src/main/java/org/jackhuang/hmcl/mod/{Datapack.java => DataPack.java} (89%) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DatapackListPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DataPackListPage.java similarity index 73% rename from HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DatapackListPage.java rename to HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DataPackListPage.java index 66745e5ad7..8f619a6ee6 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DatapackListPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DataPackListPage.java @@ -22,7 +22,7 @@ import javafx.scene.control.Skin; import javafx.stage.FileChooser; import org.jackhuang.hmcl.game.World; -import org.jackhuang.hmcl.mod.Datapack; +import org.jackhuang.hmcl.mod.DataPack; import org.jackhuang.hmcl.task.Schedulers; import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.ui.Controllers; @@ -44,45 +44,45 @@ import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import static org.jackhuang.hmcl.util.logging.Logger.LOG; -public final class DatapackListPage extends ListPageBase implements WorldManagePage.WorldRefreshable { +public final class DataPackListPage extends ListPageBase implements WorldManagePage.WorldRefreshable { private final World world; - private final Datapack datapack; + private final DataPack dataPack; final BooleanProperty readOnly; - public DatapackListPage(WorldManagePage worldManagePage) { + public DataPackListPage(WorldManagePage worldManagePage) { world = worldManagePage.getWorld(); - datapack = new Datapack(world.getFile().resolve("datapacks")); - setItems(MappedObservableList.create(datapack.getPacks(), DatapackListPageSkin.DatapackInfoObject::new)); + dataPack = new DataPack(world.getFile().resolve("datapacks")); + setItems(MappedObservableList.create(dataPack.getPacks(), DataPackListPageSkin.DataPackInfoObject::new)); readOnly = worldManagePage.readOnlyProperty(); FXUtils.applyDragListener(this, it -> Objects.equals("zip", FileUtils.getExtension(it)), - this::installMultiDatapack, this::refresh); + this::installMultiDataPack, this::refresh); refresh(); } - private void installMultiDatapack(List datapackPath) { - datapackPath.forEach(this::installSingleDatapack); + private void installMultiDataPack(List dataPackPath) { + dataPackPath.forEach(this::installSingleDataPack); if (readOnly.get()) { Controllers.showToast(i18n("datapack.reload.toast")); } } - private void installSingleDatapack(Path datapack) { + private void installSingleDataPack(Path dataPack) { try { - this.datapack.installPack(datapack, world.getGameVersion()); + this.dataPack.installPack(dataPack, world.getGameVersion()); } catch (IOException | IllegalArgumentException e) { - LOG.warning("Unable to parse datapack file " + datapack, e); + LOG.warning("Unable to parse datapack file " + dataPack, e); } } @Override protected Skin createDefaultSkin() { - return new DatapackListPageSkin(this); + return new DataPackListPageSkin(this); } public void refresh() { setLoading(true); - Task.runAsync(datapack::loadFromDir) + Task.runAsync(dataPack::loadFromDir) .withRunAsync(Schedulers.javafx(), () -> setLoading(false)) .start(); } @@ -94,18 +94,18 @@ public void add() { List res = FileUtils.toPaths(chooser.showOpenMultipleDialog(Controllers.getStage())); if (res != null) { - installMultiDatapack(res); + installMultiDataPack(res); } - datapack.loadFromDir(); + dataPack.loadFromDir(); } - void removeSelected(ObservableList selectedItems) { + void removeSelected(ObservableList selectedItems) { selectedItems.stream() - .map(DatapackListPageSkin.DatapackInfoObject::getPackInfo) + .map(DataPackListPageSkin.DataPackInfoObject::getPackInfo) .forEach(pack -> { try { - datapack.deletePack(pack); + dataPack.deletePack(pack); } catch (IOException e) { // Fail to remove mods if the game is running or the datapack is absent. LOG.warning("Failed to delete datapack \"" + pack.getId() + "\"", e); @@ -113,23 +113,23 @@ void removeSelected(ObservableList sele }); } - void enableSelected(ObservableList selectedItems) { + void enableSelected(ObservableList selectedItems) { selectedItems.stream() - .map(DatapackListPageSkin.DatapackInfoObject::getPackInfo) + .map(DataPackListPageSkin.DataPackInfoObject::getPackInfo) .forEach(pack -> pack.setActive(true)); } - void disableSelected(ObservableList selectedItems) { + void disableSelected(ObservableList selectedItems) { selectedItems.stream() - .map(DatapackListPageSkin.DatapackInfoObject::getPackInfo) + .map(DataPackListPageSkin.DataPackInfoObject::getPackInfo) .forEach(pack -> pack.setActive(false)); } void openDataPackFolder() { - FXUtils.openFolder(datapack.getPath()); + FXUtils.openFolder(dataPack.getPath()); } - @NotNull Predicate updateSearchPredicate(String queryString) { + @NotNull Predicate updateSearchPredicate(String queryString) { if (queryString.isBlank()) { return dataPack -> true; } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DatapackListPageSkin.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DataPackListPageSkin.java similarity index 94% rename from HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DatapackListPageSkin.java rename to HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DataPackListPageSkin.java index 822b16564e..342170f86d 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DatapackListPageSkin.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DataPackListPageSkin.java @@ -42,7 +42,7 @@ import javafx.scene.layout.Priority; import javafx.scene.layout.StackPane; import javafx.util.Duration; -import org.jackhuang.hmcl.mod.Datapack; +import org.jackhuang.hmcl.mod.DataPack; import org.jackhuang.hmcl.task.Schedulers; import org.jackhuang.hmcl.ui.Controllers; import org.jackhuang.hmcl.ui.FXUtils; @@ -67,7 +67,7 @@ import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import static org.jackhuang.hmcl.util.logging.Logger.LOG; -final class DatapackListPageSkin extends SkinBase { +final class DataPackListPageSkin extends SkinBase { private final TransitionPane toolbarPane; private final HBox searchBar; @@ -75,8 +75,8 @@ final class DatapackListPageSkin extends SkinBase { private final HBox selectingToolbar; InvalidationListener updateBarByStateWeakListener; - private final JFXListView listView; - private final FilteredList filteredList; + private final JFXListView listView; + private final FilteredList filteredList; private final BooleanProperty isSearching = new SimpleBooleanProperty(false); private final BooleanProperty isSelecting = new SimpleBooleanProperty(false); @@ -85,7 +85,7 @@ final class DatapackListPageSkin extends SkinBase { private static final AtomicInteger lastShiftClickIndex = new AtomicInteger(-1); final Consumer toggleSelect; - DatapackListPageSkin(DatapackListPage skinnable) { + DataPackListPageSkin(DataPackListPage skinnable) { super(skinnable); StackPane pane = new StackPane(); @@ -181,7 +181,7 @@ final class DatapackListPageSkin extends SkinBase { ComponentList.setVgrow(center, Priority.ALWAYS); center.loadingProperty().bind(skinnable.loadingProperty()); - listView.setCellFactory(x -> new DatapackInfoListCell(listView, getSkinnable().readOnly)); + listView.setCellFactory(x -> new DataPackInfoListCell(listView, getSkinnable().readOnly)); listView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); this.listView.setItems(filteredList); @@ -216,13 +216,13 @@ private void changeToolbar(HBox newToolbar) { } } - static class DatapackInfoObject extends RecursiveTreeObject { + static class DataPackInfoObject extends RecursiveTreeObject { private final BooleanProperty activeProperty; - private final Datapack.Pack packInfo; + private final DataPack.Pack packInfo; private SoftReference> iconCache; - DatapackInfoObject(Datapack.Pack packInfo) { + DataPackInfoObject(DataPack.Pack packInfo) { this.packInfo = packInfo; this.activeProperty = packInfo.activeProperty(); } @@ -235,7 +235,7 @@ String getSubtitle() { return packInfo.getDescription().toString(); } - Datapack.Pack getPackInfo() { + DataPack.Pack getPackInfo() { return packInfo; } @@ -270,7 +270,7 @@ Image loadIcon() { } } - public void loadIcon(ImageContainer imageContainer, @Nullable WeakReference> current) { + public void loadIcon(ImageContainer imageContainer, @Nullable WeakReference> current) { SoftReference> iconCache = this.iconCache; CompletableFuture imageFuture; if (iconCache != null && (imageFuture = iconCache.get()) != null) { @@ -286,7 +286,7 @@ public void loadIcon(ImageContainer imageContainer, @Nullable WeakReference { if (current != null) { - ObjectProperty infoObjectProperty = current.get(); + ObjectProperty infoObjectProperty = current.get(); if (infoObjectProperty == null || infoObjectProperty.get() != this) { // The current ListCell has already switched to another object return; @@ -298,13 +298,13 @@ public void loadIcon(ImageContainer imageContainer, @Nullable WeakReference { + private final class DataPackInfoListCell extends MDListCell { final JFXCheckBox checkBox = new JFXCheckBox(); ImageContainer imageContainer = new ImageContainer(32); final TwoLineListItem content = new TwoLineListItem(); BooleanProperty booleanProperty; - DatapackInfoListCell(JFXListView listView, BooleanProperty isReadOnlyProperty) { + DataPackInfoListCell(JFXListView listView, BooleanProperty isReadOnlyProperty) { super(listView); HBox container = new HBox(8); @@ -326,7 +326,7 @@ private final class DatapackInfoListCell extends MDListCell } @Override - protected void updateControl(DatapackInfoObject dataItem, boolean empty) { + protected void updateControl(DataPackInfoObject dataItem, boolean empty) { if (empty) return; content.setTitle(dataItem.getTitle()); content.setSubtitle(dataItem.getSubtitle()); @@ -338,7 +338,7 @@ protected void updateControl(DatapackInfoObject dataItem, boolean empty) { } } - public void handleSelect(DatapackInfoListCell cell, MouseEvent mouseEvent) { + public void handleSelect(DataPackInfoListCell cell, MouseEvent mouseEvent) { if (cell.isEmpty()) { mouseEvent.consume(); return; diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/WorldManagePage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/WorldManagePage.java index 0e3ada32ba..6b4f2efb80 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/WorldManagePage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/WorldManagePage.java @@ -67,7 +67,7 @@ public final class WorldManagePage extends DecoratorAnimatedPage implements Deco private final TabHeader header = new TabHeader(transitionPane); private final TabHeader.Tab worldInfoTab = new TabHeader.Tab<>("worldInfoPage"); private final TabHeader.Tab worldBackupsTab = new TabHeader.Tab<>("worldBackupsPage"); - private final TabHeader.Tab datapackTab = new TabHeader.Tab<>("datapackListPage"); + private final TabHeader.Tab dataPackTab = new TabHeader.Tab<>("dataPackListPage"); public WorldManagePage(World world, Profile profile, String instanceId) { this.world = world; @@ -86,7 +86,7 @@ public WorldManagePage(World world, Profile profile, String instanceId) { worldInfoTab.setNodeSupplier(() -> new WorldInfoPage(this)); worldBackupsTab.setNodeSupplier(() -> new WorldBackupsPage(this)); - datapackTab.setNodeSupplier(() -> new DatapackListPage(this)); + dataPackTab.setNodeSupplier(() -> new DataPackListPage(this)); this.state = new SimpleObjectProperty<>(new State(i18n("world.manage.title", StringUtils.parseColorEscapes(world.getWorldName())), null, true, true, true)); @@ -218,9 +218,9 @@ private AdvancedListBox getTabBar() { tabBar.addNavigationDrawerTab(getSkinnable().header, getSkinnable().worldInfoTab, i18n("world.info"), SVG.INFO, SVG.INFO_FILL) .addNavigationDrawerTab(getSkinnable().header, getSkinnable().worldBackupsTab, i18n("world.backup"), SVG.ARCHIVE, SVG.ARCHIVE_FILL); - if (getSkinnable().world.supportDatapacks()) { - getSkinnable().header.getTabs().add(getSkinnable().datapackTab); - tabBar.addNavigationDrawerTab(getSkinnable().header, getSkinnable().datapackTab, i18n("world.datapack"), SVG.EXTENSION, SVG.EXTENSION_FILL); + if (getSkinnable().world.supportDataPacks()) { + getSkinnable().header.getTabs().add(getSkinnable().dataPackTab); + tabBar.addNavigationDrawerTab(getSkinnable().header, getSkinnable().dataPackTab, i18n("world.datapack"), SVG.EXTENSION, SVG.EXTENSION_FILL); } } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/World.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/World.java index b3fcb96b33..2904e0204f 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/World.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/World.java @@ -166,7 +166,7 @@ public boolean isLocked() { return isLocked(getSessionLockFile()); } - public boolean supportDatapacks() { + public boolean supportDataPacks() { return getGameVersion() != null && getGameVersion().isAtLeast("1.13", "17w43a"); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/Datapack.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/DataPack.java similarity index 89% rename from HMCLCore/src/main/java/org/jackhuang/hmcl/mod/Datapack.java rename to HMCLCore/src/main/java/org/jackhuang/hmcl/mod/DataPack.java index 3ac488582d..a1ad0a4d1c 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/Datapack.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/DataPack.java @@ -39,14 +39,14 @@ import static org.jackhuang.hmcl.util.logging.Logger.LOG; -public class Datapack { +public class DataPack { private static final String DISABLED_EXT = "disabled"; private static final String ZIP_EXT = "zip"; private final Path path; private final ObservableList packs = FXCollections.observableArrayList(); - public Datapack(Path path) { + public DataPack(Path path) { this.path = path; } @@ -58,14 +58,14 @@ public ObservableList getPacks() { return packs; } - public static void installPack(Path sourceDatapackPath, Path targetDatapackDirectory, GameVersionNumber gameVersionNumber) throws IOException { + public static void installPack(Path sourceDataPackPath, Path targetDataPackDirectory, GameVersionNumber gameVersionNumber) throws IOException { boolean containsMultiplePacks; Set packs = new HashSet<>(); - try (FileSystem fs = CompressingUtils.readonly(sourceDatapackPath).setAutoDetectEncoding(true).build()) { - Path datapacks = fs.getPath("datapacks"); + try (FileSystem fs = CompressingUtils.readonly(sourceDataPackPath).setAutoDetectEncoding(true).build()) { + Path dataPacks = fs.getPath("datapacks"); Path mcmeta = fs.getPath("pack.mcmeta"); - if (Files.exists(datapacks)) { + if (Files.exists(dataPacks)) { containsMultiplePacks = true; } else if (Files.exists(mcmeta)) { containsMultiplePacks = false; @@ -74,14 +74,14 @@ public static void installPack(Path sourceDatapackPath, Path targetDatapackDirec } if (containsMultiplePacks) { - try (Stream s = Files.list(datapacks)) { + try (Stream s = Files.list(dataPacks)) { packs = s.map(FileUtils::getNameWithoutExtension).collect(Collectors.toSet()); } } else { - packs.add(FileUtils.getNameWithoutExtension(sourceDatapackPath)); + packs.add(FileUtils.getNameWithoutExtension(sourceDataPackPath)); } - try (DirectoryStream stream = Files.newDirectoryStream(targetDatapackDirectory)) { + try (DirectoryStream stream = Files.newDirectoryStream(targetDataPackDirectory)) { for (Path dir : stream) { String packName = FileUtils.getName(dir); if (FileUtils.getExtension(dir).equals(DISABLED_EXT)) { @@ -100,9 +100,9 @@ public static void installPack(Path sourceDatapackPath, Path targetDatapackDirec } if (!containsMultiplePacks) { - FileUtils.copyFile(sourceDatapackPath, targetDatapackDirectory.resolve(FileUtils.getName(sourceDatapackPath))); + FileUtils.copyFile(sourceDataPackPath, targetDataPackDirectory.resolve(FileUtils.getName(sourceDataPackPath))); } else { - new Unzipper(sourceDatapackPath, targetDatapackDirectory) + new Unzipper(sourceDataPackPath, targetDataPackDirectory) .setReplaceExistentFile(true) .setSubDirectory("/datapacks/") .unzip(); @@ -113,14 +113,14 @@ public static void installPack(Path sourceDatapackPath, Path targetDatapackDirec && gameVersionNumber.compareTo("26.1-snapshot-6") >= 0; if (useNewResourcePath) { - Files.createDirectories(targetDatapackDirectory.getParent().resolve("resourcepacks")); - targetResourceZipPath = targetDatapackDirectory.getParent().resolve("resourcepacks/resources.zip"); + Files.createDirectories(targetDataPackDirectory.getParent().resolve("resourcepacks")); + targetResourceZipPath = targetDataPackDirectory.getParent().resolve("resourcepacks/resources.zip"); } else { - targetResourceZipPath = targetDatapackDirectory.getParent().resolve("resources.zip"); + targetResourceZipPath = targetDataPackDirectory.getParent().resolve("resources.zip"); } try (FileSystem outputResourcesZipFS = CompressingUtils.createWritableZipFileSystem(targetResourceZipPath); - FileSystem inputPackZipFS = CompressingUtils.createReadOnlyZipFileSystem(sourceDatapackPath)) { + FileSystem inputPackZipFS = CompressingUtils.createReadOnlyZipFileSystem(sourceDataPackPath)) { Path resourcesZip = inputPackZipFS.getPath("resources.zip"); if (Files.isRegularFile(resourcesZip)) { Path tempResourcesFile = Files.createTempFile("hmcl", ".zip"); @@ -229,14 +229,14 @@ private Optional loadSinglePackFromZipFile(Path path) { } } - private Optional parsePack(Path datapackPath, boolean isDirectory, String name, Path mcmetaPath) { + private Optional parsePack(Path dataPackPath, boolean isDirectory, String name, Path mcmetaPath) { try { PackMcMeta mcMeta = JsonUtils.fromNonNullJson(Files.readString(mcmetaPath), PackMcMeta.class); - return Optional.of(new Pack(datapackPath, isDirectory, name, mcMeta.pack().description(), this)); + return Optional.of(new Pack(dataPackPath, isDirectory, name, mcMeta.pack().description(), this)); } catch (JsonParseException e) { - LOG.warning("Invalid pack.mcmeta format in " + datapackPath, e); + LOG.warning("Invalid pack.mcmeta format in " + dataPackPath, e); } catch (IOException e) { - LOG.warning("IO error reading " + datapackPath, e); + LOG.warning("IO error reading " + dataPackPath, e); } return Optional.empty(); } @@ -248,14 +248,14 @@ public static class Pack { private final BooleanProperty activeProperty; private final String id; private final LocalModFile.Description description; - private final Datapack parentDatapack; + private final DataPack parentDataPack; - public Pack(Path path, boolean isDirectory, String id, LocalModFile.Description description, Datapack parentDatapack) { + public Pack(Path path, boolean isDirectory, String id, LocalModFile.Description description, DataPack parentDataPack) { this.path = path; this.isDirectory = isDirectory; this.id = id; this.description = description; - this.parentDatapack = parentDatapack; + this.parentDataPack = parentDataPack; this.statusFile = initializeStatusFile(path, isDirectory); this.activeProperty = initializeActiveProperty(); @@ -313,8 +313,8 @@ public LocalModFile.Description getDescription() { return description; } - public Datapack getParentDatapack() { - return parentDatapack; + public DataPack getParentDataPack() { + return parentDataPack; } public BooleanProperty activeProperty() { From 4dce39c9eada51374e71dff1d2806bd7ed84f351 Mon Sep 17 00:00:00 2001 From: mineDiamond Date: Sat, 14 Mar 2026 15:49:10 +0800 Subject: [PATCH 2/2] =?UTF-8?q?refactor:=20=E4=BF=AE=E6=94=B9=E6=96=87?= =?UTF-8?q?=E6=9C=AC=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/resources/assets/lang/I18N.properties | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/HMCL/src/main/resources/assets/lang/I18N.properties b/HMCL/src/main/resources/assets/lang/I18N.properties index 2aeadb39df..99b0072338 100644 --- a/HMCL/src/main/resources/assets/lang/I18N.properties +++ b/HMCL/src/main/resources/assets/lang/I18N.properties @@ -393,7 +393,7 @@ extension.ps1=Windows PowerShell Script extension.sh=Shell Script extension.command=macOS Shell Script -extension.datapack=Datapack Archive +extension.datapack=Data Pack Archive extension.mod=Mod File extension.modloader.installer=Mod Loader Installer extension.resourcepack=Resource Pack Archive @@ -698,7 +698,7 @@ game.version=Game Instance help=Help help.doc=Hello Minecraft! Launcher Documentation -help.detail=For datapack and modpack makers. +help.detail=For data pack and modpack makers. input.email=The username must be an email address. input.number=The input must be numbers. @@ -984,7 +984,7 @@ modrinth.category.colored-lighting=Colored Lighting modrinth.category.combat=Combat modrinth.category.core-shaders=Core Shaders modrinth.category.cursed=Cursed -modrinth.category.datapack=Datapack +modrinth.category.datapack=Data Pack modrinth.category.decoration=Decoration modrinth.category.economy=Economy modrinth.category.entities=Entities @@ -1127,11 +1127,11 @@ nbt.open.failed=Failed to open file nbt.save.failed=Failed to save file nbt.title=View File - %s -datapack=Datapacks +datapack=Data Packs datapack.add=Add -datapack.add.title=Choose datapack archive you want to add -datapack.reload.toast=Minecraft is running, please use the /reload command to reload the data pack -datapack.title=World [%s] - Datapacks +datapack.add.title=Choose data pack archive you want to add +datapack.reload.toast=Minecraft is running. Use /reload command to reload data packs +datapack.title=World [%s] - Data Packs web.failed=Failed to load page web.open_in_browser=Do you want to open this address in a browser:\n%s @@ -1161,7 +1161,7 @@ world.duplicate.failed.empty_name=Name cannot be empty world.duplicate.failed.invalid_name=Name contains invalid characters world.duplicate.failed=Failed to duplicate the world world.duplicate.success.toast=Successfully duplicated the world -world.datapack=Datapacks +world.datapack=Data Packs world.datetime=Last played on %s world.delete=Delete the World world.delete.failed=Failed to delete world.\n%s