Parkour implementation safety save

This is just a safety save in case the code gets too broken to fix.
This commit is contained in:
Kristian Knarvik 2023-04-13 13:24:43 +02:00
parent b1e86a928b
commit 9a3f9841ab
55 changed files with 2356 additions and 695 deletions

View File

@ -1,20 +1,21 @@
# Dropper
# MiniGames
This is a plugin for a dropper mini-game (try to reach the bottom without hitting any obstacles).
To create an arena, simply use `/droppercreate <name>`, where \<name> is simply the name used to differentiate and
This plugin adds several mini-games.
To create a dropper arena, simply use `/droppercreate <name>`, where \<name> is simply the name used to differentiate
and
recognize the arena. Your location will be used as the spawn location for anyone joining the dropper arena. To start
playing, simply use `/dropperjoin <name>`, where \<name> is the same as you specified upon creation.
To modify
To modify the arena, use `/dropperedit <name> <property> <value>`.
## Permissions
| Node | Description |
|----------------|----------------------------------------------------|
| dropper.admin | Gives all permissions. |
| dropper.join | Allows a player to participate in dropper arenas. |
| dropper.create | Allows a player to create a new dropper arena. |
| dropper.edit | Allows a player to edit an existing dropper arena. |
| dropper.remove | Allows a player to remove a dropper arena. |
|------------------|------------------------------------------------------|
| minigames.admin | Gives all permissions. |
| minigames.join | Allows a player to participate in mini-game arenas. |
| minigames.create | Allows a player to create a new mini-game arena. |
| minigames.edit | Allows a player to edit an existing mini-game arena. |
| minigames.remove | Allows a player to remove a mini-game arena. |
## Commands

View File

@ -5,13 +5,13 @@
<modelVersion>4.0.0</modelVersion>
<groupId>net.knarcraft</groupId>
<artifactId>Dropper</artifactId>
<artifactId>MiniGames</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Dropper</name>
<name>MiniGames</name>
<description>A plugin for dropper mini-games</description>
<description>A plugin which adds various mini-games</description>
<properties>
<java.version>16</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

View File

@ -1,12 +1,14 @@
package net.knarcraft.dropper;
import net.knarcraft.dropper.arena.ArenaGameMode;
import net.knarcraft.dropper.arena.DropperArenaData;
import net.knarcraft.dropper.arena.DropperArenaGroup;
import net.knarcraft.dropper.arena.DropperArenaHandler;
import net.knarcraft.dropper.arena.DropperArenaPlayerRegistry;
import net.knarcraft.dropper.arena.DropperArenaRecordsRegistry;
import net.knarcraft.dropper.arena.DropperArenaSession;
import net.knarcraft.dropper.arena.dropper.DropperArenaData;
import net.knarcraft.dropper.arena.dropper.DropperArenaGameMode;
import net.knarcraft.dropper.arena.dropper.DropperArenaGroup;
import net.knarcraft.dropper.arena.dropper.DropperArenaHandler;
import net.knarcraft.dropper.arena.dropper.DropperArenaPlayerRegistry;
import net.knarcraft.dropper.arena.dropper.DropperArenaRecordsRegistry;
import net.knarcraft.dropper.arena.dropper.DropperArenaSession;
import net.knarcraft.dropper.arena.parkour.ParkourArenaHandler;
import net.knarcraft.dropper.arena.parkour.ParkourArenaPlayerRegistry;
import net.knarcraft.dropper.arena.record.IntegerRecord;
import net.knarcraft.dropper.arena.record.LongRecord;
import net.knarcraft.dropper.command.CreateArenaCommand;
@ -47,39 +49,59 @@ import java.util.logging.Level;
* The dropper plugin's main class
*/
@SuppressWarnings("unused")
public final class Dropper extends JavaPlugin {
public final class MiniGames extends JavaPlugin {
private static Dropper instance;
private static MiniGames instance;
private DropperConfiguration configuration;
private DropperArenaHandler arenaHandler;
private DropperArenaPlayerRegistry playerRegistry;
private DropperArenaHandler dropperArenaHandler;
private DropperArenaPlayerRegistry dropperArenaPlayerRegistry;
private DropperRecordExpansion dropperRecordExpansion;
private ParkourArenaHandler parkourArenaHandler;
private ParkourArenaPlayerRegistry parkourArenaPlayerRegistry;
/**
* Gets an instance of this plugin
*
* @return <p>An instance of this plugin, or null if not initialized yet.</p>
*/
public static Dropper getInstance() {
public static MiniGames getInstance() {
return instance;
}
/**
* Gets the arena handler for this instance
* Gets the dropper arena handler for this instance
*
* @return <p>A dropper arena handler</p>
*/
public DropperArenaHandler getArenaHandler() {
return this.arenaHandler;
public DropperArenaHandler getDropperArenaHandler() {
return this.dropperArenaHandler;
}
/**
* Gets the arena player registry for this instance
* Gets the parkour arena handler for this instance
*
* @return <p>A parkour arena handler</p>
*/
public ParkourArenaHandler getParkourArenaHandler() {
return this.parkourArenaHandler;
}
/**
* Gets the dropper arena player registry for this instance
*
* @return <p>A dropper arena player registry</p>
*/
public DropperArenaPlayerRegistry getPlayerRegistry() {
return this.playerRegistry;
public DropperArenaPlayerRegistry getDropperArenaPlayerRegistry() {
return this.dropperArenaPlayerRegistry;
}
/**
* Gets the parkour arena player registry for this instance
*
* @return <p>A parkour arena player registry</p>
*/
public ParkourArenaPlayerRegistry getParkourArenaPlayerRegistry() {
return this.parkourArenaPlayerRegistry;
}
/**
@ -98,7 +120,7 @@ public final class Dropper extends JavaPlugin {
* @param message <p>The message to log</p>
*/
public static void log(Level level, String message) {
Dropper.getInstance().getLogger().log(level, message);
MiniGames.getInstance().getLogger().log(level, message);
}
/**
@ -106,8 +128,8 @@ public final class Dropper extends JavaPlugin {
*/
public void reload() {
// Load all arenas again
this.arenaHandler.loadArenas();
this.arenaHandler.loadGroups();
this.dropperArenaHandler.load();
this.parkourArenaHandler.load();
// Reload configuration
this.reloadConfig();
@ -126,7 +148,7 @@ public final class Dropper extends JavaPlugin {
ConfigurationSerialization.registerClass(SerializableUUID.class);
ConfigurationSerialization.registerClass(DropperArenaData.class);
ConfigurationSerialization.registerClass(DropperArenaGroup.class);
ConfigurationSerialization.registerClass(ArenaGameMode.class);
ConfigurationSerialization.registerClass(DropperArenaGameMode.class);
ConfigurationSerialization.registerClass(LongRecord.class);
ConfigurationSerialization.registerClass(IntegerRecord.class);
}
@ -141,10 +163,12 @@ public final class Dropper extends JavaPlugin {
reloadConfig();
this.configuration = new DropperConfiguration(this.getConfig());
this.configuration.load();
this.playerRegistry = new DropperArenaPlayerRegistry();
this.arenaHandler = new DropperArenaHandler();
this.arenaHandler.loadArenas();
this.arenaHandler.loadGroups();
this.dropperArenaPlayerRegistry = new DropperArenaPlayerRegistry();
this.dropperArenaHandler = new DropperArenaHandler();
this.dropperArenaHandler.load();
this.parkourArenaHandler = new ParkourArenaHandler();
this.parkourArenaHandler.load();
PluginManager pluginManager = getServer().getPluginManager();
pluginManager.registerEvents(new DamageListener(), this);
@ -175,7 +199,7 @@ public final class Dropper extends JavaPlugin {
public void onDisable() {
// Throw out currently playing players before exiting
for (Player player : getServer().getOnlinePlayers()) {
DropperArenaSession session = playerRegistry.getArenaSession(player.getUniqueId());
DropperArenaSession session = dropperArenaPlayerRegistry.getArenaSession(player.getUniqueId());
if (session != null) {
session.triggerQuit(true);
}

View File

@ -0,0 +1,33 @@
package net.knarcraft.dropper.arena;
import org.jetbrains.annotations.NotNull;
import java.util.UUID;
/**
* An interface describing all arenas
*/
public interface Arena {
/**
* Gets the id of this arena
*
* @return <p>This arena's identifier</p>
*/
@NotNull UUID getArenaId();
/**
* Gets the name of this arena
*
* @return <p>The name of this arena</p>
*/
@NotNull String getArenaName();
/**
* Gets this arena's sanitized name
*
* @return <p>This arena's sanitized name</p>
*/
@NotNull String getArenaNameSanitized();
}

View File

@ -0,0 +1,102 @@
package net.knarcraft.dropper.arena;
import net.knarcraft.dropper.container.SerializableUUID;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
/**
* An interface describing generic arena data
*/
public abstract class ArenaData implements ConfigurationSerializable {
protected final @NotNull UUID arenaId;
private final @NotNull Map<ArenaGameMode, ArenaRecordsRegistry> recordRegistries;
private final @NotNull Map<ArenaGameMode, Set<UUID>> playersCompleted;
/**
* Instantiates arena data
*
* @param arenaId <p>The id of the arena this data belongs to</p>
* @param recordRegistries <p>The registry storing records for this arena</p>
* @param playersCompleted <p>The players that have completed this arena</p>
*/
public ArenaData(@NotNull UUID arenaId, @NotNull Map<ArenaGameMode, ArenaRecordsRegistry> recordRegistries,
@NotNull Map<ArenaGameMode, Set<UUID>> playersCompleted) {
this.arenaId = arenaId;
this.recordRegistries = recordRegistries;
this.playersCompleted = playersCompleted;
}
/**
* Gets the id of this arena
*
* @return <p>The id of this arena</p>
*/
public @NotNull UUID getArenaId() {
return this.arenaId;
}
/**
* Gets whether the given player has cleared this arena
*
* @param arenaGameMode <p>The game-mode to check for</p>
* @param player <p>The player to check</p>
* @return <p>True if the player has cleared the arena this data belongs to</p>
*/
public boolean hasNotCompleted(@NotNull ArenaGameMode arenaGameMode, @NotNull Player player) {
return !this.playersCompleted.getOrDefault(arenaGameMode, new HashSet<>()).contains(player.getUniqueId());
}
/**
* Registers the given player as having completed this arena
*
* @param arenaGameMode <p>The game-mode the player completed</p>
* @param player <p>The player that completed this data's arena</p>
*/
public boolean setCompleted(@NotNull ArenaGameMode arenaGameMode, @NotNull Player player) {
// Make sure to add an empty set to prevent a NullPointerException
if (!this.playersCompleted.containsKey(arenaGameMode)) {
this.playersCompleted.put(arenaGameMode, new HashSet<>());
}
boolean added = this.playersCompleted.get(arenaGameMode).add(player.getUniqueId());
// Persistently save the completion
if (added) {
saveData();
}
return added;
}
/**
* Saves this data to disk
*/
public abstract void saveData();
@NotNull
@Override
public Map<String, Object> serialize() {
Map<String, Object> data = new HashMap<>();
data.put("arenaId", new SerializableUUID(this.arenaId));
data.put("recordsRegistry", this.recordRegistries);
// Convert normal UUIDs to serializable UUIDs
Map<ArenaGameMode, Set<SerializableUUID>> serializablePlayersCompleted = new HashMap<>();
for (ArenaGameMode arenaGameMode : this.playersCompleted.keySet()) {
Set<SerializableUUID> playersCompleted = new HashSet<>();
for (UUID playerCompleted : this.playersCompleted.get(arenaGameMode)) {
playersCompleted.add(new SerializableUUID(playerCompleted));
}
serializablePlayersCompleted.put(arenaGameMode, playersCompleted);
}
data.put("playersCompleted", serializablePlayersCompleted);
return data;
}
}

View File

@ -1,66 +1,4 @@
package net.knarcraft.dropper.arena;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.Map;
/**
* A representation of possible arena game-modes
*/
public enum ArenaGameMode implements ConfigurationSerializable {
/**
* The default game-mode. Failing once throws the player out.
*/
DEFAULT,
/**
* A game-mode where the player's directional buttons are inverted
*/
INVERTED,
/**
* A game-mode which swaps between normal and inverted controls on a set schedule of a few seconds
*/
RANDOM_INVERTED,
;
/**
* Tries to match the correct game-mode according to the given string
*
* @param gameMode <p>The game-mode string to match</p>
* @return <p>The specified arena game-mode</p>
*/
public static @NotNull ArenaGameMode matchGamemode(@NotNull String gameMode) {
String sanitized = gameMode.trim().toLowerCase();
if (sanitized.matches("(invert(ed)?|inverse)")) {
return ArenaGameMode.INVERTED;
} else if (sanitized.matches("rand(om)?")) {
return ArenaGameMode.RANDOM_INVERTED;
} else {
return ArenaGameMode.DEFAULT;
}
}
@NotNull
@Override
public Map<String, Object> serialize() {
Map<String, Object> data = new HashMap<>();
data.put("name", this.name());
return data;
}
/**
* Deserializes the arena game-mode specified by the given data
*
* @param data <p>The data to deserialize</p>
* @return <p>The deserialized arena game-mode</p>
*/
@SuppressWarnings("unused")
public static ArenaGameMode deserialize(Map<String, Object> data) {
return ArenaGameMode.valueOf((String) data.get("name"));
}
public interface ArenaGameMode {
}

View File

@ -0,0 +1,165 @@
package net.knarcraft.dropper.arena;
import net.knarcraft.dropper.arena.dropper.DropperArenaGroup;
import net.knarcraft.dropper.container.SerializableUUID;
import net.knarcraft.dropper.util.StringSanitizer;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
public abstract class ArenaGroup implements ConfigurationSerializable {
/**
* The unique id for this group of arenas
*/
private final UUID groupId;
/**
* The unique name for this group of arenas
*/
private final String groupName;
/**
* The arenas in this group, ordered from stage 1 to stage n
*/
protected final List<UUID> arenas;
/**
* Instantiates a new dropper arena group
*
* @param groupName <p>The name of this group</p>
*/
protected ArenaGroup(@NotNull String groupName) {
this.groupId = UUID.randomUUID();
this.groupName = groupName;
this.arenas = new ArrayList<>();
}
/**
* Instantiates a new arena group
*
* @param groupId <p>The unique id of this group</p>
* @param groupName <p>The name of this group</p>
* @param arenas <p>The arenas in this group</p>
*/
protected ArenaGroup(@NotNull UUID groupId, @NotNull String groupName, @NotNull List<UUID> arenas) {
this.groupId = groupId;
this.groupName = groupName;
this.arenas = new ArrayList<>(arenas);
}
/**
* Gets the id of this arena group
*
* @return <p>The id of this group</p>
*/
public @NotNull UUID getGroupId() {
return this.groupId;
}
/**
* Gets the name of this arena group
*
* @return <p>The name of this group</p>
*/
public @NotNull String getGroupName() {
return this.groupName;
}
/**
* Gets the arenas contained in this group in the correct order
*
* @return <p>The ids of the arenas in this group</p>
*/
public @NotNull List<UUID> getArenas() {
return new ArrayList<>(arenas);
}
/**
* Removes the given arena from this group
*
* @param arenaId <p>The id of the arena to remove</p>
*/
public void removeArena(UUID arenaId) {
this.arenas.remove(arenaId);
}
/**
* Adds an arena to the end of this group
*
* @param arenaId <p>The arena to add to this group</p>
*/
public void addArena(UUID arenaId) {
addArena(arenaId, this.arenas.size());
}
/**
* Adds an arena to the end of this group
*
* @param arenaId <p>The arena to add to this group</p>
* @param index <p>The index to put the arena in</p>
*/
public void addArena(UUID arenaId, int index) {
// Make sure we don't have duplicates
if (!this.arenas.contains(arenaId)) {
this.arenas.add(index, arenaId);
}
}
/**
* Gets this group's name, but sanitized
*
* @return <p>The sanitized group name</p>
*/
public @NotNull String getGroupNameSanitized() {
return StringSanitizer.sanitizeArenaName(this.getGroupName());
}
/**
* Swaps the arenas at the given indices
*
* @param index1 <p>The index of the first arena to swap</p>
* @param index2 <p>The index of the second arena to swap</p>
*/
public void swapArenas(int index1, int index2) {
// Change nothing if not a valid request
if (index1 == index2 || index1 < 0 || index2 < 0 || index1 >= this.arenas.size() ||
index2 >= this.arenas.size()) {
return;
}
// Swap the two arena ids
UUID temporaryValue = this.arenas.get(index2);
this.arenas.set(index2, this.arenas.get(index1));
this.arenas.set(index1, temporaryValue);
}
@NotNull
@Override
public Map<String, Object> serialize() {
Map<String, Object> data = new HashMap<>();
data.put("groupId", new SerializableUUID(this.groupId));
data.put("groupName", this.groupName);
List<SerializableUUID> serializableArenas = new ArrayList<>();
for (UUID arenaId : arenas) {
serializableArenas.add(new SerializableUUID(arenaId));
}
data.put("arenas", serializableArenas);
return data;
}
@Override
public boolean equals(Object other) {
if (!(other instanceof DropperArenaGroup otherGroup)) {
return false;
}
return this.getGroupNameSanitized().equals(otherGroup.getGroupNameSanitized());
}
}

View File

@ -0,0 +1,4 @@
package net.knarcraft.dropper.arena;
public interface ArenaRecordsRegistry {
}

View File

@ -1,252 +0,0 @@
package net.knarcraft.dropper.arena;
import net.knarcraft.dropper.Dropper;
import net.knarcraft.dropper.container.SerializableUUID;
import net.knarcraft.dropper.util.StringSanitizer;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.logging.Level;
/**
* A sorted group of arenas that must be completed in sequence
*/
public class DropperArenaGroup implements ConfigurationSerializable {
/**
* The unique id for this group of arenas
*/
private final UUID groupId;
/**
* The unique name for this group of arenas
*/
private final String groupName;
/**
* The arenas in this group, ordered from stage 1 to stage n
*/
private final List<UUID> arenas;
/**
* Instantiates a new dropper arena group
*
* @param groupName <p>The name of this group</p>
*/
public DropperArenaGroup(@NotNull String groupName) {
this.groupId = UUID.randomUUID();
this.groupName = groupName;
this.arenas = new ArrayList<>();
}
/**
* Instantiates a new dropper arena group
*
* @param groupId <p>The unique id of this group</p>
* @param groupName <p>The name of this group</p>
* @param arenas <p>The arenas in this group</p>
*/
private DropperArenaGroup(@NotNull UUID groupId, @NotNull String groupName, @NotNull List<UUID> arenas) {
this.groupId = groupId;
this.groupName = groupName;
this.arenas = new ArrayList<>(arenas);
}
/**
* Gets the id of this dropper arena group
*
* @return <p>The id of this group</p>
*/
public @NotNull UUID getGroupId() {
return this.groupId;
}
/**
* Gets the name of this dropper arena group
*
* @return <p>The name of this group</p>
*/
public @NotNull String getGroupName() {
return this.groupName;
}
/**
* Gets the arenas contained in this group in the correct order
*
* @return <p>The ids of the arenas in this group</p>
*/
public @NotNull List<UUID> getArenas() {
return new ArrayList<>(arenas);
}
/**
* Removes the given dropper arena from this group
*
* @param arenaId <p>The id of the dropper arena to remove</p>
*/
public void removeArena(UUID arenaId) {
this.arenas.remove(arenaId);
}
/**
* Adds an arena to the end of this group
*
* @param arenaId <p>The arena to add to this group</p>
*/
public void addArena(UUID arenaId) {
addArena(arenaId, this.arenas.size());
}
/**
* Adds an arena to the end of this group
*
* @param arenaId <p>The arena to add to this group</p>
* @param index <p>The index to put the arena in</p>
*/
public void addArena(UUID arenaId, int index) {
// Make sure we don't have duplicates
if (!this.arenas.contains(arenaId)) {
this.arenas.add(index, arenaId);
}
}
/**
* Checks whether the given player has beaten all arenas in this group on the given game-mode
*
* @param gameMode <p>The game-mode to check</p>
* @param player <p>The player to check</p>
* @return <p>True if the player has beaten all arenas, false otherwise</p>
*/
public boolean hasBeatenAll(ArenaGameMode gameMode, Player player) {
DropperArenaHandler arenaHandler = Dropper.getInstance().getArenaHandler();
for (UUID anArenaId : this.getArenas()) {
DropperArena dropperArena = arenaHandler.getArena(anArenaId);
if (dropperArena == null) {
// The arena would only be null if the arena has been deleted, but not removed from this group
Dropper.log(Level.WARNING, "The dropper group " + this.getGroupName() +
" contains the arena id " + anArenaId + " which is not a valid arena id!");
continue;
}
if (dropperArena.getData().hasNotCompleted(gameMode, player)) {
return false;
}
}
return true;
}
/**
* Gets whether the given player can play the given arena part of this group, on the given game-mode
*
* @param gameMode <p>The game-mode the player is trying to play</p>
* @param player <p>The player to check</p>
* @param arenaId <p>The id of the arena in this group to check</p>
* @return <p>True if the player is allowed to play the arena</p>
* @throws IllegalArgumentException <p>If checking an arena not in this group</p>
*/
public boolean canPlay(ArenaGameMode gameMode, Player player, UUID arenaId) throws IllegalArgumentException {
if (!this.arenas.contains(arenaId)) {
throw new IllegalArgumentException("Cannot check for playability for arena not in this group!");
}
DropperArenaHandler arenaHandler = Dropper.getInstance().getArenaHandler();
for (UUID anArenaId : this.getArenas()) {
// If the target arena is reached, allow, as all previous arenas must have been cleared
if (arenaId.equals(anArenaId)) {
return true;
}
DropperArena dropperArena = arenaHandler.getArena(anArenaId);
if (dropperArena == null) {
// The arena would only be null if the arena has been deleted, but not removed from this group
Dropper.log(Level.WARNING, String.format("The dropper group %s contains the" +
" arena id %s which is not a valid arena id!", this.getGroupName(), anArenaId));
continue;
}
// This is a lower-numbered arena the player has yet to complete
if (dropperArena.getData().hasNotCompleted(gameMode, player)) {
return false;
}
}
return false;
}
/**
* Gets this group's name, but sanitized
*
* @return <p>The sanitized group name</p>
*/
public @NotNull String getGroupNameSanitized() {
return StringSanitizer.sanitizeArenaName(this.getGroupName());
}
/**
* Swaps the arenas at the given indices
*
* @param index1 <p>The index of the first arena to swap</p>
* @param index2 <p>The index of the second arena to swap</p>
*/
public void swapArenas(int index1, int index2) {
// Change nothing if not a valid request
if (index1 == index2 || index1 < 0 || index2 < 0 || index1 >= this.arenas.size() ||
index2 >= this.arenas.size()) {
return;
}
// Swap the two arena ids
UUID temporaryValue = this.arenas.get(index2);
this.arenas.set(index2, this.arenas.get(index1));
this.arenas.set(index1, temporaryValue);
}
@NotNull
@Override
public Map<String, Object> serialize() {
Map<String, Object> data = new HashMap<>();
data.put("groupId", new SerializableUUID(this.groupId));
data.put("groupName", this.groupName);
List<SerializableUUID> serializableArenas = new ArrayList<>();
for (UUID arenaId : arenas) {
serializableArenas.add(new SerializableUUID(arenaId));
}
data.put("arenas", serializableArenas);
return data;
}
/**
* Deserializes the given data
*
* @param data <p>The data to deserialize</p>
* @return <p>The deserialized arena group</p>
*/
@SuppressWarnings({"unused", "unchecked"})
public static @NotNull DropperArenaGroup deserialize(@NotNull Map<String, Object> data) {
UUID id = ((SerializableUUID) data.get("groupId")).uuid();
String name = (String) data.get("groupName");
List<SerializableUUID> serializableArenas = (List<SerializableUUID>) data.get("arenas");
List<UUID> arenas = new ArrayList<>();
for (SerializableUUID arenaId : serializableArenas) {
arenas.add(arenaId.uuid());
}
return new DropperArenaGroup(id, name, arenas);
}
@Override
public boolean equals(Object other) {
if (!(other instanceof DropperArenaGroup otherGroup)) {
return false;
}
return this.getGroupNameSanitized().equals(otherGroup.getGroupNameSanitized());
}
}

View File

@ -1,11 +1,13 @@
package net.knarcraft.dropper.arena;
package net.knarcraft.dropper.arena.dropper;
import net.knarcraft.dropper.Dropper;
import net.knarcraft.dropper.MiniGames;
import net.knarcraft.dropper.arena.Arena;
import net.knarcraft.dropper.arena.ArenaGameMode;
import net.knarcraft.dropper.arena.ArenaRecordsRegistry;
import net.knarcraft.dropper.config.DropperConfiguration;
import net.knarcraft.dropper.util.StringSanitizer;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -13,10 +15,12 @@ import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import static net.knarcraft.dropper.util.InputValidationHelper.isInvalid;
/**
* A representation of one dropper arena
*/
public class DropperArena {
public class DropperArena implements Arena {
/**
* An unique and persistent identifier for this arena
@ -103,7 +107,7 @@ public class DropperArena {
*/
public DropperArena(@NotNull String arenaName, @NotNull Location spawnLocation,
@NotNull DropperArenaHandler arenaHandler) {
DropperConfiguration configuration = Dropper.getInstance().getDropperConfiguration();
DropperConfiguration configuration = MiniGames.getInstance().getDropperConfiguration();
this.arenaId = UUID.randomUUID();
this.arenaName = arenaName;
this.spawnLocation = spawnLocation;
@ -111,8 +115,8 @@ public class DropperArena {
this.playerVerticalVelocity = configuration.getVerticalVelocity();
this.playerHorizontalVelocity = configuration.getHorizontalVelocity();
Map<ArenaGameMode, DropperArenaRecordsRegistry> recordRegistries = new HashMap<>();
for (ArenaGameMode arenaGameMode : ArenaGameMode.values()) {
Map<ArenaGameMode, ArenaRecordsRegistry> recordRegistries = new HashMap<>();
for (ArenaGameMode arenaGameMode : DropperArenaGameMode.values()) {
recordRegistries.put(arenaGameMode, new DropperArenaRecordsRegistry(this.arenaId));
}
@ -130,20 +134,12 @@ public class DropperArena {
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;
}
@ -156,7 +152,7 @@ public class DropperArena {
* @return <p>This arena's spawn location.</p>
*/
public @NotNull Location getSpawnLocation() {
return this.spawnLocation;
return this.spawnLocation.clone();
}
/**
@ -165,7 +161,7 @@ public class DropperArena {
* @return <p>This arena's exit location, or null if no such location is set.</p>
*/
public @Nullable Location getExitLocation() {
return this.exitLocation;
return this.exitLocation != null ? this.exitLocation.clone() : null;
}
/**
@ -200,11 +196,7 @@ public class DropperArena {
return this.winBlockType;
}
/**
* Gets this arena's sanitized name
*
* @return <p>This arena's sanitized name</p>
*/
@Override
public @NotNull String getArenaNameSanitized() {
return StringSanitizer.sanitizeArenaName(this.getArenaName());
}
@ -320,15 +312,4 @@ public class DropperArena {
return this.getArenaNameSanitized().equals(otherArena.getArenaNameSanitized());
}
/**
* Checks whether the given location is valid
*
* @param location <p>The location to validate</p>
* @return <p>False if the location is valid</p>
*/
private boolean isInvalid(Location location) {
World world = location.getWorld();
return world == null || !world.getWorldBorder().isInside(location);
}
}

View File

@ -0,0 +1,75 @@
package net.knarcraft.dropper.arena.dropper;
import net.knarcraft.dropper.MiniGames;
import net.knarcraft.dropper.arena.ArenaData;
import net.knarcraft.dropper.arena.ArenaGameMode;
import net.knarcraft.dropper.arena.ArenaRecordsRegistry;
import net.knarcraft.dropper.container.SerializableUUID;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
/**
* Data stored for an arena
*/
public class DropperArenaData extends ArenaData {
/**
* Instantiates a new dropper arena data object
*
* @param arenaId <p>The id of the arena this data belongs to</p>
* @param recordRegistries <p>The registries of this arena's records</p>
* @param playersCompleted <p>The set of the players that have cleared this arena for each game-mode</p>
*/
public DropperArenaData(@NotNull UUID arenaId,
@NotNull Map<ArenaGameMode, ArenaRecordsRegistry> recordRegistries,
@NotNull Map<ArenaGameMode, Set<UUID>> playersCompleted) {
super(arenaId, recordRegistries, playersCompleted);
}
@Override
public void saveData() {
MiniGames.getInstance().getDropperArenaHandler().saveData(this.arenaId);
}
/**
* Deserializes a dropper arena data from the given data
*
* @param data <p>The data to deserialize</p>
* @return <p>The deserialized dropper arena data</p>
*/
@SuppressWarnings({"unused", "unchecked"})
public static @NotNull DropperArenaData deserialize(@NotNull Map<String, Object> data) {
SerializableUUID serializableUUID = (SerializableUUID) data.get("arenaId");
Map<ArenaGameMode, ArenaRecordsRegistry> recordsRegistry =
(Map<ArenaGameMode, ArenaRecordsRegistry>) data.get("recordsRegistry");
Map<ArenaGameMode, Set<SerializableUUID>> playersCompletedData =
(Map<ArenaGameMode, Set<SerializableUUID>>) data.get("playersCompleted");
if (recordsRegistry == null) {
recordsRegistry = new HashMap<>();
} else if (playersCompletedData == null) {
playersCompletedData = new HashMap<>();
}
// Convert the serializable UUIDs to normal UUIDs
Map<ArenaGameMode, Set<UUID>> allPlayersCompleted = new HashMap<>();
for (ArenaGameMode arenaGameMode : playersCompletedData.keySet()) {
Set<UUID> playersCompleted = new HashSet<>();
for (SerializableUUID completedId : playersCompletedData.get(arenaGameMode)) {
playersCompleted.add(completedId.uuid());
}
allPlayersCompleted.put(arenaGameMode, playersCompleted);
if (!recordsRegistry.containsKey(arenaGameMode) || recordsRegistry.get(arenaGameMode) == null) {
recordsRegistry.put(arenaGameMode, new DropperArenaRecordsRegistry(serializableUUID.uuid()));
}
}
return new DropperArenaData(serializableUUID.uuid(), recordsRegistry, allPlayersCompleted);
}
}

View File

@ -1,4 +1,4 @@
package net.knarcraft.dropper.arena;
package net.knarcraft.dropper.arena.dropper;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -8,7 +8,7 @@ import java.util.function.Function;
/**
* All editable properties of a dropper arena
*/
public enum ArenaEditableProperty {
public enum DropperArenaEditableProperty {
/**
* The name of the arena
@ -49,7 +49,7 @@ public enum ArenaEditableProperty {
*
* @param argumentString <p>The argument string used to specify this property</p>
*/
ArenaEditableProperty(@NotNull String argumentString, Function<DropperArena, String> currentValueProvider) {
DropperArenaEditableProperty(@NotNull String argumentString, Function<DropperArena, String> currentValueProvider) {
this.argumentString = argumentString;
this.currentValueProvider = currentValueProvider;
}
@ -79,8 +79,8 @@ public enum ArenaEditableProperty {
* @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 ArenaEditableProperty getFromArgumentString(String argumentString) {
for (ArenaEditableProperty property : ArenaEditableProperty.values()) {
public static @Nullable DropperArenaEditableProperty getFromArgumentString(String argumentString) {
for (DropperArenaEditableProperty property : DropperArenaEditableProperty.values()) {
if (property.argumentString.equalsIgnoreCase(argumentString)) {
return property;
}

View File

@ -0,0 +1,67 @@
package net.knarcraft.dropper.arena.dropper;
import net.knarcraft.dropper.arena.ArenaGameMode;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.Map;
/**
* A representation of possible arena game-modes
*/
public enum DropperArenaGameMode implements ConfigurationSerializable, ArenaGameMode {
/**
* The default game-mode. Failing once throws the player out.
*/
DEFAULT,
/**
* A game-mode where the player's directional buttons are inverted
*/
INVERTED,
/**
* A game-mode which swaps between normal and inverted controls on a set schedule of a few seconds
*/
RANDOM_INVERTED,
;
/**
* Tries to match the correct game-mode according to the given string
*
* @param gameMode <p>The game-mode string to match</p>
* @return <p>The specified arena game-mode</p>
*/
public static @NotNull DropperArenaGameMode matchGamemode(@NotNull String gameMode) {
String sanitized = gameMode.trim().toLowerCase();
if (sanitized.matches("(invert(ed)?|inverse)")) {
return DropperArenaGameMode.INVERTED;
} else if (sanitized.matches("rand(om)?")) {
return DropperArenaGameMode.RANDOM_INVERTED;
} else {
return DropperArenaGameMode.DEFAULT;
}
}
@NotNull
@Override
public Map<String, Object> serialize() {
Map<String, Object> data = new HashMap<>();
data.put("name", this.name());
return data;
}
/**
* Deserializes the arena game-mode specified by the given data
*
* @param data <p>The data to deserialize</p>
* @return <p>The deserialized arena game-mode</p>
*/
@SuppressWarnings("unused")
public static DropperArenaGameMode deserialize(Map<String, Object> data) {
return DropperArenaGameMode.valueOf((String) data.get("name"));
}
}

View File

@ -0,0 +1,122 @@
package net.knarcraft.dropper.arena.dropper;
import net.knarcraft.dropper.MiniGames;
import net.knarcraft.dropper.arena.ArenaGroup;
import net.knarcraft.dropper.container.SerializableUUID;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.logging.Level;
/**
* A sorted group of arenas that must be completed in sequence
*/
public class DropperArenaGroup extends ArenaGroup {
/**
* Instantiates a new dropper arena group
*
* @param groupName <p>The name of this group</p>
*/
public DropperArenaGroup(@NotNull String groupName) {
super(groupName);
}
/**
* Instantiates a new dropper arena group
*
* @param groupId <p>The unique id of this group</p>
* @param groupName <p>The name of this group</p>
* @param arenas <p>The arenas in this group</p>
*/
private DropperArenaGroup(@NotNull UUID groupId, @NotNull String groupName, @NotNull List<UUID> arenas) {
super(groupId, groupName, arenas);
}
/**
* Checks whether the given player has beaten all arenas in this group on the given game-mode
*
* @param gameMode <p>The game-mode to check</p>
* @param player <p>The player to check</p>
* @return <p>True if the player has beaten all arenas, false otherwise</p>
*/
public boolean hasBeatenAll(DropperArenaGameMode gameMode, Player player) {
DropperArenaHandler arenaHandler = MiniGames.getInstance().getDropperArenaHandler();
for (UUID anArenaId : this.getArenas()) {
DropperArena dropperArena = arenaHandler.getArena(anArenaId);
if (dropperArena == null) {
// The arena would only be null if the arena has been deleted, but not removed from this group
MiniGames.log(Level.WARNING, "The dropper group " + this.getGroupName() +
" contains the arena id " + anArenaId + " which is not a valid arena id!");
continue;
}
if (dropperArena.getData().hasNotCompleted(gameMode, player)) {
return false;
}
}
return true;
}
/**
* Gets whether the given player can play the given arena part of this group, on the given game-mode
*
* @param gameMode <p>The game-mode the player is trying to play</p>
* @param player <p>The player to check</p>
* @param arenaId <p>The id of the arena in this group to check</p>
* @return <p>True if the player is allowed to play the arena</p>
* @throws IllegalArgumentException <p>If checking an arena not in this group</p>
*/
public boolean canPlay(DropperArenaGameMode gameMode, Player player, UUID arenaId) throws IllegalArgumentException {
if (!this.arenas.contains(arenaId)) {
throw new IllegalArgumentException("Cannot check for playability for arena not in this group!");
}
DropperArenaHandler arenaHandler = MiniGames.getInstance().getDropperArenaHandler();
for (UUID anArenaId : this.getArenas()) {
// If the target arena is reached, allow, as all previous arenas must have been cleared
if (arenaId.equals(anArenaId)) {
return true;
}
DropperArena dropperArena = arenaHandler.getArena(anArenaId);
if (dropperArena == null) {
// The arena would only be null if the arena has been deleted, but not removed from this group
MiniGames.log(Level.WARNING, String.format("The dropper group %s contains the" +
" arena id %s which is not a valid arena id!", this.getGroupName(), anArenaId));
continue;
}
// This is a lower-numbered arena the player has yet to complete
if (dropperArena.getData().hasNotCompleted(gameMode, player)) {
return false;
}
}
return false;
}
/**
* Deserializes the given data
*
* @param data <p>The data to deserialize</p>
* @return <p>The deserialized arena group</p>
*/
@SuppressWarnings({"unused", "unchecked"})
public static @NotNull DropperArenaGroup deserialize(@NotNull Map<String, Object> data) {
UUID id = ((SerializableUUID) data.get("groupId")).uuid();
String name = (String) data.get("groupName");
List<SerializableUUID> serializableArenas = (List<SerializableUUID>) data.get("arenas");
List<UUID> arenas = new ArrayList<>();
for (SerializableUUID arenaId : serializableArenas) {
arenas.add(arenaId.uuid());
}
return new DropperArenaGroup(id, name, arenas);
}
}

View File

@ -1,6 +1,6 @@
package net.knarcraft.dropper.arena;
package net.knarcraft.dropper.arena.dropper;
import net.knarcraft.dropper.Dropper;
import net.knarcraft.dropper.MiniGames;
import net.knarcraft.dropper.util.ArenaStorageHelper;
import net.knarcraft.dropper.util.StringSanitizer;
import org.jetbrains.annotations.NotNull;
@ -159,12 +159,12 @@ public class DropperArenaHandler {
*/
public void removeArena(@NotNull DropperArena arena) {
UUID arenaId = arena.getArenaId();
Dropper.getInstance().getPlayerRegistry().removeForArena(arena);
MiniGames.getInstance().getDropperArenaPlayerRegistry().removeForArena(arena);
this.arenas.remove(arenaId);
this.arenaNameLookup.remove(arena.getArenaNameSanitized());
this.arenaGroups.remove(arenaId);
if (!ArenaStorageHelper.removeArenaData(arenaId)) {
Dropper.log(Level.WARNING, "Unable to remove dropper arena data file " + arenaId + ".yml. " +
if (!ArenaStorageHelper.removeDropperArenaData(arenaId)) {
MiniGames.log(Level.WARNING, "Unable to remove dropper arena data file " + arenaId + ".yml. " +
"You must remove it manually!");
}
this.saveArenas();
@ -177,10 +177,10 @@ public class DropperArenaHandler {
*/
public void saveData(UUID arenaId) {
try {
ArenaStorageHelper.saveArenaData(this.arenas.get(arenaId).getData());
ArenaStorageHelper.saveDropperArenaData(this.arenas.get(arenaId).getData());
} catch (IOException e) {
Dropper.log(Level.SEVERE, "Unable to save arena data! Data loss can occur!");
Dropper.log(Level.SEVERE, e.getMessage());
MiniGames.log(Level.SEVERE, "Unable to save arena data! Data loss can occur!");
MiniGames.log(Level.SEVERE, e.getMessage());
}
}
@ -191,16 +191,24 @@ public class DropperArenaHandler {
try {
ArenaStorageHelper.saveDropperArenaGroups(new HashSet<>(this.arenaGroups.values()));
} catch (IOException e) {
Dropper.log(Level.SEVERE, "Unable to save current arena groups! " +
MiniGames.log(Level.SEVERE, "Unable to save current arena groups! " +
"Data loss can occur!");
Dropper.log(Level.SEVERE, e.getMessage());
MiniGames.log(Level.SEVERE, e.getMessage());
}
}
/**
* Loads all arenas and groups from disk
*/
public void load() {
loadArenas();
loadGroups();
}
/**
* Loads all dropper groups from disk
*/
public void loadGroups() {
private void loadGroups() {
Set<DropperArenaGroup> arenaGroups = ArenaStorageHelper.loadDropperArenaGroups();
Map<UUID, DropperArenaGroup> arenaGroupMap = new HashMap<>();
for (DropperArenaGroup arenaGroup : arenaGroups) {
@ -216,19 +224,19 @@ public class DropperArenaHandler {
*/
public void saveArenas() {
try {
ArenaStorageHelper.saveArenas(this.arenas);
ArenaStorageHelper.saveDropperArenas(this.arenas);
} catch (IOException e) {
Dropper.log(Level.SEVERE, "Unable to save current arenas! " +
MiniGames.log(Level.SEVERE, "Unable to save current arenas! " +
"Data loss can occur!");
Dropper.log(Level.SEVERE, e.getMessage());
MiniGames.log(Level.SEVERE, e.getMessage());
}
}
/**
* Loads all arenas from disk
*/
public void loadArenas() {
this.arenas = ArenaStorageHelper.loadArenas();
private void loadArenas() {
this.arenas = ArenaStorageHelper.loadDropperArenas();
// Save a map from arena name to arena id for improved performance
this.arenaNameLookup = new HashMap<>();

View File

@ -1,4 +1,4 @@
package net.knarcraft.dropper.arena;
package net.knarcraft.dropper.arena.dropper;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

View File

@ -1,6 +1,7 @@
package net.knarcraft.dropper.arena;
package net.knarcraft.dropper.arena.dropper;
import net.knarcraft.dropper.Dropper;
import net.knarcraft.dropper.MiniGames;
import net.knarcraft.dropper.arena.ArenaRecordsRegistry;
import net.knarcraft.dropper.arena.record.ArenaRecord;
import net.knarcraft.dropper.arena.record.IntegerRecord;
import net.knarcraft.dropper.arena.record.LongRecord;
@ -23,7 +24,7 @@ import java.util.function.Consumer;
/**
* A registry keeping track of all records
*/
public class DropperArenaRecordsRegistry implements ConfigurationSerializable {
public class DropperArenaRecordsRegistry implements ConfigurationSerializable, ArenaRecordsRegistry {
private final UUID arenaId;
private final @NotNull Set<IntegerRecord> leastDeaths;
@ -105,7 +106,7 @@ public class DropperArenaRecordsRegistry implements ConfigurationSerializable {
* Saves changed records
*/
private void save() {
Dropper.getInstance().getArenaHandler().saveData(this.arenaId);
MiniGames.getInstance().getDropperArenaHandler().saveData(this.arenaId);
}
/**

View File

@ -1,6 +1,6 @@
package net.knarcraft.dropper.arena;
package net.knarcraft.dropper.arena.dropper;
import net.knarcraft.dropper.Dropper;
import net.knarcraft.dropper.MiniGames;
import net.knarcraft.dropper.config.DropperConfiguration;
import net.knarcraft.dropper.property.RecordResult;
import net.knarcraft.dropper.util.PlayerTeleporter;
@ -17,10 +17,10 @@ public class DropperArenaSession {
private final @NotNull DropperArena arena;
private final @NotNull Player player;
private final @NotNull ArenaGameMode gameMode;
private final @NotNull DropperArenaGameMode gameMode;
private int deaths;
private final long startTime;
private final PlayerEntryState entryState;
private final DropperPlayerEntryState entryState;
/**
* Instantiates a new dropper arena session
@ -30,17 +30,17 @@ public class DropperArenaSession {
* @param gameMode <p>The game-mode</p>
*/
public DropperArenaSession(@NotNull DropperArena dropperArena, @NotNull Player player,
@NotNull ArenaGameMode gameMode) {
@NotNull DropperArenaGameMode gameMode) {
this.arena = dropperArena;
this.player = player;
this.gameMode = gameMode;
this.deaths = 0;
this.startTime = System.currentTimeMillis();
DropperConfiguration configuration = Dropper.getInstance().getDropperConfiguration();
DropperConfiguration configuration = MiniGames.getInstance().getDropperConfiguration();
boolean makeInvisible = configuration.makePlayersInvisible();
boolean disableCollision = configuration.disableHitCollision();
this.entryState = new PlayerEntryState(player, gameMode, makeInvisible, disableCollision);
this.entryState = new DropperPlayerEntryState(player, gameMode, makeInvisible, disableCollision);
// Make the player fly to improve mobility in the air
this.entryState.setArenaState(this.arena.getPlayerHorizontalVelocity());
}
@ -50,7 +50,7 @@ public class DropperArenaSession {
*
* @return <p>The game-mode for this session</p>
*/
public @NotNull ArenaGameMode getGameMode() {
public @NotNull DropperArenaGameMode getGameMode() {
return this.gameMode;
}
@ -59,7 +59,7 @@ public class DropperArenaSession {
*
* @return <p>The player's entry state</p>
*/
public @NotNull PlayerEntryState getEntryState() {
public @NotNull DropperPlayerEntryState getEntryState() {
return this.entryState;
}
@ -71,15 +71,15 @@ public class DropperArenaSession {
stopSession();
// Check for, and display, records
Dropper dropper = Dropper.getInstance();
boolean ignore = dropper.getDropperConfiguration().ignoreRecordsUntilGroupBeatenOnce();
DropperArenaGroup group = dropper.getArenaHandler().getGroup(this.arena.getArenaId());
MiniGames miniGames = MiniGames.getInstance();
boolean ignore = miniGames.getDropperConfiguration().ignoreRecordsUntilGroupBeatenOnce();
DropperArenaGroup group = miniGames.getDropperArenaHandler().getGroup(this.arena.getArenaId());
if (!ignore || group == null || group.hasBeatenAll(this.gameMode, this.player)) {
registerRecord();
}
// Mark the arena as cleared
if (this.arena.getData().addCompleted(this.gameMode, this.player)) {
if (this.arena.getData().setCompleted(this.gameMode, this.player)) {
this.player.sendMessage("You cleared the arena!");
}
this.player.sendMessage("You won!");
@ -107,9 +107,9 @@ 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.getUniqueId());
boolean removedSession = MiniGames.getInstance().getDropperArenaPlayerRegistry().removePlayer(player.getUniqueId());
if (!removedSession) {
Dropper.log(Level.SEVERE, "Unable to remove dropper arena session for " + player.getName() + ". " +
MiniGames.log(Level.SEVERE, "Unable to remove dropper arena session for " + player.getName() + ". " +
"This will have unintended consequences.");
}
}

View File

@ -1,11 +1,11 @@
package net.knarcraft.dropper.arena;
package net.knarcraft.dropper.arena.dropper;
import org.jetbrains.annotations.NotNull;
/**
* A representation of each key used for storing arena data
*/
public enum ArenaStorageKey {
public enum DropperArenaStorageKey {
/**
* The key for an arena's id
@ -55,7 +55,7 @@ public enum ArenaStorageKey {
*
* @param key <p>The string path of the configuration key this value represents.</p>
*/
ArenaStorageKey(@NotNull String key) {
DropperArenaStorageKey(@NotNull String key) {
this.key = key;
}

View File

@ -1,4 +1,4 @@
package net.knarcraft.dropper.arena;
package net.knarcraft.dropper.arena.dropper;
import org.bukkit.GameMode;
import org.bukkit.Location;
@ -10,7 +10,7 @@ import org.jetbrains.annotations.NotNull;
/**
* The state of a player before entering a dropper arena
*/
public class PlayerEntryState {
public class DropperPlayerEntryState {
private final Player player;
private final Location entryLocation;
@ -23,14 +23,14 @@ public class PlayerEntryState {
private final boolean originalCollideAble;
private final boolean makePlayerInvisible;
private final boolean disableHitCollision;
private final ArenaGameMode arenaGameMode;
private final DropperArenaGameMode arenaGameMode;
/**
* Instantiates a new player state
*
* @param player <p>The player whose state should be stored</p>
*/
public PlayerEntryState(@NotNull Player player, @NotNull ArenaGameMode arenaGameMode, boolean makePlayerInvisible,
public DropperPlayerEntryState(@NotNull Player player, @NotNull DropperArenaGameMode arenaGameMode, boolean makePlayerInvisible,
boolean disableHitCollision) {
this.player = player;
this.entryLocation = player.getLocation().clone();
@ -65,7 +65,7 @@ public class PlayerEntryState {
}
// If playing on the inverted game-mode, negate the horizontal velocity to swap the controls
if (arenaGameMode == ArenaGameMode.INVERTED) {
if (arenaGameMode == DropperArenaGameMode.INVERTED) {
this.player.setFlySpeed(-horizontalVelocity);
} else {
this.player.setFlySpeed(horizontalVelocity);

View File

@ -0,0 +1,284 @@
package net.knarcraft.dropper.arena.parkour;
import net.knarcraft.dropper.util.StringSanitizer;
import org.bukkit.Location;
import org.bukkit.Material;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import static net.knarcraft.dropper.util.InputValidationHelper.isInvalid;
/**
* A representation of one dropper arena
*/
public class ParkourArena {
/**
* An unique and persistent identifier for this arena
*/
private final UUID arenaId;
/**
* A name used when listing and storing this arena.
*/
private @NotNull String arenaName;
/**
* The location players are teleported to when joining this arena.
*/
private @NotNull Location spawnLocation;
/**
* The location players will be sent to when they win or lose the arena. If not set, their entry location should be
* used instead.
*/
private @Nullable Location exitLocation;
/**
* The material of the block players have to hit to win this dropper arena
*/
private @NotNull Material winBlockType;
/**
* The location the player has to reach to win. If not set, winBlockType is used instead
*/
private @Nullable Location winLocation;
/**
* The checkpoints for this arena. Entering a checkpoint overrides the player's spawn location.
*/
private @Nullable List<Location> checkpoints;
/**
* The arena data for this arena
*/
private final ParkourArenaData parkourArenaData;
private final ParkourArenaHandler parkourArenaHandler;
/**
* Instantiates a new dropper arena
*
* @param arenaId <p>The id of the arena</p>
* @param arenaName <p>The name of the arena</p>
* @param spawnLocation <p>The location players spawn in when entering the arena</p>
* @param exitLocation <p>The location the players are teleported to when exiting the arena, or null</p>
* @param winBlockType <p>The material of the block players have to hit to win this dropper arena</p>
* @param parkourArenaData <p>The arena data keeping track of which players have done what in this arena</p>
* @param arenaHandler <p>The arena handler used for saving any changes</p>
*/
public ParkourArena(@NotNull UUID arenaId, @NotNull String arenaName, @NotNull Location spawnLocation,
@Nullable Location exitLocation, @NotNull Material winBlockType,
@NotNull ParkourArenaData parkourArenaData, @NotNull ParkourArenaHandler arenaHandler) {
this.arenaId = arenaId;
this.arenaName = arenaName;
this.spawnLocation = spawnLocation;
this.exitLocation = exitLocation;
this.winBlockType = winBlockType;
this.parkourArenaData = parkourArenaData;
this.parkourArenaHandler = arenaHandler;
}
/**
* Instantiates a new dropper arena
*
* <p>Note that this minimal constructor can be used to quickly create a new dropper arena at the player's given
* location, simply by them giving an arena name.</p>
*
* @param arenaName <p>The name of the arena</p>
* @param spawnLocation <p>The location players spawn in when entering the arena</p>
* @param arenaHandler <p>The arena handler used for saving any changes</p>
*/
public ParkourArena(@NotNull String arenaName, @NotNull Location spawnLocation,
@NotNull ParkourArenaHandler arenaHandler) {
this.arenaId = UUID.randomUUID();
this.arenaName = arenaName;
this.spawnLocation = spawnLocation;
this.exitLocation = null;
this.winLocation = null;
Map<ParkourArenaGameMode, ParkourArenaRecordsRegistry> recordRegistries = new HashMap<>();
for (ParkourArenaGameMode arenaGameMode : ParkourArenaGameMode.values()) {
recordRegistries.put(arenaGameMode, new ParkourArenaRecordsRegistry(this.arenaId));
}
this.parkourArenaData = new ParkourArenaData(this.arenaId, recordRegistries, new HashMap<>());
this.winBlockType = Material.EMERALD_BLOCK;
this.parkourArenaHandler = arenaHandler;
}
/**
* Gets this arena's data
*
* @return <p>This arena's data</p>
*/
public @NotNull ParkourArenaData getData() {
return this.parkourArenaData;
}
/**
* Gets the id of this arena
*
* @return <p>This arena's identifier</p>
*/
public @NotNull UUID getArenaId() {
return this.arenaId;
}
/**
* Gets the name of this arena
*
* @return <p>The name of this arena</p>
*/
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>
*/
public @NotNull Location getSpawnLocation() {
return this.spawnLocation;
}
/**
* Gets this arena's exit location
*
* @return <p>This arena's exit location, or null if no such location is set.</p>
*/
public @Nullable Location getExitLocation() {
return this.exitLocation;
}
/**
* Gets the type of block a player has to hit to win this arena
*
* @return <p>The kind of block players must hit</p>
*/
public @NotNull Material getWinBlockType() {
return this.winBlockType;
}
/**
* The location a player has to reach to win this arena
*
* <p></p>
*
* @return <p>The win trigger's location</p>
*/
public @Nullable Location getWinLocation() {
return this.winLocation != null ? this.winLocation.clone() : null;
}
/**
* Gets this arena's sanitized name
*
* @return <p>This arena's sanitized name</p>
*/
public @NotNull String getArenaNameSanitized() {
return StringSanitizer.sanitizeArenaName(this.getArenaName());
}
/**
* Sets the spawn location for this arena
*
* @param newLocation <p>The new spawn location</p>
* @return <p>True if successfully updated</p>
*/
public boolean setSpawnLocation(@NotNull Location newLocation) {
if (isInvalid(newLocation)) {
return false;
} else {
this.spawnLocation = newLocation;
parkourArenaHandler.saveArenas();
return true;
}
}
/**
* Sets the exit location for this arena
*
* @param newLocation <p>The new exit location</p>
* @return <p>True if successfully updated</p>
*/
public boolean setExitLocation(@NotNull Location newLocation) {
if (isInvalid(newLocation)) {
return false;
} else {
this.exitLocation = newLocation;
parkourArenaHandler.saveArenas();
return true;
}
}
/**
* Sets the name of this arena
*
* @param arenaName <p>The new name</p>
* @return <p>True if successfully updated</p>
*/
public boolean setName(@NotNull String arenaName) {
if (!arenaName.isBlank()) {
String oldName = this.getArenaNameSanitized();
this.arenaName = arenaName;
// Update the arena lookup map to make sure the new name can be used immediately
parkourArenaHandler.updateLookupName(oldName, this.getArenaNameSanitized());
parkourArenaHandler.saveArenas();
return true;
} else {
return false;
}
}
/**
* Sets the material of the win block type
*
* <p>The win block type is the type of block a player must hit to win in this arena</p>
*
* @param material <p>The material to set for the win block type</p>
* @return <p>True if successfully updated</p>
*/
public boolean setWinBlockType(@NotNull Material material) {
if (material.isAir() || !material.isBlock()) {
return false;
} else {
this.winBlockType = material;
parkourArenaHandler.saveArenas();
return true;
}
}
/**
* Sets the location players need to reach to win this arena
*
* @param newLocation <p>The location players have to reach</p>
* @return <p>True if successfully changed</p>
*/
public boolean setWinLocation(@NotNull Location newLocation) {
if (isInvalid(newLocation)) {
return false;
} else {
this.exitLocation = newLocation;
parkourArenaHandler.saveArenas();
return true;
}
}
@Override
public boolean equals(Object other) {
if (!(other instanceof ParkourArena otherArena)) {
return false;
}
return this.getArenaNameSanitized().equals(otherArena.getArenaNameSanitized());
}
}

View File

@ -1,6 +1,6 @@
package net.knarcraft.dropper.arena;
package net.knarcraft.dropper.arena.parkour;
import net.knarcraft.dropper.Dropper;
import net.knarcraft.dropper.MiniGames;
import net.knarcraft.dropper.container.SerializableUUID;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.bukkit.entity.Player;
@ -17,22 +17,22 @@ import java.util.UUID;
*
* @param arenaId <p>The id of the arena this data belongs to</p>
* @param recordRegistries <p>The records belonging to the arena</p>
* @param playersCompleted <p>A list of all player that have completed this arena</p>
* @param playersCompleted <p>A set of all player that have completed this arena</p>
*/
public record DropperArenaData(@NotNull UUID arenaId,
@NotNull Map<ArenaGameMode, DropperArenaRecordsRegistry> recordRegistries,
@NotNull Map<ArenaGameMode, Set<UUID>> playersCompleted) implements ConfigurationSerializable {
public record ParkourArenaData(@NotNull UUID arenaId,
@NotNull Map<ParkourArenaGameMode, ParkourArenaRecordsRegistry> recordRegistries,
@NotNull Map<ParkourArenaGameMode, Set<UUID>> playersCompleted) implements ConfigurationSerializable {
/**
* Instantiates a new dropper arena data object
*
* @param arenaId <p>The id of the arena this data belongs to</p>
* @param recordRegistries <p>The registries of this arena's records</p>
* @param playersCompleted <p>The set of the players that have cleared this arena for each game-mode</p>
* @param recordRegistries <p>The registry of this arena's records</p>
* @param playersCompleted <p>The set of the players that have cleared this arena</p>
*/
public DropperArenaData(@NotNull UUID arenaId,
@NotNull Map<ArenaGameMode, DropperArenaRecordsRegistry> recordRegistries,
@NotNull Map<ArenaGameMode, Set<UUID>> playersCompleted) {
public ParkourArenaData(@NotNull UUID arenaId,
@NotNull Map<ParkourArenaGameMode, ParkourArenaRecordsRegistry> recordRegistries,
@NotNull Map<ParkourArenaGameMode, Set<UUID>> playersCompleted) {
this.arenaId = arenaId;
this.recordRegistries = recordRegistries;
this.playersCompleted = new HashMap<>(playersCompleted);
@ -41,20 +41,20 @@ public record DropperArenaData(@NotNull UUID arenaId,
/**
* Gets whether the given player has cleared this arena
*
* @param arenaGameMode <p>The game-mode to check for</p>
* @param player <p>The player to check</p>
* @return <p>True if the player has cleared the arena this data belongs to</p>
*/
public boolean hasNotCompleted(@NotNull ArenaGameMode arenaGameMode, @NotNull Player player) {
public boolean hasNotCompleted(@NotNull ParkourArenaGameMode arenaGameMode, @NotNull Player player) {
return !this.playersCompleted.getOrDefault(arenaGameMode, new HashSet<>()).contains(player.getUniqueId());
}
/**
* Registers the given player as having completed this arena
*
* @param arenaGameMode <p>The game-mode the player completed</p>
* @param player <p>The player that completed this data's arena</p>
*/
public boolean addCompleted(@NotNull ArenaGameMode arenaGameMode, @NotNull Player player) {
public boolean addCompleted(@NotNull ParkourArenaGameMode arenaGameMode, @NotNull Player player) {
// Make sure to add an empty set to prevent a NullPointerException
if (!this.playersCompleted.containsKey(arenaGameMode)) {
this.playersCompleted.put(arenaGameMode, new HashSet<>());
@ -63,7 +63,7 @@ public record DropperArenaData(@NotNull UUID arenaId,
boolean added = this.playersCompleted.get(arenaGameMode).add(player.getUniqueId());
// Persistently save the completion
if (added) {
Dropper.getInstance().getArenaHandler().saveData(this.arenaId);
MiniGames.getInstance().getDropperArenaHandler().saveData(this.arenaId);
}
return added;
}
@ -76,8 +76,8 @@ public record DropperArenaData(@NotNull UUID arenaId,
data.put("recordsRegistry", this.recordRegistries);
// Convert normal UUIDs to serializable UUIDs
Map<ArenaGameMode, Set<SerializableUUID>> serializablePlayersCompleted = new HashMap<>();
for (ArenaGameMode arenaGameMode : this.playersCompleted.keySet()) {
Map<ParkourArenaGameMode, Set<SerializableUUID>> serializablePlayersCompleted = new HashMap<>();
for (ParkourArenaGameMode arenaGameMode : this.playersCompleted.keySet()) {
Set<SerializableUUID> playersCompleted = new HashSet<>();
for (UUID playerCompleted : this.playersCompleted.get(arenaGameMode)) {
playersCompleted.add(new SerializableUUID(playerCompleted));
@ -95,12 +95,12 @@ public record DropperArenaData(@NotNull UUID arenaId,
* @return <p>The deserialized dropper arena data</p>
*/
@SuppressWarnings({"unused", "unchecked"})
public static @NotNull DropperArenaData deserialize(@NotNull Map<String, Object> data) {
public static @NotNull ParkourArenaData deserialize(@NotNull Map<String, Object> data) {
SerializableUUID serializableUUID = (SerializableUUID) data.get("arenaId");
Map<ArenaGameMode, DropperArenaRecordsRegistry> recordsRegistry =
(Map<ArenaGameMode, DropperArenaRecordsRegistry>) data.get("recordsRegistry");
Map<ArenaGameMode, Set<SerializableUUID>> playersCompletedData =
(Map<ArenaGameMode, Set<SerializableUUID>>) data.get("playersCompleted");
Map<ParkourArenaGameMode, ParkourArenaRecordsRegistry> recordsRegistry =
(Map<ParkourArenaGameMode, ParkourArenaRecordsRegistry>) data.get("recordsRegistry");
Map<ParkourArenaGameMode, Set<SerializableUUID>> playersCompletedData =
(Map<ParkourArenaGameMode, Set<SerializableUUID>>) data.get("playersCompleted");
if (recordsRegistry == null) {
recordsRegistry = new HashMap<>();
@ -109,8 +109,8 @@ public record DropperArenaData(@NotNull UUID arenaId,
}
// Convert the serializable UUIDs to normal UUIDs
Map<ArenaGameMode, Set<UUID>> allPlayersCompleted = new HashMap<>();
for (ArenaGameMode arenaGameMode : playersCompletedData.keySet()) {
Map<ParkourArenaGameMode, Set<UUID>> allPlayersCompleted = new HashMap<>();
for (ParkourArenaGameMode arenaGameMode : playersCompletedData.keySet()) {
Set<UUID> playersCompleted = new HashSet<>();
for (SerializableUUID completedId : playersCompletedData.get(arenaGameMode)) {
playersCompleted.add(completedId.uuid());
@ -118,10 +118,10 @@ public record DropperArenaData(@NotNull UUID arenaId,
allPlayersCompleted.put(arenaGameMode, playersCompleted);
if (!recordsRegistry.containsKey(arenaGameMode) || recordsRegistry.get(arenaGameMode) == null) {
recordsRegistry.put(arenaGameMode, new DropperArenaRecordsRegistry(serializableUUID.uuid()));
recordsRegistry.put(arenaGameMode, new ParkourArenaRecordsRegistry(serializableUUID.uuid()));
}
}
return new DropperArenaData(serializableUUID.uuid(), recordsRegistry, allPlayersCompleted);
return new ParkourArenaData(serializableUUID.uuid(), recordsRegistry, allPlayersCompleted);
}
}

View File

@ -0,0 +1,50 @@
package net.knarcraft.dropper.arena.parkour;
import net.knarcraft.dropper.arena.ArenaGameMode;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.Map;
/**
* A representation of possible arena game-modes
*/
public enum ParkourArenaGameMode implements ConfigurationSerializable, ArenaGameMode {
/**
* The default game-mode. Failing once throws the player out.
*/
DEFAULT,
;
/**
* Tries to match the correct game-mode according to the given string
*
* @param gameMode <p>The game-mode string to match</p>
* @return <p>The specified arena game-mode</p>
*/
public static @NotNull ParkourArenaGameMode matchGamemode(@NotNull String gameMode) {
return ParkourArenaGameMode.DEFAULT;
}
@NotNull
@Override
public Map<String, Object> serialize() {
Map<String, Object> data = new HashMap<>();
data.put("name", this.name());
return data;
}
/**
* Deserializes the arena game-mode specified by the given data
*
* @param data <p>The data to deserialize</p>
* @return <p>The deserialized arena game-mode</p>
*/
@SuppressWarnings("unused")
public static ParkourArenaGameMode deserialize(Map<String, Object> data) {
return ParkourArenaGameMode.valueOf((String) data.get("name"));
}
}

View File

@ -0,0 +1,122 @@
package net.knarcraft.dropper.arena.parkour;
import net.knarcraft.dropper.MiniGames;
import net.knarcraft.dropper.arena.ArenaGroup;
import net.knarcraft.dropper.container.SerializableUUID;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.logging.Level;
/**
* A sorted group of arenas that must be completed in sequence
*/
public class ParkourArenaGroup extends ArenaGroup {
/**
* Instantiates a new dropper arena group
*
* @param groupName <p>The name of this group</p>
*/
public ParkourArenaGroup(@NotNull String groupName) {
super(groupName);
}
/**
* Instantiates a new dropper arena group
*
* @param groupId <p>The unique id of this group</p>
* @param groupName <p>The name of this group</p>
* @param arenas <p>The arenas in this group</p>
*/
private ParkourArenaGroup(@NotNull UUID groupId, @NotNull String groupName, @NotNull List<UUID> arenas) {
super(groupId, groupName, arenas);
}
/**
* Checks whether the given player has beaten all arenas in this group on the given game-mode
*
* @param gameMode <p>The game-mode to check</p>
* @param player <p>The player to check</p>
* @return <p>True if the player has beaten all arenas, false otherwise</p>
*/
public boolean hasBeatenAll(ParkourArenaGameMode gameMode, Player player) {
ParkourArenaHandler arenaHandler = MiniGames.getInstance().getParkourArenaHandler();
for (UUID anArenaId : this.getArenas()) {
ParkourArena dropperArena = arenaHandler.getArena(anArenaId);
if (dropperArena == null) {
// The arena would only be null if the arena has been deleted, but not removed from this group
MiniGames.log(Level.WARNING, "The dropper group " + this.getGroupName() +
" contains the arena id " + anArenaId + " which is not a valid arena id!");
continue;
}
if (dropperArena.getData().hasNotCompleted(gameMode, player)) {
return false;
}
}
return true;
}
/**
* Gets whether the given player can play the given arena part of this group, on the given game-mode
*
* @param gameMode <p>The game-mode the player is trying to play</p>
* @param player <p>The player to check</p>
* @param arenaId <p>The id of the arena in this group to check</p>
* @return <p>True if the player is allowed to play the arena</p>
* @throws IllegalArgumentException <p>If checking an arena not in this group</p>
*/
public boolean canPlay(ParkourArenaGameMode gameMode, Player player, UUID arenaId) throws IllegalArgumentException {
if (!this.arenas.contains(arenaId)) {
throw new IllegalArgumentException("Cannot check for playability for arena not in this group!");
}
ParkourArenaHandler arenaHandler = MiniGames.getInstance().getParkourArenaHandler();
for (UUID anArenaId : this.getArenas()) {
// If the target arena is reached, allow, as all previous arenas must have been cleared
if (arenaId.equals(anArenaId)) {
return true;
}
ParkourArena parkourArena = arenaHandler.getArena(anArenaId);
if (parkourArena == null) {
// The arena would only be null if the arena has been deleted, but not removed from this group
MiniGames.log(Level.WARNING, String.format("The dropper group %s contains the" +
" arena id %s which is not a valid arena id!", this.getGroupName(), anArenaId));
continue;
}
// This is a lower-numbered arena the player has yet to complete
if (parkourArena.getData().hasNotCompleted(gameMode, player)) {
return false;
}
}
return false;
}
/**
* Deserializes the given data
*
* @param data <p>The data to deserialize</p>
* @return <p>The deserialized arena group</p>
*/
@SuppressWarnings({"unused", "unchecked"})
public static @NotNull ParkourArenaGroup deserialize(@NotNull Map<String, Object> data) {
UUID id = ((SerializableUUID) data.get("groupId")).uuid();
String name = (String) data.get("groupName");
List<SerializableUUID> serializableArenas = (List<SerializableUUID>) data.get("arenas");
List<UUID> arenas = new ArrayList<>();
for (SerializableUUID arenaId : serializableArenas) {
arenas.add(arenaId.uuid());
}
return new ParkourArenaGroup(id, name, arenas);
}
}

View File

@ -0,0 +1,249 @@
package net.knarcraft.dropper.arena.parkour;
import net.knarcraft.dropper.MiniGames;
import net.knarcraft.dropper.util.ArenaStorageHelper;
import net.knarcraft.dropper.util.StringSanitizer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Level;
/**
* A handler that keeps track of all dropper arenas
*/
public class ParkourArenaHandler {
private Map<UUID, ParkourArena> arenas = new HashMap<>();
private Map<UUID, ParkourArenaGroup> arenaGroups = new HashMap<>();
private Map<String, UUID> arenaNameLookup = new HashMap<>();
/**
* Gets all arenas that are within a group
*
* @return <p>All arenas in a group</p>
*/
public @NotNull Set<ParkourArena> getArenasInAGroup() {
Set<ParkourArena> arenas = new HashSet<>();
for (UUID arenaId : arenaGroups.keySet()) {
arenas.add(this.arenas.get(arenaId));
}
return arenas;
}
/**
* Gets a copy of all dropper groups
*
* @return <p>All dropper groups</p>
*/
public Set<ParkourArenaGroup> getAllGroups() {
return new HashSet<>(arenaGroups.values());
}
/**
* Gets the group the given arena belongs to
*
* @param arenaId <p>The id of the arena to get the group of</p>
* @return <p>The group the arena belongs to, or null if not in a group</p>
*/
public @Nullable ParkourArenaGroup getGroup(@NotNull UUID arenaId) {
return this.arenaGroups.get(arenaId);
}
/**
* Sets the group for the given arena
*
* @param arenaId <p>The id of the arena to change</p>
* @param arenaGroup <p>The group to add the arena to, or null to remove the current group</p>
*/
public void setGroup(@NotNull UUID arenaId, @Nullable ParkourArenaGroup arenaGroup) {
if (arenaGroup == null) {
// No need to remove something non-existing
if (!this.arenaGroups.containsKey(arenaId)) {
return;
}
// Remove the existing group
ParkourArenaGroup oldGroup = this.arenaGroups.remove(arenaId);
oldGroup.removeArena(arenaId);
} else {
// Make sure to remove the arena from the old group's internal tracking
if (this.arenaGroups.containsKey(arenaId)) {
this.arenaGroups.remove(arenaId).removeArena(arenaId);
}
this.arenaGroups.put(arenaId, arenaGroup);
arenaGroup.addArena(arenaId);
}
saveGroups();
}
/**
* Gets the dropper arena group with the given name
*
* @param groupName <p>The name of the group to get</p>
* @return <p>The group, or null if not found</p>
*/
public @Nullable ParkourArenaGroup getGroup(String groupName) {
String sanitized = StringSanitizer.sanitizeArenaName(groupName);
for (ParkourArenaGroup arenaGroup : this.arenaGroups.values()) {
if (arenaGroup.getGroupNameSanitized().equals(sanitized)) {
return arenaGroup;
}
}
return null;
}
/**
* Replaces an arena's lookup name
*
* @param oldName <p>The arena's old sanitized lookup name</p>
* @param newName <p>The arena's new sanitized lookup name</p>
*/
public void updateLookupName(@NotNull String oldName, @NotNull String newName) {
UUID arenaId = this.arenaNameLookup.remove(oldName);
if (arenaId != null) {
this.arenaNameLookup.put(newName, arenaId);
}
}
/**
* Adds a new arena
*
* @param arena <p>The arena to add</p>
*/
public void addArena(@NotNull ParkourArena arena) {
this.arenas.put(arena.getArenaId(), arena);
this.arenaNameLookup.put(arena.getArenaNameSanitized(), arena.getArenaId());
this.saveArenas();
}
/**
* Gets the arena with the given id
*
* @param arenaId <p>The id of the arena to get</p>
* @return <p>The arena, or null if no arena could be found</p>
*/
public @Nullable ParkourArena getArena(@NotNull UUID arenaId) {
return this.arenas.get(arenaId);
}
/**
* Gets the arena with the given name
*
* @param arenaName <p>The arena to get</p>
* @return <p>The arena with the given name, or null if not found</p>
*/
public @Nullable ParkourArena getArena(@NotNull String arenaName) {
return this.arenas.get(this.arenaNameLookup.get(StringSanitizer.sanitizeArenaName(arenaName)));
}
/**
* Gets all known arenas
*
* @return <p>All known arenas</p>
*/
public @NotNull Map<UUID, ParkourArena> getArenas() {
return new HashMap<>(this.arenas);
}
/**
* Removes the given arena
*
* @param arena <p>The arena to remove</p>
*/
public void removeArena(@NotNull ParkourArena arena) {
UUID arenaId = arena.getArenaId();
MiniGames.getInstance().getParkourArenaPlayerRegistry().removeForArena(arena);
this.arenas.remove(arenaId);
this.arenaNameLookup.remove(arena.getArenaNameSanitized());
this.arenaGroups.remove(arenaId);
if (!ArenaStorageHelper.removeDropperArenaData(arenaId)) {
MiniGames.log(Level.WARNING, "Unable to remove dropper arena data file " + arenaId + ".yml. " +
"You must remove it manually!");
}
this.saveArenas();
}
/**
* Stores the data for the given arena
*
* @param arenaId <p>The id of the arena whose data should be saved</p>
*/
public void saveData(UUID arenaId) {
try {
ArenaStorageHelper.saveParkourArenaData(this.arenas.get(arenaId).getData());
} catch (IOException e) {
MiniGames.log(Level.SEVERE, "Unable to save arena data! Data loss can occur!");
MiniGames.log(Level.SEVERE, e.getMessage());
}
}
/**
* Saves all current dropper groups to disk
*/
public void saveGroups() {
try {
ArenaStorageHelper.saveParkourArenaGroups(new HashSet<>(this.arenaGroups.values()));
} catch (IOException e) {
MiniGames.log(Level.SEVERE, "Unable to save current arena groups! " +
"Data loss can occur!");
MiniGames.log(Level.SEVERE, e.getMessage());
}
}
/**
* Loads all arenas and groups from disk
*/
public void load() {
loadArenas();
loadGroups();
}
/**
* Loads all dropper groups from disk
*/
private void loadGroups() {
Set<ParkourArenaGroup> arenaGroups = ArenaStorageHelper.loadParkourArenaGroups();
Map<UUID, ParkourArenaGroup> arenaGroupMap = new HashMap<>();
for (ParkourArenaGroup arenaGroup : arenaGroups) {
for (UUID arenaId : arenaGroup.getArenas()) {
arenaGroupMap.put(arenaId, arenaGroup);
}
}
this.arenaGroups = arenaGroupMap;
}
/**
* Saves all current arenas to disk
*/
public void saveArenas() {
try {
ArenaStorageHelper.saveParkourArenas(this.arenas);
} catch (IOException e) {
MiniGames.log(Level.SEVERE, "Unable to save current arenas! " +
"Data loss can occur!");
MiniGames.log(Level.SEVERE, e.getMessage());
}
}
/**
* Loads all arenas from disk
*/
private void loadArenas() {
this.arenas = ArenaStorageHelper.loadParkourArenas();
// Save a map from arena name to arena id for improved performance
this.arenaNameLookup = new HashMap<>();
for (Map.Entry<UUID, ParkourArena> arena : this.arenas.entrySet()) {
String sanitizedName = arena.getValue().getArenaNameSanitized();
this.arenaNameLookup.put(sanitizedName, arena.getKey());
}
}
}

View File

@ -0,0 +1,61 @@
package net.knarcraft.dropper.arena.parkour;
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 ParkourArenaPlayerRegistry {
private final Map<UUID, ParkourArenaSession> arenaPlayers = new HashMap<>();
/**
* Registers that the given player has started playing the given parkour arena session
*
* @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 UUID playerId, @NotNull ParkourArenaSession arena) {
this.arenaPlayers.put(playerId, arena);
}
/**
* Removes this player from players currently playing
*
* @param playerId <p>The id of the player to remove</p>
*/
public boolean removePlayer(@NotNull UUID playerId) {
return this.arenaPlayers.remove(playerId) != null;
}
/**
* Gets the player's active parkour arena session
*
* @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 ParkourArenaSession getArenaSession(@NotNull UUID playerId) {
return this.arenaPlayers.getOrDefault(playerId, null);
}
/**
* Removes all active sessions for the given arena
*
* @param arena <p>The arena to remove sessions for</p>
*/
public void removeForArena(ParkourArena arena) {
for (Map.Entry<UUID, ParkourArenaSession> entry : this.arenaPlayers.entrySet()) {
if (entry.getValue().getArena() == arena) {
// Kick the player gracefully
entry.getValue().triggerQuit(false);
this.arenaPlayers.remove(entry.getKey());
}
}
}
}

View File

@ -0,0 +1,198 @@
package net.knarcraft.dropper.arena.parkour;
import net.knarcraft.dropper.MiniGames;
import net.knarcraft.dropper.arena.record.ArenaRecord;
import net.knarcraft.dropper.arena.record.IntegerRecord;
import net.knarcraft.dropper.arena.record.LongRecord;
import net.knarcraft.dropper.arena.record.SummableArenaRecord;
import net.knarcraft.dropper.container.SerializableUUID;
import net.knarcraft.dropper.property.RecordResult;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
/**
* A registry keeping track of all records
*/
public class ParkourArenaRecordsRegistry implements ConfigurationSerializable {
private final UUID arenaId;
private final @NotNull Set<IntegerRecord> leastDeaths;
private final @NotNull Set<LongRecord> shortestTimeMilliSeconds;
/**
* Instantiates a new empty records registry
*/
public ParkourArenaRecordsRegistry(@NotNull UUID arenaId) {
this.arenaId = arenaId;
this.leastDeaths = new HashSet<>();
this.shortestTimeMilliSeconds = new HashSet<>();
}
/**
* Instantiates a new records registry
*
* @param leastDeaths <p>The existing least death records to use</p>
* @param shortestTimeMilliSeconds <p>The existing leash time records to use</p>
*/
private ParkourArenaRecordsRegistry(@NotNull UUID arenaId, @NotNull Set<IntegerRecord> leastDeaths,
@NotNull Set<LongRecord> shortestTimeMilliSeconds) {
this.arenaId = arenaId;
this.leastDeaths = new HashSet<>(leastDeaths);
this.shortestTimeMilliSeconds = new HashSet<>(shortestTimeMilliSeconds);
}
/**
* Gets all existing death records
*
* @return <p>Existing death records</p>
*/
public Set<SummableArenaRecord<Integer>> getLeastDeathsRecords() {
return new HashSet<>(this.leastDeaths);
}
/**
* Gets all existing time records
*
* @return <p>Existing time records</p>
*/
public Set<SummableArenaRecord<Long>> getShortestTimeMilliSecondsRecords() {
return new HashSet<>(this.shortestTimeMilliSeconds);
}
/**
* Registers a new deaths-record
*
* @param playerId <p>The id of the player that performed the records</p>
* @param deaths <p>The number of deaths suffered before the player finished the arena</p>
* @return <p>The result explaining what type of record was achieved</p>
*/
public @NotNull RecordResult registerDeathRecord(@NotNull UUID playerId, int deaths) {
Consumer<Integer> consumer = (value) -> {
leastDeaths.removeIf((item) -> item.getUserId().equals(playerId));
leastDeaths.add(new IntegerRecord(playerId, value));
};
Set<ArenaRecord<Integer>> asInt = new HashSet<>(leastDeaths);
return registerRecord(asInt, consumer, playerId, deaths);
}
/**
* Registers a new time-record
*
* @param playerId <p>The id of the player that performed the records</p>
* @param milliseconds <p>The number of milliseconds it took the player to finish the dropper arena</p>
* @return <p>The result explaining what type of record was achieved</p>
*/
public @NotNull RecordResult registerTimeRecord(@NotNull UUID playerId, long milliseconds) {
Consumer<Long> consumer = (value) -> {
shortestTimeMilliSeconds.removeIf((item) -> item.getUserId().equals(playerId));
shortestTimeMilliSeconds.add(new LongRecord(playerId, value));
};
Set<ArenaRecord<Long>> asLong = new HashSet<>(shortestTimeMilliSeconds);
return registerRecord(asLong, consumer, playerId, milliseconds);
}
/**
* Saves changed records
*/
private void save() {
MiniGames.getInstance().getDropperArenaHandler().saveData(this.arenaId);
}
/**
* Registers a new record if applicable
*
* @param existingRecords <p>The map of existing records to use</p>
* @param recordSetter <p>The consumer used to set a new record</p>
* @param playerId <p>The id of the player that potentially achieved a record</p>
* @param amount <p>The amount of whatever the player achieved</p>
* @return <p>The result of the player's record attempt</p>
*/
private <T extends Comparable<T>> @NotNull RecordResult registerRecord(@NotNull Set<ArenaRecord<T>> existingRecords,
@NotNull Consumer<T> recordSetter,
@NotNull UUID playerId, T amount) {
RecordResult result;
if (existingRecords.stream().allMatch((entry) -> amount.compareTo(entry.getRecord()) < 0)) {
// If the given value is less than all other values, that's a world record!
result = RecordResult.WORLD_RECORD;
recordSetter.accept(amount);
save();
return result;
}
ArenaRecord<T> playerRecord = getRecord(existingRecords, playerId);
if (playerRecord != null && amount.compareTo(playerRecord.getRecord()) < 0) {
// If the given value is less than the player's previous value, that's a personal best!
result = RecordResult.PERSONAL_BEST;
recordSetter.accept(amount);
save();
} else {
// Make sure to save the record if this is the user's first attempt
if (playerRecord == null) {
recordSetter.accept(amount);
save();
}
result = RecordResult.NONE;
}
return result;
}
/**
* Gets the record stored for the given player
*
* @param existingRecords <p>The existing records to look through</p>
* @param playerId <p>The id of the player to look for</p>
* @param <T> <p>The type of the stored record</p>
* @return <p>The record, or null if not found</p>
*/
private <T extends Comparable<T>> @Nullable ArenaRecord<T> getRecord(@NotNull Set<ArenaRecord<T>> existingRecords,
@NotNull UUID playerId) {
AtomicReference<ArenaRecord<T>> record = new AtomicReference<>();
existingRecords.forEach((item) -> {
if (item.getUserId().equals(playerId)) {
record.set(item);
}
});
return record.get();
}
@NotNull
@Override
public Map<String, Object> serialize() {
Map<String, Object> data = new HashMap<>();
data.put("arenaId", new SerializableUUID(this.arenaId));
data.put("leastDeaths", this.leastDeaths);
data.put("shortestTime", this.shortestTimeMilliSeconds);
return data;
}
/**
* Deserializes the given data
*
* @param data <p>The data to deserialize</p>
* @return <p>The deserialized records registry</p>
*/
@SuppressWarnings({"unused", "unchecked"})
public static ParkourArenaRecordsRegistry deserialize(Map<String, Object> data) {
UUID arenaId = ((SerializableUUID) data.get("arenaId")).uuid();
Set<IntegerRecord> leastDeaths =
(Set<IntegerRecord>) data.getOrDefault("leastDeaths", new HashMap<>());
Set<LongRecord> shortestTimeMilliseconds =
(Set<LongRecord>) data.getOrDefault("shortestTime", new HashMap<>());
leastDeaths.removeIf(Objects::isNull);
shortestTimeMilliseconds.removeIf(Objects::isNull);
return new ParkourArenaRecordsRegistry(arenaId, leastDeaths, shortestTimeMilliseconds);
}
}

View File

@ -0,0 +1,193 @@
package net.knarcraft.dropper.arena.parkour;
import net.knarcraft.dropper.MiniGames;
import net.knarcraft.dropper.config.DropperConfiguration;
import net.knarcraft.dropper.property.RecordResult;
import net.knarcraft.dropper.util.PlayerTeleporter;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.logging.Level;
/**
* A representation of a player's current session in a dropper arena
*/
public class ParkourArenaSession {
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;
/**
* Instantiates a new parkour arena session
*
* @param dropperArena <p>The arena that's being played in</p>
* @param player <p>The player playing the arena</p>
* @param gameMode <p>The game-mode</p>
*/
public ParkourArenaSession(@NotNull ParkourArena dropperArena, @NotNull Player player,
@NotNull ParkourArenaGameMode gameMode) {
this.arena = dropperArena;
this.player = player;
this.gameMode = gameMode;
this.deaths = 0;
this.startTime = System.currentTimeMillis();
DropperConfiguration configuration = MiniGames.getInstance().getDropperConfiguration();
boolean makeInvisible = configuration.makePlayersInvisible();
this.entryState = new ParkourPlayerEntryState(player, makeInvisible);
// Make the player fly to improve mobility in the air
this.entryState.setArenaState();
}
/**
* Gets the state of the player when they joined the session
*
* @return <p>The player's entry state</p>
*/
public @NotNull ParkourPlayerEntryState getEntryState() {
return this.entryState;
}
/**
* Triggers a win for the player playing in this session
*/
public void triggerWin() {
// Stop this session
stopSession();
// Check for, and display, records
MiniGames miniGames = MiniGames.getInstance();
boolean ignore = miniGames.getDropperConfiguration().ignoreRecordsUntilGroupBeatenOnce();
ParkourArenaGroup group = miniGames.getParkourArenaHandler().getGroup(this.arena.getArenaId());
if (!ignore || group == null || group.hasBeatenAll(this.gameMode, this.player)) {
registerRecord();
}
// Mark the arena as cleared
if (this.arena.getData().addCompleted(this.gameMode, this.player)) {
this.player.sendMessage("You cleared the arena!");
}
this.player.sendMessage("You won!");
// Teleport the player out of the arena
teleportToExit(false);
}
/**
* Teleports the playing player out of the arena
*/
private void teleportToExit(boolean immediately) {
// Teleport the player out of the arena
Location exitLocation;
if (this.arena.getExitLocation() != null) {
exitLocation = this.arena.getExitLocation();
} else {
exitLocation = this.entryState.getEntryLocation();
}
PlayerTeleporter.teleportPlayer(this.player, exitLocation, true, immediately);
}
/**
* Removes this session from current sessions
*/
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());
if (!removedSession) {
MiniGames.log(Level.SEVERE, "Unable to remove dropper arena session for " + player.getName() + ". " +
"This will have unintended consequences.");
}
}
/**
* Registers the player's record if necessary, and prints record information to the player
*/
private void registerRecord() {
ParkourArenaRecordsRegistry recordsRegistry = this.arena.getData().recordRegistries().get(this.gameMode);
long timeElapsed = System.currentTimeMillis() - this.startTime;
announceRecord(recordsRegistry.registerTimeRecord(this.player.getUniqueId(), timeElapsed), "time");
announceRecord(recordsRegistry.registerDeathRecord(this.player.getUniqueId(), this.deaths), "least deaths");
}
/**
* Announces a record set by this player
*
* @param recordResult <p>The result of the record</p>
* @param type <p>The type of record set (time or deaths)</p>
*/
private void announceRecord(@NotNull RecordResult recordResult, @NotNull String type) {
if (recordResult == RecordResult.NONE) {
return;
}
// Gets a string representation of the played game-mode
String gameModeString = switch (this.gameMode) {
case DEFAULT -> "default";
};
String recordString = "You just set a %s on the %s game-mode!";
recordString = switch (recordResult) {
case WORLD_RECORD -> String.format(recordString, "new %s record", gameModeString);
case PERSONAL_BEST -> String.format(recordString, "personal %s record", gameModeString);
default -> throw new IllegalStateException("Unexpected value: " + recordResult);
};
player.sendMessage(String.format(recordString, type));
}
/**
* Triggers a loss for the player playing in this session
*/
public void triggerLoss() {
this.deaths++;
//Teleport the player back to the top
PlayerTeleporter.teleportPlayer(this.player, this.arena.getSpawnLocation(), true, false);
this.entryState.setArenaState();
}
/**
* Triggers a quit for the player playing in this session
*/
public void triggerQuit(boolean immediately) {
// Stop this session
stopSession();
// Teleport the player out of the arena
teleportToExit(immediately);
player.sendMessage("You quit the arena!");
}
/**
* Stops this session, and disables flight mode
*/
private void stopSession() {
// Remove this session from game sessions to stop listeners from fiddling more with the player
removeSession();
// Remove flight mode
entryState.restore();
}
/**
* Gets the arena this session is being played in
*
* @return <p>The session's arena</p>
*/
public @NotNull ParkourArena getArena() {
return this.arena;
}
/**
* Gets the player playing in this session
*
* @return <p>This session's player</p>
*/
public @NotNull Player getPlayer() {
return this.player;
}
}

View File

@ -0,0 +1,81 @@
package net.knarcraft.dropper.arena.parkour;
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 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;
/**
* Instantiates a new player state
*
* @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;
}
/**
* Sets the state of the stored player to the state used by arenas
*/
public void 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,8 +1,8 @@
package net.knarcraft.dropper.command;
import net.knarcraft.dropper.Dropper;
import net.knarcraft.dropper.arena.DropperArena;
import net.knarcraft.dropper.arena.DropperArenaHandler;
import net.knarcraft.dropper.MiniGames;
import net.knarcraft.dropper.arena.dropper.DropperArena;
import net.knarcraft.dropper.arena.dropper.DropperArenaHandler;
import net.knarcraft.dropper.util.StringSanitizer;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
@ -36,7 +36,7 @@ public class CreateArenaCommand implements CommandExecutor {
return false;
}
DropperArenaHandler arenaHandler = Dropper.getInstance().getArenaHandler();
DropperArenaHandler arenaHandler = MiniGames.getInstance().getDropperArenaHandler();
DropperArena existingArena = arenaHandler.getArena(arenaName);
if (existingArena != null) {

View File

@ -1,8 +1,8 @@
package net.knarcraft.dropper.command;
import net.knarcraft.dropper.Dropper;
import net.knarcraft.dropper.arena.ArenaEditableProperty;
import net.knarcraft.dropper.arena.DropperArena;
import net.knarcraft.dropper.MiniGames;
import net.knarcraft.dropper.arena.dropper.DropperArena;
import net.knarcraft.dropper.arena.dropper.DropperArenaEditableProperty;
import net.knarcraft.dropper.config.DropperConfiguration;
import org.bukkit.Location;
import org.bukkit.Material;
@ -40,13 +40,13 @@ public class EditArenaCommand implements CommandExecutor {
return false;
}
DropperArena specifiedArena = Dropper.getInstance().getArenaHandler().getArena(arguments[0]);
DropperArena specifiedArena = MiniGames.getInstance().getDropperArenaHandler().getArena(arguments[0]);
if (specifiedArena == null) {
commandSender.sendMessage("Unable to find the specified dropper arena.");
return false;
}
ArenaEditableProperty editableProperty = ArenaEditableProperty.getFromArgumentString(arguments[1]);
DropperArenaEditableProperty editableProperty = DropperArenaEditableProperty.getFromArgumentString(arguments[1]);
if (editableProperty == null) {
commandSender.sendMessage("Unknown property specified.");
return false;
@ -79,7 +79,7 @@ public class EditArenaCommand implements CommandExecutor {
* @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 DropperArena arena, @NotNull ArenaEditableProperty property,
private boolean changeValue(@NotNull DropperArena arena, @NotNull DropperArenaEditableProperty property,
@NotNull String value, @NotNull Player player) {
return switch (property) {
case WIN_BLOCK_TYPE -> arena.setWinBlockType(parseMaterial(value));

View File

@ -1,9 +1,9 @@
package net.knarcraft.dropper.command;
import net.knarcraft.dropper.Dropper;
import net.knarcraft.dropper.arena.DropperArena;
import net.knarcraft.dropper.arena.DropperArenaGroup;
import net.knarcraft.dropper.arena.DropperArenaHandler;
import net.knarcraft.dropper.MiniGames;
import net.knarcraft.dropper.arena.dropper.DropperArena;
import net.knarcraft.dropper.arena.dropper.DropperArenaGroup;
import net.knarcraft.dropper.arena.dropper.DropperArenaHandler;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabExecutor;
@ -22,7 +22,7 @@ public class GroupListCommand implements TabExecutor {
@Override
public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
@NotNull String[] arguments) {
DropperArenaHandler arenaHandler = Dropper.getInstance().getArenaHandler();
DropperArenaHandler arenaHandler = MiniGames.getInstance().getDropperArenaHandler();
if (arguments.length == 0) {
displayExistingGroups(arenaHandler, commandSender);
return true;
@ -81,7 +81,7 @@ public class GroupListCommand implements TabExecutor {
@NotNull String[] arguments) {
if (arguments.length == 1) {
List<String> groupNames = new ArrayList<>();
for (DropperArenaGroup group : Dropper.getInstance().getArenaHandler().getAllGroups()) {
for (DropperArenaGroup group : MiniGames.getInstance().getDropperArenaHandler().getAllGroups()) {
groupNames.add(group.getGroupName());
}
return groupNames;

View File

@ -1,9 +1,9 @@
package net.knarcraft.dropper.command;
import net.knarcraft.dropper.Dropper;
import net.knarcraft.dropper.arena.DropperArena;
import net.knarcraft.dropper.arena.DropperArenaGroup;
import net.knarcraft.dropper.arena.DropperArenaHandler;
import net.knarcraft.dropper.MiniGames;
import net.knarcraft.dropper.arena.dropper.DropperArena;
import net.knarcraft.dropper.arena.dropper.DropperArenaGroup;
import net.knarcraft.dropper.arena.dropper.DropperArenaHandler;
import net.knarcraft.dropper.util.StringSanitizer;
import net.knarcraft.dropper.util.TabCompleteHelper;
import org.bukkit.command.Command;
@ -27,7 +27,7 @@ public class GroupSetCommand implements TabExecutor {
return false;
}
DropperArenaHandler arenaHandler = Dropper.getInstance().getArenaHandler();
DropperArenaHandler arenaHandler = MiniGames.getInstance().getDropperArenaHandler();
DropperArena specifiedArena = arenaHandler.getArena(arguments[0]);
if (specifiedArena == null) {
@ -67,7 +67,7 @@ public class GroupSetCommand implements TabExecutor {
List<String> possibleValues = new ArrayList<>();
possibleValues.add("none");
possibleValues.add("GroupName");
for (DropperArenaGroup group : Dropper.getInstance().getArenaHandler().getAllGroups()) {
for (DropperArenaGroup group : MiniGames.getInstance().getDropperArenaHandler().getAllGroups()) {
possibleValues.add(group.getGroupName());
}
return possibleValues;

View File

@ -1,9 +1,9 @@
package net.knarcraft.dropper.command;
import net.knarcraft.dropper.Dropper;
import net.knarcraft.dropper.arena.DropperArena;
import net.knarcraft.dropper.arena.DropperArenaGroup;
import net.knarcraft.dropper.arena.DropperArenaHandler;
import net.knarcraft.dropper.MiniGames;
import net.knarcraft.dropper.arena.dropper.DropperArena;
import net.knarcraft.dropper.arena.dropper.DropperArenaGroup;
import net.knarcraft.dropper.arena.dropper.DropperArenaHandler;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabExecutor;
@ -26,7 +26,7 @@ public class GroupSwapCommand implements TabExecutor {
return false;
}
DropperArenaHandler arenaHandler = Dropper.getInstance().getArenaHandler();
DropperArenaHandler arenaHandler = MiniGames.getInstance().getDropperArenaHandler();
DropperArena arena1 = arenaHandler.getArena(arguments[0]);
if (arena1 == null) {
@ -57,7 +57,7 @@ public class GroupSwapCommand implements TabExecutor {
@Override
public List<String> onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
@NotNull String[] arguments) {
DropperArenaHandler arenaHandler = Dropper.getInstance().getArenaHandler();
DropperArenaHandler arenaHandler = MiniGames.getInstance().getDropperArenaHandler();
if (arguments.length == 1) {
List<String> arenaNames = new ArrayList<>();
for (DropperArena dropperArena : arenaHandler.getArenasInAGroup()) {
@ -78,7 +78,7 @@ public class GroupSwapCommand implements TabExecutor {
* @return <p>The names of the arenas in the same group</p>
*/
private List<String> getArenaNamesInSameGroup(String arenaName) {
DropperArenaHandler arenaHandler = Dropper.getInstance().getArenaHandler();
DropperArenaHandler arenaHandler = MiniGames.getInstance().getDropperArenaHandler();
DropperArena arena1 = arenaHandler.getArena(arenaName);
if (arena1 == null) {
return new ArrayList<>();

View File

@ -1,11 +1,11 @@
package net.knarcraft.dropper.command;
import net.knarcraft.dropper.Dropper;
import net.knarcraft.dropper.arena.ArenaGameMode;
import net.knarcraft.dropper.arena.DropperArena;
import net.knarcraft.dropper.arena.DropperArenaGroup;
import net.knarcraft.dropper.arena.DropperArenaPlayerRegistry;
import net.knarcraft.dropper.arena.DropperArenaSession;
import net.knarcraft.dropper.MiniGames;
import net.knarcraft.dropper.arena.dropper.DropperArena;
import net.knarcraft.dropper.arena.dropper.DropperArenaGameMode;
import net.knarcraft.dropper.arena.dropper.DropperArenaGroup;
import net.knarcraft.dropper.arena.dropper.DropperArenaPlayerRegistry;
import net.knarcraft.dropper.arena.dropper.DropperArenaSession;
import net.knarcraft.dropper.config.DropperConfiguration;
import net.knarcraft.dropper.util.PlayerTeleporter;
import org.bukkit.command.Command;
@ -32,14 +32,14 @@ public class JoinArenaCommand implements CommandExecutor {
}
// Disallow joining if the player is already in a dropper arena
DropperArenaSession existingSession = Dropper.getInstance().getPlayerRegistry().getArenaSession(player.getUniqueId());
DropperArenaSession existingSession = MiniGames.getInstance().getDropperArenaPlayerRegistry().getArenaSession(player.getUniqueId());
if (existingSession != null) {
commandSender.sendMessage("You are already in a dropper arena!");
return false;
}
// Make sure the arena exists
DropperArena specifiedArena = Dropper.getInstance().getArenaHandler().getArena(arguments[0]);
DropperArena specifiedArena = MiniGames.getInstance().getDropperArenaHandler().getArena(arguments[0]);
if (specifiedArena == null) {
commandSender.sendMessage("Unable to find the specified dropper arena.");
return false;
@ -64,30 +64,30 @@ public class JoinArenaCommand implements CommandExecutor {
*/
private boolean joinArena(DropperArena specifiedArena, Player player, String[] arguments) {
// Find the specified game-mode
ArenaGameMode gameMode;
DropperArenaGameMode gameMode;
if (arguments.length > 1) {
gameMode = ArenaGameMode.matchGamemode(arguments[1]);
gameMode = DropperArenaGameMode.matchGamemode(arguments[1]);
} else {
gameMode = ArenaGameMode.DEFAULT;
gameMode = DropperArenaGameMode.DEFAULT;
}
// Make sure the player has beaten the necessary levels
DropperArenaGroup arenaGroup = Dropper.getInstance().getArenaHandler().getGroup(specifiedArena.getArenaId());
DropperArenaGroup arenaGroup = MiniGames.getInstance().getDropperArenaHandler().getGroup(specifiedArena.getArenaId());
if (arenaGroup != null && !doGroupChecks(specifiedArena, arenaGroup, gameMode, player)) {
return false;
}
// Make sure the player has beaten the arena once in normal mode before playing another mode
if (Dropper.getInstance().getDropperConfiguration().mustDoNormalModeFirst() &&
gameMode != ArenaGameMode.DEFAULT &&
specifiedArena.getData().hasNotCompleted(ArenaGameMode.DEFAULT, player)) {
if (MiniGames.getInstance().getDropperConfiguration().mustDoNormalModeFirst() &&
gameMode != DropperArenaGameMode.DEFAULT &&
specifiedArena.getData().hasNotCompleted(DropperArenaGameMode.DEFAULT, player)) {
player.sendMessage("You must complete this arena in normal mode first!");
return false;
}
// Register the player's session
DropperArenaSession newSession = new DropperArenaSession(specifiedArena, player, gameMode);
DropperArenaPlayerRegistry playerRegistry = Dropper.getInstance().getPlayerRegistry();
DropperArenaPlayerRegistry playerRegistry = MiniGames.getInstance().getDropperArenaPlayerRegistry();
playerRegistry.registerPlayer(player.getUniqueId(), newSession);
// Try to teleport the player to the arena
@ -114,11 +114,11 @@ public class JoinArenaCommand implements CommandExecutor {
* @return <p>False if any checks failed</p>
*/
private boolean doGroupChecks(@NotNull DropperArena dropperArena, @NotNull DropperArenaGroup arenaGroup,
@NotNull ArenaGameMode arenaGameMode, @NotNull Player player) {
DropperConfiguration configuration = Dropper.getInstance().getDropperConfiguration();
@NotNull DropperArenaGameMode arenaGameMode, @NotNull Player player) {
DropperConfiguration configuration = MiniGames.getInstance().getDropperConfiguration();
// Require that players beat all arenas in the group in the normal game-mode before trying challenge modes
if (configuration.mustDoNormalModeFirst() && arenaGameMode != ArenaGameMode.DEFAULT &&
!arenaGroup.hasBeatenAll(ArenaGameMode.DEFAULT, player)) {
if (configuration.mustDoNormalModeFirst() && arenaGameMode != DropperArenaGameMode.DEFAULT &&
!arenaGroup.hasBeatenAll(DropperArenaGameMode.DEFAULT, player)) {
player.sendMessage("You have not yet beaten all arenas in this group!");
return false;
}

View File

@ -1,7 +1,7 @@
package net.knarcraft.dropper.command;
import net.knarcraft.dropper.Dropper;
import net.knarcraft.dropper.arena.DropperArenaSession;
import net.knarcraft.dropper.MiniGames;
import net.knarcraft.dropper.arena.dropper.DropperArenaSession;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabExecutor;
@ -25,7 +25,7 @@ public class LeaveArenaCommand implements TabExecutor {
return false;
}
DropperArenaSession existingSession = Dropper.getInstance().getPlayerRegistry().getArenaSession(
DropperArenaSession existingSession = MiniGames.getInstance().getDropperArenaPlayerRegistry().getArenaSession(
player.getUniqueId());
if (existingSession == null) {
commandSender.sendMessage("You are not in a dropper arena!");

View File

@ -1,6 +1,6 @@
package net.knarcraft.dropper.command;
import net.knarcraft.dropper.Dropper;
import net.knarcraft.dropper.MiniGames;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabExecutor;
@ -18,7 +18,7 @@ public class ReloadCommand implements TabExecutor {
@Override
public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
@NotNull String[] arguments) {
Dropper.getInstance().reload();
MiniGames.getInstance().reload();
commandSender.sendMessage("Plugin reloaded!");
return true;
}

View File

@ -1,7 +1,7 @@
package net.knarcraft.dropper.command;
import net.knarcraft.dropper.Dropper;
import net.knarcraft.dropper.arena.DropperArena;
import net.knarcraft.dropper.MiniGames;
import net.knarcraft.dropper.arena.dropper.DropperArena;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
@ -21,14 +21,14 @@ public class RemoveArenaCommand implements CommandExecutor {
}
// Get the specified arena
DropperArena targetArena = Dropper.getInstance().getArenaHandler().getArena(arguments[0]);
DropperArena targetArena = MiniGames.getInstance().getDropperArenaHandler().getArena(arguments[0]);
if (targetArena == null) {
commandSender.sendMessage("Unable to find the specified arena");
return false;
}
// Remove the arena
Dropper.getInstance().getArenaHandler().removeArena(targetArena);
MiniGames.getInstance().getDropperArenaHandler().removeArena(targetArena);
commandSender.sendMessage("The specified arena has been successfully removed");
return true;
}

View File

@ -1,6 +1,6 @@
package net.knarcraft.dropper.config;
import net.knarcraft.dropper.Dropper;
import net.knarcraft.dropper.MiniGames;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
@ -16,11 +16,10 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* The configuration keeping track of the player's current configuration
* The configuration keeping track of dropper settings
*/
public class DropperConfiguration {
public class DropperConfiguration extends MiniGameConfiguration {
private FileConfiguration configuration;
private final static String rootNode = "dropper.";
private double verticalVelocity;
@ -31,8 +30,6 @@ public class DropperConfiguration {
private boolean mustDoNormalModeFirst;
private boolean makePlayersInvisible;
private boolean disableHitCollision;
private double liquidHitBoxDepth;
private double solidHitBoxDistance;
private boolean blockSneaking;
private boolean blockSprinting;
private Set<Material> blockWhitelist;
@ -43,7 +40,7 @@ public class DropperConfiguration {
* @param configuration <p>The YAML configuration to use internally</p>
*/
public DropperConfiguration(FileConfiguration configuration) {
this.configuration = configuration;
super(configuration);
}
/**
@ -127,30 +124,6 @@ public class DropperConfiguration {
return this.disableHitCollision;
}
/**
* Gets the negative depth a player must reach in a liquid block for fail/win detection to trigger
*
* <p>This decides how far inside a non-solid block the player must go before detection triggers. The closer to -1
* it is, the more accurate it will seem to the player, but the likelihood of not detecting the hit increases.</p>
*
* @return <p>The liquid hit box depth to use</p>
*/
public double getLiquidHitBoxDepth() {
return this.liquidHitBoxDepth;
}
/**
* Gets the positive distance a player must at most be from a block for fail/win detection to trigger
*
* <p>This decides the distance the player must be from a block below them before a hit triggers. If too low, the
* likelihood of detecting the hit decreases, but it won't look like the player hit the block without being near.</p>
*
* @return <p>The solid hit box distance to use</p>
*/
public double getSolidHitBoxDistance() {
return this.solidHitBoxDistance;
}
/**
* Gets whether players trying to sneak while in a dropper arena to increase their downwards speed should be blocked
*
@ -169,19 +142,7 @@ public class DropperConfiguration {
return this.blockSprinting;
}
/**
* Loads all configuration values from disk
*
* @param configuration <p>The configuration to load</p>
*/
public void load(FileConfiguration configuration) {
this.configuration = configuration;
this.load();
}
/**
* Loads all configuration values from disk
*/
@Override
public void load() {
this.verticalVelocity = configuration.getDouble(rootNode + "verticalVelocity", 1.0);
this.horizontalVelocity = (float) configuration.getDouble(rootNode + "horizontalVelocity", 1.0);
@ -191,8 +152,6 @@ public class DropperConfiguration {
this.mustDoNormalModeFirst = configuration.getBoolean(rootNode + "mustDoNormalModeFirst", true);
this.makePlayersInvisible = configuration.getBoolean(rootNode + "makePlayersInvisible", false);
this.disableHitCollision = configuration.getBoolean(rootNode + "disableHitCollision", true);
this.liquidHitBoxDepth = configuration.getDouble(rootNode + "liquidHitBoxDepth", -0.8);
this.solidHitBoxDistance = configuration.getDouble(rootNode + "solidHitBoxDistance", 0.2);
this.blockSprinting = configuration.getBoolean(rootNode + "blockSprinting", true);
this.blockSneaking = configuration.getBoolean(rootNode + "blockSneaking", true);
sanitizeValues();
@ -204,14 +163,6 @@ public class DropperConfiguration {
* Sanitizes configuration values to ensure they are within expected bounds
*/
private void sanitizeValues() {
if (this.liquidHitBoxDepth <= -1 || this.liquidHitBoxDepth > 0) {
this.liquidHitBoxDepth = -0.8;
}
if (this.solidHitBoxDistance <= 0 || this.solidHitBoxDistance > 1) {
this.solidHitBoxDistance = 0.2;
}
if (this.horizontalVelocity > 1 || this.horizontalVelocity <= 0) {
this.horizontalVelocity = 1;
}
@ -246,7 +197,7 @@ public class DropperConfiguration {
if (matched != null) {
this.blockWhitelist.add(matched);
} else {
Dropper.log(Level.WARNING, "Unable to parse: " + string);
MiniGames.log(Level.WARNING, "Unable to parse: " + string);
}
}
}
@ -267,7 +218,7 @@ public class DropperConfiguration {
if (tag != null) {
this.blockWhitelist.addAll(tag.getValues());
} else {
Dropper.log(Level.WARNING, "Unable to parse: " + materialName);
MiniGames.log(Level.WARNING, "Unable to parse: " + materialName);
}
return true;
}
@ -286,8 +237,6 @@ public class DropperConfiguration {
"\n" + "Must do normal mode first: " + mustDoNormalModeFirst +
"\n" + "Make players invisible: " + makePlayersInvisible +
"\n" + "Disable hit collision: " + disableHitCollision +
"\n" + "Liquid hit box depth: " + liquidHitBoxDepth +
"\n" + "Solid hit box distance: " + solidHitBoxDistance +
"\n" + "Block whitelist: ");
for (Material material : blockWhitelist) {
builder.append("\n - ").append(material.name());

View File

@ -0,0 +1,37 @@
package net.knarcraft.dropper.config;
import org.bukkit.configuration.file.FileConfiguration;
import org.jetbrains.annotations.NotNull;
/**
* A configuration for a mini-game
*/
public abstract class MiniGameConfiguration {
protected FileConfiguration configuration;
/**
* Instantiates a new mini-game configuration
*
* @param configuration <p>The YAML configuration to use internally</p>
*/
public MiniGameConfiguration(@NotNull FileConfiguration configuration) {
this.configuration = configuration;
}
/**
* Loads all configuration values from disk
*
* @param configuration <p>The configuration to load</p>
*/
public void load(FileConfiguration configuration) {
this.configuration = configuration;
this.load();
}
/**
* Loads all configuration values from disk, using the current file configuration
*/
public abstract void load();
}

View File

@ -0,0 +1,67 @@
package net.knarcraft.dropper.config;
import org.bukkit.configuration.file.FileConfiguration;
/**
* The configuration keeping track of parkour settings
*/
public class ParkourConfiguration extends MiniGameConfiguration {
private final static String rootNode = "parkour.";
private boolean mustDoGroupedInSequence;
private boolean ignoreRecordsUntilGroupBeatenOnce;
private boolean makePlayersInvisible;
/**
* Instantiates a new dropper configuration
*
* @param configuration <p>The YAML configuration to use internally</p>
*/
public ParkourConfiguration(FileConfiguration configuration) {
super(configuration);
}
/**
* Gets whether grouped arenas must be done in the set sequence
*
* @return <p>Whether grouped arenas must be done in sequence</p>
*/
public boolean mustDoGroupedInSequence() {
return this.mustDoGroupedInSequence;
}
/**
* Gets whether records should be discarded, unless the player has already beaten all arenas in the group
*
* @return <p>Whether to ignore records on the first play-through</p>
*/
public boolean ignoreRecordsUntilGroupBeatenOnce() {
return this.ignoreRecordsUntilGroupBeatenOnce;
}
/**
* Gets whether players should be made invisible while in an arena
*
* @return <p>Whether players should be made invisible</p>
*/
public boolean makePlayersInvisible() {
return this.makePlayersInvisible;
}
@Override
public void load() {
this.mustDoGroupedInSequence = configuration.getBoolean(rootNode + "mustDoGroupedInSequence", true);
this.ignoreRecordsUntilGroupBeatenOnce = configuration.getBoolean(rootNode + "ignoreRecordsUntilGroupBeatenOnce", false);
this.makePlayersInvisible = configuration.getBoolean(rootNode + "makePlayersInvisible", false);
}
@Override
public String toString() {
return "Current configuration:" +
"\n" + "Must do groups in sequence: " + mustDoGroupedInSequence +
"\n" + "Ignore records until group beaten once: " + ignoreRecordsUntilGroupBeatenOnce +
"\n" + "Make players invisible: " + makePlayersInvisible;
}
}

View File

@ -0,0 +1,69 @@
package net.knarcraft.dropper.config;
import org.bukkit.configuration.file.FileConfiguration;
import org.jetbrains.annotations.NotNull;
/**
* The configuration keeping track of shared settings
*/
public class SharedConfiguration extends MiniGameConfiguration {
private final static String rootNode = "shared.";
private double liquidHitBoxDepth;
private double solidHitBoxDistance;
/**
* Instantiates a new shared configuration
*
* @param configuration <p>The YAML configuration to use internally</p>
*/
public SharedConfiguration(@NotNull FileConfiguration configuration) {
super(configuration);
}
/**
* Gets the negative depth a player must reach in a liquid block for fail/win detection to trigger
*
* <p>This decides how far inside a non-solid block the player must go before detection triggers. The closer to -1
* it is, the more accurate it will seem to the player, but the likelihood of not detecting the hit increases.</p>
*
* @return <p>The liquid hit box depth to use</p>
*/
public double getLiquidHitBoxDepth() {
return this.liquidHitBoxDepth;
}
/**
* Gets the positive distance a player must at most be from a block for fail/win detection to trigger
*
* <p>This decides the distance the player must be from a block below them before a hit triggers. If too low, the
* likelihood of detecting the hit decreases, but it won't look like the player hit the block without being near.</p>
*
* @return <p>The solid hit box distance to use</p>
*/
public double getSolidHitBoxDistance() {
return this.solidHitBoxDistance;
}
@Override
public void load() {
this.liquidHitBoxDepth = configuration.getDouble(rootNode + "liquidHitBoxDepth", -0.8);
this.solidHitBoxDistance = configuration.getDouble(rootNode + "solidHitBoxDistance", 0.2);
if (this.liquidHitBoxDepth <= -1 || this.liquidHitBoxDepth > 0) {
this.liquidHitBoxDepth = -0.8;
}
if (this.solidHitBoxDistance <= 0 || this.solidHitBoxDistance > 1) {
this.solidHitBoxDistance = 0.2;
}
}
@Override
public String toString() {
return "Current configuration:" +
"\n" + "Liquid hit box depth: " + liquidHitBoxDepth +
"\n" + "Solid hit box distance: " + solidHitBoxDistance;
}
}

View File

@ -1,7 +1,7 @@
package net.knarcraft.dropper.listener;
import net.knarcraft.dropper.Dropper;
import net.knarcraft.dropper.arena.DropperArenaSession;
import net.knarcraft.dropper.MiniGames;
import net.knarcraft.dropper.arena.dropper.DropperArenaSession;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
@ -18,7 +18,7 @@ public class CommandListener implements Listener {
@EventHandler
public void onCommand(PlayerCommandPreprocessEvent event) {
Player player = event.getPlayer();
DropperArenaSession existingSession = Dropper.getInstance().getPlayerRegistry().getArenaSession(
DropperArenaSession existingSession = MiniGames.getInstance().getDropperArenaPlayerRegistry().getArenaSession(
player.getUniqueId());
if (existingSession == null) {
return;

View File

@ -1,8 +1,8 @@
package net.knarcraft.dropper.listener;
import net.knarcraft.dropper.Dropper;
import net.knarcraft.dropper.arena.DropperArenaPlayerRegistry;
import net.knarcraft.dropper.arena.DropperArenaSession;
import net.knarcraft.dropper.MiniGames;
import net.knarcraft.dropper.arena.dropper.DropperArenaPlayerRegistry;
import net.knarcraft.dropper.arena.dropper.DropperArenaSession;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@ -25,7 +25,7 @@ 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.getUniqueId());
DropperArenaSession arenaSession = MiniGames.getInstance().getDropperArenaPlayerRegistry().getArenaSession(player.getUniqueId());
if (arenaSession == null) {
return;
}
@ -44,7 +44,7 @@ public class DamageListener implements Listener {
return;
}
DropperArenaPlayerRegistry registry = Dropper.getInstance().getPlayerRegistry();
DropperArenaPlayerRegistry registry = MiniGames.getInstance().getDropperArenaPlayerRegistry();
DropperArenaSession arenaSession = registry.getArenaSession(event.getEntity().getUniqueId());
if (arenaSession != null) {
// Cancel combustion for any player in an arena

View File

@ -1,9 +1,9 @@
package net.knarcraft.dropper.listener;
import net.knarcraft.dropper.Dropper;
import net.knarcraft.dropper.arena.ArenaGameMode;
import net.knarcraft.dropper.arena.DropperArenaPlayerRegistry;
import net.knarcraft.dropper.arena.DropperArenaSession;
import net.knarcraft.dropper.MiniGames;
import net.knarcraft.dropper.arena.dropper.DropperArenaGameMode;
import net.knarcraft.dropper.arena.dropper.DropperArenaPlayerRegistry;
import net.knarcraft.dropper.arena.dropper.DropperArenaSession;
import net.knarcraft.dropper.config.DropperConfiguration;
import org.bukkit.Location;
import org.bukkit.Material;
@ -43,7 +43,7 @@ public class MoveListener implements Listener {
}
Player player = event.getPlayer();
DropperArenaPlayerRegistry playerRegistry = Dropper.getInstance().getPlayerRegistry();
DropperArenaPlayerRegistry playerRegistry = MiniGames.getInstance().getDropperArenaPlayerRegistry();
DropperArenaSession arenaSession = playerRegistry.getArenaSession(player.getUniqueId());
if (arenaSession == null) {
return;
@ -144,7 +144,7 @@ public class MoveListener implements Listener {
* @param session <p>The session to possibly invert flying for</p>
*/
private void toggleFlyInversion(@NotNull DropperArenaSession session) {
if (session.getGameMode() != ArenaGameMode.RANDOM_INVERTED) {
if (session.getGameMode() != DropperArenaGameMode.RANDOM_INVERTED) {
return;
}
Player player = session.getPlayer();

View File

@ -1,7 +1,7 @@
package net.knarcraft.dropper.listener;
import net.knarcraft.dropper.Dropper;
import net.knarcraft.dropper.arena.DropperArenaSession;
import net.knarcraft.dropper.MiniGames;
import net.knarcraft.dropper.arena.dropper.DropperArenaSession;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@ -32,7 +32,7 @@ public class PlayerLeaveListener implements Listener {
return;
}
Dropper.log(Level.WARNING, "Found player " + player.getUniqueId() +
MiniGames.log(Level.WARNING, "Found player " + player.getUniqueId() +
" leaving in the middle of a session!");
leftSessions.put(player.getUniqueId(), arenaSession);
}
@ -42,10 +42,10 @@ public class PlayerLeaveListener implements Listener {
UUID playerId = event.getPlayer().getUniqueId();
// Force the player to quit from the session once they re-join
if (leftSessions.containsKey(playerId)) {
Dropper.log(Level.WARNING, "Found un-exited dropper session!");
Bukkit.getScheduler().runTaskLater(Dropper.getInstance(), () -> {
MiniGames.log(Level.WARNING, "Found un-exited dropper session!");
Bukkit.getScheduler().runTaskLater(MiniGames.getInstance(), () -> {
leftSessions.get(playerId).triggerQuit(false);
Dropper.log(Level.WARNING, "Triggered a quit!");
MiniGames.log(Level.WARNING, "Triggered a quit!");
leftSessions.remove(playerId);
}, 80);
}
@ -76,7 +76,7 @@ public class PlayerLeaveListener implements Listener {
* @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());
return MiniGames.getInstance().getDropperArenaPlayerRegistry().getArenaSession(player.getUniqueId());
}
}

View File

@ -1,12 +1,12 @@
package net.knarcraft.dropper.placeholder;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import net.knarcraft.dropper.Dropper;
import net.knarcraft.dropper.arena.ArenaGameMode;
import net.knarcraft.dropper.arena.DropperArena;
import net.knarcraft.dropper.arena.DropperArenaGroup;
import net.knarcraft.dropper.arena.DropperArenaHandler;
import net.knarcraft.dropper.arena.DropperArenaRecordsRegistry;
import net.knarcraft.dropper.MiniGames;
import net.knarcraft.dropper.arena.dropper.DropperArena;
import net.knarcraft.dropper.arena.dropper.DropperArenaGameMode;
import net.knarcraft.dropper.arena.dropper.DropperArenaGroup;
import net.knarcraft.dropper.arena.dropper.DropperArenaHandler;
import net.knarcraft.dropper.arena.dropper.DropperArenaRecordsRegistry;
import net.knarcraft.dropper.arena.record.ArenaRecord;
import net.knarcraft.dropper.placeholder.parsing.InfoType;
import net.knarcraft.dropper.placeholder.parsing.SelectionType;
@ -33,7 +33,7 @@ import java.util.function.Supplier;
*/
public class DropperRecordExpansion extends PlaceholderExpansion {
private final Dropper plugin;
private final MiniGames plugin;
private final Map<UUID, Set<GroupRecordCache<Integer>>> groupRecordDeathsCache;
private final Map<UUID, Set<GroupRecordCache<Long>>> groupRecordTimeCache;
@ -42,7 +42,7 @@ public class DropperRecordExpansion extends PlaceholderExpansion {
*
* @param plugin <p>A reference to the dropper plugin</p>
*/
public DropperRecordExpansion(Dropper plugin) {
public DropperRecordExpansion(MiniGames plugin) {
this.plugin = plugin;
this.groupRecordDeathsCache = new HashMap<>();
this.groupRecordTimeCache = new HashMap<>();
@ -76,7 +76,7 @@ public class DropperRecordExpansion extends PlaceholderExpansion {
return parameters;
}
RecordType recordType = RecordType.getFromString(parts[1]);
ArenaGameMode gameMode = ArenaGameMode.matchGamemode(parts[2]);
DropperArenaGameMode gameMode = DropperArenaGameMode.matchGamemode(parts[2]);
SelectionType selectionType = SelectionType.getFromString(parts[3]);
String identifier = parts[4];
int recordNumber = Integer.parseInt(parts[5]) - 1;
@ -87,7 +87,7 @@ public class DropperRecordExpansion extends PlaceholderExpansion {
}
String info = null;
DropperArenaHandler arenaHandler = plugin.getArenaHandler();
DropperArenaHandler arenaHandler = plugin.getDropperArenaHandler();
if (selectionType == SelectionType.GROUP) {
info = getGroupRecord(arenaHandler, identifier, gameMode, recordType, recordNumber, infoType);
} else if (selectionType == SelectionType.ARENA) {
@ -117,7 +117,7 @@ public class DropperRecordExpansion extends PlaceholderExpansion {
* @return <p>The selected information about the record, or null if not found</p>
*/
private @Nullable String getGroupRecord(@NotNull DropperArenaHandler arenaHandler, @NotNull String identifier,
@NotNull ArenaGameMode gameMode, @NotNull RecordType recordType,
@NotNull DropperArenaGameMode gameMode, @NotNull RecordType recordType,
int recordNumber, @NotNull InfoType infoType) {
// Allow specifying the group UUID or the arena name
DropperArenaGroup group;
@ -154,7 +154,7 @@ public class DropperRecordExpansion extends PlaceholderExpansion {
* @return <p>The record, or null if not found</p>
*/
private @Nullable ArenaRecord<?> getGroupTimeRecord(@NotNull DropperArenaGroup group,
@NotNull ArenaGameMode gameMode, int recordNumber) {
@NotNull DropperArenaGameMode gameMode, int recordNumber) {
return getCachedGroupRecord(group, gameMode, RecordType.TIME, recordNumber, groupRecordTimeCache,
() -> DropperGroupRecordHelper.getCombinedTime(group, gameMode));
}
@ -168,7 +168,7 @@ public class DropperRecordExpansion extends PlaceholderExpansion {
* @return <p>The record, or null if not found</p>
*/
private @Nullable ArenaRecord<?> getGroupDeathRecord(@NotNull DropperArenaGroup group,
@NotNull ArenaGameMode gameMode, int recordNumber) {
@NotNull DropperArenaGameMode gameMode, int recordNumber) {
return getCachedGroupRecord(group, gameMode, RecordType.DEATHS, recordNumber, groupRecordDeathsCache,
() -> DropperGroupRecordHelper.getCombinedDeaths(group, gameMode));
}
@ -186,7 +186,7 @@ public class DropperRecordExpansion extends PlaceholderExpansion {
* @return <p>The specified record, or null if not found</p>
*/
private <K extends Comparable<K>> @Nullable ArenaRecord<?> getCachedGroupRecord(@NotNull DropperArenaGroup group,
@NotNull ArenaGameMode gameMode,
@NotNull DropperArenaGameMode gameMode,
@NotNull RecordType recordType,
int recordNumber,
@NotNull Map<UUID, Set<GroupRecordCache<K>>> caches,
@ -233,7 +233,7 @@ public class DropperRecordExpansion extends PlaceholderExpansion {
* @return <p>The selected information about the record, or null if not found</p>
*/
private @Nullable String getArenaRecord(@NotNull DropperArenaHandler arenaHandler, @NotNull String identifier,
@NotNull ArenaGameMode gameMode, @NotNull RecordType recordType,
@NotNull DropperArenaGameMode gameMode, @NotNull RecordType recordType,
int recordNumber, @NotNull InfoType infoType) {
// Allow specifying the arena UUID or the arena name
DropperArena arena;
@ -245,7 +245,7 @@ public class DropperRecordExpansion extends PlaceholderExpansion {
if (arena == null) {
return null;
}
@NotNull Map<ArenaGameMode, DropperArenaRecordsRegistry> registries = arena.getData().recordRegistries();
@NotNull Map<DropperArenaGameMode, DropperArenaRecordsRegistry> registries = arena.getData().recordRegistries();
DropperArenaRecordsRegistry recordsRegistry = registries.get(gameMode);
ArenaRecord<?> record = getRecord(recordsRegistry, recordType, recordNumber);

View File

@ -1,6 +1,6 @@
package net.knarcraft.dropper.placeholder;
import net.knarcraft.dropper.arena.ArenaGameMode;
import net.knarcraft.dropper.arena.dropper.DropperArenaGameMode;
import net.knarcraft.dropper.arena.record.ArenaRecord;
import net.knarcraft.dropper.property.RecordType;
import org.jetbrains.annotations.NotNull;
@ -15,7 +15,8 @@ import java.util.Set;
* @param records <p>The stored records</p>
* @param createdTime <p>The time this cache was created</p>
*/
public record GroupRecordCache<K extends Comparable<K>>(@NotNull ArenaGameMode gameMode, @NotNull RecordType recordType,
public record GroupRecordCache<K extends Comparable<K>>(@NotNull DropperArenaGameMode gameMode,
@NotNull RecordType recordType,
@NotNull Set<ArenaRecord<K>> records,
@NotNull Long createdTime) {
}

View File

@ -1,12 +1,14 @@
package net.knarcraft.dropper.util;
import net.knarcraft.dropper.Dropper;
import net.knarcraft.dropper.MiniGames;
import net.knarcraft.dropper.arena.ArenaGameMode;
import net.knarcraft.dropper.arena.ArenaStorageKey;
import net.knarcraft.dropper.arena.DropperArena;
import net.knarcraft.dropper.arena.DropperArenaData;
import net.knarcraft.dropper.arena.DropperArenaGroup;
import net.knarcraft.dropper.arena.DropperArenaRecordsRegistry;
import net.knarcraft.dropper.arena.ArenaRecordsRegistry;
import net.knarcraft.dropper.arena.dropper.DropperArena;
import net.knarcraft.dropper.arena.dropper.DropperArenaData;
import net.knarcraft.dropper.arena.dropper.DropperArenaGameMode;
import net.knarcraft.dropper.arena.dropper.DropperArenaGroup;
import net.knarcraft.dropper.arena.dropper.DropperArenaRecordsRegistry;
import net.knarcraft.dropper.arena.dropper.DropperArenaStorageKey;
import net.knarcraft.dropper.container.SerializableMaterial;
import net.knarcraft.dropper.container.SerializableUUID;
import org.bukkit.Location;
@ -30,11 +32,13 @@ import java.util.logging.Level;
*/
public final class ArenaStorageHelper {
private final static File dataFolder = MiniGames.getInstance().getDataFolder();
private final static String arenasConfigurationSection = "arenas";
private final static String groupsConfigurationSection = "groups";
private static final File arenaFile = new File(Dropper.getInstance().getDataFolder(), "arenas.yml");
private static final File groupFile = new File(Dropper.getInstance().getDataFolder(), "groups.yml");
private static final File arenaDataFolder = new File(Dropper.getInstance().getDataFolder(), "arena_data");
private static final File arenaFile = new File(dataFolder, "arenas.yml");
private static final File groupFile = new File(dataFolder, "groups.yml");
private static final File dropperArenaDataFolder = new File(dataFolder, "dropper_arena_data");
private static final File parkourArenaDataFolder = new File(dataFolder, "parkour_arena_data");
private ArenaStorageHelper() {
@ -85,21 +89,21 @@ public final class ArenaStorageHelper {
* @param arenas <p>The arenas to save</p>
* @throws IOException <p>If unable to write to the file</p>
*/
public static void saveArenas(@NotNull Map<UUID, DropperArena> arenas) throws IOException {
public static void saveDropperArenas(@NotNull Map<UUID, DropperArena> arenas) throws IOException {
YamlConfiguration configuration = new YamlConfiguration();
ConfigurationSection arenaSection = configuration.createSection(arenasConfigurationSection);
for (DropperArena arena : arenas.values()) {
//Note: While the arena name is used as the key, as the key has to be sanitized, the un-sanitized arena name
// must be stored as well
@NotNull ConfigurationSection configSection = arenaSection.createSection(arena.getArenaId().toString());
configSection.set(ArenaStorageKey.ID.getKey(), new SerializableUUID(arena.getArenaId()));
configSection.set(ArenaStorageKey.NAME.getKey(), arena.getArenaName());
configSection.set(ArenaStorageKey.SPAWN_LOCATION.getKey(), arena.getSpawnLocation());
configSection.set(ArenaStorageKey.EXIT_LOCATION.getKey(), arena.getExitLocation());
configSection.set(ArenaStorageKey.PLAYER_VERTICAL_VELOCITY.getKey(), arena.getPlayerVerticalVelocity());
configSection.set(ArenaStorageKey.PLAYER_HORIZONTAL_VELOCITY.getKey(), arena.getPlayerHorizontalVelocity());
configSection.set(ArenaStorageKey.WIN_BLOCK_TYPE.getKey(), new SerializableMaterial(arena.getWinBlockType()));
saveArenaData(arena.getData());
configSection.set(DropperArenaStorageKey.ID.getKey(), new SerializableUUID(arena.getArenaId()));
configSection.set(DropperArenaStorageKey.NAME.getKey(), arena.getArenaName());
configSection.set(DropperArenaStorageKey.SPAWN_LOCATION.getKey(), arena.getSpawnLocation());
configSection.set(DropperArenaStorageKey.EXIT_LOCATION.getKey(), arena.getExitLocation());
configSection.set(DropperArenaStorageKey.PLAYER_VERTICAL_VELOCITY.getKey(), arena.getPlayerVerticalVelocity());
configSection.set(DropperArenaStorageKey.PLAYER_HORIZONTAL_VELOCITY.getKey(), arena.getPlayerHorizontalVelocity());
configSection.set(DropperArenaStorageKey.WIN_BLOCK_TYPE.getKey(), new SerializableMaterial(arena.getWinBlockType()));
saveDropperArenaData(arena.getData());
}
configuration.save(arenaFile);
}
@ -109,7 +113,7 @@ public final class ArenaStorageHelper {
*
* @return <p>The loaded arenas, or null if the arenas configuration section is missing.</p>
*/
public static @NotNull Map<UUID, DropperArena> loadArenas() {
public static @NotNull Map<UUID, DropperArena> loadDropperArenas() {
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
@ -126,7 +130,7 @@ public final class ArenaStorageHelper {
continue;
}
DropperArena arena = loadArena(configurationSection);
DropperArena arena = loadDropperArena(configurationSection);
if (arena != null) {
loadedArenas.put(arena.getArenaId(), arena);
}
@ -141,20 +145,20 @@ public final class ArenaStorageHelper {
* @param configurationSection <p>The configuration section containing arena data</p>
* @return <p>The loaded arena, or null if invalid</p>
*/
private static @Nullable DropperArena loadArena(@NotNull ConfigurationSection configurationSection) {
UUID arenaId = ((SerializableUUID) configurationSection.get(ArenaStorageKey.ID.getKey(),
private static @Nullable DropperArena loadDropperArena(@NotNull ConfigurationSection configurationSection) {
UUID arenaId = ((SerializableUUID) configurationSection.get(DropperArenaStorageKey.ID.getKey(),
new SerializableUUID(UUID.randomUUID()))).uuid();
String arenaName = configurationSection.getString(ArenaStorageKey.NAME.getKey());
Location spawnLocation = (Location) configurationSection.get(ArenaStorageKey.SPAWN_LOCATION.getKey());
Location exitLocation = (Location) configurationSection.get(ArenaStorageKey.EXIT_LOCATION.getKey());
double verticalVelocity = configurationSection.getDouble(ArenaStorageKey.PLAYER_VERTICAL_VELOCITY.getKey());
String arenaName = configurationSection.getString(DropperArenaStorageKey.NAME.getKey());
Location spawnLocation = (Location) configurationSection.get(DropperArenaStorageKey.SPAWN_LOCATION.getKey());
Location exitLocation = (Location) configurationSection.get(DropperArenaStorageKey.EXIT_LOCATION.getKey());
double verticalVelocity = configurationSection.getDouble(DropperArenaStorageKey.PLAYER_VERTICAL_VELOCITY.getKey());
float horizontalVelocity = sanitizeHorizontalVelocity((float) configurationSection.getDouble(
ArenaStorageKey.PLAYER_HORIZONTAL_VELOCITY.getKey()));
DropperArenaStorageKey.PLAYER_HORIZONTAL_VELOCITY.getKey()));
SerializableMaterial winBlockType = (SerializableMaterial) configurationSection.get(
ArenaStorageKey.WIN_BLOCK_TYPE.getKey());
DropperArenaStorageKey.WIN_BLOCK_TYPE.getKey());
if (arenaName == null || spawnLocation == null) {
Dropper.log(Level.SEVERE, "Could not load the arena at configuration " +
MiniGames.log(Level.SEVERE, "Could not load the arena at configuration " +
"section " + configurationSection.getName() + ". Please check the arenas storage file for issues.");
return null;
}
@ -162,19 +166,19 @@ public final class ArenaStorageHelper {
winBlockType = new SerializableMaterial(Material.WATER);
}
DropperArenaData arenaData = loadArenaData(arenaId);
DropperArenaData arenaData = loadDropperArenaData(arenaId);
if (arenaData == null) {
Dropper.log(Level.SEVERE, "Unable to load arena data for " + arenaId);
MiniGames.log(Level.SEVERE, "Unable to load arena data for " + arenaId);
Map<ArenaGameMode, DropperArenaRecordsRegistry> recordRegistries = new HashMap<>();
for (ArenaGameMode arenaGameMode : ArenaGameMode.values()) {
Map<ArenaGameMode, ArenaRecordsRegistry> recordRegistries = new HashMap<>();
for (ArenaGameMode arenaGameMode : DropperArenaGameMode.values()) {
recordRegistries.put(arenaGameMode, new DropperArenaRecordsRegistry(arenaId));
}
arenaData = new DropperArenaData(arenaId, recordRegistries, new HashMap<>());
}
return new DropperArena(arenaId, arenaName, spawnLocation, exitLocation, verticalVelocity, horizontalVelocity,
winBlockType.material(), arenaData, Dropper.getInstance().getArenaHandler());
winBlockType.material(), arenaData, MiniGames.getInstance().getDropperArenaHandler());
}
/**
@ -182,11 +186,11 @@ public final class ArenaStorageHelper {
*
* @param arenaData <p>The arena data to store</p>
*/
public static void saveArenaData(@NotNull DropperArenaData arenaData) throws IOException {
public static void saveDropperArenaData(@NotNull DropperArenaData arenaData) throws IOException {
YamlConfiguration configuration = new YamlConfiguration();
configuration.set(ArenaStorageKey.DATA.getKey(), arenaData);
configuration.set(DropperArenaStorageKey.DATA.getKey(), arenaData);
configuration.save(getArenaDataFile(arenaData.arenaId()));
configuration.save(getDropperArenaDataFile(arenaData.getArenaId()));
}
/**
@ -195,10 +199,10 @@ public final class ArenaStorageHelper {
* @param arenaId <p>The id of the arena to get data for</p>
* @return <p>The loaded arena data</p>
*/
private static @Nullable DropperArenaData loadArenaData(@NotNull UUID arenaId) {
File arenaDataFile = getArenaDataFile(arenaId);
private static @Nullable DropperArenaData loadDropperArenaData(@NotNull UUID arenaId) {
File arenaDataFile = getDropperArenaDataFile(arenaId);
YamlConfiguration configuration = YamlConfiguration.loadConfiguration(arenaDataFile);
return (DropperArenaData) configuration.get(ArenaStorageKey.DATA.getKey());
return (DropperArenaData) configuration.get(DropperArenaStorageKey.DATA.getKey());
}
/**
@ -207,8 +211,8 @@ public final class ArenaStorageHelper {
* @param arenaId <p>The id of the arena to remove data for</p>
* @return <p>True if the data was successfully removed</p>
*/
public static boolean removeArenaData(@NotNull UUID arenaId) {
return getArenaDataFile(arenaId).delete();
public static boolean removeDropperArenaData(@NotNull UUID arenaId) {
return getDropperArenaDataFile(arenaId).delete();
}
/**
@ -217,10 +221,10 @@ public final class ArenaStorageHelper {
* @param arenaId <p>The id of the arena to get a data file for</p>
* @return <p>The file the arena's data is/should be stored in</p>
*/
private static @NotNull File getArenaDataFile(@NotNull UUID arenaId) {
File arenaDataFile = new File(arenaDataFolder, arenaId + ".yml");
if (!arenaDataFolder.exists() && !arenaDataFolder.mkdirs()) {
Dropper.log(Level.SEVERE, "Unable to create the arena data directories");
private static @NotNull File getDropperArenaDataFile(@NotNull UUID arenaId) {
File arenaDataFile = new File(parkourArenaDataFolder, arenaId + ".yml");
if (!parkourArenaDataFolder.exists() && !parkourArenaDataFolder.mkdirs()) {
MiniGames.log(Level.SEVERE, "Unable to create the arena data directories");
}
return arenaDataFile;
}

View File

@ -1,10 +1,10 @@
package net.knarcraft.dropper.util;
import net.knarcraft.dropper.Dropper;
import net.knarcraft.dropper.arena.ArenaGameMode;
import net.knarcraft.dropper.arena.DropperArena;
import net.knarcraft.dropper.arena.DropperArenaGroup;
import net.knarcraft.dropper.arena.DropperArenaHandler;
import net.knarcraft.dropper.MiniGames;
import net.knarcraft.dropper.arena.dropper.DropperArena;
import net.knarcraft.dropper.arena.dropper.DropperArenaGameMode;
import net.knarcraft.dropper.arena.dropper.DropperArenaGroup;
import net.knarcraft.dropper.arena.dropper.DropperArenaHandler;
import net.knarcraft.dropper.arena.record.ArenaRecord;
import net.knarcraft.dropper.arena.record.SummableArenaRecord;
import org.jetbrains.annotations.NotNull;
@ -33,9 +33,9 @@ public final class DropperGroupRecordHelper {
* @return <p>The combined death records</p>
*/
public static @NotNull Set<ArenaRecord<Integer>> getCombinedDeaths(@NotNull DropperArenaGroup group,
@NotNull ArenaGameMode gameMode) {
@NotNull DropperArenaGameMode gameMode) {
Map<UUID, SummableArenaRecord<Integer>> records = new HashMap<>();
@NotNull BiFunction<DropperArena, ArenaGameMode, Set<SummableArenaRecord<Integer>>> recordSupplier =
@NotNull BiFunction<DropperArena, DropperArenaGameMode, Set<SummableArenaRecord<Integer>>> recordSupplier =
(arena, aGameMode) -> arena.getData().recordRegistries().get(gameMode).getLeastDeathsRecords();
return getCombined(group, gameMode, records, recordSupplier);
@ -49,9 +49,9 @@ public final class DropperGroupRecordHelper {
* @return <p>The combined least-time records</p>
*/
public static @NotNull Set<ArenaRecord<Long>> getCombinedTime(@NotNull DropperArenaGroup group,
@NotNull ArenaGameMode gameMode) {
@NotNull DropperArenaGameMode gameMode) {
Map<UUID, SummableArenaRecord<Long>> records = new HashMap<>();
@NotNull BiFunction<DropperArena, ArenaGameMode, Set<SummableArenaRecord<Long>>> recordSupplier =
@NotNull BiFunction<DropperArena, DropperArenaGameMode, Set<SummableArenaRecord<Long>>> recordSupplier =
(arena, aGameMode) -> arena.getData().recordRegistries().get(gameMode).getShortestTimeMilliSecondsRecords();
return getCombined(group, gameMode, records, recordSupplier);
@ -68,13 +68,13 @@ public final class DropperGroupRecordHelper {
* @return <p>The combined records</p>
*/
private static <K extends Comparable<K>> @NotNull Set<ArenaRecord<K>> getCombined(@NotNull DropperArenaGroup group,
@NotNull ArenaGameMode gameMode,
@NotNull DropperArenaGameMode gameMode,
@NotNull Map<UUID,
SummableArenaRecord<K>> records,
@NotNull BiFunction<DropperArena,
ArenaGameMode,
DropperArenaGameMode,
Set<SummableArenaRecord<K>>> recordSupplier) {
DropperArenaHandler arenaHandler = Dropper.getInstance().getArenaHandler();
DropperArenaHandler arenaHandler = MiniGames.getInstance().getDropperArenaHandler();
// Get all arenas in the group
Set<DropperArena> arenas = getArenas(arenaHandler, group);
@ -137,11 +137,11 @@ public final class DropperGroupRecordHelper {
* @param <K> <p>The type of record to combine</p>
*/
private static <K extends Comparable<K>> void combineRecords(@NotNull Set<DropperArena> arenas,
@NotNull ArenaGameMode gameMode,
@NotNull DropperArenaGameMode gameMode,
@NotNull Map<UUID,
SummableArenaRecord<K>> combinedRecords,
@NotNull Map<UUID, Integer> recordsFound,
@NotNull BiFunction<DropperArena, ArenaGameMode,
@NotNull BiFunction<DropperArena, DropperArenaGameMode,
Set<SummableArenaRecord<K>>> recordSupplier) {
for (DropperArena arena : arenas) {
Set<SummableArenaRecord<K>> existingRecords = recordSupplier.apply(arena, gameMode);

View File

@ -0,0 +1,26 @@
package net.knarcraft.dropper.util;
import org.bukkit.Location;
import org.bukkit.World;
/**
* A helper class for validating whether given input is valid
*/
public final class InputValidationHelper {
private InputValidationHelper() {
}
/**
* Checks whether the given location is valid
*
* @param location <p>The location to validate</p>
* @return <p>False if the location is valid</p>
*/
public static boolean isInvalid(Location location) {
World world = location.getWorld();
return world == null || !world.getWorldBorder().isInside(location);
}
}

View File

@ -1,6 +1,6 @@
package net.knarcraft.dropper.util;
import net.knarcraft.dropper.Dropper;
import net.knarcraft.dropper.MiniGames;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
@ -57,7 +57,7 @@ public final class PlayerTeleporter {
//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
if (!immediately) {
Bukkit.getScheduler().runTaskLater(Dropper.getInstance(), () -> player.setInvulnerable(false), 5);
Bukkit.getScheduler().runTaskLater(MiniGames.getInstance(), () -> player.setInvulnerable(false), 5);
} else {
player.setInvulnerable(false);
}

View File

@ -1,8 +1,8 @@
package net.knarcraft.dropper.util;
import net.knarcraft.dropper.Dropper;
import net.knarcraft.dropper.arena.ArenaEditableProperty;
import net.knarcraft.dropper.arena.DropperArena;
import net.knarcraft.dropper.MiniGames;
import net.knarcraft.dropper.arena.dropper.DropperArena;
import net.knarcraft.dropper.arena.dropper.DropperArenaEditableProperty;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
@ -24,7 +24,7 @@ public final class TabCompleteHelper {
*/
public static @NotNull List<String> getArenas() {
List<String> arenaNames = new ArrayList<>();
for (DropperArena dropperArena : Dropper.getInstance().getArenaHandler().getArenas().values()) {
for (DropperArena dropperArena : MiniGames.getInstance().getDropperArenaHandler().getArenas().values()) {
arenaNames.add(dropperArena.getArenaName());
}
return arenaNames;
@ -37,7 +37,7 @@ public final class TabCompleteHelper {
*/
public static @NotNull List<String> getArenaProperties() {
List<String> arenaProperties = new ArrayList<>();
for (ArenaEditableProperty property : ArenaEditableProperty.values()) {
for (DropperArenaEditableProperty property : DropperArenaEditableProperty.values()) {
arenaProperties.add(property.getArgumentString());
}
return arenaProperties;

View File

@ -1,8 +1,8 @@
name: Dropper
version: '${project.version}'
main: net.knarcraft.dropper.Dropper
main: net.knarcraft.dropper.MiniGames
api-version: 1.19
description: A plugin for dropper mini-games
description: A plugin that adds various mini-games
softdepend:
- PlaceholderAPI

View File

@ -1,5 +1,6 @@
package net.knarcraft.dropper.arena;
import net.knarcraft.dropper.arena.dropper.DropperArenaGroup;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@ -10,7 +11,7 @@ import java.util.UUID;
/**
* Tests for arena dropper groups
*/
public class DropperArenaGroupTest {
public class MiniGamesArenaGroupTest {
@Test
public void swapTest() {