1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2024-09-29 23:40:46 +00:00

Various improvements to peripheral invalidation

- Abstract peripheral ID and type checking into separate class
 - Update peripherals directly rather than marking as invalid then
   fetching from the network.
 - Update peripherals when adjacent tiles change

This does result in a slightly more ugly interface, but reduces the
amount of work needed to perform partial updates of peripherals, such as
those done by neighbouring tile updates.
This commit is contained in:
SquidDev 2018-04-16 18:22:28 +01:00
parent 04f162ef25
commit 6cf32f1f74
8 changed files with 289 additions and 201 deletions

View File

@ -1,11 +1,8 @@
package dan200.computercraft.api.network.wired; package dan200.computercraft.api.network.wired;
import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.peripheral.IPeripheral;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.Collections;
import java.util.Map;
/** /**
* An object which may be part of a wired network. * An object which may be part of a wired network.
@ -19,21 +16,6 @@ import java.util.Map;
*/ */
public interface IWiredElement extends IWiredSender public interface IWiredElement extends IWiredSender
{ {
/**
* Fetch the peripherals this network element provides.
*
* This is only called when initially attaching to a network and after a call to {@link IWiredNode#invalidate()}}, so
* one does not <em>need</em> to cache the return value.
*
* @return The peripherals this node provides.
* @see IWiredNode#invalidate()
*/
@Nonnull
default Map<String, IPeripheral> getPeripherals()
{
return Collections.emptyMap();
}
/** /**
* Called when objects on the network change. This may occur when network nodes are added or removed, or when * Called when objects on the network change. This may occur when network nodes are added or removed, or when
* peripherals change. * peripherals change.

View File

@ -1,6 +1,9 @@
package dan200.computercraft.api.network.wired; package dan200.computercraft.api.network.wired;
import dan200.computercraft.api.peripheral.IPeripheral;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.Map;
/** /**
* A wired network is composed of one of more {@link IWiredNode}s, a set of connections between them, and a series * A wired network is composed of one of more {@link IWiredNode}s, a set of connections between them, and a series
@ -51,7 +54,8 @@ public interface IWiredNetwork
/** /**
* Sever all connections this node has, removing it from this network. * Sever all connections this node has, removing it from this network.
* *
* This should only be used on the server thread. * This should only be used on the server thread. You should only call this on nodes
* that your network element owns.
* *
* @param node The node to remove * @param node The node to remove
* @return Whether this node was removed from the network. One cannot remove a node from a network where it is the * @return Whether this node was removed from the network. One cannot remove a node from a network where it is the
@ -62,13 +66,15 @@ public interface IWiredNetwork
boolean remove( @Nonnull IWiredNode node ); boolean remove( @Nonnull IWiredNode node );
/** /**
* Mark this node's peripherals as having changed. * Update the peripherals a node provides.
* *
* This should only be used on the server thread. * This should only be used on the server thread. You should only call this on nodes
* that your network element owns.
* *
* @param node The node to mark as invalid. * @param node The node to attach peripherals for.
* @param peripherals The new peripherals for this node.
* @throws IllegalArgumentException If the node is not in the network. * @throws IllegalArgumentException If the node is not in the network.
* @see IWiredElement#getPeripherals() * @see IWiredNode#updatePeripherals(Map)
*/ */
void invalidate( @Nonnull IWiredNode node ); void updatePeripherals( @Nonnull IWiredNode node, @Nonnull Map<String, IPeripheral> peripherals );
} }

View File

@ -1,8 +1,10 @@
package dan200.computercraft.api.network.wired; package dan200.computercraft.api.network.wired;
import dan200.computercraft.api.network.IPacketNetwork; import dan200.computercraft.api.network.IPacketNetwork;
import dan200.computercraft.api.peripheral.IPeripheral;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.Map;
/** /**
* Wired nodes act as a layer between {@link IWiredElement}s and {@link IWiredNetwork}s. * Wired nodes act as a layer between {@link IWiredElement}s and {@link IWiredNetwork}s.
@ -72,7 +74,8 @@ public interface IWiredNode extends IPacketNetwork
/** /**
* Sever all connections this node has, removing it from this network. * Sever all connections this node has, removing it from this network.
* *
* This should only be used on the server thread. * This should only be used on the server thread. You should only call this on nodes
* that your network element owns.
* *
* @return Whether this node was removed from the network. One cannot remove a node from a network where it is the * @return Whether this node was removed from the network. One cannot remove a node from a network where it is the
* only element. * only element.
@ -87,12 +90,14 @@ public interface IWiredNode extends IPacketNetwork
/** /**
* Mark this node's peripherals as having changed. * Mark this node's peripherals as having changed.
* *
* This should only be used on the server thread. * This should only be used on the server thread. You should only call this on nodes
* that your network element owns.
* *
* @see IWiredElement#getPeripherals() * @param peripherals The new peripherals for this node.
* @see IWiredNetwork#updatePeripherals(IWiredNode, Map)
*/ */
default void invalidate() default void updatePeripherals( @Nonnull Map<String, IPeripheral> peripherals )
{ {
getNetwork().invalidate( this ); getNetwork().updatePeripherals( this, peripherals );
} }
} }

View File

@ -16,10 +16,7 @@ import dan200.computercraft.shared.peripheral.PeripheralType;
import dan200.computercraft.shared.peripheral.common.BlockCable; import dan200.computercraft.shared.peripheral.common.BlockCable;
import dan200.computercraft.shared.peripheral.common.BlockCableModemVariant; import dan200.computercraft.shared.peripheral.common.BlockCableModemVariant;
import dan200.computercraft.shared.peripheral.common.PeripheralItemFactory; import dan200.computercraft.shared.peripheral.common.PeripheralItemFactory;
import dan200.computercraft.shared.util.IDAssigner;
import dan200.computercraft.shared.util.PeripheralUtil;
import dan200.computercraft.shared.wired.CapabilityWiredElement; import dan200.computercraft.shared.wired.CapabilityWiredElement;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
@ -35,7 +32,6 @@ import net.minecraftforge.common.capabilities.Capability;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.io.File;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -79,16 +75,6 @@ public class TileCable extends TileModemBase
return new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ); return new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 );
} }
@Nonnull
@Override
public Map<String, IPeripheral> getPeripherals()
{
IPeripheral peripheral = m_entity.getConnectedPeripheral();
return peripheral != null
? Collections.singletonMap( m_entity.getConnectedPeripheralName(), peripheral )
: Collections.emptyMap();
}
@Override @Override
protected void attachPeripheral( String name, IPeripheral peripheral ) protected void attachPeripheral( String name, IPeripheral peripheral )
{ {
@ -105,9 +91,9 @@ public class TileCable extends TileModemBase
// Members // Members
private boolean m_peripheralAccessAllowed; private boolean m_peripheralAccessAllowed;
private int m_attachedPeripheralID; private WiredModemLocalPeripheral m_peripheral = new WiredModemLocalPeripheral();
private boolean m_destroyed; private boolean m_destroyed = false;
private boolean m_hasDirection = false; private boolean m_hasDirection = false;
private boolean m_connectionsFormed = false; private boolean m_connectionsFormed = false;
@ -115,14 +101,6 @@ public class TileCable extends TileModemBase
private WiredModemElement m_cable; private WiredModemElement m_cable;
private IWiredNode m_node; private IWiredNode m_node;
public TileCable()
{
m_peripheralAccessAllowed = false;
m_attachedPeripheralID = -1;
m_destroyed = false;
}
@Override @Override
protected ModemPeripheral createPeripheral() protected ModemPeripheral createPeripheral()
{ {
@ -133,7 +111,7 @@ public class TileCable extends TileModemBase
@Override @Override
protected boolean canSeePeripheral( @Nonnull String peripheralName ) protected boolean canSeePeripheral( @Nonnull String peripheralName )
{ {
return !peripheralName.equals( getConnectedPeripheralName() ); return !peripheralName.equals( m_peripheral.getConnectedName() );
} }
@Nonnull @Nonnull
@ -294,10 +272,29 @@ public class TileCable extends TileModemBase
modemChanged(); modemChanged();
connectionsChanged(); connectionsChanged();
break; return;
} }
} }
} }
if( !world.isRemote && m_peripheralAccessAllowed )
{
if( m_peripheral.attach( world, getPos(), dir ) ) updateConnectedPeripherals();
}
}
@Override
public void onNeighbourTileEntityChange( @Nonnull BlockPos neighbour )
{
super.onNeighbourTileEntityChange( neighbour );
if( !world.isRemote && m_peripheralAccessAllowed )
{
EnumFacing facing = getDirection();
if( getPos().offset( facing ).equals( neighbour ) )
{
if( m_peripheral.attach( world, getPos(), facing ) ) updateConnectedPeripherals();
}
}
} }
public AxisAlignedBB getModemBounds() public AxisAlignedBB getModemBounds()
@ -400,9 +397,9 @@ public class TileCable extends TileModemBase
if( !getWorld().isRemote ) if( !getWorld().isRemote )
{ {
// On server, we interacted if a peripheral was found // On server, we interacted if a peripheral was found
String oldPeriphName = getConnectedPeripheralName(); String oldPeriphName = m_peripheral.getConnectedName();
togglePeripheralAccess(); togglePeripheralAccess();
String periphName = getConnectedPeripheralName(); String periphName = m_peripheral.getConnectedName();
if( !Objects.equal( periphName, oldPeriphName ) ) if( !Objects.equal( periphName, oldPeriphName ) )
{ {
@ -437,7 +434,7 @@ public class TileCable extends TileModemBase
// Read properties // Read properties
super.readFromNBT( nbttagcompound ); super.readFromNBT( nbttagcompound );
m_peripheralAccessAllowed = nbttagcompound.getBoolean( "peripheralAccess" ); m_peripheralAccessAllowed = nbttagcompound.getBoolean( "peripheralAccess" );
m_attachedPeripheralID = nbttagcompound.getInteger( "peripheralID" ); m_peripheral.readNBT( nbttagcompound, "" );
} }
@Nonnull @Nonnull
@ -447,7 +444,7 @@ public class TileCable extends TileModemBase
// Write properties // Write properties
nbttagcompound = super.writeToNBT( nbttagcompound ); nbttagcompound = super.writeToNBT( nbttagcompound );
nbttagcompound.setBoolean( "peripheralAccess", m_peripheralAccessAllowed ); nbttagcompound.setBoolean( "peripheralAccess", m_peripheralAccessAllowed );
nbttagcompound.setInteger( "peripheralID", m_attachedPeripheralID ); m_peripheral.writeNBT( nbttagcompound, "" );
return nbttagcompound; return nbttagcompound;
} }
@ -476,8 +473,13 @@ public class TileCable extends TileModemBase
if( !m_connectionsFormed ) if( !m_connectionsFormed )
{ {
m_connectionsFormed = true; m_connectionsFormed = true;
connectionsChanged(); connectionsChanged();
if( m_peripheralAccessAllowed ) m_node.invalidate(); if( m_peripheralAccessAllowed )
{
m_peripheral.attach( world, pos, m_dir );
updateConnectedPeripherals();
}
} }
} }
} }
@ -515,15 +517,11 @@ public class TileCable extends TileModemBase
if( getWorld().isRemote ) return; if( getWorld().isRemote ) return;
PeripheralType type = getPeripheralType(); PeripheralType type = getPeripheralType();
if( type == PeripheralType.Cable )
{
m_attachedPeripheralID = -1;
}
if( type != PeripheralType.WiredModemWithCable && m_peripheralAccessAllowed ) if( type != PeripheralType.WiredModemWithCable && m_peripheralAccessAllowed )
{ {
m_peripheralAccessAllowed = false; m_peripheralAccessAllowed = false;
m_node.invalidate(); m_peripheral.detach();
m_node.updatePeripherals( Collections.emptyMap() );
markDirty(); markDirty();
updateAnim(); updateAnim();
} }
@ -534,61 +532,34 @@ public class TileCable extends TileModemBase
{ {
if( !m_peripheralAccessAllowed ) if( !m_peripheralAccessAllowed )
{ {
m_peripheral.attach( world, getPos(), getDirection() );
if( !m_peripheral.hasPeripheral() ) return;
m_peripheralAccessAllowed = true; m_peripheralAccessAllowed = true;
if( getConnectedPeripheral() == null ) m_node.updatePeripherals( m_peripheral.toMap() );
{
m_peripheralAccessAllowed = false;
return;
}
} }
else else
{ {
m_peripheral.detach();
m_peripheralAccessAllowed = false; m_peripheralAccessAllowed = false;
m_node.updatePeripherals( Collections.emptyMap() );
} }
updateAnim(); updateAnim();
m_node.invalidate();
} }
private String getConnectedPeripheralName() private void updateConnectedPeripherals()
{ {
IPeripheral periph = getConnectedPeripheral(); Map<String, IPeripheral> peripherals = m_peripheral.toMap();
if( periph != null ) if( peripherals.isEmpty() )
{ {
String type = periph.getType(); // If there are no peripherals then disable access and update the display state.
if( m_attachedPeripheralID < 0 ) m_peripheralAccessAllowed = false;
{ updateAnim();
m_attachedPeripheralID = IDAssigner.getNextIDFromFile( new File(
ComputerCraft.getWorldDir( getWorld() ),
"computer/lastid_" + type + ".txt"
) );
}
return type + "_" + m_attachedPeripheralID;
}
return null;
} }
private IPeripheral getConnectedPeripheral() m_node.updatePeripherals( peripherals );
{
if( m_peripheralAccessAllowed )
{
if( getPeripheralType() == PeripheralType.WiredModemWithCable )
{
EnumFacing facing = getDirection();
BlockPos neighbour = getPos().offset( facing );
IPeripheral peripheral = getPeripheral( getWorld(), neighbour, facing.getOpposite() );
return peripheral == null || peripheral instanceof WiredModemPeripheral ? null : peripheral;
}
}
return null;
}
public static IPeripheral getPeripheral( World world, BlockPos pos, EnumFacing facing )
{
Block block = world.getBlockState( pos ).getBlock();
if( block == ComputerCraft.Blocks.wiredModemFull || block == ComputerCraft.Blocks.cable ) return null;
return PeripheralUtil.getPeripheral( world, pos, facing );
} }
@Override @Override

View File

@ -13,7 +13,6 @@ import dan200.computercraft.api.network.wired.IWiredNode;
import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.shared.peripheral.common.BlockCable; import dan200.computercraft.shared.peripheral.common.BlockCable;
import dan200.computercraft.shared.peripheral.common.TilePeripheralBase; import dan200.computercraft.shared.peripheral.common.TilePeripheralBase;
import dan200.computercraft.shared.util.IDAssigner;
import dan200.computercraft.shared.wired.CapabilityWiredElement; import dan200.computercraft.shared.wired.CapabilityWiredElement;
import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagCompound;
@ -24,11 +23,9 @@ import net.minecraft.util.math.Vec3d;
import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.Constants;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.io.File;
import java.util.*; import java.util.*;
public class TileWiredModemFull extends TilePeripheralBase public class TileWiredModemFull extends TilePeripheralBase
@ -76,20 +73,12 @@ public class TileWiredModemFull extends TilePeripheralBase
BlockPos pos = m_entity.getPos(); BlockPos pos = m_entity.getPos();
return new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ); return new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 );
} }
@Nonnull
@Override
public Map<String, IPeripheral> getPeripherals()
{
return m_entity.getPeripherals();
}
} }
private WiredModemPeripheral[] m_modems = new WiredModemPeripheral[6]; private WiredModemPeripheral[] m_modems = new WiredModemPeripheral[6];
private boolean m_peripheralAccessAllowed = false; private boolean m_peripheralAccessAllowed = false;
private int[] m_attachedPeripheralIDs = new int[6]; private WiredModemLocalPeripheral[] m_peripherals = new WiredModemLocalPeripheral[6];
private String[] m_attachedPeripheralTypes = new String[6];
private boolean m_destroyed = false; private boolean m_destroyed = false;
private boolean m_connectionsFormed = false; private boolean m_connectionsFormed = false;
@ -99,7 +88,7 @@ public class TileWiredModemFull extends TilePeripheralBase
public TileWiredModemFull() public TileWiredModemFull()
{ {
Arrays.fill( m_attachedPeripheralIDs, -1 ); for( int i = 0; i < m_peripherals.length; i++ ) m_peripherals[i] = new WiredModemLocalPeripheral();
} }
private void remove() private void remove()
@ -152,18 +141,29 @@ public class TileWiredModemFull extends TilePeripheralBase
{ {
if( !world.isRemote && m_peripheralAccessAllowed ) if( !world.isRemote && m_peripheralAccessAllowed )
{ {
Map<String, IPeripheral> updated = getPeripherals(); boolean hasChanged = false;
for( EnumFacing facing : EnumFacing.VALUES )
if( updated.isEmpty() )
{ {
// If there are no peripherals then disable access and update the display state. hasChanged |= m_peripherals[facing.ordinal()].attach( world, getPos(), facing );
m_peripheralAccessAllowed = false;
updateAnim();
} }
// Always invalidate the node: it's more accurate than checking if the peripherals if( hasChanged ) updateConnectedPeripherals();
// have changed }
m_node.invalidate(); }
@Override
public void onNeighbourTileEntityChange( @Nonnull BlockPos neighbour )
{
if( !world.isRemote && m_peripheralAccessAllowed )
{
for( EnumFacing facing : EnumFacing.VALUES )
{
if( getPos().offset( facing ).equals( neighbour ) )
{
WiredModemLocalPeripheral peripheral = m_peripherals[facing.ordinal()];
if( peripheral.attach( world, getPos(), facing ) ) updateConnectedPeripherals();
}
}
} }
} }
@ -180,9 +180,9 @@ public class TileWiredModemFull extends TilePeripheralBase
if( !getWorld().isRemote ) if( !getWorld().isRemote )
{ {
// On server, we interacted if a peripheral was found // On server, we interacted if a peripheral was found
Set<String> oldPeriphName = getPeripherals().keySet(); Set<String> oldPeriphName = getConnectedPeripheralNames();
togglePeripheralAccess(); togglePeripheralAccess();
Set<String> periphName = getPeripherals().keySet(); Set<String> periphName = getConnectedPeripheralNames();
if( !Objects.equal( periphName, oldPeriphName ) ) if( !Objects.equal( periphName, oldPeriphName ) )
{ {
@ -220,17 +220,7 @@ public class TileWiredModemFull extends TilePeripheralBase
{ {
super.readFromNBT( tag ); super.readFromNBT( tag );
m_peripheralAccessAllowed = tag.getBoolean( "peripheralAccess" ); m_peripheralAccessAllowed = tag.getBoolean( "peripheralAccess" );
for( int i = 0; i < m_attachedPeripheralIDs.length; i++ ) for( int i = 0; i < m_peripherals.length; i++ ) m_peripherals[i].readNBT( tag, "_" + i );
{
if( tag.hasKey( "peripheralID_" + i, Constants.NBT.TAG_ANY_NUMERIC ) )
{
m_attachedPeripheralIDs[i] = tag.getInteger( "peripheralID_" + i );
}
if( tag.hasKey( "peripheralType_" + i, Constants.NBT.TAG_STRING ) )
{
m_attachedPeripheralTypes[i] = tag.getString( "peripheralType_" + i );
}
}
} }
@Nonnull @Nonnull
@ -239,17 +229,7 @@ public class TileWiredModemFull extends TilePeripheralBase
{ {
tag = super.writeToNBT( tag ); tag = super.writeToNBT( tag );
tag.setBoolean( "peripheralAccess", m_peripheralAccessAllowed ); tag.setBoolean( "peripheralAccess", m_peripheralAccessAllowed );
for( int i = 0; i < m_attachedPeripheralIDs.length; i++ ) for( int i = 0; i < m_peripherals.length; i++ ) m_peripherals[i].writeNBT( tag, "_" + i );
{
if( m_attachedPeripheralIDs[i] >= 0 )
{
tag.setInteger( "peripheralID_" + i, m_attachedPeripheralIDs[i] );
}
if( m_attachedPeripheralTypes[i] != null )
{
tag.setString( "peripheralType_" + i, m_attachedPeripheralTypes[i] );
}
}
return tag; return tag;
} }
@ -294,8 +274,16 @@ public class TileWiredModemFull extends TilePeripheralBase
if( !m_connectionsFormed ) if( !m_connectionsFormed )
{ {
m_connectionsFormed = true; m_connectionsFormed = true;
connectionsChanged(); connectionsChanged();
if( m_peripheralAccessAllowed ) m_node.invalidate(); if( m_peripheralAccessAllowed )
{
for( EnumFacing facing : EnumFacing.VALUES )
{
m_peripherals[facing.ordinal()].attach( world, getPos(), facing );
}
updateConnectedPeripherals();
}
} }
} }
@ -326,60 +314,63 @@ public class TileWiredModemFull extends TilePeripheralBase
{ {
if( !m_peripheralAccessAllowed ) if( !m_peripheralAccessAllowed )
{ {
m_peripheralAccessAllowed = true; boolean hasAny = false;
if( getPeripherals().isEmpty() ) for( EnumFacing facing : EnumFacing.VALUES )
{ {
m_peripheralAccessAllowed = false; WiredModemLocalPeripheral peripheral = m_peripherals[facing.ordinal()];
return; peripheral.attach( world, getPos(), facing );
hasAny |= peripheral.hasPeripheral();
} }
if( !hasAny ) return;
m_peripheralAccessAllowed = true;
m_node.updatePeripherals( getConnectedPeripherals() );
} }
else else
{ {
m_peripheralAccessAllowed = false; m_peripheralAccessAllowed = false;
for( WiredModemLocalPeripheral peripheral : m_peripherals ) peripheral.detach();
m_node.updatePeripherals( Collections.emptyMap() );
} }
updateAnim(); updateAnim();
m_node.invalidate();
} }
@Nonnull private Set<String> getConnectedPeripheralNames()
private Map<String, IPeripheral> getPeripherals() {
if( !m_peripheralAccessAllowed ) return Collections.emptySet();
Set<String> peripherals = new HashSet<>( 6 );
for( WiredModemLocalPeripheral m_peripheral : m_peripherals )
{
String name = m_peripheral.getConnectedName();
if( name != null ) peripherals.add( name );
}
return peripherals;
}
private Map<String, IPeripheral> getConnectedPeripherals()
{ {
if( !m_peripheralAccessAllowed ) return Collections.emptyMap(); if( !m_peripheralAccessAllowed ) return Collections.emptyMap();
Map<String, IPeripheral> peripherals = new HashMap<>( 6 ); Map<String, IPeripheral> peripherals = new HashMap<>( 6 );
for( EnumFacing facing : EnumFacing.VALUES ) for( WiredModemLocalPeripheral m_peripheral : m_peripherals ) m_peripheral.extendMap( peripherals );
{
BlockPos neighbour = getPos().offset( facing );
IPeripheral peripheral = TileCable.getPeripheral( getWorld(), neighbour, facing.getOpposite() );
if( peripheral != null && !(peripheral instanceof WiredModemPeripheral) )
{
String type = peripheral.getType();
int id = m_attachedPeripheralIDs[facing.ordinal()];
String oldType = m_attachedPeripheralTypes[facing.ordinal()];
if( id < 0 || !type.equals( oldType ) )
{
m_attachedPeripheralTypes[facing.ordinal()] = type;
id = m_attachedPeripheralIDs[facing.ordinal()] = IDAssigner.getNextIDFromFile( new File(
ComputerCraft.getWorldDir( getWorld() ),
"computer/lastid_" + type + ".txt"
) );
}
peripherals.put( type + "_" + id, peripheral );
}
}
return peripherals; return peripherals;
} }
private String getCachedPeripheralName( EnumFacing facing ) private void updateConnectedPeripherals()
{ {
if( !m_peripheralAccessAllowed ) return null; Map<String, IPeripheral> peripherals = getConnectedPeripherals();
if( peripherals.isEmpty() )
{
// If there are no peripherals then disable access and update the display state.
m_peripheralAccessAllowed = false;
updateAnim();
}
int id = m_attachedPeripheralIDs[facing.ordinal()]; m_node.updatePeripherals( peripherals );
String type = m_attachedPeripheralTypes[facing.ordinal()];
return id < 0 || type == null ? null : type + "_" + id;
} }
// IWiredElementTile // IWiredElementTile
@ -415,7 +406,7 @@ public class TileWiredModemFull extends TilePeripheralBase
@Override @Override
protected boolean canSeePeripheral( @Nonnull String peripheralName ) protected boolean canSeePeripheral( @Nonnull String peripheralName )
{ {
return !peripheralName.equals( getCachedPeripheralName( side ) ); return !peripheralName.equals( m_peripherals[side.ordinal()].getConnectedName() );
} }
@Nonnull @Nonnull

View File

@ -0,0 +1,139 @@
package dan200.computercraft.shared.peripheral.modem;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.shared.util.IDAssigner;
import dan200.computercraft.shared.util.PeripheralUtil;
import net.minecraft.block.Block;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.common.util.Constants;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.File;
import java.util.Collections;
import java.util.Map;
/**
* Represents a local peripheral exposed on the wired network
*
* This is responsible for getting the peripheral in world, tracking id and type and determining whether
* it has changed.
*/
public final class WiredModemLocalPeripheral
{
private int id;
private String type;
private IPeripheral peripheral;
/**
* Attach a new peripheral from the world
*
* @param world The world to search in
* @param origin The position to search from
* @param direction The direction so search in
* @return Whether the peripheral changed.
*/
public boolean attach( @Nonnull World world, @Nonnull BlockPos origin, @Nonnull EnumFacing direction )
{
IPeripheral oldPeripheral = this.peripheral;
IPeripheral peripheral = this.peripheral = getPeripheralFrom( world, origin, direction );
if( peripheral == null )
{
return oldPeripheral != null;
}
else
{
String type = peripheral.getType();
int id = this.id;
if( id > 0 && this.type == null )
{
// If we had an ID but no type, then just set the type.
this.type = type;
}
else if( id < 0 || !type.equals( this.type ) )
{
this.type = type;
this.id = IDAssigner.getNextIDFromFile( new File(
ComputerCraft.getWorldDir( world ),
"computer/lastid_" + type + ".txt"
) );
}
return oldPeripheral == null || !oldPeripheral.equals( peripheral );
}
}
/**
* Detach the current peripheral
*
* @return Whether the peripheral changed
*/
public boolean detach()
{
if( peripheral == null ) return false;
peripheral = null;
return true;
}
@Nullable
public String getConnectedName()
{
return peripheral != null ? type + "_" + id : null;
}
@Nullable
public IPeripheral getPeripheral()
{
return peripheral;
}
public boolean hasPeripheral()
{
return peripheral != null;
}
public void extendMap( @Nonnull Map<String, IPeripheral> peripherals )
{
if( peripheral != null ) peripherals.put( type + "_" + id, peripheral );
}
public Map<String, IPeripheral> toMap()
{
return peripheral == null
? Collections.emptyMap()
: Collections.singletonMap( type + "_" + id, peripheral );
}
public void writeNBT( @Nonnull NBTTagCompound tag, @Nonnull String suffix )
{
if( id >= 0 ) tag.setInteger( "peripheralID" + suffix, id );
if( type != null ) tag.setString( "peripheralType" + suffix, type );
}
public void readNBT( @Nonnull NBTTagCompound tag, @Nonnull String suffix )
{
id = tag.hasKey( "peripheralID" + suffix, Constants.NBT.TAG_ANY_NUMERIC )
? tag.getInteger( "peripheralID" + suffix ) : -1;
type = tag.hasKey( "peripheralType" + suffix, Constants.NBT.TAG_STRING )
? tag.getString( "peripheralType" + suffix ) : null;
}
private static IPeripheral getPeripheralFrom( World world, BlockPos pos, EnumFacing direction )
{
BlockPos offset = pos.offset( direction );
Block block = world.getBlockState( offset ).getBlock();
if( block == ComputerCraft.Blocks.wiredModemFull || block == ComputerCraft.Blocks.cable ) return null;
IPeripheral peripheral = PeripheralUtil.getPeripheral( world, offset, direction.getOpposite() );
return peripheral instanceof WiredModemPeripheral ? null : peripheral;
}
}

View File

@ -1,5 +1,7 @@
package dan200.computercraft.shared.wired; package dan200.computercraft.shared.wired;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import dan200.computercraft.api.network.Packet; import dan200.computercraft.api.network.Packet;
import dan200.computercraft.api.network.wired.IWiredNetwork; import dan200.computercraft.api.network.wired.IWiredNetwork;
import dan200.computercraft.api.network.wired.IWiredNode; import dan200.computercraft.api.network.wired.IWiredNode;
@ -283,9 +285,10 @@ public final class WiredNetwork implements IWiredNetwork
} }
@Override @Override
public void invalidate( @Nonnull IWiredNode node ) public void updatePeripherals( @Nonnull IWiredNode node, @Nonnull Map<String, IPeripheral> newPeripherals )
{ {
WiredNode wired = checkNode( node ); WiredNode wired = checkNode( node );
Preconditions.checkNotNull( peripherals, "peripherals cannot be null" );
lock.writeLock().lock(); lock.writeLock().lock();
try try
@ -293,11 +296,10 @@ public final class WiredNetwork implements IWiredNetwork
if( wired.network != this ) throw new IllegalStateException( "Node is not on this network" ); if( wired.network != this ) throw new IllegalStateException( "Node is not on this network" );
Map<String, IPeripheral> oldPeripherals = wired.peripherals; Map<String, IPeripheral> oldPeripherals = wired.peripherals;
Map<String, IPeripheral> newPeripherals = wired.element.getPeripherals();
WiredNetworkChange change = WiredNetworkChange.changeOf( oldPeripherals, newPeripherals ); WiredNetworkChange change = WiredNetworkChange.changeOf( oldPeripherals, newPeripherals );
if( change.isEmpty() ) return; if( change.isEmpty() ) return;
wired.peripherals = newPeripherals; wired.peripherals = ImmutableMap.copyOf( newPeripherals );
// Detach the old peripherals then remove them. // Detach the old peripherals then remove them.
peripherals.keySet().removeAll( change.peripheralsRemoved().keySet() ); peripherals.keySet().removeAll( change.peripheralsRemoved().keySet() );

View File

@ -23,7 +23,6 @@ import org.junit.Test;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Collections;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
@ -379,17 +378,10 @@ public class NetworkTest
remotePeripherals.putAll( change.peripheralsAdded() ); remotePeripherals.putAll( change.peripheralsAdded() );
} }
@Nonnull
@Override
public Map<String, IPeripheral> getPeripherals()
{
return Collections.unmodifiableMap( localPeripherals );
}
public NetworkElement addPeripheral( String name ) public NetworkElement addPeripheral( String name )
{ {
localPeripherals.put( name, new NetworkPeripheral() ); localPeripherals.put( name, new NetworkPeripheral() );
getNode().invalidate(); getNode().updatePeripherals( localPeripherals );
return this; return this;
} }