All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sucy.skill.api.target.TargetHelper Maven / Gradle / Ivy

Go to download

A Minecraft Bukkit plugin aiming to provide an easy code API and skill editor for all server owners to create unique and fully custom classes and skills.

There is a newer version: 1.3.1-R1
Show newest version
package com.sucy.skill.api.target;

import com.sucy.skill.hook.DisguiseHook;
import com.sucy.skill.hook.PluginChecker;
import me.libraryaddict.disguise.DisguiseAPI;
import me.libraryaddict.disguise.utilities.reflection.FakeBoundingBox;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.util.Vector;

import java.util.ArrayList;
import java.util.List;
import java.util.TreeMap;

public abstract class TargetHelper {


    /**
     * 

Number of pixels that end up displaying about 1 degree of vision in the client window

*

Not really useful since you can't get the client's window size, but I added it in case * it becomes useful sometime

*/ private static final int PIXELS_PER_DEGREE = 35; /** *

Gets all entities the player is looking at within the range

*

Has a little bit of tolerance to make targeting easier

* * @param source living entity to get the targets of * @param range maximum range to check * @return all entities in the player's vision line */ public static List getLivingTargets(LivingEntity source, double range) { return getLivingTargets(source, range, 4); } /** *

Gets all entities the player is looking at within the range using * the given tolerance.

* * @param source living entity to get the targets of * @param range maximum range to check * @param tolerance tolerance of the line calculation * @return all entities in the player's vision line */ public static List getLivingTargets(LivingEntity source, double range, double tolerance) { List list = source.getNearbyEntities(range, range, range); TreeMap targets = new TreeMap<>(); Location location = source.getEyeLocation(); Vector origin = location.toVector(); AABB.Ray3D ray = new AABB.Ray3D(location); for (Entity entity : list) { if (!isInFront(source, entity) || !(entity instanceof LivingEntity)) continue; AABB aabb = getAABB(entity); aabb.expand(tolerance); AABB.Vec3D collision = aabb.intersectsRay(ray, 0, range); if (collision != null) { targets.put(new Vector(collision.x, collision.y, collision.z).distance(origin), (LivingEntity) entity); } } return new ArrayList<>(targets.values()); } /** *

Gets the entity the player is looking at

*

Has a little bit of tolerance to make targeting easier

* * @param source living entity to get the target of * @param range maximum range to check * @return entity player is looing at or null if not found */ public static LivingEntity getLivingTarget(LivingEntity source, double range) { return getLivingTarget(source, range, 4); } /** *

Gets the entity the player is looking at

*

Has a little bit of tolerance to make targeting easier

* * @param source living entity to get the target of * @param range maximum range to check * @param tolerance tolerance of the line calculation * @return entity player is looking at or null if not found */ public static LivingEntity getLivingTarget(LivingEntity source, double range, double tolerance) { List targets = getLivingTargets(source, range, tolerance); if (targets.size() == 0) return null; return targets.get(0); } /** * Gets the targets in a cone * * @param source entity to get the targets for * @param arc arc angle of the cone * @param range range of the cone * @return list of targets */ public static List getConeTargets(LivingEntity source, double arc, double range) { List targets = new ArrayList<>(); List list = source.getNearbyEntities(range, range, range); if (arc <= 0) return targets; // Initialize values Location sourceLocation = source.getEyeLocation(); Vector dir = sourceLocation.getDirection(); dir.setY(0); double cos = Math.cos(arc * Math.PI / 180); double cosSq = cos * cos; // Get the targets in the cone for (Entity entity : list) { if (entity instanceof LivingEntity) { // Greater than 360 degrees is all targets if (arc >= 360) { targets.add((LivingEntity) entity); } // Otherwise, select targets based on dot product else { Vector relative = entity.getLocation() .clone() .add(0, getHeight(entity) * 0.5, 0) .subtract(sourceLocation) .toVector(); relative.setY(0); double dot = relative.dot(dir); double value = dot * dot / relative.lengthSquared(); if (arc < 180 && dot > 0 && value >= cosSq) targets.add((LivingEntity) entity); else if (arc >= 180 && (dot > 0 || dot <= cosSq)) targets.add((LivingEntity) entity); } } } return targets; } /** * Checks if the entity is in front of the entity * * @param entity entity to check for * @param target target to check against * @return true if the target is in front of the entity */ public static boolean isInFront(Entity entity, Entity target) { // Get the necessary vectors Vector facing = entity.getLocation().getDirection(); Vector relative = target.getLocation().clone() // Get the target's location and add half their height, so we have the "center of mass" .add(0, getHeight(entity) * -0.5, 0) // Subtract the entity location so we translate to our origin .subtract(entity.getLocation()) .toVector(); // If the dot product is positive, the target is in front return facing.dot(relative) >= 0; } /** * Checks if the entity is in front of the entity restricted to the given angle * * @param entity entity to check for * @param target target to check against * @param angle angle to restrict it to (0-360) * @return true if the target is in front of the entity */ public static boolean isInFront(Entity entity, Entity target, double angle) { if (angle <= 0) return false; if (angle >= 360) return true; // Get the necessary data double dotTarget = Math.cos(angle); Vector facing = entity.getLocation().getDirection(); Vector relative = target.getLocation().clone() .add(0, getHeight(entity) * -0.5, 0) .subtract(entity.getLocation()) .toVector().normalize(); // Compare the target dot product with the actual result return facing.dot(relative) >= dotTarget; } /** * Checks if the target is behind the entity * * @param entity entity to check for * @param target target to check against * @return true if the target is behind the entity */ public static boolean isBehind(Entity entity, Entity target) { return !isInFront(entity, target); } /** * Checks if the entity is behind the player restricted to the given angle * * @param entity entity to check for * @param target target to check against * @param angle angle to restrict it to (0-360) * @return true if the target is behind the entity */ public static boolean isBehind(Entity entity, Entity target, double angle) { return !isInFront(entity, target, angle); } /** * Checks whether the line between the two points is obstructed * * @param loc1 first location * @param loc2 second location * @return the location of obstruction or null if not obstructed */ public static boolean isObstructed(Location loc1, Location loc2) { if (loc1.getX() == loc2.getX() && loc1.getY() == loc2.getY() && loc1.getZ() == loc2.getZ()) { return false; } Vector slope = loc2.clone().subtract(loc1).toVector(); int steps = (int) (slope.length() * 4) + 1; slope.multiply(1.0 / steps); Location temp = loc1.clone(); for (int i = 0; i < steps; i++) { temp.add(slope); if (isSolid(temp.getBlock().getType())) { return true; } } return false; } /** * Retrieves an open location along the line for teleporting or linear targeting * * @param loc1 start location of the path * @param loc2 end location of the path * @param throughWall whether going through walls is allowed * @return the farthest open location along the path */ public static Location getOpenLocation(Location loc1, Location loc2, boolean throughWall) { // Special case if (loc1.getX() == loc2.getX() && loc1.getY() == loc2.getY() && loc1.getZ() == loc2.getZ()) { return loc1; } // Common data Vector slope = loc2.clone().subtract(loc1).toVector(); int steps = (int) (slope.length() * 4) + 1; slope.multiply(1.0 / steps); // Going through walls starts at the end and traverses backwards if (throughWall) { Location temp = loc2.clone(); while (isSolid(temp.getBlock().getType()) && steps > 0) { temp.subtract(slope); steps--; } temp.setX(temp.getBlockX() + 0.5); temp.setZ(temp.getBlockZ() + 0.5); temp.setY(temp.getBlockY() + 1); return temp; } // Not going through walls starts at the beginning and traverses forward else { Location temp = loc1.clone(); while (!isSolid(temp.getBlock().getType()) && steps > 0) { temp.add(slope); steps--; } temp.subtract(slope); temp.setX(temp.getBlockX() + 0.5); temp.setZ(temp.getBlockZ() + 0.5); temp.setY(temp.getBlockY() + 1); return temp; } } public static boolean isSolid(Material mat) { if (!mat.isSolid()) return false; else return mat.isOccluding() || mat.name().contains("STAIR"); // Not going to worry about doors, slabs, trapdoors, etc that *could* be blocking the path of a projectile. // We'll just assume that these are good to go. // This is where we'd make special accommodations for things like doors or trapdoors if need be. } public static AABB getAABB(Entity entity) { AABB.Vec3D origin = AABB.Vec3D.fromLocation(entity.getLocation()); try { if (PluginChecker.isDisguiseActive() && DisguiseAPI.isDisguised(entity) && DisguiseAPI.getDisguise(entity) .isModifyBoundingBox()) { FakeBoundingBox boundingBox = DisguiseHook.getFakeBoundingBox(entity); return new AABB(origin.add(new AABB.Vec3D(-boundingBox.getX(), 0, -boundingBox.getZ())), origin.add(new AABB.Vec3D(boundingBox.getX(), boundingBox.getY(), boundingBox.getZ()))); } } catch (NullPointerException ignored) { } double halfWidth = entity.getWidth() / 2; return new AABB(origin.add(new AABB.Vec3D(-halfWidth, 0, -halfWidth)), origin.add(new AABB.Vec3D(halfWidth, entity.getHeight(), halfWidth))); } public static double getHeight(Entity entity) { return (PluginChecker.isDisguiseActive() && DisguiseAPI.isDisguised(entity)) ? DisguiseHook.getFakeBoundingBox(entity).getY() : entity.getHeight(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy