diff --git a/editor/js/component.js b/editor/js/component.js index 1a884308..6a5a5921 100644 --- a/editor/js/component.js +++ b/editor/js/component.js @@ -868,8 +868,8 @@ function TargetLinear() this.data.push(new AttributeValue("Range", "range", 5, 0) .setTooltip('The max distance away any target can be in blocks') ); - this.data.push(new AttributeValue("Tolerance", "tolerance", 4, 0) - .setTooltip('How lenient the targeting is. Larger numbers allow easier targeting. It is essentially how wide a cone is which is where you are targeting.') + this.data.push(new AttributeValue("Tolerance", "tolerance", 0, 0) + .setTooltip('How much to expand the potential entity\'s hitbox in all directions, in blocks. This makes it easier to aim') ); this.data.push(new ListValue("Group", "group", ["Ally", "Enemy", "Both"], "Enemy") .setTooltip('The alignment of targets to get') @@ -972,8 +972,8 @@ function TargetSingle() this.data.push(new AttributeValue("Range", "range", 5, 0) .setTooltip('The max distance away any target can be in blocks') ); - this.data.push(new AttributeValue("Tolerance", "tolerance", 4, 0) - .setTooltip('How lenient the targeting is. Larger numbers allow easier targeting. It is essentially how wide a cone is which is where you are targeting.') + this.data.push(new AttributeValue("Tolerance", "tolerance", 0, 0) + .setTooltip('How much to expand the potential entity\'s hitbox in all directions, in blocks. This makes it easier to aim') ); this.data.push(new ListValue("Group", "group", ["Ally", "Enemy", "Both"], "Enemy") .setTooltip('The alignment of targets to get') @@ -1765,10 +1765,10 @@ function MechanicCommand() this.description ='Executes a command for each of the targets.'; this.data.push(new StringValue('Command', 'command', '') - .setTooltip('The command to execute') + .setTooltip('The command to execute. {player} = caster\'s name, {target} = target\'s name, {targetUUID} = target\'s UUID (useful if targets are non players), &lc: "{", &rc: "}", &sq: "\'"') ); this.data.push(new ListValue('Execute Type', 'type', [ 'Console', 'OP' ], 'OP') - .setTooltip('Console: executes the command from the console. OP: Only if the target is a player, will have them execute it while given a temporary OP permission (If server closes in the meantime, the permission might stay, not recommended!!). {player} = caster\'s name, {target} = target\'s name, {targetUUID} = target\'s UUID (useful if targets are non players), &lc: "{", &rc: "}"') + .setTooltip('Console: executes the command from the console. OP: Only if the target is a player, will have them execute it while given a temporary OP permission (If server closes in the meantime, the permission might stay, not recommended!!)') ); } @@ -2229,7 +2229,7 @@ function MechanicMessage() this.description = 'Sends a message to each player target. To include numbers from Value mechanics, use the filters {} where is the key the value is stored under.' this.data.push(new StringValue('Message', 'message', 'text') - .setTooltip('The message to display') + .setTooltip('The message to display. {player} = caster\'s name, {target} = target\'s name, {targetUUID} = target\'s UUID (useful if targets are non players), &lc: "{", &rc: "}", &sq: "\'"') ); } diff --git a/pom.xml b/pom.xml index 7ba5d1d5..0ba1f081 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.sucy.skill SkillAPI - s1.96 + s1.97 jar SkillAPI @@ -109,7 +109,7 @@ org.spigotmc spigot-api - 1.15.2-R0.1-SNAPSHOT + 1.16.4-R0.1-SNAPSHOT provided diff --git a/src/main/java/com/sucy/skill/SkillAPI.java b/src/main/java/com/sucy/skill/SkillAPI.java index b7f003ac..eef0f04e 100644 --- a/src/main/java/com/sucy/skill/SkillAPI.java +++ b/src/main/java/com/sucy/skill/SkillAPI.java @@ -167,6 +167,8 @@ public void onEnable() { listen(new DeathListener(), !VersionManager.isVersionAtLeast(11000)); listen(new LingeringPotionListener(), VersionManager.isVersionAtLeast(VersionManager.V1_9_0)); listen(new ExperienceListener(), settings.yieldsEnabled()); + listen(new PluginChecker(), true); + // Set up tasks if (settings.isManaEnabled()) { diff --git a/src/main/java/com/sucy/skill/api/player/PlayerData.java b/src/main/java/com/sucy/skill/api/player/PlayerData.java index 67aaea14..42af1464 100644 --- a/src/main/java/com/sucy/skill/api/player/PlayerData.java +++ b/src/main/java/com/sucy/skill/api/player/PlayerData.java @@ -29,7 +29,7 @@ import com.rit.sucy.config.Filter; import com.rit.sucy.config.FilterType; import com.rit.sucy.config.parse.DataSection; -import com.sucy.skill.api.TargetHelper; +import com.sucy.skill.api.target.TargetHelper; import com.rit.sucy.version.VersionManager; import com.rit.sucy.version.VersionPlayer; import com.sucy.skill.SkillAPI; diff --git a/src/main/java/com/sucy/skill/api/projectile/CustomProjectile.java b/src/main/java/com/sucy/skill/api/projectile/CustomProjectile.java index 27faca45..ce666f41 100644 --- a/src/main/java/com/sucy/skill/api/projectile/CustomProjectile.java +++ b/src/main/java/com/sucy/skill/api/projectile/CustomProjectile.java @@ -182,8 +182,9 @@ public void applyLanded() { /** * Checks if the projectile collides with a given list of entities + * Returns true if another check should happen, false other wise */ - protected void checkCollision(final boolean pierce) { + protected boolean checkCollision(final boolean pierce) { for (LivingEntity entity : getColliding()) { if (entity == thrower || hit.contains(entity.getEntityId())) { continue; @@ -202,9 +203,10 @@ protected void checkCollision(final boolean pierce) { if (!pierce) { cancel(); - return; + return false; } } + return true; } /** diff --git a/src/main/java/com/sucy/skill/api/projectile/ParticleProjectile.java b/src/main/java/com/sucy/skill/api/projectile/ParticleProjectile.java index d1e6eeef..926dffca 100644 --- a/src/main/java/com/sucy/skill/api/projectile/ParticleProjectile.java +++ b/src/main/java/com/sucy/skill/api/projectile/ParticleProjectile.java @@ -206,7 +206,7 @@ public void run() if (!isTraveling()) return; - checkCollision(pierce); + if (!checkCollision(pierce)) break; } // Particle along path diff --git a/src/main/java/com/sucy/skill/api/target/AABB.java b/src/main/java/com/sucy/skill/api/target/AABB.java new file mode 100644 index 00000000..104c832b --- /dev/null +++ b/src/main/java/com/sucy/skill/api/target/AABB.java @@ -0,0 +1,235 @@ +package com.sucy.skill.api.target; + +import com.google.common.base.Objects; +import org.bukkit.Location; +import org.bukkit.util.Vector; + +/** + * Represents an axix-aligned bounding box. + * + * @author Kristian + */ +public class AABB { + public static class Vec3D { + /** + * Point with the coordinate (1, 1, 1). + */ + public static final Vec3D UNIT_MAX = new Vec3D(1, 1, 1); + + /** X coordinate. */ + public final double x; + /** Y coordinate. */ + public final double y; + /** Z coordinate. */ + public final double z; + + /** + * Creates a new vector with the given coordinates. + * @param x the x + * @param y the y + * @param z the z + */ + public Vec3D(double x, double y, double z) { + this.x = x; + this.y = y; + this.z = z; + } + + /** + * Creates a new vector with the coordinates of the given vector. + * @param v vector to copy. + */ + public Vec3D(Vec3D v) { + this.x = v.x; + this.y = v.y; + this.z = v.z; + } + + /** + * Construct a vector from a Bukkit location. + * @param loc - the Bukkit location. + */ + public static Vec3D fromLocation(Location loc) { + return new Vec3D(loc.getX(), loc.getY(), loc.getZ()); + } + + /** + * Construct a copy of our immutable vector from Bukkit's mutable vector. + * @param v - Bukkit vector. + * @return A copy of the given vector. + */ + public static Vec3D fromVector(Vector v) { + return new Vec3D(v.getX(), v.getY(), v.getZ()); + } + + /** + * Add vector v and returns result as new vector. + * + * @param v vector to add + * @return result as new vector + */ + public final Vec3D add(Vec3D v) { + return new Vec3D(x + v.x, y + v.y, z + v.z); + } + + /** + * Scales vector uniformly and returns result as new vector. + * + * @param s scale factor + * + * @return new vector + */ + public Vec3D scale(double s) { + return new Vec3D(x * s, y * s, z * s); + } + + /** + * Normalizes the vector so that its magnitude = 1. + * @return The normalized vector. + */ + public Vec3D normalize() { + double mag = Math.sqrt(x * x + y * y + z * z); + + if (mag > 0) + return scale(1.0 / mag); + return this; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Vec3D) { + final Vec3D v = (Vec3D) obj; + return x == v.x && y == v.y && z == v.z; + } + return false; + } + + @Override + public int hashCode() { + return Objects.hashCode(x, y, z); + } + + public String toString() { + return String.format("{x: %g, y: %g, z: %g}", x, y, z); + } + } + + public static class Ray3D extends Vec3D { + public final Vec3D dir; + + public Ray3D(Vec3D origin, Vec3D direction) { + super(origin); + dir = direction.normalize(); + } + + /** + * Construct a 3D ray from a location. + * @param loc - the Bukkit location. + */ + public Ray3D(Location loc) { + this(Vec3D.fromLocation(loc), Vec3D.fromVector(loc.getDirection())); + } + + public Vec3D getDirection() { + return dir; + } + + public Vec3D getPointAtDistance(double dist) { + return add(dir.scale(dist)); + } + + public String toString() { + return "origin: " + super.toString() + " dir: " + dir; + } + } + + private Vec3D max; + private Vec3D min; + + /** + * Creates a new instance from a minimum point and a maximum point. + */ + public AABB(Vec3D min, Vec3D max) { + this.min = min; + this.max = max; + } + + /** + * Create a new AABB from a given block. + * @param block - the block. + */ + public AABB(Location block) { + this(Vec3D.fromLocation(block), Vec3D.fromLocation(block).add(Vec3D.UNIT_MAX)); + } + + public Vec3D getMax() { return max; } + public Vec3D getMin() { return min; } + + public void expand(double expand) { + min = min.add(new Vec3D(-expand, -expand, -expand)); + max = max.add(new Vec3D(expand, expand, expand)); + } + + /** + * Calculates intersection with the given ray between a certain distance + * interval. + *

+ * Ray-box intersection is using IEEE numerical properties to ensure the + * test is both robust and efficient, as described in: + *
+ * Amy Williams, Steve Barrus, R. Keith Morley, and Peter Shirley: "An + * Efficient and Robust Ray-Box Intersection Algorithm" Journal of graphics + * tools, 10(1):49-54, 2005 + * + * @param ray incident ray + * @param minDist + * @param maxDist + * @return intersection point on the bounding box (only the first is + * returned) or null if no intersection + */ + public Vec3D intersectsRay(Ray3D ray, float minDist, double maxDist) { + Vec3D invDir = new Vec3D(1f / ray.dir.x, 1f / ray.dir.y, 1f / ray.dir.z); + + boolean signDirX = invDir.x < 0; + boolean signDirY = invDir.y < 0; + boolean signDirZ = invDir.z < 0; + + Vec3D bbox = signDirX ? max : min; + double tmin = (bbox.x - ray.x) * invDir.x; + bbox = signDirX ? min : max; + double tmax = (bbox.x - ray.x) * invDir.x; + bbox = signDirY ? max : min; + double tymin = (bbox.y - ray.y) * invDir.y; + bbox = signDirY ? min : max; + double tymax = (bbox.y - ray.y) * invDir.y; + + if ((tmin > tymax) || (tymin > tmax)) { + return null; + } + if (tymin > tmin) { + tmin = tymin; + } + if (tymax < tmax) { + tmax = tymax; + } + + bbox = signDirZ ? max : min; + double tzmin = (bbox.z - ray.z) * invDir.z; + bbox = signDirZ ? min : max; + double tzmax = (bbox.z - ray.z) * invDir.z; + + if ((tmin > tzmax) || (tzmin > tmax)) { + return null; + } + if (tzmin > tmin) { + tmin = tzmin; + } + if (tzmax < tmax) { + tmax = tzmax; + } + if ((tmin < maxDist) && (tmax > minDist)) { + return ray.getPointAtDistance(tmin); + } + return null; + } +} \ No newline at end of file diff --git a/src/main/java/com/sucy/skill/api/TargetHelper.java b/src/main/java/com/sucy/skill/api/target/TargetHelper.java similarity index 77% rename from src/main/java/com/sucy/skill/api/TargetHelper.java rename to src/main/java/com/sucy/skill/api/target/TargetHelper.java index f64cf953..dfe6f771 100644 --- a/src/main/java/com/sucy/skill/api/TargetHelper.java +++ b/src/main/java/com/sucy/skill/api/target/TargetHelper.java @@ -1,15 +1,22 @@ -package com.sucy.skill.api; +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.Particle; 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 @@ -44,28 +51,28 @@ public static List getLivingTargets(LivingEntity source, double ra public static List getLivingTargets(LivingEntity source, double range, double tolerance) { List list = source.getNearbyEntities(range, range, range); - List targets = new ArrayList<>(); + TreeMap targets = new TreeMap<>(); - Location sourceLocation = source.getEyeLocation(); - Vector facing = sourceLocation.getDirection(); - double fLengthSq = facing.lengthSquared(); + 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; - Vector relative = entity.getLocation().clone().add(0,entity.getBoundingBox().getHeight()*0.5,0).subtract(sourceLocation).toVector(); - double dot = relative.dot(facing); - double rLengthSq = relative.lengthSquared(); - double cosSquared = (dot * dot) / (rLengthSq * fLengthSq); - double sinSquared = 1 - cosSquared; - double dSquared = rLengthSq * sinSquared; - - // If close enough to vision line, return the entity - if (dSquared < tolerance) targets.add((LivingEntity) entity); + AABB aabb = getAABB(entity); + aabb.expand(tolerance); + AABB.Vec3D min = aabb.getMin(); + AABB.Vec3D max = aabb.getMax(); + entity.getWorld().spawnParticle(Particle.CRIT,min.x, min.y, min.z,1,0,0,0,0,null); + entity.getWorld().spawnParticle(Particle.CRIT,max.x, max.y, max.z,1,0,0,0,0,null); + 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 targets; + return new ArrayList<>(targets.values()); } /** @@ -96,19 +103,7 @@ public static LivingEntity getLivingTarget(LivingEntity source, double range, do { List targets = getLivingTargets(source, range, tolerance); if (targets.size() == 0) return null; - Location sourceLocation = source.getEyeLocation(); - LivingEntity target = targets.get(0); - double minDistance = target.getLocation().clone().add(0,target.getBoundingBox().getHeight()*0.5,0).distanceSquared(sourceLocation); - for (LivingEntity entity : targets) - { - double distance = entity.getLocation().distanceSquared(sourceLocation); - if (distance < minDistance) - { - minDistance = distance; - target = entity; - } - } - return target; + return targets.get(0); } /** @@ -148,7 +143,7 @@ public static List getConeTargets(LivingEntity source, double arc, // Otherwise, select targets based on dot product else { - Vector relative = entity.getLocation().clone().add(0,entity.getBoundingBox().getHeight()*0.5,0).subtract(sourceLocation).toVector(); + 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(); @@ -174,7 +169,7 @@ public static boolean isInFront(Entity entity, Entity target) // Get the necessary vectors Vector facing = entity.getLocation().getDirection(); - Vector relative = target.getLocation().clone().add(0,target.getBoundingBox().getHeight()*0.5,0).subtract(entity.getLocation()).toVector(); + Vector relative = target.getLocation().clone().add(0,getHeight(entity)*0.5,0).subtract(entity.getLocation()).toVector(); // If the dot product is positive, the target is in front return facing.dot(relative) >= 0; @@ -197,7 +192,7 @@ public static boolean isInFront(Entity entity, Entity target, double angle) // Get the necessary data double dotTarget = Math.cos(angle); Vector facing = entity.getLocation().getDirection(); - Vector relative = target.getLocation().clone().add(0,target.getBoundingBox().getHeight()*0.5,0).subtract(entity.getLocation()).toVector().normalize(); + 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; @@ -233,7 +228,7 @@ public static boolean isBehind(Entity entity, Entity target, double angle) // Get the necessary data double dotTarget = Math.cos(angle); Vector facing = entity.getLocation().getDirection(); - Vector relative = entity.getLocation().clone().add(0,entity.getBoundingBox().getHeight()*0.5,0).subtract(target.getLocation()).toVector().normalize(); + Vector relative = entity.getLocation().clone().add(0,getHeight(entity)*0.5,0).subtract(target.getLocation()).toVector().normalize(); // Compare the target dot product and the actual result return facing.dot(relative) >= dotTarget; @@ -321,4 +316,20 @@ public static Location getOpenLocation(Location loc1, Location loc2, boolean thr return temp; } } + + 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(); + } } \ No newline at end of file diff --git a/src/main/java/com/sucy/skill/api/util/Nearby.java b/src/main/java/com/sucy/skill/api/util/Nearby.java index 4f8a2661..9aa8323b 100644 --- a/src/main/java/com/sucy/skill/api/util/Nearby.java +++ b/src/main/java/com/sucy/skill/api/util/Nearby.java @@ -32,6 +32,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.TreeMap; /** * Fetches nearby entities by going through possible chunks @@ -80,7 +81,7 @@ public static List getLivingNearby(Location loc, double radius) { } private static List getLivingNearby(Entity source, Location loc, double radius) { - List result = new ArrayList(); + TreeMap result = new TreeMap<>(); int minX = (int) (loc.getX() - radius) >> 4; int maxX = (int) (loc.getX() + radius) >> 4; @@ -96,9 +97,9 @@ private static List getLivingNearby(Entity source, Location loc, d && entity instanceof LivingEntity && entity.getWorld() == loc.getWorld() && entity.getLocation().distanceSquared(loc) < radius) - result.add((LivingEntity) entity); + result.put(entity.getLocation().distance(loc), (LivingEntity) entity); - return result; + return new ArrayList<>(result.values()); } /** diff --git a/src/main/java/com/sucy/skill/data/Settings.java b/src/main/java/com/sucy/skill/data/Settings.java index d90a2c65..c128c384 100644 --- a/src/main/java/com/sucy/skill/data/Settings.java +++ b/src/main/java/com/sucy/skill/data/Settings.java @@ -45,6 +45,7 @@ import com.sucy.skill.data.formula.value.CustomValue; import com.sucy.skill.dynamic.DynamicSkill; import com.sucy.skill.gui.tool.GUITool; +import com.sucy.skill.hook.PluginChecker; import com.sucy.skill.log.Logger; import org.bukkit.Material; import org.bukkit.World; @@ -67,6 +68,7 @@ public class Settings { private DataSection config; private boolean OLD_DURABILITY; + private boolean BOUNDING_BOX; /** *

Initializes a new settings manager.

@@ -97,6 +99,12 @@ public void reload() { } catch (ClassNotFoundException e) { OLD_DURABILITY = true; } + try { + Entity.class.getMethod("getBoundingBox"); + BOUNDING_BOX = true; + } catch (NoSuchMethodException e) { + BOUNDING_BOX = false; + } loadExperienceSettings(); loadAccountSettings(); @@ -117,6 +125,7 @@ public void reload() { } public boolean useOldDurability() { return OLD_DURABILITY; } + public boolean useBoundingBoxes() { return BOUNDING_BOX; } /////////////////////////////////////////////////////// // // @@ -371,7 +380,7 @@ public boolean canAttack(LivingEntity attacker, LivingEntity target) { } else if (target instanceof Player) { if (playerAlly || playerWorlds.contains(attacker.getWorld().getName())) { return false; } - if (partiesAlly) { + if (PluginChecker.isPartiesActive() && partiesAlly) { final Parties parties = Parties.getPlugin(Parties.class); final Party p1 = parties.getJoinedParty(player); final Party p2 = parties.getJoinedParty((Player) target); diff --git a/src/main/java/com/sucy/skill/dynamic/EffectComponent.java b/src/main/java/com/sucy/skill/dynamic/EffectComponent.java index a5148512..57a83f40 100644 --- a/src/main/java/com/sucy/skill/dynamic/EffectComponent.java +++ b/src/main/java/com/sucy/skill/dynamic/EffectComponent.java @@ -300,6 +300,11 @@ private static String filterSpecialChars(String string) { builder.append('{'); i = j+3; break; + case "sq": + builder.append(string, i, j); + builder.append('\''); + i = j+3; + break; } j = string.indexOf('&',i); } diff --git a/src/main/java/com/sucy/skill/dynamic/TempEntity.java b/src/main/java/com/sucy/skill/dynamic/TempEntity.java index 1ef2e650..1e50cbdc 100644 --- a/src/main/java/com/sucy/skill/dynamic/TempEntity.java +++ b/src/main/java/com/sucy/skill/dynamic/TempEntity.java @@ -166,13 +166,23 @@ public void setMaximumAir(int i) { } + @Override + public int getArrowCooldown() { return 0; } + + @Override + public void setArrowCooldown(int ticks) {} + + @Override + public int getArrowsInBody() { return 0; } + + @Override + public void setArrowsInBody(int count) {} + public int getMaximumNoDamageTicks() { return 0; } - public void setMaximumNoDamageTicks(int i) { - - } + public void setMaximumNoDamageTicks(int i) {} public double getLastDamage() { return 0; @@ -182,21 +192,15 @@ public int _INVALID_getLastDamage() { return 0; } - public void setLastDamage(double v) { - - } + public void setLastDamage(double v) {} - public void _INVALID_setLastDamage(int i) { - - } + public void _INVALID_setLastDamage(int i) {} public int getNoDamageTicks() { return 0; } - public void setNoDamageTicks(int i) { - - } + public void setNoDamageTicks(int i) {} public Player getKiller() { return null; @@ -404,31 +408,33 @@ public boolean isCollidable() { return false; } + @Override + public @NotNull Set getCollidableExemptions() { return null; } + @Override public @Nullable T getMemory(@NotNull MemoryKey memoryKey) { return null; } @Override - public void setMemory(@NotNull MemoryKey memoryKey, @Nullable T memoryValue) { - - } - - public void damage(double v) { + public void setMemory(@NotNull MemoryKey memoryKey, @Nullable T memoryValue) {} - } + @Override + public @NotNull EntityCategory getCategory() { return EntityCategory.NONE; } - public void _INVALID_damage(int i) { + @Override + public void setInvisible(boolean invisible) {} - } + @Override + public boolean isInvisible() { return true; } - public void damage(double v, Entity entity) { + public void damage(double v) {} - } + public void _INVALID_damage(int i) {} - public void _INVALID_damage(int i, Entity entity) { + public void damage(double v, Entity entity) {} - } + public void _INVALID_damage(int i, Entity entity) {} public double getHealth() { return 1; @@ -438,9 +444,7 @@ public int _INVALID_getHealth() { return 0; } - public void setHealth(double v) { - - } + public void setHealth(double v) {} @Override public double getAbsorptionAmount() { @@ -448,13 +452,9 @@ public double getAbsorptionAmount() { } @Override - public void setAbsorptionAmount(double v) { + public void setAbsorptionAmount(double v) {} - } - - public void _INVALID_setHealth(int i) { - - } + public void _INVALID_setHealth(int i) {} public double getMaxHealth() { return 1; @@ -464,17 +464,11 @@ public int _INVALID_getMaxHealth() { return 0; } - public void setMaxHealth(double v) { + public void setMaxHealth(double v) {} - } - - public void _INVALID_setMaxHealth(int i) { - - } + public void _INVALID_setMaxHealth(int i) {} - public void resetMaxHealth() { - - } + public void resetMaxHealth() {} public Location getLocation() { return target.getLocation().clone(); @@ -491,9 +485,7 @@ public Location getLocation(final Location location) { return location; } - public void setVelocity(Vector vector) { - - } + public void setVelocity(Vector vector) {} public Vector getVelocity() { return new Vector(0, 0, 0); @@ -521,9 +513,7 @@ public World getWorld() { } @Override - public void setRotation(float yaw, float pitch) { - - } + public void setRotation(float yaw, float pitch) {} public boolean teleport(Location location) { target = new FixedTarget(location); @@ -561,13 +551,9 @@ public int getMaxFireTicks() { return 0; } - public void setFireTicks(int i) { + public void setFireTicks(int i) {} - } - - public void remove() { - - } + public void remove() {} public boolean isDead() { return false; @@ -577,13 +563,15 @@ public boolean isValid() { return true; } - public void sendMessage(String s) { + public void sendMessage(String s) {} - } + public void sendMessage(String[] strings) {} - public void sendMessage(String[] strings) { + @Override + public void sendMessage(@Nullable UUID sender, @NotNull String message) {} - } + @Override + public void sendMessage(@Nullable UUID sender, @NotNull String[] messages) {} public Server getServer() { return Bukkit.getServer(); @@ -595,9 +583,7 @@ public boolean isPersistent() { } @Override - public void setPersistent(boolean persistent) { - - } + public void setPersistent(boolean persistent) {} public String getName() { return "Location"; @@ -639,9 +625,7 @@ public void setFallDistance(float v) { } - public void setLastDamageCause(EntityDamageEvent entityDamageEvent) { - - } + public void setLastDamageCause(EntityDamageEvent entityDamageEvent) {} public EntityDamageEvent getLastDamageCause() { return null; @@ -655,12 +639,9 @@ public int getTicksLived() { return 0; } - public void setTicksLived(int i) { + public void setTicksLived(int i) {} - } - - public void playEffect(EntityEffect entityEffect) { - } + public void playEffect(EntityEffect entityEffect) {} public EntityType getType() { return EntityType.CHICKEN; diff --git a/src/main/java/com/sucy/skill/dynamic/condition/DirectionCondition.java b/src/main/java/com/sucy/skill/dynamic/condition/DirectionCondition.java index 1754c5d4..2c1a0713 100644 --- a/src/main/java/com/sucy/skill/dynamic/condition/DirectionCondition.java +++ b/src/main/java/com/sucy/skill/dynamic/condition/DirectionCondition.java @@ -27,7 +27,7 @@ package com.sucy.skill.dynamic.condition; import com.rit.sucy.config.parse.DataSection; -import com.sucy.skill.api.TargetHelper; +import com.sucy.skill.api.target.TargetHelper; import com.sucy.skill.dynamic.DynamicSkill; import org.bukkit.entity.LivingEntity; diff --git a/src/main/java/com/sucy/skill/dynamic/mechanic/CommandMechanic.java b/src/main/java/com/sucy/skill/dynamic/mechanic/CommandMechanic.java index cd934432..98255c56 100644 --- a/src/main/java/com/sucy/skill/dynamic/mechanic/CommandMechanic.java +++ b/src/main/java/com/sucy/skill/dynamic/mechanic/CommandMechanic.java @@ -43,6 +43,7 @@ import java.util.List; import java.util.Set; +import java.util.UUID; /** * Executes a command for each target @@ -112,6 +113,9 @@ private static class SilentConsoleCommandSender implements ConsoleCommandSender @Override public void sendRawMessage(String paramString) {} + @Override + public void sendRawMessage(@Nullable UUID sender, @NotNull String message) {} + @Override public boolean isConversing() { return false; @@ -189,6 +193,12 @@ public PermissionAttachment addAttachment(Plugin paramPlugin, String paramString @Override public void sendMessage(String[] paramArrayOfString) {} + @Override + public void sendMessage(@Nullable UUID sender, @NotNull String message) {} + + @Override + public void sendMessage(@Nullable UUID sender, @NotNull String[] messages) { } + @Override public void sendMessage(String paramString) {} diff --git a/src/main/java/com/sucy/skill/dynamic/mechanic/WarpMechanic.java b/src/main/java/com/sucy/skill/dynamic/mechanic/WarpMechanic.java index 5da33c24..5cee6482 100644 --- a/src/main/java/com/sucy/skill/dynamic/mechanic/WarpMechanic.java +++ b/src/main/java/com/sucy/skill/dynamic/mechanic/WarpMechanic.java @@ -26,7 +26,7 @@ */ package com.sucy.skill.dynamic.mechanic; -import com.sucy.skill.api.TargetHelper; +import com.sucy.skill.api.target.TargetHelper; import org.bukkit.Location; import org.bukkit.block.BlockFace; import org.bukkit.entity.LivingEntity; diff --git a/src/main/java/com/sucy/skill/dynamic/mechanic/WarpRandomMechanic.java b/src/main/java/com/sucy/skill/dynamic/mechanic/WarpRandomMechanic.java index 3afb81d6..3c0473fa 100644 --- a/src/main/java/com/sucy/skill/dynamic/mechanic/WarpRandomMechanic.java +++ b/src/main/java/com/sucy/skill/dynamic/mechanic/WarpRandomMechanic.java @@ -26,7 +26,7 @@ */ package com.sucy.skill.dynamic.mechanic; -import com.sucy.skill.api.TargetHelper; +import com.sucy.skill.api.target.TargetHelper; import org.bukkit.Location; import org.bukkit.block.BlockFace; import org.bukkit.entity.LivingEntity; diff --git a/src/main/java/com/sucy/skill/dynamic/target/AreaTarget.java b/src/main/java/com/sucy/skill/dynamic/target/AreaTarget.java index c52b8d72..c83a62b6 100644 --- a/src/main/java/com/sucy/skill/dynamic/target/AreaTarget.java +++ b/src/main/java/com/sucy/skill/dynamic/target/AreaTarget.java @@ -52,7 +52,7 @@ List getTargets( final double radius = parseValues(caster, RADIUS, level, 3.0); final boolean random = settings.getBool(RANDOM, false); - return determineTargets(caster, level, targets, t -> shuffle(Nearby.getLivingNearby(t.getLocation(), radius), random)); + return determineTargets(caster, level, targets, t -> shuffle(Nearby.getLivingNearby(caster, radius), random)); } /** {@inheritDoc} */ diff --git a/src/main/java/com/sucy/skill/dynamic/target/ConeTarget.java b/src/main/java/com/sucy/skill/dynamic/target/ConeTarget.java index 7852fbb5..05782d67 100644 --- a/src/main/java/com/sucy/skill/dynamic/target/ConeTarget.java +++ b/src/main/java/com/sucy/skill/dynamic/target/ConeTarget.java @@ -26,7 +26,7 @@ */ package com.sucy.skill.dynamic.target; -import com.sucy.skill.api.TargetHelper; +import com.sucy.skill.api.target.TargetHelper; import com.sucy.skill.cast.IIndicator; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; diff --git a/src/main/java/com/sucy/skill/dynamic/target/LinearTarget.java b/src/main/java/com/sucy/skill/dynamic/target/LinearTarget.java index 340c7262..c3636161 100644 --- a/src/main/java/com/sucy/skill/dynamic/target/LinearTarget.java +++ b/src/main/java/com/sucy/skill/dynamic/target/LinearTarget.java @@ -26,7 +26,7 @@ */ package com.sucy.skill.dynamic.target; -import com.sucy.skill.api.TargetHelper; +import com.sucy.skill.api.target.TargetHelper; import com.sucy.skill.cast.IIndicator; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; diff --git a/src/main/java/com/sucy/skill/dynamic/target/LocationTarget.java b/src/main/java/com/sucy/skill/dynamic/target/LocationTarget.java index 43e43eda..14dc9d62 100644 --- a/src/main/java/com/sucy/skill/dynamic/target/LocationTarget.java +++ b/src/main/java/com/sucy/skill/dynamic/target/LocationTarget.java @@ -27,7 +27,7 @@ package com.sucy.skill.dynamic.target; import com.google.common.collect.ImmutableList; -import com.sucy.skill.api.TargetHelper; +import com.sucy.skill.api.target.TargetHelper; import com.sucy.skill.cast.IIndicator; import com.sucy.skill.dynamic.TempEntity; import org.bukkit.Location; diff --git a/src/main/java/com/sucy/skill/dynamic/target/SingleTarget.java b/src/main/java/com/sucy/skill/dynamic/target/SingleTarget.java index 077dbd78..ecc995f2 100644 --- a/src/main/java/com/sucy/skill/dynamic/target/SingleTarget.java +++ b/src/main/java/com/sucy/skill/dynamic/target/SingleTarget.java @@ -27,7 +27,7 @@ package com.sucy.skill.dynamic.target; import com.google.common.collect.ImmutableList; -import com.sucy.skill.api.TargetHelper; +import com.sucy.skill.api.target.TargetHelper; import com.sucy.skill.cast.IIndicator; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; diff --git a/src/main/java/com/sucy/skill/dynamic/target/TargetComponent.java b/src/main/java/com/sucy/skill/dynamic/target/TargetComponent.java index ddc4615c..6bb8f744 100644 --- a/src/main/java/com/sucy/skill/dynamic/target/TargetComponent.java +++ b/src/main/java/com/sucy/skill/dynamic/target/TargetComponent.java @@ -1,13 +1,9 @@ package com.sucy.skill.dynamic.target; import com.rit.sucy.config.parse.DataSection; -import com.sucy.skill.api.TargetHelper; import com.sucy.skill.SkillAPI; -import com.sucy.skill.cast.CircleIndicator; -import com.sucy.skill.cast.ConeIndicator; -import com.sucy.skill.cast.IIndicator; -import com.sucy.skill.cast.IndicatorType; -import com.sucy.skill.cast.SphereIndicator; +import com.sucy.skill.api.target.TargetHelper; +import com.sucy.skill.cast.*; import com.sucy.skill.dynamic.ComponentType; import com.sucy.skill.dynamic.DynamicSkill; import com.sucy.skill.dynamic.EffectComponent; @@ -131,15 +127,14 @@ List determineTargets( final List list = new ArrayList<>(); from.forEach(target -> { - final int count = list.size(); final List found = conversion.apply(target); + int count = 0; + for (LivingEntity entity : found) { - if (isValidTarget(caster, target, entity)) { - list.add(entity); - if (list.size() - count >= max) { - break; - } - } + if (count >= max) break; + if (!isValidTarget(caster, target, entity)) continue; + list.add(found.get(count)); + count++; } }); if (self) { diff --git a/src/main/java/com/sucy/skill/hook/DisguiseHook.java b/src/main/java/com/sucy/skill/hook/DisguiseHook.java index 4053e587..4a221963 100644 --- a/src/main/java/com/sucy/skill/hook/DisguiseHook.java +++ b/src/main/java/com/sucy/skill/hook/DisguiseHook.java @@ -29,7 +29,13 @@ import com.sucy.skill.log.Logger; import me.libraryaddict.disguise.DisguiseAPI; import me.libraryaddict.disguise.disguisetypes.*; +import me.libraryaddict.disguise.disguisetypes.watchers.ArmorStandWatcher; +import me.libraryaddict.disguise.disguisetypes.watchers.SlimeWatcher; +import me.libraryaddict.disguise.utilities.DisguiseValues; +import me.libraryaddict.disguise.utilities.reflection.FakeBoundingBox; +import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; /** * Handles calling functions from Lib's Disguise @@ -116,4 +122,42 @@ public static void removeDisguise(LivingEntity target) for (Disguise disguise : DisguiseAPI.getDisguises(target)) disguise.removeDisguise(); } + + public static FakeBoundingBox getFakeBoundingBox(Entity entity) { + Disguise disguise = DisguiseAPI.getDisguise(entity); + if (disguise instanceof MiscDisguise) { + DisguiseValues values = DisguiseValues.getDisguiseValues(disguise.getType()); + if (values == null) return null; + else return values.getAdultBox(); + } else if (disguise instanceof MobDisguise) { + MobDisguise mobDisguise = (MobDisguise) disguise; + DisguiseValues values = DisguiseValues.getDisguiseValues(mobDisguise.getType()); + if (values != null && values.getAdultBox() != null) { + if (!mobDisguise.isAdult() && values.getBabyBox() != null) { + return values.getBabyBox(); + } else { + if (mobDisguise.getWatcher() != null) { + if (mobDisguise.getType() == DisguiseType.ARMOR_STAND) { + return (((ArmorStandWatcher)mobDisguise.getWatcher()).isSmall() ? values.getBabyBox() : values.getAdultBox()); + } + + if (mobDisguise.getType() == DisguiseType.SLIME || mobDisguise.getType() == DisguiseType.MAGMA_CUBE) { + double a = 0.51D * 0.255D * (double)((SlimeWatcher)mobDisguise.getWatcher()).getSize(); + return new FakeBoundingBox(a, a, a); + } + } + return values.getAdultBox(); + } + } else { return null; } + } else if (disguise instanceof ModdedDisguise) { return null; + } else if (disguise instanceof PlayerDisguise) { + if (disguise.getWatcher() == null) { + return new FakeBoundingBox(0.6, 0.6, 1.8); + } else if (disguise.getEntity() != null && !disguise.getWatcher().getModifiedEntityAnimations()[1]) { + return disguise.getEntity() instanceof Player && ((Player)disguise.getEntity()).isSneaking() ? new FakeBoundingBox(0.6, 0.6, 1.5) : new FakeBoundingBox(0.6, 0.6, 1.8); + } else { + return disguise.getWatcher().isSneaking() ? new FakeBoundingBox(0.6, 0.6, 1.5) : new FakeBoundingBox(0.6, 0.6, 1.8); + } + } else return null; + } } diff --git a/src/main/java/com/sucy/skill/hook/PluginChecker.java b/src/main/java/com/sucy/skill/hook/PluginChecker.java index 0792067d..77d1ff2b 100644 --- a/src/main/java/com/sucy/skill/hook/PluginChecker.java +++ b/src/main/java/com/sucy/skill/hook/PluginChecker.java @@ -26,81 +26,146 @@ */ package com.sucy.skill.hook; +import com.sucy.skill.listener.SkillAPIListener; import org.bukkit.Bukkit; +import org.bukkit.event.EventHandler; +import org.bukkit.event.server.PluginDisableEvent; +import org.bukkit.event.server.PluginEnableEvent; +import org.bukkit.plugin.PluginManager; /** * Handler for checking whether or not hooked plugins are present * and active before using related code. */ -public class PluginChecker -{ +public class PluginChecker extends SkillAPIListener { + private static boolean vault; + private static boolean libsDisguises; + private static boolean noCheatPlus; + private static boolean rpgInventory; + private static boolean papi; + private static boolean bungee; + private static boolean mythicMobs; + private static boolean worldGuard; + private static boolean parties; + + @Override + public void init() { + PluginManager pluginManager = Bukkit.getPluginManager(); + + vault = pluginManager.isPluginEnabled("Vault") && VaultHook.isValid(); + libsDisguises = pluginManager.isPluginEnabled("LibsDisguises"); + noCheatPlus = pluginManager.isPluginEnabled("NoCheatPlus"); + rpgInventory = pluginManager.isPluginEnabled("RPGInventory"); + papi = pluginManager.isPluginEnabled("PlaceholderAPI"); + try { + Class.forName("net.md_5.bungee.Util"); + bungee = true; + } catch (Exception ex) { bungee = false; } + mythicMobs = pluginManager.isPluginEnabled("MythicMobs"); + worldGuard = pluginManager.isPluginEnabled("WorldGuard"); + parties = pluginManager.isPluginEnabled("Parties"); + } + + @EventHandler + public void onPluginEnable(PluginEnableEvent event) { + switch (event.getPlugin().getName()) { + case "Vault": + vault = true; + break; + case "LibsDisguises": + libsDisguises = true; + break; + case "NoCheatPlus": + noCheatPlus = true; + break; + case "RPGInventory": + rpgInventory = true; + break; + case "PlaceholderAPI": + papi = true; + break; + case "MythicMobs": + mythicMobs = true; + break; + case "WorldGuard": + worldGuard = true; + break; + case "Parties": + parties = true; + break; + } + } + + @EventHandler + public void onPluginDisable(PluginDisableEvent event) { + switch (event.getPlugin().getName()) { + case "Vault": + vault = false; + break; + case "LibsDisguises": + libsDisguises = false; + break; + case "NoCheatPlus": + noCheatPlus = false; + break; + case "RPGInventory": + rpgInventory = false; + break; + case "PlaceholderAPI": + papi = true; + break; + case "MythicMobs": + mythicMobs = false; + break; + case "WorldGuard": + worldGuard = false; + break; + case "Parties": + parties = false; + break; + } + } + /** * Checks if vault is active on the server * * @return true if active with permissions plugin, false otherwise */ - public static boolean isVaultActive() - { - return Bukkit.getPluginManager().isPluginEnabled("Vault") && VaultHook.isValid(); - } + public static boolean isVaultActive() { return vault; } /** * Checks whether or not Lib's Disguises is active * * @return true if active */ - public static boolean isDisguiseActive() - { - return Bukkit.getPluginManager().isPluginEnabled("LibsDisguises"); - } + public static boolean isDisguiseActive() { return libsDisguises; } /** * Checks whether or not NoCheatPlus is active on the server * * @return true if active, false otherwise */ - public static boolean isNoCheatActive() - { - return Bukkit.getPluginManager().isPluginEnabled("NoCheatPlus"); - } + public static boolean isNoCheatActive() { return noCheatPlus; } /** * Checks whether or not RPGInventory is active on the server * * @return true if active, false otherwise */ - public static boolean isRPGInventoryActive() - { - return Bukkit.getPluginManager().isPluginEnabled("RPGInventory"); - } + public static boolean isRPGInventoryActive() { return rpgInventory; } - public static boolean isPlaceholderAPIActive() { - return Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI"); - } + public static boolean isPlaceholderAPIActive() { return papi; } /** * Checks whether or not bungee is present * * @return true if present, false otherwise */ - public static boolean isBungeeActive() - { - try - { - Class.forName("net.md_5.bungee.Util"); - return true; - } - catch (Exception ex) - { - return false; - } - } + public static boolean isBungeeActive() { return bungee; } - public static boolean isMythicMobsActive() { - return Bukkit.getPluginManager().isPluginEnabled("MythicMobs"); - } + public static boolean isMythicMobsActive() { return mythicMobs; } - public static boolean isWorldGuardActive() { - return Bukkit.getPluginManager().isPluginEnabled("WorldGuard"); - } + public static boolean isWorldGuardActive() { return worldGuard; } + + public static boolean isPartiesActive() { return parties; } } diff --git a/src/main/java/com/sucy/skill/hook/WorldGuardHook.java b/src/main/java/com/sucy/skill/hook/WorldGuardHook.java index ed34e1dc..4b424b73 100644 --- a/src/main/java/com/sucy/skill/hook/WorldGuardHook.java +++ b/src/main/java/com/sucy/skill/hook/WorldGuardHook.java @@ -1,8 +1,8 @@ package com.sucy.skill.hook; import com.google.common.collect.ImmutableList; -import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldguard.WorldGuard; import com.sk89q.worldguard.bukkit.WorldGuardPlugin; import com.sk89q.worldguard.protection.managers.RegionManager; @@ -10,6 +10,7 @@ import org.bukkit.Location; import org.bukkit.World; +import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.List; @@ -21,6 +22,10 @@ public class WorldGuardHook { private static Method regionMethod; + private static Class vectorClass; + private static Constructor vectorConstructor; + private static Method applicableRegionsMethod; + /** * Fetches the list of region IDs applicable to a given location * @@ -33,21 +38,26 @@ public static List getRegionIds(final Location loc) { .getPlatform() .getRegionContainer() .get(BukkitAdapter.adapt(loc.getWorld())) - .getApplicableRegionsIDs(asVector(loc)); + .getApplicableRegionsIDs(BlockVector3.at(loc.getX(), loc.getY(),loc.getZ())); } catch (NoClassDefFoundError ex) { try { final WorldGuardPlugin plugin = SkillAPI.getPlugin(WorldGuardPlugin.class); - return ((RegionManager) getRegionMethod().invoke(plugin, loc.getWorld())) - .getApplicableRegionsIDs(asVector(loc)); + return (List) getApplicableRegionsMethod().invoke((getRegionMethod().invoke(plugin, loc.getWorld())), vectorConstructor.newInstance(loc.getX(), loc.getY(),loc.getZ())); } catch (final Exception e) { // Cannot handle world guard + e.printStackTrace(); return ImmutableList.of(); } } } - private static BlockVector3 asVector(final Location location) { - return BlockVector3.at(location.getX(), location.getY(),location.getZ()); + private static Method getApplicableRegionsMethod() throws Exception { + if (applicableRegionsMethod == null) { + vectorClass = Class.forName("com.sk89q.worldedit.Vector"); + vectorConstructor = vectorClass.getConstructor(double.class, double.class, double.class); + applicableRegionsMethod = RegionManager.class.getMethod("getApplicableRegionsIDs", vectorClass); + } + return applicableRegionsMethod; } private static Method getRegionMethod() throws Exception { diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 9bfeccf7..a080752a 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,11 +1,11 @@ name: SkillAPI main: com.sucy.skill.SkillAPI -version: s1.96 +version: s1.97 authors: [Eniripsa96, Sentropic] depend: [MCCore] softdepend: [Vault, ProtocolLib, Parties, RPGInventory, LibsDisguises, PlaceholderAPI, NoCheatPlus, MythicMobs, WorldGuard, WorldEdit] loadbefore: [Quests] -api-version: 1.15 +api-version: 1.16 permissions: skillapi.basic: