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/ModemPeripheral.java
Daniel Ratcliffe 7d497f2835 ComputerCraft 1.80pr0
Updated the source code to the version shipped as the 1.80pr0 alpha
release. Also removed some unnecessary files from the LuaJ subfolder
which were bulking up the repository.
2017-05-01 14:51:26 +01:00

407 lines
9.3 KiB
Java

/**
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.peripheral.modem;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.peripheral.IComputerAccess;
import dan200.computercraft.api.peripheral.IPeripheral;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public abstract class ModemPeripheral
implements IPeripheral
{
private static class SingleChannelReceiver implements IReceiver
{
private ModemPeripheral m_owner;
private int m_channel;
public SingleChannelReceiver( ModemPeripheral owner, int channel )
{
m_owner = owner;
m_channel = channel;
}
// IReceiver implementation
@Override
public int getChannel()
{
return m_channel;
}
@Override
public World getWorld()
{
return m_owner.getWorld();
}
@Override
public Vec3d getWorldPosition()
{
return m_owner.getWorldPosition();
}
@Override
public boolean isInterdimensional()
{
return m_owner.isInterdimensional();
}
@Override
public double getReceiveRange()
{
return m_owner.getReceiveRange();
}
@Override
public void receiveSameDimension( int replyChannel, Object payload, double distance, Object senderObject )
{
if( senderObject != m_owner )
{
m_owner.receiveSameDimension( m_channel, replyChannel, payload, distance );
}
}
@Override
public void receiveDifferentDimension( int replyChannel, Object payload, Object senderObject )
{
if( senderObject != m_owner )
{
m_owner.receiveDifferentDimension( m_channel, replyChannel, payload );
}
}
}
private INetwork m_network;
private IComputerAccess m_computer;
private Map<Integer, IReceiver> m_channels;
private boolean m_open;
private boolean m_changed;
public ModemPeripheral()
{
m_network = null;
m_computer = null;
m_channels = new HashMap<Integer, IReceiver>();
m_open = false;
m_changed = true;
}
private synchronized void setNetwork( INetwork network )
{
if( m_network != network )
{
// Leave old network
if( m_network != null )
{
Iterator<IReceiver> it = m_channels.values().iterator();
while( it.hasNext() )
{
m_network.removeReceiver( it.next() );
}
}
// Set new network
m_network = network;
// Join new network
if( m_network != null )
{
Iterator<IReceiver> it = m_channels.values().iterator();
while( it.hasNext() )
{
m_network.addReceiver( it.next() );
}
}
}
}
protected void switchNetwork()
{
setNetwork( getNetwork() );
}
protected abstract World getWorld();
protected abstract Vec3d getPosition();
public synchronized void destroy()
{
setNetwork( null );
m_channels.clear();
m_open = false;
}
public synchronized boolean pollChanged()
{
if( m_changed )
{
m_changed = false;
return true;
}
return false;
}
protected abstract double getTransmitRange();
protected abstract boolean isInterdimensional();
public synchronized boolean isActive()
{
return (m_computer != null) && m_open;
}
public synchronized Vec3d getWorldPosition()
{
return getPosition();
}
public synchronized double getReceiveRange()
{
return getTransmitRange();
}
public void receiveSameDimension( int channel, int replyChannel, Object payload, double distance )
{
synchronized (m_channels)
{
if( m_computer != null && m_channels.containsKey( channel ) )
{
m_computer.queueEvent( "modem_message", new Object[] {
m_computer.getAttachmentName(), channel, replyChannel, payload, distance
} );
}
}
}
public void receiveDifferentDimension( int channel, int replyChannel, Object payload )
{
synchronized (m_channels)
{
if( m_computer != null && m_channels.containsKey( channel ) )
{
m_computer.queueEvent( "modem_message", new Object[] {
m_computer.getAttachmentName(), channel, replyChannel, payload
} );
}
}
}
protected abstract INetwork getNetwork();
// IPeripheral implementation
@Override
public String getType()
{
return "modem";
}
@Override
public String[] getMethodNames()
{
return new String[] {
"open",
"isOpen",
"close",
"closeAll",
"transmit",
"isWireless",
};
}
private static int parseChannel( Object[] arguments, int index ) throws LuaException
{
if( arguments.length <= index || !(arguments[index] instanceof Double) )
{
throw new LuaException( "Expected number" );
}
int channel = (int)((Double)arguments[index]).doubleValue();
if( channel < 0 || channel > 65535 )
{
throw new LuaException( "Expected number in range 0-65535" );
}
return channel;
}
@Override
public Object[] callMethod( IComputerAccess computer, ILuaContext context, int method, Object[] arguments ) throws LuaException, InterruptedException
{
switch( method )
{
case 0:
{
// open
int channel = parseChannel( arguments, 0 );
synchronized( this )
{
if( !m_channels.containsKey( channel ) )
{
if( m_channels.size() >= 128 )
{
throw new LuaException( "Too many open channels" );
}
IReceiver receiver = new SingleChannelReceiver( this, channel );
m_channels.put( channel, receiver );
if( m_network != null )
{
m_network.addReceiver( receiver );
}
if( !m_open )
{
m_open = true;
m_changed = true;
}
}
}
return null;
}
case 1:
{
// isOpen
int channel = parseChannel( arguments, 0 );
synchronized( this )
{
boolean open = m_channels.containsKey( channel );
return new Object[] { open };
}
}
case 2:
{
// close
int channel = parseChannel( arguments, 0 );
synchronized( this )
{
if( m_channels.containsKey( channel ) )
{
IReceiver receiver = m_channels.get( channel );
if( m_network != null )
{
m_network.removeReceiver( receiver );
}
m_channels.remove( channel );
if( m_channels.size() == 0 )
{
m_open = false;
m_changed = true;
}
}
}
return null;
}
case 3:
{
// closeAll
synchronized( this )
{
if( m_channels.size() > 0 )
{
if( m_network != null )
{
Iterator<IReceiver> it = m_channels.values().iterator();
while( it.hasNext() )
{
m_network.removeReceiver( it.next() );
}
}
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 )
{
World world = getWorld();
Vec3d position = getPosition();
if( world != null && position != null && m_network != null)
{
m_network.transmit( channel, replyChannel, payload, world, position, getTransmitRange(), isInterdimensional(), this );
}
}
return null;
}
case 5:
{
// isWireless
synchronized( this )
{
if( m_network != null )
{
return new Object[] { m_network.isWireless() };
}
}
return new Object[] { false };
}
default:
{
return null;
}
}
}
@Override
public synchronized void attach( IComputerAccess computer )
{
m_computer = computer;
setNetwork( getNetwork() );
m_open = !m_channels.isEmpty();
}
@Override
public synchronized void detach( IComputerAccess computer )
{
if( m_network != null )
{
Iterator<IReceiver> it = m_channels.values().iterator();
while( it.hasNext() )
{
m_network.removeReceiver( it.next() );
}
m_channels.clear();
m_network = null;
}
m_computer = null;
if( m_open )
{
m_open = false;
m_changed = true;
}
}
@Override
public abstract boolean equals( IPeripheral other );
public IComputerAccess getComputer()
{
return m_computer;
}
}