mirror of
https://github.com/SunNetservers/MiniGames.git
synced 2024-12-05 00:43:15 +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. |
|
| 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 when stepped on. +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. |
|
| 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
|
## 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 |
|
| 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. |
|
| 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. |
|
| 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:
|
#### blockWhitelist default:
|
||||||
|
|
||||||
@ -270,6 +271,12 @@ These are all the options that can be changed for an arena.
|
|||||||
- LAVA
|
- LAVA
|
||||||
- MAGMA_BLOCK
|
- MAGMA_BLOCK
|
||||||
|
|
||||||
|
#### obstacleBlocks default:
|
||||||
|
|
||||||
|
- END_ROD
|
||||||
|
- LIGHTNING_ROD
|
||||||
|
- CHAIN
|
||||||
|
|
||||||
## Record placeholders
|
## Record placeholders
|
||||||
|
|
||||||
Player records can be displayed on a leaderboard by using PlaceholderAPI. If you want to display a sign-based
|
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;
|
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.
|
* 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
|
* 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 types of blocks that trigger a loss when stepped on</p>
|
||||||
* @param horizontalKillPlaneHitBox <p>The number of horizontal blocks the hit-box of kill plane blocks should cover</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 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>
|
||||||
*/
|
*/
|
||||||
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, double horizontalKillPlaneHitBox,
|
@Nullable Set<String> killPlaneBlockNames, @Nullable Set<String> obstacleBlockNames,
|
||||||
@NotNull List<Location> checkpoints,
|
@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) {
|
||||||
@ -123,7 +128,9 @@ 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.obstacleBlockNames = obstacleBlockNames;
|
||||||
|
this.obstacleBlocks = this.obstacleBlockNames == null ? null : MaterialHelper.loadMaterialList(
|
||||||
|
new ArrayList<>(obstacleBlockNames), "+", MiniGames.getInstance().getLogger());
|
||||||
this.checkpoints = checkpoints;
|
this.checkpoints = checkpoints;
|
||||||
this.parkourArenaData = parkourArenaData;
|
this.parkourArenaData = parkourArenaData;
|
||||||
this.parkourArenaHandler = arenaHandler;
|
this.parkourArenaHandler = arenaHandler;
|
||||||
@ -156,9 +163,9 @@ public class ParkourArena implements Arena {
|
|||||||
this.parkourArenaData = new ParkourArenaData(this.arenaId, recordRegistries, new HashMap<>());
|
this.parkourArenaData = new ParkourArenaData(this.arenaId, recordRegistries, new HashMap<>());
|
||||||
this.winBlockType = Material.EMERALD_BLOCK;
|
this.winBlockType = Material.EMERALD_BLOCK;
|
||||||
this.killPlaneBlocks = null;
|
this.killPlaneBlocks = null;
|
||||||
|
this.obstacleBlocks = null;
|
||||||
this.checkpoints = new ArrayList<>();
|
this.checkpoints = new ArrayList<>();
|
||||||
this.parkourArenaHandler = arenaHandler;
|
this.parkourArenaHandler = arenaHandler;
|
||||||
this.horizontalKillPlaneHitBox = 0.1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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
|
* @return <p>The types of blocks used as obstacles</p>
|
||||||
* 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() {
|
public @NotNull Set<Material> getObstacleBlocks() {
|
||||||
return this.horizontalKillPlaneHitBox;
|
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
|
* @return <p>The names of the blocks used as this arena's obstacle blocks</p>
|
||||||
* 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) {
|
public @Nullable Set<String> getObstacleBlockNames() {
|
||||||
if (horizontalKillPlaneHitBox > 1 || horizontalKillPlaneHitBox < -1) {
|
return this.obstacleBlockNames;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
this.horizontalKillPlaneHitBox = horizontalKillPlaneHitBox;
|
|
||||||
this.saveArena();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -335,7 +333,7 @@ public class ParkourArena implements Arena {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean willCauseLoss(Block block) {
|
public boolean willCauseLoss(Block block) {
|
||||||
return this.getKillPlaneBlocks().contains(block.getType());
|
return this.getKillPlaneBlocks().contains(block.getType()) || this.getObstacleBlocks().contains(block.getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -451,6 +449,28 @@ public class ParkourArena implements Arena {
|
|||||||
return true;
|
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
|
* Adds a checkpoint to this arena
|
||||||
*
|
*
|
||||||
|
@ -64,10 +64,12 @@ public enum ParkourArenaEditableProperty {
|
|||||||
EditablePropertyType.MATERIAL_LIST),
|
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",
|
OBSTACLE_BLOCKS("obstacleBlocks", (arena) -> String.valueOf(arena.getObstacleBlockNames()),
|
||||||
(arena) -> String.valueOf(arena.getHorizontalKillPlaneHitBox()), EditablePropertyType.DOUBLE);
|
EditablePropertyType.MATERIAL_LIST),
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
private final @NotNull String argumentString;
|
private final @NotNull String argumentString;
|
||||||
private final Function<ParkourArena, String> currentValueProvider;
|
private final Function<ParkourArena, String> currentValueProvider;
|
||||||
|
@ -43,9 +43,9 @@ public enum ParkourArenaStorageKey {
|
|||||||
KILL_PLANE_BLOCKS("killPlaneBlocks"),
|
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
|
* 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_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));
|
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 mustDoGroupedInSequence;
|
||||||
private boolean ignoreRecordsUntilGroupBeatenOnce;
|
private boolean ignoreRecordsUntilGroupBeatenOnce;
|
||||||
private Set<Material> killPlaneBlocks;
|
private Set<Material> killPlaneBlocks;
|
||||||
|
private Set<Material> obstacleBlocks;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiates a new dropper configuration
|
* Instantiates a new dropper configuration
|
||||||
@ -63,12 +64,22 @@ public class ParkourConfiguration extends MiniGameConfiguration {
|
|||||||
return new HashSet<>(this.killPlaneBlocks);
|
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
|
@Override
|
||||||
protected void load() {
|
protected void load() {
|
||||||
this.enforceCheckpointOrder = configuration.getBoolean(rootNode + "enforceCheckpointOrder", false);
|
this.enforceCheckpointOrder = configuration.getBoolean(rootNode + "enforceCheckpointOrder", false);
|
||||||
this.mustDoGroupedInSequence = configuration.getBoolean(rootNode + "mustDoGroupedInSequence", true);
|
this.mustDoGroupedInSequence = configuration.getBoolean(rootNode + "mustDoGroupedInSequence", true);
|
||||||
this.ignoreRecordsUntilGroupBeatenOnce = configuration.getBoolean(rootNode + "ignoreRecordsUntilGroupBeatenOnce", false);
|
this.ignoreRecordsUntilGroupBeatenOnce = configuration.getBoolean(rootNode + "ignoreRecordsUntilGroupBeatenOnce", false);
|
||||||
this.killPlaneBlocks = loadMaterialList(rootNode + "killPlaneBlocks");
|
this.killPlaneBlocks = loadMaterialList(rootNode + "killPlaneBlocks");
|
||||||
|
this.obstacleBlocks = loadMaterialList(rootNode + "obstacleBlocks");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -82,6 +93,10 @@ public class ParkourConfiguration extends MiniGameConfiguration {
|
|||||||
for (Material material : killPlaneBlocks) {
|
for (Material material : killPlaneBlocks) {
|
||||||
builder.append("\n - ").append(material.name());
|
builder.append("\n - ").append(material.name());
|
||||||
}
|
}
|
||||||
|
builder.append("\n" + "Obstacle blocks: ");
|
||||||
|
for (Material material : obstacleBlocks) {
|
||||||
|
builder.append("\n - ").append(material.name());
|
||||||
|
}
|
||||||
return builder.toString();
|
return builder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ import net.knarcraft.minigames.config.ParkourConfiguration;
|
|||||||
import net.knarcraft.minigames.config.SharedConfiguration;
|
import net.knarcraft.minigames.config.SharedConfiguration;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
@ -34,6 +35,8 @@ import java.util.Set;
|
|||||||
*/
|
*/
|
||||||
public class MoveListener implements Listener {
|
public class MoveListener implements Listener {
|
||||||
|
|
||||||
|
private static final BoundingBox fullBlockBox = new BoundingBox(0, 0, 0, 1, 1, 1);
|
||||||
|
|
||||||
private final DropperConfiguration dropperConfiguration;
|
private final DropperConfiguration dropperConfiguration;
|
||||||
private final ParkourConfiguration parkourConfiguration;
|
private final ParkourConfiguration parkourConfiguration;
|
||||||
|
|
||||||
@ -51,12 +54,15 @@ public class MoveListener implements Listener {
|
|||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPlayerMove(PlayerMoveEvent event) {
|
public void onPlayerMove(PlayerMoveEvent event) {
|
||||||
// Ignore if no actual movement is happening
|
// Ignore if no actual movement is happening
|
||||||
if (event.getFrom().equals(event.getTo()) || event.getTo() == null) {
|
if (event.getTo() == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ArenaSession session = MiniGames.getInstance().getSession(event.getPlayer().getUniqueId());
|
ArenaSession session = MiniGames.getInstance().getSession(event.getPlayer().getUniqueId());
|
||||||
if (session instanceof DropperArenaSession dropperSession) {
|
if (session instanceof DropperArenaSession dropperSession) {
|
||||||
|
if (event.getFrom().equals(event.getTo())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
doDropperArenaChecks(event, dropperSession);
|
doDropperArenaChecks(event, dropperSession);
|
||||||
} else if (session instanceof ParkourArenaSession parkourSession) {
|
} else if (session instanceof ParkourArenaSession parkourSession) {
|
||||||
doParkourArenaChecks(event, 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>
|
* @param arenaSession <p>The dropper session of the player triggering the event</p>
|
||||||
*/
|
*/
|
||||||
private void doParkourArenaChecks(@NotNull PlayerMoveEvent event, ParkourArenaSession arenaSession) {
|
private void doParkourArenaChecks(@NotNull PlayerMoveEvent event, ParkourArenaSession arenaSession) {
|
||||||
// Ignore movement which won't cause the player's block to change
|
if (event.getTo() == null) {
|
||||||
if (event.getTo() == null || isSameLocation(event.getFrom(), event.getTo())) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,7 +233,7 @@ public class MoveListener implements Listener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (arena instanceof ParkourArena) {
|
} else if (arena instanceof ParkourArena) {
|
||||||
return checkParkourDeathBlock(arenaSession, toLocation);
|
return checkParkourDeathBlock((ParkourArenaSession) arenaSession, toLocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -241,35 +246,49 @@ public class MoveListener implements Listener {
|
|||||||
* @param toLocation <p>The location the player is moving to</p>
|
* @param toLocation <p>The location the player is moving to</p>
|
||||||
* @return <p>True if the player hit a death block</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) {
|
@NotNull Location toLocation) {
|
||||||
// If the player is standing on a non-full block, event.getTo will give the correct block, but if not, the
|
// A simple check, only for kill blocks
|
||||||
// block below has to be checked instead.
|
if (isOnKillBlock(arenaSession, toLocation)) {
|
||||||
Set<Block> blocksBelow = getBlocksBeneathLocation(toLocation, 0);
|
return true;
|
||||||
Set<Block> adjustedBlocks = new HashSet<>();
|
}
|
||||||
for (Block block : blocksBelow) {
|
|
||||||
if (block.getType().isAir()) {
|
// As the check for obstacle blocks is extensive, it's skipped if possible
|
||||||
block = block.getLocation().clone().subtract(0, 0.2, 0).getBlock();
|
Set<Material> obstacleBlocks = arenaSession.getArena().getObstacleBlocks();
|
||||||
// Only trigger hit detection for passable blocks if the player is in the block
|
if (obstacleBlocks.isEmpty()) {
|
||||||
if (block.isPassable()) {
|
return false;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (arenaSession.getArena().willCauseLoss(block)) {
|
|
||||||
adjustedBlocks.add(block);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a hit-box approximate to the player's real hit-box
|
// Create a hit-box approximate to the player's real hit-box
|
||||||
double horizontalHitBox = ((ParkourArena) arenaSession.getArena()).getHorizontalKillPlaneHitBox();
|
double playerHeight = 1.8;
|
||||||
BoundingBox playerBox = new BoundingBox(-horizontalHitBox, -0.1, -horizontalHitBox,
|
Player player = Bukkit.getPlayer(arenaSession.getEntryState().getPlayerId());
|
||||||
0.6 + horizontalHitBox, 1, 0.6 + horizontalHitBox).shift(
|
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);
|
toLocation).shift(-0.3, 0, -0.3);
|
||||||
for (Block block : adjustedBlocks) {
|
Set<Block> possiblyHitBlocks = new HashSet<>();
|
||||||
// For liquids, or anything without a proper collision shape, trigger collision
|
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()) {
|
if (block.isLiquid() || block.getCollisionShape().getBoundingBoxes().isEmpty()) {
|
||||||
arenaSession.triggerLoss();
|
if (playerPassableBox.overlaps(fullBlockBox.clone().shift(block.getLocation()))) {
|
||||||
return true;
|
arenaSession.triggerLoss();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether the player's actual hit-box is intersecting with a block
|
// Check whether the player's actual hit-box is intersecting with a block
|
||||||
@ -286,6 +305,34 @@ public class MoveListener implements Listener {
|
|||||||
return false;
|
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
|
* 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>
|
* @return <p>The blocks beneath the player</p>
|
||||||
*/
|
*/
|
||||||
private Set<Block> getBlocksBeneathLocation(Location location, double depth) {
|
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<>();
|
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());
|
||||||
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;
|
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_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.OBSTACLE_BLOCKS.getKey(), getObstacleBlocks(arena));
|
||||||
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());
|
||||||
@ -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
|
* Loads all arenas
|
||||||
*
|
*
|
||||||
@ -205,12 +219,17 @@ public final class ParkourArenaStorageHelper {
|
|||||||
List<?> killPlaneBlockNamesList = configurationSection.getList(ParkourArenaStorageKey.KILL_PLANE_BLOCKS.getKey());
|
List<?> killPlaneBlockNamesList = configurationSection.getList(ParkourArenaStorageKey.KILL_PLANE_BLOCKS.getKey());
|
||||||
Set<String> killPlaneBlockNames;
|
Set<String> killPlaneBlockNames;
|
||||||
if (killPlaneBlockNamesList == null) {
|
if (killPlaneBlockNamesList == null) {
|
||||||
killPlaneBlockNames = new HashSet<>();
|
killPlaneBlockNames = null;
|
||||||
} else {
|
} else {
|
||||||
killPlaneBlockNames = new HashSet<>((List<String>) killPlaneBlockNamesList);
|
killPlaneBlockNames = new HashSet<>((List<String>) killPlaneBlockNamesList);
|
||||||
}
|
}
|
||||||
double horizontalKillPlaneHitBox = configurationSection.getDouble(
|
List<?> obstacleBlockNamesList = configurationSection.getList(ParkourArenaStorageKey.OBSTACLE_BLOCKS.getKey());
|
||||||
ParkourArenaStorageKey.HORIZONTAL_KILL_PLANE_HIT_BOX.getKey(), 0);
|
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());
|
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,
|
||||||
@ -242,7 +261,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, horizontalKillPlaneHitBox, checkpoints, rewards, arenaData,
|
killPlaneBlockNames, obstacleBlockNames, checkpoints, rewards, arenaData,
|
||||||
MiniGames.getInstance().getParkourArenaHandler());
|
MiniGames.getInstance().getParkourArenaHandler());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,6 +137,7 @@ public final class TabCompleteHelper {
|
|||||||
List<String> suggestions = new ArrayList<>();
|
List<String> suggestions = new ArrayList<>();
|
||||||
suggestions.add("LAVA,MAGMA_BLOCK");
|
suggestions.add("LAVA,MAGMA_BLOCK");
|
||||||
suggestions.add("WATER,MAGMA_BLOCK,LAVA,+BUTTONS,+CORALS");
|
suggestions.add("WATER,MAGMA_BLOCK,LAVA,+BUTTONS,+CORALS");
|
||||||
|
suggestions.add("CHAIN,END_ROD,LIGHTNING_ROD");
|
||||||
return suggestions;
|
return suggestions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +20,12 @@ parkour:
|
|||||||
killPlaneBlocks:
|
killPlaneBlocks:
|
||||||
- LAVA
|
- LAVA
|
||||||
- MAGMA_BLOCK
|
- 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:
|
dropper:
|
||||||
# Whether to block using the shift key to drop faster than the intended drop speed
|
# Whether to block using the shift key to drop faster than the intended drop speed
|
||||||
blockSneaking: true
|
blockSneaking: true
|
||||||
|
Loading…
Reference in New Issue
Block a user