Implements several configuration options #15

This commit is contained in:
Kristian Knarvik 2023-04-11 13:25:45 +02:00
parent 3bbf41206c
commit 50978d8baf
20 changed files with 419 additions and 63 deletions

View File

@ -1,5 +1,6 @@
package net.knarcraft.dropper;
import net.knarcraft.dropper.arena.ArenaGameMode;
import net.knarcraft.dropper.arena.DropperArenaData;
import net.knarcraft.dropper.arena.DropperArenaGroup;
import net.knarcraft.dropper.arena.DropperArenaHandler;
@ -21,6 +22,7 @@ import net.knarcraft.dropper.command.ListArenaCommand;
import net.knarcraft.dropper.command.ReloadCommand;
import net.knarcraft.dropper.command.RemoveArenaCommand;
import net.knarcraft.dropper.command.RemoveArenaTabCompleter;
import net.knarcraft.dropper.config.DropperConfiguration;
import net.knarcraft.dropper.container.SerializableMaterial;
import net.knarcraft.dropper.container.SerializableUUID;
import net.knarcraft.dropper.listener.CommandListener;
@ -28,7 +30,6 @@ import net.knarcraft.dropper.listener.DamageListener;
import net.knarcraft.dropper.listener.MoveListener;
import net.knarcraft.dropper.listener.PlayerLeaveListener;
import net.knarcraft.dropper.placeholder.DropperRecordExpansion;
import net.knarcraft.dropper.property.ArenaGameMode;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.PluginCommand;
@ -49,8 +50,10 @@ import java.util.logging.Level;
public final class Dropper extends JavaPlugin {
private static Dropper instance;
private DropperConfiguration configuration;
private DropperArenaHandler arenaHandler;
private DropperArenaPlayerRegistry playerRegistry;
private DropperRecordExpansion dropperRecordExpansion;
/**
* Gets an instance of this plugin
@ -79,6 +82,25 @@ public final class Dropper extends JavaPlugin {
return this.playerRegistry;
}
/**
* Gets the dropper configuration
*
* @return <p>The dropper configuration</p>
*/
public DropperConfiguration getDropperConfiguration() {
return this.configuration;
}
/**
* Logs a message
*
* @param level <p>The message level to log at</p>
* @param message <p>The message to log</p>
*/
public static void log(Level level, String message) {
Dropper.getInstance().getLogger().log(level, message);
}
/**
* Reloads all configurations and data from disk
*/
@ -86,6 +108,13 @@ public final class Dropper extends JavaPlugin {
// Load all arenas again
this.arenaHandler.loadArenas();
this.arenaHandler.loadGroups();
// Reload configuration
this.reloadConfig();
configuration.load();
// Clear record caches
dropperRecordExpansion.clearCaches();
}
@Override
@ -106,6 +135,8 @@ public final class Dropper extends JavaPlugin {
public void onEnable() {
// Plugin startup logic
instance = this;
this.saveDefaultConfig();
this.configuration = new DropperConfiguration(this.getConfig());
this.playerRegistry = new DropperArenaPlayerRegistry();
this.arenaHandler = new DropperArenaHandler();
this.arenaHandler.loadArenas();
@ -113,7 +144,7 @@ public final class Dropper extends JavaPlugin {
PluginManager pluginManager = getServer().getPluginManager();
pluginManager.registerEvents(new DamageListener(), this);
pluginManager.registerEvents(new MoveListener(), this);
pluginManager.registerEvents(new MoveListener(this.configuration), this);
pluginManager.registerEvents(new PlayerLeaveListener(), this);
pluginManager.registerEvents(new CommandListener(), this);
@ -122,14 +153,15 @@ public final class Dropper extends JavaPlugin {
registerCommand("dropperList", new ListArenaCommand(), null);
registerCommand("dropperJoin", new JoinArenaCommand(), new JoinArenaTabCompleter());
registerCommand("dropperLeave", new LeaveArenaCommand(), null);
registerCommand("dropperEdit", new EditArenaCommand(), new EditArenaTabCompleter());
registerCommand("dropperEdit", new EditArenaCommand(this.configuration), new EditArenaTabCompleter());
registerCommand("dropperRemove", new RemoveArenaCommand(), new RemoveArenaTabCompleter());
registerCommand("dropperGroupSet", new GroupSetCommand(), null);
registerCommand("dropperGroupSwap", new GroupSwapCommand(), null);
registerCommand("dropperGroupList", new GroupListCommand(), null);
if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) {
if (!new DropperRecordExpansion(this).register()) {
this.dropperRecordExpansion = new DropperRecordExpansion(this);
if (!this.dropperRecordExpansion.register()) {
getLogger().log(Level.WARNING, "Unable to register PlaceholderAPI expansion!");
}
}

View File

@ -1,6 +1,5 @@
package net.knarcraft.dropper.property;
package net.knarcraft.dropper.arena;
import net.knarcraft.dropper.arena.DropperArena;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

View File

@ -1,4 +1,4 @@
package net.knarcraft.dropper.property;
package net.knarcraft.dropper.arena;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.jetbrains.annotations.NotNull;

View File

@ -1,4 +1,4 @@
package net.knarcraft.dropper.property;
package net.knarcraft.dropper.arena;
import org.jetbrains.annotations.NotNull;

View File

@ -1,6 +1,7 @@
package net.knarcraft.dropper.arena;
import net.knarcraft.dropper.property.ArenaGameMode;
import net.knarcraft.dropper.Dropper;
import net.knarcraft.dropper.config.DropperConfiguration;
import net.knarcraft.dropper.util.StringSanitizer;
import org.bukkit.Location;
import org.bukkit.Material;
@ -102,12 +103,13 @@ public class DropperArena {
*/
public DropperArena(@NotNull String arenaName, @NotNull Location spawnLocation,
@NotNull DropperArenaHandler arenaHandler) {
DropperConfiguration configuration = Dropper.getInstance().getDropperConfiguration();
this.arenaId = UUID.randomUUID();
this.arenaName = arenaName;
this.spawnLocation = spawnLocation;
this.exitLocation = null;
this.playerVerticalVelocity = 3.92;
this.playerHorizontalVelocity = 1;
this.playerVerticalVelocity = configuration.getVerticalVelocity();
this.playerHorizontalVelocity = configuration.getHorizontalVelocity();
Map<ArenaGameMode, DropperArenaRecordsRegistry> recordRegistries = new HashMap<>();
for (ArenaGameMode arenaGameMode : ArenaGameMode.values()) {

View File

@ -2,7 +2,6 @@ package net.knarcraft.dropper.arena;
import net.knarcraft.dropper.Dropper;
import net.knarcraft.dropper.container.SerializableUUID;
import net.knarcraft.dropper.property.ArenaGameMode;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;

View File

@ -2,7 +2,6 @@ package net.knarcraft.dropper.arena;
import net.knarcraft.dropper.Dropper;
import net.knarcraft.dropper.container.SerializableUUID;
import net.knarcraft.dropper.property.ArenaGameMode;
import net.knarcraft.dropper.util.StringSanitizer;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.bukkit.entity.Player;

View File

@ -1,7 +1,7 @@
package net.knarcraft.dropper.arena;
import net.knarcraft.dropper.Dropper;
import net.knarcraft.dropper.property.ArenaGameMode;
import net.knarcraft.dropper.config.DropperConfiguration;
import net.knarcraft.dropper.property.RecordResult;
import net.knarcraft.dropper.util.PlayerTeleporter;
import org.bukkit.Location;
@ -37,7 +37,10 @@ public class DropperArenaSession {
this.deaths = 0;
this.startTime = System.currentTimeMillis();
this.entryState = new PlayerEntryState(player, gameMode);
DropperConfiguration configuration = Dropper.getInstance().getDropperConfiguration();
boolean makeInvisible = configuration.makePlayersInvisible();
boolean disableCollision = configuration.disableHitCollision();
this.entryState = new PlayerEntryState(player, gameMode, makeInvisible, disableCollision);
// Make the player fly to improve mobility in the air
this.entryState.setArenaState(this.arena.getPlayerHorizontalVelocity());
}
@ -68,7 +71,12 @@ public class DropperArenaSession {
stopSession();
// Check for, and display, records
registerRecord();
Dropper dropper = Dropper.getInstance();
boolean ignore = dropper.getDropperConfiguration().ignoreRecordsUntilGroupBeatenOnce();
DropperArenaGroup group = dropper.getArenaHandler().getGroup(this.arena.getArenaId());
if (!ignore || group == null || group.hasBeatenAll(this.gameMode, this.player)) {
registerRecord();
}
// Mark the arena as cleared
if (this.arena.getData().addCompleted(this.gameMode, this.player)) {

View File

@ -1,6 +1,5 @@
package net.knarcraft.dropper.arena;
import net.knarcraft.dropper.property.ArenaGameMode;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.entity.Player;
@ -22,6 +21,8 @@ public class PlayerEntryState {
private final boolean originalInvulnerable;
private final boolean originalIsSwimming;
private final boolean originalCollideAble;
private final boolean makePlayerInvisible;
private final boolean disableHitCollision;
private final ArenaGameMode arenaGameMode;
/**
@ -29,7 +30,8 @@ public class PlayerEntryState {
*
* @param player <p>The player whose state should be stored</p>
*/
public PlayerEntryState(@NotNull Player player, @NotNull ArenaGameMode arenaGameMode) {
public PlayerEntryState(@NotNull Player player, @NotNull ArenaGameMode arenaGameMode, boolean makePlayerInvisible,
boolean disableHitCollision) {
this.player = player;
this.entryLocation = player.getLocation().clone();
this.originalFlySpeed = player.getFlySpeed();
@ -40,6 +42,8 @@ public class PlayerEntryState {
this.originalIsSwimming = player.isSwimming();
this.arenaGameMode = arenaGameMode;
this.originalCollideAble = player.isCollidable();
this.makePlayerInvisible = makePlayerInvisible;
this.disableHitCollision = disableHitCollision;
}
/**
@ -52,8 +56,13 @@ public class PlayerEntryState {
this.player.setFlying(true);
this.player.setGameMode(GameMode.ADVENTURE);
this.player.setSwimming(false);
this.player.setCollidable(false);
this.player.addPotionEffect(new PotionEffect(PotionEffectType.INVISIBILITY, PotionEffect.INFINITE_DURATION, 3));
if (this.disableHitCollision) {
this.player.setCollidable(false);
}
if (this.makePlayerInvisible) {
this.player.addPotionEffect(new PotionEffect(PotionEffectType.INVISIBILITY,
PotionEffect.INFINITE_DURATION, 3));
}
// If playing on the inverted game-mode, negate the horizontal velocity to swap the controls
if (arenaGameMode == ArenaGameMode.INVERTED) {
@ -73,8 +82,12 @@ public class PlayerEntryState {
this.player.setFlySpeed(this.originalFlySpeed);
this.player.setInvulnerable(this.originalInvulnerable);
this.player.setSwimming(this.originalIsSwimming);
this.player.setCollidable(this.originalCollideAble);
this.player.removePotionEffect(PotionEffectType.INVISIBILITY);
if (this.disableHitCollision) {
this.player.setCollidable(this.originalCollideAble);
}
if (this.makePlayerInvisible) {
this.player.removePotionEffect(PotionEffectType.INVISIBILITY);
}
}
/**

View File

@ -1,8 +1,9 @@
package net.knarcraft.dropper.command;
import net.knarcraft.dropper.Dropper;
import net.knarcraft.dropper.arena.ArenaEditableProperty;
import net.knarcraft.dropper.arena.DropperArena;
import net.knarcraft.dropper.property.ArenaEditableProperty;
import net.knarcraft.dropper.config.DropperConfiguration;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.command.Command;
@ -16,6 +17,17 @@ import org.jetbrains.annotations.NotNull;
*/
public class EditArenaCommand implements CommandExecutor {
private final DropperConfiguration configuration;
/**
* Instantiates a new edit arena command
*
* @param configuration <p>The configuration to use</p>
*/
public EditArenaCommand(DropperConfiguration configuration) {
this.configuration = configuration;
}
@Override
public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
@NotNull String[] arguments) {
@ -92,7 +104,7 @@ public class EditArenaCommand implements CommandExecutor {
try {
velocity = Double.parseDouble(velocityString);
} catch (NumberFormatException exception) {
velocity = 3.92;
velocity = configuration.getVerticalVelocity();
}
// Require at least speed of 0.001, and at most 75 blocks/s
@ -111,12 +123,7 @@ public class EditArenaCommand implements CommandExecutor {
try {
velocity = Float.parseFloat(velocityString);
} catch (NumberFormatException exception) {
velocity = 1;
}
// Make sure the velocity isn't exactly 0
if (velocity == 0) {
velocity = 0.5f;
velocity = configuration.getHorizontalVelocity();
}
// If outside bonds, choose the most extreme value

View File

@ -1,11 +1,12 @@
package net.knarcraft.dropper.command;
import net.knarcraft.dropper.Dropper;
import net.knarcraft.dropper.arena.ArenaGameMode;
import net.knarcraft.dropper.arena.DropperArena;
import net.knarcraft.dropper.arena.DropperArenaGroup;
import net.knarcraft.dropper.arena.DropperArenaPlayerRegistry;
import net.knarcraft.dropper.arena.DropperArenaSession;
import net.knarcraft.dropper.property.ArenaGameMode;
import net.knarcraft.dropper.config.DropperConfiguration;
import net.knarcraft.dropper.util.PlayerTeleporter;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
@ -77,7 +78,8 @@ public class JoinArenaCommand implements CommandExecutor {
}
// Make sure the player has beaten the arena once in normal mode before playing another mode
if (gameMode != ArenaGameMode.DEFAULT &&
if (Dropper.getInstance().getDropperConfiguration().mustDoNormalModeFirst() &&
gameMode != ArenaGameMode.DEFAULT &&
specifiedArena.getData().hasNotCompleted(ArenaGameMode.DEFAULT, player)) {
player.sendMessage("You must complete this arena in normal mode first!");
return false;
@ -113,16 +115,17 @@ public class JoinArenaCommand implements CommandExecutor {
*/
private boolean doGroupChecks(@NotNull DropperArena dropperArena, @NotNull DropperArenaGroup arenaGroup,
@NotNull ArenaGameMode arenaGameMode, @NotNull Player player) {
DropperConfiguration configuration = Dropper.getInstance().getDropperConfiguration();
// Require that players beat all arenas in the group in the normal game-mode before trying challenge modes
if (arenaGameMode != ArenaGameMode.DEFAULT) {
if (!arenaGroup.hasBeatenAll(ArenaGameMode.DEFAULT, player)) {
player.sendMessage("You have not yet beaten all arenas in this group!");
return false;
}
if (configuration.mustDoNormalModeFirst() && arenaGameMode != ArenaGameMode.DEFAULT &&
!arenaGroup.hasBeatenAll(ArenaGameMode.DEFAULT, player)) {
player.sendMessage("You have not yet beaten all arenas in this group!");
return false;
}
// Require that the player has beaten the previous arena on the same game-mode before trying this one
if (!arenaGroup.canPlay(arenaGameMode, player, dropperArena.getArenaId())) {
if (configuration.mustDoGroupedInSequence() &&
!arenaGroup.canPlay(arenaGameMode, player, dropperArena.getArenaId())) {
player.sendMessage("You have not yet beaten the previous arena!");
return false;
}

View File

@ -0,0 +1,226 @@
package net.knarcraft.dropper.config;
import net.knarcraft.dropper.Dropper;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.Tag;
import org.bukkit.configuration.file.FileConfiguration;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class DropperConfiguration {
private final FileConfiguration configuration;
private double verticalVelocity;
private float horizontalVelocity;
private int randomlyInvertedTimer;
private boolean mustDoGroupedInSequence;
private boolean ignoreRecordsUntilGroupBeatenOnce;
private boolean mustDoNormalModeFirst;
private boolean makePlayersInvisible;
private boolean disableHitCollision;
private boolean overrideVerticalVelocity;
private double liquidHitBoxDepth;
private double solidHitBoxDistance;
private Set<Material> blockWhitelist;
/**
* Instantiates a new dropper configuration
*
* @param configuration <p>The YAML configuration to use internally</p>
*/
public DropperConfiguration(FileConfiguration configuration) {
this.configuration = configuration;
}
/**
* Gets whether vertical velocity should be overridden
*
* @return <p>Whether vertical velocity should be overridden</p>
*/
public boolean overrideVerticalVelocity() {
return this.overrideVerticalVelocity;
}
/**
* Gets the default vertical velocity
*
* @return <p>The default vertical velocity</p>
*/
public double getVerticalVelocity() {
return this.verticalVelocity;
}
/**
* Gets the default horizontal velocity
*
* @return <p>The default horizontal velocity</p>
*/
public float getHorizontalVelocity() {
return this.horizontalVelocity;
}
/**
* Gets the number of seconds before the randomly inverted game-mode toggles
*
* @return <p>Number of seconds before the inversion toggles</p>
*/
public int getRandomlyInvertedTimer() {
return this.randomlyInvertedTimer;
}
/**
* Gets whether grouped arenas must be done in the set sequence
*
* @return <p>Whether grouped arenas must be done in sequence</p>
*/
public boolean mustDoGroupedInSequence() {
return this.mustDoGroupedInSequence;
}
/**
* Gets whether the normal/default mode must be beaten before playing another game-mode
*
* @return <p>Whether the normal game-mode must be beaten first</p>
*/
public boolean mustDoNormalModeFirst() {
return this.mustDoNormalModeFirst;
}
/**
* Gets the types of block which should not trigger a loss
*
* @return <p>The materials that should not trigger a loss</p>
*/
public Set<Material> getBlockWhitelist() {
return new HashSet<>(this.blockWhitelist);
}
/**
* Gets whether records should be discarded, unless the player has already beaten all arenas in the group
*
* @return <p>Whether to ignore records on the first play-through</p>
*/
public boolean ignoreRecordsUntilGroupBeatenOnce() {
return this.ignoreRecordsUntilGroupBeatenOnce;
}
/**
* Gets whether players should be made invisible while in an arena
*
* @return <p>Whether players should be made invisible</p>
*/
public boolean makePlayersInvisible() {
return this.makePlayersInvisible;
}
/**
* Gets whether entity hit-collision of players in an arena should be disabled
*
* @return <p>Whether to disable hit collision</p>
*/
public boolean disableHitCollision() {
return this.disableHitCollision;
}
/**
* Gets the negative depth a player must reach in a liquid block for fail/win detection to trigger
*
* <p>This decides how far inside a non-solid block the player must go before detection triggers. The closer to -1
* it is, the more accurate it will seem to the player, but the likelihood of not detecting the hit increases.</p>
*
* @return <p>The liquid hit box depth to use</p>
*/
public double getLiquidHitBoxDepth() {
return this.liquidHitBoxDepth;
}
/**
* Gets the positive distance a player must at most be from a block for fail/win detection to trigger
*
* <p>This decides the distance the player must be from a block below them before a hit triggers. If too low, the
* likelihood of detecting the hit decreases, but it won't look like the player hit the block without being near.</p>
*
* @return <p>The solid hit box distance to use</p>
*/
public double getSolidHitBoxDistance() {
return this.solidHitBoxDistance;
}
/**
* Loads all configuration values from disk
*/
public void load() {
this.verticalVelocity = configuration.getDouble("verticalVelocity", 1.0);
this.horizontalVelocity = (float) configuration.getDouble("horizontalVelocity", 1.0);
this.randomlyInvertedTimer = configuration.getInt("randomlyInvertedTimer", 7);
this.mustDoGroupedInSequence = configuration.getBoolean("mustDoGroupedInSequence", true);
this.ignoreRecordsUntilGroupBeatenOnce = configuration.getBoolean("ignoreRecordsUntilGroupBeatenOnce", false);
this.mustDoNormalModeFirst = configuration.getBoolean("mustDoNormalModeFirst", true);
this.makePlayersInvisible = configuration.getBoolean("makePlayersInvisible", false);
this.disableHitCollision = configuration.getBoolean("disableHitCollision", true);
this.overrideVerticalVelocity = configuration.getBoolean("overrideVerticalVelocity", true);
this.liquidHitBoxDepth = configuration.getDouble("liquidHitBoxDepth", -0.8);
this.solidHitBoxDistance = configuration.getDouble("solidHitBoxDistance", 0.2);
loadBlockWhitelist();
}
/**
* Loads the materials specified in the block whitelist
*/
private void loadBlockWhitelist() {
this.blockWhitelist = new HashSet<>();
List<?> blockWhitelist = configuration.getList("blockWhiteList", new ArrayList<>());
for (Object value : blockWhitelist) {
if (!(value instanceof String string)) {
continue;
}
// Try to parse a material tag first
if (parseMaterialTag(string)) {
continue;
}
// Try to parse a material name
Material matched = Material.matchMaterial(string);
if (matched != null) {
this.blockWhitelist.add(matched);
} else {
Dropper.log(Level.WARNING, "Unable to parse: " + string);
}
}
}
/**
* Tries to parse the material tag in the specified material name
*
* @param materialName <p>The material name that might be a material tag</p>
* @return <p>True if a tag was found</p>
*/
private boolean parseMaterialTag(String materialName) {
Pattern pattern = Pattern.compile("^\\+([a-zA-Z_]+)");
Matcher matcher = pattern.matcher(materialName);
if (matcher.find()) {
// The material is a material tag
Tag<Material> tag = Bukkit.getTag(Tag.REGISTRY_BLOCKS, NamespacedKey.minecraft(
matcher.group(1).toLowerCase()), Material.class);
if (tag != null) {
this.blockWhitelist.addAll(tag.getValues());
} else {
Dropper.log(Level.WARNING, "Unable to parse: " + materialName);
}
return true;
}
return false;
}
}

View File

@ -1,12 +1,12 @@
package net.knarcraft.dropper.listener;
import net.knarcraft.dropper.Dropper;
import net.knarcraft.dropper.arena.ArenaGameMode;
import net.knarcraft.dropper.arena.DropperArenaPlayerRegistry;
import net.knarcraft.dropper.arena.DropperArenaSession;
import net.knarcraft.dropper.property.ArenaGameMode;
import net.knarcraft.dropper.config.DropperConfiguration;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Tag;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@ -24,6 +24,17 @@ import java.util.Set;
*/
public class MoveListener implements Listener {
private final DropperConfiguration configuration;
/**
* Instantiates a new move listener
*
* @param configuration <p>The configuration to use</p>
*/
public MoveListener(DropperConfiguration configuration) {
this.configuration = configuration;
}
@EventHandler
public void onPlayerMove(PlayerMoveEvent event) {
// Ignore if no actual movement is happening
@ -65,12 +76,8 @@ public class MoveListener implements Listener {
* @return <p>True if a special block has been hit</p>
*/
private boolean checkForSpecialBlock(DropperArenaSession arenaSession, Location toLocation) {
/* This decides how far inside a non-solid block the player must go before detection triggers. The closer to -1
it is, the more accurate it will seem to the player, but the likelihood of not detecting the hit decreases */
double liquidDepth = -0.8;
/* This decides the distance the player must be from the block below before a hit triggers. If too low, the
likelihood of detecting the hit decreases, but the immersion increases. */
double solidDepth = 0.2;
double liquidDepth = configuration.getLiquidHitBoxDepth();
double solidDepth = configuration.getSolidHitBoxDistance();
// Check if the player enters water
Material winBlockType = arenaSession.getArena().getWinBlockType();
@ -84,10 +91,10 @@ public class MoveListener implements Listener {
}
// Check if the player is about to hit a non-air and non-liquid block
Set<Material> whitelisted = configuration.getBlockWhitelist();
for (Block block : getBlocksBeneathLocation(toLocation, solidDepth)) {
Material blockType = block.getType();
if (!blockType.isAir() && blockType != Material.STRUCTURE_VOID && blockType != Material.WATER &&
blockType != Material.LAVA && !Tag.WALL_SIGNS.isTagged(blockType)) {
if (!blockType.isAir() && !whitelisted.contains(blockType)) {
arenaSession.triggerLoss();
return true;
}
@ -118,11 +125,14 @@ public class MoveListener implements Listener {
* @param session <p>The session to update the velocity for</p>
*/
private void updatePlayerVelocity(@NotNull DropperArenaSession session) {
Player player = session.getPlayer();
Vector playerVelocity = player.getVelocity();
double arenaVelocity = session.getArena().getPlayerVerticalVelocity();
Vector newVelocity = new Vector(playerVelocity.getX(), -arenaVelocity, playerVelocity.getZ());
player.setVelocity(newVelocity);
// Override the vertical velocity, if enabled
if (configuration.overrideVerticalVelocity()) {
Player player = session.getPlayer();
Vector playerVelocity = player.getVelocity();
double arenaVelocity = session.getArena().getPlayerVerticalVelocity();
Vector newVelocity = new Vector(playerVelocity.getX(), -arenaVelocity, playerVelocity.getZ());
player.setVelocity(newVelocity);
}
// Toggle the direction of the player's flying, as necessary
toggleFlyInversion(session);
@ -139,7 +149,7 @@ public class MoveListener implements Listener {
}
Player player = session.getPlayer();
float horizontalVelocity = session.getArena().getPlayerHorizontalVelocity();
float secondsBetweenToggle = 7;
float secondsBetweenToggle = configuration.getRandomlyInvertedTimer();
int seconds = Calendar.getInstance().get(Calendar.SECOND);
/*

View File

@ -2,15 +2,15 @@ package net.knarcraft.dropper.placeholder;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import net.knarcraft.dropper.Dropper;
import net.knarcraft.dropper.arena.ArenaGameMode;
import net.knarcraft.dropper.arena.DropperArena;
import net.knarcraft.dropper.arena.DropperArenaGroup;
import net.knarcraft.dropper.arena.DropperArenaHandler;
import net.knarcraft.dropper.arena.DropperArenaRecordsRegistry;
import net.knarcraft.dropper.arena.record.ArenaRecord;
import net.knarcraft.dropper.placeholder.parsing.InfoType;
import net.knarcraft.dropper.placeholder.parsing.RecordType;
import net.knarcraft.dropper.placeholder.parsing.SelectionType;
import net.knarcraft.dropper.property.ArenaGameMode;
import net.knarcraft.dropper.property.RecordType;
import net.knarcraft.dropper.util.DropperGroupRecordHelper;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
@ -97,6 +97,14 @@ public class DropperRecordExpansion extends PlaceholderExpansion {
return Objects.requireNonNullElse(info, parameters);
}
/**
* Clears all record caches
*/
public void clearCaches() {
this.groupRecordDeathsCache.clear();
this.groupRecordTimeCache.clear();
}
/**
* Gets a piece of record information from a dropper arena group
*

View File

@ -1,8 +1,8 @@
package net.knarcraft.dropper.placeholder;
import net.knarcraft.dropper.arena.ArenaGameMode;
import net.knarcraft.dropper.arena.record.ArenaRecord;
import net.knarcraft.dropper.placeholder.parsing.RecordType;
import net.knarcraft.dropper.property.ArenaGameMode;
import net.knarcraft.dropper.property.RecordType;
import org.jetbrains.annotations.NotNull;
import java.util.Set;

View File

@ -1,4 +1,4 @@
package net.knarcraft.dropper.placeholder.parsing;
package net.knarcraft.dropper.property;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

View File

@ -1,14 +1,14 @@
package net.knarcraft.dropper.util;
import net.knarcraft.dropper.Dropper;
import net.knarcraft.dropper.arena.ArenaGameMode;
import net.knarcraft.dropper.arena.ArenaStorageKey;
import net.knarcraft.dropper.arena.DropperArena;
import net.knarcraft.dropper.arena.DropperArenaData;
import net.knarcraft.dropper.arena.DropperArenaGroup;
import net.knarcraft.dropper.arena.DropperArenaRecordsRegistry;
import net.knarcraft.dropper.container.SerializableMaterial;
import net.knarcraft.dropper.container.SerializableUUID;
import net.knarcraft.dropper.property.ArenaGameMode;
import net.knarcraft.dropper.property.ArenaStorageKey;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection;

View File

@ -1,12 +1,12 @@
package net.knarcraft.dropper.util;
import net.knarcraft.dropper.Dropper;
import net.knarcraft.dropper.arena.ArenaGameMode;
import net.knarcraft.dropper.arena.DropperArena;
import net.knarcraft.dropper.arena.DropperArenaGroup;
import net.knarcraft.dropper.arena.DropperArenaHandler;
import net.knarcraft.dropper.arena.record.ArenaRecord;
import net.knarcraft.dropper.arena.record.SummableArenaRecord;
import net.knarcraft.dropper.property.ArenaGameMode;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;

View File

@ -1,8 +1,8 @@
package net.knarcraft.dropper.util;
import net.knarcraft.dropper.Dropper;
import net.knarcraft.dropper.arena.ArenaEditableProperty;
import net.knarcraft.dropper.arena.DropperArena;
import net.knarcraft.dropper.property.ArenaEditableProperty;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;

View File

@ -0,0 +1,50 @@
# Configuration values for droppers
dropper:
# Whether the vertical velocity should be overridden, and thus changeable. If not enabled, all horizontalVelocity
# settings, both the global one and per-arena, will be ignored.
overrideVerticalVelocity: true
# The vertical velocity used as default for all arenas. Must be greater than 0. 3.92 is the max speed of a falling
# player.
verticalVelocity: 1.0
# The horizontal velocity used as default for all arenas (technically fly-speed). Must be between 0 (exclusive) and 1
# (inclusive).
horizontalVelocity: 1.0
# The number of seconds before the randomly inverted game-mode switches between normal and inverted movement
randomlyInvertedTimer: 7
# Whether grouped dropper arenas must be played in the correct sequence
mustDoGroupedInSequence: true
# 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: false
# Whether a player must do the normal/default game-mode before playing any other game-modes
mustDoNormalModeFirst: true
# Whether players should be made invisible while playing in a dropper arena
makePlayersInvisible: false
# Whether players should have their entity hit collision disabled while in an arena. This prevents players from
# pushing each-other if in the same arena.
disableHitCollision: true
# This decides how far inside a non-solid block the player must go before detection triggers. The closer to -1
# it is, the more accurate it will seem to the player, but the likelihood of not detecting the hit increases.
liquidHitBoxDepth: -0.8
# This decides the distance the player must be from a block below them before a hit triggers. If too low, the
# likelihood of detecting the hit decreases, but it won't look like the player hit the block without being near.
solidHitBoxDistance: 0.2
# A whitelist for which blocks won't trigger a loss when hit/passed through. The win block check happens before the
# loss check, so even blocks on the whitelist can be used as the win-block. "+" denotes a material tag.
blockWhitelist:
- WATER
- LAVA
- +WALL_SIGNS
- +STANDING_SIGNS
- STRUCTURE_VOID