Implements #42

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

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.RewardCondition;
import net.knarcraft.minigames.config.MiniGameMessage;
import net.knarcraft.minigames.util.InputValidationHelper;
import net.knarcraft.minigames.util.RewardHelper;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
@@ -60,7 +61,7 @@ public class SetArenaRewardCommand implements CommandExecutor {
return false;
}
if (arguments[0].equalsIgnoreCase("clear")) {
if (InputValidationHelper.isEmptyValue(arguments[0])) {
arena.clearRewards(condition);
MiniGames.getInstance().getStringFormatter().displaySuccessMessage(player,
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.reward.RewardCondition;
import net.knarcraft.minigames.arena.reward.RewardType;
import net.knarcraft.minigames.util.InputValidationHelper;
import net.knarcraft.minigames.util.TabCompleteHelper;
import org.bukkit.Material;
import org.bukkit.command.Command;
@@ -40,7 +41,7 @@ public class SetArenaRewardTabCompleter implements TabCompleter {
}
if (arguments.length >= 2) {
// 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<>();
}
}
@@ -73,8 +74,7 @@ public class SetArenaRewardTabCompleter implements TabCompleter {
}
if (arguments.length >= 5) {
// If the condition is invalid, or it's the clear action, stop tab-completion
if (RewardCondition.getFromString(arguments[3]) == null ||
arguments[0].equalsIgnoreCase("clear")) {
if (RewardCondition.getFromString(arguments[3]) == null || InputValidationHelper.isEmptyValue(arguments[0])) {
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.DropperArenaHandler;
import net.knarcraft.minigames.config.MiniGameMessage;
import net.knarcraft.minigames.util.InputValidationHelper;
import net.knarcraft.minigames.util.StringSanitizer;
import net.knarcraft.minigames.util.TabCompleteHelper;
import org.bukkit.command.Command;
@@ -46,7 +47,7 @@ public class DropperGroupSetCommand implements TabExecutor {
}
DropperArenaGroup arenaGroup;
if (groupName.equalsIgnoreCase("null") || groupName.equalsIgnoreCase("none")) {
if (InputValidationHelper.isEmptyValue(groupName)) {
arenaGroup = null;
} else {
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.arena.dropper.DropperArena;
import net.knarcraft.minigames.arena.dropper.DropperArenaEditableProperty;
import net.knarcraft.minigames.command.EditArenaCommand;
import net.knarcraft.minigames.config.DropperConfiguration;
import net.knarcraft.minigames.config.MiniGameMessage;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
@@ -17,9 +15,7 @@ import org.jetbrains.annotations.NotNull;
/**
* The command for editing an existing dropper arena
*/
public class EditDropperArenaCommand implements CommandExecutor {
private final DropperConfiguration configuration;
public class EditDropperArenaCommand extends EditArenaCommand {
/**
* Instantiates a new edit arena command
@@ -27,7 +23,7 @@ public class EditDropperArenaCommand implements CommandExecutor {
* @param configuration <p>The configuration to use</p>
*/
public EditDropperArenaCommand(DropperConfiguration configuration) {
this.configuration = configuration;
super(configuration);
}
@Override
@@ -93,80 +89,8 @@ public class EditDropperArenaCommand implements CommandExecutor {
case SPAWN_LOCATION -> arena.setSpawnLocation(parseLocation(player, value));
case NAME -> arena.setName(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;
}
// 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);
return true;
}

View File

@@ -4,16 +4,12 @@ import net.knarcraft.knarlib.formatting.StringFormatter;
import net.knarcraft.minigames.MiniGames;
import net.knarcraft.minigames.arena.parkour.ParkourArena;
import net.knarcraft.minigames.arena.parkour.ParkourArenaEditableProperty;
import net.knarcraft.minigames.command.EditArenaCommand;
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.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashSet;
import java.util.List;
@@ -21,12 +17,13 @@ import java.util.List;
/**
* The command for editing an existing dropper arena
*/
public class EditParkourArenaCommand implements CommandExecutor {
public class EditParkourArenaCommand extends EditArenaCommand {
/**
* Instantiates a new edit arena command
*/
public EditParkourArenaCommand() {
super(null);
}
@Override
@@ -101,43 +98,8 @@ public class EditParkourArenaCommand implements CommandExecutor {
case CHECKPOINT_CLEAR -> arena.clearCheckpoints();
case KILL_PLANE_BLOCKS -> arena.setKillPlaneBlocks(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;
}
// 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);
return true;
}
@@ -69,7 +76,7 @@ public class JoinParkourArenaCommand implements CommandExecutor {
// Find the specified game-mode
ParkourArenaGameMode gameMode;
if (arguments.length > 1) {
gameMode = ParkourArenaGameMode.matchGamemode(arguments[1]);
gameMode = ParkourArenaGameMode.matchGameMode(arguments[1]);
} else {
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.ParkourArenaHandler;
import net.knarcraft.minigames.config.MiniGameMessage;
import net.knarcraft.minigames.util.InputValidationHelper;
import net.knarcraft.minigames.util.StringSanitizer;
import net.knarcraft.minigames.util.TabCompleteHelper;
import org.bukkit.command.Command;
@@ -47,7 +48,7 @@ public class ParkourGroupSetCommand implements TabExecutor {
}
ParkourArenaGroup arenaGroup;
if (groupName.equalsIgnoreCase("null") || groupName.equalsIgnoreCase("none")) {
if (InputValidationHelper.isEmptyValue(groupName)) {
arenaGroup = null;
} else {
arenaGroup = arenaHandler.getGroup(groupName);