package me.km.entities; import java.util.List; import me.km.KajetansMod; import me.km.snuviscript.ScriptEvents; import me.km.utils.ReflectionUtils; import net.minecraft.entity.Entity; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.IProjectile; import net.minecraft.entity.item.ItemEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.util.DamageSource; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; public class EntityItemProjectile extends ItemEntity implements IProjectile { private final LivingEntity thrower; private boolean noHit; private final float damage; public EntityItemProjectile(LivingEntity thrower, ItemStack stack, float damage) { super(thrower.world, thrower.posX, thrower.posY + thrower.getEyeHeight() - 0.1d, thrower.posZ, stack); this.thrower = thrower; this.noHit = true; super.setInfinitePickupDelay(); this.damage = damage; } public EntityItemProjectile(LivingEntity thrower, ItemStack stack) { this(thrower, stack, -1); } public LivingEntity getItemThrower() { return thrower; } public void setHeadingFromThrower(Entity thrower, float rotationPitchIn, float rotationYawIn, float pitchOffset, float velocity, float inaccuracy) { float f = -MathHelper.sin(rotationYawIn * 0.017453292F) * MathHelper.cos(rotationPitchIn * 0.017453292F); float f1 = -MathHelper.sin((rotationPitchIn + pitchOffset) * 0.017453292F); float f2 = MathHelper.cos(rotationYawIn * 0.017453292F) * MathHelper.cos(rotationPitchIn * 0.017453292F); this.shoot(f, f1, f2, velocity, inaccuracy); double y = thrower.onGround ? 0.0 : thrower.getMotion().getY(); this.setMotion(this.getMotion().add(thrower.getMotion().getX(), y, thrower.getMotion().getZ())); } public void shoot(Entity shooter, float pitch, float yaw, float velocity, float inaccuracy) { float f = -MathHelper.sin(yaw * 0.017453292F) * MathHelper.cos(pitch * 0.017453292F); float f1 = -MathHelper.sin(pitch * 0.017453292F); float f2 = MathHelper.cos(yaw * 0.017453292F) * MathHelper.cos(pitch * 0.017453292F); this.shoot(f, f1, f2, velocity, inaccuracy); double y = shooter.onGround ? 0.0 : shooter.getMotion().getY(); this.setMotion(this.getMotion().add(shooter.getMotion().getX(), y, shooter.getMotion().getZ())); } @Override public void shoot(double x, double y, double z, float velocity, float inaccuracy) { float f = MathHelper.sqrt(x * x + y * y + z * z); x = x / (double)f; y = y / (double)f; z = z / (double)f; x = x + this.rand.nextGaussian() * 0.0075d * (double)inaccuracy; y = y + this.rand.nextGaussian() * 0.0075d * (double)inaccuracy; z = z + this.rand.nextGaussian() * 0.0075d * (double)inaccuracy; x = x * (double)velocity; y = y * (double)velocity; z = z * (double)velocity; this.setMotion(x, y, z); float f1 = MathHelper.sqrt(x * x + z * z); this.rotationYaw = (float)(MathHelper.atan2(x, z) * (180D / Math.PI)); this.rotationPitch = (float)(MathHelper.atan2(y, (double)f1) * (180D / Math.PI)); this.prevRotationYaw = this.rotationYaw; this.prevRotationPitch = this.rotationPitch; } @Override public void tick() { super.tick(); if(noHit) { if(this.onGround) { noHit = false; this.setDefaultPickupDelay(); return; } float fw = this.getWidth() / 2; float fh = this.getHeight() / 2; List list = this.world.getEntitiesWithinAABBExcludingEntity(this, new AxisAlignedBB(prevPosX, prevPosY, prevPosZ, posX, posY, posZ).expand(fw, fh, fw)); if(list.isEmpty()) { return; } Vec3d oldV = new Vec3d(this.prevPosX, prevPosY, prevPosZ); Vec3d newV = new Vec3d(this.posX, this.posY, this.posZ); list.removeIf(ent -> { // this prevents the projectile from hitting its shooter during // the first ticks if(ent == thrower && ReflectionUtils.getAge(this) < 5) { return true; } // size of the projectile is 0.25 x 0.25 return !ent.getBoundingBox().grow(0.25f).intersects(oldV, newV); }); if(!list.isEmpty()) { noHit = false; this.setDefaultPickupDelay(); onImpact(list); } } } protected void onImpact(List list) { if(damage == -1) { if(KajetansMod.scripts != null && thrower instanceof PlayerEntity) { ScriptEvents.onEntityItemProjectileHit(this, (PlayerEntity) thrower, this.getItem(), list); } } else { list.forEach(ent -> ent.attackEntityFrom(DamageSource.causeThrownDamage(this, thrower), damage)); } } }