CC-Tweaked/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java

254 lines
10 KiB
Java

/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.peripheral.modem.wired;
import com.google.common.collect.ImmutableMap;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.shared.Registry;
import dan200.computercraft.shared.common.BlockGeneric;
import dan200.computercraft.shared.util.WorldUtil;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.IWaterLoggable;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.fluid.IFluidState;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.item.ItemStack;
import net.minecraft.state.BooleanProperty;
import net.minecraft.state.EnumProperty;
import net.minecraft.state.StateContainer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.RayTraceContext;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorld;
import net.minecraft.world.IWorldReader;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.EnumMap;
import static dan200.computercraft.shared.util.WaterloggableHelpers.*;
public class BlockCable extends BlockGeneric implements IWaterLoggable
{
public static final EnumProperty<CableModemVariant> MODEM = EnumProperty.create( "modem", CableModemVariant.class );
public static final BooleanProperty CABLE = BooleanProperty.create( "cable" );
private static final BooleanProperty NORTH = BooleanProperty.create( "north" );
private static final BooleanProperty SOUTH = BooleanProperty.create( "south" );
private static final BooleanProperty EAST = BooleanProperty.create( "east" );
private static final BooleanProperty WEST = BooleanProperty.create( "west" );
private static final BooleanProperty UP = BooleanProperty.create( "up" );
private static final BooleanProperty DOWN = BooleanProperty.create( "down" );
static final EnumMap<Direction, BooleanProperty> CONNECTIONS =
new EnumMap<>( new ImmutableMap.Builder<Direction, BooleanProperty>()
.put( Direction.DOWN, DOWN ).put( Direction.UP, UP )
.put( Direction.NORTH, NORTH ).put( Direction.SOUTH, SOUTH )
.put( Direction.WEST, WEST ).put( Direction.EAST, EAST )
.build() );
public BlockCable( Properties settings )
{
super( settings, Registry.ModTiles.CABLE );
registerDefaultState( getStateDefinition().any()
.setValue( MODEM, CableModemVariant.None )
.setValue( CABLE, false )
.setValue( NORTH, false ).setValue( SOUTH, false )
.setValue( EAST, false ).setValue( WEST, false )
.setValue( UP, false ).setValue( DOWN, false )
.setValue( WATERLOGGED, false )
);
}
@Override
protected void createBlockStateDefinition( StateContainer.Builder<Block, BlockState> builder )
{
builder.add( MODEM, CABLE, NORTH, SOUTH, EAST, WEST, UP, DOWN, WATERLOGGED );
}
public static boolean canConnectIn( BlockState state, Direction direction )
{
return state.getValue( BlockCable.CABLE ) && state.getValue( BlockCable.MODEM ).getFacing() != direction;
}
public static boolean doesConnectVisually( BlockState state, IBlockReader world, BlockPos pos, Direction direction )
{
if( !state.getValue( CABLE ) ) return false;
if( state.getValue( MODEM ).getFacing() == direction ) return true;
return ComputerCraftAPI.getWiredElementAt( world, pos.relative( direction ), direction.getOpposite() ).isPresent();
}
@Nonnull
@Override
@Deprecated
public VoxelShape getShape( @Nonnull BlockState state, @Nonnull IBlockReader world, @Nonnull BlockPos pos, @Nonnull ISelectionContext context )
{
return CableShapes.getShape( state );
}
@Override
public boolean removedByPlayer( BlockState state, World world, BlockPos pos, PlayerEntity player, boolean willHarvest, IFluidState fluid )
{
if( state.getValue( CABLE ) && state.getValue( MODEM ).getFacing() != null )
{
BlockRayTraceResult hit = world.clip( new RayTraceContext(
WorldUtil.getRayStart( player ), WorldUtil.getRayEnd( player ),
RayTraceContext.BlockMode.COLLIDER, RayTraceContext.FluidMode.NONE, player
) );
if( hit.getType() == RayTraceResult.Type.BLOCK )
{
TileEntity tile = world.getBlockEntity( pos );
if( tile instanceof TileCable && tile.hasLevel() )
{
TileCable cable = (TileCable) tile;
ItemStack item;
BlockState newState;
if( WorldUtil.isVecInside( CableShapes.getModemShape( state ), hit.getLocation().subtract( pos.getX(), pos.getY(), pos.getZ() ) ) )
{
newState = state.setValue( MODEM, CableModemVariant.None );
item = new ItemStack( Registry.ModItems.WIRED_MODEM.get() );
}
else
{
newState = state.setValue( CABLE, false );
item = new ItemStack( Registry.ModItems.CABLE.get() );
}
world.setBlock( pos, correctConnections( world, pos, newState ), 3 );
cable.modemChanged();
cable.connectionsChanged();
if( !world.isClientSide && !player.abilities.instabuild )
{
Block.popResource( world, pos, item );
}
return false;
}
}
}
return super.removedByPlayer( state, world, pos, player, willHarvest, fluid );
}
@Nonnull
@Override
public ItemStack getPickBlock( BlockState state, RayTraceResult hit, IBlockReader world, BlockPos pos, PlayerEntity player )
{
Direction modem = state.getValue( MODEM ).getFacing();
boolean cable = state.getValue( CABLE );
// If we've only got one, just use that.
if( !cable ) return new ItemStack( Registry.ModItems.WIRED_MODEM.get() );
if( modem == null ) return new ItemStack( Registry.ModItems.CABLE.get() );
// We've a modem and cable, so try to work out which one we're interacting with
return hit != null && WorldUtil.isVecInside( CableShapes.getModemShape( state ), hit.getLocation().subtract( pos.getX(), pos.getY(), pos.getZ() ) )
? new ItemStack( Registry.ModItems.WIRED_MODEM.get() )
: new ItemStack( Registry.ModItems.CABLE.get() );
}
@Override
public void setPlacedBy( World world, @Nonnull BlockPos pos, @Nonnull BlockState state, LivingEntity placer, @Nonnull ItemStack stack )
{
TileEntity tile = world.getBlockEntity( pos );
if( tile instanceof TileCable )
{
TileCable cable = (TileCable) tile;
if( cable.hasCable() ) cable.connectionsChanged();
}
super.setPlacedBy( world, pos, state, placer, stack );
}
@Nonnull
@Override
@Deprecated
public IFluidState getFluidState( @Nonnull BlockState state )
{
return getWaterloggedFluidState( state );
}
@Nonnull
@Override
@Deprecated
public BlockState updateShape( @Nonnull BlockState state, @Nonnull Direction side, @Nonnull BlockState otherState, @Nonnull IWorld world, @Nonnull BlockPos pos, @Nonnull BlockPos otherPos )
{
updateWaterloggedPostPlacement( state, world, pos );
// Should never happen, but handle the case where we've no modem or cable.
if( !state.getValue( CABLE ) && state.getValue( MODEM ) == CableModemVariant.None )
{
return getFluidState( state ).createLegacyBlock();
}
return state.setValue( CONNECTIONS.get( side ), doesConnectVisually( state, world, pos, side ) );
}
@Override
@Deprecated
public boolean canSurvive( BlockState state, @Nonnull IWorldReader world, @Nonnull BlockPos pos )
{
Direction facing = state.getValue( MODEM ).getFacing();
if( facing == null ) return true;
BlockPos offsetPos = pos.relative( facing );
BlockState offsetState = world.getBlockState( offsetPos );
return isFaceSturdy( offsetState, world, offsetPos, facing.getOpposite() );
}
@Nullable
@Override
public BlockState getStateForPlacement( @Nonnull BlockItemUseContext context )
{
BlockState state = defaultBlockState()
.setValue( WATERLOGGED, getWaterloggedStateForPlacement( context ) );
if( context.getItemInHand().getItem() instanceof ItemBlockCable.Cable )
{
World world = context.getLevel();
BlockPos pos = context.getClickedPos();
return correctConnections( world, pos, state.setValue( CABLE, true ) );
}
else
{
return state.setValue( MODEM, CableModemVariant.from( context.getClickedFace().getOpposite() ) );
}
}
public static BlockState correctConnections( World world, BlockPos pos, BlockState state )
{
if( state.getValue( CABLE ) )
{
return state
.setValue( NORTH, doesConnectVisually( state, world, pos, Direction.NORTH ) )
.setValue( SOUTH, doesConnectVisually( state, world, pos, Direction.SOUTH ) )
.setValue( EAST, doesConnectVisually( state, world, pos, Direction.EAST ) )
.setValue( WEST, doesConnectVisually( state, world, pos, Direction.WEST ) )
.setValue( UP, doesConnectVisually( state, world, pos, Direction.UP ) )
.setValue( DOWN, doesConnectVisually( state, world, pos, Direction.DOWN ) );
}
else
{
return state
.setValue( NORTH, false ).setValue( SOUTH, false ).setValue( EAST, false )
.setValue( WEST, false ).setValue( UP, false ).setValue( DOWN, false );
}
}
}