From 23b429940cd5aa3b3ded6fec1613626e6ea37e3d Mon Sep 17 00:00:00 2001 From: Ben Woo <30431861+benwoo1110@users.noreply.github.com> Date: Thu, 14 Sep 2023 11:03:45 +0800 Subject: [PATCH] Fully implement AsyncResult --- .../core/commands/DeleteCommand.java | 4 +- .../core/commands/RegenCommand.java | 4 +- .../core/commands/RemoveCommand.java | 6 +-- .../core/commands/TeleportCommand.java | 4 +- .../core/commands/UnloadCommand.java | 4 +- .../teleportation/AsyncSafetyTeleporter.java | 20 ++++---- .../result/{AsyncResult.java => Async.java} | 46 +++++++++---------- .../core/utils/result/AsyncAttempt.java | 21 ++++++++- .../world/helpers/PlayerWorldTeleporter.java | 35 ++++++++------ 9 files changed, 84 insertions(+), 60 deletions(-) rename src/main/java/org/mvplugins/multiverse/core/utils/result/{AsyncResult.java => Async.java} (74%) 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 dc311e84..f0113280 100644 --- a/src/main/java/org/mvplugins/multiverse/core/commands/DeleteCommand.java +++ b/src/main/java/org/mvplugins/multiverse/core/commands/DeleteCommand.java @@ -24,7 +24,7 @@ import org.mvplugins.multiverse.core.commandtools.flags.CommandFlag; import org.mvplugins.multiverse.core.commandtools.flags.ParsedCommandFlags; import org.mvplugins.multiverse.core.commandtools.queue.QueuedCommand; import org.mvplugins.multiverse.core.utils.MVCorei18n; -import org.mvplugins.multiverse.core.utils.result.AsyncResult; +import org.mvplugins.multiverse.core.utils.result.Async; import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld; import org.mvplugins.multiverse.core.world.WorldManager; import org.mvplugins.multiverse.core.world.helpers.PlayerWorldTeleporter; @@ -83,7 +83,7 @@ class DeleteCommand extends MultiverseCommand { var future = parsedFlags.hasFlag(REMOVE_PLAYERS_FLAG) ? playerWorldTeleporter.removeFromWorld(world) - : AsyncResult.completedFuture(Collections.emptyList()); + : Async.completedFuture(Collections.emptyList()); future.thenRun(() -> doWorldDeleting(issuer, world)); } 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 0c6a8ffb..23f56a14 100644 --- a/src/main/java/org/mvplugins/multiverse/core/commands/RegenCommand.java +++ b/src/main/java/org/mvplugins/multiverse/core/commands/RegenCommand.java @@ -26,7 +26,7 @@ import org.mvplugins.multiverse.core.commandtools.flags.CommandValueFlag; import org.mvplugins.multiverse.core.commandtools.flags.ParsedCommandFlags; import org.mvplugins.multiverse.core.commandtools.queue.QueuedCommand; import org.mvplugins.multiverse.core.utils.MVCorei18n; -import org.mvplugins.multiverse.core.utils.result.AsyncResult; +import org.mvplugins.multiverse.core.utils.result.Async; import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld; import org.mvplugins.multiverse.core.world.WorldManager; import org.mvplugins.multiverse.core.world.helpers.PlayerWorldTeleporter; @@ -101,7 +101,7 @@ class RegenCommand extends MultiverseCommand { var future = parsedFlags.hasFlag(REMOVE_PLAYERS_FLAG) ? playerWorldTeleporter.removeFromWorld(world) - : AsyncResult.completedFuture(Collections.emptyList()); + : Async.completedFuture(Collections.emptyList()); future.thenRun(() -> doWorldRegening(issuer, world, parsedFlags, worldPlayers)); } 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 9a62bf6f..a17206ee 100644 --- a/src/main/java/org/mvplugins/multiverse/core/commands/RemoveCommand.java +++ b/src/main/java/org/mvplugins/multiverse/core/commands/RemoveCommand.java @@ -22,7 +22,7 @@ import org.mvplugins.multiverse.core.commandtools.MultiverseCommand; import org.mvplugins.multiverse.core.commandtools.flags.CommandFlag; import org.mvplugins.multiverse.core.commandtools.flags.ParsedCommandFlags; import org.mvplugins.multiverse.core.utils.MVCorei18n; -import org.mvplugins.multiverse.core.utils.result.AsyncResult; +import org.mvplugins.multiverse.core.utils.result.Async; import org.mvplugins.multiverse.core.world.WorldManager; import org.mvplugins.multiverse.core.world.helpers.PlayerWorldTeleporter; @@ -70,8 +70,8 @@ class RemoveCommand extends MultiverseCommand { var future = parsedFlags.hasFlag(REMOVE_PLAYERS_FLAG) ? worldManager.getLoadedWorld(worldName) .map(playerWorldTeleporter::removeFromWorld) - .getOrElse(AsyncResult.completedFuture(Collections.emptyList())) - : AsyncResult.completedFuture(Collections.emptyList()); + .getOrElse(Async.completedFuture(Collections.emptyList())) + : Async.completedFuture(Collections.emptyList()); future.thenRun(() -> doWorldRemoving(issuer, worldName)); } 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 8b2e454b..149e9652 100644 --- a/src/main/java/org/mvplugins/multiverse/core/commands/TeleportCommand.java +++ b/src/main/java/org/mvplugins/multiverse/core/commands/TeleportCommand.java @@ -22,7 +22,7 @@ import org.mvplugins.multiverse.core.destination.ParsedDestination; import org.mvplugins.multiverse.core.permissions.CorePermissionsChecker; import org.mvplugins.multiverse.core.teleportation.AsyncSafetyTeleporter; import org.mvplugins.multiverse.core.utils.MVCorei18n; -import org.mvplugins.multiverse.core.utils.result.AsyncResult; +import org.mvplugins.multiverse.core.utils.result.AsyncAttempt; @Service @CommandAlias("mv") @@ -72,7 +72,7 @@ class TeleportCommand extends MultiverseCommand { issuer.sendInfo(MVCorei18n.TELEPORT_SUCCESS, "{player}", playerName, "{destination}", destination.toString()); - AsyncResult.allOf(Arrays.stream(players) + AsyncAttempt.allOf(Arrays.stream(players) .map(player -> safetyTeleporter.teleportSafely(issuer.getIssuer(), player, destination)) .toList()) .thenRun(() -> Logging.fine("Async teleport result: %s")) 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 e9e9abdb..42a85aa4 100644 --- a/src/main/java/org/mvplugins/multiverse/core/commands/UnloadCommand.java +++ b/src/main/java/org/mvplugins/multiverse/core/commands/UnloadCommand.java @@ -20,7 +20,7 @@ import org.mvplugins.multiverse.core.commandtools.MultiverseCommand; import org.mvplugins.multiverse.core.commandtools.flags.CommandFlag; import org.mvplugins.multiverse.core.commandtools.flags.ParsedCommandFlags; import org.mvplugins.multiverse.core.utils.MVCorei18n; -import org.mvplugins.multiverse.core.utils.result.AsyncResult; +import org.mvplugins.multiverse.core.utils.result.Async; import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld; import org.mvplugins.multiverse.core.world.WorldManager; import org.mvplugins.multiverse.core.world.helpers.PlayerWorldTeleporter; @@ -73,7 +73,7 @@ class UnloadCommand extends MultiverseCommand { var future = parsedFlags.hasFlag(REMOVE_PLAYERS_FLAG) ? playerWorldTeleporter.removeFromWorld(world) - : AsyncResult.completedFuture(Collections.emptyList()); + : Async.completedFuture(Collections.emptyList()); future.thenRun(() -> doWorldUnloading(issuer, world, parsedFlags)); } 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 5d76ebb5..dc49301e 100644 --- a/src/main/java/org/mvplugins/multiverse/core/teleportation/AsyncSafetyTeleporter.java +++ b/src/main/java/org/mvplugins/multiverse/core/teleportation/AsyncSafetyTeleporter.java @@ -4,7 +4,6 @@ import java.util.List; import com.dumptruckman.minecraft.util.Logging; import io.papermc.lib.PaperLib; -import io.vavr.control.Try; import jakarta.inject.Inject; import org.bukkit.Location; import org.bukkit.command.CommandSender; @@ -16,12 +15,13 @@ 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.utils.result.Async; import org.mvplugins.multiverse.core.utils.result.AsyncAttempt; -import org.mvplugins.multiverse.core.utils.result.AsyncResult; import org.mvplugins.multiverse.core.utils.result.Attempt; -import org.mvplugins.multiverse.core.utils.result.Result; -@SuppressWarnings("unchecked") +/** + * Teleports entities safely and asynchronously. + */ @Service public class AsyncSafetyTeleporter { private final BlockSafety blockSafety; @@ -41,11 +41,11 @@ public class AsyncSafetyTeleporter { return teleportSafely(null, teleportee, destination); } - public AsyncResult>> teleportSafely( + public Async>> teleportSafely( @Nullable CommandSender teleporter, @NotNull List teleportees, @Nullable ParsedDestination destination) { - return AsyncResult.allOf(teleportees.stream() + return AsyncAttempt.allOf(teleportees.stream() .map(teleportee -> teleportSafely(teleporter, teleportee, destination)) .toList()); } @@ -82,10 +82,10 @@ public class AsyncSafetyTeleporter { return teleport(teleporter, teleportee, safeLocation); } - public AsyncResult>> teleport( + public Async>> teleport( @NotNull List teleportees, @Nullable ParsedDestination destination) { - return AsyncResult.allOf(teleportees.stream() + return AsyncAttempt.allOf(teleportees.stream() .map(teleportee -> teleport(teleportee, destination)) .toList()); } @@ -106,10 +106,10 @@ public class AsyncSafetyTeleporter { return teleport(teleporter, teleportee, destination.getLocation(teleportee)); } - public AsyncResult>> teleport( + public Async>> teleport( @NotNull List teleportees, @Nullable Location location) { - return AsyncResult.allOf(teleportees.stream() + return AsyncAttempt.allOf(teleportees.stream() .map(teleportee -> teleport(teleportee, location)) .toList()); } diff --git a/src/main/java/org/mvplugins/multiverse/core/utils/result/AsyncResult.java b/src/main/java/org/mvplugins/multiverse/core/utils/result/Async.java similarity index 74% rename from src/main/java/org/mvplugins/multiverse/core/utils/result/AsyncResult.java rename to src/main/java/org/mvplugins/multiverse/core/utils/result/Async.java index 8d0a268a..4718a2f8 100644 --- a/src/main/java/org/mvplugins/multiverse/core/utils/result/AsyncResult.java +++ b/src/main/java/org/mvplugins/multiverse/core/utils/result/Async.java @@ -11,7 +11,7 @@ import java.util.function.Function; * * @param The type of the value. */ -public final class AsyncResult { +public final class Async { /** * Returns a new AsyncResult that is completed when all of the given AsyncResult complete. @@ -19,8 +19,8 @@ public final class AsyncResult { * @param results The results to wait for. * @return A new AsyncResult that is completed when all of the given AsyncResult complete. */ - public static AsyncResult allOf(AsyncResult... results) { - return new AsyncResult<>(CompletableFuture.allOf(Arrays.stream(results) + public static Async allOf(Async... results) { + return new Async<>(CompletableFuture.allOf(Arrays.stream(results) .map(result -> result.future) .toArray(CompletableFuture[]::new))); } @@ -32,8 +32,8 @@ public final class AsyncResult { * @param The type of the AsyncResult. * @return A new AsyncResult that is completed when all of the given AsyncResult complete. */ - public static AsyncResult> allOf(List> results) { - return new AsyncResult<>(CompletableFuture.allOf(results.stream() + public static Async> allOf(List> results) { + return new Async<>(CompletableFuture.allOf(results.stream() .map(result -> result.future) .toArray(CompletableFuture[]::new)) .thenApply(v -> results.stream() @@ -48,8 +48,8 @@ public final class AsyncResult { * @param The type of the future. * @return A new AsyncResult that is completed when the given future completes. */ - public static AsyncResult of(CompletableFuture future) { - return new AsyncResult<>(future); + public static Async of(CompletableFuture future) { + return new Async<>(future); } /** @@ -59,8 +59,8 @@ public final class AsyncResult { * @param The type of the value. * @return The completed AsyncResult. */ - public static AsyncResult completedFuture(T value) { - return new AsyncResult<>(CompletableFuture.completedFuture(value)); + public static Async completedFuture(T value) { + return new Async<>(CompletableFuture.completedFuture(value)); } /** @@ -70,8 +70,8 @@ public final class AsyncResult { * @param The type of the value. * @return The completed AsyncResult. */ - public static AsyncResult failedFuture(Throwable throwable) { - return new AsyncResult<>(CompletableFuture.failedFuture(throwable)); + public static Async failedFuture(Throwable throwable) { + return new Async<>(CompletableFuture.failedFuture(throwable)); } private final CompletableFuture future; @@ -79,11 +79,11 @@ public final class AsyncResult { /** * Creates a new AsyncResult. */ - public AsyncResult() { + public Async() { this(new CompletableFuture<>()); } - private AsyncResult(CompletableFuture future) { + private Async(CompletableFuture future) { this.future = future; } @@ -113,8 +113,8 @@ public final class AsyncResult { * @param consumer The action to perform. * @return This AsyncResult. */ - public AsyncResult thenAccept(Consumer consumer) { - return new AsyncResult<>(future.thenAccept(consumer)); + public Async thenAccept(Consumer consumer) { + return new Async<>(future.thenAccept(consumer)); } /** @@ -123,8 +123,8 @@ public final class AsyncResult { * @param runnable The action to perform. * @return This AsyncResult. */ - public AsyncResult thenRun(Runnable runnable) { - return new AsyncResult<>(future.thenRun(runnable)); + public Async thenRun(Runnable runnable) { + return new Async<>(future.thenRun(runnable)); } /** @@ -134,8 +134,8 @@ public final class AsyncResult { * @param The type of the new value. * @return A new AsyncResult with the new value. */ - public AsyncResult thenApply(Function function) { - return new AsyncResult<>(future.thenApply(function)); + public Async thenApply(Function function) { + return new Async<>(future.thenApply(function)); } /** @@ -144,8 +144,8 @@ public final class AsyncResult { * @param consumer The action to perform. * @return This AsyncResult. */ - public AsyncResult exceptionally(Consumer consumer) { - return new AsyncResult<>(future.exceptionally(throwable -> { + public Async exceptionally(Consumer consumer) { + return new Async<>(future.exceptionally(throwable -> { consumer.accept(throwable); return null; })); @@ -157,7 +157,7 @@ public final class AsyncResult { * @param function The action to perform. * @return A new AsyncResult with the new value. */ - public AsyncResult exceptionally(Function function) { - return new AsyncResult<>(future.exceptionally(function)); + public Async exceptionally(Function function) { + return new Async<>(future.exceptionally(function)); } } diff --git a/src/main/java/org/mvplugins/multiverse/core/utils/result/AsyncAttempt.java b/src/main/java/org/mvplugins/multiverse/core/utils/result/AsyncAttempt.java index 3ffd6013..1bde2779 100644 --- a/src/main/java/org/mvplugins/multiverse/core/utils/result/AsyncAttempt.java +++ b/src/main/java/org/mvplugins/multiverse/core/utils/result/AsyncAttempt.java @@ -1,5 +1,6 @@ package org.mvplugins.multiverse.core.utils.result; +import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.function.BiFunction; import java.util.function.Function; @@ -8,6 +9,15 @@ import org.mvplugins.multiverse.core.utils.message.MessageReplacement; public final class AsyncAttempt { + public static Async>> allOf(List> attempts) { + return Async.of(CompletableFuture.allOf(attempts.stream() + .map(attempt -> attempt.future) + .toArray(CompletableFuture[]::new)) + .thenApply(v -> attempts.stream() + .map(attempt -> attempt.future.join()) + .toList())); + } + public static AsyncAttempt of( CompletableFuture future, BiFunction> completionHandler) { @@ -39,18 +49,25 @@ public final class AsyncAttempt { } private final CompletableFuture> future; -` + private AsyncAttempt(CompletableFuture> future) { this.future = future; } public AsyncAttempt map(Function mapper) { - + return new AsyncAttempt<>(future.thenApply(attempt -> attempt.map(mapper))); } public AsyncAttempt mapAsyncAttempt(Function> mapper) { + return new AsyncAttempt<>(future.thenApplyAsync( + attempt -> attempt.mapAttempt(rasult -> mapper.apply(rasult).toAttempt()))); } public AsyncAttempt onSuccess(Runnable runnable) { + return new AsyncAttempt<>(future.thenApply(attempt -> attempt.onSuccess(runnable))); + } + + public Attempt toAttempt() { + return future.join(); } } diff --git a/src/main/java/org/mvplugins/multiverse/core/world/helpers/PlayerWorldTeleporter.java b/src/main/java/org/mvplugins/multiverse/core/world/helpers/PlayerWorldTeleporter.java index e340767d..27bc87bf 100644 --- a/src/main/java/org/mvplugins/multiverse/core/world/helpers/PlayerWorldTeleporter.java +++ b/src/main/java/org/mvplugins/multiverse/core/world/helpers/PlayerWorldTeleporter.java @@ -12,8 +12,8 @@ import org.jvnet.hk2.annotations.Service; import org.mvplugins.multiverse.core.teleportation.AsyncSafetyTeleporter; import org.mvplugins.multiverse.core.teleportation.TeleportResult; -import org.mvplugins.multiverse.core.utils.result.AsyncResult; -import org.mvplugins.multiverse.core.utils.result.Result; +import org.mvplugins.multiverse.core.utils.result.Async; +import org.mvplugins.multiverse.core.utils.result.Attempt; import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld; /** @@ -32,9 +32,9 @@ public class PlayerWorldTeleporter { * Removes all players from the given world. * * @param world The world to remove all players from. + * @return A list of async futures that represent the teleportation result of each player. */ - public AsyncResult>> - removeFromWorld(@NotNull LoadedMultiverseWorld world) { + public Async>> removeFromWorld(@NotNull LoadedMultiverseWorld world) { // TODO: Better handling of fallback world World toWorld = Bukkit.getWorlds().get(0); return transferFromWorldTo(world, toWorld); @@ -45,9 +45,11 @@ public class PlayerWorldTeleporter { * * @param from The world to transfer players from. * @param to The location to transfer players to. + * @return A list of async futures that represent the teleportation result of each player. */ - public AsyncResult>> - transferFromWorldTo(@NotNull LoadedMultiverseWorld from, @NotNull LoadedMultiverseWorld to) { + public Async>> transferFromWorldTo( + @NotNull LoadedMultiverseWorld from, + @NotNull LoadedMultiverseWorld to) { return transferAllFromWorldToLocation(from, to.getSpawnLocation()); } @@ -56,9 +58,11 @@ public class PlayerWorldTeleporter { * * @param from The world to transfer players from. * @param to The world to transfer players to. + * @return A list of async futures that represent the teleportation result of each player. */ - public AsyncResult>> - transferFromWorldTo(@NotNull LoadedMultiverseWorld from, @NotNull World to) { + public Async>> transferFromWorldTo( + @NotNull LoadedMultiverseWorld from, + @NotNull World to) { return transferAllFromWorldToLocation(from, to.getSpawnLocation()); } @@ -67,13 +71,14 @@ public class PlayerWorldTeleporter { * * @param world The world to transfer players from. * @param location The location to transfer players to. - * @return A list of futures that represent the teleportation of each player. + * @return A list of async futures that represent the teleportation result of each player. */ - public AsyncResult>> - transferAllFromWorldToLocation(@NotNull LoadedMultiverseWorld world, @NotNull Location location) { + public Async>> transferAllFromWorldToLocation( + @NotNull LoadedMultiverseWorld world, + @NotNull Location location) { return world.getPlayers() .map(players -> safetyTeleporter.teleport(players, location)) - .getOrElse(() -> AsyncResult.failedFuture( + .getOrElse(() -> Async.failedFuture( new IllegalStateException("Unable to get players from world" + world.getName()))); } @@ -82,9 +87,11 @@ public class PlayerWorldTeleporter { * * @param players The players to teleport. * @param world The world to teleport players to. + * @return A list of async futures that represent the teleportation result of each player. */ - public AsyncResult>> - teleportPlayersToWorld(@NotNull List players, @NotNull LoadedMultiverseWorld world) { + public Async>> teleportPlayersToWorld( + @NotNull List players, + @NotNull LoadedMultiverseWorld world) { Location spawnLocation = world.getSpawnLocation(); return safetyTeleporter.teleport(players, spawnLocation); }