Using the High-Level Networking API

Quickly create distributed, stateful gameplay with ARDK’s built-in high level networking API.

Introduction

Imagine the simplest way to replicate an object’s position with the MultipeerNetworking interface. It probably involves serializing the position Vector3 into a byte[], sending that byte[] with a specific tag, then listening for that tag and deserializing the Vector3 on the receiving end. Extending this pattern to support two objects would require another tag (or some prefix on the byte[] to specify the target). What about extending this to thousands of objects with different lifetimes, or adding additional fields (each object now has a color, and a name), or ownership over an object (which peer can manipulate it, who sees updates)?

The High Level Networking API (Hlapi) is a networking layer that sits on top of the MultipeerNetworking interface and solves these problems with a hierarchical addressing scheme. Each networked object is represented as NetworkGroup interface with a NetworkId tag, and each NetworkGroup contains any number of NetworkedDataHandlers, which are identified by strings and are the actual handlers of the data (e.g., sends the current position of the GameObject that it is attached to, and uses any received data to update position). Intermediate classes (such as the HlapiSession and NetworkGroup) deal with networking problems such as addressing, caching, and serializing data.

Features

With this architecture in mind, the Hlapi includes several features to quickly start building a multiplayer experience.

  • Network Spawning/Despawning : Register your object as a NetworkedUnityObject, the networked equivalent of a GameObject, and spawn (or despawn) that object for all peers in the session with a single API call.

  • Authority: Define ownership over networked data, so all peers agree on who is permitted to despawn objects, write to certain fields, listen for updates on those fields and more.

  • Networked Transforms: Drag-and-drop the NetTransform onto a GameObject to automatically hook into the Hlapi and enable the peer with Authority over the object to manipulate its transform for all other peers in the network session.

  • Generic Networked Fields: Construct a NetworkedField<T> to automatically propagate updates of a generic value to other peers in the network session.

  • Message Streams: Send and receive objects of type T in a stream instead of raw byte messages using the MessageStreamReplicator<T>.

When to use the Hlapi vs MultipeerNetworking (low level networking)

The Hlapi is a prebuilt system that works out-of-the-box, but is also generic enough to support custom implementations at any of its levels. However, it does come with some per-message networking overhead (every message is tagged with a NetworkGroup ID, as well as a NetworkedDataHandler ID, for routing) as well as run-time overhead (peer management, querying groups/handlers for messages every frame).

It is worth considering using only the MultipeerNetworking API if your application has very few message types (i.e. just spawning a single object and moving it around), or if you have a preferred networking library that can utilize the raw byte message API and handle its own addressing/parsing.

Each HlapiSession uses a single message tag for all of its messages (set when the session is constructed), so it is possible to use the Hlapi for some functionality (i.e. network spawning), while sending and parsing raw byte messages for other networked functionality. In this case, it is especially important to keep track of what message tags are being used, to avoid conflicting messages from the two systems.

using Niantic.ARDK.AR.Networking;
using Niantic.ARDK.Networking.HLAPI.Object.Unity;

// Reference set in Inspector
public NetworkedUnityObject _objectToNetworkSpawn;

// Enum list containing all message tags used in the application
public enum GameActionMessageTags : uint
{
 // Other game actions
 PerformSomeGameAction = 40U,
 // ...
}

// Use the Hlapi to network spawn an object across all peers
void SpawnObjectForAllPeers()
{
  // Note that NetworkSpawn is an extension method coming from NetworkSpawner
  _objectToNetworkSpawn.NetworkSpawn();
}

void PerformActionForAllPeers(IMultipeerNetworking networking, byte[] gameData)
{
  networking.BroadcastData(GameActionMessageTags.PerformSomeGameAction, gameData, TransportType.UnreliableUnordered);
}

void SubscribeToPeerDataReceived(IMultipeerNetworking networking)
{
  networking.PeerDataReceived += OnPeerDataReceived;
}

// Since the Hlapi also uses byte messages, this will be fired each time an object is NetworkSpawned as well
void OnPeerDataReceived(PeerDataReceivedArgs args)
{
  // Check that it is a message we care about, rather than an Hlapi message
  if(args.Tag != GameActionMessageTags.PerformSomeGameAction)
  {
    return;
  }

  // We now know this is the message that this class cares about, so use the data to perform some update
}

See Also

Low level networking

The high level networking API (Hlapi)