Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@
import co.aikar.commands.annotation.CommandAlias;
import co.aikar.commands.annotation.CommandCompletion;
import co.aikar.commands.annotation.CommandPermission;
import co.aikar.commands.annotation.Conditions;
import co.aikar.commands.annotation.Description;
import co.aikar.commands.annotation.Single;
import co.aikar.commands.annotation.Optional;
import co.aikar.commands.annotation.Subcommand;
import co.aikar.commands.annotation.Syntax;
import com.dumptruckman.minecraft.util.Logging;
Expand All @@ -15,19 +14,26 @@

import org.mvplugins.multiverse.core.command.LegacyAliasCommand;
import org.mvplugins.multiverse.core.command.MVCommandIssuer;
import org.mvplugins.multiverse.core.command.MVCommandManager;
import org.mvplugins.multiverse.core.command.flag.CommandFlag;
import org.mvplugins.multiverse.core.command.flag.CommandFlagsManager;
import org.mvplugins.multiverse.core.command.flag.ParsedCommandFlags;
import org.mvplugins.multiverse.core.command.flags.RemovePlayerFlags;
import org.mvplugins.multiverse.core.locale.MVCorei18n;
import org.mvplugins.multiverse.core.locale.message.MessageReplacement.Replace;
import org.mvplugins.multiverse.core.world.MultiverseWorld;
import org.mvplugins.multiverse.core.world.WorldManager;
import org.mvplugins.multiverse.core.world.options.LoadWorldOptions;

@Service
class LoadCommand extends CoreCommand {

private final WorldManager worldManager;
private final LoadCommand.Flags flags;

@Inject
LoadCommand(@NotNull WorldManager worldManager) {
LoadCommand(@NotNull WorldManager worldManager, @NotNull Flags flags) {
this.worldManager = worldManager;
this.flags = flags;
}

@Subcommand("load")
Expand All @@ -38,13 +44,19 @@ class LoadCommand extends CoreCommand {
void onLoadCommand(
MVCommandIssuer issuer,

@Single
@Conditions("worldname:scope=unloaded")
@Syntax("<world>")
@Description("{@@mv-core.load.world.description}")
String worldName) {
issuer.sendInfo(MVCorei18n.LOAD_LOADING, Replace.WORLD.with(worldName));
worldManager.loadWorld(worldName)
MultiverseWorld world,

@Optional
@Syntax("[--remove-players]")
@Description("")
String[] flagArray) {
ParsedCommandFlags parsedFlags = flags.parse(flagArray);

issuer.sendInfo(MVCorei18n.LOAD_LOADING, Replace.WORLD.with(world.getName()));
worldManager.loadWorld(LoadWorldOptions.world(world)
.doFolderCheck(!parsedFlags.hasFlag(flags.skipFolderCheck)))
.onSuccess(newWorld -> {
Logging.fine("World load success: " + newWorld);
issuer.sendInfo(MVCorei18n.LOAD_SUCCESS, Replace.WORLD.with(newWorld.getName()));
Expand All @@ -54,17 +66,32 @@ void onLoadCommand(
});
}

@Service
private static final class Flags extends RemovePlayerFlags {

private static final String NAME = "mvunload";

@Inject
private Flags(@NotNull CommandFlagsManager flagsManager) {
super(NAME, flagsManager);
}

private final CommandFlag skipFolderCheck = flag(CommandFlag.builder("--skip-folder-check")
.addAlias("-f")
.build());
}

@Service
private static final class LegacyAlias extends LoadCommand implements LegacyAliasCommand {
@Inject
LegacyAlias(@NotNull WorldManager worldManager) {
super(worldManager);
LegacyAlias(@NotNull WorldManager worldManager, @NotNull Flags flags) {
super(worldManager, flags);
}

@Override
@CommandAlias("mvload")
void onLoadCommand(MVCommandIssuer issuer, String worldName) {
super.onLoadCommand(issuer, worldName);
void onLoadCommand(MVCommandIssuer issuer, MultiverseWorld world, String[] flagArray) {
super.onLoadCommand(issuer, world, flagArray);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.mvplugins.multiverse.core.dynamiclistener.annotations.DefaultEventPriority;
import org.mvplugins.multiverse.core.dynamiclistener.annotations.EventMethod;
import org.mvplugins.multiverse.core.world.WorldManager;
import org.mvplugins.multiverse.core.world.options.LoadWorldOptions;
import org.mvplugins.multiverse.core.world.options.UnloadWorldOptions;
import org.mvplugins.multiverse.core.world.reasons.LoadFailureReason;
import org.mvplugins.multiverse.core.world.reasons.UnloadFailureReason;
Expand Down Expand Up @@ -68,7 +69,7 @@ void worldLoad(WorldLoadEvent event) {
worldManager.getUnloadedWorld(event.getWorld().getName())
.peek(world -> {
Logging.fine("Loading world: " + world.getName());
worldManager.loadWorld(world).onFailure(failure -> {
worldManager.loadWorld(LoadWorldOptions.world(world)).onFailure(failure -> {
if (failure.getFailureReason() != LoadFailureReason.WORLD_ALREADY_LOADING) {
Logging.severe("Failed to load world: " + failure);
}
Expand Down
68 changes: 51 additions & 17 deletions src/main/java/org/mvplugins/multiverse/core/world/WorldManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
import org.mvplugins.multiverse.core.world.options.DeleteWorldOptions;
import org.mvplugins.multiverse.core.world.options.ImportWorldOptions;
import org.mvplugins.multiverse.core.world.options.KeepWorldSettingsOptions;
import org.mvplugins.multiverse.core.world.options.LoadWorldOptions;
import org.mvplugins.multiverse.core.world.options.RegenWorldOptions;
import org.mvplugins.multiverse.core.world.options.RemoveWorldOptions;
import org.mvplugins.multiverse.core.world.options.UnloadWorldOptions;
Expand Down Expand Up @@ -226,8 +227,9 @@
if (isLoadedWorld(world) || !world.isAutoLoad()) {
return;
}
loadWorld(world).onFailure(failure -> Logging.severe("Failed to load world %s: %s",
world.getName(), failure));
loadWorld(LoadWorldOptions.world(world))
.onFailure(failure ->
Logging.severe("Failed to load world %s: %s", world.getName(), failure));
});
}

Expand Down Expand Up @@ -403,10 +405,14 @@
*
* @param worldName The name of the world to load.
* @return The result of the load.
*
* @deprecated Use {@link #loadWorld(LoadWorldOptions)} instead.
*/
@Deprecated(since = "5.2", forRemoval = true)
@ApiStatus.ScheduledForRemoval(inVersion = "6.0")
public Attempt<LoadedMultiverseWorld, LoadFailureReason> loadWorld(@NotNull String worldName) {
return getWorld(worldName)
.map(this::loadWorld)
.map(world -> loadWorld(LoadWorldOptions.world(world)))
.getOrElse(() -> worldNameChecker.isValidWorldFolder(worldName)
? worldActionResult(LoadFailureReason.WORLD_EXIST_FOLDER, worldName)
: worldActionResult(LoadFailureReason.WORLD_NON_EXISTENT, worldName));
Expand All @@ -417,12 +423,30 @@
*
* @param world The world to load.
* @return The result of the load.
*
* @deprecated Use {@link #loadWorld(LoadWorldOptions)} instead.
*/
@Deprecated(since = "5.2", forRemoval = true)
@ApiStatus.ScheduledForRemoval(inVersion = "6.0")
public Attempt<LoadedMultiverseWorld, LoadFailureReason> loadWorld(@NotNull MultiverseWorld world) {
return validateWorldToLoad(world).mapAttempt(this::doLoadWorld);
return loadWorld(LoadWorldOptions.world(world));
}

private Attempt<MultiverseWorld, LoadFailureReason> validateWorldToLoad(@NotNull MultiverseWorld mvWorld) {
/**
* Loads an existing world in config.
*
* @param options The options for customizing the loading of a world.
* @return The result of the load.
*
* @since 5.2
*/
@ApiStatus.AvailableSince("5.2")
public Attempt<LoadedMultiverseWorld, LoadFailureReason> loadWorld(@NotNull LoadWorldOptions options) {
return validateWorldToLoad(options).mapAttempt(this::doLoadWorld);
}

private Attempt<LoadWorldOptions, LoadFailureReason> validateWorldToLoad(@NotNull LoadWorldOptions options) {

Check warning on line 448 in src/main/java/org/mvplugins/multiverse/core/world/WorldManager.java

View workflow job for this annotation

GitHub Actions / checkstyle / checkstyle

[checkstyle] reported by reviewdog 🐶 Return count is 3 (max allowed for non-void methods/lambdas is 2). Raw Output: /github/workspace/./src/main/java/org/mvplugins/multiverse/core/world/WorldManager.java:448:5: info: Return count is 3 (max allowed for non-void methods/lambdas is 2). (com.puppycrawl.tools.checkstyle.checks.coding.ReturnCountCheck)
MultiverseWorld mvWorld = options.world();
if (loadTracker.contains(mvWorld.getName())) {
// This is to prevent recursive calls by WorldLoadEvent
Logging.fine("World already loading: " + mvWorld.getName());
Expand All @@ -431,21 +455,19 @@
Logging.severe("World already loaded: " + mvWorld.getName());
return worldActionResult(LoadFailureReason.WORLD_EXIST_LOADED, mvWorld.getName());
}
return worldActionResult(mvWorld);
return worldActionResult(options);
}

private Attempt<LoadedMultiverseWorld, LoadFailureReason> doLoadWorld(@NotNull MultiverseWorld mvWorld) {
private Attempt<LoadedMultiverseWorld, LoadFailureReason> doLoadWorld(@NotNull LoadWorldOptions options) {

Check warning on line 461 in src/main/java/org/mvplugins/multiverse/core/world/WorldManager.java

View workflow job for this annotation

GitHub Actions / checkstyle / checkstyle

[checkstyle] reported by reviewdog 🐶 Return count is 3 (max allowed for non-void methods/lambdas is 2). Raw Output: /github/workspace/./src/main/java/org/mvplugins/multiverse/core/world/WorldManager.java:461:5: info: Return count is 3 (max allowed for non-void methods/lambdas is 2). (com.puppycrawl.tools.checkstyle.checks.coding.ReturnCountCheck)
MultiverseWorld mvWorld = options.world();

World bukkitWorld = Bukkit.getWorld(mvWorld.getName());
if (bukkitWorld != null) {
if (bukkitWorld.getEnvironment() != mvWorld.getEnvironment()) {
return Attempt.failure(LoadFailureReason.BUKKIT_ENVIRONMENT_MISMATCH,
Replace.WORLD.with(mvWorld.getName()),
replace("{bukkitEnvironment}").with(bukkitWorld.getEnvironment().name()),
replace("{mvEnvironment}").with(mvWorld.getEnvironment().name()));
}
// World already loaded, maybe by another plugin
Logging.finer("World already loaded in bukkit: " + mvWorld.getName());
return newLoadedMultiverseWorld(mvWorld, bukkitWorld);
return doLoadBukkitWorld(bukkitWorld, mvWorld);
}

if (options.doFolderCheck() && !worldNameChecker.isValidWorldFolder(mvWorld.getName())) {
return worldActionResult(LoadFailureReason.WORLD_FOLDER_INVALID, mvWorld.getName());
}

WorldCreator worldCreator = WorldCreator.name(mvWorld.getName())
Expand All @@ -458,6 +480,18 @@
.mapAttempt(newBukkitWorld -> newLoadedMultiverseWorld(mvWorld, newBukkitWorld));
}

private @NotNull Attempt<LoadedMultiverseWorld, LoadFailureReason> doLoadBukkitWorld(World bukkitWorld, MultiverseWorld mvWorld) {

Check warning on line 483 in src/main/java/org/mvplugins/multiverse/core/world/WorldManager.java

View workflow job for this annotation

GitHub Actions / checkstyle / checkstyle

[checkstyle] reported by reviewdog 🐶 Line is longer than 120 characters (found 134). Raw Output: /github/workspace/./src/main/java/org/mvplugins/multiverse/core/world/WorldManager.java:483:0: warning: Line is longer than 120 characters (found 134). (com.puppycrawl.tools.checkstyle.checks.sizes.LineLengthCheck)
if (bukkitWorld.getEnvironment() != mvWorld.getEnvironment()) {
return Attempt.failure(LoadFailureReason.BUKKIT_ENVIRONMENT_MISMATCH,
Replace.WORLD.with(mvWorld.getName()),
replace("{bukkitEnvironment}").with(bukkitWorld.getEnvironment().name()),
replace("{mvEnvironment}").with(mvWorld.getEnvironment().name()));
}
// World already loaded, maybe by another plugin
Logging.finer("World already loaded in bukkit: " + mvWorld.getName());
return newLoadedMultiverseWorld(mvWorld, bukkitWorld);
}

private Attempt<LoadedMultiverseWorld, LoadFailureReason> newLoadedMultiverseWorld(MultiverseWorld mvWorld, World bukkitWorld) {
WorldConfig worldConfig = worldsConfigManager.getWorldConfig(mvWorld.getName()).get(); //TODO: null check here, but logically it should never be null.
LoadedMultiverseWorld loadedWorld = new LoadedMultiverseWorld(
Expand Down Expand Up @@ -615,7 +649,7 @@
*/
public Attempt<String, DeleteFailureReason> deleteWorld(@NotNull DeleteWorldOptions options) {
return getLoadedWorld(options.world()).fold(
() -> loadWorld(options.world())
() -> loadWorld(LoadWorldOptions.world(options.world()))
.transform(DeleteFailureReason.LOAD_FAILED)
.mapAttempt(world -> doDeleteWorld(world, options)),
world -> doDeleteWorld(world, options));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package org.mvplugins.multiverse.core.world.options;

import org.jetbrains.annotations.ApiStatus;
import org.mvplugins.multiverse.core.world.MultiverseWorld;

Check warning on line 4 in src/main/java/org/mvplugins/multiverse/core/world/options/LoadWorldOptions.java

View workflow job for this annotation

GitHub Actions / checkstyle / checkstyle

[checkstyle] reported by reviewdog 🐶 'org.mvplugins.multiverse.core.world.MultiverseWorld' should be separated from previous imports. Raw Output: /github/workspace/./src/main/java/org/mvplugins/multiverse/core/world/options/LoadWorldOptions.java:4:1: warning: 'org.mvplugins.multiverse.core.world.MultiverseWorld' should be separated from previous imports. (com.puppycrawl.tools.checkstyle.checks.imports.ImportOrderCheck)

/**
* Options for customizing the loading of a world.
*
* @since 5.2
*/
@ApiStatus.AvailableSince("5.2")
public final class LoadWorldOptions {

/**
* Creates a new {@link LoadWorldOptions} instance with the given world.
*
* @param world The world to load.
* @return A new {@link LoadWorldOptions} instance.
*
* @since 5.2
*/
@ApiStatus.AvailableSince("5.2")
public static LoadWorldOptions world(MultiverseWorld world) {
return new LoadWorldOptions(world);
}

private final MultiverseWorld world;
private boolean doFolderCheck = true;

LoadWorldOptions(MultiverseWorld world) {
this.world = world;
}

/**
* Gets the world to load.
*
* @return The world to load.
*
* @since 5.2
*/
@ApiStatus.AvailableSince("5.2")
public MultiverseWorld world() {
return world;
}

/**
* Sets whether to check if the world folder is valid before loading the world.
* <br />
* This helps to prevent deleted world folders from being re-created.
*
* @return Whether to check if the world folder is valid before loading the world.
*
* @since 5.2
*/
@ApiStatus.AvailableSince("5.2")
public boolean doFolderCheck() {
return doFolderCheck;
}

/**
* Sets whether to check if the world folder is valid before loading the world.
*
* @return This {@link LoadWorldOptions} instance.
*
* @since 5.2
*/
@ApiStatus.AvailableSince("5.2")
public LoadWorldOptions doFolderCheck(boolean doFolderCheck) {

Check warning on line 68 in src/main/java/org/mvplugins/multiverse/core/world/options/LoadWorldOptions.java

View workflow job for this annotation

GitHub Actions / checkstyle / checkstyle

[checkstyle] reported by reviewdog 🐶 Expected @param tag for 'doFolderCheck'. Raw Output: /github/workspace/./src/main/java/org/mvplugins/multiverse/core/world/options/LoadWorldOptions.java:68:51: warning: Expected @param tag for 'doFolderCheck'. (com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocMethodCheck)
this.doFolderCheck = doFolderCheck;
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ public enum LoadFailureReason implements FailureReason {
*/
WORLD_EXIST_FOLDER(MVCorei18n.LOADWORLD_WORLDEXISTFOLDER),

/**
* The world folder is invalid.
*
* @since 5.2
*/
@ApiStatus.AvailableSince("5.2")
WORLD_FOLDER_INVALID(MVCorei18n.IMPORTWORLD_WORLDFOLDERINVALID),

/**
* The world is already loaded.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import org.mvplugins.multiverse.core.event.world.*
import org.mvplugins.multiverse.core.world.options.CloneWorldOptions
import org.mvplugins.multiverse.core.world.options.CreateWorldOptions
import org.mvplugins.multiverse.core.world.options.DeleteWorldOptions
import org.mvplugins.multiverse.core.world.options.LoadWorldOptions
import org.mvplugins.multiverse.core.world.options.RegenWorldOptions
import org.mvplugins.multiverse.core.world.options.RemoveWorldOptions
import org.mvplugins.multiverse.core.world.options.UnloadWorldOptions
Expand Down Expand Up @@ -133,13 +134,23 @@ class WorldManagerTest : TestWithMockBukkit() {
assertTrue(worldManager.getWorld("world2").isDefined)
assertTrue(worldManager.getUnloadedWorld("world2").isDefined)

assertTrue(worldManager.loadWorld("world2").isSuccess)
assertTrue(worldManager.loadWorld(LoadWorldOptions.world(world2)).isSuccess)
assertTrue(world2.isLoaded)
assertTrue(worldManager.getLoadedWorld("world2").flatMap{ w -> w.bukkitWorld }.isDefined)
assertTrue(worldManager.getLoadedWorld("world2").isDefined)
assertFalse(worldManager.getUnloadedWorld("world2").isDefined)
}

@Test
fun `Load world failed - invalid world folder`() {
assertTrue(worldManager.unloadWorld(UnloadWorldOptions.world(world2)).isSuccess)
File(Bukkit.getWorldContainer(), "world2/").deleteRecursively()
assertEquals(
LoadFailureReason.WORLD_FOLDER_INVALID,
worldManager.loadWorld(LoadWorldOptions.world(world2)).failureReason
)
}

@Test
fun `Load world failed - non-existent world`() {
assertEquals(
Expand Down
Loading