1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2024-12-12 19:20:29 +00:00

Overhaul monitor's terminal code

This restructures monitor in order to make it thread-safe: namely
removing any world interaction from the computer thread.

Instead of each monitor having their own terminal, resize flag, etc...
we use a monitor "multiblock" object. This is constructed on the origin
monitor and propagated to other monitors when required.

We attempt to construct the multiblock object (and so the corresponding
terminal) as lazily as posible. Consequently, we only create the
terminal when fetching the peripheral (not when attaching, as that is
done on the computer thread).

If a monitor is resized (say due to placing/breaking a monitor) then we
will invalidate all references to the multiblock object, construct a new
one if required, and propagate it to all component monitors.

This commit also fixes several instances of glLists not being deleted
after use. It is not a comprehensive fix, but that is outside the scope
of this commit.
This commit is contained in:
SquidDev 2018-02-14 21:21:00 +00:00
parent 4c14431a3d
commit 662fb96beb
5 changed files with 328 additions and 264 deletions

View File

@ -10,7 +10,7 @@ import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.gui.FixedWidthFontRenderer;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.shared.common.ClientTerminal;
import dan200.computercraft.shared.peripheral.monitor.ClientMonitor;
import dan200.computercraft.shared.peripheral.monitor.TileMonitor;
import dan200.computercraft.shared.util.Colour;
import dan200.computercraft.shared.util.DirectionUtil;
@ -43,24 +43,22 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
private void renderMonitorAt( TileMonitor monitor, double posX, double posY, double posZ, float f, int i )
{
// Render from the origin monitor
TileMonitor origin = monitor.getOrigin();
if( origin == null )
{
return;
}
ClientMonitor originTerminal = monitor.getClientMonitor();
if( originTerminal == null ) return;
TileMonitor origin = originTerminal.getOrigin();
// Ensure each monitor is rendered only once
long renderFrame = ComputerCraft.getRenderFrame();
if( origin.m_lastRenderFrame == renderFrame )
if( originTerminal.lastRenderFrame == renderFrame )
{
return;
}
else
{
origin.m_lastRenderFrame = renderFrame;
originTerminal.lastRenderFrame = renderFrame;
}
boolean redraw = origin.pollChanged();
BlockPos monitorPos = monitor.getPos();
BlockPos originPos = origin.getPos();
posX += originPos.getX() - monitorPos.getX();
@ -94,9 +92,7 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
BufferBuilder renderer = tessellator.getBuffer();
// Get terminal
ClientTerminal clientTerminal = (ClientTerminal)origin.getTerminal();
Terminal terminal = (clientTerminal != null) ? clientTerminal.getTerminal() : null;
redraw = redraw || (clientTerminal != null && clientTerminal.hasTerminalChanged());
boolean redraw = originTerminal.hasTerminalChanged();
// Draw the contents
GlStateManager.depthMask( false );
@ -104,19 +100,20 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
mc.entityRenderer.disableLightmap();
try
{
Terminal terminal = originTerminal.getTerminal();
if( terminal != null )
{
Palette palette = terminal.getPalette();
// Allocate display lists
if( origin.m_renderDisplayList < 0 )
if( originTerminal.renderDisplayList < 0 )
{
origin.m_renderDisplayList = GlStateManager.glGenLists( 3 );
originTerminal.renderDisplayList = GlStateManager.glGenLists( 3 );
redraw = true;
}
// Draw a terminal
boolean greyscale = !clientTerminal.isColour();
boolean greyscale = !originTerminal.isColour();
int width = terminal.getWidth();
int height = terminal.getHeight();
int cursorX = terminal.getCursorX();
@ -135,7 +132,7 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
if( redraw )
{
// Build background display list
GlStateManager.glNewList( origin.m_renderDisplayList, GL11.GL_COMPILE );
GlStateManager.glNewList( originTerminal.renderDisplayList, GL11.GL_COMPILE );
try
{
double marginXSize = TileMonitor.RENDER_MARGIN / xScale;
@ -174,7 +171,7 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
GlStateManager.glEndList();
}
}
GlStateManager.callList( origin.m_renderDisplayList );
GlStateManager.callList( originTerminal.renderDisplayList );
GlStateManager.resetColor();
// Draw text
@ -182,7 +179,7 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
if( redraw )
{
// Build text display list
GlStateManager.glNewList( origin.m_renderDisplayList + 1, GL11.GL_COMPILE );
GlStateManager.glNewList( originTerminal.renderDisplayList + 1, GL11.GL_COMPILE );
try
{
// Lines
@ -202,7 +199,7 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
GlStateManager.glEndList();
}
}
GlStateManager.callList( origin.m_renderDisplayList + 1 );
GlStateManager.callList( originTerminal.renderDisplayList + 1 );
GlStateManager.resetColor();
// Draw cursor
@ -210,7 +207,7 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
if( redraw )
{
// Build cursor display list
GlStateManager.glNewList( origin.m_renderDisplayList + 2, GL11.GL_COMPILE );
GlStateManager.glNewList( originTerminal.renderDisplayList + 2, GL11.GL_COMPILE );
try
{
// Cursor
@ -236,7 +233,7 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
}
if( ComputerCraft.getGlobalCursorBlink() )
{
GlStateManager.callList( origin.m_renderDisplayList + 2 );
GlStateManager.callList( originTerminal.renderDisplayList + 2 );
GlStateManager.resetColor();
}
}

View File

@ -0,0 +1,34 @@
package dan200.computercraft.shared.peripheral.monitor;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.common.ClientTerminal;
import gnu.trove.set.hash.TIntHashSet;
public class ClientMonitor extends ClientTerminal
{
private static final TIntHashSet displayLists = new TIntHashSet();
private final TileMonitor origin;
public long lastRenderFrame = -1;
public int renderDisplayList = -1;
public ClientMonitor( boolean colour, TileMonitor origin )
{
super( colour );
this.origin = origin;
}
public TileMonitor getOrigin()
{
return origin;
}
public void destroy()
{
if( renderDisplayList != -1 )
{
ComputerCraft.deleteDisplayLists( renderDisplayList, 3 );
}
}
}

View File

@ -73,6 +73,12 @@ public class MonitorPeripheral implements IPeripheral
@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 detatched" );
Terminal terminal = monitor.getTerminal();
if( terminal == null ) throw new LuaException( "Monitor has been detatched" );
switch( method )
{
case 0:
@ -84,7 +90,6 @@ public class MonitorPeripheral implements IPeripheral
} else {
text = "";
}
Terminal terminal = m_monitor.getTerminal().getTerminal();
terminal.write( text );
terminal.setCursorPos( terminal.getCursorX() + text.length(), terminal.getCursorY() );
return null;
@ -93,7 +98,6 @@ public class MonitorPeripheral implements IPeripheral
{
// scroll
int value = getInt( args, 0 );
Terminal terminal = m_monitor.getTerminal().getTerminal();
terminal.scroll( value );
return null;
}
@ -102,7 +106,6 @@ public class MonitorPeripheral implements IPeripheral
// setCursorPos
int x = getInt( args, 0 ) - 1;
int y = getInt( args, 1 ) - 1;
Terminal terminal = m_monitor.getTerminal().getTerminal();
terminal.setCursorPos( x, y );
return null;
}
@ -110,14 +113,12 @@ public class MonitorPeripheral implements IPeripheral
{
// setCursorBlink
boolean blink = getBoolean( args, 0 );
Terminal terminal = m_monitor.getTerminal().getTerminal();
terminal.setCursorBlink( blink );
return null;
}
case 4:
{
// getCursorPos
Terminal terminal = m_monitor.getTerminal().getTerminal();
return new Object[] {
terminal.getCursorX() + 1,
terminal.getCursorY() + 1
@ -126,7 +127,6 @@ public class MonitorPeripheral implements IPeripheral
case 5:
{
// getSize
Terminal terminal = m_monitor.getTerminal().getTerminal();
return new Object[] {
terminal.getWidth(),
terminal.getHeight()
@ -135,14 +135,12 @@ public class MonitorPeripheral implements IPeripheral
case 6:
{
// clear
Terminal terminal = m_monitor.getTerminal().getTerminal();
terminal.clear();
return null;
}
case 7:
{
// clearLine
Terminal terminal = m_monitor.getTerminal().getTerminal();
terminal.clearLine();
return null;
}
@ -154,7 +152,7 @@ public class MonitorPeripheral implements IPeripheral
{
throw new LuaException( "Expected number in range 0.5-5" );
}
m_monitor.setTextScale( scale );
monitor.setTextScale( scale );
return null;
}
case 9:
@ -162,7 +160,6 @@ public class MonitorPeripheral implements IPeripheral
{
// setTextColour/setTextColor
int colour = TermAPI.parseColour( args );
Terminal terminal = m_monitor.getTerminal().getTerminal();
terminal.setTextColour( colour );
return null;
}
@ -171,7 +168,6 @@ public class MonitorPeripheral implements IPeripheral
{
// setBackgroundColour/setBackgroundColor
int colour = TermAPI.parseColour( args );
Terminal terminal = m_monitor.getTerminal().getTerminal();
terminal.setBackgroundColour( colour );
return null;
}
@ -180,21 +176,19 @@ public class MonitorPeripheral implements IPeripheral
{
// isColour/isColor
return new Object[] {
m_monitor.getTerminal().isColour()
monitor.isColour()
};
}
case 15:
case 16:
{
// getTextColour/getTextColor
Terminal terminal = m_monitor.getTerminal().getTerminal();
return TermAPI.encodeColour( terminal.getTextColour() );
}
case 17:
case 18:
{
// getBackgroundColour/getBackgroundColor
Terminal terminal = m_monitor.getTerminal().getTerminal();
return TermAPI.encodeColour( terminal.getBackgroundColour() );
}
case 19:
@ -208,7 +202,6 @@ public class MonitorPeripheral implements IPeripheral
throw new LuaException( "Arguments must be the same length" );
}
Terminal terminal = m_monitor.getTerminal().getTerminal();
terminal.blit( text, textColour, backgroundColour );
terminal.setCursorPos( terminal.getCursorX() + text.length(), terminal.getCursorY() );
return null;
@ -217,8 +210,6 @@ public class MonitorPeripheral implements IPeripheral
case 21:
{
// setPaletteColour/setPaletteColor
Terminal terminal = m_monitor.getTerminal().getTerminal();
int colour = 15 - TermAPI.parseColour( args );
if( args.length == 2 )
{
@ -239,7 +230,6 @@ public class MonitorPeripheral implements IPeripheral
case 23:
{
// getPaletteColour/getPaletteColor
Terminal terminal = m_monitor.getTerminal().getTerminal();
Palette palette = terminal.getPalette();
int colour = 15 - TermAPI.parseColour( args );
@ -253,7 +243,7 @@ public class MonitorPeripheral implements IPeripheral
case 24:
{
// getTextScale
return new Object[] { m_monitor.getTextScale() };
return new Object[] { monitor.getTextScale() };
}
}
return null;

View File

@ -0,0 +1,64 @@
package dan200.computercraft.shared.peripheral.monitor;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.shared.common.ServerTerminal;
public class ServerMonitor extends ServerTerminal
{
private final TileMonitor origin;
private int textScale = 2;
private boolean resized;
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 = true;
}
}
public int getTextScale()
{
return textScale;
}
public synchronized void setTextScale( int textScale )
{
if( this.textScale == textScale ) return;
this.textScale = textScale;
rebuild();
}
public synchronized boolean pollResized()
{
if( resized )
{
resized = false;
return true;
}
return false;
}
}

View File

@ -10,19 +10,17 @@ 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.ClientTerminal;
import dan200.computercraft.shared.common.ITerminal;
import dan200.computercraft.shared.common.ITerminalTile;
import dan200.computercraft.shared.common.ServerTerminal;
import dan200.computercraft.shared.peripheral.PeripheralType;
import dan200.computercraft.shared.peripheral.common.BlockPeripheral;
import dan200.computercraft.shared.peripheral.common.TilePeripheralBase;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.EnumFacing;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
@ -30,7 +28,6 @@ import java.util.HashSet;
import java.util.Set;
public class TileMonitor extends TilePeripheralBase
implements ITerminalTile
{
// Statics
@ -42,26 +39,22 @@ public class TileMonitor extends TilePeripheralBase
private static final int MAX_HEIGHT = 6;
// Members
private ServerTerminal m_serverTerminal;
private ClientTerminal m_clientTerminal;
private ServerMonitor m_serverMonitor;
private ClientMonitor m_clientMonitor;
private boolean hasPeripheral;
private final Set<IComputerAccess> m_computers;
public long m_lastRenderFrame = -1; // For rendering use only
public int m_renderDisplayList = -1; // For rendering use only
private boolean m_destroyed;
private boolean m_ignoreMe;
private boolean m_changed;
private int m_textScale;
private int m_width;
private int m_height;
private int m_xIndex;
private int m_yIndex;
private int m_dir;
private boolean m_sizeChangedQueued;
private boolean m_advanced;
public TileMonitor()
{
@ -69,17 +62,23 @@ public class TileMonitor extends TilePeripheralBase
m_destroyed = false;
m_ignoreMe = false;
m_textScale = 2;
m_width = 1;
m_height = 1;
m_xIndex = 0;
m_yIndex = 0;
m_changed = false;
m_dir = 2;
}
@Override
public void onLoad()
{
super.onLoad();
m_advanced = getBlockState().getValue( BlockPeripheral.Properties.VARIANT )
.getPeripheralType() == PeripheralType.AdvancedMonitor;
}
@Override
public void destroy()
{
@ -91,11 +90,20 @@ public class TileMonitor extends TilePeripheralBase
contractNeighbours();
}
}
if( m_renderDisplayList >= 0 )
{
ComputerCraft.deleteDisplayLists( m_renderDisplayList, 3 );
m_renderDisplayList = -1;
}
@Override
public void invalidate()
{
super.invalidate();
if( m_clientMonitor != null && m_xIndex == 0 && m_yIndex == 0 ) m_clientMonitor.destroy();
}
@Override
public void onChunkUnload()
{
super.onChunkUnload();
if( m_clientMonitor != null && m_xIndex == 0 && m_yIndex == 0 ) m_clientMonitor.destroy();
}
@Override
@ -143,41 +151,38 @@ public class TileMonitor extends TilePeripheralBase
if( !getWorld().isRemote )
{
if( m_sizeChangedQueued )
if( m_xIndex == 0 && m_yIndex == 0 && m_serverMonitor != null )
{
for( IComputerAccess computer : m_computers )
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()
} );
}
m_sizeChangedQueued = false;
}
if( m_serverTerminal != null )
{
m_serverTerminal.update();
if( m_serverTerminal.hasTerminalChanged() )
{
updateBlock();
}
}
if( m_clientTerminal != null )
{
m_clientTerminal.update();
}
}
}
public boolean pollChanged()
{
if( m_changed )
{
m_changed = false;
return true;
m_serverMonitor.update();
if( m_serverMonitor.hasTerminalChanged() ) updateBlock();
}
}
else
{
if( m_xIndex == 0 && m_yIndex == 0 && m_clientMonitor != null )
{
m_clientMonitor.update();
}
}
return false;
}
// IPeripheralTile implementation
@ -185,24 +190,71 @@ public class TileMonitor extends TilePeripheralBase
@Override
public IPeripheral getPeripheral( EnumFacing side )
{
hasPeripheral = true;
createServerMonitor(); // Ensure the monitor is created before doing anything else.
return new MonitorPeripheral( this );
}
public void setTextScale( int scale )
public ServerMonitor getCachedServerMonitor()
{
return m_serverMonitor;
}
private ServerMonitor getServerMonitor()
{
if( m_serverMonitor != null ) return m_serverMonitor;
TileMonitor origin = getOrigin();
if( origin != null )
if( origin == null ) return null;
return m_serverMonitor = origin.m_serverMonitor;
}
private ServerMonitor createServerMonitor()
{
synchronized( origin )
if( m_serverMonitor != null )
{
if( origin.m_textScale != scale )
return m_serverMonitor;
}
else if( m_xIndex == 0 && m_yIndex == 0 )
{
origin.m_textScale = scale;
origin.rebuildTerminal();
origin.updateBlock();
// If we're the origin, set up the new monitor
m_serverMonitor = new ServerMonitor( m_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();
TileEntity te = world.getTileEntity( 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();
TileEntity te = world.getTileEntity( pos.offset( getRight(), -m_xIndex ).offset( getDown(), -m_yIndex ) );
if( !(te instanceof TileMonitor) ) return null;
return m_clientMonitor = ((TileMonitor) te).m_clientMonitor;
}
// Networking stuff
@ -215,9 +267,12 @@ public class TileMonitor extends TilePeripheralBase
nbttagcompound.setInteger( "yIndex", m_yIndex );
nbttagcompound.setInteger( "width", m_width );
nbttagcompound.setInteger( "height", m_height );
nbttagcompound.setInteger( "textScale", m_textScale );
nbttagcompound.setInteger( "monitorDir", m_dir );
((ServerTerminal)getLocalTerminal()).writeDescription( nbttagcompound );
if( m_xIndex == 0 && m_yIndex == 0 && m_serverMonitor != null )
{
m_serverMonitor.writeDescription( nbttagcompound );
}
}
@Override
@ -229,110 +284,40 @@ public class TileMonitor extends TilePeripheralBase
int oldYIndex = m_yIndex;
int oldWidth = m_width;
int oldHeight = m_height;
int oldTextScale = m_textScale;
int oldDir = m_dir;
m_xIndex = nbttagcompound.getInteger( "xIndex" );
m_yIndex = nbttagcompound.getInteger( "yIndex" );
m_width = nbttagcompound.getInteger( "width" );
m_height = nbttagcompound.getInteger( "height" );
m_textScale = nbttagcompound.getInteger( "textScale" );
m_dir = nbttagcompound.getInteger( "monitorDir" );
((ClientTerminal)getLocalTerminal()).readDescription( nbttagcompound );
m_changed = true;
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( m_advanced, this );
m_clientMonitor.readDescription( nbttagcompound );
}
if( oldXIndex != m_xIndex || oldYIndex != m_yIndex ||
oldWidth != m_width || oldHeight != m_height ||
oldTextScale != m_textScale || oldDir != m_dir )
oldDir != m_dir )
{
// One of our properties has changed, so ensure we redraw the block
updateBlock();
}
}
// ITerminalTile implementation
@Override
public ITerminal getTerminal()
{
TileMonitor origin = getOrigin();
if( origin != null )
{
return origin.getLocalTerminal();
}
return null;
}
private ITerminal getLocalTerminal()
{
if( !getWorld().isRemote )
{
if( m_serverTerminal == null )
{
m_serverTerminal = new ServerTerminal(
getPeripheralType() == PeripheralType.AdvancedMonitor
);
}
return m_serverTerminal;
}
else
{
if( m_clientTerminal == null )
{
m_clientTerminal = new ClientTerminal(
getPeripheralType() == PeripheralType.AdvancedMonitor
);
}
return m_clientTerminal;
}
}
// Sizing and placement stuff
public double getTextScale()
{
TileMonitor origin = getOrigin();
return (origin == null ? m_textScale : origin.m_textScale) * 0.5;
}
private void rebuildTerminal()
{
Terminal oldTerm = getTerminal().getTerminal();
int oldWidth = (oldTerm != null) ? oldTerm.getWidth() : -1;
int oldHeight = (oldTerm != null) ? oldTerm.getHeight() : -1;
double textScale = getTextScale();
int termWidth = (int)Math.max(
Math.round( (m_width - 2.0 * ( TileMonitor.RENDER_BORDER + TileMonitor.RENDER_MARGIN )) / (textScale * 6.0 * TileMonitor.RENDER_PIXEL_SCALE) ),
1.0
);
int termHeight = (int)Math.max(
Math.round( (m_height - 2.0 * ( TileMonitor.RENDER_BORDER + TileMonitor.RENDER_MARGIN )) / (textScale * 9.0 * TileMonitor.RENDER_PIXEL_SCALE) ),
1.0
);
((ServerTerminal)getLocalTerminal()).resize( termWidth, termHeight );
if( oldWidth != termWidth || oldHeight != termHeight )
{
getLocalTerminal().getTerminal().clear();
for( int y=0; y<m_height; ++y )
{
for( int x=0; x<m_width; ++x )
{
TileMonitor monitor = getNeighbour( x, y );
if( monitor != null )
{
monitor.queueSizeChangedEvent();
}
}
}
}
}
private void destroyTerminal()
{
((ServerTerminal)getLocalTerminal()).delete();
}
@Override
public EnumFacing getDirection()
{
@ -354,7 +339,6 @@ public class TileMonitor extends TilePeripheralBase
public void setDir( int dir )
{
m_dir = dir;
m_changed = true;
markDirty();
}
@ -432,8 +416,7 @@ public class TileMonitor extends TilePeripheralBase
if( tile != null && tile instanceof TileMonitor )
{
TileMonitor monitor = (TileMonitor) tile;
if( monitor.getDir() == getDir() &&
monitor.getLocalTerminal().isColour() == getLocalTerminal().isColour() &&
if( monitor.getDir() == getDir() && monitor.m_advanced == m_advanced &&
!monitor.m_destroyed && !monitor.m_ignoreMe )
{
return monitor;
@ -464,34 +447,59 @@ public class TileMonitor extends TilePeripheralBase
private void resize( int width, int height )
{
// Update the positions and indexes of the other monitors
BlockPos pos = getPos();
EnumFacing right = getRight();
EnumFacing down = getDown();
for( int y=0; y<height; ++y )
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 x=0; x<width; ++x )
for( int y = 0; y < height; y++ )
{
TileMonitor monitor = getSimilarMonitorAt(
pos.offset( right, x ).offset( down, y )
);
if( monitor != null )
TileMonitor monitor = getNeighbour( x, y );
if( monitor != null && monitor.hasPeripheral )
{
monitor.m_xIndex = x;
monitor.m_yIndex = y;
monitor.m_width = width;
monitor.m_height = height;
monitor.updateBlock();
if( x != 0 || y != 0 )
{
monitor.destroyTerminal();
}
needsTerminal = true;
break terminalCheck;
}
}
}
// Rebuild this terminal (will invoke resize events)
rebuildTerminal();
// Either delete the current monitor or sync a new one.
if( needsTerminal )
{
if( m_serverMonitor == null ) m_serverMonitor = new ServerMonitor( m_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.updateBlock();
}
}
}
private boolean mergeLeft()
@ -700,18 +708,14 @@ public class TileMonitor extends TilePeripheralBase
return;
}
Terminal originTerminal = getTerminal().getTerminal();
if( originTerminal == null )
{
return;
}
if( !getTerminal().isColour() )
{
return;
}
ServerTerminal serverTerminal = getServerMonitor();
if( serverTerminal == null || !serverTerminal.isColour() ) 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());
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 ) );
@ -721,27 +725,16 @@ public class TileMonitor extends TilePeripheralBase
for( int x = 0; x < m_width; ++x )
{
TileMonitor monitor = getNeighbour( x, y );
if( monitor != null )
{
monitor.queueTouchEvent(xCharPos, yCharPos);
}
}
}
}
if( monitor == null )continue;
private void queueTouchEvent( int xCharPos, int yCharPos )
{
for( IComputerAccess computer : m_computers )
for( IComputerAccess computer : monitor.m_computers )
{
computer.queueEvent( "monitor_touch", new Object[] {
computer.getAttachmentName(), xCharPos, yCharPos
} );
}
}
private void queueSizeChangedEvent()
{
m_sizeChangedQueued = true;
}
}
private XYPair convertToXY( float xPos, float yPos, float zPos, int side )
@ -780,32 +773,18 @@ public class TileMonitor extends TilePeripheralBase
public void addComputer( IComputerAccess computer )
{
synchronized( this )
{
if( m_computers.size() == 0 )
{
TileMonitor origin = getOrigin();
if( origin != null )
{
origin.rebuildTerminal();
}
}
if( !m_computers.contains(computer) )
{
m_computers.add( computer );
}
}
}
public void removeComputer( IComputerAccess computer )
{
synchronized( this )
{
if( m_computers.contains(computer) )
{
m_computers.remove( computer );
}
}
}
public static class XYPair
{