package in.twizmwaz.cardinal.module.modules.damageIndicator; import com.google.common.base.Optional; import in.twizmwaz.cardinal.Cardinal; import in.twizmwaz.cardinal.event.CardinalDeathEvent; import in.twizmwaz.cardinal.module.modules.observers.ObserverModule; import in.twizmwaz.cardinal.module.modules.team.TeamModule; import in.twizmwaz.cardinal.util.Numbers; import in.twizmwaz.cardinal.util.PacketUtils; import in.twizmwaz.cardinal.util.Teams; import in.twizmwaz.cardinal.util.Watchers; import net.minecraft.server.Packet; import net.minecraft.server.PacketPlayOutEntity; import net.minecraft.server.PacketPlayOutEntityDestroy; import net.minecraft.server.PacketPlayOutEntityTeleport; import net.minecraft.server.PacketPlayOutSpawnEntityLiving; import org.apache.commons.lang.ArrayUtils; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.event.player.PlayerUseUnknownEntityEvent; import org.bukkit.util.Vector; import java.util.ArrayList; import java.util.List; import java.util.UUID; class PlayerBoundingBox implements Listener { private static double MAX_DISTANCE = 10; private UUID player; private Optional<TeamModule> team; private List<UUID> viewers = new ArrayList<>(); private List<Integer> zombieID = new ArrayList<>(); private int mainTask; protected PlayerBoundingBox(UUID player, Optional<TeamModule> team) { this.player = player; this.team = team; for (int i = 0; i < 4; i++) { zombieID.add(Bukkit.allocateEntityId()); } Bukkit.getPluginManager().registerEvents(this, Cardinal.getInstance()); mainTask = Bukkit.getScheduler().scheduleSyncDelayedTask(Cardinal.getInstance(), new Runnable() { @Override public void run() { updateAndTeleport(null); } }, 20L); } public void destroy(){ Bukkit.getScheduler().cancelTask(mainTask); broadcastRemovePacket(); HandlerList.unregisterAll(this); } @EventHandler public void onZombieAttack(PlayerUseUnknownEntityEvent event) { if (shouldShow(event.getPlayer()) && event.isAttack() && this.zombieID.contains(event.getEntityId())) { ((CraftPlayer)event.getPlayer()).getHandle().attack(((CraftPlayer)Bukkit.getPlayer(player)).getHandle()); } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPlayerMove(PlayerTeleportEvent event) { if (event.getPlayer().getUniqueId().equals(this.player)) { updateAndTeleport(event.getTo().position()); } else { sendOrRemoveZombies(event.getPlayer(), event.getTo().position(), Bukkit.getPlayer(player).getLocation().position()); } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPlayerMove(PlayerMoveEvent event) { if (event.getPlayer().getUniqueId().equals(this.player)) { for (Player player : Bukkit.getOnlinePlayers()) { sendOrRemoveZombies(player, player.getLocation().position(), event.getTo().position()); } Vector diff = Numbers.clone(event.getTo().position()).subtract(event.getFrom().position()); relativeMoveBoundingBox(Math.round(4096 * (diff.getX())), Math.round(4096 * (diff.getY())), Math.round(4096 * (diff.getZ())), event.getPlayer().isOnGround()); } else { sendOrRemoveZombies(event.getPlayer(), event.getTo().position(), Bukkit.getPlayer(player).getLocation().position()); } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPlayerDeath(CardinalDeathEvent event) { if (event.getPlayer().getUniqueId().equals(this.player)) { broadcastRemovePacket(); } else { sendRemovePacket(event.getPlayer()); } } private boolean shouldShow(Player player) { Optional<TeamModule> team = Teams.getTeamByPlayer(player); return !ObserverModule.testObserverOrDead(player) && (team.isPresent() && !team.get().equals(this.team.get())); } public void sendOrRemoveZombies(Player player, Vector playerPos, Vector bbPos) { if (shouldShow(player) && bbPos.distance(playerPos) < MAX_DISTANCE) { sendSpawnPackets(player); } else { sendRemovePacket(player); } } public void updateAndTeleport(Vector loc) { if (loc == null) loc = Bukkit.getPlayer(this.player).getLocation().position(); for (Player player : Bukkit.getOnlinePlayers()) { sendOrRemoveZombies(player, player.getLocation().position(), loc); } teleportBoundingBox(loc, Bukkit.getPlayer(this.player).isOnGround()); } public void teleportBoundingBox(Vector to, boolean onGround) { int i = 0; for (int x = -1; x < 2; x += 2) { for (int z = -1; z < 2; z += 2) { Packet teleportPacket = new PacketPlayOutEntityTeleport(zombieID.get(i), to.getX() + (x * DamageIndicator.OFFSET), to.getY() , to.getZ() + (z * DamageIndicator.OFFSET), (byte) 2, (byte) 0, onGround); PacketUtils.broadcastPacketByUUID(teleportPacket, viewers); i++; } } } public void relativeMoveBoundingBox(long x, long y, long z, boolean onGround) { for (Integer zombie : zombieID) { PacketUtils.broadcastPacketByUUID(new PacketPlayOutEntity.PacketPlayOutRelEntityMove(zombie, x, y, z, onGround), viewers); } } public void sendSpawnPackets(Player viewer) { if (viewers.contains(viewer.getUniqueId())) return; Player player = Bukkit.getPlayer(this.player); Location loc = player.getLocation(); int i = 0; for (int x = -1; x < 2; x += 2) { for (int z = -1; z < 2; z += 2) { Packet spawnPacket = new PacketPlayOutSpawnEntityLiving( zombieID.get(i++), UUID.randomUUID(), 54, // Entity id, UUID, and type (Zombie) loc.getX() + (x * DamageIndicator.OFFSET), loc.getY(),// X, Y loc.getZ() + (z * DamageIndicator.OFFSET), // and Z coords 0, 0, 0, // X, Y and Z Motion (byte) 2, (byte) 0, (byte) 2, // Yaw, Pitch and Head Pitch Watchers.toList(Watchers.INVISIBLE)); // Metadata PacketUtils.sendPacket(viewer, spawnPacket); } } viewers.add(viewer.getUniqueId()); } private Packet getRemovePacket() { int[] ids = ArrayUtils.toPrimitive(zombieID.toArray(new Integer[4])); return new PacketPlayOutEntityDestroy(ids); } public void sendRemovePacket(Player player) { if (!viewers.contains(player.getUniqueId())) return; PacketUtils.sendPacket(player, getRemovePacket()); viewers.remove(player.getUniqueId()); } private void broadcastRemovePacket() { PacketUtils.broadcastPacketByUUID(getRemovePacket(), viewers); } }