diff --git a/README.md b/README.md index ecbd510..507a38b 100644 --- a/README.md +++ b/README.md @@ -204,16 +204,17 @@ This command allows editing the specified property for the specified parkour are These are all the options that can be changed for an arena. -| Option | Details | -|-----------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| name | The name of the arena. Used mainly to select the arena in commands. Note that underscore (_) cannot be used if you want to utilize placeholders, as it's used to split placeholder arguments. | -| spawnLocation | The spawn location of any player joining the arena. Use `56.546,64.0,44.45` to specify coordinates, or `here`, `this` or any other string to select your current location. | -| exitLocation | The location players will be sent to when exiting the arena. If not set, the player will be sent to where they joined from. Valid values are the same as for spawnLocation. | -| winBlockType | The type of block players must hit to win the arena. It can be any material as long as it's a block, and not a type of air. | -| winLocation | The location players must reach to win the arena (see spawnLocation for valid values). If set, this overrides, and is used instead of, the win block type. | -| checkpointAdd | Adds a new checkpoint to the arena's checkpoints (see spawnLocation for valid values). | -| checkpointClear | Clears all current checkpoints. Give any value to execute. If not given a value, current checkpoints are shown. | -| killPlaneBlocks | A comma-separated list of materials which will force a loss on hit. +WOOL and other [material tags](#notes-about-material-tags) are supported as well. | +| Option | Details | +|---------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| name | The name of the arena. Used mainly to select the arena in commands. Note that underscore (_) cannot be used if you want to utilize placeholders, as it's used to split placeholder arguments. | +| spawnLocation | The spawn location of any player joining the arena. Use `56.546,64.0,44.45` to specify coordinates, or `here`, `this` or any other string to select your current location. | +| exitLocation | The location players will be sent to when exiting the arena. If not set, the player will be sent to where they joined from. Valid values are the same as for spawnLocation. | +| winBlockType | The type of block players must hit to win the arena. It can be any material as long as it's a block, and not a type of air. | +| winLocation | The location players must reach to win the arena (see spawnLocation for valid values). If set, this overrides, and is used instead of, the win block type. | +| checkpointAdd | Adds a new checkpoint to the arena's checkpoints (see spawnLocation for valid values). | +| checkpointClear | Clears all current checkpoints. Give any value to execute. If not given a value, current checkpoints are shown. | +| killPlaneBlocks | A comma-separated list of materials which will force a loss on hit. +WOOL and other [material tags](#notes-about-material-tags) are supported as well. | +| horizontalKillPlaneHitBox | The number of blocks away kill plane blocks will trigger horizontally (0-1). This only affects things less than 1 block wide, such as horizontal lightning and end rods. | ## Configuration options diff --git a/src/main/java/net/knarcraft/minigames/arena/EditablePropertyType.java b/src/main/java/net/knarcraft/minigames/arena/EditablePropertyType.java index 6f07e87..f919176 100644 --- a/src/main/java/net/knarcraft/minigames/arena/EditablePropertyType.java +++ b/src/main/java/net/knarcraft/minigames/arena/EditablePropertyType.java @@ -38,6 +38,11 @@ public enum EditablePropertyType { /** * The property is a comma-separated list of materials */ - MATERIAL_LIST + MATERIAL_LIST, + + /** + * The property is any double value + */ + DOUBLE, } diff --git a/src/main/java/net/knarcraft/minigames/arena/parkour/ParkourArena.java b/src/main/java/net/knarcraft/minigames/arena/parkour/ParkourArena.java index bbe15a5..b6e9ed5 100644 --- a/src/main/java/net/knarcraft/minigames/arena/parkour/ParkourArena.java +++ b/src/main/java/net/knarcraft/minigames/arena/parkour/ParkourArena.java @@ -73,6 +73,11 @@ public class ParkourArena implements Arena { */ private @Nullable Set killPlaneBlocks; + /** + * The number of horizontal blocks the hit-box of kill plane blocks should cover + */ + private double horizontalKillPlaneHitBox; + /** * The checkpoints for this arena. Entering a checkpoint overrides the player's spawn location. */ @@ -90,21 +95,23 @@ public class ParkourArena implements Arena { /** * Instantiates a new parkour arena * - * @param arenaId

The id of the arena

- * @param arenaName

The name of the arena

- * @param spawnLocation

The location players spawn in when entering the arena

- * @param exitLocation

The location the players are teleported to when exiting the arena, or null

- * @param winBlockType

The material of the block players have to hit to win this parkour arena

- * @param winLocation

The location a player has to reach to win this arena

- * @param killPlaneBlockNames

The names of the type of blocks

- * @param checkpoints

The checkpoints set for this arena

- * @param rewards

The rewards given by this arena

- * @param parkourArenaData

The arena data keeping track of which players have done what in this arena

- * @param arenaHandler

The arena handler used for saving any changes

+ * @param arenaId

The id of the arena

+ * @param arenaName

The name of the arena

+ * @param spawnLocation

The location players spawn in when entering the arena

+ * @param exitLocation

The location the players are teleported to when exiting the arena, or null

+ * @param winBlockType

The material of the block players have to hit to win this parkour arena

+ * @param winLocation

The location a player has to reach to win this arena

+ * @param killPlaneBlockNames

The names of the type of blocks

+ * @param horizontalKillPlaneHitBox

The number of horizontal blocks the hit-box of kill plane blocks should cover

+ * @param checkpoints

The checkpoints set for this arena

+ * @param rewards

The rewards given by this arena

+ * @param parkourArenaData

The arena data keeping track of which players have done what in this arena

+ * @param arenaHandler

The arena handler used for saving any changes

*/ public ParkourArena(@NotNull UUID arenaId, @NotNull String arenaName, @NotNull Location spawnLocation, @Nullable Location exitLocation, @NotNull Material winBlockType, @Nullable Location winLocation, - @Nullable Set killPlaneBlockNames, @NotNull List checkpoints, + @Nullable Set killPlaneBlockNames, double horizontalKillPlaneHitBox, + @NotNull List checkpoints, @NotNull Map> rewards, @NotNull ParkourArenaData parkourArenaData, @NotNull ParkourArenaHandler arenaHandler) { this.arenaId = arenaId; @@ -116,6 +123,7 @@ public class ParkourArena implements Arena { this.killPlaneBlockNames = killPlaneBlockNames; this.killPlaneBlocks = this.killPlaneBlockNames == null ? null : MaterialHelper.loadMaterialList( new ArrayList<>(killPlaneBlockNames), "+", MiniGames.getInstance().getLogger()); + this.horizontalKillPlaneHitBox = horizontalKillPlaneHitBox; this.checkpoints = checkpoints; this.parkourArenaData = parkourArenaData; this.parkourArenaHandler = arenaHandler; @@ -150,6 +158,7 @@ public class ParkourArena implements Arena { this.killPlaneBlocks = null; this.checkpoints = new ArrayList<>(); this.parkourArenaHandler = arenaHandler; + this.horizontalKillPlaneHitBox = 0.1; } @Override @@ -241,6 +250,37 @@ public class ParkourArena implements Arena { return this.killPlaneBlockNames; } + /** + * Gets the number of horizontal blocks the hit-box of kill plane blocks should cover + * + *

This is kind of hard to explain, but basically, when the player is less than the specified amount of blocks + * away from a kill plane block horizontally, a fail will be triggered. Sane values for this would usually be + * between 0.01 amd 1.

+ * + * @return

The number of horizontal blocks the hit-box of kill plane blocks should cover

+ */ + public double getHorizontalKillPlaneHitBox() { + return this.horizontalKillPlaneHitBox; + } + + /** + * Sets the number of horizontal blocks the hit-box of kill plane blocks should cover + * + *

This is kind of hard to explain, but basically, when the player is less than the specified amount of blocks + * away from a kill plane block horizontally, a fail will be triggered. Sane values for this would usually be + * between 0.01 amd 1.

+ * + * @param horizontalKillPlaneHitBox

The number of horizontal blocks the hit-box of kill plane blocks should cover

+ */ + public boolean setHorizontalKillPlaneHitBox(double horizontalKillPlaneHitBox) { + if (horizontalKillPlaneHitBox > 1 || horizontalKillPlaneHitBox < -1) { + return false; + } + this.horizontalKillPlaneHitBox = horizontalKillPlaneHitBox; + this.saveArena(); + return true; + } + /** * Gets all checkpoint locations for this arena * diff --git a/src/main/java/net/knarcraft/minigames/arena/parkour/ParkourArenaEditableProperty.java b/src/main/java/net/knarcraft/minigames/arena/parkour/ParkourArenaEditableProperty.java index 8e90c93..2a20438 100644 --- a/src/main/java/net/knarcraft/minigames/arena/parkour/ParkourArenaEditableProperty.java +++ b/src/main/java/net/knarcraft/minigames/arena/parkour/ParkourArenaEditableProperty.java @@ -62,7 +62,12 @@ public enum ParkourArenaEditableProperty { */ KILL_PLANE_BLOCKS("killPlaneBlocks", (arena) -> String.valueOf(arena.getKillPlaneBlockNames()), EditablePropertyType.MATERIAL_LIST), - ; + + /** + * The horizontal hit-box of kill blocks + */ + HORIZONTAL_KILL_PLANE_HIT_BOX("horizontalKillPlaneHitBox", + (arena) -> String.valueOf(arena.getHorizontalKillPlaneHitBox()), EditablePropertyType.DOUBLE); private final @NotNull String argumentString; private final Function currentValueProvider; diff --git a/src/main/java/net/knarcraft/minigames/arena/parkour/ParkourArenaStorageKey.java b/src/main/java/net/knarcraft/minigames/arena/parkour/ParkourArenaStorageKey.java index aaca647..7b9da13 100644 --- a/src/main/java/net/knarcraft/minigames/arena/parkour/ParkourArenaStorageKey.java +++ b/src/main/java/net/knarcraft/minigames/arena/parkour/ParkourArenaStorageKey.java @@ -42,6 +42,11 @@ public enum ParkourArenaStorageKey { */ KILL_PLANE_BLOCKS("killPlaneBlocks"), + /** + * The key for this arena's horizontal kill plane hit box + */ + HORIZONTAL_KILL_PLANE_HIT_BOX("horizontalKillPlaneHitBox"), + /** * The key for this arena's checkpoint locations */ diff --git a/src/main/java/net/knarcraft/minigames/command/parkour/EditParkourArenaCommand.java b/src/main/java/net/knarcraft/minigames/command/parkour/EditParkourArenaCommand.java index 2b28184..238dbac 100644 --- a/src/main/java/net/knarcraft/minigames/command/parkour/EditParkourArenaCommand.java +++ b/src/main/java/net/knarcraft/minigames/command/parkour/EditParkourArenaCommand.java @@ -60,7 +60,12 @@ public class EditParkourArenaCommand implements CommandExecutor { new String[]{editableProperty.getArgumentString(), value})); return true; } else { - boolean successful = changeValue(specifiedArena, editableProperty, arguments[2], player); + boolean successful; + try { + successful = changeValue(specifiedArena, editableProperty, arguments[2], player); + } catch (NumberFormatException exception) { + successful = false; + } if (successful) { stringFormatter.displaySuccessMessage(player, stringFormatter.replacePlaceholder( MiniGameMessage.SUCCESS_PROPERTY_CHANGED, "{property}", @@ -80,9 +85,10 @@ public class EditParkourArenaCommand implements CommandExecutor { * @param value

The new value of the property

* @param player

The player trying to change the value

* @return

True if the value was successfully changed

+ * @throws NumberFormatException

If unable to parse a given numeric value

*/ private boolean changeValue(@NotNull ParkourArena arena, @NotNull ParkourArenaEditableProperty property, - @NotNull String value, @NotNull Player player) { + @NotNull String value, @NotNull Player player) throws NumberFormatException { return switch (property) { case WIN_BLOCK_TYPE -> arena.setWinBlockType(parseMaterial(value)); case SPAWN_LOCATION -> arena.setSpawnLocation(parseLocation(player, value)); @@ -92,6 +98,7 @@ public class EditParkourArenaCommand implements CommandExecutor { case CHECKPOINT_ADD -> arena.addCheckpoint(parseLocation(player, value)); case CHECKPOINT_CLEAR -> arena.clearCheckpoints(); case KILL_PLANE_BLOCKS -> arena.setKillPlaneBlocks(new HashSet<>(List.of(value.split(",")))); + case HORIZONTAL_KILL_PLANE_HIT_BOX -> arena.setHorizontalKillPlaneHitBox(Double.parseDouble(value)); }; } diff --git a/src/main/java/net/knarcraft/minigames/listener/MoveListener.java b/src/main/java/net/knarcraft/minigames/listener/MoveListener.java index 8aaf3f3..029a16d 100644 --- a/src/main/java/net/knarcraft/minigames/listener/MoveListener.java +++ b/src/main/java/net/knarcraft/minigames/listener/MoveListener.java @@ -261,7 +261,9 @@ public class MoveListener implements Listener { } // Create a hit-box approximate to the player's real hit-box - BoundingBox playerBox = new BoundingBox(0, -0.1, 0, 0.6, 1, 0.6).shift( + double horizontalHitBox = ((ParkourArena) arenaSession.getArena()).getHorizontalKillPlaneHitBox(); + BoundingBox playerBox = new BoundingBox(-horizontalHitBox, -0.1, -horizontalHitBox, + 0.6 + horizontalHitBox, 1, 0.6 + horizontalHitBox).shift( toLocation).shift(-0.3, 0, -0.3); for (Block block : adjustedBlocks) { // For liquids, or anything without a proper collision shape, trigger collision diff --git a/src/main/java/net/knarcraft/minigames/util/ParkourArenaStorageHelper.java b/src/main/java/net/knarcraft/minigames/util/ParkourArenaStorageHelper.java index 9171d0d..f7c7135 100644 --- a/src/main/java/net/knarcraft/minigames/util/ParkourArenaStorageHelper.java +++ b/src/main/java/net/knarcraft/minigames/util/ParkourArenaStorageHelper.java @@ -135,6 +135,7 @@ public final class ParkourArenaStorageHelper { configSection.set(ParkourArenaStorageKey.WIN_BLOCK_TYPE.getKey(), new SerializableMaterial(arena.getWinBlockType())); configSection.set(ParkourArenaStorageKey.WIN_LOCATION.getKey(), arena.getWinLocation()); configSection.set(ParkourArenaStorageKey.KILL_PLANE_BLOCKS.getKey(), getKillPlaneBlocks(arena)); + configSection.set(ParkourArenaStorageKey.HORIZONTAL_KILL_PLANE_HIT_BOX.getKey(), arena.getHorizontalKillPlaneHitBox()); configSection.set(ParkourArenaStorageKey.CHECKPOINTS.getKey(), arena.getCheckpoints()); RewardStorageHelper.saveRewards(arena, configSection, ParkourArenaStorageKey.REWARDS.getKey()); saveParkourArenaData(arena.getData()); @@ -208,6 +209,8 @@ public final class ParkourArenaStorageHelper { } else { killPlaneBlockNames = new HashSet<>((List) killPlaneBlockNamesList); } + double horizontalKillPlaneHitBox = configurationSection.getDouble( + ParkourArenaStorageKey.HORIZONTAL_KILL_PLANE_HIT_BOX.getKey(), 0); List checkpoints = (List) configurationSection.get(ParkourArenaStorageKey.CHECKPOINTS.getKey()); Map> rewards = RewardStorageHelper.loadRewards(configurationSection, @@ -239,7 +242,8 @@ public final class ParkourArenaStorageHelper { } return new ParkourArena(arenaId, arenaName, spawnLocation, exitLocation, winBlockType.getRawValue(), winLocation, - killPlaneBlockNames, checkpoints, rewards, arenaData, MiniGames.getInstance().getParkourArenaHandler()); + killPlaneBlockNames, horizontalKillPlaneHitBox, checkpoints, rewards, arenaData, + MiniGames.getInstance().getParkourArenaHandler()); } /** diff --git a/src/main/java/net/knarcraft/minigames/util/TabCompleteHelper.java b/src/main/java/net/knarcraft/minigames/util/TabCompleteHelper.java index 8153c6e..3ceb900 100644 --- a/src/main/java/net/knarcraft/minigames/util/TabCompleteHelper.java +++ b/src/main/java/net/knarcraft/minigames/util/TabCompleteHelper.java @@ -104,11 +104,30 @@ public final class TabCompleteHelper { tabCompleteSuggestions.put(EditablePropertyType.BLOCK_TYPE, getBlockTypeSuggestions()); tabCompleteSuggestions.put(EditablePropertyType.CHECKPOINT_CLEAR, getCheckpointClearSuggestions()); tabCompleteSuggestions.put(EditablePropertyType.MATERIAL_LIST, getMaterialListSuggestions()); + tabCompleteSuggestions.put(EditablePropertyType.DOUBLE, getDoubleSuggestions()); } return tabCompleteSuggestions.get(propertyType); } + /** + * Gets suggestions for double values + * + * @return

A list of suggestions

+ */ + private static List getDoubleSuggestions() { + List suggestions = new ArrayList<>(); + suggestions.add("0"); + suggestions.add("0.01"); + suggestions.add("0.1"); + suggestions.add("0.2"); + suggestions.add("0.3"); + suggestions.add("0.4"); + suggestions.add("0.5"); + suggestions.add("1"); + return suggestions; + } + /** * Gets suggestions for a list of materials *