Skip to content

Commit

Permalink
Merge pull request #3150 from Multiverse/ben/mv5/revamp-teleport
Browse files Browse the repository at this point in the history
Ben/mv5/revamp teleport
  • Loading branch information
benwoo1110 authored Jan 10, 2025
2 parents 303ac03 + 7c2b7e5 commit bb6d236
Show file tree
Hide file tree
Showing 19 changed files with 342 additions and 214 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,9 @@ void onSpawnTpCommand(

// Teleport the player to spawn
// TODO: Different message for teleporting self vs others
safetyTeleporter.teleportSafely(issuer.getIssuer(), player, world.getSpawnLocation())
safetyTeleporter.to(world.getSpawnLocation())
.by(issuer)
.teleport(player)
.onSuccess(() -> player.sendMessage(commandManager.formatMessage(
issuer,
MessageType.INFO,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,12 @@ void onTeleportCommand(
return;
}

(parsedFlags.hasFlag(UNSAFE_FLAG)
? safetyTeleporter.teleport(issuer.getIssuer(), List.of(players), destination)
: safetyTeleporter.teleportSafely(issuer.getIssuer(), List.of(players), destination))
safetyTeleporter.to(destination)
.by(issuer)
.checkSafety(!parsedFlags.hasFlag(UNSAFE_FLAG) && destination.checkTeleportSafety())
.teleport(List.of(players))
.thenAccept(attempts -> {
//todo: Check for attempt results
Logging.fine("Async teleport completed: %s", attempts);
issuer.sendInfo(MVCorei18n.TELEPORT_SUCCESS,
"{player}", playerName, "{destination}", destination.toString());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ public void playerJoin(PlayerJoinEvent event) {
* Will teleport the player to the destination specified in config
* @param player The {@link Player} to teleport
*/
//todo: Explore the use of PlayerSpawnLocationEvent
private void handleJoinDestination(@NotNull Player player) {
if (!config.getEnableJoinDestination()) {
Logging.finer("JoinDestination is disabled");
Expand All @@ -209,7 +210,7 @@ private void handleJoinDestination(@NotNull Player player) {

Logging.finer("JoinDestination is " + config.getJoinDestination());
destinationsProvider.parseDestination(config.getJoinDestination())
.peek(destination -> safetyTeleporter.teleportSafely(player, player, destination))
.peek(destination -> safetyTeleporter.to(destination).teleport(player))
.onEmpty(() -> Logging.warning("The destination in JoinDestination in config is invalid"));
}

Expand Down Expand Up @@ -363,7 +364,7 @@ private void sendPlayerToDefaultWorld(final Player player, DestinationInstance<?
new Runnable() {
@Override
public void run() {
safetyTeleporter.teleportSafely(player, player, parsedDestination);
safetyTeleporter.to(parsedDestination).teleport(player);
}
}, 1L);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,18 @@
package org.mvplugins.multiverse.core.teleportation;

import java.util.List;

import com.dumptruckman.minecraft.util.Logging;
import io.papermc.lib.PaperLib;
import io.vavr.control.Either;
import jakarta.inject.Inject;
import org.bukkit.Location;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.plugin.PluginManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jvnet.hk2.annotations.Service;

import org.mvplugins.multiverse.core.api.BlockSafety;
import org.mvplugins.multiverse.core.destination.DestinationInstance;
import org.mvplugins.multiverse.core.event.MVTeleportDestinationEvent;
import org.mvplugins.multiverse.core.utils.result.Async;
import org.mvplugins.multiverse.core.utils.result.AsyncAttempt;
import org.mvplugins.multiverse.core.utils.result.Attempt;

/**
* Teleports entities safely and asynchronously.
* Teleports entities safely and asynchronously. Provider for the {@link AsyncSafetyTeleporterAction}.
*/
@Service
public class AsyncSafetyTeleporter {
Expand All @@ -40,150 +30,33 @@ public class AsyncSafetyTeleporter {
this.pluginManager = pluginManager;
}

public AsyncAttempt<Void, TeleportResult.Failure> teleportSafely(
@NotNull Entity teleportee,
@Nullable DestinationInstance<?, ?> destination) {
return teleportSafely(null, teleportee, destination);
}

public <T extends Entity> Async<List<Attempt<Void, TeleportResult.Failure>>> teleportSafely(
@Nullable CommandSender teleporter,
@NotNull List<T> teleportees,
@Nullable DestinationInstance<?, ?> destination) {
return AsyncAttempt.allOf(teleportees.stream()
.map(teleportee -> teleportSafely(teleporter, teleportee, destination))
.toList());
}

public AsyncAttempt<Void, TeleportResult.Failure> teleportSafely(
@Nullable CommandSender teleporter,
@NotNull Entity teleportee,
@Nullable DestinationInstance<?, ?> destination) {
if (destination == null) {
return AsyncAttempt.failure(TeleportResult.Failure.NULL_DESTINATION);
}
MVTeleportDestinationEvent event = new MVTeleportDestinationEvent(destination, teleportee, teleporter);
this.pluginManager.callEvent(event);
if (event.isCancelled()) {
return AsyncAttempt.failure(TeleportResult.Failure.EVENT_CANCELLED);
}
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<Void, TeleportResult.Failure> teleportSafely(
@NotNull Entity teleportee,
@Nullable Location location) {
return teleportSafely(null, teleportee, location);
}

public AsyncAttempt<Void, TeleportResult.Failure> teleportSafely(
@Nullable CommandSender teleporter,
@NotNull Entity teleportee,
@Nullable Location location) {
if (location == null) {
return AsyncAttempt.failure(TeleportResult.Failure.NULL_LOCATION);
}
Location safeLocation = blockSafety.getSafeLocation(location);
if (safeLocation == null) {
return AsyncAttempt.failure(TeleportResult.Failure.UNSAFE_LOCATION);
}
return teleport(teleporter, teleportee, safeLocation);
}

public <T extends Entity> Async<List<Attempt<Void, TeleportResult.Failure>>> teleport(
@Nullable CommandSender teleporter,
@NotNull List<T> teleportees,
@Nullable DestinationInstance<?, ?> destination) {
return AsyncAttempt.allOf(teleportees.stream()
.map(teleportee -> teleport(teleporter, teleportee, destination))
.toList());
}

public <T extends Entity> Async<List<Attempt<Void, TeleportResult.Failure>>> teleport(
@NotNull List<T> teleportees,
@Nullable DestinationInstance<?, ?> destination) {
return AsyncAttempt.allOf(teleportees.stream()
.map(teleportee -> teleport(teleportee, destination))
.toList());
}

public AsyncAttempt<Void, TeleportResult.Failure> teleport(
@NotNull Entity teleportee,
@Nullable DestinationInstance<?, ?> destination) {
return teleport(null, teleportee, destination);
}

public AsyncAttempt<Void, TeleportResult.Failure> teleport(
@Nullable CommandSender teleporter,
@NotNull Entity teleportee,
@Nullable DestinationInstance<?, ?> destination) {
if (destination == null) {
return AsyncAttempt.failure(TeleportResult.Failure.NULL_DESTINATION);
}
MVTeleportDestinationEvent event = new MVTeleportDestinationEvent(destination, teleportee, teleporter);
this.pluginManager.callEvent(event);
if (event.isCancelled()) {
return AsyncAttempt.failure(TeleportResult.Failure.EVENT_CANCELLED);
}
return destination.getLocation(teleportee)
.map(location -> teleport(teleporter, teleportee, location))
.getOrElse(AsyncAttempt.failure(TeleportResult.Failure.NULL_LOCATION));
}

public <T extends Entity> Async<List<Attempt<Void, TeleportResult.Failure>>> teleport(
@NotNull List<T> teleportees,
@Nullable Location location) {
return AsyncAttempt.allOf(teleportees.stream()
.map(teleportee -> teleport(teleportee, location))
.toList());
}

public AsyncAttempt<Void, TeleportResult.Failure> teleport(
@NotNull Entity teleportee,
@Nullable Location location) {
return teleport(null, teleportee, location);
}

public AsyncAttempt<Void, TeleportResult.Failure> teleport(
@Nullable CommandSender teleporter,
@NotNull Entity teleportee,
@Nullable Location location) {
if (location == null) {
return AsyncAttempt.failure(TeleportResult.Failure.NULL_LOCATION);
}

boolean shouldAddToQueue = teleportee instanceof Player;
if (shouldAddToQueue) {
if (teleporter == null) {
teleporter = teleportee;
}
teleportQueue.addToQueue(teleporter.getName(), teleportee.getName());
}

return doAsyncTeleport(teleportee, location, shouldAddToQueue);
}

private AsyncAttempt<Void, TeleportResult.Failure> doAsyncTeleport(
@NotNull Entity teleportee,
@NotNull Location location,
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(success -> {
if (shouldRemoveFromQueue) {
teleportQueue.popFromQueue(teleportee.getName());
}
if (success) {
Logging.finer("Teleported async %s to %s", teleportee.getName(), location);
return Attempt.success(null);
}
return Attempt.failure(TeleportResult.Failure.TELEPORT_FAILED);
});
/**
* Sets the location to teleport to.
*
* @param location The location
* @return A new {@link AsyncSafetyTeleporterAction} to be chained
*/
public AsyncSafetyTeleporterAction to(@Nullable Location location) {
return new AsyncSafetyTeleporterAction(
blockSafety,
teleportQueue,
pluginManager,
Either.left(location)
);
}

/**
* Sets the destination to teleport to.
*
* @param destination The destination
* @return A new {@link AsyncSafetyTeleporterAction} to be chained
*/
public AsyncSafetyTeleporterAction to(@Nullable DestinationInstance<?, ?> destination) {
return new AsyncSafetyTeleporterAction(
blockSafety,
teleportQueue,
pluginManager,
Either.right(destination)
);
}
}
Loading

0 comments on commit bb6d236

Please sign in to comment.