Finishes the changes for parkour arenas, hopefully

This commit is contained in:
Kristian Knarvik 2023-04-15 18:29:58 +02:00
parent 12789980c0
commit 904761ba4e
44 changed files with 1413 additions and 292 deletions

View File

@ -1,5 +1,6 @@
package net.knarcraft.minigames;
import net.knarcraft.minigames.arena.ArenaSession;
import net.knarcraft.minigames.arena.dropper.DropperArenaData;
import net.knarcraft.minigames.arena.dropper.DropperArenaGameMode;
import net.knarcraft.minigames.arena.dropper.DropperArenaGroup;
@ -7,23 +8,38 @@ import net.knarcraft.minigames.arena.dropper.DropperArenaHandler;
import net.knarcraft.minigames.arena.dropper.DropperArenaPlayerRegistry;
import net.knarcraft.minigames.arena.dropper.DropperArenaRecordsRegistry;
import net.knarcraft.minigames.arena.dropper.DropperArenaSession;
import net.knarcraft.minigames.arena.parkour.ParkourArenaData;
import net.knarcraft.minigames.arena.parkour.ParkourArenaGameMode;
import net.knarcraft.minigames.arena.parkour.ParkourArenaGroup;
import net.knarcraft.minigames.arena.parkour.ParkourArenaHandler;
import net.knarcraft.minigames.arena.parkour.ParkourArenaPlayerRegistry;
import net.knarcraft.minigames.arena.parkour.ParkourArenaRecordsRegistry;
import net.knarcraft.minigames.arena.record.IntegerRecord;
import net.knarcraft.minigames.arena.record.LongRecord;
import net.knarcraft.minigames.command.CreateArenaCommand;
import net.knarcraft.minigames.command.EditArenaCommand;
import net.knarcraft.minigames.command.EditArenaTabCompleter;
import net.knarcraft.minigames.command.GroupListCommand;
import net.knarcraft.minigames.command.GroupSetCommand;
import net.knarcraft.minigames.command.GroupSwapCommand;
import net.knarcraft.minigames.command.JoinArenaCommand;
import net.knarcraft.minigames.command.JoinArenaTabCompleter;
import net.knarcraft.minigames.command.LeaveArenaCommand;
import net.knarcraft.minigames.command.ListArenaCommand;
import net.knarcraft.minigames.command.ReloadCommand;
import net.knarcraft.minigames.command.RemoveArenaCommand;
import net.knarcraft.minigames.command.RemoveArenaTabCompleter;
import net.knarcraft.minigames.command.dropper.CreateDropperArenaCommand;
import net.knarcraft.minigames.command.dropper.DropperGroupListCommand;
import net.knarcraft.minigames.command.dropper.DropperGroupSetCommand;
import net.knarcraft.minigames.command.dropper.DropperGroupSwapCommand;
import net.knarcraft.minigames.command.dropper.EditDropperArenaCommand;
import net.knarcraft.minigames.command.dropper.EditDropperArenaTabCompleter;
import net.knarcraft.minigames.command.dropper.JoinDropperArenaCommand;
import net.knarcraft.minigames.command.dropper.JoinDropperArenaTabCompleter;
import net.knarcraft.minigames.command.dropper.ListDropperArenaCommand;
import net.knarcraft.minigames.command.dropper.RemoveDropperArenaCommand;
import net.knarcraft.minigames.command.dropper.RemoveDropperArenaTabCompleter;
import net.knarcraft.minigames.command.parkour.CreateParkourArenaCommand;
import net.knarcraft.minigames.command.parkour.EditParkourArenaCommand;
import net.knarcraft.minigames.command.parkour.EditParkourArenaTabCompleter;
import net.knarcraft.minigames.command.parkour.JoinParkourArenaCommand;
import net.knarcraft.minigames.command.parkour.JoinParkourArenaTabCompleter;
import net.knarcraft.minigames.command.parkour.ListParkourArenaCommand;
import net.knarcraft.minigames.command.parkour.ParkourGroupListCommand;
import net.knarcraft.minigames.command.parkour.ParkourGroupSetCommand;
import net.knarcraft.minigames.command.parkour.ParkourGroupSwapCommand;
import net.knarcraft.minigames.command.parkour.RemoveParkourArenaCommand;
import net.knarcraft.minigames.command.parkour.RemoveParkourArenaTabCompleter;
import net.knarcraft.minigames.config.DropperConfiguration;
import net.knarcraft.minigames.config.ParkourConfiguration;
import net.knarcraft.minigames.config.SharedConfiguration;
@ -45,6 +61,7 @@ import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.UUID;
import java.util.logging.Level;
/**
@ -137,6 +154,21 @@ public final class MiniGames extends JavaPlugin {
return this.parkourConfiguration;
}
/**
* Gets the current session of the given player
*
* @param playerId <p>The id of the player to get a session for</p>
* @return <p>The player's current session, or null if not found</p>
*/
public @Nullable ArenaSession getSession(@NotNull UUID playerId) {
DropperArenaSession dropperArenaSession = dropperArenaPlayerRegistry.getArenaSession(playerId);
if (dropperArenaSession != null) {
return dropperArenaSession;
}
return parkourArenaPlayerRegistry.getArenaSession(playerId);
}
/**
* Logs a message
*
@ -177,6 +209,10 @@ public final class MiniGames extends JavaPlugin {
ConfigurationSerialization.registerClass(DropperArenaGameMode.class);
ConfigurationSerialization.registerClass(LongRecord.class);
ConfigurationSerialization.registerClass(IntegerRecord.class);
ConfigurationSerialization.registerClass(ParkourArenaRecordsRegistry.class);
ConfigurationSerialization.registerClass(ParkourArenaData.class);
ConfigurationSerialization.registerClass(ParkourArenaGroup.class);
ConfigurationSerialization.registerClass(ParkourArenaGameMode.class);
}
@Override
@ -203,16 +239,26 @@ public final class MiniGames extends JavaPlugin {
pluginManager.registerEvents(new PlayerLeaveListener(), this);
pluginManager.registerEvents(new CommandListener(), this);
registerCommand("dropperReload", new ReloadCommand(), null);
registerCommand("dropperCreate", new CreateArenaCommand(), null);
registerCommand("dropperList", new ListArenaCommand(), null);
registerCommand("dropperJoin", new JoinArenaCommand(), new JoinArenaTabCompleter());
registerCommand("dropperLeave", new LeaveArenaCommand(), null);
registerCommand("dropperEdit", new EditArenaCommand(this.dropperConfiguration), new EditArenaTabCompleter());
registerCommand("dropperRemove", new RemoveArenaCommand(), new RemoveArenaTabCompleter());
registerCommand("dropperGroupSet", new GroupSetCommand(), null);
registerCommand("dropperGroupSwap", new GroupSwapCommand(), null);
registerCommand("dropperGroupList", new GroupListCommand(), null);
registerCommand("miniGamesReload", new ReloadCommand(), null);
registerCommand("miniGamesLeave", new LeaveArenaCommand(), null);
registerCommand("dropperCreate", new CreateDropperArenaCommand(), null);
registerCommand("dropperList", new ListDropperArenaCommand(), null);
registerCommand("dropperJoin", new JoinDropperArenaCommand(), new JoinDropperArenaTabCompleter());
registerCommand("dropperEdit", new EditDropperArenaCommand(this.dropperConfiguration), new EditDropperArenaTabCompleter());
registerCommand("dropperRemove", new RemoveDropperArenaCommand(), new RemoveDropperArenaTabCompleter());
registerCommand("dropperGroupSet", new DropperGroupSetCommand(), null);
registerCommand("dropperGroupSwap", new DropperGroupSwapCommand(), null);
registerCommand("dropperGroupList", new DropperGroupListCommand(), null);
registerCommand("parkourCreate", new CreateParkourArenaCommand(), null);
registerCommand("parkourList", new ListParkourArenaCommand(), null);
registerCommand("parkourJoin", new JoinParkourArenaCommand(), new JoinParkourArenaTabCompleter());
registerCommand("parkourEdit", new EditParkourArenaCommand(), new EditParkourArenaTabCompleter());
registerCommand("parkourRemove", new RemoveParkourArenaCommand(), new RemoveParkourArenaTabCompleter());
registerCommand("parkourGroupSet", new ParkourGroupSetCommand(), null);
registerCommand("parkourGroupSwap", new ParkourGroupSwapCommand(), null);
registerCommand("parkourGroupList", new ParkourGroupListCommand(), null);
if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) {
this.dropperRecordExpansion = new DropperRecordExpansion(this);

View File

@ -0,0 +1,69 @@
package net.knarcraft.minigames.arena;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
/**
* An abstract representation of a player's entry state
*/
public abstract class AbstractPlayerEntryState implements PlayerEntryState {
protected final Player player;
private final boolean makePlayerInvisible;
private final Location entryLocation;
private final boolean originalIsFlying;
private final GameMode originalGameMode;
private final boolean originalAllowFlight;
private final boolean originalInvulnerable;
private final boolean originalIsSwimming;
private final boolean originalCollideAble;
/**
* Instantiates a new abstract player entry state
*
* @param player <p>The player whose state this should keep track of</p>
* @param makePlayerInvisible <p>Whether players should be made invisible while in the arena</p>
*/
public AbstractPlayerEntryState(@NotNull Player player, boolean makePlayerInvisible) {
this.player = player;
this.makePlayerInvisible = makePlayerInvisible;
this.entryLocation = player.getLocation().clone();
this.originalIsFlying = player.isFlying();
this.originalGameMode = player.getGameMode();
this.originalAllowFlight = player.getAllowFlight();
this.originalInvulnerable = player.isInvulnerable();
this.originalIsSwimming = player.isSwimming();
this.originalCollideAble = player.isCollidable();
}
@Override
public void setArenaState() {
if (this.makePlayerInvisible) {
this.player.addPotionEffect(new PotionEffect(PotionEffectType.INVISIBILITY,
PotionEffect.INFINITE_DURATION, 3));
}
}
@Override
public void restore() {
this.player.setFlying(this.originalIsFlying);
this.player.setGameMode(this.originalGameMode);
this.player.setAllowFlight(this.originalAllowFlight);
this.player.setInvulnerable(this.originalInvulnerable);
this.player.setSwimming(this.originalIsSwimming);
this.player.setCollidable(this.originalCollideAble);
if (this.makePlayerInvisible) {
this.player.removePotionEffect(PotionEffectType.INVISIBILITY);
}
}
@Override
public Location getEntryLocation() {
return this.entryLocation;
}
}

View File

@ -1,5 +1,7 @@
package net.knarcraft.minigames.arena;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.jetbrains.annotations.NotNull;
import java.util.UUID;
@ -9,12 +11,19 @@ import java.util.UUID;
*/
public interface Arena {
/**
* Gets the name of this arena
*
* @return <p>The name of this arena</p>
*/
@NotNull String getArenaName();
/**
* Gets the data stored for this arena
*
* @return <p>The stored data</p>
*/
ArenaData getData();
@NotNull ArenaData getData();
/**
* Gets the id of this arena
@ -44,4 +53,34 @@ public interface Arena {
*/
boolean saveData();
/**
* Gets whether standing on the given block should cause a win
*
* @param block <p>The block to check</p>
* @return <p>True if standing on the block will cause a win</p>
*/
boolean willCauseWin(Block block);
/**
* Gets whether standing on the given block should cause a loss
*
* @param block <p>The block to check</p>
* @return <p>True if standing on the block will cause a loss</p>
*/
boolean willCauseLoss(Block block);
/**
* Gets whether the win location is a solid block
*
* @return <p>True if the location is a solid block</p>
*/
boolean winLocationIsSolid();
/**
* Gets the location of this arena's spawn
*
* @return <p>This arena's spawn location</p>
*/
@NotNull Location getSpawnLocation();
}

View File

@ -1,8 +1,24 @@
package net.knarcraft.minigames.arena;
import org.jetbrains.annotations.NotNull;
/**
* An interface describing any arena game-mode
*/
public interface ArenaGameMode {
/**
* Gets the name of this game-mode
*
* @return <p>The name of this game-mode</p>
*/
@NotNull String name();
/**
* Gets a set of all available arena game-modes in the type definition of this game-mode
*
* @return <p>All game-modes in this game-mode's class</p>
*/
@NotNull ArenaGameMode[] getValues();
}

View File

@ -14,6 +14,12 @@ import java.util.Map;
import java.util.UUID;
import java.util.logging.Level;
/**
* A group containing a list of arenas
*
* @param <K> <p>The type of arena stored</p>
* @param <S> <p>The type of arena group stored in the given arena handler</p>
*/
public abstract class ArenaGroup<K extends Arena, S extends ArenaGroup<K, S>> implements ConfigurationSerializable {
/**

View File

@ -0,0 +1,56 @@
package net.knarcraft.minigames.arena;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
/**
* A player's session while in an arena
*/
public interface ArenaSession {
/**
* Gets the game-mode the player is playing in this session
*
* @return <p>The game-mode for this session</p>
*/
@NotNull ArenaGameMode getGameMode();
/**
* Gets the state of the player when they joined the session
*
* @return <p>The player's entry state</p>
*/
@NotNull PlayerEntryState getEntryState();
/**
* Triggers a win for the player playing in this session
*/
void triggerWin();
/**
* Triggers a loss for the player playing in this session
*/
void triggerLoss();
/**
* Triggers a quit for the player playing in this session
*
* @param immediately <p>Whether to to the teleportation immediately, not using any timers</p>
*/
void triggerQuit(boolean immediately);
/**
* Gets the arena this session is being played in
*
* @return <p>The session's arena</p>
*/
@NotNull Arena getArena();
/**
* Gets the player playing in this session
*
* @return <p>This session's player</p>
*/
@NotNull Player getPlayer();
}

View File

@ -0,0 +1,27 @@
package net.knarcraft.minigames.arena;
import org.bukkit.Location;
/**
* The stored state of a player
*/
public interface PlayerEntryState {
/**
* Sets the state of the stored player to the state used by the arena
*/
void setArenaState();
/**
* Restores the stored state for the stored player
*/
void restore();
/**
* Gets the location the player entered from
*
* @return <p>The location the player entered from</p>
*/
Location getEntryLocation();
}

View File

@ -9,6 +9,7 @@ import net.knarcraft.minigames.util.DropperArenaStorageHelper;
import net.knarcraft.minigames.util.StringSanitizer;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -69,6 +70,8 @@ public class DropperArena implements Arena {
private final DropperArenaHandler dropperArenaHandler;
private static final DropperConfiguration dropperConfiguration = MiniGames.getInstance().getDropperConfiguration();
/**
* Instantiates a new dropper arena
*
@ -127,40 +130,22 @@ public class DropperArena implements Arena {
this.dropperArenaHandler = arenaHandler;
}
/**
* Gets this arena's data
*
* @return <p>This arena's data</p>
*/
@Override
public @NotNull DropperArenaData getData() {
return this.dropperArenaData;
}
/**
* Gets the id of this arena
*
* @return <p>This arena's identifier</p>
*/
@Override
public @NotNull UUID getArenaId() {
return this.arenaId;
}
/**
* Gets the name of this arena
*
* @return <p>The name of this arena</p>
*/
@Override
public @NotNull String getArenaName() {
return this.arenaName;
}
/**
* Gets this arena's spawn location
*
* <p>The spawn location is the location every player starts from when entering the dropper.</p>
*
* @return <p>This arena's spawn location.</p>
*/
@Override
public @NotNull Location getSpawnLocation() {
return this.spawnLocation.clone();
}
@ -230,6 +215,21 @@ public class DropperArena implements Arena {
}
}
@Override
public boolean willCauseWin(Block block) {
return block.getType() == winBlockType;
}
@Override
public boolean willCauseLoss(Block block) {
return !dropperConfiguration.getBlockWhitelist().contains(block.getType());
}
@Override
public boolean winLocationIsSolid() {
return winBlockType.isSolid();
}
/**
* Sets the spawn location for this arena
*

View File

@ -64,4 +64,9 @@ public enum DropperArenaGameMode implements ConfigurationSerializable, ArenaGame
return DropperArenaGameMode.valueOf((String) data.get("name"));
}
@Override
public @NotNull DropperArenaGameMode[] getValues() {
return DropperArenaGameMode.values();
}
}

View File

@ -2,6 +2,8 @@ package net.knarcraft.minigames.arena.dropper;
import net.knarcraft.minigames.MiniGames;
import net.knarcraft.minigames.arena.ArenaRecordsRegistry;
import net.knarcraft.minigames.arena.ArenaSession;
import net.knarcraft.minigames.arena.PlayerEntryState;
import net.knarcraft.minigames.config.DropperConfiguration;
import net.knarcraft.minigames.property.RecordResult;
import net.knarcraft.minigames.util.PlayerTeleporter;
@ -14,14 +16,14 @@ import java.util.logging.Level;
/**
* A representation of a player's current session in a dropper arena
*/
public class DropperArenaSession {
public class DropperArenaSession implements ArenaSession {
private final @NotNull DropperArena arena;
private final @NotNull Player player;
private final @NotNull DropperArenaGameMode gameMode;
private int deaths;
private final long startTime;
private final DropperPlayerEntryState entryState;
private final PlayerEntryState entryState;
/**
* Instantiates a new dropper arena session
@ -41,9 +43,10 @@ public class DropperArenaSession {
DropperConfiguration configuration = MiniGames.getInstance().getDropperConfiguration();
boolean makeInvisible = configuration.makePlayersInvisible();
boolean disableCollision = configuration.disableHitCollision();
this.entryState = new DropperPlayerEntryState(player, gameMode, makeInvisible, disableCollision);
this.entryState = new DropperPlayerEntryState(player, gameMode, makeInvisible, disableCollision,
dropperArena.getPlayerHorizontalVelocity());
// Make the player fly to improve mobility in the air
this.entryState.setArenaState(this.arena.getPlayerHorizontalVelocity());
this.entryState.setArenaState();
}
/**
@ -60,7 +63,7 @@ public class DropperArenaSession {
*
* @return <p>The player's entry state</p>
*/
public @NotNull DropperPlayerEntryState getEntryState() {
public @NotNull PlayerEntryState getEntryState() {
return this.entryState;
}
@ -91,6 +94,8 @@ public class DropperArenaSession {
/**
* Teleports the playing player out of the arena
*
* @param immediately <p>Whether to to the teleportation immediately, not using any timers</p>
*/
private void teleportToExit(boolean immediately) {
// Teleport the player out of the arena
@ -159,11 +164,13 @@ public class DropperArenaSession {
this.deaths++;
//Teleport the player back to the top
PlayerTeleporter.teleportPlayer(this.player, this.arena.getSpawnLocation(), true, false);
this.entryState.setArenaState(this.arena.getPlayerHorizontalVelocity());
this.entryState.setArenaState();
}
/**
* Triggers a quit for the player playing in this session
*
* @param immediately <p>Whether to to the teleportation immediately, not using any timers</p>
*/
public void triggerQuit(boolean immediately) {
// Stop this session

View File

@ -1,28 +1,18 @@
package net.knarcraft.minigames.arena.dropper;
import net.knarcraft.minigames.arena.AbstractPlayerEntryState;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
/**
* The state of a player before entering a dropper arena
*/
public class DropperPlayerEntryState {
public class DropperPlayerEntryState extends AbstractPlayerEntryState {
private final Player player;
private final Location entryLocation;
private final boolean originalIsFlying;
private final float originalFlySpeed;
private final GameMode originalGameMode;
private final boolean originalAllowFlight;
private final boolean originalInvulnerable;
private final boolean originalIsSwimming;
private final boolean originalCollideAble;
private final boolean makePlayerInvisible;
private final boolean disableHitCollision;
private final float horizontalVelocity;
private final DropperArenaGameMode arenaGameMode;
/**
@ -30,28 +20,18 @@ public class DropperPlayerEntryState {
*
* @param player <p>The player whose state should be stored</p>
*/
public DropperPlayerEntryState(@NotNull Player player, @NotNull DropperArenaGameMode arenaGameMode, boolean makePlayerInvisible,
boolean disableHitCollision) {
this.player = player;
this.entryLocation = player.getLocation().clone();
public DropperPlayerEntryState(@NotNull Player player, @NotNull DropperArenaGameMode arenaGameMode,
boolean makePlayerInvisible, boolean disableHitCollision, float horizontalVelocity) {
super(player, makePlayerInvisible);
this.originalFlySpeed = player.getFlySpeed();
this.originalIsFlying = player.isFlying();
this.originalGameMode = player.getGameMode();
this.originalAllowFlight = player.getAllowFlight();
this.originalInvulnerable = player.isInvulnerable();
this.originalIsSwimming = player.isSwimming();
this.arenaGameMode = arenaGameMode;
this.originalCollideAble = player.isCollidable();
this.makePlayerInvisible = makePlayerInvisible;
this.disableHitCollision = disableHitCollision;
this.horizontalVelocity = horizontalVelocity;
}
/**
* Sets the state of the stored player to the state used by arenas
*
* @param horizontalVelocity <p>The horizontal velocity to apply to the player</p>
*/
public void setArenaState(float horizontalVelocity) {
@Override
public void setArenaState() {
super.setArenaState();
this.player.setAllowFlight(true);
this.player.setFlying(true);
this.player.setGameMode(GameMode.ADVENTURE);
@ -59,44 +39,19 @@ public class DropperPlayerEntryState {
if (this.disableHitCollision) {
this.player.setCollidable(false);
}
if (this.makePlayerInvisible) {
this.player.addPotionEffect(new PotionEffect(PotionEffectType.INVISIBILITY,
PotionEffect.INFINITE_DURATION, 3));
}
// If playing on the inverted game-mode, negate the horizontal velocity to swap the controls
if (arenaGameMode == DropperArenaGameMode.INVERTED) {
this.player.setFlySpeed(-horizontalVelocity);
if (this.arenaGameMode == DropperArenaGameMode.INVERTED) {
this.player.setFlySpeed(-this.horizontalVelocity);
} else {
this.player.setFlySpeed(horizontalVelocity);
this.player.setFlySpeed(this.horizontalVelocity);
}
}
/**
* Restores the stored state for the stored player
*/
@Override
public void restore() {
this.player.setFlying(this.originalIsFlying);
this.player.setGameMode(this.originalGameMode);
this.player.setAllowFlight(this.originalAllowFlight);
super.restore();
this.player.setFlySpeed(this.originalFlySpeed);
this.player.setInvulnerable(this.originalInvulnerable);
this.player.setSwimming(this.originalIsSwimming);
if (this.disableHitCollision) {
this.player.setCollidable(this.originalCollideAble);
}
if (this.makePlayerInvisible) {
this.player.removePotionEffect(PotionEffectType.INVISIBILITY);
}
}
/**
* Gets the location the player entered from
*
* @return <p>The location the player entered from</p>
*/
public Location getEntryLocation() {
return this.entryLocation;
}
}

View File

@ -9,6 +9,7 @@ import net.knarcraft.minigames.util.ParkourArenaStorageHelper;
import net.knarcraft.minigames.util.StringSanitizer;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -72,7 +73,7 @@ public class ParkourArena implements Arena {
/**
* The checkpoints for this arena. Entering a checkpoint overrides the player's spawn location.
*/
private @NotNull List<Location> checkpoints;
private final @NotNull List<Location> checkpoints;
/**
* The arena data for this arena
@ -141,40 +142,22 @@ public class ParkourArena implements Arena {
this.parkourArenaHandler = arenaHandler;
}
/**
* Gets this arena's data
*
* @return <p>This arena's data</p>
*/
@Override
public @NotNull ParkourArenaData getData() {
return this.parkourArenaData;
}
/**
* Gets the id of this arena
*
* @return <p>This arena's identifier</p>
*/
@Override
public @NotNull UUID getArenaId() {
return this.arenaId;
}
/**
* Gets the name of this arena
*
* @return <p>The name of this arena</p>
*/
@Override
public @NotNull String getArenaName() {
return this.arenaName;
}
/**
* Gets this arena's spawn location
*
* <p>The spawn location is the location every player starts from when entering the parkour arena.</p>
*
* @return <p>This arena's spawn location.</p>
*/
@Override
public @NotNull Location getSpawnLocation() {
return this.spawnLocation;
}
@ -213,7 +196,7 @@ public class ParkourArena implements Arena {
*
* @return <p>The types of blocks that cause a loss</p>
*/
public Set<Material> getKillPlaneBlocks() {
public @NotNull Set<Material> getKillPlaneBlocks() {
if (this.killPlaneBlocks != null) {
return new HashSet<>(this.killPlaneBlocks);
} else {
@ -267,6 +250,23 @@ public class ParkourArena implements Arena {
}
}
@Override
public boolean willCauseWin(Block block) {
return (this.winLocation != null && this.winLocation.getBlock().equals(block)) ||
this.winBlockType == block.getType();
}
@Override
public boolean willCauseLoss(Block block) {
return this.getKillPlaneBlocks().contains(block.getType());
}
@Override
public boolean winLocationIsSolid() {
return (this.winLocation != null && this.winLocation.getBlock().getType().isSolid()) ||
this.winBlockType.isSolid();
}
/**
* Sets the spawn location for this arena
*
@ -357,26 +357,41 @@ public class ParkourArena implements Arena {
*
* @param killPlaneBlockNames <p>The names of the blocks that will cause players to lose</p>
*/
public void setKillPlaneBlocks(@NotNull Set<String> killPlaneBlockNames) {
this.killPlaneBlocks = MaterialHelper.loadMaterialList(new ArrayList<>(killPlaneBlockNames));
public boolean setKillPlaneBlocks(@NotNull Set<String> killPlaneBlockNames) {
if (killPlaneBlockNames.isEmpty()) {
this.killPlaneBlocks = null;
} else {
Set<Material> parsed = MaterialHelper.loadMaterialList(new ArrayList<>(killPlaneBlockNames));
if (parsed.isEmpty()) {
return false;
}
this.killPlaneBlocks = parsed;
}
return true;
}
/**
* Sets the checkpoints of this arena
* Adds a checkpoint to this arena
*
* @param checkpoints <p>The checkpoints to use</p>
* @return <p>True if successfully changed</p>
* @param checkpoint <p>The checkpoint to add</p>
* @return <p>True if successfully added</p>
*/
public boolean setCheckpoints(@NotNull List<Location> checkpoints) {
List<Location> copy = new ArrayList<>(checkpoints.size());
for (Location location : checkpoints) {
if (isInvalid(location)) {
return false;
}
copy.add(location.clone());
public boolean addCheckpoint(@NotNull Location checkpoint) {
if (isInvalid(checkpoint)) {
return false;
}
this.checkpoints = copy;
this.checkpoints.add(checkpoint.clone());
return true;
}
/**
* Clears all checkpoints from this arena
*
* @return <p>True if successfully cleared</p>
*/
public boolean clearCheckpoints() {
this.checkpoints.clear();
return true;
}

View File

@ -4,7 +4,6 @@ import net.knarcraft.minigames.MiniGames;
import net.knarcraft.minigames.arena.ArenaData;
import net.knarcraft.minigames.arena.ArenaGameMode;
import net.knarcraft.minigames.arena.ArenaRecordsRegistry;
import net.knarcraft.minigames.arena.dropper.DropperArenaRecordsRegistry;
import net.knarcraft.minigames.container.SerializableContainer;
import net.knarcraft.minigames.container.SerializableUUID;
import net.knarcraft.minigames.util.SerializableConverter;
@ -39,10 +38,10 @@ public class ParkourArenaData extends ArenaData {
}
/**
* Deserializes a dropper arena data from the given data
* Deserializes a parkour arena data from the given data
*
* @param data <p>The data to deserialize</p>
* @return <p>The deserialized dropper arena data</p>
* @return <p>The deserialized parkour arena data</p>
*/
@SuppressWarnings({"unused", "unchecked"})
public static @NotNull ParkourArenaData deserialize(@NotNull Map<String, Object> data) {
@ -64,7 +63,7 @@ public class ParkourArenaData extends ArenaData {
for (ArenaGameMode arenaGameMode : playersCompletedData.keySet()) {
if (!recordsRegistry.containsKey(arenaGameMode) || recordsRegistry.get(arenaGameMode) == null) {
recordsRegistry.put(arenaGameMode, new DropperArenaRecordsRegistry(serializableUUID.getRawValue()));
recordsRegistry.put(arenaGameMode, new ParkourArenaRecordsRegistry(serializableUUID.getRawValue()));
}
}
return new ParkourArenaData(serializableUUID.getRawValue(), recordsRegistry, allPlayersCompleted);

View File

@ -0,0 +1,107 @@
package net.knarcraft.minigames.arena.parkour;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.Function;
/**
* All editable properties of a parkour arena
*/
public enum ParkourArenaEditableProperty {
/**
* The name of the arena
*/
NAME("name", ParkourArena::getArenaName),
/**
* The arena's spawn location
*/
SPAWN_LOCATION("spawnLocation", (arena) -> String.valueOf(arena.getSpawnLocation())),
/**
* The arena's exit location
*/
EXIT_LOCATION("exitLocation", (arena) -> String.valueOf(arena.getExitLocation())),
/**
* The arena's win block type
*/
WIN_BLOCK_TYPE("winBlockType", (arena) -> arena.getWinBlockType().toString()),
/**
* The arena's win location (overrides the win block type)
*/
WIN_LOCATION("winLocation", (arena) -> {
if (arena.getWinLocation() != null) {
return arena.getWinLocation().toString();
} else {
return "null";
}
}),
/**
* The arena's check points. Specifically used for adding.
*/
CHECKPOINT_ADD("checkpointAdd", (arena) -> String.valueOf(arena.getCheckpoints())),
/**
* The arena's check points. Specifically used for clearing.
*/
CHECKPOINT_CLEAR("checkpointClear", (arena) -> String.valueOf(arena.getCheckpoints())),
/**
* The blocks constituting the arena's lethal blocks
*/
KILL_PLANE_BLOCKS("killPlaneBlocks", (arena) -> String.valueOf(arena.getKillPlaneBlockNames())),
;
private final @NotNull String argumentString;
private final Function<ParkourArena, String> currentValueProvider;
/**
* Instantiates a new arena editable property
*
* @param argumentString <p>The argument string used to specify this property</p>
*/
ParkourArenaEditableProperty(@NotNull String argumentString, Function<ParkourArena, String> currentValueProvider) {
this.argumentString = argumentString;
this.currentValueProvider = currentValueProvider;
}
/**
* Gets the string representation of this property's current value
*
* @param arena <p>The arena to check the value for</p>
* @return <p>The current value as a string</p>
*/
public String getCurrentValueAsString(ParkourArena arena) {
return this.currentValueProvider.apply(arena);
}
/**
* Gets the argument string used to specify this property
*
* @return <p>The argument string</p>
*/
public @NotNull String getArgumentString() {
return this.argumentString;
}
/**
* Gets the editable property corresponding to the given argument string
*
* @param argumentString <p>The argument string used to specify an editable property</p>
* @return <p>The corresponding editable property, or null if not found</p>
*/
public static @Nullable ParkourArenaEditableProperty getFromArgumentString(String argumentString) {
for (ParkourArenaEditableProperty property : ParkourArenaEditableProperty.values()) {
if (property.argumentString.equalsIgnoreCase(argumentString)) {
return property;
}
}
return null;
}
}

View File

@ -47,4 +47,9 @@ public enum ParkourArenaGameMode implements ConfigurationSerializable, ArenaGame
return ParkourArenaGameMode.valueOf((String) data.get("name"));
}
@Override
public @NotNull ParkourArenaGameMode[] getValues() {
return ParkourArenaGameMode.values();
}
}

View File

@ -1,7 +1,10 @@
package net.knarcraft.minigames.arena.parkour;
import net.knarcraft.minigames.MiniGames;
import net.knarcraft.minigames.arena.ArenaGameMode;
import net.knarcraft.minigames.arena.ArenaRecordsRegistry;
import net.knarcraft.minigames.arena.ArenaSession;
import net.knarcraft.minigames.arena.PlayerEntryState;
import net.knarcraft.minigames.config.ParkourConfiguration;
import net.knarcraft.minigames.property.RecordResult;
import net.knarcraft.minigames.util.PlayerTeleporter;
@ -14,14 +17,14 @@ import java.util.logging.Level;
/**
* A representation of a player's current session in a parkour arena
*/
public class ParkourArenaSession {
public class ParkourArenaSession implements ArenaSession {
private final @NotNull ParkourArena arena;
private final @NotNull Player player;
private final @NotNull ParkourArenaGameMode gameMode;
private int deaths;
private final long startTime;
private final ParkourPlayerEntryState entryState;
private final PlayerEntryState entryState;
/**
* Instantiates a new parkour arena session
@ -45,12 +48,17 @@ public class ParkourArenaSession {
this.entryState.setArenaState();
}
@Override
public @NotNull ArenaGameMode getGameMode() {
return this.gameMode;
}
/**
* Gets the state of the player when they joined the session
*
* @return <p>The player's entry state</p>
*/
public @NotNull ParkourPlayerEntryState getEntryState() {
public @NotNull PlayerEntryState getEntryState() {
return this.entryState;
}
@ -63,7 +71,7 @@ public class ParkourArenaSession {
// Check for, and display, records
MiniGames miniGames = MiniGames.getInstance();
boolean ignore = miniGames.getDropperConfiguration().ignoreRecordsUntilGroupBeatenOnce();
boolean ignore = miniGames.getParkourConfiguration().ignoreRecordsUntilGroupBeatenOnce();
ParkourArenaGroup group = miniGames.getParkourArenaHandler().getGroup(this.arena.getArenaId());
if (!ignore || group == null || group.hasBeatenAll(this.gameMode, this.player)) {
registerRecord();
@ -98,9 +106,9 @@ public class ParkourArenaSession {
*/
private void removeSession() {
// Remove this session for game sessions to stop listeners from fiddling more with the player
boolean removedSession = MiniGames.getInstance().getDropperArenaPlayerRegistry().removePlayer(player.getUniqueId());
boolean removedSession = MiniGames.getInstance().getParkourArenaPlayerRegistry().removePlayer(player.getUniqueId());
if (!removedSession) {
MiniGames.log(Level.SEVERE, "Unable to remove dropper arena session for " + player.getName() + ". " +
MiniGames.log(Level.SEVERE, "Unable to remove parkour arena session for " + player.getName() + ". " +
"This will have unintended consequences.");
}
}

View File

@ -1,26 +1,14 @@
package net.knarcraft.minigames.arena.parkour;
import net.knarcraft.minigames.arena.AbstractPlayerEntryState;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
/**
* The state of a player before entering a dropper arena
* The state of a player before entering a parkour arena
*/
public class ParkourPlayerEntryState {
private final Player player;
private final Location entryLocation;
private final boolean originalIsFlying;
private final GameMode originalGameMode;
private final boolean originalAllowFlight;
private final boolean originalInvulnerable;
private final boolean originalIsSwimming;
private final boolean originalCollideAble;
private final boolean makePlayerInvisible;
public class ParkourPlayerEntryState extends AbstractPlayerEntryState {
/**
* Instantiates a new player state
@ -28,54 +16,17 @@ public class ParkourPlayerEntryState {
* @param player <p>The player whose state should be stored</p>
*/
public ParkourPlayerEntryState(@NotNull Player player, boolean makePlayerInvisible) {
this.player = player;
this.entryLocation = player.getLocation().clone();
this.originalIsFlying = player.isFlying();
this.originalGameMode = player.getGameMode();
this.originalAllowFlight = player.getAllowFlight();
this.originalInvulnerable = player.isInvulnerable();
this.originalIsSwimming = player.isSwimming();
this.originalCollideAble = player.isCollidable();
this.makePlayerInvisible = makePlayerInvisible;
super(player, makePlayerInvisible);
}
/**
* Sets the state of the stored player to the state used by arenas
*/
@Override
public void setArenaState() {
super.setArenaState();
this.player.setAllowFlight(false);
this.player.setFlying(false);
this.player.setGameMode(GameMode.ADVENTURE);
this.player.setSwimming(false);
this.player.setCollidable(false);
if (this.makePlayerInvisible) {
this.player.addPotionEffect(new PotionEffect(PotionEffectType.INVISIBILITY,
PotionEffect.INFINITE_DURATION, 3));
}
}
/**
* Restores the stored state for the stored player
*/
public void restore() {
this.player.setFlying(this.originalIsFlying);
this.player.setGameMode(this.originalGameMode);
this.player.setAllowFlight(this.originalAllowFlight);
this.player.setInvulnerable(this.originalInvulnerable);
this.player.setSwimming(this.originalIsSwimming);
this.player.setCollidable(this.originalCollideAble);
if (this.makePlayerInvisible) {
this.player.removePotionEffect(PotionEffectType.INVISIBILITY);
}
}
/**
* Gets the location the player entered from
*
* @return <p>The location the player entered from</p>
*/
public Location getEntryLocation() {
return this.entryLocation;
}
}

View File

@ -1,6 +1,6 @@
package net.knarcraft.minigames.command;
import net.knarcraft.minigames.util.TabCompleteHelper;
import net.knarcraft.minigames.arena.ArenaGameMode;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
@ -9,22 +9,37 @@ import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
/**
* The tab-completer for the join command
* An abstract class for an arena joining tab-completer
*/
public class JoinArenaTabCompleter implements TabCompleter {
public abstract class JoinArenaTabCompleter implements TabCompleter {
private final ArenaGameMode gameMode;
private final Supplier<List<String>> arenaNameSupplier;
/**
* Implements a new join arena tab completer
*
* @param arenaNameSupplier <p>The supplier to ask for arena names</p>
* @param gameMode <p>An instance of one of the available game-modes</p>
*/
public JoinArenaTabCompleter(Supplier<List<String>> arenaNameSupplier, ArenaGameMode gameMode) {
this.arenaNameSupplier = arenaNameSupplier;
this.gameMode = gameMode;
}
@Override
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command,
@NotNull String label, @NotNull String[] arguments) {
if (arguments.length == 1) {
return TabCompleteHelper.getArenas();
return arenaNameSupplier.get();
} else if (arguments.length == 2) {
List<String> gameModes = new ArrayList<>();
gameModes.add("default");
gameModes.add("inverted");
gameModes.add("random");
for (ArenaGameMode gameMode : gameMode.getValues()) {
gameModes.add(gameMode.name().toLowerCase());
}
return gameModes;
} else {
return new ArrayList<>();

View File

@ -1,4 +1,4 @@
package net.knarcraft.minigames.command;
package net.knarcraft.minigames.command.dropper;
import net.knarcraft.minigames.MiniGames;
import net.knarcraft.minigames.arena.dropper.DropperArena;
@ -13,7 +13,7 @@ import org.jetbrains.annotations.NotNull;
/**
* The command for creating a new dropper arena
*/
public class CreateArenaCommand implements CommandExecutor {
public class CreateDropperArenaCommand implements CommandExecutor {
@Override
public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,

View File

@ -1,4 +1,4 @@
package net.knarcraft.minigames.command;
package net.knarcraft.minigames.command.dropper;
import net.knarcraft.minigames.MiniGames;
import net.knarcraft.minigames.arena.dropper.DropperArena;
@ -17,7 +17,7 @@ import java.util.UUID;
/**
* The command for listing groups and the stages within
*/
public class GroupListCommand implements TabExecutor {
public class DropperGroupListCommand implements TabExecutor {
@Override
public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,

View File

@ -1,4 +1,4 @@
package net.knarcraft.minigames.command;
package net.knarcraft.minigames.command.dropper;
import net.knarcraft.minigames.MiniGames;
import net.knarcraft.minigames.arena.dropper.DropperArena;
@ -18,7 +18,7 @@ import java.util.List;
/**
* The command for setting the group of an arena
*/
public class GroupSetCommand implements TabExecutor {
public class DropperGroupSetCommand implements TabExecutor {
@Override
public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
@ -62,7 +62,7 @@ public class GroupSetCommand implements TabExecutor {
public List<String> onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
@NotNull String[] arguments) {
if (arguments.length == 1) {
return TabCompleteHelper.getArenas();
return TabCompleteHelper.getDropperArenas();
} else if (arguments.length == 2) {
List<String> possibleValues = new ArrayList<>();
possibleValues.add("none");

View File

@ -1,4 +1,4 @@
package net.knarcraft.minigames.command;
package net.knarcraft.minigames.command.dropper;
import net.knarcraft.minigames.MiniGames;
import net.knarcraft.minigames.arena.dropper.DropperArena;
@ -17,7 +17,7 @@ import java.util.UUID;
/**
* The command for swapping the order of two arenas in a group
*/
public class GroupSwapCommand implements TabExecutor {
public class DropperGroupSwapCommand implements TabExecutor {
@Override
public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,

View File

@ -1,4 +1,4 @@
package net.knarcraft.minigames.command;
package net.knarcraft.minigames.command.dropper;
import net.knarcraft.minigames.MiniGames;
import net.knarcraft.minigames.arena.dropper.DropperArena;
@ -15,7 +15,7 @@ import org.jetbrains.annotations.NotNull;
/**
* The command for editing an existing dropper arena
*/
public class EditArenaCommand implements CommandExecutor {
public class EditDropperArenaCommand implements CommandExecutor {
private final DropperConfiguration configuration;
@ -24,7 +24,7 @@ public class EditArenaCommand implements CommandExecutor {
*
* @param configuration <p>The configuration to use</p>
*/
public EditArenaCommand(DropperConfiguration configuration) {
public EditDropperArenaCommand(DropperConfiguration configuration) {
this.configuration = configuration;
}

View File

@ -1,4 +1,4 @@
package net.knarcraft.minigames.command;
package net.knarcraft.minigames.command.dropper;
import net.knarcraft.minigames.util.TabCompleteHelper;
import org.bukkit.command.Command;
@ -13,15 +13,15 @@ import java.util.List;
/**
* The tab-completer for the edit arena command
*/
public class EditArenaTabCompleter implements TabCompleter {
public class EditDropperArenaTabCompleter implements TabCompleter {
@Override
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command,
@NotNull String label, @NotNull String[] args) {
if (args.length == 1) {
return TabCompleteHelper.getArenas();
return TabCompleteHelper.getDropperArenas();
} else if (args.length == 2) {
return TabCompleteHelper.getArenaProperties();
return TabCompleteHelper.getDropperArenaProperties();
} else if (args.length == 3) {
//TODO: Tab-complete possible values for the given property
return null;

View File

@ -1,4 +1,4 @@
package net.knarcraft.minigames.command;
package net.knarcraft.minigames.command.dropper;
import net.knarcraft.minigames.MiniGames;
import net.knarcraft.minigames.arena.dropper.DropperArena;
@ -17,7 +17,7 @@ import org.jetbrains.annotations.NotNull;
/**
* The command used to join a dropper arena
*/
public class JoinArenaCommand implements CommandExecutor {
public class JoinDropperArenaCommand implements CommandExecutor {
@Override
public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
@ -31,10 +31,9 @@ public class JoinArenaCommand implements CommandExecutor {
return false;
}
// Disallow joining if the player is already in a dropper arena
DropperArenaSession existingSession = MiniGames.getInstance().getDropperArenaPlayerRegistry().getArenaSession(player.getUniqueId());
if (existingSession != null) {
commandSender.sendMessage("You are already in a dropper arena!");
// Disallow joining if the player is already in a mini-game arena
if (MiniGames.getInstance().getSession(player.getUniqueId()) != null) {
commandSender.sendMessage("You are already playing a mini-game!");
return false;
}
@ -99,7 +98,7 @@ public class JoinArenaCommand implements CommandExecutor {
return false;
} else {
// Make sure to update the state again in the air to remove a potential swimming state
newSession.getEntryState().setArenaState(specifiedArena.getPlayerHorizontalVelocity());
newSession.getEntryState().setArenaState();
return true;
}
}

View File

@ -0,0 +1,19 @@
package net.knarcraft.minigames.command.dropper;
import net.knarcraft.minigames.arena.dropper.DropperArenaGameMode;
import net.knarcraft.minigames.command.JoinArenaTabCompleter;
import net.knarcraft.minigames.util.TabCompleteHelper;
/**
* The tab-completer for the join command
*/
public class JoinDropperArenaTabCompleter extends JoinArenaTabCompleter {
/**
* Implements a new join arena tab completer
*/
public JoinDropperArenaTabCompleter() {
super(TabCompleteHelper::getDropperArenas, DropperArenaGameMode.DEFAULT);
}
}

View File

@ -1,4 +1,4 @@
package net.knarcraft.minigames.command;
package net.knarcraft.minigames.command.dropper;
import net.knarcraft.minigames.util.TabCompleteHelper;
import org.bukkit.command.Command;
@ -13,13 +13,13 @@ import java.util.List;
/**
* A command for listing existing dropper arenas
*/
public class ListArenaCommand implements TabExecutor {
public class ListDropperArenaCommand implements TabExecutor {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label,
@NotNull String[] arguments) {
sender.sendMessage("Dropper arenas:");
for (String arenaName : TabCompleteHelper.getArenas()) {
for (String arenaName : TabCompleteHelper.getDropperArenas()) {
sender.sendMessage(arenaName);
}
return true;

View File

@ -1,4 +1,4 @@
package net.knarcraft.minigames.command;
package net.knarcraft.minigames.command.dropper;
import net.knarcraft.minigames.MiniGames;
import net.knarcraft.minigames.arena.dropper.DropperArena;
@ -10,7 +10,7 @@ import org.jetbrains.annotations.NotNull;
/**
* The method used for removing an existing arena
*/
public class RemoveArenaCommand implements CommandExecutor {
public class RemoveDropperArenaCommand implements CommandExecutor {
@Override
public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,

View File

@ -1,4 +1,4 @@
package net.knarcraft.minigames.command;
package net.knarcraft.minigames.command.dropper;
import net.knarcraft.minigames.util.TabCompleteHelper;
import org.bukkit.command.Command;
@ -13,14 +13,14 @@ import java.util.List;
/**
* The tab-completer for the remove arena command
*/
public class RemoveArenaTabCompleter implements TabCompleter {
public class RemoveDropperArenaTabCompleter implements TabCompleter {
@Nullable
@Override
public List<String> onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
@NotNull String[] arguments) {
if (arguments.length == 1) {
return TabCompleteHelper.getArenas();
return TabCompleteHelper.getDropperArenas();
} else {
return new ArrayList<>();
}

View File

@ -0,0 +1,53 @@
package net.knarcraft.minigames.command.parkour;
import net.knarcraft.minigames.MiniGames;
import net.knarcraft.minigames.arena.parkour.ParkourArena;
import net.knarcraft.minigames.arena.parkour.ParkourArenaHandler;
import net.knarcraft.minigames.util.StringSanitizer;
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;
/**
* The command for creating a new parkour arena
*/
public class CreateParkourArenaCommand implements CommandExecutor {
@Override
public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
@NotNull String[] arguments) {
if (!(commandSender instanceof Player player)) {
commandSender.sendMessage("This command must be used by a player");
return false;
}
// Abort if no name was specified
if (arguments.length < 1) {
return false;
}
// Remove known characters that are likely to cause trouble if used in an arena name
String arenaName = StringSanitizer.removeUnwantedCharacters(arguments[0]);
// An arena name is required
if (arenaName.isBlank()) {
return false;
}
ParkourArenaHandler arenaHandler = MiniGames.getInstance().getParkourArenaHandler();
ParkourArena existingArena = arenaHandler.getArena(arenaName);
if (existingArena != null) {
commandSender.sendMessage("There already exists a parkour arena with that name!");
return false;
}
ParkourArena arena = new ParkourArena(arenaName, player.getLocation(), arenaHandler);
arenaHandler.addArena(arena);
commandSender.sendMessage("The arena was successfully created!");
return true;
}
}

View File

@ -0,0 +1,128 @@
package net.knarcraft.minigames.command.parkour;
import net.knarcraft.minigames.MiniGames;
import net.knarcraft.minigames.arena.parkour.ParkourArena;
import net.knarcraft.minigames.arena.parkour.ParkourArenaEditableProperty;
import org.bukkit.Location;
import org.bukkit.Material;
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;
import java.util.HashSet;
import java.util.List;
/**
* The command for editing an existing dropper arena
*/
public class EditParkourArenaCommand implements CommandExecutor {
/**
* Instantiates a new edit arena command
*/
public EditParkourArenaCommand() {
}
@Override
public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
@NotNull String[] arguments) {
//TODO: Checkpoints are quite different from everything else, so some custom code is needed for dealing with them
if (!(commandSender instanceof Player player)) {
commandSender.sendMessage("This command must be used by a player");
return false;
}
if (arguments.length < 2) {
return false;
}
ParkourArena specifiedArena = MiniGames.getInstance().getParkourArenaHandler().getArena(arguments[0]);
if (specifiedArena == null) {
commandSender.sendMessage("Unable to find the specified dropper arena.");
return false;
}
ParkourArenaEditableProperty editableProperty = ParkourArenaEditableProperty.getFromArgumentString(arguments[1]);
if (editableProperty == null) {
commandSender.sendMessage("Unknown property specified.");
return false;
}
String currentValueFormat = "Current value of %s is: %s";
if (arguments.length < 3) {
// Print the current value of the property
String value = editableProperty.getCurrentValueAsString(specifiedArena);
commandSender.sendMessage(String.format(currentValueFormat, editableProperty.getArgumentString(), value));
return true;
} else {
boolean successful = changeValue(specifiedArena, editableProperty, arguments[2], player);
if (successful) {
player.sendMessage(String.format("Property %s changed to: %s", editableProperty, arguments[2]));
} else {
player.sendMessage("Unable to change the property. Make sure your input is valid!");
}
return successful;
}
}
/**
* Changes the given property to the given value
*
* @param arena <p>The arena to change the property for</p>
* @param property <p>The property to change</p>
* @param value <p>The new value of the property</p>
* @param player <p>The player trying to change the value</p>
* @return <p>True if the value was successfully changed</p>
*/
private boolean changeValue(@NotNull ParkourArena arena, @NotNull ParkourArenaEditableProperty property,
@NotNull String value, @NotNull Player player) {
return switch (property) {
case WIN_BLOCK_TYPE -> arena.setWinBlockType(parseMaterial(value));
case SPAWN_LOCATION -> arena.setSpawnLocation(parseLocation(player, value));
case NAME -> arena.setName(value);
case EXIT_LOCATION -> arena.setExitLocation(parseLocation(player, value));
case WIN_LOCATION -> arena.setWinLocation(parseLocation(player, value));
case CHECKPOINT_ADD -> arena.addCheckpoint(parseLocation(player, value));
case CHECKPOINT_CLEAR -> arena.clearCheckpoints();
case KILL_PLANE_BLOCKS -> arena.setKillPlaneBlocks(new HashSet<>(List.of(value.split(","))));
};
}
/**
* Parses the given location string
*
* @param player <p>The player changing a location</p>
* @param locationString <p>The location string to parse</p>
* @return <p>The parsed location, or the player's location if not parse-able</p>
*/
private @NotNull Location parseLocation(Player player, String locationString) {
if ((locationString.trim() + ",").matches("([0-9]+.?[0-9]*,){3}")) {
String[] parts = locationString.split(",");
Location newLocation = player.getLocation().clone();
newLocation.setX(Double.parseDouble(parts[0].trim()));
newLocation.setY(Double.parseDouble(parts[1].trim()));
newLocation.setZ(Double.parseDouble(parts[2].trim()));
return newLocation;
} else {
return player.getLocation().clone();
}
}
/**
* Parses the given material name
*
* @param materialName <p>The material name to parse</p>
* @return <p>The parsed material, or AIR if not valid</p>
*/
private @NotNull Material parseMaterial(String materialName) {
Material material = Material.matchMaterial(materialName);
if (material == null) {
material = Material.AIR;
}
return material;
}
}

View File

@ -0,0 +1,33 @@
package net.knarcraft.minigames.command.parkour;
import net.knarcraft.minigames.util.TabCompleteHelper;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
/**
* The tab-completer for the edit arena command
*/
public class EditParkourArenaTabCompleter implements TabCompleter {
@Override
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command,
@NotNull String label, @NotNull String[] args) {
if (args.length == 1) {
return TabCompleteHelper.getParkourArenas();
} else if (args.length == 2) {
return TabCompleteHelper.getParkourArenaProperties();
} else if (args.length == 3) {
//TODO: Tab-complete possible values for the given property
return null;
} else {
return new ArrayList<>();
}
}
}

View File

@ -0,0 +1,121 @@
package net.knarcraft.minigames.command.parkour;
import net.knarcraft.minigames.MiniGames;
import net.knarcraft.minigames.arena.parkour.ParkourArena;
import net.knarcraft.minigames.arena.parkour.ParkourArenaGameMode;
import net.knarcraft.minigames.arena.parkour.ParkourArenaGroup;
import net.knarcraft.minigames.arena.parkour.ParkourArenaPlayerRegistry;
import net.knarcraft.minigames.arena.parkour.ParkourArenaSession;
import net.knarcraft.minigames.config.ParkourConfiguration;
import net.knarcraft.minigames.util.PlayerTeleporter;
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;
/**
* The command used to join a parkour arena
*/
public class JoinParkourArenaCommand implements CommandExecutor {
@Override
public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
@NotNull String[] arguments) {
if (!(commandSender instanceof Player player)) {
commandSender.sendMessage("This command must be used by a player");
return false;
}
if (arguments.length < 1) {
return false;
}
// Disallow joining if the player is already in a mini-game arena
if (MiniGames.getInstance().getSession(player.getUniqueId()) != null) {
commandSender.sendMessage("You are already playing a mini-game!");
return false;
}
// Make sure the arena exists
ParkourArena specifiedArena = MiniGames.getInstance().getParkourArenaHandler().getArena(arguments[0]);
if (specifiedArena == null) {
commandSender.sendMessage("Unable to find the specified parkour arena.");
return false;
}
// Deny vehicles as allowing this is tricky, and will cause problems in some cases
if (player.isInsideVehicle() || !player.getPassengers().isEmpty()) {
commandSender.sendMessage("You cannot join an arena while inside a vehicle or carrying a passenger.");
return false;
}
return joinArena(specifiedArena, player, arguments);
}
/**
* Performs the actual arena joining
*
* @param specifiedArena <p>The arena the player wants to join</p>
* @param player <p>The player joining the arena</p>
* @param arguments <p>The arguments given</p>
* @return <p>Whether the arena was joined successfully</p>
*/
private boolean joinArena(ParkourArena specifiedArena, Player player, String[] arguments) {
// Find the specified game-mode
ParkourArenaGameMode gameMode;
if (arguments.length > 1) {
gameMode = ParkourArenaGameMode.matchGamemode(arguments[1]);
} else {
gameMode = ParkourArenaGameMode.DEFAULT;
}
// Make sure the player has beaten the necessary levels
ParkourArenaGroup arenaGroup = MiniGames.getInstance().getParkourArenaHandler().getGroup(specifiedArena.getArenaId());
if (arenaGroup != null && !doGroupChecks(specifiedArena, arenaGroup, gameMode, player)) {
return false;
}
// Register the player's session
ParkourArenaSession newSession = new ParkourArenaSession(specifiedArena, player, gameMode);
ParkourArenaPlayerRegistry playerRegistry = MiniGames.getInstance().getParkourArenaPlayerRegistry();
playerRegistry.registerPlayer(player.getUniqueId(), newSession);
// Try to teleport the player to the arena
boolean teleported = PlayerTeleporter.teleportPlayer(player, specifiedArena.getSpawnLocation(), false, false);
if (!teleported) {
player.sendMessage("Unable to teleport you to the parkour arena. Make sure you're not in a vehicle," +
"and not carrying a passenger!");
newSession.triggerQuit(false);
return false;
} else {
// Make sure to update the state again in the air to remove a potential swimming state
newSession.getEntryState().setArenaState();
return true;
}
}
/**
* Performs necessary check for the given arena's group
*
* @param parkourArena <p>The arena the player is trying to join</p>
* @param arenaGroup <p>The arena group the arena belongs to</p>
* @param arenaGameMode <p>The game-mode the player selected</p>
* @param player <p>The the player trying to join the arena</p>
* @return <p>False if any checks failed</p>
*/
private boolean doGroupChecks(@NotNull ParkourArena parkourArena, @NotNull ParkourArenaGroup arenaGroup,
@NotNull ParkourArenaGameMode arenaGameMode, @NotNull Player player) {
ParkourConfiguration configuration = MiniGames.getInstance().getParkourConfiguration();
// Require that the player has beaten the previous arena on the same game-mode before trying this one
if (configuration.mustDoGroupedInSequence() &&
!arenaGroup.canPlay(arenaGameMode, player, parkourArena.getArenaId())) {
player.sendMessage("You have not yet beaten the previous arena!");
return false;
}
return true;
}
}

View File

@ -0,0 +1,19 @@
package net.knarcraft.minigames.command.parkour;
import net.knarcraft.minigames.arena.parkour.ParkourArenaGameMode;
import net.knarcraft.minigames.command.JoinArenaTabCompleter;
import net.knarcraft.minigames.util.TabCompleteHelper;
/**
* The tab-completer for the join command
*/
public class JoinParkourArenaTabCompleter extends JoinArenaTabCompleter {
/**
* Implements a new join arena tab completer
*/
public JoinParkourArenaTabCompleter() {
super(TabCompleteHelper::getParkourArenas, ParkourArenaGameMode.DEFAULT);
}
}

View File

@ -0,0 +1,35 @@
package net.knarcraft.minigames.command.parkour;
import net.knarcraft.minigames.util.TabCompleteHelper;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabExecutor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
/**
* A command for listing existing parkour arenas
*/
public class ListParkourArenaCommand implements TabExecutor {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label,
@NotNull String[] arguments) {
sender.sendMessage("Parkour arenas:");
for (String arenaName : TabCompleteHelper.getParkourArenas()) {
sender.sendMessage(arenaName);
}
return true;
}
@Nullable
@Override
public List<String> onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
@NotNull String[] arguments) {
return new ArrayList<>();
}
}

View File

@ -0,0 +1,95 @@
package net.knarcraft.minigames.command.parkour;
import net.knarcraft.minigames.MiniGames;
import net.knarcraft.minigames.arena.parkour.ParkourArena;
import net.knarcraft.minigames.arena.parkour.ParkourArenaGroup;
import net.knarcraft.minigames.arena.parkour.ParkourArenaHandler;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabExecutor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID;
/**
* The command for listing groups and the stages within
*/
public class ParkourGroupListCommand implements TabExecutor {
@Override
public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
@NotNull String[] arguments) {
ParkourArenaHandler arenaHandler = MiniGames.getInstance().getParkourArenaHandler();
if (arguments.length == 0) {
displayExistingGroups(arenaHandler, commandSender);
return true;
} else if (arguments.length == 1) {
return displayOrderedArenaNames(arenaHandler, commandSender, arguments[0]);
} else {
return false;
}
}
/**
* Displays all currently existing parkour arena groups
*
* @param arenaHandler <p>The arena handler to get groups from</p>
* @param sender <p>The command sender to display the groups to</p>
*/
private void displayExistingGroups(@NotNull ParkourArenaHandler arenaHandler, @NotNull CommandSender sender) {
StringBuilder builder = new StringBuilder("Parkour arena groups:").append("\n");
arenaHandler.getAllGroups().stream().sorted().forEachOrdered((group) ->
builder.append(group.getGroupName()).append("\n"));
sender.sendMessage(builder.toString());
}
/**
* Displays the ordered stages in a specified group to the specified command sender
*
* @param arenaHandler <p>The arena handler to get groups from</p>
* @param sender <p>The command sender to display the stages to</p>
* @param groupName <p>The name of the group to display stages for</p>
* @return <p>True if the stages were successfully displayed</p>
*/
private boolean displayOrderedArenaNames(@NotNull ParkourArenaHandler arenaHandler, @NotNull CommandSender sender,
@NotNull String groupName) {
ParkourArenaGroup arenaGroup = arenaHandler.getGroup(groupName);
if (arenaGroup == null) {
sender.sendMessage("Unable to find the specified group!");
return false;
}
// Send a list of all stages (arenas in the group)
StringBuilder builder = new StringBuilder(groupName).append("'s stages:").append("\n");
int counter = 1;
for (UUID arenaId : arenaGroup.getArenas()) {
ParkourArena arena = arenaHandler.getArena(arenaId);
if (arena != null) {
builder.append(counter++).append(". ").append(arena.getArenaName()).append("\n");
}
}
sender.sendMessage(builder.toString());
return true;
}
@Nullable
@Override
public List<String> onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
@NotNull String[] arguments) {
if (arguments.length == 1) {
List<String> groupNames = new ArrayList<>();
Set<ParkourArenaGroup> arenaGroups = MiniGames.getInstance().getParkourArenaHandler().getAllGroups();
for (ParkourArenaGroup group : arenaGroups) {
groupNames.add(group.getGroupName());
}
return groupNames;
} else {
return new ArrayList<>();
}
}
}

View File

@ -0,0 +1,79 @@
package net.knarcraft.minigames.command.parkour;
import net.knarcraft.minigames.MiniGames;
import net.knarcraft.minigames.arena.parkour.ParkourArena;
import net.knarcraft.minigames.arena.parkour.ParkourArenaGroup;
import net.knarcraft.minigames.arena.parkour.ParkourArenaHandler;
import net.knarcraft.minigames.util.StringSanitizer;
import net.knarcraft.minigames.util.TabCompleteHelper;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabExecutor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
/**
* The command for setting the group of an arena
*/
public class ParkourGroupSetCommand implements TabExecutor {
@Override
public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
@NotNull String[] arguments) {
if (arguments.length < 2) {
return false;
}
ParkourArenaHandler arenaHandler = MiniGames.getInstance().getParkourArenaHandler();
ParkourArena specifiedArena = arenaHandler.getArena(arguments[0]);
if (specifiedArena == null) {
commandSender.sendMessage("Unable to find the specified parkour arena.");
return false;
}
String groupName = StringSanitizer.removeUnwantedCharacters(arguments[1]);
if (groupName.isBlank()) {
return false;
}
ParkourArenaGroup arenaGroup;
if (groupName.equalsIgnoreCase("null") || groupName.equalsIgnoreCase("none")) {
arenaGroup = null;
} else {
arenaGroup = arenaHandler.getGroup(groupName);
if (arenaGroup == null) {
arenaGroup = new ParkourArenaGroup(groupName);
}
}
arenaHandler.setGroup(specifiedArena.getArenaId(), arenaGroup);
commandSender.sendMessage("The arena's group has been updated");
return true;
}
@Nullable
@Override
public List<String> onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
@NotNull String[] arguments) {
if (arguments.length == 1) {
return TabCompleteHelper.getParkourArenas();
} else if (arguments.length == 2) {
List<String> possibleValues = new ArrayList<>();
possibleValues.add("none");
possibleValues.add("GroupName");
for (ParkourArenaGroup group : MiniGames.getInstance().getParkourArenaHandler().getAllGroups()) {
possibleValues.add(group.getGroupName());
}
return possibleValues;
} else {
return new ArrayList<>();
}
}
}

View File

@ -0,0 +1,102 @@
package net.knarcraft.minigames.command.parkour;
import net.knarcraft.minigames.MiniGames;
import net.knarcraft.minigames.arena.parkour.ParkourArena;
import net.knarcraft.minigames.arena.parkour.ParkourArenaGroup;
import net.knarcraft.minigames.arena.parkour.ParkourArenaHandler;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabExecutor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/**
* The command for swapping the order of two arenas in a group
*/
public class ParkourGroupSwapCommand implements TabExecutor {
@Override
public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
@NotNull String[] arguments) {
if (arguments.length < 2) {
return false;
}
ParkourArenaHandler arenaHandler = MiniGames.getInstance().getParkourArenaHandler();
ParkourArena arena1 = arenaHandler.getArena(arguments[0]);
if (arena1 == null) {
commandSender.sendMessage("Unable to find the first specified parkour arena.");
return false;
}
ParkourArena arena2 = arenaHandler.getArena(arguments[1]);
if (arena2 == null) {
commandSender.sendMessage("Unable to find the second specified parkour arena.");
return false;
}
ParkourArenaGroup arena1Group = arenaHandler.getGroup(arena1.getArenaId());
ParkourArenaGroup arena2Group = arenaHandler.getGroup(arena2.getArenaId());
if (arena1Group == null || !arena1Group.equals(arena2Group)) {
commandSender.sendMessage("You cannot swap arenas in different groups!");
return false;
}
arena1Group.swapArenas(arena1Group.getArenas().indexOf(arena1.getArenaId()),
arena1Group.getArenas().indexOf(arena2.getArenaId()));
commandSender.sendMessage("The arenas have been swapped!");
return true;
}
@Nullable
@Override
public List<String> onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
@NotNull String[] arguments) {
ParkourArenaHandler arenaHandler = MiniGames.getInstance().getParkourArenaHandler();
if (arguments.length == 1) {
List<String> arenaNames = new ArrayList<>();
for (ParkourArena parkourArena : arenaHandler.getArenasInAGroup()) {
arenaNames.add(parkourArena.getArenaName());
}
return arenaNames;
} else if (arguments.length == 2) {
return getArenaNamesInSameGroup(arguments[0]);
} else {
return new ArrayList<>();
}
}
/**
* Gets the names of all arenas in the same group as the specified arena
*
* @param arenaName <p>The name of the specified arena</p>
* @return <p>The names of the arenas in the same group</p>
*/
private List<String> getArenaNamesInSameGroup(String arenaName) {
ParkourArenaHandler arenaHandler = MiniGames.getInstance().getParkourArenaHandler();
ParkourArena arena1 = arenaHandler.getArena(arenaName);
if (arena1 == null) {
return new ArrayList<>();
}
// Only display other arenas in the selected group
List<String> arenaNames = new ArrayList<>();
ParkourArenaGroup group = arenaHandler.getGroup(arena1.getArenaId());
if (group == null) {
return new ArrayList<>();
}
for (UUID arenaId : group.getArenas()) {
ParkourArena arena = arenaHandler.getArena(arenaId);
if (arena != null && arena.getArenaId() != arena1.getArenaId()) {
arenaNames.add(arena.getArenaName());
}
}
return arenaNames;
}
}

View File

@ -0,0 +1,36 @@
package net.knarcraft.minigames.command.parkour;
import net.knarcraft.minigames.MiniGames;
import net.knarcraft.minigames.arena.parkour.ParkourArena;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
/**
* The method used for removing an existing arena
*/
public class RemoveParkourArenaCommand implements CommandExecutor {
@Override
public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
@NotNull String[] arguments) {
// Abort if no name was specified
if (arguments.length < 1) {
return false;
}
// Get the specified arena
ParkourArena targetArena = MiniGames.getInstance().getParkourArenaHandler().getArena(arguments[0]);
if (targetArena == null) {
commandSender.sendMessage("Unable to find the specified arena");
return false;
}
// Remove the arena
MiniGames.getInstance().getParkourArenaHandler().removeArena(targetArena);
commandSender.sendMessage("The specified arena has been successfully removed");
return true;
}
}

View File

@ -0,0 +1,29 @@
package net.knarcraft.minigames.command.parkour;
import net.knarcraft.minigames.util.TabCompleteHelper;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
/**
* The tab-completer for the remove arena command
*/
public class RemoveParkourArenaTabCompleter implements TabCompleter {
@Nullable
@Override
public List<String> onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
@NotNull String[] arguments) {
if (arguments.length == 1) {
return TabCompleteHelper.getParkourArenas();
} else {
return new ArrayList<>();
}
}
}

View File

@ -1,7 +1,7 @@
package net.knarcraft.minigames.listener;
import net.knarcraft.minigames.MiniGames;
import net.knarcraft.minigames.arena.dropper.DropperArenaPlayerRegistry;
import net.knarcraft.minigames.arena.ArenaSession;
import net.knarcraft.minigames.arena.dropper.DropperArenaSession;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
@ -25,15 +25,15 @@ public class DamageListener implements Listener {
Player player = (Player) event.getEntity();
// We don't care about damage outside arenas
DropperArenaSession arenaSession = MiniGames.getInstance().getDropperArenaPlayerRegistry().getArenaSession(player.getUniqueId());
ArenaSession arenaSession = MiniGames.getInstance().getSession(player.getUniqueId());
if (arenaSession == null) {
return;
}
event.setCancelled(true);
// Only trigger a loss when a player suffers fall damage
if (event.getCause() == EntityDamageEvent.DamageCause.FALL) {
// Only trigger a loss when a player suffers fall damage in a dropper arena
if (arenaSession instanceof DropperArenaSession && event.getCause() == EntityDamageEvent.DamageCause.FALL) {
arenaSession.triggerLoss();
}
}
@ -44,8 +44,7 @@ public class DamageListener implements Listener {
return;
}
DropperArenaPlayerRegistry registry = MiniGames.getInstance().getDropperArenaPlayerRegistry();
DropperArenaSession arenaSession = registry.getArenaSession(event.getEntity().getUniqueId());
ArenaSession arenaSession = MiniGames.getInstance().getSession(event.getEntity().getUniqueId());
if (arenaSession != null) {
// Cancel combustion for any player in an arena
event.setCancelled(true);

View File

@ -1,13 +1,14 @@
package net.knarcraft.minigames.listener;
import net.knarcraft.minigames.MiniGames;
import net.knarcraft.minigames.arena.Arena;
import net.knarcraft.minigames.arena.ArenaSession;
import net.knarcraft.minigames.arena.dropper.DropperArenaGameMode;
import net.knarcraft.minigames.arena.dropper.DropperArenaPlayerRegistry;
import net.knarcraft.minigames.arena.dropper.DropperArenaSession;
import net.knarcraft.minigames.arena.parkour.ParkourArenaSession;
import net.knarcraft.minigames.config.DropperConfiguration;
import net.knarcraft.minigames.config.SharedConfiguration;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@ -43,13 +44,40 @@ public class MoveListener implements Listener {
return;
}
Player player = event.getPlayer();
DropperArenaPlayerRegistry playerRegistry = MiniGames.getInstance().getDropperArenaPlayerRegistry();
DropperArenaSession arenaSession = playerRegistry.getArenaSession(player.getUniqueId());
if (arenaSession == null) {
ArenaSession session = MiniGames.getInstance().getSession(event.getPlayer().getUniqueId());
if (session instanceof DropperArenaSession dropperSession) {
doDropperArenaChecks(event, dropperSession);
} else if (session instanceof ParkourArenaSession parkourSession) {
doParkourArenaChecks(event, parkourSession);
}
}
/**
* Performs the necessary checks and tasks for the player's session
*
* @param event <p>The move event triggered</p>
* @param arenaSession <p>The dropper session of the player triggering the event</p>
*/
private void doParkourArenaChecks(@NotNull PlayerMoveEvent event, ParkourArenaSession arenaSession) {
if (event.getTo() == null) {
return;
}
// Only do block type checking if the block beneath the player changes
if (event.getFrom().getBlock() != event.getTo().getBlock()) {
checkForSpecialBlock(arenaSession, event.getTo());
}
}
/**
* Performs the necessary checks and tasks for the player's session
*
* @param event <p>The move event triggered</p>
* @param arenaSession <p>The dropper session of the player triggering the event</p>
*/
private void doDropperArenaChecks(@NotNull PlayerMoveEvent event, @NotNull DropperArenaSession arenaSession) {
if (event.getTo() == null) {
return;
}
// Prevent the player from flying upwards while in flight mode
if (event.getFrom().getY() < event.getTo().getY() ||
(configuration.blockSneaking() && event.getPlayer().isSneaking()) ||
@ -78,27 +106,25 @@ public class MoveListener implements Listener {
* @param toLocation <p>The location the player's session is about to hit</p>
* @return <p>True if a special block has been hit</p>
*/
private boolean checkForSpecialBlock(DropperArenaSession arenaSession, Location toLocation) {
private boolean checkForSpecialBlock(ArenaSession arenaSession, Location toLocation) {
SharedConfiguration sharedConfiguration = MiniGames.getInstance().getSharedConfiguration();
double liquidDepth = sharedConfiguration.getLiquidHitBoxDepth();
double solidDepth = sharedConfiguration.getSolidHitBoxDistance();
// Check if the player enters water
Material winBlockType = arenaSession.getArena().getWinBlockType();
Arena arena = arenaSession.getArena();
// For water, only trigger when the player enters the water, but trigger earlier for everything else
double depth = !winBlockType.isSolid() ? liquidDepth : solidDepth;
double depth = arena.winLocationIsSolid() ? solidDepth : liquidDepth;
for (Block block : getBlocksBeneathLocation(toLocation, depth)) {
if (block.getType() == winBlockType) {
if (arena.willCauseWin(block)) {
arenaSession.triggerWin();
return true;
}
}
// Check if the player is about to hit a non-air and non-liquid block
Set<Material> whitelisted = configuration.getBlockWhitelist();
for (Block block : getBlocksBeneathLocation(toLocation, solidDepth)) {
Material blockType = block.getType();
if (!blockType.isAir() && !whitelisted.contains(blockType)) {
if (!block.getType().isAir() && arena.willCauseLoss(block)) {
arenaSession.triggerLoss();
return true;
}

View File

@ -1,7 +1,7 @@
package net.knarcraft.minigames.listener;
import net.knarcraft.minigames.MiniGames;
import net.knarcraft.minigames.arena.dropper.DropperArenaSession;
import net.knarcraft.minigames.arena.ArenaSession;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@ -9,8 +9,6 @@ import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
@ -22,12 +20,13 @@ import java.util.logging.Level;
*/
public class PlayerLeaveListener implements Listener {
private final Map<UUID, DropperArenaSession> leftSessions = new HashMap<>();
private final Map<UUID, ArenaSession> leftSessions = new HashMap<>();
@EventHandler
public void onPlayerLeave(PlayerQuitEvent event) {
Player player = event.getPlayer();
DropperArenaSession arenaSession = getSession(player);
ArenaSession arenaSession = MiniGames.getInstance().getSession(event.getPlayer().getUniqueId());
if (arenaSession == null) {
return;
}
@ -57,7 +56,7 @@ public class PlayerLeaveListener implements Listener {
return;
}
DropperArenaSession arenaSession = getSession(event.getPlayer());
ArenaSession arenaSession = MiniGames.getInstance().getSession(event.getPlayer().getUniqueId());
if (arenaSession == null) {
return;
}
@ -69,14 +68,4 @@ public class PlayerLeaveListener implements Listener {
arenaSession.triggerQuit(false);
}
/**
* 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 MiniGames.getInstance().getDropperArenaPlayerRegistry().getArenaSession(player.getUniqueId());
}
}

View File

@ -1,8 +1,10 @@
package net.knarcraft.minigames.util;
import net.knarcraft.minigames.MiniGames;
import net.knarcraft.minigames.arena.dropper.DropperArena;
import net.knarcraft.minigames.arena.Arena;
import net.knarcraft.minigames.arena.ArenaHandler;
import net.knarcraft.minigames.arena.dropper.DropperArenaEditableProperty;
import net.knarcraft.minigames.arena.parkour.ParkourArenaEditableProperty;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
@ -22,10 +24,28 @@ public final class TabCompleteHelper {
*
* @return <p>All arena names</p>
*/
public static @NotNull List<String> getArenas() {
public static @NotNull List<String> getDropperArenas() {
return getArenas(MiniGames.getInstance().getDropperArenaHandler());
}
/**
* Gets the names of all current arenas
*
* @return <p>All arena names</p>
*/
public static @NotNull List<String> getParkourArenas() {
return getArenas(MiniGames.getInstance().getParkourArenaHandler());
}
/**
* Gets the names of all current arenas
*
* @return <p>All arena names</p>
*/
private static @NotNull List<String> getArenas(ArenaHandler<?, ?> arenaHandler) {
List<String> arenaNames = new ArrayList<>();
for (DropperArena dropperArena : MiniGames.getInstance().getDropperArenaHandler().getArenas().values()) {
arenaNames.add(dropperArena.getArenaName());
for (Arena arena : arenaHandler.getArenas().values()) {
arenaNames.add(arena.getArenaName());
}
return arenaNames;
}
@ -35,7 +55,7 @@ public final class TabCompleteHelper {
*
* @return <p>All arena properties</p>
*/
public static @NotNull List<String> getArenaProperties() {
public static @NotNull List<String> getDropperArenaProperties() {
List<String> arenaProperties = new ArrayList<>();
for (DropperArenaEditableProperty property : DropperArenaEditableProperty.values()) {
arenaProperties.add(property.getArgumentString());
@ -43,4 +63,17 @@ public final class TabCompleteHelper {
return arenaProperties;
}
/**
* Gets the argument strings of all arena properties
*
* @return <p>All arena properties</p>
*/
public static @NotNull List<String> getParkourArenaProperties() {
List<String> arenaProperties = new ArrayList<>();
for (ParkourArenaEditableProperty property : ParkourArenaEditableProperty.values()) {
arenaProperties.add(property.getArgumentString());
}
return arenaProperties;
}
}