diff --git a/bukkit/src/main/java/us/myles/ViaVersion/bukkit/listeners/multiversion/PlayerSneakListener.java b/bukkit/src/main/java/us/myles/ViaVersion/bukkit/listeners/multiversion/PlayerSneakListener.java index 993cd8f14..a44dc1e74 100644 --- a/bukkit/src/main/java/us/myles/ViaVersion/bukkit/listeners/multiversion/PlayerSneakListener.java +++ b/bukkit/src/main/java/us/myles/ViaVersion/bukkit/listeners/multiversion/PlayerSneakListener.java @@ -1,7 +1,9 @@ package us.myles.ViaVersion.bukkit.listeners.multiversion; +import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.player.PlayerToggleSneakEvent; import us.myles.ViaVersion.ViaVersionPlugin; @@ -9,13 +11,11 @@ import us.myles.ViaVersion.api.data.UserConnection; import us.myles.ViaVersion.api.protocol.ProtocolRegistry; import us.myles.ViaVersion.api.protocol.ProtocolVersion; import us.myles.ViaVersion.bukkit.listeners.ViaBukkitListener; -import us.myles.ViaVersion.bukkit.platform.BukkitViaLoader; import us.myles.ViaVersion.protocols.base.ProtocolInfo; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.Map; +import java.util.*; public class PlayerSneakListener extends ViaBukkitListener { private static final float STANDING_HEIGHT = 1.8F; @@ -24,13 +24,14 @@ public class PlayerSneakListener extends ViaBukkitListener { private static final float DEFAULT_WIDTH = 0.6F; private Map sneaking; // true = 1.14+, else false + private Set sneakingUuids; private Method getHandle; private Method setSize; private boolean is1_9Fix; private boolean is1_14Fix; private boolean useCache; - public PlayerSneakListener(ViaVersionPlugin plugin, BukkitViaLoader viaLoader, boolean is1_9Fix, boolean is1_14Fix) { + public PlayerSneakListener(ViaVersionPlugin plugin, boolean is1_9Fix, boolean is1_14Fix) { super(plugin, null); this.is1_9Fix = is1_9Fix; this.is1_14Fix = is1_14Fix; @@ -41,16 +42,11 @@ public class PlayerSneakListener extends ViaBukkitListener { } catch (ClassNotFoundException | NoSuchMethodException e) { e.printStackTrace(); } + // From 1.9 upwards the server hitbox is set in every entity tick, so we have to reset it everytime if (ProtocolRegistry.SERVER_PROTOCOL >= ProtocolVersion.v1_9.getId()) { - sneaking = new HashMap<>(); + sneaking = new WeakHashMap<>(); useCache = true; - viaLoader.storeListener(new ViaBukkitListener(plugin, null) { - @EventHandler - public void playerQuit(PlayerQuitEvent event) { - sneaking.remove(event.getPlayer()); - } - }).register(); plugin.getServer().getScheduler().runTaskTimer(plugin, new Runnable() { @Override public void run() { @@ -60,6 +56,11 @@ public class PlayerSneakListener extends ViaBukkitListener { } }, 1, 1); } + + // Suffocation removal only required for 1.14+ clients. + if (is1_14Fix) { + sneakingUuids = new HashSet<>(); + } } @EventHandler(ignoreCancelled = true) @@ -73,6 +74,11 @@ public class PlayerSneakListener extends ViaBukkitListener { int protocolVersion = info.getProtocolVersion(); if (is1_14Fix && protocolVersion >= ProtocolVersion.v1_14.getId()) { setHeight(player, event.isSneaking() ? HEIGHT_1_14 : STANDING_HEIGHT); + if (event.isSneaking()) + sneakingUuids.add(player.getUniqueId()); + else + sneakingUuids.remove(player.getUniqueId()); + if (!useCache) return; if (event.isSneaking()) sneaking.put(player, true); @@ -88,6 +94,32 @@ public class PlayerSneakListener extends ViaBukkitListener { } } + @EventHandler(ignoreCancelled = true) + public void playerDamage(EntityDamageEvent event) { + if (!is1_14Fix) return; + if (event.getCause() != EntityDamageEvent.DamageCause.SUFFOCATION) return; + if (event.getEntityType() != EntityType.PLAYER) return; + + Player player = (Player) event.getEntity(); + if (!sneakingUuids.contains(player.getUniqueId())) return; + + // Don't cancel when they should actually be suffocating; Essentially cancel when the head is in the top block only ever so slightly + // ~0.041 should suffice, but gotta stay be safe + double y = player.getEyeLocation().getY() + 0.045; + y -= (int) y; + if (y < 0.09) { + event.setCancelled(true); + } + } + + @EventHandler + public void playerQuit(PlayerQuitEvent event) { + if (sneaking != null) + sneaking.remove(event.getPlayer()); + if (sneakingUuids != null) + sneakingUuids.remove(event.getPlayer().getUniqueId()); + } + private void setHeight(Player player, float height) { try { setSize.invoke(getHandle.invoke(player), DEFAULT_WIDTH, height); @@ -95,4 +127,4 @@ public class PlayerSneakListener extends ViaBukkitListener { e.printStackTrace(); } } -} +} \ No newline at end of file diff --git a/bukkit/src/main/java/us/myles/ViaVersion/bukkit/platform/BukkitViaLoader.java b/bukkit/src/main/java/us/myles/ViaVersion/bukkit/platform/BukkitViaLoader.java index ca5fc776f..b2e3e82e8 100644 --- a/bukkit/src/main/java/us/myles/ViaVersion/bukkit/platform/BukkitViaLoader.java +++ b/bukkit/src/main/java/us/myles/ViaVersion/bukkit/platform/BukkitViaLoader.java @@ -82,7 +82,7 @@ public class BukkitViaLoader implements ViaPlatformLoader { if (ProtocolRegistry.SERVER_PROTOCOL < ProtocolVersion.v1_14.getId()) { boolean use1_9Fix = plugin.getConf().is1_9HitboxFix() && ProtocolRegistry.SERVER_PROTOCOL < ProtocolVersion.v1_9.getId(); if (use1_9Fix || plugin.getConf().is1_14HitboxFix()) { - storeListener(new PlayerSneakListener(plugin, this, use1_9Fix, plugin.getConf().is1_14HitboxFix())).register(); + storeListener(new PlayerSneakListener(plugin, use1_9Fix, plugin.getConf().is1_14HitboxFix())).register(); } } diff --git a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/packets/InventoryPackets.java b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/packets/InventoryPackets.java index 2d8ad2522..52c41be67 100644 --- a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/packets/InventoryPackets.java +++ b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/packets/InventoryPackets.java @@ -178,7 +178,12 @@ public class InventoryPackets { Via.getPlatform().getLogger().warning("Ignoring plugin channel in outgoing REGISTER: " + channels[i]); } } - wrapper.write(Type.REMAINING_BYTES, Joiner.on('\0').join(rewrittenChannels).getBytes(StandardCharsets.UTF_8)); + if (!rewrittenChannels.isEmpty()) { + wrapper.write(Type.REMAINING_BYTES, Joiner.on('\0').join(rewrittenChannels).getBytes(StandardCharsets.UTF_8)); + } else { + wrapper.cancel(); + return; + } } } wrapper.set(Type.STRING, 0, channel);