From af7b9852f47f42cfbcd05fb2fb64310674650ca2 Mon Sep 17 00:00:00 2001 From: totemo Date: Sat, 30 Sep 2017 05:21:25 +0930 Subject: [PATCH] Version 1.9.0 * Assist take-off by setting glide when a player fires a rocket while in the air and wearing unbroken elytra. This mitigates overly the harsh NCP SurvivalFly check. * Refactor to combine similar elytra wearing checks. --- pom.xml | 2 +- src/io/totemo/wingcommander/PlayerState.java | 64 ++++++++++-------- .../totemo/wingcommander/WingCommander.java | 66 ++++++++++++------- 3 files changed, 78 insertions(+), 54 deletions(-) diff --git a/pom.xml b/pom.xml index f25991b..ef31742 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ io.totemo WingCommander ${project.name} - 1.8.0 + 1.9.0 jar Enables powered flight with elytra. https://github.com/totemo/${project.name} diff --git a/src/io/totemo/wingcommander/PlayerState.java b/src/io/totemo/wingcommander/PlayerState.java index 9daa2b9..af3a396 100644 --- a/src/io/totemo/wingcommander/PlayerState.java +++ b/src/io/totemo/wingcommander/PlayerState.java @@ -51,8 +51,7 @@ public PlayerState(Player player, YamlConfiguration config) { */ public void onTick() { // During take-off, force glide. - long now = System.currentTimeMillis(); - if (now - _takeOffTime < WingCommander.CONFIG.TAKEOFF_GLIDE_MILLIS) { + if (isTakingOff()) { _player.setGliding(true); } @@ -78,8 +77,8 @@ public void onCrouch() { long now = System.currentTimeMillis(); if (now - _lastCrouchTime < WingCommander.CONFIG.TAKEOFF_TAP_MILLIS) { _lastCrouchTime = 0; - _takeOffTime = now; - if (!areElytraBroken()) { + setTakingOff(); + if (WingCommander.isWearingElytra(_player, true)) { _player.setVelocity(new Vector(0, WingCommander.CONFIG.ACCELERATION_TAKEOFF_VERTICAL, 0)); } accelerate(WingCommander.CONFIG.ACCELERATION_TAKEOFF_LOOK); @@ -89,6 +88,28 @@ public void onCrouch() { } } // onCrouch + // ------------------------------------------------------------------------ + /** + * Signify that the player has initiated a take-off. + * + * The start time of the take-off is recorded, and glide is forced for the + * configured time period thereafter in {@link PlayerState#onTick()}. + */ + public void setTakingOff() { + _takeOffTime = System.currentTimeMillis(); + } + + // ------------------------------------------------------------------------ + /** + * Return true if the player is still in the time-limited take-off state. + * + * @return true if the player is still in the time-limited take-off state. + */ + public boolean isTakingOff() { + long now = System.currentTimeMillis(); + return (now - _takeOffTime < WingCommander.CONFIG.TAKEOFF_GLIDE_MILLIS); + } + // ------------------------------------------------------------------------ /** * Set or toggle visibility of the altimeter. @@ -190,7 +211,7 @@ public void save(YamlConfiguration config) { * * @param config the configuration from which player preferences are loaded. */ - protected void load(YamlConfiguration config) { + public void load(YamlConfiguration config) { ConfigurationSection section = config.getConfigurationSection(_player.getUniqueId().toString()); if (section == null) { section = config.createSection(_player.getUniqueId().toString()); @@ -283,21 +304,6 @@ protected void checkVacuumSuffocation() { } } - // ------------------------------------------------------------------------ - /** - * Return true if the player is not wearing eltra, or if they are too - * damaged to glide. - * - * @return true if the player is not wearing eltra, or if they are too - * damaged to glide. - */ - protected boolean areElytraBroken() { - ItemStack chest = _player.getEquipment().getChestplate(); - return chest == null || - chest.getType() != Material.ELYTRA || - Material.ELYTRA.getMaxDurability() - chest.getDurability() < 1; - } - // ------------------------------------------------------------------------ /** * Boost the player's velocity in the player's look direction, but limit the @@ -328,14 +334,9 @@ protected void accelerate(double acceleration) { float speedFraction = (float) (Math.max(0.0, velocity.dot(look)) / WingCommander.CONFIG.MAX_VELOCITY); float pitch = 0.5f + 1.5f * speedFraction; - if (areElytraBroken()) { - loc.getWorld().playSound(loc, WingCommander.CONFIG.BROKEN_SOUND, - WingCommander.CONFIG.BROKEN_VOLUME, pitch); - if (WingCommander.CONFIG.BROKEN_GLIDE) { - _player.setGliding(true); - _player.setFallDistance(Math.max(0, _player.getFallDistance() - WingCommander.CONFIG.BROKEN_GLIDE_FALL_REDUCTION)); - } - } else { + // Method precondition is "wearing elytra irrespective of durability". + // Check for unbroken elytra. + if (WingCommander.isWearingElytra(_player, true)) { _player.setGliding(true); Vector boost = look; @@ -363,6 +364,13 @@ protected void accelerate(double acceleration) { loc.getWorld().playSound(loc, WingCommander.CONFIG.EXHAUST_SOUND, WingCommander.CONFIG.EXHAUST_VOLUME, pitch); } + } else { + loc.getWorld().playSound(loc, WingCommander.CONFIG.BROKEN_SOUND, + WingCommander.CONFIG.BROKEN_VOLUME, pitch); + if (WingCommander.CONFIG.BROKEN_GLIDE) { + _player.setGliding(true); + _player.setFallDistance(Math.max(0, _player.getFallDistance() - WingCommander.CONFIG.BROKEN_GLIDE_FALL_REDUCTION)); + } } } // accelerate diff --git a/src/io/totemo/wingcommander/WingCommander.java b/src/io/totemo/wingcommander/WingCommander.java index 2a3a94a..33d3796 100644 --- a/src/io/totemo/wingcommander/WingCommander.java +++ b/src/io/totemo/wingcommander/WingCommander.java @@ -7,6 +7,7 @@ import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Material; +import org.bukkit.block.Block; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.configuration.file.YamlConfiguration; @@ -140,36 +141,49 @@ public void onPlayerToggleSneak(PlayerToggleSneakEvent event) { // ------------------------------------------------------------------------ /** - * Handle player interactions - launch TNT if permitted and gliding. + * Handle player interactions: + * */ @EventHandler public void onPlayerInteract(PlayerInteractEvent event) { Player player = event.getPlayer(); - // Check permissions - if (!player.hasPermission("wingcommander.tnt")) { - return; - } - - // Only throw TNT if gliding - if (!player.isGliding()) { - return; - } - // Only handle left and right click air events Action action = event.getAction(); if (action != Action.LEFT_CLICK_AIR && action != Action.RIGHT_CLICK_AIR) { return; } - // See if there is TNT in our hand PlayerInventory inventory = player.getInventory(); ItemStack stack = inventory.getItemInMainHand(); - if (stack.getType() != Material.TNT) { + + // Assisted takeoff if wearing unbroken elytra. + if (action == Action.RIGHT_CLICK_AIR && + stack.getType() == Material.FIREWORK && + !player.isOnGround() && + isWearingElytra(player, true)) { + + // Player must be in air, not water (to be like vanilla). + Block feetBlock = player.getLocation().getBlock(); + if (feetBlock != null && feetBlock.getType() == Material.AIR) { + PlayerState state = getState(player); + state.setTakingOff(); + player.setGliding(true); + } + } + + // Only throw TNT if permitted, gliding and holding TNT. + if (!player.hasPermission("wingcommander.tnt") || + !player.isGliding() || + stack.getType() != Material.TNT) { return; } - // Use up a TNT + // Use up a TNT. int amount = stack.getAmount() - 1; if (amount > 1) { stack.setAmount(amount); @@ -177,35 +191,37 @@ public void onPlayerInteract(PlayerInteractEvent event) { inventory.setItemInMainHand(null); } - // Spawn TNT + // Spawn TNT. Entity tnt = player.getWorld().spawnEntity(player.getLocation(), EntityType.PRIMED_TNT); if (action == Action.LEFT_CLICK_AIR) { - // Throw the TNT forward + // Throw the TNT forward. Vector TNTVelocity = player.getLocation().getDirection(); TNTVelocity.normalize(); TNTVelocity.multiply(WingCommander.CONFIG.TNT_THROW_SPEED); TNTVelocity.add(player.getVelocity()); tnt.setVelocity(TNTVelocity); } else if (action == Action.RIGHT_CLICK_AIR) { - // Drop the TNT with current velocity + // Drop the TNT with current velocity. tnt.setVelocity(player.getVelocity()); } - } // OnPlayerInteract + } // onPlayerInteract // ------------------------------------------------------------------------ /** * Return true if the player is wearing elytra. * - * Note that this method doesn't care whether the elytra are broken - * (durability <=1). - * * @param player the player. - * @return true if the player is wearing elytra. + * @param requireDurability if true, the elytra must have durability > 0; if + * false, even broken elytra are considered valid. + * @return true if the player is wearing elytra, with durability if + * required. */ - protected static boolean isWearingElytra(Player player) { + protected static boolean isWearingElytra(Player player, boolean requireDurability) { ItemStack chest = player.getEquipment().getChestplate(); - return chest != null && chest.getType() == Material.ELYTRA; + return chest != null && + chest.getType() == Material.ELYTRA && + (!requireDurability || Material.ELYTRA.getMaxDurability() - chest.getDurability() > 0); } // ------------------------------------------------------------------------ @@ -218,7 +234,7 @@ protected static boolean isWearingElytra(Player player) { * powered flight. */ protected static boolean isFlightCapable(Player player) { - return isWearingElytra(player) && player.hasPermission("wingcommander.fly"); + return isWearingElytra(player, false) && player.hasPermission("wingcommander.fly"); } // ------------------------------------------------------------------------