Search in sources :

Example 6 with HitBox

use of me.deecaad.weaponmechanics.weapon.projectile.HitBox in project MechanicsMain by WeaponMechanics.

the class WeaponProjectile method getHits.

private List<RayTraceResult> getHits(boolean disableEntityCollisions) {
    List<RayTraceResult> hits = null;
    Vector normalizedMotion = getNormalizedMotion();
    Vector location = getLocation();
    double distance = Math.ceil(getMotionLength());
    // If distance is 0 or below, it will cause issues
    if (NumberUtil.equals(distance, 0.0))
        distance = 1;
    BlockIterator blocks = new BlockIterator(getWorld(), location, normalizedMotion, 0.0, (int) distance);
    int maximumBlockHits = through == null ? 1 : through.getMaximumThroughAmount() + 1;
    while (blocks.hasNext()) {
        Block block = blocks.next();
        if (equalToLastHit(block))
            continue;
        HitBox blockBox = weaponCompatibility.getHitBox(block);
        if (blockBox == null)
            continue;
        RayTraceResult rayTraceResult = blockBox.rayTrace(location, normalizedMotion);
        // Didn't hit
        if (rayTraceResult == null)
            continue;
        if (hits == null)
            hits = new ArrayList<>(1);
        hits.add(rayTraceResult);
        // If through isn't used, it is enough to get one block hit
        if (through == null)
            break;
        // projectile can't go through blocks anymore after this one.
        if (--maximumBlockHits == 0)
            break;
        // If it isn't valid it can't go through
        if (!through.quickValidCheck(block.getType()))
            break;
    }
    if (!disableEntityCollisions) {
        List<LivingEntity> entities = getPossibleEntities();
        if (entities != null && !entities.isEmpty()) {
            for (LivingEntity entity : entities) {
                if (equalToLastHit(entity))
                    continue;
                HitBox entityBox = weaponCompatibility.getHitBox(entity);
                if (entityBox == null)
                    continue;
                RayTraceResult rayTraceResult = entityBox.rayTrace(location, normalizedMotion);
                // Didn't hit
                if (rayTraceResult == null)
                    continue;
                if (hits == null)
                    hits = new ArrayList<>(1);
                hits.add(rayTraceResult);
            }
        }
    }
    // Sort based on the distance travelled before hit if there is more than 1 hits
    if (hits != null && hits.size() > 1)
        hits.sort((hit1, hit2) -> (int) (hit1.getDistanceTravelled() - hit2.getDistanceTravelled()));
    return hits;
}
Also used : LivingEntity(org.bukkit.entity.LivingEntity) IWeaponCompatibility(me.deecaad.weaponmechanics.compatibility.IWeaponCompatibility) NumberUtil(me.deecaad.core.utils.NumberUtil) Entity(org.bukkit.entity.Entity) ProjectileEndEvent(me.deecaad.weaponmechanics.weapon.weaponevents.ProjectileEndEvent) VectorUtil(me.deecaad.core.utils.VectorUtil) HitBox(me.deecaad.weaponmechanics.weapon.projectile.HitBox) LivingEntity(org.bukkit.entity.LivingEntity) AProjectile(me.deecaad.weaponmechanics.weapon.projectile.AProjectile) ItemStack(org.bukkit.inventory.ItemStack) ArrayList(java.util.ArrayList) BlockIterator(org.bukkit.util.BlockIterator) Vector(org.bukkit.util.Vector) List(java.util.List) Block(org.bukkit.block.Block) Location(org.bukkit.Location) ThreadLocalRandom(java.util.concurrent.ThreadLocalRandom) Chunk(org.bukkit.Chunk) Nullable(javax.annotation.Nullable) WeaponCompatibilityAPI(me.deecaad.weaponmechanics.compatibility.WeaponCompatibilityAPI) Bukkit(org.bukkit.Bukkit) BlockIterator(org.bukkit.util.BlockIterator) HitBox(me.deecaad.weaponmechanics.weapon.projectile.HitBox) ArrayList(java.util.ArrayList) Block(org.bukkit.block.Block) Vector(org.bukkit.util.Vector)

Example 7 with HitBox

use of me.deecaad.weaponmechanics.weapon.projectile.HitBox in project MechanicsMain by WeaponMechanics.

the class Ray method getEntities.

public Map<Entity, HitBox> getEntities(TraceCollision collision) {
    // The number 2.0 is taken from Mojang's code. It is probably big
    // enough to include entities whose hit-box is within the bounds, but
    // their actual location is not in the box.
    Vector min = VectorUtil.add(VectorUtil.min(origin, end), -2.0, -2.0, -2.0);
    Vector max = VectorUtil.add(VectorUtil.max(origin, end), 2.0, 2.0, 2.0);
    int minChunkX = (int) Math.floor(min.getX() / 16.0);
    int minChunkZ = (int) Math.floor(min.getZ() / 16.0);
    int maxChunkX = (int) Math.ceil(max.getX() / 16.0);
    int maxChunkZ = (int) Math.ceil(max.getZ() / 16.0);
    // Using Map for O(1) lookup
    Map<Entity, HitBox> temp = new HashMap<>();
    // By reusing the same location, we stop spigot from instantiating a
    // new location every time we grab an entity's location. This probably
    // saves computing power.
    Location reuse = new Location(null, 0, 0, 0);
    for (int x = minChunkX; x <= maxChunkX; x++) {
        for (int z = minChunkZ; z <= maxChunkZ; z++) {
            Chunk chunk = world.getChunkAt(x, z);
            for (Entity entity : chunk.getEntities()) {
                if (contains(min, max, entity.getLocation(reuse)) && collision.canHit(entity)) {
                    temp.put(entity, WeaponCompatibilityAPI.getWeaponCompatibility().getHitBox(entity));
                }
            }
        }
    }
    return temp;
}
Also used : Entity(org.bukkit.entity.Entity) HitBox(me.deecaad.weaponmechanics.weapon.projectile.HitBox) HashMap(java.util.HashMap) Chunk(org.bukkit.Chunk) Vector(org.bukkit.util.Vector) Location(org.bukkit.Location)

Example 8 with HitBox

use of me.deecaad.weaponmechanics.weapon.projectile.HitBox in project MechanicsMain by WeaponMechanics.

the class Ray method trace.

/**
 * Traces along this ray, colliding with block(s) and/or entity(s), depending on the given
 * <code>collision</code>.
 *
 * @param collision What the ray collides with
 * @param accuracy  The distance (in blocks) between checks
 * @param isShow    Useful for debugging. Spawns redstone particles that are removed after 1 minute
 * @return The collision data
 */
public TraceResult trace(@Nonnull TraceCollision collision, @Nonnegative double accuracy, boolean isShow) {
    IWeaponCompatibility factory = WeaponCompatibilityAPI.getWeaponCompatibility();
    // Store the entities between the starting and ending point of the ray. Map the
    // entities to their hit box. If this ray is too long, this method becomes
    // inefficient -- Ideally rays should be kept to 25 blocks max
    Map<Entity, HitBox> availableEntities = collision.isHitEntity() ? getEntities(collision) : Collections.emptyMap();
    // can hit, then we can take a shortcut and return an empty trace result, saving resources
    if (!collision.isHitBlock() && availableEntities.isEmpty()) {
        return new TraceResult(Collections.emptySet(), Collections.emptySet());
    }
    final LinkedHashSet<Block> blocks = new LinkedHashSet<>();
    final LinkedHashSet<Entity> entities = new LinkedHashSet<>();
    // Step is a number [0.0, 1.0] that defines a percentage of distance
    // between our starting and stopping point. If step exceeds 1, that
    // means the Ray is shorter than the accuracy allows.
    double step = accuracy / directionLength;
    if (step > 1.0) {
        return new TraceResult(entities, blocks);
    }
    // We start i at step to skip the first trace step. Doing this will
    // help prevent explosion rays from being blocks by minor floating
    // point differences. See issue #26.
    boolean collides = false;
    for (double i = step; i <= 1; i += step) {
        Vector point = VectorUtil.lerp(origin, end, i);
        Block block = world.getBlockAt(point.getBlockX(), point.getBlockY(), point.getBlockZ());
        // if this specific block can be hit, and if we actually collide with the block's hitbox
        if (collision.isHitBlock() && collision.canHit(block) && contains(factory.getHitBox(block), point)) {
            blocks.add(block);
            collides = true;
        }
        // entity's hitbox
        for (Map.Entry<Entity, HitBox> entry : availableEntities.entrySet()) {
            Entity entity = entry.getKey();
            HitBox hitbox = entry.getValue();
            if (collision.isHitEntity() && collision.canHit(entity) && contains(hitbox, point)) {
                entities.add(entity);
                collides = true;
                if (collision.isFirst()) {
                    break;
                }
            }
        }
        // once, then break out of the loop
        if (collides && collision.isFirst()) {
            break;
        }
        // particle for each point.
        if (isShow) {
            displayPoint(point, collides);
        }
        collides = false;
    }
    return new TraceResult(entities, blocks);
}
Also used : LinkedHashSet(java.util.LinkedHashSet) Entity(org.bukkit.entity.Entity) HitBox(me.deecaad.weaponmechanics.weapon.projectile.HitBox) IWeaponCompatibility(me.deecaad.weaponmechanics.compatibility.IWeaponCompatibility) Block(org.bukkit.block.Block) Vector(org.bukkit.util.Vector) HashMap(java.util.HashMap) Map(java.util.Map)

Example 9 with HitBox

use of me.deecaad.weaponmechanics.weapon.projectile.HitBox in project MechanicsMain by WeaponMechanics.

the class MeleeHandler method getPossibleEntities.

private List<LivingEntity> getPossibleEntities(LivingEntity shooter, Location start, Vector end) {
    // Get the box of current location to end of this iteration
    HitBox hitBox = new HitBox(start.toVector(), end);
    int minX = floor((hitBox.getMinX() - 2.0D) / 16.0D);
    int maxX = floor((hitBox.getMaxX() + 2.0D) / 16.0D);
    int minZ = floor((hitBox.getMinZ() - 2.0D) / 16.0D);
    int maxZ = floor((hitBox.getMaxZ() + 2.0D) / 16.0D);
    List<LivingEntity> entities = new ArrayList<>(8);
    World world = start.getWorld();
    for (int x = minX; x <= maxX; ++x) {
        for (int z = minZ; z <= maxZ; ++z) {
            Chunk chunk = world.getChunkAt(x, z);
            for (final Entity entity : chunk.getEntities()) {
                if (!entity.getType().isAlive() || entity.isInvulnerable() || entity.getEntityId() == shooter.getEntityId())
                    continue;
                entities.add((LivingEntity) entity);
            }
        }
    }
    return entities.isEmpty() ? null : entities;
}
Also used : LivingEntity(org.bukkit.entity.LivingEntity) Entity(org.bukkit.entity.Entity) LivingEntity(org.bukkit.entity.LivingEntity) HitBox(me.deecaad.weaponmechanics.weapon.projectile.HitBox) ArrayList(java.util.ArrayList) World(org.bukkit.World) Chunk(org.bukkit.Chunk)

Example 10 with HitBox

use of me.deecaad.weaponmechanics.weapon.projectile.HitBox in project MechanicsMain by WeaponMechanics.

the class DefaultExposure method getExposure.

/**
 * Gets a double [0, 1] representing how exposed the entity is to the explosion
 *
 * @param vec3d The origin of the explosion
 * @param entity The entity exposed to the explosion
 * @return The level of exposure of the entity to the epxlosion
 */
private static double getExposure(Vector vec3d, Entity entity) {
    HitBox box = WeaponCompatibilityAPI.getWeaponCompatibility().getHitBox(entity);
    if (box == null) {
        return 0.0;
    }
    // Get the dimensions of the bounding box
    double width = box.getWidth();
    double height = box.getHeight();
    double depth = box.getDepth();
    // Gets the size of the grid in each axis
    double stepX = width * 2.0 + 1.0;
    double stepY = height * 2.0 + 1.0;
    double stepZ = depth * 2.0 + 1.0;
    double gridX = 1.0 / stepX;
    double gridY = 1.0 / stepY;
    double gridZ = 1.0 / stepZ;
    // Outside the grid
    if (gridX < 0.0 || gridY < 0.0 || gridZ < 0.0)
        return 0.0;
    double d3 = (1.0 - Math.floor(stepX) * gridX) / 2.0;
    double d4 = (1.0 - Math.floor(stepZ) * gridZ) / 2.0;
    // Setup variables for the loop
    World world = entity.getWorld();
    int successfulTraces = 0;
    int totalTraces = 0;
    // For each grid on the bounding box
    for (double x = 0; x <= 1; x += gridX) {
        for (double y = 0; y <= 1; y += gridY) {
            for (double z = 0; z <= 1; z += gridZ) {
                double a = NumberUtil.lerp(box.getMinX(), box.getMaxX(), x);
                double b = NumberUtil.lerp(box.getMinY(), box.getMaxY(), y);
                double c = NumberUtil.lerp(box.getMinZ(), box.getMaxZ(), z);
                // Calculates a path from the origin of the explosion
                // (0, 0, 0) to the current grid on the entity's bounding
                // box. The Vector is then ray traced to check for obstructions
                Vector vector = new Vector(a + d3, b, c + d4).subtract(vec3d);
                Ray ray = new Ray(vec3d.toLocation(world), vector);
                TraceResult trace = ray.trace(TraceCollision.BLOCK, 0.3);
                if (trace.getBlocks().isEmpty()) {
                    successfulTraces++;
                }
                totalTraces++;
            }
        }
    }
    // The percentage of successful traces
    return ((double) successfulTraces) / totalTraces;
}
Also used : HitBox(me.deecaad.weaponmechanics.weapon.projectile.HitBox) Ray(me.deecaad.weaponmechanics.weapon.explode.raytrace.Ray) TraceResult(me.deecaad.weaponmechanics.weapon.explode.raytrace.TraceResult) World(org.bukkit.World) Vector(org.bukkit.util.Vector)

Aggregations

HitBox (me.deecaad.weaponmechanics.weapon.projectile.HitBox)25 Vector (org.bukkit.util.Vector)7 Entity (org.bukkit.entity.Entity)6 BoundingBox (org.bukkit.util.BoundingBox)6 Block (org.bukkit.block.Block)5 ComplexEntityPart (org.bukkit.entity.ComplexEntityPart)5 ComplexLivingEntity (org.bukkit.entity.ComplexLivingEntity)5 LivingEntity (org.bukkit.entity.LivingEntity)5 ArrayList (java.util.ArrayList)4 IWeaponCompatibility (me.deecaad.weaponmechanics.compatibility.IWeaponCompatibility)4 Chunk (org.bukkit.Chunk)3 World (org.bukkit.World)3 BlockIterator (org.bukkit.util.BlockIterator)3 HashMap (java.util.HashMap)2 Ray (me.deecaad.weaponmechanics.weapon.explode.raytrace.Ray)2 TraceResult (me.deecaad.weaponmechanics.weapon.explode.raytrace.TraceResult)2 RayTraceResult (me.deecaad.weaponmechanics.weapon.projectile.weaponprojectile.RayTraceResult)2 AxisAlignedBB (net.minecraft.server.v1_10_R1.AxisAlignedBB)2 AxisAlignedBB (net.minecraft.server.v1_11_R1.AxisAlignedBB)2 AxisAlignedBB (net.minecraft.server.v1_12_R1.AxisAlignedBB)2