2017-05-07 00:18:59 +00:00
|
|
|
/*
|
2017-05-01 13:32:39 +00:00
|
|
|
* This file is part of ComputerCraft - http://www.computercraft.info
|
2017-05-13 18:20:39 +00:00
|
|
|
* Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
|
2017-05-01 13:32:39 +00:00
|
|
|
* Send enquiries to dratcliffe@gmail.com
|
|
|
|
*/
|
|
|
|
|
|
|
|
package dan200.computercraft.shared.peripheral.modem;
|
|
|
|
|
|
|
|
import dan200.computercraft.api.lua.ILuaContext;
|
|
|
|
import dan200.computercraft.api.lua.LuaException;
|
2017-05-06 20:19:55 +00:00
|
|
|
import dan200.computercraft.api.network.IPacketNetwork;
|
|
|
|
import dan200.computercraft.api.network.IPacketReceiver;
|
|
|
|
import dan200.computercraft.api.network.IPacketSender;
|
|
|
|
import dan200.computercraft.api.network.Packet;
|
2017-05-01 13:32:39 +00:00
|
|
|
import dan200.computercraft.api.peripheral.IComputerAccess;
|
|
|
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
2017-05-06 20:19:55 +00:00
|
|
|
import gnu.trove.set.TIntSet;
|
|
|
|
import gnu.trove.set.hash.TIntHashSet;
|
2017-05-01 13:51:26 +00:00
|
|
|
import net.minecraft.util.math.Vec3d;
|
2017-05-01 13:32:39 +00:00
|
|
|
import net.minecraft.world.World;
|
|
|
|
|
2017-05-06 23:07:42 +00:00
|
|
|
import javax.annotation.Nonnull;
|
2017-05-01 13:32:39 +00:00
|
|
|
|
2017-06-12 09:28:31 +00:00
|
|
|
import static dan200.computercraft.core.apis.ArgumentHelper.getInt;
|
|
|
|
|
2017-05-01 13:32:39 +00:00
|
|
|
public abstract class ModemPeripheral
|
2017-05-06 20:19:55 +00:00
|
|
|
implements IPeripheral, IPacketSender, IPacketReceiver
|
|
|
|
{
|
|
|
|
private IPacketNetwork m_network;
|
2017-05-01 14:48:44 +00:00
|
|
|
private IComputerAccess m_computer;
|
2017-05-06 20:19:55 +00:00
|
|
|
private final TIntSet m_channels;
|
2017-05-01 13:32:39 +00:00
|
|
|
|
2017-05-01 14:48:44 +00:00
|
|
|
private boolean m_open;
|
|
|
|
private boolean m_changed;
|
2017-05-01 13:32:39 +00:00
|
|
|
|
|
|
|
public ModemPeripheral()
|
|
|
|
{
|
|
|
|
m_network = null;
|
|
|
|
m_computer = null;
|
2017-05-06 20:19:55 +00:00
|
|
|
m_channels = new TIntHashSet();
|
2017-05-01 13:32:39 +00:00
|
|
|
m_open = false;
|
|
|
|
m_changed = true;
|
|
|
|
}
|
|
|
|
|
2017-05-06 20:19:55 +00:00
|
|
|
private synchronized void setNetwork( IPacketNetwork network )
|
2017-05-01 13:32:39 +00:00
|
|
|
{
|
|
|
|
if( m_network != network )
|
|
|
|
{
|
|
|
|
// Leave old network
|
|
|
|
if( m_network != null )
|
|
|
|
{
|
2017-05-06 20:19:55 +00:00
|
|
|
m_network.removeReceiver( this );
|
2017-05-01 13:32:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Set new network
|
|
|
|
m_network = network;
|
|
|
|
|
|
|
|
// Join new network
|
|
|
|
if( m_network != null )
|
|
|
|
{
|
2017-05-06 20:19:55 +00:00
|
|
|
m_network.addReceiver( this );
|
2017-05-01 13:32:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected void switchNetwork()
|
|
|
|
{
|
|
|
|
setNetwork( getNetwork() );
|
|
|
|
}
|
|
|
|
|
|
|
|
public synchronized void destroy()
|
|
|
|
{
|
|
|
|
setNetwork( null );
|
|
|
|
m_channels.clear();
|
|
|
|
m_open = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
public synchronized boolean pollChanged()
|
|
|
|
{
|
2017-05-01 14:48:44 +00:00
|
|
|
if( m_changed )
|
|
|
|
{
|
|
|
|
m_changed = false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2017-05-01 13:32:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public synchronized boolean isActive()
|
2017-05-01 14:48:44 +00:00
|
|
|
{
|
|
|
|
return (m_computer != null) && m_open;
|
|
|
|
}
|
2017-05-01 13:32:39 +00:00
|
|
|
|
2017-05-06 20:19:55 +00:00
|
|
|
@Override
|
|
|
|
public void receiveSameDimension( @Nonnull Packet packet, double distance )
|
2017-05-01 14:48:44 +00:00
|
|
|
{
|
2017-05-06 20:19:55 +00:00
|
|
|
if( packet.getSender() == this ) return;
|
|
|
|
|
2017-05-01 14:48:44 +00:00
|
|
|
synchronized (m_channels)
|
|
|
|
{
|
2017-05-06 20:19:55 +00:00
|
|
|
if( m_computer != null && m_channels.contains( packet.getChannel() ) )
|
2017-05-01 14:48:44 +00:00
|
|
|
{
|
|
|
|
m_computer.queueEvent( "modem_message", new Object[] {
|
2017-05-06 20:19:55 +00:00
|
|
|
m_computer.getAttachmentName(), packet.getChannel(), packet.getReplyChannel(), packet.getPayload(), distance
|
2017-05-01 14:48:44 +00:00
|
|
|
} );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-05-01 13:32:39 +00:00
|
|
|
|
2017-05-06 20:19:55 +00:00
|
|
|
@Override
|
|
|
|
public void receiveDifferentDimension( @Nonnull Packet packet )
|
2017-05-01 13:32:39 +00:00
|
|
|
{
|
2017-05-06 20:19:55 +00:00
|
|
|
if( packet.getSender() == this ) return;
|
|
|
|
|
2017-05-01 13:32:39 +00:00
|
|
|
synchronized (m_channels)
|
|
|
|
{
|
2017-05-06 20:19:55 +00:00
|
|
|
if( m_computer != null && m_channels.contains( packet.getChannel() ) )
|
2017-05-01 13:32:39 +00:00
|
|
|
{
|
|
|
|
m_computer.queueEvent( "modem_message", new Object[] {
|
2017-05-06 20:19:55 +00:00
|
|
|
m_computer.getAttachmentName(), packet.getChannel(), packet.getReplyChannel(), packet.getPayload()
|
2017-05-01 13:32:39 +00:00
|
|
|
} );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-06 20:19:55 +00:00
|
|
|
protected abstract IPacketNetwork getNetwork();
|
2017-05-01 13:32:39 +00:00
|
|
|
|
2017-05-01 14:48:44 +00:00
|
|
|
// IPeripheral implementation
|
2017-05-01 13:32:39 +00:00
|
|
|
|
2017-05-06 23:07:42 +00:00
|
|
|
@Nonnull
|
2017-05-01 14:48:44 +00:00
|
|
|
@Override
|
2017-05-01 13:32:39 +00:00
|
|
|
public String getType()
|
|
|
|
{
|
2017-05-01 14:48:44 +00:00
|
|
|
return "modem";
|
2017-05-01 13:32:39 +00:00
|
|
|
}
|
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
|
2017-05-01 13:32:39 +00:00
|
|
|
public String[] getMethodNames()
|
|
|
|
{
|
2017-05-01 14:48:44 +00:00
|
|
|
return new String[] {
|
|
|
|
"open",
|
|
|
|
"isOpen",
|
|
|
|
"close",
|
|
|
|
"closeAll",
|
|
|
|
"transmit",
|
|
|
|
"isWireless",
|
|
|
|
};
|
2017-05-01 13:32:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private static int parseChannel( Object[] arguments, int index ) throws LuaException
|
|
|
|
{
|
2017-06-12 09:28:31 +00:00
|
|
|
int channel = getInt( arguments, index );
|
2017-05-01 14:48:44 +00:00
|
|
|
if( channel < 0 || channel > 65535 )
|
|
|
|
{
|
|
|
|
throw new LuaException( "Expected number in range 0-65535" );
|
|
|
|
}
|
|
|
|
return channel;
|
2017-05-01 13:32:39 +00:00
|
|
|
}
|
|
|
|
|
2017-05-01 14:48:44 +00:00
|
|
|
@Override
|
2017-05-06 23:07:42 +00:00
|
|
|
public Object[] callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
|
2017-05-01 13:32:39 +00:00
|
|
|
{
|
2017-05-01 14:48:44 +00:00
|
|
|
switch( method )
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
{
|
|
|
|
// open
|
|
|
|
int channel = parseChannel( arguments, 0 );
|
|
|
|
synchronized( this )
|
|
|
|
{
|
2017-05-06 20:19:55 +00:00
|
|
|
if( !m_channels.contains( channel ) )
|
2017-05-01 14:48:44 +00:00
|
|
|
{
|
|
|
|
if( m_channels.size() >= 128 )
|
|
|
|
{
|
|
|
|
throw new LuaException( "Too many open channels" );
|
|
|
|
}
|
2017-05-06 20:19:55 +00:00
|
|
|
|
|
|
|
m_channels.add( channel );
|
2017-05-01 14:48:44 +00:00
|
|
|
if( !m_open )
|
|
|
|
{
|
|
|
|
m_open = true;
|
|
|
|
m_changed = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
case 1:
|
|
|
|
{
|
|
|
|
// isOpen
|
|
|
|
int channel = parseChannel( arguments, 0 );
|
|
|
|
synchronized( this )
|
|
|
|
{
|
2017-05-06 20:19:55 +00:00
|
|
|
boolean open = m_channels.contains( channel );
|
2017-05-01 14:48:44 +00:00
|
|
|
return new Object[] { open };
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case 2:
|
|
|
|
{
|
|
|
|
// close
|
|
|
|
int channel = parseChannel( arguments, 0 );
|
|
|
|
synchronized( this )
|
|
|
|
{
|
2017-05-06 20:19:55 +00:00
|
|
|
if( m_channels.remove( channel ) )
|
2017-05-01 14:48:44 +00:00
|
|
|
{
|
|
|
|
if( m_channels.size() == 0 )
|
|
|
|
{
|
|
|
|
m_open = false;
|
|
|
|
m_changed = true;
|
2017-05-01 13:32:39 +00:00
|
|
|
}
|
2017-05-01 14:48:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
case 3:
|
|
|
|
{
|
|
|
|
// closeAll
|
|
|
|
synchronized( this )
|
|
|
|
{
|
|
|
|
if( m_channels.size() > 0 )
|
|
|
|
{
|
|
|
|
m_channels.clear();
|
|
|
|
|
|
|
|
if( m_open )
|
|
|
|
{
|
|
|
|
m_open = false;
|
|
|
|
m_changed = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
case 4:
|
|
|
|
{
|
|
|
|
// transmit
|
|
|
|
int channel = parseChannel( arguments, 0 );
|
|
|
|
int replyChannel = parseChannel( arguments, 1 );
|
|
|
|
Object payload = (arguments.length >= 3) ? arguments[2] : null;
|
|
|
|
synchronized( this )
|
|
|
|
{
|
2017-05-01 13:32:39 +00:00
|
|
|
World world = getWorld();
|
2017-05-01 14:48:44 +00:00
|
|
|
Vec3d position = getPosition();
|
2017-05-01 13:32:39 +00:00
|
|
|
if( world != null && position != null && m_network != null)
|
|
|
|
{
|
2017-05-18 22:50:14 +00:00
|
|
|
Packet packet = new Packet( channel, replyChannel, payload, this );
|
|
|
|
if( isInterdimensional() )
|
|
|
|
{
|
|
|
|
m_network.transmitInterdimensional( packet );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_network.transmitSameDimension( packet, getRange() );
|
|
|
|
}
|
2017-05-01 13:32:39 +00:00
|
|
|
}
|
2017-05-01 14:48:44 +00:00
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
case 5:
|
|
|
|
{
|
|
|
|
// isWireless
|
2017-05-01 13:32:39 +00:00
|
|
|
synchronized( this )
|
|
|
|
{
|
|
|
|
if( m_network != null )
|
|
|
|
{
|
|
|
|
return new Object[] { m_network.isWireless() };
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return new Object[] { false };
|
2017-05-01 14:48:44 +00:00
|
|
|
}
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
2017-05-01 13:32:39 +00:00
|
|
|
}
|
|
|
|
|
2017-05-01 14:48:44 +00:00
|
|
|
@Override
|
2017-05-06 23:07:42 +00:00
|
|
|
public synchronized void attach( @Nonnull IComputerAccess computer )
|
2017-05-01 13:32:39 +00:00
|
|
|
{
|
2017-05-01 14:48:44 +00:00
|
|
|
m_computer = computer;
|
|
|
|
setNetwork( getNetwork() );
|
|
|
|
m_open = !m_channels.isEmpty();
|
2017-05-01 13:32:39 +00:00
|
|
|
}
|
|
|
|
|
2017-05-01 14:48:44 +00:00
|
|
|
@Override
|
2017-05-06 23:07:42 +00:00
|
|
|
public synchronized void detach( @Nonnull IComputerAccess computer )
|
2017-05-01 13:32:39 +00:00
|
|
|
{
|
2017-05-01 14:48:44 +00:00
|
|
|
if( m_network != null )
|
|
|
|
{
|
2017-05-06 20:19:55 +00:00
|
|
|
m_network.removeReceiver( this );
|
2017-05-01 14:48:44 +00:00
|
|
|
m_channels.clear();
|
|
|
|
m_network = null;
|
|
|
|
}
|
2017-05-01 13:32:39 +00:00
|
|
|
|
2017-05-01 14:48:44 +00:00
|
|
|
m_computer = null;
|
|
|
|
|
|
|
|
if( m_open )
|
|
|
|
{
|
|
|
|
m_open = false;
|
|
|
|
m_changed = true;
|
|
|
|
}
|
2017-05-01 13:32:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public IComputerAccess getComputer()
|
|
|
|
{
|
2017-05-01 14:48:44 +00:00
|
|
|
return m_computer;
|
2017-05-01 13:32:39 +00:00
|
|
|
}
|
2017-05-06 20:19:55 +00:00
|
|
|
|
|
|
|
@Nonnull
|
|
|
|
@Override
|
|
|
|
public String getSenderID()
|
|
|
|
{
|
|
|
|
if( m_computer == null )
|
|
|
|
{
|
|
|
|
return "unknown";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return m_computer.getID() + "_" + m_computer.getAttachmentName();
|
|
|
|
}
|
|
|
|
}
|
2017-05-01 13:32:39 +00:00
|
|
|
}
|