IAsyncTeleport#teleport not properly implemented to handle passed CompletableFuture instances for players without the bypass permission.
qruet opened this issue ยท 1 comments
Type of bug
Other unexpected behaviour
/ess version
output
2.18.2.0
Server startup log
https://paste.gg/p/anonymous/6f60d0e22fb7422597adc58b4c56fbc7
EssentialsX config files
https://paste.gg/p/anonymous/fed6c8e0005d42209343b677e73d4a6f
Error log (if applicable)
No response
Bug description
I am a plugin developer who has hooked into the Essential's API to call teleportation functions so that my plugin may integrate with the already existing teleportation cooldown system. The following code snippet:
CompletableFuture<Boolean> future = new CompletableFuture<>();
future.exceptionally((e) -> {
LanguageIO.processMessage("Generics.Error.Critical Server Error", player, msg -> msg = msg.replaceAll("%error%", "VisitCmd Essentials Teleport"));
e.printStackTrace();
return false;
});
future.thenAccept((e) -> {
island.addVisitor(player);
});
((IAsyncTeleport) teleport).teleport(to, null, PlayerTeleportEvent.TeleportCause.COMMAND, future);
If a player does not have the permission essentials.teleport.timer.bypass
then the passed CompletableFuture#thenAccept is never called. Digging into the teleport function, there is no implementation of a loop, therefore unless the teleportation is instantaneous the passed instance is lost.
Steps to reproduce
- Debug:
CompletableFuture<Boolean> future = new CompletableFuture<>();
future.thenAccept((e) -> {
Bukkit.broadcastMessage("#thenAccept");
});
((IAsyncTeleport) teleport).teleport(to, null, PlayerTeleportEvent.TeleportCause.COMMAND, future);
- Remove the
essentials.teleport.timer.bypass
permission from a player - Have them teleport somewhere with a cooldown
- The debug statement will never been called.
- Add the
essentials.teleport.timer.bypass
permission to a player - They will bypass the cooldown and the debug statement is called on teleport.
Expected behaviour
CompletableFuture#thenAccept should be called after a player has teleported regardless of the cooldown.
Actual behaviour
CompletableFuture#thenAccept does not work if the teleportation is not instantaneous.
A quick and dirty fix was to simply implement a BukkitRunnable loop that iterated once every tick and called on the AsyncTeleport#cooldown function until it returned true. Once the function returns true, CompletableFuture#complete is called.
Confirmed on:
[00:13:43 INFO]: Server version: 1.16.5-R0.1-SNAPSHOT git-Paper-542 (MC: 1.16.5)
[00:13:43 INFO]: EssentialsX version: 2.19.0-dev+96-1cf2b11
Minimal reproduction steps:
- Set
teleport-delay
in the config to something larger than 0. - Make sure player doesn't have the
essentials.teleport.timer.bypass
permission. - Call AsyncTeleport#teleport for player and observe that the passed future is never completed.