package pneumaticCraft.common.block;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.entity.Entity;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.util.Vec3;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.common.util.ForgeDirection;
import org.apache.commons.lang3.tuple.Pair;
import pneumaticCraft.common.block.tubes.ModuleRegistrator;
import pneumaticCraft.common.block.tubes.TubeModule;
import pneumaticCraft.common.block.tubes.TubeModuleRedstoneEmitting;
import pneumaticCraft.common.item.ItemTubeModule;
import pneumaticCraft.common.item.Itemss;
import pneumaticCraft.common.thirdparty.ModInteractionUtils;
import pneumaticCraft.common.tileentity.TileEntityPressureTube;
import pneumaticCraft.common.util.PneumaticCraftUtils;
import pneumaticCraft.lib.BBConstants;
import pneumaticCraft.lib.PneumaticValues;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public class BlockPressureTube extends BlockPneumaticCraftModeled{
public AxisAlignedBB[] boundingBoxes = new AxisAlignedBB[6];
private final float dangerPressure, criticalPressure;
private final int volume;
public BlockPressureTube(Material par2Material, float dangerPressure, float criticalPressure, int volume){
super(par2Material);
double width = (BBConstants.PRESSURE_PIPE_MAX_POS - BBConstants.PRESSURE_PIPE_MIN_POS) / 2;
double height = BBConstants.PRESSURE_PIPE_MIN_POS;
boundingBoxes[0] = AxisAlignedBB.getBoundingBox(0.5 - width, BBConstants.PRESSURE_PIPE_MIN_POS - height, 0.5 - width, 0.5 + width, BBConstants.PRESSURE_PIPE_MIN_POS, 0.5 + width);
boundingBoxes[1] = AxisAlignedBB.getBoundingBox(0.5 - width, BBConstants.PRESSURE_PIPE_MAX_POS, 0.5 - width, 0.5 + width, BBConstants.PRESSURE_PIPE_MAX_POS + height, 0.5 + width);
boundingBoxes[2] = AxisAlignedBB.getBoundingBox(0.5 - width, 0.5 - width, BBConstants.PRESSURE_PIPE_MIN_POS - height, 0.5 + width, 0.5 + width, BBConstants.PRESSURE_PIPE_MIN_POS);
boundingBoxes[3] = AxisAlignedBB.getBoundingBox(0.5 - width, 0.5 - width, BBConstants.PRESSURE_PIPE_MAX_POS, 0.5 + width, 0.5 + width, BBConstants.PRESSURE_PIPE_MAX_POS + height);
boundingBoxes[4] = AxisAlignedBB.getBoundingBox(BBConstants.PRESSURE_PIPE_MIN_POS - height, 0.5 - width, 0.5 - width, BBConstants.PRESSURE_PIPE_MIN_POS, 0.5 + width, 0.5 + width);
boundingBoxes[5] = AxisAlignedBB.getBoundingBox(BBConstants.PRESSURE_PIPE_MAX_POS, 0.5 - width, 0.5 - width, BBConstants.PRESSURE_PIPE_MAX_POS + height, 0.5 + width, 0.5 + width);
this.dangerPressure = dangerPressure;
this.criticalPressure = criticalPressure;
this.volume = volume;
}
@Override
protected Class<? extends TileEntity> getTileEntityClass(){
return TileEntityPressureTube.class;
}
@Override
public TileEntity createNewTileEntity(World world, int metadata){
return new TileEntityPressureTube(dangerPressure, criticalPressure, volume);
}
@Override
public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int par6, float par7, float par8, float par9){
if(!world.isRemote) {
if(tryPlaceModule(player, world, x, y, z, par6, false)) return true;
}
if(!player.isSneaking()) {
TubeModule module = getLookedModule(world, x, y, z, player);
if(module != null) {
return module.onActivated(player);
}
}
return false;
}
public boolean tryPlaceModule(EntityPlayer player, World world, int x, int y, int z, int par6, boolean simulate){
if(player.getCurrentEquippedItem() != null) {
if(player.getCurrentEquippedItem().getItem() instanceof ItemTubeModule) {
TileEntityPressureTube pressureTube = ModInteractionUtils.getInstance().getTube(world.getTileEntity(x, y, z));
if(pressureTube.modules[par6] == null && ModInteractionUtils.getInstance().occlusionTest(boundingBoxes[par6], world.getTileEntity(x, y, z))) {
TubeModule module = ModuleRegistrator.getModule(((ItemTubeModule)player.getCurrentEquippedItem().getItem()).moduleName);
if(simulate) module.markFake();
pressureTube.setModule(module, ForgeDirection.getOrientation(par6));
if(!simulate) {
onNeighborBlockChange(world, x, y, z, this);
world.notifyBlocksOfNeighborChange(x, y, z, this, ForgeDirection.getOrientation(par6).getOpposite().ordinal());
if(!player.capabilities.isCreativeMode) player.getCurrentEquippedItem().stackSize--;
world.playSoundEffect(x + 0.5, y + 0.5, z + 0.5, Block.soundTypeGlass.getStepResourcePath(), Block.soundTypeGlass.getVolume() * 5.0F, Block.soundTypeGlass.getPitch() * .9F);
}
return true;
}
} else if(player.getCurrentEquippedItem().getItem() == Itemss.advancedPCB && !simulate) {
TubeModule module = BlockPressureTube.getLookedModule(world, x, y, z, player);
if(module != null && !module.isUpgraded() && module.canUpgrade()) {
if(!world.isRemote) {
module.upgrade();
if(!player.capabilities.isCreativeMode) player.getCurrentEquippedItem().stackSize--;
}
return true;
}
}
}
return false;
}
public static TubeModule getLookedModule(World world, int x, int y, int z, EntityPlayer player){
Pair<Vec3, Vec3> vecs = PneumaticCraftUtils.getStartAndEndLookVec(player);
MovingObjectPosition mop = Blockss.pressureTube.collisionRayTrace(world, x, y, z, vecs.getLeft(), vecs.getRight());
if(mop != null && mop.hitInfo instanceof ForgeDirection && (ForgeDirection)mop.hitInfo != ForgeDirection.UNKNOWN) {
TileEntityPressureTube tube = ModInteractionUtils.getInstance().getTube(world.getTileEntity(x, y, z));
return tube.modules[((ForgeDirection)mop.hitInfo).ordinal()];
}
return null;
}
@Override
public MovingObjectPosition collisionRayTrace(World world, int x, int y, int z, Vec3 origin, Vec3 direction){
MovingObjectPosition bestMOP = null;
AxisAlignedBB bestAABB = null;
setBlockBounds(BBConstants.PRESSURE_PIPE_MIN_POS, BBConstants.PRESSURE_PIPE_MIN_POS, BBConstants.PRESSURE_PIPE_MIN_POS, BBConstants.PRESSURE_PIPE_MAX_POS, BBConstants.PRESSURE_PIPE_MAX_POS, BBConstants.PRESSURE_PIPE_MAX_POS);
MovingObjectPosition mop = super.collisionRayTrace(world, x, y, z, origin, direction);
if(isCloserMOP(origin, bestMOP, mop)) {
bestMOP = mop;
bestAABB = AxisAlignedBB.getBoundingBox(minX, minY, minZ, maxX, maxY, maxZ);
}
TileEntityPressureTube tube = ModInteractionUtils.getInstance().getTube(world.getTileEntity(x, y, z));
for(int i = 0; i < 6; i++) {
if(tube.sidesConnected[i]) {
setBlockBounds(boundingBoxes[i]);
mop = super.collisionRayTrace(world, x, y, z, origin, direction);
if(isCloserMOP(origin, bestMOP, mop)) {
bestMOP = mop;
bestAABB = AxisAlignedBB.getBoundingBox(minX, minY, minZ, maxX, maxY, maxZ);
}
}
}
if(bestMOP != null) bestMOP.hitInfo = ForgeDirection.UNKNOWN;//unknown indicates we hit the tube.
TubeModule[] modules = tube.modules;
for(ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) {
if(modules[dir.ordinal()] != null) {
setBlockBounds(modules[dir.ordinal()].boundingBoxes[dir.ordinal()]);
mop = super.collisionRayTrace(world, x, y, z, origin, direction);
if(isCloserMOP(origin, bestMOP, mop)) {
mop.hitInfo = dir;
bestMOP = mop;
bestAABB = AxisAlignedBB.getBoundingBox(minX, minY, minZ, maxX, maxY, maxZ);
}
}
}
if(bestAABB != null) setBlockBounds(bestAABB);
return bestMOP;
}
private boolean isCloserMOP(Vec3 origin, MovingObjectPosition originalMOP, MovingObjectPosition newMOP){
if(newMOP == null) return false;
if(originalMOP == null) return true;
return PneumaticCraftUtils.distBetween(origin, newMOP.hitVec) < PneumaticCraftUtils.distBetween(origin, originalMOP.hitVec);
}
@Override
public ItemStack getPickBlock(MovingObjectPosition target, World world, int x, int y, int z){
if(target.hitInfo == ForgeDirection.UNKNOWN) {
return super.getPickBlock(target, world, x, y, z);
} else {
TileEntityPressureTube tube = (TileEntityPressureTube)world.getTileEntity(x, y, z);
return new ItemStack(ModuleRegistrator.getModuleItem(tube.modules[((ForgeDirection)target.hitInfo).ordinal()].getType()));
}
}
private void setBlockBounds(AxisAlignedBB aabb){
this.setBlockBounds((float)aabb.minX, (float)aabb.minY, (float)aabb.minZ, (float)aabb.maxX, (float)aabb.maxY, (float)aabb.maxZ);
}
@Override
public boolean rotateBlock(World world, EntityPlayer player, int x, int y, int z, ForgeDirection side){
TileEntityPressureTube tube = ModInteractionUtils.getInstance().getTube(world.getTileEntity(x, y, z));
if(player.isSneaking()) {
TubeModule module = getLookedModule(world, x, y, z, player);
if(module != null) {
if(!player.capabilities.isCreativeMode) {
List<ItemStack> drops = module.getDrops();
for(ItemStack drop : drops) {
EntityItem entity = new EntityItem(world, x + 0.5, y + 0.5, z + 0.5);
entity.setEntityItemStack(drop);
world.spawnEntityInWorld(entity);
entity.onCollideWithPlayer(player);
}
}
tube.setModule(null, module.getDirection());
onNeighborBlockChange(world, x, y, z, this);
world.notifyBlocksOfNeighborChange(x, y, z, this, module.getDirection().getOpposite().ordinal());
return true;
}
if(!player.capabilities.isCreativeMode) {
EntityItem entity = new EntityItem(world, x + 0.5, y + 0.5, z + 0.5, new ItemStack(tube.maxPressure <= PneumaticValues.MAX_PRESSURE_PRESSURE_TUBE ? Blockss.pressureTube : Blockss.advancedPressureTube));
world.spawnEntityInWorld(entity);
entity.onCollideWithPlayer(player);
}
ModInteractionUtils.getInstance().removeTube(world.getTileEntity(x, y, z));
return true;
} else {
return super.rotateBlock(world, player, x, y, z, side);
}
}
@Override
public void breakBlock(World world, int x, int y, int z, Block block, int meta){
List<ItemStack> drops = getModuleDrops((TileEntityPressureTube)world.getTileEntity(x, y, z));
for(ItemStack drop : drops) {
EntityItem entity = new EntityItem(world, x + 0.5, y + 0.5, z + 0.5);
entity.setEntityItemStack(drop);
world.spawnEntityInWorld(entity);
}
super.breakBlock(world, x, y, z, block, meta);
}
public static List<ItemStack> getModuleDrops(TileEntityPressureTube tube){
List<ItemStack> drops = new ArrayList<ItemStack>();
for(TubeModule module : tube.modules) {
if(module != null) {
drops.addAll(module.getDrops());
}
}
return drops;
}
@Override
public void addCollisionBoxesToList(World world, int x, int y, int z, AxisAlignedBB axisalignedbb, List arraylist, Entity par7Entity){
setBlockBounds(BBConstants.PRESSURE_PIPE_MIN_POS, BBConstants.PRESSURE_PIPE_MIN_POS, BBConstants.PRESSURE_PIPE_MIN_POS, BBConstants.PRESSURE_PIPE_MAX_POS, BBConstants.PRESSURE_PIPE_MAX_POS, BBConstants.PRESSURE_PIPE_MAX_POS);
super.addCollisionBoxesToList(world, x, y, z, axisalignedbb, arraylist, par7Entity);
TileEntity te = world.getTileEntity(x, y, z);
TileEntityPressureTube tePt = (TileEntityPressureTube)te;
for(int i = 0; i < 6; i++) {
if(tePt.sidesConnected[i]) {
setBlockBounds(boundingBoxes[i]);
super.addCollisionBoxesToList(world, x, y, z, axisalignedbb, arraylist, par7Entity);
} else if(tePt.modules[i] != null) {
setBlockBounds(tePt.modules[i].boundingBoxes[i]);
super.addCollisionBoxesToList(world, x, y, z, axisalignedbb, arraylist, par7Entity);
}
}
setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
}
@Override
public void onBlockAdded(World world, int x, int y, int z){
super.onBlockAdded(world, x, y, z);
TileEntity te = world.getTileEntity(x, y, z);
if(te != null && te instanceof TileEntityPressureTube) {
TileEntityPressureTube tePt = (TileEntityPressureTube)te;
tePt.updateConnections(world, x, y, z);
}
}
@Override
@SideOnly(Side.CLIENT)
/**
* A randomly called display update to be able to add particles or other items for display
*/
public void randomDisplayTick(World par1World, int par2, int par3, int par4, Random par5Random){
TileEntity te = par1World.getTileEntity(par2, par3, par4);
if(te instanceof TileEntityPressureTube) {
TileEntityPressureTube tePt = (TileEntityPressureTube)te;
int l = 0;
for(TubeModule module : tePt.modules)
if(module != null) l = Math.max(l, module.getRedstoneLevel());
if(l > 0) {
// for(int i = 0; i < 4; i++){
double d0 = par2 + 0.5D + (par5Random.nextFloat() - 0.5D) * 0.5D;
double d1 = par3 + 0.5D + (par5Random.nextFloat() - 0.5D) * 0.5D;
double d2 = par4 + 0.5D + (par5Random.nextFloat() - 0.5D) * 0.5D;
float f = l / 15.0F;
float f1 = f * 0.6F + 0.4F;
float f2 = f * f * 0.7F - 0.5F;
float f3 = f * f * 0.6F - 0.7F;
if(f2 < 0.0F) {
f2 = 0.0F;
}
if(f3 < 0.0F) {
f3 = 0.0F;
}
// PacketDispatcher.sendPacketToAllPlayers(PacketHandlerPneumaticCraft.spawnParticle("reddust",
// d0, d1, d2, (double)f1, (double)f2, (double)f3));
par1World.spawnParticle("reddust", d0, d1, d2, f1, f2, f3);
// }
}
}
}
/**
* Returns true if the block is emitting direct/strong redstone power on the
* specified side. Args: World, X, Y, Z, side. Note that the side is
* reversed - eg it is 1 (up) when checking the bottom of the block.
*/
@Override
public int isProvidingStrongPower(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5){
return 0;
}
/**
* Returns true if the block is emitting indirect/weak redstone power on the
* specified side. If isBlockNormalCube returns true, standard redstone
* propagation rules will apply instead and this will not be called. Args:
* World, X, Y, Z, side. Note that the side is reversed - eg it is 1 (up)
* when checking the bottom of the block.
*/
@Override
public int isProvidingWeakPower(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int side){
TileEntity te = par1IBlockAccess.getTileEntity(par2, par3, par4);
if(te instanceof TileEntityPressureTube) {
TileEntityPressureTube tePt = (TileEntityPressureTube)te;
int redstoneLevel = 0;
for(int i = 0; i < 6; i++) {
if(tePt.modules[i] != null) {
if((side ^ 1) == i || i != side && tePt.modules[i].isInline()) {//if we are on the same side, or when we have an 'in line' module that is not on the opposite side.
redstoneLevel = Math.max(redstoneLevel, tePt.modules[i].getRedstoneLevel());
}
}
}
return redstoneLevel;
}
return 0;
}
/**
* Determine if this block can make a redstone connection on the side provided,
* Useful to control which sides are inputs and outputs for redstone wires.
*
* Side:
* -1: UP
* 0: NORTH
* 1: EAST
* 2: SOUTH
* 3: WEST
*
* @param world The current world
* @param x X Position
* @param y Y Position
* @param z Z Position
* @param side The side that is trying to make the connection
* @return True to make the connection
*/
@Override
public boolean canConnectRedstone(IBlockAccess world, int x, int y, int z, int side){
if(side < 0 || side > 3) return false;
TileEntityPressureTube tube = (TileEntityPressureTube)world.getTileEntity(x, y, z);
ForgeDirection d = ForgeDirection.NORTH;
for(int i = 0; i < side; i++) {
d = d.getRotation(ForgeDirection.UP);
}
side = d.ordinal();
for(int i = 0; i < 6; i++) {
if(tube.modules[i] != null) {
if((side ^ 1) == i || i != side && tube.modules[i].isInline()) {//if we are on the same side, or when we have an 'in line' module that is not on the opposite side.
if(tube.modules[i] instanceof TubeModuleRedstoneEmitting) return true;
}
}
}
return false;
}
}