package micdoodle8.mods.galacticraft.planets.asteroids.tile;
import micdoodle8.mods.galacticraft.api.power.ILaserNode;
import micdoodle8.mods.galacticraft.api.vector.BlockVec3;
import micdoodle8.mods.galacticraft.api.vector.Vector3;
import micdoodle8.mods.galacticraft.core.Constants;
import micdoodle8.mods.galacticraft.core.tile.TileEntityAdvanced;
import micdoodle8.mods.miccore.Annotations.NetworkedField;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.BlockPos;
import net.minecraft.util.EnumFacing;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
import net.minecraftforge.fml.relauncher.Side;
import java.util.LinkedList;
public abstract class TileEntityBeamOutput extends TileEntityAdvanced implements ILaserNode
{
public LinkedList<ILaserNode> nodeList = new LinkedList<ILaserNode>();
@NetworkedField(targetSide = Side.CLIENT)
public BlockPos targetVec = new BlockPos(-1, -1, -1);
public float pitch;
public float yaw;
private BlockPos preLoadTarget = null;
private BlockPos lastTargetVec = new BlockPos(-1, -1, -1);
@Override
public void update()
{
if (this.preLoadTarget != null)
{
TileEntity tileAtTarget = this.worldObj.getTileEntity(this.preLoadTarget);
if (tileAtTarget != null && tileAtTarget instanceof ILaserNode)
{
this.setTarget((ILaserNode) tileAtTarget);
this.preLoadTarget = null;
}
}
super.update();
if (!this.targetVec.equals(this.lastTargetVec))
{
this.markDirty();
}
this.lastTargetVec = this.targetVec;
if (this.worldObj.isRemote)
{
this.updateOrientation();
}
else if (this.targetVec.getX() == -1 && this.targetVec.getY() == -1 && this.targetVec.getZ() == -1)
{
this.initiateReflector();
}
}
@Override
public void invalidate()
{
super.invalidate();
this.invalidateReflector();
}
@Override
public void onLoad()
{
}
@Override
public void onChunkUnload()
{
this.invalidateReflector();
}
public void invalidateReflector()
{
for (ILaserNode node : this.nodeList)
{
node.removeNode(this);
}
this.nodeList.clear();
}
public void initiateReflector()
{
this.nodeList.clear();
int chunkXMin = this.getPos().getX() - 15 >> 4;
int chunkZMin = this.getPos().getZ() - 15 >> 4;
int chunkXMax = this.getPos().getX() + 15 >> 4;
int chunkZMax = this.getPos().getZ() + 15 >> 4;
for (int cX = chunkXMin; cX <= chunkXMax; cX++)
{
for (int cZ = chunkZMin; cZ <= chunkZMax; cZ++)
{
if (this.worldObj.getChunkProvider().chunkExists(cX, cZ))
{
Chunk chunk = this.worldObj.getChunkFromChunkCoords(cX, cZ);
for (Object obj : chunk.getTileEntityMap().values())
{
if (obj != this && obj instanceof ILaserNode)
{
BlockVec3 deltaPos = new BlockVec3(this).subtract(new BlockVec3(((ILaserNode) obj).getTile()));
if (deltaPos.x < 16 && deltaPos.y < 16 && deltaPos.z < 16)
{
ILaserNode laserNode = (ILaserNode) obj;
if (this.canConnectTo(laserNode) && laserNode.canConnectTo(this))
{
this.addNode(laserNode);
laserNode.addNode(this);
}
}
}
}
}
}
}
this.setTarget(this.nodeList.peekFirst());
}
@Override
public void addNode(ILaserNode node)
{
int index = -1;
for (int i = 0; i < this.nodeList.size(); i++)
{
if (new BlockVec3(this.nodeList.get(i).getTile()).equals(new BlockVec3(node.getTile())))
{
index = i;
break;
}
}
if (index != -1)
{
this.nodeList.set(index, node);
return;
}
if (this.nodeList.isEmpty())
{
this.nodeList.add(node);
}
else
{
int nodeCompare = this.nodeList.get(0).compareTo(node, new BlockVec3(this));
if (nodeCompare <= 0)
{
this.nodeList.addFirst(node);
return;
}
nodeCompare = this.nodeList.get(this.nodeList.size() - 1).compareTo(node, new BlockVec3(this));
if (nodeCompare >= 0)
{
this.nodeList.addLast(node);
return;
}
index = 1;
while (index < this.nodeList.size())
{
index++;
}
this.nodeList.add(index, node);
}
}
@Override
public void removeNode(ILaserNode node)
{
int index = -1;
for (int i = 0; i < this.nodeList.size(); i++)
{
if (new BlockVec3(this.nodeList.get(i).getTile()).equals(new BlockVec3(node.getTile())))
{
index = i;
break;
}
}
if (new BlockVec3(node.getTile()).equals(new BlockVec3(this.targetVec)))
{
if (index == 0)
{
if (this.nodeList.size() > 1)
{
this.setTarget(this.nodeList.get(index + 1));
}
else
{
this.setTarget(null);
}
}
else if (index > 0)
{
this.setTarget(this.nodeList.get(index - 1));
}
else
{
this.setTarget(null);
}
}
if (index != -1)
{
this.nodeList.remove(index);
}
}
public void updateOrientation()
{
if (this.getTarget() != null)
{
Vector3 direction = Vector3.subtract(this.getOutputPoint(false), this.getTarget().getInputPoint()).normalize();
this.pitch = (float) -Vector3.getAngle(new Vector3(-direction.x, -direction.y, -direction.z), new Vector3(0, 1, 0)) * Constants.RADIANS_TO_DEGREES + 90;
this.yaw = (float) -(Math.atan2(direction.z, direction.x) * Constants.RADIANS_TO_DEGREES) + 90;
}
}
@Override
public TileEntity getTile()
{
return this;
}
@Override
public int compareTo(ILaserNode otherNode, BlockVec3 origin)
{
int thisDistance = new BlockVec3(this).subtract(origin).getMagnitudeSquared();
int otherDistance = new BlockVec3(otherNode.getTile()).subtract(origin).getMagnitudeSquared();
if (thisDistance < otherDistance)
{
return 1;
}
else if (thisDistance > otherDistance)
{
return -1;
}
return 0;
}
public boolean onMachineActivated(World worldIn, BlockPos pos, IBlockState state, EntityPlayer playerIn, EnumFacing side, float hitX, float hitY, float hitZ)
{
if (this.nodeList.size() > 1)
{
int index = -1;
if (this.getTarget() != null)
{
for (int i = 0; i < this.nodeList.size(); i++)
{
if (new BlockVec3(this.nodeList.get(i).getTile()).equals(new BlockVec3(this.getTarget().getTile())))
{
index = i;
break;
}
}
}
if (index == -1)
{
// This shouldn't happen, but just in case...
this.initiateReflector();
}
else
{
index++;
index %= this.nodeList.size();
this.setTarget(this.nodeList.get(index));
return true;
}
}
return false;
}
@Override
public ILaserNode getTarget()
{
if (this.targetVec.getX() != -1 || this.targetVec.getY() != -1 || this.targetVec.getZ() != -1)
{
TileEntity tileAtTarget = this.worldObj.getTileEntity(this.targetVec);
if (tileAtTarget != null && tileAtTarget instanceof ILaserNode)
{
return (ILaserNode) tileAtTarget;
}
return null;
}
return null;
}
public void setTarget(ILaserNode target)
{
if (target != null)
{
this.targetVec = target.getTile().getPos();
}
else
{
this.targetVec = new BlockPos(-1, -1, -1);
}
}
@Override
public void readFromNBT(NBTTagCompound nbt)
{
super.readFromNBT(nbt);
if (nbt.getBoolean("HasTarget"))
{
this.preLoadTarget = new BlockPos(nbt.getInteger("TargetX"), nbt.getInteger("TargetY"), nbt.getInteger("TargetZ"));
}
}
@Override
public void writeToNBT(NBTTagCompound nbt)
{
super.writeToNBT(nbt);
nbt.setBoolean("HasTarget", this.getTarget() != null);
if (this.getTarget() != null)
{
nbt.setInteger("TargetX", this.getTarget().getTile().getPos().getX());
nbt.setInteger("TargetY", this.getTarget().getTile().getPos().getY());
nbt.setInteger("TargetZ", this.getTarget().getTile().getPos().getZ());
}
}
}