1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2024-12-12 03:00:30 +00:00

Handle managing computer inputs/outputs separatly

The Computer class currently has several resposiblities such as storing
id/label, managing redstone/peirpherals, handling management of the
computer (on/off/events) and updating the output.

In order to simplify this a little bit, we move our IAPIEnvironment
implementation into a separate file, and store all "world state"
(redstone + peripherals) in there. While we still need to have some
level of updating them within the main Computer instance, it's
substantially simpler.
This commit is contained in:
SquidDev 2019-02-11 16:21:51 +00:00
parent 9f2884bc0f
commit d6e0f368df
10 changed files with 559 additions and 551 deletions

View File

@ -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 );
}

View File

@ -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;
}

View File

@ -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<Object, Object> 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;
}

View File

@ -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 );
}
}

View File

@ -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<ILuaAPI> m_apis;
private final APIEnvironment m_apiEnvironment;
private ILuaMachine m_machine = null;
private final List<ILuaAPI> 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();
}
}

View File

@ -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();
}
}

View File

@ -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.
*
* <h2>Redstone</h2>
* We holds three kinds of arrays for redstone, in normal and bundled versions:
* <ul>
* <li>{@link #internalOutput} is the redstone output which the computer has currently set. This is read on both
* threads, and written on the computer thread.</li>
* <li>{@link #externalOutput} is the redstone output currently propagated to the world. This is only read and written
* on the main thread.</li>
* <li>{@link #input} is the redstone input from external sources. This is read on both threads, and written on the main
* thread.</li>
* </ul>
*
* <h2>Peripheral</h2>
* 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 );
}
}

View File

@ -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() ) );
}
}

View File

@ -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 );

View File

@ -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 )