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; } }