package at.chaosfield.openradio.entity;
import at.chaosfield.openradio.OpenRadio;
import at.chaosfield.openradio.block.LaserBlock;
import at.chaosfield.openradio.interfaces.ILaserModifier;
import at.chaosfield.openradio.render.LaserParticle;
import at.chaosfield.openradio.tileentity.LaserTileEntity;
import at.chaosfield.openradio.util.DamageSourceLaser;
import at.chaosfield.openradio.util.Location;
import io.netty.buffer.ByteBuf;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.server.MinecraftServer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.WorldServer;
import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.Entity;
import net.minecraft.entity.IProjectile;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.world.World;
import net.minecraftforge.common.DimensionManager;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Jakob Riepler (XDjackieXD)
*/
public class LaserEntity extends Entity implements IProjectile, IEntityAdditionalSpawnData{
private List<Location> appliedModifier = new ArrayList<Location>();
private Location senderLaser;
private Location locNow;
private double distance = 1;
private double maxDistance = 0;
private double multiplier = 1;
private float colorR = 1.0F, colorG = 0, colorB = 0, colorA = 1.0F;
private int laserTier = 1;
Vec3d lastParticle = new Vec3d(0, 0, 0);
private int lastParticleDim;
public LaserEntity(World world){
super(world);
this.setSize(0.25F, 0.25F);
this.setInvisible(true);
}
protected void entityInit(){
}
@SideOnly(Side.CLIENT)
public boolean isInRangeToRenderDist(double renderDistance){
/*double d1 = this.boundingBox.getAverageEdgeLength() * 4.0D;
d1 *= 64.0D;
return renderDistance < d1 * d1;*/
return false;
}
public LaserEntity(World world, double x, double y, double z, double accX, double accY, double accZ, int laserDim, int laserX, int laserY, int laserZ, double maxDistance, int laserTier){
this(world);
this.setSize(0.25F, 0.25F);
this.setPosition(x, y, z);
this.motionX = accX;
this.motionY = accY;
this.motionZ = accZ;
this.senderLaser = new Location(laserDim, laserX, laserY, laserZ);
this.maxDistance = maxDistance;
if(!worldObj.isRemote){
this.locNow = new Location(world.provider.getDimension(), (int) Math.floor(x), (int) Math.floor(y), (int) Math.floor(z));
}
this.lastParticle = new Vec3d(x, y, z);
this.lastParticleDim = laserDim;
this.laserTier = laserTier;
}
public void setThrowableHeading(double accX, double accY, double accZ, float accMult, float accRand){
float f2 = MathHelper.sqrt_double(accX * accX + accY * accY + accZ * accZ);
accX /= (double) f2;
accY /= (double) f2;
accZ /= (double) f2;
accX += this.rand.nextGaussian() * 0.007499999832361937D * (double) accRand;
accY += this.rand.nextGaussian() * 0.007499999832361937D * (double) accRand;
accZ += this.rand.nextGaussian() * 0.007499999832361937D * (double) accRand;
accX *= (double) accMult;
accY *= (double) accMult;
accZ *= (double) accMult;
this.motionX = accX;
this.motionY = accY;
this.motionZ = accZ;
float f3 = MathHelper.sqrt_double(accX * accX + accZ * accZ);
//noinspection SuspiciousNameCombination
this.prevRotationYaw = this.rotationYaw = (float) (Math.atan2(accX, accZ) * 180.0D / 3.141592653589793D);
this.prevRotationPitch = this.rotationPitch = (float) (Math.atan2(accY, (double) f3) * 180.0D / 3.141592653589793D);
}
public void setVelocity(double accX, double accY, double accZ){
this.motionX = accX;
this.motionY = accY;
this.motionZ = accZ;
}
@Override
public void onEntityUpdate(){
this.lastTickPosX = this.posX;
this.lastTickPosY = this.posY;
this.lastTickPosZ = this.posZ;
/**** Replace Super onUpdate because some not-needed stuff in there ****/
this.worldObj.theProfiler.startSection("entityBaseTick");
this.prevDistanceWalkedModified = this.distanceWalkedModified;
this.prevPosX = this.posX;
this.prevPosY = this.posY;
this.prevPosZ = this.posZ;
this.prevRotationPitch = this.rotationPitch;
this.prevRotationYaw = this.rotationYaw;
if(!this.worldObj.isRemote && this.worldObj instanceof WorldServer){
this.worldObj.theProfiler.startSection("portal");
MinecraftServer minecraftserver = this.worldObj.getMinecraftServer();
int i = this.getMaxInPortalTime();
if(this.inPortal){
if(minecraftserver != null && minecraftserver.getAllowNether()){
if(this.getRidingEntity() == null && this.portalCounter++ >= i){
this.portalCounter = i;
this.timeUntilPortal = this.getPortalCooldown();
int j;
if(this.worldObj.provider.getDimension() == -1){
j = 0;
}else{
j = -1;
}
this.changeDimension(j);
}
this.inPortal = false;
}
}else{
if(this.portalCounter > 0){
this.portalCounter -= 4;
}
if(this.portalCounter < 0){
this.portalCounter = 0;
}
}
if(this.timeUntilPortal > 0){
--this.timeUntilPortal;
}
this.worldObj.theProfiler.endSection();
}
if(this.posY < -64.0D){
this.kill();
}
this.firstUpdate = false;
this.worldObj.theProfiler.endSection();
/***********************************************************************/
if(!worldObj.isRemote){
if(this.locNow != null){
if(((int) Math.floor(this.posX) != this.locNow.getX()) || ((int) Math.floor(this.posY) != this.locNow.getY()) || ((int) Math.floor(this.posZ) != this.locNow.getZ()) || (worldObj.provider.getDimension() != this.locNow.getDim())){
this.locNow.setX((int) Math.floor(this.posX));
this.locNow.setY((int) Math.floor(this.posY));
this.locNow.setZ((int) Math.floor(this.posZ));
this.locNow.setDim(worldObj.provider.getDimension());
Block block = DimensionManager.getWorld(this.locNow.getDim()).getBlockState(this.locNow.getPos()).getBlock();
if(block.isAir(DimensionManager.getWorld(this.locNow.getDim()).getBlockState(this.locNow.getPos()), DimensionManager.getWorld(this.locNow.getDim()), this.locNow.getPos())){
distance += OpenRadio.instance.settings.DistancePerAir;
}else if(!block.getBlockState().getBaseState().getMaterial().isSolid()){
distance += OpenRadio.instance.settings.DistancePerTransparent;
}
}
}else{
this.locNow = new Location(worldObj.provider.getDimension(), (int) Math.floor(this.posX), (int) Math.floor(this.posY), (int) Math.floor(this.posZ));
}
if(distance > maxDistance * multiplier){
this.setDead();
}
}else{
if(lastParticleDim != this.worldObj.provider.getDimension() || ((new Vec3d(this.posX, this.posY, this.posZ)).distanceTo(lastParticle) >= 1.0)){
lastParticleDim = this.worldObj.provider.getDimension();
lastParticle = new Vec3d(this.posX, this.posY, this.posZ);
renderParticle();
}
}
if(!worldObj.isRemote){
List<Entity> list = this.worldObj.getEntitiesWithinAABBExcludingEntity(this, this.getEntityBoundingBox().addCoord(this.motionX, this.motionY, this.motionZ));
for(Entity entity : list){
if(entity instanceof EntityLivingBase && entity.canBeCollidedWith()){
if(!(entity instanceof EntityPlayer && ((EntityPlayer) entity).isCreative()))
switch(this.laserTier){
case 2:
entity.attackEntityFrom(DamageSourceLaser.DAMAGE_SOURCE_LASER, 3);
entity.setFire(1);
break;
case 3:
entity.attackEntityFrom(DamageSourceLaser.DAMAGE_SOURCE_LASER, 6);
entity.setFire(10);
break;
default:
}
}
}
}
Vec3d posVec = new Vec3d(this.posX, this.posY, this.posZ);
Vec3d nextPosVec = new Vec3d(this.posX + this.motionX, this.posY + this.motionY, this.posZ + this.motionZ);
RayTraceResult movingobjectposition = this.worldObj.rayTraceBlocks(posVec, nextPosVec);
if(movingobjectposition != null){
if(movingobjectposition.typeOfHit == RayTraceResult.Type.BLOCK)
if(this.worldObj.getBlockState(movingobjectposition.getBlockPos()).getBlock() == Blocks.PORTAL){
this.setPortal(this.getPosition());
}else{
if(movingobjectposition.getBlockPos().getX() == MathHelper.floor_double(this.posX) &&
movingobjectposition.getBlockPos().getY() == MathHelper.floor_double(this.posY) &&
movingobjectposition.getBlockPos().getZ() == MathHelper.floor_double(this.posZ)){
movingobjectposition.sideHit = movingobjectposition.sideHit.getOpposite();
}
this.onImpact(movingobjectposition);
}
}
this.posX += this.motionX;
this.posY += this.motionY;
this.posZ += this.motionZ;
this.setPosition(this.posX, this.posY, this.posZ);
}
public void setTier(int laserTier){
this.colorR = OpenRadio.instance.settings.LaserColor[laserTier - 1][0];
this.colorG = OpenRadio.instance.settings.LaserColor[laserTier - 1][1];
this.colorB = OpenRadio.instance.settings.LaserColor[laserTier - 1][2];
this.colorA = OpenRadio.instance.settings.LaserColor[laserTier - 1][3];
}
public void addDistance(int blocks){
distance += blocks;
}
@SideOnly(Side.CLIENT)
private void renderParticle(){
LaserParticle particle = new LaserParticle(this.worldObj, this.posX, this.posY, this.posZ, 0.75F, this.colorR, this.colorG, this.colorB, this.colorA);
particle.setRBGColorF(this.colorR, this.colorG, this.colorB);
Minecraft.getMinecraft().effectRenderer.addEffect(particle);
}
public void writeEntityToNBT(NBTTagCompound tagCompound){
tagCompound.setTag("direction", this.newDoubleNBTList(this.motionX, this.motionY, this.motionZ));
tagCompound.setIntArray("senderLaser", new int[]{this.senderLaser.getDim(), this.senderLaser.getX(), this.senderLaser.getY(), this.senderLaser.getZ()});
tagCompound.setTag("color", this.newFloatNBTList(this.colorR, this.colorG, this.colorB, this.colorA));
tagCompound.setInteger("lastParticleDim", this.lastParticleDim);
tagCompound.setDouble("distance", this.distance);
tagCompound.setDouble("maxDistance", this.maxDistance);
tagCompound.setDouble("multiplier", this.multiplier);
}
public void readEntityFromNBT(NBTTagCompound tagCompound){
if(tagCompound.hasKey("direction", 9)){
NBTTagList nbttaglist = tagCompound.getTagList("direction", 6);
this.motionX = nbttaglist.getDoubleAt(0);
this.motionY = nbttaglist.getDoubleAt(1);
this.motionZ = nbttaglist.getDoubleAt(2);
}else{
this.setDead();
}
int[] sender = tagCompound.getIntArray("senderLaser");
this.senderLaser = new Location(sender[0], sender[1], sender[2], sender[3]);
NBTTagList nbttaglist = tagCompound.getTagList("color", 5);
this.colorR = nbttaglist.getFloatAt(0);
this.colorG = nbttaglist.getFloatAt(1);
this.colorB = nbttaglist.getFloatAt(2);
this.colorA = nbttaglist.getFloatAt(3);
this.lastParticleDim = tagCompound.getInteger("lastParticleDim");
this.distance = tagCompound.getDouble("distance");
this.maxDistance = tagCompound.getDouble("maxDistance");
this.multiplier = tagCompound.getDouble("multiplier");
}
@Override
public boolean writeToNBTOptional(NBTTagCompound nbtTagCompound){
//Don't save to disk!
return false;
}
protected void onImpact(RayTraceResult mop){
TileEntity senderLaserTe = null;
if(!worldObj.isRemote){
senderLaserTe = DimensionManager.getWorld(senderLaser.getDim()).getTileEntity(senderLaser.getPos());
}
if(mop.typeOfHit == RayTraceResult.Type.BLOCK){
Block hitBlock = this.worldObj.getBlockState(mop.getBlockPos()).getBlock();
if(hitBlock instanceof LaserBlock && senderLaserTe instanceof LaserTileEntity){
TileEntity te = this.worldObj.getTileEntity(mop.getBlockPos());
if(te instanceof LaserTileEntity){
if(mop.sideHit.getIndex() == te.getBlockMetadata()){
((LaserTileEntity) senderLaserTe).setDestination(this.worldObj.provider.getDimension(), mop.getBlockPos(), this.distance);
}else
((LaserTileEntity) senderLaserTe).disconnect();
}else
((LaserTileEntity) senderLaserTe).disconnect();
this.setDead();
}else if(hitBlock instanceof ILaserModifier){
if(!appliedModifier.contains(new Location(this.dimension, mop.getBlockPos()))){
appliedModifier.add(new Location(this.dimension, mop.getBlockPos()));
((ILaserModifier) hitBlock).hitByLaser(this, mop.getBlockPos(), this.worldObj, mop.sideHit);
}
}else if(this.worldObj.getBlockState(mop.getBlockPos()).isOpaqueCube()){
this.setDead();
if(senderLaserTe instanceof LaserTileEntity)
((LaserTileEntity) senderLaserTe).disconnect();
}
}else{
this.setDead();
if(senderLaserTe instanceof LaserTileEntity)
((LaserTileEntity) senderLaserTe).disconnect();
}
}
public double getMultiplier(){
return multiplier;
}
public void setMultiplier(double multiplier){
this.multiplier = multiplier;
}
public double getMaxDistance(){
return maxDistance;
}
@Override
public void writeSpawnData(ByteBuf buffer){
buffer.writeInt(this.laserTier);
}
@Override
public void readSpawnData(ByteBuf additionalData){
this.laserTier = additionalData.readInt();
setTier(this.laserTier);
}
}