Fixes various smaller issues

Fixes players immediately being thrown out because the spawn teleportation triggered the PlayerLeaveListener
Reduces default velocity from the insane terminal velocity to just 1
Uses UUID instead of player object when storing dropper arena sessions
Prevents players from joining an arena if in creative, spectator mode, or is flying
Implements the leave command to allow leaving the arena
Only counts fall damage as a loss, but still prevents all damage in the arena
Prevents players from dying of fall damage when exiting the dropper arena
Prevents loadArenas from returning null
This commit is contained in:
Kristian Knarvik 2023-03-24 13:15:56 +01:00
parent b840a3f500
commit eb67705300
9 changed files with 82 additions and 34 deletions

View File

@ -1,46 +1,46 @@
package net.knarcraft.dropper.arena;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* A registry to keep track of which players are playing in which arenas
*/
public class DropperArenaPlayerRegistry {
private final Map<Player, DropperArenaSession> arenaPlayers = new HashMap<>();
private final Map<UUID, DropperArenaSession> arenaPlayers = new HashMap<>();
/**
* Registers that the given player has started playing the given dropper arena session
*
* @param player <p>The player that started playing</p>
* @param arena <p>The arena session to register</p>
* @param playerId <p>The id of the player that started playing</p>
* @param arena <p>The arena session to register</p>
*/
public void registerPlayer(@NotNull Player player, @NotNull DropperArenaSession arena) {
this.arenaPlayers.put(player, arena);
public void registerPlayer(@NotNull UUID playerId, @NotNull DropperArenaSession arena) {
this.arenaPlayers.put(playerId, arena);
}
/**
* Removes this player from players currently playing
*
* @param player <p>The player to remove</p>
* @param playerId <p>The id of the player to remove</p>
*/
public boolean removePlayer(@NotNull Player player) {
return this.arenaPlayers.remove(player) != null;
public boolean removePlayer(@NotNull UUID playerId) {
return this.arenaPlayers.remove(playerId) != null;
}
/**
* Gets the player's active dropper arena session
*
* @param player <p>The player to get arena for</p>
* @param playerId <p>The id of the player to get arena for</p>
* @return <p>The player's active arena session, or null if not currently playing</p>
*/
public @Nullable DropperArenaSession getArenaSession(@NotNull Player player) {
return this.arenaPlayers.getOrDefault(player, null);
public @Nullable DropperArenaSession getArenaSession(@NotNull UUID playerId) {
return this.arenaPlayers.getOrDefault(playerId, null);
}
}

View File

@ -65,6 +65,8 @@ public class DropperArenaSession {
}
}
player.sendMessage("You won!");
// Teleport the player out of the arena
teleportToExit();
}
@ -88,7 +90,7 @@ public class DropperArenaSession {
*/
private void removeSession() {
// Remove this session for game sessions to stop listeners from fiddling more with the player
boolean removedSession = Dropper.getInstance().getPlayerRegistry().removePlayer(player);
boolean removedSession = Dropper.getInstance().getPlayerRegistry().removePlayer(player.getUniqueId());
if (!removedSession) {
Dropper.getInstance().getLogger().log(Level.SEVERE, "Unable to remove dropper arena session for " +
player.getName() + ". This will have unintended consequences.");
@ -134,6 +136,8 @@ public class DropperArenaSession {
player.setAllowFlight(false);
// Teleport the player out of the arena
teleportToExit();
player.sendMessage("You quit the arena!");
}
/**

View File

@ -7,6 +7,7 @@ import net.knarcraft.dropper.arena.DropperArenaSession;
import net.knarcraft.dropper.property.ArenaGameMode;
import net.knarcraft.dropper.util.ArenaStorageHelper;
import net.knarcraft.dropper.util.PlayerTeleporter;
import org.bukkit.GameMode;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
@ -30,8 +31,14 @@ public class JoinArenaCommand implements CommandExecutor {
return false;
}
if (player.isFlying() || player.getGameMode() == GameMode.CREATIVE ||
player.getGameMode() == GameMode.SPECTATOR) {
commandSender.sendMessage("You cannot join a dropper arena while able to fly!");
return false;
}
// Disallow joining if the player is already in a dropper arena
DropperArenaSession existingSession = Dropper.getInstance().getPlayerRegistry().getArenaSession(player);
DropperArenaSession existingSession = Dropper.getInstance().getPlayerRegistry().getArenaSession(player.getUniqueId());
if (existingSession != null) {
commandSender.sendMessage("You are already in a dropper arena!");
return false;
@ -64,7 +71,7 @@ public class JoinArenaCommand implements CommandExecutor {
// Register the player's session
DropperArenaSession newSession = new DropperArenaSession(specifiedArena, player, gameMode);
DropperArenaPlayerRegistry playerRegistry = Dropper.getInstance().getPlayerRegistry();
playerRegistry.registerPlayer(player, newSession);
playerRegistry.registerPlayer(player.getUniqueId(), newSession);
// Try to teleport the player to the arena
boolean teleported = PlayerTeleporter.teleportPlayer(player, specifiedArena.getSpawnLocation(), false);

View File

@ -1,8 +1,11 @@
package net.knarcraft.dropper.command;
import net.knarcraft.dropper.Dropper;
import net.knarcraft.dropper.arena.DropperArenaSession;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
/**
@ -13,10 +16,19 @@ public class LeaveArenaCommand implements CommandExecutor {
@Override
public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
@NotNull String[] strings) {
//TODO: Make sure the console cannot run this
//TODO: If the player isn't currently in an arena, just display an error message
//TODO: Trigger the player's session's triggerQuit() method
return false;
if (!(commandSender instanceof Player player)) {
commandSender.sendMessage("This command must be used by a player");
return false;
}
DropperArenaSession existingSession = Dropper.getInstance().getPlayerRegistry().getArenaSession(player.getUniqueId());
if (existingSession == null) {
commandSender.sendMessage("You are not in a dropper arena!");
return false;
}
existingSession.triggerQuit();
return true;
}
}

View File

@ -23,14 +23,17 @@ public class DamageListener implements Listener {
Player player = (Player) event.getEntity();
// We don't care about damage outside arenas
DropperArenaSession arenaSession = Dropper.getInstance().getPlayerRegistry().getArenaSession(player);
DropperArenaSession arenaSession = Dropper.getInstance().getPlayerRegistry().getArenaSession(player.getUniqueId());
if (arenaSession == null) {
return;
}
event.setCancelled(true);
arenaSession.triggerLoss();
// Only trigger a loss when a player suffers fall damage
if (event.getCause() == EntityDamageEvent.DamageCause.FALL) {
arenaSession.triggerLoss();
}
}
}

View File

@ -17,16 +17,11 @@ import org.bukkit.util.Vector;
*/
public class MoveListener implements Listener {
/**
* The terminal velocity of a falling player, as defined by the WIKI
*/
private static final double TERMINAL_VELOCITY = 78.4;
@EventHandler
public void onPlayerMove(PlayerMoveEvent event) {
Player player = event.getPlayer();
DropperArenaPlayerRegistry playerRegistry = Dropper.getInstance().getPlayerRegistry();
DropperArenaSession arenaSession = playerRegistry.getArenaSession(player);
DropperArenaSession arenaSession = playerRegistry.getArenaSession(player.getUniqueId());
if (arenaSession == null) {
return;
}
@ -63,8 +58,7 @@ public class MoveListener implements Listener {
Player player = session.getPlayer();
Vector playerVelocity = player.getVelocity();
double arenaVelocity = session.getArena().getPlayerVelocity();
double yVelocity = TERMINAL_VELOCITY * arenaVelocity;
Vector newVelocity = new Vector(playerVelocity.getX(), yVelocity, playerVelocity.getZ());
Vector newVelocity = new Vector(playerVelocity.getX(), -arenaVelocity, playerVelocity.getZ());
player.setVelocity(newVelocity);
}

View File

@ -7,6 +7,8 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* A listener for players leaving the server or the arena
@ -20,6 +22,15 @@ public class PlayerLeaveListener implements Listener {
@EventHandler
public void onPlayerTeleport(PlayerTeleportEvent event) {
DropperArenaSession arenaSession = getSession(event.getPlayer());
if (arenaSession == null) {
return;
}
if (event.getTo().equals(arenaSession.getArena().getSpawnLocation())) {
return;
}
triggerQuit(event.getPlayer());
}
@ -29,15 +40,25 @@ public class PlayerLeaveListener implements Listener {
* @param player <p>The player to trigger a quit for</p>
*/
private void triggerQuit(Player player) {
DropperArenaSession arenaSession = Dropper.getInstance().getPlayerRegistry().getArenaSession(player);
DropperArenaSession arenaSession = getSession(player);
if (arenaSession == null) {
return;
}
arenaSession.triggerQuit();
//TODO: It might not be possible to alter the player's location here. It might be necessary to move them once
//TODO: It might not be possible to alter a leaving player's location here. It might be necessary to move them once
// they join again
}
/**
* Gets the arena session for the given player
*
* @param player <p>The player to get the arena session for</p>
* @return <p>The player's session, or null if not in a session</p>
*/
private @Nullable DropperArenaSession getSession(@NotNull Player player) {
return Dropper.getInstance().getPlayerRegistry().getArenaSession(player.getUniqueId());
}
}

View File

@ -58,12 +58,12 @@ public final class ArenaStorageHelper {
* @param arenaFile <p>The file used to store the arenas</p>
* @return <p>The loaded arenas, or null if the arenas configuration section is missing.</p>
*/
public static @Nullable List<DropperArena> loadArenas(@NotNull File arenaFile) {
public static @NotNull List<DropperArena> loadArenas(@NotNull File arenaFile) {
YamlConfiguration configuration = YamlConfiguration.loadConfiguration(arenaFile);
ConfigurationSection arenaSection = configuration.getConfigurationSection(arenasConfigurationSection);
//If no such section exists, it must be the case that there is no data to load
if (arenaSection == null) {
return null;
return new ArrayList<>();
}
List<DropperArena> loadedArenas = new ArrayList<>();

View File

@ -1,5 +1,7 @@
package net.knarcraft.dropper.util;
import net.knarcraft.dropper.Dropper;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
@ -46,9 +48,14 @@ public final class PlayerTeleporter {
return false;
}
}
//Stop the player velocity to prevent unevenness between players
//Stop the existing player velocity to prevent unevenness between players
player.setVelocity(new Vector(0, 0, 0));
player.setInvulnerable(true);
player.teleport(location);
player.setVelocity(new Vector(0, 0, 0));
//When teleporting a player out of the arena, sometimes the move listener is slow to react, giving the player
// lethal velocity, and causing damage. That's why the player is given 5 ticks of invulnerability
Bukkit.getScheduler().runTaskLater(Dropper.getInstance(), () -> player.setInvulnerable(false), 5);
return true;
}