Applied-Energistics-2-tiler.../src/main/java/appeng/parts/CableBusContainer.java
Sebastian Hartte 633ea48d42 Cleaned up unused Mod integrations other than for mods that are likely to be integrated soon.
Introduced an easier Facade class to access mod integration abstractions (called Integrations). Removed the link between IntegrationType and integration abstraction. Integrations are now explicitly instantiated inside of IntegrationNode.
2016-11-06 01:03:02 +01:00

1337 lines
31 KiB
Java

/*
* 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 )
{
IBlockState blockState = facade.getBlockState();
if( blockState != null )
{
EnumSet<EnumFacing> openFaces = calculateFaceOpenFaces( side );
return new FacadeRenderState( blockState, openFaces );
}
}
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;
}
}