Performs a lot of changes. Mostly implements #3

Properly and persistently stores which players have beaten which arenas
Adds a hopefully fully functional DropperArenaGroup class
Stores arena groups in the arena handler
Adds a lookup map to improve performance of getting arena by name
Adds saving and loading of groups
Adds all necessary checks for whether players have beaten the required dropper arenas before joining
Removes stage from arenas
Adds a test to make sure changing the order of arenas in a group works as intended
This commit is contained in:
Kristian Knarvik 2023-03-29 00:55:19 +02:00
parent 51237cb11a
commit 21425f73a1
12 changed files with 524 additions and 68 deletions

View File

@ -73,5 +73,11 @@
<version>24.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.9.2</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -1,6 +1,7 @@
package net.knarcraft.dropper;
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;
@ -76,6 +77,7 @@ public final class Dropper extends JavaPlugin {
public void reload() {
// Load all arenas again
this.arenaHandler.loadArenas();
this.arenaHandler.loadGroups();
}
@Override
@ -86,6 +88,7 @@ public final class Dropper extends JavaPlugin {
ConfigurationSerialization.registerClass(DropperArenaRecordsRegistry.class);
ConfigurationSerialization.registerClass(SerializableUUID.class);
ConfigurationSerialization.registerClass(DropperArenaData.class);
ConfigurationSerialization.registerClass(DropperArenaGroup.class);
}
@Override
@ -95,6 +98,7 @@ public final class Dropper extends JavaPlugin {
this.playerRegistry = new DropperArenaPlayerRegistry();
this.arenaHandler = new DropperArenaHandler();
this.arenaHandler.loadArenas();
this.arenaHandler.loadGroups();
//TODO: Store various information about players' performance, and hook into PlaceholderAPI

View File

@ -1,5 +1,6 @@
package net.knarcraft.dropper.arena;
import net.knarcraft.dropper.util.ArenaStorageHelper;
import org.bukkit.Location;
import org.bukkit.Material;
import org.jetbrains.annotations.NotNull;
@ -46,11 +47,6 @@ public class DropperArena {
*/
private final float playerHorizontalVelocity;
/**
* The stage number of this arena. If not null, the previous stage number must be cleared before access.
*/
private final @Nullable Integer stage;
/**
* The material of the block players have to hit to win this dropper arena
*/
@ -72,21 +68,18 @@ public class DropperArena {
* @param exitLocation <p>The location the players are teleported to when exiting the arena, or null</p>
* @param playerVerticalVelocity <p>The velocity to use for players' vertical velocity</p>
* @param playerHorizontalVelocity <p>The velocity to use for players' horizontal velocity (-1 to 1)</p>
* @param stage <p>The stage number of this stage, or null if not limited to stages</p>
* @param winBlockType <p>The material of the block players have to hit to win this dropper arena</p>
* @param dropperArenaData <p>The arena data keeping track of which players have done what in this arena</p>
*/
public DropperArena(@NotNull UUID arenaId, @NotNull String arenaName, @NotNull Location spawnLocation,
@Nullable Location exitLocation, double playerVerticalVelocity, float playerHorizontalVelocity,
@Nullable Integer stage, @NotNull Material winBlockType,
@NotNull DropperArenaData dropperArenaData) {
@NotNull Material winBlockType, @NotNull DropperArenaData dropperArenaData) {
this.arenaId = arenaId;
this.arenaName = arenaName;
this.spawnLocation = spawnLocation;
this.exitLocation = exitLocation;
this.playerVerticalVelocity = playerVerticalVelocity;
this.playerHorizontalVelocity = playerHorizontalVelocity;
this.stage = stage;
this.winBlockType = winBlockType;
this.dropperArenaData = dropperArenaData;
}
@ -107,7 +100,6 @@ public class DropperArena {
this.exitLocation = null;
this.playerVerticalVelocity = 1;
this.playerHorizontalVelocity = 1;
this.stage = null;
this.dropperArenaData = new DropperArenaData(this.arenaId, new DropperArenaRecordsRegistry(this.arenaId),
new HashSet<>());
this.winBlockType = Material.WATER;
@ -183,18 +175,6 @@ public class DropperArena {
return this.playerHorizontalVelocity;
}
/**
* Gets the stage this arena belongs to
*
* <p>It's assumed that arena stages go from 1,2,3,4,... and upwards. If the stage number is set, this arena can
* only be played if all previous stages have been beaten. If not set, however, this arena can be used freely.</p>
*
* @return <p>This arena's stage number</p>
*/
public @Nullable Integer getStage() {
return this.stage;
}
/**
* Gets the type of block a player has to hit to win this arena
*
@ -204,4 +184,21 @@ public class DropperArena {
return this.winBlockType;
}
/**
* Gets this arena's sanitized name
*
* @return <p>This arena's sanitized name</p>
*/
public @NotNull String getArenaNameSanitized() {
return ArenaStorageHelper.sanitizeArenaName(this.getArenaName());
}
@Override
public boolean equals(Object other) {
if (!(other instanceof DropperArena otherArena)) {
return false;
}
return this.getArenaNameSanitized().equals(otherArena.getArenaNameSanitized());
}
}

View File

@ -1,5 +1,6 @@
package net.knarcraft.dropper.arena;
import net.knarcraft.dropper.Dropper;
import net.knarcraft.dropper.container.SerializableUUID;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.bukkit.entity.Player;
@ -41,8 +42,8 @@ public record DropperArenaData(@NotNull UUID arenaId, @NotNull DropperArenaRecor
* @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 hasCompleted(@NotNull Player player) {
return this.playersCompleted.contains(new SerializableUUID(player.getUniqueId()));
public boolean hasNotCompleted(@NotNull Player player) {
return !this.playersCompleted.contains(new SerializableUUID(player.getUniqueId()));
}
/**
@ -50,8 +51,13 @@ public record DropperArenaData(@NotNull UUID arenaId, @NotNull DropperArenaRecor
*
* @param player <p>The player that completed this data's arena</p>
*/
public void addCompleted(@NotNull Player player) {
this.playersCompleted.add(new SerializableUUID(player.getUniqueId()));
public boolean addCompleted(@NotNull Player player) {
boolean added = this.playersCompleted.add(new SerializableUUID(player.getUniqueId()));
// Persistently save the completion
if (added) {
Dropper.getInstance().getArenaHandler().saveData(this.arenaId);
}
return added;
}
@NotNull

View File

@ -0,0 +1,250 @@
package net.knarcraft.dropper.arena;
import net.knarcraft.dropper.Dropper;
import net.knarcraft.dropper.container.SerializableUUID;
import net.knarcraft.dropper.util.ArenaStorageHelper;
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
*
* @param player <p>The player to check</p>
* @return <p>True if the player has beaten all arenas, false otherwise</p>
*/
public boolean hasBeatenAll(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.getInstance().getLogger().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(player)) {
return false;
}
}
return true;
}
/**
* Gets whether the given player can play the given arena part of this group
*
* @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(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 == 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.getInstance().getLogger().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(player)) {
return false;
}
}
return false;
}
/**
* Gets this group's name, but sanitized
*
* @return <p>The sanitized group name</p>
*/
public @NotNull String getGroupNameSanitized() {
return ArenaStorageHelper.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

@ -2,13 +2,13 @@ package net.knarcraft.dropper.arena;
import net.knarcraft.dropper.Dropper;
import net.knarcraft.dropper.util.ArenaStorageHelper;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Level;
@ -18,22 +18,57 @@ import java.util.logging.Level;
public class DropperArenaHandler {
private Map<UUID, DropperArena> arenas = new HashMap<>();
private final Map<Player, Integer> stagesCleared = new HashMap<>();
private Map<UUID, DropperArenaGroup> arenaGroups = new HashMap<>();
private Map<String, UUID> arenaNameLookup = new HashMap<>();
/**
* Tries to register the given stage as cleared
* Gets the group the given arena belongs to
*
* @param player <p>The player that cleared a stage</p>
* @param stage <p>The stage the player cleared</p>
* @return <p>True if the player cleared a new stage</p>
* @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 boolean registerStageCleared(@NotNull Player player, int stage) {
if ((!stagesCleared.containsKey(player) && stage == 1) || (stagesCleared.containsKey(player) &&
stage == stagesCleared.get(player) + 1)) {
stagesCleared.put(player, stage);
return true;
} else {
return false;
public @Nullable DropperArenaGroup 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</p>
*/
public void setGroup(@NotNull UUID arenaId, @NotNull DropperArenaGroup arenaGroup) {
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 DropperArenaGroup getGroup(String groupName) {
String sanitized = ArenaStorageHelper.sanitizeArenaName(groupName);
for (DropperArenaGroup arenaGroup : this.arenaGroups.values()) {
if (arenaGroup.getGroupNameSanitized().equals(sanitized)) {
return arenaGroup;
}
}
return null;
}
/**
* Removes the given arena from its group
*
* @param arenaId <p>The id of the arena to ungroup</p>
*/
public void removeFromGroup(@NotNull UUID arenaId) {
if (this.arenaGroups.containsKey(arenaId)) {
this.arenaGroups.get(arenaId).removeArena(arenaId);
this.arenaGroups.remove(arenaId);
saveGroups();
}
}
@ -44,9 +79,20 @@ public class DropperArenaHandler {
*/
public void addArena(@NotNull DropperArena 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 DropperArena getArena(@NotNull UUID arenaId) {
return this.arenas.get(arenaId);
}
/**
* Gets the arena with the given name
*
@ -54,13 +100,7 @@ public class DropperArenaHandler {
* @return <p>The arena with the given name, or null if not found</p>
*/
public @Nullable DropperArena getArena(@NotNull String arenaName) {
arenaName = ArenaStorageHelper.sanitizeArenaName(arenaName);
for (DropperArena arena : arenas.values()) {
if (ArenaStorageHelper.sanitizeArenaName(arena.getArenaName()).equals(arenaName)) {
return arena;
}
}
return null;
return this.arenas.get(this.arenaNameLookup.get(ArenaStorageHelper.sanitizeArenaName(arenaName)));
}
/**
@ -80,6 +120,8 @@ public class DropperArenaHandler {
public void removeArena(@NotNull DropperArena arena) {
Dropper.getInstance().getPlayerRegistry().removeForArena(arena);
this.arenas.remove(arena.getArenaId());
this.arenaNameLookup.remove(arena.getArenaNameSanitized());
this.arenaGroups.remove(arena.getArenaId());
this.saveArenas();
}
@ -97,6 +139,33 @@ public class DropperArenaHandler {
}
}
/**
* Saves all current dropper groups to disk
*/
public void saveGroups() {
try {
ArenaStorageHelper.saveDropperArenaGroups((Set<DropperArenaGroup>) this.arenaGroups.values());
} catch (IOException e) {
Dropper.getInstance().getLogger().log(Level.SEVERE, "Unable to save current arena groups! " +
"Data loss can occur!");
Dropper.getInstance().getLogger().log(Level.SEVERE, e.getMessage());
}
}
/**
* Loads all dropper groups from disk
*/
public void loadGroups() {
Set<DropperArenaGroup> arenaGroups = ArenaStorageHelper.loadDropperArenaGroups();
Map<UUID, DropperArenaGroup> arenaGroupMap = new HashMap<>();
for (DropperArenaGroup arenaGroup : arenaGroups) {
for (UUID arenaId : arenaGroup.getArenas()) {
arenaGroupMap.put(arenaId, arenaGroup);
}
}
this.arenaGroups = arenaGroupMap;
}
/**
* Saves all current arenas to disk
*/
@ -115,6 +184,13 @@ public class DropperArenaHandler {
*/
public void loadArenas() {
this.arenas = ArenaStorageHelper.loadArenas();
// Save a map from arena name to arena id for improved performance
this.arenaNameLookup = new HashMap<>();
for (Map.Entry<UUID, DropperArena> arena : this.arenas.entrySet()) {
String sanitizedName = arena.getValue().getArenaNameSanitized();
this.arenaNameLookup.put(sanitizedName, arena.getKey());
}
}
}

View File

@ -63,15 +63,10 @@ public class DropperArenaSession {
//TODO: Give reward?
// Register and announce any cleared stages
Integer arenaStage = this.arena.getStage();
if (arenaStage != null) {
boolean clearedNewStage = Dropper.getInstance().getArenaHandler().registerStageCleared(this.player, arenaStage);
if (clearedNewStage) {
this.player.sendMessage("You cleared stage " + arenaStage + "!");
}
// Mark the arena as cleared
if (this.arena.getData().addCompleted(this.player)) {
this.player.sendMessage("You cleared the arena!");
}
this.player.sendMessage("You won!");
// Teleport the player out of the arena

View File

@ -25,7 +25,7 @@ public class CreateArenaCommand implements CommandExecutor {
if (arguments.length < 1) {
return false;
}
DropperArena existingArena = Dropper.getInstance().getArenaHandler().getArena(arguments[0]);
if (existingArena != null) {
commandSender.sendMessage("There already exists a dropper arena with that name!");

View File

@ -2,6 +2,7 @@ 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.DropperArenaPlayerRegistry;
import net.knarcraft.dropper.arena.DropperArenaSession;
import net.knarcraft.dropper.property.ArenaGameMode;
@ -69,7 +70,17 @@ public class JoinArenaCommand implements CommandExecutor {
gameMode = ArenaGameMode.DEFAULT;
}
//TODO: Check if the arena has been beaten if the non-default game-mode has been chosen
// Make sure the player has beaten the necessary levels
DropperArenaGroup arenaGroup = Dropper.getInstance().getArenaHandler().getGroup(specifiedArena.getArenaId());
if (arenaGroup != null && !doGroupChecks(specifiedArena, arenaGroup, gameMode, player)) {
return false;
}
// Make sure the player has beaten the arena once before playing a challenge mode
if (gameMode != ArenaGameMode.DEFAULT && specifiedArena.getData().hasNotCompleted(player)) {
player.sendMessage("You must complete this arena in normal mode before starting a challenge!");
return false;
}
// Register the player's session
DropperArenaSession newSession = new DropperArenaSession(specifiedArena, player, gameMode);
@ -90,4 +101,30 @@ public class JoinArenaCommand implements CommandExecutor {
}
}
/**
* Performs necessary check for the given arena's group
*
* @param dropperArena <p>The arena the player is trying to join</p>
* @param arenaGroup <p>The arena group the arena belongs to</p>
* @param arenaGameMode <p>The game-mode the player selected</p>
* @param player <p>The the player trying to join the arena</p>
* @return <p>False if any checks failed</p>
*/
private boolean doGroupChecks(@NotNull DropperArena dropperArena, @NotNull DropperArenaGroup arenaGroup,
@NotNull ArenaGameMode arenaGameMode, @NotNull Player player) {
if (arenaGameMode == ArenaGameMode.DEFAULT) {
if (!arenaGroup.canPlay(player, dropperArena.getArenaId())) {
player.sendMessage("You have not yet beaten the previous arena!");
return false;
}
} else {
if (arenaGroup.hasBeatenAll(player)) {
player.sendMessage("You have not yet beaten all arenas in this group!");
return false;
}
}
return true;
}
}

View File

@ -37,11 +37,6 @@ public enum ArenaStorageKey {
*/
PLAYER_HORIZONTAL_VELOCITY("arenaPlayerHorizontalVelocity"),
/**
* The key for this arena's stage
*/
STAGE("arenaStage"),
/**
* The key for the type of this arena's win block
*/

View File

@ -3,6 +3,7 @@ package net.knarcraft.dropper.util;
import net.knarcraft.dropper.Dropper;
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.container.SerializableMaterial;
import net.knarcraft.dropper.container.SerializableUUID;
@ -19,6 +20,7 @@ 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;
@ -28,7 +30,9 @@ import java.util.logging.Level;
public final class ArenaStorageHelper {
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 ArenaStorageHelper() {
@ -36,7 +40,46 @@ public final class ArenaStorageHelper {
}
/**
* Saves the given arenas to the given file
* Saves the given dropper arena groups
*
* @param arenaGroups <p>The arena groups to save</p>
* @throws IOException <p>If unable to write to the file</p>
*/
public static void saveDropperArenaGroups(@NotNull Set<DropperArenaGroup> arenaGroups) throws IOException {
YamlConfiguration configuration = new YamlConfiguration();
ConfigurationSection groupSection = configuration.createSection(groupsConfigurationSection);
for (DropperArenaGroup arenaGroup : arenaGroups) {
groupSection.set(arenaGroup.getGroupId().toString(), arenaGroup);
}
configuration.save(groupFile);
}
/**
* Loads all existing dropper arena groups
*
* @return <p>The loaded arena groups</p>
*/
public static @NotNull Set<DropperArenaGroup> loadDropperArenaGroups() {
YamlConfiguration configuration = YamlConfiguration.loadConfiguration(groupFile);
ConfigurationSection groupSection = configuration.getConfigurationSection(groupsConfigurationSection);
//If no such section exists, it must be the case that there is no data to load
if (groupSection == null) {
return new HashSet<>();
}
Set<DropperArenaGroup> arenaGroups = new HashSet<>();
for (String sectionName : groupSection.getKeys(false)) {
arenaGroups.add((DropperArenaGroup) groupSection.get(sectionName));
}
return arenaGroups;
}
/**
* Saves the given arenas
*
* @param arenas <p>The arenas to save</p>
* @throws IOException <p>If unable to write to the file</p>
@ -47,15 +90,13 @@ public final class ArenaStorageHelper {
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(sanitizeArenaName(
arena.getArenaName()));
@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.STAGE.getKey(), arena.getStage());
configSection.set(ArenaStorageKey.WIN_BLOCK_TYPE.getKey(), new SerializableMaterial(arena.getWinBlockType()));
saveArenaData(arena.getData());
}
@ -63,7 +104,7 @@ public final class ArenaStorageHelper {
}
/**
* Loads all arenas from the given file
* Loads all arenas
*
* @return <p>The loaded arenas, or null if the arenas configuration section is missing.</p>
*/
@ -108,7 +149,6 @@ public final class ArenaStorageHelper {
double verticalVelocity = configurationSection.getDouble(ArenaStorageKey.PLAYER_VERTICAL_VELOCITY.getKey());
float horizontalVelocity = sanitizeHorizontalVelocity((float) configurationSection.getDouble(
ArenaStorageKey.PLAYER_HORIZONTAL_VELOCITY.getKey()));
Integer stage = (Integer) configurationSection.get(ArenaStorageKey.STAGE.getKey());
SerializableMaterial winBlockType = (SerializableMaterial) configurationSection.get(
ArenaStorageKey.WIN_BLOCK_TYPE.getKey());
@ -128,7 +168,7 @@ public final class ArenaStorageHelper {
}
return new DropperArena(arenaId, arenaName, spawnLocation, exitLocation, verticalVelocity, horizontalVelocity,
stage, winBlockType.material(), arenaData);
winBlockType.material(), arenaData);
}
/**

View File

@ -0,0 +1,50 @@
package net.knarcraft.dropper.arena;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/**
* Tests for arena dropper groups
*/
public class DropperArenaGroupTest {
@Test
public void swapTest() {
/*
This test makes sure the order of arenas is as expected when the arenas are added to a group. It also makes
sure that swapping two items works as expected.
*/
DropperArenaGroup arenaGroup = new DropperArenaGroup("test");
UUID arena1Id = UUID.randomUUID();
UUID arena2Id = UUID.randomUUID();
UUID arena3Id = UUID.randomUUID();
UUID arena4Id = UUID.randomUUID();
arenaGroup.addArena(arena1Id);
arenaGroup.addArena(arena2Id);
arenaGroup.addArena(arena3Id);
arenaGroup.addArena(arena4Id);
List<UUID> initialOrder = new ArrayList<>();
initialOrder.add(arena1Id);
initialOrder.add(arena2Id);
initialOrder.add(arena3Id);
initialOrder.add(arena4Id);
Assertions.assertEquals(initialOrder, arenaGroup.getArenas());
arenaGroup.swapArenas(1, 3);
List<UUID> swapped = new ArrayList<>();
swapped.add(arena1Id);
swapped.add(arena4Id);
swapped.add(arena3Id);
swapped.add(arena2Id);
Assertions.assertEquals(swapped, arenaGroup.getArenas());
}
}