diff --git a/src/main/java/dan200/computercraft/core/apis/IAPIEnvironment.java b/src/main/java/dan200/computercraft/core/apis/IAPIEnvironment.java index eb8a5b316..cdadd0330 100644 --- a/src/main/java/dan200/computercraft/core/apis/IAPIEnvironment.java +++ b/src/main/java/dan200/computercraft/core/apis/IAPIEnvironment.java @@ -14,20 +14,32 @@ import dan200.computercraft.core.filesystem.FileSystem; import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.core.tracking.TrackingField; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + public interface IAPIEnvironment extends IComputerOwned { + String[] SIDE_NAMES = new String[] { + "bottom", "top", "back", "front", "right", "left", + }; + + int SIDE_COUNT = 6; + interface IPeripheralChangeListener { - void onPeripheralChanged( int side, IPeripheral newPeripheral ); + void onPeripheralChanged( int side, @Nullable IPeripheral newPeripheral ); } + @Nonnull @Override Computer getComputer(); int getComputerID(); + @Nonnull IComputerEnvironment getComputerEnvironment(); + @Nonnull Terminal getTerminal(); FileSystem getFileSystem(); @@ -50,17 +62,18 @@ public interface IAPIEnvironment extends IComputerOwned int getBundledInput( int side ); - void setPeripheralChangeListener( IPeripheralChangeListener listener ); + void setPeripheralChangeListener( @Nullable IPeripheralChangeListener listener ); + @Nullable IPeripheral getPeripheral( int side ); String getLabel(); - void setLabel( String label ); + void setLabel( @Nullable String label ); - void addTrackingChange( TrackingField field, long change ); + void addTrackingChange( @Nonnull TrackingField field, long change ); - default void addTrackingChange( TrackingField field ) + default void addTrackingChange( @Nonnull TrackingField field ) { addTrackingChange( field, 1 ); } diff --git a/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java b/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java index 05e03858d..df124e660 100644 --- a/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java @@ -278,13 +278,13 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange }, null ); // Queue a detachment event - m_environment.queueEvent( "peripheral_detach", new Object[] { Computer.s_sideNames[side] } ); + m_environment.queueEvent( "peripheral_detach", new Object[] { IAPIEnvironment.SIDE_NAMES[side] } ); } // Assign the new peripheral if( newPeripheral != null ) { - m_peripherals[side] = new PeripheralWrapper( newPeripheral, Computer.s_sideNames[side] ); + m_peripherals[side] = new PeripheralWrapper( newPeripheral, IAPIEnvironment.SIDE_NAMES[side] ); } else { @@ -317,7 +317,7 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange }, null ); // Queue an attachment event - m_environment.queueEvent( "peripheral", new Object[] { Computer.s_sideNames[side] } ); + m_environment.queueEvent( "peripheral", new Object[] { IAPIEnvironment.SIDE_NAMES[side] } ); } } } @@ -483,9 +483,9 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange private int parseSide( Object[] args ) throws LuaException { String side = getString( args, 0 ); - for( int n = 0; n < Computer.s_sideNames.length; n++ ) + for( int n = 0; n < IAPIEnvironment.SIDE_NAMES.length; n++ ) { - if( side.equals( Computer.s_sideNames[n] ) ) + if( side.equals( IAPIEnvironment.SIDE_NAMES[n] ) ) { return n; } diff --git a/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java b/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java index 22427aca2..460e58c2a 100644 --- a/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java @@ -9,7 +9,6 @@ package dan200.computercraft.core.apis; import dan200.computercraft.api.lua.ILuaAPI; import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; -import dan200.computercraft.core.computer.Computer; import javax.annotation.Nonnull; import java.util.HashMap; @@ -65,9 +64,9 @@ public class RedstoneAPI implements ILuaAPI { // getSides Map table = new HashMap<>(); - for( int i = 0; i < Computer.s_sideNames.length; i++ ) + for( int i = 0; i < IAPIEnvironment.SIDE_NAMES.length; i++ ) { - table.put( i + 1, Computer.s_sideNames[i] ); + table.put( i + 1, IAPIEnvironment.SIDE_NAMES[i] ); } return new Object[] { table }; } @@ -156,9 +155,9 @@ public class RedstoneAPI implements ILuaAPI private int parseSide( Object[] args ) throws LuaException { String side = getString( args, 0 ); - for( int n = 0; n < Computer.s_sideNames.length; n++ ) + for( int n = 0; n < IAPIEnvironment.SIDE_NAMES.length; n++ ) { - if( side.equals( Computer.s_sideNames[n] ) ) + if( side.equals( IAPIEnvironment.SIDE_NAMES[n] ) ) { return n; } diff --git a/src/main/java/dan200/computercraft/core/computer/ApiWrapper.java b/src/main/java/dan200/computercraft/core/computer/ApiWrapper.java new file mode 100644 index 000000000..68866e2c7 --- /dev/null +++ b/src/main/java/dan200/computercraft/core/computer/ApiWrapper.java @@ -0,0 +1,68 @@ +/* + * 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.core.computer; + +import dan200.computercraft.api.lua.ILuaAPI; +import dan200.computercraft.api.lua.ILuaContext; +import dan200.computercraft.api.lua.LuaException; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * A wrapper for {@link ILuaAPI}s which cleans up after a {@link ComputerSystem} when the computer is shutdown. + */ +public class ApiWrapper implements ILuaAPI +{ + private final ILuaAPI delegate; + private final ComputerSystem system; + + ApiWrapper( ILuaAPI delegate, ComputerSystem system ) + { + this.delegate = delegate; + this.system = system; + } + + @Override + public String[] getNames() + { + return delegate.getNames(); + } + + @Override + public void startup() + { + delegate.startup(); + } + + @Override + public void update() + { + delegate.update(); + } + + @Override + public void shutdown() + { + delegate.shutdown(); + system.unmountAll(); + } + + @Nonnull + @Override + public String[] getMethodNames() + { + return delegate.getMethodNames(); + } + + @Nullable + @Override + public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException + { + return delegate.callMethod( context, method, arguments ); + } +} diff --git a/src/main/java/dan200/computercraft/core/computer/Computer.java b/src/main/java/dan200/computercraft/core/computer/Computer.java index 61ce6716f..a6fdca0ba 100644 --- a/src/main/java/dan200/computercraft/core/computer/Computer.java +++ b/src/main/java/dan200/computercraft/core/computer/Computer.java @@ -8,11 +8,10 @@ package dan200.computercraft.core.computer; import com.google.common.base.Objects; import dan200.computercraft.ComputerCraft; -import dan200.computercraft.api.filesystem.IFileSystem; import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.filesystem.IWritableMount; import dan200.computercraft.api.lua.ILuaAPI; -import dan200.computercraft.api.lua.*; +import dan200.computercraft.api.lua.ILuaAPIFactory; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.core.apis.*; import dan200.computercraft.core.filesystem.FileSystem; @@ -20,11 +19,7 @@ import dan200.computercraft.core.filesystem.FileSystemException; import dan200.computercraft.core.lua.CobaltLuaMachine; import dan200.computercraft.core.lua.ILuaMachine; import dan200.computercraft.core.terminal.Terminal; -import dan200.computercraft.core.tracking.Tracking; -import dan200.computercraft.core.tracking.TrackingField; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; @@ -32,10 +27,6 @@ import java.util.List; public class Computer { - public static final String[] s_sideNames = new String[] { - "bottom", "top", "back", "front", "right", "left", - }; - private enum State { Off, @@ -44,319 +35,81 @@ public class Computer Stopping, } - private static class APIEnvironment implements IAPIEnvironment - { - private Computer m_computer; - private IAPIEnvironment.IPeripheralChangeListener m_peripheralListener; - - public APIEnvironment( Computer computer ) - { - m_computer = computer; - m_peripheralListener = null; - } - - @Override - public Computer getComputer() - { - return m_computer; - } - - @Override - public int getComputerID() - { - return m_computer.assignID(); - } - - @Override - public IComputerEnvironment getComputerEnvironment() - { - return m_computer.m_environment; - } - - @Override - public Terminal getTerminal() - { - return m_computer.m_terminal; - } - - @Override - public FileSystem getFileSystem() - { - return m_computer.m_fileSystem; - } - - @Override - public void shutdown() - { - m_computer.shutdown(); - } - - @Override - public void reboot() - { - m_computer.reboot(); - } - - @Override - public void queueEvent( String event, Object[] args ) - { - m_computer.queueEvent( event, args ); - } - - @Override - public void setOutput( int side, int output ) - { - m_computer.setRedstoneOutput( side, output ); - } - - @Override - public int getOutput( int side ) - { - return m_computer.getInternalRedstoneOutput( side ); - } - - @Override - public int getInput( int side ) - { - return m_computer.getRedstoneInput( side ); - } - - @Override - public void setBundledOutput( int side, int output ) - { - m_computer.setBundledRedstoneOutput( side, output ); - } - - @Override - public int getBundledOutput( int side ) - { - return m_computer.getInternalBundledRedstoneOutput( side ); - } - - @Override - public int getBundledInput( int side ) - { - return m_computer.getBundledRedstoneInput( side ); - } - - @Override - public IPeripheral getPeripheral( int side ) - { - synchronized( m_computer.m_peripherals ) - { - return m_computer.m_peripherals[side]; - } - } - - @Override - public void setPeripheralChangeListener( IPeripheralChangeListener listener ) - { - synchronized( m_computer.m_peripherals ) - { - m_peripheralListener = listener; - } - } - - @Override - public String getLabel() - { - return m_computer.getLabel(); - } - - @Override - public void setLabel( String label ) - { - m_computer.setLabel( label ); - } - - @Override - public void addTrackingChange( TrackingField field, long change ) - { - Tracking.addValue( m_computer, field, change ); - } - - public void onPeripheralChanged( int side, IPeripheral peripheral ) - { - synchronized( m_computer.m_peripherals ) - { - if( m_peripheralListener != null ) - { - m_peripheralListener.onPeripheralChanged( side, peripheral ); - } - } - } - } - - private static class ComputerSystem extends ComputerAccess implements IComputerSystem - { - private final IAPIEnvironment m_environment; - - private ComputerSystem( IAPIEnvironment m_environment ) - { - super( m_environment ); - this.m_environment = m_environment; - } - - @Nonnull - @Override - public String getAttachmentName() - { - return "computer"; - } - - @Nullable - @Override - public IFileSystem getFileSystem() - { - FileSystem fs = m_environment.getFileSystem(); - return fs == null ? null : fs.getMountWrapper(); - } - - @Nullable - @Override - public String getLabel() - { - return m_environment.getLabel(); - } - } - - private static class APIWrapper implements ILuaAPI - { - private final ILuaAPI delegate; - private final ComputerSystem system; - - private APIWrapper( ILuaAPI delegate, ComputerSystem system ) - { - this.delegate = delegate; - this.system = system; - } - - @Override - public String[] getNames() - { - return delegate.getNames(); - } - - @Override - public void startup() - { - delegate.startup(); - } - - @Override - public void update() - { - delegate.update(); - } - - @Override - public void shutdown() - { - delegate.shutdown(); - system.unmountAll(); - } - - @Nonnull - @Override - public String[] getMethodNames() - { - return delegate.getMethodNames(); - } - - @Nullable - @Override - public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException - { - return delegate.callMethod( context, method, arguments ); - } - } - private static IMount s_romMount = null; private int m_id; - private String m_label; + private String m_label = null; private final IComputerEnvironment m_environment; - private int m_ticksSinceStart; - private boolean m_startRequested; - private State m_state; - private boolean m_blinking; + private int m_ticksSinceStart = -1; + private boolean m_startRequested = false; + private State m_state = State.Off; + private boolean m_blinking = false; - private ILuaMachine m_machine; - private final List m_apis; - private final APIEnvironment m_apiEnvironment; + private ILuaMachine m_machine = null; + private final List m_apis = new ArrayList<>(); + private final Environment m_internalEnvironment = new Environment( this ); private final Terminal m_terminal; - private FileSystem m_fileSystem; - private IWritableMount m_rootMount; + private FileSystem m_fileSystem = null; + private IWritableMount m_rootMount = null; - private final int[] m_internalOutput; - private final int[] m_internalBundledOutput; - private boolean m_internalOutputChanged; - - private final int[] m_externalOutput; - private final int[] m_externalBundledOutput; private boolean m_externalOutputChanged; - private final int[] m_input; - private final int[] m_bundledInput; - private boolean m_inputChanged; - - private final IPeripheral[] m_peripherals; - public Computer( IComputerEnvironment environment, Terminal terminal, int id ) { + m_id = id; + m_environment = environment; + m_terminal = terminal; + + // Ensure the computer thread is running as required. ComputerThread.start(); - m_id = id; - m_label = null; - m_environment = environment; + // Add all default APIs to the loaded list. + m_apis.add( new TermAPI( m_internalEnvironment ) ); + m_apis.add( new RedstoneAPI( m_internalEnvironment ) ); + m_apis.add( new FSAPI( m_internalEnvironment ) ); + m_apis.add( new PeripheralAPI( m_internalEnvironment ) ); + m_apis.add( new OSAPI( m_internalEnvironment ) ); + if( ComputerCraft.http_enable ) m_apis.add( new HTTPAPI( m_internalEnvironment ) ); - m_ticksSinceStart = -1; - m_startRequested = false; - m_state = State.Off; - m_blinking = false; - - m_terminal = terminal; - m_fileSystem = null; - - m_machine = null; - m_apis = new ArrayList<>(); - m_apiEnvironment = new APIEnvironment( this ); - - m_internalOutput = new int[6]; - m_internalBundledOutput = new int[6]; - m_internalOutputChanged = true; - - m_externalOutput = new int[6]; - m_externalBundledOutput = new int[6]; - m_externalOutputChanged = true; - - m_input = new int[6]; - m_bundledInput = new int[6]; - m_inputChanged = false; - - m_peripherals = new IPeripheral[6]; - for( int i = 0; i < 6; i++ ) + // Load in the API registered APIs. + for( ILuaAPIFactory factory : ApiFactories.getAll() ) { - m_peripherals[i] = null; + ComputerSystem system = new ComputerSystem( m_internalEnvironment ); + ILuaAPI api = factory.create( system ); + if( api != null ) m_apis.add( new ApiWrapper( api, system ) ); } + } - m_rootMount = null; - createAPIs(); + IComputerEnvironment getComputerEnvironment() + { + return m_environment; + } + + FileSystem getFileSystem() + { + return m_fileSystem; + } + + Terminal getTerminal() + { + return m_terminal; + } + + public Environment getEnvironment() + { + return m_internalEnvironment; } public IAPIEnvironment getAPIEnvironment() { - return m_apiEnvironment; + return m_internalEnvironment; } public void turnOn() { - if( m_state == State.Off ) - { - m_startRequested = true; - } + if( m_state == State.Off ) m_startRequested = true; } public void shutdown() @@ -397,10 +150,7 @@ public class Computer public void unload() { - synchronized( this ) - { - stopComputer( false ); - } + stopComputer( false ); } public int getID() @@ -436,7 +186,7 @@ public class Computer } } - public void advance( double _dt ) + public void advance() { synchronized( this ) { @@ -453,67 +203,27 @@ public class Computer if( m_state == State.Running ) { - // Fire the redstone event if our redstone input has changed - synchronized( m_input ) - { - if( m_inputChanged ) - { - queueEvent( "redstone", null ); - m_inputChanged = false; - } - } + // Update the environment's internal state. + m_internalEnvironment.update(); // Advance our APIs - synchronized( m_apis ) - { - for( ILuaAPI api : m_apis ) - { - api.update(); - } - } + for( ILuaAPI api : m_apis ) api.update(); } } - // Set outputchanged if the internal redstone has changed - synchronized( m_internalOutput ) - { - if( m_internalOutputChanged ) - { - boolean changed = false; - for( int i = 0; i < 6; i++ ) - { - if( m_externalOutput[i] != m_internalOutput[i] ) - { - m_externalOutput[i] = m_internalOutput[i]; - changed = true; - } - if( m_externalBundledOutput[i] != m_internalBundledOutput[i] ) - { - m_externalBundledOutput[i] = m_internalBundledOutput[i]; - changed = true; - } - } - m_internalOutputChanged = false; - if( changed ) - { - m_externalOutputChanged = true; - } - } - } + // Prepare to propagate the environment's output to the world. + if( m_internalEnvironment.updateOutput() ) m_externalOutputChanged = true; - // Set outputchanged if the terminal has changed from blinking to not - synchronized( m_terminal ) - { - boolean blinking = - m_terminal.getCursorBlink() && - m_terminal.getCursorX() >= 0 && m_terminal.getCursorX() < m_terminal.getWidth() && - m_terminal.getCursorY() >= 0 && m_terminal.getCursorY() < m_terminal.getHeight(); + // Set output changed if the terminal has changed from blinking to not + boolean blinking = + m_terminal.getCursorBlink() && + m_terminal.getCursorX() >= 0 && m_terminal.getCursorX() < m_terminal.getWidth() && + m_terminal.getCursorY() >= 0 && m_terminal.getCursorY() < m_terminal.getHeight(); - if( blinking != m_blinking ) - { - m_blinking = blinking; - m_externalOutputChanged = true; - } + if( blinking != m_blinking ) + { + m_blinking = blinking; + m_externalOutputChanged = true; } } @@ -529,10 +239,7 @@ public class Computer public boolean isBlinking() { - synchronized( m_terminal ) - { - return isOn() && m_blinking; - } + return isOn() && m_blinking; } public IWritableMount getRootMount() @@ -553,10 +260,7 @@ public class Computer try { m_fileSystem = new FileSystem( "hdd", getRootMount() ); - if( s_romMount == null ) - { - s_romMount = m_environment.createResourceMount( "computercraft", "lua/rom" ); - } + if( s_romMount == null ) s_romMount = m_environment.createResourceMount( "computercraft", "lua/rom" ); if( s_romMount != null ) { m_fileSystem.mount( "rom", "rom", s_romMount ); @@ -571,104 +275,6 @@ public class Computer } } - // Redstone - - public int getRedstoneOutput( int side ) - { - synchronized( m_internalOutput ) - { - return isOn() ? m_externalOutput[side] : 0; - } - } - - private int getInternalRedstoneOutput( int side ) - { - synchronized( m_internalOutput ) - { - return isOn() ? m_internalOutput[side] : 0; - } - } - - private void setRedstoneOutput( int side, int level ) - { - synchronized( m_internalOutput ) - { - if( m_internalOutput[side] != level ) - { - m_internalOutput[side] = level; - m_internalOutputChanged = true; - } - } - } - - public void setRedstoneInput( int side, int level ) - { - synchronized( m_input ) - { - if( m_input[side] != level ) - { - m_input[side] = level; - m_inputChanged = true; - } - } - } - - private int getRedstoneInput( int side ) - { - synchronized( m_input ) - { - return m_input[side]; - } - } - - public int getBundledRedstoneOutput( int side ) - { - synchronized( m_internalOutput ) - { - return isOn() ? m_externalBundledOutput[side] : 0; - } - } - - private int getInternalBundledRedstoneOutput( int side ) - { - synchronized( m_internalOutput ) - { - return isOn() ? m_internalBundledOutput[side] : 0; - } - } - - private void setBundledRedstoneOutput( int side, int combination ) - { - synchronized( m_internalOutput ) - { - if( m_internalBundledOutput[side] != combination ) - { - m_internalBundledOutput[side] = combination; - m_internalOutputChanged = true; - } - } - } - - public void setBundledRedstoneInput( int side, int combination ) - { - synchronized( m_input ) - { - if( m_bundledInput[side] != combination ) - { - m_bundledInput[side] = combination; - m_inputChanged = true; - } - } - } - - private int getBundledRedstoneInput( int side ) - { - synchronized( m_input ) - { - return m_bundledInput[side]; - } - } - // Peripherals public void addAPI( ILuaAPI api ) @@ -676,57 +282,8 @@ public class Computer m_apis.add( api ); } - @SuppressWarnings( "deprecation" ) - public void addAPI( dan200.computercraft.core.apis.ILuaAPI api ) - { - addAPI( (ILuaAPI) api ); - } - - public void setPeripheral( int side, IPeripheral peripheral ) - { - synchronized( m_peripherals ) - { - IPeripheral existing = m_peripherals[side]; - if( (existing == null && peripheral != null) || - (existing != null && peripheral == null) || - (existing != null && !existing.equals( peripheral )) ) - { - m_peripherals[side] = peripheral; - m_apiEnvironment.onPeripheralChanged( side, peripheral ); - } - } - } - - public IPeripheral getPeripheral( int side ) - { - synchronized( m_peripherals ) - { - return m_peripherals[side]; - } - } - // Lua - private void createAPIs() - { - m_apis.add( new TermAPI( m_apiEnvironment ) ); - m_apis.add( new RedstoneAPI( m_apiEnvironment ) ); - m_apis.add( new FSAPI( m_apiEnvironment ) ); - m_apis.add( new PeripheralAPI( m_apiEnvironment ) ); - m_apis.add( new OSAPI( m_apiEnvironment ) ); - if( ComputerCraft.http_enable ) - { - m_apis.add( new HTTPAPI( m_apiEnvironment ) ); - } - - for( ILuaAPIFactory factory : ApiFactories.getAll() ) - { - ComputerSystem system = new ComputerSystem( m_apiEnvironment ); - ILuaAPI api = factory.create( system ); - if( api != null ) m_apis.add( api ); - } - } - private void initLua() { // Create the lua machine @@ -824,10 +381,7 @@ public class Computer } // Init terminal - synchronized( m_terminal ) - { - m_terminal.reset(); - } + m_terminal.reset(); // Init filesystem if( !initFileSystem() ) @@ -920,10 +474,7 @@ public class Computer if( m_machine != null ) { - synchronized( m_terminal ) - { - m_terminal.reset(); - } + m_terminal.reset(); synchronized( m_machine ) { @@ -933,15 +484,7 @@ public class Computer } // Reset redstone output - synchronized( m_internalOutput ) - { - for( int i = 0; i < 6; i++ ) - { - m_internalOutput[i] = 0; - m_internalBundledOutput[i] = 0; - } - m_internalOutputChanged = true; - } + m_internalEnvironment.resetOutput(); m_state = State.Off; m_externalOutputChanged = true; @@ -1002,4 +545,23 @@ public class Computer ComputerThread.queueTask( task, computer ); } + + @Deprecated + public void setPeripheral( int side, IPeripheral peripheral ) + { + m_internalEnvironment.setPeripheral( side, peripheral ); + } + + @Deprecated + public void addAPI( dan200.computercraft.core.apis.ILuaAPI api ) + { + addAPI( (ILuaAPI) api ); + } + + @Deprecated + @SuppressWarnings( "unused" ) + public void advance( double dt ) + { + advance(); + } } diff --git a/src/main/java/dan200/computercraft/core/computer/ComputerSystem.java b/src/main/java/dan200/computercraft/core/computer/ComputerSystem.java new file mode 100644 index 000000000..a66996e44 --- /dev/null +++ b/src/main/java/dan200/computercraft/core/computer/ComputerSystem.java @@ -0,0 +1,58 @@ +/* + * 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.core.computer; + +import dan200.computercraft.api.filesystem.IFileSystem; +import dan200.computercraft.api.lua.IComputerSystem; +import dan200.computercraft.api.lua.ILuaAPIFactory; +import dan200.computercraft.api.peripheral.IComputerAccess; +import dan200.computercraft.core.apis.ComputerAccess; +import dan200.computercraft.core.apis.IAPIEnvironment; +import dan200.computercraft.core.filesystem.FileSystem; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * Implementation of {@link IComputerAccess}/{@link IComputerSystem} for external APIs. + * + * @see dan200.computercraft.api.ComputerCraftAPI#registerAPIFactory(ILuaAPIFactory) + * @see ILuaAPIFactory + * @see ApiWrapper + */ +public class ComputerSystem extends ComputerAccess implements IComputerSystem +{ + private final IAPIEnvironment m_environment; + + ComputerSystem( IAPIEnvironment m_environment ) + { + super( m_environment ); + this.m_environment = m_environment; + } + + @Nonnull + @Override + public String getAttachmentName() + { + return "computer"; + } + + @Nullable + @Override + public IFileSystem getFileSystem() + { + FileSystem fs = m_environment.getFileSystem(); + return fs == null ? null : fs.getMountWrapper(); + } + + @Nullable + @Override + public String getLabel() + { + return m_environment.getLabel(); + } +} diff --git a/src/main/java/dan200/computercraft/core/computer/Environment.java b/src/main/java/dan200/computercraft/core/computer/Environment.java new file mode 100644 index 000000000..95dd85222 --- /dev/null +++ b/src/main/java/dan200/computercraft/core/computer/Environment.java @@ -0,0 +1,306 @@ +/* + * 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.core.computer; + +import dan200.computercraft.api.peripheral.IPeripheral; +import dan200.computercraft.core.apis.IAPIEnvironment; +import dan200.computercraft.core.filesystem.FileSystem; +import dan200.computercraft.core.terminal.Terminal; +import dan200.computercraft.core.tracking.Tracking; +import dan200.computercraft.core.tracking.TrackingField; + +import javax.annotation.Nonnull; +import java.util.Arrays; + +/** + * Represents the "environment" that a {@link Computer} exists in. + * + * This handles storing and updating of peripherals and redstone. + * + *

Redstone

+ * We holds three kinds of arrays for redstone, in normal and bundled versions: + *
    + *
  • {@link #internalOutput} is the redstone output which the computer has currently set. This is read on both + * threads, and written on the computer thread.
  • + *
  • {@link #externalOutput} is the redstone output currently propagated to the world. This is only read and written + * on the main thread.
  • + *
  • {@link #input} is the redstone input from external sources. This is read on both threads, and written on the main + * thread.
  • + *
+ * + *

Peripheral

+ * We also keep track of peripherals. These are read on both threads, and only written on the main thread. + */ +public final class Environment implements IAPIEnvironment +{ + private final Computer computer; + + private boolean internalOutputChanged = false; + private final int[] internalOutput = new int[SIDE_COUNT]; + private final int[] internalBundledOutput = new int[SIDE_COUNT]; + + private final int[] externalOutput = new int[SIDE_COUNT]; + private final int[] externalBundledOutput = new int[SIDE_COUNT]; + + private boolean inputChanged = false; + private final int[] input = new int[SIDE_COUNT]; + private final int[] bundledInput = new int[SIDE_COUNT]; + + private final IPeripheral[] peripherals = new IPeripheral[SIDE_COUNT]; + private IPeripheralChangeListener peripheralListener = null; + + Environment( Computer computer ) + { + this.computer = computer; + } + + @Nonnull + @Override + public Computer getComputer() + { + return computer; + } + + @Override + public int getComputerID() + { + return computer.assignID(); + } + + @Nonnull + @Override + public IComputerEnvironment getComputerEnvironment() + { + return computer.getComputerEnvironment(); + } + + @Nonnull + @Override + public Terminal getTerminal() + { + return computer.getTerminal(); + } + + @Override + public FileSystem getFileSystem() + { + return computer.getFileSystem(); + } + + @Override + public void shutdown() + { + computer.shutdown(); + } + + @Override + public void reboot() + { + computer.reboot(); + } + + @Override + public void queueEvent( String event, Object[] args ) + { + computer.queueEvent( event, args ); + } + + @Override + public int getInput( int side ) + { + return input[side]; + } + + @Override + public int getBundledInput( int side ) + { + return bundledInput[side]; + } + + @Override + public void setOutput( int side, int output ) + { + synchronized( internalOutput ) + { + if( internalOutput[side] != output ) + { + internalOutput[side] = output; + internalOutputChanged = true; + } + } + } + + @Override + public int getOutput( int side ) + { + synchronized( internalOutput ) + { + return computer.isOn() ? internalOutput[side] : 0; + } + } + + @Override + public void setBundledOutput( int side, int output ) + { + synchronized( internalOutput ) + { + if( internalBundledOutput[side] != output ) + { + internalBundledOutput[side] = output; + internalOutputChanged = true; + } + } + } + + @Override + public int getBundledOutput( int side ) + { + synchronized( internalOutput ) + { + return computer.isOn() ? internalBundledOutput[side] : 0; + } + } + + public int getExternalRedstoneOutput( int side ) + { + return computer.isOn() ? externalOutput[side] : 0; + } + + public int getExternalBundledRedstoneOutput( int side ) + { + return computer.isOn() ? externalBundledOutput[side] : 0; + } + + public void setRedstoneInput( int side, int level ) + { + if( input[side] != level ) + { + input[side] = level; + inputChanged = true; + } + } + + public void setBundledRedstoneInput( int side, int combination ) + { + if( bundledInput[side] != combination ) + { + bundledInput[side] = combination; + inputChanged = true; + } + } + + /** + * Called on the main thread to update the internal state of the computer. + * + * This just queues a {@code redstone} event if the input has changed. + */ + void update() + { + if( inputChanged ) + { + inputChanged = false; + queueEvent( "redstone", null ); + } + } + + /** + * Called on the main thread to propagate the internal outputs to the external ones. + * + * @return If the outputs have changed. + */ + boolean updateOutput() + { + // Set outputchanged if the internal redstone has changed + synchronized( internalOutput ) + { + if( !internalOutputChanged ) return false; + + boolean changed = false; + + for( int i = 0; i < SIDE_COUNT; i++ ) + { + if( externalOutput[i] != internalOutput[i] ) + { + externalOutput[i] = internalOutput[i]; + changed = true; + } + + if( externalBundledOutput[i] != internalBundledOutput[i] ) + { + externalBundledOutput[i] = internalBundledOutput[i]; + changed = true; + } + } + + internalOutputChanged = false; + + return changed; + } + } + + void resetOutput() + { + // Reset redstone output + synchronized( internalOutput ) + { + Arrays.fill( internalOutput, 0 ); + Arrays.fill( internalBundledOutput, 0 ); + internalOutputChanged = true; + } + } + + @Override + public IPeripheral getPeripheral( int side ) + { + synchronized( peripherals ) + { + return peripherals[side]; + } + } + + public void setPeripheral( int side, IPeripheral peripheral ) + { + synchronized( peripherals ) + { + IPeripheral existing = peripherals[side]; + if( (existing == null && peripheral != null) || + (existing != null && peripheral == null) || + (existing != null && !existing.equals( peripheral )) ) + { + peripherals[side] = peripheral; + if( peripheralListener != null ) peripheralListener.onPeripheralChanged( side, peripheral ); + } + } + } + + @Override + public void setPeripheralChangeListener( IPeripheralChangeListener listener ) + { + synchronized( peripherals ) + { + peripheralListener = listener; + } + } + + @Override + public String getLabel() + { + return computer.getLabel(); + } + + @Override + public void setLabel( String label ) + { + computer.setLabel( label ); + } + + @Override + public void addTrackingChange( @Nonnull TrackingField field, long change ) + { + Tracking.addValue( computer, field, change ); + } +} diff --git a/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java b/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java index 3f6543cee..cd7b14010 100644 --- a/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java +++ b/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java @@ -9,6 +9,7 @@ package dan200.computercraft.shared.command; import com.google.common.collect.Sets; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.peripheral.IPeripheral; +import dan200.computercraft.core.apis.IAPIEnvironment; import dan200.computercraft.core.computer.Computer; import dan200.computercraft.core.tracking.ComputerTracker; import dan200.computercraft.core.tracking.Tracking; @@ -126,7 +127,7 @@ public final class CommandComputerCraft extends CommandDelegate IPeripheral peripheral = computer.getPeripheral( i ); if( peripheral != null ) { - table.row( header( "Peripheral " + Computer.s_sideNames[i] ), text( peripheral.getType() ) ); + table.row( header( "Peripheral " + IAPIEnvironment.SIDE_NAMES[i] ), text( peripheral.getType() ) ); } } diff --git a/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java b/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java index 25d53cce4..dee0d93a8 100644 --- a/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java +++ b/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java @@ -51,6 +51,7 @@ public abstract class BlockGeneric extends Block implements ITileEntityProvider @Override @Deprecated + @SuppressWarnings( "deprecation" ) public final void neighborChanged( IBlockState state, World world, BlockPos pos, Block block, BlockPos neighbour ) { TileEntity tile = world.getTileEntity( pos ); diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java b/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java index d59f9a794..a3c98ddff 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java @@ -105,7 +105,7 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput public void update() { super.update(); - m_computer.advance( 0.05 ); + m_computer.advance(); m_changedLastFrame = m_computer.pollAndResetChanged() || m_changed; m_changed = false; @@ -283,22 +283,22 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput public int getRedstoneOutput( int side ) { - return m_computer.getRedstoneOutput( side ); + return m_computer.getEnvironment().getExternalRedstoneOutput( side ); } public void setRedstoneInput( int side, int level ) { - m_computer.setRedstoneInput( side, level ); + m_computer.getEnvironment().setRedstoneInput( side, level ); } public int getBundledRedstoneOutput( int side ) { - return m_computer.getBundledRedstoneOutput( side ); + return m_computer.getEnvironment().getExternalBundledRedstoneOutput( side ); } public void setBundledRedstoneInput( int side, int combination ) { - m_computer.setBundledRedstoneInput( side, combination ); + m_computer.getEnvironment().setBundledRedstoneInput( side, combination ); } public void addAPI( ILuaAPI api ) @@ -306,7 +306,7 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput m_computer.addAPI( api ); } - @SuppressWarnings( "deprecation" ) + @Deprecated public void addAPI( dan200.computercraft.core.apis.ILuaAPI api ) { m_computer.addAPI( api ); @@ -314,12 +314,12 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput public void setPeripheral( int side, IPeripheral peripheral ) { - m_computer.setPeripheral( side, peripheral ); + m_computer.getEnvironment().setPeripheral( side, peripheral ); } public IPeripheral getPeripheral( int side ) { - return m_computer.getPeripheral( side ); + return m_computer.getEnvironment().getPeripheral( side ); } public void setLabel( String label )