mirror of
https://github.com/SunNetservers/MiniGames.git
synced 2024-12-04 16:33:14 +01:00
Adds obstacle blocks for parkour
This change reverts the advanced hit-box detection for kill plane blocks, giving them a full block's hit-box again. Instead, obstacle blocks have been added, which have an accurate hit-box, and can trigger a hit from any direction. The horizontal kill plane hit box option has been removed as it's no longer useful.
This commit is contained in:
parent
fc6bd33e87
commit
310802b42d
11
README.md
11
README.md
@ -213,8 +213,8 @@ These are all the options that can be changed for an arena.
|
||||
| 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. |
|
||||
| killPlaneBlocks | A comma-separated list of materials which will force a loss when stepped on. +WOOL and other [material tags](#notes-about-material-tags) are supported as well. |
|
||||
| obstacleBlocks | A comma-separated list of materials which will force a loss when touched from any direction. +WOOL and other [material tags](#notes-about-material-tags) are supported as well. |
|
||||
|
||||
## Configuration options
|
||||
|
||||
@ -249,6 +249,7 @@ These are all the options that can be changed for an arena.
|
||||
| mustDoGroupedInSequence | true/false | true | Whether grouped dropper arenas must be played in the correct sequence |
|
||||
| ignoreRecordsUntilGroupBeatenOnce | true/false | false | Whether records won't be registered unless the player has already beaten all arenas in a group. That means players are required to do a second play-through to register a record for a grouped arena. |
|
||||
| killPlaneBlocks | list | [see this](#killplaneblocks-default) | The types of blocks compromising parkour arenas' kill planes. Add any materials you want to use for the "bottom" of your parkour arenas. +WOOL and other [material tags](#notes-about-material-tags) are supported. |
|
||||
| obstacleBlocks | list | [see this](#obstacleblocks-default) | The types of blocks treated as obstacles in every direction. +WOOL and other [material tags](#notes-about-material-tags) are supported. |
|
||||
|
||||
#### blockWhitelist default:
|
||||
|
||||
@ -270,6 +271,12 @@ These are all the options that can be changed for an arena.
|
||||
- LAVA
|
||||
- MAGMA_BLOCK
|
||||
|
||||
#### obstacleBlocks default:
|
||||
|
||||
- END_ROD
|
||||
- LIGHTNING_ROD
|
||||
- CHAIN
|
||||
|
||||
## Record placeholders
|
||||
|
||||
Player records can be displayed on a leaderboard by using PlaceholderAPI. If you want to display a sign-based
|
||||
|
@ -74,9 +74,14 @@ public class ParkourArena implements Arena {
|
||||
private @Nullable Set<Material> killPlaneBlocks;
|
||||
|
||||
/**
|
||||
* The number of horizontal blocks the hit-box of kill plane blocks should cover
|
||||
* The names of the block types serving as obstacles for this arena
|
||||
*/
|
||||
private double horizontalKillPlaneHitBox;
|
||||
private @Nullable Set<String> obstacleBlockNames;
|
||||
|
||||
/**
|
||||
* The block types serving as obstacles for this arena
|
||||
*/
|
||||
private @Nullable Set<Material> obstacleBlocks;
|
||||
|
||||
/**
|
||||
* The checkpoints for this arena. Entering a checkpoint overrides the player's spawn location.
|
||||
@ -95,22 +100,22 @@ public class ParkourArena implements Arena {
|
||||
/**
|
||||
* Instantiates a new parkour arena
|
||||
*
|
||||
* @param arenaId <p>The id 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 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 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 horizontalKillPlaneHitBox <p>The number of horizontal blocks the hit-box of kill plane blocks should cover</p>
|
||||
* @param checkpoints <p>The checkpoints set for 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 arenaHandler <p>The arena handler used for saving any changes</p>
|
||||
* @param arenaId <p>The id 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 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 winLocation <p>The location a player has to reach to win this arena</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 checkpoints <p>The checkpoints set for 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 arenaHandler <p>The arena handler used for saving any changes</p>
|
||||
*/
|
||||
public ParkourArena(@NotNull UUID arenaId, @NotNull String arenaName, @NotNull Location spawnLocation,
|
||||
@Nullable Location exitLocation, @NotNull Material winBlockType, @Nullable Location winLocation,
|
||||
@Nullable Set<String> killPlaneBlockNames, double horizontalKillPlaneHitBox,
|
||||
@Nullable Set<String> killPlaneBlockNames, @Nullable Set<String> obstacleBlockNames,
|
||||
@NotNull List<Location> checkpoints,
|
||||
@NotNull Map<RewardCondition, Set<Reward>> rewards,
|
||||
@NotNull ParkourArenaData parkourArenaData, @NotNull ParkourArenaHandler arenaHandler) {
|
||||
@ -123,7 +128,9 @@ 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.obstacleBlockNames = obstacleBlockNames;
|
||||
this.obstacleBlocks = this.obstacleBlockNames == null ? null : MaterialHelper.loadMaterialList(
|
||||
new ArrayList<>(obstacleBlockNames), "+", MiniGames.getInstance().getLogger());
|
||||
this.checkpoints = checkpoints;
|
||||
this.parkourArenaData = parkourArenaData;
|
||||
this.parkourArenaHandler = arenaHandler;
|
||||
@ -156,9 +163,9 @@ public class ParkourArena implements Arena {
|
||||
this.parkourArenaData = new ParkourArenaData(this.arenaId, recordRegistries, new HashMap<>());
|
||||
this.winBlockType = Material.EMERALD_BLOCK;
|
||||
this.killPlaneBlocks = null;
|
||||
this.obstacleBlocks = null;
|
||||
this.checkpoints = new ArrayList<>();
|
||||
this.parkourArenaHandler = arenaHandler;
|
||||
this.horizontalKillPlaneHitBox = 0.1;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -251,34 +258,25 @@ public class ParkourArena implements Arena {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of horizontal blocks the hit-box of kill plane blocks should cover
|
||||
* Gets the block types used for this parkour arena's obstacle blocks
|
||||
*
|
||||
* <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>
|
||||
* @return <p>The types of blocks used as obstacles</p>
|
||||
*/
|
||||
public double getHorizontalKillPlaneHitBox() {
|
||||
return this.horizontalKillPlaneHitBox;
|
||||
public @NotNull Set<Material> getObstacleBlocks() {
|
||||
if (this.obstacleBlocks != null) {
|
||||
return new HashSet<>(this.obstacleBlocks);
|
||||
} else {
|
||||
return MiniGames.getInstance().getParkourConfiguration().getObstacleBlocks();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the number of horizontal blocks the hit-box of kill plane blocks should cover
|
||||
* Gets the names of the blocks used as this arena's obstacle blocks
|
||||
*
|
||||
* <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>
|
||||
* @return <p>The names of the blocks used as this arena's obstacle blocks</p>
|
||||
*/
|
||||
public boolean setHorizontalKillPlaneHitBox(double horizontalKillPlaneHitBox) {
|
||||
if (horizontalKillPlaneHitBox > 1 || horizontalKillPlaneHitBox < -1) {
|
||||
return false;
|
||||
}
|
||||
this.horizontalKillPlaneHitBox = horizontalKillPlaneHitBox;
|
||||
this.saveArena();
|
||||
return true;
|
||||
public @Nullable Set<String> getObstacleBlockNames() {
|
||||
return this.obstacleBlockNames;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -335,7 +333,7 @@ public class ParkourArena implements Arena {
|
||||
|
||||
@Override
|
||||
public boolean willCauseLoss(Block block) {
|
||||
return this.getKillPlaneBlocks().contains(block.getType());
|
||||
return this.getKillPlaneBlocks().contains(block.getType()) || this.getObstacleBlocks().contains(block.getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -451,6 +449,28 @@ public class ParkourArena implements Arena {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the type of blocks used as obstacle blocks
|
||||
*
|
||||
* @param obstacleBlockNames <p>The names of the obstacle blocks</p>
|
||||
*/
|
||||
public boolean setObstacleBlocks(@NotNull Set<String> obstacleBlockNames) {
|
||||
if (obstacleBlockNames.isEmpty()) {
|
||||
this.obstacleBlockNames = null;
|
||||
this.obstacleBlocks = null;
|
||||
} else {
|
||||
Set<Material> parsed = MaterialHelper.loadMaterialList(new ArrayList<>(obstacleBlockNames), "+",
|
||||
MiniGames.getInstance().getLogger());
|
||||
if (parsed.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
this.obstacleBlockNames = obstacleBlockNames;
|
||||
this.obstacleBlocks = parsed;
|
||||
}
|
||||
this.saveArena();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a checkpoint to this arena
|
||||
*
|
||||
|
@ -64,10 +64,12 @@ public enum ParkourArenaEditableProperty {
|
||||
EditablePropertyType.MATERIAL_LIST),
|
||||
|
||||
/**
|
||||
* The horizontal hit-box of kill blocks
|
||||
* The blocks used as this arena's obstacle blocks
|
||||
*/
|
||||
HORIZONTAL_KILL_PLANE_HIT_BOX("horizontalKillPlaneHitBox",
|
||||
(arena) -> String.valueOf(arena.getHorizontalKillPlaneHitBox()), EditablePropertyType.DOUBLE);
|
||||
OBSTACLE_BLOCKS("obstacleBlocks", (arena) -> String.valueOf(arena.getObstacleBlockNames()),
|
||||
EditablePropertyType.MATERIAL_LIST),
|
||||
|
||||
;
|
||||
|
||||
private final @NotNull String argumentString;
|
||||
private final Function<ParkourArena, String> currentValueProvider;
|
||||
|
@ -43,9 +43,9 @@ public enum ParkourArenaStorageKey {
|
||||
KILL_PLANE_BLOCKS("killPlaneBlocks"),
|
||||
|
||||
/**
|
||||
* The key for this arena's horizontal kill plane hit box
|
||||
* The key for this arena's obstacle blocks (overrides the config)
|
||||
*/
|
||||
HORIZONTAL_KILL_PLANE_HIT_BOX("horizontalKillPlaneHitBox"),
|
||||
OBSTACLE_BLOCKS("obstacleBlocks"),
|
||||
|
||||
/**
|
||||
* The key for this arena's checkpoint locations
|
||||
|
@ -98,7 +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));
|
||||
case OBSTACLE_BLOCKS -> arena.setObstacleBlocks(new HashSet<>(List.of(value.split(","))));
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@ public class ParkourConfiguration extends MiniGameConfiguration {
|
||||
private boolean mustDoGroupedInSequence;
|
||||
private boolean ignoreRecordsUntilGroupBeatenOnce;
|
||||
private Set<Material> killPlaneBlocks;
|
||||
private Set<Material> obstacleBlocks;
|
||||
|
||||
/**
|
||||
* Instantiates a new dropper configuration
|
||||
@ -63,12 +64,22 @@ public class ParkourConfiguration extends MiniGameConfiguration {
|
||||
return new HashSet<>(this.killPlaneBlocks);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all types of blocks constituting parkour arena's obstacle blocks
|
||||
*
|
||||
* @return <p>The types of blocks constituting parkour arena's obstacle blocks</p>
|
||||
*/
|
||||
public Set<Material> getObstacleBlocks() {
|
||||
return new HashSet<>(this.obstacleBlocks);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void load() {
|
||||
this.enforceCheckpointOrder = configuration.getBoolean(rootNode + "enforceCheckpointOrder", false);
|
||||
this.mustDoGroupedInSequence = configuration.getBoolean(rootNode + "mustDoGroupedInSequence", true);
|
||||
this.ignoreRecordsUntilGroupBeatenOnce = configuration.getBoolean(rootNode + "ignoreRecordsUntilGroupBeatenOnce", false);
|
||||
this.killPlaneBlocks = loadMaterialList(rootNode + "killPlaneBlocks");
|
||||
this.obstacleBlocks = loadMaterialList(rootNode + "obstacleBlocks");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -82,6 +93,10 @@ public class ParkourConfiguration extends MiniGameConfiguration {
|
||||
for (Material material : killPlaneBlocks) {
|
||||
builder.append("\n - ").append(material.name());
|
||||
}
|
||||
builder.append("\n" + "Obstacle blocks: ");
|
||||
for (Material material : obstacleBlocks) {
|
||||
builder.append("\n - ").append(material.name());
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@ import net.knarcraft.minigames.config.ParkourConfiguration;
|
||||
import net.knarcraft.minigames.config.SharedConfiguration;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
@ -34,6 +35,8 @@ import java.util.Set;
|
||||
*/
|
||||
public class MoveListener implements Listener {
|
||||
|
||||
private static final BoundingBox fullBlockBox = new BoundingBox(0, 0, 0, 1, 1, 1);
|
||||
|
||||
private final DropperConfiguration dropperConfiguration;
|
||||
private final ParkourConfiguration parkourConfiguration;
|
||||
|
||||
@ -51,12 +54,15 @@ public class MoveListener implements Listener {
|
||||
@EventHandler
|
||||
public void onPlayerMove(PlayerMoveEvent event) {
|
||||
// Ignore if no actual movement is happening
|
||||
if (event.getFrom().equals(event.getTo()) || event.getTo() == null) {
|
||||
if (event.getTo() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ArenaSession session = MiniGames.getInstance().getSession(event.getPlayer().getUniqueId());
|
||||
if (session instanceof DropperArenaSession dropperSession) {
|
||||
if (event.getFrom().equals(event.getTo())) {
|
||||
return;
|
||||
}
|
||||
doDropperArenaChecks(event, dropperSession);
|
||||
} else if (session instanceof ParkourArenaSession parkourSession) {
|
||||
doParkourArenaChecks(event, parkourSession);
|
||||
@ -70,8 +76,7 @@ public class MoveListener implements Listener {
|
||||
* @param arenaSession <p>The dropper session of the player triggering the event</p>
|
||||
*/
|
||||
private void doParkourArenaChecks(@NotNull PlayerMoveEvent event, ParkourArenaSession arenaSession) {
|
||||
// Ignore movement which won't cause the player's block to change
|
||||
if (event.getTo() == null || isSameLocation(event.getFrom(), event.getTo())) {
|
||||
if (event.getTo() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -228,7 +233,7 @@ public class MoveListener implements Listener {
|
||||
}
|
||||
}
|
||||
} else if (arena instanceof ParkourArena) {
|
||||
return checkParkourDeathBlock(arenaSession, toLocation);
|
||||
return checkParkourDeathBlock((ParkourArenaSession) arenaSession, toLocation);
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -241,35 +246,49 @@ public class MoveListener implements Listener {
|
||||
* @param toLocation <p>The location the player is moving to</p>
|
||||
* @return <p>True if the player hit a death block</p>
|
||||
*/
|
||||
private boolean checkParkourDeathBlock(@NotNull ArenaSession arenaSession,
|
||||
private boolean checkParkourDeathBlock(@NotNull ParkourArenaSession arenaSession,
|
||||
@NotNull Location toLocation) {
|
||||
// If the player is standing on a non-full block, event.getTo will give the correct block, but if not, the
|
||||
// block below has to be checked instead.
|
||||
Set<Block> blocksBelow = getBlocksBeneathLocation(toLocation, 0);
|
||||
Set<Block> adjustedBlocks = new HashSet<>();
|
||||
for (Block block : blocksBelow) {
|
||||
if (block.getType().isAir()) {
|
||||
block = block.getLocation().clone().subtract(0, 0.2, 0).getBlock();
|
||||
// Only trigger hit detection for passable blocks if the player is in the block
|
||||
if (block.isPassable()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (arenaSession.getArena().willCauseLoss(block)) {
|
||||
adjustedBlocks.add(block);
|
||||
}
|
||||
// A simple check, only for kill blocks
|
||||
if (isOnKillBlock(arenaSession, toLocation)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// As the check for obstacle blocks is extensive, it's skipped if possible
|
||||
Set<Material> obstacleBlocks = arenaSession.getArena().getObstacleBlocks();
|
||||
if (obstacleBlocks.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create a hit-box approximate to the player's real hit-box
|
||||
double horizontalHitBox = ((ParkourArena) arenaSession.getArena()).getHorizontalKillPlaneHitBox();
|
||||
BoundingBox playerBox = new BoundingBox(-horizontalHitBox, -0.1, -horizontalHitBox,
|
||||
0.6 + horizontalHitBox, 1, 0.6 + horizontalHitBox).shift(
|
||||
double playerHeight = 1.8;
|
||||
Player player = Bukkit.getPlayer(arenaSession.getEntryState().getPlayerId());
|
||||
if (player != null && player.isSneaking()) {
|
||||
playerHeight = 1.5;
|
||||
}
|
||||
BoundingBox playerBox = new BoundingBox(-0.05, -0.05, -0.05,
|
||||
0.6 + 0.05, playerHeight + 0.05, 0.6 + 0.05).shift(
|
||||
toLocation).shift(-0.3, -0.05, -0.3);
|
||||
BoundingBox playerPassableBox = new BoundingBox(0.2, 0.5, 0.2,
|
||||
0.4, playerHeight - 0.5, 0.4).shift(
|
||||
toLocation).shift(-0.3, 0, -0.3);
|
||||
for (Block block : adjustedBlocks) {
|
||||
// For liquids, or anything without a proper collision shape, trigger collision
|
||||
Set<Block> possiblyHitBlocks = new HashSet<>();
|
||||
possiblyHitBlocks.addAll(getBlocksBeneathLocation(toLocation, 0, 0.01));
|
||||
possiblyHitBlocks.addAll(getBlocksBeneathLocation(toLocation, 1, 0.01));
|
||||
possiblyHitBlocks.addAll(getBlocksBeneathLocation(toLocation, -1, 0.01));
|
||||
possiblyHitBlocks.addAll(getBlocksBeneathLocation(toLocation, -2, 0.01));
|
||||
|
||||
for (Block block : possiblyHitBlocks) {
|
||||
if (!obstacleBlocks.contains(block.getType())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// For liquids, or anything without a proper collision shape, trigger collision if the player is partly
|
||||
// inside when treated as a full block
|
||||
if (block.isLiquid() || block.getCollisionShape().getBoundingBoxes().isEmpty()) {
|
||||
arenaSession.triggerLoss();
|
||||
return true;
|
||||
if (playerPassableBox.overlaps(fullBlockBox.clone().shift(block.getLocation()))) {
|
||||
arenaSession.triggerLoss();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check whether the player's actual hit-box is intersecting with a block
|
||||
@ -286,6 +305,34 @@ public class MoveListener implements Listener {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* As simple check for whether a player is moving on top of a kill block
|
||||
*
|
||||
* @param arenaSession <p>The arena session the player is in</p>
|
||||
* @param toLocation <p>The location the player is moving to</p>
|
||||
* @return <p>True if the player is on a kill block, and a loss has been triggered</p>
|
||||
*/
|
||||
private boolean isOnKillBlock(ParkourArenaSession arenaSession, Location toLocation) {
|
||||
// If the player is standing on a non-full block, event.getTo will give the correct block, but if not, the
|
||||
// block below has to be checked instead.
|
||||
Set<Block> blocksBelow = getBlocksBeneathLocation(toLocation, 0);
|
||||
Set<Material> killPlaneBlocks = arenaSession.getArena().getKillPlaneBlocks();
|
||||
for (Block block : blocksBelow) {
|
||||
if (block.getType().isAir()) {
|
||||
block = block.getLocation().clone().subtract(0, 0.2, 0).getBlock();
|
||||
// Only trigger hit detection for passable blocks if the player is in the block
|
||||
if (block.isPassable()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (killPlaneBlocks.contains(block.getType())) {
|
||||
arenaSession.triggerLoss();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the blocks at the given location that will be affected by the player's hit-box
|
||||
*
|
||||
@ -293,12 +340,31 @@ public class MoveListener implements Listener {
|
||||
* @return <p>The blocks beneath the player</p>
|
||||
*/
|
||||
private Set<Block> getBlocksBeneathLocation(Location location, double depth) {
|
||||
return getBlocksBeneathLocation(location, depth, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the blocks at the given location that will be affected by the player's hit-box
|
||||
*
|
||||
* @param location <p>The location to check</p>
|
||||
* @param extraRange <p>Extra range of the square used for finding blocks</p>
|
||||
* @return <p>The blocks beneath the player</p>
|
||||
*/
|
||||
private Set<Block> getBlocksBeneathLocation(Location location, double depth, double extraRange) {
|
||||
Set<Block> blocksBeneath = new HashSet<>();
|
||||
double halfPlayerWidth = 0.3;
|
||||
double halfPlayerWidth = 0.3 + extraRange;
|
||||
blocksBeneath.add(location.clone().subtract(halfPlayerWidth, depth, halfPlayerWidth).getBlock());
|
||||
blocksBeneath.add(location.clone().subtract(-halfPlayerWidth, depth, halfPlayerWidth).getBlock());
|
||||
blocksBeneath.add(location.clone().subtract(halfPlayerWidth, depth, -halfPlayerWidth).getBlock());
|
||||
blocksBeneath.add(location.clone().subtract(-halfPlayerWidth, depth, -halfPlayerWidth).getBlock());
|
||||
// Once a certain size is reached, if the player is in the centre of a block, 9 must be accounted for
|
||||
if (halfPlayerWidth > 0.5) {
|
||||
blocksBeneath.add(location.getBlock());
|
||||
blocksBeneath.add(location.clone().subtract(halfPlayerWidth, depth, 0).getBlock());
|
||||
blocksBeneath.add(location.clone().subtract(-halfPlayerWidth, depth, 0).getBlock());
|
||||
blocksBeneath.add(location.clone().subtract(0, depth, -halfPlayerWidth).getBlock());
|
||||
blocksBeneath.add(location.clone().subtract(0, depth, halfPlayerWidth).getBlock());
|
||||
}
|
||||
return blocksBeneath;
|
||||
}
|
||||
|
||||
|
@ -135,7 +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.OBSTACLE_BLOCKS.getKey(), getObstacleBlocks(arena));
|
||||
configSection.set(ParkourArenaStorageKey.CHECKPOINTS.getKey(), arena.getCheckpoints());
|
||||
RewardStorageHelper.saveRewards(arena, configSection, ParkourArenaStorageKey.REWARDS.getKey());
|
||||
saveParkourArenaData(arena.getData());
|
||||
@ -155,6 +155,20 @@ public final class ParkourArenaStorageHelper {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of the obstacle blocks for the given arena
|
||||
*
|
||||
* @param arena <p>The arena to get obstacle blocks for</p>
|
||||
* @return <p>The obstacle blocks</p>
|
||||
*/
|
||||
private static List<String> getObstacleBlocks(ParkourArena arena) {
|
||||
if (arena.getObstacleBlockNames() == null) {
|
||||
return new ArrayList<>();
|
||||
} else {
|
||||
return new ArrayList<>(arena.getObstacleBlockNames());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all arenas
|
||||
*
|
||||
@ -205,12 +219,17 @@ public final class ParkourArenaStorageHelper {
|
||||
List<?> killPlaneBlockNamesList = configurationSection.getList(ParkourArenaStorageKey.KILL_PLANE_BLOCKS.getKey());
|
||||
Set<String> killPlaneBlockNames;
|
||||
if (killPlaneBlockNamesList == null) {
|
||||
killPlaneBlockNames = new HashSet<>();
|
||||
killPlaneBlockNames = null;
|
||||
} else {
|
||||
killPlaneBlockNames = new HashSet<>((List<String>) killPlaneBlockNamesList);
|
||||
}
|
||||
double horizontalKillPlaneHitBox = configurationSection.getDouble(
|
||||
ParkourArenaStorageKey.HORIZONTAL_KILL_PLANE_HIT_BOX.getKey(), 0);
|
||||
List<?> obstacleBlockNamesList = configurationSection.getList(ParkourArenaStorageKey.OBSTACLE_BLOCKS.getKey());
|
||||
Set<String> obstacleBlockNames;
|
||||
if (obstacleBlockNamesList == null) {
|
||||
obstacleBlockNames = null;
|
||||
} else {
|
||||
obstacleBlockNames = new HashSet<>((List<String>) obstacleBlockNamesList);
|
||||
}
|
||||
List<Location> checkpoints = (List<Location>) configurationSection.get(ParkourArenaStorageKey.CHECKPOINTS.getKey());
|
||||
|
||||
Map<RewardCondition, Set<Reward>> rewards = RewardStorageHelper.loadRewards(configurationSection,
|
||||
@ -242,7 +261,7 @@ public final class ParkourArenaStorageHelper {
|
||||
}
|
||||
|
||||
return new ParkourArena(arenaId, arenaName, spawnLocation, exitLocation, winBlockType.getRawValue(), winLocation,
|
||||
killPlaneBlockNames, horizontalKillPlaneHitBox, checkpoints, rewards, arenaData,
|
||||
killPlaneBlockNames, obstacleBlockNames, checkpoints, rewards, arenaData,
|
||||
MiniGames.getInstance().getParkourArenaHandler());
|
||||
}
|
||||
|
||||
|
@ -137,6 +137,7 @@ public final class TabCompleteHelper {
|
||||
List<String> suggestions = new ArrayList<>();
|
||||
suggestions.add("LAVA,MAGMA_BLOCK");
|
||||
suggestions.add("WATER,MAGMA_BLOCK,LAVA,+BUTTONS,+CORALS");
|
||||
suggestions.add("CHAIN,END_ROD,LIGHTNING_ROD");
|
||||
return suggestions;
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,12 @@ parkour:
|
||||
killPlaneBlocks:
|
||||
- LAVA
|
||||
- MAGMA_BLOCK
|
||||
|
||||
# The blocks treated as obstacles in a parkour arena, which will trigger a loss in any direction
|
||||
obstacleBlocks:
|
||||
- END_ROD
|
||||
- LIGHTNING_ROD
|
||||
- CHAIN
|
||||
dropper:
|
||||
# Whether to block using the shift key to drop faster than the intended drop speed
|
||||
blockSneaking: true
|
||||
|
Loading…
Reference in New Issue
Block a user