.. _explain-modem: Modem networking ================ Computers in general can network through various ways. In ComputerCraft and OpenComputers, although other means such as redstone or other mods exist in order to make two computers communicate, the most common one is modems. A **modem** is a device that allows **hosts** to send **messages**, as datagrams, on given **ports** (also named channels). These messages can either be directed at given computers, which is called "addressing", or broadcasted. A port can have different formats, specific to the modem type, and there can be a maximal number of opened ports by modem. Messages can have varying types according to the modem type. Some examples are: * ComputerCraft modem messages can be a string, a number, or a table combining these types. * Skynet modem messages can be any message CBOR-encodable. ComputerCraft modems -------------------- .. sidebar:: ComputerCraft modems .. figure:: modem-types.png :alt: Modem types represented in ComputerCraft. *From left to right: wired modem, wireless modem, ender modem.* .. list-table:: :widths: 2 8 * - addressing - no * - max_open - 128 * - port_fmt - :math:`[0, 65535]` * - msg_fmt - any string, number, boolean or table ComputerCraft adds three different kinds of modems: * **wired modems**, which allows a computer to be connected to another through wires. * **wireless modems**, which allows a computer to be connected to others without wires with a limited range depending on the weather. * **ender modems** are similar to wireless modems (in fact, ComputerCraft recognizes them as “advanced” wireless modems), except that for a given channel, they can communicate with all wireless and ender modems in all dimensions, and listen to all communications from wireless and ender modems from all dimensions; see `WirelessNetwork.tryTransmit`_ (where ``interdimensional`` is set for packets sent by ender modems, and ``receiver.isInterdimensional`` is true if the receiver is an ender modem). Note that what ComputerCraft wiki calls dimensions corresponds to what Mojang mappings calls worlds (hence the technical name ``net.minecraft.world.World``). All modems work the same: datagrams are sent on ports whose numbers vary between 0 and 65535 (see `modem.open`_). Through such a modem, computers can send a message from any arbitrary port, and receive messages on up to 128 simultaneously opened ports at once. .. note:: The opened port limit can be pushed further by using several modems on a computer; e.g. up to 256 ports can be opened when two wireless modems are connected. Messages are Lua strings, numbers, or tables; metatables are not transmitted along the way, a byproduct of using the ``@LuaFunction`` decorator from ComputerCraft. Any message on the given modems also send along the pipe the “reply channel”, which for Rednet-enabled devices corresponds to the source channel. Note that this can be set by the user program when sending a message and does not correspond to a MAC address or anything, therefore cannot be used as a reliable source port (see Rednet). When receiving a message, in the produced ``modem_message`` event in CraftOS, wireless and ender modems within the same dimensions include the distance from the emitting device; this specificity is used on some protocols, such as the GPS one (see :ref:`modem-gps`). Note that the distance is calculated not using the position of the modem themselves, but: * When the modem is plugged on the side bus (see :ref:`bus-cc-side`), the position of the center of the computer directly. * When the modem is plugged on the wired bus (see :ref:`bus-cc-wired`), the position of the center of the wired modem that is directly aside the modem receiving the message. The distance itself is calculated: * On wireless modems, the distance between the two positions determined using the method described above. * On wired modems, the number of cables and wired modems (including those used to send and receive the message on both sides) traversed by the message. .. warning:: If you're running a version of ComputerCraft before 1.53, tables are not supported as valid message types. .. note:: Although modem as blocks use integer coordinates, even turtles when they move (positions update immediately to the new block position), some modems can have decimal positions, most importantly pocket computers, linked to the player's coordinates. Classic GPS hosts round the coordinates with a .01 precision. Basic wireless modems have a limit on how far they can send modem messages. The formula for determining this limit, named :math:`D_{max}` and represented in blocks, is the following: .. math:: \begin{cases} D_{max} = R_{low} + (y - 96) * ((R_{high} - R_{low}) / (Y_{max} - 1 - 96) \text{ if $y > 96$} \\ D_{max} = R_{low} \text{ if $y <= 96$} \end{cases} Where the variables are the following: * :math:`y` is the modem's y coordinate. * :math:`Y_{max}` is the maximum Y coordinate, equal to 256 in Minecraft 1.16. * :math:`R_{low}` represents the range of wireless modems at "low altitude", i.e. at :math:`y = 96` and below; it is configurable, but is of 64 in both clear weather and storm. * :math:`R_{high}` represents the range of wireless modems at "high altitude", i.e. at :math:`y = Y_{max}`; it is configurable, but is of 384 in both clear weather and storm. .. note:: In legacy ComputerCraft, the values were the following: .. list-table:: :widths: 5 5 5 :header-rows: 1 * - Weather - Range at low alt. - Range at high alt. * - Clear - 64 - 384 * - Storm - 16 - 96 .. figure:: modem-wireless-range.png :align: center :alt: Wireless range evolution. A vizualization of the range depending on the current y coordinate, with :math:`Y_{max}` being defined to 256, its current value. The values taken for clear and stormy weathers are those of legacy ComputerCraft. See `WirelessModemPeripheral.getRange`_, `Config.Config`_ and `ComputerCraft.modemRange`_ for reference. In versions of ComputerCraft prior to 1.80pr1.3, wired modems/network cables have a limit of 256 cables. OpenComputers modems -------------------- .. sidebar:: OpenComputers modems .. list-table:: :widths: 2 8 * - addressing - yes * - max_open - none * - addr_fmt - component uuid * - port_fmt - :math:`[0, 65535]` * - msg_fmt - sequence of 1 to 8 of nil, boolean, number or string OpenComputers adds network cards which you can add to computers for network connectivity. They actually have a maximum packet size. In order to calculate the packet size from the given sequence as the message format: * Take the product of the number of members in the sequence and two. This is because each member of the sequence adds two bytes of overhead. * Then, for each number of the sequence: - If it is a ``nil`` or a boolean, add four. - Otherwise, if it is an empty string, add one. - Otherwise, if it is a string, add the number of bytes in the string. - Otherwise, if it is a number, add eight. Example sequences are the following: * ``"currentStatus", 300``: the number of bytes of the packet is :math:`2 * 2 + 13 + 8 = 25` * ``nil``: the number of bytes of the packet is :math:`2 * 1 + 4 = 6` .. todo:: There is plenty more to say about OpenComputers modems. Also, might be worth to try and get the maximum packet size into the general modem abstraction. See the `OpenComputers modem API`_ for more information. Skynet modems ------------- .. sidebar:: Skynet .. list-table:: :widths: 2 8 * - addressing - no * - max_open - none * - port_fmt - any string or number * - msg_fmt - any string, number, boolean or table `Skynet`_ is a virtual modem running on top of websockets. It is centralized, based on a server operated by the project's author, :ref:`player-gollark`. The project itself was started in 2018, and the current version as of March 22nd, 2021, is version 2. The virtual modem is much like your typical ComputerCraft modem, except that: * It is inter-platform: computers can communicate across servers, and even with other devices on the Internet; however, note that from a security perspective, making your devices communicating with a server you own directly is better. * There is no arbitrary limit to the number of channels a host can open. * A channel identifier can either be a number or a string. Note that ``"5"`` and ``5`` are two different channels. For joining the network, the client connects to the connect endpoint. As of February 26th, 2021, this URL is ``wss://skynet.osmarks.net/connect`` (previously ``wss://osmarks.tk/skynet2/connect/``). The websocket is used for a request/response protocol with server push for events. Modem messages used in both parts of the protocols are used as a table containing the following fields: * ``channel``: the channel identifier on which the message should be posted or is to be posted. * ``meta`` (*optional*): a metadata table using strings as keys and any CBOR-encodable values as values. * ``time`` (*only in received messages*): the time at which the message has been posted; set by the server to the UNIX timestamp in the UTC timezone when received. * ``data``: the data of the message, as a CBOR-encodable value. On the request/response part, the client sends a request as a CBOR-encoded sequence of two elements: the request type as a string, and the argument. The requests can be the following: * ``{"open", channel}`` where ``channel`` represents the channel identifier: this opens the channel, which will cause server pushes in case a message is sent by another host on the channel with that identifier. * ``{"close", channel}`` where ``channel`` represents the channel identifier: this closes the channel if it was previously opened by the client; if it wasn't opened, this request does not do anything. * ``{"send", message}`` where ``message`` is the message table: this sends a message on a channel, regardless of if the channel was previously opened by the client or not. If there was an error while decoding the message, the server answers with a CBOR-encoded sequence being ``{"error", "deserialization_failure", message}``, where ``message`` is a detailed error message provided by the deserializer. Otherwise, the server does not answer. .. note:: As there is no websocket message identifier and no acknowledgment in case of a successfully sent message, in case the modem driver has sent several messages, it cannot determine which one is erroneous. However, as the websocket is used in a connectionless fashion, the connection can still be used, but the messages sent to it must be used as datagrams. This makes the error messages actually useless, and only useful when testing a Skynet implementation manually, as shared logs. When a message is sent on a channel that the client has opened, the server pushes a message to the client as a CBOR-encoded sequence containing the following: ``{"message", message}``, where ``message`` is a message table. Skynet has a special channel, named ``"*"``, which corresponds to the wildcard channel. This channel can be used as a normal channel to send messages to and listening to messages on, except that when listening to the wildcard channel, all messages are received. See `Lua-CBOR`_, the `Skynet source`_ (including a Rust implementation of the server and a Lua implementation of the client) and :download:`Gollark's description of Skynet ` for reference. For experimenting, Gollark has made a `web client for Skynet `_. rednoot modems -------------- .. sidebar:: rednoot .. list-table:: :widths: 2 8 * - addressing - no * - max_open - none * - port_fmt - :math:`[1, 65535]` * - msg_fmt - any string, number, boolean or table `rednoot`_ (`thread `_) is a virtual modem running on top of websockets. The project was started in 2017 by :ref:`player-justync7`; it is no longer maintained, and the public instance recommended by the repo is no longer available, although the source code for both the client and the server are published under MIT, along with its `protocol specification `_. The virtual modem behaves like a ComputerCraft modem, except that: * It is inter-platform: computers can communicate no matter the distance, across servers, and even with other devices on the Internet; however, note that from a security perspective, making your devices communicating with a server you own directly is better. * There is no arbitrary limit to the number of channels a host can open. * Modem channels are numbers between 1 and 65535; channel number 0 isn't a valid channel like for ComputerCraft modems, which can be a problem when using Rednet with rednoot since 0 is the first computer ID attributed on any world save; however, a client is attributed an identifier when connecting, so using the local computer identifier is discouraged when using rednoot. Some remarks about the protocol itself described in the specification: * Messages are exchanged as stringified JSON documents, which the length as a number of characters (not bytes) must not exceed 65535 characters (resulting in a ``message_too_long`` error) and for which the root element of the parsed document must be a JSON array, other types resulting in an ``invalid_type`` error. * When connecting to a rednoot network, clients are attributed an identifier proper to the modem instead of using their computer ID. This is an efficient way to get an identifier that is guaranteed to be unique network-wide. This identifier is a number comprised between 1 and 65535; it can therefore be used for Rednet-like communications. * When sending messages, the client receives no acknowledgment but might receive an error message, without the message identifier. This is only useful when debugging an implementation manually. See the `rednoot client script`_ and the `rednoot message callback function`_ for reference. .. _modem.open: https://tweaked.cc/peripheral/modem.html#v:open .. _WirelessModemPeripheral.getRange: ttps://github.com/cc-tweaked/CC-Tweaked/blob/9d1ee6f61db478f364afa15a439a123ab21175ae/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java#L32 .. _Config.Config: ttps://github.com/cc-tweaked/CC-Tweaked/blob/58054ad2d1a9a967f1ef5dc981da5db938bb2c71/src/main/java/dan200/computercraft/shared/Config.java#L206 .. _ComputerCraft.modemRange: ttps://github.com/cc-tweaked/CC-Tweaked/blob/e4b0a5b3ce035eb23feb4191432fc49af5772c5b/src/main/java/dan200/computercraft/ComputerCraft.java#L60 .. _WirelessNetwork.tryTransmit: ttps://github.com/cc-tweaked/CC-Tweaked/blob/1316d6a3c906eb1dcc0323982b46f655777ee628/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessNetwork.java#L64 .. _rednoot: https://github.com/Lustyn/rednoot .. _Skynet: https://forums.computercraft.cc/index.php?topic=71 .. _Skynet source: https://github.com/osmarks/skynet .. _Lua-CBOR: https://www.zash.se/lua-cbor.html .. _rednoot specification: https://github.com/Lustyn/rednoot/blob/master/SPECIFICATION.md .. _rednoot message callback function: https://github.com/Lustyn/rednoot/blob/e29b30546d59ddda475509f5d272ed8eaa0b3396/app.js#L158 .. _rednoot client script: https://github.com/Lustyn/rednoot/blob/e29b30546d59ddda475509f5d272ed8eaa0b3396/client.lua .. _rednoot on ComputerCraft forums: http://www.computercraft.info/forums2/index.php?/topic/28595-rednoot-a-global-rednetmodem-bridge/ .. _OpenComputers modem API: https://ocdoc.cil.li/component:modem