mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2024-12-14 12:10:30 +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:
parent
298f339376
commit
53811f8169
@ -2,7 +2,7 @@
|
||||
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
|
||||
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.Nullable;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* The interface that defines a peripheral.
|
||||
@ -31,6 +33,18 @@ public interface IPeripheral
|
||||
@Nonnull
|
||||
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.
|
||||
*
|
||||
|
@ -6,9 +6,13 @@
|
||||
package dan200.computercraft.api.peripheral;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* The type of a {@link GenericPeripheral}.
|
||||
@ -18,13 +22,19 @@ import javax.annotation.Nullable;
|
||||
*/
|
||||
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 Set<String> additionalTypes;
|
||||
|
||||
public PeripheralType( String type )
|
||||
public PeripheralType( String type, Set<String> additionalTypes )
|
||||
{
|
||||
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 )
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.computer.ComputerSide;
|
||||
import dan200.computercraft.core.tracking.TrackingField;
|
||||
import dan200.computercraft.shared.util.LuaUtil;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
@ -36,6 +37,7 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
|
||||
private final IPeripheral peripheral;
|
||||
|
||||
private final String type;
|
||||
private final Set<String> additionalTypes;
|
||||
private final Map<String, PeripheralMethod> methodMap;
|
||||
private boolean attached;
|
||||
|
||||
@ -47,6 +49,7 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
|
||||
attached = false;
|
||||
|
||||
type = Objects.requireNonNull( peripheral.getType(), "Peripheral type cannot be null" );
|
||||
additionalTypes = peripheral.getAdditionalTypes();
|
||||
|
||||
methodMap = PeripheralAPI.getMethods( peripheral );
|
||||
}
|
||||
@ -61,6 +64,11 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
|
||||
return type;
|
||||
}
|
||||
|
||||
public Set<String> getAdditionalTypes()
|
||||
{
|
||||
return additionalTypes;
|
||||
}
|
||||
|
||||
public Collection<String> getMethods()
|
||||
{
|
||||
return methodMap.keySet();
|
||||
@ -298,7 +306,23 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
|
||||
synchronized( peripherals )
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -18,18 +18,21 @@ import net.minecraft.util.ResourceLocation;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
class GenericPeripheral implements IDynamicPeripheral
|
||||
{
|
||||
private final String type;
|
||||
private final Set<String> additionalTypes;
|
||||
private final TileEntity tile;
|
||||
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();
|
||||
this.tile = tile;
|
||||
this.type = name != null ? name : (type != null ? type.toString() : "unknown");
|
||||
this.additionalTypes = additionalTypes;
|
||||
this.methods = methods;
|
||||
}
|
||||
|
||||
@ -56,6 +59,13 @@ class GenericPeripheral implements IDynamicPeripheral
|
||||
return type;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Set<String> getAdditionalTypes()
|
||||
{
|
||||
return additionalTypes;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Object getTarget()
|
||||
|
@ -20,9 +20,7 @@ import net.minecraftforge.common.util.NonNullConsumer;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.*;
|
||||
|
||||
public class GenericPeripheralProvider
|
||||
{
|
||||
@ -62,15 +60,16 @@ public class GenericPeripheralProvider
|
||||
|
||||
private static class GenericPeripheralBuilder
|
||||
{
|
||||
String name;
|
||||
final ArrayList<SaturatedMethod> methods = new ArrayList<>( 0 );
|
||||
private String name;
|
||||
private final Set<String> additionalTypes = new HashSet<>( 0 );
|
||||
private final ArrayList<SaturatedMethod> methods = new ArrayList<>( 0 );
|
||||
|
||||
IPeripheral toPeripheral( TileEntity tile )
|
||||
{
|
||||
if( methods.isEmpty() ) return null;
|
||||
|
||||
methods.trimToSize();
|
||||
return new GenericPeripheral( tile, name, methods );
|
||||
return new GenericPeripheral( tile, name, additionalTypes, methods );
|
||||
}
|
||||
|
||||
void addMethods( Object target, List<NamedMethod<PeripheralMethod>> methods )
|
||||
@ -89,6 +88,7 @@ public class GenericPeripheralProvider
|
||||
String name = type.getPrimaryType();
|
||||
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;
|
||||
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.api.lua.GenericSource;
|
||||
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.minecraftforge.energy.IEnergyStorage;
|
||||
|
||||
@ -25,8 +26,15 @@ import javax.annotation.Nonnull;
|
||||
*
|
||||
* @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
|
||||
@Override
|
||||
public ResourceLocation id()
|
||||
|
@ -6,11 +6,12 @@
|
||||
package dan200.computercraft.shared.peripheral.generic.methods;
|
||||
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.api.lua.GenericSource;
|
||||
import dan200.computercraft.api.lua.LuaException;
|
||||
import dan200.computercraft.api.lua.LuaFunction;
|
||||
import dan200.computercraft.api.peripheral.GenericPeripheral;
|
||||
import dan200.computercraft.api.peripheral.IComputerAccess;
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.api.peripheral.PeripheralType;
|
||||
import dan200.computercraft.shared.peripheral.generic.data.FluidData;
|
||||
import net.minecraft.fluid.Fluid;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
@ -35,8 +36,15 @@ import static dan200.computercraft.shared.peripheral.generic.methods.ArgumentHel
|
||||
*
|
||||
* @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
|
||||
@Override
|
||||
public ResourceLocation id()
|
||||
|
@ -6,11 +6,12 @@
|
||||
package dan200.computercraft.shared.peripheral.generic.methods;
|
||||
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.api.lua.GenericSource;
|
||||
import dan200.computercraft.api.lua.LuaException;
|
||||
import dan200.computercraft.api.lua.LuaFunction;
|
||||
import dan200.computercraft.api.peripheral.GenericPeripheral;
|
||||
import dan200.computercraft.api.peripheral.IComputerAccess;
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.api.peripheral.PeripheralType;
|
||||
import dan200.computercraft.shared.peripheral.generic.data.ItemData;
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
@ -36,8 +37,15 @@ import static dan200.computercraft.shared.peripheral.generic.methods.ArgumentHel
|
||||
*
|
||||
* @cc.module inventory
|
||||
*/
|
||||
public class InventoryMethods implements GenericSource
|
||||
public class InventoryMethods implements GenericPeripheral
|
||||
{
|
||||
@Nonnull
|
||||
@Override
|
||||
public PeripheralType getType()
|
||||
{
|
||||
return PeripheralType.ofAdditional( "inventory" );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public ResourceLocation id()
|
||||
|
@ -21,6 +21,7 @@ import dan200.computercraft.core.apis.PeripheralAPI;
|
||||
import dan200.computercraft.core.asm.PeripheralMethod;
|
||||
import dan200.computercraft.shared.peripheral.modem.ModemPeripheral;
|
||||
import dan200.computercraft.shared.peripheral.modem.ModemState;
|
||||
import dan200.computercraft.shared.util.LuaUtil;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
@ -118,13 +119,35 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW
|
||||
* @param name 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.changed 1.99 Peripherals can have multiple types - this function returns multiple values.
|
||||
* @see PeripheralAPI#getType
|
||||
*/
|
||||
@LuaFunction
|
||||
public final Object[] getTypeRemote( IComputerAccess computer, String 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 type;
|
||||
private final Set<String> additionalTypes;
|
||||
private final Map<String, PeripheralMethod> methodMap;
|
||||
|
||||
private volatile boolean attached;
|
||||
@ -321,6 +345,7 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW
|
||||
this.name = name;
|
||||
|
||||
type = Objects.requireNonNull( peripheral.getType(), "Peripheral type cannot be null" );
|
||||
additionalTypes = peripheral.getAdditionalTypes();
|
||||
methodMap = PeripheralAPI.getMethods( peripheral );
|
||||
}
|
||||
|
||||
@ -354,6 +379,11 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW
|
||||
return type;
|
||||
}
|
||||
|
||||
public Set<String> getAdditionalTypes()
|
||||
{
|
||||
return additionalTypes;
|
||||
}
|
||||
|
||||
public Collection<String> getMethodNames()
|
||||
{
|
||||
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
|
||||
-- computer, such as the Disk Drive, the Advanced Monitor and Monitor.
|
||||
--
|
||||
-- Each peripheral block has a name, either referring to the side the peripheral
|
||||
-- can be found on, or a name on an adjacent wired network.
|
||||
--
|
||||
-- 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
|
||||
-- a cable, its side will follow the format `type_id`, for example `printer_0`.
|
||||
--
|
||||
-- Peripheral functions are called *methods*, a term borrowed from Java.
|
||||
--
|
||||
-- @module peripheral
|
||||
-- @since 1.3
|
||||
-- @changed 1.51 Add support for wired modems.
|
||||
--[[- Peripherals are blocks (or turtle and pocket computer upgrades) which can
|
||||
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
|
||||
in the world.
|
||||
|
||||
## Referencing peripherals
|
||||
|
||||
Computers can interact with adjacent peripherals. Each peripheral is given a
|
||||
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
|
||||
`"left"` , and so on for all 6 directions (`"bottom"`, `"top"`, `"left"`,
|
||||
`"right"`, `"front"`, `"back"`).
|
||||
|
||||
You can list the names of all peripherals with the `peripherals` program, or the
|
||||
@{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
|
||||
|
||||
@ -33,7 +105,7 @@ function getNames()
|
||||
local side = sides[n]
|
||||
if native.isPresent(side) then
|
||||
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")
|
||||
for _, name in ipairs(remote) do
|
||||
table.insert(results, name)
|
||||
@ -58,7 +130,7 @@ function isPresent(name)
|
||||
|
||||
for n = 1, #sides do
|
||||
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)
|
||||
then
|
||||
return true
|
||||
@ -67,12 +139,17 @@ function isPresent(name)
|
||||
return false
|
||||
end
|
||||
|
||||
--- Get the type of a wrapped peripheral, or a peripheral with the given name.
|
||||
--
|
||||
-- @tparam string|table peripheral The name of the peripheral to find, or a
|
||||
-- wrapped peripheral instance.
|
||||
-- @treturn string|nil The peripheral's type, or `nil` if it is not present.
|
||||
-- @changed 1.88.0 Accepts a wrapped peripheral as an argument.
|
||||
--[[- Get the types of a named or wrapped peripheral.
|
||||
|
||||
@tparam string|table peripheral The name of the peripheral to find, or a
|
||||
wrapped peripheral instance.
|
||||
@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.99 Now returns multiple types.
|
||||
@usage Get the type of a peripheral above this computer.
|
||||
|
||||
peripheral.getType("top")
|
||||
]]
|
||||
function getType(peripheral)
|
||||
expect(1, peripheral, "string", "table")
|
||||
if type(peripheral) == "string" then -- Peripheral name passed
|
||||
@ -81,7 +158,7 @@ function getType(peripheral)
|
||||
end
|
||||
for n = 1, #sides do
|
||||
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)
|
||||
then
|
||||
return native.call(side, "getTypeRemote", peripheral)
|
||||
@ -90,10 +167,43 @@ function getType(peripheral)
|
||||
return nil
|
||||
else
|
||||
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)
|
||||
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
|
||||
|
||||
@ -109,7 +219,7 @@ function getMethods(name)
|
||||
end
|
||||
for n = 1, #sides do
|
||||
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)
|
||||
then
|
||||
return native.call(side, "getMethodsRemote", name)
|
||||
@ -151,7 +261,7 @@ function call(name, method, ...)
|
||||
|
||||
for n = 1, #sides do
|
||||
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)
|
||||
then
|
||||
return native.call(side, "callRemote", name, method, ...)
|
||||
@ -160,15 +270,16 @@ function call(name, method, ...)
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Get a table containing functions pointing to the peripheral's methods, which
|
||||
-- can then be called as if using @{peripheral.call}.
|
||||
--- Get a table containing all functions available on a peripheral. These can
|
||||
-- then be called instead of using @{peripheral.call} every time.
|
||||
--
|
||||
-- @tparam string name The name of the peripheral to wrap.
|
||||
-- @treturn table|nil The table containing the peripheral's methods, or `nil` if
|
||||
-- there is no peripheral present with the given name.
|
||||
-- @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)
|
||||
expect(1, name, "string")
|
||||
|
||||
@ -177,10 +288,14 @@ function wrap(name)
|
||||
return nil
|
||||
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({}, {
|
||||
__name = "peripheral",
|
||||
name = name,
|
||||
type = peripheral.getType(name),
|
||||
type = types[1],
|
||||
types = types,
|
||||
})
|
||||
for _, method in ipairs(methods) do
|
||||
result[method] = function(...)
|
||||
@ -222,7 +337,7 @@ function find(ty, filter)
|
||||
|
||||
local results = {}
|
||||
for _, name in ipairs(peripheral.getNames()) do
|
||||
if peripheral.getType(name) == ty then
|
||||
if peripheral.hasType(name, ty) then
|
||||
local wrapped = peripheral.wrap(name)
|
||||
if filter == nil or filter(name, wrapped) then
|
||||
table.insert(results, wrapped)
|
||||
|
@ -3,7 +3,7 @@ print("Attached Peripherals:")
|
||||
if #tPeripherals > 0 then
|
||||
for n = 1, #tPeripherals do
|
||||
local sPeripheral = tPeripherals[n]
|
||||
print(sPeripheral .. " (" .. peripheral.getType(sPeripheral) .. ")")
|
||||
print(sPeripheral .. " (" .. table.concat({ peripheral.getType(sPeripheral) }, ", ") .. ")")
|
||||
end
|
||||
else
|
||||
print("None")
|
||||
|
@ -1,6 +1,13 @@
|
||||
describe("The peripheral library", function()
|
||||
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()
|
||||
it("validates arguments", function()
|
||||
peripheral.isPresent("")
|
||||
@ -26,6 +33,10 @@ describe("The peripheral library", function()
|
||||
expect.error(peripheral.getType, {}):eq("bad argument #1 (table is not a peripheral)")
|
||||
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()
|
||||
expect(peripheral.getType("top")):eq("modem")
|
||||
end)
|
||||
@ -33,6 +44,38 @@ describe("The peripheral library", function()
|
||||
it_modem("can get the type of a wrapped peripheral", function()
|
||||
expect(peripheral.getType(peripheral.wrap("top"))):eq("modem")
|
||||
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)
|
||||
|
||||
describe("peripheral.getMethods", function()
|
||||
|
Loading…
Reference in New Issue
Block a user