diff --git a/src/main/java/dan200/computercraft/ComputerCraft.java b/src/main/java/dan200/computercraft/ComputerCraft.java index 6607de8d8..10b255db3 100644 --- a/src/main/java/dan200/computercraft/ComputerCraft.java +++ b/src/main/java/dan200/computercraft/ComputerCraft.java @@ -11,6 +11,7 @@ import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.filesystem.IWritableMount; import dan200.computercraft.api.media.IMedia; import dan200.computercraft.api.media.IMediaProvider; +import dan200.computercraft.api.network.IPacketNetwork; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheralProvider; import dan200.computercraft.api.permissions.ITurtlePermissionProvider; @@ -736,6 +737,11 @@ public class ComputerCraft return upgrades; } + public IPacketNetwork getWirelessNetwork() + { + return WirelessNetwork.getUniversal(); + } + public static int createUniqueNumberedSaveDir( World world, String parentSubPath ) { return IDAssigner.getNextIDFromDirectory(new File(getWorldDir(world), parentSubPath)); diff --git a/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java b/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java index c32b00085..f1a33b15d 100644 --- a/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java +++ b/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java @@ -10,6 +10,7 @@ import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.filesystem.IWritableMount; import dan200.computercraft.api.media.IMedia; import dan200.computercraft.api.media.IMediaProvider; +import dan200.computercraft.api.network.IPacketNetwork; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheralProvider; @@ -289,6 +290,27 @@ public final class ComputerCraftAPI } } + /** + * Attempt to get the game-wide wireless network. + * + * @return The global wireless network, or {@code null} if it could not be fetched. + */ + public static IPacketNetwork getWirelessNetwork() + { + findCC(); + if( computerCraft_getWirelessNetwork != null ) + { + try + { + return (IPacketNetwork) computerCraft_getWirelessNetwork.invoke( null ); + } catch (Exception e) { + // It failed; + } + } + + return null; + } + // The functions below here are private, and are used to interface with the non-API ComputerCraft classes. // Reflection is used here so you can develop your mod without decompiling ComputerCraft and including // it in your solution, and so your mod won't crash if ComputerCraft is installed. @@ -330,6 +352,8 @@ public final class ComputerCraftAPI computerCraft_registerPocketUpgrade = findCCMethod( "registerPocketUpgrade", new Class[] { IPocketUpgrade.class } ); + computerCraft_getWirelessNetwork = findCCMethod( "getWirelessNetwork", new Class[] { + } ); } catch( Exception e ) { System.out.println( "ComputerCraftAPI: ComputerCraft not found." ); } finally { @@ -365,4 +389,5 @@ public final class ComputerCraftAPI private static Method computerCraft_registerMediaProvider = null; private static Method computerCraft_registerPermissionProvider = null; private static Method computerCraft_registerPocketUpgrade = null; + private static Method computerCraft_getWirelessNetwork = null; } diff --git a/src/main/java/dan200/computercraft/api/network/IPacketNetwork.java b/src/main/java/dan200/computercraft/api/network/IPacketNetwork.java new file mode 100644 index 000000000..4b07e0ee7 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/network/IPacketNetwork.java @@ -0,0 +1,58 @@ +/* + * 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.api.network; + +import javax.annotation.Nonnull; + +/** + * A packet network represents a collection of devices which can send and receive packets. + * + * @see Packet + * @see IPacketReceiver + */ +public interface IPacketNetwork +{ + /** + * Add a receiver to the network. + * + * @param receiver The receiver to register to the network. + */ + void addReceiver( @Nonnull IPacketReceiver receiver ); + + /** + * Remove a receiver from the network. + * + * @param receiver The device to remove from the network. + */ + void removeReceiver( @Nonnull IPacketReceiver receiver ); + + /** + * Determine whether this network is wireless. + * + * @return Whether this network is wireless. + */ + boolean isWireless(); + + /** + * Submit a packet for transmitting across the network. This will route the packet through the network, sending it + * to all receivers within range (or any interdimensional ones). + * + * @param packet The packet to send. + * @see #transmitInterdimensional(Packet) + * @see IPacketReceiver#receiveSameDimension(Packet, double) + */ + void transmitSameDimension( @Nonnull Packet packet, double range ); + + /** + * Submit a packet for transmitting across the network. This will route the packet through the network, sending it + * to all receivers across all dimensions. + * + * @param packet The packet to send. + * @see #transmitSameDimension(Packet, double) + * @see IPacketReceiver#receiveDifferentDimension(Packet) + */ + void transmitInterdimensional( @Nonnull Packet packet ); +} diff --git a/src/main/java/dan200/computercraft/api/network/IPacketReceiver.java b/src/main/java/dan200/computercraft/api/network/IPacketReceiver.java new file mode 100644 index 000000000..58a0b7e2f --- /dev/null +++ b/src/main/java/dan200/computercraft/api/network/IPacketReceiver.java @@ -0,0 +1,84 @@ +/* + * 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.api.network; + +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +import javax.annotation.Nonnull; + +/** + * An object on an {@link IPacketNetwork}, capable of receiving packets. + */ +public interface IPacketReceiver +{ + /** + * Get the world in which this packet receiver exists. + * + * @return The receivers's world. + */ + @Nonnull + World getWorld(); + + /** + * Get the position in the world at which this receiver exists. + * + * @return The receiver's position. + */ + @Nonnull + Vec3d getPosition(); + + /** + * Get the maximum distance this receiver can send and receive messages. + * + * When determining whether a receiver can receive a message, the largest distance of the packet and receiver is + * used - ensuring it is within range. If the packet or receiver is inter-dimensional, then the packet will always + * be received. + * + * @return The maximum distance this device can send and receive messages. + * @see #isInterdimensional() + * @see #receiveSameDimension(Packet packet, double) + * @see IPacketNetwork#transmitInterdimensional(Packet) + */ + double getRange(); + + /** + * Determine whether this receiver can receive packets from other dimensions. + * + * A device will receive an inter-dimensional packet if either it or the sending device is inter-dimensional. + * + * @return Whether this receiver receives packets from other dimensions. + * @see #getRange() + * @see #receiveDifferentDimension(Packet) + * @see IPacketNetwork#transmitInterdimensional(Packet) + */ + boolean isInterdimensional(); + + /** + * Receive a network packet from the same dimension. + * + * @param packet The packet to receive. Generally you should check that you are listening on the given channel and, + * if so, queue the appropriate modem event. + * @param distance The distance this packet has travelled from the source. + * @see Packet + * @see #getRange() + * @see IPacketNetwork#transmitSameDimension(Packet, double) + * @see IPacketNetwork#transmitInterdimensional(Packet) + */ + void receiveSameDimension( @Nonnull Packet packet, double distance ); + + /** + * Receive a network packet from a different dimension. + * + * @param packet The packet to receive. Generally you should check that you are listening on the given channel and, + * if so, queue the appropriate modem event. + * @see Packet + * @see IPacketNetwork#transmitInterdimensional(Packet) + * @see IPacketNetwork#transmitSameDimension(Packet, double) + * @see #isInterdimensional() + */ + void receiveDifferentDimension( @Nonnull Packet packet ); +} diff --git a/src/main/java/dan200/computercraft/api/network/IPacketSender.java b/src/main/java/dan200/computercraft/api/network/IPacketSender.java new file mode 100644 index 000000000..777c23f7d --- /dev/null +++ b/src/main/java/dan200/computercraft/api/network/IPacketSender.java @@ -0,0 +1,42 @@ +/* + * 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.api.network; + +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +import javax.annotation.Nonnull; + +/** + * An object on a {@link IPacketNetwork}, capable of sending packets. + */ +public interface IPacketSender +{ + /** + * Get the world in which this packet sender exists. + * + * @return The sender's world. + */ + @Nonnull + World getWorld(); + + /** + * Get the position in the world at which this sender exists. + * + * @return The sender's position. + */ + @Nonnull + Vec3d getPosition(); + + /** + * Get some sort of identification string for this sender. This does not strictly need to be unique, but you + * should be able to extract some identifiable information from it. + * + * @return This device's id. + */ + @Nonnull + String getSenderID(); +} diff --git a/src/main/java/dan200/computercraft/api/network/Packet.java b/src/main/java/dan200/computercraft/api/network/Packet.java new file mode 100644 index 000000000..070ce5a01 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/network/Packet.java @@ -0,0 +1,118 @@ +/* + * 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.api.network; + +import com.google.common.base.Preconditions; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * Represents a packet which may be sent across a {@link IPacketNetwork}. + * + * @see IPacketSender + * @see IPacketNetwork#transmitSameDimension(Packet, double) + * @see IPacketNetwork#transmitInterdimensional(Packet) + * @see IPacketReceiver#receiveDifferentDimension(Packet) + * @see IPacketReceiver#receiveSameDimension(Packet, double) + */ +public class Packet +{ + private final int m_channel; + private final int m_replyChannel; + private final Object m_payload; + + private final IPacketSender m_sender; + + /** + * Create a new packet, ready for transmitting across the network. + * + * @param channel The channel to send the packet along. Receiving devices should only process packets from on + * channels they are listening to. + * @param replyChannel The channel to reply on. + * @param payload The contents of this packet. This should be a "valid" Lua object, safe for queuing as an + * event or returning from a peripheral call. + * @param sender The object which sent this packet. + */ + public Packet( int channel, int replyChannel, @Nullable Object payload, @Nonnull IPacketSender sender ) + { + Preconditions.checkNotNull( sender, "sender cannot be null" ); + + m_channel = channel; + m_replyChannel = replyChannel; + m_payload = payload; + m_sender = sender; + } + + /** + * Get the channel this packet is sent along. Receivers should generally only process packets from on channels they + * are listening to. + * + * @return This packet's channel. + */ + public int getChannel() + { + return m_channel; + } + + /** + * The channel to reply on. Objects which will reply should send it along this channel. + * + * @return This channel to reply on. + */ + public int getReplyChannel() + { + return m_replyChannel; + } + + /** + * The actual data of this packet. This should be a "valid" Lua object, safe for queuing as an + * event or returning from a peripheral call. + * + * @return The packet's payload + */ + @Nullable + public Object getPayload() + { + return m_payload; + } + + /** + * The object which sent this message. + * + * @return The sending object. + */ + @Nonnull + public IPacketSender getSender() + { + return m_sender; + } + + @Override + public boolean equals( Object o ) + { + if( this == o ) return true; + if( o == null || getClass() != o.getClass() ) return false; + + Packet packet = (Packet) o; + + if( m_channel != packet.m_channel ) return false; + if( m_replyChannel != packet.m_replyChannel ) return false; + if( m_payload != null ? !m_payload.equals( packet.m_payload ) : packet.m_payload != null ) return false; + return m_sender.equals( packet.m_sender ); + } + + @Override + public int hashCode() + { + int result; + result = m_channel; + result = 31 * result + m_replyChannel; + result = 31 * result + (m_payload != null ? m_payload.hashCode() : 0); + result = 31 * result + m_sender.hashCode(); + return result; + } +} diff --git a/src/main/java/dan200/computercraft/api/network/package-info.java b/src/main/java/dan200/computercraft/api/network/package-info.java new file mode 100644 index 000000000..c445f4474 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/network/package-info.java @@ -0,0 +1,10 @@ +/* + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +@API( owner="ComputerCraft", provides="ComputerCraft|API|Network", apiVersion="${version}" ) +package dan200.computercraft.api.network; + +import net.minecraftforge.fml.common.API; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/INetwork.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/INetwork.java deleted file mode 100644 index 133324d3e..000000000 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/INetwork.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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.shared.peripheral.modem; - -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.World; - -public interface INetwork -{ - void addReceiver( IReceiver receiver ); - void removeReceiver( IReceiver receiver ); - void transmit( int channel, int replyChannel, Object payload, World world, Vec3d pos, double range, boolean interdimensional, Object senderObject ); - boolean isWireless(); -} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/IReceiver.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/IReceiver.java deleted file mode 100644 index 0849ab6d3..000000000 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/IReceiver.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * 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.shared.peripheral.modem; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.World; - -public interface IReceiver -{ - int getChannel(); - World getWorld(); - Vec3d getWorldPosition(); - boolean isInterdimensional(); - double getReceiveRange(); - void receiveSameDimension( int replyChannel, Object payload, double distance, Object senderObject ); - void receiveDifferentDimension( int replyChannel, Object payload, Object senderObject ); -} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java index ebef94f8c..c5daff739 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java @@ -8,83 +8,25 @@ package dan200.computercraft.shared.peripheral.modem; import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.network.IPacketNetwork; +import dan200.computercraft.api.network.IPacketReceiver; +import dan200.computercraft.api.network.IPacketSender; +import dan200.computercraft.api.network.Packet; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; +import gnu.trove.set.TIntSet; +import gnu.trove.set.hash.TIntHashSet; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import javax.annotation.Nonnull; -import java.util.HashMap; -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; + implements IPeripheral, IPacketSender, IPacketReceiver +{ + private IPacketNetwork m_network; private IComputerAccess m_computer; - private final Map m_channels; + private final TIntSet m_channels; private boolean m_open; private boolean m_changed; @@ -93,23 +35,19 @@ public abstract class ModemPeripheral { m_network = null; m_computer = null; - - m_channels = new HashMap(); + m_channels = new TIntHashSet(); m_open = false; m_changed = true; } - private synchronized void setNetwork( INetwork network ) + private synchronized void setNetwork( IPacketNetwork network ) { if( m_network != network ) { // Leave old network if( m_network != null ) { - for( IReceiver iReceiver : m_channels.values() ) - { - m_network.removeReceiver( iReceiver ); - } + m_network.removeReceiver( this ); } // Set new network @@ -118,10 +56,7 @@ public abstract class ModemPeripheral // Join new network if( m_network != null ) { - for( IReceiver iReceiver : m_channels.values() ) - { - m_network.addReceiver( iReceiver ); - } + m_network.addReceiver( this ); } } } @@ -131,10 +66,6 @@ public abstract class ModemPeripheral setNetwork( getNetwork() ); } - protected abstract World getWorld(); - - protected abstract Vec3d getPosition(); - public synchronized void destroy() { setNetwork( null ); @@ -151,53 +82,45 @@ public abstract class ModemPeripheral } 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 ) + @Override + public void receiveSameDimension( @Nonnull Packet packet, double distance ) { + if( packet.getSender() == this ) return; + synchronized (m_channels) { - if( m_computer != null && m_channels.containsKey( channel ) ) + if( m_computer != null && m_channels.contains( packet.getChannel() ) ) { m_computer.queueEvent( "modem_message", new Object[] { - m_computer.getAttachmentName(), channel, replyChannel, payload, distance + m_computer.getAttachmentName(), packet.getChannel(), packet.getReplyChannel(), packet.getPayload(), distance } ); } } } - public void receiveDifferentDimension( int channel, int replyChannel, Object payload ) + @Override + public void receiveDifferentDimension( @Nonnull Packet packet ) { + if( packet.getSender() == this ) return; + synchronized (m_channels) { - if( m_computer != null && m_channels.containsKey( channel ) ) + if( m_computer != null && m_channels.contains( packet.getChannel() ) ) { m_computer.queueEvent( "modem_message", new Object[] { - m_computer.getAttachmentName(), channel, replyChannel, payload + m_computer.getAttachmentName(), packet.getChannel(), packet.getReplyChannel(), packet.getPayload() } ); } } } - protected abstract INetwork getNetwork(); + protected abstract IPacketNetwork getNetwork(); // IPeripheral implementation @@ -247,19 +170,14 @@ public abstract class ModemPeripheral int channel = parseChannel( arguments, 0 ); synchronized( this ) { - if( !m_channels.containsKey( channel ) ) + if( !m_channels.contains( 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 ); - } + + m_channels.add( channel ); if( !m_open ) { m_open = true; @@ -275,7 +193,7 @@ public abstract class ModemPeripheral int channel = parseChannel( arguments, 0 ); synchronized( this ) { - boolean open = m_channels.containsKey( channel ); + boolean open = m_channels.contains( channel ); return new Object[] { open }; } } @@ -285,15 +203,8 @@ public abstract class ModemPeripheral int channel = parseChannel( arguments, 0 ); synchronized( this ) { - if( m_channels.containsKey( channel ) ) + if( m_channels.remove( 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; @@ -310,13 +221,6 @@ public abstract class ModemPeripheral { if( m_channels.size() > 0 ) { - if( m_network != null ) - { - for( IReceiver iReceiver : m_channels.values() ) - { - m_network.removeReceiver( iReceiver ); - } - } m_channels.clear(); if( m_open ) @@ -340,7 +244,15 @@ public abstract class ModemPeripheral Vec3d position = getPosition(); if( world != null && position != null && m_network != null) { - m_network.transmit( channel, replyChannel, payload, world, position, getTransmitRange(), isInterdimensional(), this ); + Packet packet = new Packet( channel, replyChannel, payload, this ); + if( isInterdimensional() ) + { + m_network.transmitInterdimensional( packet ); + } + else + { + m_network.transmitSameDimension( packet, getRange() ); + } } } return null; @@ -377,10 +289,7 @@ public abstract class ModemPeripheral { if( m_network != null ) { - for( IReceiver iReceiver : m_channels.values() ) - { - m_network.removeReceiver( iReceiver ); - } + m_network.removeReceiver( this ); m_channels.clear(); m_network = null; } @@ -394,11 +303,22 @@ public abstract class ModemPeripheral } } - @Override - public abstract boolean equals( IPeripheral other ); - public IComputerAccess getComputer() { return m_computer; } + + @Nonnull + @Override + public String getSenderID() + { + if( m_computer == null ) + { + return "unknown"; + } + else + { + return m_computer.getID() + "_" + m_computer.getAttachmentName(); + } + } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/TileAdvancedModem.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/TileAdvancedModem.java index 5529b5896..1ce820cb9 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/TileAdvancedModem.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/TileAdvancedModem.java @@ -13,6 +13,8 @@ import net.minecraft.util.EnumFacing; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; +import javax.annotation.Nonnull; + public class TileAdvancedModem extends TileModemBase { // Statics @@ -27,14 +29,16 @@ public class TileAdvancedModem extends TileModemBase m_entity = entity; } + @Nonnull @Override public World getWorld() { return m_entity.getWorld(); } + @Nonnull @Override - protected Vec3d getPosition() + public Vec3d getPosition() { BlockPos pos = m_entity.getPos().offset( m_entity.getDirection() ); return new Vec3d( (double)pos.getX(), (double)pos.getY(), (double)pos.getZ() ); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/TileCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/TileCable.java index 9a6c57e5d..fc8502378 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/TileCable.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/TileCable.java @@ -12,6 +12,9 @@ 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.IPacketReceiver; +import dan200.computercraft.api.network.Packet; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.shared.common.BlockGeneric; @@ -38,7 +41,7 @@ import java.io.File; import java.util.*; public class TileCable extends TileModemBase - implements INetwork + implements IPacketNetwork { private static final double MIN = 0.375; private static final double MAX = 1 - MIN; @@ -65,31 +68,33 @@ public class TileCable extends TileModemBase } @Override - protected boolean isInterdimensional() + public boolean isInterdimensional() { return false; } @Override - protected double getTransmitRange() + public double getRange() { return 256.0; } @Override - protected INetwork getNetwork() + protected IPacketNetwork getNetwork() { return m_entity; } + @Nonnull @Override - protected World getWorld() + public World getWorld() { return m_entity.getWorld(); } + @Nonnull @Override - protected Vec3d getPosition() + public Vec3d getPosition() { EnumFacing direction = m_entity.getDirection(); BlockPos pos = m_entity.getPos().offset( direction ); @@ -233,8 +238,8 @@ public class TileCable extends TileModemBase // Members - private final Map> m_receivers; - private final Queue m_transmitQueue; + private final Set m_receivers; + private final Queue m_transmitQueue; private boolean m_peripheralAccessAllowed; private int m_attachedPeripheralID; @@ -248,8 +253,8 @@ public class TileCable extends TileModemBase public TileCable() { - m_receivers = new HashMap>(); - m_transmitQueue = new LinkedList(); + m_receivers = new HashSet(); + m_transmitQueue = new LinkedList(); m_peripheralAccessAllowed = false; m_attachedPeripheralID = -1; @@ -564,7 +569,7 @@ public class TileCable extends TileModemBase { while( m_transmitQueue.peek() != null ) { - Packet p = m_transmitQueue.remove(); + PacketWrapper p = m_transmitQueue.remove(); if( p != null ) { dispatchPacket( p ); @@ -573,53 +578,45 @@ public class TileCable extends TileModemBase } } } - - // INetwork implementation - + + // IPacketNetwork implementation + @Override - public void addReceiver( IReceiver receiver ) + public void addReceiver( @Nonnull IPacketReceiver receiver ) { synchronized( m_receivers ) { - int channel = receiver.getChannel(); - Set receivers = m_receivers.get( channel ); - if( receivers == null ) - { - receivers = new HashSet(); - m_receivers.put( channel, receivers ); - } - receivers.add( receiver ); + m_receivers.add( receiver ); } } @Override - public void removeReceiver( IReceiver receiver ) + public void removeReceiver( @Nonnull IPacketReceiver receiver ) { synchronized( m_receivers ) { - int channel = receiver.getChannel(); - Set receivers = m_receivers.get( channel ); - if( receivers != null ) - { - receivers.remove( receiver ); - } + m_receivers.remove( receiver ); } } - + @Override - public void transmit( int channel, int replyChannel, Object payload, World world, Vec3d pos, double range, boolean interdimensional, Object senderObject ) + public void transmitSameDimension( @Nonnull Packet packet, double range ) { - Packet p = new Packet(); - p.channel = channel; - p.replyChannel = replyChannel; - p.payload = payload; - p.senderObject = senderObject; synchronized( m_transmitQueue ) { - m_transmitQueue.offer(p); + m_transmitQueue.offer( new PacketWrapper( packet, range ) ); } } - + + @Override + public void transmitInterdimensional( @Nonnull Packet packet ) + { + synchronized( m_transmitQueue ) + { + m_transmitQueue.offer( new PacketWrapper( packet, Double.MAX_VALUE ) ); + } + } + @Override public boolean isWireless() { @@ -726,21 +723,28 @@ public class TileCable extends TileModemBase // private stuff // Packet sending - - private class Packet + + private static class PacketWrapper { - public int channel; - public int replyChannel; - public Object payload; - public Object senderObject; + final Packet m_packet; + final double m_range; + + private PacketWrapper( Packet m_packet, double m_range ) + { + this.m_packet = m_packet; + this.m_range = m_range; + } } - private void dispatchPacket( final Packet packet ) + private void dispatchPacket( final PacketWrapper packet ) { searchNetwork( new ICableVisitor() { public void visit( TileCable modem, int distance ) { - modem.receivePacket( packet, distance ); + if( distance <= packet.m_range) + { + modem.receivePacket( packet.m_packet, distance ); + } } } ); } @@ -749,13 +753,9 @@ public class TileCable extends TileModemBase { synchronized( m_receivers ) { - Set receivers = m_receivers.get( packet.channel ); - if( receivers != null ) + for (IPacketReceiver device : m_receivers) { - for( IReceiver receiver : receivers ) - { - receiver.receiveSameDimension( packet.replyChannel, packet.payload, (double) distanceTravelled, packet.senderObject ); - } + device.receiveSameDimension( packet, distanceTravelled ); } } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/TileWirelessModem.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/TileWirelessModem.java index 0acefa378..4f4ca12a3 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/TileWirelessModem.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/TileWirelessModem.java @@ -33,14 +33,16 @@ public class TileWirelessModem extends TileModemBase m_entity = entity; } + @Nonnull @Override - protected World getWorld() + public World getWorld() { return m_entity.getWorld(); } + @Nonnull @Override - protected Vec3d getPosition() + public Vec3d getPosition() { BlockPos pos = m_entity.getPos().offset( m_entity.getDirection() ); return new Vec3d( (double)pos.getX(), (double)pos.getY(), (double)pos.getZ() ); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/WirelessModemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/WirelessModemPeripheral.java index 81d45c773..27ad9701d 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/WirelessModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/WirelessModemPeripheral.java @@ -7,6 +7,7 @@ package dan200.computercraft.shared.peripheral.modem; import dan200.computercraft.ComputerCraft; +import dan200.computercraft.api.network.IPacketNetwork; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; @@ -20,13 +21,13 @@ public abstract class WirelessModemPeripheral extends ModemPeripheral } @Override - protected boolean isInterdimensional() + public boolean isInterdimensional() { return m_advanced; } @Override - protected double getTransmitRange() + public double getRange() { if( m_advanced ) { @@ -56,7 +57,7 @@ public abstract class WirelessModemPeripheral extends ModemPeripheral } @Override - protected INetwork getNetwork() + protected IPacketNetwork getNetwork() { return WirelessNetwork.getUniversal(); } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/WirelessNetwork.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/WirelessNetwork.java index 6f420bc25..6c859007c 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/WirelessNetwork.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/WirelessNetwork.java @@ -6,12 +6,17 @@ package dan200.computercraft.shared.peripheral.modem; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.World; +import com.google.common.base.Preconditions; +import dan200.computercraft.api.network.IPacketNetwork; +import dan200.computercraft.api.network.IPacketReceiver; +import dan200.computercraft.api.network.IPacketSender; +import dan200.computercraft.api.network.Packet; -import java.util.*; +import javax.annotation.Nonnull; +import java.util.HashSet; +import java.util.Set; -public class WirelessNetwork implements INetwork +public class WirelessNetwork implements IPacketNetwork { private static WirelessNetwork s_universalNetwork = null; @@ -28,68 +33,65 @@ public class WirelessNetwork implements INetwork { s_universalNetwork = null; } - - private Map> m_receivers; - + + private final Set m_receivers; + private WirelessNetwork() { - m_receivers = new HashMap>(); + m_receivers = new HashSet(); } @Override - public synchronized void addReceiver( IReceiver receiver ) + public synchronized void addReceiver( @Nonnull IPacketReceiver receiver ) { - int channel = receiver.getChannel(); - Set receivers = m_receivers.get( channel ); - if( receivers == null ) - { - receivers = new HashSet(); - m_receivers.put( channel, receivers ); - } - receivers.add( receiver ); + Preconditions.checkNotNull( receiver, "device cannot be null" ); + m_receivers.add( receiver ); } - + @Override - public synchronized void removeReceiver( IReceiver receiver ) + public synchronized void removeReceiver( @Nonnull IPacketReceiver receiver ) { - int channel = receiver.getChannel(); - Set receivers = m_receivers.get( channel ); - if( receivers != null ) - { - receivers.remove( receiver ); - } + Preconditions.checkNotNull( receiver, "device cannot be null" ); + m_receivers.remove( receiver ); } - + @Override - public synchronized void transmit( int channel, int replyChannel, Object payload, World world, Vec3d pos, double range, boolean interdimensional, Object senderObject ) + public synchronized void transmitSameDimension( @Nonnull Packet packet, double range ) { - Set receivers = m_receivers.get( channel ); - if( receivers != null ) + Preconditions.checkNotNull( packet, "packet cannot be null" ); + for( IPacketReceiver device : m_receivers ) { - for( IReceiver receiver : receivers ) - { - tryTransmit( receiver, replyChannel, payload, world, pos, range, interdimensional, senderObject ); - } + tryTransmit( device, packet, range, false ); } } - - private void tryTransmit( IReceiver receiver, int replyChannel, Object payload, World world, Vec3d pos, double range, boolean interdimensional, Object senderObject ) + + @Override + public synchronized void transmitInterdimensional( @Nonnull Packet packet ) { - if( receiver.getWorld() == world ) + Preconditions.checkNotNull( packet, "packet cannot be null" ); + for (IPacketReceiver device : m_receivers) { - Vec3d position = receiver.getWorldPosition(); - double receiveRange = Math.max( range, receiver.getReceiveRange() ); // Ensure range is symmetrical - double distanceSq = position.squareDistanceTo( pos ); - if( interdimensional || receiver.isInterdimensional() || distanceSq <= ( receiveRange * receiveRange ) ) + tryTransmit( device, packet, 0, true ); + } + } + + private void tryTransmit( IPacketReceiver receiver, Packet packet, double range, boolean interdimensional ) + { + IPacketSender sender = packet.getSender(); + if( receiver.getWorld() == sender.getWorld() ) + { + double receiveRange = Math.max( range, receiver.getRange() ); // Ensure range is symmetrical + double distanceSq = receiver.getPosition().squareDistanceTo( sender.getPosition() ); + if( interdimensional || receiver.isInterdimensional() || distanceSq <= (receiveRange * receiveRange) ) { - receiver.receiveSameDimension( replyChannel, payload, Math.sqrt( distanceSq ), senderObject ); + receiver.receiveSameDimension( packet, Math.sqrt( distanceSq ) ); } } else { if( interdimensional || receiver.isInterdimensional() ) { - receiver.receiveDifferentDimension( replyChannel, payload, senderObject ); + receiver.receiveDifferentDimension( packet ); } } } diff --git a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModemPeripheral.java b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModemPeripheral.java index 6a6483da0..5ec82623d 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModemPeripheral.java @@ -1,3 +1,8 @@ +/* + * 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.shared.pocket.peripherals; import dan200.computercraft.api.peripheral.IPeripheral; @@ -5,11 +10,7 @@ import dan200.computercraft.shared.peripheral.modem.WirelessModemPeripheral; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; -/* - * 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 - */ +import javax.annotation.Nonnull; public class PocketModemPeripheral extends WirelessModemPeripheral { @@ -33,14 +34,16 @@ public class PocketModemPeripheral extends WirelessModemPeripheral } } + @Nonnull @Override - protected World getWorld() + public World getWorld() { return m_world; } + @Nonnull @Override - protected Vec3d getPosition() + public Vec3d getPosition() { if( m_world != null ) { diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java index 0b3d2f932..181ca778c 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java @@ -42,14 +42,16 @@ public class TurtleModem implements ITurtleUpgrade m_turtle = turtle; } + @Nonnull @Override - protected World getWorld() + public World getWorld() { return m_turtle.getWorld(); } + @Nonnull @Override - protected Vec3d getPosition() + public Vec3d getPosition() { BlockPos turtlePos = m_turtle.getPosition(); return new Vec3d(