Skip to content

Commit

Permalink
fix repeated checkpoint setting + bypass teleport check for back-to-c…
Browse files Browse the repository at this point in the history
…heckpoint teleports + fix replacing checkpoints with the pressure plate (#14)

* add currentlyTeleporting field to the run manager

* update listeners
use currentlyTeleporting to ensure only players teleported by the plugin (for respawning at checkpoint) will be allowed to continue their run
refactor uuid
use more descriptive names for locations
change checkpoint store to use block locations, so comparisons can more accurately be made

* increase location mock to make tests pass

* stop adding 0.5x ?y 0.5z on teleport to warpspot. also correctly replace exisitng warps on placement of further pressure plates

instead, the conversion from block location (on pressure plate place)  to player location (on teleport) is done just for that one path

* make teleport async
  • Loading branch information
456dev authored Aug 10, 2023
1 parent 421e5a5 commit 1724823
Show file tree
Hide file tree
Showing 9 changed files with 78 additions and 71 deletions.
3 changes: 2 additions & 1 deletion src/main/java/world/bentobox/parkour/Parkour.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package world.bentobox.parkour;

import java.util.ArrayList;
import java.util.HashMap;

import org.bukkit.Material;
Expand Down Expand Up @@ -91,7 +92,7 @@ public void setup() {
adminCommand = new DefaultAdminCommand(this) {
};

parkourRunRecord = new ParkourRunRecord(new HashMap<>(), new HashMap<>());
parkourRunRecord = new ParkourRunRecord(new HashMap<>(), new HashMap<>(), new ArrayList<>());

registerFlag(PARKOUR_CREATIVE);

Expand Down
4 changes: 3 additions & 1 deletion src/main/java/world/bentobox/parkour/ParkourRunRecord.java
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
package world.bentobox.parkour;

import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.bukkit.Location;

public record ParkourRunRecord(Map<UUID, Location> checkpoints, Map<UUID, Long> timers) {
public record ParkourRunRecord(Map<UUID, Location> checkpoints, Map<UUID, Long> timers, List<UUID> currentlyTeleporting) {
/**
* Clears any current times or checkpoints
* @param uuid UUID of runner
*/
public void clear(UUID uuid) {
checkpoints.remove(uuid);
timers.remove(uuid);
currentlyTeleporting.remove(uuid);
}

}
10 changes: 5 additions & 5 deletions src/main/java/world/bentobox/parkour/commands/WarpCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@

/**
* Warps to a
* @author tastybento
*
* @author tastybento
*/
public class WarpCommand extends CompositeCommand {

Expand Down Expand Up @@ -48,7 +48,7 @@ public boolean canExecute(User user, String label, List<String> args) {
}
if (args.isEmpty()) {
Optional<Island> island = getIslands().getIslandAt(user.getLocation());
if (island.isEmpty() || !((Parkour)getAddon()).inWorld(user.getWorld())) {
if (island.isEmpty() || !((Parkour) getAddon()).inWorld(user.getWorld())) {
user.sendMessage("parkour.errors.not-on-island");
this.showHelp(this, user);
return false;
Expand Down Expand Up @@ -81,18 +81,18 @@ public boolean execute(User user, String label, List<String> args) {
// Teleport user
user.getPlayer().playSound(user.getLocation(), Sound.ENTITY_BAT_TAKEOFF, 1F, 1F);
user.getPlayer().playSound(warpSpot, Sound.ENTITY_BAT_TAKEOFF, 1F, 1F);
Util.teleportAsync(user.getPlayer(), warpSpot.clone().add(new Vector(0.5, 0.5, 0.5)), TeleportCause.COMMAND);
Util.teleportAsync(user.getPlayer(), warpSpot, TeleportCause.COMMAND);
return true;
}

@Override
public Optional<List<String>> tabComplete(User user, String alias, List<String> args) {
ArrayList<String> options = new ArrayList<>(((Parkour)getAddon()).getParkourManager().getWarps().keySet());
ArrayList<String> options = new ArrayList<>(((Parkour) getAddon()).getParkourManager().getWarps().keySet());
if (options.size() < 10) {
return Optional.of(options);
}
// List is too long; require at least the first letter
String lastArg = !args.isEmpty() ? args.get(args.size()-1) : "";
String lastArg = !args.isEmpty() ? args.get(args.size() - 1) : "";
if (args.isEmpty()) {
return Optional.empty();
}
Expand Down
29 changes: 16 additions & 13 deletions src/main/java/world/bentobox/parkour/gui/CoursesTab.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.util.Vector;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;

Expand All @@ -25,9 +24,9 @@

/**
* Implements a {@link Tab} that shows course rankings
*
* @author tastybento
* @since 1.0.0
*
*/
public class CoursesTab implements Tab {

Expand All @@ -36,8 +35,9 @@ public class CoursesTab implements Tab {

/**
* Show a tab of settings
*
* @param addon - addon
* @param user - user who is viewing the tab
* @param user - user who is viewing the tab
*/
public CoursesTab(Parkour addon, User user) {
super();
Expand All @@ -47,6 +47,7 @@ public CoursesTab(Parkour addon, User user) {

/**
* Get the icon for this tab
*
* @return panel item
*/
@Override
Expand All @@ -69,6 +70,7 @@ public String getName() {

/**
* Get all the flags as panel items
*
* @return list of all the panel items for this flag type
*/
@Override
Expand All @@ -78,20 +80,21 @@ public String getName() {
List<PanelItem> heads = new ArrayList<>();
// Sort the courses by runs
addon.getParkourManager().getParkourData().stream()
.sorted()
.filter(hs -> Objects.nonNull(hs.getWarpSpot()))
.forEach(hs -> {
UUID owner = addon.getIslands().getIslandById(hs.getUniqueId()).map(Island::getOwner).orElse(null);
if (owner != null) {
heads.add(getHead(hs, owner));
}
});
.sorted()
.filter(hs -> Objects.nonNull(hs.getWarpSpot()))
.forEach(hs -> {
UUID owner = addon.getIslands().getIslandById(hs.getUniqueId()).map(Island::getOwner).orElse(null);
if (owner != null) {
heads.add(getHead(hs, owner));
}
});
return heads;
}

/**
* Get the head panel item
* @param pd - parkour data
*
* @param pd - parkour data
* @param playerUUID - the UUID of the owner
* @return PanelItem
*/
Expand All @@ -115,7 +118,7 @@ private PanelItem getHead(ParkourData pd, UUID playerUUID) {
.clickHandler((panel, user, clickType, slot) -> {
user.sendMessage("parkour.warp.warping");
// Teleport user
Util.teleportAsync(user.getPlayer(), pd.getWarpSpot().clone().add(new Vector(0.5, 1, 0.5)), TeleportCause.COMMAND);
Util.teleportAsync(user.getPlayer(), pd.getWarpSpot(), TeleportCause.COMMAND);
return true;
})
.description(description);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;

import org.bukkit.EntityEffect;
import org.bukkit.GameMode;
Expand All @@ -28,6 +29,7 @@
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.util.Util;
import world.bentobox.parkour.Parkour;
import world.bentobox.parkour.ParkourRunRecord;

Expand Down Expand Up @@ -113,27 +115,31 @@ public void onVisitorFall(EntityDamageEvent e) {
player.playEffect(EntityEffect.ENTITY_POOF);
player.setVelocity(new Vector(0, 0, 0));
player.setFallDistance(0);
player.teleport(parkourRunManager.checkpoints().get(player.getUniqueId()));

Location checkpointLocation = parkourRunManager.checkpoints().get(player.getUniqueId());
checkpointLocation = checkpointLocation.clone().add(0.5, 0, 0.5);
parkourRunManager.currentlyTeleporting().add(player.getUniqueId());
Util.teleportAsync(player, checkpointLocation, PlayerTeleportEvent.TeleportCause.PLUGIN)
.thenAccept(b -> parkourRunManager.currentlyTeleporting().remove(player.getUniqueId()));
}

@EventHandler
public void onTeleport(PlayerTeleportEvent e) {
boolean shouldStopRun = switch (e.getCause()) {
case ENDER_PEARL, CHORUS_FRUIT, DISMOUNT, EXIT_BED -> false;
case COMMAND, PLUGIN, NETHER_PORTAL, END_PORTAL, SPECTATE, END_GATEWAY, UNKNOWN -> true;
case ENDER_PEARL, CHORUS_FRUIT, DISMOUNT, EXIT_BED -> false;
case COMMAND, PLUGIN, NETHER_PORTAL, END_PORTAL, SPECTATE, END_GATEWAY, UNKNOWN -> true;
};
if (shouldStopRun && parkourRunManager.timers().containsKey(e.getPlayer().getUniqueId())) {
User user = User.getInstance(e.getPlayer().getUniqueId());
if (parkourRunManager.checkpoints().containsKey(e.getPlayer().getUniqueId()) && user.isOnline()) {
UUID playerUUID = e.getPlayer().getUniqueId();
if (!parkourRunManager.currentlyTeleporting().contains(playerUUID) && shouldStopRun && parkourRunManager.timers().containsKey(playerUUID)) {
User user = User.getInstance(playerUUID);
if (parkourRunManager.checkpoints().containsKey(playerUUID) && user.isOnline()) {
user.notify("parkour.session-ended");
}
parkourRunManager.clear(e.getPlayer().getUniqueId());
parkourRunManager.clear(playerUUID);
}
// Check world - only apply flag actions to Parkour world and only if player is not actively running the course
if (e.getTo() == null // To can sometimes be null...
|| !addon.inWorld(e.getTo())
|| parkourRunManager.timers().containsKey(e.getPlayer().getUniqueId())) {
|| parkourRunManager.timers().containsKey(playerUUID)) {
return;
}
// Handle flag action for players who are not running
Expand Down Expand Up @@ -205,44 +211,44 @@ public void onStartEndSet(PlayerInteractEvent e) {
return;
}

Location l = e.getClickedBlock().getLocation();
Location blockLocation = e.getClickedBlock().getLocation();
User user = User.getInstance(e.getPlayer());
addon.getIslands().getProtectedIslandAt(l).ifPresent(island -> {
addon.getIslands().getProtectedIslandAt(blockLocation).ifPresent(island -> {
Optional<Location> start = addon.getParkourManager().getStart(island);
Optional<Location> end = addon.getParkourManager().getEnd(island);

// Check if start and end is set
if (start.filter(startLoc -> isLocEquals(l, startLoc)).isPresent()) {
if (start.filter(startLoc -> isLocEquals(blockLocation, startLoc)).isPresent()) {
// End is not set
if (end.isEmpty()) {
user.sendMessage("parkour.set-the-end");
return;
}
// Start the race!
if (!parkourRunManager.timers().containsKey(e.getPlayer().getUniqueId())) {
parkourStart(user, l);
parkourStart(user, blockLocation);
}
} else if (end.filter(endLoc -> isLocEquals(l, endLoc)).isPresent()
} else if (end.filter(endLoc -> isLocEquals(blockLocation, endLoc)).isPresent()
&& parkourRunManager.timers().containsKey(e.getPlayer().getUniqueId())) {
// End the race!
parkourEnd(user, island, l);
parkourEnd(user, island, blockLocation);
}
});
}

void parkourStart(User user, Location l) {
void parkourStart(User user, Location blockLocation) {
user.sendMessage("parkour.start");
user.getPlayer().playSound(l, Sound.ENTITY_FIREWORK_ROCKET_LAUNCH, 1F, 1F);
user.getPlayer().playSound(blockLocation, Sound.ENTITY_FIREWORK_ROCKET_LAUNCH, 1F, 1F);
parkourRunManager.timers().put(user.getUniqueId(), System.currentTimeMillis());
parkourRunManager.checkpoints().put(user.getUniqueId(), user.getLocation());
parkourRunManager.checkpoints().put(user.getUniqueId(), blockLocation);
user.setGameMode(GameMode.SURVIVAL);

}

void parkourEnd(User user, Island island, Location l) {
void parkourEnd(User user, Island island, Location blockLocation) {
long duration = (System.currentTimeMillis() - Objects.requireNonNull(parkourRunManager.timers().get(user.getUniqueId())));
user.notify("parkour.end");
user.getPlayer().playSound(l, Sound.ENTITY_FIREWORK_ROCKET_LAUNCH, 1F, 1F);
user.getPlayer().playSound(blockLocation, Sound.ENTITY_FIREWORK_ROCKET_LAUNCH, 1F, 1F);
user.notify("parkour.you-took", TextVariables.NUMBER, getDuration(user, duration));
parkourRunManager.clear(user.getUniqueId());

Expand Down Expand Up @@ -279,14 +285,18 @@ public void onCheckpoint(PlayerInteractEvent e) {
|| !parkourRunManager.timers().containsKey(e.getPlayer().getUniqueId())) {
return;
}
Location l = e.getClickedBlock().getLocation();
User user = User.getInstance(e.getPlayer());
Vector checkPoint = parkourRunManager.checkpoints().get(e.getPlayer().getUniqueId()).toVector();

if (addon.getIslands().getProtectedIslandAt(l).isPresent() && !l.toVector().equals(checkPoint)) {
user.notify("parkour.checkpoint");
e.getPlayer().playSound(l, Sound.BLOCK_BELL_USE, 1F, 1F);
parkourRunManager.checkpoints().put(user.getUniqueId(), e.getPlayer().getLocation());
Location newCheckpointBlockLocation = e.getClickedBlock().getLocation();
if (addon.getIslands().getProtectedIslandAt(newCheckpointBlockLocation).isPresent()) {
// pressure plate should be a checkpoint
Location currentCheckpointBlockLocation = parkourRunManager.checkpoints().get(e.getPlayer().getUniqueId());
if (!isLocEquals(newCheckpointBlockLocation, currentCheckpointBlockLocation)) {
// new location is different
User user = User.getInstance(e.getPlayer());
user.sendMessage("parkour.checkpoint");
e.getPlayer().playSound(newCheckpointBlockLocation, Sound.BLOCK_BELL_USE, 1F, 1F);
parkourRunManager.checkpoints().put(user.getUniqueId(), newCheckpointBlockLocation);
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,11 @@ public void onWarpSet(BlockPlaceEvent e) {
Optional<Location> warpSpot = addon.getParkourManager().getWarpSpot(island);
if (warpSpot.isEmpty()) {
user.notify("parkour.warp.set");
addon.getParkourManager().setWarpSpot(island, l);
} else {
user.notify("parkour.warp.replaced");
}
// shift from block to player location
addon.getParkourManager().setWarpSpot(island, l.add(0.5,0,0.5));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;
Expand Down Expand Up @@ -109,7 +110,7 @@ public void setUp() throws Exception {
when(ac.getWorld()).thenReturn(world);
when(ac.getAddon()).thenReturn(addon);

prm = new ParkourRunRecord(new HashMap<>(), new HashMap<>());
prm = new ParkourRunRecord(new HashMap<>(), new HashMap<>(), new ArrayList<>());
prm.timers().put(uuid, 20L);
when(addon.getParkourRunRecord()).thenReturn(prm);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,6 @@ public void setUp() throws Exception {

// Location
when(location.clone()).thenReturn(location);
when(location.add(any(Vector.class))).thenReturn(location);

// Settings
Settings settings = new Settings();
Expand Down Expand Up @@ -267,7 +266,6 @@ public void testExecuteUserStringListOfString() {
verify(user).sendMessage("parkour.warp.warping");
// Teleport user
verify(p, times(2)).playSound(location, Sound.ENTITY_BAT_TAKEOFF, 1F, 1F);
verify(location).add(any(Vector.class));
PowerMockito.verifyStatic(Util.class);
Util.teleportAsync(p, location, TeleportCause.COMMAND);

Expand Down
Loading

0 comments on commit 1724823

Please sign in to comment.