package micdoodle8.mods.galacticraft.core.util; import micdoodle8.mods.galacticraft.api.block.IPartialSealableBlock; import micdoodle8.mods.galacticraft.api.item.IBreathableArmor; import micdoodle8.mods.galacticraft.api.item.IBreathableArmor.EnumGearType; import micdoodle8.mods.galacticraft.api.transmission.NetworkType; import micdoodle8.mods.galacticraft.api.transmission.tile.IConnector; import micdoodle8.mods.galacticraft.api.vector.BlockVec3; import micdoodle8.mods.galacticraft.api.vector.BlockVec3Dim; import micdoodle8.mods.galacticraft.api.world.IAtmosphericGas; import micdoodle8.mods.galacticraft.api.world.IGalacticraftWorldProvider; import micdoodle8.mods.galacticraft.core.GCBlocks; import micdoodle8.mods.galacticraft.core.energy.EnergyConfigHandler; import micdoodle8.mods.galacticraft.core.entities.player.GCPlayerStats; import micdoodle8.mods.galacticraft.core.fluid.OxygenPressureProtocol; import micdoodle8.mods.galacticraft.core.items.ItemCanisterOxygenInfinite; import micdoodle8.mods.galacticraft.core.items.ItemOxygenGear; import micdoodle8.mods.galacticraft.core.items.ItemOxygenMask; import micdoodle8.mods.galacticraft.core.items.ItemOxygenTank; import micdoodle8.mods.galacticraft.core.tile.TileEntityOxygenDistributor; import net.minecraft.block.*; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; import net.minecraft.client.gui.GuiChat; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.gui.inventory.GuiInventory; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.AxisAlignedBB; import net.minecraft.util.BlockPos; import net.minecraft.util.EnumFacing; import net.minecraft.util.MathHelper; import net.minecraft.world.World; import net.minecraft.world.WorldProvider; import net.minecraftforge.fluids.IFluidHandler; import net.minecraftforge.fml.client.FMLClientHandler; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import java.util.ArrayList; import java.util.HashSet; public class OxygenUtil { private static HashSet<BlockPos> checked; @SideOnly(Side.CLIENT) public static boolean shouldDisplayTankGui(GuiScreen gui) { if (FMLClientHandler.instance().getClient().gameSettings.hideGUI) { return false; } if (gui == null) { return true; } if (gui instanceof GuiInventory) { return false; } return gui instanceof GuiChat; } public static boolean isAABBInBreathableAirBlock(EntityLivingBase entity) { return isAABBInBreathableAirBlock(entity, false); } public static boolean isAABBInBreathableAirBlock(EntityLivingBase entity, boolean testThermal) { double y = entity.posY + entity.getEyeHeight(); double x = entity.posX; double z = entity.posZ; double sx = entity.getEntityBoundingBox().maxX - entity.getEntityBoundingBox().minX; double sy = entity.getEntityBoundingBox().maxY - entity.getEntityBoundingBox().minY; double sz = entity.getEntityBoundingBox().maxZ - entity.getEntityBoundingBox().minZ; //A good first estimate of head size is that it's the smallest of the entity's 3 dimensions (e.g. front to back, for Steve) double smin = Math.min(sx, Math.min(sy, sz)) / 2; return OxygenUtil.isAABBInBreathableAirBlock(entity.worldObj, AxisAlignedBB.fromBounds(x - smin, y - smin, z - smin, x + smin, y + smin, z + smin), testThermal); } public static boolean isAABBInBreathableAirBlock(World world, AxisAlignedBB bb) { return isAABBInBreathableAirBlock(world, bb, false); } @SuppressWarnings("rawtypes") public static boolean isAABBInBreathableAirBlock(World world, AxisAlignedBB bb, boolean testThermal) { final double avgX = (bb.minX + bb.maxX) / 2.0D; final double avgY = (bb.minY + bb.maxY) / 2.0D; final double avgZ = (bb.minZ + bb.maxZ) / 2.0D; if (testThermal) { return OxygenUtil.isInOxygenAndThermalBlock(world, bb); } if (OxygenUtil.inOxygenBubble(world, avgX, avgY, avgZ)) { return true; } return OxygenUtil.isInOxygenBlock(world, bb); } public static boolean isInOxygenBlock(World world, AxisAlignedBB bb) { int xm = MathHelper.floor_double(bb.minX + 0.001D); int xx = MathHelper.floor_double(bb.maxX - 0.001D); int ym = MathHelper.floor_double(bb.minY + 0.001D); int yy = MathHelper.floor_double(bb.maxY - 0.001D); int zm = MathHelper.floor_double(bb.minZ + 0.001D); int zz = MathHelper.floor_double(bb.maxZ - 0.001D); OxygenUtil.checked = new HashSet(); if (world.isAreaLoaded(new BlockPos(xm, ym, zm), new BlockPos(xx, yy, zz))) { for (int x = xm; x <= xx; ++x) { for (int z = zm; z <= zz; ++z) { for (int y = ym; y <= yy; ++y) { BlockPos pos = new BlockPos(x, y, z); Block block = world.getBlockState(pos).getBlock(); if (OxygenUtil.testContactWithBreathableAir(world, block, pos, 0) >= 0) { return true; } } } } } return false; } public static boolean isInOxygenAndThermalBlock(World world, AxisAlignedBB bb) { int i = MathHelper.floor_double(bb.minX + 0.001D); int j = MathHelper.floor_double(bb.maxX - 0.001D); int k = MathHelper.floor_double(bb.minY + 0.001D); int l = MathHelper.floor_double(bb.maxY - 0.001D); int i1 = MathHelper.floor_double(bb.minZ + 0.001D); int j1 = MathHelper.floor_double(bb.maxZ - 0.001D); OxygenUtil.checked = new HashSet(); if (world.isAreaLoaded(new BlockPos(i, k, i1), new BlockPos(j, l, j1))) { for (int x = i; x <= j; ++x) { for (int y = k; y <= l; ++y) { for (int z = i1; z <= j1; ++z) { BlockPos pos = new BlockPos(x, y, z); Block block = world.getBlockState(pos).getBlock(); if (OxygenUtil.testContactWithBreathableAir(world, block, pos, 0) == 1) // Thermal air has metadata 1 { return true; } } } } } return false; } /* * A simplified version of the breathable air check which checks * all 6 sides of the given block (because a torch can pass air on all sides) * Used in BlockUnlitTorch. */ public static boolean checkTorchHasOxygen(World world, BlockPos pos) { if (OxygenUtil.inOxygenBubble(world, pos.getX() + 0.5D, pos.getY() + 0.6D, pos.getZ() + 0.5D)) { return true; } OxygenUtil.checked = new HashSet(); BlockVec3 vec = new BlockVec3(pos); for (int side = 0; side < 6; side++) { BlockVec3 sidevec = vec.newVecSide(side); Block newblock = sidevec.getBlockID_noChunkLoad(world); if (OxygenUtil.testContactWithBreathableAir(world, newblock, sidevec.toBlockPos(), 1) >= 0) { return true; } } return false; } /* * Test whether the given block at (x,y,z) coordinates is either: * - breathable air (returns true) * - solid, or air which is not breathable (returns false) * - an air-permeable block, for example a torch, in which case test the surrounding * air-reachable blocks (up to 5 blocks away) and return true if breathable air is found * in one of them, or false if not. */ private static int testContactWithBreathableAir(World world, Block block, BlockPos pos, int limitCount) { checked.add(pos); if (block == GCBlocks.breatheableAir || block == GCBlocks.brightBreatheableAir) { return block.getMetaFromState(world.getBlockState(pos)); } if (block == null || block.getMaterial() == Material.air) { return -1; } //Test for non-sided permeable or solid blocks first boolean permeableFlag = false; if (!(block instanceof BlockLeavesBase)) { if (block.isOpaqueCube()) { if (block instanceof BlockGravel || block.getMaterial() == Material.cloth || block instanceof BlockSponge) { permeableFlag = true; } else { return -1; } } else if (block instanceof BlockGlass || block instanceof BlockStainedGlass) { return -1; } else if (block instanceof BlockLiquid) { return -1; } else if (OxygenPressureProtocol.nonPermeableBlocks.containsKey(block)) { ArrayList<Integer> metaList = OxygenPressureProtocol.nonPermeableBlocks.get(block); IBlockState state = world.getBlockState(pos); if (metaList.contains(Integer.valueOf(-1)) || metaList.contains(state.getBlock().getMetaFromState(state))) { return -1; } } } else { permeableFlag = true; } //Testing a non-air, permeable block (for example a torch or a ladder) if (limitCount < 5) { for (EnumFacing side : EnumFacing.values()) { if (permeableFlag || OxygenUtil.canBlockPassAirOnSide(world, block, pos, side)) { BlockPos sidevec = pos.add(side.getFrontOffsetX(), side.getFrontOffsetY(), side.getFrontOffsetZ()); if (!checked.contains(sidevec)) { Block newblock = world.getBlockState(sidevec).getBlock(); int adjResult = OxygenUtil.testContactWithBreathableAir(world, newblock, sidevec, limitCount + 1); if (adjResult >= 0) { return adjResult; } } } } } return -1; } //TODO - performance, could add a 'safe' version of this code (inside world borders) //TODO - add more performance increase, these sided checks could be done once only private static boolean canBlockPassAirOnSide(World world, Block block, BlockPos vec, EnumFacing side) { if (block instanceof IPartialSealableBlock) { return !((IPartialSealableBlock) block).isSealed(world, vec, side); } //Half slab seals on the top side or the bottom side according to its metadata if (block instanceof BlockSlab) { IBlockState state = world.getBlockState(vec); int meta = state.getBlock().getMetaFromState(state); return !(side == EnumFacing.DOWN && (meta & 8) == 8 || side == EnumFacing.UP && (meta & 8) == 0); } //Farmland etc only seals on the solid underside if (block instanceof BlockFarmland || block instanceof BlockEnchantmentTable || block instanceof BlockLiquid) { return side != EnumFacing.UP; } if (block instanceof BlockPistonBase) { IBlockState state = world.getBlockState(vec); if (((Boolean) state.getValue(BlockPistonBase.EXTENDED)).booleanValue()) { int meta0 = state.getBlock().getMetaFromState(state); EnumFacing facing = BlockPistonBase.getFacing(meta0); return side != facing; } return false; } return !block.isSideSolid(world, vec, EnumFacing.getFront(side.getIndex() ^ 1)); } public static int getDrainSpacing(ItemStack tank, ItemStack tank2) { boolean tank1Valid = tank != null && tank.getItem() instanceof ItemOxygenTank && tank.getMaxDamage() - tank.getItemDamage() > 0; boolean tank2Valid = tank2 != null && tank2.getItem() instanceof ItemOxygenTank && tank2.getMaxDamage() - tank2.getItemDamage() > 0; if (!tank1Valid && !tank2Valid) { return 0; } return 9; } public static boolean hasValidOxygenSetup(EntityPlayerMP player) { boolean missingComponent = false; GCPlayerStats stats = GCPlayerStats.get(player); if (stats.getExtendedInventory().getStackInSlot(0) == null || !OxygenUtil.isItemValidForPlayerTankInv(0, stats.getExtendedInventory().getStackInSlot(0))) { boolean handled = false; for (final ItemStack armorStack : player.inventory.armorInventory) { if (armorStack != null && armorStack.getItem() instanceof IBreathableArmor) { final IBreathableArmor breathableArmor = (IBreathableArmor) armorStack.getItem(); if (breathableArmor.handleGearType(EnumGearType.HELMET)) { if (breathableArmor.canBreathe(armorStack, player, EnumGearType.HELMET)) { handled = true; } } } } if (!handled) { missingComponent = true; } } if (stats.getExtendedInventory().getStackInSlot(1) == null || !OxygenUtil.isItemValidForPlayerTankInv(1, stats.getExtendedInventory().getStackInSlot(1))) { boolean handled = false; for (final ItemStack armorStack : player.inventory.armorInventory) { if (armorStack != null && armorStack.getItem() instanceof IBreathableArmor) { final IBreathableArmor breathableArmor = (IBreathableArmor) armorStack.getItem(); if (breathableArmor.handleGearType(EnumGearType.GEAR)) { if (breathableArmor.canBreathe(armorStack, player, EnumGearType.GEAR)) { handled = true; } } } } if (!handled) { missingComponent = true; } } if ((stats.getExtendedInventory().getStackInSlot(2) == null || !OxygenUtil.isItemValidForPlayerTankInv(2, stats.getExtendedInventory().getStackInSlot(2))) && (stats.getExtendedInventory().getStackInSlot(3) == null || !OxygenUtil.isItemValidForPlayerTankInv(3, stats.getExtendedInventory().getStackInSlot(3)))) { boolean handled = false; for (final ItemStack armorStack : player.inventory.armorInventory) { if (armorStack != null && armorStack.getItem() instanceof IBreathableArmor) { final IBreathableArmor breathableArmor = (IBreathableArmor) armorStack.getItem(); if (breathableArmor.handleGearType(EnumGearType.TANK1)) { if (breathableArmor.canBreathe(armorStack, player, EnumGearType.TANK1)) { handled = true; } } if (breathableArmor.handleGearType(EnumGearType.TANK2)) { if (breathableArmor.canBreathe(armorStack, player, EnumGearType.TANK2)) { handled = true; } } } } if (!handled) { missingComponent = true; } } return !missingComponent; } public static boolean isItemValidForPlayerTankInv(int slotIndex, ItemStack stack) { switch (slotIndex) { case 0: return stack.getItem() instanceof ItemOxygenMask; case 1: return stack.getItem() instanceof ItemOxygenGear; case 2: case 3: return stack.getItem() instanceof ItemOxygenTank || stack.getItem() instanceof ItemCanisterOxygenInfinite; } return false; } public static TileEntity[] getAdjacentFluidConnections(TileEntity tile) { return getAdjacentFluidConnections(tile, false); } public static TileEntity[] getAdjacentFluidConnections(TileEntity tile, boolean ignoreConnect) { TileEntity[] adjacentConnections = new TileEntity[EnumFacing.values().length]; boolean isMekLoaded = EnergyConfigHandler.isMekanismLoaded(); BlockVec3 thisVec = new BlockVec3(tile); for (EnumFacing direction : EnumFacing.values()) { TileEntity tileEntity = thisVec.getTileEntityOnSide(tile.getWorld(), direction); if (tileEntity instanceof IFluidHandler) { if (ignoreConnect || !(tileEntity instanceof IConnector) || ((IConnector) tileEntity).canConnect(direction.getOpposite(), NetworkType.FLUID)) { adjacentConnections[direction.ordinal()] = tileEntity; } } // else if (isMekLoaded) // { // if (tileEntity instanceof ITubeConnection && (!(tileEntity instanceof IGasTransmitter) || TransmissionType.checkTransmissionType(tileEntity, TransmissionType.GAS, tileEntity))) // { // if (((ITubeConnection) tileEntity).canTubeConnect(direction)) // { // adjacentConnections[direction.ordinal()] = tileEntity; // } // } // } } return adjacentConnections; } public static boolean noAtmosphericCombustion(WorldProvider provider) { if (provider instanceof IGalacticraftWorldProvider) { return (!((IGalacticraftWorldProvider) provider).isGasPresent(IAtmosphericGas.OXYGEN) && !((IGalacticraftWorldProvider) provider).hasBreathableAtmosphere()); } return false; } public static boolean inOxygenBubble(World worldObj, double avgX, double avgY, double avgZ) { int dimID = GCCoreUtil.getDimensionID(worldObj); for (final BlockVec3Dim blockVec : TileEntityOxygenDistributor.loadedTiles) { if (blockVec != null && blockVec.dim == dimID) { TileEntity tile = blockVec.getTileEntity(); if (tile instanceof TileEntityOxygenDistributor) { if (((TileEntityOxygenDistributor) tile).inBubble(avgX, avgY, avgZ)) { return true; } } } } return false; } }