package crazypants.enderio.conduit; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Random; import mods.immibis.core.api.multipart.IMultipartRenderingBlockMarker; import mods.immibis.core.api.multipart.IMultipartSystem; import net.minecraft.block.Block; import net.minecraft.client.Minecraft; import net.minecraft.client.audio.ISound; import net.minecraft.client.particle.EffectRenderer; import net.minecraft.client.particle.EntityDiggingFX; import net.minecraft.client.renderer.texture.IIconRegister; import net.minecraft.entity.Entity; 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.IIcon; import net.minecraft.util.MovingObjectPosition; import net.minecraft.util.Vec3; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; import net.minecraftforge.client.event.sound.PlaySoundSourceEvent; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.util.ForgeDirection; import net.minecraftforge.event.entity.PlaySoundAtEntityEvent; import net.minecraftforge.event.entity.player.PlayerEvent.BreakSpeed; import powercrystals.minefactoryreloaded.api.rednet.IRedNetOmniNode; import powercrystals.minefactoryreloaded.api.rednet.connectivity.RedNetConnectionType; import com.enderio.core.client.render.BoundingBox; import com.enderio.core.common.util.BlockCoord; import com.enderio.core.common.util.Util; import cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.common.Optional; import cpw.mods.fml.common.Optional.Interface; import cpw.mods.fml.common.eventhandler.SubscribeEvent; import cpw.mods.fml.common.network.IGuiHandler; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import crazypants.enderio.BlockEio; import crazypants.enderio.EnderIO; import crazypants.enderio.GuiHandler; import crazypants.enderio.ModObject; import crazypants.enderio.api.tool.ITool; import crazypants.enderio.conduit.facade.ItemConduitFacade.FacadeType; import crazypants.enderio.conduit.geom.CollidableComponent; import crazypants.enderio.conduit.geom.ConduitConnectorType; import crazypants.enderio.conduit.gui.ExternalConnectionContainer; import crazypants.enderio.conduit.gui.GuiExternalConnection; import crazypants.enderio.conduit.gui.GuiExternalConnectionSelector; import crazypants.enderio.conduit.gui.PacketFluidFilter; import crazypants.enderio.conduit.gui.PacketOpenConduitUI; import crazypants.enderio.conduit.gui.PacketSlotVisibility; import crazypants.enderio.conduit.gui.item.PacketExistingItemFilterSnapshot; import crazypants.enderio.conduit.gui.item.PacketModItemFilter; import crazypants.enderio.conduit.liquid.PacketFluidLevel; import crazypants.enderio.conduit.packet.PacketConnectionMode; import crazypants.enderio.conduit.packet.PacketExtractMode; import crazypants.enderio.conduit.packet.PacketItemConduitFilter; import crazypants.enderio.conduit.packet.PacketOCConduitSignalColor; import crazypants.enderio.conduit.packet.PacketRedstoneConduitOutputStrength; import crazypants.enderio.conduit.packet.PacketRedstoneConduitSignalColor; import crazypants.enderio.conduit.redstone.IInsulatedRedstoneConduit; import crazypants.enderio.conduit.redstone.IRedstoneConduit; import crazypants.enderio.conduit.redstone.InsulatedRedstoneConduit; import crazypants.enderio.item.IRotatableFacade; import crazypants.enderio.item.ItemConduitProbe; import crazypants.enderio.machine.painter.PainterUtil; import crazypants.enderio.network.PacketHandler; import crazypants.enderio.tool.ToolUtil; import crazypants.util.IFacade; @Optional.InterfaceList({ @Interface(iface = "powercrystals.minefactoryreloaded.api.rednet.IRedNetOmniNode", modid = "MineFactoryReloaded"), @Interface(iface = "mods.immibis.core.api.multipart.IMultipartRenderingBlockMarker", modid = "ImmibisMicroblocks") }) public class BlockConduitBundle extends BlockEio implements IGuiHandler, IFacade, IRotatableFacade, IRedNetOmniNode, IMultipartRenderingBlockMarker { private static final String KEY_CONNECTOR_ICON = "enderIO:conduitConnector"; private static final String KEY_CONNECTOR_ICON_EXTERNAL = "enderIO:conduitConnectorExternal"; public static BlockConduitBundle create() { MinecraftForge.EVENT_BUS.register(ConduitNetworkTickHandler.instance); FMLCommonHandler.instance().bus().register(ConduitNetworkTickHandler.instance); PacketHandler.INSTANCE.registerMessage(PacketFluidLevel.class, PacketFluidLevel.class, PacketHandler.nextID(), Side.CLIENT); PacketHandler.INSTANCE.registerMessage(PacketExtractMode.class, PacketExtractMode.class, PacketHandler.nextID(), Side.SERVER); PacketHandler.INSTANCE.registerMessage(PacketConnectionMode.class, PacketConnectionMode.class, PacketHandler.nextID(), Side.SERVER); PacketHandler.INSTANCE.registerMessage(PacketItemConduitFilter.class, PacketItemConduitFilter.class, PacketHandler.nextID(), Side.SERVER); PacketHandler.INSTANCE.registerMessage(PacketExistingItemFilterSnapshot.class, PacketExistingItemFilterSnapshot.class, PacketHandler.nextID(), Side.SERVER); PacketHandler.INSTANCE.registerMessage(PacketModItemFilter.class, PacketModItemFilter.class, PacketHandler.nextID(), Side.SERVER); PacketHandler.INSTANCE.registerMessage(PacketFluidFilter.class, PacketFluidFilter.class, PacketHandler.nextID(), Side.SERVER); PacketHandler.INSTANCE.registerMessage(PacketRedstoneConduitSignalColor.class, PacketRedstoneConduitSignalColor.class, PacketHandler.nextID(), Side.SERVER); PacketHandler.INSTANCE.registerMessage(PacketRedstoneConduitOutputStrength.class, PacketRedstoneConduitOutputStrength.class, PacketHandler.nextID(), Side.SERVER); PacketHandler.INSTANCE.registerMessage(PacketOpenConduitUI.class, PacketOpenConduitUI.class, PacketHandler.nextID(), Side.SERVER); PacketHandler.INSTANCE.registerMessage(PacketSlotVisibility.class, PacketSlotVisibility.class, PacketHandler.nextID(), Side.SERVER); PacketHandler.INSTANCE.registerMessage(PacketOCConduitSignalColor.class, PacketOCConduitSignalColor.class, PacketHandler.nextID(), Side.SERVER); BlockConduitBundle result = new BlockConduitBundle(); result.init(); MinecraftForge.EVENT_BUS.register(result); return result; } public static int rendererId = -1; private IIcon connectorIcon, connectorIconExternal; private IIcon lastRemovedComponetIcon = null; private final Random rand = new Random(); protected BlockConduitBundle() { super(ModObject.blockConduitBundle.unlocalisedName, TileConduitBundle.class); setBlockBounds(0.334f, 0.334f, 0.334f, 0.667f, 0.667f, 0.667f); setHardness(1.5f); setResistance(10.0f); setCreativeTab(null); this.stepSound = new SoundType("silence", 0, 0) { @Override public String getBreakSound() { return "EnderIO:" + soundName + ".dig"; } @Override public String getStepResourcePath() { return "EnderIO:" + soundName + ".step"; } }; } @SideOnly(Side.CLIENT) @Override public boolean addHitEffects(World world, MovingObjectPosition target, EffectRenderer effectRenderer) { if (MicroblocksUtil.supportMicroblocks() && IM__addHitEffects(world, target, effectRenderer)) { return true; } IIcon tex = null; TileConduitBundle cb = (TileConduitBundle) world.getTileEntity(target.blockX, target.blockY, target.blockZ); if(ConduitUtil.isSolidFacadeRendered(cb, Minecraft.getMinecraft().thePlayer)) { if(cb.getFacadeId() != null) { tex = cb.getFacadeId().getIcon(target.sideHit, cb.getFacadeMetadata()); } } else if(target.hitInfo instanceof CollidableComponent) { CollidableComponent cc = (CollidableComponent) target.hitInfo; IConduit con = cb.getConduit(cc.conduitType); if(con != null) { tex = con.getTextureForState(cc); } } if(tex == null) { tex = blockIcon; } lastRemovedComponetIcon = tex; addBlockHitEffects(world, effectRenderer, target.blockX, target.blockY, target.blockZ, target.sideHit, tex); return true; } @Override @SideOnly(Side.CLIENT) public boolean addDestroyEffects(World world, int x, int y, int z, int meta, EffectRenderer effectRenderer) { if (MicroblocksUtil.supportMicroblocks() && IM__addDestroyEffects(world, x, y, z, meta, effectRenderer)) { return true; } IIcon tex = lastRemovedComponetIcon; byte b0 = 4; for (int j1 = 0; j1 < b0; ++j1) { for (int k1 = 0; k1 < b0; ++k1) { for (int l1 = 0; l1 < b0; ++l1) { double d0 = x + (j1 + 0.5D) / b0; double d1 = y + (k1 + 0.5D) / b0; double d2 = z + (l1 + 0.5D) / b0; int i2 = rand.nextInt(6); EntityDiggingFX fx = new EntityDiggingFX(world, d0, d1, d2, d0 - x - 0.5D, d1 - y - 0.5D, d2 - z - 0.5D, this, i2, 0).applyColourMultiplier(x, y, z); fx.setParticleIcon(tex); effectRenderer.addEffect(fx); } } } return true; } @SideOnly(Side.CLIENT) private void addBlockHitEffects(World world, EffectRenderer effectRenderer, int x, int y, int z, int side, IIcon tex) { float f = 0.1F; double d0 = x + rand.nextDouble() * (getBlockBoundsMaxX() - getBlockBoundsMinX() - f * 2.0F) + f + getBlockBoundsMinX(); double d1 = y + rand.nextDouble() * (getBlockBoundsMaxY() - getBlockBoundsMinY() - f * 2.0F) + f + getBlockBoundsMinY(); double d2 = z + rand.nextDouble() * (getBlockBoundsMaxZ() - getBlockBoundsMinZ() - f * 2.0F) + f + getBlockBoundsMinZ(); if(side == 0) { d1 = y + getBlockBoundsMinY() - f; } else if(side == 1) { d1 = y + getBlockBoundsMaxY() + f; } else if(side == 2) { d2 = z + getBlockBoundsMinZ() - f; } else if(side == 3) { d2 = z + getBlockBoundsMaxZ() + f; } else if(side == 4) { d0 = x + getBlockBoundsMinX() - f; } else if(side == 5) { d0 = x + getBlockBoundsMaxX() + f; } EntityDiggingFX digFX = new EntityDiggingFX(world, d0, d1, d2, 0.0D, 0.0D, 0.0D, this, side, 0); digFX.applyColourMultiplier(x, y, z).multiplyVelocity(0.2F).multipleParticleScaleBy(0.6F); digFX.setParticleIcon(tex); effectRenderer.addEffect(digFX); } @SideOnly(Side.CLIENT) @SubscribeEvent public void onPlaySound(PlaySoundSourceEvent event) { String path = event.sound.getPositionedSoundLocation().getResourcePath(); if ("silence.step".equals(path)) { ISound snd = event.sound; World world = EnderIO.proxy.getClientWorld(); BlockCoord bc = new BlockCoord(snd.getXPosF(), snd.getYPosF(), snd.getZPosF()); TileEntity te = bc.getTileEntity(world); if (te != null && te instanceof TileConduitBundle && ((TileConduitBundle) te).hasFacade()) { Block facade = getFacade(world, bc.x, bc.y, bc.z, -1); ConduitUtil.playHitSound(facade.stepSound, world, bc.x, bc.y, bc.z); } else { ConduitUtil.playHitSound(Block.soundTypeMetal, world, bc.x, bc.y, bc.z); } } } @SideOnly(Side.CLIENT) @SubscribeEvent public void onPlaySoundAtEntity(PlaySoundAtEntityEvent event) { String path = event.name; World world = event.entity.worldObj; if ("EnderIO:silence.step".equals(path) && world.isRemote) { BlockCoord bc = new BlockCoord(event.entity.posX, event.entity.posY - 2, event.entity.posZ); TileEntity te = bc.getTileEntity(world); if (te != null && te instanceof TileConduitBundle && ((TileConduitBundle) te).hasFacade()) { Block facade = getFacade(world, bc.x, bc.y, bc.z, -1); ConduitUtil.playStepSound(facade.stepSound, world, bc.x, bc.y, bc.z); } else { ConduitUtil.playStepSound(Block.soundTypeMetal, world, bc.x, bc.y, bc.z); } } } @Override protected void init() { super.init(); for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) { EnderIO.guiHandler.registerGuiHandler(GuiHandler.GUI_ID_EXTERNAL_CONNECTION_BASE + dir.ordinal(), this); } EnderIO.guiHandler.registerGuiHandler(GuiHandler.GUI_ID_EXTERNAL_CONNECTION_SELECTOR, this); } @Override public ItemStack getPickBlock(MovingObjectPosition target, World world, int x, int y, int z) { return getPickBlock(target, world, x, y, z, null); } @Override public ItemStack getPickBlock(MovingObjectPosition target, World world, int x, int y, int z, EntityPlayer player) { ItemStack ret = null; if (MicroblocksUtil.supportMicroblocks()) { ret = getMicroblockPickBlock(target, world, x, y, z, player); } if(ret == null && target != null && target.hitInfo instanceof CollidableComponent) { CollidableComponent cc = (CollidableComponent) target.hitInfo; TileConduitBundle bundle = (TileConduitBundle) world.getTileEntity(x, y, z); IConduit conduit = bundle.getConduit(cc.conduitType); if(conduit != null) { ret = conduit.createItem(); } else if(cc.conduitType == null && bundle.getFacadeId() != null) { // use the facde ret = new ItemStack(EnderIO.itemConduitFacade, 1, 0); PainterUtil.setSourceBlock(ret, bundle.getFacadeId(), bundle.getFacadeMetadata()); } } return ret; } @Override public int getDamageValue(World world, int x, int y, int z) { TileEntity te = world.getTileEntity(x, y, z); if(!(te instanceof IConduitBundle)) { return 0; } IConduitBundle bun = (IConduitBundle) te; return bun.getFacadeId() != null ? bun.getFacadeMetadata() : 0; } @Override public int quantityDropped(Random r) { return 0; } public IIcon getConnectorIcon(Object data) { return data == ConduitConnectorType.EXTERNAL ? connectorIconExternal : connectorIcon; } @Override @SideOnly(Side.CLIENT) public void registerBlockIcons(IIconRegister IIconRegister) { connectorIcon = IIconRegister.registerIcon(KEY_CONNECTOR_ICON); connectorIconExternal = IIconRegister.registerIcon(KEY_CONNECTOR_ICON_EXTERNAL); blockIcon = connectorIcon; } @Override public boolean isSideSolid(IBlockAccess world, int x, int y, int z, ForgeDirection side) { if (MicroblocksUtil.supportMicroblocks() && IM__isSideSolid(world, x, y, z, side)) { return true; } TileEntity te = world.getTileEntity(x, y, z); if (!(te instanceof IConduitBundle)) { return false; } IConduitBundle con = (IConduitBundle) te; return con.hasFacade(); } @Override public boolean canBeReplacedByLeaves(IBlockAccess world, int x, int y, int z) { return false; } @Override public boolean isOpaqueCube() { return false; } @Override public int getRenderType() { return rendererId; } @Override public boolean renderAsNormalBlock() { return false; } @Override public int getLightOpacity(IBlockAccess world, int x, int y, int z) { TileEntity te = world.getTileEntity(x, y, z); if(!(te instanceof IConduitBundle)) { return super.getLightOpacity(world, x, y, z); } IConduitBundle con = (IConduitBundle) te; return con.getLightOpacity(); } @Override public int getLightValue(IBlockAccess world, int x, int y, int z) { TileEntity te = world.getTileEntity(x, y, z); if(!(te instanceof IConduitBundle)) { return super.getLightValue(world, x, y, z); } IConduitBundle con = (IConduitBundle) te; if(con.getFacadeId() != null && con.getFacadeId().isOpaqueCube()) { return 0; } Collection<IConduit> conduits = con.getConduits(); int result = 0; for (IConduit conduit : conduits) { result += conduit.getLightValue(); } return result; } @Override public float getBlockHardness(World world, int x, int y, int z) { IConduitBundle te = (IConduitBundle) world.getTileEntity(x, y, z); return te != null && te.getFacadeType() == FacadeType.HARDENED ? blockHardness * 10 : blockHardness; } @Override public float getExplosionResistance(Entity par1Entity, World world, int x, int y, int z, double explosionX, double explosionY, double explosionZ) { float resist = getExplosionResistance(par1Entity); IConduitBundle te = (IConduitBundle) world.getTileEntity(x, y, z); return te != null && te.getFacadeType() == FacadeType.HARDENED ? resist * 10 : resist; } @SubscribeEvent public void onBreakSpeed(BreakSpeed event) { if(event.block == this) { ItemStack held = event.entityPlayer.getCurrentEquippedItem(); if(held == null || held.getItem().getHarvestLevel(held, "pickaxe") == -1) { event.newSpeed += 2; } IConduitBundle te = (IConduitBundle) event.entity.worldObj.getTileEntity(event.x, event.y, event.z); if(te != null && te.getFacadeType() == FacadeType.HARDENED) { if(!ConduitUtil.isSolidFacadeRendered(te, event.entityPlayer)) { event.newSpeed *= 6; } else { event.newSpeed *= 2; } } } } @Override @SideOnly(Side.CLIENT) public int getRenderBlockPass() { return 1; } @Override @SideOnly(Side.CLIENT) public boolean canRenderInPass(int pass) { return pass == 0 || pass == 1; } @Override public int isProvidingStrongPower(IBlockAccess world, int x, int y, int z, int par5) { IRedstoneConduit con = getRedstoneConduit(world, x, y, z); if(con == null) { return 0; } return con.isProvidingStrongPower(ForgeDirection.getOrientation(par5)); } @Override public int isProvidingWeakPower(IBlockAccess world, int x, int y, int z, int par5) { IRedstoneConduit con = getRedstoneConduit(world, x, y, z); if(con == null) { return 0; } return con.isProvidingWeakPower(ForgeDirection.getOrientation(par5)); } @Override public boolean canProvidePower() { return true; } @Override public boolean removedByPlayer(World world, EntityPlayer player, int x, int y, int z, boolean willHarvest) { IConduitBundle te = (IConduitBundle) world.getTileEntity(x, y, z); if(te == null) { return true; } boolean breakBlock = true; List<ItemStack> drop = new ArrayList<ItemStack>(); if(ConduitUtil.isSolidFacadeRendered(te, player)) { breakBlock = false; ItemStack fac = new ItemStack(EnderIO.itemConduitFacade, 1, te.getFacadeType().ordinal()); PainterUtil.setSourceBlock(fac, te.getFacadeId(), te.getFacadeMetadata()); drop.add(fac); ConduitUtil.playBreakSound(te.getFacadeId().stepSound, world, x, y, z); te.setFacadeId(null); te.setFacadeMetadata(0); te.setFacadeType(FacadeType.BASIC); } if(breakBlock) { List<RaytraceResult> results = doRayTraceAll(world, x, y, z, player); RaytraceResult.sort(Util.getEyePosition(player), results); for (RaytraceResult rt : results) { if(breakConduit(te, drop, rt, player)) { break; } } } breakBlock = te.getConduits().isEmpty() && !te.hasFacade(); if(!breakBlock) { world.markBlockForUpdate(x, y, z); } // TODO no microblock sounds...not sure if fixable, need to contact immibis if (MicroblocksUtil.supportMicroblocks()) { IM__getDrops(drop, world, x, y, z, te.getEntity().getBlockMetadata(), 0); } if (!world.isRemote && !player.capabilities.isCreativeMode) { for (ItemStack st : drop) { Util.dropItems(world, st, x, y, z, false); } } if (breakBlock) { world.setBlockToAir(x, y, z); return true; } return false; } private boolean breakConduit(IConduitBundle te, List<ItemStack> drop, RaytraceResult rt, EntityPlayer player) { if(rt == null || rt.component == null) { return false; } Class<? extends IConduit> type = rt.component.conduitType; if(!ConduitUtil.renderConduit(player, type)) { return false; } if(type == null) { // broke a conector so drop any conduits with no connections as there // is no other way to remove these List<IConduit> cons = new ArrayList<IConduit>(te.getConduits()); boolean droppedUnconected = false; for (IConduit con : cons) { if(con.getConduitConnections().isEmpty() && con.getExternalConnections().isEmpty() && ConduitUtil.renderConduit(player, con)) { te.removeConduit(con); drop.addAll(con.getDrops()); droppedUnconected = true; } } // If there isn't, then drop em all if(!droppedUnconected) { for (IConduit con : cons) { if(ConduitUtil.renderConduit(player, con)) { te.removeConduit(con); drop.addAll(con.getDrops()); } } } } else { IConduit con = te.getConduit(type); if(con != null) { te.removeConduit(con); drop.addAll(con.getDrops()); } } BlockCoord bc = te.getLocation(); ConduitUtil.playBreakSound(Block.soundTypeMetal, te.getWorld(), bc.x, bc.y, bc.z); return true; } @Override public void breakBlock(World world, int x, int y, int z, Block par5, int par6) { TileEntity tile = world.getTileEntity(x, y, z); if(!(tile instanceof IConduitBundle)) { return; } IConduitBundle te = (IConduitBundle) tile; te.onBlockRemoved(); world.removeTileEntity(x, y, z); } @Override public void onBlockClicked(World world, int x, int y, int z, EntityPlayer player) { ItemStack equipped = player.getCurrentEquippedItem(); if(!player.isSneaking() || equipped == null || equipped.getItem() != EnderIO.itemYetaWench) { return; } ConduitUtil.openConduitGui(world, x, y, z, player); } @Override public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int side, float par7, float par8, float par9) { IConduitBundle bundle = (IConduitBundle) world.getTileEntity(x, y, z); if(bundle == null) { return false; } ItemStack stack = player.getCurrentEquippedItem(); if(stack != null && stack.getItem() == EnderIO.itemConduitFacade) { // add or replace facade return handleFacadeClick(world, x, y, z, player, side, bundle, stack); } else if(ConduitUtil.isConduitEquipped(player)) { // Add conduit if(player.isSneaking()) { return false; } if(handleConduitClick(world, x, y, z, player, bundle, stack)) { return true; } } else if(ConduitUtil.isProbeEquipped(player)) { //Handle copy / paste of settings if(handleConduitProbeClick(world, x, y, z, player, bundle, stack)) { return true; } } else if(ToolUtil.isToolEquipped(player) && player.isSneaking()) { // Break conduit with tool if(handleWrenchClick(world, x, y, z, player)) { return true; } } // Check conduit defined actions RaytraceResult closest = doRayTrace(world, x, y, z, player); List<RaytraceResult> all = null; if(closest != null) { all = doRayTraceAll(world, x, y, z, player); } if(closest != null && closest.component != null && closest.component.data instanceof ConduitConnectorType) { ConduitConnectorType conType = (ConduitConnectorType) closest.component.data; if(conType == ConduitConnectorType.INTERNAL) { boolean result = false; // if its a connector pass the event on to all conduits for (IConduit con : bundle.getConduits()) { if(ConduitUtil.renderConduit(player, con.getCollidableType()) && con.onBlockActivated(player, getHitForConduitType(all, con.getCollidableType()), all)) { bundle.getEntity().markDirty(); result = true; } } if(result) { return true; } } else { if(!world.isRemote) { player.openGui(EnderIO.instance, GuiHandler.GUI_ID_EXTERNAL_CONNECTION_BASE + closest.component.dir.ordinal(), world, x, y, z); } return true; } } if(closest == null || closest.component == null || closest.component.conduitType == null && all == null) { // Nothing of interest hit return false; } // Conduit specific actions if(all != null) { RaytraceResult.sort(Util.getEyePosition(player), all); for (RaytraceResult rr : all) { if(ConduitUtil.renderConduit(player, rr.component.conduitType) && !(rr.component.data instanceof ConduitConnectorType)) { IConduit con = bundle.getConduit(rr.component.conduitType); if(con != null && con.onBlockActivated(player, rr, all)) { bundle.getEntity().markDirty(); return true; } } } } else { IConduit closestConduit = bundle.getConduit(closest.component.conduitType); if(closestConduit != null && ConduitUtil.renderConduit(player, closestConduit) && closestConduit.onBlockActivated(player, closest, all)) { bundle.getEntity().markDirty(); return true; } } return false; } private boolean handleWrenchClick(World world, int x, int y, int z, EntityPlayer player) { ITool tool = ToolUtil.getEquippedTool(player); if(tool != null) { if(tool.canUse(player.getCurrentEquippedItem(), player, x, y, z)) { if(!world.isRemote) { removedByPlayer(world, player, x, y, z, true); tool.used(player.getCurrentEquippedItem(), player, x, y, z); } return true; } } return false; } private boolean handleConduitProbeClick(World world, int x, int y, int z, EntityPlayer player, IConduitBundle bundle, ItemStack stack) { if(stack.getItemDamage() != 1) { return false; //not in copy paste mode } RaytraceResult rr = doRayTrace(world, x, y, z, player); if(rr == null || rr.component == null) { return false; } return ItemConduitProbe.copyPasteSettings(player, stack, bundle, rr.component.dir); } private boolean handleConduitClick(World world, int x, int y, int z, EntityPlayer player, IConduitBundle bundle, ItemStack stack) { IConduitItem equipped = (IConduitItem) stack.getItem(); if(!bundle.hasType(equipped.getBaseConduitType())) { if(!world.isRemote) { bundle.addConduit(equipped.createConduit(stack, player)); ConduitUtil.playBreakSound(soundTypeMetal, world, x, y, z); if(!player.capabilities.isCreativeMode) { player.getCurrentEquippedItem().stackSize--; } } return true; } return false; } public boolean handleFacadeClick(World world, int x, int y, int z, EntityPlayer player, int side, IConduitBundle bundle, ItemStack stack) { if (MicroblocksUtil.supportMicroblocks() && hasMicroblocks(bundle)) { return false; } // Add facade if(player.isSneaking()) { return false; } Block facadeID = PainterUtil.getSourceBlock(player.getCurrentEquippedItem()); if(facadeID == null) { return false; } int facadeMeta = PainterUtil.getSourceBlockMetadata(player.getCurrentEquippedItem()); facadeMeta = PainterUtil.adjustFacadeMetadata(facadeID, facadeMeta, side); int facadeType = player.getCurrentEquippedItem().getItemDamage(); if (bundle.hasFacade()) { if (!ConduitUtil.isSolidFacadeRendered(bundle, player) || facadeEquals(bundle, facadeID, facadeMeta, facadeType)) { return false; } if (!world.isRemote && !player.capabilities.isCreativeMode) { ItemStack fac = new ItemStack(EnderIO.itemConduitFacade, 1, bundle.getFacadeType().ordinal()); PainterUtil.setSourceBlock(fac, bundle.getFacadeId(), bundle.getFacadeMetadata()); Util.dropItems(world, fac, x, y, z, false); } } bundle.setFacadeId(facadeID); bundle.setFacadeMetadata(facadeMeta); bundle.setFacadeType(FacadeType.values()[facadeType]); if (!world.isRemote) { ConduitUtil.playPlaceSound(facadeID.stepSound, world, x, y, z); } if (!player.capabilities.isCreativeMode) { stack.stackSize--; } world.markBlockForUpdate(x, y, z); bundle.getEntity().markDirty(); return true; } private boolean facadeEquals(IConduitBundle bundle, Block facadeID, int facadeMeta, int facadeType) { return bundle.getFacadeId().equals(facadeID) && bundle.getFacadeMetadata() == facadeMeta && bundle.getFacadeType().ordinal() == facadeType; } @Override public boolean tryRotateFacade(World world, int x, int y, int z, ForgeDirection axis) { IConduitBundle bundle = (IConduitBundle) world.getTileEntity(x, y, z); if(bundle == null) { return false; } int oldMeta = bundle.getFacadeMetadata(); int newMeta = PainterUtil.rotateFacadeMetadata(bundle.getFacadeId(), oldMeta, axis); if(newMeta == oldMeta) { return false; } bundle.setFacadeMetadata(newMeta); world.markBlockForUpdate(x, y, z); bundle.getEntity().markDirty(); return true; } @Override public Object getServerGuiElement(int id, EntityPlayer player, World world, int x, int y, int z) { if(id == GuiHandler.GUI_ID_EXTERNAL_CONNECTION_SELECTOR) { return null; } // The server needs the container as it manages the adding and removing of // items, which are then sent to the client for display TileEntity te = world.getTileEntity(x, y, z); if(te instanceof IConduitBundle) { return new ExternalConnectionContainer(player.inventory, (IConduitBundle) te, ForgeDirection.values()[id - GuiHandler.GUI_ID_EXTERNAL_CONNECTION_BASE]); } return null; } @Override public Object getClientGuiElement(int id, EntityPlayer player, World world, int x, int y, int z) { TileEntity te = world.getTileEntity(x, y, z); if(te instanceof IConduitBundle) { if(id == GuiHandler.GUI_ID_EXTERNAL_CONNECTION_SELECTOR) { return new GuiExternalConnectionSelector((IConduitBundle) te); } return new GuiExternalConnection(player.inventory, (IConduitBundle) te, ForgeDirection.values()[id - GuiHandler.GUI_ID_EXTERNAL_CONNECTION_BASE]); } return null; } private RaytraceResult getHitForConduitType(List<RaytraceResult> all, Class<? extends IConduit> collidableType) { for (RaytraceResult rr : all) { if(rr.component != null && rr.component.conduitType == collidableType) { return rr; } } return null; } @Override public void onNeighborBlockChange(World world, int x, int y, int z, Block blockId) { TileEntity tile = world.getTileEntity(x, y, z); if((tile instanceof IConduitBundle)) { ((IConduitBundle) tile).onNeighborBlockChange(blockId); } } @Override public void onNeighborChange(IBlockAccess world, int x, int y, int z, int tileX, int tileY, int tileZ) { TileEntity conduit = world.getTileEntity(x, y, z); if(conduit instanceof IConduitBundle) { ((IConduitBundle) conduit).onNeighborChange(world, x, y, z, tileX, tileY, tileZ); } } @Override public void addCollisionBoxesToList(World world, int x, int y, int z, AxisAlignedBB axisalignedbb, @SuppressWarnings("rawtypes") List arraylist, Entity par7Entity) { if (MicroblocksUtil.supportMicroblocks()) { IM__addCollisionBoxesToList(world, x, y, z, axisalignedbb, arraylist, par7Entity); } TileEntity te = world.getTileEntity(x, y, z); if(!(te instanceof IConduitBundle)) { return; } IConduitBundle con = (IConduitBundle) te; if(con.getFacadeId() != null) { setBlockBounds(0, 0, 0, 1, 1, 1); super.addCollisionBoxesToList(world, x, y, z, axisalignedbb, arraylist, par7Entity); } else { Collection<CollidableComponent> bounds = con.getCollidableComponents(); for (CollidableComponent bnd : bounds) { setBlockBounds(bnd.bound.minX, bnd.bound.minY, bnd.bound.minZ, bnd.bound.maxX, bnd.bound.maxY, bnd.bound.maxZ); super.addCollisionBoxesToList(world, x, y, z, axisalignedbb, arraylist, par7Entity); } if(con.getConduits().isEmpty()) { // just in case setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); super.addCollisionBoxesToList(world, x, y, z, axisalignedbb, arraylist, par7Entity); } } setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); } @Override @SideOnly(Side.CLIENT) public AxisAlignedBB getSelectedBoundingBoxFromPool(World world, int x, int y, int z) { TileEntity te = world.getTileEntity(x, y, z); EntityPlayer player = Minecraft.getMinecraft().thePlayer; if(!(te instanceof IConduitBundle)) { return null; } IConduitBundle con = (IConduitBundle) te; BoundingBox minBB = new BoundingBox(1, 1, 1, 0, 0, 0); if(!ConduitUtil.isSolidFacadeRendered(con, EnderIO.proxy.getClientPlayer())) { List<RaytraceResult> results = doRayTraceAll(world, x, y, z, player); Iterator<RaytraceResult> iter = results.iterator(); while (iter.hasNext()) { CollidableComponent component = iter.next().component; if(component == null || (component.conduitType == null && component.data != ConduitConnectorType.EXTERNAL)) { iter.remove(); } } // This is an ugly special case, TODO fix this for (RaytraceResult hit : results) { IInsulatedRedstoneConduit cond = con.getConduit(IInsulatedRedstoneConduit.class); if(cond != null && hit.component != null && cond.getExternalConnections().contains(hit.component.dir) && !cond.isSpecialConnection(hit.component.dir) && hit.component.data == InsulatedRedstoneConduit.COLOR_CONTROLLER_ID) { minBB = hit.component.bound; } } if(!minBB.isValid()) { RaytraceResult hit = RaytraceResult.getClosestHit(Util.getEyePosition(player), results); if(hit != null && hit.component != null && hit.component.bound != null) { minBB = hit.component.bound; if(hit.component.conduitType == null) { ForgeDirection dir = hit.component.dir.getOpposite(); float trans = 0.0125f; minBB = minBB.translate(dir.offsetX * trans, dir.offsetY * trans, dir.offsetZ * trans); float scale = 0.7f; minBB = minBB.scale(1 + Math.abs(dir.offsetX) * scale, 1 + Math.abs(dir.offsetY) * scale, 1 + Math.abs(dir.offsetZ) * scale); } else { minBB = minBB.scale(1.09, 1.09, 1.09); } } } } else { minBB = new BoundingBox(0, 0, 0, 1, 1, 1); } if(!minBB.isValid()) { minBB = new BoundingBox(0, 0, 0, 1, 1, 1); } return AxisAlignedBB.getBoundingBox(x + minBB.minX, y + minBB.minY, z + minBB.minZ, x + minBB.maxX, y + minBB.maxY, z + minBB.maxZ); } @Override public MovingObjectPosition collisionRayTrace(World world, int x, int y, int z, Vec3 origin, Vec3 direction) { RaytraceResult raytraceResult = doRayTrace(world, x, y, z, origin, direction, null); MovingObjectPosition ret = null; if (raytraceResult != null) { ret = raytraceResult.movingObjectPosition; if (ret != null) { ret.hitInfo = raytraceResult.component; } } if (MicroblocksUtil.supportMicroblocks()) { return IM__collisionRayTrace(ret, world, x, y, z, origin, direction); } return ret; } public RaytraceResult doRayTrace(World world, int x, int y, int z, EntityPlayer entityPlayer) { List<RaytraceResult> allHits = doRayTraceAll(world, x, y, z, entityPlayer); if(allHits == null) { return null; } Vec3 origin = Util.getEyePosition(entityPlayer); return RaytraceResult.getClosestHit(origin, allHits); } public List<RaytraceResult> doRayTraceAll(World world, int x, int y, int z, EntityPlayer entityPlayer) { double pitch = Math.toRadians(entityPlayer.rotationPitch); double yaw = Math.toRadians(entityPlayer.rotationYaw); double dirX = -Math.sin(yaw) * Math.cos(pitch); double dirY = -Math.sin(pitch); double dirZ = Math.cos(yaw) * Math.cos(pitch); double reachDistance = EnderIO.proxy.getReachDistanceForPlayer(entityPlayer); Vec3 origin = Util.getEyePosition(entityPlayer); Vec3 direction = origin.addVector(dirX * reachDistance, dirY * reachDistance, dirZ * reachDistance); return doRayTraceAll(world, x, y, z, origin, direction, entityPlayer); } private RaytraceResult doRayTrace(World world, int x, int y, int z, Vec3 origin, Vec3 direction, EntityPlayer entityPlayer) { List<RaytraceResult> allHits = doRayTraceAll(world, x, y, z, origin, direction, entityPlayer); if(allHits == null) { return null; } return RaytraceResult.getClosestHit(origin, allHits); } protected List<RaytraceResult> doRayTraceAll(World world, int x, int y, int z, Vec3 origin, Vec3 direction, EntityPlayer player) { TileEntity te = world.getTileEntity(x, y, z); if(!(te instanceof IConduitBundle)) { return null; } IConduitBundle bundle = (IConduitBundle) te; List<RaytraceResult> hits = new ArrayList<RaytraceResult>(); if(player == null) { player = EnderIO.proxy.getClientPlayer(); } if(ConduitUtil.isSolidFacadeRendered(bundle, player)) { setBlockBounds(0, 0, 0, 1, 1, 1); MovingObjectPosition hitPos = super.collisionRayTrace(world, x, y, z, origin, direction); if(hitPos != null) { hits.add(new RaytraceResult(new CollidableComponent(null, BoundingBox.UNIT_CUBE, ForgeDirection.UNKNOWN, null), hitPos)); } } else { ConduitDisplayMode mode = ConduitUtil.getDisplayMode(player); Collection<CollidableComponent> components = new ArrayList<CollidableComponent>(bundle.getCollidableComponents()); for (CollidableComponent component : components) { if((component.conduitType != null || mode == ConduitDisplayMode.ALL) && ConduitUtil.renderConduit(player, component.conduitType)) { setBlockBounds(component.bound.minX, component.bound.minY, component.bound.minZ, component.bound.maxX, component.bound.maxY, component.bound.maxZ); MovingObjectPosition hitPos = super.collisionRayTrace(world, x, y, z, origin, direction); if(hitPos != null) { hits.add(new RaytraceResult(component, hitPos)); } } } // safety to prevent unbreakable empty bundles in case of a bug if(bundle.getConduits().isEmpty() && !ConduitUtil.isFacadeHidden(bundle, player)) { setBlockBounds(0, 0, 0, 1, 1, 1); MovingObjectPosition hitPos = super.collisionRayTrace(world, x, y, z, origin, direction); if(hitPos != null) { hits.add(new RaytraceResult(null, hitPos)); } } } setBlockBounds(0, 0, 0, 1, 1, 1); return hits; } @Override public int getFacadeMetadata(IBlockAccess world, int x, int y, int z, int side) { TileEntity te = world.getTileEntity(x, y, z); if(!(te instanceof IConduitBundle)) { return 0; } IConduitBundle cb = (IConduitBundle) te; return cb.getFacadeMetadata(); } @Override public Block getFacade(IBlockAccess world, int x, int y, int z, int side) { TileEntity te = world.getTileEntity(x, y, z); if(!(te instanceof IConduitBundle)) { return this; } IConduitBundle cb = (IConduitBundle) te; Block res = cb.getFacadeId(); if(res == null) { return this; } return res; } @Override public Block getVisualBlock(IBlockAccess world, int x, int y, int z, ForgeDirection side) { return getFacade(world, x, y, z, side.ordinal()); } @Override public int getVisualMeta(IBlockAccess world, int x, int y, int z, ForgeDirection side) { return getFacadeMetadata(world, x, y, z, side.ordinal()); } @Override public boolean supportsVisualConnections() { return true; } @Override public void onInputsChanged(World world, int x, int y, int z, ForgeDirection side, int[] inputValues) { IRedstoneConduit conduit = getRedstoneConduit(world, x, y, z); if(conduit == null) { return; } conduit.onInputsChanged(world, x, y, z, side, inputValues); } @Override public void onInputChanged(World world, int x, int y, int z, ForgeDirection side, int inputValue) { // Unused because only called in "Single" mode. } @Override public int[] getOutputValues(World world, int x, int y, int z, ForgeDirection side) { IRedstoneConduit conduit = getRedstoneConduit(world, x, y, z); if(conduit == null) { return null; } return conduit.getOutputValues(world, x, y, z, side); } @Override public int getOutputValue(World world, int x, int y, int z, ForgeDirection side, int subnet) { IRedstoneConduit conduit = getRedstoneConduit(world, x, y, z); if(conduit == null) { return 0; } return conduit.getOutputValue(world, x, y, z, side, subnet); } @Override @Optional.Method(modid = "MineFactoryReloaded") public RedNetConnectionType getConnectionType(World world, int x, int y, int z, ForgeDirection side) { IRedstoneConduit conduit = getRedstoneConduit(world, x, y, z); if(conduit == null) { return RedNetConnectionType.None; } return conduit.canConnectToExternal(side, false) ? RedNetConnectionType.CableAll : RedNetConnectionType.None; } private static IRedstoneConduit getRedstoneConduit(IBlockAccess world, int x, int y, int z) { TileEntity te = world.getTileEntity(x, y, z); if(!(te instanceof IConduitBundle)) { return null; } IConduitBundle bundle = (IConduitBundle) te; return bundle.getConduit(IRedstoneConduit.class); } public ItemStack getMicroblockPickBlock(MovingObjectPosition target, World world, int x, int y, int z, EntityPlayer player) { return IMultipartSystem.instance.hook_getPickBlock(target, world, x, y, z, player); } // IM Hooks private boolean IM__isSideSolid(IBlockAccess world, int x, int y, int z, ForgeDirection side) { return IMultipartSystem.instance.hook_isSideSolid(world, x, y, z, side); } @SideOnly(Side.CLIENT) private boolean IM__addDestroyEffects(World world, int x, int y, int z, int meta, EffectRenderer effectRenderer) { return IMultipartSystem.instance.hook_addDestroyEffects(world, x, y, z, meta, effectRenderer); } @SideOnly(Side.CLIENT) private boolean IM__addHitEffects(World worldObj, MovingObjectPosition target, EffectRenderer effectRenderer) { return IMultipartSystem.instance.hook_addHitEffects(worldObj, target, effectRenderer); } private MovingObjectPosition IM__collisionRayTrace(MovingObjectPosition cur, World world, int x, int y, int z, Vec3 src, Vec3 dst) { return IMultipartSystem.instance.hook_collisionRayTrace(cur, world, x, y, z, src, dst); } @SuppressWarnings({ "rawtypes", "unchecked" }) private void IM__addCollisionBoxesToList(World world, int x, int y, int z, AxisAlignedBB mask, List list, Entity entity) { IMultipartSystem.instance.hook_addCollisionBoxesToList(world, x, y, z, mask, list, entity); } private ArrayList<ItemStack> IM__getDrops(List<ItemStack> cur, World world, int x, int y, int z, int metadata, int fortune) { return IMultipartSystem.instance.hook_getDrops(cur, world, x, y, z, metadata, fortune); } private boolean hasMicroblocks(IConduitBundle bundle) { return !bundle.getCoverSystem().getAllParts().isEmpty(); } }