--JPERIPHERALS --[[- Find and control peripherals attached to this computer. 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. :::info 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 native = peripheral for k, v in pairs(native) do print(k) end local sides = rs.getSides() --- Provides a list of all peripherals available. -- -- If a device is located directly next to the system, then its name will be -- listed as the side it is attached to. If a device is attached via a Wired -- Modem, then it'll be reported according to its name on the wired network. -- -- @treturn { string... } A list of the names of all attached peripherals. -- @since 1.51 function getNames() local results = {} for n = 1, #sides do local side = sides[n] if native.isPresent(side) then table.insert(results, side) 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) end end end end return results end --- Determines if a peripheral is present with the given name. -- -- @tparam string name The side or network name that you want to check. -- @treturn boolean If a peripheral is present with the given name. -- @usage peripheral.isPresent("top") -- @usage peripheral.isPresent("monitor_0") function isPresent(name) expect(1, name, "string") if native.isPresent(name) then return true 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", name) then return true end end return false end --[[- 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 if native.isPresent(peripheral) then return native.getType(peripheral) 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, "getTypeRemote", peripheral) 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 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 --- Get all available methods for the peripheral with the given name. -- -- @tparam string name The name of the peripheral to find. -- @treturn { string... }|nil A list of methods provided by this peripheral, or `nil` if -- it is not present. function getMethods(name) expect(1, name, "string") if native.isPresent(name) then return native.getMethods(name) 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", name) then return native.call(side, "getMethodsRemote", name) end end return nil end --- Get the name of a peripheral wrapped with @{peripheral.wrap}. -- -- @tparam table peripheral The peripheral to get the name of. -- @treturn string The name of the given peripheral. -- @since 1.88.0 function getName(peripheral) expect(1, peripheral, "table") local mt = getmetatable(peripheral) if not mt or mt.__name ~= "peripheral" or type(mt.name) ~= "string" then error("bad argument #1 (table is not a peripheral)", 2) end return mt.name end --- Call a method on the peripheral with the given name. -- -- @tparam string name The name of the peripheral to invoke the method on. -- @tparam string method The name of the method -- @param ... Additional arguments to pass to the method -- @return The return values of the peripheral method. -- -- @usage Open the modem on the top of this computer. -- -- peripheral.call("top", "open", 1) function call(name, method, ...) expect(1, name, "string") expect(2, method, "string") if native.isPresent(name) then return native.call(name, method, ...) 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", name) then return native.call(side, "callRemote", name, method, ...) end end return nil end --- 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. -- -- local modem = peripheral.wrap("top") -- modem.open(1) function wrap(name) expect(1, name, "string") local methods = peripheral.getMethods(name) if not methods then 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 = types[1], types = types, }) for _, method in ipairs(methods) do result[method] = function(...) return peripheral.call(name, method, ...) end end return result end --[[- Find all peripherals of a specific type, and return the @{peripheral.wrap|wrapped} peripherals. @tparam string ty The type of peripheral to look for. @tparam[opt] function(name:string, wrapped:table):boolean filter A filter function, which takes the peripheral's name and wrapped table and returns if it should be included in the result. @treturn table... 0 or more wrapped peripherals matching the given filters. @usage Find all monitors and store them in a table, writing "Hello" on each one. local monitors = { peripheral.find("monitor") } for _, monitor in pairs(monitors) do monitor.write("Hello") end @usage Find all wireless modems connected to this computer. local modems = { peripheral.find("modem", function(name, modem) return modem.isWireless() -- Check this modem is wireless. end) } @usage This abuses the `filter` argument to call @{rednet.open} on every modem. peripheral.find("modem", rednet.open) @since 1.6 ]] function find(ty, filter) expect(1, ty, "string") expect(2, filter, "function", "nil") local results = {} for _, name in ipairs(peripheral.getNames()) do if peripheral.hasType(name, ty) then local wrapped = peripheral.wrap(name) if filter == nil or filter(name, wrapped) then table.insert(results, wrapped) end end end return table.unpack(results) end