From cb6906e2ec5bf7eaa73b5e6a4a0ea04a7e3d6240 Mon Sep 17 00:00:00 2001 From: Hut512 Date: Fri, 11 Sep 2026 18:23:43 +0200 Subject: [PATCH] Make Smart Place thread safe --- .../smartplace/SmartPlaceListener.java | 140 +++++++++--------- 1 file changed, 66 insertions(+), 74 deletions(-) diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/smartplace/SmartPlaceListener.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/smartplace/SmartPlaceListener.java index 6f70fc55..fb63555c 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/smartplace/SmartPlaceListener.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/smartplace/SmartPlaceListener.java @@ -19,12 +19,10 @@ package de.steamwar.bausystem.features.smartplace; -import com.comphenix.tinyprotocol.TinyProtocol; import de.steamwar.bausystem.BauSystem; import de.steamwar.bausystem.Permission; import de.steamwar.bausystem.configplayer.Config; import de.steamwar.linkage.Linked; -import net.minecraft.network.protocol.game.ServerboundUseItemOnPacket; import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; @@ -34,104 +32,98 @@ import org.bukkit.block.data.*; import org.bukkit.block.data.type.*; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.Action; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.inventory.ItemStack; -import org.bukkit.util.RayTraceResult; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.UUID; import java.util.stream.Collectors; @Linked public class SmartPlaceListener implements Listener { - private static final Set CONTAINERS = new HashSet<>(); - private static final Set IGNORED = new HashSet<>(); + private static final Set IGNORED = Set.of(Material.TNT, Material.REDSTONE_ORE, Material.BEEHIVE, Material.SEA_PICKLE); - static { - World world = Bukkit.getWorlds().get(0); - Block block = world.getBlockAt(0, 0, 0); - block.setType(Material.AIR); - BlockState state = block.getState(); - for (Material material : Material.values()) { - if (material.isLegacy()) continue; - if (!material.isInteractable() && !material.isBlock()) continue; - BlockData blockData = material.createBlockData(); - block.setBlockData(blockData); - if (block.getState() instanceof TileState) { - CONTAINERS.add(material); - } else if (blockData instanceof Stairs) { - CONTAINERS.add(material); - } - state.update(true, false); - } - CONTAINERS.add(Material.GRINDSTONE); - CONTAINERS.remove(Material.COMPARATOR); - state.update(true, false); + private static final Set FAKED_SNEAK = new HashSet<>(); - IGNORED.add(Material.TNT); - IGNORED.add(Material.REDSTONE_ORE); - IGNORED.add(Material.BEEHIVE); - IGNORED.add(Material.SEA_PICKLE); - IGNORED.remove(Material.STONE); - IGNORED.remove(Material.BARRIER); + private static boolean isContainer(Block block) { + if (block.getType() == Material.COMPARATOR) return false; + if (block.getType() == Material.GRINDSTONE) return true; + return block.getState() instanceof TileState || block.getBlockData() instanceof Stairs; } - private static final Set SMART_PLACING = new HashSet<>(); - private static final Set WAS_EXECUTED = new HashSet<>(); + private static boolean isReallySneaking(Player player) { + return player.isSneaking() && !FAKED_SNEAK.contains(player.getUniqueId()); + } - public SmartPlaceListener() { - TinyProtocol.instance.addFilter(ServerboundUseItemOnPacket.class, (player, packet) -> { - if (!Permission.BUILD.hasPermission(player)) return packet; - if (!Config.getInstance().get(player).getPlainValueOrDefault("smartPlace", false)) return packet; - RayTraceResult rayTraceResult = player.rayTraceBlocks(6); - Block block = rayTraceResult != null ? rayTraceResult.getHitBlock() : null; - BlockFace blockFace = rayTraceResult != null ? rayTraceResult.getHitBlockFace() : null; - boolean shouldSneak = false; - if (block != null) { - ItemStack itemStack = player.getInventory().getItemInMainHand(); - if (block.getType().isInteractable() || block.getType() == Material.NOTE_BLOCK) { - shouldSneak = true; - } - if (CONTAINERS.contains(block.getType())) { - if (itemStack.getType() == Material.TNT) { - if (block.getType() == Material.CHEST || block.getType() == Material.BARREL || block.getType().name().endsWith("SHULKER_BOX")) { - shouldSneak = false; - } - } - } else { - shouldSneak = false; - } - if (IGNORED.contains(block.getType())) { - shouldSneak = false; - } - if (blockFace == BlockFace.DOWN && (block.getType() == Material.REPEATER || block.getType() == Material.COMPARATOR) && itemStack.getType().isSolid()) { - shouldSneak = true; + private static boolean shouldSmartPlace(Block block, BlockFace blockFace, Material heldType) { + boolean smartPlace = false; + if (block.getType().isInteractable() || block.getType() == Material.NOTE_BLOCK) { + smartPlace = true; + } + if (isContainer(block)) { + if (heldType == Material.TNT) { + if (block.getType() == Material.CHEST || block.getType() == Material.BARREL || block.getType().name().endsWith("SHULKER_BOX")) { + smartPlace = false; } } - boolean sneaking = player.isSneaking(); - if (sneaking) SMART_PLACING.add(player); - player.setSneaking(shouldSneak || sneaking); - Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> { - SMART_PLACING.remove(player); - player.setSneaking(sneaking); - }, 0); - return packet; + } else { + smartPlace = false; + } + if (IGNORED.contains(block.getType())) { + smartPlace = false; + } + if (blockFace == BlockFace.DOWN && (block.getType() == Material.REPEATER || block.getType() == Material.COMPARATOR) && heldType.isSolid()) { + smartPlace = true; + } + return smartPlace; + } + + private static boolean smartPlaceEnabled(Player player) { + return Config.getInstance().get(player).getPlainValueOrDefault("smartPlace", false); + } + + @EventHandler(priority = EventPriority.LOW) + public void onSmartPlace(PlayerInteractEvent event) { + if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return; + Player player = event.getPlayer(); + if (player.getGameMode() == GameMode.SPECTATOR) return; + if (!Permission.BUILD.hasPermission(player)) return; + if (!smartPlaceEnabled(player)) return; + if (player.isSneaking()) return; + + ItemStack itemStack = event.getItem(); + if (itemStack == null || itemStack.getType().isAir()) return; + if (!shouldSmartPlace(event.getClickedBlock(), event.getBlockFace(), itemStack.getType())) return; + + player.setSneaking(true); + FAKED_SNEAK.add(player.getUniqueId()); + Bukkit.getScheduler().runTask(BauSystem.getInstance(), () -> { + if (FAKED_SNEAK.remove(player.getUniqueId())) { + player.setSneaking(false); + } }); } + @EventHandler + public void onQuit(PlayerQuitEvent event) { + FAKED_SNEAK.remove(event.getPlayer().getUniqueId()); + } + @EventHandler public void onPlayerInteract(PlayerInteractEvent event) { if (!Permission.BUILD.hasPermission(event.getPlayer())) return; - if (!Config.getInstance().get(event.getPlayer()).getPlainValueOrDefault("smartPlace", false)) return; - WAS_EXECUTED.add(event.getPlayer()); + if (!smartPlaceEnabled(event.getPlayer())) return; if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return; if (event.getPlayer().getGameMode() == GameMode.SPECTATOR) return; - if (!event.getPlayer().isSneaking()) return; + if (!isReallySneaking(event.getPlayer())) return; if (event.getClickedBlock().getType() != Material.REPEATER) return; if ((event.getItem() == null || event.getItem().getType() == Material.REPEATER)) { Repeater repeater = (Repeater) event.getClickedBlock().getBlockData(); @@ -146,9 +138,9 @@ public class SmartPlaceListener implements Listener { @EventHandler public void onBlockPlace(BlockPlaceEvent event) { if (!Permission.BUILD.hasPermission(event.getPlayer())) return; - if (!Config.getInstance().get(event.getPlayer()).getPlainValueOrDefault("smartPlace", false)) return; - if (!SMART_PLACING.contains(event.getPlayer())) { - if (CONTAINERS.contains(event.getBlockAgainst().getType())) { + if (!smartPlaceEnabled(event.getPlayer())) return; + if (!isReallySneaking(event.getPlayer())) { + if (isContainer(event.getBlockAgainst())) { SoundGroup soundGroup = event.getBlockPlaced().getBlockData().getSoundGroup(); event.getPlayer().playSound(event.getBlockPlaced().getLocation(), soundGroup.getPlaceSound(), soundGroup.getVolume() * 0.8F, soundGroup.getPitch() * 0.8F); }