1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-11-16 21:27:10 +00:00

Started work on upgrading to 1.16.1. Not in a compilable state yet

This commit is contained in:
Alex Evelyn
2020-07-07 13:27:13 -04:00
parent cb66ef7e30
commit 605e1f6b9b
513 changed files with 48117 additions and 534 deletions

View File

@@ -0,0 +1,99 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.peripheral.monitor;
import dan200.computercraft.shared.common.BlockGeneric;
import dan200.computercraft.shared.common.TileGeneric;
import dan200.computercraft.shared.util.NamedBlockEntityType;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.client.render.RenderLayer;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.ItemPlacementContext;
import net.minecraft.item.ItemStack;
import net.minecraft.state.StateManager;
import net.minecraft.state.property.DirectionProperty;
import net.minecraft.state.property.EnumProperty;
import net.minecraft.state.property.Properties;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.World;
import javax.annotation.Nullable;
public class BlockMonitor extends BlockGeneric
{
public static final DirectionProperty ORIENTATION = DirectionProperty.of( "orientation",
Direction.UP, Direction.DOWN, Direction.NORTH );
public static final DirectionProperty FACING = Properties.HORIZONTAL_FACING;
static final EnumProperty<MonitorEdgeState> STATE = EnumProperty.of( "state", MonitorEdgeState.class );
public BlockMonitor( Settings settings, NamedBlockEntityType<? extends TileGeneric> type )
{
super( settings, type );
setDefaultState( getStateManager().getDefaultState()
.with( ORIENTATION, Direction.NORTH )
.with( FACING, Direction.NORTH )
.with( STATE, MonitorEdgeState.NONE ) );
}
@Override
public RenderLayer getRenderLayer()
{
return RenderLayer.CUTOUT;
}
@Override
protected void appendProperties( StateManager.Builder<Block, BlockState> builder )
{
builder.add( ORIENTATION, FACING, STATE );
}
@Override
@Nullable
public BlockState getPlacementState( ItemPlacementContext context )
{
float pitch = context.getPlayer() == null ? 0 : context.getPlayer().pitch;
Direction orientation;
if( pitch > 66.5f )
{
// If the player is looking down, place it facing upwards
orientation = Direction.UP;
}
else if( pitch < -66.5f )
{
// If they're looking up, place it down.
orientation = Direction.DOWN;
}
else
{
orientation = Direction.NORTH;
}
return getDefaultState()
.with( FACING, context.getPlayerFacing().getOpposite() )
.with( ORIENTATION, orientation );
}
@Override
public void onPlaced( World world, BlockPos pos, BlockState blockState, @Nullable LivingEntity livingEntity, ItemStack itemStack )
{
super.onPlaced( world, pos, blockState, livingEntity, itemStack );
BlockEntity entity = world.getBlockEntity( pos );
if( entity instanceof TileMonitor && !world.isClient )
{
TileMonitor monitor = (TileMonitor) entity;
monitor.contractNeighbours();
monitor.contract();
monitor.expand();
}
}
}

View File

@@ -0,0 +1,99 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.peripheral.monitor;
import com.mojang.blaze3d.platform.GlStateManager;
import dan200.computercraft.shared.common.ClientTerminal;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.util.math.BlockPos;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class ClientMonitor extends ClientTerminal
{
private static final Set<ClientMonitor> allMonitors = new HashSet<>();
private final TileMonitor origin;
public long lastRenderFrame = -1;
public BlockPos lastRenderPos = null;
public int[] renderDisplayLists = null;
public ClientMonitor( boolean colour, TileMonitor origin )
{
super( colour );
this.origin = origin;
}
public TileMonitor getOrigin()
{
return origin;
}
@Environment( EnvType.CLIENT )
public void createLists()
{
if( renderDisplayLists == null )
{
renderDisplayLists = new int[3];
for( int i = 0; i < renderDisplayLists.length; i++ )
{
renderDisplayLists[i] = GlStateManager.genLists( 1 );
}
synchronized( allMonitors )
{
allMonitors.add( this );
}
}
}
@Environment( EnvType.CLIENT )
public void destroy()
{
if( renderDisplayLists != null )
{
synchronized( allMonitors )
{
allMonitors.remove( this );
}
for( int list : renderDisplayLists )
{
GlStateManager.deleteLists( list, 1 );
}
renderDisplayLists = null;
}
}
@Environment( EnvType.CLIENT )
public static void destroyAll()
{
synchronized( allMonitors )
{
for( Iterator<ClientMonitor> iterator = allMonitors.iterator(); iterator.hasNext(); )
{
ClientMonitor monitor = iterator.next();
if( monitor.renderDisplayLists != null )
{
for( int list : monitor.renderDisplayLists )
{
GlStateManager.deleteLists( list, 1 );
}
monitor.renderDisplayLists = null;
}
iterator.remove();
}
}
}
}

View File

@@ -0,0 +1,75 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.peripheral.monitor;
import net.minecraft.util.StringIdentifiable;
import javax.annotation.Nonnull;
import static dan200.computercraft.shared.peripheral.monitor.MonitorEdgeState.Flags.*;
public enum MonitorEdgeState implements StringIdentifiable
{
NONE( "none", 0 ),
L( "l", LEFT ),
R( "r", RIGHT ),
LR( "lr", LEFT | RIGHT ),
U( "u", UP ),
D( "d", DOWN ),
UD( "ud", UP | DOWN ),
RD( "rd", RIGHT | DOWN ),
LD( "ld", LEFT | DOWN ),
RU( "ru", RIGHT | UP ),
LU( "lu", LEFT | UP ),
LRD( "lrd", LEFT | RIGHT | DOWN ),
RUD( "rud", RIGHT | UP | DOWN ),
LUD( "lud", LEFT | UP | DOWN ),
LRU( "lru", LEFT | RIGHT | UP ),
LRUD( "lrud", LEFT | RIGHT | UP | DOWN );
private final String name;
private final int flags;
MonitorEdgeState( String name, int flags )
{
this.name = name;
this.flags = flags;
}
private static final MonitorEdgeState[] BY_FLAG = new MonitorEdgeState[16];
static
{
for( MonitorEdgeState state : values() )
{
BY_FLAG[state.flags] = state;
}
}
public static MonitorEdgeState fromConnections( boolean up, boolean down, boolean left, boolean right )
{
return BY_FLAG[(up ? UP : 0) | (down ? DOWN : 0) | (left ? LEFT : 0) | (right ? RIGHT : 0)];
}
@Nonnull
@Override
public String asString()
{
return name;
}
static final class Flags
{
static final int UP = 1 << 0;
static final int DOWN = 1 << 1;
static final int LEFT = 1 << 2;
static final int RIGHT = 1 << 3;
}
}

View File

@@ -0,0 +1,235 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.peripheral.monitor;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.peripheral.IComputerAccess;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.core.apis.TermAPI;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.shared.util.Palette;
import org.apache.commons.lang3.ArrayUtils;
import javax.annotation.Nonnull;
import static dan200.computercraft.core.apis.ArgumentHelper.*;
public class MonitorPeripheral implements IPeripheral
{
private final TileMonitor m_monitor;
public MonitorPeripheral( TileMonitor monitor )
{
m_monitor = monitor;
}
@Nonnull
@Override
public String getType()
{
return "monitor";
}
@Nonnull
@Override
public String[] getMethodNames()
{
return new String[] {
"write",
"scroll",
"setCursorPos",
"setCursorBlink",
"getCursorPos",
"getSize",
"clear",
"clearLine",
"setTextScale",
"setTextColour",
"setTextColor",
"setBackgroundColour",
"setBackgroundColor",
"isColour",
"isColor",
"getTextColour",
"getTextColor",
"getBackgroundColour",
"getBackgroundColor",
"blit",
"setPaletteColour",
"setPaletteColor",
"getPaletteColour",
"getPaletteColor",
"getTextScale",
"getCursorBlink",
};
}
@Override
public Object[] callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException
{
ServerMonitor monitor = m_monitor.getCachedServerMonitor();
if( monitor == null ) throw new LuaException( "Monitor has been detached" );
Terminal terminal = monitor.getTerminal();
if( terminal == null ) throw new LuaException( "Monitor has been detached" );
switch( method )
{
case 0:
{
// write
String text = args.length > 0 && args[0] != null ? args[0].toString() : "";
terminal.write( text );
terminal.setCursorPos( terminal.getCursorX() + text.length(), terminal.getCursorY() );
return null;
}
case 1:
{
// scroll
int value = getInt( args, 0 );
terminal.scroll( value );
return null;
}
case 2:
{
// setCursorPos
int x = getInt( args, 0 ) - 1;
int y = getInt( args, 1 ) - 1;
terminal.setCursorPos( x, y );
return null;
}
case 3:
{
// setCursorBlink
boolean blink = getBoolean( args, 0 );
terminal.setCursorBlink( blink );
return null;
}
case 4: // getCursorPos
return new Object[] { terminal.getCursorX() + 1, terminal.getCursorY() + 1 };
case 5: // getSize
return new Object[] { terminal.getWidth(), terminal.getHeight() };
case 6: // clear
terminal.clear();
return null;
case 7: // clearLine
terminal.clearLine();
return null;
case 8:
{
// setTextScale
int scale = (int) (getReal( args, 0 ) * 2.0);
if( scale < 1 || scale > 10 )
{
throw new LuaException( "Expected number in range 0.5-5" );
}
monitor.setTextScale( scale );
return null;
}
case 9:
case 10:
{
// setTextColour/setTextColor
int colour = TermAPI.parseColour( args );
terminal.setTextColour( colour );
return null;
}
case 11:
case 12:
{
// setBackgroundColour/setBackgroundColor
int colour = TermAPI.parseColour( args );
terminal.setBackgroundColour( colour );
return null;
}
case 13:
case 14: // isColour/isColor
return new Object[] { monitor.isColour() };
case 15:
case 16: // getTextColour/getTextColor
return TermAPI.encodeColour( terminal.getTextColour() );
case 17:
case 18: // getBackgroundColour/getBackgroundColor
return TermAPI.encodeColour( terminal.getBackgroundColour() );
case 19:
{
// blit
String text = getString( args, 0 );
String textColour = getString( args, 1 );
String backgroundColour = getString( args, 2 );
if( textColour.length() != text.length() || backgroundColour.length() != text.length() )
{
throw new LuaException( "Arguments must be the same length" );
}
terminal.blit( text, textColour, backgroundColour );
terminal.setCursorPos( terminal.getCursorX() + text.length(), terminal.getCursorY() );
return null;
}
case 20:
case 21:
{
// setPaletteColour/setPaletteColor
int colour = 15 - TermAPI.parseColour( args );
if( args.length == 2 )
{
int hex = getInt( args, 1 );
double[] rgb = Palette.decodeRGB8( hex );
TermAPI.setColour( terminal, colour, rgb[0], rgb[1], rgb[2] );
}
else
{
double r = getReal( args, 1 );
double g = getReal( args, 2 );
double b = getReal( args, 3 );
TermAPI.setColour( terminal, colour, r, g, b );
}
return null;
}
case 22:
case 23:
{
// getPaletteColour/getPaletteColor
Palette palette = terminal.getPalette();
int colour = 15 - TermAPI.parseColour( args );
if( palette != null )
{
return ArrayUtils.toObject( palette.getColour( colour ) );
}
return null;
}
case 24: // getTextScale
return new Object[] { monitor.getTextScale() / 2.0 };
case 25:
// getCursorBlink
return new Object[] { terminal.getCursorBlink() };
default:
return null;
}
}
@Override
public void attach( @Nonnull IComputerAccess computer )
{
m_monitor.addComputer( computer );
}
@Override
public void detach( @Nonnull IComputerAccess computer )
{
m_monitor.removeComputer( computer );
}
@Override
public boolean equals( IPeripheral other )
{
return other instanceof MonitorPeripheral && m_monitor == ((MonitorPeripheral) other).m_monitor;
}
}

View File

@@ -0,0 +1,92 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.peripheral.monitor;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.shared.common.ServerTerminal;
import dan200.computercraft.shared.util.TickScheduler;
import java.util.concurrent.atomic.AtomicBoolean;
public class ServerMonitor extends ServerTerminal
{
private final TileMonitor origin;
private int textScale = 2;
private final AtomicBoolean resized = new AtomicBoolean( false );
private final AtomicBoolean changed = new AtomicBoolean( false );
public ServerMonitor( boolean colour, TileMonitor origin )
{
super( colour );
this.origin = origin;
}
public synchronized void rebuild()
{
Terminal oldTerm = getTerminal();
int oldWidth = oldTerm == null ? -1 : oldTerm.getWidth();
int oldHeight = oldTerm == null ? -1 : oldTerm.getHeight();
double textScale = this.textScale * 0.5;
int termWidth = (int) Math.max(
Math.round( (origin.getWidth() - 2.0 * (TileMonitor.RENDER_BORDER + TileMonitor.RENDER_MARGIN)) / (textScale * 6.0 * TileMonitor.RENDER_PIXEL_SCALE) ),
1.0
);
int termHeight = (int) Math.max(
Math.round( (origin.getHeight() - 2.0 * (TileMonitor.RENDER_BORDER + TileMonitor.RENDER_MARGIN)) / (textScale * 9.0 * TileMonitor.RENDER_PIXEL_SCALE) ),
1.0
);
resize( termWidth, termHeight );
if( oldWidth != termWidth || oldHeight != termHeight )
{
getTerminal().clear();
resized.set( true );
markChanged();
}
}
@Override
protected void markTerminalChanged()
{
super.markTerminalChanged();
markChanged();
}
private void markChanged()
{
if( !changed.getAndSet( true ) ) TickScheduler.schedule( origin );
}
protected void clearChanged()
{
changed.set( false );
}
public int getTextScale()
{
return textScale;
}
public synchronized void setTextScale( int textScale )
{
if( this.textScale == textScale ) return;
this.textScale = textScale;
rebuild();
}
public boolean pollResized()
{
return resized.getAndSet( false );
}
public boolean pollTerminalChanged()
{
update();
return hasTerminalChanged();
}
}

View File

@@ -0,0 +1,683 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. 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.api.peripheral.IPeripheralTile;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.shared.common.ServerTerminal;
import dan200.computercraft.shared.common.TileGeneric;
import dan200.computercraft.shared.util.NamedBlockEntityType;
import dan200.computercraft.shared.util.TickScheduler;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.util.Hand;
import net.minecraft.util.Identifier;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
import java.util.HashSet;
import java.util.Set;
public class TileMonitor extends TileGeneric implements IPeripheralTile
{
public static final NamedBlockEntityType<TileMonitor> FACTORY_NORMAL = NamedBlockEntityType.create(
new Identifier( ComputerCraft.MOD_ID, "monitor_normal" ),
f -> new TileMonitor( f, false )
);
public static final NamedBlockEntityType<TileMonitor> FACTORY_ADVANCED = NamedBlockEntityType.create(
new Identifier( ComputerCraft.MOD_ID, "monitor_advanced" ),
f -> new TileMonitor( f, true )
);
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 int MAX_WIDTH = 8;
private static final int MAX_HEIGHT = 6;
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 m_serverMonitor;
private ClientMonitor m_clientMonitor;
private MonitorPeripheral m_peripheral;
private final Set<IComputerAccess> m_computers = new HashSet<>();
private boolean m_destroyed = false;
private boolean visiting = false;
private int m_width = 1;
private int m_height = 1;
private int m_xIndex = 0;
private int m_yIndex = 0;
public TileMonitor( BlockEntityType<? extends TileMonitor> type, boolean advanced )
{
super( type );
this.advanced = advanced;
}
@Override
public void cancelRemoval()
{
super.cancelRemoval();
TickScheduler.schedule( this );
}
@Override
public void destroy()
{
// TODO: Call this before using the block
if( m_destroyed ) return;
m_destroyed = true;
if( !getWorld().isClient ) contractNeighbours();
}
@Override
public void markRemoved()
{
super.markRemoved();
if( m_clientMonitor != null && m_xIndex == 0 && m_yIndex == 0 ) m_clientMonitor.destroy();
}
/*
@Override
public void onChunkUnloaded()
{
super.onChunkUnloaded();
if( m_clientMonitor != null && m_xIndex == 0 && m_yIndex == 0 ) m_clientMonitor.destroy();
}
*/
@Override
public boolean onActivate( PlayerEntity player, Hand hand, BlockHitResult hit )
{
if( !player.isSneaking() && getFront() == hit.getSide() )
{
if( !getWorld().isClient )
{
monitorTouched(
(float) (hit.getPos().x - hit.getBlockPos().getX()),
(float) (hit.getPos().y - hit.getBlockPos().getY()),
(float) (hit.getPos().z - hit.getBlockPos().getZ())
);
}
return true;
}
return false;
}
@Nonnull
@Override
public CompoundTag toTag( CompoundTag tag )
{
tag.putInt( NBT_X, m_xIndex );
tag.putInt( NBT_Y, m_yIndex );
tag.putInt( NBT_WIDTH, m_width );
tag.putInt( NBT_HEIGHT, m_height );
return super.toTag( tag );
}
@Override
public void fromTag( CompoundTag tag )
{
super.fromTag( tag );
m_xIndex = tag.getInt( NBT_X );
m_yIndex = tag.getInt( NBT_Y );
m_width = tag.getInt( NBT_WIDTH );
m_height = tag.getInt( NBT_HEIGHT );
}
@Override
public void blockTick()
{
if( m_xIndex != 0 || m_yIndex != 0 || m_serverMonitor == null ) return;
m_serverMonitor.clearChanged();
if( m_serverMonitor.pollResized() )
{
for( int x = 0; x < m_width; x++ )
{
for( int y = 0; y < m_height; y++ )
{
TileMonitor monitor = getNeighbour( x, y );
if( monitor == null ) continue;
for( IComputerAccess computer : monitor.m_computers )
{
computer.queueEvent( "monitor_resize", new Object[] {
computer.getAttachmentName()
} );
}
}
}
}
if( m_serverMonitor.pollTerminalChanged() ) updateBlock();
}
// IPeripheralTile implementation
@Override
public IPeripheral getPeripheral( @Nonnull Direction side )
{
createServerMonitor(); // Ensure the monitor is created before doing anything else.
if( m_peripheral == null ) m_peripheral = new MonitorPeripheral( this );
return m_peripheral;
}
public ServerMonitor getCachedServerMonitor()
{
return m_serverMonitor;
}
private ServerMonitor getServerMonitor()
{
if( m_serverMonitor != null ) return m_serverMonitor;
TileMonitor origin = getOrigin();
if( origin == null ) return null;
return m_serverMonitor = origin.m_serverMonitor;
}
private ServerMonitor createServerMonitor()
{
if( m_serverMonitor != null ) return m_serverMonitor;
if( m_xIndex == 0 && m_yIndex == 0 )
{
// If we're the origin, set up the new monitor
m_serverMonitor = new ServerMonitor( advanced, this );
m_serverMonitor.rebuild();
// And propagate it to child monitors
for( int x = 0; x < m_width; x++ )
{
for( int y = 0; y < m_height; y++ )
{
TileMonitor monitor = getNeighbour( x, y );
if( monitor != null ) monitor.m_serverMonitor = m_serverMonitor;
}
}
return m_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 = getPos();
BlockEntity te = world.getBlockEntity( pos.offset( getRight(), -m_xIndex ).offset( getDown(), -m_yIndex ) );
if( !(te instanceof TileMonitor) ) return null;
return m_serverMonitor = ((TileMonitor) te).createServerMonitor();
}
}
public ClientMonitor getClientMonitor()
{
if( m_clientMonitor != null ) return m_clientMonitor;
BlockPos pos = getPos();
BlockEntity te = world.getBlockEntity( pos.offset( getRight(), -m_xIndex ).offset( getDown(), -m_yIndex ) );
if( !(te instanceof TileMonitor) ) return null;
return m_clientMonitor = ((TileMonitor) te).m_clientMonitor;
}
// Networking stuff
@Override
protected void writeDescription( @Nonnull CompoundTag nbt )
{
super.writeDescription( nbt );
nbt.putInt( NBT_X, m_xIndex );
nbt.putInt( NBT_Y, m_yIndex );
nbt.putInt( NBT_WIDTH, m_width );
nbt.putInt( NBT_HEIGHT, m_height );
if( m_xIndex == 0 && m_yIndex == 0 && m_serverMonitor != null )
{
m_serverMonitor.writeDescription( nbt );
}
}
@Override
protected final void readDescription( @Nonnull CompoundTag nbt )
{
super.readDescription( nbt );
int oldXIndex = m_xIndex;
int oldYIndex = m_yIndex;
int oldWidth = m_width;
int oldHeight = m_height;
m_xIndex = nbt.getInt( NBT_X );
m_yIndex = nbt.getInt( NBT_Y );
m_width = nbt.getInt( NBT_WIDTH );
m_height = nbt.getInt( NBT_HEIGHT );
if( oldXIndex != m_xIndex || oldYIndex != m_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 && m_clientMonitor != null ) m_clientMonitor.destroy();
m_clientMonitor = null;
}
if( m_xIndex == 0 && m_yIndex == 0 )
{
// If we're the origin terminal then read the description
if( m_clientMonitor == null ) m_clientMonitor = new ClientMonitor( advanced, this );
m_clientMonitor.readDescription( nbt );
}
if( oldXIndex != m_xIndex || oldYIndex != m_yIndex ||
oldWidth != m_width || oldHeight != m_height )
{
// One of our properties has changed, so ensure we redraw the block
updateBlock();
}
}
private void updateBlockState()
{
getWorld().setBlockState( getPos(), getCachedState()
.with( BlockMonitor.STATE, MonitorEdgeState.fromConnections(
m_yIndex < m_height - 1, m_yIndex > 0,
m_xIndex > 0, m_xIndex < m_width - 1 ) ), 2 );
}
// region Sizing and placement stuff
public Direction getDirection()
{
return getCachedState().get( BlockMonitor.FACING );
}
public Direction getOrientation()
{
return getCachedState().get( BlockMonitor.ORIENTATION );
}
public Direction getFront()
{
Direction orientation = getOrientation();
return orientation == Direction.NORTH ? getDirection() : orientation;
}
public Direction getRight()
{
return getDirection().rotateYCounterclockwise();
}
public Direction getDown()
{
Direction orientation = getOrientation();
if( orientation == Direction.NORTH ) return Direction.UP;
return orientation == Direction.DOWN ? getDirection() : getDirection().getOpposite();
}
public int getWidth()
{
return m_width;
}
public int getHeight()
{
return m_height;
}
public int getXIndex()
{
return m_xIndex;
}
public int getYIndex()
{
return m_yIndex;
}
private TileMonitor getSimilarMonitorAt( BlockPos pos )
{
if( pos.equals( getPos() ) ) return this;
int y = pos.getY();
World world = getWorld();
if( world == null || !world.isBlockLoaded( pos ) ) return null;
BlockEntity tile = world.getBlockEntity( pos );
if( !(tile instanceof TileMonitor) ) return null;
TileMonitor monitor = (TileMonitor) tile;
return !monitor.visiting && !monitor.m_destroyed && advanced == monitor.advanced
&& getDirection() == monitor.getDirection() && getOrientation() == monitor.getOrientation()
? monitor : null;
}
private TileMonitor getNeighbour( int x, int y )
{
BlockPos pos = getPos();
Direction right = getRight();
Direction down = getDown();
int xOffset = -m_xIndex + x;
int yOffset = -m_yIndex + y;
return getSimilarMonitorAt( pos.offset( right, xOffset ).offset( down, yOffset ) );
}
private TileMonitor getOrigin()
{
return getNeighbour( 0, 0 );
}
private void resize( int width, int height )
{
// If we're not already the origin then we'll need to generate a new terminal.
if( m_xIndex != 0 || m_yIndex != 0 ) m_serverMonitor = null;
m_xIndex = 0;
m_yIndex = 0;
m_width = width;
m_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++ )
{
for( int y = 0; y < height; y++ )
{
TileMonitor monitor = getNeighbour( x, y );
if( monitor != null && monitor.m_peripheral != null )
{
needsTerminal = true;
break terminalCheck;
}
}
}
// Either delete the current monitor or sync a new one.
if( needsTerminal )
{
if( m_serverMonitor == null ) m_serverMonitor = new ServerMonitor( advanced, this );
}
else
{
m_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( m_serverMonitor != null ) m_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 );
if( monitor == null ) continue;
monitor.m_xIndex = x;
monitor.m_yIndex = y;
monitor.m_width = width;
monitor.m_height = height;
monitor.m_serverMonitor = m_serverMonitor;
monitor.updateBlockState();
monitor.updateBlock();
}
}
}
private boolean mergeLeft()
{
TileMonitor left = getNeighbour( -1, 0 );
if( left == null || left.m_yIndex != 0 || left.m_height != m_height ) return false;
int width = left.m_width + m_width;
if( width > MAX_WIDTH ) return false;
TileMonitor origin = left.getOrigin();
if( origin != null ) origin.resize( width, m_height );
left.expand();
return true;
}
private boolean mergeRight()
{
TileMonitor right = getNeighbour( m_width, 0 );
if( right == null || right.m_yIndex != 0 || right.m_height != m_height ) return false;
int width = m_width + right.m_width;
if( width > MAX_WIDTH ) return false;
TileMonitor origin = getOrigin();
if( origin != null ) origin.resize( width, m_height );
expand();
return true;
}
private boolean mergeUp()
{
TileMonitor above = getNeighbour( 0, m_height );
if( above == null || above.m_xIndex != 0 || above.m_width != m_width ) return false;
int height = above.m_height + m_height;
if( height > MAX_HEIGHT ) return false;
TileMonitor origin = getOrigin();
if( origin != null ) origin.resize( m_width, height );
expand();
return true;
}
private boolean mergeDown()
{
TileMonitor below = getNeighbour( 0, -1 );
if( below == null || below.m_xIndex != 0 || below.m_width != m_width ) return false;
int height = m_height + below.m_height;
if( height > MAX_HEIGHT ) return false;
TileMonitor origin = below.getOrigin();
if( origin != null ) origin.resize( m_width, height );
below.expand();
return true;
}
@SuppressWarnings( "StatementWithEmptyBody" )
void expand()
{
while( mergeLeft() || mergeRight() || mergeUp() || mergeDown() ) ;
}
void contractNeighbours()
{
visiting = true;
if( m_xIndex > 0 )
{
TileMonitor left = getNeighbour( m_xIndex - 1, m_yIndex );
if( left != null ) left.contract();
}
if( m_xIndex + 1 < m_width )
{
TileMonitor right = getNeighbour( m_xIndex + 1, m_yIndex );
if( right != null ) right.contract();
}
if( m_yIndex > 0 )
{
TileMonitor below = getNeighbour( m_xIndex, m_yIndex - 1 );
if( below != null ) below.contract();
}
if( m_yIndex + 1 < m_height )
{
TileMonitor above = getNeighbour( m_xIndex, m_yIndex + 1 );
if( above != null ) above.contract();
}
visiting = false;
}
void contract()
{
int height = m_height;
int width = m_width;
TileMonitor origin = getOrigin();
if( origin == null )
{
TileMonitor right = width > 1 ? getNeighbour( 1, 0 ) : null;
TileMonitor below = height > 1 ? getNeighbour( 0, 1 ) : 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();
return;
}
for( int y = 0; y < height; y++ )
{
for( int x = 0; x < width; x++ )
{
TileMonitor monitor = origin.getNeighbour( x, y );
if( monitor != null ) continue;
// Decompose
TileMonitor above = null;
TileMonitor left = null;
TileMonitor right = null;
TileMonitor below = null;
if( y > 0 )
{
above = origin;
above.resize( width, y );
}
if( x > 0 )
{
left = origin.getNeighbour( 0, y );
left.resize( x, 1 );
}
if( x + 1 < width )
{
right = origin.getNeighbour( x + 1, y );
right.resize( width - (x + 1), 1 );
}
if( y + 1 < height )
{
below = origin.getNeighbour( 0, y + 1 );
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;
}
}
}
private void monitorTouched( float xPos, float yPos, float zPos )
{
XYPair pair = XYPair
.of( xPos, yPos, zPos, getDirection(), getOrientation() )
.add( m_xIndex, m_height - m_yIndex - 1 );
if( pair.x > m_width - RENDER_BORDER || pair.y > m_height - RENDER_BORDER || pair.x < RENDER_BORDER || pair.y < RENDER_BORDER )
{
return;
}
ServerTerminal serverTerminal = getServerMonitor();
if( serverTerminal == null || !serverTerminal.isColour() ) return;
Terminal originTerminal = serverTerminal.getTerminal();
if( originTerminal == null ) return;
double xCharWidth = (m_width - (RENDER_BORDER + RENDER_MARGIN) * 2.0) / originTerminal.getWidth();
double yCharHeight = (m_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 < m_height; y++ )
{
for( int x = 0; x < m_width; x++ )
{
TileMonitor monitor = getNeighbour( x, y );
if( monitor == null ) continue;
for( IComputerAccess computer : monitor.m_computers )
{
computer.queueEvent( "monitor_touch", new Object[] {
computer.getAttachmentName(), xCharPos, yCharPos
} );
}
}
}
}
// endregion
void addComputer( IComputerAccess computer )
{
m_computers.add( computer );
}
void removeComputer( IComputerAccess computer )
{
m_computers.remove( computer );
}
/*
@Nonnull
@Override
public AxisAlignedBB getRenderBoundingBox()
{
TileMonitor start = getNeighbour( 0, 0 );
TileMonitor end = getNeighbour( width - 1, height - 1 );
if( start != null && end != null )
{
BlockPos startPos = start.getPos();
BlockPos endPos = end.getPos();
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 = getPos();
return new AxisAlignedBB( pos.getX(), pos.getY(), pos.getZ(), pos.getX() + 1, pos.getY() + 1, pos.getZ() + 1 );
}
}
*/
}

View File

@@ -0,0 +1,74 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.peripheral.monitor;
import net.minecraft.util.math.Direction;
public class XYPair
{
public final float x;
public final float y;
public XYPair( float x, float y )
{
this.x = x;
this.y = y;
}
public XYPair add( float x, float y )
{
return new XYPair( this.x + x, this.y + y );
}
public static XYPair of( float xPos, float yPos, float zPos, Direction facing, Direction orientation )
{
switch( orientation )
{
case NORTH:
switch( facing )
{
case NORTH:
return new XYPair( 1 - xPos, 1 - yPos );
case SOUTH:
return new XYPair( xPos, 1 - yPos );
case WEST:
return new XYPair( zPos, 1 - yPos );
case EAST:
return new XYPair( 1 - zPos, 1 - yPos );
}
break;
case DOWN:
switch( facing )
{
case NORTH:
return new XYPair( 1 - xPos, zPos );
case SOUTH:
return new XYPair( xPos, 1 - zPos );
case WEST:
return new XYPair( zPos, xPos );
case EAST:
return new XYPair( 1 - zPos, 1 - xPos );
}
break;
case UP:
switch( facing )
{
case NORTH:
return new XYPair( 1 - xPos, 1 - zPos );
case SOUTH:
return new XYPair( xPos, zPos );
case WEST:
return new XYPair( zPos, 1 - xPos );
case EAST:
return new XYPair( 1 - zPos, xPos );
}
break;
}
return new XYPair( xPos, zPos );
}
}