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

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 GPS protocol). 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 ComputerCraft side bus), the position of the center of the computer directly.

  • When the modem is plugged on the wired bus (see ComputerCraft wired bus), 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 D_{max} and represented in blocks, is the following:

\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:

  • y is the modem’s y coordinate.

  • Y_{max} is the maximum Y coordinate, equal to 256 in Minecraft 1.16.

  • R_{low} represents the range of wireless modems at “low altitude”, i.e. at y = 96 and below; it is configurable, but is of 64 in both clear weather and storm.

  • R_{high} represents the range of wireless modems at “high altitude”, i.e. at 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:

Weather

Range at low alt.

Range at high alt.

Clear

64

384

Storm

16

96

Wireless range evolution.

A vizualization of the range depending on the current y coordinate, with 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

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 2 * 2 + 13 + 8 = 25

  • nil: the number of bytes of the packet is 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

Skynet is a virtual modem running on top of websockets. It is centralized, based on a server operated by the project’s author, 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 Gollark's description of Skynet for reference. For experimenting, Gollark has made a web client for Skynet.

rednoot modems

rednoot is a virtual modem running on top of websockets. The project was started in 2017 by 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.