diff --git a/src/main/java/org/mvplugins/multiverse/core/MultiverseCore.java b/src/main/java/org/mvplugins/multiverse/core/MultiverseCore.java index 5b6d61de..a8b2460c 100644 --- a/src/main/java/org/mvplugins/multiverse/core/MultiverseCore.java +++ b/src/main/java/org/mvplugins/multiverse/core/MultiverseCore.java @@ -23,7 +23,7 @@ import org.jetbrains.annotations.NotNull; import org.jvnet.hk2.annotations.Service; import org.mvplugins.multiverse.core.anchor.AnchorManager; -import org.mvplugins.multiverse.core.api.Destination; +import org.mvplugins.multiverse.core.destination.Destination; import org.mvplugins.multiverse.core.api.MVCore; import org.mvplugins.multiverse.core.commands.CoreCommand; import org.mvplugins.multiverse.core.commandtools.MVCommandManager; diff --git a/src/main/java/org/mvplugins/multiverse/core/api/DestinationInstance.java b/src/main/java/org/mvplugins/multiverse/core/api/DestinationInstance.java deleted file mode 100644 index ddc9bb64..00000000 --- a/src/main/java/org/mvplugins/multiverse/core/api/DestinationInstance.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.mvplugins.multiverse.core.api; - -import org.bukkit.Location; -import org.bukkit.entity.Entity; -import org.bukkit.util.Vector; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public interface DestinationInstance { - /** - * Gets the exact location to teleport an entity to. - * - * @param teleportee The entity to teleport. - * @return The location to teleport to. - */ - @Nullable Location getLocation(@NotNull Entity teleportee); - - /** - * Gets the velocity to apply to an entity after teleporting. - * - * @param teleportee The entity to teleport. - * @return A vector representing the speed/direction the player should travel when arriving at the destination. - */ - @Nullable Vector getVelocity(@NotNull Entity teleportee); - - /** - * Gets the permission suffix to check for when teleporting to this destination. - * This is used for finer per world/player permissions, such as "multiverse.teleport.self.worldname". - * - *

For example, if the destination is "w:world", the permission suffix is "world".

- * - * @return The permission suffix. - */ - @Nullable String getFinerPermissionSuffix(); - - /** - * Serialises the destination instance to a savable string. - * - *

This is used when plugins save destinations to configuration, - * and when the destination is displayed to the user.

- * - * @return The serialised destination instance. - */ - @NotNull String serialise(); -} diff --git a/src/main/java/org/mvplugins/multiverse/core/commands/CheckCommand.java b/src/main/java/org/mvplugins/multiverse/core/commands/CheckCommand.java index 5310c5b7..9e75633b 100644 --- a/src/main/java/org/mvplugins/multiverse/core/commands/CheckCommand.java +++ b/src/main/java/org/mvplugins/multiverse/core/commands/CheckCommand.java @@ -13,9 +13,8 @@ import org.jvnet.hk2.annotations.Service; import org.mvplugins.multiverse.core.commandtools.MVCommandIssuer; import org.mvplugins.multiverse.core.commandtools.MVCommandManager; -import org.mvplugins.multiverse.core.commandtools.MultiverseCommand; +import org.mvplugins.multiverse.core.destination.DestinationInstance; import org.mvplugins.multiverse.core.destination.DestinationsProvider; -import org.mvplugins.multiverse.core.destination.ParsedDestination; import org.mvplugins.multiverse.core.utils.MVCorei18n; @Service @@ -45,7 +44,7 @@ class CheckCommand extends CoreCommand { @Syntax("") @Description("{@@mv-core.check.destination.description}") - ParsedDestination destination) { + DestinationInstance destination) { issuer.sendInfo(MVCorei18n.CHECK_CHECKING, "{player}", player.getName(), "{destination}", destination.toString()); diff --git a/src/main/java/org/mvplugins/multiverse/core/commands/TeleportCommand.java b/src/main/java/org/mvplugins/multiverse/core/commands/TeleportCommand.java index 398c6d34..0cab796a 100644 --- a/src/main/java/org/mvplugins/multiverse/core/commands/TeleportCommand.java +++ b/src/main/java/org/mvplugins/multiverse/core/commands/TeleportCommand.java @@ -17,8 +17,7 @@ import org.jvnet.hk2.annotations.Service; import org.mvplugins.multiverse.core.commandtools.MVCommandIssuer; import org.mvplugins.multiverse.core.commandtools.MVCommandManager; -import org.mvplugins.multiverse.core.commandtools.MultiverseCommand; -import org.mvplugins.multiverse.core.destination.ParsedDestination; +import org.mvplugins.multiverse.core.destination.DestinationInstance; import org.mvplugins.multiverse.core.permissions.CorePermissionsChecker; import org.mvplugins.multiverse.core.teleportation.AsyncSafetyTeleporter; import org.mvplugins.multiverse.core.utils.MVCorei18n; @@ -55,7 +54,7 @@ class TeleportCommand extends CoreCommand { @Syntax("") @Description("{@@mv-core.teleport.destination.description}") - ParsedDestination destination) { + DestinationInstance destination) { // TODO: Add warning if teleporting too many players at once. String playerName = players.length == 1 diff --git a/src/main/java/org/mvplugins/multiverse/core/commandtools/MVCommandCompletions.java b/src/main/java/org/mvplugins/multiverse/core/commandtools/MVCommandCompletions.java index 63b9f69e..b1a0ff13 100644 --- a/src/main/java/org/mvplugins/multiverse/core/commandtools/MVCommandCompletions.java +++ b/src/main/java/org/mvplugins/multiverse/core/commandtools/MVCommandCompletions.java @@ -28,8 +28,8 @@ import org.jvnet.hk2.annotations.Service; import org.mvplugins.multiverse.core.config.MVCoreConfig; import org.mvplugins.multiverse.core.configuration.handle.PropertyModifyAction; +import org.mvplugins.multiverse.core.destination.DestinationInstance; import org.mvplugins.multiverse.core.destination.DestinationsProvider; -import org.mvplugins.multiverse.core.destination.ParsedDestination; import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld; import org.mvplugins.multiverse.core.world.MultiverseWorld; import org.mvplugins.multiverse.core.world.WorldManager; @@ -68,7 +68,7 @@ class MVCommandCompletions extends PaperCommandCompletions { registerAsyncCompletion("mvworldpropsvalue", this::suggestMVWorldPropsValue); registerStaticCompletion("propsmodifyaction", suggestEnums(PropertyModifyAction.class)); - setDefaultCompletion("destinations", ParsedDestination.class); + setDefaultCompletion("destinations", DestinationInstance.class); setDefaultCompletion("difficulties", Difficulty.class); setDefaultCompletion("environments", World.Environment.class); setDefaultCompletion("flags", String[].class); diff --git a/src/main/java/org/mvplugins/multiverse/core/commandtools/MVCommandContexts.java b/src/main/java/org/mvplugins/multiverse/core/commandtools/MVCommandContexts.java index e12c54b3..fb12bbc0 100644 --- a/src/main/java/org/mvplugins/multiverse/core/commandtools/MVCommandContexts.java +++ b/src/main/java/org/mvplugins/multiverse/core/commandtools/MVCommandContexts.java @@ -16,8 +16,8 @@ import org.jvnet.hk2.annotations.Service; import org.mvplugins.multiverse.core.commandtools.context.GameRuleValue; import org.mvplugins.multiverse.core.config.MVCoreConfig; +import org.mvplugins.multiverse.core.destination.DestinationInstance; import org.mvplugins.multiverse.core.destination.DestinationsProvider; -import org.mvplugins.multiverse.core.destination.ParsedDestination; import org.mvplugins.multiverse.core.display.filters.ContentFilter; import org.mvplugins.multiverse.core.display.filters.DefaultContentFilter; import org.mvplugins.multiverse.core.display.filters.RegexContentFilter; @@ -49,7 +49,7 @@ class MVCommandContexts extends PaperCommandContexts { registerIssuerOnlyContext(BukkitCommandIssuer.class, BukkitCommandExecutionContext::getIssuer); registerIssuerOnlyContext(MVCommandIssuer.class, this::parseMVCommandIssuer); registerOptionalContext(ContentFilter.class, this::parseContentFilter); - registerContext(ParsedDestination.class, this::parseDestination); + registerContext(DestinationInstance.class, this::parseDestination); registerContext(GameRule.class, this::parseGameRule); registerContext(GameRuleValue.class, this::parseGameRuleValue); registerIssuerAwareContext(LoadedMultiverseWorld.class, this::parseLoadedMultiverseWorld); @@ -74,18 +74,14 @@ class MVCommandContexts extends PaperCommandContexts { return RegexContentFilter.fromString(filterString); } - private ParsedDestination parseDestination(BukkitCommandExecutionContext context) { + private DestinationInstance parseDestination(BukkitCommandExecutionContext context) { String destination = context.popFirstArg(); if (Strings.isNullOrEmpty(destination)) { throw new InvalidCommandArgument("No destination specified."); } - ParsedDestination parsedDestination = destinationsProvider.parseDestination(destination); - if (parsedDestination == null) { - throw new InvalidCommandArgument("The destination " + destination + " is not valid."); - } - - return parsedDestination; + return destinationsProvider.parseDestination(destination) + .getOrElseThrow(() -> new InvalidCommandArgument("The destination " + destination + " is not valid.")); } private GameRule parseGameRule(BukkitCommandExecutionContext context) { diff --git a/src/main/java/org/mvplugins/multiverse/core/api/Destination.java b/src/main/java/org/mvplugins/multiverse/core/destination/Destination.java similarity index 80% rename from src/main/java/org/mvplugins/multiverse/core/api/Destination.java rename to src/main/java/org/mvplugins/multiverse/core/destination/Destination.java index b5dd193c..6ee076d4 100644 --- a/src/main/java/org/mvplugins/multiverse/core/api/Destination.java +++ b/src/main/java/org/mvplugins/multiverse/core/destination/Destination.java @@ -1,4 +1,4 @@ -package org.mvplugins.multiverse.core.api; +package org.mvplugins.multiverse.core.destination; import java.util.Collection; @@ -8,7 +8,7 @@ import org.jetbrains.annotations.Nullable; import org.jvnet.hk2.annotations.Contract; @Contract -public interface Destination { +public interface Destination, T extends DestinationInstance> { /** * Returns the identifier or prefix that is required for this destination. * @@ -36,13 +36,4 @@ public interface Destination { * @return A list of possible destinations. */ @NotNull Collection suggestDestinations(@NotNull BukkitCommandIssuer issuer, @Nullable String destinationParams); - - /** - * Should the Multiverse SafeTeleporter be used? - * - *

If not, MV will blindly take people to the location specified.

- * - * @return True if the SafeTeleporter will be used, false if not. - */ - boolean checkTeleportSafety(); } diff --git a/src/main/java/org/mvplugins/multiverse/core/destination/DestinationInstance.java b/src/main/java/org/mvplugins/multiverse/core/destination/DestinationInstance.java new file mode 100644 index 00000000..a5949f38 --- /dev/null +++ b/src/main/java/org/mvplugins/multiverse/core/destination/DestinationInstance.java @@ -0,0 +1,90 @@ +package org.mvplugins.multiverse.core.destination; + +import io.vavr.control.Option; +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.util.Vector; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public abstract class DestinationInstance, T extends Destination> { + + protected final T destination; + + protected DestinationInstance(@NotNull T destination) { + this.destination = destination; + } + + /** + * Gets the destination that created this instance. + * + * @return The destination. + */ + public @NotNull T getDestination() { + return this.destination; + } + + /** + * Gets the {@link Destination#getIdentifier()} for this instance. + * + * @return The identifier. + */ + public @NotNull String getIdentifier() { + return this.destination.getIdentifier(); + } + + /** + * Gets the exact location to teleport an entity to. + * + * @param teleportee The entity to teleport. + * @return The location to teleport to. + */ + public abstract @NotNull Option getLocation(@NotNull Entity teleportee); + + /** + * Gets the velocity to apply to an entity after teleporting. + * + * @param teleportee The entity to teleport. + * @return A vector representing the speed/direction the player should travel when arriving at the destination. + */ + public abstract @NotNull Option getVelocity(@NotNull Entity teleportee); + + /** + * Should the Multiverse SafeTeleporter be used? + * + *

If not, MV will blindly take people to the location specified.

+ * + * @return True if the SafeTeleporter will be used, false if not. + */ + public abstract boolean checkTeleportSafety(); + + /** + * Gets the permission suffix to check for when teleporting to this destination. + * This is used for finer per world/player permissions, such as "multiverse.teleport.self.worldname". + * + *

For example, if the destination is "w:world", the permission suffix is "world".

+ * + * @return The permission suffix. + */ + public abstract @NotNull Option getFinerPermissionSuffix(); + + /** + * Serialises the destination instance to a savable string. + * + *

This is used when plugins save destinations to configuration, + * and when the destination is displayed to the user.

+ * + * @return The serialised destination instance. + */ + @NotNull + protected abstract String serialise(); + + /** + * String representation of the destination instance that can be deserialised back into the destination instance. + * @return The string representation of the destination instance. + */ + @Override + public String toString() { + return this.destination.getIdentifier() + ":" + this.serialise(); + } +} diff --git a/src/main/java/org/mvplugins/multiverse/core/destination/DestinationsProvider.java b/src/main/java/org/mvplugins/multiverse/core/destination/DestinationsProvider.java index 50d75da3..2ad7ec44 100644 --- a/src/main/java/org/mvplugins/multiverse/core/destination/DestinationsProvider.java +++ b/src/main/java/org/mvplugins/multiverse/core/destination/DestinationsProvider.java @@ -6,6 +6,7 @@ import java.util.Map; import java.util.stream.Collectors; import co.aikar.commands.BukkitCommandIssuer; +import io.vavr.control.Option; import jakarta.inject.Inject; import org.bukkit.permissions.Permission; import org.bukkit.plugin.PluginManager; @@ -13,9 +14,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jvnet.hk2.annotations.Service; -import org.mvplugins.multiverse.core.api.Destination; -import org.mvplugins.multiverse.core.api.DestinationInstance; - /** * Provides destinations for teleportation. */ @@ -25,7 +23,7 @@ public class DestinationsProvider { private static final String PERMISSION_PREFIX = "multiverse.teleport."; private final PluginManager pluginManager; - private final Map> destinationMap; + private final Map> destinationMap; @Inject DestinationsProvider(@NotNull PluginManager pluginManager) { @@ -38,12 +36,12 @@ public class DestinationsProvider { * * @param destination The destination. */ - public void registerDestination(@NotNull Destination destination) { + public void registerDestination(@NotNull Destination destination) { this.destinationMap.put(destination.getIdentifier(), destination); this.registerDestinationPerms(destination); } - private void registerDestinationPerms(@NotNull Destination destination) { + private void registerDestinationPerms(@NotNull Destination destination) { pluginManager.addPermission(new Permission(PERMISSION_PREFIX + "self." + destination.getIdentifier())); pluginManager.addPermission(new Permission(PERMISSION_PREFIX + "other." + destination.getIdentifier())); } @@ -74,13 +72,13 @@ public class DestinationsProvider { * @param destinationString The destination string. * @return The destination object, or null if invalid format. */ - @Nullable - public ParsedDestination parseDestination(@NotNull String destinationString) { + @NotNull + public Option> parseDestination(@NotNull String destinationString) { String[] items = destinationString.split(SEPARATOR, 2); String idString = items[0]; String destinationParams; - Destination destination; + Destination destination; if (items.length < 2) { // Assume world destination @@ -92,15 +90,10 @@ public class DestinationsProvider { } if (destination == null) { - return null; + return Option.none(); } - DestinationInstance destinationInstance = destination.getDestinationInstance(destinationParams); - if (destinationInstance == null) { - return null; - } - - return new ParsedDestination<>(destination, destinationInstance); + return Option.of(destination.getDestinationInstance(destinationParams)); } /** @@ -109,7 +102,7 @@ public class DestinationsProvider { * @param identifier The identifier. * @return The destination, or null if not found. */ - public @Nullable Destination getDestinationById(@Nullable String identifier) { + public @Nullable Destination getDestinationById(@Nullable String identifier) { return this.destinationMap.get(identifier); } @@ -118,7 +111,7 @@ public class DestinationsProvider { * * @return A collection of destinations. */ - public @NotNull Collection> getDestinations() { + public @NotNull Collection> getDestinations() { return this.destinationMap.values(); } } diff --git a/src/main/java/org/mvplugins/multiverse/core/destination/ParsedDestination.java b/src/main/java/org/mvplugins/multiverse/core/destination/ParsedDestination.java deleted file mode 100644 index 5bf1894e..00000000 --- a/src/main/java/org/mvplugins/multiverse/core/destination/ParsedDestination.java +++ /dev/null @@ -1,86 +0,0 @@ -package org.mvplugins.multiverse.core.destination; - -import org.bukkit.Location; -import org.bukkit.entity.Entity; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import org.mvplugins.multiverse.core.api.Destination; -import org.mvplugins.multiverse.core.api.DestinationInstance; - -/** - * A parsed destination. - * - * @param The destination instance type. - */ -public class ParsedDestination { - private final Destination destination; - private final DestinationInstance destinationInstance; - - /** - * Creates a new parsed destination. - * - * @param destination The destination. - * @param destinationInstance The destination instance. - */ - public ParsedDestination(Destination destination, DestinationInstance destinationInstance) { - this.destination = destination; - this.destinationInstance = destinationInstance; - } - - /** - * Shortcut for {@link Destination#getIdentifier()}. - * - * @return The destination identifier. - */ - public @NotNull String getIdentifier() { - return destination.getIdentifier(); - } - - /** - * Shortcut for {@link DestinationInstance#getLocation(Entity)}. - * - * @param teleportee The entity to teleport. - * @return The location to teleport to. - */ - public @Nullable Location getLocation(@NotNull Entity teleportee) { - return destinationInstance.getLocation(teleportee); - } - - /** - * Shortcut for {@link DestinationInstance#getFinerPermissionSuffix()}. - * - * @return The finer permission suffix. - */ - public @Nullable String getFinerPermissionSuffix() { - return destinationInstance.getFinerPermissionSuffix(); - } - - /** - * Gets the destination. - * - * @return The destination. - */ - public Destination getDestination() { - return destination; - } - - /** - * Gets the destination instance. - * - * @return The destination instance. - */ - public DestinationInstance getDestinationInstance() { - return destinationInstance; - } - - /** - * Converts to saveable string representation of this destination. - * - * @return Serialized string. - */ - @Override - public String toString() { - return getIdentifier() + ":" + destinationInstance.serialise(); - } -} diff --git a/src/main/java/org/mvplugins/multiverse/core/destination/core/AnchorDestination.java b/src/main/java/org/mvplugins/multiverse/core/destination/core/AnchorDestination.java index 88ded3ba..4793c470 100644 --- a/src/main/java/org/mvplugins/multiverse/core/destination/core/AnchorDestination.java +++ b/src/main/java/org/mvplugins/multiverse/core/destination/core/AnchorDestination.java @@ -10,13 +10,13 @@ import org.jetbrains.annotations.Nullable; import org.jvnet.hk2.annotations.Service; import org.mvplugins.multiverse.core.anchor.AnchorManager; -import org.mvplugins.multiverse.core.api.Destination; +import org.mvplugins.multiverse.core.destination.Destination; /** * {@link Destination} implementation for anchors. */ @Service -public class AnchorDestination implements Destination { +public class AnchorDestination implements Destination { private final AnchorManager anchorManager; @@ -38,11 +38,14 @@ public class AnchorDestination implements Destination */ @Override public @Nullable AnchorDestinationInstance getDestinationInstance(@Nullable String destinationParams) { + if (destinationParams == null) { + return null; + } Location anchorLocation = this.anchorManager.getAnchorLocation(destinationParams); if (anchorLocation == null) { return null; } - return new AnchorDestinationInstance(destinationParams, anchorLocation); + return new AnchorDestinationInstance(this, destinationParams, anchorLocation); } /** @@ -52,12 +55,4 @@ public class AnchorDestination implements Destination public @NotNull Collection suggestDestinations(@NotNull BukkitCommandIssuer issuer, @Nullable String destinationParams) { return this.anchorManager.getAnchors(issuer.getPlayer()); } - - /** - * {@inheritDoc} - */ - @Override - public boolean checkTeleportSafety() { - return true; - } } diff --git a/src/main/java/org/mvplugins/multiverse/core/destination/core/AnchorDestinationInstance.java b/src/main/java/org/mvplugins/multiverse/core/destination/core/AnchorDestinationInstance.java index e96d6878..615a2868 100644 --- a/src/main/java/org/mvplugins/multiverse/core/destination/core/AnchorDestinationInstance.java +++ b/src/main/java/org/mvplugins/multiverse/core/destination/core/AnchorDestinationInstance.java @@ -1,17 +1,18 @@ package org.mvplugins.multiverse.core.destination.core; +import io.vavr.control.Option; import org.bukkit.Location; import org.bukkit.entity.Entity; import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.mvplugins.multiverse.core.api.DestinationInstance; +import org.mvplugins.multiverse.core.destination.DestinationInstance; /** * Destination instance implementation for the {@link AnchorDestination}. */ -public class AnchorDestinationInstance implements DestinationInstance { +public class AnchorDestinationInstance extends DestinationInstance { private final String anchorName; private final Location anchorLocation; @@ -21,7 +22,12 @@ public class AnchorDestinationInstance implements DestinationInstance { * @param anchorName The name of the anchor. * @param anchorLocation The location of the anchor. */ - AnchorDestinationInstance(@NotNull String anchorName, @NotNull Location anchorLocation) { + AnchorDestinationInstance( + @NotNull AnchorDestination destination, + @NotNull String anchorName, + @NotNull Location anchorLocation + ) { + super(destination); this.anchorName = anchorName; this.anchorLocation = anchorLocation; } @@ -30,24 +36,32 @@ public class AnchorDestinationInstance implements DestinationInstance { * {@inheritDoc} */ @Override - public @Nullable Location getLocation(@NotNull Entity teleportee) { - return anchorLocation; + public @NotNull Option getLocation(@NotNull Entity teleportee) { + return Option.of(anchorLocation); } /** * {@inheritDoc} */ @Override - public @Nullable Vector getVelocity(@NotNull Entity teleportee) { - return null; + public @NotNull Option getVelocity(@NotNull Entity teleportee) { + return Option.none(); } /** * {@inheritDoc} */ @Override - public @Nullable String getFinerPermissionSuffix() { - return anchorName; + public boolean checkTeleportSafety() { + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public @NotNull Option getFinerPermissionSuffix() { + return Option.of(anchorName); } /** diff --git a/src/main/java/org/mvplugins/multiverse/core/destination/core/BedDestination.java b/src/main/java/org/mvplugins/multiverse/core/destination/core/BedDestination.java index 2204703a..312c16a6 100644 --- a/src/main/java/org/mvplugins/multiverse/core/destination/core/BedDestination.java +++ b/src/main/java/org/mvplugins/multiverse/core/destination/core/BedDestination.java @@ -11,14 +11,14 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jvnet.hk2.annotations.Service; -import org.mvplugins.multiverse.core.api.Destination; +import org.mvplugins.multiverse.core.destination.Destination; import org.mvplugins.multiverse.core.utils.PlayerFinder; /** * {@link Destination} implementation for beds. */ @Service -public class BedDestination implements Destination { +public class BedDestination implements Destination { static final String OWN_BED_STRING = "playerbed"; BedDestination() { @@ -41,7 +41,7 @@ public class BedDestination implements Destination { if (player == null && !destinationParams.equals(OWN_BED_STRING)) { return null; } - return new BedDestinationInstance(player); + return new BedDestinationInstance(this, player); } /** @@ -53,12 +53,4 @@ public class BedDestination implements Destination { collect.add(OWN_BED_STRING); return collect; } - - /** - * {@inheritDoc} - */ - @Override - public boolean checkTeleportSafety() { - return false; - } } diff --git a/src/main/java/org/mvplugins/multiverse/core/destination/core/BedDestinationInstance.java b/src/main/java/org/mvplugins/multiverse/core/destination/core/BedDestinationInstance.java index d73c2ad6..3c3bb104 100644 --- a/src/main/java/org/mvplugins/multiverse/core/destination/core/BedDestinationInstance.java +++ b/src/main/java/org/mvplugins/multiverse/core/destination/core/BedDestinationInstance.java @@ -1,5 +1,6 @@ package org.mvplugins.multiverse.core.destination.core; +import io.vavr.control.Option; import org.bukkit.Location; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; @@ -7,12 +8,12 @@ import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.mvplugins.multiverse.core.api.DestinationInstance; +import org.mvplugins.multiverse.core.destination.DestinationInstance; /** * Destination instance implementation for the {@link BedDestination}. */ -public class BedDestinationInstance implements DestinationInstance { +public class BedDestinationInstance extends DestinationInstance { private final Player player; /** @@ -20,7 +21,8 @@ public class BedDestinationInstance implements DestinationInstance { * * @param player The player whose bed to use. */ - BedDestinationInstance(Player player) { + BedDestinationInstance(@NotNull BedDestination destination, @Nullable Player player) { + super(destination); this.player = player; } @@ -28,30 +30,38 @@ public class BedDestinationInstance implements DestinationInstance { * {@inheritDoc} */ @Override - public @Nullable Location getLocation(@NotNull Entity teleportee) { + public @NotNull Option getLocation(@NotNull Entity teleportee) { if (player != null) { - return player.getBedSpawnLocation(); + return Option.of(player.getBedSpawnLocation()); } if (teleportee instanceof Player) { - return ((Player) teleportee).getBedSpawnLocation(); + return Option.of(((Player) teleportee).getBedSpawnLocation()); } - return null; + return Option.none(); } /** * {@inheritDoc} */ @Override - public @Nullable Vector getVelocity(@NotNull Entity teleportee) { - return null; + public @NotNull Option getVelocity(@NotNull Entity teleportee) { + return Option.none(); } /** * {@inheritDoc} */ @Override - public @Nullable String getFinerPermissionSuffix() { - return player != null ? player.getName() : BedDestination.OWN_BED_STRING; + public boolean checkTeleportSafety() { + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public @NotNull Option getFinerPermissionSuffix() { + return Option.of(player != null ? player.getName() : BedDestination.OWN_BED_STRING); } /** diff --git a/src/main/java/org/mvplugins/multiverse/core/destination/core/CannonDestination.java b/src/main/java/org/mvplugins/multiverse/core/destination/core/CannonDestination.java index 84c7db23..4b6ce529 100644 --- a/src/main/java/org/mvplugins/multiverse/core/destination/core/CannonDestination.java +++ b/src/main/java/org/mvplugins/multiverse/core/destination/core/CannonDestination.java @@ -11,7 +11,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jvnet.hk2.annotations.Service; -import org.mvplugins.multiverse.core.api.Destination; +import org.mvplugins.multiverse.core.destination.Destination; import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld; import org.mvplugins.multiverse.core.world.WorldManager; @@ -19,7 +19,7 @@ import org.mvplugins.multiverse.core.world.WorldManager; * {@link Destination} implementation for cannons. */ @Service -public class CannonDestination implements Destination { +public class CannonDestination implements Destination { private final WorldManager worldManager; @@ -78,7 +78,7 @@ public class CannonDestination implements Destination return null; } - return new CannonDestinationInstance(location, dSpeed); + return new CannonDestinationInstance(this, location, dSpeed); } /** @@ -88,12 +88,4 @@ public class CannonDestination implements Destination public @NotNull Collection suggestDestinations(@NotNull BukkitCommandIssuer issuer, @Nullable String destinationParams) { return Collections.singleton(""); } - - /** - * {@inheritDoc} - */ - @Override - public boolean checkTeleportSafety() { - return false; - } } diff --git a/src/main/java/org/mvplugins/multiverse/core/destination/core/CannonDestinationInstance.java b/src/main/java/org/mvplugins/multiverse/core/destination/core/CannonDestinationInstance.java index 41205ac6..93e146b3 100644 --- a/src/main/java/org/mvplugins/multiverse/core/destination/core/CannonDestinationInstance.java +++ b/src/main/java/org/mvplugins/multiverse/core/destination/core/CannonDestinationInstance.java @@ -1,17 +1,19 @@ package org.mvplugins.multiverse.core.destination.core; +import io.vavr.control.Option; import org.bukkit.Location; +import org.bukkit.World; import org.bukkit.entity.Entity; import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.mvplugins.multiverse.core.api.DestinationInstance; +import org.mvplugins.multiverse.core.destination.DestinationInstance; /** * Destination instance implementation for the {@link CannonDestination}. */ -public class CannonDestinationInstance implements DestinationInstance { +public class CannonDestinationInstance extends DestinationInstance { private final Location location; private final double speed; @@ -21,7 +23,8 @@ public class CannonDestinationInstance implements DestinationInstance { * @param location The location to teleport to. * @param speed The speed to fire the player at. */ - CannonDestinationInstance(@NotNull Location location, double speed) { + CannonDestinationInstance(@NotNull CannonDestination destination, @NotNull Location location, double speed) { + super(destination); this.location = location; this.speed = speed; } @@ -30,15 +33,15 @@ public class CannonDestinationInstance implements DestinationInstance { * {@inheritDoc} */ @Override - public @Nullable Location getLocation(@NotNull Entity teleportee) { - return location; + public @NotNull Option getLocation(@NotNull Entity teleportee) { + return Option.of(location); } /** * {@inheritDoc} */ @Override - public @Nullable Vector getVelocity(@NotNull Entity teleportee) { + public @NotNull Option getVelocity(@NotNull Entity teleportee) { double pitchRadians = Math.toRadians(location.getPitch()); double yawRadians = Math.toRadians(location.getYaw()); double x = Math.sin(yawRadians) * speed * -1; @@ -47,15 +50,23 @@ public class CannonDestinationInstance implements DestinationInstance { // Account for the angle they were pointed, and take away velocity x = Math.cos(pitchRadians) * x; z = Math.cos(pitchRadians) * z; - return new Vector(x, y, z); + return Option.of(new Vector(x, y, z)); } /** * {@inheritDoc} */ @Override - public @Nullable String getFinerPermissionSuffix() { - return location.getWorld().getName(); + public boolean checkTeleportSafety() { + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public @NotNull Option getFinerPermissionSuffix() { + return Option.of(location.getWorld()).map(World::getName); } /** diff --git a/src/main/java/org/mvplugins/multiverse/core/destination/core/ExactDestination.java b/src/main/java/org/mvplugins/multiverse/core/destination/core/ExactDestination.java index 0eaaf2b5..d62f3dfd 100644 --- a/src/main/java/org/mvplugins/multiverse/core/destination/core/ExactDestination.java +++ b/src/main/java/org/mvplugins/multiverse/core/destination/core/ExactDestination.java @@ -11,7 +11,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jvnet.hk2.annotations.Service; -import org.mvplugins.multiverse.core.api.Destination; +import org.mvplugins.multiverse.core.destination.Destination; import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld; import org.mvplugins.multiverse.core.world.WorldManager; @@ -19,7 +19,7 @@ import org.mvplugins.multiverse.core.world.WorldManager; * {@link Destination} implementation for exact locations. */ @Service -public class ExactDestination implements Destination { +public class ExactDestination implements Destination { private final WorldManager worldManager; @@ -36,6 +36,16 @@ public class ExactDestination implements Destination { return "e"; } + /** + * Make a new {@link ExactDestinationInstance} from a {@link Location}. + * + * @param location The target location + * @return A new {@link ExactDestinationInstance} + */ + public @NotNull ExactDestinationInstance fromLocation(@NotNull Location location) { + return new ExactDestinationInstance(this, location); + } + /** * {@inheritDoc} */ @@ -53,7 +63,7 @@ public class ExactDestination implements Destination { return null; } - World world = this.worldManager.getLoadedWorld(worldName).map(LoadedMultiverseWorld::getBukkitWorld).getOrNull().getOrNull(); + World world = this.worldManager.getLoadedWorld(worldName).flatMap(LoadedMultiverseWorld::getBukkitWorld).getOrNull(); if (world == null) { return null; } @@ -81,7 +91,7 @@ public class ExactDestination implements Destination { } } - return new ExactDestinationInstance(location); + return new ExactDestinationInstance(this, location); } /** @@ -91,12 +101,4 @@ public class ExactDestination implements Destination { public @NotNull Collection suggestDestinations(@NotNull BukkitCommandIssuer issuer, @Nullable String destinationParams) { return Collections.singleton(""); } - - /** - * {@inheritDoc} - */ - @Override - public boolean checkTeleportSafety() { - return false; - } } diff --git a/src/main/java/org/mvplugins/multiverse/core/destination/core/ExactDestinationInstance.java b/src/main/java/org/mvplugins/multiverse/core/destination/core/ExactDestinationInstance.java index 24882ded..d8561a43 100644 --- a/src/main/java/org/mvplugins/multiverse/core/destination/core/ExactDestinationInstance.java +++ b/src/main/java/org/mvplugins/multiverse/core/destination/core/ExactDestinationInstance.java @@ -1,17 +1,19 @@ package org.mvplugins.multiverse.core.destination.core; +import io.vavr.control.Option; import org.bukkit.Location; +import org.bukkit.World; import org.bukkit.entity.Entity; import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.mvplugins.multiverse.core.api.DestinationInstance; +import org.mvplugins.multiverse.core.destination.DestinationInstance; /** * Destination instance implementation for the {@link ExactDestination}. */ -public class ExactDestinationInstance implements DestinationInstance { +public class ExactDestinationInstance extends DestinationInstance { private final Location location; /** @@ -19,7 +21,8 @@ public class ExactDestinationInstance implements DestinationInstance { * * @param location The location to teleport to. */ - ExactDestinationInstance(Location location) { + ExactDestinationInstance(@NotNull ExactDestination destination, @NotNull Location location) { + super(destination); this.location = location; } @@ -27,24 +30,33 @@ public class ExactDestinationInstance implements DestinationInstance { * {@inheritDoc} */ @Override - public @Nullable Location getLocation(@NotNull Entity teleportee) { - return location; + public @NotNull Option getLocation(@NotNull Entity teleportee) { + // todo: maybe check if the world is null? + return Option.of(location); } /** * {@inheritDoc} */ @Override - public @Nullable Vector getVelocity(@NotNull Entity teleportee) { - return null; + public @NotNull Option getVelocity(@NotNull Entity teleportee) { + return Option.none(); } /** * {@inheritDoc} */ @Override - public @Nullable String getFinerPermissionSuffix() { - return location.getWorld().getName(); + public boolean checkTeleportSafety() { + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public @NotNull Option getFinerPermissionSuffix() { + return Option.of(location.getWorld()).map(World::getName); } /** diff --git a/src/main/java/org/mvplugins/multiverse/core/destination/core/PlayerDestination.java b/src/main/java/org/mvplugins/multiverse/core/destination/core/PlayerDestination.java index 64253f8d..00d5a535 100644 --- a/src/main/java/org/mvplugins/multiverse/core/destination/core/PlayerDestination.java +++ b/src/main/java/org/mvplugins/multiverse/core/destination/core/PlayerDestination.java @@ -10,14 +10,14 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jvnet.hk2.annotations.Service; -import org.mvplugins.multiverse.core.api.Destination; +import org.mvplugins.multiverse.core.destination.Destination; import org.mvplugins.multiverse.core.utils.PlayerFinder; /** * {@link Destination} implementation for players.s */ @Service -public class PlayerDestination implements Destination { +public class PlayerDestination implements Destination { /** * Creates a new instance of the PlayerDestination. */ @@ -41,7 +41,7 @@ public class PlayerDestination implements Destination if (player == null) { return null; } - return new PlayerDestinationInstance(player); + return new PlayerDestinationInstance(this, player); } /** @@ -49,14 +49,6 @@ public class PlayerDestination implements Destination */ @Override public @NotNull Collection suggestDestinations(@NotNull BukkitCommandIssuer issuer, @Nullable String destinationParams) { - return Bukkit.getOnlinePlayers().stream().map(Player::getName).collect(Collectors.toList()); - } - - /** - * {@inheritDoc} - */ - @Override - public boolean checkTeleportSafety() { - return true; + return Bukkit.getOnlinePlayers().stream().map(Player::getName).toList(); } } diff --git a/src/main/java/org/mvplugins/multiverse/core/destination/core/PlayerDestinationInstance.java b/src/main/java/org/mvplugins/multiverse/core/destination/core/PlayerDestinationInstance.java index fd67f737..ecba3b8d 100644 --- a/src/main/java/org/mvplugins/multiverse/core/destination/core/PlayerDestinationInstance.java +++ b/src/main/java/org/mvplugins/multiverse/core/destination/core/PlayerDestinationInstance.java @@ -1,5 +1,6 @@ package org.mvplugins.multiverse.core.destination.core; +import io.vavr.control.Option; import org.bukkit.Location; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; @@ -7,12 +8,12 @@ import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.mvplugins.multiverse.core.api.DestinationInstance; +import org.mvplugins.multiverse.core.destination.DestinationInstance; /** * Destination instance implementation for the {@link PlayerDestination}. */ -public class PlayerDestinationInstance implements DestinationInstance { +public class PlayerDestinationInstance extends DestinationInstance { private final Player player; /** @@ -20,7 +21,8 @@ public class PlayerDestinationInstance implements DestinationInstance { * * @param player The player whose location to go to. */ - PlayerDestinationInstance(Player player) { + PlayerDestinationInstance(@NotNull PlayerDestination destination, @NotNull Player player) { + super(destination); this.player = player; } @@ -28,24 +30,32 @@ public class PlayerDestinationInstance implements DestinationInstance { * {@inheritDoc} */ @Override - public @Nullable Location getLocation(@NotNull Entity teleportee) { - return player.getLocation(); + public @NotNull Option getLocation(@NotNull Entity teleportee) { + return Option.of(player.getLocation()); } /** * {@inheritDoc} */ @Override - public @Nullable Vector getVelocity(@NotNull Entity teleportee) { - return null; + public @NotNull Option getVelocity(@NotNull Entity teleportee) { + return Option.none(); } /** * {@inheritDoc} */ @Override - public @Nullable String getFinerPermissionSuffix() { - return player.getName(); + public boolean checkTeleportSafety() { + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public @NotNull Option getFinerPermissionSuffix() { + return Option.of(player.getName()); } /** 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 b28aec4c..bf85af04 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 @@ -9,7 +9,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jvnet.hk2.annotations.Service; -import org.mvplugins.multiverse.core.api.Destination; +import org.mvplugins.multiverse.core.destination.Destination; import org.mvplugins.multiverse.core.api.LocationManipulation; import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld; import org.mvplugins.multiverse.core.world.WorldManager; @@ -18,7 +18,7 @@ import org.mvplugins.multiverse.core.world.WorldManager; * {@link Destination} implementation for exact locations. */ @Service -public class WorldDestination implements Destination { +public class WorldDestination implements Destination { private final WorldManager worldManager; private final LocationManipulation locationManipulation; @@ -56,7 +56,7 @@ public class WorldDestination implements Destination { String direction = (items.length == 2) ? items[1] : null; float yaw = direction != null ? this.locationManipulation.getYaw(direction) : -1; - return new WorldDestinationInstance(world, direction, yaw); + return new WorldDestinationInstance(this, world, direction, yaw); } /** @@ -67,12 +67,4 @@ public class WorldDestination implements Destination { // Autocomplete of worlds is done by MVCommandCompletion without prefix return Collections.emptyList(); } - - /** - * {@inheritDoc} - */ - @Override - public boolean checkTeleportSafety() { - return true; - } } diff --git a/src/main/java/org/mvplugins/multiverse/core/destination/core/WorldDestinationInstance.java b/src/main/java/org/mvplugins/multiverse/core/destination/core/WorldDestinationInstance.java index f0ce05fe..3f09d718 100644 --- a/src/main/java/org/mvplugins/multiverse/core/destination/core/WorldDestinationInstance.java +++ b/src/main/java/org/mvplugins/multiverse/core/destination/core/WorldDestinationInstance.java @@ -1,18 +1,19 @@ package org.mvplugins.multiverse.core.destination.core; +import io.vavr.control.Option; import org.bukkit.Location; import org.bukkit.entity.Entity; import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.mvplugins.multiverse.core.api.DestinationInstance; +import org.mvplugins.multiverse.core.destination.DestinationInstance; import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld; /** * Destination instance implementation for the {@link WorldDestination}. */ -public class WorldDestinationInstance implements DestinationInstance { +public class WorldDestinationInstance extends DestinationInstance { private final LoadedMultiverseWorld world; private final String direction; private final float yaw; @@ -20,11 +21,18 @@ public class WorldDestinationInstance implements DestinationInstance { /** * Constructor. * - * @param world The world to teleport to. - * @param direction The direction to face. - * @param yaw The yaw to face. + * @param destination The destination. + * @param world The world to teleport to. + * @param direction The direction to face. + * @param yaw The yaw to face. */ - WorldDestinationInstance(@NotNull LoadedMultiverseWorld world, @Nullable String direction, float yaw) { + WorldDestinationInstance( + @NotNull WorldDestination destination, + @NotNull LoadedMultiverseWorld world, + @Nullable String direction, + float yaw + ) { + super(destination); this.world = world; this.direction = direction; this.yaw = yaw; @@ -34,29 +42,37 @@ public class WorldDestinationInstance implements DestinationInstance { * {@inheritDoc} */ @Override - public @Nullable Location getLocation(@NotNull Entity teleportee) { + public @NotNull Option getLocation(@NotNull Entity teleportee) { Location worldLoc = world.getSpawnLocation(); if (this.yaw >= 0) { // Only modify the yaw if its set. worldLoc.setYaw(this.yaw); } - return worldLoc; + return Option.of(worldLoc); } /** * {@inheritDoc} */ @Override - public @Nullable Vector getVelocity(@NotNull Entity teleportee) { - return null; + public @NotNull Option getVelocity(@NotNull Entity teleportee) { + return Option.none(); } /** * {@inheritDoc} */ @Override - public @Nullable String getFinerPermissionSuffix() { - return world.getName(); + public boolean checkTeleportSafety() { + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public @NotNull Option getFinerPermissionSuffix() { + return Option.of(world.getName()); } /** diff --git a/src/main/java/org/mvplugins/multiverse/core/event/MVTeleportEvent.java b/src/main/java/org/mvplugins/multiverse/core/event/MVTeleportEvent.java index 532213b3..196ddb59 100644 --- a/src/main/java/org/mvplugins/multiverse/core/event/MVTeleportEvent.java +++ b/src/main/java/org/mvplugins/multiverse/core/event/MVTeleportEvent.java @@ -14,7 +14,7 @@ import org.bukkit.event.Cancellable; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; -import org.mvplugins.multiverse.core.destination.ParsedDestination; +import org.mvplugins.multiverse.core.destination.DestinationInstance; import org.mvplugins.multiverse.core.teleportation.AsyncSafetyTeleporter; /** @@ -23,11 +23,11 @@ import org.mvplugins.multiverse.core.teleportation.AsyncSafetyTeleporter; public class MVTeleportEvent extends Event implements Cancellable { private Player teleportee; private CommandSender teleporter; - private ParsedDestination dest; + private DestinationInstance dest; private boolean useSafeTeleport; private boolean isCancelled; - public MVTeleportEvent(ParsedDestination dest, Player teleportee, CommandSender teleporter, boolean safeTeleport) { + public MVTeleportEvent(DestinationInstance dest, Player teleportee, CommandSender teleporter, boolean safeTeleport) { this.teleportee = teleportee; this.teleporter = teleporter; this.dest = dest; @@ -84,7 +84,7 @@ public class MVTeleportEvent extends Event implements Cancellable { * * @return The destination the player will spawn at. */ - public ParsedDestination getDestination() { + public DestinationInstance getDestination() { return this.dest; } diff --git a/src/main/java/org/mvplugins/multiverse/core/listeners/MVPlayerListener.java b/src/main/java/org/mvplugins/multiverse/core/listeners/MVPlayerListener.java index dca3ef50..07334465 100644 --- a/src/main/java/org/mvplugins/multiverse/core/listeners/MVPlayerListener.java +++ b/src/main/java/org/mvplugins/multiverse/core/listeners/MVPlayerListener.java @@ -36,8 +36,8 @@ import org.mvplugins.multiverse.core.MultiverseCore; import org.mvplugins.multiverse.core.api.BlockSafety; import org.mvplugins.multiverse.core.commandtools.MVCommandManager; import org.mvplugins.multiverse.core.config.MVCoreConfig; +import org.mvplugins.multiverse.core.destination.DestinationInstance; import org.mvplugins.multiverse.core.destination.DestinationsProvider; -import org.mvplugins.multiverse.core.destination.ParsedDestination; import org.mvplugins.multiverse.core.economy.MVEconomist; import org.mvplugins.multiverse.core.event.MVRespawnEvent; import org.mvplugins.multiverse.core.teleportation.AsyncSafetyTeleporter; @@ -173,7 +173,8 @@ public class MVPlayerListener implements CoreListener { return; } - Option.of(destinationsProvider.parseDestination(config.getFirstSpawnLocation())) + // todo: Config should auto serialise to and from DestinationInstance + destinationsProvider.parseDestination(config.getFirstSpawnLocation()) .peek(parsedDestination -> { if (!player.hasPlayedBefore()) { Logging.finer("Player joined for the FIRST time!"); @@ -207,15 +208,9 @@ public class MVPlayerListener implements CoreListener { } Logging.finer("JoinDestination is " + config.getJoinDestination()); - ParsedDestination joinDestination = destinationsProvider.parseDestination(config.getJoinDestination()); - - if (joinDestination == null) { - Logging.warning("The destination in JoinDestination in config is invalid"); - return; - } - - // Finally, teleport the player - safetyTeleporter.teleportSafely(player, player, joinDestination); + destinationsProvider.parseDestination(config.getJoinDestination()) + .peek(destination -> safetyTeleporter.teleportSafely(player, player, destination)) + .onEmpty(() -> Logging.warning("The destination in JoinDestination in config is invalid")); } /** @@ -350,7 +345,7 @@ public class MVPlayerListener implements CoreListener { Logging.fine("Teleport result: %s", entryResult); } - private void sendPlayerToDefaultWorld(final Player player, ParsedDestination parsedDestination) { + private void sendPlayerToDefaultWorld(final Player player, DestinationInstance parsedDestination) { // Remove the player 1 tick after the login. I'm sure there's GOT to be a better way to do this... this.server.getScheduler().scheduleSyncDelayedTask(this.plugin, new Runnable() { diff --git a/src/main/java/org/mvplugins/multiverse/core/permissions/CorePermissionsChecker.java b/src/main/java/org/mvplugins/multiverse/core/permissions/CorePermissionsChecker.java index 9e934535..9fea9c46 100644 --- a/src/main/java/org/mvplugins/multiverse/core/permissions/CorePermissionsChecker.java +++ b/src/main/java/org/mvplugins/multiverse/core/permissions/CorePermissionsChecker.java @@ -7,16 +7,16 @@ import org.bukkit.entity.Entity; import org.jetbrains.annotations.NotNull; import org.jvnet.hk2.annotations.Service; -import org.mvplugins.multiverse.core.api.Destination; +import org.mvplugins.multiverse.core.destination.Destination; +import org.mvplugins.multiverse.core.destination.DestinationInstance; import org.mvplugins.multiverse.core.destination.DestinationsProvider; -import org.mvplugins.multiverse.core.destination.ParsedDestination; import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld; import org.mvplugins.multiverse.core.world.MultiverseWorld; @Service public class CorePermissionsChecker { - private DestinationsProvider destinationsProvider; + private final DestinationsProvider destinationsProvider; @Inject CorePermissionsChecker(@NotNull DestinationsProvider destinationsProvider) { @@ -50,7 +50,7 @@ public class CorePermissionsChecker { public boolean checkTeleportPermissions( @NotNull CommandSender teleporter, @NotNull Entity teleportee, - @NotNull ParsedDestination destination) { + @NotNull DestinationInstance destination) { String permission = concatPermission( CorePermissions.TELEPORT, @@ -61,13 +61,13 @@ public class CorePermissionsChecker { } // TODO: Config whether to use finer permission - String finerPermissionSuffix = destination.getDestinationInstance().getFinerPermissionSuffix(); - if (finerPermissionSuffix == null || finerPermissionSuffix.isEmpty()) { - return true; - } - - String finerPermission = concatPermission(permission, finerPermissionSuffix); - return hasPermission(teleporter, finerPermission); + return destination.getFinerPermissionSuffix() + .filter(String::isBlank) + .map(finerPermissionSuffix -> hasPermission( + teleporter, + concatPermission(permission, finerPermissionSuffix) + )) + .getOrElse(true); } /** @@ -77,7 +77,7 @@ public class CorePermissionsChecker { * @return True if the issuer has permission, false otherwise. */ public boolean hasAnyTeleportPermission(CommandSender sender) { - for (Destination destination : destinationsProvider.getDestinations()) { + for (Destination destination : destinationsProvider.getDestinations()) { String permission = concatPermission(CorePermissions.TELEPORT, "self", destination.getIdentifier()); if (hasPermission(sender, permission)) { return true; diff --git a/src/main/java/org/mvplugins/multiverse/core/teleportation/AsyncSafetyTeleporter.java b/src/main/java/org/mvplugins/multiverse/core/teleportation/AsyncSafetyTeleporter.java index 4ee84d1a..9c9de783 100644 --- a/src/main/java/org/mvplugins/multiverse/core/teleportation/AsyncSafetyTeleporter.java +++ b/src/main/java/org/mvplugins/multiverse/core/teleportation/AsyncSafetyTeleporter.java @@ -14,7 +14,7 @@ import org.jetbrains.annotations.Nullable; import org.jvnet.hk2.annotations.Service; import org.mvplugins.multiverse.core.api.BlockSafety; -import org.mvplugins.multiverse.core.destination.ParsedDestination; +import org.mvplugins.multiverse.core.destination.DestinationInstance; import org.mvplugins.multiverse.core.utils.result.Async; import org.mvplugins.multiverse.core.utils.result.AsyncAttempt; import org.mvplugins.multiverse.core.utils.result.Attempt; @@ -37,14 +37,14 @@ public class AsyncSafetyTeleporter { public AsyncAttempt teleportSafely( @NotNull Entity teleportee, - @Nullable ParsedDestination destination) { + @Nullable DestinationInstance destination) { return teleportSafely(null, teleportee, destination); } public Async>> teleportSafely( @Nullable CommandSender teleporter, @NotNull List teleportees, - @Nullable ParsedDestination destination) { + @Nullable DestinationInstance destination) { return AsyncAttempt.allOf(teleportees.stream() .map(teleportee -> teleportSafely(teleporter, teleportee, destination)) .toList()); @@ -53,13 +53,15 @@ public class AsyncSafetyTeleporter { public AsyncAttempt teleportSafely( @Nullable CommandSender teleporter, @NotNull Entity teleportee, - @Nullable ParsedDestination destination) { + @Nullable DestinationInstance destination) { if (destination == null) { return AsyncAttempt.failure(TeleportResult.Failure.NULL_DESTINATION); } - return destination.getDestination().checkTeleportSafety() - ? teleportSafely(teleporter, teleportee, destination.getLocation(teleportee)) - : teleport(teleporter, teleportee, destination.getLocation(teleportee)); + return destination.getLocation(teleportee) + .map(location -> destination.checkTeleportSafety() + ? teleportSafely(teleporter, teleportee, location) + : teleport(teleporter, teleportee, location)) + .getOrElse(AsyncAttempt.failure(TeleportResult.Failure.NULL_LOCATION)); } public AsyncAttempt teleportSafely( @@ -84,7 +86,7 @@ public class AsyncSafetyTeleporter { public Async>> teleport( @NotNull List teleportees, - @Nullable ParsedDestination destination) { + @Nullable DestinationInstance destination) { return AsyncAttempt.allOf(teleportees.stream() .map(teleportee -> teleport(teleportee, destination)) .toList()); @@ -92,18 +94,20 @@ public class AsyncSafetyTeleporter { public AsyncAttempt teleport( @NotNull Entity teleportee, - @Nullable ParsedDestination destination) { + @Nullable DestinationInstance destination) { return teleport(null, teleportee, destination); } public AsyncAttempt teleport( @Nullable CommandSender teleporter, @NotNull Entity teleportee, - @Nullable ParsedDestination destination) { - if (destination == null) { - return AsyncAttempt.failure(TeleportResult.Failure.NULL_DESTINATION); - } - return teleport(teleporter, teleportee, destination.getLocation(teleportee)); + @Nullable DestinationInstance destination) { + if (destination == null) { + return AsyncAttempt.failure(TeleportResult.Failure.NULL_DESTINATION); + } + return destination.getLocation(teleportee) + .map(location -> teleport(teleporter, teleportee, location)) + .getOrElse(AsyncAttempt.failure(TeleportResult.Failure.NULL_LOCATION)); } public Async>> teleport( @@ -139,15 +143,15 @@ public class AsyncSafetyTeleporter { private AsyncAttempt doAsyncTeleport( @NotNull Entity teleportee, @NotNull Location location, - boolean shouldAddToQueue) { + boolean shouldRemoveFromQueue) { return AsyncAttempt.of(PaperLib.teleportAsync(teleportee, location), exception -> { Logging.warning("Failed to teleport %s to %s: %s", teleportee.getName(), location, exception.getMessage()); return Attempt.failure(TeleportResult.Failure.TELEPORT_FAILED_EXCEPTION); - }).mapAttempt(result -> { + }).mapAttempt(success -> { Logging.finer("Teleported async %s to %s", teleportee.getName(), location); - if (result) { - if (shouldAddToQueue) { + if (success) { + if (shouldRemoveFromQueue) { teleportQueue.popFromQueue(teleportee.getName()); } return Attempt.success(null); diff --git a/src/test/java/org/mvplugins/multiverse/core/destination/DestinationTest.kt b/src/test/java/org/mvplugins/multiverse/core/destination/DestinationTest.kt new file mode 100644 index 00000000..b260ab04 --- /dev/null +++ b/src/test/java/org/mvplugins/multiverse/core/destination/DestinationTest.kt @@ -0,0 +1,122 @@ +package org.mvplugins.multiverse.core.destination + +import org.bukkit.Location +import org.mockbukkit.mockbukkit.entity.PlayerMock +import org.mvplugins.multiverse.core.TestWithMockBukkit +import org.mvplugins.multiverse.core.destination.core.* +import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld +import org.mvplugins.multiverse.core.world.WorldManager +import org.mvplugins.multiverse.core.world.options.CreateWorldOptions +import kotlin.test.BeforeTest +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +class DestinationTest : TestWithMockBukkit() { + + private lateinit var worldManager: WorldManager + private lateinit var destinationsProvider: DestinationsProvider + private lateinit var world: LoadedMultiverseWorld + private lateinit var player: PlayerMock + + @BeforeTest + fun setUp() { + worldManager = serviceLocator.getActiveService(WorldManager::class.java).takeIf { it != null } ?: run { + throw IllegalStateException("WorldManager is not available as a service") } + destinationsProvider = serviceLocator.getActiveService(DestinationsProvider::class.java).takeIf { it != null } ?: run { + throw IllegalStateException("DestinationsProvider is not available as a service") } + + world = worldManager.createWorld(CreateWorldOptions.worldName("world")).get() + player = server.addPlayer("benji_0224") + player.bedSpawnLocation = Location(world.bukkitWorld.orNull, 5.0, 10.0, 5.0) + } + + @Test + fun `Bed destination instance`() { + assertTrue(destinationsProvider.getDestinationById("b") is BedDestination) + val destination = destinationsProvider.parseDestination("b:benji_0224").orNull + assertTrue(destination is BedDestinationInstance) + assertEquals(player.bedSpawnLocation, destination.getLocation(player).orNull) + assertEquals("b:benji_0224", destination.toString()) + } + + @Test + fun `Bed destination instance own player`() { + val destination = destinationsProvider.parseDestination("b:playerbed").orNull + assertTrue(destination is BedDestinationInstance) + assertEquals(player.bedSpawnLocation, destination.getLocation(player).orNull) + assertEquals("b:playerbed", destination.toString()) + } + + @Test + fun `Cannon destination instance`() { + assertTrue(destinationsProvider.getDestinationById("ca") is CannonDestination) + val destination = destinationsProvider.parseDestination("ca:world:1.2,2,3:10.5:9.5:5").orNull + assertTrue(destination is CannonDestinationInstance) + val expectedLocation = Location(world.bukkitWorld.orNull, 1.2, 2.0, 3.0, 9.5F, 10.5F) + assertEquals(expectedLocation, destination.getLocation(player).orNull) + // todo: assert the Vector + assertEquals("ca:world:1.2,2.0,3.0:10.5:9.5:5.0", destination.toString()) + } + + @Test + fun `Exact destination instance`() { + assertTrue(destinationsProvider.getDestinationById("e") is ExactDestination) + val destination = destinationsProvider.parseDestination("e:world:1.2,2,3:10.5:9.5").orNull + assertTrue(destination is ExactDestinationInstance) + val expectedLocation = Location(world.bukkitWorld.orNull, 1.2, 2.0, 3.0, 9.5F, 10.5F) + assertEquals(expectedLocation, destination.getLocation(player).orNull) + assertEquals("e:world:1.2,2.0,3.0:10.5:9.5", destination.toString()) + } + + @Test + fun `Exact destination instance from location`() { + val exactDestination = serviceLocator.getActiveService(ExactDestination::class.java).takeIf { it != null } ?: run { + throw IllegalStateException("ExactDestination is not available as a service") } + + val location = Location(world.bukkitWorld.orNull, 1.2, 2.0, 3.0, 9.5F, 10.5F) + val destination = exactDestination.fromLocation(location) + assertEquals(location, destination.getLocation(player).orNull) + assertEquals("e:world:1.2,2.0,3.0:10.5:9.5", destination.toString()) + } + + @Test + fun `Player destination instance`() { + assertTrue(destinationsProvider.getDestinationById("pl") is PlayerDestination) + val destination = destinationsProvider.parseDestination("pl:benji_0224").orNull + assertTrue(destination is PlayerDestinationInstance) + assertEquals(player.location, destination.getLocation(player).orNull) + assertEquals("pl:benji_0224", destination.toString()) + } + + @Test + fun `World destination instance`() { + assertTrue(destinationsProvider.getDestinationById("w") is WorldDestination) + val destination = destinationsProvider.parseDestination("w:world").orNull + assertTrue(destination is WorldDestinationInstance) + assertEquals(world.spawnLocation, destination.getLocation(player).orNull) + assertEquals("w:world", destination.toString()) + } + + @Test + fun `World destination instance without identifier`() { + val destination = destinationsProvider.parseDestination("world").orNull + assertTrue(destination is WorldDestinationInstance) + assertEquals(world.spawnLocation, destination.getLocation(player).orNull) + assertEquals("w:world", destination.toString()) + } + + @Test + fun `Invalid destination instance`() { + assertTrue(destinationsProvider.parseDestination("").isEmpty) + assertTrue(destinationsProvider.parseDestination("idk:world").isEmpty) + assertTrue(destinationsProvider.parseDestination("a:invalid-anchor").isEmpty) + assertTrue(destinationsProvider.parseDestination("b:invalid-bed").isEmpty) + assertTrue(destinationsProvider.parseDestination("ca:invalid-cannon").isEmpty) + assertTrue(destinationsProvider.parseDestination("e:world:1,2,x").isEmpty) + assertTrue(destinationsProvider.parseDestination("pl:invalid-player").isEmpty) + assertTrue(destinationsProvider.parseDestination("w:invalid-world").isEmpty) + // todo: should we make invalid yaw for WorldDestination fail? + // assertTrue(destinationsProvider.parseDestination("w:world:f").isEmpty) + } +} diff --git a/src/test/java/org/mvplugins/multiverse/core/inject/InjectionTest.kt b/src/test/java/org/mvplugins/multiverse/core/inject/InjectionTest.kt index 15c00dce..1dc0de8d 100644 --- a/src/test/java/org/mvplugins/multiverse/core/inject/InjectionTest.kt +++ b/src/test/java/org/mvplugins/multiverse/core/inject/InjectionTest.kt @@ -3,7 +3,7 @@ package org.mvplugins.multiverse.core.inject import org.mvplugins.multiverse.core.TestWithMockBukkit import org.mvplugins.multiverse.core.anchor.AnchorManager import org.mvplugins.multiverse.core.api.BlockSafety -import org.mvplugins.multiverse.core.api.Destination +import org.mvplugins.multiverse.core.destination.Destination import org.mvplugins.multiverse.core.api.LocationManipulation import org.mvplugins.multiverse.core.commandtools.MVCommandManager import org.mvplugins.multiverse.core.commandtools.MultiverseCommand @@ -17,7 +17,6 @@ import org.mvplugins.multiverse.core.teleportation.SimpleLocationManipulation import org.mvplugins.multiverse.core.teleportation.TeleportQueue import org.mvplugins.multiverse.core.utils.metrics.MetricsConfigurator import org.mvplugins.multiverse.core.world.WorldManager -import org.mvplugins.multiverse.core.world.config.WorldsConfigManager import kotlin.test.* class InjectionTest : TestWithMockBukkit() { @@ -110,7 +109,6 @@ class InjectionTest : TestWithMockBukkit() { @Test fun `Destinations are available as services`() { val destinations = serviceLocator.getAllActiveServices(Destination::class.java) - // TODO: come up with a better way to test this like via actually testing the effect of using each destination assertEquals(6, destinations.size) }