Skip to content

Commit

Permalink
Merge pull request #5 from SquidDev-CC/feature/network-api
Browse files Browse the repository at this point in the history
Well, how badly can this go?
  • Loading branch information
SquidDev authored Feb 21, 2018
2 parents 15a3882 + 922f424 commit 9be61ab
Show file tree
Hide file tree
Showing 45 changed files with 3,133 additions and 697 deletions.
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ dependencies {
deobfProvided "mezz.jei:jei_1.12:4.7.5.86:api"
runtime "mezz.jei:jei_1.12:4.7.5.86"
shade 'org.squiddev:Cobalt:0.3.1'

testCompile 'junit:junit:4.11'
}

javadoc {
Expand Down
36 changes: 36 additions & 0 deletions src/main/java/dan200/computercraft/ComputerCraft.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
import dan200.computercraft.api.media.IMedia;
import dan200.computercraft.api.media.IMediaProvider;
import dan200.computercraft.api.network.IPacketNetwork;
import dan200.computercraft.api.network.wired.IWiredElement;
import dan200.computercraft.api.network.wired.IWiredNode;
import dan200.computercraft.api.network.wired.IWiredProvider;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.peripheral.IPeripheralProvider;
import dan200.computercraft.api.permissions.ITurtlePermissionProvider;
Expand Down Expand Up @@ -44,6 +47,7 @@
import dan200.computercraft.shared.network.PacketHandler;
import dan200.computercraft.shared.peripheral.common.BlockCable;
import dan200.computercraft.shared.peripheral.common.BlockPeripheral;
import dan200.computercraft.shared.peripheral.common.BlockWiredModemFull;
import dan200.computercraft.shared.peripheral.diskdrive.TileDiskDrive;
import dan200.computercraft.shared.peripheral.modem.BlockAdvancedModem;
import dan200.computercraft.shared.peripheral.modem.WirelessNetwork;
Expand All @@ -57,6 +61,7 @@
import dan200.computercraft.shared.turtle.blocks.TileTurtle;
import dan200.computercraft.shared.turtle.upgrades.*;
import dan200.computercraft.shared.util.*;
import dan200.computercraft.shared.wired.WiredNode;
import io.netty.buffer.Unpooled;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
Expand All @@ -69,6 +74,7 @@
import net.minecraft.util.NonNullList;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.common.config.ConfigCategory;
import net.minecraftforge.common.config.Configuration;
Expand Down Expand Up @@ -175,6 +181,7 @@ public static class Blocks
public static BlockTurtle turtleAdvanced;
public static BlockCommandComputer commandComputer;
public static BlockAdvancedModem advancedModem;
public static BlockWiredModemFull wiredModemFull;
}

public static class Items
Expand Down Expand Up @@ -259,6 +266,7 @@ public static class Config {
private static List<ITurtlePermissionProvider> permissionProviders = new ArrayList<>();
private static final Map<String, IPocketUpgrade> pocketUpgrades = new HashMap<>();
private static final Set<ILuaAPIFactory> apiFactories = new LinkedHashSet<>();
private static final Set<IWiredProvider> wiredProviders = new LinkedHashSet<>();

// Implementation
@Mod.Instance( value = ComputerCraft.MOD_ID )
Expand Down Expand Up @@ -730,6 +738,16 @@ public static void registerAPIFactory( ILuaAPIFactory provider )
}
}

public static void registerWiredProvider( IWiredProvider provider )
{
if( provider != null ) wiredProviders.add( provider );
}

public static IWiredNode createWiredNodeForElement( IWiredElement element )
{
return new WiredNode( element );
}

public static IPeripheral getPeripheralAt( World world, BlockPos pos, EnumFacing side )
{
// Try the handlers in order:
Expand All @@ -751,6 +769,24 @@ public static IPeripheral getPeripheralAt( World world, BlockPos pos, EnumFacing
return null;
}

public static IWiredElement getWiredElementAt( IBlockAccess world, BlockPos pos, EnumFacing side )
{
// Try the handlers in order:
for( IWiredProvider provider : wiredProviders )
{
try
{
IWiredElement element = provider.getElement( world, pos, side );
if( element != null ) return element;
}
catch( Exception e )
{
ComputerCraft.log.error( "Wired element provider " + provider + " errored.", e );
}
}
return null;
}

public static int getDefaultBundledRedstoneOutput( World world, BlockPos pos, EnumFacing side )
{
if( WorldUtil.isBlockInWorld( world, pos ) )
Expand Down
91 changes: 91 additions & 0 deletions src/main/java/dan200/computercraft/api/ComputerCraftAPI.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
import dan200.computercraft.api.media.IMedia;
import dan200.computercraft.api.media.IMediaProvider;
import dan200.computercraft.api.network.IPacketNetwork;
import dan200.computercraft.api.network.wired.IWiredElement;
import dan200.computercraft.api.network.wired.IWiredNode;
import dan200.computercraft.api.network.wired.IWiredProvider;
import dan200.computercraft.api.peripheral.IComputerAccess;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.peripheral.IPeripheralProvider;
Expand All @@ -21,6 +24,7 @@
import dan200.computercraft.api.turtle.ITurtleUpgrade;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;

import javax.annotation.Nonnull;
Expand Down Expand Up @@ -328,6 +332,81 @@ public static void registerAPIFactory( @Nonnull ILuaAPIFactory upgrade )
}
}

/**
* Registers a peripheral handler to convert blocks into {@link IPeripheral} implementations.
*
* @param handler The peripheral provider to register.
* @see dan200.computercraft.api.peripheral.IPeripheral
* @see dan200.computercraft.api.peripheral.IPeripheralProvider
*/
public static void registerWiredProvider( @Nonnull IWiredProvider handler )
{
findCC();
if ( computerCraft_registerWiredProvider != null)
{
try {
computerCraft_registerWiredProvider.invoke( null, handler );
} catch (Exception e){
// It failed
}
}
}

/**
* Construct a new wired node for a given wired element
*
* @param element The element to construct it for
* @return The element's node
* @see IWiredElement#getNode()
*/
@Nonnull
public static IWiredNode createWiredNodeForElement( @Nonnull IWiredElement element )
{
findCC();
if( computerCraft_createWiredNodeForElement != null )
{
try
{
return (IWiredNode) computerCraft_createWiredNodeForElement.invoke( null, element );
}
catch( ReflectiveOperationException e )
{
throw new IllegalStateException( "Error creating wired node", e );
}
}
else
{
throw new IllegalStateException( "ComputerCraft cannot be found" );
}
}

/**
* Get the wired network element for a block in world
*
* @param world The world the block exists in
* @param pos The position the block exists in
* @param side The side to extract the network element from
* @return The element's node
* @see IWiredElement#getNode()
*/
@Nullable
public static IWiredElement getWiredElementAt( @Nonnull IBlockAccess world, @Nonnull BlockPos pos, @Nonnull EnumFacing side )
{
findCC();
if( computerCraft_getWiredElementAt != null )
{
try
{
return (IWiredElement) computerCraft_getWiredElementAt.invoke( null, world, pos, side );
}
catch( ReflectiveOperationException ignored )
{
}
}

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.
Expand Down Expand Up @@ -374,6 +453,15 @@ private static void findCC()
computerCraft_registerAPIFactory = findCCMethod( "registerAPIFactory", new Class<?>[] {
ILuaAPIFactory.class
} );
computerCraft_registerWiredProvider = findCCMethod( "registerWiredProvider", new Class<?>[] {
IWiredProvider.class
} );
computerCraft_createWiredNodeForElement = findCCMethod( "createWiredNodeForElement", new Class<?>[] {
IWiredElement.class
} );
computerCraft_getWiredElementAt = findCCMethod( "getWiredElementAt", new Class<?>[]{
IBlockAccess.class, BlockPos.class, EnumFacing.class
} );
} catch( Exception e ) {
System.out.println( "ComputerCraftAPI: ComputerCraft not found." );
} finally {
Expand Down Expand Up @@ -411,4 +499,7 @@ private static Method findCCMethod( String name, Class<?>[] args )
private static Method computerCraft_registerPocketUpgrade = null;
private static Method computerCraft_getWirelessNetwork = null;
private static Method computerCraft_registerAPIFactory = null;
private static Method computerCraft_registerWiredProvider = null;
private static Method computerCraft_createWiredNodeForElement = null;
private static Method computerCraft_getWiredElementAt = null;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package dan200.computercraft.api.network.wired;

import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.peripheral.IPeripheral;

import javax.annotation.Nonnull;
import java.util.Collections;
import java.util.Map;

/**
* An object which may be part of a wired network.
*
* Elements should construct a node using {@link ComputerCraftAPI#createWiredNodeForElement(IWiredElement)}. This acts
* as a proxy for all network objects. Whilst the node may change networks, an element's node should remain constant
* for its lifespan.
*
* Elements are generally tied to a block or tile entity in world. One should either register an {@link IWiredProvider}
* or implement {@link IWiredElementTile} on your tile entity.
*
* @see IWiredProvider
* @see ComputerCraftAPI#registerWiredProvider(IWiredProvider)
* @see IWiredElementTile
*/
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
* peripherals change.
*
* @param change The change which occurred.
* @see IWiredNetworkChange
*/
default void networkChanged( @Nonnull IWiredNetworkChange change )
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package dan200.computercraft.api.network.wired;

import net.minecraft.util.EnumFacing;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

/**
* A {@link net.minecraft.tileentity.TileEntity} which provides a {@link IWiredElement}. This acts
* as a simpler alternative to a full-blown {@link IWiredProvider}.
*/
public interface IWiredElementTile
{
/**
* Get the wired element of this tile for a given side.
*
* @param side The side to get the network element from.
* @return A network element, or {@code null} if there is no element here.
*/
@Nullable
IWiredElement getWiredElement( @Nonnull EnumFacing side );
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package dan200.computercraft.api.network.wired;

import javax.annotation.Nonnull;

/**
* A wired network is composed of one of more {@link IWiredNode}s, a set of connections between them, and a series
* of peripherals.
*
* Networks from a connected graph. This means there is some path between all nodes on the network. Further more, if
* there is some path between two nodes then they must be on the same network. {@link IWiredNetwork} will automatically
* handle the merging and splitting of networks (and thus changing of available nodes and peripherals) as connections
* change.
*
* This does mean one can not rely on the network remaining consistent between subsequent operations. Consequently,
* it is generally preferred to use the methods provided by {@link IWiredNode}.
*
* @see IWiredNode#getNetwork()
*/
public interface IWiredNetwork
{
/**
* Create a connection between two nodes.
*
* This should only be used on the server thread.
*
* @param left The first node to connect
* @param right The second node to connect
* @return {@code true} if a connection was created or {@code false} if the connection already exists.
* @throws IllegalStateException If neither node is on the network.
* @throws IllegalArgumentException If {@code left} and {@code right} are equal.
* @see IWiredNode#connectTo(IWiredNode)
* @see IWiredNetwork#connect(IWiredNode, IWiredNode)
*/
boolean connect( @Nonnull IWiredNode left, @Nonnull IWiredNode right );

/**
* Destroy a connection between this node and another.
*
* This should only be used on the server thread.
*
* @param left The first node in the connection.
* @param right The second node in the connection.
* @return {@code true} if a connection was destroyed or {@code false} if no connection exists.
* @throws IllegalArgumentException If either node is not on the network.
* @throws IllegalArgumentException If {@code left} and {@code right} are equal.
* @see IWiredNode#disconnectFrom(IWiredNode)
* @see IWiredNetwork#connect(IWiredNode, IWiredNode)
*/
boolean disconnect( @Nonnull IWiredNode left, @Nonnull IWiredNode right );

/**
* Sever all connections this node has, removing it from this network.
*
* This should only be used on the server thread.
*
* @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
* only element.
* @throws IllegalArgumentException If the node is not in the network.
* @see IWiredNode#remove()
*/
boolean remove( @Nonnull IWiredNode node );

/**
* Mark this node's peripherals as having changed.
*
* This should only be used on the server thread.
*
* @param node The node to mark as invalid.
* @throws IllegalArgumentException If the node is not in the network.
* @see IWiredElement#getPeripherals()
*/
void invalidate( @Nonnull IWiredNode node );
}
Loading

0 comments on commit 9be61ab

Please sign in to comment.