1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2024-06-25 22:53:22 +00:00
CC-Tweaked/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java

485 lines
14 KiB
Java
Raw Normal View History

/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.core.apis;
import dan200.computercraft.api.filesystem.IMount;
import dan200.computercraft.api.filesystem.IWritableMount;
import dan200.computercraft.api.lua.ILuaAPI;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.core.computer.Computer;
import dan200.computercraft.core.computer.ComputerThread;
import dan200.computercraft.core.computer.ITask;
import dan200.computercraft.core.tracking.TrackingField;
2017-05-06 23:07:42 +00:00
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import static dan200.computercraft.core.apis.ArgumentHelper.getString;
public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChangeListener
{
private class PeripheralWrapper extends ComputerAccess
2017-05-01 14:48:44 +00:00
{
private final String m_side;
private final IPeripheral m_peripheral;
2017-05-01 14:48:44 +00:00
private String m_type;
private String[] m_methods;
private Map<String, Integer> m_methodMap;
private boolean m_attached;
2017-05-01 14:48:44 +00:00
public PeripheralWrapper( IPeripheral peripheral, String side )
{
super(m_environment);
2017-05-01 14:48:44 +00:00
m_side = side;
m_peripheral = peripheral;
m_attached = false;
2017-05-01 14:48:44 +00:00
m_type = peripheral.getType();
m_methods = peripheral.getMethodNames();
assert( m_type != null );
assert( m_methods != null );
m_methodMap = new HashMap<>();
2017-05-01 14:48:44 +00:00
for(int i=0; i<m_methods.length; ++i ) {
if( m_methods[i] != null ) {
m_methodMap.put( m_methods[i], i );
}
}
}
2017-05-01 14:48:44 +00:00
public IPeripheral getPeripheral()
{
return m_peripheral;
}
2017-05-01 14:48:44 +00:00
public String getType()
{
return m_type;
}
2017-05-01 14:48:44 +00:00
public String[] getMethods()
{
return m_methods;
}
2017-05-01 14:48:44 +00:00
public synchronized boolean isAttached()
{
return m_attached;
}
2017-05-01 14:48:44 +00:00
public synchronized void attach()
{
m_attached = true;
m_peripheral.attach( this );
}
public void detach()
2017-05-01 14:48:44 +00:00
{
// Call detach
m_peripheral.detach( this );
synchronized( this )
{
// Unmount everything the detach function forgot to do
unmountAll();
2017-05-01 14:48:44 +00:00
}
m_attached = false;
2017-05-01 14:48:44 +00:00
}
2017-05-01 14:48:44 +00:00
public Object[] call( ILuaContext context, String methodName, Object[] arguments ) throws LuaException, InterruptedException
{
int method = -1;
synchronized( this )
2017-05-01 14:48:44 +00:00
{
if( m_methodMap.containsKey( methodName ) )
{
method = m_methodMap.get( methodName );
}
}
if( method >= 0 )
{
m_environment.addTrackingChange( TrackingField.PERIPHERAL_OPS );
2017-05-01 14:48:44 +00:00
return m_peripheral.callMethod( this, context, method, arguments );
}
else
{
throw new LuaException( "No such method " + methodName );
}
}
2017-05-01 14:48:44 +00:00
// IComputerAccess implementation
@Override
2017-05-06 23:07:42 +00:00
public synchronized String mount( @Nonnull String desiredLoc, @Nonnull IMount mount, @Nonnull String driveName )
2017-05-01 14:48:44 +00:00
{
if( !m_attached )
{
throw new RuntimeException( "You are not attached to this Computer" );
}
return super.mount( desiredLoc, mount, driveName );
}
2017-05-01 14:48:44 +00:00
@Override
2017-05-06 23:07:42 +00:00
public synchronized String mountWritable( @Nonnull String desiredLoc, @Nonnull IWritableMount mount, @Nonnull String driveName )
2017-05-01 14:48:44 +00:00
{
if( !m_attached )
{
throw new RuntimeException( "You are not attached to this Computer" );
}
return super.mountWritable( desiredLoc, mount, driveName );
2017-05-01 14:48:44 +00:00
}
2017-05-01 14:48:44 +00:00
@Override
public synchronized void unmount( String location )
{
if( !m_attached )
2017-05-01 14:48:44 +00:00
{
throw new RuntimeException( "You are not attached to this Computer" );
}
super.unmount( location );
2017-05-01 14:48:44 +00:00
}
2017-05-01 14:48:44 +00:00
@Override
public int getID()
2017-05-01 14:48:44 +00:00
{
if( !m_attached )
{
2017-05-01 14:48:44 +00:00
throw new RuntimeException( "You are not attached to this Computer" );
}
return super.getID();
2017-05-01 14:48:44 +00:00
}
2017-05-01 14:48:44 +00:00
@Override
public void queueEvent( @Nonnull final String event, final Object[] arguments )
2017-05-01 14:48:44 +00:00
{
if( !m_attached )
{
2017-05-01 14:48:44 +00:00
throw new RuntimeException( "You are not attached to this Computer" );
}
super.queueEvent( event, arguments );
2017-05-01 14:48:44 +00:00
}
2017-05-06 23:07:42 +00:00
@Nonnull
2017-05-01 14:48:44 +00:00
@Override
public String getAttachmentName()
2017-05-01 14:48:44 +00:00
{
if( !m_attached )
{
2017-05-01 14:48:44 +00:00
throw new RuntimeException( "You are not attached to this Computer" );
}
return m_side;
}
@Nonnull
@Override
public Map<String, IPeripheral> getAvailablePeripherals()
{
if( !m_attached )
{
throw new RuntimeException( "You are not attached to this Computer" );
}
Map<String, IPeripheral> peripherals = new HashMap<>();
for( PeripheralWrapper wrapper : m_peripherals )
{
if( wrapper != null && wrapper.isAttached() )
{
peripherals.put( wrapper.getAttachmentName(), wrapper.getPeripheral() );
}
}
return Collections.unmodifiableMap( peripherals );
}
@Nullable
@Override
public IPeripheral getAvailablePeripheral( @Nonnull String name )
{
if( !m_attached )
{
throw new RuntimeException( "You are not attached to this Computer" );
}
for( PeripheralWrapper wrapper : m_peripherals )
{
if( wrapper != null && wrapper.isAttached() && wrapper.getAttachmentName().equals( name ) )
{
return wrapper.getPeripheral();
}
}
return null;
}
2017-05-01 14:48:44 +00:00
}
2017-05-07 00:52:55 +00:00
private final IAPIEnvironment m_environment;
private final PeripheralWrapper[] m_peripherals;
2017-05-01 14:48:44 +00:00
private boolean m_running;
2017-05-01 14:48:44 +00:00
public PeripheralAPI( IAPIEnvironment _environment )
{
m_environment = _environment;
m_environment.setPeripheralChangeListener( this );
2017-05-01 14:48:44 +00:00
m_peripherals = new PeripheralWrapper[6];
for(int i=0; i<6; ++i)
{
m_peripherals[i] = null;
}
2017-05-01 14:48:44 +00:00
m_running = false;
}
2017-05-01 14:48:44 +00:00
// IPeripheralChangeListener
@Override
2017-05-01 14:48:44 +00:00
public void onPeripheralChanged( int side, IPeripheral newPeripheral )
{
synchronized( m_peripherals )
{
if( m_peripherals[side] != null )
{
// Queue a detachment
final PeripheralWrapper wrapper = m_peripherals[side];
ComputerThread.queueTask(new ITask() {
@Override
public Computer getOwner() {
return m_environment.getComputer();
}
@Override
public void execute() {
synchronized (m_peripherals) {
if (wrapper.isAttached()) {
wrapper.detach();
}
}
}
}, null);
2017-05-01 14:48:44 +00:00
// Queue a detachment event
m_environment.queueEvent( "peripheral_detach", new Object[] { Computer.s_sideNames[side] } );
}
2017-05-01 14:48:44 +00:00
// Assign the new peripheral
if( newPeripheral != null )
{
m_peripherals[side] = new PeripheralWrapper( newPeripheral, Computer.s_sideNames[side] );
}
else
{
m_peripherals[side] = null;
}
2017-05-01 14:48:44 +00:00
if( m_peripherals[side] != null )
{
// Queue an attachment
final PeripheralWrapper wrapper = m_peripherals[side];
ComputerThread.queueTask( new ITask() {
@Override
2017-05-01 14:48:44 +00:00
public Computer getOwner() {
return m_environment.getComputer();
}
@Override
2017-05-01 14:48:44 +00:00
public void execute() {
synchronized( m_peripherals )
{
if( m_running && !wrapper.isAttached() )
{
wrapper.attach();
}
}
}
}, null );
2017-05-01 14:48:44 +00:00
// Queue an attachment event
m_environment.queueEvent( "peripheral", new Object[] { Computer.s_sideNames[side] } );
}
}
}
2017-05-01 14:48:44 +00:00
// ILuaAPI implementation
2017-05-01 14:48:44 +00:00
@Override
public String[] getNames()
{
2017-05-01 14:48:44 +00:00
return new String[] {
"peripheral"
};
}
2017-05-01 14:48:44 +00:00
@Override
public void startup( )
{
synchronized( m_peripherals )
{
m_running = true;
for( int i=0; i<6; ++i )
{
PeripheralWrapper wrapper = m_peripherals[i];
if( wrapper != null && !wrapper.isAttached() )
{
wrapper.attach();
}
}
}
}
2017-05-01 14:48:44 +00:00
@Override
public void shutdown( )
{
synchronized( m_peripherals )
{
m_running = false;
for( int i=0; i<6; ++i )
{
PeripheralWrapper wrapper = m_peripherals[i];
if( wrapper != null && wrapper.isAttached() )
{
wrapper.detach();
}
}
}
}
2017-05-06 23:07:42 +00:00
@Nonnull
2017-05-01 14:48:44 +00:00
@Override
public String[] getMethodNames()
{
2017-05-01 14:48:44 +00:00
return new String[] {
"isPresent",
"getType",
"getMethods",
"call"
};
}
2017-05-01 14:48:44 +00:00
@Override
2017-05-06 23:07:42 +00:00
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException, InterruptedException
{
2017-05-01 14:48:44 +00:00
switch( method )
{
case 0:
{
// isPresent
boolean present = false;
int side = parseSide( args );
if( side >= 0 )
{
synchronized( m_peripherals )
{
PeripheralWrapper p = m_peripherals[ side ];
if( p != null )
{
present = true;
}
}
}
return new Object[] { present };
}
case 1:
{
// getType
String type = null;
int side = parseSide( args );
if( side >= 0 )
{
synchronized( m_peripherals )
{
PeripheralWrapper p = m_peripherals[ side ];
if( p != null )
{
type = p.getType();
}
}
if( type != null )
{
return new Object[] { type };
}
}
return null;
}
case 2:
{
// getMethods
String[] methods = null;
int side = parseSide( args );
if( side >= 0 )
{
synchronized( m_peripherals )
{
PeripheralWrapper p = m_peripherals[ side ];
if( p != null )
{
methods = p.getMethods();
}
}
}
if( methods != null )
{
Map<Object,Object> table = new HashMap<>();
2017-05-01 14:48:44 +00:00
for(int i=0; i<methods.length; ++i ) {
table.put( i+1, methods[i] );
}
return new Object[] { table };
}
return null;
}
case 3:
{
// call
int side = parseSide( args );
String methodName = getString( args, 1 );
Object[] methodArgs = Arrays.copyOfRange( args, 2, args.length );
2017-05-01 14:48:44 +00:00
if( side >= 0 )
{
PeripheralWrapper p;
2017-05-01 14:48:44 +00:00
synchronized( m_peripherals )
{
p = m_peripherals[ side ];
}
if( p != null )
{
return p.call( context, methodName, methodArgs );
2017-05-01 14:48:44 +00:00
}
}
throw new LuaException( "No peripheral attached" );
}
default:
{
return null;
}
}
}
// Privates
2017-05-01 14:48:44 +00:00
private int parseSide( Object[] args ) throws LuaException
{
String side = getString( args, 0 );
2017-05-01 14:48:44 +00:00
for( int n=0; n<Computer.s_sideNames.length; ++n )
{
if( side.equals( Computer.s_sideNames[n] ) )
{
return n;
}
}
return -1;
}
}