Java tutorial
/* * This file is part of Applied Energistics 2. * Copyright (c) 2013 - 2015, AlgorithmX2, All rights reserved. * * Applied Energistics 2 is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Applied Energistics 2 is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>. */ package appeng.parts; import java.io.IOException; import java.util.EnumSet; import java.util.LinkedList; import java.util.List; import java.util.Random; import java.util.Set; import javax.annotation.Nullable; import io.netty.buffer.ByteBuf; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; import appeng.api.AEApi; import appeng.api.config.YesNo; import appeng.api.exceptions.FailedConnection; import appeng.api.implementations.parts.IPartCable; import appeng.api.networking.IGridHost; import appeng.api.networking.IGridNode; import appeng.api.parts.IFacadeContainer; import appeng.api.parts.IFacadePart; import appeng.api.parts.IPart; import appeng.api.parts.IPartCollisionHelper; import appeng.api.parts.IPartHost; import appeng.api.parts.IPartItem; import appeng.api.parts.LayerFlags; import appeng.api.parts.PartItemStack; import appeng.api.parts.SelectedPart; import appeng.api.util.AECableType; import appeng.api.util.AEColor; import appeng.api.util.AEPartLocation; import appeng.api.util.DimensionalCoord; import appeng.client.render.cablebus.CableBusRenderState; import appeng.client.render.cablebus.CableCoreType; import appeng.client.render.cablebus.FacadeRenderState; import appeng.core.AELog; import appeng.facade.FacadeContainer; import appeng.helpers.AEMultiTile; import appeng.me.GridConnection; import appeng.parts.networking.PartCable; import appeng.util.Platform; public class CableBusContainer extends CableBusStorage implements AEMultiTile, ICableBusContainer { private static final ThreadLocal<Boolean> IS_LOADING = new ThreadLocal<Boolean>(); private final EnumSet<LayerFlags> myLayerFlags = EnumSet.noneOf(LayerFlags.class); private YesNo hasRedstone = YesNo.UNDECIDED; private IPartHost tcb; // TODO 1.10.2-R - does somebody seriously want to make parts TESR??? Hope not. private boolean requiresDynamicRender = false; private boolean inWorld = false; public CableBusContainer(final IPartHost host) { this.tcb = host; } public static boolean isLoading() { final Boolean is = IS_LOADING.get(); return is != null && is; } public void setHost(final IPartHost host) { this.tcb.clearContainer(); this.tcb = host; } public void rotateLeft() { final IPart[] newSides = new IPart[6]; newSides[AEPartLocation.UP.ordinal()] = this.getSide(AEPartLocation.UP); newSides[AEPartLocation.DOWN.ordinal()] = this.getSide(AEPartLocation.DOWN); newSides[AEPartLocation.EAST.ordinal()] = this.getSide(AEPartLocation.NORTH); newSides[AEPartLocation.SOUTH.ordinal()] = this.getSide(AEPartLocation.EAST); newSides[AEPartLocation.WEST.ordinal()] = this.getSide(AEPartLocation.SOUTH); newSides[AEPartLocation.NORTH.ordinal()] = this.getSide(AEPartLocation.WEST); for (final AEPartLocation dir : AEPartLocation.SIDE_LOCATIONS) { this.setSide(dir, newSides[dir.ordinal()]); } this.getFacadeContainer().rotateLeft(); } @Override public IFacadeContainer getFacadeContainer() { return new FacadeContainer(this); } @Override public boolean canAddPart(ItemStack is, final AEPartLocation side) { if (PartPlacement.isFacade(is, side) != null) { return true; } if (is.getItem() instanceof IPartItem) { final IPartItem bi = (IPartItem) is.getItem(); is = is.copy(); is.stackSize = 1; final IPart bp = bi.createPartFromItemStack(is); if (bp != null) { if (bp instanceof IPartCable) { boolean canPlace = true; for (final AEPartLocation d : AEPartLocation.SIDE_LOCATIONS) { if (this.getPart(d) != null && !this.getPart(d).canBePlacedOn(((IPartCable) bp).supportsBuses())) { canPlace = false; } } if (!canPlace) { return false; } return this.getPart(AEPartLocation.INTERNAL) == null; } else if (!(bp instanceof IPartCable) && side != AEPartLocation.INTERNAL) { final IPart cable = this.getPart(AEPartLocation.INTERNAL); if (cable != null && !bp.canBePlacedOn(((IPartCable) cable).supportsBuses())) { return false; } return this.getPart(side) == null; } } } return false; } @Override public AEPartLocation addPart(ItemStack is, final AEPartLocation side, final @Nullable EntityPlayer player, final @Nullable EnumHand hand) { if (this.canAddPart(is, side)) { if (is.getItem() instanceof IPartItem) { final IPartItem bi = (IPartItem) is.getItem(); is = is.copy(); is.stackSize = 1; final IPart bp = bi.createPartFromItemStack(is); if (bp instanceof IPartCable) { boolean canPlace = true; for (final AEPartLocation d : AEPartLocation.SIDE_LOCATIONS) { if (this.getPart(d) != null && !this.getPart(d).canBePlacedOn(((IPartCable) bp).supportsBuses())) { canPlace = false; } } if (!canPlace) { return null; } if (this.getPart(AEPartLocation.INTERNAL) != null) { return null; } this.setCenter((IPartCable) bp); bp.setPartHostInfo(AEPartLocation.INTERNAL, this, this.tcb.getTile()); if (player != null) { bp.onPlacement(player, hand, is, side); } if (this.inWorld) { bp.addToWorld(); } final IGridNode cn = this.getCenter().getGridNode(); if (cn != null) { for (final AEPartLocation ins : AEPartLocation.SIDE_LOCATIONS) { final IPart sbp = this.getPart(ins); if (sbp != null) { final IGridNode sn = sbp.getGridNode(); if (sn != null) { try { new GridConnection(cn, sn, AEPartLocation.INTERNAL); } catch (final FailedConnection e) { // ekk! bp.removeFromWorld(); this.setCenter(null); return null; } } } } } this.updateConnections(); this.markForUpdate(); this.markForSave(); this.partChanged(); return AEPartLocation.INTERNAL; } else if (bp != null && !(bp instanceof IPartCable) && side != AEPartLocation.INTERNAL) { final IPart cable = this.getPart(AEPartLocation.INTERNAL); if (cable != null && !bp.canBePlacedOn(((IPartCable) cable).supportsBuses())) { return null; } this.setSide(side, bp); bp.setPartHostInfo(side, this, this.getTile()); if (player != null) { bp.onPlacement(player, hand, is, side); } if (this.inWorld) { bp.addToWorld(); } if (this.getCenter() != null) { final IGridNode cn = this.getCenter().getGridNode(); final IGridNode sn = bp.getGridNode(); if (cn != null && sn != null) { try { new GridConnection(cn, sn, AEPartLocation.INTERNAL); } catch (final FailedConnection e) { // ekk! bp.removeFromWorld(); this.setSide(side, null); return null; } } } this.updateDynamicRender(); this.updateConnections(); this.markForUpdate(); this.markForSave(); this.partChanged(); return side; } } } return null; } @Override public IPart getPart(final AEPartLocation partLocation) { if (partLocation == AEPartLocation.INTERNAL) { return this.getCenter(); } return this.getSide(partLocation); } @Override public IPart getPart(final EnumFacing side) { return this.getSide(AEPartLocation.fromFacing(side)); } @Override public void removePart(final AEPartLocation side, final boolean suppressUpdate) { if (side == AEPartLocation.INTERNAL) { if (this.getCenter() != null) { this.getCenter().removeFromWorld(); } this.setCenter(null); } else { if (this.getSide(side) != null) { this.getSide(side).removeFromWorld(); } this.setSide(side, null); } if (!suppressUpdate) { this.updateDynamicRender(); this.updateConnections(); this.markForUpdate(); this.markForSave(); this.partChanged(); } } @Override public void markForUpdate() { this.tcb.markForUpdate(); } @Override public DimensionalCoord getLocation() { return this.tcb.getLocation(); } @Override public TileEntity getTile() { return this.tcb.getTile(); } @Override public AEColor getColor() { if (this.getCenter() != null) { final IPartCable c = this.getCenter(); return c.getCableColor(); } return AEColor.TRANSPARENT; } @Override public void clearContainer() { throw new UnsupportedOperationException("Now that is silly!"); } @Override public boolean isBlocked(final EnumFacing side) { return this.tcb.isBlocked(side); } @Override public SelectedPart selectPart(final Vec3d pos) { for (final AEPartLocation side : AEPartLocation.values()) { final IPart p = this.getPart(side); if (p != null) { final List<AxisAlignedBB> boxes = new LinkedList<AxisAlignedBB>(); final IPartCollisionHelper bch = new BusCollisionHelper(boxes, side, null, true); p.getBoxes(bch); for (AxisAlignedBB bb : boxes) { bb = bb.expand(0.002, 0.002, 0.002); if (bb.isVecInside(pos)) { return new SelectedPart(p, side); } } } } if (AEApi.instance().partHelper().getCableRenderMode().opaqueFacades) { final IFacadeContainer fc = this.getFacadeContainer(); for (final AEPartLocation side : AEPartLocation.SIDE_LOCATIONS) { final IFacadePart p = fc.getFacade(side); if (p != null) { final List<AxisAlignedBB> boxes = new LinkedList<AxisAlignedBB>(); final IPartCollisionHelper bch = new BusCollisionHelper(boxes, side, null, true); p.getBoxes(bch, null); for (AxisAlignedBB bb : boxes) { bb = bb.expand(0.01, 0.01, 0.01); if (bb.isVecInside(pos)) { return new SelectedPart(p, side); } } } } } return new SelectedPart(); } @Override public void markForSave() { this.tcb.markForSave(); } @Override public void partChanged() { if (this.getCenter() == null) { final List<ItemStack> facades = new LinkedList<ItemStack>(); final IFacadeContainer fc = this.getFacadeContainer(); for (final AEPartLocation d : AEPartLocation.SIDE_LOCATIONS) { final IFacadePart fp = fc.getFacade(d); if (fp != null) { facades.add(fp.getItemStack()); fc.removeFacade(this.tcb, d); } } if (!facades.isEmpty()) { final TileEntity te = this.tcb.getTile(); Platform.spawnDrops(te.getWorld(), te.getPos(), facades); } } this.tcb.partChanged(); } @Override public boolean hasRedstone(final AEPartLocation side) { if (this.hasRedstone == YesNo.UNDECIDED) { this.updateRedstone(); } return this.hasRedstone == YesNo.YES; } @Override public boolean isEmpty() { final IFacadeContainer fc = this.getFacadeContainer(); for (final AEPartLocation s : AEPartLocation.values()) { final IPart part = this.getPart(s); if (part != null) { return false; } if (s != AEPartLocation.INTERNAL) { final IFacadePart fp = fc.getFacade(s); if (fp != null) { return false; } } } return true; } @Override public Set<LayerFlags> getLayerFlags() { return this.myLayerFlags; } @Override public void cleanup() { this.tcb.cleanup(); } @Override public void notifyNeighbors() { this.tcb.notifyNeighbors(); } @Override public boolean isInWorld() { return this.inWorld; } private void updateRedstone() { final TileEntity te = this.getTile(); this.hasRedstone = te.getWorld().isBlockIndirectlyGettingPowered(te.getPos()) != 0 ? YesNo.YES : YesNo.NO; } private void updateDynamicRender() { this.requiresDynamicRender = false; for (final AEPartLocation s : AEPartLocation.SIDE_LOCATIONS) { final IPart p = this.getPart(s); if (p != null) { this.setRequiresDynamicRender(this.isRequiresDynamicRender() || p.requireDynamicRender()); } } } /** * use for FMP */ public void updateConnections() { if (this.getCenter() != null) { final EnumSet<EnumFacing> sides = EnumSet.allOf(EnumFacing.class); for (final EnumFacing s : EnumFacing.VALUES) { if (this.getPart(s) != null || this.isBlocked(s)) { sides.remove(s); } } this.getCenter().setValidSides(sides); final IGridNode n = this.getCenter().getGridNode(); if (n != null) { n.updateState(); } } } public void addToWorld() { if (this.inWorld) { return; } this.inWorld = true; IS_LOADING.set(true); final TileEntity te = this.getTile(); // start with the center, then install the side parts into the grid. for (int x = 6; x >= 0; x--) { final AEPartLocation s = AEPartLocation.fromOrdinal(x); final IPart part = this.getPart(s); if (part != null) { part.setPartHostInfo(s, this, te); part.addToWorld(); if (s != AEPartLocation.INTERNAL) { final IGridNode sn = part.getGridNode(); if (sn != null) { // this is a really stupid if statement, why was this // here? // if ( !sn.getConnections().iterator().hasNext() ) final IPart center = this.getPart(AEPartLocation.INTERNAL); if (center != null) { final IGridNode cn = center.getGridNode(); if (cn != null) { try { AEApi.instance().createGridConnection(cn, sn); } catch (final FailedConnection e) { // ekk } } } } } } } this.partChanged(); IS_LOADING.set(false); } public void removeFromWorld() { if (!this.inWorld) { return; } this.inWorld = false; for (final AEPartLocation s : AEPartLocation.values()) { final IPart part = this.getPart(s); if (part != null) { part.removeFromWorld(); } } this.partChanged(); } @Override public IGridNode getGridNode(final AEPartLocation side) { final IPart part = this.getPart(side); if (part != null) { final IGridNode n = part.getExternalFacingNode(); if (n != null) { return n; } } if (this.getCenter() != null) { return this.getCenter().getGridNode(); } return null; } @Override public AECableType getCableConnectionType(final AEPartLocation dir) { final IPart part = this.getPart(dir); if (part instanceof IGridHost) { final AECableType t = ((IGridHost) part).getCableConnectionType(dir); if (t != null && t != AECableType.NONE) { return t; } } if (this.getCenter() != null) { final IPartCable c = this.getCenter(); return c.getCableConnectionType(); } return AECableType.NONE; } @Override public float getCableConnectionLength(AECableType cable) { return getPart(AEPartLocation.INTERNAL) instanceof IPartCable ? getPart(AEPartLocation.INTERNAL).getCableConnectionLength(cable) : -1; } @Override public void securityBreak() { for (final AEPartLocation d : AEPartLocation.values()) { final IPart p = this.getPart(d); if (p instanceof IGridHost) { ((IGridHost) p).securityBreak(); } } } public Iterable<AxisAlignedBB> getSelectedBoundingBoxesFromPool(final boolean ignoreConnections, final boolean includeFacades, final Entity e, final boolean visual) { final List<AxisAlignedBB> boxes = new LinkedList<AxisAlignedBB>(); final IFacadeContainer fc = this.getFacadeContainer(); for (final AEPartLocation s : AEPartLocation.values()) { final IPartCollisionHelper bch = new BusCollisionHelper(boxes, s, e, visual); final IPart part = this.getPart(s); if (part != null) { if (ignoreConnections && part instanceof IPartCable) { bch.addBox(6.0, 6.0, 6.0, 10.0, 10.0, 10.0); } else { part.getBoxes(bch); } } if (AEApi.instance().partHelper().getCableRenderMode().opaqueFacades || !visual) { if (includeFacades && s != null && s != AEPartLocation.INTERNAL) { final IFacadePart fp = fc.getFacade(s); if (fp != null) { fp.getBoxes(bch, e); } } } } return boxes; } @Override public int isProvidingStrongPower(final EnumFacing side) { final IPart part = this.getPart(side); return part != null ? part.isProvidingStrongPower() : 0; } @Override public int isProvidingWeakPower(final EnumFacing side) { final IPart part = this.getPart(side); return part != null ? part.isProvidingWeakPower() : 0; } @Override public boolean canConnectRedstone(final EnumSet<EnumFacing> enumSet) { for (final EnumFacing dir : enumSet) { final IPart part = this.getPart(dir); if (part != null && part.canConnectRedstone()) { return true; } } return false; } @Override public void onEntityCollision(final Entity entity) { for (final AEPartLocation s : AEPartLocation.values()) { final IPart part = this.getPart(s); if (part != null) { part.onEntityCollision(entity); } } } @Override public boolean activate(final EntityPlayer player, final EnumHand hand, final Vec3d pos) { final SelectedPart p = this.selectPart(pos); if (p != null && p.part != null) { return p.part.onActivate(player, hand, pos); } return false; } @Override public void onNeighborChanged() { this.hasRedstone = YesNo.UNDECIDED; for (final AEPartLocation s : AEPartLocation.values()) { final IPart part = this.getPart(s); if (part != null) { part.onNeighborChanged(); } } } @Override public boolean isSolidOnSide(final EnumFacing side) { if (side == null) { return false; } // facades are solid.. final IFacadePart fp = this.getFacadeContainer().getFacade(AEPartLocation.fromFacing(side)); if (fp != null) { return true; } // buses can be too. final IPart part = this.getPart(side); return part != null && part.isSolid(); } @Override public boolean isLadder(final EntityLivingBase entity) { for (final AEPartLocation side : AEPartLocation.values()) { final IPart p = this.getPart(side); if (p != null) { if (p.isLadder(entity)) { return true; } } } return false; } @Override public void randomDisplayTick(final World world, final BlockPos pos, final Random r) { for (final AEPartLocation side : AEPartLocation.values()) { final IPart p = this.getPart(side); if (p != null) { p.randomDisplayTick(world, pos, r); } } } @Override public int getLightValue() { int light = 0; for (final AEPartLocation d : AEPartLocation.values()) { final IPart p = this.getPart(d); if (p != null) { light = Math.max(p.getLightLevel(), light); } } return light; } public void writeToStream(final ByteBuf data) throws IOException { int sides = 0; for (int x = 0; x < 7; x++) { final IPart p = this.getPart(AEPartLocation.fromOrdinal(x)); if (p != null) { sides |= (1 << x); } } data.writeByte((byte) sides); for (int x = 0; x < 7; x++) { final IPart p = this.getPart(AEPartLocation.fromOrdinal(x)); if (p != null) { final ItemStack is = p.getItemStack(PartItemStack.NETWORK); data.writeShort(Item.getIdFromItem(is.getItem())); data.writeShort(is.getItemDamage()); p.writeToStream(data); } } this.getFacadeContainer().writeToStream(data); } public boolean readFromStream(final ByteBuf data) throws IOException { final byte sides = data.readByte(); boolean updateBlock = false; for (int x = 0; x < 7; x++) { AEPartLocation side = AEPartLocation.fromOrdinal(x); if (((sides & (1 << x)) == (1 << x))) { IPart p = this.getPart(side); final short itemID = data.readShort(); final short dmgValue = data.readShort(); final Item myItem = Item.getItemById(itemID); final ItemStack current = p != null ? p.getItemStack(PartItemStack.NETWORK) : null; if (current != null && current.getItem() == myItem && current.getItemDamage() == dmgValue) { if (p.readFromStream(data)) { updateBlock = true; } } else { this.removePart(side, false); side = this.addPart(new ItemStack(myItem, 1, dmgValue), side, null, null); if (side != null) { p = this.getPart(side); p.readFromStream(data); } else { throw new IllegalStateException("Invalid Stream For CableBus Container."); } } } else if (this.getPart(side) != null) { this.removePart(side, false); } } if (this.getFacadeContainer().readFromStream(data)) { return true; } return updateBlock; } public void writeToNBT(final NBTTagCompound data) { data.setInteger("hasRedstone", this.hasRedstone.ordinal()); final IFacadeContainer fc = this.getFacadeContainer(); for (final AEPartLocation s : AEPartLocation.values()) { fc.writeToNBT(data); final IPart part = this.getPart(s); if (part != null) { final NBTTagCompound def = new NBTTagCompound(); part.getItemStack(PartItemStack.WORLD).writeToNBT(def); final NBTTagCompound extra = new NBTTagCompound(); part.writeToNBT(extra); data.setTag("def:" + this.getSide(part).ordinal(), def); data.setTag("extra:" + this.getSide(part).ordinal(), extra); } } } private AEPartLocation getSide(final IPart part) { if (this.getCenter() == part) { return AEPartLocation.INTERNAL; } else { for (final AEPartLocation side : AEPartLocation.SIDE_LOCATIONS) { if (this.getSide(side) == part) { return side; } } } throw new IllegalStateException("Uhh Bad Part (" + part + ") on Side."); } public void readFromNBT(final NBTTagCompound data) { if (data.hasKey("hasRedstone")) { this.hasRedstone = YesNo.values()[data.getInteger("hasRedstone")]; } for (int x = 0; x < 7; x++) { AEPartLocation side = AEPartLocation.fromOrdinal(x); final NBTTagCompound def = data.getCompoundTag("def:" + side.ordinal()); final NBTTagCompound extra = data.getCompoundTag("extra:" + side.ordinal()); if (def != null && extra != null) { IPart p = this.getPart(side); final ItemStack iss = ItemStack.loadItemStackFromNBT(def); if (iss == null) { continue; } final ItemStack current = p == null ? null : p.getItemStack(PartItemStack.WORLD); if (Platform.itemComparisons().isEqualItemType(iss, current)) { p.readFromNBT(extra); } else { this.removePart(side, true); side = this.addPart(iss, side, null, null); if (side != null) { p = this.getPart(side); p.readFromNBT(extra); } else { AELog.warn("Invalid NBT For CableBus Container: " + iss.getItem().getClass().getName() + " is not a valid part; it was ignored."); } } } else { this.removePart(side, false); } } this.getFacadeContainer().readFromNBT(data); } public List getDrops(final List drops) { for (final AEPartLocation s : AEPartLocation.values()) { final IPart part = this.getPart(s); if (part != null) { drops.add(part.getItemStack(PartItemStack.BREAK)); part.getDrops(drops, false); } if (s != AEPartLocation.INTERNAL) { final IFacadePart fp = this.getFacadeContainer().getFacade(s); if (fp != null) { drops.add(fp.getItemStack()); } } } return drops; } public List getNoDrops(final List drops) { for (final AEPartLocation s : AEPartLocation.values()) { final IPart part = this.getPart(s); if (part != null) { part.getDrops(drops, false); } } return drops; } @Override public boolean recolourBlock(final EnumFacing side, final AEColor colour, final EntityPlayer who) { final IPart cable = this.getPart(AEPartLocation.INTERNAL); if (cable != null) { final IPartCable pc = (IPartCable) cable; return pc.changeColor(colour, who); } return false; } public boolean isRequiresDynamicRender() { return this.requiresDynamicRender; } private void setRequiresDynamicRender(final boolean requiresDynamicRender) { this.requiresDynamicRender = requiresDynamicRender; } @Override public CableBusRenderState getRenderState() { PartCable cable = (PartCable) getCenter(); CableBusRenderState renderState = new CableBusRenderState(); if (cable != null) { renderState.setCableColor(cable.getCableColor()); renderState.setCableType(cable.getCableConnectionType()); renderState.setCoreType(CableCoreType.fromCableType(cable.getCableConnectionType())); // Check each outgoing connection for the desired characteristics for (EnumFacing facing : EnumFacing.values()) { // Is there a connection? if (!cable.isConnected(facing)) { continue; } // If there is one, check out which type it has, but default to this cable's type AECableType connectionType = cable.getCableConnectionType(); // Only use the incoming cable-type of the adjacent block, if it's not a cable bus itself // Dense cables however also respect the adjacent cable-type since their outgoing connection // point would look too big for other cable types BlockPos adjacentPos = this.getTile().getPos().offset(facing); TileEntity adjacentTe = this.getTile().getWorld().getTileEntity(adjacentPos); if (adjacentTe instanceof IGridHost) { if (!(adjacentTe instanceof IPartHost) || cable.getCableConnectionType() == AECableType.DENSE) { IGridHost gridHost = (IGridHost) adjacentTe; connectionType = gridHost .getCableConnectionType(AEPartLocation.fromFacing(facing.getOpposite())); } } // Check if the adjacent TE is a cable bus or not if (adjacentTe instanceof IPartHost) { renderState.getCableBusAdjacent().add(facing); } renderState.getConnectionTypes().put(facing, connectionType); } // Collect the number of channels used per side // We have to do this even for non-smart cables since a glass cable can display a connection as smart if the adjacent tile requires it for (EnumFacing facing : EnumFacing.values()) { int channels = cable.getChannelsOnSide(facing); renderState.getChannelsOnSide().put(facing, channels); } } // Determine attachments and facades for (EnumFacing facing : EnumFacing.values()) { FacadeRenderState facadeState = getFacadeRenderState(facing); if (facadeState != null) { renderState.getFacades().put(facing, facadeState); } IPart part = getPart(facing); if (part == null) { continue; } // This will add the part's bounding boxes to the render state, which is required for facades AEPartLocation loc = AEPartLocation.fromFacing(facing); IPartCollisionHelper bch = new BusCollisionHelper(renderState.getBoundingBoxes(), loc, null, true); part.getBoxes(bch); if (part instanceof IGridHost) { // Some attachments want a thicker cable than glass, account for that IGridHost gridHost = (IGridHost) part; AECableType desiredType = gridHost.getCableConnectionType(AEPartLocation.INTERNAL); if (renderState.getCoreType() == CableCoreType.GLASS && (desiredType == AECableType.SMART || desiredType == AECableType.COVERED)) { renderState.setCoreType(CableCoreType.COVERED); } int length = (int) part.getCableConnectionLength(null); if (length > 0 && length <= 8) { renderState.getAttachmentConnections().put(facing, length); } } renderState.getAttachments().put(facing, part.getStaticModels()); } return renderState; } private FacadeRenderState getFacadeRenderState(EnumFacing side) { // Store the "masqueraded" itemstack for the given side, if there is a facade IFacadePart facade = getFacade(side.ordinal()); if (facade != null) { ItemStack textureItem = facade.getTextureItem(); IBlockState blockState = facade.getBlockState(); if (blockState != null && textureItem != null) { EnumSet<EnumFacing> openFaces = calculateFaceOpenFaces(side); return new FacadeRenderState(blockState, openFaces, textureItem); } } return null; } private EnumSet<EnumFacing> calculateFaceOpenFaces(EnumFacing side) { final EnumSet<EnumFacing> out = EnumSet.of(side, side.getOpposite()); final IFacadePart facade = getFacade(side.ordinal()); IBlockAccess blockAccess = getTile().getWorld(); BlockPos pos = getTile().getPos(); for (final EnumFacing it : EnumFacing.values()) { if (!out.contains(it) && this.hasAlphaDiff(blockAccess.getTileEntity(pos.offset(it)), side, facade)) { out.add(it); } } if (out.contains(EnumFacing.UP) && (side.getFrontOffsetX() != 0 || side.getFrontOffsetZ() != 0)) { final IFacadePart fp = getFacade(EnumFacing.UP.ordinal()); if (fp != null && (fp.isTransparent() == facade.isTransparent())) { out.remove(EnumFacing.UP); } } if (out.contains(EnumFacing.DOWN) && (side.getFrontOffsetX() != 0 || side.getFrontOffsetZ() != 0)) { final IFacadePart fp = getFacade(EnumFacing.DOWN.ordinal()); if (fp != null && (fp.isTransparent() == facade.isTransparent())) { out.remove(EnumFacing.DOWN); } } if (out.contains(EnumFacing.SOUTH) && (side.getFrontOffsetX() != 0)) { final IFacadePart fp = getFacade(EnumFacing.SOUTH.ordinal()); if (fp != null && (fp.isTransparent() == facade.isTransparent())) { out.remove(EnumFacing.SOUTH); } } if (out.contains(EnumFacing.NORTH) && (side.getFrontOffsetX() != 0)) { final IFacadePart fp = getFacade(EnumFacing.NORTH.ordinal()); if (fp != null && (fp.isTransparent() == facade.isTransparent())) { out.remove(EnumFacing.NORTH); } } return out; } private boolean hasAlphaDiff(final TileEntity tileEntity, final EnumFacing side, final IFacadePart facade) { if (tileEntity instanceof IPartHost) { final IPartHost ph = (IPartHost) tileEntity; final IFacadePart fp = ph.getFacadeContainer().getFacade(AEPartLocation.fromFacing(side)); return fp == null || (fp.isTransparent() != facade.isTransparent()); } return true; } }