Fix delayed futures never being completed correctly (#4066)

This PR fixes issues related to timed teleports. All timed teleports before this PR would create their own future to send back to the AsyncTeleport api causing the futures returned in the base methods never being completed.

This PR pases the future returned in AsyncTeleport methods to the timed teleport and completes it after the timed teleport has been completed.

Fixes #4065.
This commit is contained in:
Josh Roy 2021-03-20 11:48:40 -04:00 committed by GitHub
parent bfeb0ef2ad
commit 454698bf98
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 28 additions and 13 deletions

View File

@ -299,7 +299,7 @@ public class AsyncTeleport implements IAsyncTeleport {
cancel(false);
warnUser(teleportee, delay);
initTimer((long) (delay * 1000.0), teleportee, target, cashCharge, cause, false);
initTimer((long) (delay * 1000.0), teleportee, target, cashCharge, cause, false, future);
}
private void teleportOther(final IUser teleporter, final IUser teleportee, final ITarget target, final Trade chargeFor, final TeleportCause cause, final CompletableFuture<Boolean> future) {
@ -345,12 +345,13 @@ public class AsyncTeleport implements IAsyncTeleport {
return;
}
}
future.complete(true);
return;
}
cancel(false);
warnUser(teleportee, delay);
initTimer((long) (delay * 1000.0), teleportee, target, cashCharge, cause, false);
initTimer((long) (delay * 1000.0), teleportee, target, cashCharge, cause, false, future);
}
@Override
@ -381,12 +382,13 @@ public class AsyncTeleport implements IAsyncTeleport {
if (chargeFor != null) {
chargeFor.charge(teleportOwner, future);
}
future.complete(true);
return;
}
cancel(false);
warnUser(teleportOwner, delay);
initTimer((long) (delay * 1000.0), teleportOwner, null, chargeFor, cause, true);
initTimer((long) (delay * 1000.0), teleportOwner, null, chargeFor, cause, true, future);
}
void respawnNow(final IUser teleportee, final TeleportCause cause, final CompletableFuture<Boolean> future) {
@ -466,8 +468,8 @@ public class AsyncTeleport implements IAsyncTeleport {
}
}
private void initTimer(final long delay, final IUser teleportUser, final ITarget target, final Trade chargeFor, final TeleportCause cause, final boolean respawn) {
timedTeleport = new AsyncTimedTeleport(teleportOwner, ess, this, delay, teleportUser, target, chargeFor, cause, respawn);
private void initTimer(final long delay, final IUser teleportUser, final ITarget target, final Trade chargeFor, final TeleportCause cause, final boolean respawn, CompletableFuture<Boolean> future) {
timedTeleport = new AsyncTimedTeleport(teleportOwner, ess, this, delay, future, teleportUser, target, chargeFor, cause, respawn);
}
public enum TeleportType {

View File

@ -18,6 +18,7 @@ public class AsyncTimedTeleport implements Runnable {
private final UUID timer_teleportee;
private final long timer_started; // time this task was initiated
private final long timer_delay; // how long to delay the teleportPlayer
private final CompletableFuture<Boolean> parentFuture;
// note that I initially stored a clone of the location for reference, but...
// when comparing locations, I got incorrect mismatches (rounding errors, looked like)
// so, the X/Y/Z values are stored instead and rounded off
@ -33,6 +34,10 @@ public class AsyncTimedTeleport implements Runnable {
private double timer_health;
AsyncTimedTeleport(final IUser user, final IEssentials ess, final AsyncTeleport teleport, final long delay, final IUser teleportUser, final ITarget target, final Trade chargeFor, final TeleportCause cause, final boolean respawn) {
this(user, ess, teleport, delay, null, teleportUser, target, chargeFor, cause, respawn);
}
AsyncTimedTeleport(final IUser user, final IEssentials ess, final AsyncTeleport teleport, final long delay, final CompletableFuture<Boolean> future, final IUser teleportUser, final ITarget target, final Trade chargeFor, final TeleportCause cause, final boolean respawn) {
this.teleportOwner = user;
this.ess = ess;
this.teleport = teleport;
@ -50,6 +55,18 @@ public class AsyncTimedTeleport implements Runnable {
this.timer_canMove = user.isAuthorized("essentials.teleport.timer.move");
timer_task = ess.runTaskTimerAsynchronously(this, 20, 20).getTaskId();
if (future != null) {
this.parentFuture = future;
return;
}
final CompletableFuture<Boolean> cFuture = new CompletableFuture<>();
cFuture.exceptionally(e -> {
ess.showError(teleportOwner.getSource(), e, "\\ teleport");
return false;
});
this.parentFuture = cFuture;
}
@Override
@ -98,20 +115,16 @@ public class AsyncTimedTeleport implements Runnable {
cancelTimer(false);
teleportUser.sendMessage(tl("teleportationCommencing"));
final CompletableFuture<Boolean> future = new CompletableFuture<>();
future.exceptionally(e -> {
ess.showError(teleportOwner.getSource(), e, "\\ teleport");
return false;
});
if (timer_chargeFor != null) {
timer_chargeFor.isAffordableFor(teleportOwner);
}
if (timer_respawn) {
teleport.respawnNow(teleportUser, timer_cause, future);
teleport.respawnNow(teleportUser, timer_cause, parentFuture);
} else {
teleport.nowAsync(teleportUser, timer_teleportTarget, timer_cause, future);
teleport.nowAsync(teleportUser, timer_teleportTarget, timer_cause, parentFuture);
}
future.thenAccept(success -> {
parentFuture.thenAccept(success -> {
if (timer_chargeFor != null) {
try {
timer_chargeFor.charge(teleportOwner);