Device Network

Device networking allows machines and devices to communicate with each other while adhering to restrictions like range or being connected to the same powernet. Players will also have the abillity to interact with the device network in multiple ways. For example one could use a packet sniffer in their pda (Not yet implemented) to listen to messages sent over the wireless device network.

Quick Overview

Entities can join a network and will be assigned a network address. These entities can then optionally choose to listen on some frequency. Any device on a network can send packets on any frequency (not just one it’s listening on). The packets can either be broadcast, or directed at a specific address. The actual packets take the form of ECS events. A system just needs to listen for a DeviceNetworkPacketEvent. This event contains information about the sender and a NetworkPayload, which is basically just a Dictionary<string, object>. The contents of the payload and how to interpret them is just hard coded in each system. Some commonly used string keys are defined in DeviceNetworkConstants.cs.

Network ids:

Device Net Ids are used to segregate devices into different sub networks. This is done for performance and organisational reasons and to prevent players from interacting with packets that are not supposed to be interacted with.

Warning

Device net ids do not specify how a device connects to other devices (e.g wireless). Use the components for that.

0 - PRIVATE netId: Private This network is not supposed to be interacted with by players.

1 - WIRED netId: Wired Used for wired networks. This is supposed to be used with the WiredNetworkComponent if the device doesn’t use a custom device net id.

2 - WIRELESS netId: Wireless Used for wireless networks. This is supposed to be used with the WirelessNetworkComponent if the device doesn’t use a custom device net id.

3 - ApcNet netId: Apc Used for wired networks that are limited to apc extension cables. E.g. light switches. This is supposed to be used with the ApcNetworkComponent if the device doesn’t use a custom device net id.

4 - AtmosDevices netId: AtmosDevices Used for atmospherics devices like scrubbers to segregate them from other networks

Network Connection Components

To use the device network you need to add the DeviceNetworkComponent and the component for the type of connection you want. You can also not use one of the connection components when you want the device to always be able to send and receive messages. There are different types of connection components.

Device Network Component

This is the required component for sending and receiving device network messages.

YAML
components:
- type: DeviceNetwork
  deviceNetId: <Private|Wired|Wireless|Apc>
  receiveFrequency: <uint?>
  receiveFrequencyId: <string?>
  transmitFrequency: <uint?>
  transmitFrequencyId: <string?>
  address: <string>
  customAddress: <bool>
  prefix: <string>
  receiveAll: <bool>
  autoConnect: <bool>
  sendBroadcastAttemptEvent: <bool>

deviceNetId Set the DeviceNetId of this device. If you need to add a new one add it to DeviceNetIdDefaults in DeviceNetworkComponent.cs. Defaults to 0 (Private).

receiveFrequency The frequency this connection receives packets on. Defaults to null, in which case this device will not receive any packets (though it can still send them).

Unless your device has to possibly listen for messages, this should be set to null for performance reasons. E.g., while every player’s suit-sensors will send packets on a given frequency, they do not listen for packets on any frequency.

receiveFrequencyId The ID string for a FrequencyPrototype. If this field is not null, then during mapinit component’s receiveFrequency will be updated to match the prototype’s frequency. These prototypes are basically just named uints. E.g., the SuitSensor prototype should be used for all suit-sensor or crew-monitor related devices.

transmitFrequency This is the default frequency that a device will use to transmit packets. It is simply used as a default argument for the send-packet function.

transmitFrequencyId Like receiveFrequencyId, but for transmitFrequency

address The address of a device on a network. Used to ensure that devices have persistent addresses when a map is saved or loaded. By default, addresses are auto-generated when first connecting to a network. If the address field is already filled in, and the requested address is already taken, it will simply generate a new address.

customAddress Specifies whether the address was randomly generated when connecting to a network, or explicitly specified. If the address is a custom address, it will not be overriden by automatically generated addresses when connecting to networks.

prefix A prefix string that is prepended to any randomly generated addresses (which are just hex-code strings). Useful for allowing a device-type to be identifiable via the address. E.g., all atmos vents have a Vnt- prefix.

receiveAll If true, this device will receive all packets sent on the receiveFrequency, instead of only those that are either broadcast or directed at this devices’ address. Can be used to snoop in on messages.

autoConnect Determines whether a device should attempt to join a network on map init. Usually true, unless a device was explicitly disconnected from a network, in which case it should not re-connect when a map is re-loaded.

sendBroadcastAttemptEvent Sends the broadcast recipients list to the sender before broadcasting a packet so it can be filtered if set to true. Defaults to false.

Wireless Network Component

The wireles network component checks if the devices are in range of each other before allowing a message to be sent.

YAML

Allows a devices to send packets to other devices as long as the are the sender’s wireless range is large enough.

components:
    - type: DeviceNetworkComponent
    ...
    - type: WirelessNetworkConnection
      range: <int>

range The range this connection sends and receives at.

Apc Network Component

Danger

It’s very hard to prevent APCs from connection with each other during mapping and limiting an APC to a specific room or making sure all the devices you want are connected is difficult. This component might get removed in the future because of that.

Allows devices send packets to each other as long as they are drawing power from the same APC.

YAML
components:
    - type: DeviceNetworkComponent
    ...
    - type: ApcNetworkConnection

Wired Network Component

Danger

Currently it only checks if the devices are on the same grid. Behavior will be implemented in the future.

YAML
components:
    - type: DeviceNetworkComponent
    ...
    - type: WiredNetworkComponent

Station Limited Network Component

Allows devices that belong to the same station to send and receive packets to each other.

YAML
components:
    - type: DeviceNetworkComponent
    ...
    - type: StationLimitedNetwork
      allowNonStationPackets: <bool>

allowNonStationPackets Allows the device to receive packets from devices that don’t have a StationLimitedNetwork component.

Device Network Requires Power Component

Prevents any packets from being received if the device doesn’t have power.

YAML
components:
    - type: DeviceNetworkComponent
    ...
    - type: DeviceNetworkRequiresPower

The device network system

Events

There are three events used by the system to send messages to devices:

BeforeBroadcastAttemptEvent This event is sent to an entity that is about to broadcast a packet if sendBroadcastAttemptEvent is set to true on the sending device. This event can be used to modify the recipients of that broadcast or to cancel it.

DETAILS

BeforeBroadcastAttemptEvent(IReadOnlySet<DeviceNetworkComponent> recipients)

recipients The list of recipients the broadcast is about to send packets to. Property: ModifiedRecipients This is a property on the event that can to be set to the new list of recipients. If this property is null the broadcast will be canceled.

BeforePacketSentEvent This event is raised before a device network message is sent. Subscribed to by other systems to prevent the message from being sent.

DETAILS

BeforePacketSentEvent(EntityUid sender, TransformComponent xform, Vector2 senderPosition)

sender The EntityUid of the entity the message was sent from. xform The transform component of the sender. senderPosition The world-position of the sender.

DeviceNetworkPacketEvent Event raised directed at an entity when a device network message is received.

DETAILS

DeviceNetworkPacketEvent(ConnectionType netId, string? address, uint frequency, string senderAddress, EntityUid sender, NetworkPayload data)

netId The network that was used to send the packet.

address The address that the packet was sent to. Null if the packet was broadcast.

frequency The frequency the message was sent on.

senderAddress The device network address of the sending entity

sender The sender’s EntityUid

data The data that is beeing sent.

Methods

QueuePacket Sends the given payload as a device network message to the entity with the given address and frequency.

DETAILS

QueuePacket(EntityUid uid, string? address, NetworkPayload data, uint? frequency = null, int? network = null, DeviceNetworkComponent? device = null)

uid The EntityUid of the sending entity.

address The address of the entity that the packet gets sent to. If null, the packet gets broadcast.

data The data that is beeing sent.

frequency The frequency on which to send the data. If null, will default to the devices current transmit frequency.

network The network id to send on.

The device network system contains more public methods for things like setting the listening frequency of a device.

The network payload class

The network payload class contains the data that is sent over the device network which can eventually be seen by the player. The player will only be able to see and manipulate primitive types if they can see or manipulate the payload.

Creating a network payload:

var payload = new NetworkPayload
{
    ["Key1"] = Value1,
    ["Key2"] = Value2,
    ["Key3"] = Value3
    //...
};

The device network constants class

The class DeviceNetworkConstants contains common network ids and string constants for creating network payloads. You are not restricted to using the ids or string constants provided in this class but you should try to use COMMAND when applicable.

When creating network payloads you should try to use constants for keys and values that are always the same.

One example of a command and message is the mailing units get_mailer_tag for querying other units and its mailer_tag message for responding with its tag.

Standard payload constants:

COMMAND The key used for specifying the command/type of payload e.g. pda_mail.

Examples:

Sending a network Message

//This is somewhere at the top of your entity system
[Dependency] private readonly DeviceNetworkSystem _deviceNetworkSystem = default!;

public const string NetCmdPdaMail = "pda_mail";
public const string NetTargetMail = "target_mail_address";
public const string NetSenderMail = "sender_mail_address";
public const string NetMessage = "message";
...
//When you want to send a network message you need to construct a network payload and send it using the DeviceNetworkSystems QueuePacket method.
var payload = new NetworkPayload
{
    [DeviceNetworkConstants.COMMAND] = NetCmdPdaMail,
    //You're not restricted to using DeviceNetworkConstants.COMMAND
    [NetMessage] = "Hi Bob, bla bla bla...",
    [NetTargetMail] = "[email protected]",
    [NetSenderMail] = "[email protected]"
};

_deviceNetworkSystem.QueuePacket(uuidOfCurrentEntity, addressOfMailserverOrSomething, payload);

The sending entity should either be pre-configured to send on the mailing frequency, or else you would need to resolve the mailing frequency prototype and pass the correct frequency as an argument.

Receiving and handling a network message

...
[Dependency] private readonly DeviceNetworkSystem _deviceNetworkSystem = default!;

public const string NetCmdPing = "ping"
public const string NetMessage = "message";

public override void Initialize()
{
    base.Initialize();

		...
	  SubscribeLocalEvent<DeviceNetworkComponent, DeviceNetworkPacketEvent>(OnPacketReceived);
		...
}
...

private void OnPacketReceived(Entity<DeviceNetworkComponent> ent, ref DeviceNetworkPacketEvent args)
{
    //Since we are doing it the recommended way of using the command constant we try to get it from the payload
    if (args.Data.TryGetValue(DeviceNetworkConstants.COMMAND, out String command))
    {
        //If that command is the PING command (you can check for your own command here)
        if (command == NetCmdPing)
        {
            //We create a payload containing the ping_response command and "Hello World" as a message. 
            //(For this example I just passed the command name as a string instead of creating a constant.)
            var payload = new NetworkPayload
            {
                [DeviceNetworkConstants.COMMAND] "ping_response",
                [NetMessage] = "Hello World"
            };
            
            //And send the response to that ping
            _deviceNetworkSystem.QueuePacket(ent, args.SenderAddress, payload, args.Frequency);
        }
    }
}

Subpages