1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2024-06-26 07:03:22 +00:00
CC-Tweaked/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java
SquidDev 5d05205d69 Introduce IWorkMonitor into the public API
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.
2019-03-26 11:21:16 +00:00

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