Implements #42

This commit is contained in:
Kristian Knarvik 2024-04-30 15:50:18 +02:00
parent 98b5ea5abe
commit fb68c18fe6
31 changed files with 415 additions and 254 deletions

View File

@ -314,13 +314,23 @@ format for the built-in placeholders is as follows:
| Variable | Values | Description | | Variable | Values | Description |
|-----------------|----------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------| |-----------------|----------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------|
| gameMode | dropper / parkour | A selection of which game-mode you are getting a record for | | gameMode | dropper / parkour | A selection of which game-mode you are getting a record for |
| players_playing | | This must be as-is. It's a selector in case placeholders are added for more than playing players. | | players_playing | | This must be as-is. |
| gameModeType | default / inverted / random / hardcore / all | Selects the game-mode to get the players for. Note that "all" combines players for all game-modes. | | gameModeType | default / inverted / random / hardcore / all | Selects the game-mode to get the players for. Note that "all" combines players for all game-modes. |
| identifierType | arena / group | The type of thing the following identifier points to (an arena or an arena group). | | identifierType | arena / group | The type of thing the following identifier points to (an arena or an arena group). |
| identifier | ? | An identifier (the name or UUID) for an arena or a group (whichever was chosen as identifierType). | | identifier | ? | An identifier (the name or UUID) for an arena or a group (whichever was chosen as identifierType). |
| playerInfoType | player / count | The type of info to get. Player gets the player name, and count gets the total number of players. | | playerInfoType | player / count | The type of info to get. Player gets the player name, and count gets the total number of players. |
| playerNumber | 1 / 2 / 3 / ... | The player number to get the name of. Players are numbered after their sorted names. This argument is not used when getting the player count. | | playerNumber | 1 / 2 / 3 / ... | The player number to get the name of. Players are numbered after their sorted names. This argument is not used when getting the player count. |
### Max Players Placeholder
`%gameMode_players_max_arenaName%`
| Variable | Values | Description |
|-----------------|-------------------|-------------------------------------------------------------|
| gameMode | dropper / parkour | A selection of which game-mode you are getting a record for |
| players_maximum | | This must be as-is. |
| arenaName | ? | An identifier (the name or UUID) for an arena. |
## Notes about material tags ## Notes about material tags
Where a list of material is allowed, this plugin supports using material tags that specify a set of blocks. This makes Where a list of material is allowed, this plugin supports using material tags that specify a set of blocks. This makes

View File

@ -3,6 +3,7 @@ package net.knarcraft.minigames.arena;
import net.knarcraft.minigames.arena.reward.Reward; import net.knarcraft.minigames.arena.reward.Reward;
import net.knarcraft.minigames.arena.reward.RewardCondition; import net.knarcraft.minigames.arena.reward.RewardCondition;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -13,6 +14,7 @@ import java.util.UUID;
/** /**
* An interface describing an arena * An interface describing an arena
*/ */
@SuppressWarnings("unused")
public interface Arena { public interface Arena {
/** /**
@ -23,6 +25,14 @@ public interface Arena {
@NotNull @NotNull
String getArenaName(); String getArenaName();
/**
* Sets the name of this arena
*
* @param arenaName <p>The new name</p>
* @return <p>True if successfully updated</p>
*/
boolean setName(@NotNull String arenaName);
/** /**
* Gets the data stored for this arena * Gets the data stored for this arena
* *
@ -61,6 +71,24 @@ public interface Arena {
*/ */
boolean saveData(); boolean saveData();
/**
* Gets the type of block a player has to hit to win this arena
*
* @return <p>The kind of block players must hit</p>
*/
@NotNull
Material getWinBlockType();
/**
* 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>
*/
boolean setWinBlockType(@NotNull Material material);
/** /**
* Gets whether standing on the given block should cause a win * Gets whether standing on the given block should cause a win
* *
@ -92,6 +120,14 @@ public interface Arena {
@NotNull @NotNull
Location getSpawnLocation(); Location getSpawnLocation();
/**
* Sets the spawn location for this arena
*
* @param newLocation <p>The new spawn location</p>
* @return <p>True if successfully updated</p>
*/
boolean setSpawnLocation(@Nullable Location newLocation);
/** /**
* Gets this arena's exit location * Gets this arena's exit location
* *
@ -100,6 +136,14 @@ public interface Arena {
@Nullable @Nullable
Location getExitLocation(); Location getExitLocation();
/**
* Sets the exit location for this arena
*
* @param newLocation <p>The new exit location</p>
* @return <p>True if successfully updated</p>
*/
boolean setExitLocation(@Nullable Location newLocation);
/** /**
* Adds a reward to this arena * Adds a reward to this arena
* *
@ -124,4 +168,18 @@ public interface Arena {
@NotNull @NotNull
Set<Reward> getRewards(RewardCondition rewardCondition); Set<Reward> getRewards(RewardCondition rewardCondition);
/**
* Gets the maximum amount of players that can join this arena at once
*
* @return <p>The maximum amount of players</p>
*/
int getMaxPlayers();
/**
* Sets the maximum amount of players that can join this arena at once
*
* @param newValue <p>The new maximum amount of players</p>
*/
boolean setMaxPlayers(int newValue);
} }

View File

@ -151,8 +151,12 @@ public abstract class ArenaHandler<K extends Arena, S extends ArenaGroup<K, S>>
* @return <p>The arena with the given name, or null if not found</p> * @return <p>The arena with the given name, or null if not found</p>
*/ */
public @Nullable K getArena(@NotNull String arenaName) { public @Nullable K getArena(@NotNull String arenaName) {
try {
return this.arenas.get(UUID.fromString(arenaName));
} catch (IllegalArgumentException exception) {
return this.arenas.get(this.arenaNameLookup.get(StringSanitizer.sanitizeArenaName(arenaName))); return this.arenas.get(this.arenaNameLookup.get(StringSanitizer.sanitizeArenaName(arenaName)));
} }
}
/** /**
* Gets all known arenas * Gets all known arenas

View File

@ -45,4 +45,9 @@ public enum EditablePropertyType {
*/ */
DOUBLE, DOUBLE,
/**
* The property is an integer with no particular restrictions
*/
INTEGER,
} }

View File

@ -63,6 +63,11 @@ public class DropperArena implements Arena {
*/ */
private float playerHorizontalVelocity; private float playerHorizontalVelocity;
/**
* The maximum amount of players able to join this arena at any time
*/
private int maxPlayers = -1;
/** /**
* The material of the block players have to hit to win this dropper arena * The material of the block players have to hit to win this dropper arena
*/ */
@ -89,14 +94,16 @@ public class DropperArena implements Arena {
* @param playerVerticalVelocity <p>The velocity to use for players' vertical velocity</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 playerHorizontalVelocity <p>The velocity to use for players' horizontal velocity (-1 to 1)</p>
* @param winBlockType <p>The material of the block players have to hit to win this dropper arena</p> * @param winBlockType <p>The material of the block players have to hit to win this dropper arena</p>
* @param maxPlayers <p>The maximum amount of players able to join this arena at once</p>
* @param rewards <p>The rewards given by this arena</p> * @param rewards <p>The rewards given by this arena</p>
* @param dropperArenaData <p>The arena data keeping track of which players have done what in this arena</p> * @param dropperArenaData <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> * @param arenaHandler <p>The arena handler used for saving any changes</p>
*/ */
public DropperArena(@NotNull UUID arenaId, @NotNull String arenaName, @NotNull Location spawnLocation, public DropperArena(@NotNull UUID arenaId, @NotNull String arenaName, @NotNull Location spawnLocation,
@Nullable Location exitLocation, double playerVerticalVelocity, float playerHorizontalVelocity, @Nullable Location exitLocation, double playerVerticalVelocity, float playerHorizontalVelocity,
@NotNull Material winBlockType, @NotNull Map<RewardCondition, Set<Reward>> rewards, @NotNull Material winBlockType, int maxPlayers,
@NotNull DropperArenaData dropperArenaData, @NotNull DropperArenaHandler arenaHandler) { @NotNull Map<RewardCondition, Set<Reward>> rewards, @NotNull DropperArenaData dropperArenaData,
@NotNull DropperArenaHandler arenaHandler) {
this.arenaId = arenaId; this.arenaId = arenaId;
this.arenaName = arenaName; this.arenaName = arenaName;
this.spawnLocation = spawnLocation; this.spawnLocation = spawnLocation;
@ -107,6 +114,7 @@ public class DropperArena implements Arena {
this.dropperArenaData = dropperArenaData; this.dropperArenaData = dropperArenaData;
this.dropperArenaHandler = arenaHandler; this.dropperArenaHandler = arenaHandler;
this.rewards = rewards; this.rewards = rewards;
this.maxPlayers = maxPlayers;
} }
/** /**
@ -186,44 +194,27 @@ public class DropperArena implements Arena {
} }
} }
/** @Override
* Gets the vertical velocity for players in this arena public int getMaxPlayers() {
* return this.maxPlayers;
* <p>This velocity will be set on the negative y-axis, for all players in this arena.</p>
*
* @return <p>Players' velocity in this arena</p>
*/
public double getPlayerVerticalVelocity() {
return this.playerVerticalVelocity;
} }
@Override
/** public boolean setMaxPlayers(int newValue) {
* Gets the horizontal for players in this arena this.maxPlayers = newValue;
* this.saveArena();
* <p>This will be used for players' fly-speed in this arena</p> return true;
*
* @return <p>Players' velocity in this arena</p>
*/
public float getPlayerHorizontalVelocity() {
return this.playerHorizontalVelocity;
} }
/** @Override
* Gets the type of block a player has to hit to win this arena @NotNull
* public Material getWinBlockType() {
* @return <p>The kind of block players must hit</p>
*/
public @NotNull Material getWinBlockType() {
return this.winBlockType; return this.winBlockType;
} }
/** @Override
* Gets this arena's sanitized name @NotNull
* public String getArenaNameSanitized() {
* @return <p>This arena's sanitized name</p>
*/
public @NotNull String getArenaNameSanitized() {
return StringSanitizer.sanitizeArenaName(this.getArenaName()); return StringSanitizer.sanitizeArenaName(this.getArenaName());
} }
@ -257,12 +248,7 @@ public class DropperArena implements Arena {
return winBlockType.isSolid(); return winBlockType.isSolid();
} }
/** @Override
* 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(@Nullable Location newLocation) { public boolean setSpawnLocation(@Nullable Location newLocation) {
if (isInvalid(newLocation)) { if (isInvalid(newLocation)) {
return false; return false;
@ -273,12 +259,7 @@ public class DropperArena implements Arena {
} }
} }
/** @Override
* 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(@Nullable Location newLocation) { public boolean setExitLocation(@Nullable Location newLocation) {
if (isInvalid(newLocation)) { if (isInvalid(newLocation)) {
return false; return false;
@ -289,12 +270,7 @@ public class DropperArena implements Arena {
} }
} }
/** @Override
* 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) { public boolean setName(@NotNull String arenaName) {
if (!arenaName.isBlank()) { if (!arenaName.isBlank()) {
String oldName = this.getArenaNameSanitized(); String oldName = this.getArenaNameSanitized();
@ -309,13 +285,29 @@ public class DropperArena implements Arena {
} }
/** /**
* Sets the material of the win block type * Gets the vertical velocity for players in this arena
* *
* <p>The win block type is the type of block a player must hit to win in this arena</p> * <p>This velocity will be set on the negative y-axis, for all players in this arena.</p>
* *
* @param material <p>The material to set for the win block type</p> * @return <p>Players' velocity in this arena</p>
* @return <p>True if successfully updated</p>
*/ */
public double getPlayerVerticalVelocity() {
return this.playerVerticalVelocity;
}
/**
* Gets the horizontal for players in this arena
*
* <p>This will be used for players' fly-speed in this arena</p>
*
* @return <p>Players' velocity in this arena</p>
*/
public float getPlayerHorizontalVelocity() {
return this.playerHorizontalVelocity;
}
@Override
public boolean setWinBlockType(@NotNull Material material) { public boolean setWinBlockType(@NotNull Material material) {
if (material.isAir() || !material.isBlock()) { if (material.isAir() || !material.isBlock()) {
return false; return false;

View File

@ -45,6 +45,12 @@ public enum DropperArenaEditableProperty {
*/ */
WIN_BLOCK_TYPE("winBlockType", (arena) -> arena.getWinBlockType().toString(), WIN_BLOCK_TYPE("winBlockType", (arena) -> arena.getWinBlockType().toString(),
EditablePropertyType.BLOCK_TYPE), EditablePropertyType.BLOCK_TYPE),
/**
* The arena's max players
*/
MAX_PLAYERS("maxPlayers", (arena) -> String.valueOf(arena.getMaxPlayers()),
EditablePropertyType.INTEGER),
; ;
private final @NotNull String argumentString; private final @NotNull String argumentString;

View File

@ -51,6 +51,11 @@ public enum DropperArenaStorageKey {
* The key for this arena's rewards * The key for this arena's rewards
*/ */
REWARDS("rewards"), REWARDS("rewards"),
/**
* The key for this arena's maximum players
*/
MAX_PLAYERS("maxPlayers"),
; ;
private final @NotNull String key; private final @NotNull String key;

View File

@ -84,6 +84,11 @@ public class ParkourArena implements Arena {
*/ */
private @Nullable Set<Material> obstacleBlocks; private @Nullable Set<Material> obstacleBlocks;
/**
* The maximum amount of players able to join this arena at any time
*/
private int maxPlayers;
/** /**
* The checkpoints for this arena. Entering a checkpoint overrides the player's spawn location. * The checkpoints for this arena. Entering a checkpoint overrides the player's spawn location.
*/ */
@ -110,6 +115,7 @@ public class ParkourArena implements Arena {
* @param killPlaneBlockNames <p>The names of the types of blocks that trigger a loss when stepped on</p> * @param killPlaneBlockNames <p>The names of the types of blocks that trigger a loss when stepped on</p>
* @param obstacleBlockNames <p>The names of the types of blocks that trigger a loss when touched</p> * @param obstacleBlockNames <p>The names of the types of blocks that trigger a loss when touched</p>
* @param checkpoints <p>The checkpoints set for this arena</p> * @param checkpoints <p>The checkpoints set for this arena</p>
* @param maxPlayers <p>The maximum amount of players able to join this arena at once</p>
* @param rewards <p>The rewards given by this arena</p> * @param rewards <p>The rewards given by this arena</p>
* @param parkourArenaData <p>The arena data keeping track of which players have done what in this 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> * @param arenaHandler <p>The arena handler used for saving any changes</p>
@ -117,7 +123,7 @@ public class ParkourArena implements Arena {
public ParkourArena(@NotNull UUID arenaId, @NotNull String arenaName, @NotNull Location spawnLocation, public ParkourArena(@NotNull UUID arenaId, @NotNull String arenaName, @NotNull Location spawnLocation,
@Nullable Location exitLocation, @NotNull Material winBlockType, @Nullable Location winLocation, @Nullable Location exitLocation, @NotNull Material winBlockType, @Nullable Location winLocation,
@Nullable Set<String> killPlaneBlockNames, @Nullable Set<String> obstacleBlockNames, @Nullable Set<String> killPlaneBlockNames, @Nullable Set<String> obstacleBlockNames,
@NotNull List<Location> checkpoints, @NotNull List<Location> checkpoints, int maxPlayers,
@NotNull Map<RewardCondition, Set<Reward>> rewards, @NotNull Map<RewardCondition, Set<Reward>> rewards,
@NotNull ParkourArenaData parkourArenaData, @NotNull ParkourArenaHandler arenaHandler) { @NotNull ParkourArenaData parkourArenaData, @NotNull ParkourArenaHandler arenaHandler) {
this.arenaId = arenaId; this.arenaId = arenaId;
@ -136,6 +142,7 @@ public class ParkourArena implements Arena {
this.parkourArenaData = parkourArenaData; this.parkourArenaData = parkourArenaData;
this.parkourArenaHandler = arenaHandler; this.parkourArenaHandler = arenaHandler;
this.rewards = rewards; this.rewards = rewards;
this.maxPlayers = maxPlayers;
} }
/** /**
@ -167,6 +174,7 @@ public class ParkourArena implements Arena {
this.obstacleBlocks = null; this.obstacleBlocks = null;
this.checkpoints = new ArrayList<>(); this.checkpoints = new ArrayList<>();
this.parkourArenaHandler = arenaHandler; this.parkourArenaHandler = arenaHandler;
this.maxPlayers = -1;
} }
@Override @Override
@ -216,12 +224,25 @@ public class ParkourArena implements Arena {
} }
} }
/** @Override
* Gets the type of block a player has to hit to win this arena public int getMaxPlayers() {
* return this.maxPlayers;
* @return <p>The kind of block players must hit</p> }
*/
public @NotNull Material getWinBlockType() { @Override
public boolean setMaxPlayers(int newValue) {
if (newValue < -1) {
return false;
}
this.maxPlayers = newValue;
this.saveArena();
return true;
}
@Override
@NotNull
public Material getWinBlockType() {
return this.winBlockType; return this.winBlockType;
} }
@ -302,12 +323,9 @@ public class ParkourArena implements Arena {
return this.checkpoints.isEmpty(); return this.checkpoints.isEmpty();
} }
/** @Override
* Gets this arena's sanitized name @NotNull
* public String getArenaNameSanitized() {
* @return <p>This arena's sanitized name</p>
*/
public @NotNull String getArenaNameSanitized() {
return StringSanitizer.sanitizeArenaName(this.getArenaName()); return StringSanitizer.sanitizeArenaName(this.getArenaName());
} }
@ -350,12 +368,7 @@ public class ParkourArena implements Arena {
this.winBlockType.isSolid(); this.winBlockType.isSolid();
} }
/** @Override
* 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(@Nullable Location newLocation) { public boolean setSpawnLocation(@Nullable Location newLocation) {
if (isInvalid(newLocation)) { if (isInvalid(newLocation)) {
return false; return false;
@ -366,12 +379,7 @@ public class ParkourArena implements Arena {
} }
} }
/** @Override
* 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(@Nullable Location newLocation) { public boolean setExitLocation(@Nullable Location newLocation) {
if (isInvalid(newLocation)) { if (isInvalid(newLocation)) {
return false; return false;
@ -382,12 +390,7 @@ public class ParkourArena implements Arena {
} }
} }
/** @Override
* 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) { public boolean setName(@NotNull String arenaName) {
if (!arenaName.isBlank()) { if (!arenaName.isBlank()) {
String oldName = this.getArenaNameSanitized(); String oldName = this.getArenaNameSanitized();
@ -401,14 +404,7 @@ public class ParkourArena implements Arena {
} }
} }
/** @Override
* 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) { public boolean setWinBlockType(@NotNull Material material) {
if (material.isAir() || !material.isBlock()) { if (material.isAir() || !material.isBlock()) {
return false; return false;

View File

@ -69,6 +69,11 @@ public enum ParkourArenaEditableProperty {
OBSTACLE_BLOCKS("obstacleBlocks", (arena) -> String.valueOf(arena.getObstacleBlockNames()), OBSTACLE_BLOCKS("obstacleBlocks", (arena) -> String.valueOf(arena.getObstacleBlockNames()),
EditablePropertyType.MATERIAL_LIST), EditablePropertyType.MATERIAL_LIST),
/**
* The arena's max players
*/
MAX_PLAYERS("maxPlayers", (arena) -> String.valueOf(arena.getMaxPlayers()),
EditablePropertyType.INTEGER),
; ;
private final @NotNull String argumentString; private final @NotNull String argumentString;

View File

@ -29,7 +29,7 @@ public enum ParkourArenaGameMode implements ConfigurationSerializable, ArenaGame
* @param gameMode <p>The game-mode string to match</p> * @param gameMode <p>The game-mode string to match</p>
* @return <p>The specified arena game-mode</p> * @return <p>The specified arena game-mode</p>
*/ */
public static @NotNull ParkourArenaGameMode matchGamemode(@NotNull String gameMode) { public static @NotNull ParkourArenaGameMode matchGameMode(@NotNull String gameMode) {
try { try {
return ParkourArenaGameMode.valueOf(gameMode.toUpperCase()); return ParkourArenaGameMode.valueOf(gameMode.toUpperCase());
} catch (IllegalArgumentException exception) { } catch (IllegalArgumentException exception) {

View File

@ -61,6 +61,11 @@ public enum ParkourArenaStorageKey {
* The key for this arena's rewards * The key for this arena's rewards
*/ */
REWARDS("rewards"), REWARDS("rewards"),
/**
* The key for this arena's maximum players
*/
MAX_PLAYERS("maxPlayers"),
; ;
private final @NotNull String key; private final @NotNull String key;

View File

@ -0,0 +1,113 @@
package net.knarcraft.minigames.command;
import net.knarcraft.minigames.config.DropperConfiguration;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.command.CommandExecutor;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
/**
* An abstract arena edit command, implementing input validation
*/
public abstract class EditArenaCommand implements CommandExecutor {
private final DropperConfiguration configuration;
/**
* Instantiates a new edit arena command
*
* @param configuration <p>The configuration to use</p>
*/
public EditArenaCommand(DropperConfiguration configuration) {
this.configuration = configuration;
}
/**
* Parses the specified max players
*
* @param maxPlayers <p>The max players string to parse</p>
* @return <p>The parsed value, or -1 if not parse-able</p>
*/
protected int parseMaxPlayers(@NotNull String maxPlayers) {
try {
return Integer.parseInt(maxPlayers);
} catch (NumberFormatException exception) {
return -1;
}
}
/**
* Sanitizes the player's specified vertical velocity
*
* @param velocityString <p>The string to parse into a velocity</p>
* @return <p>The parsed velocity, defaulting to 0.5 if not parse-able</p>
*/
protected double sanitizeVerticalVelocity(@NotNull String velocityString) {
// Vertical velocity should not be negative, as it would make the player go upwards. There is technically not a
// max speed limit, but setting it too high makes the arena unplayable
double velocity;
try {
velocity = Double.parseDouble(velocityString);
} catch (NumberFormatException exception) {
velocity = configuration.getVerticalVelocity();
}
// Require at least speed of 0.001, and at most 75 blocks/s
return Math.min(Math.max(velocity, 0.001), 75);
}
/**
* Sanitizes the user's specified horizontal velocity
*
* @param velocityString <p>The string to parse into a velocity</p>
* @return <p>The parsed velocity, defaulting to 1 if not parse-able</p>
*/
protected float sanitizeHorizontalVelocity(@NotNull String velocityString) {
// Horizontal velocity is valid between -1 and 1, where negative values swaps directions
float velocity;
try {
velocity = Float.parseFloat(velocityString);
} catch (NumberFormatException exception) {
velocity = configuration.getHorizontalVelocity();
}
// If outside bonds, choose the most extreme value
return Math.min(Math.max(0.1f, velocity), 1);
}
/**
* Parses the given location string
*
* @param player <p>The player changing a location</p>
* @param locationString <p>The location string to parse</p>
* @return <p>The parsed location, or the player's location if not parse-able</p>
*/
protected @NotNull Location parseLocation(Player player, String locationString) {
if ((locationString.trim() + ",").matches("([0-9]+.?[0-9]*,){3}")) {
String[] parts = locationString.split(",");
Location newLocation = player.getLocation().clone();
newLocation.setX(Double.parseDouble(parts[0].trim()));
newLocation.setY(Double.parseDouble(parts[1].trim()));
newLocation.setZ(Double.parseDouble(parts[2].trim()));
return newLocation;
} else {
return player.getLocation().clone();
}
}
/**
* Parses the given material name
*
* @param materialName <p>The material name to parse</p>
* @return <p>The parsed material, or AIR if not valid</p>
*/
protected @NotNull Material parseMaterial(String materialName) {
Material material = Material.matchMaterial(materialName);
if (material == null) {
material = Material.AIR;
}
return material;
}
}

View File

@ -5,6 +5,7 @@ import net.knarcraft.minigames.arena.Arena;
import net.knarcraft.minigames.arena.reward.Reward; import net.knarcraft.minigames.arena.reward.Reward;
import net.knarcraft.minigames.arena.reward.RewardCondition; import net.knarcraft.minigames.arena.reward.RewardCondition;
import net.knarcraft.minigames.config.MiniGameMessage; import net.knarcraft.minigames.config.MiniGameMessage;
import net.knarcraft.minigames.util.InputValidationHelper;
import net.knarcraft.minigames.util.RewardHelper; import net.knarcraft.minigames.util.RewardHelper;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandExecutor;
@ -60,7 +61,7 @@ public class SetArenaRewardCommand implements CommandExecutor {
return false; return false;
} }
if (arguments[0].equalsIgnoreCase("clear")) { if (InputValidationHelper.isEmptyValue(arguments[0])) {
arena.clearRewards(condition); arena.clearRewards(condition);
MiniGames.getInstance().getStringFormatter().displaySuccessMessage(player, MiniGames.getInstance().getStringFormatter().displaySuccessMessage(player,
MiniGameMessage.SUCCESS_REWARDS_CLEARED); MiniGameMessage.SUCCESS_REWARDS_CLEARED);

View File

@ -6,6 +6,7 @@ import net.knarcraft.minigames.MiniGames;
import net.knarcraft.minigames.arena.Arena; import net.knarcraft.minigames.arena.Arena;
import net.knarcraft.minigames.arena.reward.RewardCondition; import net.knarcraft.minigames.arena.reward.RewardCondition;
import net.knarcraft.minigames.arena.reward.RewardType; import net.knarcraft.minigames.arena.reward.RewardType;
import net.knarcraft.minigames.util.InputValidationHelper;
import net.knarcraft.minigames.util.TabCompleteHelper; import net.knarcraft.minigames.util.TabCompleteHelper;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.command.Command; import org.bukkit.command.Command;
@ -40,7 +41,7 @@ public class SetArenaRewardTabCompleter implements TabCompleter {
} }
if (arguments.length >= 2) { if (arguments.length >= 2) {
// If the first argument is invalid, stop further tab completion // If the first argument is invalid, stop further tab completion
if (!arguments[0].equalsIgnoreCase("add") && !arguments[0].equalsIgnoreCase("clear")) { if (!arguments[0].equalsIgnoreCase("add") && !InputValidationHelper.isEmptyValue(arguments[0])) {
return new ArrayList<>(); return new ArrayList<>();
} }
} }
@ -73,8 +74,7 @@ public class SetArenaRewardTabCompleter implements TabCompleter {
} }
if (arguments.length >= 5) { if (arguments.length >= 5) {
// If the condition is invalid, or it's the clear action, stop tab-completion // If the condition is invalid, or it's the clear action, stop tab-completion
if (RewardCondition.getFromString(arguments[3]) == null || if (RewardCondition.getFromString(arguments[3]) == null || InputValidationHelper.isEmptyValue(arguments[0])) {
arguments[0].equalsIgnoreCase("clear")) {
return new ArrayList<>(); return new ArrayList<>();
} }
} }

View File

@ -5,6 +5,7 @@ import net.knarcraft.minigames.arena.dropper.DropperArena;
import net.knarcraft.minigames.arena.dropper.DropperArenaGroup; import net.knarcraft.minigames.arena.dropper.DropperArenaGroup;
import net.knarcraft.minigames.arena.dropper.DropperArenaHandler; import net.knarcraft.minigames.arena.dropper.DropperArenaHandler;
import net.knarcraft.minigames.config.MiniGameMessage; import net.knarcraft.minigames.config.MiniGameMessage;
import net.knarcraft.minigames.util.InputValidationHelper;
import net.knarcraft.minigames.util.StringSanitizer; import net.knarcraft.minigames.util.StringSanitizer;
import net.knarcraft.minigames.util.TabCompleteHelper; import net.knarcraft.minigames.util.TabCompleteHelper;
import org.bukkit.command.Command; import org.bukkit.command.Command;
@ -46,7 +47,7 @@ public class DropperGroupSetCommand implements TabExecutor {
} }
DropperArenaGroup arenaGroup; DropperArenaGroup arenaGroup;
if (groupName.equalsIgnoreCase("null") || groupName.equalsIgnoreCase("none")) { if (InputValidationHelper.isEmptyValue(groupName)) {
arenaGroup = null; arenaGroup = null;
} else { } else {
arenaGroup = arenaHandler.getGroup(groupName); arenaGroup = arenaHandler.getGroup(groupName);

View File

@ -4,12 +4,10 @@ import net.knarcraft.knarlib.formatting.StringFormatter;
import net.knarcraft.minigames.MiniGames; import net.knarcraft.minigames.MiniGames;
import net.knarcraft.minigames.arena.dropper.DropperArena; import net.knarcraft.minigames.arena.dropper.DropperArena;
import net.knarcraft.minigames.arena.dropper.DropperArenaEditableProperty; import net.knarcraft.minigames.arena.dropper.DropperArenaEditableProperty;
import net.knarcraft.minigames.command.EditArenaCommand;
import net.knarcraft.minigames.config.DropperConfiguration; import net.knarcraft.minigames.config.DropperConfiguration;
import net.knarcraft.minigames.config.MiniGameMessage; import net.knarcraft.minigames.config.MiniGameMessage;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -17,9 +15,7 @@ import org.jetbrains.annotations.NotNull;
/** /**
* The command for editing an existing dropper arena * The command for editing an existing dropper arena
*/ */
public class EditDropperArenaCommand implements CommandExecutor { public class EditDropperArenaCommand extends EditArenaCommand {
private final DropperConfiguration configuration;
/** /**
* Instantiates a new edit arena command * Instantiates a new edit arena command
@ -27,7 +23,7 @@ public class EditDropperArenaCommand implements CommandExecutor {
* @param configuration <p>The configuration to use</p> * @param configuration <p>The configuration to use</p>
*/ */
public EditDropperArenaCommand(DropperConfiguration configuration) { public EditDropperArenaCommand(DropperConfiguration configuration) {
this.configuration = configuration; super(configuration);
} }
@Override @Override
@ -93,80 +89,8 @@ public class EditDropperArenaCommand implements CommandExecutor {
case SPAWN_LOCATION -> arena.setSpawnLocation(parseLocation(player, value)); case SPAWN_LOCATION -> arena.setSpawnLocation(parseLocation(player, value));
case NAME -> arena.setName(value); case NAME -> arena.setName(value);
case EXIT_LOCATION -> arena.setExitLocation(parseLocation(player, value)); case EXIT_LOCATION -> arena.setExitLocation(parseLocation(player, value));
case MAX_PLAYERS -> arena.setMaxPlayers(parseMaxPlayers(value));
}; };
} }
/**
* Sanitizes the player's specified vertical velocity
*
* @param velocityString <p>The string to parse into a velocity</p>
* @return <p>The parsed velocity, defaulting to 0.5 if not parse-able</p>
*/
private double sanitizeVerticalVelocity(@NotNull String velocityString) {
// Vertical velocity should not be negative, as it would make the player go upwards. There is technically not a
// max speed limit, but setting it too high makes the arena unplayable
double velocity;
try {
velocity = Double.parseDouble(velocityString);
} catch (NumberFormatException exception) {
velocity = configuration.getVerticalVelocity();
}
// Require at least speed of 0.001, and at most 75 blocks/s
return Math.min(Math.max(velocity, 0.001), 75);
}
/**
* Sanitizes the user's specified horizontal velocity
*
* @param velocityString <p>The string to parse into a velocity</p>
* @return <p>The parsed velocity, defaulting to 1 if not parse-able</p>
*/
private float sanitizeHorizontalVelocity(@NotNull String velocityString) {
// Horizontal velocity is valid between -1 and 1, where negative values swaps directions
float velocity;
try {
velocity = Float.parseFloat(velocityString);
} catch (NumberFormatException exception) {
velocity = configuration.getHorizontalVelocity();
}
// If outside bonds, choose the most extreme value
return Math.min(Math.max(0.1f, velocity), 1);
}
/**
* Parses the given location string
*
* @param player <p>The player changing a location</p>
* @param locationString <p>The location string to parse</p>
* @return <p>The parsed location, or the player's location if not parse-able</p>
*/
private @NotNull Location parseLocation(Player player, String locationString) {
if ((locationString.trim() + ",").matches("([0-9]+.?[0-9]*,){3}")) {
String[] parts = locationString.split(",");
Location newLocation = player.getLocation().clone();
newLocation.setX(Double.parseDouble(parts[0].trim()));
newLocation.setY(Double.parseDouble(parts[1].trim()));
newLocation.setZ(Double.parseDouble(parts[2].trim()));
return newLocation;
} else {
return player.getLocation().clone();
}
}
/**
* Parses the given material name
*
* @param materialName <p>The material name to parse</p>
* @return <p>The parsed material, or AIR if not valid</p>
*/
private @NotNull Material parseMaterial(String materialName) {
Material material = Material.matchMaterial(materialName);
if (material == null) {
material = Material.AIR;
}
return material;
}
} }

View File

@ -60,6 +60,13 @@ public class JoinDropperArenaCommand implements CommandExecutor {
return true; return true;
} }
// Deny joining full arenas
int playingNow = MiniGames.getInstance().getDropperArenaPlayerRegistry().getPlayingPlayers(specifiedArena).size();
if (specifiedArena.getMaxPlayers() > 0 && playingNow >= specifiedArena.getMaxPlayers()) {
stringFormatter.displayErrorMessage(commandSender, MiniGameMessage.ERROR_JOIN_ARENA_FULL);
return true;
}
joinArena(specifiedArena, player, arguments); joinArena(specifiedArena, player, arguments);
return true; return true;
} }

View File

@ -4,16 +4,12 @@ import net.knarcraft.knarlib.formatting.StringFormatter;
import net.knarcraft.minigames.MiniGames; import net.knarcraft.minigames.MiniGames;
import net.knarcraft.minigames.arena.parkour.ParkourArena; import net.knarcraft.minigames.arena.parkour.ParkourArena;
import net.knarcraft.minigames.arena.parkour.ParkourArenaEditableProperty; import net.knarcraft.minigames.arena.parkour.ParkourArenaEditableProperty;
import net.knarcraft.minigames.command.EditArenaCommand;
import net.knarcraft.minigames.config.MiniGameMessage; import net.knarcraft.minigames.config.MiniGameMessage;
import net.knarcraft.minigames.util.InputValidationHelper;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@ -21,12 +17,13 @@ import java.util.List;
/** /**
* The command for editing an existing dropper arena * The command for editing an existing dropper arena
*/ */
public class EditParkourArenaCommand implements CommandExecutor { public class EditParkourArenaCommand extends EditArenaCommand {
/** /**
* Instantiates a new edit arena command * Instantiates a new edit arena command
*/ */
public EditParkourArenaCommand() { public EditParkourArenaCommand() {
super(null);
} }
@Override @Override
@ -101,43 +98,8 @@ public class EditParkourArenaCommand implements CommandExecutor {
case CHECKPOINT_CLEAR -> arena.clearCheckpoints(); case CHECKPOINT_CLEAR -> arena.clearCheckpoints();
case KILL_PLANE_BLOCKS -> arena.setKillPlaneBlocks(new HashSet<>(List.of(value.split(",")))); case KILL_PLANE_BLOCKS -> arena.setKillPlaneBlocks(new HashSet<>(List.of(value.split(","))));
case OBSTACLE_BLOCKS -> arena.setObstacleBlocks(new HashSet<>(List.of(value.split(",")))); case OBSTACLE_BLOCKS -> arena.setObstacleBlocks(new HashSet<>(List.of(value.split(","))));
case MAX_PLAYERS -> arena.setMaxPlayers(parseMaxPlayers(value));
}; };
} }
/**
* Parses the given location string
*
* @param player <p>The player changing a location</p>
* @param locationString <p>The location string to parse</p>
* @return <p>The parsed location, or the player's location if not parse-able</p>
*/
private @Nullable Location parseLocation(Player player, String locationString) {
if ((locationString.trim() + ",").matches("([0-9]+.?[0-9]*,){3}")) {
String[] parts = locationString.split(",");
Location newLocation = player.getLocation().clone();
newLocation.setX(Double.parseDouble(parts[0].trim()));
newLocation.setY(Double.parseDouble(parts[1].trim()));
newLocation.setZ(Double.parseDouble(parts[2].trim()));
return newLocation;
} else if (InputValidationHelper.isEmptyValue(locationString)) {
return null;
} else {
return player.getLocation().clone();
}
}
/**
* Parses the given material name
*
* @param materialName <p>The material name to parse</p>
* @return <p>The parsed material, or AIR if not valid</p>
*/
private @NotNull Material parseMaterial(String materialName) {
Material material = Material.matchMaterial(materialName);
if (material == null) {
material = Material.AIR;
}
return material;
}
} }

View File

@ -54,6 +54,13 @@ public class JoinParkourArenaCommand implements CommandExecutor {
return true; return true;
} }
// Deny joining full arenas
int playingNow = MiniGames.getInstance().getParkourArenaPlayerRegistry().getPlayingPlayers(specifiedArena).size();
if (specifiedArena.getMaxPlayers() > 0 && playingNow >= specifiedArena.getMaxPlayers()) {
stringFormatter.displayErrorMessage(commandSender, MiniGameMessage.ERROR_JOIN_ARENA_FULL);
return true;
}
joinArena(specifiedArena, player, arguments); joinArena(specifiedArena, player, arguments);
return true; return true;
} }
@ -69,7 +76,7 @@ public class JoinParkourArenaCommand implements CommandExecutor {
// Find the specified game-mode // Find the specified game-mode
ParkourArenaGameMode gameMode; ParkourArenaGameMode gameMode;
if (arguments.length > 1) { if (arguments.length > 1) {
gameMode = ParkourArenaGameMode.matchGamemode(arguments[1]); gameMode = ParkourArenaGameMode.matchGameMode(arguments[1]);
} else { } else {
gameMode = ParkourArenaGameMode.DEFAULT; gameMode = ParkourArenaGameMode.DEFAULT;
} }

View File

@ -6,6 +6,7 @@ import net.knarcraft.minigames.arena.parkour.ParkourArena;
import net.knarcraft.minigames.arena.parkour.ParkourArenaGroup; import net.knarcraft.minigames.arena.parkour.ParkourArenaGroup;
import net.knarcraft.minigames.arena.parkour.ParkourArenaHandler; import net.knarcraft.minigames.arena.parkour.ParkourArenaHandler;
import net.knarcraft.minigames.config.MiniGameMessage; import net.knarcraft.minigames.config.MiniGameMessage;
import net.knarcraft.minigames.util.InputValidationHelper;
import net.knarcraft.minigames.util.StringSanitizer; import net.knarcraft.minigames.util.StringSanitizer;
import net.knarcraft.minigames.util.TabCompleteHelper; import net.knarcraft.minigames.util.TabCompleteHelper;
import org.bukkit.command.Command; import org.bukkit.command.Command;
@ -47,7 +48,7 @@ public class ParkourGroupSetCommand implements TabExecutor {
} }
ParkourArenaGroup arenaGroup; ParkourArenaGroup arenaGroup;
if (groupName.equalsIgnoreCase("null") || groupName.equalsIgnoreCase("none")) { if (InputValidationHelper.isEmptyValue(groupName)) {
arenaGroup = null; arenaGroup = null;
} else { } else {
arenaGroup = arenaHandler.getGroup(groupName); arenaGroup = arenaHandler.getGroup(groupName);

View File

@ -170,6 +170,11 @@ public enum MiniGameMessage implements TranslatableMessage {
*/ */
ERROR_GEYSER_DROPPER, ERROR_GEYSER_DROPPER,
/**
* The message displayed when a player attempts to join a full arena
*/
ERROR_JOIN_ARENA_FULL,
/* **************** * /* **************** *
* Success messages * * Success messages *
* **************** */ * **************** */

View File

@ -9,6 +9,7 @@ import net.knarcraft.minigames.placeholder.parsing.PlayerPlaceholderParser;
import net.knarcraft.minigames.placeholder.parsing.RecordPlaceholderParser; import net.knarcraft.minigames.placeholder.parsing.RecordPlaceholderParser;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/** /**
* A placeholderAPI expansion for Dropper-related placeholders * A placeholderAPI expansion for Dropper-related placeholders
@ -58,13 +59,14 @@ public class DropperExpansion extends PlaceholderExpansion {
} }
@Override @Override
@Nullable
public String onRequest(OfflinePlayer player, String parameters) { public String onRequest(OfflinePlayer player, String parameters) {
String[] parts = parameters.split("_"); String[] parts = parameters.split("_");
// Record is used as the prefix for all record placeholders in case more placeholder types are added // Record is used as the prefix for all record placeholders in case more placeholder types are added
if (parts[0].equalsIgnoreCase("record") && parts.length >= 7) { if (parts[0].equalsIgnoreCase("record") && parts.length >= 7) {
return recordPlaceholderParser.onRequest(parameters, parts); return recordPlaceholderParser.onRequest(parts);
} else if (parts[0].equalsIgnoreCase("players")) { } else if (parts[0].equalsIgnoreCase("players")) {
return this.playerPlaceholderParser.onRequest(parameters, parts); return this.playerPlaceholderParser.onRequest(parts);
} else { } else {
return parameters; return parameters;
} }

View File

@ -9,6 +9,7 @@ import net.knarcraft.minigames.placeholder.parsing.PlayerPlaceholderParser;
import net.knarcraft.minigames.placeholder.parsing.RecordPlaceholderParser; import net.knarcraft.minigames.placeholder.parsing.RecordPlaceholderParser;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/** /**
* A placeholderAPI expansion for Parkour-related placeholders * A placeholderAPI expansion for Parkour-related placeholders
@ -25,8 +26,8 @@ public class ParkourExpansion extends PlaceholderExpansion {
*/ */
public ParkourExpansion(@NotNull MiniGames plugin) { public ParkourExpansion(@NotNull MiniGames plugin) {
ParkourArenaHandler arenaHandler = plugin.getParkourArenaHandler(); ParkourArenaHandler arenaHandler = plugin.getParkourArenaHandler();
this.recordPlaceholderParser = new RecordPlaceholderParser(arenaHandler, ParkourArenaGameMode::matchGamemode); this.recordPlaceholderParser = new RecordPlaceholderParser(arenaHandler, ParkourArenaGameMode::matchGameMode);
this.playerPlaceholderParser = new PlayerPlaceholderParser<>(arenaHandler, ParkourArenaGameMode::matchGamemode, this.playerPlaceholderParser = new PlayerPlaceholderParser<>(arenaHandler, ParkourArenaGameMode::matchGameMode,
plugin.getParkourArenaPlayerRegistry()); plugin.getParkourArenaPlayerRegistry());
} }
@ -58,13 +59,14 @@ public class ParkourExpansion extends PlaceholderExpansion {
} }
@Override @Override
@Nullable
public String onRequest(OfflinePlayer player, String parameters) { public String onRequest(OfflinePlayer player, String parameters) {
String[] parts = parameters.split("_"); String[] parts = parameters.split("_");
// Record is used as the prefix for all record placeholders in case more placeholder types are added // Record is used as the prefix for all record placeholders in case more placeholder types are added
if (parts[0].equalsIgnoreCase("record") && parts.length >= 7) { if (parts[0].equalsIgnoreCase("record") && parts.length >= 7) {
return recordPlaceholderParser.onRequest(parameters, parts); return recordPlaceholderParser.onRequest(parts);
} else if (parts[0].equalsIgnoreCase("players")) { } else if (parts[0].equalsIgnoreCase("players")) {
return this.playerPlaceholderParser.onRequest(parameters, parts); return this.playerPlaceholderParser.onRequest(parts);
} else { } else {
return parameters; return parameters;
} }

View File

@ -16,7 +16,6 @@ import java.util.ArrayList;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.function.Function; import java.util.function.Function;
@ -49,16 +48,49 @@ public class PlayerPlaceholderParser<K extends Arena> {
/** /**
* The method to run when parsing a record placeholder request * The method to run when parsing a record placeholder request
* *
* @param parameters <p>The parameters specified</p> * @param parts <p>The split parameters, without irrelevant info</p>
* @return <p>The resulting string</p> * @return <p>The resulting string</p>
*/ */
@NotNull @Nullable
public String onRequest(@NotNull String parameters, @NotNull String[] parts) { public String onRequest(@NotNull String[] parts) {
if (parts.length < 6) { if (parts.length < 2) {
return parameters; return null;
} }
// String selector = parts[1]; // The selector for which aspect of players to get. Playing is the only one available yet. String selector = parts[1];
if (parts.length >= 6 && selector.equalsIgnoreCase("playing")) {
return getPlayingPlayersInfo(parts);
} else if (parts.length >= 3 && selector.equalsIgnoreCase("maximum")) {
return getMaxPlayersInfo(parts);
} else {
return null;
}
}
/**
* Gets placeholder info about max players
*
* @param parts <p>The split parameters, without irrelevant info</p>
* @return <p>The resulting string</p>
*/
@Nullable
private String getMaxPlayersInfo(@NotNull String[] parts) {
String info = null;
K arena = arenaHandler.getArena(parts[2]);
if (arena != null) {
info = String.valueOf(arena.getMaxPlayers());
}
return info;
}
/**
* Gets placeholder info about playing players
*
* @param parts <p>The split parameters, without irrelevant info</p>
* @return <p>The resulting string</p>
*/
@Nullable
private String getPlayingPlayersInfo(@NotNull String[] parts) {
String gameModeName = parts[2]; String gameModeName = parts[2];
ArenaGameMode gameMode = gameModeParser.apply(gameModeName); ArenaGameMode gameMode = gameModeParser.apply(gameModeName);
if (gameModeName.equalsIgnoreCase("combined") || gameModeName.equalsIgnoreCase("all")) { if (gameModeName.equalsIgnoreCase("combined") || gameModeName.equalsIgnoreCase("all")) {
@ -71,7 +103,7 @@ public class PlayerPlaceholderParser<K extends Arena> {
// The type of info to get. Either count (number of players) or player_position (a named player). // The type of info to get. Either count (number of players) or player_position (a named player).
PlayerInfoType infoType = PlayerInfoType.getFromString(parts[5]); PlayerInfoType infoType = PlayerInfoType.getFromString(parts[5]);
if (infoType == null) { if (infoType == null) {
return parameters; return null;
} }
String info = null; String info = null;
@ -84,7 +116,7 @@ public class PlayerPlaceholderParser<K extends Arena> {
info = getArenaInfo(identifier, gameMode, infoType, parts); info = getArenaInfo(identifier, gameMode, infoType, parts);
} }
return Objects.requireNonNullElse(info, parameters); return info;
} }
/** /**

View File

@ -20,7 +20,6 @@ import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.function.Function; import java.util.function.Function;
@ -51,13 +50,13 @@ public class RecordPlaceholderParser {
/** /**
* The method to run when parsing a record placeholder request * The method to run when parsing a record placeholder request
* *
* @param parameters <p>The parameters specified</p> * @param parts <p>All parts of the placeholder</p>
* @return <p>The resulting string</p> * @return <p>The resulting string</p>
*/ */
@NotNull @Nullable
public String onRequest(@NotNull String parameters, @NotNull String[] parts) { public String onRequest(@NotNull String[] parts) {
if (parts.length < 7) { if (parts.length < 7) {
return parameters; return null;
} }
RecordType recordType = RecordType.getFromString(parts[1]); RecordType recordType = RecordType.getFromString(parts[1]);
@ -70,12 +69,12 @@ public class RecordPlaceholderParser {
} catch (NumberFormatException exception) { } catch (NumberFormatException exception) {
MiniGames.log(Level.WARNING, "Invalid placeholder given. " + parts[5] + MiniGames.log(Level.WARNING, "Invalid placeholder given. " + parts[5] +
" supplied instead of record position."); " supplied instead of record position.");
return parameters; return null;
} }
InfoType infoType = InfoType.getFromString(parts[6]); InfoType infoType = InfoType.getFromString(parts[6]);
if (recordType == null || infoType == null) { if (recordType == null || infoType == null) {
return parameters; return null;
} }
String info = null; String info = null;
@ -85,7 +84,7 @@ public class RecordPlaceholderParser {
info = getArenaRecord(arenaHandler, identifier, gameMode, recordType, recordNumber, infoType); info = getArenaRecord(arenaHandler, identifier, gameMode, recordType, recordNumber, infoType);
} }
return Objects.requireNonNullElse(info, parameters); return info;
} }
/** /**

View File

@ -137,6 +137,7 @@ public final class DropperArenaStorageHelper {
configSection.set(DropperArenaStorageKey.PLAYER_VERTICAL_VELOCITY.getKey(), arena.getPlayerVerticalVelocity()); configSection.set(DropperArenaStorageKey.PLAYER_VERTICAL_VELOCITY.getKey(), arena.getPlayerVerticalVelocity());
configSection.set(DropperArenaStorageKey.PLAYER_HORIZONTAL_VELOCITY.getKey(), arena.getPlayerHorizontalVelocity()); configSection.set(DropperArenaStorageKey.PLAYER_HORIZONTAL_VELOCITY.getKey(), arena.getPlayerHorizontalVelocity());
configSection.set(DropperArenaStorageKey.WIN_BLOCK_TYPE.getKey(), new SerializableMaterial(arena.getWinBlockType())); configSection.set(DropperArenaStorageKey.WIN_BLOCK_TYPE.getKey(), new SerializableMaterial(arena.getWinBlockType()));
configSection.set(DropperArenaStorageKey.MAX_PLAYERS.getKey(), arena.getMaxPlayers());
RewardStorageHelper.saveRewards(arena, configSection, DropperArenaStorageKey.REWARDS.getKey()); RewardStorageHelper.saveRewards(arena, configSection, DropperArenaStorageKey.REWARDS.getKey());
saveDropperArenaData(arena.getData()); saveDropperArenaData(arena.getData());
} }
@ -187,6 +188,7 @@ public final class DropperArenaStorageHelper {
double verticalVelocity = configurationSection.getDouble(DropperArenaStorageKey.PLAYER_VERTICAL_VELOCITY.getKey()); double verticalVelocity = configurationSection.getDouble(DropperArenaStorageKey.PLAYER_VERTICAL_VELOCITY.getKey());
float horizontalVelocity = sanitizeHorizontalVelocity((float) configurationSection.getDouble( float horizontalVelocity = sanitizeHorizontalVelocity((float) configurationSection.getDouble(
DropperArenaStorageKey.PLAYER_HORIZONTAL_VELOCITY.getKey())); DropperArenaStorageKey.PLAYER_HORIZONTAL_VELOCITY.getKey()));
int maxPlayers = configurationSection.getInt(DropperArenaStorageKey.MAX_PLAYERS.getKey(), -1);
SerializableMaterial winBlockType = (SerializableMaterial) configurationSection.get( SerializableMaterial winBlockType = (SerializableMaterial) configurationSection.get(
DropperArenaStorageKey.WIN_BLOCK_TYPE.getKey()); DropperArenaStorageKey.WIN_BLOCK_TYPE.getKey());
@ -212,7 +214,7 @@ public final class DropperArenaStorageHelper {
} }
return new DropperArena(arenaId, arenaName, spawnLocation, exitLocation, verticalVelocity, horizontalVelocity, return new DropperArena(arenaId, arenaName, spawnLocation, exitLocation, verticalVelocity, horizontalVelocity,
winBlockType.getRawValue(), rewards, arenaData, MiniGames.getInstance().getDropperArenaHandler()); winBlockType.getRawValue(), maxPlayers, rewards, arenaData, MiniGames.getInstance().getDropperArenaHandler());
} }
/** /**

View File

@ -35,8 +35,8 @@ public final class InputValidationHelper {
* @return <p>True if the value can be considered as empty</p> * @return <p>True if the value can be considered as empty</p>
*/ */
public static boolean isEmptyValue(@NotNull String value) { public static boolean isEmptyValue(@NotNull String value) {
return value.equalsIgnoreCase("null") || value.equalsIgnoreCase("0") || return value.equalsIgnoreCase("null") || value.equalsIgnoreCase("clear") ||
value.equalsIgnoreCase("clear") || value.equalsIgnoreCase("none"); value.equalsIgnoreCase("none");
} }
} }

View File

@ -140,6 +140,7 @@ public final class ParkourArenaStorageHelper {
configSection.set(ParkourArenaStorageKey.KILL_PLANE_BLOCKS.getKey(), getKillPlaneBlocks(arena)); configSection.set(ParkourArenaStorageKey.KILL_PLANE_BLOCKS.getKey(), getKillPlaneBlocks(arena));
configSection.set(ParkourArenaStorageKey.OBSTACLE_BLOCKS.getKey(), getObstacleBlocks(arena)); configSection.set(ParkourArenaStorageKey.OBSTACLE_BLOCKS.getKey(), getObstacleBlocks(arena));
configSection.set(ParkourArenaStorageKey.CHECKPOINTS.getKey(), arena.getCheckpoints()); configSection.set(ParkourArenaStorageKey.CHECKPOINTS.getKey(), arena.getCheckpoints());
configSection.set(ParkourArenaStorageKey.MAX_PLAYERS.getKey(), arena.getMaxPlayers());
RewardStorageHelper.saveRewards(arena, configSection, ParkourArenaStorageKey.REWARDS.getKey()); RewardStorageHelper.saveRewards(arena, configSection, ParkourArenaStorageKey.REWARDS.getKey());
saveParkourArenaData(arena.getData()); saveParkourArenaData(arena.getData());
} }
@ -217,6 +218,7 @@ public final class ParkourArenaStorageHelper {
Location spawnLocation = (Location) configurationSection.get(ParkourArenaStorageKey.SPAWN_LOCATION.getKey()); Location spawnLocation = (Location) configurationSection.get(ParkourArenaStorageKey.SPAWN_LOCATION.getKey());
Location exitLocation = (Location) configurationSection.get(ParkourArenaStorageKey.EXIT_LOCATION.getKey()); Location exitLocation = (Location) configurationSection.get(ParkourArenaStorageKey.EXIT_LOCATION.getKey());
Location winLocation = (Location) configurationSection.get(ParkourArenaStorageKey.WIN_LOCATION.getKey()); Location winLocation = (Location) configurationSection.get(ParkourArenaStorageKey.WIN_LOCATION.getKey());
int maxPlayers = configurationSection.getInt(ParkourArenaStorageKey.MAX_PLAYERS.getKey(), -1);
SerializableMaterial winBlockType = (SerializableMaterial) configurationSection.get( SerializableMaterial winBlockType = (SerializableMaterial) configurationSection.get(
ParkourArenaStorageKey.WIN_BLOCK_TYPE.getKey()); ParkourArenaStorageKey.WIN_BLOCK_TYPE.getKey());
List<?> killPlaneBlockNamesList = configurationSection.getList(ParkourArenaStorageKey.KILL_PLANE_BLOCKS.getKey()); List<?> killPlaneBlockNamesList = configurationSection.getList(ParkourArenaStorageKey.KILL_PLANE_BLOCKS.getKey());
@ -264,7 +266,7 @@ public final class ParkourArenaStorageHelper {
} }
return new ParkourArena(arenaId, arenaName, spawnLocation, exitLocation, winBlockType.getRawValue(), winLocation, return new ParkourArena(arenaId, arenaName, spawnLocation, exitLocation, winBlockType.getRawValue(), winLocation,
killPlaneBlockNames, obstacleBlockNames, checkpoints, rewards, arenaData, killPlaneBlockNames, obstacleBlockNames, checkpoints, maxPlayers, rewards, arenaData,
MiniGames.getInstance().getParkourArenaHandler()); MiniGames.getInstance().getParkourArenaHandler());
} }

View File

@ -22,7 +22,7 @@ import java.util.Collection;
import java.util.UUID; import java.util.UUID;
/** /**
* A helopr class for getting the reward specified in user input * A helper class for getting the reward specified in user input
*/ */
public final class RewardHelper { public final class RewardHelper {

View File

@ -111,11 +111,25 @@ public final class TabCompleteHelper {
tabCompleteSuggestions.put(EditablePropertyType.CHECKPOINT_CLEAR, getCheckpointClearSuggestions()); tabCompleteSuggestions.put(EditablePropertyType.CHECKPOINT_CLEAR, getCheckpointClearSuggestions());
tabCompleteSuggestions.put(EditablePropertyType.MATERIAL_LIST, getMaterialListSuggestions()); tabCompleteSuggestions.put(EditablePropertyType.MATERIAL_LIST, getMaterialListSuggestions());
tabCompleteSuggestions.put(EditablePropertyType.DOUBLE, getDoubleSuggestions()); tabCompleteSuggestions.put(EditablePropertyType.DOUBLE, getDoubleSuggestions());
tabCompleteSuggestions.put(EditablePropertyType.INTEGER, getIntegerSuggestions());
} }
return tabCompleteSuggestions.get(propertyType); return tabCompleteSuggestions.get(propertyType);
} }
private static List<String> getIntegerSuggestions() {
List<String> suggestions = new ArrayList<>();
suggestions.add("-1");
suggestions.add("1");
suggestions.add("2");
suggestions.add("3");
suggestions.add("4");
suggestions.add("5");
suggestions.add("6");
suggestions.add("7");
return suggestions;
}
/** /**
* Gets suggestions for double values * Gets suggestions for double values
* *

View File

@ -30,6 +30,7 @@ en:
ERROR_REWARD_TYPE_INVALID: "You have specified an invalid reward type" ERROR_REWARD_TYPE_INVALID: "You have specified an invalid reward type"
ERROR_REWARD_CONDITION_INVALID: "You have specified an invalid reward condition" ERROR_REWARD_CONDITION_INVALID: "You have specified an invalid reward condition"
ERROR_GEYSER_DROPPER: "Because of version differences, droppers don't work properly using the Bedrock client. Please use Minecraft Java Edition instead." ERROR_GEYSER_DROPPER: "Because of version differences, droppers don't work properly using the Bedrock client. Please use Minecraft Java Edition instead."
ERROR_JOIN_ARENA_FULL: "The maximum amount of players are already in the arena"
SUCCESS_ARENA_GROUP_UPDATED: "The arena's group has been updated" SUCCESS_ARENA_GROUP_UPDATED: "The arena's group has been updated"
SUCCESS_PLUGIN_RELOADED: "Plugin reloaded!" SUCCESS_PLUGIN_RELOADED: "Plugin reloaded!"
SUCCESS_ARENA_CREATED: "The arena was successfully created!" SUCCESS_ARENA_CREATED: "The arena was successfully created!"