/**
* This class was created by <Vazkii>. It's distributed as
* part of the Botania Mod. Get the Source Code in github:
* https://github.com/Vazkii/Botania
*
* Botania is Open Source and distributed under the
* Botania License: http://botaniamod.net/license.php
*
* File Created @ [Aug 16, 2015, 4:01:43 PM (GMT)]
*/
package vazkii.botania.common.entity;
import java.util.List;
import java.util.UUID;
import javax.annotation.Nonnull;
import net.minecraft.block.Block;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.IProjectile;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
// A copy of the vanilla EntityThrowable class
// Doing this because if I didn't do this it'd be an EntityThrowable
// And we all know how much mods like deflecting EntityThrowables
public abstract class EntityThrowableCopy extends Entity implements IProjectile
{
private int xTile;
private int yTile;
private int zTile;
private Block inTile;
protected boolean inGround;
public int throwableShake;
/** The entity that threw this throwable item. */
private EntityLivingBase thrower;
private String throwerName;
private int ticksInGround;
public Entity field_184539_c;
private int field_184540_av;
public EntityThrowableCopy(World worldIn)
{
super(worldIn);
xTile = -1;
yTile = -1;
zTile = -1;
setSize(0.25F, 0.25F);
}
public EntityThrowableCopy(World worldIn, double x, double y, double z)
{
this(worldIn);
setPosition(x, y, z);
}
public EntityThrowableCopy(World worldIn, EntityLivingBase throwerIn)
{
this(worldIn, throwerIn.posX, throwerIn.posY + throwerIn.getEyeHeight() - 0.10000000149011612D, throwerIn.posZ);
thrower = throwerIn;
}
@Override
protected void entityInit()
{
}
/**
* Checks if the entity is in range to render by using the past in distance and comparing it to its average edge
* length * 64 * renderDistanceWeight Args: distance
*/
@Override
@SideOnly(Side.CLIENT)
public boolean isInRangeToRenderDist(double distance)
{
double d0 = getEntityBoundingBox().getAverageEdgeLength() * 4.0D;
if (Double.isNaN(d0))
{
d0 = 4.0D;
}
d0 = d0 * 64.0D;
return distance < d0 * d0;
}
public void func_184538_a(Entity p_184538_1_, float p_184538_2_, float p_184538_3_, float p_184538_4_, float p_184538_5_, float p_184538_6_)
{
float f = -MathHelper.sin(p_184538_3_ * 0.017453292F) * MathHelper.cos(p_184538_2_ * 0.017453292F);
float f1 = -MathHelper.sin((p_184538_2_ + p_184538_4_) * 0.017453292F);
float f2 = MathHelper.cos(p_184538_3_ * 0.017453292F) * MathHelper.cos(p_184538_2_ * 0.017453292F);
setThrowableHeading(f, f1, f2, p_184538_5_, p_184538_6_);
motionX += p_184538_1_.motionX;
motionZ += p_184538_1_.motionZ;
if (!p_184538_1_.onGround)
{
motionY += p_184538_1_.motionY;
}
}
/**
* Similar to setArrowHeading, it's point the throwable entity to a x, y, z direction.
*/
@Override
public void setThrowableHeading(double x, double y, double z, float velocity, float inaccuracy)
{
float f = MathHelper.sqrt(x * x + y * y + z * z);
x = x / f;
y = y / f;
z = z / f;
x = x + rand.nextGaussian() * 0.007499999832361937D * inaccuracy;
y = y + rand.nextGaussian() * 0.007499999832361937D * inaccuracy;
z = z + rand.nextGaussian() * 0.007499999832361937D * inaccuracy;
x = x * velocity;
y = y * velocity;
z = z * velocity;
motionX = x;
motionY = y;
motionZ = z;
float f1 = MathHelper.sqrt(x * x + z * z);
prevRotationYaw = rotationYaw = (float)(MathHelper.atan2(x, z) * (180D / Math.PI));
prevRotationPitch = rotationPitch = (float)(MathHelper.atan2(y, f1) * (180D / Math.PI));
ticksInGround = 0;
}
/**
* Updates the velocity of the entity to a new value.
*/
@Override
@SideOnly(Side.CLIENT)
public void setVelocity(double x, double y, double z)
{
motionX = x;
motionY = y;
motionZ = z;
if (prevRotationPitch == 0.0F && prevRotationYaw == 0.0F)
{
float f = MathHelper.sqrt(x * x + z * z);
prevRotationYaw = rotationYaw = (float)(MathHelper.atan2(x, z) * (180D / Math.PI));
prevRotationPitch = rotationPitch = (float)(MathHelper.atan2(y, f) * (180D / Math.PI));
}
}
/**
* Called to update the entity's position/logic.
*/
@Override
public void onUpdate()
{
lastTickPosX = posX;
lastTickPosY = posY;
lastTickPosZ = posZ;
super.onUpdate();
if (throwableShake > 0)
{
--throwableShake;
}
if (inGround)
{
if (world.getBlockState(new BlockPos(xTile, yTile, zTile)).getBlock() == inTile)
{
++ticksInGround;
if (ticksInGround == 1200)
{
setDead();
}
return;
}
inGround = false;
motionX *= rand.nextFloat() * 0.2F;
motionY *= rand.nextFloat() * 0.2F;
motionZ *= rand.nextFloat() * 0.2F;
ticksInGround = 0;
}
else
{
}
Vec3d vec3d = new Vec3d(posX, posY, posZ);
Vec3d vec3d1 = new Vec3d(posX + motionX, posY + motionY, posZ + motionZ);
RayTraceResult raytraceresult = world.rayTraceBlocks(vec3d, vec3d1);
vec3d = new Vec3d(posX, posY, posZ);
vec3d1 = new Vec3d(posX + motionX, posY + motionY, posZ + motionZ);
if (raytraceresult != null)
{
vec3d1 = new Vec3d(raytraceresult.hitVec.xCoord, raytraceresult.hitVec.yCoord, raytraceresult.hitVec.zCoord);
}
Entity entity = null;
List<Entity> list = world.getEntitiesWithinAABBExcludingEntity(this, getEntityBoundingBox().addCoord(motionX, motionY, motionZ).expandXyz(1.0D));
double d0 = 0.0D;
boolean flag = false;
for (int i = 0; i < list.size(); ++i)
{
Entity entity1 = list.get(i);
if (entity1.canBeCollidedWith())
{
if (entity1 == field_184539_c)
{
flag = true;
}
else if (ticksExisted < 2 && field_184539_c == null)
{
field_184539_c = entity1;
flag = true;
}
else
{
flag = false;
AxisAlignedBB axisalignedbb = entity1.getEntityBoundingBox().expandXyz(0.30000001192092896D);
RayTraceResult raytraceresult1 = axisalignedbb.calculateIntercept(vec3d, vec3d1);
if (raytraceresult1 != null)
{
double d1 = vec3d.squareDistanceTo(raytraceresult1.hitVec);
if (d1 < d0 || d0 == 0.0D)
{
entity = entity1;
d0 = d1;
}
}
}
}
}
if (field_184539_c != null)
{
if (flag)
{
field_184540_av = 2;
}
else if (field_184540_av-- <= 0)
{
field_184539_c = null;
}
}
if (entity != null)
{
raytraceresult = new RayTraceResult(entity);
}
if (raytraceresult != null)
{
if (raytraceresult.typeOfHit == RayTraceResult.Type.BLOCK && world.getBlockState(raytraceresult.getBlockPos()).getBlock() == Blocks.PORTAL)
{
setPortal(raytraceresult.getBlockPos());
}
else
{
onImpact(raytraceresult);
}
}
posX += motionX;
posY += motionY;
posZ += motionZ;
float f = MathHelper.sqrt(motionX * motionX + motionZ * motionZ);
rotationYaw = (float)(MathHelper.atan2(motionX, motionZ) * (180D / Math.PI));
for (rotationPitch = (float)(MathHelper.atan2(motionY, f) * (180D / Math.PI)); rotationPitch - prevRotationPitch < -180.0F; prevRotationPitch -= 360.0F)
{
;
}
while (rotationPitch - prevRotationPitch >= 180.0F)
{
prevRotationPitch += 360.0F;
}
while (rotationYaw - prevRotationYaw < -180.0F)
{
prevRotationYaw -= 360.0F;
}
while (rotationYaw - prevRotationYaw >= 180.0F)
{
prevRotationYaw += 360.0F;
}
rotationPitch = prevRotationPitch + (rotationPitch - prevRotationPitch) * 0.2F;
rotationYaw = prevRotationYaw + (rotationYaw - prevRotationYaw) * 0.2F;
float f1 = 0.99F;
float f2 = getGravityVelocity();
if (isInWater())
{
for (int j = 0; j < 4; ++j)
{
float f3 = 0.25F;
world.spawnParticle(EnumParticleTypes.WATER_BUBBLE, posX - motionX * f3, posY - motionY * f3, posZ - motionZ * f3, motionX, motionY, motionZ);
}
f1 = 0.8F;
}
motionX *= f1;
motionY *= f1;
motionZ *= f1;
motionY -= f2;
setPosition(posX, posY, posZ);
}
/**
* Gets the amount of gravity to apply to the thrown entity with each tick.
*/
protected float getGravityVelocity()
{
return 0.03F;
}
/**
* Called when this EntityThrowable hits a block or entity.
*/
protected abstract void onImpact(RayTraceResult result);
/**
* (abstract) Protected helper method to write subclass entity data to NBT.
*/
@Override
public void writeEntityToNBT(@Nonnull NBTTagCompound compound)
{
compound.setInteger("xTile", xTile);
compound.setInteger("yTile", yTile);
compound.setInteger("zTile", zTile);
ResourceLocation resourcelocation = Block.REGISTRY.getNameForObject(inTile);
compound.setString("inTile", resourcelocation == null ? "" : resourcelocation.toString());
compound.setByte("shake", (byte)throwableShake);
compound.setByte("inGround", (byte)(inGround ? 1 : 0));
if ((throwerName == null || throwerName.isEmpty()) && thrower instanceof EntityPlayer)
{
throwerName = thrower.getName();
}
compound.setString("ownerName", throwerName == null ? "" : throwerName);
}
/**
* (abstract) Protected helper method to read subclass entity data from NBT.
*/
@Override
public void readEntityFromNBT(@Nonnull NBTTagCompound compound)
{
xTile = compound.getInteger("xTile");
yTile = compound.getInteger("yTile");
zTile = compound.getInteger("zTile");
if (compound.hasKey("inTile", 8))
{
inTile = Block.getBlockFromName(compound.getString("inTile"));
}
else
{
inTile = Block.getBlockById(compound.getByte("inTile") & 255);
}
throwableShake = compound.getByte("shake") & 255;
inGround = compound.getByte("inGround") == 1;
thrower = null;
throwerName = compound.getString("ownerName");
if (throwerName != null && throwerName.isEmpty())
{
throwerName = null;
}
thrower = getThrower();
}
public EntityLivingBase getThrower()
{
if (thrower == null && throwerName != null && !throwerName.isEmpty())
{
thrower = world.getPlayerEntityByName(throwerName);
if (thrower == null && world instanceof WorldServer)
{
try
{
Entity entity = ((WorldServer)world).getEntityFromUuid(UUID.fromString(throwerName));
if (entity instanceof EntityLivingBase)
{
thrower = (EntityLivingBase)entity;
}
}
catch (Throwable var2)
{
thrower = null;
}
}
}
return thrower;
}
}