package mekanism.common.entity;
import java.util.UUID;
import mekanism.api.Coord4D;
import mekanism.api.EnumColor;
import mekanism.api.Pos3D;
import net.minecraft.client.Minecraft;
import net.minecraft.client.particle.EntityFX;
import net.minecraft.client.particle.EntityReddustFX;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.DamageSource;
import net.minecraft.util.MathHelper;
import net.minecraft.world.World;
import cpw.mods.fml.common.registry.IEntityAdditionalSpawnData;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import io.netty.buffer.ByteBuf;
public class EntityBalloon extends Entity implements IEntityAdditionalSpawnData
{
public EnumColor color = EnumColor.DARK_BLUE;
public Coord4D latched;
public EntityLivingBase latchedEntity;
/* server-only */
public boolean hasCachedEntity;
public UUID cachedEntityUUID;
public EntityBalloon(World world)
{
super(world);
ignoreFrustumCheck = true;
preventEntitySpawning = true;
setPosition(posX + 0.5F, posY + 3F, posZ + 0.5F);
yOffset = height / 2.0F;
setSize(0.25F, 0.25F);
motionY = 0.04;
dataWatcher.addObject(2, new Byte((byte)0)); /* Is latched */
dataWatcher.addObject(3, new Integer(0)); /* Latched X */
dataWatcher.addObject(4, new Integer(0)); /* Latched Y */
dataWatcher.addObject(5, new Integer(0)); /* Latched Z */
dataWatcher.addObject(6, new Integer(-1)); /* Latched entity ID */
}
public EntityBalloon(World world, double x, double y, double z, EnumColor c)
{
this(world);
setPosition(x + 0.5F, y + 3F, z + 0.5F);
prevPosX = posX;
prevPosY = posY;
prevPosZ = posZ;
color = c;
}
public EntityBalloon(EntityLivingBase entity, EnumColor c)
{
this(entity.worldObj);
latchedEntity = entity;
setPosition(latchedEntity.posX, latchedEntity.posY + latchedEntity.height + 1.7F, latchedEntity.posZ);
prevPosX = posX;
prevPosY = posY;
prevPosZ = posZ;
color = c;
dataWatcher.updateObject(2, new Byte((byte)2)); /* Is latched */
dataWatcher.updateObject(3, new Integer(0)); /* Latched X */
dataWatcher.updateObject(4, new Integer(0)); /* Latched Y */
dataWatcher.updateObject(5, new Integer(0)); /* Latched Z */
dataWatcher.updateObject(6, new Integer(entity.getEntityId())); /* Latched entity ID */
}
public EntityBalloon(World world, Coord4D obj, EnumColor c)
{
this(world);
latched = obj;
setPosition(latched.xCoord + 0.5F, latched.yCoord + 2.8F, latched.zCoord + 0.5F);
prevPosX = posX;
prevPosY = posY;
prevPosZ = posZ;
color = c;
dataWatcher.updateObject(2, new Byte((byte)1)); /* Is latched */
dataWatcher.updateObject(3, new Integer(latched != null ? latched.xCoord : 0)); /* Latched X */
dataWatcher.updateObject(4, new Integer(latched != null ? latched.yCoord : 0)); /* Latched Y */
dataWatcher.updateObject(5, new Integer(latched != null ? latched.zCoord : 0)); /* Latched Z */
dataWatcher.updateObject(6, new Integer(-1)); /* Latched entity ID */
}
@Override
public void onUpdate()
{
prevPosX = posX;
prevPosY = posY;
prevPosZ = posZ;
if(posY > 255)
{
pop();
return;
}
if(worldObj.isRemote)
{
if(dataWatcher.getWatchableObjectByte(2) == 1)
{
latched = new Coord4D(dataWatcher.getWatchableObjectInt(3), dataWatcher.getWatchableObjectInt(4), dataWatcher.getWatchableObjectInt(5), worldObj.provider.dimensionId);
}
else {
latched = null;
}
if(dataWatcher.getWatchableObjectByte(2) == 2)
{
latchedEntity = (EntityLivingBase)worldObj.getEntityByID(dataWatcher.getWatchableObjectInt(6));
}
else {
latchedEntity = null;
}
}
else {
if(hasCachedEntity)
{
findCachedEntity();
cachedEntityUUID = null;
hasCachedEntity = false;
}
if(ticksExisted == 1)
{
dataWatcher.updateObject(2, new Byte(latched != null ? (byte)1 : (latchedEntity != null ? (byte)2 : (byte)0))); /* Is latched */
dataWatcher.updateObject(3, new Integer(latched != null ? latched.xCoord : 0)); /* Latched X */
dataWatcher.updateObject(4, new Integer(latched != null ? latched.yCoord : 0)); /* Latched Y */
dataWatcher.updateObject(5, new Integer(latched != null ? latched.zCoord : 0)); /* Latched Z */
dataWatcher.updateObject(6, new Integer(latchedEntity != null ? latchedEntity.getEntityId() : -1)); /* Latched entity ID */
}
}
if(!worldObj.isRemote)
{
if(latched != null && (latched.exists(worldObj) && latched.isAirBlock(worldObj)))
{
latched = null;
dataWatcher.updateObject(2, (byte)0); /* Is latched */
}
if(latchedEntity != null && (latchedEntity.getHealth() <= 0 || latchedEntity.isDead || !worldObj.loadedEntityList.contains(latchedEntity)))
{
latchedEntity = null;
dataWatcher.updateObject(2, (byte)0); /* Is latched */
}
}
if(!isLatched())
{
motionY = Math.min(motionY*1.02F, 0.2F);
moveEntity(motionX, motionY, motionZ);
motionX *= 0.98;
motionZ *= 0.98;
if(onGround)
{
motionX *= 0.7;
motionZ *= 0.7;
}
if(motionY == 0)
{
motionY = 0.04;
}
}
else if(latched != null)
{
motionX = 0;
motionY = 0;
motionZ = 0;
}
else if(latchedEntity != null && latchedEntity.getHealth() > 0)
{
int floor = getFloor(latchedEntity);
if(latchedEntity.posY-(floor+1) < -0.1)
{
latchedEntity.motionY = Math.max(0.04, latchedEntity.motionY*1.015);
}
else if(latchedEntity.posY-(floor+1) > 0.1)
{
latchedEntity.motionY = Math.min(-0.04, latchedEntity.motionY*1.015);
}
else {
latchedEntity.motionY = 0;
}
setPosition(latchedEntity.posX, latchedEntity.posY + latchedEntity.height + 1.7F, latchedEntity.posZ);
}
}
private int getFloor(EntityLivingBase entity)
{
int xPos = MathHelper.floor_double(entity.posX);
int yPos = MathHelper.floor_double(entity.posY);
int zPos = MathHelper.floor_double(entity.posZ);
for(int i = yPos; i > 0; i--)
{
if(i < 256 && !worldObj.isAirBlock(xPos, i, zPos))
{
return i+1;
}
}
return -1;
}
private void findCachedEntity()
{
for(Object obj : worldObj.loadedEntityList)
{
if(obj instanceof EntityLivingBase)
{
EntityLivingBase entity = (EntityLivingBase)obj;
if(entity.getUniqueID().equals(cachedEntityUUID))
{
latchedEntity = entity;
}
}
}
}
private void pop()
{
worldObj.playSoundAtEntity(this, "mekanism:etc.Pop", 1, 1);
if(worldObj.isRemote)
{
for(int i = 0; i < 10; i++)
{
try {
doParticle();
} catch(Throwable t) {}
}
}
setDead();
}
@SideOnly(Side.CLIENT)
private void doParticle()
{
Pos3D pos = new Pos3D(posX + (rand.nextFloat()*.6 - 0.3), posY - 0.8 + (rand.nextFloat()*.6 - 0.3), posZ + (rand.nextFloat()*.6 - 0.3));
EntityFX fx = new EntityReddustFX(worldObj, pos.xPos, pos.yPos, pos.zPos, 1, 0, 0, 0);
fx.setRBGColorF(color.getColor(0), color.getColor(1), color.getColor(2));
Minecraft.getMinecraft().effectRenderer.addEffect(fx);
}
@Override
public boolean canBePushed()
{
return latched == null;
}
@Override
public boolean canBeCollidedWith()
{
return !isDead;
}
@Override
protected boolean canTriggerWalking()
{
return false;
}
@Override
protected void entityInit() {}
@Override
protected void readEntityFromNBT(NBTTagCompound nbtTags)
{
color = EnumColor.values()[nbtTags.getInteger("color")];
if(nbtTags.hasKey("latched"))
{
latched = Coord4D.read(nbtTags.getCompoundTag("latched"));
}
if(nbtTags.hasKey("idMost"))
{
hasCachedEntity = true;
cachedEntityUUID = new UUID(nbtTags.getLong("idMost"), nbtTags.getLong("idLeast"));
}
}
@Override
protected void writeEntityToNBT(NBTTagCompound nbtTags)
{
nbtTags.setInteger("color", color.ordinal());
if(latched != null)
{
nbtTags.setTag("latched", latched.write(new NBTTagCompound()));
}
if(latchedEntity != null)
{
nbtTags.setLong("idMost", latchedEntity.getUniqueID().getMostSignificantBits());
nbtTags.setLong("idLeast", latchedEntity.getUniqueID().getLeastSignificantBits());
}
}
@Override
public boolean hitByEntity(Entity entity)
{
pop();
return true;
}
@Override
public void writeSpawnData(ByteBuf data)
{
data.writeDouble(posX);
data.writeDouble(posY);
data.writeDouble(posZ);
data.writeInt(color.ordinal());
if(latched != null)
{
data.writeByte((byte)1);
data.writeInt(latched.xCoord);
data.writeInt(latched.yCoord);
data.writeInt(latched.zCoord);
data.writeInt(latched.dimensionId);
}
else if(latchedEntity != null)
{
data.writeByte((byte)2);
data.writeInt(latchedEntity.getEntityId());
}
else {
data.writeByte((byte)0);
}
}
@Override
public void readSpawnData(ByteBuf data)
{
setPosition(data.readDouble(), data.readDouble(), data.readDouble());
color = EnumColor.values()[data.readInt()];
byte type = data.readByte();
if(type == 1)
{
latched = Coord4D.read(data);
}
else if(type == 2)
{
latchedEntity = (EntityLivingBase)worldObj.getEntityByID(data.readInt());
}
else {
latched = null;
}
}
@Override
public void setDead()
{
super.setDead();
if(latchedEntity != null)
{
latchedEntity.isAirBorne = false;
}
}
@Override
public boolean isInRangeToRenderDist(double dist)
{
return dist <= 64;
}
@Override
public boolean isInRangeToRender3d(double p_145770_1_, double p_145770_3_, double p_145770_5_)
{
return true;
}
@Override
public boolean attackEntityFrom(DamageSource dmgSource, float damage)
{
if(isEntityInvulnerable())
{
return false;
}
else {
setBeenAttacked();
if(dmgSource != DamageSource.magic && dmgSource != DamageSource.drown && dmgSource != DamageSource.fall)
{
pop();
return true;
}
return false;
}
}
public boolean isLatched()
{
if(!worldObj.isRemote)
{
return latched != null || latchedEntity != null;
}
else {
return dataWatcher.getWatchableObjectByte(2) > 0;
}
}
public boolean isLatchedToEntity()
{
return dataWatcher.getWatchableObjectByte(2) == 2 && latchedEntity != null;
}
}