diff --git a/config/mv_checks.xml b/config/mv_checks.xml
index 78a095c1..994e530d 100644
--- a/config/mv_checks.xml
+++ b/config/mv_checks.xml
@@ -145,7 +145,10 @@
-
+
+
+
+
@@ -380,7 +383,9 @@
-
+
+
+
@@ -518,15 +523,30 @@
-
-
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/java/com/onarandombox/MultiverseCore/worldnew/WorldManager.java b/src/main/java/com/onarandombox/MultiverseCore/worldnew/WorldManager.java
index 6d19ca24..54159120 100644
--- a/src/main/java/com/onarandombox/MultiverseCore/worldnew/WorldManager.java
+++ b/src/main/java/com/onarandombox/MultiverseCore/worldnew/WorldManager.java
@@ -18,6 +18,7 @@ import com.onarandombox.MultiverseCore.worldnew.helpers.FilesManipulator;
import com.onarandombox.MultiverseCore.worldnew.options.CloneWorldOptions;
import com.onarandombox.MultiverseCore.worldnew.options.CreateWorldOptions;
import com.onarandombox.MultiverseCore.worldnew.options.ImportWorldOptions;
+import com.onarandombox.MultiverseCore.worldnew.options.KeepWorldSettingsOptions;
import com.onarandombox.MultiverseCore.worldnew.options.RegenWorldOptions;
import com.onarandombox.MultiverseCore.worldnew.results.CloneWorldResult;
import com.onarandombox.MultiverseCore.worldnew.results.CreateWorldResult;
@@ -54,7 +55,7 @@ import static com.onarandombox.MultiverseCore.worldnew.helpers.DataStore.WorldCo
/**
* This manager contains all the world managing functions that your heart desires.
*/
-@Service
+@Service // SUPPRESS CHECKSTYLE: ClassFanOutComplexity This is the world manager, it's going to be complex.
public class WorldManager {
private static final List CLONE_IGNORE_FILES = Arrays.asList("uid.dat", "session.lock");
@@ -100,7 +101,7 @@ public class WorldManager {
* @return The result of the load.
*/
public Try initAllWorlds() {
- return populateWorldFromConfig().andThenTry(() -> {
+ return updateWorldsFromConfig().andThenTry(() -> {
loadDefaultWorlds();
autoLoadWorlds();
saveWorldsConfig();
@@ -108,30 +109,33 @@ public class WorldManager {
}
/**
- * Populate world map from the worlds.yml config.
+ * Updates the current set of worlds to match the worlds config.
*
- * @return The result of the world map population.
+ * @return A successful Try if the worlds.yml config was loaded successfully.
*/
- private Try populateWorldFromConfig() {
+ private Try updateWorldsFromConfig() {
return worldsConfigManager.load().mapTry(result -> {
- var newWorldConfigs = result._1();
- var removedWorlds = result._2();
-
- newWorldConfigs.forEach(worldConfig -> getWorld(worldConfig.getWorldName())
- .peek(unloadedWorld -> unloadedWorld.setWorldConfig(worldConfig))
- .onEmpty(() -> {
- MultiverseWorld mvWorld = new MultiverseWorld(worldConfig.getWorldName(), worldConfig);
- worldsMap.put(mvWorld.getName(), mvWorld);
- }));
-
- removedWorlds.forEach(worldName -> removeWorld(worldName)
- .onFailure(failure -> Logging.severe("Failed to unload world %s: %s", worldName, failure))
- .onSuccess(success -> Logging.fine("Unloaded world %s as it was removed from config", worldName)));
-
+ loadNewWorldConfigs(result._1());
+ removeWorldsNotInConfigs(result._2());
return null;
});
}
+ private void loadNewWorldConfigs(Collection newWorldConfigs) {
+ newWorldConfigs.forEach(worldConfig -> getWorld(worldConfig.getWorldName())
+ .peek(unloadedWorld -> unloadedWorld.setWorldConfig(worldConfig))
+ .onEmpty(() -> {
+ MultiverseWorld mvWorld = new MultiverseWorld(worldConfig.getWorldName(), worldConfig);
+ worldsMap.put(mvWorld.getName(), mvWorld);
+ }));
+ }
+
+ private void removeWorldsNotInConfigs(Collection removedWorlds) {
+ removedWorlds.forEach(worldName -> removeWorld(worldName)
+ .onFailure(failure -> Logging.severe("Failed to unload world %s: %s", worldName, failure))
+ .onSuccess(success -> Logging.fine("Unloaded world %s as it was removed from config", worldName)));
+ }
+
/**
* Load worlds that are already loaded by bukkit before Multiverse-Core is loaded.
*/
@@ -166,29 +170,40 @@ public class WorldManager {
* @return The result of the creation.
*/
public Result createWorld(CreateWorldOptions options) {
- // Params validations
+ return invalidateCreateWorldOptions(options).getOrElse(() -> createValidatedWorld(options));
+ }
+
+ private Option> invalidateCreateWorldOptions(
+ CreateWorldOptions options) {
+ Result result = null;
+
if (!worldNameChecker.isValidWorldName(options.worldName())) {
- return worldActionResult(CreateWorldResult.Failure.INVALID_WORLDNAME, options.worldName());
- }
- if (getLoadedWorld(options.worldName()).isDefined()) {
- return worldActionResult(CreateWorldResult.Failure.WORLD_EXIST_LOADED, options.worldName());
- }
- if (getWorld(options.worldName()).isDefined()) {
- return worldActionResult(CreateWorldResult.Failure.WORLD_EXIST_UNLOADED, options.worldName());
- }
- File worldFolder = new File(Bukkit.getWorldContainer(), options.worldName());
- if (worldFolder.exists()) {
- return worldActionResult(CreateWorldResult.Failure.WORLD_EXIST_FOLDER, options.worldName());
+ result = worldActionResult(CreateWorldResult.Failure.INVALID_WORLDNAME, options.worldName());
+ } else if (getLoadedWorld(options.worldName()).isDefined()) {
+ result = worldActionResult(CreateWorldResult.Failure.WORLD_EXIST_LOADED, options.worldName());
+ } else if (getWorld(options.worldName()).isDefined()) {
+ result = worldActionResult(CreateWorldResult.Failure.WORLD_EXIST_UNLOADED, options.worldName());
+ } else if (hasWorldFolder(options.worldName())) {
+ result = worldActionResult(CreateWorldResult.Failure.WORLD_EXIST_FOLDER, options.worldName());
}
+ return Option.of(result);
+ }
+
+ private boolean hasWorldFolder(String worldName) {
+ File worldFolder = new File(Bukkit.getWorldContainer(), worldName);
+ return worldFolder.exists();
+ }
+
+ private Result createValidatedWorld(
+ CreateWorldOptions options) {
String parsedGenerator = parseGenerator(options.worldName(), options.generator());
return createBukkitWorld(WorldCreator.name(options.worldName())
.environment(options.environment())
.generateStructures(options.generateStructures())
.generator(parsedGenerator)
.seed(options.seed())
- .type(options.worldType()))
- .fold(
+ .type(options.worldType())).fold(
exception -> worldActionResult(CreateWorldResult.Failure.BUKKIT_CREATION_FAILED,
options.worldName(), exception.getMessage()),
world -> {
@@ -197,7 +212,6 @@ public class WorldManager {
});
}
-
/**
* Imports an existing world folder.
*
@@ -205,25 +219,32 @@ public class WorldManager {
* @return The result of the import.
*/
public Result importWorld(ImportWorldOptions options) {
- // Params validations
+ return invalidateImportWorldOptions(options).getOrElse(() -> importValidatedWorld(options));
+ }
+
+ private Option> invalidateImportWorldOptions(
+ ImportWorldOptions options) {
+ Result result = null;
+
if (!worldNameChecker.isValidWorldName(options.worldName())) {
- return worldActionResult(ImportWorldResult.Failure.INVALID_WORLDNAME, options.worldName());
- }
- if (!worldNameChecker.isValidWorldFolder(options.worldName())) {
- return worldActionResult(ImportWorldResult.Failure.WORLD_FOLDER_INVALID, options.worldName());
- }
- if (isLoadedWorld(options.worldName())) {
- return worldActionResult(ImportWorldResult.Failure.WORLD_EXIST_LOADED, options.worldName());
- }
- if (isWorld(options.worldName())) {
- return worldActionResult(ImportWorldResult.Failure.WORLD_EXIST_UNLOADED, options.worldName());
+ result = worldActionResult(ImportWorldResult.Failure.INVALID_WORLDNAME, options.worldName());
+ } else if (!worldNameChecker.isValidWorldFolder(options.worldName())) {
+ result = worldActionResult(ImportWorldResult.Failure.WORLD_FOLDER_INVALID, options.worldName());
+ } else if (isLoadedWorld(options.worldName())) {
+ result = worldActionResult(ImportWorldResult.Failure.WORLD_EXIST_LOADED, options.worldName());
+ } else if (isWorld(options.worldName())) {
+ result = worldActionResult(ImportWorldResult.Failure.WORLD_EXIST_UNLOADED, options.worldName());
}
+ return Option.of(result);
+ }
+
+ private Result importValidatedWorld(
+ ImportWorldOptions options) {
String parsedGenerator = parseGenerator(options.worldName(), options.generator());
return createBukkitWorld(WorldCreator.name(options.worldName())
.environment(options.environment())
- .generator(parsedGenerator))
- .fold(
+ .generator(parsedGenerator)).fold(
exception -> worldActionResult(ImportWorldResult.Failure.BUKKIT_CREATION_FAILED,
options.worldName(), exception.getMessage()),
world -> {
@@ -291,17 +312,27 @@ public class WorldManager {
* @return The result of the load.
*/
public Result loadWorld(@NotNull MultiverseWorld mvWorld) {
- // Params validations
+ return invalidateWorldToLoad(mvWorld).getOrElse(() -> loadValidatedWorld(mvWorld));
+ }
+
+ private Option> invalidateWorldToLoad(
+ @NotNull MultiverseWorld mvWorld) {
+ Result result = null;
+
if (loadTracker.contains(mvWorld.getName())) {
// This is to prevent recursive calls by WorldLoadEvent
Logging.fine("World already loading: " + mvWorld.getName());
- return worldActionResult(LoadWorldResult.Failure.WORLD_ALREADY_LOADING, mvWorld.getName());
- }
- if (isLoadedWorld(mvWorld)) {
+ result = worldActionResult(LoadWorldResult.Failure.WORLD_ALREADY_LOADING, mvWorld.getName());
+ } else if (isLoadedWorld(mvWorld)) {
Logging.severe("World already loaded: " + mvWorld.getName());
- return worldActionResult(LoadWorldResult.Failure.WORLD_EXIST_LOADED, mvWorld.getName());
+ result = worldActionResult(LoadWorldResult.Failure.WORLD_EXIST_LOADED, mvWorld.getName());
}
+ return Option.of(result);
+ }
+
+ private Result loadValidatedWorld(
+ @NotNull MultiverseWorld mvWorld) {
return createBukkitWorld(WorldCreator.name(mvWorld.getName())
.environment(mvWorld.getEnvironment())
.generator(Strings.isNullOrEmpty(mvWorld.getGenerator()) ? null : mvWorld.getGenerator())
@@ -353,8 +384,8 @@ public class WorldManager {
* @param world The multiverse world to unload.
* @return The result of the unload action.
*/
- public Result
- unloadWorld(@NotNull LoadedMultiverseWorld world) {
+ public Result unloadWorld(
+ @NotNull LoadedMultiverseWorld world) {
if (unloadTracker.contains(world.getName())) {
// This is to prevent recursive calls by WorldUnloadEvent
Logging.fine("World already unloading: " + world.getName());
@@ -385,8 +416,8 @@ public class WorldManager {
* @param worldName The name of the world to remove.
* @return The result of the remove.
*/
- public Result
- removeWorld(@NotNull String worldName) {
+ public Result removeWorld(
+ @NotNull String worldName) {
return getWorld(worldName)
.map(this::removeWorld)
.getOrElse(() -> worldActionResult(RemoveWorldResult.Failure.WORLD_NON_EXISTENT, worldName));
@@ -412,8 +443,8 @@ public class WorldManager {
* @param loadedWorld The multiverse world to remove.
* @return The result of the remove.
*/
- public Result
- removeWorld(@NotNull LoadedMultiverseWorld loadedWorld) {
+ public Result removeWorld(
+ @NotNull LoadedMultiverseWorld loadedWorld) {
var result = unloadWorld(loadedWorld);
if (result.isFailure()) {
return Result.failure(RemoveWorldResult.Failure.UNLOAD_FAILED, result.getReasonMessage());
@@ -524,8 +555,8 @@ public class WorldManager {
}));
}
- private Result
- cloneWorldValidateWorld(@NotNull CloneWorldOptions options) {
+ private Result cloneWorldValidateWorld(
+ @NotNull CloneWorldOptions options) {
String newWorldName = options.newWorldName();
if (!worldNameChecker.isValidWorldName(newWorldName)) {
Logging.severe("Invalid world name: " + newWorldName);
@@ -545,8 +576,8 @@ public class WorldManager {
return Result.success();
}
- private Result
- cloneWorldCopyFolder(@NotNull CloneWorldOptions options) {
+ private Result cloneWorldCopyFolder(
+ @NotNull CloneWorldOptions options) {
// TODO: Check null?
File worldFolder = options.world().getBukkitWorld().map(World::getWorldFolder).getOrNull();
File newWorldFolder = new File(Bukkit.getWorldContainer(), options.newWorldName());
@@ -557,8 +588,14 @@ public class WorldManager {
}
private void cloneWorldTransferData(@NotNull CloneWorldOptions options, @NotNull LoadedMultiverseWorld newWorld) {
- LoadedMultiverseWorld world = options.world();
+ DataTransfer dataTransfer = transferData(options, options.world());
+ dataTransfer.pasteAllTo(newWorld);
+ }
+
+ private DataTransfer transferData(
+ @NotNull KeepWorldSettingsOptions options, @NotNull LoadedMultiverseWorld world) {
DataTransfer dataTransfer = new DataTransfer<>();
+
if (options.keepWorldConfig()) {
dataTransfer.addDataStore(new WorldConfigStore(), world);
}
@@ -568,7 +605,8 @@ public class WorldManager {
if (options.keepWorldBorder()) {
dataTransfer.addDataStore(new WorldBorderStore(), world);
}
- dataTransfer.pasteAllTo(newWorld);
+
+ return dataTransfer;
}
/**
@@ -581,16 +619,7 @@ public class WorldManager {
// TODO: Teleport players out of world, and back in after regen
LoadedMultiverseWorld world = options.world();
- DataTransfer dataTransfer = new DataTransfer<>();
- if (options.keepWorldConfig()) {
- dataTransfer.addDataStore(new WorldConfigStore(), world);
- }
- if (options.keepGameRule()) {
- dataTransfer.addDataStore(new GameRulesStore(), world);
- }
- if (options.keepWorldBorder()) {
- dataTransfer.addDataStore(new WorldBorderStore(), world);
- }
+ DataTransfer dataTransfer = transferData(options, world);
CreateWorldOptions createWorldOptions = CreateWorldOptions.worldName(world.getName())
.environment(world.getEnvironment())
diff --git a/src/main/java/com/onarandombox/MultiverseCore/worldnew/options/CloneWorldOptions.java b/src/main/java/com/onarandombox/MultiverseCore/worldnew/options/CloneWorldOptions.java
index e6b66366..153e2dd1 100644
--- a/src/main/java/com/onarandombox/MultiverseCore/worldnew/options/CloneWorldOptions.java
+++ b/src/main/java/com/onarandombox/MultiverseCore/worldnew/options/CloneWorldOptions.java
@@ -6,7 +6,7 @@ import org.jetbrains.annotations.NotNull;
/**
* Options for customizing the cloning of a world.
*/
-public class CloneWorldOptions {
+public final class CloneWorldOptions implements KeepWorldSettingsOptions {
/**
* Creates a new {@link CloneWorldOptions} instance with the given world.
@@ -55,6 +55,7 @@ public class CloneWorldOptions {
* @param keepGameRule Whether to keep the game rule of the world during cloning.
* @return This {@link CloneWorldOptions} instance.
*/
+ @Override
public @NotNull CloneWorldOptions keepGameRule(boolean keepGameRule) {
this.keepGameRule = keepGameRule;
return this;
@@ -65,10 +66,12 @@ public class CloneWorldOptions {
*
* @return Whether to keep the game rule of the world during cloning.
*/
+ @Override
public boolean keepGameRule() {
return keepGameRule;
}
+ @Override
public @NotNull CloneWorldOptions keepWorldConfig(boolean keepWorldConfig) {
this.keepWorldConfig = keepWorldConfig;
return this;
@@ -79,10 +82,12 @@ public class CloneWorldOptions {
*
* @return Whether to keep the world config of the world during cloning.
*/
+ @Override
public boolean keepWorldConfig() {
return keepWorldConfig;
}
+ @Override
public @NotNull CloneWorldOptions keepWorldBorder(boolean keepWorldBorder) {
this.keepWorldBorder = keepWorldBorder;
return this;
@@ -93,6 +98,7 @@ public class CloneWorldOptions {
*
* @return Whether to keep the world border of the world during cloning.
*/
+ @Override
public boolean keepWorldBorder() {
return keepWorldBorder;
}
diff --git a/src/main/java/com/onarandombox/MultiverseCore/worldnew/options/KeepWorldSettingsOptions.java b/src/main/java/com/onarandombox/MultiverseCore/worldnew/options/KeepWorldSettingsOptions.java
new file mode 100644
index 00000000..51a6bb94
--- /dev/null
+++ b/src/main/java/com/onarandombox/MultiverseCore/worldnew/options/KeepWorldSettingsOptions.java
@@ -0,0 +1,51 @@
+package com.onarandombox.MultiverseCore.worldnew.options;
+
+import org.jetbrains.annotations.NotNull;
+
+public sealed interface KeepWorldSettingsOptions permits CloneWorldOptions, RegenWorldOptions {
+
+ /**
+ * Sets whether to keep the game rule of the world.
+ *
+ * @param keepGameRule Whether to keep the game rule of the world.
+ * @return This {@link KeepWorldSettingsOptions} instance.
+ */
+ @NotNull KeepWorldSettingsOptions keepGameRule(boolean keepGameRule);
+
+ /**
+ * Gets whether to keep the game rule of the world.
+ *
+ * @return Whether to keep the game rule of the world.
+ */
+ boolean keepGameRule();
+
+ /**
+ * Sets whether to keep the world config of the world.
+ *
+ * @param keepWorldConfig Whether to keep the world config of the world.
+ * @return This {@link KeepWorldSettingsOptions} instance.
+ */
+ @NotNull KeepWorldSettingsOptions keepWorldConfig(boolean keepWorldConfig);
+
+ /**
+ * Gets whether to keep the world config of the world.
+ *
+ * @return Whether to keep the world config of the world.
+ */
+ boolean keepWorldConfig();
+
+ /**
+ * Sets whether to keep the world border of the world.
+ *
+ * @param keepWorldBorder Whether to keep the world border of the world.
+ * @return This {@link KeepWorldSettingsOptions} instance.
+ */
+ @NotNull KeepWorldSettingsOptions keepWorldBorder(boolean keepWorldBorder);
+
+ /**
+ * Gets whether to keep the world border of the world.
+ *
+ * @return Whether to keep the world border of the world.
+ */
+ boolean keepWorldBorder();
+}
diff --git a/src/main/java/com/onarandombox/MultiverseCore/worldnew/options/RegenWorldOptions.java b/src/main/java/com/onarandombox/MultiverseCore/worldnew/options/RegenWorldOptions.java
index 9cd9c8d7..00ed0476 100644
--- a/src/main/java/com/onarandombox/MultiverseCore/worldnew/options/RegenWorldOptions.java
+++ b/src/main/java/com/onarandombox/MultiverseCore/worldnew/options/RegenWorldOptions.java
@@ -9,7 +9,7 @@ import java.util.Random;
/**
* Options for customizing the regeneration of a world.
*/
-public class RegenWorldOptions {
+public final class RegenWorldOptions implements KeepWorldSettingsOptions {
/**
* Creates a new {@link RegenWorldOptions} instance with the given world.
@@ -48,6 +48,7 @@ public class RegenWorldOptions {
* @param keepGameRule Whether to keep the game rule of the world during regeneration.
* @return This {@link RegenWorldOptions} instance.
*/
+ @Override
public @NotNull RegenWorldOptions keepGameRule(boolean keepGameRule) {
this.keepGameRule = keepGameRule;
return this;
@@ -58,6 +59,7 @@ public class RegenWorldOptions {
*
* @return Whether to keep the game rule of the world during regeneration.
*/
+ @Override
public boolean keepGameRule() {
return keepGameRule;
}
@@ -68,6 +70,7 @@ public class RegenWorldOptions {
* @param keepWorldConfig Whether to keep the world config of the world during regeneration.
* @return This {@link RegenWorldOptions} instance.
*/
+ @Override
public @NotNull RegenWorldOptions keepWorldConfig(boolean keepWorldConfig) {
this.keepWorldConfig = keepWorldConfig;
return this;