mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2024-06-26 07:03:22 +00:00
![SquidDev](/assets/img/avatar_default.png)
This effectively acts as a public interface to canExecuteExternal() and consumeTime(). It's hopefully sufficiently general that we can mess around with the backend as much as we like in the future. One thing to note here is that this is based on a polling API, as it's largely intended for people running work every tick. It would be possible to adapt this with callbacks for when work is available, etc..., but that was not needed immediately. This also removes IComputerOwned, as Plethora no longer needs it.
413 lines
13 KiB
Java
413 lines
13 KiB
Java
/*
|
|
* This file is part of ComputerCraft - http://www.computercraft.info
|
|
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
|
|
* Send enquiries to dratcliffe@gmail.com
|
|
*/
|
|
|
|
package dan200.computercraft.shared.peripheral.modem.wired;
|
|
|
|
import com.google.common.collect.ImmutableMap;
|
|
import dan200.computercraft.api.filesystem.IMount;
|
|
import dan200.computercraft.api.filesystem.IWritableMount;
|
|
import dan200.computercraft.api.lua.ILuaContext;
|
|
import dan200.computercraft.api.lua.LuaException;
|
|
import dan200.computercraft.api.network.IPacketNetwork;
|
|
import dan200.computercraft.api.network.wired.IWiredNode;
|
|
import dan200.computercraft.api.network.wired.IWiredSender;
|
|
import dan200.computercraft.api.peripheral.IComputerAccess;
|
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
|
import dan200.computercraft.api.peripheral.IWorkMonitor;
|
|
import dan200.computercraft.shared.peripheral.modem.ModemPeripheral;
|
|
import dan200.computercraft.shared.peripheral.modem.ModemState;
|
|
import net.minecraft.world.World;
|
|
|
|
import javax.annotation.Nonnull;
|
|
import javax.annotation.Nullable;
|
|
import java.util.HashMap;
|
|
import java.util.Map;
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
import java.util.concurrent.ConcurrentMap;
|
|
|
|
import static dan200.computercraft.core.apis.ArgumentHelper.getString;
|
|
|
|
public abstract class WiredModemPeripheral extends ModemPeripheral implements IWiredSender
|
|
{
|
|
private final WiredModemElement modem;
|
|
|
|
private final Map<IComputerAccess, ConcurrentMap<String, RemotePeripheralWrapper>> peripheralWrappers = new HashMap<>( 1 );
|
|
|
|
public WiredModemPeripheral( ModemState state, WiredModemElement modem )
|
|
{
|
|
super( state );
|
|
this.modem = modem;
|
|
}
|
|
|
|
//region IPacketSender implementation
|
|
@Override
|
|
public boolean isInterdimensional()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public double getRange()
|
|
{
|
|
return 256.0;
|
|
}
|
|
|
|
@Override
|
|
protected IPacketNetwork getNetwork()
|
|
{
|
|
return modem.getNode();
|
|
}
|
|
|
|
@Nonnull
|
|
@Override
|
|
public World getWorld()
|
|
{
|
|
return modem.getWorld();
|
|
}
|
|
|
|
@Nonnull
|
|
protected abstract WiredModemLocalPeripheral getLocalPeripheral();
|
|
//endregion
|
|
|
|
//region IPeripheral
|
|
@Nonnull
|
|
@Override
|
|
public String[] getMethodNames()
|
|
{
|
|
String[] methods = super.getMethodNames();
|
|
String[] newMethods = new String[methods.length + 6];
|
|
System.arraycopy( methods, 0, newMethods, 0, methods.length );
|
|
newMethods[methods.length] = "getNamesRemote";
|
|
newMethods[methods.length + 1] = "isPresentRemote";
|
|
newMethods[methods.length + 2] = "getTypeRemote";
|
|
newMethods[methods.length + 3] = "getMethodsRemote";
|
|
newMethods[methods.length + 4] = "callRemote";
|
|
newMethods[methods.length + 5] = "getNameLocal";
|
|
return newMethods;
|
|
}
|
|
|
|
@Override
|
|
public Object[] callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
|
|
{
|
|
String[] methods = super.getMethodNames();
|
|
switch( method - methods.length )
|
|
{
|
|
case 0:
|
|
{
|
|
// getNamesRemote
|
|
Map<String, RemotePeripheralWrapper> wrappers = getWrappers( computer );
|
|
Map<Object, Object> table = new HashMap<>();
|
|
if( wrappers != null )
|
|
{
|
|
int idx = 1;
|
|
for( String name : wrappers.keySet() ) table.put( idx++, name );
|
|
}
|
|
return new Object[] { table };
|
|
}
|
|
case 1:
|
|
{
|
|
// isPresentRemote
|
|
String name = getString( arguments, 0 );
|
|
return new Object[] { getWrapper( computer, name ) != null };
|
|
}
|
|
case 2:
|
|
{
|
|
// getTypeRemote
|
|
String name = getString( arguments, 0 );
|
|
RemotePeripheralWrapper wrapper = getWrapper( computer, name );
|
|
return wrapper != null ? new Object[] { wrapper.getType() } : null;
|
|
}
|
|
case 3:
|
|
{
|
|
// getMethodsRemote
|
|
String name = getString( arguments, 0 );
|
|
RemotePeripheralWrapper wrapper = getWrapper( computer, name );
|
|
if( wrapper == null ) return null;
|
|
|
|
String[] methodNames = wrapper.getMethodNames();
|
|
Map<Object, Object> table = new HashMap<>();
|
|
for( int i = 0; i < methodNames.length; i++ )
|
|
{
|
|
table.put( i + 1, methodNames[i] );
|
|
}
|
|
return new Object[] { table };
|
|
}
|
|
case 4:
|
|
{
|
|
// callRemote
|
|
String remoteName = getString( arguments, 0 );
|
|
String methodName = getString( arguments, 1 );
|
|
RemotePeripheralWrapper wrapper = getWrapper( computer, remoteName );
|
|
if( wrapper == null ) throw new LuaException( "No peripheral: " + remoteName );
|
|
|
|
Object[] methodArgs = new Object[arguments.length - 2];
|
|
System.arraycopy( arguments, 2, methodArgs, 0, arguments.length - 2 );
|
|
return wrapper.callMethod( context, methodName, methodArgs );
|
|
}
|
|
case 5:
|
|
{
|
|
// getNameLocal
|
|
String local = getLocalPeripheral().getConnectedName();
|
|
return local == null ? null : new Object[] { local };
|
|
}
|
|
default:
|
|
{
|
|
// The regular modem methods
|
|
return super.callMethod( computer, context, method, arguments );
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void attach( @Nonnull IComputerAccess computer )
|
|
{
|
|
super.attach( computer );
|
|
|
|
ConcurrentMap<String, RemotePeripheralWrapper> wrappers;
|
|
synchronized( peripheralWrappers )
|
|
{
|
|
wrappers = peripheralWrappers.get( computer );
|
|
if( wrappers == null ) peripheralWrappers.put( computer, wrappers = new ConcurrentHashMap<>() );
|
|
}
|
|
|
|
synchronized( modem.getRemotePeripherals() )
|
|
{
|
|
for( Map.Entry<String, IPeripheral> entry : modem.getRemotePeripherals().entrySet() )
|
|
{
|
|
attachPeripheralImpl( computer, wrappers, entry.getKey(), entry.getValue() );
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void detach( @Nonnull IComputerAccess computer )
|
|
{
|
|
Map<String, RemotePeripheralWrapper> wrappers;
|
|
synchronized( peripheralWrappers )
|
|
{
|
|
wrappers = peripheralWrappers.remove( computer );
|
|
}
|
|
if( wrappers != null )
|
|
{
|
|
for( RemotePeripheralWrapper wrapper : wrappers.values() ) wrapper.detach();
|
|
wrappers.clear();
|
|
}
|
|
|
|
super.detach( computer );
|
|
}
|
|
|
|
@Override
|
|
public boolean equals( IPeripheral other )
|
|
{
|
|
if( other instanceof WiredModemPeripheral )
|
|
{
|
|
WiredModemPeripheral otherModem = (WiredModemPeripheral) other;
|
|
return otherModem.modem == modem;
|
|
}
|
|
return false;
|
|
}
|
|
//endregion
|
|
|
|
@Nonnull
|
|
@Override
|
|
public IWiredNode getNode()
|
|
{
|
|
return modem.getNode();
|
|
}
|
|
|
|
public void attachPeripheral( String name, IPeripheral peripheral )
|
|
{
|
|
synchronized( peripheralWrappers )
|
|
{
|
|
for( Map.Entry<IComputerAccess, ConcurrentMap<String, RemotePeripheralWrapper>> entry : peripheralWrappers.entrySet() )
|
|
{
|
|
attachPeripheralImpl( entry.getKey(), entry.getValue(), name, peripheral );
|
|
}
|
|
}
|
|
}
|
|
|
|
public void detachPeripheral( String name )
|
|
{
|
|
synchronized( peripheralWrappers )
|
|
{
|
|
for( ConcurrentMap<String, RemotePeripheralWrapper> wrappers : peripheralWrappers.values() )
|
|
{
|
|
RemotePeripheralWrapper wrapper = wrappers.remove( name );
|
|
if( wrapper != null ) wrapper.detach();
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
private void attachPeripheralImpl( IComputerAccess computer, ConcurrentMap<String, RemotePeripheralWrapper> peripherals, String periphName, IPeripheral peripheral )
|
|
{
|
|
if( !peripherals.containsKey( periphName ) && !periphName.equals( getLocalPeripheral().getConnectedName() ) )
|
|
{
|
|
RemotePeripheralWrapper wrapper = new RemotePeripheralWrapper( modem, peripheral, computer, periphName );
|
|
peripherals.put( periphName, wrapper );
|
|
wrapper.attach();
|
|
}
|
|
}
|
|
|
|
private ConcurrentMap<String, RemotePeripheralWrapper> getWrappers( IComputerAccess computer )
|
|
{
|
|
synchronized( peripheralWrappers )
|
|
{
|
|
return peripheralWrappers.get( computer );
|
|
}
|
|
}
|
|
|
|
private RemotePeripheralWrapper getWrapper( IComputerAccess computer, String remoteName )
|
|
{
|
|
ConcurrentMap<String, RemotePeripheralWrapper> wrappers = getWrappers( computer );
|
|
return wrappers == null ? null : wrappers.get( remoteName );
|
|
}
|
|
|
|
private static class RemotePeripheralWrapper implements IComputerAccess
|
|
{
|
|
private final WiredModemElement m_element;
|
|
private final IPeripheral m_peripheral;
|
|
private final IComputerAccess m_computer;
|
|
private final String m_name;
|
|
|
|
private final String m_type;
|
|
private final String[] m_methods;
|
|
private final Map<String, Integer> m_methodMap;
|
|
|
|
public RemotePeripheralWrapper( WiredModemElement element, IPeripheral peripheral, IComputerAccess computer, String name )
|
|
{
|
|
m_element = element;
|
|
m_peripheral = peripheral;
|
|
m_computer = computer;
|
|
m_name = name;
|
|
|
|
m_type = peripheral.getType();
|
|
m_methods = peripheral.getMethodNames();
|
|
assert (m_type != null);
|
|
assert (m_methods != null);
|
|
|
|
m_methodMap = new HashMap<>();
|
|
for( int i = 0; i < m_methods.length; i++ )
|
|
{
|
|
if( m_methods[i] != null )
|
|
{
|
|
m_methodMap.put( m_methods[i], i );
|
|
}
|
|
}
|
|
}
|
|
|
|
public void attach()
|
|
{
|
|
m_peripheral.attach( this );
|
|
m_computer.queueEvent( "peripheral", new Object[] { getAttachmentName() } );
|
|
}
|
|
|
|
public void detach()
|
|
{
|
|
m_peripheral.detach( this );
|
|
m_computer.queueEvent( "peripheral_detach", new Object[] { getAttachmentName() } );
|
|
}
|
|
|
|
public String getType()
|
|
{
|
|
return m_type;
|
|
}
|
|
|
|
public String[] getMethodNames()
|
|
{
|
|
return m_methods;
|
|
}
|
|
|
|
public Object[] callMethod( ILuaContext context, String methodName, Object[] arguments ) throws LuaException, InterruptedException
|
|
{
|
|
if( m_methodMap.containsKey( methodName ) )
|
|
{
|
|
int method = m_methodMap.get( methodName );
|
|
return m_peripheral.callMethod( this, context, method, arguments );
|
|
}
|
|
throw new LuaException( "No such method " + methodName );
|
|
}
|
|
|
|
// IComputerAccess implementation
|
|
|
|
@Override
|
|
public String mount( @Nonnull String desiredLocation, @Nonnull IMount mount )
|
|
{
|
|
return m_computer.mount( desiredLocation, mount, m_name );
|
|
}
|
|
|
|
@Override
|
|
public String mount( @Nonnull String desiredLocation, @Nonnull IMount mount, @Nonnull String driveName )
|
|
{
|
|
return m_computer.mount( desiredLocation, mount, driveName );
|
|
}
|
|
|
|
@Override
|
|
public String mountWritable( @Nonnull String desiredLocation, @Nonnull IWritableMount mount )
|
|
{
|
|
return m_computer.mountWritable( desiredLocation, mount, m_name );
|
|
}
|
|
|
|
@Override
|
|
public String mountWritable( @Nonnull String desiredLocation, @Nonnull IWritableMount mount, @Nonnull String driveName )
|
|
{
|
|
return m_computer.mountWritable( desiredLocation, mount, driveName );
|
|
}
|
|
|
|
@Override
|
|
public void unmount( String location )
|
|
{
|
|
m_computer.unmount( location );
|
|
}
|
|
|
|
@Override
|
|
public int getID()
|
|
{
|
|
return m_computer.getID();
|
|
}
|
|
|
|
@Override
|
|
public void queueEvent( @Nonnull String event, Object[] arguments )
|
|
{
|
|
m_computer.queueEvent( event, arguments );
|
|
}
|
|
|
|
@Nullable
|
|
@Override
|
|
public IWorkMonitor getMainThreadMonitor()
|
|
{
|
|
return m_computer.getMainThreadMonitor();
|
|
}
|
|
|
|
@Nonnull
|
|
@Override
|
|
public String getAttachmentName()
|
|
{
|
|
return m_name;
|
|
}
|
|
|
|
@Nonnull
|
|
@Override
|
|
public Map<String, IPeripheral> getAvailablePeripherals()
|
|
{
|
|
synchronized( m_element.getRemotePeripherals() )
|
|
{
|
|
return ImmutableMap.copyOf( m_element.getRemotePeripherals() );
|
|
}
|
|
}
|
|
|
|
@Nullable
|
|
@Override
|
|
public IPeripheral getAvailablePeripheral( @Nonnull String name )
|
|
{
|
|
synchronized( m_element.getRemotePeripherals() )
|
|
{
|
|
return m_element.getRemotePeripherals().get( name );
|
|
}
|
|
}
|
|
}
|
|
}
|