CC-Tweaked/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java

753 lines
24 KiB
Java
Raw Normal View History

/*
* 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.monitor;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.peripheral.IComputerAccess;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.shared.common.ServerTerminal;
import dan200.computercraft.shared.common.TileGeneric;
import dan200.computercraft.shared.network.client.TerminalState;
import dan200.computercraft.shared.util.CapabilityUtil;
import dan200.computercraft.shared.util.TickScheduler;
import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.Direction;
import net.minecraft.util.Hand;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.world.World;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.LazyOptional;
2017-05-06 23:07:42 +00:00
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.HashSet;
import java.util.Set;
import static dan200.computercraft.shared.Capabilities.CAPABILITY_PERIPHERAL;
public class TileMonitor extends TileGeneric
{
public static final double RENDER_BORDER = 2.0 / 16.0;
public static final double RENDER_MARGIN = 0.5 / 16.0;
public static final double RENDER_PIXEL_SCALE = 1.0 / 64.0;
private static final String NBT_X = "XIndex";
private static final String NBT_Y = "YIndex";
private static final String NBT_WIDTH = "Width";
private static final String NBT_HEIGHT = "Height";
private final boolean advanced;
private ServerMonitor serverMonitor;
private ClientMonitor clientMonitor;
private MonitorPeripheral peripheral;
private LazyOptional<IPeripheral> peripheralCap;
private final Set<IComputerAccess> computers = new HashSet<>();
private boolean needsUpdate = false;
private boolean needsValidating = false;
private boolean destroyed = false;
private boolean visiting = false;
// MonitorWatcher state.
boolean enqueued;
TerminalState cached;
private int width = 1;
private int height = 1;
private int xIndex = 0;
private int yIndex = 0;
public TileMonitor( TileEntityType<? extends TileMonitor> type, boolean advanced )
{
super( type );
this.advanced = advanced;
}
@Override
public void onLoad()
{
super.onLoad();
needsValidating = true;
TickScheduler.schedule( this );
}
@Override
public void destroy()
{
// TODO: Call this before using the block
if( destroyed ) return;
destroyed = true;
if( !getLevel().isClientSide ) contractNeighbours();
}
@Override
public void setRemoved()
{
super.setRemoved();
if( clientMonitor != null && xIndex == 0 && yIndex == 0 ) clientMonitor.destroy();
}
@Override
public void onChunkUnloaded()
{
super.onChunkUnloaded();
if( clientMonitor != null && xIndex == 0 && yIndex == 0 ) clientMonitor.destroy();
2017-05-01 14:48:44 +00:00
}
@Nonnull
@Override
public ActionResultType onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit )
{
if( !player.isCrouching() && getFront() == hit.getDirection() )
{
if( !getLevel().isClientSide )
{
monitorTouched(
(float) (hit.getLocation().x - hit.getBlockPos().getX()),
(float) (hit.getLocation().y - hit.getBlockPos().getY()),
(float) (hit.getLocation().z - hit.getBlockPos().getZ())
);
}
return ActionResultType.SUCCESS;
}
return ActionResultType.PASS;
}
2017-05-06 23:07:42 +00:00
@Nonnull
@Override
public CompoundNBT save( CompoundNBT tag )
{
tag.putInt( NBT_X, xIndex );
tag.putInt( NBT_Y, yIndex );
tag.putInt( NBT_WIDTH, width );
tag.putInt( NBT_HEIGHT, height );
return super.save( tag );
}
@Override
public void load( @Nonnull CompoundNBT tag )
{
super.load( tag );
xIndex = tag.getInt( NBT_X );
yIndex = tag.getInt( NBT_Y );
width = tag.getInt( NBT_WIDTH );
height = tag.getInt( NBT_HEIGHT );
}
@Override
public void blockTick()
{
if( needsValidating )
{
needsValidating = false;
validate();
}
if( needsUpdate )
{
needsUpdate = false;
updateNeighbors();
}
if( xIndex != 0 || yIndex != 0 || serverMonitor == null ) return;
serverMonitor.clearChanged();
if( serverMonitor.pollResized() )
{
for( int x = 0; x < width; x++ )
{
for( int y = 0; y < height; y++ )
{
TileMonitor monitor = getNeighbour( x, y ).getMonitor();
if( monitor == null ) continue;
for( IComputerAccess computer : monitor.computers )
{
Replace getMethodNames/callMethod with annotations (#447) When creating a peripheral or custom Lua object, one must implement two methods: - getMethodNames(): String[] - Returns the name of the methods - callMethod(int, ...): Object[] - Invokes the method using an index in the above array. This has a couple of problems: - It's somewhat unwieldy to use - you need to keep track of array indices, which leads to ugly code. - Functions which yield (for instance, those which run on the main thread) are blocking. This means we need to spawn new threads for each CC-side yield. We replace this system with a few changes: - @LuaFunction annotation: One may annotate a public instance method with this annotation. This then exposes a peripheral/lua object method. Furthermore, this method can accept and return a variety of types, which often makes functions cleaner (e.g. can return an int rather than an Object[], and specify and int argument rather than Object[]). - MethodResult: Instead of returning an Object[] and having blocking yields, functions return a MethodResult. This either contains an immediate return, or an instruction to yield with some continuation to resume with. MethodResult is then interpreted by the Lua runtime (i.e. Cobalt), rather than our weird bodgey hacks before. This means we no longer spawn new threads when yielding within CC. - Methods accept IArguments instead of a raw Object array. This has a few benefits: - Consistent argument handling - people no longer need to use ArgumentHelper (as it doesn't exist!), or even be aware of its existence - you're rather forced into using it. - More efficient code in some cases. We provide a Cobalt-specific implementation of IArguments, which avoids the boxing/unboxing when handling numbers and binary strings.
2020-05-15 12:21:16 +00:00
computer.queueEvent( "monitor_resize", computer.getAttachmentName() );
}
}
}
2017-05-01 14:48:44 +00:00
}
if( serverMonitor.pollTerminalChanged() ) MonitorWatcher.enqueue( this );
2017-05-01 14:48:44 +00:00
}
@Override
protected void invalidateCaps()
{
super.invalidateCaps();
peripheralCap = CapabilityUtil.invalidate( peripheralCap );
}
@Nonnull
@Override
public <T> LazyOptional<T> getCapability( @Nonnull Capability<T> cap, @Nullable Direction side )
{
if( cap == CAPABILITY_PERIPHERAL )
{
createServerMonitor(); // Ensure the monitor is created before doing anything else.
if( peripheral == null ) peripheral = new MonitorPeripheral( this );
if( peripheralCap == null ) peripheralCap = LazyOptional.of( () -> peripheral );
return peripheralCap.cast();
}
return super.getCapability( cap, side );
}
public ServerMonitor getCachedServerMonitor()
{
return serverMonitor;
}
private ServerMonitor getServerMonitor()
{
if( serverMonitor != null ) return serverMonitor;
TileMonitor origin = getOrigin().getMonitor();
if( origin == null ) return null;
return serverMonitor = origin.serverMonitor;
}
private ServerMonitor createServerMonitor()
{
if( serverMonitor != null ) return serverMonitor;
if( xIndex == 0 && yIndex == 0 )
{
// If we're the origin, set up the new monitor
serverMonitor = new ServerMonitor( advanced, this );
serverMonitor.rebuild();
// And propagate it to child monitors
for( int x = 0; x < width; x++ )
{
for( int y = 0; y < height; y++ )
{
TileMonitor monitor = getNeighbour( x, y ).getMonitor();
if( monitor != null ) monitor.serverMonitor = serverMonitor;
}
}
return serverMonitor;
}
else
{
// Otherwise fetch the origin and attempt to get its monitor
// Note this may load chunks, but we don't really have a choice here.
BlockPos pos = getBlockPos();
TileEntity te = level.getBlockEntity( pos.relative( getRight(), -xIndex ).relative( getDown(), -yIndex ) );
if( !(te instanceof TileMonitor) ) return null;
return serverMonitor = ((TileMonitor) te).createServerMonitor();
}
}
public ClientMonitor getClientMonitor()
{
if( clientMonitor != null ) return clientMonitor;
BlockPos pos = getBlockPos();
TileEntity te = level.getBlockEntity( pos.relative( getRight(), -xIndex ).relative( getDown(), -yIndex ) );
if( !(te instanceof TileMonitor) ) return null;
return clientMonitor = ((TileMonitor) te).clientMonitor;
}
2017-05-01 14:48:44 +00:00
// Networking stuff
@Override
protected void writeDescription( @Nonnull CompoundNBT nbt )
{
super.writeDescription( nbt );
nbt.putInt( NBT_X, xIndex );
nbt.putInt( NBT_Y, yIndex );
nbt.putInt( NBT_WIDTH, width );
nbt.putInt( NBT_HEIGHT, height );
}
@Override
protected final void readDescription( @Nonnull CompoundNBT nbt )
{
super.readDescription( nbt );
int oldXIndex = xIndex;
int oldYIndex = yIndex;
xIndex = nbt.getInt( NBT_X );
yIndex = nbt.getInt( NBT_Y );
width = nbt.getInt( NBT_WIDTH );
height = nbt.getInt( NBT_HEIGHT );
if( oldXIndex != xIndex || oldYIndex != yIndex )
{
// If our index has changed then it's possible the origin monitor has changed. Thus
// we'll clear our cache. If we're the origin then we'll need to remove the glList as well.
if( oldXIndex == 0 && oldYIndex == 0 && clientMonitor != null ) clientMonitor.destroy();
clientMonitor = null;
}
if( xIndex == 0 && yIndex == 0 )
{
// If we're the origin terminal then create it.
if( clientMonitor == null ) clientMonitor = new ClientMonitor( advanced, this );
}
}
public final void read( TerminalState state )
{
if( xIndex != 0 || yIndex != 0 )
{
ComputerCraft.log.warn( "Receiving monitor state for non-origin terminal at {}", getBlockPos() );
return;
}
if( clientMonitor == null ) clientMonitor = new ClientMonitor( advanced, this );
clientMonitor.read( state );
}
// Sizing and placement stuff
private void updateBlockState()
{
getLevel().setBlock( getBlockPos(), getBlockState()
.setValue( BlockMonitor.STATE, MonitorEdgeState.fromConnections(
yIndex < height - 1, yIndex > 0,
xIndex > 0, xIndex < width - 1 ) ), 2 );
}
// region Sizing and placement stuff
public Direction getDirection()
{
// Ensure we're actually a monitor block. This _should_ always be the case, but sometimes there's
// fun problems with the block being missing on the client.
BlockState state = getBlockState();
return state.hasProperty( BlockMonitor.FACING ) ? state.getValue( BlockMonitor.FACING ) : Direction.NORTH;
}
public Direction getOrientation()
{
BlockState state = getBlockState();
return state.hasProperty( BlockMonitor.ORIENTATION ) ? state.getValue( BlockMonitor.ORIENTATION ) : Direction.NORTH;
}
public Direction getFront()
{
Direction orientation = getOrientation();
return orientation == Direction.NORTH ? getDirection() : orientation;
}
public Direction getRight()
{
return getDirection().getCounterClockWise();
}
public Direction getDown()
{
Direction orientation = getOrientation();
if( orientation == Direction.NORTH ) return Direction.UP;
return orientation == Direction.DOWN ? getDirection() : getDirection().getOpposite();
}
public int getWidth()
{
return width;
}
public int getHeight()
{
return height;
}
public int getXIndex()
{
return xIndex;
}
public int getYIndex()
{
return yIndex;
}
@Nonnull
private MonitorState getSimilarMonitorAt( BlockPos pos )
{
if( pos.equals( getBlockPos() ) ) return MonitorState.present( this );
World world = getLevel();
if( world == null || !world.isAreaLoaded( pos, 0 ) ) return MonitorState.UNLOADED;
TileEntity tile = world.getBlockEntity( pos );
if( !(tile instanceof TileMonitor) ) return MonitorState.MISSING;
TileMonitor monitor = (TileMonitor) tile;
return !monitor.visiting && !monitor.destroyed && advanced == monitor.advanced
&& getDirection() == monitor.getDirection() && getOrientation() == monitor.getOrientation()
? MonitorState.present( monitor ) : MonitorState.MISSING;
}
private MonitorState getNeighbour( int x, int y )
{
BlockPos pos = getBlockPos();
Direction right = getRight();
Direction down = getDown();
int xOffset = -xIndex + x;
int yOffset = -yIndex + y;
return getSimilarMonitorAt( pos.relative( right, xOffset ).relative( down, yOffset ) );
}
private MonitorState getOrigin()
{
2017-05-01 14:48:44 +00:00
return getNeighbour( 0, 0 );
}
private void resize( int width, int height )
{
2018-02-14 21:21:00 +00:00
// If we're not already the origin then we'll need to generate a new terminal.
if( xIndex != 0 || yIndex != 0 ) serverMonitor = null;
2018-02-14 21:21:00 +00:00
xIndex = 0;
yIndex = 0;
this.width = width;
this.height = height;
// Determine if we actually need a monitor. In order to do this, simply check if
// any component monitor been wrapped as a peripheral. Whilst this flag may be
// out of date,
boolean needsTerminal = false;
terminalCheck:
for( int x = 0; x < width; x++ )
2017-05-01 14:48:44 +00:00
{
for( int y = 0; y < height; y++ )
2017-05-01 14:48:44 +00:00
{
TileMonitor monitor = getNeighbour( x, y ).getMonitor();
if( monitor != null && monitor.peripheral != null )
2017-05-01 14:48:44 +00:00
{
needsTerminal = true;
break terminalCheck;
2017-05-01 14:48:44 +00:00
}
}
}
// Either delete the current monitor or sync a new one.
if( needsTerminal )
{
if( serverMonitor == null ) serverMonitor = new ServerMonitor( advanced, this );
}
else
{
serverMonitor = null;
}
// Update the terminal's width and height and rebuild it. This ensures the monitor
// is consistent when syncing it to other monitors.
if( serverMonitor != null ) serverMonitor.rebuild();
// Update the other monitors, setting coordinates, dimensions and the server terminal
for( int x = 0; x < width; x++ )
{
for( int y = 0; y < height; y++ )
{
TileMonitor monitor = getNeighbour( x, y ).getMonitor();
if( monitor == null ) continue;
monitor.xIndex = x;
monitor.yIndex = y;
monitor.width = width;
monitor.height = height;
monitor.serverMonitor = serverMonitor;
monitor.updateBlockState();
monitor.updateBlock();
}
}
2017-05-01 14:48:44 +00:00
}
2017-05-01 14:48:44 +00:00
private boolean mergeLeft()
{
TileMonitor left = getNeighbour( -1, 0 ).getMonitor();
if( left == null || left.yIndex != 0 || left.height != height ) return false;
int width = left.width + this.width;
if( width > ComputerCraft.monitorWidth ) return false;
TileMonitor origin = left.getOrigin().getMonitor();
if( origin != null ) origin.resize( width, height );
left.expand();
return true;
}
private boolean mergeRight()
{
TileMonitor right = getNeighbour( width, 0 ).getMonitor();
if( right == null || right.yIndex != 0 || right.height != height ) return false;
int width = this.width + right.width;
if( width > ComputerCraft.monitorWidth ) return false;
TileMonitor origin = getOrigin().getMonitor();
if( origin != null ) origin.resize( width, height );
expand();
return true;
}
private boolean mergeUp()
{
TileMonitor above = getNeighbour( 0, height ).getMonitor();
if( above == null || above.xIndex != 0 || above.width != width ) return false;
int height = above.height + this.height;
if( height > ComputerCraft.monitorHeight ) return false;
TileMonitor origin = getOrigin().getMonitor();
if( origin != null ) origin.resize( width, height );
expand();
return true;
}
private boolean mergeDown()
{
TileMonitor below = getNeighbour( 0, -1 ).getMonitor();
if( below == null || below.xIndex != 0 || below.width != width ) return false;
int height = this.height + below.height;
if( height > ComputerCraft.monitorHeight ) return false;
TileMonitor origin = below.getOrigin().getMonitor();
if( origin != null ) origin.resize( width, height );
below.expand();
return true;
}
void updateNeighborsDeferred()
{
needsUpdate = true;
}
void updateNeighbors()
{
contractNeighbours();
contract();
expand();
}
@SuppressWarnings( "StatementWithEmptyBody" )
void expand()
{
while( mergeLeft() || mergeRight() || mergeUp() || mergeDown() ) ;
2017-05-01 14:48:44 +00:00
}
void contractNeighbours()
2017-05-01 14:48:44 +00:00
{
visiting = true;
if( xIndex > 0 )
{
TileMonitor left = getNeighbour( xIndex - 1, yIndex ).getMonitor();
if( left != null ) left.contract();
2017-05-01 14:48:44 +00:00
}
if( xIndex + 1 < width )
{
TileMonitor right = getNeighbour( xIndex + 1, yIndex ).getMonitor();
if( right != null ) right.contract();
2017-05-01 14:48:44 +00:00
}
if( yIndex > 0 )
{
TileMonitor below = getNeighbour( xIndex, yIndex - 1 ).getMonitor();
if( below != null ) below.contract();
2017-05-01 14:48:44 +00:00
}
if( yIndex + 1 < height )
{
TileMonitor above = getNeighbour( xIndex, yIndex + 1 ).getMonitor();
if( above != null ) above.contract();
2017-05-01 14:48:44 +00:00
}
visiting = false;
2017-05-01 14:48:44 +00:00
}
void contract()
{
int height = this.height;
int width = this.width;
TileMonitor origin = getOrigin().getMonitor();
2017-05-01 14:48:44 +00:00
if( origin == null )
{
TileMonitor right = width > 1 ? getNeighbour( 1, 0 ).getMonitor() : null;
TileMonitor below = height > 1 ? getNeighbour( 0, 1 ).getMonitor() : null;
if( right != null ) right.resize( width - 1, 1 );
if( below != null ) below.resize( width, height - 1 );
if( right != null ) right.expand();
if( below != null ) below.expand();
2017-05-01 14:48:44 +00:00
return;
}
for( int y = 0; y < height; y++ )
2017-05-01 14:48:44 +00:00
{
for( int x = 0; x < width; x++ )
2017-05-01 14:48:44 +00:00
{
TileMonitor monitor = origin.getNeighbour( x, y ).getMonitor();
if( monitor != null ) continue;
// Decompose
TileMonitor above = null;
TileMonitor left = null;
TileMonitor right = null;
TileMonitor below = null;
2017-05-01 14:48:44 +00:00
if( y > 0 )
{
above = origin;
above.resize( width, y );
}
if( x > 0 )
{
left = origin.getNeighbour( 0, y ).getMonitor();
left.resize( x, 1 );
}
if( x + 1 < width )
{
right = origin.getNeighbour( x + 1, y ).getMonitor();
right.resize( width - (x + 1), 1 );
}
if( y + 1 < height )
{
below = origin.getNeighbour( 0, y + 1 ).getMonitor();
below.resize( width, height - (y + 1) );
}
// Re-expand
if( above != null ) above.expand();
if( left != null ) left.expand();
if( right != null ) right.expand();
if( below != null ) below.expand();
return;
2017-05-01 14:48:44 +00:00
}
}
}
private boolean checkMonitorAt( int xIndex, int yIndex )
{
BlockPos pos = getBlockPos();
Direction right = getRight();
Direction down = getDown();
MonitorState state = getSimilarMonitorAt( pos.relative( right, xIndex ).relative( down, yIndex ) );
if( state.isMissing() ) return false;
TileMonitor monitor = state.getMonitor();
if( monitor == null ) return true;
return monitor.xIndex == xIndex && monitor.yIndex == yIndex && monitor.width == width && monitor.height == height;
}
private void validate()
{
if( xIndex == 0 && yIndex == 0 && width == 1 || height == 1 ) return;
if( checkMonitorAt( 0, 0 ) && checkMonitorAt( 0, height - 1 ) &&
checkMonitorAt( width - 1, 0 ) && checkMonitorAt( width - 1, height - 1 ) )
{
return;
}
// Something in our monitor is invalid. For now, let's just reset ourselves and then try to integrate ourselves
// later.
resize( 1, 1 );
needsUpdate = true;
}
private void monitorTouched( float xPos, float yPos, float zPos )
2017-05-01 14:48:44 +00:00
{
XYPair pair = XYPair
.of( xPos, yPos, zPos, getDirection(), getOrientation() )
.add( xIndex, height - yIndex - 1 );
if( pair.x > width - RENDER_BORDER || pair.y > height - RENDER_BORDER || pair.x < RENDER_BORDER || pair.y < RENDER_BORDER )
2017-05-01 14:48:44 +00:00
{
return;
}
ServerTerminal serverTerminal = getServerMonitor();
if( serverTerminal == null || !serverTerminal.isColour() ) return;
Terminal originTerminal = serverTerminal.getTerminal();
if( originTerminal == null ) return;
double xCharWidth = (width - (RENDER_BORDER + RENDER_MARGIN) * 2.0) / originTerminal.getWidth();
double yCharHeight = (height - (RENDER_BORDER + RENDER_MARGIN) * 2.0) / originTerminal.getHeight();
int xCharPos = (int) Math.min( originTerminal.getWidth(), Math.max( (pair.x - RENDER_BORDER - RENDER_MARGIN) / xCharWidth + 1.0, 1.0 ) );
int yCharPos = (int) Math.min( originTerminal.getHeight(), Math.max( (pair.y - RENDER_BORDER - RENDER_MARGIN) / yCharHeight + 1.0, 1.0 ) );
for( int y = 0; y < height; y++ )
2017-05-01 14:48:44 +00:00
{
for( int x = 0; x < width; x++ )
2017-05-01 14:48:44 +00:00
{
TileMonitor monitor = getNeighbour( x, y ).getMonitor();
if( monitor == null ) continue;
for( IComputerAccess computer : monitor.computers )
2017-05-01 14:48:44 +00:00
{
Replace getMethodNames/callMethod with annotations (#447) When creating a peripheral or custom Lua object, one must implement two methods: - getMethodNames(): String[] - Returns the name of the methods - callMethod(int, ...): Object[] - Invokes the method using an index in the above array. This has a couple of problems: - It's somewhat unwieldy to use - you need to keep track of array indices, which leads to ugly code. - Functions which yield (for instance, those which run on the main thread) are blocking. This means we need to spawn new threads for each CC-side yield. We replace this system with a few changes: - @LuaFunction annotation: One may annotate a public instance method with this annotation. This then exposes a peripheral/lua object method. Furthermore, this method can accept and return a variety of types, which often makes functions cleaner (e.g. can return an int rather than an Object[], and specify and int argument rather than Object[]). - MethodResult: Instead of returning an Object[] and having blocking yields, functions return a MethodResult. This either contains an immediate return, or an instruction to yield with some continuation to resume with. MethodResult is then interpreted by the Lua runtime (i.e. Cobalt), rather than our weird bodgey hacks before. This means we no longer spawn new threads when yielding within CC. - Methods accept IArguments instead of a raw Object array. This has a few benefits: - Consistent argument handling - people no longer need to use ArgumentHelper (as it doesn't exist!), or even be aware of its existence - you're rather forced into using it. - More efficient code in some cases. We provide a Cobalt-specific implementation of IArguments, which avoids the boxing/unboxing when handling numbers and binary strings.
2020-05-15 12:21:16 +00:00
computer.queueEvent( "monitor_touch", computer.getAttachmentName(), xCharPos, yCharPos );
2017-05-01 14:48:44 +00:00
}
}
}
}
// endregion
void addComputer( IComputerAccess computer )
2017-05-01 14:48:44 +00:00
{
computers.add( computer );
2017-05-01 14:48:44 +00:00
}
void removeComputer( IComputerAccess computer )
2017-05-01 14:48:44 +00:00
{
computers.remove( computer );
2017-05-01 14:48:44 +00:00
}
2017-05-06 23:07:42 +00:00
@Nonnull
2017-05-01 14:48:44 +00:00
@Override
public AxisAlignedBB getRenderBoundingBox()
{
TileMonitor start = getNeighbour( 0, 0 ).getMonitor();
TileMonitor end = getNeighbour( width - 1, height - 1 ).getMonitor();
2017-05-01 14:48:44 +00:00
if( start != null && end != null )
{
BlockPos startPos = start.getBlockPos();
BlockPos endPos = end.getBlockPos();
2017-05-01 14:48:44 +00:00
int minX = Math.min( startPos.getX(), endPos.getX() );
int minY = Math.min( startPos.getY(), endPos.getY() );
int minZ = Math.min( startPos.getZ(), endPos.getZ() );
int maxX = Math.max( startPos.getX(), endPos.getX() ) + 1;
int maxY = Math.max( startPos.getY(), endPos.getY() ) + 1;
int maxZ = Math.max( startPos.getZ(), endPos.getZ() ) + 1;
return new AxisAlignedBB( minX, minY, minZ, maxX, maxY, maxZ );
}
else
{
BlockPos pos = getBlockPos();
return new AxisAlignedBB( pos.getX(), pos.getY(), pos.getZ(), pos.getX() + 1, pos.getY() + 1, pos.getZ() + 1 );
}
}
@Override
public double getViewDistance()
{
return ComputerCraft.monitorDistanceSq;
}
}