fix: support new world / dimension directory structure#4874
fix: support new world / dimension directory structure#4874PierreSchwang wants to merge 7 commits into
Conversation
70d3cb1 to
eac6a4f
Compare
|
@NO-UUID can you verify this resolves your issue? |
while the actual folder p2 is looking for is: /home/minecraft/creative/worlds/buildtest/dimensions/minecraft/world/region server.properties: bukkit.yml |
|
So I guess it would work with just world-container: ./worlds/ but not with level-name=buildtest ? |
|
Actually no, even after changing level-name to world in server.properties, it would still error: and in this case should be |
There was a problem hiding this comment.
Pull request overview
This PR updates PlotSquared’ world file I/O to support Minecraft 26.1’s changed world/dimension directory layout (fixing trim failures like “could not find region folder”), and migrates several code paths from java.io.File to java.nio.file.Path.
Changes:
- Add platform APIs for resolving dimension/world paths (
getWorldContainer,getWorldPath) and update Bukkit implementation. - Update world/region file discovery and deletion to use NIO (
Files.*) and the new directory structure. - Adjust legacy world upload/import/conversion utilities to operate on the new paths.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| Core/src/main/java/com/plotsquared/core/util/WorldUtil.java | Updates region traversal and world download zip creation to use NIO + new layout. |
| Core/src/main/java/com/plotsquared/core/util/RegionManager.java | Updates region file deletion to use Path/Files. |
| Core/src/main/java/com/plotsquared/core/util/CloseShieldOutputStream.java | Adds output stream wrapper to prevent closing an underlying stream. |
| Core/src/main/java/com/plotsquared/core/PlotPlatform.java | Introduces new platform APIs to resolve dimension/world paths. |
| Core/src/main/java/com/plotsquared/core/plot/world/SinglePlotManager.java | Changes single-plot world deletion to NIO. |
| Core/src/main/java/com/plotsquared/core/plot/world/SinglePlotArea.java | Updates single-plot world migration/copy logic to NIO. |
| Core/src/main/java/com/plotsquared/core/command/DebugImportWorlds.java | Updates debug import to walk the world container via NIO. |
| Core/src/main/java/com/plotsquared/core/command/DatabaseCommand.java | Updates single-plot world rename during DB import to Files.move. |
| Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java | Implements the new platform path resolution methods for Bukkit. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| return file; | ||
| private @Nullable Path getDat(final @NonNull String world) { | ||
| Path path; | ||
| if (MinecraftVersion.current().isOlderOrEqualThan(MinecraftVersion.TINY_TAKEOVER)) { |
| public @NonNull Path getWorldContainer(final String namespace) { | ||
| Path root = Bukkit.getWorldContainer().toPath(); | ||
| if (MinecraftVersion.current().isOlderOrEqualThan(MinecraftVersion.TINY_TAKEOVER)) { | ||
| return root.resolve("world").resolve("dimensions").resolve(namespace); | ||
| } | ||
| return root; | ||
| } |
| public @NonNull Path getWorldPath(final String namespace, final String world) { | ||
| Path root = Bukkit.getWorldContainer().toPath(); | ||
| if (MinecraftVersion.current().isOlderOrEqualThan(MinecraftVersion.TINY_TAKEOVER)) { | ||
| return root.resolve("world").resolve("dimensions").resolve(namespace).resolve(world); | ||
| } | ||
| return root.resolve(world); | ||
| } |
| Path path = PlotSquared.platform().getWorldPath(plot.getWorldName()); | ||
| TaskManager.getPlatformImplementation().taskAsync(() -> { | ||
| FileUtils.deleteDirectory(worldFolder); | ||
| try { | ||
| Files.deleteIfExists(path); | ||
| } catch (IOException e) { | ||
| throw new RuntimeException("Failed to delete directory", e); | ||
| } |
| try (Stream<Path> stream = Files.walk(container, 1)) { | ||
| stream.map(path -> new PathWithName(path, path.getFileName().toString())) | ||
| .filter(p -> !this.worldUtil.isWorld(p.name())) | ||
| .filter(p -> PlotId.fromStringOrNull(p.name()) == null) | ||
| .forEach(new ImportAction(player, area, container)); | ||
| } catch (IOException e) { | ||
| LOGGER.error("Failed to import world", e); | ||
| throw new CommandException(StaticCaption.of("<red>World import failed. Check console.</red>")); | ||
| } |
| Path target; | ||
| if (Files.exists(target = this.container.resolve(this.id.toCommaSeparatedString()))) { | ||
| this.id = this.id.getNextId(); | ||
| } | ||
| try { | ||
| Files.move(p.path(), target); | ||
| Objects.requireNonNull(this.area.getPlot(this.id)).setOwner(uuid); | ||
| } catch (IOException ignored) { | ||
| } |
| Path path = regionRoot.resolve(String.format("r.%s.%s.mca", loc.getX(), loc.getZ())); | ||
| LOGGER.info("- Deleting file: {} (max 1024 chunks)", path.getFileName()); | ||
| try { | ||
| Files.deleteIfExists(path); | ||
| } catch (IOException e) { | ||
| throw new RuntimeException("Failed to delete region file", e); | ||
| } | ||
| } | ||
| TaskManager.runTask(whenDone); |
|
No clue how I should get the actual level key by the world name (as those are two co-existing things now???), given I don't have any world reference at many places. The underlying platform world would return a NamespacedKey / Key / whatever API definition exists, but I only have the user inputted name or plot world string, which might not be loaded in bukkit at the point of usage... |
|
Technically there is no need to get the key from the loaded world as it will always be that of the dimension folder names |
Overview
Fixes #4872
Description
MC 26 changed the world /dimension / level folder structure quite drastically, which this PR attempts to implement. Trim works in the latest version. I also updated all other usages of I/O world access. download of world files should also work now (even though it's been deprecated for quite a while).
I've not tested the changes on older versions yet. Feel free to.
Submitter Checklist
@since TODO.