Java Code Examples for org.bukkit.util.Vector#lengthSquared()

The following examples show how to use org.bukkit.util.Vector#lengthSquared() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: SentinelCrackShot.java    From Sentinel with MIT License 6 votes vote down vote up
@Override
public boolean tryAttack(SentinelTrait st, LivingEntity ent) {
    if (!(st.getLivingEntity() instanceof Player)) {
        return false;
    }
    CSDirector direc = (CSDirector) Bukkit.getPluginManager().getPlugin("CrackShot");
    String node = direc.returnParentNode((Player) st.getLivingEntity());
    if (node == null) {
        return false;
    }
    Vector faceAcc = ent.getEyeLocation().toVector().subtract(st.getLivingEntity().getEyeLocation().toVector());
    if (faceAcc.lengthSquared() > 0.0) {
        faceAcc = faceAcc.normalize();
    }
    faceAcc = st.fixForAcc(faceAcc);
    st.faceLocation(st.getLivingEntity().getEyeLocation().clone().add(faceAcc.multiply(10)));
    ItemStack itm = ((Player) st.getLivingEntity()).getItemInHand();
    direc.csminion.weaponInteraction((Player) st.getLivingEntity(), node, false);
    ((Player) st.getLivingEntity()).setItemInHand(itm);
    if (st.rangedChase) {
        st.attackHelper.rechase();
    }
    return true;
}
 
Example 2
Source File: TargetHelper.java    From ActionHealth with MIT License 5 votes vote down vote up
/**
 * 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 List<LivingEntity> getConeTargets(LivingEntity source, double arc, double range) {
    List<LivingEntity> targets = new ArrayList<LivingEntity>();
    List<Entity> list = source.getNearbyEntities(range, range, range);
    if (arc <= 0) return targets;

    // Initialize values
    Vector dir = source.getLocation().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().subtract(source.getLocation()).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;
}
 
Example 3
Source File: SentinelWeaponHelper.java    From Sentinel with MIT License 5 votes vote down vote up
/**
 * Knocks a target back from damage received (for hacked-in damage applications when required by config).
 */
public void knockback(LivingEntity entity) {
    Vector relative = entity.getLocation().toVector().subtract(getLivingEntity().getLocation().toVector());
    if (relative.lengthSquared() > 0) {
        relative = relative.normalize();
    }
    relative.setY(0.75);
    relative.multiply(0.5 / Math.max(1.0, entity.getVelocity().length()));
    entity.setVelocity(entity.getVelocity().multiply(0.25).add(relative));
    if (SentinelPlugin.debugMe) {
        debug("applied knockback velocity adder of " + relative);
    }
}
 
Example 4
Source File: AccelerationPlayerFacet.java    From ProjectAres with GNU Affero General Public License v3.0 5 votes vote down vote up
@Repeatable(scope = MatchScope.LOADED)
public void tickForce() {
    final Vector acceleration = new Vector();
    for(PlayerForce force : forces) {
        acceleration.add(force.acceleration(matchPlayer));
    }
    if(acceleration.lengthSquared() > MIN_FORCE) {
        player.applyImpulse(acceleration);
    }
}
 
Example 5
Source File: RegionDefinitionParser.java    From ProjectAres with GNU Affero General Public License v3.0 5 votes vote down vote up
@MethodParser
public MirroredRegion mirror(Element el) throws InvalidXMLException {
    Vector normal = XMLUtils.parseVector(XMLUtils.getRequiredAttribute(el, "normal"));
    if(normal.lengthSquared() == 0) {
        throw new InvalidXMLException("normal must have a non-zero length", el);
    }

    Vector origin = XMLUtils.parseVector(el.getAttribute("origin"), new Vector());
    return new MirroredRegion(regionParser.parseReferenceAndChildUnion(el), origin, normal);
}
 
Example 6
Source File: RegionDefinitionParser.java    From ProjectAres with GNU Affero General Public License v3.0 5 votes vote down vote up
@MethodParser
public HalfspaceRegion half(Element el) throws InvalidXMLException {
    Vector normal = XMLUtils.parseVector(XMLUtils.getRequiredAttribute(el, "normal"));
    if(normal.lengthSquared() == 0) {
        throw new InvalidXMLException("normal must have a non-zero length", el);
    }

    Vector origin = XMLUtils.parseVector(el.getAttribute("origin"), new Vector());

    return new HalfspaceRegion(origin, normal);
}
 
Example 7
Source File: RegionParser.java    From PGM with GNU Affero General Public License v3.0 5 votes vote down vote up
@MethodParser("half")
public HalfspaceRegion parseHalfspace(Element el) throws InvalidXMLException {
  Vector normal = XMLUtils.parseVector(XMLUtils.getRequiredAttribute(el, "normal"));
  if (normal.lengthSquared() == 0) {
    throw new InvalidXMLException("normal must have a non-zero length", el);
  }

  Vector origin = XMLUtils.parseVector(el.getAttribute("origin"), new Vector());

  return new HalfspaceRegion(origin, normal);
}
 
Example 8
Source File: TargetHelper.java    From ActionHealth with MIT License 5 votes vote down vote up
/**
 * <p>Gets all entities the player is looking at within the range using
 * the given tolerance.</p>
 *
 * @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 List<LivingEntity> getLivingTargets(LivingEntity source, double range, double tolerance) {
    if (source == null) {
        return new ArrayList<>();
    }

    List<Entity> list = source.getNearbyEntities(range, range, range);
    List<LivingEntity> targets = new ArrayList<LivingEntity>();

    Vector facing = source.getLocation().getDirection();
    double fLengthSq = facing.lengthSquared();

    for (Entity entity : list) {
        if (!isInFront(source, entity) || !(entity instanceof LivingEntity)) continue;

        Vector relative = entity.getLocation().subtract(source.getLocation()).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);
    }

    return targets;
}
 
Example 9
Source File: MoveEvent.java    From Hawk with GNU General Public License v3.0 5 votes vote down vote up
private Vector computeWaterFlowForce() {
    Vector finalForce = new Vector();
    for(Pair<Block, Vector> liquid : liquidsAndDirections) {
        Material mat = liquid.getKey().getType();
        if(mat == Material.STATIONARY_WATER || mat == Material.WATER) {
            finalForce.add(liquid.getValue());
        }
    }
    if(finalForce.lengthSquared() > 0 && !pp.isFlying()) {
        finalForce.normalize();
        finalForce.multiply(Physics.WATER_FLOW_FORCE_MULTIPLIER);
        return finalForce;
    }
    return finalForce;
}
 
Example 10
Source File: Inertia.java    From Hawk with GNU General Public License v3.0 5 votes vote down vote up
@Override
public void check(MoveEvent e) {
    Player p = e.getPlayer();
    HawkPlayer pp = e.getHawkPlayer();
    Vector moveVector = new Vector(e.getTo().getX() - e.getFrom().getX(), 0, e.getTo().getZ() - e.getFrom().getZ());
    Vector prevVector = pp.getVelocity().clone().setY(0);
    double horizSpeedSquared = Math.pow(e.getTo().getX() - e.getFrom().getX(), 2) + Math.pow(e.getTo().getZ() - e.getFrom().getZ(), 2);
    double deltaAngle = MathPlus.angle(moveVector, prevVector);
    boolean onGround = e.isOnGround(); //um... is this safe?
    boolean wasOnGround = pp.isOnGround(); //um... is this safe?

    if (!AdjacentBlocks.blockNearbyIsSolid(e.getTo(), true) && !wasOnGround && !onGround && !e.hasAcceptedKnockback() && !e.isTouchingBlocks() &&
            !AdjacentBlocks.blockNearbyIsSolid(e.getTo().clone().add(0, 1, 0), true) && !pp.isFlying() && !p.isInsideVehicle()) {

        //setting up expected values
        double magnitudeThres;
        double prevSpeed = e.hasHitSlowdown() ? prevVector.length() * 0.6 : prevVector.length();
        if(AdjacentBlocks.blockAdjacentIsLiquid(e.getFrom()) || AdjacentBlocks.blockAdjacentIsLiquid(e.getFrom().clone().add(0, 1, 0))) {
            magnitudeThres = 0; //screw it
        }
        else {
            magnitudeThres = e.getFriction() * prevSpeed - 0.026001;
        }

        //angle check
        if (horizSpeedSquared > 0.05 && deltaAngle > 0.2) {
            punishAndTryRubberband(pp, e);

        //magnitude check
        } else if(prevVector.lengthSquared() > 0.01 && moveVector.length() < magnitudeThres) {
            punishAndTryRubberband(pp, e);
        }

        else {
            reward(pp);
        }
    }
}
 
Example 11
Source File: RegionParser.java    From PGM with GNU Affero General Public License v3.0 5 votes vote down vote up
@MethodParser("mirror")
public MirroredRegion parseMirror(Element el) throws InvalidXMLException {
  Vector normal = XMLUtils.parseVector(XMLUtils.getRequiredAttribute(el, "normal"));
  if (normal.lengthSquared() == 0) {
    throw new InvalidXMLException("normal must have a non-zero length", el);
  }

  Vector origin = XMLUtils.parseVector(el.getAttribute("origin"), new Vector());

  return new MirroredRegion(this.parseChildren(el), origin, normal);
}
 
Example 12
Source File: EntityInteractDirection.java    From Hawk with GNU General Public License v3.0 4 votes vote down vote up
@Override
protected void check(InteractEntityEvent e) {
    Player p = e.getPlayer();
    HawkPlayer pp = e.getHawkPlayer();
    Entity victimEntity = e.getEntity();
    if (!(victimEntity instanceof Player) && !CHECK_OTHER_ENTITIES)
        return;
    int ping = ServerUtils.getPing(e.getPlayer());
    if (PING_LIMIT > -1 && ping > PING_LIMIT)
        return;
    Vector pos;
    if(pp.isInVehicle()) {
        pos = hawk.getLagCompensator().getHistoryLocation(ping, p).toVector();
        pos.setY(pos.getY() + p.getEyeHeight());
    }
    else {
        pos = pp.getHeadPosition();
    }
    //As I always say in math class, converting polar coordinates to rectangular coordinates is a pain in
    //the ass. If you want to use the previous direction vector, you cannot make an accurate cut through the AABB
    //using only the previous and extrapolated direction vectors. You'd think you could since the extrapolation
    //on yaw and pitch is linear, but the current direction vector won't lie between the other two. Remember Non-
    //Euclidean geometry!
    Vector dir = MathPlus.getDirection(pp.getYaw(), pp.getPitch());
    //Note: in MC 1.8, the cursor yaw is not updated per frame, but rather per tick.
    //For ray-hitbox checks, this means that we do not need to extrapolate the yaw,
    //but for this check it does not matter whether we do it or not.
    Vector extraDir = MathPlus.getDirection(pp.getYaw() + pp.getDeltaYaw(), pp.getPitch() + pp.getDeltaPitch());

    Location victimLoc;
    if(LAG_COMPENSATION)
        victimLoc = hawk.getLagCompensator().getHistoryLocation(ping, victimEntity);
    else
        victimLoc = e.getEntity().getLocation();

    AABB victimAABB = WrappedEntity.getWrappedEntity(e.getEntity()).getHitbox(victimLoc.toVector());
    victimAABB.expand(BOX_EXPAND, BOX_EXPAND, BOX_EXPAND);

    //this is a crappy workaround to one of the issues with AABB#betweenRays. I'll keep this here until it is rewritten.
    Vector toVictim = victimLoc.toVector().setY(0).subtract(pos.clone().setY(0));
    boolean behind = toVictim.clone().normalize().dot(dir.clone().setY(0).normalize()) < 0 && toVictim.lengthSquared() > victimAABB.getMax().clone().setY(0).subtract(victimAABB.getMin().clone().setY(0)).lengthSquared();

    if(victimAABB.betweenRays(pos, dir, extraDir) && !behind) {
        reward(pp);
    }
    else {
        punish(pp, true, e);
    }
}
 
Example 13
Source File: SprintDirection.java    From Hawk with GNU General Public License v3.0 4 votes vote down vote up
@Override
protected void check(MoveEvent e) {
    HawkPlayer pp = e.getHawkPlayer();

    boolean collisionHorizontal = collidingHorizontally(e);
    Vector moveHoriz = e.getTo().toVector().subtract(e.getFrom().toVector()).setY(0);

    if(!pp.isSprinting())
        lastSprintTickMap.put(pp.getUuid(), pp.getCurrentTick());

    Set<Material> collidedMats = WrappedEntity.getWrappedEntity(e.getPlayer()).getCollisionBox(e.getFrom().toVector()).getMaterials(pp.getWorld());
    if(pp.isSwimming() || e.hasTeleported() || e.hasAcceptedKnockback() ||
            (collisionHorizontal && !collisionHorizontalSet.contains(pp.getUuid())) ||
            pp.getCurrentTick() - lastSprintTickMap.getOrDefault(pp.getUuid(), pp.getCurrentTick()) < 2 ||
            moveHoriz.lengthSquared() < 0.04 || collidedMats.contains(Material.LADDER) ||
            collidedMats.contains(Material.VINE)) {
        return;
    }

    float yaw = e.getTo().getYaw();
    Vector prevVelocity = pp.getVelocity().clone();
    if(e.hasHitSlowdown()) {
        prevVelocity.multiply(0.6);
    }
    double dX = e.getTo().getX() - e.getFrom().getX();
    double dZ = e.getTo().getZ() - e.getFrom().getZ();
    float friction = e.getFriction();
    dX /= friction;
    dZ /= friction;
    if(e.isJump()) {
        float yawRadians = yaw * 0.017453292F;
        dX += (MathPlus.sin(yawRadians) * 0.2F);
        dZ -= (MathPlus.cos(yawRadians) * 0.2F);
    }

    //Div by 1.7948708571637845???? What the hell are these numbers?

    dX -= prevVelocity.getX();
    dZ -= prevVelocity.getZ();

    Vector moveForce = new Vector(dX, 0, dZ);
    Vector yawVec = MathPlus.getDirection(yaw, 0);

    if(MathPlus.angle(yawVec, moveForce) > Math.PI / 4 + 0.3) { //0.3 is arbitrary. Prevents falses due to silly stuff in game
        punishAndTryRubberband(pp, e);
    }
    else {
        reward(pp);
    }

    if(collisionHorizontal)
        collisionHorizontalSet.add(pp.getUuid());
    else
        collisionHorizontalSet.remove(pp.getUuid());
}
 
Example 14
Source File: SentinelQAHandler.java    From QualityArmory with GNU General Public License v3.0 4 votes vote down vote up
@SuppressWarnings("deprecation")
@Override
public boolean tryAttack(SentinelTrait st, LivingEntity ent) {
	QAMain.DEBUG("Sentinel about to shoot!");
	if (!(st.getLivingEntity() instanceof Player)) {
		return false;
	}
	ItemStack itm = ((Player) st.getLivingEntity()).getItemInHand();
	Gun g = QualityArmory.getGun(itm);
	QAMain.DEBUG("Getting gun! gun = "+g);
	if (g == null)
		return false;
	// CSDirector direc = (CSDirector)
	// Bukkit.getPluginManager().getPlugin("CrackShot");
	// String node = direc.returnParentNode((Player) st.getLivingEntity());
	// if (node == null) {
	// return false;
	// }
	Vector faceAcc = ent.getEyeLocation().toVector().subtract(st.getLivingEntity().getEyeLocation().toVector());
	if (faceAcc.lengthSquared() > 0.0) {
		faceAcc = faceAcc.normalize();
	}
	faceAcc = st.fixForAcc(faceAcc);
	st.faceLocation(st.getLivingEntity().getEyeLocation().clone().add(faceAcc.multiply(10)));

	double sway = g.getSway() * 0.75;
	if (g.usesCustomProjctiles()) {
		for (int i = 0; i < g.getBulletsPerShot(); i++) {
			Vector go = st.getLivingEntity().getEyeLocation().getDirection().normalize();
			go.add(new Vector((Math.random() * 2 * sway) - sway, (Math.random() * 2 * sway) - sway,
					(Math.random() * 2 * sway) - sway)).normalize();
			Vector two = go.clone();// .multiply();
			g.getCustomProjectile().spawn(g, st.getLivingEntity().getEyeLocation(), (Player) st.getLivingEntity(),
					two);
		}
	} else {
		GunUtil.shootInstantVector(g, ((Player) st.getLivingEntity()), sway, g.getDurabilityDamage(), g.getBulletsPerShot(),
				g.getMaxDistance());
	}

	GunUtil.playShoot(g, (Player) st.getLivingEntity());
	QAMain.DEBUG("Sentinel shooting!");
	
	// direc.csminion.weaponInteraction((Player) st.getLivingEntity(), node, false);
	 ((Player) st.getLivingEntity()).setItemInHand(itm);
	if (st.rangedChase) {
		st.attackHelper.rechase();
		QAMain.DEBUG("Sentinel rechase");
	}
	return true;
}
 
Example 15
Source File: ExprVectorSquaredLength.java    From Skript with GNU General Public License v3.0 4 votes vote down vote up
@SuppressWarnings({"null", "unused"})
@Override
public Number convert(Vector vector) {
	return vector.lengthSquared();
}
 
Example 16
Source File: Strafe.java    From Hawk with GNU General Public License v3.0 4 votes vote down vote up
@Override
protected void check(MoveEvent e) {
    HawkPlayer pp = e.getHawkPlayer();

    boolean bounced = bouncedSet.contains(pp.getUuid());
    boolean collidingHorizontally = collidingHorizontally(e);

    Block footBlock = ServerUtils.getBlockAsync(pp.getPlayer().getLocation().clone().add(0, -0.1, 0));
    if(footBlock == null)
        return;

    long ticksSinceIdle = pp.getCurrentTick() - lastIdleTick.getOrDefault(pp.getUuid(), pp.getCurrentTick());
    double friction = e.getFriction();
    //A really rough check to handle sneaking on edge of blocks.
    boolean sneakEdge = pp.isSneaking() && !WrappedBlock.getWrappedBlock(footBlock, pp.getClientVersion()).isSolid() && e.isOnGround();

    Vector prevVelocity = pp.getVelocity().clone();
    if(e.hasHitSlowdown()) {
        prevVelocity.multiply(0.6);
    }

    Set<Material> collidedMats = WrappedEntity.getWrappedEntity(e.getPlayer()).getCollisionBox(e.getFrom().toVector()).getMaterials(pp.getWorld());
    if(collidedMats.contains(Material.SOUL_SAND)) {
        prevVelocity.multiply(0.4);
    }

    boolean nearLiquid = testLiquid(collidedMats);

    if(Math.abs(prevVelocity.getX() * friction) < 0.005) {
        prevVelocity.setX(0);
    }
    if(Math.abs(prevVelocity.getZ() * friction) < 0.005) {
        prevVelocity.setZ(0);
    }

    double dX = e.getTo().getX() - e.getFrom().getX();
    double dZ = e.getTo().getZ() - e.getFrom().getZ();
    dX /= friction;
    dZ /= friction;
    dX -= prevVelocity.getX();
    dZ -= prevVelocity.getZ();

    Vector accelDir = new Vector(dX, 0, dZ);
    Vector yaw = MathPlus.getDirection(e.getTo().getYaw(), 0);

    //Return if player hasn't sent at least 2 moves in a row. Let Speed handle any bypasses for this.
    if(e.hasTeleported() || e.hasAcceptedKnockback() || bounced || collidingHorizontally ||
            !e.isUpdatePos() || sneakEdge || e.isJump() || ticksSinceIdle <= 2 || nearLiquid || //TODO get rid of e.isJump() from here and actually try to handle it
            pp.getCurrentTick() - pp.getLastVelocityAcceptTick() == 1 || collidedMats.contains(Material.LADDER) ||
            collidedMats.contains(Material.VINE)) {
        prepareNextMove(e, pp, pp.getCurrentTick());
        return;
    }

    //You aren't pressing a WASD key
    if(accelDir.lengthSquared() < 0.000001) {
        prepareNextMove(e, pp, pp.getCurrentTick());
        return;
    }

    boolean vectorDir = accelDir.clone().crossProduct(yaw).dot(new Vector(0, 1, 0)) >= 0;
    double angle = (vectorDir ? 1 : -1) * MathPlus.angle(accelDir, yaw);

    if(!isValidStrafe(angle)) {
        Debug.broadcastMessage(pp.isSneaking());
        punishAndTryRubberband(pp, e);
    }
    else
        reward(pp);

    prepareNextMove(e, pp, pp.getCurrentTick());
}
 
Example 17
Source File: SentinelWeaponHelper.java    From Sentinel with MIT License 4 votes vote down vote up
/**
 * Fires an arrow from the NPC at a target.
 */
public void fireArrow(ItemStack type, Location target, Vector lead) {
    Location launchStart;
    Vector baseVelocity;
    if (SentinelVersionCompat.v1_14 && type.getType() == Material.FIREWORK_ROCKET) {
        launchStart = sentinel.getLivingEntity().getEyeLocation();
        launchStart = launchStart.clone().add(launchStart.getDirection());
        baseVelocity = target.toVector().subtract(launchStart.toVector().add(lead));
        if (baseVelocity.lengthSquared() > 0) {
            baseVelocity = baseVelocity.normalize();
        }
        baseVelocity = baseVelocity.multiply(2);
    }
    else {
        HashMap.SimpleEntry<Location, Vector> start = sentinel.getLaunchDetail(target, lead);
        if (start == null || start.getKey() == null) {
            return;
        }
        launchStart = start.getKey();
        baseVelocity = start.getValue();
    }
    Vector velocity = sentinel.fixForAcc(baseVelocity);
    sentinel.stats_arrowsFired++;
    Entity arrow;
    if (SentinelVersionCompat.v1_9) {
        if (SentinelVersionCompat.v1_14) {
            double length = Math.max(1.0, velocity.length());
            if (type.getType() == Material.FIREWORK_ROCKET) {
                FireworkMeta meta = (FireworkMeta) type.getItemMeta();
                meta.setPower(3);
                arrow = launchStart.getWorld().spawn(launchStart, EntityType.FIREWORK.getEntityClass(), (e) -> {
                    ((Firework) e).setShotAtAngle(true);
                    ((Firework) e).setFireworkMeta(meta);
                    e.setVelocity(velocity);
                });
            }
            else {
                Class toShoot;
                toShoot = type.getType() == Material.SPECTRAL_ARROW ? SpectralArrow.class :
                        (type.getType() == Material.TIPPED_ARROW ? TippedArrow.class : Arrow.class);
                arrow = launchStart.getWorld().spawnArrow(launchStart, velocity.multiply(1.0 / length), (float) length, 0f, toShoot);
                ((Projectile) arrow).setShooter(getLivingEntity());
                ((Arrow) arrow).setPickupStatus(Arrow.PickupStatus.DISALLOWED);
                if (type.getItemMeta() instanceof PotionMeta) {
                    PotionData data = ((PotionMeta) type.getItemMeta()).getBasePotionData();
                    if (data.getType() == null || data.getType() == PotionType.UNCRAFTABLE) {
                        if (SentinelPlugin.debugMe) {
                            sentinel.debug("Potion data '" + data + "' for '" + type.toString() + "' is invalid.");
                        }
                    }
                    else {
                        ((Arrow) arrow).setBasePotionData(data);
                        for (PotionEffect effect : ((PotionMeta) type.getItemMeta()).getCustomEffects()) {
                            ((Arrow) arrow).addCustomEffect(effect, true);
                        }
                    }
                }
            }
        }
        else {
            arrow = launchStart.getWorld().spawnEntity(launchStart,
                    type.getType() == Material.SPECTRAL_ARROW ? EntityType.SPECTRAL_ARROW :
                            (type.getType() == Material.TIPPED_ARROW ? TIPPED_ARROW : EntityType.ARROW));
            arrow.setVelocity(velocity);
            ((Projectile) arrow).setShooter(getLivingEntity());
        }
    }
    else {
        arrow = launchStart.getWorld().spawnEntity(launchStart, EntityType.ARROW);
        ((Projectile) arrow).setShooter(getLivingEntity());
        arrow.setVelocity(velocity);
    }
    if (sentinel.itemHelper.getHeldItem().containsEnchantment(Enchantment.ARROW_FIRE)) {
        arrow.setFireTicks(10000);
    }
    sentinel.useItem();
}