diff --git a/src/main/java/org/mvplugins/multiverse/core/command/flag/CommandValueFlag.java b/src/main/java/org/mvplugins/multiverse/core/command/flag/CommandValueFlag.java index 24f0f67df..85b689cdb 100644 --- a/src/main/java/org/mvplugins/multiverse/core/command/flag/CommandValueFlag.java +++ b/src/main/java/org/mvplugins/multiverse/core/command/flag/CommandValueFlag.java @@ -5,8 +5,10 @@ import java.util.List; import java.util.Locale; import java.util.function.Function; +import java.util.function.Supplier; import co.aikar.commands.InvalidCommandArgument; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -40,34 +42,34 @@ public class CommandValueFlag extends CommandFlag { private final Class type; private final boolean optional; - private final T defaultValue; + private final Supplier defaultValueSupplier; private final Function context; private final Function> completion; /** * Creates a new flag. * - * @param key The key for the new flag. - * @param aliases The aliases that also refer to this flag. - * @param type The type of the value. - * @param optional Allow for flag without value. - * @param defaultValue The default value if optional is true and user does not specify a value. - * @param context Function to parse string into value type. - * @param completion Function to get completion for this flag. + * @param key The key for the new flag. + * @param aliases The aliases that also refer to this flag. + * @param type The type of the value. + * @param optional Allow for flag without value. + * @param defaultValueSupplier The default value if optional is true and user does not specify a value. + * @param context Function to parse string into value type. + * @param completion Function to get completion for this flag. */ protected CommandValueFlag( @NotNull String key, @NotNull List aliases, @NotNull Class type, boolean optional, - @Nullable T defaultValue, + @Nullable Supplier defaultValueSupplier, @Nullable Function context, @Nullable Function> completion ) { super(key, aliases); this.type = type; this.optional = optional; - this.defaultValue = defaultValue; + this.defaultValueSupplier = defaultValueSupplier; this.context = context; this.completion = completion; } @@ -96,7 +98,7 @@ public boolean isOptional() { * @return The default value. */ public @Nullable T getDefaultValue() { - return defaultValue; + return defaultValueSupplier == null ? null : defaultValueSupplier.get(); } /** @@ -126,7 +128,7 @@ public boolean isOptional() { public static class Builder> extends CommandFlag.Builder { protected final Class type; protected boolean optional = false; - protected T defaultValue = null; + protected Supplier defaultValueSupplier = null; protected Function context = null; protected Function> completion = null; @@ -158,7 +160,21 @@ public Builder(@NotNull String key, @NotNull Class type) { * @return The builder. */ public @NotNull S defaultValue(@NotNull T defaultValue) { - this.defaultValue = defaultValue; + return defaultValue(() -> defaultValue); + } + + /** + * Set the default value supplier. Used if optional is true and user does not specify a value. + * Supplier is only called when command is executed with the flag is present in input. + * + * @param defaultValueSupplier The default value supplier + * @return The builder + * + * @since 5.7 + */ + @ApiStatus.AvailableSince("5.7") + public @NotNull S defaultValue(@NotNull Supplier defaultValueSupplier) { + this.defaultValueSupplier = defaultValueSupplier; return (S) this; } @@ -194,7 +210,7 @@ public Builder(@NotNull String key, @NotNull Class type) { if (context == null && !String.class.equals(type)) { throw new IllegalStateException("Context is required for non-string value flags"); } - return new CommandValueFlag<>(key, aliases, type, optional, defaultValue, context, completion); + return new CommandValueFlag<>(key, aliases, type, optional, defaultValueSupplier, context, completion); } } @@ -207,7 +223,7 @@ public Builder(@NotNull String key, @NotNull Class type) { public static class EnumBuilder, S extends EnumBuilder> extends CommandFlag.Builder { protected final Class type; protected boolean optional = false; - protected T defaultValue = null; + protected Supplier defaultValueSupplier = null; protected Function context = null; protected Function> completion = null; @@ -253,7 +269,21 @@ private void setEnumCompletion() { * @return The builder. */ public @NotNull S defaultValue(@NotNull T defaultValue) { - this.defaultValue = defaultValue; + return defaultValue(() -> defaultValue); + } + + /** + * Set the default value to supply. Used if optional is true and user does not specify a value. + * Supplier is only called when command is executed with the flag is present in input. + * + * @param defaultValueSupplier The default value supplier. + * @return The builder. + * + * @since 5.7 + */ + @ApiStatus.AvailableSince("5.7") + public @NotNull S defaultValue(@NotNull Supplier defaultValueSupplier) { + this.defaultValueSupplier = defaultValueSupplier; return (S) this; } @@ -264,7 +294,7 @@ private void setEnumCompletion() { */ @Override public @NotNull CommandValueFlag build() { - return new CommandValueFlag<>(key, aliases, type, optional, defaultValue, context, completion); + return new CommandValueFlag<>(key, aliases, type, optional, defaultValueSupplier, context, completion); } } } diff --git a/src/main/java/org/mvplugins/multiverse/core/command/flags/RemovePlayerDestinationFlags.java b/src/main/java/org/mvplugins/multiverse/core/command/flags/RemovePlayerDestinationFlags.java new file mode 100644 index 000000000..a2f7fb875 --- /dev/null +++ b/src/main/java/org/mvplugins/multiverse/core/command/flags/RemovePlayerDestinationFlags.java @@ -0,0 +1,65 @@ +package org.mvplugins.multiverse.core.command.flags; + +import co.aikar.commands.InvalidCommandArgument; +import jakarta.inject.Inject; +import org.bukkit.Bukkit; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; +import org.jvnet.hk2.annotations.Service; +import org.mvplugins.multiverse.core.command.flag.CommandFlagsManager; +import org.mvplugins.multiverse.core.command.flag.CommandValueFlag; +import org.mvplugins.multiverse.core.command.flag.FlagBuilder; +import org.mvplugins.multiverse.core.destination.DestinationInstance; +import org.mvplugins.multiverse.core.destination.DestinationsProvider; +import org.mvplugins.multiverse.core.destination.core.WorldDestination; +import org.mvplugins.multiverse.core.exceptions.command.MVInvalidCommandArgument; +import org.mvplugins.multiverse.core.world.WorldManager; + +@ApiStatus.AvailableSince("5.7") +@Service +public class RemovePlayerDestinationFlags extends FlagBuilder { + + public static final String NAME = "removeplayer"; + + private WorldManager worldManager; + private DestinationsProvider destinationsProvider; + private WorldDestination worldDestination; + + protected RemovePlayerDestinationFlags( + @NotNull String name, + @NotNull CommandFlagsManager flagsManager, + @NotNull WorldManager worldManager, + @NotNull DestinationsProvider destinationsProvider, + @NotNull WorldDestination worldDestination + ) { + super(name, flagsManager); + this.worldManager = worldManager; + this.destinationsProvider = destinationsProvider; + this.worldDestination = worldDestination; + } + + @Inject + private RemovePlayerDestinationFlags( + @NotNull CommandFlagsManager flagsManager, + @NotNull WorldManager worldManager, + @NotNull DestinationsProvider destinationsProvider, + @NotNull WorldDestination worldDestination + ) { + super(NAME, flagsManager); + this.destinationsProvider = destinationsProvider; + this.worldManager = worldManager; + this.worldDestination = worldDestination; + } + + public final CommandValueFlag removePlayers = flag(CommandValueFlag.builder("--remove-players", DestinationInstance.class) + .addAlias("-r") + .defaultValue(() -> worldManager.getDefaultWorld() + .map(defaultWorld -> worldDestination.fromWorld(defaultWorld)) + .getOrElseThrow(() -> new InvalidCommandArgument("No default world found, so the --remove-players flag requires a destination argument."))) //TODO: locale + .completion(input -> destinationsProvider.suggestDestinationStrings(Bukkit.getConsoleSender(), input)) + .context(input -> destinationsProvider.parseDestination(input) + .getOrThrow(failure -> + MVInvalidCommandArgument.of(failure.getFailureMessage()))) + .optional() + .build()); +} diff --git a/src/main/java/org/mvplugins/multiverse/core/command/flags/RemovePlayerFlags.java b/src/main/java/org/mvplugins/multiverse/core/command/flags/RemovePlayerFlags.java index 11c37fa3f..0f16b54b7 100644 --- a/src/main/java/org/mvplugins/multiverse/core/command/flags/RemovePlayerFlags.java +++ b/src/main/java/org/mvplugins/multiverse/core/command/flags/RemovePlayerFlags.java @@ -1,12 +1,19 @@ package org.mvplugins.multiverse.core.command.flags; import jakarta.inject.Inject; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jvnet.hk2.annotations.Service; import org.mvplugins.multiverse.core.command.flag.CommandFlag; import org.mvplugins.multiverse.core.command.flag.CommandFlagsManager; import org.mvplugins.multiverse.core.command.flag.FlagBuilder; +/** + * @deprecated The --remove-players flag is being removed in favor of a more flexible system that allows for specifying + * a destination for players to be teleported to when a world is unloaded. See {@link RemovePlayerDestinationFlags}. + */ +@Deprecated(forRemoval = true, since = "5.7") +@ApiStatus.ScheduledForRemoval(inVersion = "6.0") @Service public class RemovePlayerFlags extends FlagBuilder { diff --git a/src/main/java/org/mvplugins/multiverse/core/commands/DeleteCommand.java b/src/main/java/org/mvplugins/multiverse/core/commands/DeleteCommand.java index 7b6c86b9d..c5119e535 100644 --- a/src/main/java/org/mvplugins/multiverse/core/commands/DeleteCommand.java +++ b/src/main/java/org/mvplugins/multiverse/core/commands/DeleteCommand.java @@ -15,11 +15,11 @@ 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.ParsedCommandFlags; -import org.mvplugins.multiverse.core.command.flags.RemovePlayerFlags; +import org.mvplugins.multiverse.core.command.flags.RemovePlayerDestinationFlags; import org.mvplugins.multiverse.core.command.queue.CommandQueueManager; import org.mvplugins.multiverse.core.command.queue.CommandQueuePayload; +import org.mvplugins.multiverse.core.destination.DestinationInstance; import org.mvplugins.multiverse.core.locale.MVCorei18n; import org.mvplugins.multiverse.core.locale.message.Message; import org.mvplugins.multiverse.core.locale.message.MessageReplacement.Replace; @@ -31,6 +31,8 @@ import org.mvplugins.multiverse.core.world.helpers.PlayerWorldTeleporter; import org.mvplugins.multiverse.core.world.options.DeleteWorldOptions; +import java.util.Objects; + @Service class DeleteCommand extends CoreCommand { @@ -38,7 +40,7 @@ class DeleteCommand extends CoreCommand { private final WorldManager worldManager; private final PlayerWorldTeleporter playerWorldTeleporter; private final WorldTickDeferrer worldTickDeferrer; - private final RemovePlayerFlags flags; + private final RemovePlayerDestinationFlags flags; @Inject DeleteCommand( @@ -46,7 +48,7 @@ class DeleteCommand extends CoreCommand { @NotNull WorldManager worldManager, @NotNull PlayerWorldTeleporter playerWorldTeleporter, @NotNull WorldTickDeferrer worldTickDeferrer, - @NotNull RemovePlayerFlags flags + @NotNull RemovePlayerDestinationFlags flags ) { this.commandQueueManager = commandQueueManager; this.worldManager = worldManager; @@ -57,8 +59,8 @@ class DeleteCommand extends CoreCommand { @Subcommand("delete") @CommandPermission("multiverse.core.delete") - @CommandCompletion("@mvworlds:scope=both @flags:groupName=" + RemovePlayerFlags.NAME) - @Syntax("") + @CommandCompletion("@mvworlds:scope=both @flags:groupName=" + RemovePlayerDestinationFlags.NAME) + @Syntax(" [--remove-players [destination]]") @Description("{@@mv-core.delete.description}") void onDeleteCommand( MVCommandIssuer issuer, @@ -69,7 +71,7 @@ void onDeleteCommand( MultiverseWorld world, @Optional - @Syntax("[--remove-players]") + @Syntax("[--remove-players [destination]]") @Description("") String[] flagArray) { ParsedCommandFlags parsedFlags = flags.parse(flagArray); @@ -84,10 +86,11 @@ void onDeleteCommand( private void runDeleteCommand(MVCommandIssuer issuer, MultiverseWorld world, ParsedCommandFlags parsedFlags) { issuer.sendInfo(MVCorei18n.DELETE_DELETING, Replace.WORLD.with(world.getName())); - var future = parsedFlags.hasFlag(flags.removePlayers) + DestinationInstance removeToDestination = parsedFlags.flagValue(flags.removePlayers); + var future = Objects.nonNull(removeToDestination) && world.isLoaded() && world instanceof LoadedMultiverseWorld loadedWorld - ? playerWorldTeleporter.removeFromWorld(loadedWorld) + ? playerWorldTeleporter.transferAllFromWorldToDestination(loadedWorld, removeToDestination) : AsyncAttemptsAggregate.emptySuccess(); future.onSuccess(() -> worldTickDeferrer.deferWorldTick(() -> doWorldDeleting(issuer, world))) @@ -113,7 +116,7 @@ private static final class LegacyAlias extends DeleteCommand implements LegacyAl @NotNull WorldManager worldManager, @NotNull PlayerWorldTeleporter playerWorldTeleporter, @NotNull WorldTickDeferrer worldTickDeferrer, - @NotNull RemovePlayerFlags flags) { + @NotNull RemovePlayerDestinationFlags flags) { super(commandQueueManager, worldManager, playerWorldTeleporter, worldTickDeferrer, flags); } diff --git a/src/main/java/org/mvplugins/multiverse/core/commands/RegenCommand.java b/src/main/java/org/mvplugins/multiverse/core/commands/RegenCommand.java index 745ffe93d..971aa197c 100644 --- a/src/main/java/org/mvplugins/multiverse/core/commands/RegenCommand.java +++ b/src/main/java/org/mvplugins/multiverse/core/commands/RegenCommand.java @@ -2,6 +2,7 @@ import java.util.Collections; import java.util.List; +import java.util.Objects; import co.aikar.commands.ACFUtil; import co.aikar.commands.annotation.CommandAlias; @@ -23,9 +24,12 @@ import org.mvplugins.multiverse.core.command.flag.CommandFlagsManager; import org.mvplugins.multiverse.core.command.flag.CommandValueFlag; import org.mvplugins.multiverse.core.command.flag.ParsedCommandFlags; -import org.mvplugins.multiverse.core.command.flags.RemovePlayerFlags; +import org.mvplugins.multiverse.core.command.flags.RemovePlayerDestinationFlags; import org.mvplugins.multiverse.core.command.queue.CommandQueueManager; import org.mvplugins.multiverse.core.command.queue.CommandQueuePayload; +import org.mvplugins.multiverse.core.destination.DestinationInstance; +import org.mvplugins.multiverse.core.destination.DestinationsProvider; +import org.mvplugins.multiverse.core.destination.core.WorldDestination; import org.mvplugins.multiverse.core.locale.MVCorei18n; import org.mvplugins.multiverse.core.locale.message.Message; import org.mvplugins.multiverse.core.locale.message.MessageReplacement.Replace; @@ -65,7 +69,8 @@ class RegenCommand extends CoreCommand { @Subcommand("regen") @CommandPermission("multiverse.core.regen") @CommandCompletion("@mvworlds:scope=loaded @flags:groupName=" + Flags.NAME) - @Syntax(" [--seed [seed] --reset-world-config --reset-gamerules --reset-world-border --remove-players]") + @Syntax(" [--seed [seed]] [--reset-world-config] [--reset-gamerules] [--reset-world-border] " + + "[--remove-players [destination]]") @Description("{@@mv-core.regen.description}") void onRegenCommand( MVCommandIssuer issuer, @@ -75,7 +80,8 @@ void onRegenCommand( LoadedMultiverseWorld world, @Optional - @Syntax("[--seed [seed] --reset-world-config --reset-gamerules --reset-world-border --remove-players]") + @Syntax("[--seed [seed]] [--reset-world-config] [--reset-gamerules] [--reset-world-border] " + + "[--remove-players [destination]]") @Description("{@@mv-core.regen.other.description}") String[] flagArray) { ParsedCommandFlags parsedFlags = flags.parse(flagArray); @@ -91,8 +97,9 @@ private void runRegenCommand(MVCommandIssuer issuer, LoadedMultiverseWorld world issuer.sendInfo(MVCorei18n.REGEN_REGENERATING, Replace.WORLD.with(world.getName())); List worldPlayers = world.getPlayers().getOrElse(Collections.emptyList()); - var future = parsedFlags.hasFlag(flags.removePlayers) - ? playerWorldTeleporter.removeFromWorld(world) + DestinationInstance removeToDestination = parsedFlags.flagValue(flags.removePlayers); + var future = Objects.nonNull(removeToDestination) + ? playerWorldTeleporter.transferAllFromWorldToDestination(world, removeToDestination) : AsyncAttemptsAggregate.emptySuccess(); // todo: using future will hide stacktrace @@ -128,13 +135,18 @@ private void doWorldRegening( } @Service - private static final class Flags extends RemovePlayerFlags { + private static final class Flags extends RemovePlayerDestinationFlags { private static final String NAME = "mvregen"; @Inject - private Flags(@NotNull CommandFlagsManager flagsManager) { - super(NAME, flagsManager); + private Flags( + @NotNull CommandFlagsManager flagsManager, + @NotNull WorldManager worldManager, + @NotNull DestinationsProvider destinationsProvider, + @NotNull WorldDestination worldDestination + ) { + super(NAME, flagsManager, worldManager, destinationsProvider, worldDestination); } private final CommandValueFlag seed = flag(CommandValueFlag.builder("--seed", String.class) diff --git a/src/main/java/org/mvplugins/multiverse/core/commands/RemoveCommand.java b/src/main/java/org/mvplugins/multiverse/core/commands/RemoveCommand.java index 0054cfd2c..22d4be28b 100644 --- a/src/main/java/org/mvplugins/multiverse/core/commands/RemoveCommand.java +++ b/src/main/java/org/mvplugins/multiverse/core/commands/RemoveCommand.java @@ -14,11 +14,13 @@ 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.command.flags.RemovePlayerDestinationFlags; +import org.mvplugins.multiverse.core.destination.DestinationInstance; +import org.mvplugins.multiverse.core.destination.DestinationsProvider; +import org.mvplugins.multiverse.core.destination.core.WorldDestination; import org.mvplugins.multiverse.core.locale.MVCorei18n; import org.mvplugins.multiverse.core.locale.message.MessageReplacement.Replace; import org.mvplugins.multiverse.core.utils.result.AsyncAttemptsAggregate; @@ -27,6 +29,8 @@ import org.mvplugins.multiverse.core.world.helpers.PlayerWorldTeleporter; import org.mvplugins.multiverse.core.world.options.RemoveWorldOptions; +import java.util.Objects; + @Service class RemoveCommand extends CoreCommand { @@ -48,7 +52,7 @@ class RemoveCommand extends CoreCommand { @Subcommand("remove") @CommandPermission("multiverse.core.remove") @CommandCompletion("@mvworlds:scope=both @flags:groupName=" + Flags.NAME) - @Syntax("") + @Syntax(" [--remove-players [destination]] [--no-unload-bukkit-world] [--no-save]") @Description("{@@mv-core.remove.description}") void onRemoveCommand( MVCommandIssuer issuer, @@ -58,13 +62,16 @@ void onRemoveCommand( MultiverseWorld world, @Optional - @Syntax("[--remove-players]") + @Syntax("[--remove-players [destination]] [--no-unload-bukkit-world] [--no-save]") @Description("") String[] flagArray) { ParsedCommandFlags parsedFlags = flags.parse(flagArray); - var future = parsedFlags.hasFlag(flags.removePlayers) - ? worldManager.getLoadedWorld(world).map(playerWorldTeleporter::removeFromWorld).getOrElse(AsyncAttemptsAggregate::emptySuccess) + DestinationInstance removeToDestination = parsedFlags.flagValue(flags.removePlayers); + var future = Objects.nonNull(removeToDestination) + ? world.asLoadedWorld() + .map(loadedWorld -> playerWorldTeleporter.transferAllFromWorldToDestination(loadedWorld, removeToDestination)) + .getOrElse(AsyncAttemptsAggregate::emptySuccess) : AsyncAttemptsAggregate.emptySuccess(); future.onSuccess(() -> doWorldRemoving(issuer, world, parsedFlags)) @@ -85,13 +92,18 @@ private void doWorldRemoving(MVCommandIssuer issuer, MultiverseWorld world, Pars } @Service - private static final class Flags extends RemovePlayerFlags { + private static final class Flags extends RemovePlayerDestinationFlags { private static final String NAME = "mvremove"; @Inject - private Flags(@NotNull CommandFlagsManager flagsManager) { - super(NAME, flagsManager); + private Flags( + @NotNull CommandFlagsManager flagsManager, + @NotNull WorldManager worldManager, + @NotNull DestinationsProvider destinationsProvider, + @NotNull WorldDestination worldDestination + ) { + super(NAME, flagsManager, worldManager, destinationsProvider, worldDestination); } private final CommandFlag noUnloadBukkitWorld = flag(CommandFlag.builder("--no-unload-bukkit-world") diff --git a/src/main/java/org/mvplugins/multiverse/core/commands/UnloadCommand.java b/src/main/java/org/mvplugins/multiverse/core/commands/UnloadCommand.java index ee639b7ae..403d2b58c 100644 --- a/src/main/java/org/mvplugins/multiverse/core/commands/UnloadCommand.java +++ b/src/main/java/org/mvplugins/multiverse/core/commands/UnloadCommand.java @@ -14,11 +14,13 @@ 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.command.flags.RemovePlayerDestinationFlags; +import org.mvplugins.multiverse.core.destination.DestinationInstance; +import org.mvplugins.multiverse.core.destination.DestinationsProvider; +import org.mvplugins.multiverse.core.destination.core.WorldDestination; import org.mvplugins.multiverse.core.locale.MVCorei18n; import org.mvplugins.multiverse.core.locale.message.MessageReplacement.Replace; import org.mvplugins.multiverse.core.utils.result.AsyncAttemptsAggregate; @@ -27,6 +29,8 @@ import org.mvplugins.multiverse.core.world.helpers.PlayerWorldTeleporter; import org.mvplugins.multiverse.core.world.options.UnloadWorldOptions; +import java.util.Objects; + @Service class UnloadCommand extends CoreCommand { @@ -48,7 +52,7 @@ class UnloadCommand extends CoreCommand { @Subcommand("unload") @CommandPermission("multiverse.core.unload") @CommandCompletion("@mvworlds @flags:groupName=" + Flags.NAME) - @Syntax("") + @Syntax(" [--remove-players [destination]] [--no-save]") @Description("{@@mv-core.unload.description}") void onUnloadCommand( MVCommandIssuer issuer, @@ -58,15 +62,16 @@ void onUnloadCommand( LoadedMultiverseWorld world, @Optional - @Syntax("[--remove-players] [--no-save]") + @Syntax("[--remove-players [destination]] [--no-save]") @Description("{@@mv-core.gamerules.description.page}") String[] flagArray) { ParsedCommandFlags parsedFlags = flags.parse(flagArray); issuer.sendInfo(MVCorei18n.UNLOAD_UNLOADING, Replace.WORLD.with(world.getAliasOrName())); - var future = parsedFlags.hasFlag(flags.removePlayers) - ? playerWorldTeleporter.removeFromWorld(world) + DestinationInstance removeToDestination = parsedFlags.flagValue(flags.removePlayers); + var future = Objects.nonNull(removeToDestination) + ? playerWorldTeleporter.transferAllFromWorldToDestination(world, removeToDestination) : AsyncAttemptsAggregate.emptySuccess(); future.onSuccess(() -> doWorldUnloading(issuer, world, parsedFlags)) @@ -88,13 +93,18 @@ private void doWorldUnloading(MVCommandIssuer issuer, LoadedMultiverseWorld worl } @Service - private static final class Flags extends RemovePlayerFlags { + private static final class Flags extends RemovePlayerDestinationFlags { private static final String NAME = "mvunload"; @Inject - private Flags(@NotNull CommandFlagsManager flagsManager) { - super(NAME, flagsManager); + private Flags( + @NotNull CommandFlagsManager flagsManager, + @NotNull WorldManager worldManager, + @NotNull DestinationsProvider destinationsProvider, + @NotNull WorldDestination worldDestination + ) { + super(NAME, flagsManager, worldManager, destinationsProvider, worldDestination); } private final CommandFlag noUnloadBukkitWorld = flag(CommandFlag.builder("--no-unload-bukkit-world") diff --git a/src/main/java/org/mvplugins/multiverse/core/destination/core/WorldDestination.java b/src/main/java/org/mvplugins/multiverse/core/destination/core/WorldDestination.java index 7c86c9d83..f4f2b0b91 100644 --- a/src/main/java/org/mvplugins/multiverse/core/destination/core/WorldDestination.java +++ b/src/main/java/org/mvplugins/multiverse/core/destination/core/WorldDestination.java @@ -6,6 +6,7 @@ import co.aikar.locales.MessageKeyProvider; import jakarta.inject.Inject; import org.bukkit.command.CommandSender; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jvnet.hk2.annotations.Service; @@ -14,13 +15,11 @@ import org.mvplugins.multiverse.core.destination.Destination; import org.mvplugins.multiverse.core.destination.DestinationSuggestionPacket; import org.mvplugins.multiverse.core.locale.MVCorei18n; -import org.mvplugins.multiverse.core.locale.message.MessageReplacement; import org.mvplugins.multiverse.core.locale.message.MessageReplacement.Replace; import org.mvplugins.multiverse.core.teleportation.LocationManipulation; import org.mvplugins.multiverse.core.utils.REPatterns; import org.mvplugins.multiverse.core.utils.result.Attempt; import org.mvplugins.multiverse.core.utils.result.FailureReason; -import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld; import org.mvplugins.multiverse.core.world.MultiverseWorld; import org.mvplugins.multiverse.core.world.WorldManager; import org.mvplugins.multiverse.core.world.entrycheck.WorldEntryCheckerProvider; @@ -56,6 +55,19 @@ public final class WorldDestination implements Destination transferAllFromWorldT .getOrElse(AsyncAttemptsAggregate::emptySuccess); } + /** + * Transfers all players from the given world to the given destination. + * + * @param world The world to transfer players from. + * @param destinationInstance The destination instance to transfer players to. + * @return A list of async futures that represent the teleportation result of each player. + * + * @since 5.7 + */ + @ApiStatus.AvailableSince("5.7") + public AsyncAttemptsAggregate transferAllFromWorldToDestination( + @NotNull LoadedMultiverseWorld world, + @NotNull DestinationInstance destinationInstance) { + return world.getPlayers() + .map(players -> safetyTeleporter.to(destinationInstance).teleport(players)) + .getOrElse(AsyncAttemptsAggregate::emptySuccess); + } + /** * Teleports all players to the given world's spawn location. *