diff --git a/BauSystem_Main/src/de/steamwar/bausystem/features/smartplace/SmartPlaceListener.java b/BauSystem_Main/src/de/steamwar/bausystem/features/smartplace/SmartPlaceListener.java
index 75f60d53..a3ca2a66 100644
--- a/BauSystem_Main/src/de/steamwar/bausystem/features/smartplace/SmartPlaceListener.java
+++ b/BauSystem_Main/src/de/steamwar/bausystem/features/smartplace/SmartPlaceListener.java
@@ -1,103 +1,202 @@
/*
- * This file is a part of the SteamWar software.
+ * This file is a part of the SteamWar software.
*
- * Copyright (C) 2021 SteamWar.de-Serverteam
+ * Copyright (C) 2023 SteamWar.de-Serverteam
*
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
*
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
*
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
*/
package de.steamwar.bausystem.features.smartplace;
+import com.comphenix.tinyprotocol.Reflection;
+import com.comphenix.tinyprotocol.TinyProtocol;
+import de.steamwar.bausystem.BauSystem;
import de.steamwar.bausystem.configplayer.Config;
-import de.steamwar.bausystem.utils.PlaceItemUtils;
import de.steamwar.linkage.Linked;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.Material;
-import org.bukkit.SoundGroup;
+import org.bukkit.World;
import org.bukkit.block.Block;
-import org.bukkit.block.data.BlockData;
-import org.bukkit.block.data.type.Repeater;
-import org.bukkit.block.data.type.Sign;
-import org.bukkit.block.data.type.Switch;
+import org.bukkit.block.BlockFace;
+import org.bukkit.block.BlockState;
+import org.bukkit.block.TileState;
+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.BlockBreakEvent;
+import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.player.PlayerInteractEvent;
+import org.bukkit.event.player.PlayerQuitEvent;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
@Linked
public class SmartPlaceListener implements Listener {
- @EventHandler(priority = EventPriority.HIGHEST)
- public void onPlayerInteract(PlayerInteractEvent event) {
- if (!Config.getInstance().get(event.getPlayer()).getPlainValueOrDefault("smartPlace", false)) return;
- if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return;
- if (event.getPlayer().getGameMode() == GameMode.SPECTATOR) return;
+ // TODO: Sneaking not reset sometimes
- boolean shouldRotate = event.getPlayer().isSneaking();
- Material blockType = event.getClickedBlock().getType();
- switch (blockType) {
- case REPEATER:
- if (shouldRotate && (event.getItem() == null || event.getItem().getType() == Material.REPEATER)) {
- Repeater repeater = (Repeater) event.getClickedBlock().getBlockData();
- int i = repeater.getDelay() - 1;
- if (i <= 0) i += 4;
- repeater.setDelay(i);
- event.getClickedBlock().setBlockData(repeater);
- event.setCancelled(true);
- }
- return;
- }
- BlockData blockData = event.getClickedBlock().getBlockData();
- if (blockData instanceof Switch) {
- if (!shouldRotate && (event.getItem() == null || event.getItem().getType() == event.getClickedBlock().getType())) {
- return;
- }
- shouldRotate = false;
- }
+ private static final Set CONTAINERS = new HashSet<>();
- PlaceItemUtils.PlaceItemResult result = PlaceItemUtils.placeItem(event.getPlayer(), event.getItem(), event.getClickedBlock(), event.getBlockFace(), event.getHand(), true, true, shouldRotate, false);
- if (result.isSuccess()) {
- event.setCancelled(true);
- Block block = event.getClickedBlock().getRelative(event.getBlockFace());
- SoundGroup soundGroup = block.getBlockData().getSoundGroup();
- Bukkit.getOnlinePlayers().forEach(player -> {
- if (!(event.getClickedBlock().getBlockData() instanceof Sign) && player == event.getPlayer()) {
- return;
- }
- player.playSound(block.getLocation(), soundGroup.getPlaceSound(), soundGroup.getVolume() * 0.8F, soundGroup.getPitch() * 0.8F);
- });
- if (result.wasForced()) {
- event.getPlayer().playSound(block.getLocation(), soundGroup.getPlaceSound(), soundGroup.getVolume() * 0.8F, soundGroup.getPitch() * 0.8F);
+ static {
+ World world = Bukkit.getWorlds().get(0);
+ Block block = world.getBlockAt(0, 0, 0);
+ 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);
}
}
- // Fix Double sound for original player
+ CONTAINERS.add(Material.GRINDSTONE);
+ state.update(true, false);
+ }
+
+ private static final Class> useItem = Reflection.getClass("{nms.network.protocol.game}.PacketPlayInUseItem");
+ private static final Set SMART_PLACING = new HashSet<>();
+
+ public SmartPlaceListener() {
+ TinyProtocol.instance.addFilter(useItem, (player, object) -> {
+ if (!Config.getInstance().get(player).getPlainValueOrDefault("smartPlace", false)) {
+ return object;
+ }
+
+ Block block = player.getTargetBlockExact(6);
+ if (block != null && (block.getType().isInteractable() || block.getType() == Material.NOTE_BLOCK) && !CONTAINERS.contains(block.getType())) {
+ return object;
+ }
+
+ boolean isSneaking = player.isSneaking();
+ if (isSneaking) {
+ SMART_PLACING.add(player);
+ }
+ if (!isSneaking) {
+ player.setSneaking(true);
+ }
+ Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
+ player.setSneaking(isSneaking);
+ SMART_PLACING.remove(player);
+ }, 0);
+ return object;
+ });
}
@EventHandler
- public void onBlockBreak(BlockBreakEvent event) {
- if (!Config.getInstance().get(event.getPlayer()).getPlainValueOrDefault("smartPlace", false)) return;
+ public void onPlayerInteract(PlayerInteractEvent event) {
+ if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return;
+ if (event.getPlayer().getGameMode() == GameMode.SPECTATOR) return;
if (!event.getPlayer().isSneaking()) return;
- event.setCancelled(true);
- event.getBlock().setType(Material.AIR, false);
+ if (event.getClickedBlock().getType() != Material.REPEATER) return;
+ if ((event.getItem() == null || event.getItem().getType() == Material.REPEATER)) {
+ Repeater repeater = (Repeater) event.getClickedBlock().getBlockData();
+ int i = repeater.getDelay() - 1;
+ if (i <= 0) i += 4;
+ repeater.setDelay(i);
+ event.getClickedBlock().setBlockData(repeater);
+ event.setCancelled(true);
+ }
+ }
- SoundGroup soundGroup = event.getBlock().getBlockData().getSoundGroup();
- Bukkit.getOnlinePlayers().forEach(player -> {
- if (player == event.getPlayer()) return;
- player.playSound(event.getBlock().getLocation(), soundGroup.getBreakSound(), soundGroup.getVolume() * 0.8F, soundGroup.getPitch() * 0.8F);
- });
+ @EventHandler
+ public void onBlockPlace(BlockPlaceEvent event) {
+ if (!SMART_PLACING.contains(event.getPlayer())) return;
+ BlockData blockData = event.getBlock().getBlockData();
+ if (blockData instanceof Bed) {
+ Bed bed = (Bed) blockData;
+ Block bedHead = event.getBlock().getRelative(bed.getFacing());
+ bed.setPart(Bed.Part.HEAD);
+ bed.setFacing(bed.getFacing().getOppositeFace());
+
+ bed = (Bed) bedHead.getBlockData();
+ bed.setPart(Bed.Part.FOOT);
+ bed.setFacing(bed.getFacing().getOppositeFace());
+ bedHead.setBlockData(bed, false);
+ } else if (blockData instanceof FaceAttachable && ((FaceAttachable) blockData).getAttachedFace() != FaceAttachable.AttachedFace.WALL) {
+ FaceAttachable faceAttachable = (FaceAttachable) blockData;
+ faceAttachable.setAttachedFace(faceAttachable.getAttachedFace() == FaceAttachable.AttachedFace.CEILING ? FaceAttachable.AttachedFace.FLOOR : FaceAttachable.AttachedFace.CEILING);
+ } else if (blockData instanceof Rotatable) {
+ Rotatable rotatable = (Rotatable) blockData;
+ rotatable.setRotation(rotatable.getRotation().getOppositeFace());
+ } else if (blockData instanceof Directional) {
+ Directional directional = (Directional) blockData;
+ BlockFace face = directional.getFacing().getOppositeFace();
+ if (directional.getFaces().contains(face)) {
+ directional.setFacing(face);
+ }
+ } else if (blockData instanceof MultipleFacing && !(blockData instanceof Fence)) {
+ MultipleFacing multipleFacing = (MultipleFacing) blockData;
+ List blockFaceList = multipleFacing.getFaces()
+ .stream()
+ .map(BlockFace::getOppositeFace)
+ .collect(Collectors.toList());
+ if (multipleFacing.getAllowedFaces().containsAll(blockFaceList)) {
+ multipleFacing.getFaces().forEach(blockFace -> {
+ multipleFacing.setFace(blockFace, false);
+ });
+ blockFaceList.forEach(blockFace -> {
+ multipleFacing.setFace(blockFace, true);
+ });
+ }
+ }
+ if (blockData instanceof Stairs) {
+ Stairs stairs = (Stairs) blockData;
+ switch (stairs.getShape()) {
+ case OUTER_LEFT:
+ stairs.setShape(Stairs.Shape.INNER_RIGHT);
+ break;
+ case INNER_LEFT:
+ stairs.setShape(Stairs.Shape.OUTER_RIGHT);
+ break;
+ case OUTER_RIGHT:
+ stairs.setShape(Stairs.Shape.INNER_LEFT);
+ break;
+ case INNER_RIGHT:
+ stairs.setShape(Stairs.Shape.OUTER_LEFT);
+ break;
+ case STRAIGHT:
+ break;
+ }
+ }
+ if (blockData instanceof Piston) {
+ Piston piston = (Piston) blockData;
+ Block block = event.getBlock().getRelative(piston.getFacing().getOppositeFace());
+ Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
+ event.getPlayer().sendBlockChange(block.getLocation(), block.getBlockData());
+ }, 2);
+ } else if (blockData.getMaterial() == Material.REPEATER || blockData.getMaterial() == Material.COMPARATOR) {
+ Block block = event.getBlock().getRelative(BlockFace.DOWN);
+ BlockState old = block.getState();
+ Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
+ block.setType(Material.GLASS);
+ old.update(true, false);
+ }, 1);
+ }
+ event.getBlock().setBlockData(blockData, true);
+ }
+
+ @EventHandler
+ public void onPlayerQuit(PlayerQuitEvent event) {
+ SMART_PLACING.remove(event.getPlayer());
}
}