mirror of
				https://github.com/SquidDev-CC/CC-Tweaked
				synced 2025-10-31 13:42:59 +00:00 
			
		
		
		
	Allow peripherals to have multiple types (#963)
Peripherals can now have multiple types:
 - A single primary type. This is the same as the current idea of a
   type - some identifier which (mostly) uniquely identifies this kind
   of peripheral. For instance, "speaker" or "minecraft:chest".
 - 0 or more "additional" types. These are more like traits, and
   describe what other behaviour the peripheral has - is it an
   inventory? Does it supply additional peripherals (like a wired
   modem)?.
This is mostly intended for the generic peripheral system, but it might
prove useful elsewhere too - we'll have to see!
 - peripheral.getType (and modem.getTypeRemote) now returns 1 or more
   values, rather than exactly one.
 - Add a new peripheral.hasType (and modem.hasTypeRemote) function which
   determines if a peripheral has the given type (primary or
   additional).
 - Change peripheral.find and all internal peripheral methods to use
   peripheral.hasType instead.
 - Update the peripherals program to show all types
This effectively allows you to do things like
`peripheral.find("inventory")` to find all inventories.
This also rewrites the introduction to the peripheral API, hopefully
making it a little more useful.
			
			
This commit is contained in:
		| @@ -2,7 +2,7 @@ | |||||||
| module: [kind=event] redstone | module: [kind=event] redstone | ||||||
| --- | --- | ||||||
| 
 | 
 | ||||||
| The @{redstone} event is fired whenever any redstone inputs on the computer change. | The @{event!redstone} event is fired whenever any redstone inputs on the computer change. | ||||||
| 
 | 
 | ||||||
| ## Example | ## Example | ||||||
| Prints a message when a redstone input changes: | Prints a message when a redstone input changes: | ||||||
|   | |||||||
| @@ -10,6 +10,8 @@ import net.minecraftforge.common.capabilities.Capability; | |||||||
| 
 | 
 | ||||||
| import javax.annotation.Nonnull; | import javax.annotation.Nonnull; | ||||||
| import javax.annotation.Nullable; | import javax.annotation.Nullable; | ||||||
|  | import java.util.Collections; | ||||||
|  | import java.util.Set; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * The interface that defines a peripheral. |  * The interface that defines a peripheral. | ||||||
| @@ -31,6 +33,18 @@ public interface IPeripheral | |||||||
|     @Nonnull |     @Nonnull | ||||||
|     String getType(); |     String getType(); | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * Return additional types/traits associated with this object. | ||||||
|  |      * | ||||||
|  |      * @return A collection of additional object traits. | ||||||
|  |      * @see PeripheralType#getAdditionalTypes() | ||||||
|  |      */ | ||||||
|  |     @Nonnull | ||||||
|  |     default Set<String> getAdditionalTypes() | ||||||
|  |     { | ||||||
|  |         return Collections.emptySet(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * Is called when when a computer is attaching to the peripheral. |      * Is called when when a computer is attaching to the peripheral. | ||||||
|      * |      * | ||||||
|   | |||||||
| @@ -6,9 +6,13 @@ | |||||||
| package dan200.computercraft.api.peripheral; | package dan200.computercraft.api.peripheral; | ||||||
| 
 | 
 | ||||||
| import com.google.common.base.Strings; | import com.google.common.base.Strings; | ||||||
|  | import com.google.common.collect.ImmutableSet; | ||||||
| 
 | 
 | ||||||
| import javax.annotation.Nonnull; | import javax.annotation.Nonnull; | ||||||
| import javax.annotation.Nullable; | import javax.annotation.Nullable; | ||||||
|  | import java.util.Collection; | ||||||
|  | import java.util.Collections; | ||||||
|  | import java.util.Set; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * The type of a {@link GenericPeripheral}. |  * The type of a {@link GenericPeripheral}. | ||||||
| @@ -18,13 +22,19 @@ import javax.annotation.Nullable; | |||||||
|  */ |  */ | ||||||
| public final class PeripheralType | public final class PeripheralType | ||||||
| { | { | ||||||
|     private static final PeripheralType UNTYPED = new PeripheralType( null ); |     private static final PeripheralType UNTYPED = new PeripheralType( null, Collections.emptySet() ); | ||||||
| 
 | 
 | ||||||
|     private final String type; |     private final String type; | ||||||
|  |     private final Set<String> additionalTypes; | ||||||
| 
 | 
 | ||||||
|     public PeripheralType( String type ) |     public PeripheralType( String type, Set<String> additionalTypes ) | ||||||
|     { |     { | ||||||
|         this.type = type; |         this.type = type; | ||||||
|  |         this.additionalTypes = additionalTypes; | ||||||
|  |         if( additionalTypes.contains( null ) ) | ||||||
|  |         { | ||||||
|  |             throw new IllegalArgumentException( "All additional types must be non-null" ); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| @@ -46,7 +56,55 @@ public final class PeripheralType | |||||||
|     public static PeripheralType ofType( @Nonnull String type ) |     public static PeripheralType ofType( @Nonnull String type ) | ||||||
|     { |     { | ||||||
|         if( Strings.isNullOrEmpty( type ) ) throw new IllegalArgumentException( "type cannot be null or empty" ); |         if( Strings.isNullOrEmpty( type ) ) throw new IllegalArgumentException( "type cannot be null or empty" ); | ||||||
|         return new PeripheralType( type ); |         return new PeripheralType( type, Collections.emptySet() ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Create a new non-empty peripheral type with additional traits. | ||||||
|  |      * | ||||||
|  |      * @param type            The name of the type. | ||||||
|  |      * @param additionalTypes Additional types, or "traits" of this peripheral. For instance, {@literal "inventory"}. | ||||||
|  |      * @return The constructed peripheral type. | ||||||
|  |      */ | ||||||
|  |     public static PeripheralType ofType( @Nonnull String type, Collection<String> additionalTypes ) | ||||||
|  |     { | ||||||
|  |         if( Strings.isNullOrEmpty( type ) ) throw new IllegalArgumentException( "type cannot be null or empty" ); | ||||||
|  |         return new PeripheralType( type, ImmutableSet.copyOf( additionalTypes ) ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Create a new non-empty peripheral type with additional traits. | ||||||
|  |      * | ||||||
|  |      * @param type            The name of the type. | ||||||
|  |      * @param additionalTypes Additional types, or "traits" of this peripheral. For instance, {@literal "inventory"}. | ||||||
|  |      * @return The constructed peripheral type. | ||||||
|  |      */ | ||||||
|  |     public static PeripheralType ofType( @Nonnull String type, @Nonnull String... additionalTypes ) | ||||||
|  |     { | ||||||
|  |         if( Strings.isNullOrEmpty( type ) ) throw new IllegalArgumentException( "type cannot be null or empty" ); | ||||||
|  |         return new PeripheralType( type, ImmutableSet.copyOf( additionalTypes ) ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Create a new peripheral type with no primary type but additional traits. | ||||||
|  |      * | ||||||
|  |      * @param additionalTypes Additional types, or "traits" of this peripheral. For instance, {@literal "inventory"}. | ||||||
|  |      * @return The constructed peripheral type. | ||||||
|  |      */ | ||||||
|  |     public static PeripheralType ofAdditional( Collection<String> additionalTypes ) | ||||||
|  |     { | ||||||
|  |         return new PeripheralType( null, ImmutableSet.copyOf( additionalTypes ) ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Create a new peripheral type with no primary type but additional traits. | ||||||
|  |      * | ||||||
|  |      * @param additionalTypes Additional types, or "traits" of this peripheral. For instance, {@literal "inventory"}. | ||||||
|  |      * @return The constructed peripheral type. | ||||||
|  |      */ | ||||||
|  |     public static PeripheralType ofAdditional( @Nonnull String... additionalTypes ) | ||||||
|  |     { | ||||||
|  |         return new PeripheralType( null, ImmutableSet.copyOf( additionalTypes ) ); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| @@ -59,4 +117,15 @@ public final class PeripheralType | |||||||
|     { |     { | ||||||
|         return type; |         return type; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Get any additional types or "traits" of this peripheral. These effectively act as a standard set of interfaces | ||||||
|  |      * a peripheral might have. | ||||||
|  |      * | ||||||
|  |      * @return All additional types. | ||||||
|  |      */ | ||||||
|  |     public Set<String> getAdditionalTypes() | ||||||
|  |     { | ||||||
|  |         return additionalTypes; | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -17,6 +17,7 @@ import dan200.computercraft.core.asm.NamedMethod; | |||||||
| import dan200.computercraft.core.asm.PeripheralMethod; | import dan200.computercraft.core.asm.PeripheralMethod; | ||||||
| import dan200.computercraft.core.computer.ComputerSide; | import dan200.computercraft.core.computer.ComputerSide; | ||||||
| import dan200.computercraft.core.tracking.TrackingField; | import dan200.computercraft.core.tracking.TrackingField; | ||||||
|  | import dan200.computercraft.shared.util.LuaUtil; | ||||||
| 
 | 
 | ||||||
| import javax.annotation.Nonnull; | import javax.annotation.Nonnull; | ||||||
| import javax.annotation.Nullable; | import javax.annotation.Nullable; | ||||||
| @@ -36,6 +37,7 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange | |||||||
|         private final IPeripheral peripheral; |         private final IPeripheral peripheral; | ||||||
| 
 | 
 | ||||||
|         private final String type; |         private final String type; | ||||||
|  |         private final Set<String> additionalTypes; | ||||||
|         private final Map<String, PeripheralMethod> methodMap; |         private final Map<String, PeripheralMethod> methodMap; | ||||||
|         private boolean attached; |         private boolean attached; | ||||||
| 
 | 
 | ||||||
| @@ -47,6 +49,7 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange | |||||||
|             attached = false; |             attached = false; | ||||||
| 
 | 
 | ||||||
|             type = Objects.requireNonNull( peripheral.getType(), "Peripheral type cannot be null" ); |             type = Objects.requireNonNull( peripheral.getType(), "Peripheral type cannot be null" ); | ||||||
|  |             additionalTypes = peripheral.getAdditionalTypes(); | ||||||
| 
 | 
 | ||||||
|             methodMap = PeripheralAPI.getMethods( peripheral ); |             methodMap = PeripheralAPI.getMethods( peripheral ); | ||||||
|         } |         } | ||||||
| @@ -61,6 +64,11 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange | |||||||
|             return type; |             return type; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         public Set<String> getAdditionalTypes() | ||||||
|  |         { | ||||||
|  |             return additionalTypes; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         public Collection<String> getMethods() |         public Collection<String> getMethods() | ||||||
|         { |         { | ||||||
|             return methodMap.keySet(); |             return methodMap.keySet(); | ||||||
| @@ -298,7 +306,23 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange | |||||||
|         synchronized( peripherals ) |         synchronized( peripherals ) | ||||||
|         { |         { | ||||||
|             PeripheralWrapper p = peripherals[side.ordinal()]; |             PeripheralWrapper p = peripherals[side.ordinal()]; | ||||||
|             if( p != null ) return new Object[] { p.getType() }; |             return p == null ? null : LuaUtil.consArray( p.getType(), p.getAdditionalTypes() ); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @LuaFunction | ||||||
|  |     public final Object[] hasType( String sideName, String type ) | ||||||
|  |     { | ||||||
|  |         ComputerSide side = ComputerSide.valueOfInsensitive( sideName ); | ||||||
|  |         if( side == null ) return null; | ||||||
|  | 
 | ||||||
|  |         synchronized( peripherals ) | ||||||
|  |         { | ||||||
|  |             PeripheralWrapper p = peripherals[side.ordinal()]; | ||||||
|  |             if( p != null ) | ||||||
|  |             { | ||||||
|  |                 return new Object[] { p.getType().equals( type ) || p.getAdditionalTypes().contains( type ) }; | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|         return null; |         return null; | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -18,18 +18,21 @@ import net.minecraft.util.ResourceLocation; | |||||||
| import javax.annotation.Nonnull; | import javax.annotation.Nonnull; | ||||||
| import javax.annotation.Nullable; | import javax.annotation.Nullable; | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  | import java.util.Set; | ||||||
| 
 | 
 | ||||||
| class GenericPeripheral implements IDynamicPeripheral | class GenericPeripheral implements IDynamicPeripheral | ||||||
| { | { | ||||||
|     private final String type; |     private final String type; | ||||||
|  |     private final Set<String> additionalTypes; | ||||||
|     private final TileEntity tile; |     private final TileEntity tile; | ||||||
|     private final List<SaturatedMethod> methods; |     private final List<SaturatedMethod> methods; | ||||||
| 
 | 
 | ||||||
|     GenericPeripheral( TileEntity tile, String name, List<SaturatedMethod> methods ) |     GenericPeripheral( TileEntity tile, String name, Set<String> additionalTypes, List<SaturatedMethod> methods ) | ||||||
|     { |     { | ||||||
|         ResourceLocation type = tile.getType().getRegistryName(); |         ResourceLocation type = tile.getType().getRegistryName(); | ||||||
|         this.tile = tile; |         this.tile = tile; | ||||||
|         this.type = name != null ? name : (type != null ? type.toString() : "unknown"); |         this.type = name != null ? name : (type != null ? type.toString() : "unknown"); | ||||||
|  |         this.additionalTypes = additionalTypes; | ||||||
|         this.methods = methods; |         this.methods = methods; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @@ -56,6 +59,13 @@ class GenericPeripheral implements IDynamicPeripheral | |||||||
|         return type; |         return type; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     @Nonnull | ||||||
|  |     @Override | ||||||
|  |     public Set<String> getAdditionalTypes() | ||||||
|  |     { | ||||||
|  |         return additionalTypes; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     @Nullable |     @Nullable | ||||||
|     @Override |     @Override | ||||||
|     public Object getTarget() |     public Object getTarget() | ||||||
|   | |||||||
| @@ -20,9 +20,7 @@ import net.minecraftforge.common.util.NonNullConsumer; | |||||||
| 
 | 
 | ||||||
| import javax.annotation.Nonnull; | import javax.annotation.Nonnull; | ||||||
| import javax.annotation.Nullable; | import javax.annotation.Nullable; | ||||||
| import java.util.ArrayList; | import java.util.*; | ||||||
| import java.util.List; |  | ||||||
| import java.util.Objects; |  | ||||||
| 
 | 
 | ||||||
| public class GenericPeripheralProvider | public class GenericPeripheralProvider | ||||||
| { | { | ||||||
| @@ -62,15 +60,16 @@ public class GenericPeripheralProvider | |||||||
| 
 | 
 | ||||||
|     private static class GenericPeripheralBuilder |     private static class GenericPeripheralBuilder | ||||||
|     { |     { | ||||||
|         String name; |         private String name; | ||||||
|         final ArrayList<SaturatedMethod> methods = new ArrayList<>( 0 ); |         private final Set<String> additionalTypes = new HashSet<>( 0 ); | ||||||
|  |         private final ArrayList<SaturatedMethod> methods = new ArrayList<>( 0 ); | ||||||
| 
 | 
 | ||||||
|         IPeripheral toPeripheral( TileEntity tile ) |         IPeripheral toPeripheral( TileEntity tile ) | ||||||
|         { |         { | ||||||
|             if( methods.isEmpty() ) return null; |             if( methods.isEmpty() ) return null; | ||||||
| 
 | 
 | ||||||
|             methods.trimToSize(); |             methods.trimToSize(); | ||||||
|             return new GenericPeripheral( tile, name, methods ); |             return new GenericPeripheral( tile, name, additionalTypes, methods ); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         void addMethods( Object target, List<NamedMethod<PeripheralMethod>> methods ) |         void addMethods( Object target, List<NamedMethod<PeripheralMethod>> methods ) | ||||||
| @@ -89,6 +88,7 @@ public class GenericPeripheralProvider | |||||||
|                     String name = type.getPrimaryType(); |                     String name = type.getPrimaryType(); | ||||||
|                     if( this.name == null || this.name.compareTo( name ) > 0 ) this.name = name; |                     if( this.name == null || this.name.compareTo( name ) > 0 ) this.name = name; | ||||||
|                 } |                 } | ||||||
|  |                 if( type != null ) additionalTypes.addAll( type.getAdditionalTypes() ); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -6,8 +6,9 @@ | |||||||
| package dan200.computercraft.shared.peripheral.generic.methods; | package dan200.computercraft.shared.peripheral.generic.methods; | ||||||
| 
 | 
 | ||||||
| import dan200.computercraft.ComputerCraft; | import dan200.computercraft.ComputerCraft; | ||||||
| import dan200.computercraft.api.lua.GenericSource; |  | ||||||
| import dan200.computercraft.api.lua.LuaFunction; | import dan200.computercraft.api.lua.LuaFunction; | ||||||
|  | import dan200.computercraft.api.peripheral.GenericPeripheral; | ||||||
|  | import dan200.computercraft.api.peripheral.PeripheralType; | ||||||
| import net.minecraft.util.ResourceLocation; | import net.minecraft.util.ResourceLocation; | ||||||
| import net.minecraftforge.energy.IEnergyStorage; | import net.minecraftforge.energy.IEnergyStorage; | ||||||
| 
 | 
 | ||||||
| @@ -25,8 +26,15 @@ import javax.annotation.Nonnull; | |||||||
|  * |  * | ||||||
|  * @cc.module energy_storage |  * @cc.module energy_storage | ||||||
|  */ |  */ | ||||||
| public class EnergyMethods implements GenericSource | public class EnergyMethods implements GenericPeripheral | ||||||
| { | { | ||||||
|  |     @Nonnull | ||||||
|  |     @Override | ||||||
|  |     public PeripheralType getType() | ||||||
|  |     { | ||||||
|  |         return PeripheralType.ofAdditional( "energy_storage" ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     @Nonnull |     @Nonnull | ||||||
|     @Override |     @Override | ||||||
|     public ResourceLocation id() |     public ResourceLocation id() | ||||||
|   | |||||||
| @@ -6,11 +6,12 @@ | |||||||
| package dan200.computercraft.shared.peripheral.generic.methods; | package dan200.computercraft.shared.peripheral.generic.methods; | ||||||
| 
 | 
 | ||||||
| import dan200.computercraft.ComputerCraft; | import dan200.computercraft.ComputerCraft; | ||||||
| import dan200.computercraft.api.lua.GenericSource; |  | ||||||
| import dan200.computercraft.api.lua.LuaException; | import dan200.computercraft.api.lua.LuaException; | ||||||
| import dan200.computercraft.api.lua.LuaFunction; | import dan200.computercraft.api.lua.LuaFunction; | ||||||
|  | import dan200.computercraft.api.peripheral.GenericPeripheral; | ||||||
| import dan200.computercraft.api.peripheral.IComputerAccess; | import dan200.computercraft.api.peripheral.IComputerAccess; | ||||||
| import dan200.computercraft.api.peripheral.IPeripheral; | import dan200.computercraft.api.peripheral.IPeripheral; | ||||||
|  | import dan200.computercraft.api.peripheral.PeripheralType; | ||||||
| import dan200.computercraft.shared.peripheral.generic.data.FluidData; | import dan200.computercraft.shared.peripheral.generic.data.FluidData; | ||||||
| import net.minecraft.fluid.Fluid; | import net.minecraft.fluid.Fluid; | ||||||
| import net.minecraft.tileentity.TileEntity; | import net.minecraft.tileentity.TileEntity; | ||||||
| @@ -35,8 +36,15 @@ import static dan200.computercraft.shared.peripheral.generic.methods.ArgumentHel | |||||||
|  * |  * | ||||||
|  * @cc.module fluid_storage |  * @cc.module fluid_storage | ||||||
|  */ |  */ | ||||||
| public class FluidMethods implements GenericSource | public class FluidMethods implements GenericPeripheral | ||||||
| { | { | ||||||
|  |     @Nonnull | ||||||
|  |     @Override | ||||||
|  |     public PeripheralType getType() | ||||||
|  |     { | ||||||
|  |         return PeripheralType.ofAdditional( "fluid_storage" ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     @Nonnull |     @Nonnull | ||||||
|     @Override |     @Override | ||||||
|     public ResourceLocation id() |     public ResourceLocation id() | ||||||
|   | |||||||
| @@ -6,11 +6,12 @@ | |||||||
| package dan200.computercraft.shared.peripheral.generic.methods; | package dan200.computercraft.shared.peripheral.generic.methods; | ||||||
| 
 | 
 | ||||||
| import dan200.computercraft.ComputerCraft; | import dan200.computercraft.ComputerCraft; | ||||||
| import dan200.computercraft.api.lua.GenericSource; |  | ||||||
| import dan200.computercraft.api.lua.LuaException; | import dan200.computercraft.api.lua.LuaException; | ||||||
| import dan200.computercraft.api.lua.LuaFunction; | import dan200.computercraft.api.lua.LuaFunction; | ||||||
|  | import dan200.computercraft.api.peripheral.GenericPeripheral; | ||||||
| import dan200.computercraft.api.peripheral.IComputerAccess; | import dan200.computercraft.api.peripheral.IComputerAccess; | ||||||
| import dan200.computercraft.api.peripheral.IPeripheral; | import dan200.computercraft.api.peripheral.IPeripheral; | ||||||
|  | import dan200.computercraft.api.peripheral.PeripheralType; | ||||||
| import dan200.computercraft.shared.peripheral.generic.data.ItemData; | import dan200.computercraft.shared.peripheral.generic.data.ItemData; | ||||||
| import net.minecraft.inventory.IInventory; | import net.minecraft.inventory.IInventory; | ||||||
| import net.minecraft.item.ItemStack; | import net.minecraft.item.ItemStack; | ||||||
| @@ -36,8 +37,15 @@ import static dan200.computercraft.shared.peripheral.generic.methods.ArgumentHel | |||||||
|  * |  * | ||||||
|  * @cc.module inventory |  * @cc.module inventory | ||||||
|  */ |  */ | ||||||
| public class InventoryMethods implements GenericSource | public class InventoryMethods implements GenericPeripheral | ||||||
| { | { | ||||||
|  |     @Nonnull | ||||||
|  |     @Override | ||||||
|  |     public PeripheralType getType() | ||||||
|  |     { | ||||||
|  |         return PeripheralType.ofAdditional( "inventory" ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     @Nonnull |     @Nonnull | ||||||
|     @Override |     @Override | ||||||
|     public ResourceLocation id() |     public ResourceLocation id() | ||||||
|   | |||||||
| @@ -21,6 +21,7 @@ import dan200.computercraft.core.apis.PeripheralAPI; | |||||||
| import dan200.computercraft.core.asm.PeripheralMethod; | import dan200.computercraft.core.asm.PeripheralMethod; | ||||||
| import dan200.computercraft.shared.peripheral.modem.ModemPeripheral; | import dan200.computercraft.shared.peripheral.modem.ModemPeripheral; | ||||||
| import dan200.computercraft.shared.peripheral.modem.ModemState; | import dan200.computercraft.shared.peripheral.modem.ModemState; | ||||||
|  | import dan200.computercraft.shared.util.LuaUtil; | ||||||
| import net.minecraft.world.World; | import net.minecraft.world.World; | ||||||
| 
 | 
 | ||||||
| import javax.annotation.Nonnull; | import javax.annotation.Nonnull; | ||||||
| @@ -118,13 +119,35 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW | |||||||
|      * @param name     The peripheral's name. |      * @param name     The peripheral's name. | ||||||
|      * @return The peripheral's name. |      * @return The peripheral's name. | ||||||
|      * @cc.treturn string|nil The peripheral's type, or {@code nil} if it is not present. |      * @cc.treturn string|nil The peripheral's type, or {@code nil} if it is not present. | ||||||
|  |      * @cc.changed 1.99 Peripherals can have multiple types - this function returns multiple values. | ||||||
|      * @see PeripheralAPI#getType |      * @see PeripheralAPI#getType | ||||||
|      */ |      */ | ||||||
|     @LuaFunction |     @LuaFunction | ||||||
|     public final Object[] getTypeRemote( IComputerAccess computer, String name ) |     public final Object[] getTypeRemote( IComputerAccess computer, String name ) | ||||||
|     { |     { | ||||||
|         RemotePeripheralWrapper wrapper = getWrapper( computer, name ); |         RemotePeripheralWrapper wrapper = getWrapper( computer, name ); | ||||||
|         return wrapper != null ? new Object[] { wrapper.getType() } : null; |         return wrapper == null ? null : LuaUtil.consArray( wrapper.getType(), wrapper.getAdditionalTypes() ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Check a peripheral is of a particular type. | ||||||
|  |      * | ||||||
|  |      * <blockquote><strong>Important:</strong> This function only appears on wired modems. Check {@link #isWireless} | ||||||
|  |      * returns false before calling it.</blockquote> | ||||||
|  |      * | ||||||
|  |      * @param computer The calling computer. | ||||||
|  |      * @param name     The peripheral's name. | ||||||
|  |      * @param type     The type to check. | ||||||
|  |      * @return The peripheral's name. | ||||||
|  |      * @cc.treturn boolean|nil If a peripheral has a particular type, or {@literal nil} if it is not present. | ||||||
|  |      * @cc.since 1.99 | ||||||
|  |      * @see PeripheralAPI#getType | ||||||
|  |      */ | ||||||
|  |     @LuaFunction | ||||||
|  |     public final Object[] hasTypeRemote( IComputerAccess computer, String name, String type ) | ||||||
|  |     { | ||||||
|  |         RemotePeripheralWrapper wrapper = getWrapper( computer, name ); | ||||||
|  |         return wrapper == null ? null : new Object[] { wrapper.getType().equals( type ) || wrapper.getAdditionalTypes().contains( getType() ) }; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| @@ -308,6 +331,7 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW | |||||||
|         private final String name; |         private final String name; | ||||||
| 
 | 
 | ||||||
|         private final String type; |         private final String type; | ||||||
|  |         private final Set<String> additionalTypes; | ||||||
|         private final Map<String, PeripheralMethod> methodMap; |         private final Map<String, PeripheralMethod> methodMap; | ||||||
| 
 | 
 | ||||||
|         private volatile boolean attached; |         private volatile boolean attached; | ||||||
| @@ -321,6 +345,7 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW | |||||||
|             this.name = name; |             this.name = name; | ||||||
| 
 | 
 | ||||||
|             type = Objects.requireNonNull( peripheral.getType(), "Peripheral type cannot be null" ); |             type = Objects.requireNonNull( peripheral.getType(), "Peripheral type cannot be null" ); | ||||||
|  |             additionalTypes = peripheral.getAdditionalTypes(); | ||||||
|             methodMap = PeripheralAPI.getMethods( peripheral ); |             methodMap = PeripheralAPI.getMethods( peripheral ); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @@ -354,6 +379,11 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW | |||||||
|             return type; |             return type; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         public Set<String> getAdditionalTypes() | ||||||
|  |         { | ||||||
|  |             return additionalTypes; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         public Collection<String> getMethodNames() |         public Collection<String> getMethodNames() | ||||||
|         { |         { | ||||||
|             return methodMap.keySet(); |             return methodMap.keySet(); | ||||||
|   | |||||||
							
								
								
									
										23
									
								
								src/main/java/dan200/computercraft/shared/util/LuaUtil.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/main/java/dan200/computercraft/shared/util/LuaUtil.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | |||||||
|  | /* | ||||||
|  |  * This file is part of ComputerCraft - http://www.computercraft.info | ||||||
|  |  * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. | ||||||
|  |  * Send enquiries to dratcliffe@gmail.com | ||||||
|  |  */ | ||||||
|  | package dan200.computercraft.shared.util; | ||||||
|  | 
 | ||||||
|  | import java.util.Collection; | ||||||
|  | 
 | ||||||
|  | public class LuaUtil | ||||||
|  | { | ||||||
|  |     public static Object[] consArray( Object value, Collection<?> rest ) | ||||||
|  |     { | ||||||
|  |         if( rest.isEmpty() ) return new Object[] { value }; | ||||||
|  | 
 | ||||||
|  |         // I'm not proud of this code. | ||||||
|  |         Object[] out = new Object[rest.size() + 1]; | ||||||
|  |         out[0] = value; | ||||||
|  |         int i = 1; | ||||||
|  |         for( Object additionalType : rest ) out[i++] = additionalType; | ||||||
|  |         return out; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,18 +1,90 @@ | |||||||
| --- The Peripheral API is for interacting with peripherals connected to the | --[[- Peripherals are blocks (or turtle and pocket computer upgrades) which can | ||||||
| -- computer, such as the Disk Drive, the Advanced Monitor and Monitor. | be controlled by a computer. For instance, the @{speaker} peripheral allows a | ||||||
| -- | computer to play music and the @{monitor} peripheral allows you to display text | ||||||
| -- Each peripheral block has a name, either referring to the side the peripheral | in the world. | ||||||
| -- can be found on, or a name on an adjacent wired network. |  | ||||||
| -- | ## Referencing peripherals | ||||||
| -- If the peripheral is next to the computer, its side is either `front`, |  | ||||||
| -- `back`, `left`, `right`, `top` or `bottom`. If the peripheral is attached by | Computers can interact with adjacent peripherals. Each peripheral is given a | ||||||
| -- a cable, its side will follow the format `type_id`, for example `printer_0`. | name based on which direction it is in. For instance, a disk drive below your | ||||||
| -- | computer will be called `"bottom"` in your Lua code, one to the left called | ||||||
| -- Peripheral functions are called *methods*, a term borrowed from Java. | `"left"` , and so on for all 6 directions (`"bottom"`, `"top"`, `"left"`, | ||||||
| -- | `"right"`, `"front"`, `"back"`). | ||||||
| -- @module peripheral |  | ||||||
| -- @since 1.3 | You can list the names of all peripherals with the `peripherals` program, or the | ||||||
| -- @changed 1.51 Add support for wired modems. | @{peripheral.getNames} function. | ||||||
|  |  | ||||||
|  | It's also possible to use peripherals which are further away from your computer | ||||||
|  | through the use of @{modem|Wired Modems}. Place one modem against your computer, | ||||||
|  | run Networking Cable to your peripheral, and then place another modem against | ||||||
|  | that block. You can then right click the modem to use (or *attach*) the | ||||||
|  | peripheral. This will print a peripheral name to chat, which can then be used | ||||||
|  | just like a direction name to access the peripheral. You can click on the message | ||||||
|  | to copy the name to your clipboard. | ||||||
|  |  | ||||||
|  | ## Using peripherals | ||||||
|  |  | ||||||
|  | Once you have the name of a peripheral, you can call functions on it using the | ||||||
|  | @{peripheral.call} function. This takes the name of our peripheral, the name of | ||||||
|  | the function we want to call, and then its arguments. | ||||||
|  |  | ||||||
|  | > Some bits of the peripheral API call peripheral functions *methods* instead | ||||||
|  | > (for example, the @{peripheral.getMethods} function). Don't worry, they're the | ||||||
|  | > same thing! | ||||||
|  |  | ||||||
|  | Let's say we have a monitor above our computer (and so "top") and want to | ||||||
|  | @{monitor.write|write some text to it}. We'd write the following: | ||||||
|  |  | ||||||
|  | ```lua | ||||||
|  | peripheral.call("top", "write", "This is displayed on a monitor!") | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | Once you start calling making a couple of peripheral calls this can get very | ||||||
|  | repetitive, and so we can @{peripheral.wrap|wrap} a peripheral. This builds a | ||||||
|  | table of all the peripheral's functions so you can use it like an API or module. | ||||||
|  |  | ||||||
|  | For instance, we could have written the above example as follows: | ||||||
|  |  | ||||||
|  | ```lua | ||||||
|  | local my_monitor = peripheral.wrap("top") | ||||||
|  | my_monitor.write("This is displayed on a monitor!") | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ## Finding peripherals | ||||||
|  |  | ||||||
|  | Sometimes when you're writing a program you don't care what a peripheral is | ||||||
|  | called, you just need to know it's there. For instance, if you're writing a | ||||||
|  | music player, you just need a speaker - it doesn't matter if it's above or below | ||||||
|  | the computer. | ||||||
|  |  | ||||||
|  | Thankfully there's a quick way to do this: @{peripheral.find}. This takes a | ||||||
|  | *peripheral type* and returns all the attached peripherals which are of this | ||||||
|  | type. | ||||||
|  |  | ||||||
|  | What is a peripheral type though? This is a string which describes what a | ||||||
|  | peripheral is, and so what functions are available on it. For instance, speakers | ||||||
|  | are just called `"speaker"`, and monitors `"monitor"`. Some peripherals might | ||||||
|  | have more than one type; a Minecraft chest is both a `"minecraft:chest"` and | ||||||
|  | `"inventory"`. | ||||||
|  |  | ||||||
|  | You can get all the types a peripheral has with @{peripheral.getType}, and check | ||||||
|  | a peripheral is a specific type with @{peripheral.hasType}. | ||||||
|  |  | ||||||
|  | To return to our original example, let's use @{peripheral.find} to find an | ||||||
|  | attached speaker: | ||||||
|  |  | ||||||
|  | ```lua | ||||||
|  | local speaker = peripheral.find("speaker") | ||||||
|  | speaker.playNote("harp") | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | @module peripheral | ||||||
|  | @see event!peripheral This event is fired whenever a new peripheral is attached. | ||||||
|  | @see event!peripheral_detach This event is fired whenever a peripheral is detached. | ||||||
|  | @since 1.3 | ||||||
|  | @changed 1.51 Add support for wired modems. | ||||||
|  | @changed 1.99 Peripherals can have multiple types. | ||||||
|  | ]] | ||||||
|  |  | ||||||
| local expect = dofile("rom/modules/main/cc/expect.lua").expect | local expect = dofile("rom/modules/main/cc/expect.lua").expect | ||||||
|  |  | ||||||
| @@ -33,7 +105,7 @@ function getNames() | |||||||
|         local side = sides[n] |         local side = sides[n] | ||||||
|         if native.isPresent(side) then |         if native.isPresent(side) then | ||||||
|             table.insert(results, side) |             table.insert(results, side) | ||||||
|             if native.getType(side) == "modem" and not native.call(side, "isWireless") then |             if native.hasType(side, "modem") and not native.call(side, "isWireless") then | ||||||
|                 local remote = native.call(side, "getNamesRemote") |                 local remote = native.call(side, "getNamesRemote") | ||||||
|                 for _, name in ipairs(remote) do |                 for _, name in ipairs(remote) do | ||||||
|                     table.insert(results, name) |                     table.insert(results, name) | ||||||
| @@ -58,7 +130,7 @@ function isPresent(name) | |||||||
|  |  | ||||||
|     for n = 1, #sides do |     for n = 1, #sides do | ||||||
|         local side = sides[n] |         local side = sides[n] | ||||||
|         if native.getType(side) == "modem" and not native.call(side, "isWireless") and |         if native.hasType(side, "modem") and not native.call(side, "isWireless") and | ||||||
|             native.call(side, "isPresentRemote", name) |             native.call(side, "isPresentRemote", name) | ||||||
|         then |         then | ||||||
|             return true |             return true | ||||||
| @@ -67,12 +139,17 @@ function isPresent(name) | |||||||
|     return false |     return false | ||||||
| end | end | ||||||
|  |  | ||||||
| --- Get the type of a wrapped peripheral, or a peripheral with the given name. | --[[- Get the types of a named or wrapped peripheral. | ||||||
| -- |  | ||||||
| -- @tparam string|table peripheral The name of the peripheral to find, or a | @tparam string|table peripheral The name of the peripheral to find, or a | ||||||
| -- wrapped peripheral instance. | wrapped peripheral instance. | ||||||
| -- @treturn string|nil The peripheral's type, or `nil` if it is not present. | @treturn string... The peripheral's types, or `nil` if it is not present. | ||||||
| -- @changed 1.88.0 Accepts a wrapped peripheral as an argument. | @changed 1.88.0 Accepts a wrapped peripheral as an argument. | ||||||
|  | @changed 1.99 Now returns multiple types. | ||||||
|  | @usage Get the type of a peripheral above this computer. | ||||||
|  |  | ||||||
|  |     peripheral.getType("top") | ||||||
|  | ]] | ||||||
| function getType(peripheral) | function getType(peripheral) | ||||||
|     expect(1, peripheral, "string", "table") |     expect(1, peripheral, "string", "table") | ||||||
|     if type(peripheral) == "string" then -- Peripheral name passed |     if type(peripheral) == "string" then -- Peripheral name passed | ||||||
| @@ -81,7 +158,7 @@ function getType(peripheral) | |||||||
|         end |         end | ||||||
|         for n = 1, #sides do |         for n = 1, #sides do | ||||||
|             local side = sides[n] |             local side = sides[n] | ||||||
|             if native.getType(side) == "modem" and not native.call(side, "isWireless") and |             if native.hasType(side, "modem") and not native.call(side, "isWireless") and | ||||||
|                 native.call(side, "isPresentRemote", peripheral) |                 native.call(side, "isPresentRemote", peripheral) | ||||||
|             then |             then | ||||||
|                 return native.call(side, "getTypeRemote", peripheral) |                 return native.call(side, "getTypeRemote", peripheral) | ||||||
| @@ -90,10 +167,43 @@ function getType(peripheral) | |||||||
|         return nil |         return nil | ||||||
|     else |     else | ||||||
|         local mt = getmetatable(peripheral) |         local mt = getmetatable(peripheral) | ||||||
|         if not mt or mt.__name ~= "peripheral" or type(mt.type) ~= "string" then |         if not mt or mt.__name ~= "peripheral" or type(mt.types) ~= "table" then | ||||||
|             error("bad argument #1 (table is not a peripheral)", 2) |             error("bad argument #1 (table is not a peripheral)", 2) | ||||||
|         end |         end | ||||||
|         return mt.type |         return table.unpack(mt.types) | ||||||
|  |     end | ||||||
|  | end | ||||||
|  |  | ||||||
|  | --[[- Check if a peripheral is of a particular type. | ||||||
|  |  | ||||||
|  | @tparam string|table peripheral The name of the peripheral or a wrapped peripheral instance. | ||||||
|  | @tparam string peripheral_type The type to check. | ||||||
|  |  | ||||||
|  | @treturn boolean|nil If a peripheral has a particular type, or `nil` if it is not present. | ||||||
|  | @since 1.99 | ||||||
|  | ]] | ||||||
|  | function hasType(peripheral, peripheral_type) | ||||||
|  |     expect(1, peripheral, "string", "table") | ||||||
|  |     expect(2, peripheral_type, "string") | ||||||
|  |     if type(peripheral) == "string" then -- Peripheral name passed | ||||||
|  |         if native.isPresent(peripheral) then | ||||||
|  |             return native.hasType(peripheral, peripheral_type) | ||||||
|  |         end | ||||||
|  |         for n = 1, #sides do | ||||||
|  |             local side = sides[n] | ||||||
|  |             if native.hasType(side, "modem") and not native.call(side, "isWireless") and | ||||||
|  |                 native.call(side, "isPresentRemote", peripheral) | ||||||
|  |             then | ||||||
|  |                 return native.call(side, "hasTypeRemote", peripheral, peripheral_type) | ||||||
|  |             end | ||||||
|  |         end | ||||||
|  |         return nil | ||||||
|  |     else | ||||||
|  |         local mt = getmetatable(peripheral) | ||||||
|  |         if not mt or mt.__name ~= "peripheral" or type(mt.types) ~= "table" then | ||||||
|  |             error("bad argument #1 (table is not a peripheral)", 2) | ||||||
|  |         end | ||||||
|  |         return mt.types[peripheral_type] ~= nil | ||||||
|     end |     end | ||||||
| end | end | ||||||
|  |  | ||||||
| @@ -109,7 +219,7 @@ function getMethods(name) | |||||||
|     end |     end | ||||||
|     for n = 1, #sides do |     for n = 1, #sides do | ||||||
|         local side = sides[n] |         local side = sides[n] | ||||||
|         if native.getType(side) == "modem" and not native.call(side, "isWireless") and |         if native.hasType(side, "modem") and not native.call(side, "isWireless") and | ||||||
|             native.call(side, "isPresentRemote", name) |             native.call(side, "isPresentRemote", name) | ||||||
|         then |         then | ||||||
|             return native.call(side, "getMethodsRemote", name) |             return native.call(side, "getMethodsRemote", name) | ||||||
| @@ -151,7 +261,7 @@ function call(name, method, ...) | |||||||
|  |  | ||||||
|     for n = 1, #sides do |     for n = 1, #sides do | ||||||
|         local side = sides[n] |         local side = sides[n] | ||||||
|         if native.getType(side) == "modem" and not native.call(side, "isWireless") and |         if native.hasType(side, "modem") and not native.call(side, "isWireless") and | ||||||
|             native.call(side, "isPresentRemote", name) |             native.call(side, "isPresentRemote", name) | ||||||
|         then |         then | ||||||
|             return native.call(side, "callRemote", name, method, ...) |             return native.call(side, "callRemote", name, method, ...) | ||||||
| @@ -160,15 +270,16 @@ function call(name, method, ...) | |||||||
|     return nil |     return nil | ||||||
| end | end | ||||||
|  |  | ||||||
| --- Get a table containing functions pointing to the peripheral's methods, which | --- Get a table containing all functions available on a peripheral. These can | ||||||
| -- can then be called as if using @{peripheral.call}. | -- then be called instead of using @{peripheral.call} every time. | ||||||
| -- | -- | ||||||
| -- @tparam string name The name of the peripheral to wrap. | -- @tparam string name The name of the peripheral to wrap. | ||||||
| -- @treturn table|nil The table containing the peripheral's methods, or `nil` if | -- @treturn table|nil The table containing the peripheral's methods, or `nil` if | ||||||
| -- there is no peripheral present with the given name. | -- there is no peripheral present with the given name. | ||||||
| -- @usage Open the modem on the top of this computer. | -- @usage Open the modem on the top of this computer. | ||||||
| -- | -- | ||||||
| --     peripheral.wrap("top").open(1) | --     local modem = peripheral.wrap("top") | ||||||
|  | --     modem.open(1) | ||||||
| function wrap(name) | function wrap(name) | ||||||
|     expect(1, name, "string") |     expect(1, name, "string") | ||||||
|  |  | ||||||
| @@ -177,10 +288,14 @@ function wrap(name) | |||||||
|         return nil |         return nil | ||||||
|     end |     end | ||||||
|  |  | ||||||
|  |     -- We store our types array as a list (for getType) and a lookup table (for hasType). | ||||||
|  |     local types = { peripheral.getType(name) } | ||||||
|  |     for i = 1, #types do types[types[i]] = true end | ||||||
|     local result = setmetatable({}, { |     local result = setmetatable({}, { | ||||||
|         __name = "peripheral", |         __name = "peripheral", | ||||||
|         name = name, |         name = name, | ||||||
|         type = peripheral.getType(name), |         type = types[1], | ||||||
|  |         types = types, | ||||||
|     }) |     }) | ||||||
|     for _, method in ipairs(methods) do |     for _, method in ipairs(methods) do | ||||||
|         result[method] = function(...) |         result[method] = function(...) | ||||||
| @@ -222,7 +337,7 @@ function find(ty, filter) | |||||||
|  |  | ||||||
|     local results = {} |     local results = {} | ||||||
|     for _, name in ipairs(peripheral.getNames()) do |     for _, name in ipairs(peripheral.getNames()) do | ||||||
|         if peripheral.getType(name) == ty then |         if peripheral.hasType(name, ty) then | ||||||
|             local wrapped = peripheral.wrap(name) |             local wrapped = peripheral.wrap(name) | ||||||
|             if filter == nil or filter(name, wrapped) then |             if filter == nil or filter(name, wrapped) then | ||||||
|                 table.insert(results, wrapped) |                 table.insert(results, wrapped) | ||||||
|   | |||||||
| @@ -3,7 +3,7 @@ print("Attached Peripherals:") | |||||||
| if #tPeripherals > 0 then | if #tPeripherals > 0 then | ||||||
|     for n = 1, #tPeripherals do |     for n = 1, #tPeripherals do | ||||||
|         local sPeripheral = tPeripherals[n] |         local sPeripheral = tPeripherals[n] | ||||||
|         print(sPeripheral .. " (" .. peripheral.getType(sPeripheral) .. ")") |         print(sPeripheral .. " (" .. table.concat({ peripheral.getType(sPeripheral) }, ", ") .. ")") | ||||||
|     end |     end | ||||||
| else | else | ||||||
|     print("None") |     print("None") | ||||||
|   | |||||||
| @@ -1,6 +1,13 @@ | |||||||
| describe("The peripheral library", function() | describe("The peripheral library", function() | ||||||
|     local it_modem = peripheral.getType("top") == "modem" and it or pending |     local it_modem = peripheral.getType("top") == "modem" and it or pending | ||||||
|  |  | ||||||
|  |     local multitype_peripheral = setmetatable({}, { | ||||||
|  |         __name = "peripheral", | ||||||
|  |         name = "top", | ||||||
|  |         type = "modem", | ||||||
|  |         types = { "modem", "inventory", modem = true, inventory = true }, | ||||||
|  |     }) | ||||||
|  |  | ||||||
|     describe("peripheral.isPresent", function() |     describe("peripheral.isPresent", function() | ||||||
|         it("validates arguments", function() |         it("validates arguments", function() | ||||||
|             peripheral.isPresent("") |             peripheral.isPresent("") | ||||||
| @@ -26,6 +33,10 @@ describe("The peripheral library", function() | |||||||
|             expect.error(peripheral.getType, {}):eq("bad argument #1 (table is not a peripheral)") |             expect.error(peripheral.getType, {}):eq("bad argument #1 (table is not a peripheral)") | ||||||
|         end) |         end) | ||||||
|  |  | ||||||
|  |         it("returns nil when no peripheral is present", function() | ||||||
|  |             expect(peripheral.getType("bottom")):eq(nil) | ||||||
|  |         end) | ||||||
|  |  | ||||||
|         it_modem("can get the type of a peripheral by side", function() |         it_modem("can get the type of a peripheral by side", function() | ||||||
|             expect(peripheral.getType("top")):eq("modem") |             expect(peripheral.getType("top")):eq("modem") | ||||||
|         end) |         end) | ||||||
| @@ -33,6 +44,38 @@ describe("The peripheral library", function() | |||||||
|         it_modem("can get the type of a wrapped peripheral", function() |         it_modem("can get the type of a wrapped peripheral", function() | ||||||
|             expect(peripheral.getType(peripheral.wrap("top"))):eq("modem") |             expect(peripheral.getType(peripheral.wrap("top"))):eq("modem") | ||||||
|         end) |         end) | ||||||
|  |  | ||||||
|  |         it("can return multiple types", function() | ||||||
|  |             expect({ peripheral.getType(multitype_peripheral) }):same { "modem", "inventory" } | ||||||
|  |         end) | ||||||
|  |     end) | ||||||
|  |  | ||||||
|  |     describe("peripheral.hasType", function() | ||||||
|  |         it("validates arguments", function() | ||||||
|  |             peripheral.getType("") | ||||||
|  |             expect.error(peripheral.hasType, nil):eq("bad argument #1 (expected string or table, got nil)") | ||||||
|  |             expect.error(peripheral.hasType, {}, ""):eq("bad argument #1 (table is not a peripheral)") | ||||||
|  |             expect.error(peripheral.hasType, ""):eq("bad argument #2 (expected string, got nil)") | ||||||
|  |         end) | ||||||
|  |  | ||||||
|  |         it("returns nil when no peripherals are present", function() | ||||||
|  |             expect(peripheral.hasType("bottom", "modem")):eq(nil) | ||||||
|  |         end) | ||||||
|  |  | ||||||
|  |         it_modem("can check type of a peripheral by side", function() | ||||||
|  |             expect(peripheral.hasType("top", "modem")):eq(true) | ||||||
|  |             expect(peripheral.hasType("top", "not_a_modem")):eq(false) | ||||||
|  |         end) | ||||||
|  |  | ||||||
|  |         it_modem("can check the type of a wrapped peripheral (true)", function() | ||||||
|  |             expect(peripheral.hasType(peripheral.wrap("top"), "modem")):eq(true) | ||||||
|  |         end) | ||||||
|  |  | ||||||
|  |         it("can check the type of a wrapped peripheral (fake)", function() | ||||||
|  |             expect(peripheral.hasType(multitype_peripheral, "modem")):eq(true) | ||||||
|  |             expect(peripheral.hasType(multitype_peripheral, "inventory")):eq(true) | ||||||
|  |             expect(peripheral.hasType(multitype_peripheral, "something else")):eq(false) | ||||||
|  |         end) | ||||||
|     end) |     end) | ||||||
|  |  | ||||||
|     describe("peripheral.getMethods", function() |     describe("peripheral.getMethods", function() | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Jonathan Coates
					Jonathan Coates