From b15460692217c2dcddc9ea25217787ed62229f31 Mon Sep 17 00:00:00 2001 From: Ben Woo <30431861+benwoo1110@users.noreply.github.com> Date: Sun, 3 Sep 2023 00:51:07 +0800 Subject: [PATCH] Finish basic CRUD for new world management --- .../commands/CreateCommand.java | 40 +++--- .../commands/DeleteCommand.java | 29 ++-- .../MultiverseCore/commands/LoadCommand.java | 30 ++-- .../commands/RemoveCommand.java | 28 ++-- .../commands/UnloadCommand.java | 31 +++-- .../commandtools/MVCommandContexts.java | 2 +- .../MultiverseCore/utils/result/Result.java | 17 +-- .../MultiverseCore/worldnew/WorldManager.java | 130 ++++++++++++++---- .../worldnew/config/WorldConfigNodes.java | 2 +- .../worldnew/options/CreateWorldOptions.java | 6 +- .../worldnew/results/CreateWorldResult.java | 33 +++++ .../worldnew/results/DeleteWorldResult.java | 19 +++ .../worldnew/results/LoadWorldResult.java | 32 +++++ .../worldnew/results/RemoveWorldResult.java | 20 +++ .../worldnew/results/UnloadWorldResult.java | 30 ++++ src/test/resources/newworld_worlds.yml | 2 +- 16 files changed, 341 insertions(+), 110 deletions(-) create mode 100644 src/main/java/com/onarandombox/MultiverseCore/worldnew/results/CreateWorldResult.java create mode 100644 src/main/java/com/onarandombox/MultiverseCore/worldnew/results/DeleteWorldResult.java create mode 100644 src/main/java/com/onarandombox/MultiverseCore/worldnew/results/LoadWorldResult.java create mode 100644 src/main/java/com/onarandombox/MultiverseCore/worldnew/results/RemoveWorldResult.java create mode 100644 src/main/java/com/onarandombox/MultiverseCore/worldnew/results/UnloadWorldResult.java diff --git a/src/main/java/com/onarandombox/MultiverseCore/commands/CreateCommand.java b/src/main/java/com/onarandombox/MultiverseCore/commands/CreateCommand.java index 271c61f5..8c74f85a 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/commands/CreateCommand.java +++ b/src/main/java/com/onarandombox/MultiverseCore/commands/CreateCommand.java @@ -17,7 +17,9 @@ import co.aikar.commands.annotation.Description; import co.aikar.commands.annotation.Optional; import co.aikar.commands.annotation.Subcommand; import co.aikar.commands.annotation.Syntax; +import com.dumptruckman.minecraft.util.Logging; import com.onarandombox.MultiverseCore.api.MVWorldManager; +import com.onarandombox.MultiverseCore.commandtools.MVCommandIssuer; import com.onarandombox.MultiverseCore.commandtools.MVCommandManager; import com.onarandombox.MultiverseCore.commandtools.MultiverseCommand; import com.onarandombox.MultiverseCore.commandtools.flags.CommandFlag; @@ -26,6 +28,8 @@ import com.onarandombox.MultiverseCore.commandtools.flags.CommandValueFlag; import com.onarandombox.MultiverseCore.commandtools.flags.ParsedCommandFlags; import com.onarandombox.MultiverseCore.utils.MVCorei18n; import com.onarandombox.MultiverseCore.utils.UnsafeCallWrapper; +import com.onarandombox.MultiverseCore.worldnew.WorldManager; +import com.onarandombox.MultiverseCore.worldnew.options.CreateWorldOptions; import jakarta.inject.Inject; import org.bukkit.Bukkit; import org.bukkit.World; @@ -38,16 +42,15 @@ import org.jvnet.hk2.annotations.Service; @CommandAlias("mv") public class CreateCommand extends MultiverseCommand { - private final MVWorldManager worldManager; + private final WorldManager worldManager; @Inject public CreateCommand( @NotNull MVCommandManager commandManager, - @NotNull MVWorldManager worldManager, + @NotNull WorldManager worldManager, @NotNull UnsafeCallWrapper unsafeCallWrapper ) { super(commandManager); - this.worldManager = worldManager; registerFlagGroup(CommandFlagGroup.builder("mvcreate") @@ -84,7 +87,7 @@ public class CreateCommand extends MultiverseCommand { @CommandCompletion("@empty @flags:groupName=mvcreate") @Syntax(" --seed [seed] --generator [generator[:id]] --world-type [worldtype] --adjust-spawn --no-structures") @Description("{@@mv-core.create.description}") - public void onCreateCommand(BukkitCommandIssuer issuer, + public void onCreateCommand(MVCommandIssuer issuer, @Conditions("worldname:scope=new") @Syntax("") @@ -107,23 +110,24 @@ public class CreateCommand extends MultiverseCommand { issuer.sendInfo(MVCorei18n.CREATE_PROPERTIES_SEED, "{seed}", parsedFlags.flagValue("--seed", "RANDOM", String.class)); issuer.sendInfo(MVCorei18n.CREATE_PROPERTIES_WORLDTYPE, "{worldType}", parsedFlags.flagValue("--world-type", WorldType.NORMAL, WorldType.class).name()); issuer.sendInfo(MVCorei18n.CREATE_PROPERTIES_ADJUSTSPAWN, "{adjustSpawn}", String.valueOf(parsedFlags.hasFlag("--adjust-spawn"))); - issuer.sendInfo(MVCorei18n.CREATE_PROPERTIES_GENERATOR, "{generator}", parsedFlags.flagValue("--generator", "null", String.class)); + issuer.sendInfo(MVCorei18n.CREATE_PROPERTIES_GENERATOR, "{generator}", parsedFlags.flagValue("--generator", "", String.class)); issuer.sendInfo(MVCorei18n.CREATE_PROPERTIES_STRUCTURES, "{structures}", String.valueOf(!parsedFlags.hasFlag("--no-structures"))); issuer.sendInfo(MVCorei18n.CREATE_LOADING); - if (!worldManager.addWorld( - worldName, - environment, - parsedFlags.flagValue("--seed", String.class), - parsedFlags.flagValue("--world-type", WorldType.NORMAL, WorldType.class), - parsedFlags.hasFlag("--adjust-spawn"), - parsedFlags.flagValue("--generator", String.class), - parsedFlags.hasFlag("--no-structures") - )) { - issuer.sendError(MVCorei18n.CREATE_FAILED, "{worldName}", worldName); - return; - } - issuer.sendInfo(MVCorei18n.CREATE_SUCCESS, "{worldName}", worldName); + worldManager.createWorld(CreateWorldOptions.worldName(worldName) + .environment(environment) + .seed(parsedFlags.flagValue("--seed", String.class)) + .worldType(parsedFlags.flagValue("--world-type", WorldType.NORMAL, WorldType.class)) + .useSpawnAdjust(parsedFlags.hasFlag("--adjust-spawn")) + .generator(parsedFlags.flagValue("--generator", "", String.class)) + .generateStructures(!parsedFlags.hasFlag("--no-structures")) + ).onSuccess((success) -> { + Logging.fine("World create success: " + success); + issuer.sendInfo(success.getReasonMessage()); + }).onFailure((failure) -> { + Logging.fine("World create failure: " + failure); + issuer.sendError(failure.getReasonMessage()); + }); } } diff --git a/src/main/java/com/onarandombox/MultiverseCore/commands/DeleteCommand.java b/src/main/java/com/onarandombox/MultiverseCore/commands/DeleteCommand.java index 4a1f1c51..ae90a430 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/commands/DeleteCommand.java +++ b/src/main/java/com/onarandombox/MultiverseCore/commands/DeleteCommand.java @@ -10,11 +10,14 @@ import co.aikar.commands.annotation.Description; import co.aikar.commands.annotation.Single; import co.aikar.commands.annotation.Subcommand; import co.aikar.commands.annotation.Syntax; +import com.dumptruckman.minecraft.util.Logging; import com.onarandombox.MultiverseCore.api.MVWorldManager; +import com.onarandombox.MultiverseCore.commandtools.MVCommandIssuer; import com.onarandombox.MultiverseCore.commandtools.MVCommandManager; import com.onarandombox.MultiverseCore.commandtools.MultiverseCommand; import com.onarandombox.MultiverseCore.commandtools.queue.QueuedCommand; import com.onarandombox.MultiverseCore.utils.MVCorei18n; +import com.onarandombox.MultiverseCore.worldnew.WorldManager; import jakarta.inject.Inject; import org.jetbrains.annotations.NotNull; import org.jvnet.hk2.annotations.Service; @@ -23,10 +26,10 @@ import org.jvnet.hk2.annotations.Service; @CommandAlias("mv") public class DeleteCommand extends MultiverseCommand { - private final MVWorldManager worldManager; + private final WorldManager worldManager; @Inject - public DeleteCommand(@NotNull MVCommandManager commandManager, @NotNull MVWorldManager worldManager) { + public DeleteCommand(@NotNull MVCommandManager commandManager, @NotNull WorldManager worldManager) { super(commandManager); this.worldManager = worldManager; } @@ -36,10 +39,10 @@ public class DeleteCommand extends MultiverseCommand { @CommandCompletion("@mvworlds:scope=both") @Syntax("") @Description("{@@mv-core.delete.description}") - public void onDeleteCommand(BukkitCommandIssuer issuer, + public void onDeleteCommand(MVCommandIssuer issuer, @Single - @Conditions("worldname:scope=both") + //@Conditions("worldname:scope=both") @Syntax("") @Description("The world you want to delete.") String worldName @@ -47,15 +50,15 @@ public class DeleteCommand extends MultiverseCommand { this.commandManager.getCommandQueueManager().addToQueue(new QueuedCommand( issuer.getIssuer(), () -> { - issuer.sendInfo(MVCorei18n.DELETE_DELETING, - "{world}", worldName); - if (!this.worldManager.deleteWorld(worldName)) { - issuer.sendError(MVCorei18n.DELETE_FAILED, - "{world}", worldName); - return; - } - issuer.sendInfo(MVCorei18n.DELETE_SUCCESS, - "{world}", worldName); + issuer.sendInfo(MVCorei18n.DELETE_DELETING, "{world}", worldName); + worldManager.deleteWorld(worldName) + .onSuccess((success) -> { + Logging.fine("World delete success: " + success); + issuer.sendInfo(success.getReasonMessage()); + }).onFailure((failure) -> { + Logging.fine("World delete failure: " + failure); + issuer.sendError(failure.getReasonMessage()); + }); }, this.commandManager.formatMessage( issuer, diff --git a/src/main/java/com/onarandombox/MultiverseCore/commands/LoadCommand.java b/src/main/java/com/onarandombox/MultiverseCore/commands/LoadCommand.java index 17849902..a0be9334 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/commands/LoadCommand.java +++ b/src/main/java/com/onarandombox/MultiverseCore/commands/LoadCommand.java @@ -9,10 +9,13 @@ import co.aikar.commands.annotation.Description; import co.aikar.commands.annotation.Single; import co.aikar.commands.annotation.Subcommand; import co.aikar.commands.annotation.Syntax; +import com.dumptruckman.minecraft.util.Logging; import com.onarandombox.MultiverseCore.api.MVWorldManager; +import com.onarandombox.MultiverseCore.commandtools.MVCommandIssuer; import com.onarandombox.MultiverseCore.commandtools.MVCommandManager; import com.onarandombox.MultiverseCore.commandtools.MultiverseCommand; import com.onarandombox.MultiverseCore.utils.MVCorei18n; +import com.onarandombox.MultiverseCore.worldnew.WorldManager; import jakarta.inject.Inject; import org.jetbrains.annotations.NotNull; import org.jvnet.hk2.annotations.Service; @@ -21,10 +24,10 @@ import org.jvnet.hk2.annotations.Service; @CommandAlias("mv") public class LoadCommand extends MultiverseCommand { - private final MVWorldManager worldManager; + private final WorldManager worldManager; @Inject - public LoadCommand(@NotNull MVCommandManager commandManager, @NotNull MVWorldManager worldManager) { + public LoadCommand(@NotNull MVCommandManager commandManager, @NotNull WorldManager worldManager) { super(commandManager); this.worldManager = worldManager; } @@ -34,23 +37,22 @@ public class LoadCommand extends MultiverseCommand { @CommandCompletion("@mvworlds:scope=unloaded") @Syntax("") @Description("{@@mv-core.load.description}") - public void onLoadCommand(BukkitCommandIssuer issuer, + public void onLoadCommand(MVCommandIssuer issuer, @Single - @Conditions("worldname:scope=unloaded") + //@Conditions("worldname:scope=unloaded") @Syntax("") @Description("{@@mv-core.load.world.description}") String worldName ) { - issuer.sendInfo(MVCorei18n.LOAD_LOADING, - "{world}", worldName); - - if (!this.worldManager.loadWorld(worldName)) { - issuer.sendError(MVCorei18n.LOAD_FAILED, - "{world}", worldName); - return; - } - issuer.sendInfo(MVCorei18n.LOAD_SUCCESS, - "{world}", worldName); + issuer.sendInfo(MVCorei18n.LOAD_LOADING, "{world}", worldName); + worldManager.loadWorld(worldName) + .onSuccess((success) -> { + Logging.fine("World load success: " + success); + issuer.sendInfo(success.getReasonMessage()); + }).onFailure((failure) -> { + Logging.fine("World load failure: " + failure); + issuer.sendError(failure.getReasonMessage()); + }); } } diff --git a/src/main/java/com/onarandombox/MultiverseCore/commands/RemoveCommand.java b/src/main/java/com/onarandombox/MultiverseCore/commands/RemoveCommand.java index a1e462de..154998d9 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/commands/RemoveCommand.java +++ b/src/main/java/com/onarandombox/MultiverseCore/commands/RemoveCommand.java @@ -1,6 +1,5 @@ package com.onarandombox.MultiverseCore.commands; -import co.aikar.commands.BukkitCommandIssuer; import co.aikar.commands.annotation.CommandAlias; import co.aikar.commands.annotation.CommandCompletion; import co.aikar.commands.annotation.CommandPermission; @@ -9,10 +8,11 @@ import co.aikar.commands.annotation.Description; import co.aikar.commands.annotation.Single; import co.aikar.commands.annotation.Subcommand; import co.aikar.commands.annotation.Syntax; -import com.onarandombox.MultiverseCore.api.MVWorldManager; +import com.dumptruckman.minecraft.util.Logging; +import com.onarandombox.MultiverseCore.commandtools.MVCommandIssuer; import com.onarandombox.MultiverseCore.commandtools.MVCommandManager; import com.onarandombox.MultiverseCore.commandtools.MultiverseCommand; -import com.onarandombox.MultiverseCore.utils.MVCorei18n; +import com.onarandombox.MultiverseCore.worldnew.WorldManager; import jakarta.inject.Inject; import org.jetbrains.annotations.NotNull; import org.jvnet.hk2.annotations.Service; @@ -21,10 +21,10 @@ import org.jvnet.hk2.annotations.Service; @CommandAlias("mv") public class RemoveCommand extends MultiverseCommand { - private final MVWorldManager worldManager; + private final WorldManager worldManager; @Inject - public RemoveCommand(@NotNull MVCommandManager commandManager, @NotNull MVWorldManager worldManager) { + public RemoveCommand(@NotNull MVCommandManager commandManager, @NotNull WorldManager worldManager) { super(commandManager); this.worldManager = worldManager; } @@ -34,19 +34,21 @@ public class RemoveCommand extends MultiverseCommand { @CommandCompletion("@mvworlds:scope=both") @Syntax("") @Description("{@@mv-core.remove.description}") - public void onRemoveCommand(BukkitCommandIssuer issuer, + public void onRemoveCommand(MVCommandIssuer issuer, @Single - @Conditions("mvworlds:scope=both") + //@Conditions("mvworlds:scope=both") @Syntax("") @Description("{@@mv-core.remove.world.description}") String worldName ) { - if (!this.worldManager.removeWorldFromConfig(worldName)) { - issuer.sendError(MVCorei18n.REMOVE_FAILED); - return; - } - issuer.sendInfo(MVCorei18n.REMOVE_SUCCESS, - "{world}", worldName); + worldManager.removeWorld(worldName) + .onSuccess((success) -> { + Logging.fine("World remove success: " + success); + issuer.sendInfo(success.getReasonMessage()); + }).onFailure((failure) -> { + Logging.fine("World remove failure: " + failure); + issuer.sendError(failure.getReasonMessage()); + }); } } diff --git a/src/main/java/com/onarandombox/MultiverseCore/commands/UnloadCommand.java b/src/main/java/com/onarandombox/MultiverseCore/commands/UnloadCommand.java index ba4fd309..0aff0a0c 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/commands/UnloadCommand.java +++ b/src/main/java/com/onarandombox/MultiverseCore/commands/UnloadCommand.java @@ -7,11 +7,14 @@ import co.aikar.commands.annotation.CommandPermission; import co.aikar.commands.annotation.Description; import co.aikar.commands.annotation.Subcommand; import co.aikar.commands.annotation.Syntax; +import com.dumptruckman.minecraft.util.Logging; import com.onarandombox.MultiverseCore.api.MVWorld; import com.onarandombox.MultiverseCore.api.MVWorldManager; +import com.onarandombox.MultiverseCore.commandtools.MVCommandIssuer; import com.onarandombox.MultiverseCore.commandtools.MVCommandManager; import com.onarandombox.MultiverseCore.commandtools.MultiverseCommand; import com.onarandombox.MultiverseCore.utils.MVCorei18n; +import com.onarandombox.MultiverseCore.worldnew.WorldManager; import jakarta.inject.Inject; import org.jetbrains.annotations.NotNull; import org.jvnet.hk2.annotations.Service; @@ -20,10 +23,10 @@ import org.jvnet.hk2.annotations.Service; @CommandAlias("mv") public class UnloadCommand extends MultiverseCommand { - private final MVWorldManager worldManager; + private final WorldManager worldManager; @Inject - public UnloadCommand(@NotNull MVCommandManager commandManager, @NotNull MVWorldManager worldManager) { + public UnloadCommand(@NotNull MVCommandManager commandManager, @NotNull WorldManager worldManager) { super(commandManager); this.worldManager = worldManager; } @@ -33,22 +36,20 @@ public class UnloadCommand extends MultiverseCommand { @CommandCompletion("@mvworlds") @Syntax("") @Description("{@@mv-core.unload.description}") - public void onUnloadCommand(BukkitCommandIssuer issuer, + public void onUnloadCommand(MVCommandIssuer issuer, @Syntax("") @Description("{@@mv-core.unload.world.description}") - MVWorld world + String worldName // TODO: Use world object ) { - issuer.sendInfo(MVCorei18n.UNLOAD_UNLOADING, - "{world}", world.getColoredWorldString()); - - // TODO: Should be able to use MVWorld object directly for unloadWorld - if (!this.worldManager.unloadWorld(world.getName())) { - issuer.sendError(MVCorei18n.UNLOAD_FAILURE, - "{world}", world.getColoredWorldString()); - return; - } - issuer.sendInfo(MVCorei18n.UNLOAD_SUCCESS, - "{world}", world.getColoredWorldString()); + issuer.sendInfo(MVCorei18n.UNLOAD_UNLOADING, "{world}", worldName); + worldManager.unloadWorld(worldName) + .onSuccess((success) -> { + Logging.fine("World unload success: " + success); + issuer.sendInfo(success.getReasonMessage()); + }).onFailure((failure) -> { + Logging.fine("World unload failure: " + failure); + issuer.sendError(failure.getReasonMessage()); + }); } } diff --git a/src/main/java/com/onarandombox/MultiverseCore/commandtools/MVCommandContexts.java b/src/main/java/com/onarandombox/MultiverseCore/commandtools/MVCommandContexts.java index 480ea29d..3c20b2ed 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/commandtools/MVCommandContexts.java +++ b/src/main/java/com/onarandombox/MultiverseCore/commandtools/MVCommandContexts.java @@ -199,7 +199,7 @@ public class MVCommandContexts extends PaperCommandContexts { context.popFirstArg(); return world; } - if (!context.isOptional()) { + if (context.isOptional()) { return null; } throw new InvalidCommandArgument("World " + worldName + " is not a loaded multiverse world."); diff --git a/src/main/java/com/onarandombox/MultiverseCore/utils/result/Result.java b/src/main/java/com/onarandombox/MultiverseCore/utils/result/Result.java index f9315998..56461586 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/utils/result/Result.java +++ b/src/main/java/com/onarandombox/MultiverseCore/utils/result/Result.java @@ -5,6 +5,7 @@ import com.onarandombox.MultiverseCore.utils.message.MessageReplacement; import org.jetbrains.annotations.NotNull; import java.util.NoSuchElementException; +import java.util.function.BiConsumer; import java.util.function.Consumer; public sealed interface Result permits Result.Success, Result.Failure { @@ -26,16 +27,16 @@ public sealed interface Result @NotNull Message getReasonMessage(); - default Result onSuccess(Consumer consumer) { - if (this.isSuccess()) { - consumer.accept(this.getSuccessReason()); + default Result onSuccess(Consumer> consumer) { + if (this instanceof Success) { + consumer.accept((Success) this); } return this; } - default Result onFailure(Consumer consumer) { - if (this.isFailure()) { - consumer.accept(this.getFailureReason()); + default Result onFailure(Consumer> consumer) { + if (this instanceof Failure) { + consumer.accept((Failure) this); } return this; } @@ -117,7 +118,7 @@ public sealed interface Result @Override public S getSuccessReason() { - throw new NoSuchElementException("No reason for success"); + throw new NoSuchElementException("No reason for failure"); } @Override @@ -127,7 +128,7 @@ public sealed interface Result @Override public @NotNull Message getReasonMessage() { - return Message.of(failureReason, "Success!", replacements); + return Message.of(failureReason, "Failed!", replacements); } @Override diff --git a/src/main/java/com/onarandombox/MultiverseCore/worldnew/WorldManager.java b/src/main/java/com/onarandombox/MultiverseCore/worldnew/WorldManager.java index 28f503b3..563d03f5 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/worldnew/WorldManager.java +++ b/src/main/java/com/onarandombox/MultiverseCore/worldnew/WorldManager.java @@ -1,16 +1,26 @@ package com.onarandombox.MultiverseCore.worldnew; import com.dumptruckman.minecraft.util.Logging; +import com.google.common.base.Strings; import com.onarandombox.MultiverseCore.utils.file.FileUtils; +import com.onarandombox.MultiverseCore.utils.result.Result; +import com.onarandombox.MultiverseCore.utils.result.SuccessReason; +import com.onarandombox.MultiverseCore.world.WorldNameChecker; import com.onarandombox.MultiverseCore.worldnew.config.WorldConfig; import com.onarandombox.MultiverseCore.worldnew.config.WorldsConfigManager; import com.onarandombox.MultiverseCore.worldnew.options.CreateWorldOptions; +import com.onarandombox.MultiverseCore.worldnew.results.CreateWorldResult; +import com.onarandombox.MultiverseCore.worldnew.results.DeleteWorldResult; +import com.onarandombox.MultiverseCore.worldnew.results.LoadWorldResult; +import com.onarandombox.MultiverseCore.worldnew.results.RemoveWorldResult; +import com.onarandombox.MultiverseCore.worldnew.results.UnloadWorldResult; import io.vavr.control.Option; import jakarta.inject.Inject; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.WorldCreator; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jvnet.hk2.annotations.Service; import java.io.File; @@ -35,9 +45,12 @@ public class WorldManager { public void initAllWorlds() { populateOfflineWorlds(); getOfflineWorlds().forEach(offlineWorld -> { - if (offlineWorld.getAutoLoad()) { - loadWorld(offlineWorld); + if (!offlineWorld.getAutoLoad()) { + return; } + loadWorld(offlineWorld).onFailure((failure) -> { + Logging.severe("Failed to load world %s: %s", offlineWorld.getName(), failure); + }); }); saveWorldsConfig(); } @@ -47,6 +60,7 @@ public class WorldManager { worldsConfigManager.getAllWorldConfigs().forEach(worldConfig -> { OfflineWorld offlineWorld = new OfflineWorld(worldConfig.getWorldName(), worldConfig); offlineWorldsMap.put(worldConfig.getWorldName(), offlineWorld); + Logging.fine("Loaded world %s from config", worldConfig.getWorldName()); }); } @@ -55,24 +69,37 @@ public class WorldManager { * * @param options The options for customizing the creation of a new world. */ - public void createWorld(CreateWorldOptions options) { - // TODO: Check valid worldname + public Result createWorld(CreateWorldOptions options) { + if (!WorldNameChecker.isValidWorldName(options.worldName())) { + return Result.failure(CreateWorldResult.Failure.INVALID_WORLDNAME); + } - // TODO: Check if world already exists + if (getMVWorld(options.worldName()).isDefined()) { + return Result.failure(CreateWorldResult.Failure.WORLD_EXIST_LOADED); + } + + if (getOfflineWorld(options.worldName()).isDefined()) { + return Result.failure(CreateWorldResult.Failure.WORLD_EXIST_OFFLINE); + } + + File worldFolder = new File(Bukkit.getWorldContainer(), options.worldName()); + if (worldFolder.exists()) { + return Result.failure(CreateWorldResult.Failure.WORLD_EXIST_FOLDER); + } // Create bukkit world World world = WorldCreator.name(options.worldName()) .environment(options.environment()) .generateStructures(options.generateStructures()) - .generator(options.generator()) + .generator(Strings.isNullOrEmpty(options.generator()) ? null : options.generator()) .seed(options.seed()) .type(options.worldType()) .createWorld(); if (world == null) { - // TODO: Better result handling Logging.severe("Failed to create world: " + options.worldName()); - return; + return Result.failure(CreateWorldResult.Failure.BUKKIT_CREATION_FAILED); } + Logging.fine("Loaded bukkit world: " + world.getName()); // Our multiverse world WorldConfig worldConfig = worldsConfigManager.addWorldConfig(options.worldName()); @@ -87,20 +114,32 @@ public class WorldManager { worldsMap.put(mvWorld.getName(), mvWorld); saveWorldsConfig(); + return Result.success(CreateWorldResult.Success.CREATED); } - public void loadWorld(@NotNull OfflineWorld offlineWorld) { + public Result loadWorld(@NotNull String worldName) { + return getOfflineWorld(worldName) + .map(this::loadWorld) + .getOrElse(() -> Result.failure(LoadWorldResult.Failure.WORLD_NON_EXISTENT)); + } + + public Result loadWorld(@NotNull OfflineWorld offlineWorld) { + if (isMVWorld(offlineWorld)) { + Logging.severe("World already loaded: " + offlineWorld.getName()); + return Result.failure(LoadWorldResult.Failure.WORLD_EXIST_LOADED); + } + // TODO: Reduce copy paste from createWorld method World world = WorldCreator.name(offlineWorld.getName()) .environment(offlineWorld.getEnvironment()) - .generator(offlineWorld.getGenerator()) + .generator(Strings.isNullOrEmpty(offlineWorld.getGenerator()) ? null : offlineWorld.getGenerator()) .seed(offlineWorld.getSeed()) .createWorld(); if (world == null) { - // TODO: Better result handling Logging.severe("Failed to create world: " + offlineWorld.getName()); - return; + return Result.failure(LoadWorldResult.Failure.BUKKIT_CREATION_FAILED); } + Logging.fine("Loaded bukkit world: " + world.getName()); // Our multiverse world WorldConfig worldConfig = worldsConfigManager.getWorldConfig(offlineWorld.getName()); @@ -108,45 +147,74 @@ public class WorldManager { worldsMap.put(mvWorld.getName(), mvWorld); saveWorldsConfig(); + return Result.success(LoadWorldResult.Success.LOADED); } - public void unloadWorld(@NotNull MVWorld world) { + public Result unloadWorld(@NotNull String worldName) { + return getMVWorld(worldName) + .map(this::unloadWorld) + .getOrElse(() -> Result.failure(UnloadWorldResult.Failure.WORLD_NON_EXISTENT)); + } + + public Result unloadWorld(@NotNull MVWorld world) { World bukkitWorld = world.getBukkitWorld(); // TODO: removePlayersFromWorld? if (!Bukkit.unloadWorld(bukkitWorld, true)) { Logging.severe("Failed to unload world: " + world.getName()); - return; - } - if (Bukkit.getWorld(world.getName()) != null) { - Logging.severe("World still loaded: " + world.getName()); - return; + return Result.failure(UnloadWorldResult.Failure.BUKKIT_UNLOAD_FAILED); } worldsMap.remove(world.getName()); + return Result.success(UnloadWorldResult.Success.UNLOADED); } - public void removeWorld(@NotNull OfflineWorld world) { + public Result removeWorld(@NotNull String worldName) { + return getOfflineWorld(worldName) + .map(this::removeWorld) + .getOrElse(() -> Result.failure(RemoveWorldResult.Failure.WORLD_NON_EXISTENT)); + } + + public Result removeWorld(@NotNull OfflineWorld world) { if (world instanceof MVWorld mvWorld) { - unloadWorld(mvWorld); + var result = unloadWorld(mvWorld); + if (result.isFailure()) { + return Result.failure(result.getFailureReason()); + } } // Remove world from config offlineWorldsMap.remove(world.getName()); worldsConfigManager.deleteWorldConfig(world.getName()); saveWorldsConfig(); + + return Result.success(RemoveWorldResult.Success.REMOVED); } - public void deleteWorld(@NotNull MVWorld world) { + public Result deleteWorld(@NotNull String worldName) { + return getMVWorld(worldName) + .map(this::deleteWorld) + .getOrElse(() -> Result.failure(DeleteWorldResult.Failure.WORLD_NON_EXISTENT)); + } + + public Result deleteWorld(@NotNull MVWorld world) { // TODO: Attempt to load if unloaded so we can actually delete the world File worldFolder = world.getBukkitWorld().getWorldFolder(); - removeWorld(world); + var result = removeWorld(world); + if (result.isFailure()) { + return Result.failure(result.getFailureReason()); + } // Erase world files from disk // TODO: Config options to keep certain files - FileUtils.deleteFolder(worldFolder); + if (!FileUtils.deleteFolder(worldFolder)) { + Logging.severe("Failed to delete world folder: " + worldFolder); + return Result.failure(DeleteWorldResult.Failure.FAILED_TO_DELETE_FOLDER); + } + + return Result.success(DeleteWorldResult.Success.DELETED); } - public Option getOfflineWorld(@NotNull String worldName) { + public Option getOfflineWorld(@Nullable String worldName) { return Option.of(offlineWorldsMap.get(worldName)); } @@ -154,10 +222,22 @@ public class WorldManager { return offlineWorldsMap.values(); } - public Option getMVWorld(@NotNull String worldName) { + public Option getMVWorld(@Nullable String worldName) { return Option.of(worldsMap.get(worldName)); } + public Collection getMVWorlds() { + return worldsMap.values(); + } + + public boolean isMVWorld(@Nullable OfflineWorld world) { + return world != null && isMVWorld(world.getName()); + } + + public boolean isMVWorld(@Nullable String worldName) { + return worldsMap.containsKey(worldName); + } + public void saveWorldsConfig() { worldsConfigManager.save(); } diff --git a/src/main/java/com/onarandombox/MultiverseCore/worldnew/config/WorldConfigNodes.java b/src/main/java/com/onarandombox/MultiverseCore/worldnew/config/WorldConfigNodes.java index ef901ae2..551870a1 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/worldnew/config/WorldConfigNodes.java +++ b/src/main/java/com/onarandombox/MultiverseCore/worldnew/config/WorldConfigNodes.java @@ -91,7 +91,7 @@ public class WorldConfigNodes { .build()); public final ConfigNode GENERATOR = node(ConfigNode.builder("generator", String.class) - .defaultValue("") + .defaultValue("@error") // this should be set on world creation .name("generator") .build()); diff --git a/src/main/java/com/onarandombox/MultiverseCore/worldnew/options/CreateWorldOptions.java b/src/main/java/com/onarandombox/MultiverseCore/worldnew/options/CreateWorldOptions.java index 2612cf91..bc9110da 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/worldnew/options/CreateWorldOptions.java +++ b/src/main/java/com/onarandombox/MultiverseCore/worldnew/options/CreateWorldOptions.java @@ -113,7 +113,11 @@ public class CreateWorldOptions { * @param seed The seed of the world to create. * @return This {@link CreateWorldOptions} instance. */ - public @NotNull CreateWorldOptions seed(@NotNull String seed) { + public @NotNull CreateWorldOptions seed(@Nullable String seed) { + if (seed == null) { + this.seed = Long.MIN_VALUE; + return this; + } try { this.seed = Long.parseLong(seed); } catch (NumberFormatException numberformatexception) { diff --git a/src/main/java/com/onarandombox/MultiverseCore/worldnew/results/CreateWorldResult.java b/src/main/java/com/onarandombox/MultiverseCore/worldnew/results/CreateWorldResult.java new file mode 100644 index 00000000..010213b3 --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/worldnew/results/CreateWorldResult.java @@ -0,0 +1,33 @@ +package com.onarandombox.MultiverseCore.worldnew.results; + +import co.aikar.locales.MessageKey; +import co.aikar.locales.MessageKeyProvider; +import com.onarandombox.MultiverseCore.utils.MVCorei18n; +import com.onarandombox.MultiverseCore.utils.result.FailureReason; +import com.onarandombox.MultiverseCore.utils.result.SuccessReason; + +public class CreateWorldResult { + public enum Success implements SuccessReason { + CREATED + } + + public enum Failure implements FailureReason { + INVALID_WORLDNAME(MVCorei18n.GENERIC_FAILURE), + WORLD_EXIST_FOLDER(MVCorei18n.GENERIC_FAILURE), + WORLD_EXIST_OFFLINE(MVCorei18n.GENERIC_FAILURE), + WORLD_EXIST_LOADED(MVCorei18n.GENERIC_FAILURE), + BUKKIT_CREATION_FAILED(MVCorei18n.GENERIC_FAILURE), + ; + + private final MessageKeyProvider message; + + Failure(MessageKeyProvider message) { + this.message = message; + } + + @Override + public MessageKey getMessageKey() { + return message.getMessageKey(); + } + } +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/worldnew/results/DeleteWorldResult.java b/src/main/java/com/onarandombox/MultiverseCore/worldnew/results/DeleteWorldResult.java new file mode 100644 index 00000000..417f511b --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/worldnew/results/DeleteWorldResult.java @@ -0,0 +1,19 @@ +package com.onarandombox.MultiverseCore.worldnew.results; + +import co.aikar.locales.MessageKeyProvider; +import com.onarandombox.MultiverseCore.utils.MVCorei18n; +import com.onarandombox.MultiverseCore.utils.result.SuccessReason; + +public class DeleteWorldResult { + public enum Success implements SuccessReason { + DELETED + } + + public static class Failure extends RemoveWorldResult.Failure { + public static final Failure FAILED_TO_DELETE_FOLDER = new Failure(MVCorei18n.GENERIC_FAILURE); + + Failure(MessageKeyProvider message) { + super(message); + } + } +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/worldnew/results/LoadWorldResult.java b/src/main/java/com/onarandombox/MultiverseCore/worldnew/results/LoadWorldResult.java new file mode 100644 index 00000000..9808465c --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/worldnew/results/LoadWorldResult.java @@ -0,0 +1,32 @@ +package com.onarandombox.MultiverseCore.worldnew.results; + +import co.aikar.locales.MessageKey; +import co.aikar.locales.MessageKeyProvider; +import com.onarandombox.MultiverseCore.utils.MVCorei18n; +import com.onarandombox.MultiverseCore.utils.result.FailureReason; +import com.onarandombox.MultiverseCore.utils.result.SuccessReason; + +public class LoadWorldResult { + public enum Success implements SuccessReason { + LOADED + } + + public enum Failure implements FailureReason { + WORLD_NON_EXISTENT(MVCorei18n.GENERIC_FAILURE), + WORLD_EXIST_FOLDER(MVCorei18n.GENERIC_FAILURE), + WORLD_EXIST_LOADED(MVCorei18n.GENERIC_FAILURE), + BUKKIT_CREATION_FAILED(MVCorei18n.GENERIC_FAILURE), + ; + + private final MessageKeyProvider message; + + Failure(MessageKeyProvider message) { + this.message = message; + } + + @Override + public MessageKey getMessageKey() { + return message.getMessageKey(); + } + } +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/worldnew/results/RemoveWorldResult.java b/src/main/java/com/onarandombox/MultiverseCore/worldnew/results/RemoveWorldResult.java new file mode 100644 index 00000000..508db744 --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/worldnew/results/RemoveWorldResult.java @@ -0,0 +1,20 @@ +package com.onarandombox.MultiverseCore.worldnew.results; + +import co.aikar.locales.MessageKey; +import co.aikar.locales.MessageKeyProvider; +import com.onarandombox.MultiverseCore.utils.MVCorei18n; +import com.onarandombox.MultiverseCore.utils.result.FailureReason; +import com.onarandombox.MultiverseCore.utils.result.SuccessReason; + +public class RemoveWorldResult { + public enum Success implements SuccessReason { + REMOVED + } + + public static class Failure extends UnloadWorldResult.Failure { + // TODO + Failure(MessageKeyProvider message) { + super(message); + } + } +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/worldnew/results/UnloadWorldResult.java b/src/main/java/com/onarandombox/MultiverseCore/worldnew/results/UnloadWorldResult.java new file mode 100644 index 00000000..3bb8b951 --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/worldnew/results/UnloadWorldResult.java @@ -0,0 +1,30 @@ +package com.onarandombox.MultiverseCore.worldnew.results; + +import co.aikar.locales.MessageKey; +import co.aikar.locales.MessageKeyProvider; +import com.onarandombox.MultiverseCore.utils.MVCorei18n; +import com.onarandombox.MultiverseCore.utils.result.FailureReason; +import com.onarandombox.MultiverseCore.utils.result.SuccessReason; + +public class UnloadWorldResult { + public enum Success implements SuccessReason { + UNLOADED + } + + public static class Failure implements FailureReason { + public static final Failure WORLD_NON_EXISTENT = new Failure(MVCorei18n.GENERIC_FAILURE); + public static final Failure WORLD_OFFLINE = new Failure(MVCorei18n.GENERIC_FAILURE); + public static final Failure BUKKIT_UNLOAD_FAILED = new Failure(MVCorei18n.GENERIC_FAILURE); + + private final MessageKeyProvider message; + + Failure(MessageKeyProvider message) { + this.message = message; + } + + @Override + public MessageKey getMessageKey() { + return message.getMessageKey(); + } + } +} diff --git a/src/test/resources/newworld_worlds.yml b/src/test/resources/newworld_worlds.yml index 976c070c..74d32a8c 100644 --- a/src/test/resources/newworld_worlds.yml +++ b/src/test/resources/newworld_worlds.yml @@ -77,7 +77,7 @@ newworld: currency: AIR environment: NORMAL gamemode: SURVIVAL - generator: '' + generator: '@error' hidden: false hunger: true keep-spawn-in-memory: true