176 lines
		
	
	
	
		
			6.4 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			176 lines
		
	
	
	
		
			6.4 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
| package net.minecraft.world.entity.projectile;
 | |
| 
 | |
| import java.util.Optional;
 | |
| import java.util.function.Predicate;
 | |
| import net.minecraft.util.Mth;
 | |
| import net.minecraft.world.InteractionHand;
 | |
| import net.minecraft.world.entity.Entity;
 | |
| import net.minecraft.world.entity.LivingEntity;
 | |
| import net.minecraft.world.item.ArrowItem;
 | |
| import net.minecraft.world.item.Item;
 | |
| import net.minecraft.world.item.ItemStack;
 | |
| import net.minecraft.world.item.Items;
 | |
| import net.minecraft.world.level.ClipContext;
 | |
| import net.minecraft.world.level.Level;
 | |
| import net.minecraft.world.phys.AABB;
 | |
| import net.minecraft.world.phys.EntityHitResult;
 | |
| import net.minecraft.world.phys.HitResult;
 | |
| import net.minecraft.world.phys.Vec3;
 | |
| import org.jetbrains.annotations.Nullable;
 | |
| 
 | |
| public final class ProjectileUtil {
 | |
| 	public static final float DEFAULT_ENTITY_HIT_RESULT_MARGIN = 0.3F;
 | |
| 
 | |
| 	public static HitResult getHitResultOnMoveVector(Entity projectile, Predicate<Entity> filter) {
 | |
| 		Vec3 vec3 = projectile.getDeltaMovement();
 | |
| 		Level level = projectile.level();
 | |
| 		Vec3 vec32 = projectile.position();
 | |
| 		return getHitResult(vec32, projectile, filter, vec3, level, computeMargin(projectile), ClipContext.Block.COLLIDER);
 | |
| 	}
 | |
| 
 | |
| 	public static HitResult getHitResultOnMoveVector(Entity projectile, Predicate<Entity> filter, ClipContext.Block clipContext) {
 | |
| 		Vec3 vec3 = projectile.getDeltaMovement();
 | |
| 		Level level = projectile.level();
 | |
| 		Vec3 vec32 = projectile.position();
 | |
| 		return getHitResult(vec32, projectile, filter, vec3, level, computeMargin(projectile), clipContext);
 | |
| 	}
 | |
| 
 | |
| 	public static HitResult getHitResultOnViewVector(Entity projectile, Predicate<Entity> filter, double scale) {
 | |
| 		Vec3 vec3 = projectile.getViewVector(0.0F).scale(scale);
 | |
| 		Level level = projectile.level();
 | |
| 		Vec3 vec32 = projectile.getEyePosition();
 | |
| 		return getHitResult(vec32, projectile, filter, vec3, level, 0.0F, ClipContext.Block.COLLIDER);
 | |
| 	}
 | |
| 
 | |
| 	private static HitResult getHitResult(
 | |
| 		Vec3 pos, Entity projectile, Predicate<Entity> filter, Vec3 deltaMovement, Level level, float margin, ClipContext.Block clipContext
 | |
| 	) {
 | |
| 		Vec3 vec3 = pos.add(deltaMovement);
 | |
| 		HitResult hitResult = level.clipIncludingBorder(new ClipContext(pos, vec3, clipContext, ClipContext.Fluid.NONE, projectile));
 | |
| 		if (hitResult.getType() != HitResult.Type.MISS) {
 | |
| 			vec3 = hitResult.getLocation();
 | |
| 		}
 | |
| 
 | |
| 		HitResult hitResult2 = getEntityHitResult(level, projectile, pos, vec3, projectile.getBoundingBox().expandTowards(deltaMovement).inflate(1.0), filter, margin);
 | |
| 		if (hitResult2 != null) {
 | |
| 			hitResult = hitResult2;
 | |
| 		}
 | |
| 
 | |
| 		return hitResult;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Gets the EntityRayTraceResult representing the entity hit
 | |
| 	 */
 | |
| 	@Nullable
 | |
| 	public static EntityHitResult getEntityHitResult(Entity shooter, Vec3 startVec, Vec3 endVec, AABB boundingBox, Predicate<Entity> filter, double distance) {
 | |
| 		Level level = shooter.level();
 | |
| 		double d = distance;
 | |
| 		Entity entity = null;
 | |
| 		Vec3 vec3 = null;
 | |
| 
 | |
| 		for (Entity entity2 : level.getEntities(shooter, boundingBox, filter)) {
 | |
| 			AABB aABB = entity2.getBoundingBox().inflate(entity2.getPickRadius());
 | |
| 			Optional<Vec3> optional = aABB.clip(startVec, endVec);
 | |
| 			if (aABB.contains(startVec)) {
 | |
| 				if (d >= 0.0) {
 | |
| 					entity = entity2;
 | |
| 					vec3 = (Vec3)optional.orElse(startVec);
 | |
| 					d = 0.0;
 | |
| 				}
 | |
| 			} else if (optional.isPresent()) {
 | |
| 				Vec3 vec32 = (Vec3)optional.get();
 | |
| 				double e = startVec.distanceToSqr(vec32);
 | |
| 				if (e < d || d == 0.0) {
 | |
| 					if (entity2.getRootVehicle() == shooter.getRootVehicle()) {
 | |
| 						if (d == 0.0) {
 | |
| 							entity = entity2;
 | |
| 							vec3 = vec32;
 | |
| 						}
 | |
| 					} else {
 | |
| 						entity = entity2;
 | |
| 						vec3 = vec32;
 | |
| 						d = e;
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		return entity == null ? null : new EntityHitResult(entity, vec3);
 | |
| 	}
 | |
| 
 | |
| 	@Nullable
 | |
| 	public static EntityHitResult getEntityHitResult(Level level, Projectile projectile, Vec3 startVec, Vec3 endVec, AABB boundingBox, Predicate<Entity> filter) {
 | |
| 		return getEntityHitResult(level, projectile, startVec, endVec, boundingBox, filter, computeMargin(projectile));
 | |
| 	}
 | |
| 
 | |
| 	public static float computeMargin(Entity entity) {
 | |
| 		return Math.max(0.0F, Math.min(0.3F, (entity.tickCount - 2) / 20.0F));
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Gets the EntityHitResult representing the entity hit
 | |
| 	 */
 | |
| 	@Nullable
 | |
| 	public static EntityHitResult getEntityHitResult(
 | |
| 		Level level, Entity projectile, Vec3 startVec, Vec3 endVec, AABB boundingBox, Predicate<Entity> filter, float inflationAmount
 | |
| 	) {
 | |
| 		double d = Double.MAX_VALUE;
 | |
| 		Optional<Vec3> optional = Optional.empty();
 | |
| 		Entity entity = null;
 | |
| 
 | |
| 		for (Entity entity2 : level.getEntities(projectile, boundingBox, filter)) {
 | |
| 			AABB aABB = entity2.getBoundingBox().inflate(inflationAmount);
 | |
| 			Optional<Vec3> optional2 = aABB.clip(startVec, endVec);
 | |
| 			if (optional2.isPresent()) {
 | |
| 				double e = startVec.distanceToSqr((Vec3)optional2.get());
 | |
| 				if (e < d) {
 | |
| 					entity = entity2;
 | |
| 					d = e;
 | |
| 					optional = optional2;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		return entity == null ? null : new EntityHitResult(entity, (Vec3)optional.get());
 | |
| 	}
 | |
| 
 | |
| 	public static void rotateTowardsMovement(Entity projectile, float rotationSpeed) {
 | |
| 		Vec3 vec3 = projectile.getDeltaMovement();
 | |
| 		if (vec3.lengthSqr() != 0.0) {
 | |
| 			double d = vec3.horizontalDistance();
 | |
| 			projectile.setYRot((float)(Mth.atan2(vec3.z, vec3.x) * 180.0F / (float)Math.PI) + 90.0F);
 | |
| 			projectile.setXRot((float)(Mth.atan2(d, vec3.y) * 180.0F / (float)Math.PI) - 90.0F);
 | |
| 
 | |
| 			while (projectile.getXRot() - projectile.xRotO < -180.0F) {
 | |
| 				projectile.xRotO -= 360.0F;
 | |
| 			}
 | |
| 
 | |
| 			while (projectile.getXRot() - projectile.xRotO >= 180.0F) {
 | |
| 				projectile.xRotO += 360.0F;
 | |
| 			}
 | |
| 
 | |
| 			while (projectile.getYRot() - projectile.yRotO < -180.0F) {
 | |
| 				projectile.yRotO -= 360.0F;
 | |
| 			}
 | |
| 
 | |
| 			while (projectile.getYRot() - projectile.yRotO >= 180.0F) {
 | |
| 				projectile.yRotO += 360.0F;
 | |
| 			}
 | |
| 
 | |
| 			projectile.setXRot(Mth.lerp(rotationSpeed, projectile.xRotO, projectile.getXRot()));
 | |
| 			projectile.setYRot(Mth.lerp(rotationSpeed, projectile.yRotO, projectile.getYRot()));
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public static InteractionHand getWeaponHoldingHand(LivingEntity shooter, Item weapon) {
 | |
| 		return shooter.getMainHandItem().is(weapon) ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND;
 | |
| 	}
 | |
| 
 | |
| 	public static AbstractArrow getMobArrow(LivingEntity shooter, ItemStack arrow, float velocity, @Nullable ItemStack weapon) {
 | |
| 		ArrowItem arrowItem = (ArrowItem)(arrow.getItem() instanceof ArrowItem ? arrow.getItem() : Items.ARROW);
 | |
| 		AbstractArrow abstractArrow = arrowItem.createArrow(shooter.level(), arrow, shooter, weapon);
 | |
| 		abstractArrow.setBaseDamageFromMob(velocity);
 | |
| 		return abstractArrow;
 | |
| 	}
 | |
| }
 |