下面列出了org.bukkit.util.Vector#normalize ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
/**
* Spawns a line from a location to another.
* Tutorial: https://www.spigotmc.org/threads/176695/
*
* @param start the starting point of the line.
* @param end the ending point of the line.
* @param rate the rate of points of the line.
* @see #drawLine(Player, double, double, ParticleDisplay)
* @since 1.0.0
*/
public static void line(Location start, Location end, double rate, ParticleDisplay display) {
Vector distance = end.toVector().subtract(start.toVector());
double length = distance.length();
distance.normalize();
double x = distance.getX();
double y = distance.getY();
double z = distance.getZ();
ParticleDisplay clone = display.clone();
clone.location = start;
for (double i = 0; i < length; i += rate) {
// Since the rate can be any number it's possible to get a higher number than
// the length in the last loop.
if (i > length) i = length;
clone.spawn(x * i, y * i, z * i);
}
}
private void applyImpulses(LivingEntity attacker) {
final KnockbackSettings knockback = this.knockback.get();
final Vector normal = victim.getLocation().subtract(attacker.getLocation()).toVector();
if(normal.isZero()) return;
normal.normalize();
final Vector victimNormal = knockback.pitchedNormal(normal);
final Vector attackerNormal = normal.times(-1);
if(victimNormal.isZero() || attackerNormal.isZero()) return;
final boolean ground = attacker.isOnGround();
final double attackSpeed = Math.max(0, attacker.getPredictedVelocity().dot(normal));
final boolean sprint = ground && attackSpeed > knockback.sprintThreshold;
victim.applyImpulse(victimNormal.multiply(knockback.power(sprint)), true);
attacker.applyImpulse(attackerNormal.multiply(knockback.recoil(ground) * attackSpeed), true);
final MatchPlayer matchAttacker = match.getPlayer(attacker);
if(matchAttacker != null) {
matchAttacker.facet(DamageDisplayPlayerFacet.class).showKnockback(victim, sprint);
}
}
@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;
}
public static Vector getDirection(BlockFace face) {
int modX = face.getModX();
int modY = face.getModY();
int modZ = face.getModZ();
Vector direction = new Vector(modX, modY, modZ);
if (modX != 0 || modY != 0 || modZ != 0) {
direction.normalize();
}
return direction;
}
public static Vector getDirection(BlockFace face) {
int modX = face.getModX();
int modY = face.getModY();
int modZ = face.getModZ();
Vector direction = new Vector(modX, modY, modZ);
if (modX != 0 || modY != 0 || modZ != 0) {
direction.normalize();
}
return direction;
}
public static void buildLine(Location locA, Location locB, Consumer<Location> action, double interval) {
Vector vectorAB = locB.clone().subtract(locA).toVector();
double vectorLength = vectorAB.length();
vectorAB.normalize();
for (double i = 0; i < vectorLength; i += interval) {
action.accept(locA.clone().add(vectorAB.clone().multiply(i)));
}
}
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;
}
public Vector pitchedNormal(Vector delta) {
delta = delta.clone();
delta.setY(0);
if(delta.isZero()) return Vectors.ZERO;
delta.normalize();
final double theta = Math.toRadians(pitch);
final double cos = Math.cos(theta);
delta.set(cos * delta.getX(),
Math.sin(theta),
cos * delta.getZ());
return delta;
}
/**
* Gets a 'launch detail' (starting location with direction vector set to correct firing direction, and a vector holding the exact launch vector, scaled to the correct speed).
*/
public static HashMap.SimpleEntry<Location, Vector> getLaunchDetail(Location start, Location target, Vector lead) {
double speeda;
double angt = Double.POSITIVE_INFINITY;
double sbase = SentinelPlugin.instance.minShootSpeed;
for (speeda = sbase; speeda <= sbase + 15; speeda += 5) {
// TODO: Mathematically calculate a valid starting speed, to avoid pointlessly looping on a math utility.
angt = SentinelUtilities.getArrowAngle(start, target, speeda, 20);
if (!Double.isInfinite(angt)) {
break;
}
}
if (Double.isInfinite(angt)) {
return null;
}
double hangT = SentinelUtilities.hangtime(angt, speeda, target.getY() - start.getY(), 20);
Location to = target.clone().add(lead.clone().multiply(hangT));
Vector relative = to.clone().subtract(start.toVector()).toVector();
double deltaXZ = Math.sqrt(relative.getX() * relative.getX() + relative.getZ() * relative.getZ());
if (deltaXZ == 0) {
deltaXZ = 0.1;
}
for (speeda = sbase; speeda <= sbase + 15; speeda += 5) {
angt = SentinelUtilities.getArrowAngle(start, to, speeda, 20);
if (!Double.isInfinite(angt)) {
break;
}
}
if (Double.isInfinite(angt)) {
return null;
}
relative.setY(Math.tan(angt) * deltaXZ);
relative = relative.normalize();
Vector normrel = relative.clone();
speeda = speeda + (1.188 * hangT * hangT);
relative = relative.multiply(speeda / 20.0);
start.setDirection(normrel);
return new HashMap.SimpleEntry<>(start, relative);
}
/**
* 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);
}
}
private Vector getVector(Location fromLoc, Location toLoc) {
if(fromLoc == null || toLoc == null) return null;
Vector fromVec = fromLoc.toVector();
Vector toVec = toLoc.toVector();
Vector subtract = fromVec.subtract(toVec);
Vector normal = subtract.normalize();
NoEntryHandler handler = getNoEntryHandler();
double strength = handler.getNoEntryKnockbackStrength();
Vector multiply = normal.multiply(strength);
return makeFinite(multiply);
}
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onBlockBreak(BlockBreakEvent event) {
if (event == null || !terraformEnabled) {
return;
}
Block block = event.getBlock();
Player player = event.getPlayer();
if (!plugin.getWorldManager().isSkyNether(block.getWorld()) || !plugin.getWorldManager().isSkyNether(player.getWorld())) {
return; // Bail out, not our problem
}
if (player.getGameMode() != GameMode.SURVIVAL) {
return;
}
if (!plugin.playerIsOnIsland(player)) {
return;
}
if (!terraFormMap.containsKey(block.getType())) {
return; // Not a block we terra-form on.
}
// TODO: 10/07/2016 - R4zorax: Handle dual-wielding (would break 1.8 compatibility)
ItemStack tool = event.getPlayer().getItemInHand();
if (event.getBlock().getDrops(tool).isEmpty()) {
return; // Only terra-form when stuff is mined correctly
}
double toolWeight = getToolWeight(tool);
Location playerLocation = player.getEyeLocation();
Location blockLocation = LocationUtil.centerInBlock(block.getLocation());
Vector v = new Vector(blockLocation.getX(), blockLocation.getY(), blockLocation.getZ());
v.subtract(new Vector(playerLocation.getX(), playerLocation.getY(), playerLocation.getZ()));
v.normalize();
// Disable spawning above the player... enabling the player to clear a region
if (playerLocation.getPitch() >= minPitch && playerLocation.getPitch() <= maxPitch) {
ProtectedCuboidRegion islandRegion = WorldGuardHandler.getIslandRegion(playerLocation);
List<Material> yield = getYield(block.getType(), toolWeight);
for (Material mat : yield) {
spawnBlock(mat, blockLocation, v, islandRegion);
}
}
}
@EventHandler
@SuppressWarnings("unused")
public void onPlayerMove(PlayerMoveEvent e) {
if (e.getTo() == null || !plugin.getWorldManager().isSkyAssociatedWorld(e.getTo().getWorld())) {
return;
}
String islandNameAt = WorldGuardHandler.getIslandNameAt(e.getTo());
if (islandNameAt == null) {
return;
}
IslandInfo islandInfo = plugin.getIslandInfo(islandNameAt);
if (islandInfo == null || islandInfo.getBans().isEmpty()) {
return;
}
Player player = e.getPlayer();
if (!player.isOp() && !player.hasPermission("usb.mod.bypassprotection") && isBlockedFromEntry(player, islandInfo)) {
e.setCancelled(true);
Location l = e.getTo().clone();
l.subtract(islandInfo.getIslandLocation());
Vector v = new Vector(l.getX(), l.getY(), l.getZ());
v.normalize();
v.multiply(1.5); // Bounce
player.setVelocity(v);
if (islandInfo.isBanned(player)) {
plugin.notifyPlayer(player, tr("\u00a7cBanned:\u00a7e You are banned from this island."));
} else {
plugin.notifyPlayer(player, tr("\u00a7cLocked:\u00a7e That island is locked! No entry allowed."));
}
}
}
public void onRun() {
Location location = getLocation();
//Lines
int mL = RandomUtils.random.nextInt(maxLines - 2) + 2;
for (int m = 0; m < mL * 2; m++) {
double x = RandomUtils.random.nextInt(max - max * (-1)) + max * (-1);
double y = RandomUtils.random.nextInt(max - max * (-1)) + max * (-1);
double z = RandomUtils.random.nextInt(max - max * (-1)) + max * (-1);
if (direction == Direction.DOWN) {
y = RandomUtils.random.nextInt(max * 2 - max) + max;
} else if (direction == Direction.UP) {
y = RandomUtils.random.nextInt(max * (-1) - max * (-2)) + max * (-2);
}
Location target = location.clone().subtract(x, y, z);
if (target == null) {
cancel();
return;
}
Vector link = target.toVector().subtract(location.toVector());
float length = (float) link.length();
link.normalize();
float ratio = length / lineParticles;
Vector v = link.multiply(ratio);
Location loc = location.clone().subtract(v);
for (int i = 0; i < lineParticles; i++) {
loc.add(v);
display(lineParticle, loc, lineColor);
}
}
//Sphere
for (int i = 0; i < sphereParticles; i++) {
Vector vector = RandomUtils.getRandomVector().multiply(sphereRadius);
location.add(vector);
display(sphereParticle, location, sphereColor);
location.subtract(vector);
}
}
public MirroredRegion(String name, RegionModule base, Vector origin, Vector normal) {
super(name);
this.origin = origin;
this.normal = normal.normalize();
this.flippedNormal = new Vector(normal.getX() * -1, normal.getY() * -1, normal.getZ() * -1);
this.base = base;
}
@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;
}
/**
* 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();
}
private void bloatEffect(Zombie eventZombie) {
/*
Spawn giant for "bloat" effect
*/
Giant giant = (Giant) eventZombie.getWorld().spawnEntity(eventZombie.getLocation(), EntityType.GIANT);
giant.setAI(false);
/*
Apply knockback to all living entities around the giant except for the original zombie entity
*/
List<Entity> nearbyEntities = giant.getNearbyEntities(4, 15, 4);
List<LivingEntity> nearbyValidLivingEntities = new ArrayList<>();
if (nearbyEntities.size() > 0)
for (Entity entity : nearbyEntities)
if (entity instanceof LivingEntity && !entity.equals(eventZombie))
nearbyValidLivingEntities.add((LivingEntity) entity);
Location entityLocation = eventZombie.getLocation();
for (LivingEntity livingEntity : nearbyValidLivingEntities) {
Location livingEntityLocation = livingEntity.getLocation();
Vector toLivingEntityVector = livingEntityLocation.subtract(entityLocation).toVector();
/*
Normalize vector to apply powers uniformly
*/
Vector normalizedVector = toLivingEntityVector.normalize();
normalizedVector = normalizedVector.multiply(new Vector(2, 0, 2)).add(new Vector(0, 1, 0));
try {
livingEntity.setVelocity(normalizedVector);
} catch (Exception e) {
//Entity was too recent to set a velocity?
}
}
livingEntityEffect(nearbyValidLivingEntities);
/*
Effect is done, start task to remove giant
*/
new BukkitRunnable() {
@Override
public void run() {
giant.remove();
eventZombie.setAI(true);
}
}.runTaskLater(MetadataHandler.PLUGIN, 10);
}
private int buildRoadSegment(Player player, Location locFirst, Location locSecond, int blockCount,
HashMap<String, SimpleBlock> simpleBlocks, int segments) throws CivException {
Vector dir = new Vector(locFirst.getX() - locSecond.getX(),
locFirst.getY() - locSecond.getY(),
locFirst.getZ() - locSecond.getZ());
dir.normalize();
dir.multiply(0.5);
getHorizontalSegment(player, locSecond, simpleBlocks);
segments++;
/* Increment towards the first location. */
double distance = locSecond.distance(locFirst);
BlockCoord lastBlockCoord = new BlockCoord(locSecond);
BlockCoord currentBlockCoord = new BlockCoord(locSecond);
int lastY = locSecond.getBlockY();
while (locSecond.distance(locFirst) > 1.0) {
locSecond.add(dir);
currentBlockCoord.setFromLocation(locSecond);
if (lastBlockCoord.distance(currentBlockCoord) < Road.WIDTH) {
continue; /* Didn't move far enough, keep going. */
} else {
lastBlockCoord.setFromLocation(locSecond);
}
/* Make sure the Y doesnt get too steep. */
if (Math.abs(lastY - locSecond.getBlockY()) > 1.0 ) {
throw new CivException("Road is too steep to be built here. Try lowering the one of the end points to make the road less steep.");
}
if (locSecond.getBlockY() < 5) {
throw new CivException("Cannot build road blocks within 5 blocks of bedrock.");
}
lastY = locSecond.getBlockY();
blockCount++;
if (blockCount > Road.RECURSION_LIMIT) {
throw new CivException("ERROR: Building road blocks exceeded recursion limit! Halted to keep server alive.");
}
getHorizontalSegment(player, locSecond, simpleBlocks);
// Road.DEBUG_DATA++;
// if (Road.DEBUG_DATA > 15) {
// Road.DEBUG_DATA = 0;
// }
segments++;
//Distance should always be going down, as a failsave
//check that it is. Abort if our distance goes up.
double tmpDist = locSecond.distance(locFirst);
if (tmpDist > distance) {
break;
}
}
/*
* Build last road segment
*/
getHorizontalSegment(player, locFirst, simpleBlocks);
return segments;
}