1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2024-12-12 19:20:29 +00:00

Convert TileCable to use the wired network API

There are several important things to note here:

 - The network element is associated with the cable, whilst the
   peripheral (and so packet sender/receiver) is associated with the
   modem. This allows us to have the main element be in the centre of
   the cable block, whilst the modem is in the centre of the adjacent
   computer.

 - Cables will connect to any adjacent network element, not just
   other cables.

 - Rednet messages are now sent on the computer thread, rather than the
   cable tick.
This commit is contained in:
SquidDev 2018-02-21 15:35:38 +00:00
parent 74f5093d2a
commit 5c7828dd79
5 changed files with 655 additions and 688 deletions

View File

@ -54,8 +54,6 @@ public class RenderOverlayCable
GlStateManager.depthMask( false );
GlStateManager.pushMatrix();
EnumFacing direction = type != PeripheralType.Cable ? cable.getDirection() : null;
{
EntityPlayer player = event.getPlayer();
double x = player.lastTickPosX + (player.posX - player.lastTickPosX) * event.getPartialTicks();
@ -78,7 +76,7 @@ public class RenderOverlayCable
for( EnumFacing facing : EnumFacing.VALUES )
{
if( direction == facing || BlockCable.isCable( world, pos.offset( facing ) ) )
if( BlockCable.doesConnectVisually( state, world, pos, facing ) )
{
flags |= 1 << facing.ordinal();

View File

@ -11,7 +11,6 @@ import dan200.computercraft.shared.common.TileGeneric;
import dan200.computercraft.shared.peripheral.PeripheralType;
import dan200.computercraft.shared.peripheral.modem.TileCable;
import dan200.computercraft.shared.util.WorldUtil;
import net.minecraft.block.Block;
import net.minecraft.block.properties.PropertyBool;
import net.minecraft.block.properties.PropertyEnum;
import net.minecraft.block.state.BlockFaceShape;
@ -51,23 +50,6 @@ public class BlockCable extends BlockPeripheralBase
public static final PropertyBool DOWN = PropertyBool.create( "down" );
}
public static boolean isCable( IBlockAccess world, BlockPos pos )
{
Block block = world.getBlockState( pos ).getBlock();
if( block == ComputerCraft.Blocks.cable )
{
switch( ComputerCraft.Blocks.cable.getPeripheralType( world, pos ) )
{
case Cable:
case WiredModemWithCable:
{
return true;
}
}
}
return false;
}
// Members
public BlockCable()
@ -175,20 +157,17 @@ public class BlockCable extends BlockPeripheralBase
}
}
private boolean doesConnect( IBlockState state, IBlockAccess world, BlockPos pos, EnumFacing dir )
public static boolean canConnectIn( IBlockState state, EnumFacing direction )
{
if( state.getValue( Properties.CABLE ) == BlockCableCableVariant.NONE )
{
return false;
}
else if( state.getValue( Properties.MODEM ).getFacing() == dir )
{
return true;
}
else
{
return isCable( world, pos.offset( dir ) );
}
return state.getValue( BlockCable.Properties.CABLE ) != BlockCableCableVariant.NONE
&& state.getValue( BlockCable.Properties.MODEM ).getFacing() != direction;
}
public static boolean doesConnectVisually( IBlockState state, IBlockAccess world, BlockPos pos, EnumFacing direction )
{
if( state.getValue( Properties.CABLE ) == BlockCableCableVariant.NONE ) return false;
if( state.getValue( Properties.MODEM ).getFacing() == direction ) return true;
return ComputerCraft.getWiredElementAt( world, pos.offset( direction ), direction.getOpposite() ) != null;
}
@Nonnull
@ -196,12 +175,12 @@ public class BlockCable extends BlockPeripheralBase
@Deprecated
public IBlockState getActualState( @Nonnull IBlockState state, IBlockAccess world, BlockPos pos )
{
state = state.withProperty( Properties.NORTH, doesConnect( state, world, pos, EnumFacing.NORTH ) );
state = state.withProperty( Properties.SOUTH, doesConnect( state, world, pos, EnumFacing.SOUTH ) );
state = state.withProperty( Properties.EAST, doesConnect( state, world, pos, EnumFacing.EAST ) );
state = state.withProperty( Properties.WEST, doesConnect( state, world, pos, EnumFacing.WEST ) );
state = state.withProperty( Properties.UP, doesConnect( state, world, pos, EnumFacing.UP ) );
state = state.withProperty( Properties.DOWN, doesConnect( state, world, pos, EnumFacing.DOWN ) );
state = state.withProperty( Properties.NORTH, doesConnectVisually( state, world, pos, EnumFacing.NORTH ) );
state = state.withProperty( Properties.SOUTH, doesConnectVisually( state, world, pos, EnumFacing.SOUTH ) );
state = state.withProperty( Properties.EAST, doesConnectVisually( state, world, pos, EnumFacing.EAST ) );
state = state.withProperty( Properties.WEST, doesConnectVisually( state, world, pos, EnumFacing.WEST ) );
state = state.withProperty( Properties.UP, doesConnectVisually( state, world, pos, EnumFacing.UP ) );
state = state.withProperty( Properties.DOWN, doesConnectVisually( state, world, pos, EnumFacing.DOWN ) );
if( state.getValue( Properties.CABLE ) != BlockCableCableVariant.NONE )
{
@ -345,7 +324,6 @@ public class BlockCable extends BlockPeripheralBase
if( WorldUtil.isVecInsideInclusive( bb, hit.hitVec.subtract( pos.getX(), pos.getY(), pos.getZ() ) ) )
{
world.setBlockState( pos, state.withProperty( Properties.MODEM, BlockCableModemVariant.None ), 3 );
cable.modemChanged();
item = PeripheralItemFactory.create( PeripheralType.WiredModem, null, 1 );
}
else
@ -365,6 +343,7 @@ public class BlockCable extends BlockPeripheralBase
return super.removedByPlayer( state, world, pos, player, willHarvest );
}
@Nonnull
@Override
public ItemStack getPickBlock( @Nonnull IBlockState state, RayTraceResult hit, @Nonnull World world, @Nonnull BlockPos pos, EntityPlayer player )
{

View File

@ -0,0 +1,59 @@
package dan200.computercraft.shared.peripheral.modem;
import dan200.computercraft.api.network.wired.IWiredNetworkChange;
import dan200.computercraft.api.network.wired.IWiredElement;
import dan200.computercraft.api.network.wired.IWiredNode;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.shared.wired.WiredNode;
import javax.annotation.Nonnull;
import java.util.HashMap;
import java.util.Map;
public abstract class WiredModemElement implements IWiredElement
{
private final IWiredNode node = new WiredNode( this );
private final Map<String, IPeripheral> remotePeripherals = new HashMap<>();
@Nonnull
@Override
public IWiredNode getNode()
{
return node;
}
@Nonnull
@Override
public String getSenderID()
{
return "modem";
}
@Override
public void networkChanged( @Nonnull IWiredNetworkChange change )
{
synchronized( remotePeripherals )
{
remotePeripherals.keySet().removeAll( change.peripheralsRemoved().keySet() );
for( String name : change.peripheralsRemoved().keySet() )
{
detachPeripheral( name );
}
for( Map.Entry<String, IPeripheral> peripheral : change.peripheralsAdded().entrySet() )
{
attachPeripheral( peripheral.getKey(), peripheral.getValue() );
}
remotePeripherals.putAll( change.peripheralsAdded() );
}
}
public Map<String, IPeripheral> getRemotePeripherals()
{
return remotePeripherals;
}
protected abstract void attachPeripheral( String name, IPeripheral peripheral );
protected abstract void detachPeripheral( String name );
}

View File

@ -0,0 +1,410 @@
package dan200.computercraft.shared.peripheral.modem;
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 net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.HashMap;
import java.util.Map;
import static dan200.computercraft.core.apis.ArgumentHelper.getString;
public class WiredModemPeripheral extends ModemPeripheral implements IWiredSender
{
private final WiredModemElement modem;
private final Map<String, RemotePeripheralWrapper> peripheralWrappers = new HashMap<>();
public WiredModemPeripheral( WiredModemElement modem )
{
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
@Override
public Vec3d getPosition()
{
return modem.getPosition();
}
//endregion
//region IPeripheral
@Nonnull
@Override
public String[] getMethodNames()
{
String[] methods = super.getMethodNames();
String[] newMethods = new String[methods.length + 5];
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";
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
synchronized( peripheralWrappers )
{
int idx = 1;
Map<Object, Object> table = new HashMap<>();
for( String name : peripheralWrappers.keySet() )
{
table.put( idx++, name );
}
return new Object[]{ table };
}
}
case 1:
{
// isPresentRemote
String type = getTypeRemote( getString( arguments, 0 ) );
return new Object[]{ type != null };
}
case 2:
{
// getTypeRemote
String type = getTypeRemote( getString( arguments, 0 ) );
if( type != null )
{
return new Object[]{ type };
}
return null;
}
case 3:
{
// getMethodsRemote
String[] methodNames = getMethodNamesRemote( getString( arguments, 0 ) );
if( methodNames != null )
{
Map<Object, Object> table = new HashMap<>();
for( int i = 0; i < methodNames.length; ++i )
{
table.put( i + 1, methodNames[i] );
}
return new Object[]{ table };
}
return null;
}
case 4:
{
// callRemote
String remoteName = getString( arguments, 0 );
String methodName = getString( arguments, 1 );
Object[] methodArgs = new Object[arguments.length - 2];
System.arraycopy( arguments, 2, methodArgs, 0, arguments.length - 2 );
return callMethodRemote( remoteName, context, methodName, methodArgs );
}
default:
{
// The regular modem methods
return super.callMethod( computer, context, method, arguments );
}
}
}
@Override
public void attach( @Nonnull IComputerAccess computer )
{
super.attach( computer );
synchronized( modem.getRemotePeripherals() )
{
synchronized( peripheralWrappers )
{
for( Map.Entry<String, IPeripheral> entry : modem.getRemotePeripherals().entrySet() )
{
attachPeripheralImpl( entry.getKey(), entry.getValue() );
}
}
}
}
@Override
public synchronized void detach( @Nonnull IComputerAccess computer )
{
synchronized( peripheralWrappers )
{
for( RemotePeripheralWrapper wrapper : peripheralWrappers.values() )
{
wrapper.detach();
}
peripheralWrappers.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 )
{
if( getComputer() == null ) return;
synchronized( peripheralWrappers )
{
attachPeripheralImpl( name, peripheral );
}
}
public void detachPeripheral( String name )
{
synchronized( peripheralWrappers )
{
RemotePeripheralWrapper wrapper = peripheralWrappers.get( name );
if( wrapper != null )
{
peripheralWrappers.remove( name );
wrapper.detach();
}
}
}
private void attachPeripheralImpl( String periphName, IPeripheral peripheral )
{
if( !peripheralWrappers.containsKey( periphName ) )
{
RemotePeripheralWrapper wrapper = new RemotePeripheralWrapper( modem, peripheral, getComputer(), periphName );
peripheralWrappers.put( periphName, wrapper );
wrapper.attach();
}
}
private String getTypeRemote( String remoteName )
{
synchronized( peripheralWrappers )
{
RemotePeripheralWrapper wrapper = peripheralWrappers.get( remoteName );
if( wrapper != null )
{
return wrapper.getType();
}
}
return null;
}
private String[] getMethodNamesRemote( String remoteName )
{
synchronized( peripheralWrappers )
{
RemotePeripheralWrapper wrapper = peripheralWrappers.get( remoteName );
if( wrapper != null )
{
return wrapper.getMethodNames();
}
}
return null;
}
private Object[] callMethodRemote( String remoteName, ILuaContext context, String method, Object[] arguments ) throws LuaException, InterruptedException
{
RemotePeripheralWrapper wrapper;
synchronized( peripheralWrappers )
{
wrapper = peripheralWrappers.get( remoteName );
}
if( wrapper != null )
{
return wrapper.callMethod( context, method, arguments );
}
throw new LuaException( "No peripheral: " + 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 );
}
@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 );
}
}
}
}