1.15.2 Fly Command Help! Fall Damage

Discussion in 'Spigot Plugin Development' started by xFadedxShadow, Feb 14, 2020.

Thread Status:
Not open for further replies.
  1. Code (Java):
    package xFadedxShadow.Essentials.Commands;

    import java.util.HashSet;
    import java.util.Set;
    import java.util.UUID;

    import org.bukkit.Bukkit;
    import org.bukkit.GameMode;
    import org.bukkit.Location;
    import org.bukkit.command.Command;
    import org.bukkit.command.CommandExecutor;
    import org.bukkit.command.CommandSender;
    import org.bukkit.entity.Player;
    import org.bukkit.event.EventHandler;
    import org.bukkit.event.Listener;
    import org.bukkit.event.entity.EntityDamageEvent;

    import xFadedxShadow.Essentials.Main;
    import xFadedxShadow.Essentials.Utils.Utils;

    public class FlyCommand implements CommandExecutor, Listener {

        private Main plugin;
        private Set<UUID> hadFlight;

        public FlyCommand(Main plugin) {
            this.plugin = plugin;
            this.hadFlight = new HashSet<>();
            plugin.getCommand("fly").setExecutor(this);
            Bukkit.getPluginManager().registerEvents(this, plugin);
        }

        @Override
        public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
            if (!(sender instanceof Player)) {
                sender.sendMessage(Utils.chat(plugin.getConfig().getString("Error.permission_message")));
                return false;
            }

            Player p = (Player) sender;
            Location pLocation = p.getLocation();
            double fallDistanceToGround = 0.0D;

            if (p.hasPermission("faded-essentials.fly")) {
                if (p.getGameMode() == GameMode.SURVIVAL) {
                    if (!p.getAllowFlight()) {
                        this.hadFlight.add(p.getUniqueId());
                        p.setAllowFlight(true);
                        p.sendMessage(Utils.chat(plugin.getConfig().getString("Command.Fly.enabled_message")));
                        return true;
                    } else {
                        while (!pLocation.getBlock().getType().isSolid()) {
                            pLocation.subtract(0.0D, 1.0D, 0.0D);
                            fallDistanceToGround++;
                        }
                        if (fallDistanceToGround > 4.0D) {
                            p.setFlying(false);
                            p.setAllowFlight(false);
                            p.sendMessage(Utils.chat(plugin.getConfig().getString("Command.Fly.disabled_message")));
                            return true;
                        } else {
                            this.hadFlight.remove(p.getUniqueId());
                            p.setFlying(false);
                            p.setAllowFlight(false);
                            p.sendMessage(Utils.chat(plugin.getConfig().getString("Command.Fly.disabled_message")));
                        }
                    }
                } else {
                    p.sendMessage(Utils.chat(plugin.getConfig().getString("Command.Fly.gamemode_error_message")));
                }
            } else {
                p.sendMessage(Utils.chat(plugin.getConfig().getString("Error.permission_message")));
            }

            return false;
        }

        @EventHandler
        public void onFallDamage(EntityDamageEvent e) {
            if (e.getEntity() instanceof Player) {
                Player p = (Player) e.getEntity();
                if (this.hadFlight.contains(p.getUniqueId())) {
                    e.setCancelled(true);
                    this.hadFlight.remove(p.getUniqueId());
                }
            }
        }

    }
     
     
  2. I have it set to when there is a Solid block under the player at a certain height they won't take damage but now i'm having trouble with falling in water and still not taking damage afterward!
     
  3. drives_a_ford

    Moderator

    You can just add a special case for when the first block below the player is water. Just get the block above the location you ended up with and check if it's water. If it is, just remove the UUID from hadFlight.
    When checking for water, the first thing you check is the type (Material.WATER), but then you will also need to check the BlockData and if it's an instance of Waterlogger, check if it's Waterlogged#isWaterlogged.

    And in your EntityDamageEvent you should check EntityDamageEvent#getCause.

    PS: It's also possible that while the player's center (i.e the location you're iterating) is on top of a water block, but the player's movement is actually stopped by something else in the way.
    This also means it's possible that the player's center is higher than 4 blocks on top of a solid block, but their fall is stopped by something else before the height at which they'd take damage. Your code would stop them from taking damage the next time around. I suggest adding a fail safe scheduled task that removes the player's UUID from hadFlight at the appropriate time (you can calculate their time of flight from gravity).
     
Thread Status:
Not open for further replies.