diff --git a/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/TNTSimulatorListener.java b/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/TNTSimulatorListener.java index 110a79e2..c64f8f80 100644 --- a/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/TNTSimulatorListener.java +++ b/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/TNTSimulatorListener.java @@ -25,6 +25,7 @@ import de.steamwar.bausystem.features.simulator.gui.SimulatorSelectionGUI; import de.steamwar.bausystem.linkage.LinkageType; import de.steamwar.bausystem.linkage.Linked; import de.steamwar.bausystem.utils.ItemUtils; +import de.steamwar.bausystem.utils.RayTraceUtils; import org.bukkit.Bukkit; import org.bukkit.FluidCollisionMode; import org.bukkit.GameMode; @@ -56,41 +57,7 @@ public class TNTSimulatorListener implements Listener { } static RayTraceResult trace(Player player, Location to, TNTSimulator simulator) { - if (player.getGameMode() == GameMode.SPECTATOR) { - return null; - } - - Location startPos = to.clone().add(0.0, player.getEyeHeight(), 0.0); - Vector direction = to.getDirection(); - RayTraceResult blocks = player.getWorld().rayTraceBlocks(startPos, direction, 10.0, FluidCollisionMode.NEVER, true); - - Entity nearestHitEntity = null; - RayTraceResult nearestHitResult = null; - double nearestDistanceSq = Double.MAX_VALUE; - for (Entity entity : simulator.getEntities()) { - BoundingBox boundingBox = entity.getBoundingBox(); - RayTraceResult hitResult = boundingBox.rayTrace(startPos.toVector(), direction, 10.0); - if (hitResult != null) { - double distanceSq = startPos.toVector().distanceSquared(hitResult.getHitPosition()); - if (distanceSq < nearestDistanceSq) { - nearestHitEntity = entity; - nearestHitResult = hitResult; - nearestDistanceSq = distanceSq; - } - } - } - RayTraceResult entities = nearestHitEntity == null ? null : new RayTraceResult(nearestHitResult.getHitPosition(), nearestHitEntity, nearestHitResult.getHitBlockFace()); - - if (blocks == null) { - return entities; - } else if (entities == null) { - return blocks; - } else { - Vector startVec = startPos.toVector(); - double blockHitDistance = startVec.distance(blocks.getHitPosition()); - double entityHitDistanceSquared = startVec.distanceSquared(entities.getHitPosition()); - return entityHitDistanceSquared < blockHitDistance * blockHitDistance ? entities : blocks; - } + return RayTraceUtils.trace(player, to, simulator.getEntities()); } @EventHandler diff --git a/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/AbstractTraceEntity.java b/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/AbstractTraceEntity.java index 980f511b..ef0df4aa 100644 --- a/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/AbstractTraceEntity.java +++ b/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/AbstractTraceEntity.java @@ -20,6 +20,7 @@ package de.steamwar.bausystem.features.tracer; import de.steamwar.bausystem.shared.AbstractEntity; +import org.bukkit.entity.Entity; import org.bukkit.entity.Player; public interface AbstractTraceEntity extends AbstractEntity { @@ -27,4 +28,6 @@ public interface AbstractTraceEntity extends AbstractEntity { void display(Player player, boolean exploded, int ticks); boolean hide(Player player, boolean always); + + Entity getBukkitEntity(); } diff --git a/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceTNTClickListener.java b/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceTNTClickListener.java new file mode 100644 index 00000000..6a9b885e --- /dev/null +++ b/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceTNTClickListener.java @@ -0,0 +1,66 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2022 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 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 . + */ + +package de.steamwar.bausystem.features.tracer; + +import com.comphenix.tinyprotocol.Reflection; +import de.steamwar.bausystem.BauSystem; +import de.steamwar.bausystem.features.tracer.show.TraceShowManager; +import de.steamwar.bausystem.linkage.LinkageType; +import de.steamwar.bausystem.linkage.Linked; +import de.steamwar.bausystem.utils.ProtocolAPI; +import de.steamwar.bausystem.utils.RayTraceUtils; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.util.RayTraceResult; + +import java.util.HashSet; +import java.util.Set; + +@Linked(LinkageType.PLAIN) +public class TraceTNTClickListener { + + private static final Class useEntity = Reflection.getClass("{nms.network.protocol.game}.PacketPlayInUseEntity"); + + { + Set playerSet = new HashSet<>(); + + ProtocolAPI.setIncomingHandler(useEntity, (player, o) -> { + if (!playerSet.add(player)) return o; + Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> { + RayTraceResult rayTraceResult = RayTraceUtils.trace(player, player.getLocation(), TraceShowManager.getEntities(player)); + if (rayTraceResult == null) return; + if (rayTraceResult.getHitEntity() == null) return; + TNTPosition tntPosition = TraceShowManager.getTNTPosition(player, rayTraceResult.getHitEntity()); + if (tntPosition == null) return; + + BauSystem.MESSAGE.sendPrefixless("TNT_CLICK_HEADER", player); + BauSystem.MESSAGE.sendPrefixless("TNT_CLICK_FUSE_TIME", player, tntPosition.getFuseTicks()); + BauSystem.MESSAGE.sendPrefixless("TNT_CLICK_POSITION_X", player, tntPosition.getLocation().getX() + ""); + BauSystem.MESSAGE.sendPrefixless("TNT_CLICK_POSITION_Y", player, tntPosition.getLocation().getY() + ""); + BauSystem.MESSAGE.sendPrefixless("TNT_CLICK_POSITION_Z", player, tntPosition.getLocation().getZ() + ""); + BauSystem.MESSAGE.sendPrefixless("TNT_CLICK_VELOCITY_X", player, tntPosition.getVelocity().getX() + ""); + BauSystem.MESSAGE.sendPrefixless("TNT_CLICK_VELOCITY_Y", player, tntPosition.getVelocity().getY() + ""); + BauSystem.MESSAGE.sendPrefixless("TNT_CLICK_VELOCITY_Z", player, tntPosition.getVelocity().getZ() + ""); + playerSet.remove(player); + }, 1); + return o; + }); + } +} diff --git a/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/show/EntityTraceShowMode.java b/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/show/EntityTraceShowMode.java new file mode 100644 index 00000000..2b73a40b --- /dev/null +++ b/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/show/EntityTraceShowMode.java @@ -0,0 +1,31 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2022 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 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 . + */ + +package de.steamwar.bausystem.features.tracer.show; + +import de.steamwar.bausystem.features.tracer.TNTPosition; +import de.steamwar.bausystem.shared.ShowMode; +import org.bukkit.entity.Entity; + +import java.util.List; + +public interface EntityTraceShowMode extends ShowMode { + List getEntities(); + TNTPosition getTNTPosition(Entity entity); +} diff --git a/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/show/TraceShowManager.java b/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/show/TraceShowManager.java index 3f93a0cb..cdb176cf 100644 --- a/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/show/TraceShowManager.java +++ b/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/show/TraceShowManager.java @@ -4,12 +4,15 @@ import de.steamwar.bausystem.BauSystem; import de.steamwar.bausystem.features.tracer.TNTPosition; import de.steamwar.bausystem.shared.ShowMode; import org.bukkit.Bukkit; +import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerQuitEvent; +import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; public class TraceShowManager implements Listener { @@ -31,6 +34,28 @@ public class TraceShowManager implements Listener { traceShowMode.hide(); } + public static List getEntities(Player player) { + ShowMode showMode = showModes.get(player); + if (showMode == null) { + return Collections.emptyList(); + } + if (showMode instanceof EntityTraceShowMode) { + return ((EntityTraceShowMode) showMode).getEntities(); + } + return Collections.emptyList(); + } + + public static TNTPosition getTNTPosition(Player player, Entity entity) { + ShowMode showMode = showModes.get(player); + if (showMode == null) { + return null; + } + if (showMode instanceof EntityTraceShowMode) { + return ((EntityTraceShowMode) showMode).getTNTPosition(entity); + } + return null; + } + public static void reshow() { Map> current = new HashMap<>(showModes); current.forEach(TraceShowManager::show); diff --git a/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/show/mode/FactoredEntityShowMode.java b/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/show/mode/FactoredEntityShowMode.java index 2a819e8c..523fc92d 100644 --- a/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/show/mode/FactoredEntityShowMode.java +++ b/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/show/mode/FactoredEntityShowMode.java @@ -21,19 +21,22 @@ package de.steamwar.bausystem.features.tracer.show.mode; import de.steamwar.bausystem.features.tracer.AbstractTraceEntity; import de.steamwar.bausystem.features.tracer.TNTPosition; +import de.steamwar.bausystem.features.tracer.show.EntityTraceShowMode; import de.steamwar.bausystem.features.tracer.show.ShowModeParameter; import de.steamwar.bausystem.shared.RoundedPosition; -import de.steamwar.bausystem.shared.ShowMode; import de.steamwar.bausystem.utils.FlatteningWrapper; import de.steamwar.bausystem.utils.NMSWrapper; +import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.util.Consumer; import org.bukkit.util.Vector; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; -public abstract class FactoredEntityShowMode implements ShowMode { +public abstract class FactoredEntityShowMode implements EntityTraceShowMode { private int factor; @@ -42,6 +45,7 @@ public abstract class FactoredEntityShowMode implements ShowMode { private final Map tntEntityMap = new HashMap<>(); private final Map updateEntityMap = new HashMap<>(); + private final Map tntPositionMap = new HashMap<>(); protected FactoredEntityShowMode(Player player, ShowModeParameter showModeParameter, int factor) { this.player = player; @@ -57,6 +61,7 @@ public abstract class FactoredEntityShowMode implements ShowMode { } RoundedPosition roundedPosition = new RoundedPosition(position, factor); AbstractTraceEntity entity = tntEntityMap.computeIfAbsent(roundedPosition, pos -> createEntity(player, position.getLocation(), true)); + tntPositionMap.put(entity.getBukkitEntity(), position); entity.display(player, position.isExploded(), showModeParameter.isTicks() ? position.getFuseTicks() : -1); return; } @@ -81,6 +86,7 @@ public abstract class FactoredEntityShowMode implements ShowMode { RoundedPosition roundedPosition = new RoundedPosition(position, factor); AbstractTraceEntity entity = tntEntityMap.computeIfAbsent(roundedPosition, pos -> createEntity(player, position.getLocation(), true)); + tntPositionMap.put(entity.getBukkitEntity(), position); entity.display(player, position.isExploded(), showModeParameter.isTicks() ? position.getFuseTicks() : -1); applyOnPosition(position, updatePointPosition -> { @@ -120,9 +126,20 @@ public abstract class FactoredEntityShowMode implements ShowMode { @Override public void hide() { + tntPositionMap.clear(); tntEntityMap.forEach((roundedPosition, abstractTraceEntity) -> abstractTraceEntity.hide(player, true)); tntEntityMap.clear(); updateEntityMap.forEach((roundedPosition, abstractTraceEntity) -> abstractTraceEntity.hide(player, true)); updateEntityMap.clear(); } + + @Override + public List getEntities() { + return new ArrayList<>(tntPositionMap.keySet()); + } + + @Override + public TNTPosition getTNTPosition(Entity entity) { + return tntPositionMap.get(entity); + } } diff --git a/BauSystem_Main/src/de/steamwar/bausystem/features/util/TNTClickListener.java b/BauSystem_Main/src/de/steamwar/bausystem/features/util/TNTClickListener.java index 9c69b022..7a2f0a67 100644 --- a/BauSystem_Main/src/de/steamwar/bausystem/features/util/TNTClickListener.java +++ b/BauSystem_Main/src/de/steamwar/bausystem/features/util/TNTClickListener.java @@ -49,8 +49,8 @@ public class TNTClickListener implements Listener { BauSystem.MESSAGE.sendPrefixless("TNT_CLICK_POSITION_Y", event.getPlayer(), tntPrimed.getLocation().getY() + ""); BauSystem.MESSAGE.sendPrefixless("TNT_CLICK_POSITION_Z", event.getPlayer(), tntPrimed.getLocation().getZ() + ""); BauSystem.MESSAGE.sendPrefixless("TNT_CLICK_VELOCITY_X", event.getPlayer(), tntPrimed.getVelocity().getX() + ""); - BauSystem.MESSAGE.sendPrefixless("TNT_CLICK_VELOCITY_Y", event.getPlayer(), tntPrimed.getVelocity().getX() + ""); - BauSystem.MESSAGE.sendPrefixless("TNT_CLICK_VELOCITY_Z", event.getPlayer(), tntPrimed.getVelocity().getX() + ""); + BauSystem.MESSAGE.sendPrefixless("TNT_CLICK_VELOCITY_Y", event.getPlayer(), tntPrimed.getVelocity().getY() + ""); + BauSystem.MESSAGE.sendPrefixless("TNT_CLICK_VELOCITY_Z", event.getPlayer(), tntPrimed.getVelocity().getZ() + ""); BauSystem.MESSAGE.sendPrefixless("TNT_CLICK_COUNT", event.getPlayer(), count + ""); } } diff --git a/BauSystem_Main/src/de/steamwar/bausystem/utils/RayTraceUtils.java b/BauSystem_Main/src/de/steamwar/bausystem/utils/RayTraceUtils.java new file mode 100644 index 00000000..2145e442 --- /dev/null +++ b/BauSystem_Main/src/de/steamwar/bausystem/utils/RayTraceUtils.java @@ -0,0 +1,74 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2022 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 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 . + */ + +package de.steamwar.bausystem.utils; + +import lombok.experimental.UtilityClass; +import org.bukkit.FluidCollisionMode; +import org.bukkit.GameMode; +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.util.BoundingBox; +import org.bukkit.util.RayTraceResult; +import org.bukkit.util.Vector; + +import java.util.List; + +@UtilityClass +public class RayTraceUtils { + + public static RayTraceResult trace(Player player, Location to, List entityList) { + if (player.getGameMode() == GameMode.SPECTATOR) { + return null; + } + + Location startPos = to.clone().add(0.0, player.getEyeHeight(), 0.0); + Vector direction = to.getDirection(); + RayTraceResult blocks = player.getWorld().rayTraceBlocks(startPos, direction, 10.0, FluidCollisionMode.NEVER, true); + + Entity nearestHitEntity = null; + RayTraceResult nearestHitResult = null; + double nearestDistanceSq = Double.MAX_VALUE; + for (Entity entity : entityList) { + BoundingBox boundingBox = entity.getBoundingBox(); + RayTraceResult hitResult = boundingBox.rayTrace(startPos.toVector(), direction, 10.0); + if (hitResult != null) { + double distanceSq = startPos.toVector().distanceSquared(hitResult.getHitPosition()); + if (distanceSq < nearestDistanceSq) { + nearestHitEntity = entity; + nearestHitResult = hitResult; + nearestDistanceSq = distanceSq; + } + } + } + RayTraceResult entities = nearestHitEntity == null ? null : new RayTraceResult(nearestHitResult.getHitPosition(), nearestHitEntity, nearestHitResult.getHitBlockFace()); + + if (blocks == null) { + return entities; + } else if (entities == null) { + return blocks; + } else { + Vector startVec = startPos.toVector(); + double blockHitDistance = startVec.distance(blocks.getHitPosition()); + double entityHitDistanceSquared = startVec.distanceSquared(entities.getHitPosition()); + return entityHitDistanceSquared < blockHitDistance * blockHitDistance ? entities : blocks; + } + } +}