Adds ability to specify horizontal hit-box for end-rods and similar

This commit is contained in:
Kristian Knarvik 2023-09-27 23:13:03 +02:00
parent ccf43060dc
commit fc6bd33e87
9 changed files with 116 additions and 28 deletions

View File

@ -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. These are all the options that can be changed for an arena.
| Option | Details | | 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. | | 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. | | 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. | | 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. | | 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. | | 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). | | 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. | | 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. | | 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 ## Configuration options

View File

@ -38,6 +38,11 @@ public enum EditablePropertyType {
/** /**
* The property is a comma-separated list of materials * The property is a comma-separated list of materials
*/ */
MATERIAL_LIST MATERIAL_LIST,
/**
* The property is any double value
*/
DOUBLE,
} }

View File

@ -73,6 +73,11 @@ public class ParkourArena implements Arena {
*/ */
private @Nullable Set<Material> killPlaneBlocks; private @Nullable Set<Material> 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. * 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 * Instantiates a new parkour arena
* *
* @param arenaId <p>The id of the arena</p> * @param arenaId <p>The id of the arena</p>
* @param arenaName <p>The name of the arena</p> * @param arenaName <p>The name of the arena</p>
* @param spawnLocation <p>The location players spawn in when entering the arena</p> * @param spawnLocation <p>The location players spawn in when entering the arena</p>
* @param exitLocation <p>The location the players are teleported to when exiting the arena, or null</p> * @param exitLocation <p>The location the players are teleported to when exiting the arena, or null</p>
* @param winBlockType <p>The material of the block players have to hit to win this parkour arena</p> * @param winBlockType <p>The material of the block players have to hit to win this parkour arena</p>
* @param winLocation <p>The location a player has to reach to win this arena</p> * @param winLocation <p>The location a player has to reach to win this arena</p>
* @param killPlaneBlockNames <p>The names of the type of blocks</p> * @param killPlaneBlockNames <p>The names of the type of blocks</p>
* @param checkpoints <p>The checkpoints set for this arena</p> * @param horizontalKillPlaneHitBox <p>The number of horizontal blocks the hit-box of kill plane blocks should cover</p>
* @param rewards <p>The rewards given by this arena</p> * @param checkpoints <p>The checkpoints set for this arena</p>
* @param parkourArenaData <p>The arena data keeping track of which players have done what in this arena</p> * @param rewards <p>The rewards given by this arena</p>
* @param arenaHandler <p>The arena handler used for saving any changes</p> * @param parkourArenaData <p>The arena data keeping track of which players have done what in this arena</p>
* @param arenaHandler <p>The arena handler used for saving any changes</p>
*/ */
public ParkourArena(@NotNull UUID arenaId, @NotNull String arenaName, @NotNull Location spawnLocation, 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, @NotNull List<Location> checkpoints, @Nullable Set<String> killPlaneBlockNames, double horizontalKillPlaneHitBox,
@NotNull List<Location> checkpoints,
@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;
@ -116,6 +123,7 @@ public class ParkourArena implements Arena {
this.killPlaneBlockNames = killPlaneBlockNames; this.killPlaneBlockNames = killPlaneBlockNames;
this.killPlaneBlocks = this.killPlaneBlockNames == null ? null : MaterialHelper.loadMaterialList( this.killPlaneBlocks = this.killPlaneBlockNames == null ? null : MaterialHelper.loadMaterialList(
new ArrayList<>(killPlaneBlockNames), "+", MiniGames.getInstance().getLogger()); new ArrayList<>(killPlaneBlockNames), "+", MiniGames.getInstance().getLogger());
this.horizontalKillPlaneHitBox = horizontalKillPlaneHitBox;
this.checkpoints = checkpoints; this.checkpoints = checkpoints;
this.parkourArenaData = parkourArenaData; this.parkourArenaData = parkourArenaData;
this.parkourArenaHandler = arenaHandler; this.parkourArenaHandler = arenaHandler;
@ -150,6 +158,7 @@ public class ParkourArena implements Arena {
this.killPlaneBlocks = null; this.killPlaneBlocks = null;
this.checkpoints = new ArrayList<>(); this.checkpoints = new ArrayList<>();
this.parkourArenaHandler = arenaHandler; this.parkourArenaHandler = arenaHandler;
this.horizontalKillPlaneHitBox = 0.1;
} }
@Override @Override
@ -241,6 +250,37 @@ public class ParkourArena implements Arena {
return this.killPlaneBlockNames; return this.killPlaneBlockNames;
} }
/**
* Gets the number of horizontal blocks the hit-box of kill plane blocks should cover
*
* <p>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.</p>
*
* @return <p>The number of horizontal blocks the hit-box of kill plane blocks should cover</p>
*/
public double getHorizontalKillPlaneHitBox() {
return this.horizontalKillPlaneHitBox;
}
/**
* Sets the number of horizontal blocks the hit-box of kill plane blocks should cover
*
* <p>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.</p>
*
* @param horizontalKillPlaneHitBox <p>The number of horizontal blocks the hit-box of kill plane blocks should cover</p>
*/
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 * Gets all checkpoint locations for this arena
* *

View File

@ -62,7 +62,12 @@ public enum ParkourArenaEditableProperty {
*/ */
KILL_PLANE_BLOCKS("killPlaneBlocks", (arena) -> String.valueOf(arena.getKillPlaneBlockNames()), KILL_PLANE_BLOCKS("killPlaneBlocks", (arena) -> String.valueOf(arena.getKillPlaneBlockNames()),
EditablePropertyType.MATERIAL_LIST), 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 @NotNull String argumentString;
private final Function<ParkourArena, String> currentValueProvider; private final Function<ParkourArena, String> currentValueProvider;

View File

@ -42,6 +42,11 @@ public enum ParkourArenaStorageKey {
*/ */
KILL_PLANE_BLOCKS("killPlaneBlocks"), 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 * The key for this arena's checkpoint locations
*/ */

View File

@ -60,7 +60,12 @@ public class EditParkourArenaCommand implements CommandExecutor {
new String[]{editableProperty.getArgumentString(), value})); new String[]{editableProperty.getArgumentString(), value}));
return true; return true;
} else { } 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) { if (successful) {
stringFormatter.displaySuccessMessage(player, stringFormatter.replacePlaceholder( stringFormatter.displaySuccessMessage(player, stringFormatter.replacePlaceholder(
MiniGameMessage.SUCCESS_PROPERTY_CHANGED, "{property}", MiniGameMessage.SUCCESS_PROPERTY_CHANGED, "{property}",
@ -80,9 +85,10 @@ public class EditParkourArenaCommand implements CommandExecutor {
* @param value <p>The new value of the property</p> * @param value <p>The new value of the property</p>
* @param player <p>The player trying to change the value</p> * @param player <p>The player trying to change the value</p>
* @return <p>True if the value was successfully changed</p> * @return <p>True if the value was successfully changed</p>
* @throws NumberFormatException <p>If unable to parse a given numeric value</p>
*/ */
private boolean changeValue(@NotNull ParkourArena arena, @NotNull ParkourArenaEditableProperty property, 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) { return switch (property) {
case WIN_BLOCK_TYPE -> arena.setWinBlockType(parseMaterial(value)); case WIN_BLOCK_TYPE -> arena.setWinBlockType(parseMaterial(value));
case SPAWN_LOCATION -> arena.setSpawnLocation(parseLocation(player, 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_ADD -> arena.addCheckpoint(parseLocation(player, value));
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 HORIZONTAL_KILL_PLANE_HIT_BOX -> arena.setHorizontalKillPlaneHitBox(Double.parseDouble(value));
}; };
} }

View File

@ -261,7 +261,9 @@ public class MoveListener implements Listener {
} }
// Create a hit-box approximate to the player's real hit-box // 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); toLocation).shift(-0.3, 0, -0.3);
for (Block block : adjustedBlocks) { for (Block block : adjustedBlocks) {
// For liquids, or anything without a proper collision shape, trigger collision // For liquids, or anything without a proper collision shape, trigger collision

View File

@ -135,6 +135,7 @@ public final class ParkourArenaStorageHelper {
configSection.set(ParkourArenaStorageKey.WIN_BLOCK_TYPE.getKey(), new SerializableMaterial(arena.getWinBlockType())); configSection.set(ParkourArenaStorageKey.WIN_BLOCK_TYPE.getKey(), new SerializableMaterial(arena.getWinBlockType()));
configSection.set(ParkourArenaStorageKey.WIN_LOCATION.getKey(), arena.getWinLocation()); configSection.set(ParkourArenaStorageKey.WIN_LOCATION.getKey(), arena.getWinLocation());
configSection.set(ParkourArenaStorageKey.KILL_PLANE_BLOCKS.getKey(), getKillPlaneBlocks(arena)); 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()); configSection.set(ParkourArenaStorageKey.CHECKPOINTS.getKey(), arena.getCheckpoints());
RewardStorageHelper.saveRewards(arena, configSection, ParkourArenaStorageKey.REWARDS.getKey()); RewardStorageHelper.saveRewards(arena, configSection, ParkourArenaStorageKey.REWARDS.getKey());
saveParkourArenaData(arena.getData()); saveParkourArenaData(arena.getData());
@ -208,6 +209,8 @@ public final class ParkourArenaStorageHelper {
} else { } else {
killPlaneBlockNames = new HashSet<>((List<String>) killPlaneBlockNamesList); killPlaneBlockNames = new HashSet<>((List<String>) killPlaneBlockNamesList);
} }
double horizontalKillPlaneHitBox = configurationSection.getDouble(
ParkourArenaStorageKey.HORIZONTAL_KILL_PLANE_HIT_BOX.getKey(), 0);
List<Location> checkpoints = (List<Location>) configurationSection.get(ParkourArenaStorageKey.CHECKPOINTS.getKey()); List<Location> checkpoints = (List<Location>) configurationSection.get(ParkourArenaStorageKey.CHECKPOINTS.getKey());
Map<RewardCondition, Set<Reward>> rewards = RewardStorageHelper.loadRewards(configurationSection, Map<RewardCondition, Set<Reward>> rewards = RewardStorageHelper.loadRewards(configurationSection,
@ -239,7 +242,8 @@ 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, checkpoints, rewards, arenaData, MiniGames.getInstance().getParkourArenaHandler()); killPlaneBlockNames, horizontalKillPlaneHitBox, checkpoints, rewards, arenaData,
MiniGames.getInstance().getParkourArenaHandler());
} }
/** /**

View File

@ -104,11 +104,30 @@ public final class TabCompleteHelper {
tabCompleteSuggestions.put(EditablePropertyType.BLOCK_TYPE, getBlockTypeSuggestions()); tabCompleteSuggestions.put(EditablePropertyType.BLOCK_TYPE, getBlockTypeSuggestions());
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());
} }
return tabCompleteSuggestions.get(propertyType); return tabCompleteSuggestions.get(propertyType);
} }
/**
* Gets suggestions for double values
*
* @return <p>A list of suggestions</p>
*/
private static List<String> getDoubleSuggestions() {
List<String> 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 * Gets suggestions for a list of materials
* *