diff --git a/src/main/java/net/thenextlvl/utilities/UtilitiesPlugin.java b/src/main/java/net/thenextlvl/utilities/UtilitiesPlugin.java index 172938b..8431e96 100644 --- a/src/main/java/net/thenextlvl/utilities/UtilitiesPlugin.java +++ b/src/main/java/net/thenextlvl/utilities/UtilitiesPlugin.java @@ -111,6 +111,7 @@ public void onDisable() { private void registerListeners() { getServer().getPluginManager().registerEvents(new AdvancedFlyListener(this), this); + getServer().getPluginManager().registerEvents(new AirPlacingListener(this), this); getServer().getPluginManager().registerEvents(new BlockBreakListener(this), this); getServer().getPluginManager().registerEvents(new BlockPhysicsListener(this), this); getServer().getPluginManager().registerEvents(new ConnectionListener(this), this); diff --git a/src/main/java/net/thenextlvl/utilities/listener/AirPlacingListener.java b/src/main/java/net/thenextlvl/utilities/listener/AirPlacingListener.java new file mode 100644 index 0000000..dd19cd0 --- /dev/null +++ b/src/main/java/net/thenextlvl/utilities/listener/AirPlacingListener.java @@ -0,0 +1,75 @@ +package net.thenextlvl.utilities.listener; + +import lombok.RequiredArgsConstructor; +import net.thenextlvl.utilities.UtilitiesPlugin; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.attribute.Attribute; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Waterlogged; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.event.player.PlayerQuitEvent; + +import java.util.Map; +import java.util.WeakHashMap; + +@RequiredArgsConstructor +public class AirPlacingListener implements Listener { + static final Map targetBlocks = new WeakHashMap<>(); + private final BlockData blockData = Material.BARRIER.createBlockData(); + private final BlockData waterlogged = Material.BARRIER.createBlockData(data -> + ((Waterlogged) data).setWaterlogged(true)); + private final UtilitiesPlugin plugin; + + @EventHandler(priority = EventPriority.MONITOR) + public void onPlayerQuit(PlayerQuitEvent event) { + targetBlocks.remove(event.getPlayer()); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onPlayerMove(PlayerMoveEvent event) { + var player = event.getPlayer(); + + if (!plugin.settingsController().isAirPlacing(player)) { + hideBlock(player); + return; + } + + if (player.getInventory().getItemInMainHand().isEmpty() + && player.getInventory().getItemInOffHand().isEmpty()) { + hideBlock(player); + return; + } + + var range = player.getAttribute(Attribute.PLAYER_BLOCK_INTERACTION_RANGE); + if (range == null || player.getTargetBlockExact((int) range.getValue()) != null) { + hideBlock(player); + return; + } + + var eyeLocation = player.getEyeLocation(); + var targetBlock = eyeLocation.add(eyeLocation.getDirection().multiply(range.getValue())); + + var lastTarget = targetBlocks.put(player, targetBlock); + + var isWater = targetBlock.getBlock().getType().equals(Material.WATER); + if ((!isWater && !targetBlock.getBlock().isEmpty()) || targetBlock.equals(lastTarget)) return; + + if (lastTarget != null) player.sendBlockChange(lastTarget, lastTarget.getBlock().getBlockData()); + + if (event.getFrom().distanceSquared(event.getTo()) > 0.5) return; + + player.sendBlockChange(targetBlock, isWater ? waterlogged : blockData); + } + + private void hideBlock(Player player) { + targetBlocks.computeIfPresent(player, (entry, location) -> { + entry.sendBlockChange(location, location.getBlock().getBlockData()); + return null; + }); + } +} diff --git a/src/main/java/net/thenextlvl/utilities/listener/ConnectionListener.java b/src/main/java/net/thenextlvl/utilities/listener/ConnectionListener.java index 7a2c8e9..3c9a316 100644 --- a/src/main/java/net/thenextlvl/utilities/listener/ConnectionListener.java +++ b/src/main/java/net/thenextlvl/utilities/listener/ConnectionListener.java @@ -48,6 +48,7 @@ public void onPlayerQuit(PlayerQuitEvent event) { AdvancedFlyListener.lastVelocity.remove(event.getPlayer()); AdvancedFlyListener.slower1.remove(event.getPlayer()); AdvancedFlyListener.slower2.remove(event.getPlayer()); + AirPlacingListener.targetBlocks.remove(event.getPlayer()); plugin.settingsController().purge(event.getPlayer()); } }