From 2feca025cfcbf786591b7650eed3f729f94ae94a Mon Sep 17 00:00:00 2001 From: david Date: Thu, 15 Aug 2024 21:08:57 +0200 Subject: [PATCH 01/13] Refactor world persistence logic and add generator support Refactored the existing world persistence functions by splitting them into separate methods. Introduced a new `persistStatus` method for handling enabled status with an optional force parameter. Added `persistGenerator` method to handle saving of world generator details. --- .../net/thenextlvl/worlds/WorldsPlugin.java | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/plugin/src/main/java/net/thenextlvl/worlds/WorldsPlugin.java b/plugin/src/main/java/net/thenextlvl/worlds/WorldsPlugin.java index a408e7c..d90cce6 100644 --- a/plugin/src/main/java/net/thenextlvl/worlds/WorldsPlugin.java +++ b/plugin/src/main/java/net/thenextlvl/worlds/WorldsPlugin.java @@ -10,6 +10,7 @@ import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; import net.thenextlvl.worlds.api.WorldsProvider; import net.thenextlvl.worlds.api.link.LinkController; +import net.thenextlvl.worlds.api.model.Generator; import net.thenextlvl.worlds.api.preset.Presets; import net.thenextlvl.worlds.api.view.GeneratorView; import net.thenextlvl.worlds.api.view.LevelView; @@ -85,10 +86,20 @@ private void unloadWorlds() { } public void persistWorld(World world, boolean enabled) { - if (world.key().asString().equals("minecraft:overworld")) return; - var container = world.getPersistentDataContainer(); - container.set(new NamespacedKey("worlds", "world_key"), STRING, world.getKey().asString()); - container.set(new NamespacedKey("worlds", "enabled"), BOOLEAN, enabled); + var worldKey = new NamespacedKey("worlds", "world_key"); + world.getPersistentDataContainer().set(worldKey, STRING, world.getKey().asString()); + persistStatus(world, enabled, true); + } + + public void persistStatus(World world, boolean enabled, boolean force) { + var enabledKey = new NamespacedKey("worlds", "enabled"); + if (!force && !world.getPersistentDataContainer().has(enabledKey)) return; + world.getPersistentDataContainer().set(enabledKey, BOOLEAN, enabled); + } + + public void persistGenerator(World world, Generator generator) { + var generatorKey = new NamespacedKey("worlds", "generator"); + world.getPersistentDataContainer().set(generatorKey, STRING, generator.serialize()); } private void registerServices() { From f94c167b29b8259c31862331dd61ce5a537f56d9 Mon Sep 17 00:00:00 2001 From: david Date: Thu, 15 Aug 2024 21:09:35 +0200 Subject: [PATCH 02/13] Refactor loadLevel conditional logic Replace map with filter to correctly check if LevelExtras are enabled. This change ensures that only enabled extras are considered when loading a level, improving accuracy and clarity in the logic. --- .../main/java/net/thenextlvl/worlds/view/PaperLevelView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/src/main/java/net/thenextlvl/worlds/view/PaperLevelView.java b/plugin/src/main/java/net/thenextlvl/worlds/view/PaperLevelView.java index 8152fa3..25be6a1 100644 --- a/plugin/src/main/java/net/thenextlvl/worlds/view/PaperLevelView.java +++ b/plugin/src/main/java/net/thenextlvl/worlds/view/PaperLevelView.java @@ -84,7 +84,7 @@ public World.Environment getEnvironment(File level) { @Override public @Nullable World loadLevel(File level, World.Environment environment) { - return loadLevel(level, environment, extras -> extras.map(LevelExtras::enabled).isPresent()); + return loadLevel(level, environment, extras -> extras.filter(LevelExtras::enabled).isPresent()); } @Override From 80ae89055fd711f398b47012605229d38b1c7b6a Mon Sep 17 00:00:00 2001 From: david Date: Thu, 15 Aug 2024 21:10:12 +0200 Subject: [PATCH 03/13] Add generator support in level creation Enhanced world creation by incorporating generator configurations and extras. Adjusted `GeneratorArgument` to utilize `Generator.deserialize` for streamlined handling. Also included a method to fetch generator plugin names. --- .../command/argument/GeneratorArgument.java | 20 ++++------------ .../worlds/view/PaperLevelView.java | 24 +++++++++++++++++-- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/plugin/src/main/java/net/thenextlvl/worlds/command/argument/GeneratorArgument.java b/plugin/src/main/java/net/thenextlvl/worlds/command/argument/GeneratorArgument.java index 923fe26..b0981dd 100644 --- a/plugin/src/main/java/net/thenextlvl/worlds/command/argument/GeneratorArgument.java +++ b/plugin/src/main/java/net/thenextlvl/worlds/command/argument/GeneratorArgument.java @@ -1,25 +1,15 @@ package net.thenextlvl.worlds.command.argument; -import com.google.common.base.Preconditions; import com.mojang.brigadier.arguments.StringArgumentType; import core.paper.command.WrappedArgumentType; import net.thenextlvl.worlds.WorldsPlugin; +import net.thenextlvl.worlds.api.model.Generator; import net.thenextlvl.worlds.command.suggestion.GeneratorSuggestionProvider; -import org.bukkit.plugin.Plugin; -import org.jetbrains.annotations.Nullable; -public class GeneratorArgument extends WrappedArgumentType { +public class GeneratorArgument extends WrappedArgumentType { public GeneratorArgument(WorldsPlugin plugin) { - super(StringArgumentType.string(), (reader, type) -> { - var split = type.split(":", 2); - var generator = plugin.getServer().getPluginManager().getPlugin(split[0]); - Preconditions.checkNotNull(generator, "Unknown plugin"); - Preconditions.checkState(generator.isEnabled(), "Plugin is not enabled"); - Preconditions.checkState(plugin.generatorView().hasGenerator(generator), "Plugin has no generator"); - return new Generator(generator, split.length > 1 ? split[1] : null); - }, new GeneratorSuggestionProvider(plugin)); - } - - public record Generator(Plugin plugin, @Nullable String id) { + super(StringArgumentType.string(), (reader, type) -> + Generator.deserialize(plugin, type), + new GeneratorSuggestionProvider(plugin)); } } diff --git a/plugin/src/main/java/net/thenextlvl/worlds/view/PaperLevelView.java b/plugin/src/main/java/net/thenextlvl/worlds/view/PaperLevelView.java index 25be6a1..a8a1795 100644 --- a/plugin/src/main/java/net/thenextlvl/worlds/view/PaperLevelView.java +++ b/plugin/src/main/java/net/thenextlvl/worlds/view/PaperLevelView.java @@ -4,8 +4,10 @@ import core.io.PathIO; import core.nbt.file.NBTFile; import core.nbt.tag.*; +import io.papermc.paper.plugin.provider.classloader.ConfiguredPluginClassLoader; import lombok.RequiredArgsConstructor; import net.thenextlvl.worlds.WorldsPlugin; +import net.thenextlvl.worlds.api.model.Generator; import net.thenextlvl.worlds.api.model.LevelExtras; import net.thenextlvl.worlds.api.model.WorldPreset; import net.thenextlvl.worlds.api.preset.Biome; @@ -141,6 +143,10 @@ public World.Environment getEnvironment(File level) { generatorSettings.ifPresent(preset -> creator.generatorSettings(preset.serialize().toString())); + var generatorExtras = extras.map(LevelExtras::generator); + generatorExtras.map(gen -> gen.biomeProvider(creator.name())).ifPresent(creator::biomeProvider); + generatorExtras.map(gen -> gen.generator(creator.name())).ifPresent(creator::generator); + return creator.createWorld(); } @@ -160,10 +166,14 @@ public Optional getExtras(CompoundTag data) { .map(Tag::getAsString) .map(NamespacedKey::fromString) .orElse(null); + var generator = values.optional("worlds:generator") + .map(Tag::getAsString) + .map(serialized -> Generator.deserialize(plugin, serialized)) + .orElse(null); var enabled = values.optional("worlds:enabled") .map(Tag::getAsBoolean) - .orElse(true); - return new LevelExtras(key, enabled); + .orElse(false); + return new LevelExtras(key, generator, enabled); }); } @@ -210,6 +220,16 @@ public Optional getFlatPreset(CompoundTag generator) { return Optional.of(preset); } + @Override + @SuppressWarnings("UnstableApiUsage") + public Optional getGenerator(World world) { + if (world.getGenerator() == null) return Optional.empty(); + var loader = world.getGenerator().getClass().getClassLoader(); + if (!(loader instanceof ConfiguredPluginClassLoader pluginLoader)) return Optional.empty(); + if (pluginLoader.getPlugin() == null) return Optional.empty(); + return Optional.of(pluginLoader.getPlugin().getName()); + } + @Override public NBTFile getLevelDataFile(File level) { return new NBTFile<>(Optional.of( From e7dcc4bd811ee14a80272eacc5fb0bde58213a0c Mon Sep 17 00:00:00 2001 From: david Date: Thu, 15 Aug 2024 21:10:37 +0200 Subject: [PATCH 04/13] Remove error log for level load failure The error log statement for a failed level load has been removed. This change prevents redundant error logging as exceptions will still capture and log any issues that arise during the process. --- .../main/java/net/thenextlvl/worlds/listener/ServerListener.java | 1 - 1 file changed, 1 deletion(-) diff --git a/plugin/src/main/java/net/thenextlvl/worlds/listener/ServerListener.java b/plugin/src/main/java/net/thenextlvl/worlds/listener/ServerListener.java index 4c7a3cb..67ce8d9 100644 --- a/plugin/src/main/java/net/thenextlvl/worlds/listener/ServerListener.java +++ b/plugin/src/main/java/net/thenextlvl/worlds/listener/ServerListener.java @@ -21,7 +21,6 @@ public void onWorldLoad(WorldLoadEvent event) { var world = plugin.levelView().loadLevel(level); if (world != null) plugin.getComponentLogger().debug("Loaded dimension {} at {}", world.key().asString(), level.getPath()); - else plugin.getComponentLogger().error("Failed to load the level {}", level.getPath()); } catch (Exception e) { plugin.getComponentLogger().error("An unexpected error occurred while loading the level {}", level.getPath(), e); From 5085f594c5d75e49836b54705517d429ae36d7b4 Mon Sep 17 00:00:00 2001 From: david Date: Thu, 15 Aug 2024 21:10:58 +0200 Subject: [PATCH 05/13] Refactor command and persistence handling in WorldUnloadCommand Updated the persistence method to use 'persistStatus' instead of 'persistWorld' to improve code clarity and functionality. Additionally, commented out an unused code block in the 'fallback' argument to streamline the command structure. --- .../net/thenextlvl/worlds/command/WorldUnloadCommand.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugin/src/main/java/net/thenextlvl/worlds/command/WorldUnloadCommand.java b/plugin/src/main/java/net/thenextlvl/worlds/command/WorldUnloadCommand.java index 1cf16c4..45891e6 100644 --- a/plugin/src/main/java/net/thenextlvl/worlds/command/WorldUnloadCommand.java +++ b/plugin/src/main/java/net/thenextlvl/worlds/command/WorldUnloadCommand.java @@ -23,7 +23,8 @@ class WorldUnloadCommand { .then(Commands.argument("world", ArgumentTypes.world()) .suggests(new WorldSuggestionProvider<>(plugin)) .then(Commands.argument("fallback", ArgumentTypes.world()) - .suggests(new WorldSuggestionProvider<>(plugin)) + .suggests(new WorldSuggestionProvider<>(plugin)) //, (context, world) -> + //!world.equals(context.getArgument("world", World.class)))) .executes(context -> { var world = context.getArgument("world", World.class); var fallback = context.getArgument("fallback", World.class); @@ -50,7 +51,7 @@ private String unload(World world, @Nullable World fallback) { : plugin.getServer().getWorlds().getFirst().getSpawnLocation(); world.getPlayers().forEach(player -> player.teleport(fallbackSpawn)); - plugin.persistWorld(world, false); + plugin.persistStatus(world, false, false); var dragonBattle = world.getEnderDragonBattle(); if (dragonBattle != null) dragonBattle.getBossBar().removeAll(); From afb1891ae03a82c9f0149b26a5d56c1df736dfbb Mon Sep 17 00:00:00 2001 From: david Date: Thu, 15 Aug 2024 21:11:35 +0200 Subject: [PATCH 06/13] Add world creation using WorldCreator in regeneration Replace manual level loading with WorldCreator to handle world generation more consistently. This change ensures that the world generator settings are copied and applied during the world regeneration process. --- .../thenextlvl/worlds/command/WorldRegenerateCommand.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/plugin/src/main/java/net/thenextlvl/worlds/command/WorldRegenerateCommand.java b/plugin/src/main/java/net/thenextlvl/worlds/command/WorldRegenerateCommand.java index c8cf99e..0f1c7d4 100644 --- a/plugin/src/main/java/net/thenextlvl/worlds/command/WorldRegenerateCommand.java +++ b/plugin/src/main/java/net/thenextlvl/worlds/command/WorldRegenerateCommand.java @@ -12,6 +12,7 @@ import net.thenextlvl.worlds.command.argument.CommandFlagsArgument; import net.thenextlvl.worlds.command.suggestion.WorldSuggestionProvider; import org.bukkit.World; +import org.bukkit.WorldCreator; import java.io.File; import java.util.Set; @@ -71,15 +72,17 @@ private String regenerateNow(World world) { var fallback = plugin.getServer().getWorlds().getFirst().getSpawnLocation(); players.forEach(player -> player.teleport(fallback, COMMAND)); - plugin.persistWorld(world, true); plugin.levelView().saveLevelData(world, false); + var creator = new WorldCreator(world.getName(), world.getKey()).copy(world); + plugin.levelView().getGenerator(world).ifPresent(creator::generator); + if (!plugin.getServer().unloadWorld(world, false)) return "world.unload.failed"; regenerate(worldFolder); - var regenerated = plugin.levelView().loadLevel(worldFolder, environment); + var regenerated = creator.createWorld(); if (regenerated != null) players.forEach(player -> player.teleportAsync(regenerated.getSpawnLocation(), COMMAND)); return regenerated != null ? "world.regenerate.success" : "world.regenerate.failed"; From 105fd1dbb496d52428c352c96589fb413a31531d Mon Sep 17 00:00:00 2001 From: david Date: Thu, 15 Aug 2024 21:14:27 +0200 Subject: [PATCH 07/13] Update WorldSuggestionProvider to accept BiPredicate Refactored WorldSuggestionProvider to use BiPredicate, enabling more context-aware filtering logic. Updated WorldLinkRemoveCommand and WorldLinkCreateCommand to pass command context to suggestion filtering mechanics. --- .../thenextlvl/worlds/command/WorldLinkCreateCommand.java | 4 ++-- .../thenextlvl/worlds/command/WorldLinkRemoveCommand.java | 2 +- .../worlds/command/suggestion/WorldSuggestionProvider.java | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/plugin/src/main/java/net/thenextlvl/worlds/command/WorldLinkCreateCommand.java b/plugin/src/main/java/net/thenextlvl/worlds/command/WorldLinkCreateCommand.java index 7cbd246..627dd5d 100644 --- a/plugin/src/main/java/net/thenextlvl/worlds/command/WorldLinkCreateCommand.java +++ b/plugin/src/main/java/net/thenextlvl/worlds/command/WorldLinkCreateCommand.java @@ -20,10 +20,10 @@ public class WorldLinkCreateCommand { return Commands.literal("create") .requires(source -> source.getSender().hasPermission("worlds.command.link.create")) .then(Commands.argument("source", ArgumentTypes.world()) - .suggests(new WorldSuggestionProvider<>(plugin, world -> + .suggests(new WorldSuggestionProvider<>(plugin, (context, world) -> world.getEnvironment().equals(World.Environment.NORMAL))) .then(Commands.argument("destination", ArgumentTypes.world()) - .suggests(new WorldSuggestionProvider<>(plugin, world -> + .suggests(new WorldSuggestionProvider<>(plugin, (context, world) -> !world.getEnvironment().equals(World.Environment.NORMAL))) .executes(context -> { var source = context.getArgument("source", World.class); diff --git a/plugin/src/main/java/net/thenextlvl/worlds/command/WorldLinkRemoveCommand.java b/plugin/src/main/java/net/thenextlvl/worlds/command/WorldLinkRemoveCommand.java index 16e8253..b70fbf6 100644 --- a/plugin/src/main/java/net/thenextlvl/worlds/command/WorldLinkRemoveCommand.java +++ b/plugin/src/main/java/net/thenextlvl/worlds/command/WorldLinkRemoveCommand.java @@ -22,7 +22,7 @@ public class WorldLinkRemoveCommand { return Commands.literal("remove") .requires(source -> source.getSender().hasPermission("worlds.command.link.remove")) .then(Commands.argument("world", ArgumentTypes.world()) - .suggests(new WorldSuggestionProvider<>(plugin, world -> + .suggests(new WorldSuggestionProvider<>(plugin, (context, world) -> world.getEnvironment().equals(World.Environment.NORMAL))) .then(Commands.argument("relative", new RelativeArgument(relative -> !relative.equals(Relative.OVERWORLD))) diff --git a/plugin/src/main/java/net/thenextlvl/worlds/command/suggestion/WorldSuggestionProvider.java b/plugin/src/main/java/net/thenextlvl/worlds/command/suggestion/WorldSuggestionProvider.java index 5f08f9e..3854ace 100644 --- a/plugin/src/main/java/net/thenextlvl/worlds/command/suggestion/WorldSuggestionProvider.java +++ b/plugin/src/main/java/net/thenextlvl/worlds/command/suggestion/WorldSuggestionProvider.java @@ -12,18 +12,18 @@ import org.bukkit.plugin.Plugin; import java.util.concurrent.CompletableFuture; -import java.util.function.Predicate; +import java.util.function.BiPredicate; @AllArgsConstructor @RequiredArgsConstructor public class WorldSuggestionProvider implements SuggestionProvider { private final Plugin plugin; - private Predicate filter = world -> true; + private BiPredicate, World> filter = (context, world) -> true; @Override public CompletableFuture getSuggestions(CommandContext context, SuggestionsBuilder builder) { plugin.getServer().getWorlds().stream() - .filter(filter) + .filter(world -> filter.test(context, world)) .map(Keyed::key) .map(Key::asString) .filter(s -> s.contains(builder.getRemaining())) From d7c08baa8cc499de04dd5af2f3ddcd8fbcecc6fc Mon Sep 17 00:00:00 2001 From: david Date: Thu, 15 Aug 2024 21:14:48 +0200 Subject: [PATCH 08/13] Add Generator model and update LevelView and LevelExtras Introduce a new Generator model to handle serialization and deserialization of generators. Updated LevelView with a new getGenerator method and modified LevelExtras to include a generator field. --- .../worlds/api/model/Generator.java | 31 +++++++++++++++++++ .../worlds/api/model/LevelExtras.java | 2 ++ .../thenextlvl/worlds/api/view/LevelView.java | 2 ++ 3 files changed, 35 insertions(+) create mode 100644 api/src/main/java/net/thenextlvl/worlds/api/model/Generator.java diff --git a/api/src/main/java/net/thenextlvl/worlds/api/model/Generator.java b/api/src/main/java/net/thenextlvl/worlds/api/model/Generator.java new file mode 100644 index 0000000..cfe1b44 --- /dev/null +++ b/api/src/main/java/net/thenextlvl/worlds/api/model/Generator.java @@ -0,0 +1,31 @@ +package net.thenextlvl.worlds.api.model; + +import com.google.common.base.Preconditions; +import net.thenextlvl.worlds.api.WorldsProvider; +import org.bukkit.generator.BiomeProvider; +import org.bukkit.generator.ChunkGenerator; +import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.Nullable; + +public record Generator(Plugin plugin, @Nullable String id) { + public String serialize() { + return id != null ? plugin.getName() + ":" + id : plugin.getName(); + } + + public static Generator deserialize(WorldsProvider provider, String serialized) { + var split = serialized.split(":", 2); + var generator = provider.getServer().getPluginManager().getPlugin(split[0]); + Preconditions.checkNotNull(generator, "Unknown plugin"); + Preconditions.checkState(generator.isEnabled(), "Plugin is not enabled"); + Preconditions.checkState(provider.generatorView().hasGenerator(generator), "Plugin has no generator"); + return new Generator(generator, split.length > 1 ? split[1] : null); + } + + public @Nullable ChunkGenerator generator(String worldName) { + return plugin().getDefaultWorldGenerator(worldName, id()); + } + + public @Nullable BiomeProvider biomeProvider(String worldName) { + return plugin().getDefaultBiomeProvider(worldName, id()); + } +} diff --git a/api/src/main/java/net/thenextlvl/worlds/api/model/LevelExtras.java b/api/src/main/java/net/thenextlvl/worlds/api/model/LevelExtras.java index 4af0c73..65eacb3 100644 --- a/api/src/main/java/net/thenextlvl/worlds/api/model/LevelExtras.java +++ b/api/src/main/java/net/thenextlvl/worlds/api/model/LevelExtras.java @@ -1,10 +1,12 @@ package net.thenextlvl.worlds.api.model; +import net.thenextlvl.worlds.api.view.GeneratorView; import org.bukkit.NamespacedKey; import org.jetbrains.annotations.Nullable; public record LevelExtras( @Nullable NamespacedKey key, + @Nullable Generator generator, boolean enabled ) { } diff --git a/api/src/main/java/net/thenextlvl/worlds/api/view/LevelView.java b/api/src/main/java/net/thenextlvl/worlds/api/view/LevelView.java index b5696b5..fa1f618 100644 --- a/api/src/main/java/net/thenextlvl/worlds/api/view/LevelView.java +++ b/api/src/main/java/net/thenextlvl/worlds/api/view/LevelView.java @@ -33,6 +33,8 @@ public interface LevelView { Optional getFlatPreset(CompoundTag generator); + Optional getGenerator(World world); + Optional getGeneratorSettings(CompoundTag generator); Optional getGeneratorType(CompoundTag generator); From cb57eb99a934e02f9dfac7ca4b8a0dd4f2eeaf1d Mon Sep 17 00:00:00 2001 From: david Date: Thu, 15 Aug 2024 21:15:01 +0200 Subject: [PATCH 09/13] Extend WorldsProvider interface with Plugin The WorldsProvider interface now extends the Plugin interface. This change ensures that WorldsProvider inherits methods from Plugin, enhancing functionality and integration within the Bukkit plugin ecosystem. --- .../main/java/net/thenextlvl/worlds/api/WorldsProvider.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/net/thenextlvl/worlds/api/WorldsProvider.java b/api/src/main/java/net/thenextlvl/worlds/api/WorldsProvider.java index d712ca8..aaf840a 100644 --- a/api/src/main/java/net/thenextlvl/worlds/api/WorldsProvider.java +++ b/api/src/main/java/net/thenextlvl/worlds/api/WorldsProvider.java @@ -3,8 +3,9 @@ import net.thenextlvl.worlds.api.link.LinkController; import net.thenextlvl.worlds.api.view.GeneratorView; import net.thenextlvl.worlds.api.view.LevelView; +import org.bukkit.plugin.Plugin; -public interface WorldsProvider { +public interface WorldsProvider extends Plugin { GeneratorView generatorView(); LevelView levelView(); From 4f0d112b76194315f51065e3da3bc0f2535b78c5 Mon Sep 17 00:00:00 2001 From: david Date: Thu, 15 Aug 2024 21:16:34 +0200 Subject: [PATCH 10/13] Refactor generator handling in World commands Replace custom generator handling with plugin's levelView API in WorldInfoCommand. Introduce direct usage of Generator class in WorldCreateCommand and ensure generators are persisted correctly. --- .../thenextlvl/worlds/command/WorldCreateCommand.java | 6 ++++-- .../thenextlvl/worlds/command/WorldInfoCommand.java | 11 +---------- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/plugin/src/main/java/net/thenextlvl/worlds/command/WorldCreateCommand.java b/plugin/src/main/java/net/thenextlvl/worlds/command/WorldCreateCommand.java index 6a262d6..b7488e7 100644 --- a/plugin/src/main/java/net/thenextlvl/worlds/command/WorldCreateCommand.java +++ b/plugin/src/main/java/net/thenextlvl/worlds/command/WorldCreateCommand.java @@ -11,6 +11,7 @@ import lombok.RequiredArgsConstructor; import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; import net.thenextlvl.worlds.WorldsPlugin; +import net.thenextlvl.worlds.api.model.Generator; import net.thenextlvl.worlds.api.preset.Preset; import net.thenextlvl.worlds.command.argument.*; import org.bukkit.NamespacedKey; @@ -75,7 +76,7 @@ private RequiredArgumentBuilder tree(Crea } private int create(CommandContext context, World.Environment environment, boolean structures, - long seed, WorldType worldType, @Nullable Preset preset, @Nullable GeneratorArgument.Generator generator) { + long seed, WorldType worldType, @Nullable Preset preset, @Nullable Generator generator) { var key = context.getArgument("key", NamespacedKey.class); var name = key.getKey(); var creator = new WorldCreator(name, key) @@ -104,6 +105,7 @@ private int create(CommandContext context, World.Environment if (world != null) { plugin.persistWorld(world, true); + if (generator != null) plugin.persistGenerator(world, generator); plugin.levelView().saveLevelData(world, true); } @@ -111,7 +113,7 @@ private int create(CommandContext context, World.Environment } private int createGenerator(CommandContext context, World.Environment environment, boolean structures, long seed) { - var generator = context.getArgument("generator", GeneratorArgument.Generator.class); + var generator = context.getArgument("generator", Generator.class); return create(context, environment, structures, seed, WorldType.NORMAL, null, generator); } diff --git a/plugin/src/main/java/net/thenextlvl/worlds/command/WorldInfoCommand.java b/plugin/src/main/java/net/thenextlvl/worlds/command/WorldInfoCommand.java index 951d12e..5ec9e21 100644 --- a/plugin/src/main/java/net/thenextlvl/worlds/command/WorldInfoCommand.java +++ b/plugin/src/main/java/net/thenextlvl/worlds/command/WorldInfoCommand.java @@ -6,7 +6,6 @@ import io.papermc.paper.command.brigadier.CommandSourceStack; import io.papermc.paper.command.brigadier.Commands; import io.papermc.paper.command.brigadier.argument.ArgumentTypes; -import io.papermc.paper.plugin.provider.classloader.ConfiguredPluginClassLoader; import lombok.RequiredArgsConstructor; import net.kyori.adventure.key.Key; import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; @@ -67,18 +66,10 @@ private int list(CommandSender sender, World world) { .orElse(WorldType.NORMAL).getName().toLowerCase())); plugin.bundle().sendMessage(sender, "world.info.dimension", Placeholder.parsed("dimension", environment.orElse("unknown"))); - getGenerator(world).ifPresent(gen -> plugin.bundle().sendMessage(sender, + plugin.levelView().getGenerator(world).ifPresent(gen -> plugin.bundle().sendMessage(sender, "world.info.generator", Placeholder.parsed("generator", gen))); plugin.bundle().sendMessage(sender, "world.info.seed", Placeholder.parsed("seed", String.valueOf(world.getSeed()))); return Command.SINGLE_SUCCESS; } - - private Optional getGenerator(World world) { - if (world.getGenerator() == null) return Optional.empty(); - var loader = world.getGenerator().getClass().getClassLoader(); - if (!(loader instanceof ConfiguredPluginClassLoader pluginLoader)) return Optional.empty(); - if (pluginLoader.getPlugin() == null) return Optional.empty(); - return Optional.of(pluginLoader.getPlugin().getName()); - } } From 91a13ec5f78f0718612e1f6fbc1e69f52a1474b7 Mon Sep 17 00:00:00 2001 From: david Date: Thu, 15 Aug 2024 21:49:13 +0200 Subject: [PATCH 11/13] Refactor PaperLevelView mapping to handle empty optionals Remove redundant orElse calls and streamline the mapping process by directly handling empty optionals. This enhancement ensures that null values are only applied if all optional fields are empty, improving code readability and efficiency. --- .../net/thenextlvl/worlds/view/PaperLevelView.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/plugin/src/main/java/net/thenextlvl/worlds/view/PaperLevelView.java b/plugin/src/main/java/net/thenextlvl/worlds/view/PaperLevelView.java index a8a1795..e4185a9 100644 --- a/plugin/src/main/java/net/thenextlvl/worlds/view/PaperLevelView.java +++ b/plugin/src/main/java/net/thenextlvl/worlds/view/PaperLevelView.java @@ -164,16 +164,14 @@ public Optional getExtras(CompoundTag data) { .map(values -> { var key = values.optional("worlds:world_key") .map(Tag::getAsString) - .map(NamespacedKey::fromString) - .orElse(null); + .map(NamespacedKey::fromString); var generator = values.optional("worlds:generator") .map(Tag::getAsString) - .map(serialized -> Generator.deserialize(plugin, serialized)) - .orElse(null); + .map(serialized -> Generator.deserialize(plugin, serialized)); var enabled = values.optional("worlds:enabled") - .map(Tag::getAsBoolean) - .orElse(false); - return new LevelExtras(key, generator, enabled); + .map(Tag::getAsBoolean); + if (key.isEmpty() && generator.isEmpty() && enabled.isEmpty()) return null; + return new LevelExtras(key.orElse(null), generator.orElse(null), enabled.orElse(false)); }); } From ba3762eab55722bbec6dbeb086fe73d1049bfe58 Mon Sep 17 00:00:00 2001 From: david Date: Thu, 15 Aug 2024 22:04:07 +0200 Subject: [PATCH 12/13] Enhance WorldLoadCommand with persistence and save actions Added persistence status update and level data saving when a world is successfully loaded. This ensures the world's state is correctly saved and can be reliably restored on subsequent loads. --- .../net/thenextlvl/worlds/command/WorldLoadCommand.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/plugin/src/main/java/net/thenextlvl/worlds/command/WorldLoadCommand.java b/plugin/src/main/java/net/thenextlvl/worlds/command/WorldLoadCommand.java index f54d53b..efa4671 100644 --- a/plugin/src/main/java/net/thenextlvl/worlds/command/WorldLoadCommand.java +++ b/plugin/src/main/java/net/thenextlvl/worlds/command/WorldLoadCommand.java @@ -32,13 +32,22 @@ class WorldLoadCommand { private int load(CommandContext context) { var name = context.getArgument("world", String.class); var level = new File(plugin.getServer().getWorldContainer(), name); + var world = plugin.levelView().isLevel(level) ? plugin.levelView().loadLevel(level, optional -> optional.map(extras -> !extras.enabled()).isPresent()) : null; + var message = world != null ? "world.load.success" : "world.load.failed"; plugin.bundle().sendMessage(context.getSource().getSender(), message, Placeholder.parsed("world", world != null ? world.key().asString() : name)); + if (world != null && context.getSource().getSender() instanceof Entity entity) entity.teleportAsync(world.getSpawnLocation(), COMMAND); + + if (world != null) { + plugin.persistStatus(world, true, true); + plugin.levelView().saveLevelData(world, true); + } + return world != null ? Command.SINGLE_SUCCESS : 0; } } From 42857f032ec9e39ddbbc0058e9132edd5b96873f Mon Sep 17 00:00:00 2001 From: david Date: Thu, 15 Aug 2024 22:04:34 +0200 Subject: [PATCH 13/13] Refactor world suggestion filtering in unload command Update the WorldUnloadCommand to include a context-based filtering mechanism for the fallback argument. This ensures the fallback world suggestion does not match the world being unloaded, enhancing command reliability. --- .../net/thenextlvl/worlds/command/WorldUnloadCommand.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin/src/main/java/net/thenextlvl/worlds/command/WorldUnloadCommand.java b/plugin/src/main/java/net/thenextlvl/worlds/command/WorldUnloadCommand.java index 45891e6..23a7d43 100644 --- a/plugin/src/main/java/net/thenextlvl/worlds/command/WorldUnloadCommand.java +++ b/plugin/src/main/java/net/thenextlvl/worlds/command/WorldUnloadCommand.java @@ -23,8 +23,8 @@ class WorldUnloadCommand { .then(Commands.argument("world", ArgumentTypes.world()) .suggests(new WorldSuggestionProvider<>(plugin)) .then(Commands.argument("fallback", ArgumentTypes.world()) - .suggests(new WorldSuggestionProvider<>(plugin)) //, (context, world) -> - //!world.equals(context.getArgument("world", World.class)))) + .suggests(new WorldSuggestionProvider<>(plugin, (context, world) -> + !world.equals(context.getLastChild().getArgument("world", World.class)))) .executes(context -> { var world = context.getArgument("world", World.class); var fallback = context.getArgument("fallback", World.class);